public async Task AcceptConnection_WritingResultsFails_ClosesConnection() { // Arrange var memoryStream = new MemoryStream(); await EmptyServerRequest.WriteAsync(memoryStream, CancellationToken.None).ConfigureAwait(true); memoryStream.Position = 0; var stream = new Mock <Stream>(MockBehavior.Strict); stream .Setup(x => x.ReadAsync(It.IsAny <byte[]>(), It.IsAny <int>(), It.IsAny <int>(), It.IsAny <CancellationToken>())) .Returns((byte[] array, int start, int length, CancellationToken ct) => memoryStream.ReadAsync(array, start, length, ct)); var connection = CreateConnection(stream.Object); var compilerHost = CreateCompilerHost(c => { c.ExecuteFunc = (req, ct) => { return(EmptyServerResponse); }; }); var connectionHost = CreateConnectionHost(); var dispatcher = new DefaultRequestDispatcher(connectionHost, compilerHost, CancellationToken.None); // Act // We expect WriteAsync to fail because the mock stream doesn't have a corresponding setup. var connectionResult = await dispatcher.AcceptConnection( Task.FromResult <Connection>(connection), accept : true, cancellationToken : CancellationToken.None); // Assert Assert.Equal(ConnectionResult.Reason.ClientDisconnect, connectionResult.CloseReason); Assert.Null(connectionResult.KeepAlive); }
public async Task Dispatcher_ClientConnectionThrowsWhenExecutingRequest_ClosesConnection() { // Arrange var called = false; var connectionTask = CreateConnectionWithEmptyServerRequest(c => { c.WaitForDisconnectAsyncFunc = (ct) => { called = true; throw new Exception(); }; }); var compilerHost = CreateCompilerHost(); var connectionHost = CreateConnectionHost(); var dispatcher = new DefaultRequestDispatcher(connectionHost, compilerHost, CancellationToken.None); // Act var connectionResult = await dispatcher.AcceptConnection( connectionTask, accept : true, cancellationToken : CancellationToken.None); // Assert Assert.True(called); Assert.Equal(ConnectionResult.Reason.ClientException, connectionResult.CloseReason); Assert.Null(connectionResult.KeepAlive); }
public void Dispatcher_ClientConnectionThrows_BeginsShutdown() { // Arrange var listenCancellationToken = default(CancellationToken); var firstConnectionTask = CreateConnectionWithEmptyServerRequest(c => { c.WaitForDisconnectAsyncFunc = (ct) => { listenCancellationToken = ct; return(Task.Delay(Timeout.Infinite, ct).ContinueWith <Connection>(_ => null)); }; }); var secondConnectionTask = CreateConnectionWithEmptyServerRequest(c => { c.WaitForDisconnectAsyncFunc = (ct) => throw new Exception(); }); var compilerHost = CreateCompilerHost(); var connectionHost = CreateConnectionHost( firstConnectionTask, secondConnectionTask, new TaskCompletionSource <Connection>().Task); var keepAlive = TimeSpan.FromSeconds(10); var eventBus = new TestableEventBus(); var dispatcher = new DefaultRequestDispatcher(connectionHost, compilerHost, CancellationToken.None, eventBus, keepAlive); // Act dispatcher.Run(); // Assert Assert.True(eventBus.HasDetectedBadConnection); Assert.True(listenCancellationToken.IsCancellationRequested); }
public void Dispatcher_ProcessMultipleConnections_HitsKeepAliveTimeout() { // Arrange var count = 5; var list = new List <Task <Connection> >(); for (var i = 0; i < count; i++) { var connectionTask = CreateConnectionWithEmptyServerRequest(); list.Add(connectionTask); } list.Add(new TaskCompletionSource <Connection>().Task); var connectionHost = CreateConnectionHost(list.ToArray()); var compilerHost = CreateCompilerHost(c => { c.ExecuteFunc = (req, ct) => { return(EmptyServerResponse); }; }); var keepAlive = TimeSpan.FromSeconds(1); var eventBus = new TestableEventBus(); var dispatcher = new DefaultRequestDispatcher(connectionHost, compilerHost, CancellationToken.None, eventBus, keepAlive); // Act dispatcher.Run(); // Assert Assert.Equal(count, eventBus.CompletedCount); Assert.True(eventBus.LastProcessedTime.HasValue); Assert.True(eventBus.HitKeepAliveTimeout); }
public async Task Dispatcher_ProcessSimultaneousConnections_HitsKeepAliveTimeout() { // Arrange var totalCount = 2; var readySource = new TaskCompletionSource <bool>(); var list = new List <TaskCompletionSource <bool> >(); var connectionHost = new Mock <ConnectionHost>(); connectionHost .Setup(x => x.WaitForConnectionAsync(It.IsAny <CancellationToken>())) .Returns((CancellationToken ct) => { if (list.Count < totalCount) { var source = new TaskCompletionSource <bool>(); var connectionTask = CreateConnectionWithEmptyServerRequest(c => { c.WaitForDisconnectAsyncFunc = _ => source.Task; }); list.Add(source); return(connectionTask); } readySource.SetResult(true); return(new TaskCompletionSource <Connection>().Task); }); var compilerHost = CreateCompilerHost(c => { c.ExecuteFunc = (req, ct) => { return(EmptyServerResponse); }; }); var keepAlive = TimeSpan.FromSeconds(1); var eventBus = new TestableEventBus(); var dispatcherTask = Task.Run(() => { var dispatcher = new DefaultRequestDispatcher(connectionHost.Object, compilerHost, CancellationToken.None, eventBus, keepAlive); dispatcher.Run(); }); await readySource.Task; foreach (var source in list) { source.SetResult(true); } // Act await dispatcherTask; // Assert Assert.Equal(totalCount, eventBus.CompletedCount); Assert.True(eventBus.LastProcessedTime.HasValue, "LastProcessedTime should have had a value."); Assert.True(eventBus.HitKeepAliveTimeout, "HitKeepAliveTimeout should have been hit."); }
public async Task AcceptConnection_ClientDisconnectsWhenExecutingRequest_ClosesConnection() { // Arrange var connectionHost = Mock.Of <ConnectionHost>(); // Fake a long running task here that we can validate later on. var buildTaskSource = new TaskCompletionSource <bool>(); var buildTaskCancellationToken = default(CancellationToken); var compilerHost = CreateCompilerHost(c => { c.ExecuteFunc = (req, ct) => { Task.WaitAll(buildTaskSource.Task); return(EmptyServerResponse); }; }); var dispatcher = new DefaultRequestDispatcher(connectionHost, compilerHost, CancellationToken.None); var readyTaskSource = new TaskCompletionSource <bool>(); var disconnectTaskSource = new TaskCompletionSource <bool>(); var connectionTask = CreateConnectionWithEmptyServerRequest(c => { c.WaitForDisconnectAsyncFunc = (ct) => { buildTaskCancellationToken = ct; readyTaskSource.SetResult(true); return(disconnectTaskSource.Task); }; }); var handleTask = dispatcher.AcceptConnection( connectionTask, accept: true, cancellationToken: CancellationToken.None); // Wait until WaitForDisconnectAsync task is actually created and running. await readyTaskSource.Task.ConfigureAwait(false); // Act // Now simulate a disconnect by the client. disconnectTaskSource.SetResult(true); var connectionResult = await handleTask; buildTaskSource.SetResult(true); // Assert Assert.Equal(ConnectionResult.Reason.ClientDisconnect, connectionResult.CloseReason); Assert.Null(connectionResult.KeepAlive); Assert.True(buildTaskCancellationToken.IsCancellationRequested); }
public async Task AcceptConnection_ReadingRequestFails_ClosesConnection() { // Arrange var stream = Mock.Of <Stream>(); var compilerHost = CreateCompilerHost(); var connectionHost = CreateConnectionHost(); var dispatcher = new DefaultRequestDispatcher(connectionHost, compilerHost, CancellationToken.None); var connection = CreateConnection(stream); // Act var result = await dispatcher.AcceptConnection( Task.FromResult <Connection>(connection), accept : true, cancellationToken : CancellationToken.None); // Assert Assert.Equal(ConnectionResult.Reason.CompilationNotStarted, result.CloseReason); }
public async Task AcceptConnection_ClientConnectionThrowsWhenConnecting_ClosesConnection() { // Arrange var compilerHost = CreateCompilerHost(); var connectionHost = CreateConnectionHost(); var dispatcher = new DefaultRequestDispatcher(connectionHost, compilerHost, CancellationToken.None); var connectionTask = Task.FromException <Connection>(new Exception()); // Act var connectionResult = await dispatcher.AcceptConnection( connectionTask, accept : true, cancellationToken : CancellationToken.None); // Assert Assert.Equal(ConnectionResult.Reason.CompilationNotStarted, connectionResult.CloseReason); Assert.Null(connectionResult.KeepAlive); }
public async Task AcceptConnection_ConnectionHostThrowsWhenConnecting_ClosesConnection() { // Arrange var connectionHost = new Mock <ConnectionHost>(MockBehavior.Strict); connectionHost.Setup(c => c.WaitForConnectionAsync(It.IsAny <CancellationToken>())).Throws(new Exception()); var compilerHost = CreateCompilerHost(); var dispatcher = new DefaultRequestDispatcher(connectionHost.Object, compilerHost, CancellationToken.None); var connection = CreateConnection(Mock.Of <Stream>()); // Act var connectionResult = await dispatcher.AcceptConnection( Task.FromResult <Connection>(connection), accept : true, cancellationToken : CancellationToken.None); // Assert Assert.Equal(ConnectionResult.Reason.CompilationNotStarted, connectionResult.CloseReason); Assert.Null(connectionResult.KeepAlive); }
public void Dispatcher_NoConnections_HitsKeepAliveTimeout() { // Arrange var keepAlive = TimeSpan.FromSeconds(3); var compilerHost = CreateCompilerHost(); var connectionHost = new Mock <ConnectionHost>(); connectionHost .Setup(x => x.WaitForConnectionAsync(It.IsAny <CancellationToken>())) .Returns(new TaskCompletionSource <Connection>().Task); var eventBus = new TestableEventBus(); var dispatcher = new DefaultRequestDispatcher(connectionHost.Object, compilerHost, CancellationToken.None, eventBus, keepAlive); var startTime = DateTime.Now; // Act dispatcher.Run(); // Assert Assert.True(eventBus.HitKeepAliveTimeout); }
public async Task AcceptConnection_ShutdownRequest_ReturnsShutdownResponse() { // Arrange var stream = new TestableStream(); await ServerRequest.CreateShutdown().WriteAsync(stream.ReadStream, CancellationToken.None); stream.ReadStream.Position = 0; var connection = CreateConnection(stream); var connectionHost = CreateConnectionHost(); var compilerHost = CreateCompilerHost(); var dispatcher = new DefaultRequestDispatcher(connectionHost, compilerHost, CancellationToken.None); // Act var connectionResult = await dispatcher.AcceptConnection( Task.FromResult <Connection>(connection), accept : true, cancellationToken : CancellationToken.None); // Assert Assert.Equal(ConnectionResult.Reason.ClientShutdownRequest, connectionResult.CloseReason); stream.WriteStream.Position = 0; var response = await ServerResponse.ReadAsync(stream.WriteStream).ConfigureAwait(false); Assert.Equal(ServerResponse.ResponseType.Shutdown, response.Type); }
public async Task AcceptConnection_AcceptFalse_RejectsBuildRequest() { // Arrange var stream = new TestableStream(); await EmptyServerRequest.WriteAsync(stream.ReadStream, CancellationToken.None); stream.ReadStream.Position = 0; var connection = CreateConnection(stream); var connectionHost = CreateConnectionHost(); var compilerHost = CreateCompilerHost(); var dispatcher = new DefaultRequestDispatcher(connectionHost, compilerHost, CancellationToken.None); // Act var connectionResult = await dispatcher.AcceptConnection( Task.FromResult <Connection>(connection), accept : false, cancellationToken : CancellationToken.None); // Assert Assert.Equal(ConnectionResult.Reason.CompilationNotStarted, connectionResult.CloseReason); stream.WriteStream.Position = 0; var response = await ServerResponse.ReadAsync(stream.WriteStream).ConfigureAwait(false); Assert.Equal(ServerResponse.ResponseType.Rejected, response.Type); }
public async Task Dispatcher_ProcessSimultaneousConnections_HitsKeepAliveTimeout() { // Arrange var totalCount = 2; var readySource = new TaskCompletionSource <bool>(); var list = new List <TaskCompletionSource <bool> >(); var connectionHost = new Mock <ConnectionHost>(); connectionHost .Setup(x => x.WaitForConnectionAsync(It.IsAny <CancellationToken>())) .Returns((CancellationToken ct) => { if (list.Count < totalCount) { var source = new TaskCompletionSource <bool>(); var connectionTask = CreateConnectionWithEmptyServerRequest(c => { // Keep the connection active until we decide to end it. c.WaitForDisconnectAsyncFunc = _ => source.Task; }); list.Add(source); return(connectionTask); } readySource.SetResult(true); return(new TaskCompletionSource <Connection>().Task); }); var compilerHost = CreateCompilerHost(c => { c.ExecuteFunc = (req, ct) => { return(EmptyServerResponse); }; }); var eventBus = new TestableEventBus(); var completedCompilations = 0; var allCompilationsComplete = new TaskCompletionSource <bool>(); eventBus.CompilationComplete += (obj, args) => { if (++completedCompilations == totalCount) { // All compilations have completed. allCompilationsComplete.SetResult(true); } }; var keepAlive = TimeSpan.FromSeconds(1); var dispatcherTask = Task.Run(() => { var dispatcher = new DefaultRequestDispatcher(connectionHost.Object, compilerHost, CancellationToken.None, eventBus, keepAlive); dispatcher.Run(); }); // Wait for all connections to be created. await readySource.Task; // Wait for all compilations to complete. await allCompilationsComplete.Task; // Now allow all the connections to be disconnected. foreach (var source in list) { source.SetResult(true); } // Act // Now dispatcher should be in an idle state with no active connections. await dispatcherTask; // Assert Assert.False(eventBus.HasDetectedBadConnection); Assert.Equal(totalCount, eventBus.CompletedCount); Assert.True(eventBus.LastProcessedTime.HasValue, "LastProcessedTime should have had a value."); Assert.True(eventBus.HitKeepAliveTimeout, "HitKeepAliveTimeout should have been hit."); }