test(integration): add deterministic NAT topology harness (#14)
quality-gate / quality (push) Failing after 1m3s
quality-gate / quality (push) Failing after 1m3s
This commit is contained in:
@@ -86,8 +86,10 @@ public sealed class UdpMediatorServiceTests
|
||||
await service.StopAsync(timeout.Token);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task NativeLiteNetLibRequestsIntroduceTheAuthorizedPair()
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public async Task NativeLiteNetLibRequestsIntroduceTheAuthorizedPair(bool restartMediator)
|
||||
{
|
||||
using CancellationTokenSource timeout = new(TimeSpan.FromSeconds(5));
|
||||
using JoinAttemptFixture fixture = new();
|
||||
@@ -103,18 +105,6 @@ public sealed class UdpMediatorServiceTests
|
||||
fixture.Sessions.Store,
|
||||
fixture.Sessions.Capabilities,
|
||||
fixture.Service);
|
||||
using UdpMediatorService service = new(
|
||||
Options.Create(new UdpMediatorOptions
|
||||
{
|
||||
ListenAddress = IPAddress.Loopback.ToString(),
|
||||
Port = 0,
|
||||
MaxDatagramsPerPoll = 8,
|
||||
PollIntervalMilliseconds = 1,
|
||||
}),
|
||||
NullLogger<UdpMediatorService>.Instance,
|
||||
processor);
|
||||
await service.StartAsync(timeout.Token);
|
||||
|
||||
EventBasedNetListener hostListener = new();
|
||||
EventBasedNetListener clientListener = new();
|
||||
NetManager host = new(hostListener) { NatPunchEnabled = true };
|
||||
@@ -127,53 +117,141 @@ public sealed class UdpMediatorServiceTests
|
||||
clientPunch.NatIntroductionSuccess += (_, _, ticket) => clientTickets.Add(ticket);
|
||||
host.NatPunchModule.Init(hostPunch);
|
||||
client.NatPunchModule.Init(clientPunch);
|
||||
UdpMediatorService? service = null;
|
||||
bool serviceStarted = false;
|
||||
|
||||
try
|
||||
{
|
||||
service = CreateMediator(processor, port: 0);
|
||||
await service.StartAsync(timeout.Token);
|
||||
serviceStarted = true;
|
||||
Assert.True(host.Start(0));
|
||||
Assert.True(client.Start(0));
|
||||
IPEndPoint mediator = Assert.IsType<IPEndPoint>(service.LocalEndpoint);
|
||||
host.NatPunchModule.SendNatIntroduceRequest(
|
||||
mediator,
|
||||
NatPunchRequestTokenCodec.Encode(
|
||||
NatPunchPeerRole.Host,
|
||||
created.MediationHandle,
|
||||
hostAttempt.HostPunchCapability));
|
||||
client.NatPunchModule.SendNatIntroduceRequest(
|
||||
mediator,
|
||||
NatPunchRequestTokenCodec.Encode(
|
||||
NatPunchPeerRole.Client,
|
||||
created.MediationHandle,
|
||||
created.ClientPunchCapability));
|
||||
|
||||
while ((hostTickets.Count == 0 || clientTickets.Count == 0)
|
||||
&& !timeout.IsCancellationRequested)
|
||||
if (restartMediator)
|
||||
{
|
||||
host.PollEvents();
|
||||
host.NatPunchModule.PollEvents();
|
||||
client.PollEvents();
|
||||
client.NatPunchModule.PollEvents();
|
||||
await Task.Delay(5, timeout.Token);
|
||||
await AssertNativeIntroductionAsync(
|
||||
service,
|
||||
host,
|
||||
client,
|
||||
hostTickets,
|
||||
clientTickets,
|
||||
created,
|
||||
hostAttempt,
|
||||
expectedCount: 1,
|
||||
cancellationToken: timeout.Token);
|
||||
created = fixture.Create(registration.ListingId, "native-litenet-after-restart");
|
||||
hostAttempt = fixture.Service.BrowseForHost(
|
||||
registration.ListingId,
|
||||
ContractLimits.ContractVersion,
|
||||
registration.LeaseToken,
|
||||
ContractLimits.BrowserPageMaxItems,
|
||||
null).Value!.Items.Single(item => item.AttemptId == created.AttemptId);
|
||||
int boundPort = Assert.IsType<IPEndPoint>(service.LocalEndpoint).Port;
|
||||
await service.StopAsync(timeout.Token);
|
||||
serviceStarted = false;
|
||||
service.Dispose();
|
||||
service = null;
|
||||
service = CreateMediator(processor, boundPort);
|
||||
await service.StartAsync(timeout.Token);
|
||||
serviceStarted = true;
|
||||
Assert.Equal(boundPort, Assert.IsType<IPEndPoint>(service.LocalEndpoint).Port);
|
||||
}
|
||||
|
||||
string hostTicket = Assert.Single(hostTickets.Distinct(StringComparer.Ordinal));
|
||||
string clientTicket = Assert.Single(clientTickets.Distinct(StringComparer.Ordinal));
|
||||
Assert.Equal(hostTicket, clientTicket);
|
||||
Assert.True(NatIntroductionTokenCodec.TryDecode(
|
||||
hostTicket,
|
||||
out NatIntroductionToken? introduction));
|
||||
Assert.NotNull(introduction);
|
||||
Assert.Equal(created.AttemptId, introduction.AttemptId);
|
||||
Assert.Equal(43, introduction.ConnectionTicket.Length);
|
||||
await AssertNativeIntroductionAsync(
|
||||
service,
|
||||
host,
|
||||
client,
|
||||
hostTickets,
|
||||
clientTickets,
|
||||
created,
|
||||
hostAttempt,
|
||||
expectedCount: restartMediator ? 2 : 1,
|
||||
cancellationToken: timeout.Token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
host.Stop();
|
||||
client.Stop();
|
||||
await service.StopAsync(CancellationToken.None);
|
||||
if (service is not null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (serviceStarted)
|
||||
{
|
||||
using CancellationTokenSource cleanup = new(TimeSpan.FromSeconds(5));
|
||||
await service.StopAsync(cleanup.Token);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
service.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task AssertNativeIntroductionAsync(
|
||||
UdpMediatorService service,
|
||||
NetManager host,
|
||||
NetManager client,
|
||||
List<string> hostTickets,
|
||||
List<string> clientTickets,
|
||||
CreateJoinAttemptResponse created,
|
||||
HostJoinAttempt hostAttempt,
|
||||
int expectedCount,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
IPEndPoint mediator = Assert.IsType<IPEndPoint>(service.LocalEndpoint);
|
||||
host.NatPunchModule.SendNatIntroduceRequest(
|
||||
mediator,
|
||||
NatPunchRequestTokenCodec.Encode(
|
||||
NatPunchPeerRole.Host,
|
||||
created.MediationHandle,
|
||||
hostAttempt.HostPunchCapability));
|
||||
client.NatPunchModule.SendNatIntroduceRequest(
|
||||
mediator,
|
||||
NatPunchRequestTokenCodec.Encode(
|
||||
NatPunchPeerRole.Client,
|
||||
created.MediationHandle,
|
||||
created.ClientPunchCapability));
|
||||
|
||||
while ((hostTickets.Distinct(StringComparer.Ordinal).Count() < expectedCount
|
||||
|| clientTickets.Distinct(StringComparer.Ordinal).Count() < expectedCount)
|
||||
&& !cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
host.PollEvents();
|
||||
host.NatPunchModule.PollEvents();
|
||||
client.PollEvents();
|
||||
client.NatPunchModule.PollEvents();
|
||||
await Task.Delay(5, cancellationToken);
|
||||
}
|
||||
|
||||
List<string> distinctHostTickets = hostTickets.Distinct(StringComparer.Ordinal).ToList();
|
||||
List<string> distinctClientTickets = clientTickets.Distinct(StringComparer.Ordinal).ToList();
|
||||
Assert.Equal(expectedCount, distinctHostTickets.Count);
|
||||
Assert.Equal(expectedCount, distinctClientTickets.Count);
|
||||
string hostTicket = distinctHostTickets[^1];
|
||||
string clientTicket = distinctClientTickets[^1];
|
||||
Assert.Equal(hostTicket, clientTicket);
|
||||
Assert.True(NatIntroductionTokenCodec.TryDecode(
|
||||
hostTicket,
|
||||
out NatIntroductionToken? introduction));
|
||||
Assert.NotNull(introduction);
|
||||
Assert.Equal(created.AttemptId, introduction.AttemptId);
|
||||
Assert.Equal(43, introduction.ConnectionTicket.Length);
|
||||
}
|
||||
|
||||
private static UdpMediatorService CreateMediator(NatMediationProcessor processor, int port) => new(
|
||||
Options.Create(new UdpMediatorOptions
|
||||
{
|
||||
ListenAddress = IPAddress.Loopback.ToString(),
|
||||
Port = port,
|
||||
MaxDatagramsPerPoll = 8,
|
||||
PollIntervalMilliseconds = 1,
|
||||
}),
|
||||
NullLogger<UdpMediatorService>.Instance,
|
||||
processor);
|
||||
|
||||
[Fact]
|
||||
public async Task FrozenV1EnvelopeIsConsumedOnTheLiteNetSocketWithinAmplificationBudget()
|
||||
{
|
||||
|
||||
+1035
-50
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user