public async Task CompletingOutputCancelsInput() { var inputCompletedTcs = new TaskCompletionSource <object>(); TestServerConnectionDispatcher connectionDispatcher = async(input, output, _) => { output.Complete(); bool exceptionThrown = true; try { await input.ReadAsync(); } catch (ConnectionAbortedException) { exceptionThrown = true; } Assert.True(exceptionThrown); inputCompletedTcs.SetResult(null); }; using (var testServer = CreateTestServer(connectionDispatcher)) { await testServer.BindAsync(); using (var client = testServer.ConnectTo()) { await inputCompletedTcs.Task; } await testServer.StopAsync(); } }
public async Task Write_Timeout() { const int bufferSize = 2048; var waitingForTimeout = new TaskCompletionSource <object>(); TestServerConnectionDispatcher connectionDispatcher = async(input, output, connection) => { Timer writeTimeout = new Timer( _ => connection.Abort(), null, Timeout.Infinite, Timeout.Infinite ); Exception exception = null; try { do { var memory = output.GetMemory(bufferSize); output.Advance(bufferSize); // If it takes 1 second to write, assume the socket // is no longer writable writeTimeout.Change(1000, Timeout.Infinite); var flushResult = await output.FlushAsync(); if (flushResult.IsCanceled || flushResult.IsCompleted) { break; } // cancel the timeout writeTimeout.Change(Timeout.Infinite, Timeout.Infinite); } while (true); } catch (Exception e) { exception = e; } Assert.NotNull(exception); Assert.IsType <ConnectionAbortedException>(exception); waitingForTimeout.SetResult(null); writeTimeout.Dispose(); output.Complete(); input.Complete(); }; using (var testServer = CreateTestServer(connectionDispatcher)) { await testServer.BindAsync(); using (var client = testServer.ConnectTo()) { // wait for the server to timeout our connection // because we aren't reading await waitingForTimeout.Task; } await testServer.StopAsync(); } }
public TestServer(TestServerOptions options = null) { options = options ?? new TestServerOptions(); _connectionDispatcher = options.ConnectionDispatcher; var transportOptions = new LinuxTransportOptions() { ThreadCount = options.ThreadCount, DeferAccept = options.DeferAccept, AioReceive = options.AioReceive, AioSend = options.AioSend, ApplicationSchedulingMode = options.ApplicationSchedulingMode, }; var loggerFactory = new LoggerFactory(); EndPoint endPoint = null; if (options.UnixSocketPath != null) { _unixSocketPath = options.UnixSocketPath; endPoint = new UnixDomainSocketEndPoint(_unixSocketPath); } else { _serverAddress = options.IPEndPoint ?? new IPEndPoint(IPAddress.Loopback, 0); endPoint = _serverAddress; } _transport = new Transport(endPoint, transportOptions, loggerFactory); }
public async Task UnixSocketListenType() { TestServerConnectionDispatcher connectionDispatcher = async(input, output, _) => { int threadId = Thread.CurrentThread.ManagedThreadId; var data = Encoding.UTF8.GetBytes(threadId.ToString()); output.Write(data); await output.FlushAsync(); output.Complete(); input.Complete(); }; using (var testServer = CreateTestServer(options => { options.ConnectionDispatcher = connectionDispatcher; options.ThreadCount = 2; options.ApplicationSchedulingMode = PipeScheduler.Inline; options.UnixSocketPath = $"{Path.GetTempPath()}/{Path.GetRandomFileName()}"; })) { await testServer.BindAsync(); // This test is racy, it's ok to ignore occasional failure. // PipeScheduler.Inline isn't inline when there is no pending IConnectionListener.AcceptAsync. // Wait a little to increase probability of AcceptAsync. await Task.Delay(50); int[] threadIds = new int[4]; for (int i = 0; i < 4; i++) { using (var client = testServer.ConnectTo()) { byte[] receiveBuffer = new byte[10]; int received = client.Receive(new ArraySegment <byte>(receiveBuffer)); int threadId; Assert.NotEqual(0, received); Assert.True(int.TryParse(Encoding.UTF8.GetString(receiveBuffer, 0, received), out threadId)); threadIds[i] = threadId; // check if the server closed the client. // this would fail if not all fds for this client are closed received = client.Receive(new ArraySegment <byte>(receiveBuffer)); Assert.Equal(0, received); } // See earlier comment, wait a little to increase probability of AcceptAsync. await Task.Delay(50); } // check we are doing round robin over 2 handling threads Assert.NotEqual(threadIds[0], threadIds[1]); Assert.Equal(threadIds[0], threadIds[2]); Assert.Equal(threadIds[1], threadIds[3]); await testServer.StopAsync(); } }
public async Task Writable() { const int bufferSize = 2048; int bytesWritten = 0; var waitingForWritable = new TaskCompletionSource <object>(); TestServerConnectionDispatcher connectionDispatcher = async(input, output, _) => { Timer writeTimeout = new Timer( // timeout -> we are waiting for the socket to become writable o => waitingForWritable.SetResult(null), null, Timeout.Infinite, Timeout.Infinite ); do { var memory = output.GetMemory(bufferSize); output.Advance(bufferSize); bytesWritten += bufferSize; // If it takes 1 second to write, assume the socket // is no longer writable writeTimeout.Change(1000, Timeout.Infinite); await output.FlushAsync(); // cancel the timeout writeTimeout.Change(Timeout.Infinite, Timeout.Infinite); } while (!waitingForWritable.Task.IsCompleted); writeTimeout.Dispose(); output.Complete(); input.Complete(); }; using (var testServer = CreateTestServer(connectionDispatcher)) { await testServer.BindAsync(); using (var client = testServer.ConnectTo()) { // wait for the server to have sent so much data // so it waiting for us to read some await waitingForWritable.Task; // read all the data int receivedBytes = 0; byte[] receiveBuffer = new byte[bufferSize]; while (receivedBytes < bytesWritten) { var received = client.Receive(new ArraySegment <byte>(receiveBuffer)); receivedBytes += received; } } await testServer.StopAsync(); } }
public async Task Receive() { // client send 1M bytes which are an int counter // server receives and checkes the counting const int receiveLength = 1000000; TestServerConnectionDispatcher connectionDispatcher = async(input, output, _) => { int bytesReceived = 0; int remainder = 0; // remaining bytes between ReadableBuffers while (true) { var readResult = await input.ReadAsync(); var buffer = readResult.Buffer; if (buffer.IsEmpty && readResult.IsCompleted) { input.AdvanceTo(buffer.End); break; } AssertCounter(ref buffer, ref bytesReceived, ref remainder); input.AdvanceTo(buffer.End); } Assert.Equal(receiveLength, bytesReceived); output.Complete(); input.Complete(); }; using (var testServer = CreateTestServer(connectionDispatcher)) { await testServer.BindAsync(); using (var client = testServer.ConnectTo()) { var buffer = new byte[1000000]; FillBuffer(new ArraySegment <byte>(buffer), 0); int offset = 0; do { offset += client.Send(new ArraySegment <byte>(buffer, offset, buffer.Length - offset)); } while (offset != buffer.Length); client.Shutdown(SHUT_WR); // wait for the server to stop var receiveBuffer = new byte[1]; client.Receive(new ArraySegment <byte>(receiveBuffer)); } await testServer.StopAsync(); } }
public async Task UnixSocketListenType() { TestServerConnectionDispatcher connectionDispatcher = async(input, output, _) => { int threadId = Thread.CurrentThread.ManagedThreadId; var data = Encoding.UTF8.GetBytes(threadId.ToString()); output.Write(data); await output.FlushAsync(); output.Complete(); input.Complete(); }; using (var testServer = CreateTestServer(options => { options.ConnectionDispatcher = connectionDispatcher; options.ThreadCount = 2; options.UnixSocketPath = $"{Path.GetTempPath()}/{Path.GetRandomFileName()}"; })) { await testServer.BindAsync(); int[] threadIds = new int[4]; for (int i = 0; i < 4; i++) { using (var client = testServer.ConnectTo()) { byte[] receiveBuffer = new byte[10]; int received = client.Receive(new ArraySegment <byte>(receiveBuffer)); int threadId; Assert.NotEqual(0, received); Assert.True(int.TryParse(Encoding.UTF8.GetString(receiveBuffer, 0, received), out threadId)); threadIds[i] = threadId; // check if the server closed the client. // this would fail if not all fds for this client are closed received = client.Receive(new ArraySegment <byte>(receiveBuffer)); Assert.Equal(0, received); } } // check we are doing round robin over 2 handling threads Assert.NotEqual(threadIds[0], threadIds[1]); Assert.Equal(threadIds[0], threadIds[2]); Assert.Equal(threadIds[1], threadIds[3]); await testServer.StopAsync(); } }
public async Task StopDisconnectsClient(bool waitForAccept) { var clientAcceptedTcs = new TaskCompletionSource <object>(); TestServerConnectionDispatcher connectionDispatcher = (input, output, context) => { clientAcceptedTcs.SetResult(output); return(Task.Delay(int.MaxValue, context.ConnectionClosed)); }; using (var testServer = CreateTestServer(connectionDispatcher)) { await testServer.BindAsync(); using (var client = testServer.ConnectTo()) { // Make sure the client is accepted. if (waitForAccept) { await clientAcceptedTcs.Task; } // Server shutdown: await testServer.UnbindAsync(); await testServer.StopAsync(); byte[] receiveBuffer = new byte[10]; var received = client.Receive(new ArraySegment <byte>(receiveBuffer)); // Socket was accepted by the server, which will do a normal TCP close. Assert.Equal(0, received); // send returns EPIPE var exception = Assert.Throws <IOException>(() => { for (int i = 0; i < 10; i++) { byte[] sendBuffer = new byte[] { 1, 2, 3 }; client.Send(new ArraySegment <byte>(sendBuffer)); } }); Assert.Equal(EPIPE, exception.HResult); } await testServer.StopAsync(); } }
public async Task Send() { // server send 1M bytes which are an int counter // client receives and checkes the counting const int sendLength = 1_000_000; TestServerConnectionDispatcher connectionDispatcher = async(input, output, _) => { FillBuffer(output, sendLength / 4); await output.FlushAsync(); output.Complete(); input.Complete(); }; using (var testServer = CreateTestServer(connectionDispatcher)) { await testServer.BindAsync(); using (var client = testServer.ConnectTo()) { int totalReceived = 0; var receiveBuffer = new byte[4000]; bool eof = false; do { int offset = 0; int received = 0; do { var receive = client.Receive(new ArraySegment <byte>(receiveBuffer, offset, receiveBuffer.Length - offset)); received += receive; offset += receive; eof = receive == 0; } while (!eof && offset != receiveBuffer.Length); AssertCounter(new ArraySegment <byte>(receiveBuffer, 0, received), totalReceived / 4); totalReceived += received; } while (!eof); Assert.True(totalReceived == sendLength); } await testServer.StopAsync(); } }
public async Task StopDisconnectsClient() { var outputTcs = new TaskCompletionSource <PipeWriter>(); TestServerConnectionDispatcher connectionDispatcher = async(input, output, _) => { outputTcs.SetResult(output); }; using (var testServer = CreateTestServer(connectionDispatcher)) { await testServer.BindAsync(); using (var client = testServer.ConnectTo()) { // Server shutdown: await testServer.UnbindAsync(); // Complete existing connections PipeWriter clientOutput = await outputTcs.Task; clientOutput.Complete(new ConnectionAbortedException()); await testServer.StopAsync(); // receive returns EOF byte[] receiveBuffer = new byte[10]; var received = client.Receive(new ArraySegment <byte>(receiveBuffer)); Assert.Equal(0, received); // send returns EPIPE var exception = Assert.Throws <IOException>(() => { for (int i = 0; i < 10; i++) { byte[] sendBuffer = new byte[] { 1, 2, 3 }; client.Send(new ArraySegment <byte>(sendBuffer)); } }); Assert.Equal(EPIPE, exception.HResult); } await testServer.StopAsync(); } }
public async Task CompletingOutputCancelsInput() { var inputCompletedTcs = new TaskCompletionSource <object>(); TestServerConnectionDispatcher connectionDispatcher = async(input, output, _) => { output.Complete(); await input.ReadAsync(); inputCompletedTcs.SetResult(null); }; using (var testServer = CreateTestServer(connectionDispatcher)) { await testServer.BindAsync(); using (var client = testServer.ConnectTo()) { await inputCompletedTcs.Task; } await testServer.StopAsync(); } }
public async Task BatchedSendReceive() { // We block the TransportThread to ensure 2 clients are sending multiple buffers with random data. // These buffers are echoed back. // The clients verify they each receive the random data they sent. const int DataLength = 10_000; int connectionCount = 0; SemaphoreSlim clientsAcceptedSemaphore = new SemaphoreSlim(0, 1); SemaphoreSlim dataSentSemaphore = new SemaphoreSlim(0, 1); TestServerConnectionDispatcher connectionDispatcher = async(input, output, _) => { connectionCount++; if (connectionCount == 3) { // Ensure we accepted the clients. clientsAcceptedSemaphore.Release(); // Now wait for clients to send data. dataSentSemaphore.Wait(); } // Echo while (true) { var result = await input.ReadAsync(); var request = result.Buffer; if (request.IsEmpty && result.IsCompleted) { input.AdvanceTo(request.End); break; } // Clients send more data than what fits in a single segment. Assert.True(!request.IsSingleSegment); foreach (var memory in request) { output.Write(memory.Span); } await output.FlushAsync(); input.AdvanceTo(request.End); } output.Complete(); input.Complete(); }; using (var testServer = CreateTestServer(connectionDispatcher)) { await testServer.BindAsync(); using (var client1 = testServer.ConnectTo()) { using (var client2 = testServer.ConnectTo()) { using (var client3 = testServer.ConnectTo()) { } // Wait for all clients to be accepted. // The TransportThread will now be blocked. clientsAcceptedSemaphore.Wait(); // Send data var client1DataSent = new byte[DataLength]; FillRandom(client1DataSent); var client2DataSent = new byte[DataLength]; FillRandom(client2DataSent); int bytesSent = client1.Send(new ArraySegment <byte>(client1DataSent)); Assert.Equal(DataLength, bytesSent); bytesSent = client2.Send(new ArraySegment <byte>(client2DataSent)); Assert.Equal(DataLength, bytesSent); // Unblock the TransportThread dataSentSemaphore.Release(); // Receive echoed data. var client1DataReceived = new byte[DataLength]; int bytesReceived = client1.Receive(new ArraySegment <byte>(client1DataReceived)); Assert.Equal(DataLength, bytesReceived); Assert.Equal(client1DataSent, client1DataReceived); var client2DataReceived = new byte[DataLength]; bytesReceived = client2.Receive(new ArraySegment <byte>(client2DataReceived)); Assert.Equal(DataLength, bytesReceived); Assert.Equal(client2DataSent, client2DataReceived); } } await testServer.StopAsync(); } }
private TestServer CreateTestServer(TestServerConnectionDispatcher connectionDispatcher) => CreateTestServer(options => options.ConnectionDispatcher = connectionDispatcher);
public TestServer(TestServerConnectionDispatcher connectionDispatcher) : this(new TestServerOptions() { ConnectionDispatcher = connectionDispatcher }) { }