diff --git a/src/Microsoft.AspNetCore.Razor.Tools/DefaultRequestDispatcher.cs b/src/Microsoft.AspNetCore.Razor.Tools/DefaultRequestDispatcher.cs index 26747a06b6..59d2bbc098 100644 --- a/src/Microsoft.AspNetCore.Razor.Tools/DefaultRequestDispatcher.cs +++ b/src/Microsoft.AspNetCore.Razor.Tools/DefaultRequestDispatcher.cs @@ -383,6 +383,8 @@ namespace Microsoft.AspNetCore.Razor.Tools ServerLogger.Log("End writing response."); reason = ConnectionResult.Reason.CompilationCompleted; + + _eventBus.CompilationCompleted(); } catch { diff --git a/src/Microsoft.AspNetCore.Razor.Tools/EventBus.cs b/src/Microsoft.AspNetCore.Razor.Tools/EventBus.cs index 958a637deb..dacd5c07e7 100644 --- a/src/Microsoft.AspNetCore.Razor.Tools/EventBus.cs +++ b/src/Microsoft.AspNetCore.Razor.Tools/EventBus.cs @@ -37,6 +37,13 @@ namespace Microsoft.AspNetCore.Razor.Tools public virtual void ConnectionCompleted(int count) { } + + /// + /// Called when a compilation is completed successfully and the response is written to the stream. + /// + public virtual void CompilationCompleted() + { + } /// /// Called when a bad client connection was detected and the server will be shutting down as a diff --git a/test/Microsoft.AspNetCore.Razor.Tools.Test/DefaultRequestDispatcherTest.cs b/test/Microsoft.AspNetCore.Razor.Tools.Test/DefaultRequestDispatcherTest.cs index 4e4f702fed..495649bd3e 100644 --- a/test/Microsoft.AspNetCore.Razor.Tools.Test/DefaultRequestDispatcherTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Tools.Test/DefaultRequestDispatcherTest.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Moq; @@ -335,7 +336,7 @@ namespace Microsoft.AspNetCore.Razor.Tools /// /// Ensure server respects keep alive and shuts down after processing simultaneous connections. /// - [Fact(Skip = "https://github.com/aspnet/Razor/issues/2018")] + [Fact] public async Task Dispatcher_ProcessSimultaneousConnections_HitsKeepAliveTimeout() { // Arrange @@ -352,6 +353,7 @@ namespace Microsoft.AspNetCore.Razor.Tools var source = new TaskCompletionSource(); var connectionTask = CreateConnectionWithEmptyServerRequest(c => { + // Keep the connection active until we decide to end it. c.WaitForDisconnectAsyncFunc = _ => source.Task; }); list.Add(source); @@ -370,24 +372,42 @@ namespace Microsoft.AspNetCore.Razor.Tools }; }); - var keepAlive = TimeSpan.FromSeconds(1); var eventBus = new TestableEventBus(); + var completedCompilations = 0; + var allCompilationsComplete = new TaskCompletionSource(); + 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."); diff --git a/test/Microsoft.AspNetCore.Razor.Tools.Test/Infrastructure/TestableEventBus.cs b/test/Microsoft.AspNetCore.Razor.Tools.Test/Infrastructure/TestableEventBus.cs index 4bc2465476..6430ce05df 100644 --- a/test/Microsoft.AspNetCore.Razor.Tools.Test/Infrastructure/TestableEventBus.cs +++ b/test/Microsoft.AspNetCore.Razor.Tools.Test/Infrastructure/TestableEventBus.cs @@ -2,21 +2,27 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Generic; -using System.Text; namespace Microsoft.AspNetCore.Razor.Tools { internal class TestableEventBus : EventBus { - public int ListeningCount; - public int ConnectionCount; - public int CompletedCount; - public DateTime? LastProcessedTime; - public TimeSpan? KeepAlive; - public bool HasDetectedBadConnection; - public bool HitKeepAliveTimeout; public event EventHandler Listening; + public event EventHandler CompilationComplete; + + public int ListeningCount { get; private set; } + + public int ConnectionCount { get; private set; } + + public int CompletedCount { get; private set; } + + public DateTime? LastProcessedTime { get; private set; } + + public TimeSpan? KeepAlive { get; private set; } + + public bool HasDetectedBadConnection { get; private set; } + + public bool HitKeepAliveTimeout { get; private set; } public override void ConnectionListening() { @@ -35,6 +41,11 @@ namespace Microsoft.AspNetCore.Razor.Tools LastProcessedTime = DateTime.Now; } + public override void CompilationCompleted() + { + CompilationComplete?.Invoke(this, EventArgs.Empty); + } + public override void UpdateKeepAlive(TimeSpan timeSpan) { KeepAlive = timeSpan; diff --git a/test/Microsoft.AspNetCore.Razor.Tools.Test/ServerLifecycleTest.cs b/test/Microsoft.AspNetCore.Razor.Tools.Test/ServerLifecycleTest.cs index 7cb6b64ae0..3f415fe509 100644 --- a/test/Microsoft.AspNetCore.Razor.Tools.Test/ServerLifecycleTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Tools.Test/ServerLifecycleTest.cs @@ -116,7 +116,8 @@ namespace Microsoft.AspNetCore.Razor.Tools /// A shutdown request should not abort an existing compilation. It should be allowed to run to /// completion. /// - [ConditionalFact(Skip = "Skipping temporarily on non-windows. https://github.com/aspnet/Razor/issues/1991")] + // Skipping temporarily on non-windows. https://github.com/aspnet/Razor/issues/1991 + [ConditionalFact] [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)] public async Task ServerRunning_ShutdownRequest_DoesNotAbortCompilation() { @@ -153,7 +154,8 @@ namespace Microsoft.AspNetCore.Razor.Tools /// /// Multiple clients should be able to send shutdown requests to the server. /// - [ConditionalFact(Skip = "Skipping temporarily on non-windows. https://github.com/aspnet/Razor/issues/1991")] + // Skipping temporarily on non-windows. https://github.com/aspnet/Razor/issues/1991 + [ConditionalFact] [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)] public async Task ServerRunning_MultipleShutdownRequests_HandlesSuccessfully() { @@ -191,7 +193,8 @@ namespace Microsoft.AspNetCore.Razor.Tools } } - [ConditionalFact(Skip = "Skipping temporarily on non-windows. https://github.com/aspnet/Razor/issues/1991")] + // Skipping temporarily on non-windows. https://github.com/aspnet/Razor/issues/1991 + [ConditionalFact] [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)] public async Task ServerRunning_CancelCompilation_CancelsSuccessfully() {