diff --git a/src/Hosting/TestHost/test/ClientHandlerTests.cs b/src/Hosting/TestHost/test/ClientHandlerTests.cs index e90a79e97b..383f0af4c7 100644 --- a/src/Hosting/TestHost/test/ClientHandlerTests.cs +++ b/src/Hosting/TestHost/test/ClientHandlerTests.cs @@ -157,51 +157,50 @@ namespace Microsoft.AspNetCore.TestHost [Fact] public async Task HeadersAvailableBeforeBodyFinished() { - ManualResetEvent block = new ManualResetEvent(false); + var block = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var handler = new ClientHandler(PathString.Empty, new DummyApplication(async context => { context.Response.Headers["TestHeader"] = "TestValue"; await context.Response.WriteAsync("BodyStarted,"); - block.WaitOne(); + await block.Task; await context.Response.WriteAsync("BodyFinished"); })); var httpClient = new HttpClient(handler); HttpResponseMessage response = await httpClient.GetAsync("https://example.com/", HttpCompletionOption.ResponseHeadersRead); Assert.Equal("TestValue", response.Headers.GetValues("TestHeader").First()); - block.Set(); + block.SetResult(0); Assert.Equal("BodyStarted,BodyFinished", await response.Content.ReadAsStringAsync()); } [Fact] public async Task FlushSendsHeaders() { - ManualResetEvent block = new ManualResetEvent(false); + var block = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var handler = new ClientHandler(PathString.Empty, new DummyApplication(async context => { context.Response.Headers["TestHeader"] = "TestValue"; context.Response.Body.Flush(); - block.WaitOne(); + await block.Task; await context.Response.WriteAsync("BodyFinished"); })); var httpClient = new HttpClient(handler); HttpResponseMessage response = await httpClient.GetAsync("https://example.com/", HttpCompletionOption.ResponseHeadersRead); Assert.Equal("TestValue", response.Headers.GetValues("TestHeader").First()); - block.Set(); + block.SetResult(0); Assert.Equal("BodyFinished", await response.Content.ReadAsStringAsync()); } [Fact] public async Task ClientDisposalCloses() { - ManualResetEvent block = new ManualResetEvent(false); + var block = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var handler = new ClientHandler(PathString.Empty, new DummyApplication(context => { context.Response.Headers["TestHeader"] = "TestValue"; context.Response.Body.Flush(); - block.WaitOne(); - return Task.FromResult(0); + return block.Task; })); var httpClient = new HttpClient(handler); HttpResponseMessage response = await httpClient.GetAsync("https://example.com/", @@ -211,21 +210,20 @@ namespace Microsoft.AspNetCore.TestHost Task readTask = responseStream.ReadAsync(new byte[100], 0, 100); Assert.False(readTask.IsCompleted); responseStream.Dispose(); - var result = await readTask.TimeoutAfter(TimeSpan.FromSeconds(10)); - Assert.Equal(0, result); - block.Set(); + var read = await readTask.WithTimeout(); + Assert.Equal(0, read); + block.SetResult(0); } [Fact] public async Task ClientCancellationAborts() { - ManualResetEvent block = new ManualResetEvent(false); + var block = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var handler = new ClientHandler(PathString.Empty, new DummyApplication(context => { context.Response.Headers["TestHeader"] = "TestValue"; context.Response.Body.Flush(); - block.WaitOne(); - return Task.FromResult(0); + return block.Task; })); var httpClient = new HttpClient(handler); HttpResponseMessage response = await httpClient.GetAsync("https://example.com/", @@ -236,8 +234,8 @@ namespace Microsoft.AspNetCore.TestHost Task readTask = responseStream.ReadAsync(new byte[100], 0, 100, cts.Token); Assert.False(readTask.IsCompleted, "Not Completed"); cts.Cancel(); - await Assert.ThrowsAsync(() => readTask.TimeoutAfter(TimeSpan.FromSeconds(10))); - block.Set(); + await Assert.ThrowsAsync(() => readTask.WithTimeout()); + block.SetResult(0); } [Fact] @@ -255,19 +253,19 @@ namespace Microsoft.AspNetCore.TestHost [Fact] public async Task ExceptionAfterFirstWriteIsReported() { - ManualResetEvent block = new ManualResetEvent(false); + var block = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var handler = new ClientHandler(PathString.Empty, new DummyApplication(async context => { context.Response.Headers["TestHeader"] = "TestValue"; await context.Response.WriteAsync("BodyStarted"); - block.WaitOne(); + await block.Task; throw new InvalidOperationException("Test Exception"); })); var httpClient = new HttpClient(handler); HttpResponseMessage response = await httpClient.GetAsync("https://example.com/", HttpCompletionOption.ResponseHeadersRead); Assert.Equal("TestValue", response.Headers.GetValues("TestHeader").First()); - block.Set(); + block.SetResult(0); var ex = await Assert.ThrowsAsync(() => response.Content.ReadAsStringAsync()); Assert.IsType(ex.GetBaseException()); } diff --git a/src/Hosting/TestHost/test/HttpContextBuilderTests.cs b/src/Hosting/TestHost/test/HttpContextBuilderTests.cs index 21539c8988..f04a2f16f9 100644 --- a/src/Hosting/TestHost/test/HttpContextBuilderTests.cs +++ b/src/Hosting/TestHost/test/HttpContextBuilderTests.cs @@ -102,18 +102,17 @@ namespace Microsoft.AspNetCore.TestHost [Fact] public async Task HeadersAvailableBeforeSyncBodyFinished() { - var block = new ManualResetEvent(false); + var block = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var builder = new WebHostBuilder().Configure(app => { - app.Run(c => + app.Run(async c => { c.Response.Headers["TestHeader"] = "TestValue"; var bytes = Encoding.UTF8.GetBytes("BodyStarted" + Environment.NewLine); c.Response.Body.Write(bytes, 0, bytes.Length); - Assert.True(block.WaitOne(TimeSpan.FromSeconds(5))); + await block.Task; bytes = Encoding.UTF8.GetBytes("BodyFinished"); c.Response.Body.Write(bytes, 0, bytes.Length); - return Task.CompletedTask; }); }); var server = new TestServer(builder); @@ -122,21 +121,21 @@ namespace Microsoft.AspNetCore.TestHost Assert.Equal("TestValue", context.Response.Headers["TestHeader"]); var reader = new StreamReader(context.Response.Body); Assert.Equal("BodyStarted", reader.ReadLine()); - block.Set(); + block.SetResult(0); Assert.Equal("BodyFinished", reader.ReadToEnd()); } [Fact] public async Task HeadersAvailableBeforeAsyncBodyFinished() { - var block = new ManualResetEvent(false); + var block = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var builder = new WebHostBuilder().Configure(app => { app.Run(async c => { c.Response.Headers["TestHeader"] = "TestValue"; await c.Response.WriteAsync("BodyStarted" + Environment.NewLine); - Assert.True(block.WaitOne(TimeSpan.FromSeconds(5))); + await block.Task; await c.Response.WriteAsync("BodyFinished"); }); }); @@ -146,21 +145,21 @@ namespace Microsoft.AspNetCore.TestHost Assert.Equal("TestValue", context.Response.Headers["TestHeader"]); var reader = new StreamReader(context.Response.Body); Assert.Equal("BodyStarted", await reader.ReadLineAsync()); - block.Set(); + block.SetResult(0); Assert.Equal("BodyFinished", await reader.ReadToEndAsync()); } [Fact] public async Task FlushSendsHeaders() { - var block = new ManualResetEvent(false); + var block = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var builder = new WebHostBuilder().Configure(app => { app.Run(async c => { c.Response.Headers["TestHeader"] = "TestValue"; c.Response.Body.Flush(); - block.WaitOne(); + await block.Task; await c.Response.WriteAsync("BodyFinished"); }); }); @@ -168,21 +167,21 @@ namespace Microsoft.AspNetCore.TestHost var context = await server.SendAsync(c => { }); Assert.Equal("TestValue", context.Response.Headers["TestHeader"]); - block.Set(); + block.SetResult(0); Assert.Equal("BodyFinished", new StreamReader(context.Response.Body).ReadToEnd()); } [Fact] public async Task ClientDisposalCloses() { - var block = new ManualResetEvent(false); + var block = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var builder = new WebHostBuilder().Configure(app => { app.Run(async c => { c.Response.Headers["TestHeader"] = "TestValue"; c.Response.Body.Flush(); - block.WaitOne(); + await block.Task; await c.Response.WriteAsync("BodyFinished"); }); }); @@ -194,20 +193,20 @@ namespace Microsoft.AspNetCore.TestHost Task readTask = responseStream.ReadAsync(new byte[100], 0, 100); Assert.False(readTask.IsCompleted); responseStream.Dispose(); - Assert.True(readTask.Wait(TimeSpan.FromSeconds(10))); - Assert.Equal(0, readTask.Result); - block.Set(); + var read = await readTask.WithTimeout(); + Assert.Equal(0, read); + block.SetResult(0); } [Fact] - public void ClientCancellationAborts() + public async Task ClientCancellationAborts() { - var block = new ManualResetEvent(false); + var block = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var builder = new WebHostBuilder().Configure(app => { app.Run(c => { - block.Set(); + block.SetResult(0); Assert.True(c.RequestAborted.WaitHandle.WaitOne(TimeSpan.FromSeconds(10))); c.RequestAborted.ThrowIfCancellationRequested(); return Task.CompletedTask; @@ -216,24 +215,23 @@ namespace Microsoft.AspNetCore.TestHost var server = new TestServer(builder); var cts = new CancellationTokenSource(); var contextTask = server.SendAsync(c => { }, cts.Token); - block.WaitOne(); + await block.Task; cts.Cancel(); - var ex = Assert.Throws(() => contextTask.Wait(TimeSpan.FromSeconds(10))); - Assert.IsAssignableFrom(ex.GetBaseException()); + await Assert.ThrowsAsync(() => contextTask.WithTimeout()); } [Fact] public async Task ClientCancellationAbortsReadAsync() { - var block = new ManualResetEvent(false); + var block = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var builder = new WebHostBuilder().Configure(app => { app.Run(async c => { c.Response.Headers["TestHeader"] = "TestValue"; c.Response.Body.Flush(); - block.WaitOne(); + await block.Task; await c.Response.WriteAsync("BodyFinished"); }); }); @@ -246,9 +244,8 @@ namespace Microsoft.AspNetCore.TestHost var readTask = responseStream.ReadAsync(new byte[100], 0, 100, cts.Token); Assert.False(readTask.IsCompleted); cts.Cancel(); - var ex = Assert.Throws(() => readTask.Wait(TimeSpan.FromSeconds(10))); - Assert.IsAssignableFrom(ex.GetBaseException()); - block.Set(); + await Assert.ThrowsAsync(() => readTask.WithTimeout()); + block.SetResult(0); } [Fact] @@ -268,14 +265,14 @@ namespace Microsoft.AspNetCore.TestHost [Fact] public async Task ExceptionAfterFirstWriteIsReported() { - var block = new ManualResetEvent(false); + var block = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var builder = new WebHostBuilder().Configure(app => { app.Run(async c => { c.Response.Headers["TestHeader"] = "TestValue"; await c.Response.WriteAsync("BodyStarted"); - block.WaitOne(); + await block.Task; throw new InvalidOperationException("Test Exception"); }); }); @@ -284,7 +281,7 @@ namespace Microsoft.AspNetCore.TestHost Assert.Equal("TestValue", context.Response.Headers["TestHeader"]); Assert.Equal(11, context.Response.Body.Read(new byte[100], 0, 100)); - block.Set(); + block.SetResult(0); var ex = Assert.Throws(() => context.Response.Body.Read(new byte[100], 0, 100)); Assert.IsAssignableFrom(ex.InnerException); } diff --git a/src/Hosting/TestHost/test/Utilities.cs b/src/Hosting/TestHost/test/Utilities.cs new file mode 100644 index 0000000000..9160356355 --- /dev/null +++ b/src/Hosting/TestHost/test/Utilities.cs @@ -0,0 +1,29 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Threading.Tasks; + +namespace Microsoft.AspNetCore.TestHost +{ + internal static class Utilities + { + internal static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(15); + + internal static Task WithTimeout(this Task task) => task.WithTimeout(DefaultTimeout); + + internal static async Task WithTimeout(this Task task, TimeSpan timeout) + { + var completedTask = await Task.WhenAny(task, Task.Delay(timeout)); + + if (completedTask == task) + { + return await task; + } + else + { + throw new TimeoutException("The task has timed out."); + } + } + } +} diff --git a/src/Middleware/WebSockets/test/AutobahnTestApp/Properties/launchSettings.json b/src/Middleware/WebSockets/test/AutobahnTestApp/Properties/launchSettings.json deleted file mode 100644 index 85a2609ccc..0000000000 --- a/src/Middleware/WebSockets/test/AutobahnTestApp/Properties/launchSettings.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:6155/", - "sslPort": 44371 - } - }, - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "ManagedSockets" - } - }, - "AutobahnTestApp": { - "commandName": "Project", - "launchBrowser": true, - "launchUrl": "http://localhost:5000", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "ManagedSockets" - } - }, - "AutobahnTestApp (SSL)": { - "commandName": "Project", - "launchBrowser": true, - "launchUrl": "https://localhost:5443", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "ManagedSockets" - } - }, - "WebListener": { - "commandName": "Project", - "commandLineArgs": "--server Microsoft.AspNetCore.Server.HttpSys", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "ManagedSockets" - } - } - } -} \ No newline at end of file diff --git a/src/Middleware/WebSockets/test/AutobahnTestApp/AutobahnTestApp.csproj b/src/Middleware/WebSockets/test/ConformanceTests/AutobahnTestApp/AutobahnTestApp.csproj similarity index 100% rename from src/Middleware/WebSockets/test/AutobahnTestApp/AutobahnTestApp.csproj rename to src/Middleware/WebSockets/test/ConformanceTests/AutobahnTestApp/AutobahnTestApp.csproj diff --git a/src/Middleware/WebSockets/test/AutobahnTestApp/Program.cs b/src/Middleware/WebSockets/test/ConformanceTests/AutobahnTestApp/Program.cs similarity index 100% rename from src/Middleware/WebSockets/test/AutobahnTestApp/Program.cs rename to src/Middleware/WebSockets/test/ConformanceTests/AutobahnTestApp/Program.cs diff --git a/src/Middleware/WebSockets/test/AutobahnTestApp/README.md b/src/Middleware/WebSockets/test/ConformanceTests/AutobahnTestApp/README.md similarity index 100% rename from src/Middleware/WebSockets/test/AutobahnTestApp/README.md rename to src/Middleware/WebSockets/test/ConformanceTests/AutobahnTestApp/README.md diff --git a/src/Middleware/WebSockets/test/AutobahnTestApp/Startup.cs b/src/Middleware/WebSockets/test/ConformanceTests/AutobahnTestApp/Startup.cs similarity index 100% rename from src/Middleware/WebSockets/test/AutobahnTestApp/Startup.cs rename to src/Middleware/WebSockets/test/ConformanceTests/AutobahnTestApp/Startup.cs diff --git a/src/Middleware/WebSockets/test/AutobahnTestApp/TestResources/testCert.pfx b/src/Middleware/WebSockets/test/ConformanceTests/AutobahnTestApp/TestResources/testCert.pfx similarity index 100% rename from src/Middleware/WebSockets/test/AutobahnTestApp/TestResources/testCert.pfx rename to src/Middleware/WebSockets/test/ConformanceTests/AutobahnTestApp/TestResources/testCert.pfx diff --git a/src/Middleware/WebSockets/test/AutobahnTestApp/TestResources/testCert.txt b/src/Middleware/WebSockets/test/ConformanceTests/AutobahnTestApp/TestResources/testCert.txt similarity index 100% rename from src/Middleware/WebSockets/test/AutobahnTestApp/TestResources/testCert.txt rename to src/Middleware/WebSockets/test/ConformanceTests/AutobahnTestApp/TestResources/testCert.txt diff --git a/src/Middleware/WebSockets/test/AutobahnTestApp/scripts/RunAutobahnTests.ps1 b/src/Middleware/WebSockets/test/ConformanceTests/AutobahnTestApp/scripts/RunAutobahnTests.ps1 similarity index 100% rename from src/Middleware/WebSockets/test/AutobahnTestApp/scripts/RunAutobahnTests.ps1 rename to src/Middleware/WebSockets/test/ConformanceTests/AutobahnTestApp/scripts/RunAutobahnTests.ps1 diff --git a/src/Middleware/WebSockets/test/AutobahnTestApp/scripts/autobahn.spec.json b/src/Middleware/WebSockets/test/ConformanceTests/AutobahnTestApp/scripts/autobahn.spec.json similarity index 100% rename from src/Middleware/WebSockets/test/AutobahnTestApp/scripts/autobahn.spec.json rename to src/Middleware/WebSockets/test/ConformanceTests/AutobahnTestApp/scripts/autobahn.spec.json diff --git a/src/Middleware/WebSockets/test/ConformanceTests/Helpers.cs b/src/Middleware/WebSockets/test/ConformanceTests/Helpers.cs index 37f65ca082..7c35b17305 100644 --- a/src/Middleware/WebSockets/test/ConformanceTests/Helpers.cs +++ b/src/Middleware/WebSockets/test/ConformanceTests/Helpers.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; namespace Microsoft.AspNetCore.WebSockets.ConformanceTest @@ -7,22 +7,7 @@ namespace Microsoft.AspNetCore.WebSockets.ConformanceTest { public static string GetApplicationPath(string projectName) { - var applicationBasePath = AppContext.BaseDirectory; - - var directoryInfo = new DirectoryInfo(applicationBasePath); - do - { - var solutionFileInfo = new FileInfo(Path.Combine(directoryInfo.FullName, "WebSockets.sln")); - if (solutionFileInfo.Exists) - { - return Path.GetFullPath(Path.Combine(directoryInfo.FullName, "test", projectName)); - } - - directoryInfo = directoryInfo.Parent; - } - while (directoryInfo.Parent != null); - - throw new Exception($"Solution root could not be found using {applicationBasePath}"); + return Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, projectName)); } } } diff --git a/src/Middleware/WebSockets/test/ConformanceTests/Microsoft.AspNetCore.WebSockets.ConformanceTests.csproj b/src/Middleware/WebSockets/test/ConformanceTests/Microsoft.AspNetCore.WebSockets.ConformanceTests.csproj index 13e075308f..64249fc7bd 100644 --- a/src/Middleware/WebSockets/test/ConformanceTests/Microsoft.AspNetCore.WebSockets.ConformanceTests.csproj +++ b/src/Middleware/WebSockets/test/ConformanceTests/Microsoft.AspNetCore.WebSockets.ConformanceTests.csproj @@ -2,6 +2,7 @@ netcoreapp2.2 + $(DefaultItemExcludes);AutobahnTestApp\**\* @@ -9,6 +10,7 @@ +