Fixed flaky shutdown tests

This commit is contained in:
Ajay Bhargav Baaskaran 2018-03-01 16:24:29 -08:00
parent 41c923926e
commit 7e18efbf1f
2 changed files with 49 additions and 23 deletions

View File

@ -26,7 +26,8 @@ namespace Microsoft.AspNetCore.Razor.Tools
internal static ServerData CreateServer( internal static ServerData CreateServer(
string pipeName = null, string pipeName = null,
CompilerHost compilerHost = null, CompilerHost compilerHost = null,
ConnectionHost connectionHost = null) ConnectionHost connectionHost = null,
Action<object, EventArgs> onListening = null)
{ {
pipeName = pipeName ?? Guid.NewGuid().ToString(); pipeName = pipeName ?? Guid.NewGuid().ToString();
compilerHost = compilerHost ?? CompilerHost.Create(); compilerHost = compilerHost ?? CompilerHost.Create();
@ -40,6 +41,10 @@ namespace Microsoft.AspNetCore.Razor.Tools
{ {
var eventBus = new TestableEventBus(); var eventBus = new TestableEventBus();
eventBus.Listening += (sender, e) => { serverListenSource.TrySetResult(true); }; eventBus.Listening += (sender, e) => { serverListenSource.TrySetResult(true); };
if (onListening != null)
{
eventBus.Listening += (sender, e) => onListening(sender, e);
}
try try
{ {
RunServer( RunServer(

View File

@ -116,17 +116,19 @@ namespace Microsoft.AspNetCore.Razor.Tools
/// A shutdown request should not abort an existing compilation. It should be allowed to run to /// A shutdown request should not abort an existing compilation. It should be allowed to run to
/// completion. /// completion.
/// </summary> /// </summary>
// Skipping temporarily on non-windows. https://github.com/aspnet/Razor/issues/1991 [Fact]
[ConditionalFact]
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
public async Task ServerRunning_ShutdownRequest_DoesNotAbortCompilation() public async Task ServerRunning_ShutdownRequest_DoesNotAbortCompilation()
{ {
// Arrange // Arrange
var completionSource = new TaskCompletionSource<bool>(); var startCompilationSource = new TaskCompletionSource<bool>();
var finishCompilationSource = new TaskCompletionSource<bool>();
var host = CreateCompilerHost(c => c.ExecuteFunc = (req, ct) => var host = CreateCompilerHost(c => c.ExecuteFunc = (req, ct) =>
{ {
// At this point, the connection has been accepted and the compilation has started.
startCompilationSource.SetResult(true);
// We want this to keep running even after the shutdown is seen. // We want this to keep running even after the shutdown is seen.
completionSource.Task.Wait(); finishCompilationSource.Task.Wait();
return EmptyServerResponse; return EmptyServerResponse;
}); });
@ -134,13 +136,16 @@ namespace Microsoft.AspNetCore.Razor.Tools
{ {
var compileTask = ServerUtilities.Send(serverData.PipeName, EmptyServerRequest); var compileTask = ServerUtilities.Send(serverData.PipeName, EmptyServerRequest);
// Wait for the request to go through and trigger compilation.
await startCompilationSource.Task;
// Act // Act
// The compilation is now in progress, send the shutdown. // The compilation is now in progress, send the shutdown.
await ServerUtilities.SendShutdown(serverData.PipeName); await ServerUtilities.SendShutdown(serverData.PipeName);
Assert.False(compileTask.IsCompleted); Assert.False(compileTask.IsCompleted);
// Now let the task complete. // Now let the task complete.
completionSource.SetResult(true); finishCompilationSource.SetResult(true);
// Assert // Assert
var response = await compileTask; var response = await compileTask;
@ -154,17 +159,19 @@ namespace Microsoft.AspNetCore.Razor.Tools
/// <summary> /// <summary>
/// Multiple clients should be able to send shutdown requests to the server. /// Multiple clients should be able to send shutdown requests to the server.
/// </summary> /// </summary>
// Skipping temporarily on non-windows. https://github.com/aspnet/Razor/issues/1991 [Fact]
[ConditionalFact]
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
public async Task ServerRunning_MultipleShutdownRequests_HandlesSuccessfully() public async Task ServerRunning_MultipleShutdownRequests_HandlesSuccessfully()
{ {
// Arrange // Arrange
var completionSource = new TaskCompletionSource<bool>(); var startCompilationSource = new TaskCompletionSource<bool>();
var finishCompilationSource = new TaskCompletionSource<bool>();
var host = CreateCompilerHost(c => c.ExecuteFunc = (req, ct) => var host = CreateCompilerHost(c => c.ExecuteFunc = (req, ct) =>
{ {
// At this point, the connection has been accepted and the compilation has started.
startCompilationSource.SetResult(true);
// We want this to keep running even after the shutdown is seen. // We want this to keep running even after the shutdown is seen.
completionSource.Task.Wait(); finishCompilationSource.Task.Wait();
return EmptyServerResponse; return EmptyServerResponse;
}); });
@ -172,6 +179,9 @@ namespace Microsoft.AspNetCore.Razor.Tools
{ {
var compileTask = ServerUtilities.Send(serverData.PipeName, EmptyServerRequest); var compileTask = ServerUtilities.Send(serverData.PipeName, EmptyServerRequest);
// Wait for the request to go through and trigger compilation.
await startCompilationSource.Task;
// Act // Act
for (var i = 0; i < 10; i++) for (var i = 0; i < 10; i++)
{ {
@ -182,7 +192,7 @@ namespace Microsoft.AspNetCore.Razor.Tools
} }
// Now let the task complete. // Now let the task complete.
completionSource.SetResult(true); finishCompilationSource.SetResult(true);
// Assert // Assert
var response = await compileTask; var response = await compileTask;
@ -193,9 +203,7 @@ namespace Microsoft.AspNetCore.Razor.Tools
} }
} }
// Skipping temporarily on non-windows. https://github.com/aspnet/Razor/issues/1991 [Fact]
[ConditionalFact]
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
public async Task ServerRunning_CancelCompilation_CancelsSuccessfully() public async Task ServerRunning_CancelCompilation_CancelsSuccessfully()
{ {
// Arrange // Arrange
@ -213,18 +221,28 @@ namespace Microsoft.AspNetCore.Razor.Tools
return new RejectedServerResponse(); return new RejectedServerResponse();
}); });
using (var serverData = ServerUtilities.CreateServer(compilerHost: host)) var semaphore = new SemaphoreSlim(1);
Action<object, EventArgs> onListening = (s, e) =>
{ {
var tasks = new List<Task<ServerResponse>>(); semaphore.Release();
};
using (var serverData = ServerUtilities.CreateServer(compilerHost: host, onListening: onListening))
{
// Send all the requests.
var clients = new List<Client>();
for (var i = 0; i < requestCount; i++) for (var i = 0; i < requestCount; i++)
{ {
var task = ServerUtilities.Send(serverData.PipeName, EmptyServerRequest); // Wait for the server to start listening.
tasks.Add(task); await semaphore.WaitAsync(TimeSpan.FromMinutes(1));
var client = await Client.ConnectAsync(serverData.PipeName, timeout: null, cancellationToken: default);
await EmptyServerRequest.WriteAsync(client.Stream);
clients.Add(client);
} }
// Act // Act
// Wait until all of the connections are being processed by the server. // Wait until all of the connections are being processed by the server.
completionSource.Task.Wait(); await completionSource.Task;
// Now cancel // Now cancel
var stats = await serverData.CancelAndCompleteAsync(); var stats = await serverData.CancelAndCompleteAsync();
@ -233,10 +251,13 @@ namespace Microsoft.AspNetCore.Razor.Tools
Assert.Equal(requestCount, stats.Connections); Assert.Equal(requestCount, stats.Connections);
Assert.Equal(requestCount, count); Assert.Equal(requestCount, count);
foreach (var task in tasks) // Read the server response to each client.
foreach (var client in clients)
{ {
var task = ServerResponse.ReadAsync(client.Stream);
// We expect this to throw because the stream is already closed. // We expect this to throw because the stream is already closed.
await Assert.ThrowsAsync<EndOfStreamException>(() => task); await Assert.ThrowsAnyAsync<IOException>(() => task);
client.Dispose();
} }
} }
} }