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); }
internal static ServerData CreateServer( string pipeName = null, CompilerHost compilerHost = null, ConnectionHost connectionHost = null, Action <object, EventArgs> onListening = null) { pipeName = pipeName ?? Guid.NewGuid().ToString(); compilerHost = compilerHost ?? CompilerHost.Create(); connectionHost = connectionHost ?? ConnectionHost.Create(pipeName); var serverStatsSource = new TaskCompletionSource <ServerStats>(); var serverListenSource = new TaskCompletionSource <bool>(); var cts = new CancellationTokenSource(); var mutexName = MutexName.GetServerMutexName(pipeName); var thread = new Thread(_ => { var eventBus = new TestableEventBus(); eventBus.Listening += (sender, e) => { serverListenSource.TrySetResult(true); }; if (onListening != null) { eventBus.Listening += (sender, e) => onListening(sender, e); } try { RunServer( pipeName, connectionHost, compilerHost, cts.Token, eventBus, Timeout.InfiniteTimeSpan); } finally { var serverStats = new ServerStats(connections: eventBus.ConnectionCount, completedConnections: eventBus.CompletedCount); serverStatsSource.SetResult(serverStats); } }); thread.Start(); // The contract of this function is that it will return once the server has started. Spin here until // we can verify the server has started or simply failed to start. while (ServerConnection.WasServerMutexOpen(mutexName) != true && thread.IsAlive) { Thread.Yield(); } return(new ServerData(cts, pipeName, serverStatsSource.Task, serverListenSource.Task)); }
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 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."); }