public async Task MessagesShouldPassThruRedundantChannelWhenNotAllChildConnectionsAreSlowOrDown() { var toxiproxyServerPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "TransactTcp.Tests", "toxiproxy-server-windows-amd64.exe"); foreach (var existentToxiserverProcess in Process.GetProcessesByName("toxiproxy-server-windows-amd64").ToList()) { existentToxiserverProcess.Kill(); } Directory.CreateDirectory(Path.GetDirectoryName(toxiproxyServerPath)); await File.WriteAllBytesAsync(toxiproxyServerPath, Utils.LoadResourceAsByteArray("toxiproxy-server-windows-amd64.exe")); using var toxyproxyServerProcess = Process.Start(toxiproxyServerPath); try { //Setting up Toxiproxy proxies var connection = new Connection(); var client = connection.Client(); var interface1Proxy = new Proxy() { Name = "interface1Proxy", Enabled = true, Listen = "127.0.0.1:12000", Upstream = "127.0.0.1:12001" }; await client.AddAsync(interface1Proxy); var interface2Proxy = new Proxy() { Name = "interface2Proxy", Enabled = true, Listen = "127.0.0.1:13000", Upstream = "127.0.0.1:13001" }; await client.AddAsync(interface2Proxy); using var serverConnection = TcpConnectionFactory.CreateRedundantServer(new[] { new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12001), new IPEndPoint(IPAddress.Parse("127.0.0.1"), 13001) }); using var clientConnection = TcpConnectionFactory.CreateRedundantClient(new[] { new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12000), new IPEndPoint(IPAddress.Parse("127.0.0.1"), 13000) }); using var serverConnectedEvent = new AutoResetEvent(false); using var clientConnectedEvent = new AutoResetEvent(false); using var errorsOnServerSideEvent = new AutoResetEvent(false); using var errorsOnClientSideEvent = new AutoResetEvent(false); int counterOfMessagesArrivedAtServer = 0; serverConnection.Start( receivedAction: (c, data) => { if (BitConverter.ToInt32(data) != counterOfMessagesArrivedAtServer) { errorsOnServerSideEvent.Set(); } counterOfMessagesArrivedAtServer++; }, connectionStateChangedAction: (c, fromState, toState) => { if (toState == ConnectionState.Connected) { serverConnectedEvent.Set(); } }); int counterOfMessagesArrivedAtClient = 0; clientConnection.Start( receivedAction: (c, data) => { if (BitConverter.ToInt32(data) != counterOfMessagesArrivedAtClient) { errorsOnClientSideEvent.Set(); } counterOfMessagesArrivedAtClient++; }, connectionStateChangedAction: (c, fromState, toState) => { if (toState == ConnectionState.Connected) { clientConnectedEvent.Set(); } }); WaitHandle.WaitAll(new[] { serverConnectedEvent, clientConnectedEvent }, 5000).ShouldBeTrue(); var cancellationTokenSource = new CancellationTokenSource(); #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed Task.Run(async() => { var counter = 0; while (!cancellationTokenSource.IsCancellationRequested) { await clientConnection.SendDataAsync(BitConverter.GetBytes(counter)); await serverConnection.SendDataAsync(BitConverter.GetBytes(counter)); await Task.Delay(500, cancellationTokenSource.Token); counter++; } }, cancellationTokenSource.Token); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed await Task.Delay(1000); interface1Proxy.Enabled = false; await client.UpdateAsync(interface1Proxy); WaitHandle.WaitAll(new[] { errorsOnServerSideEvent, errorsOnClientSideEvent }, 2000).ShouldBeFalse(); interface1Proxy.Enabled = true; await client.UpdateAsync(interface1Proxy); interface2Proxy.Enabled = false; await client.UpdateAsync(interface2Proxy); WaitHandle.WaitAll(new[] { errorsOnServerSideEvent, errorsOnClientSideEvent }, 2000).ShouldBeFalse(); interface2Proxy.Enabled = true; await client.UpdateAsync(interface2Proxy); var latencyProxy = new LatencyToxic() { Name = "latencyToxicInterface2", Stream = ToxicDirection.DownStream, Toxicity = 1.0, }; latencyProxy.Attributes.Jitter = 100; latencyProxy.Attributes.Latency = 300; await interface1Proxy.AddAsync(latencyProxy); WaitHandle.WaitAll(new[] { errorsOnServerSideEvent, errorsOnClientSideEvent }, 2000).ShouldBeFalse(); var slicerToxic = new SlicerToxic() { Name = "slicerToxicInterface1", Stream = ToxicDirection.UpStream, Toxicity = 1.0, }; slicerToxic.Attributes.AverageSize = 10; slicerToxic.Attributes.Delay = 5; slicerToxic.Attributes.SizeVariation = 1; await interface1Proxy.AddAsync(slicerToxic); WaitHandle.WaitAll(new[] { errorsOnServerSideEvent, errorsOnClientSideEvent }, 4000).ShouldBeFalse(); interface2Proxy.Enabled = false; await client.UpdateAsync(interface2Proxy); WaitHandle.WaitAll(new[] { errorsOnServerSideEvent, errorsOnClientSideEvent }, 2000).ShouldBeFalse(); cancellationTokenSource.Cancel(); } finally { toxyproxyServerProcess.Kill(); } }