diff --git a/src/DefaultBuilder/DefaultBuilder.sln b/src/DefaultBuilder/DefaultBuilder.sln index 30d7765447..7c7a6387f7 100644 --- a/src/DefaultBuilder/DefaultBuilder.sln +++ b/src/DefaultBuilder/DefaultBuilder.sln @@ -77,18 +77,16 @@ Global {766C394B-ABBB-4624-A071-C806C0A2CD3E}.Release|x64.Build.0 = Release|Any CPU {766C394B-ABBB-4624-A071-C806C0A2CD3E}.Release|x86.ActiveCfg = Release|Any CPU {766C394B-ABBB-4624-A071-C806C0A2CD3E}.Release|x86.Build.0 = Release|Any CPU - {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Debug|x64.ActiveCfg = Debug|Any CPU - {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Debug|x64.Build.0 = Debug|Any CPU - {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Debug|x86.ActiveCfg = Debug|Any CPU - {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Debug|x86.Build.0 = Debug|Any CPU - {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Release|Any CPU.Build.0 = Release|Any CPU - {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Release|x64.ActiveCfg = Release|Any CPU - {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Release|x64.Build.0 = Release|Any CPU - {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Release|x86.ActiveCfg = Release|Any CPU - {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Release|x86.Build.0 = Release|Any CPU + {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Debug|Any CPU.ActiveCfg = Debug|x86 + {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Debug|x64.ActiveCfg = Debug|x64 + {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Debug|x64.Build.0 = Debug|x64 + {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Debug|x86.ActiveCfg = Debug|x86 + {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Debug|x86.Build.0 = Debug|x86 + {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Release|Any CPU.ActiveCfg = Release|x86 + {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Release|x64.ActiveCfg = Release|x64 + {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Release|x64.Build.0 = Release|x64 + {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Release|x86.ActiveCfg = Release|x86 + {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Release|x86.Build.0 = Release|x86 {AE1F0124-996E-476A-9331-FB789F3D0577}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AE1F0124-996E-476A-9331-FB789F3D0577}.Debug|Any CPU.Build.0 = Debug|Any CPU {AE1F0124-996E-476A-9331-FB789F3D0577}.Debug|x64.ActiveCfg = Debug|Any CPU diff --git a/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebHostTests.cs b/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebHostTests.cs index 70b1806a54..d6c3d255cd 100644 --- a/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebHostTests.cs +++ b/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebHostTests.cs @@ -7,9 +7,11 @@ using System.Collections.Generic; using System.Diagnostics.Tracing; using System.Linq; using System.Threading; +using System.Threading.Tasks; using Microsoft.AspNetCore.HostFiltering; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Routing; +using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -28,7 +30,7 @@ namespace Microsoft.AspNetCore.Tests } [Fact] - public void WebHostConfiguration_HostFilterOptionsAreReloadable() + public async Task WebHostConfiguration_HostFilterOptionsAreReloadable() { var host = WebHost.CreateDefaultBuilder() .Configure(app => { }) @@ -42,15 +44,15 @@ namespace Microsoft.AspNetCore.Tests Assert.Contains("*", options.AllowedHosts); - var changed = new ManualResetEvent(false); + var changed = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); monitor.OnChange(newOptions => { - changed.Set(); + changed.SetResult(0); }); config["AllowedHosts"] = "NewHost"; - Assert.True(changed.WaitOne(TimeSpan.FromSeconds(10))); + await changed.Task.TimeoutAfter(TimeSpan.FromSeconds(10)); options = monitor.CurrentValue; Assert.Contains("NewHost", options.AllowedHosts); } diff --git a/src/Middleware/ResponseCompression/test/ResponseCompressionMiddlewareTest.cs b/src/Middleware/ResponseCompression/test/ResponseCompressionMiddlewareTest.cs index 4f5c6bf073..3c6be0aa8e 100644 --- a/src/Middleware/ResponseCompression/test/ResponseCompressionMiddlewareTest.cs +++ b/src/Middleware/ResponseCompression/test/ResponseCompressionMiddlewareTest.cs @@ -14,6 +14,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.TestHost; +using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Testing; @@ -460,7 +461,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests [MemberData(nameof(SupportedEncodingsWithBodyLength))] public async Task FlushHeaders_SendsHeaders_Compresses(string encoding, int expectedBodyLength) { - var responseReceived = new ManualResetEvent(false); + var responseReceived = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var builder = new WebHostBuilder() .ConfigureServices(services => @@ -470,13 +471,13 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests .Configure(app => { app.UseResponseCompression(); - app.Run(context => + app.Run(async context => { context.Response.Headers[HeaderNames.ContentMD5] = "MD5"; context.Response.ContentType = TextPlain; context.Response.Body.Flush(); - Assert.True(responseReceived.WaitOne(TimeSpan.FromSeconds(3))); - return context.Response.WriteAsync(new string('a', 100)); + await responseReceived.Task.TimeoutAfter(TimeSpan.FromSeconds(3)); + await context.Response.WriteAsync(new string('a', 100)); }); }); @@ -487,7 +488,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests request.Headers.AcceptEncoding.ParseAdd(encoding); var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); - responseReceived.Set(); + responseReceived.SetResult(0); await response.Content.LoadIntoBufferAsync(); @@ -498,7 +499,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests [MemberData(nameof(SupportedEncodingsWithBodyLength))] public async Task FlushAsyncHeaders_SendsHeaders_Compresses(string encoding, int expectedBodyLength) { - var responseReceived = new ManualResetEvent(false); + var responseReceived = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var builder = new WebHostBuilder() .ConfigureServices(services => @@ -513,7 +514,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests context.Response.Headers[HeaderNames.ContentMD5] = "MD5"; context.Response.ContentType = TextPlain; await context.Response.Body.FlushAsync(); - Assert.True(responseReceived.WaitOne(TimeSpan.FromSeconds(3))); + await responseReceived.Task.TimeoutAfter(TimeSpan.FromSeconds(3)); await context.Response.WriteAsync(new string('a', 100)); }); }); @@ -525,7 +526,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests request.Headers.AcceptEncoding.ParseAdd(encoding); var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); - responseReceived.Set(); + responseReceived.SetResult(0); await response.Content.LoadIntoBufferAsync(); @@ -536,7 +537,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests [MemberData(nameof(SupportedEncodings))] public async Task FlushBody_CompressesAndFlushes(string encoding) { - var responseReceived = new ManualResetEvent(false); + var responseReceived = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var builder = new WebHostBuilder() .ConfigureServices(services => @@ -546,7 +547,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests .Configure(app => { app.UseResponseCompression(); - app.Run(context => + app.Run(async context => { var feature = context.Features.Get(); if (feature != null) @@ -558,9 +559,8 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests context.Response.ContentType = TextPlain; context.Response.Body.Write(new byte[10], 0, 10); context.Response.Body.Flush(); - Assert.True(responseReceived.WaitOne(TimeSpan.FromSeconds(3))); + await responseReceived.Task.TimeoutAfter(TimeSpan.FromSeconds(3)); context.Response.Body.Write(new byte[90], 0, 90); - return Task.FromResult(0); }); }); @@ -579,7 +579,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var read = await body.ReadAsync(new byte[100], 0, 100); Assert.True(read > 0); - responseReceived.Set(); + responseReceived.SetResult(0); read = await body.ReadAsync(new byte[100], 0, 100); Assert.True(read > 0); @@ -589,7 +589,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests [MemberData(nameof(SupportedEncodings))] public async Task FlushAsyncBody_CompressesAndFlushes(string encoding) { - var responseReceived = new ManualResetEvent(false); + var responseReceived = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var builder = new WebHostBuilder() .ConfigureServices(services => @@ -605,7 +605,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests context.Response.ContentType = TextPlain; await context.Response.WriteAsync(new string('a', 10)); await context.Response.Body.FlushAsync(); - Assert.True(responseReceived.WaitOne(TimeSpan.FromSeconds(3))); + await responseReceived.Task.TimeoutAfter(TimeSpan.FromSeconds(3)); await context.Response.WriteAsync(new string('a', 90)); }); }); @@ -625,7 +625,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var read = await body.ReadAsync(new byte[100], 0, 100); Assert.True(read > 0); - responseReceived.Set(); + responseReceived.SetResult(0); read = await body.ReadAsync(new byte[100], 0, 100); Assert.True(read > 0); @@ -637,11 +637,11 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests { var responseReceived = new[] { - new ManualResetEvent(false), - new ManualResetEvent(false), - new ManualResetEvent(false), - new ManualResetEvent(false), - new ManualResetEvent(false), + new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously), + new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously), + new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously), + new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously), + new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously), }; var builder = new WebHostBuilder() @@ -652,7 +652,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests .Configure(app => { app.UseResponseCompression(); - app.Run(context => + app.Run(async context => { context.Response.Headers[HeaderNames.ContentMD5] = "MD5"; context.Response.ContentType = TextPlain; @@ -668,9 +668,8 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests { context.Response.Body.Write(new byte[1], 0, 1); context.Response.Body.Flush(); - Assert.True(signal.WaitOne(TimeSpan.FromSeconds(3))); + await signal.Task.TimeoutAfter(TimeSpan.FromSeconds(3)); } - return Task.FromResult(0); }); }); @@ -691,7 +690,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var read = await body.ReadAsync(new byte[100], 0, 100); Assert.True(read > 0); - signal.Set(); + signal.SetResult(0); } } @@ -701,11 +700,11 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests { var responseReceived = new[] { - new ManualResetEvent(false), - new ManualResetEvent(false), - new ManualResetEvent(false), - new ManualResetEvent(false), - new ManualResetEvent(false), + new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously), + new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously), + new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously), + new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously), + new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously), }; var builder = new WebHostBuilder() @@ -726,7 +725,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests { await context.Response.WriteAsync("a"); await context.Response.Body.FlushAsync(); - Assert.True(signal.WaitOne(TimeSpan.FromSeconds(3))); + await signal.Task.TimeoutAfter(TimeSpan.FromSeconds(3)); } }); }); @@ -748,7 +747,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var read = await body.ReadAsync(new byte[100], 0, 100); Assert.True(read > 0); - signal.Set(); + signal.SetResult(0); } } @@ -918,7 +917,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests [MemberData(nameof(SupportedEncodings))] public async Task Dispose_SyncWriteOrFlushNotCalled(string encoding) { - var responseReceived = new ManualResetEvent(false); + var responseReceived = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var builder = new WebHostBuilder() .ConfigureServices(services => @@ -939,7 +938,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests context.Response.ContentType = TextPlain; await context.Response.WriteAsync(new string('a', 10)); await context.Response.Body.FlushAsync(); - Assert.True(responseReceived.WaitOne(TimeSpan.FromSeconds(3))); + await responseReceived.Task.TimeoutAfter(TimeSpan.FromSeconds(3)); await context.Response.WriteAsync(new string('a', 90)); }); }); @@ -959,7 +958,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var read = await body.ReadAsync(new byte[100], 0, 100); Assert.True(read > 0); - responseReceived.Set(); + responseReceived.SetResult(0); read = await body.ReadAsync(new byte[100], 0, 100); Assert.True(read > 0); diff --git a/src/Middleware/StaticFiles/test/FunctionalTests/StaticFileMiddlewareTests.cs b/src/Middleware/StaticFiles/test/FunctionalTests/StaticFileMiddlewareTests.cs index 268accc699..0f9be47e97 100644 --- a/src/Middleware/StaticFiles/test/FunctionalTests/StaticFileMiddlewareTests.cs +++ b/src/Middleware/StaticFiles/test/FunctionalTests/StaticFileMiddlewareTests.cs @@ -16,6 +16,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Server.IntegrationTesting; using Microsoft.AspNetCore.Server.IntegrationTesting.Common; +using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging.Testing; @@ -164,25 +165,25 @@ namespace Microsoft.AspNetCore.StaticFiles }; [Fact] - public void ClientDisconnect_Kestrel_NoWriteExceptionThrown() + public Task ClientDisconnect_Kestrel_NoWriteExceptionThrown() { - ClientDisconnect_NoWriteExceptionThrown(ServerType.Kestrel); + return ClientDisconnect_NoWriteExceptionThrown(ServerType.Kestrel); } [ConditionalFact] [OSSkipCondition(OperatingSystems.Linux)] [OSSkipCondition(OperatingSystems.MacOSX)] - public void ClientDisconnect_WebListener_NoWriteExceptionThrown() + public Task ClientDisconnect_WebListener_NoWriteExceptionThrown() { - ClientDisconnect_NoWriteExceptionThrown(ServerType.HttpSys); + return ClientDisconnect_NoWriteExceptionThrown(ServerType.HttpSys); } - private void ClientDisconnect_NoWriteExceptionThrown(ServerType serverType) + private async Task ClientDisconnect_NoWriteExceptionThrown(ServerType serverType) { var interval = TimeSpan.FromSeconds(15); - var requestReceived = new ManualResetEvent(false); - var requestCancelled = new ManualResetEvent(false); - var responseComplete = new ManualResetEvent(false); + var requestReceived = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var requestCancelled = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var responseComplete = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); Exception exception = null; var builder = new WebHostBuilder() .ConfigureServices(services => services.AddSingleton(LoggerFactory)) @@ -193,8 +194,8 @@ namespace Microsoft.AspNetCore.StaticFiles { try { - requestReceived.Set(); - Assert.True(requestCancelled.WaitOne(interval), "not cancelled"); + requestReceived.SetResult(0); + await requestCancelled.Task.TimeoutAfter(interval); Assert.True(context.RequestAborted.WaitHandle.WaitOne(interval), "not aborted"); await next(); } @@ -202,7 +203,7 @@ namespace Microsoft.AspNetCore.StaticFiles { exception = ex; } - responseComplete.Set(); + responseComplete.SetResult(0); }); app.UseStaticFiles(); }); @@ -220,13 +221,13 @@ namespace Microsoft.AspNetCore.StaticFiles { // We don't use HttpClient here because it's disconnect behavior varies across platforms. var socket = SendSocketRequestAsync(server.GetAddress(), "/TestDocument1MB.txt"); - Assert.True(requestReceived.WaitOne(interval), "not received"); + await requestReceived.Task.TimeoutAfter(interval); socket.LingerState = new LingerOption(true, 0); socket.Dispose(); - requestCancelled.Set(); + requestCancelled.SetResult(0); - Assert.True(responseComplete.WaitOne(interval), "not completed"); + await responseComplete.Task.TimeoutAfter(interval); Assert.Null(exception); } } diff --git a/src/Mvc/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/CacheTagHelperTest.cs b/src/Mvc/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/CacheTagHelperTest.cs index 9d43784485..78e3645a24 100644 --- a/src/Mvc/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/CacheTagHelperTest.cs +++ b/src/Mvc/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/CacheTagHelperTest.cs @@ -17,6 +17,7 @@ using Microsoft.AspNetCore.Mvc.ViewEngines; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Routing; +using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Internal; using Microsoft.Extensions.Primitives; @@ -545,9 +546,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers // Arrange var id = "unique-id"; var childContent = "some-content"; - var resetEvent1 = new ManualResetEvent(false); - var resetEvent2 = new ManualResetEvent(false); - var resetEvent3 = new ManualResetEvent(false); + var event1 = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var event2 = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var event3 = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var calls = 0; var cache = new MemoryCache(new MemoryCacheOptions()); @@ -560,7 +561,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers getChildContentAsync: (useCachedResult, encoder) => { calls++; - resetEvent2.Set(); + event2.SetResult(0); var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetHtmlContent(childContent); @@ -570,14 +571,14 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var tagHelperOutput2 = new TagHelperOutput( "cache", new TagHelperAttributeList(), - getChildContentAsync: (useCachedResult, encoder) => + getChildContentAsync: async (useCachedResult, encoder) => { calls++; - resetEvent3.WaitOne(5000); + await event3.Task.TimeoutAfter(TimeSpan.FromSeconds(5)); var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetHtmlContent(childContent); - return Task.FromResult(tagHelperContent); + return tagHelperContent; }); var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()) @@ -596,18 +597,18 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var task1 = Task.Run(async () => { - resetEvent1.WaitOne(5000); + await event1.Task.TimeoutAfter(TimeSpan.FromSeconds(5)); await cacheTagHelper1.ProcessAsync(tagHelperContext1, tagHelperOutput1); - resetEvent3.Set(); + event3.SetResult(0); }); var task2 = Task.Run(async () => { - resetEvent2.WaitOne(5000); + await event2.Task.TimeoutAfter(TimeSpan.FromSeconds(5)); await cacheTagHelper2.ProcessAsync(tagHelperContext1, tagHelperOutput2); }); - resetEvent1.Set(); + event1.SetResult(0); await Task.WhenAll(task1, task2); // Assert @@ -630,9 +631,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers // Arrange var id = "unique-id"; var childContent = "some-content"; - var resetEvent1 = new ManualResetEvent(false); - var resetEvent2 = new ManualResetEvent(false); - var resetEvent3 = new ManualResetEvent(false); + var event1 = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var event2 = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var event3 = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var calls = 0; var cache = new MemoryCache(new MemoryCacheOptions()); @@ -645,7 +646,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers getChildContentAsync: (useCachedResult, encoder) => { calls++; - resetEvent2.Set(); + event2.SetResult(0); throw new Exception(); }); @@ -653,14 +654,14 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var tagHelperOutput2 = new TagHelperOutput( "cache", new TagHelperAttributeList(), - getChildContentAsync: (useCachedResult, encoder) => + getChildContentAsync: async (useCachedResult, encoder) => { calls++; - resetEvent3.WaitOne(5000); + await event3.Task.TimeoutAfter(TimeSpan.FromSeconds(5)); var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetHtmlContent(childContent); - return Task.FromResult(tagHelperContent); + return tagHelperContent; }); var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()) @@ -679,18 +680,18 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var task1 = Task.Run(async () => { - resetEvent1.WaitOne(5000); + await event1.Task.TimeoutAfter(TimeSpan.FromSeconds(5)); await Assert.ThrowsAsync(() => cacheTagHelper1.ProcessAsync(tagHelperContext1, tagHelperOutput1)); - resetEvent3.Set(); + event3.SetResult(0); }); var task2 = Task.Run(async () => { - resetEvent2.WaitOne(5000); + await event2.Task.TimeoutAfter(TimeSpan.FromSeconds(5)); await cacheTagHelper2.ProcessAsync(tagHelperContext2, tagHelperOutput2); }); - resetEvent1.Set(); + event1.SetResult(0); await Task.WhenAll(task1, task2); // Assert diff --git a/src/Mvc/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/DistributedCacheTagHelperTest.cs b/src/Mvc/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/DistributedCacheTagHelperTest.cs index 19d56fb5af..410e4f149c 100644 --- a/src/Mvc/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/DistributedCacheTagHelperTest.cs +++ b/src/Mvc/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/DistributedCacheTagHelperTest.cs @@ -17,6 +17,7 @@ using Microsoft.AspNetCore.Mvc.ViewEngines; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Routing; +using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Internal; @@ -538,9 +539,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers { // Arrange var childContent = "some-content"; - var resetEvent1 = new ManualResetEvent(false); - var resetEvent2 = new ManualResetEvent(false); - var resetEvent3 = new ManualResetEvent(false); + var event1 = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var event2 = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var event3 = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var calls = 0; var formatter = GetFormatter(); var storage = GetStorage(); @@ -559,7 +560,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers getChildContentAsync: (useCachedResult, encoder) => { calls++; - resetEvent2.Set(); + event2.SetResult(0); var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetHtmlContent(childContent); @@ -569,14 +570,14 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var tagHelperOutput2 = new TagHelperOutput( "distributed-cache", new TagHelperAttributeList(), - getChildContentAsync: (useCachedResult, encoder) => + getChildContentAsync: async (useCachedResult, encoder) => { calls++; - resetEvent3.WaitOne(5000); + await event3.Task.TimeoutAfter(TimeSpan.FromSeconds(5)); var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetHtmlContent(childContent); - return Task.FromResult(tagHelperContent); + return tagHelperContent; }); var cacheTagHelper1 = new DistributedCacheTagHelper( @@ -599,18 +600,18 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var task1 = Task.Run(async () => { - resetEvent1.WaitOne(5000); + await event1.Task.TimeoutAfter(TimeSpan.FromSeconds(5)); await cacheTagHelper1.ProcessAsync(tagHelperContext1, tagHelperOutput1); - resetEvent3.Set(); + event3.SetResult(0); }); var task2 = Task.Run(async () => { - resetEvent2.WaitOne(5000); + await event2.Task.TimeoutAfter(TimeSpan.FromSeconds(5)); await cacheTagHelper2.ProcessAsync(tagHelperContext1, tagHelperOutput2); }); - resetEvent1.Set(); + event1.SetResult(0); await Task.WhenAll(task1, task2); // Assert @@ -632,9 +633,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers { // Arrange var childContent = "some-content"; - var resetEvent1 = new ManualResetEvent(false); - var resetEvent2 = new ManualResetEvent(false); - var resetEvent3 = new ManualResetEvent(false); + var event1 = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var event2 = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var event3 = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var calls = 0; var formatter = GetFormatter(); var storage = GetStorage(); @@ -653,7 +654,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers getChildContentAsync: (useCachedResult, encoder) => { calls++; - resetEvent2.Set(); + event2.SetResult(0); throw new Exception(); }); @@ -661,14 +662,14 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var tagHelperOutput2 = new TagHelperOutput( "distributed-cache", new TagHelperAttributeList(), - getChildContentAsync: (useCachedResult, encoder) => + getChildContentAsync: async (useCachedResult, encoder) => { calls++; - resetEvent3.WaitOne(5000); + await event3.Task.TimeoutAfter(TimeSpan.FromSeconds(5)); var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetHtmlContent(childContent); - return Task.FromResult(tagHelperContent); + return tagHelperContent; }); var cacheTagHelper1 = new DistributedCacheTagHelper( @@ -691,18 +692,18 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var task1 = Task.Run(async () => { - resetEvent1.WaitOne(5000); + await event1.Task.TimeoutAfter(TimeSpan.FromSeconds(5)); await Assert.ThrowsAsync(() => cacheTagHelper1.ProcessAsync(tagHelperContext1, tagHelperOutput1)); - resetEvent3.Set(); + event3.SetResult(0); }); var task2 = Task.Run(async () => { - resetEvent2.WaitOne(5000); + await event2.Task.TimeoutAfter(TimeSpan.FromSeconds(5)); await cacheTagHelper2.ProcessAsync(tagHelperContext2, tagHelperOutput2); }); - resetEvent1.Set(); + event1.SetResult(0); await Task.WhenAll(task1, task2); // Assert diff --git a/src/Servers/HttpSys/test/FunctionalTests/AuthenticationTests.cs b/src/Servers/HttpSys/test/FunctionalTests/AuthenticationTests.cs index f533303309..4e8679b193 100644 --- a/src/Servers/HttpSys/test/FunctionalTests/AuthenticationTests.cs +++ b/src/Servers/HttpSys/test/FunctionalTests/AuthenticationTests.cs @@ -8,6 +8,7 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing.xunit; using Xunit; @@ -167,7 +168,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys [ConditionalFact] public async Task AuthTypes_AccessUserInOnCompleted_Success() { - var completed = new ManualResetEvent(false); + var completed = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); string userName = null; var authTypes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM; using (var server = Utilities.CreateDynamicHost(authTypes, DenyAnoymous, out var address, httpContext => @@ -178,7 +179,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys httpContext.Response.OnCompleted(() => { userName = httpContext.User.Identity.Name; - completed.Set(); + completed.SetResult(0); return Task.FromResult(0); }); return Task.FromResult(0); @@ -186,7 +187,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { var response = await SendRequestAsync(address, useDefaultCredentials: true); Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.True(completed.WaitOne(TimeSpan.FromSeconds(5))); + await completed.Task.TimeoutAfter(TimeSpan.FromSeconds(5)); Assert.False(string.IsNullOrEmpty(userName)); } } diff --git a/src/Servers/HttpSys/test/FunctionalTests/Listener/ServerTests.cs b/src/Servers/HttpSys/test/FunctionalTests/Listener/ServerTests.cs index 2cb25cc3c1..bb14512fa8 100644 --- a/src/Servers/HttpSys/test/FunctionalTests/Listener/ServerTests.cs +++ b/src/Servers/HttpSys/test/FunctionalTests/Listener/ServerTests.cs @@ -9,6 +9,7 @@ using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing.xunit; using Xunit; @@ -20,7 +21,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener public async Task Server_TokenRegisteredAfterClientDisconnects_CallCanceled() { var interval = TimeSpan.FromSeconds(1); - var canceled = new ManualResetEvent(false); + var canceled = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); string address; using (var server = Utilities.CreateHttpServer(out address)) @@ -36,11 +37,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var ct = context.DisconnectToken; Assert.True(ct.CanBeCanceled, "CanBeCanceled"); - ct.Register(() => canceled.Set()); + ct.Register(() => canceled.SetResult(0)); Assert.True(ct.WaitHandle.WaitOne(interval)); Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); - Assert.True(canceled.WaitOne(interval), "canceled"); + await canceled.Task.TimeoutAfter(interval); context.Dispose(); } @@ -51,7 +52,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener public async Task Server_TokenRegisteredAfterResponseSent_Success() { var interval = TimeSpan.FromSeconds(1); - var canceled = new ManualResetEvent(false); + var canceled = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); string address; using (var server = Utilities.CreateHttpServer(out address)) @@ -69,11 +70,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var ct = context.DisconnectToken; Assert.False(ct.CanBeCanceled, "CanBeCanceled"); - ct.Register(() => canceled.Set()); + ct.Register(() => canceled.SetResult(0)); Assert.False(ct.WaitHandle.WaitOne(interval)); Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); - Assert.False(canceled.WaitOne(interval), "canceled"); + Assert.False(canceled.Task.IsCompleted, "canceled"); } } } @@ -82,7 +83,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener public async Task Server_ConnectionCloseHeader_CancellationTokenFires() { var interval = TimeSpan.FromSeconds(1); - var canceled = new ManualResetEvent(false); + var canceled = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); string address; using (var server = Utilities.CreateHttpServer(out address)) @@ -93,7 +94,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var ct = context.DisconnectToken; Assert.True(ct.CanBeCanceled, "CanBeCanceled"); Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); - ct.Register(() => canceled.Set()); + ct.Register(() => canceled.SetResult(0)); context.Response.Headers["Connection"] = "close"; @@ -102,7 +103,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener await writer.WriteAsync("Hello World"); await writer.FlushAsync(); - Assert.True(canceled.WaitOne(interval), "Disconnected"); + await canceled.Task.TimeoutAfter(interval); Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); var response = await responseTask; diff --git a/src/Servers/HttpSys/test/FunctionalTests/OpaqueUpgradeTests.cs b/src/Servers/HttpSys/test/FunctionalTests/OpaqueUpgradeTests.cs index c9bebee2de..24144bf04a 100644 --- a/src/Servers/HttpSys/test/FunctionalTests/OpaqueUpgradeTests.cs +++ b/src/Servers/HttpSys/test/FunctionalTests/OpaqueUpgradeTests.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing.xunit; using Xunit; @@ -104,25 +105,20 @@ namespace Microsoft.AspNetCore.Server.HttpSys [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public async Task OpaqueUpgrade_GetUpgrade_Success() { - ManualResetEvent waitHandle = new ManualResetEvent(false); - bool? upgraded = null; - string address; - using (Utilities.CreateHttpServer(out address, async httpContext => + var upgraded = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + using (Utilities.CreateHttpServer(out var address, async httpContext => { httpContext.Response.Headers["Upgrade"] = "websocket"; // Win8.1 blocks anything but WebSockets var opaqueFeature = httpContext.Features.Get(); Assert.NotNull(opaqueFeature); Assert.True(opaqueFeature.IsUpgradableRequest); await opaqueFeature.UpgradeAsync(); - upgraded = true; - waitHandle.Set(); + upgraded.SetResult(true); })) { using (Stream stream = await SendOpaqueRequestAsync("GET", address)) { - Assert.True(waitHandle.WaitOne(TimeSpan.FromSeconds(1)), "Timed out"); - Assert.True(upgraded.HasValue, "Upgraded not set"); - Assert.True(upgraded.Value, "Upgrade failed"); + Assert.True(await upgraded.Task.TimeoutAfter(TimeSpan.FromSeconds(1))); } } } @@ -131,10 +127,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public async Task OpaqueUpgrade_GetUpgrade_NotAffectedByMaxRequestBodyLimit() { - ManualResetEvent waitHandle = new ManualResetEvent(false); - bool? upgraded = null; - string address; - using (Utilities.CreateHttpServer(out address, async httpContext => + var upgraded = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + using (Utilities.CreateHttpServer(out var address, async httpContext => { var feature = httpContext.Features.Get(); Assert.NotNull(feature); @@ -150,16 +144,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Null(feature.MaxRequestBodySize); Assert.Throws(() => feature.MaxRequestBodySize = 12); Assert.Equal(15, await stream.ReadAsync(new byte[15], 0, 15)); - upgraded = true; - waitHandle.Set(); + upgraded.SetResult(true); }, options => options.MaxRequestBodySize = 10)) { using (Stream stream = await SendOpaqueRequestAsync("GET", address)) { stream.Write(new byte[15], 0, 15); - Assert.True(waitHandle.WaitOne(TimeSpan.FromSeconds(10)), "Timed out"); - Assert.True(upgraded.HasValue, "Upgraded not set"); - Assert.True(upgraded.Value, "Upgrade failed"); + Assert.True(await upgraded.Task.TimeoutAfter(TimeSpan.FromSeconds(10))); } } } @@ -169,10 +160,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys public async Task OpaqueUpgrade_WithOnStarting_CallbackCalled() { var callbackCalled = false; - var waitHandle = new ManualResetEvent(false); - bool? upgraded = null; - string address; - using (Utilities.CreateHttpServer(out address, async httpContext => + var upgraded = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + using (Utilities.CreateHttpServer(out var address, async httpContext => { httpContext.Response.OnStarting(_ => { @@ -184,15 +173,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.NotNull(opaqueFeature); Assert.True(opaqueFeature.IsUpgradableRequest); await opaqueFeature.UpgradeAsync(); - upgraded = true; - waitHandle.Set(); + upgraded.SetResult(true); })) { using (Stream stream = await SendOpaqueRequestAsync("GET", address)) { - Assert.True(waitHandle.WaitOne(TimeSpan.FromSeconds(1)), "Timed out"); - Assert.True(upgraded.HasValue, "Upgraded not set"); - Assert.True(upgraded.Value, "Upgrade failed"); + Assert.True(await upgraded.Task.TimeoutAfter(TimeSpan.FromSeconds(1))); Assert.True(callbackCalled, "Callback not called"); } } @@ -364,4 +350,4 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } } -} \ No newline at end of file +} diff --git a/src/Servers/HttpSys/test/FunctionalTests/ResponseBodyTests.cs b/src/Servers/HttpSys/test/FunctionalTests/ResponseBodyTests.cs index a42071b342..0a07b456cb 100644 --- a/src/Servers/HttpSys/test/FunctionalTests/ResponseBodyTests.cs +++ b/src/Servers/HttpSys/test/FunctionalTests/ResponseBodyTests.cs @@ -10,6 +10,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing.xunit; using Xunit; @@ -157,10 +158,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys [ConditionalFact] public async Task ResponseBody_WriteContentLengthExtraWritten_Throws() { - var waitHandle = new ManualResetEvent(false); - bool? appThrew = null; - string address; - using (Utilities.CreateHttpServer(out address, httpContext => + var requestThrew = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + using (Utilities.CreateHttpServer(out var address, httpContext => { try { @@ -168,13 +167,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys httpContext.Response.Headers["Content-lenGth"] = " 10 "; httpContext.Response.Body.Write(new byte[10], 0, 10); httpContext.Response.Body.Write(new byte[9], 0, 9); - appThrew = false; + requestThrew.SetResult(false); } catch (Exception) { - appThrew = true; + requestThrew.SetResult(true); } - waitHandle.Set(); return Task.FromResult(0); })) { @@ -188,9 +186,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Null(response.Headers.TransferEncodingChunked); Assert.Equal(new byte[10], await response.Content.ReadAsByteArrayAsync()); - Assert.True(waitHandle.WaitOne(100)); - Assert.True(appThrew.HasValue, "appThrew.HasValue"); - Assert.True(appThrew.Value, "appThrew.Value"); + Assert.True(await requestThrew.Task.TimeoutAfter(TimeSpan.FromSeconds(10))); } } diff --git a/src/Servers/HttpSys/test/FunctionalTests/ResponseSendFileTests.cs b/src/Servers/HttpSys/test/FunctionalTests/ResponseSendFileTests.cs index 69f0a64ec9..6023fd42db 100644 --- a/src/Servers/HttpSys/test/FunctionalTests/ResponseSendFileTests.cs +++ b/src/Servers/HttpSys/test/FunctionalTests/ResponseSendFileTests.cs @@ -12,6 +12,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing.xunit; using Xunit; @@ -74,34 +75,26 @@ namespace Microsoft.AspNetCore.Server.HttpSys [ConditionalFact] public async Task ResponseSendFile_MissingFile_Throws() { - var waitHandle = new ManualResetEvent(false); - bool? appThrew = null; - string address; - using (Utilities.CreateHttpServer(out address, httpContext => + var appThrew = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + using (Utilities.CreateHttpServer(out var address, httpContext => { var sendFile = httpContext.Features.Get(); try { sendFile.SendFileAsync(string.Empty, 0, null, CancellationToken.None).Wait(); - appThrew = false; + appThrew.SetResult(false); } catch (Exception) { - appThrew = true; + appThrew.SetResult(true); throw; } - finally - { - waitHandle.Set(); - } return Task.FromResult(0); })) { HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); - Assert.True(waitHandle.WaitOne(100)); - Assert.True(appThrew.HasValue, "appThrew.HasValue"); - Assert.True(appThrew.Value, "appThrew.Value"); + Assert.True(await appThrew.Task.TimeoutAfter(TimeSpan.FromSeconds(10))); } } diff --git a/src/Servers/HttpSys/test/FunctionalTests/ResponseTests.cs b/src/Servers/HttpSys/test/FunctionalTests/ResponseTests.cs index f2d244edce..455ac93377 100644 --- a/src/Servers/HttpSys/test/FunctionalTests/ResponseTests.cs +++ b/src/Servers/HttpSys/test/FunctionalTests/ResponseTests.cs @@ -8,6 +8,7 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing.xunit; using Xunit; @@ -123,21 +124,21 @@ namespace Microsoft.AspNetCore.Server.HttpSys [ConditionalFact] public async Task Response_Empty_CallsOnStartingAndOnCompleted() { - var onStartingCalled = new ManualResetEvent(false); - var onCompletedCalled = new ManualResetEvent(false); - string address; - using (Utilities.CreateHttpServer(out address, httpContext => + var onStartingCalled = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var onCompletedCalled = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + + using (Utilities.CreateHttpServer(out var address, httpContext => { httpContext.Response.OnStarting(state => { Assert.Same(state, httpContext); - onStartingCalled.Set(); + onStartingCalled.SetResult(0); return Task.FromResult(0); }, httpContext); httpContext.Response.OnCompleted(state => { Assert.Same(state, httpContext); - onCompletedCalled.Set(); + onCompletedCalled.SetResult(0); return Task.FromResult(0); }, httpContext); return Task.FromResult(0); @@ -145,29 +146,28 @@ namespace Microsoft.AspNetCore.Server.HttpSys { var response = await SendRequestAsync(address); Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.True(onStartingCalled.WaitOne(0)); + await onStartingCalled.Task.TimeoutAfter(TimeSpan.FromSeconds(1)); // Fires after the response completes - Assert.True(onCompletedCalled.WaitOne(TimeSpan.FromSeconds(5))); + await onCompletedCalled.Task.TimeoutAfter(TimeSpan.FromSeconds(5)); } } [ConditionalFact] public async Task Response_OnStartingThrows_StillCallsOnCompleted() { - var onStartingCalled = new ManualResetEvent(false); - var onCompletedCalled = new ManualResetEvent(false); - string address; - using (Utilities.CreateHttpServer(out address, httpContext => + var onStartingCalled = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var onCompletedCalled = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + using (Utilities.CreateHttpServer(out var address, httpContext => { httpContext.Response.OnStarting(state => { - onStartingCalled.Set(); + onStartingCalled.SetResult(0); throw new Exception("Failed OnStarting"); }, httpContext); httpContext.Response.OnCompleted(state => { Assert.Same(state, httpContext); - onCompletedCalled.Set(); + onCompletedCalled.SetResult(0); return Task.FromResult(0); }, httpContext); return Task.FromResult(0); @@ -175,29 +175,28 @@ namespace Microsoft.AspNetCore.Server.HttpSys { var response = await SendRequestAsync(address); Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); - Assert.True(onStartingCalled.WaitOne(0)); + await onStartingCalled.Task.TimeoutAfter(TimeSpan.FromSeconds(1)); // Fires after the response completes - Assert.True(onCompletedCalled.WaitOne(TimeSpan.FromSeconds(5))); + await onCompletedCalled.Task.TimeoutAfter(TimeSpan.FromSeconds(5)); } } [ConditionalFact] public async Task Response_OnStartingThrowsAfterWrite_WriteThrowsAndStillCallsOnCompleted() { - var onStartingCalled = new ManualResetEvent(false); - var onCompletedCalled = new ManualResetEvent(false); - string address; - using (Utilities.CreateHttpServer(out address, httpContext => + var onStartingCalled = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var onCompletedCalled = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + using (Utilities.CreateHttpServer(out var address, httpContext => { httpContext.Response.OnStarting(state => { - onStartingCalled.Set(); + onStartingCalled.SetResult(0); throw new InvalidTimeZoneException("Failed OnStarting"); }, httpContext); httpContext.Response.OnCompleted(state => { Assert.Same(state, httpContext); - onCompletedCalled.Set(); + onCompletedCalled.SetResult(0); return Task.FromResult(0); }, httpContext); Assert.Throws(() => httpContext.Response.Body.Write(new byte[10], 0, 10)); @@ -206,9 +205,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys { var response = await SendRequestAsync(address); Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.True(onStartingCalled.WaitOne(0)); + await onStartingCalled.Task.TimeoutAfter(TimeSpan.FromSeconds(1)); // Fires after the response completes - Assert.True(onCompletedCalled.WaitOne(TimeSpan.FromSeconds(5))); + await onCompletedCalled.Task.TimeoutAfter(TimeSpan.FromSeconds(5)); } } diff --git a/src/Servers/HttpSys/test/FunctionalTests/ServerTests.cs b/src/Servers/HttpSys/test/FunctionalTests/ServerTests.cs index 32e328a63d..b1eceb56d7 100644 --- a/src/Servers/HttpSys/test/FunctionalTests/ServerTests.cs +++ b/src/Servers/HttpSys/test/FunctionalTests/ServerTests.cs @@ -69,17 +69,16 @@ namespace Microsoft.AspNetCore.Server.HttpSys public async Task Server_ShutdownDuringRequest_Success() { Task responseTask; - ManualResetEvent received = new ManualResetEvent(false); - string address; - using (var server = Utilities.CreateHttpServer(out address, httpContext => + var received = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + using (var server = Utilities.CreateHttpServer(out var address, httpContext => { - received.Set(); + received.SetResult(0); httpContext.Response.ContentLength = 11; return httpContext.Response.WriteAsync("Hello World"); })) { responseTask = SendRequestAsync(address); - Assert.True(received.WaitOne(10000)); + await received.Task.TimeoutAfter(TimeSpan.FromSeconds(10)); await server.StopAsync(new CancellationTokenSource(TimeSpan.FromSeconds(5)).Token); } string response = await responseTask; @@ -90,21 +89,20 @@ namespace Microsoft.AspNetCore.Server.HttpSys public async Task Server_DisposeWithoutStopDuringRequest_Aborts() { Task responseTask; - var received = new ManualResetEvent(false); - var stopped = new ManualResetEvent(false); - string address; - using (var server = Utilities.CreateHttpServer(out address, httpContext => + var received = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var stopped = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + using (var server = Utilities.CreateHttpServer(out var address, async httpContext => { - received.Set(); - Assert.True(stopped.WaitOne(TimeSpan.FromSeconds(10))); + received.SetResult(0); + await stopped.Task.TimeoutAfter(TimeSpan.FromSeconds(10)); httpContext.Response.ContentLength = 11; - return httpContext.Response.WriteAsync("Hello World"); + await httpContext.Response.WriteAsync("Hello World"); })) { responseTask = SendRequestAsync(address); - Assert.True(received.WaitOne(TimeSpan.FromSeconds(10))); + await received.Task.TimeoutAfter(TimeSpan.FromSeconds(10)); } - stopped.Set(); + stopped.SetResult(0); await Assert.ThrowsAsync(async () => await responseTask); } @@ -112,24 +110,21 @@ namespace Microsoft.AspNetCore.Server.HttpSys public async Task Server_ShutdownDuringLongRunningRequest_TimesOut() { Task responseTask; - var received = new ManualResetEvent(false); - bool? shutdown = null; - var waitForShutdown = new ManualResetEvent(false); - string address; - using (var server = Utilities.CreateHttpServer(out address, httpContext => + var received = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var shutdown = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + using (var server = Utilities.CreateHttpServer(out var address, async httpContext => { - received.Set(); - shutdown = waitForShutdown.WaitOne(TimeSpan.FromSeconds(15)); + received.SetResult(0); + await shutdown.Task.TimeoutAfter(TimeSpan.FromSeconds(15)); httpContext.Response.ContentLength = 11; - return httpContext.Response.WriteAsync("Hello World"); + await httpContext.Response.WriteAsync("Hello World"); })) { responseTask = SendRequestAsync(address); - Assert.True(received.WaitOne(TimeSpan.FromSeconds(10))); - Assert.False(shutdown.HasValue); + await received.Task.TimeoutAfter(TimeSpan.FromSeconds(10)); await server.StopAsync(new CancellationTokenSource(TimeSpan.FromSeconds(5)).Token); } - waitForShutdown.Set(); + shutdown.SetResult(0); await Assert.ThrowsAsync(async () => await responseTask); } @@ -217,64 +212,59 @@ namespace Microsoft.AspNetCore.Server.HttpSys [ConditionalFact] public async Task Server_ClientDisconnects_CallCanceled() { - TimeSpan interval = TimeSpan.FromSeconds(10); - ManualResetEvent received = new ManualResetEvent(false); - ManualResetEvent aborted = new ManualResetEvent(false); - ManualResetEvent canceled = new ManualResetEvent(false); + var interval = TimeSpan.FromSeconds(10); + var received = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var aborted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var canceled = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - string address; - using (Utilities.CreateHttpServer(out address, httpContext => + using (Utilities.CreateHttpServer(out var address, async httpContext => { - CancellationToken ct = httpContext.RequestAborted; + var ct = httpContext.RequestAborted; Assert.True(ct.CanBeCanceled, "CanBeCanceled"); Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); - ct.Register(() => canceled.Set()); - received.Set(); - Assert.True(aborted.WaitOne(interval), "Aborted"); + ct.Register(() => canceled.SetResult(0)); + received.SetResult(0); + await aborted.Task.TimeoutAfter(interval); Assert.True(ct.WaitHandle.WaitOne(interval), "CT Wait"); Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); - return Task.FromResult(0); })) { // Note: System.Net.Sockets does not RST the connection by default, it just FINs. // Http.Sys's disconnect notice requires a RST. using (var client = await SendHungRequestAsync("GET", address)) { - Assert.True(received.WaitOne(interval), "Receive Timeout"); + await received.Task.TimeoutAfter(interval); // Force a RST client.LingerState = new LingerOption(true, 0); } - aborted.Set(); - Assert.True(canceled.WaitOne(interval), "canceled"); + aborted.SetResult(0); + await canceled.Task.TimeoutAfter(interval); } } [ConditionalFact] public async Task Server_Abort_CallCanceled() { - TimeSpan interval = TimeSpan.FromSeconds(100); - ManualResetEvent received = new ManualResetEvent(false); - ManualResetEvent aborted = new ManualResetEvent(false); - ManualResetEvent canceled = new ManualResetEvent(false); + var interval = TimeSpan.FromSeconds(10); + var received = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var canceled = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - string address; - using (Utilities.CreateHttpServer(out address, httpContext => + using (Utilities.CreateHttpServer(out var address, async httpContext => { CancellationToken ct = httpContext.RequestAborted; Assert.True(ct.CanBeCanceled, "CanBeCanceled"); Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); - ct.Register(() => canceled.Set()); - received.Set(); + ct.Register(() => canceled.SetResult(0)); + received.SetResult(0); httpContext.Abort(); - Assert.True(canceled.WaitOne(interval), "Aborted"); + await canceled.Task.TimeoutAfter(interval); Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); - return Task.FromResult(0); })) { using (var client = await SendHungRequestAsync("GET", address)) { - Assert.True(received.WaitOne(interval), "Receive Timeout"); + await received.Task.TimeoutAfter(interval); Assert.Throws(() => client.GetStream().Read(new byte[10], 0, 10)); } } @@ -423,19 +413,18 @@ namespace Microsoft.AspNetCore.Server.HttpSys public async Task Server_MultipleStopAsyncCallsWaitForRequestsToDrain_Success() { Task responseTask; - ManualResetEvent received = new ManualResetEvent(false); - ManualResetEvent run = new ManualResetEvent(false); - string address; - using (var server = Utilities.CreateHttpServer(out address, httpContext => + var received = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var run = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + using (var server = Utilities.CreateHttpServer(out var address, async httpContext => { - received.Set(); - Assert.True(run.WaitOne(TimeSpan.FromSeconds(10))); + received.SetResult(0); + await run.Task.TimeoutAfter(TimeSpan.FromSeconds(10)); httpContext.Response.ContentLength = 11; - return httpContext.Response.WriteAsync("Hello World"); + await httpContext.Response.WriteAsync("Hello World"); })) { responseTask = SendRequestAsync(address); - Assert.True(received.WaitOne(TimeSpan.FromSeconds(10))); + await received.Task.TimeoutAfter(TimeSpan.FromSeconds(10)); var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); var stopTask1 = server.StopAsync(cts.Token); @@ -446,11 +435,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.False(stopTask2.IsCompleted); Assert.False(stopTask3.IsCompleted); - run.Set(); + run.SetResult(0); await Task.WhenAll(stopTask1, stopTask2, stopTask3).TimeoutAfter(TimeSpan.FromSeconds(10)); } - string response = await responseTask; + var response = await responseTask; Assert.Equal("Hello World", response); } @@ -458,19 +447,18 @@ namespace Microsoft.AspNetCore.Server.HttpSys public async Task Server_MultipleStopAsyncCallsCompleteOnCancellation_SameToken_Success() { Task responseTask; - ManualResetEvent received = new ManualResetEvent(false); - ManualResetEvent run = new ManualResetEvent(false); - string address; - using (var server = Utilities.CreateHttpServer(out address, httpContext => + var received = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var run = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + using (var server = Utilities.CreateHttpServer(out var address, async httpContext => { - received.Set(); - Assert.True(run.WaitOne(TimeSpan.FromSeconds(10))); + received.SetResult(0); + await run.Task.TimeoutAfter(TimeSpan.FromSeconds(10)); httpContext.Response.ContentLength = 11; - return httpContext.Response.WriteAsync("Hello World"); + await httpContext.Response.WriteAsync("Hello World"); })) { responseTask = SendRequestAsync(address); - Assert.True(received.WaitOne(TimeSpan.FromSeconds(10))); + await received.Task.TimeoutAfter(TimeSpan.FromSeconds(10)); var cts = new CancellationTokenSource(); var stopTask1 = server.StopAsync(cts.Token); @@ -485,7 +473,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys await Task.WhenAll(stopTask1, stopTask2, stopTask3).TimeoutAfter(TimeSpan.FromSeconds(10)); - run.Set(); + run.SetResult(0); string response = await responseTask; Assert.Equal("Hello World", response); @@ -496,19 +484,18 @@ namespace Microsoft.AspNetCore.Server.HttpSys public async Task Server_MultipleStopAsyncCallsCompleteOnSingleCancellation_FirstToken_Success() { Task responseTask; - ManualResetEvent received = new ManualResetEvent(false); - ManualResetEvent run = new ManualResetEvent(false); - string address; - using (var server = Utilities.CreateHttpServer(out address, httpContext => + var received = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var run = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + using (var server = Utilities.CreateHttpServer(out var address, async httpContext => { - received.Set(); - Assert.True(run.WaitOne(TimeSpan.FromSeconds(10))); + received.SetResult(0); + await run.Task.TimeoutAfter(TimeSpan.FromSeconds(10)); httpContext.Response.ContentLength = 11; - return httpContext.Response.WriteAsync("Hello World"); + await httpContext.Response.WriteAsync("Hello World"); })) { responseTask = SendRequestAsync(address); - Assert.True(received.WaitOne(TimeSpan.FromSeconds(10))); + await received.Task.TimeoutAfter(TimeSpan.FromSeconds(10)); var cts = new CancellationTokenSource(); var stopTask1 = server.StopAsync(cts.Token); @@ -523,7 +510,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys await Task.WhenAll(stopTask1, stopTask2, stopTask3).TimeoutAfter(TimeSpan.FromSeconds(10)); - run.Set(); + run.SetResult(0); string response = await responseTask; Assert.Equal("Hello World", response); @@ -534,19 +521,18 @@ namespace Microsoft.AspNetCore.Server.HttpSys public async Task Server_MultipleStopAsyncCallsCompleteOnSingleCancellation_SubsequentToken_Success() { Task responseTask; - ManualResetEvent received = new ManualResetEvent(false); - ManualResetEvent run = new ManualResetEvent(false); - string address; - using (var server = Utilities.CreateHttpServer(out address, httpContext => + var received = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var run = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + using (var server = Utilities.CreateHttpServer(out var address, async httpContext => { - received.Set(); - Assert.True(run.WaitOne(TimeSpan.FromSeconds(10))); + received.SetResult(0); + await run.Task.TimeoutAfter(TimeSpan.FromSeconds(10)); httpContext.Response.ContentLength = 11; - return httpContext.Response.WriteAsync("Hello World"); + await httpContext.Response.WriteAsync("Hello World"); })) { responseTask = SendRequestAsync(address); - Assert.True(received.WaitOne(10000)); + await received.Task.TimeoutAfter(TimeSpan.FromSeconds(10)); var cts = new CancellationTokenSource(); var stopTask1 = server.StopAsync(new CancellationTokenSource().Token); @@ -561,7 +547,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys await Task.WhenAll(stopTask1, stopTask2, stopTask3).TimeoutAfter(TimeSpan.FromSeconds(10)); - run.Set(); + run.SetResult(0); string response = await responseTask; Assert.Equal("Hello World", response); @@ -572,21 +558,20 @@ namespace Microsoft.AspNetCore.Server.HttpSys public async Task Server_DisposeContinuesPendingStopAsyncCalls() { Task responseTask; - ManualResetEvent received = new ManualResetEvent(false); - ManualResetEvent run = new ManualResetEvent(false); - string address; + var received = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var run = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); Task stopTask1; Task stopTask2; - using (var server = Utilities.CreateHttpServer(out address, httpContext => + using (var server = Utilities.CreateHttpServer(out var address, async httpContext => { - received.Set(); - Assert.True(run.WaitOne(TimeSpan.FromSeconds(10))); + received.SetResult(0); + await run.Task.TimeoutAfter(TimeSpan.FromSeconds(15)); httpContext.Response.ContentLength = 11; - return httpContext.Response.WriteAsync("Hello World"); + await httpContext.Response.WriteAsync("Hello World"); })) { responseTask = SendRequestAsync(address); - Assert.True(received.WaitOne(TimeSpan.FromSeconds(10))); + await received.Task.TimeoutAfter(TimeSpan.FromSeconds(10)); stopTask1 = server.StopAsync(new CancellationTokenSource().Token); stopTask2 = server.StopAsync(new CancellationTokenSource().Token); @@ -596,6 +581,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } await Task.WhenAll(stopTask1, stopTask2).TimeoutAfter(TimeSpan.FromSeconds(10)); + run.SetResult(0); } [ConditionalFact] diff --git a/src/Servers/HttpSys/test/FunctionalTests/Utilities.cs b/src/Servers/HttpSys/test/FunctionalTests/Utilities.cs index eeaf0faa95..bd38eafd81 100644 --- a/src/Servers/HttpSys/test/FunctionalTests/Utilities.cs +++ b/src/Servers/HttpSys/test/FunctionalTests/Utilities.cs @@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -160,37 +161,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys return server; } - internal static Task WithTimeout(this Task task) => task.WithTimeout(DefaultTimeout); + internal static Task WithTimeout(this Task task) => task.TimeoutAfter(DefaultTimeout); - internal static async Task WithTimeout(this Task task, TimeSpan timeout) - { - var completedTask = await Task.WhenAny(task, Task.Delay(timeout)); - - if (completedTask == task) - { - await task; - return; - } - else - { - throw new TimeoutException("The task has timed out."); - } - } - - 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."); - } - } + internal static Task WithTimeout(this Task task) => task.TimeoutAfter(DefaultTimeout); } } diff --git a/src/Servers/IIS/IISIntegration/test/Tests/IISMiddlewareTests.cs b/src/Servers/IIS/IISIntegration/test/Tests/IISMiddlewareTests.cs index 0898b7ae21..a0ee6a124c 100644 --- a/src/Servers/IIS/IISIntegration/test/Tests/IISMiddlewareTests.cs +++ b/src/Servers/IIS/IISIntegration/test/Tests/IISMiddlewareTests.cs @@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http.Features.Authentication; using Microsoft.AspNetCore.TestHost; +using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.DependencyInjection; using Xunit; @@ -81,8 +82,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration [InlineData("/pathBase", "/pathBase/iisintegration", "Shutdown")] public async Task MiddlewareShutsdownGivenANCMShutdown(string pathBase, string requestPath, string shutdownEvent) { - var requestExecuted = new ManualResetEvent(false); - var applicationStoppingFired = new ManualResetEvent(false); + var requestExecuted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var applicationStoppingFired = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var builder = new WebHostBuilder() .UseSetting("TOKEN", "TestToken") .UseSetting("PORT", "12345") @@ -91,11 +92,11 @@ namespace Microsoft.AspNetCore.Server.IISIntegration .Configure(app => { var appLifetime = app.ApplicationServices.GetRequiredService(); - appLifetime.ApplicationStopping.Register(() => applicationStoppingFired.Set()); + appLifetime.ApplicationStopping.Register(() => applicationStoppingFired.SetResult(0)); app.Run(context => { - requestExecuted.Set(); + requestExecuted.SetResult(0); return Task.FromResult(0); }); }); @@ -106,8 +107,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration request.Headers.TryAddWithoutValidation("MS-ASPNETCORE-EVENT", shutdownEvent); var response = await server.CreateClient().SendAsync(request); - Assert.True(applicationStoppingFired.WaitOne(TimeSpan.FromSeconds(5))); - Assert.False(requestExecuted.WaitOne(0)); + await applicationStoppingFired.Task.TimeoutAfter(TimeSpan.FromSeconds(5)); + Assert.False(requestExecuted.Task.IsCompleted); Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); } @@ -131,8 +132,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration [MemberData(nameof(InvalidShutdownMethods))] public async Task MiddlewareIgnoresShutdownGivenWrongMethod(HttpMethod method) { - var requestExecuted = new ManualResetEvent(false); - var applicationStoppingFired = new ManualResetEvent(false); + var requestExecuted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var applicationStoppingFired = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var builder = new WebHostBuilder() .UseSetting("TOKEN", "TestToken") .UseSetting("PORT", "12345") @@ -141,11 +142,11 @@ namespace Microsoft.AspNetCore.Server.IISIntegration .Configure(app => { var appLifetime = app.ApplicationServices.GetRequiredService(); - appLifetime.ApplicationStopping.Register(() => applicationStoppingFired.Set()); + appLifetime.ApplicationStopping.Register(() => applicationStoppingFired.SetResult(0)); app.Run(context => { - requestExecuted.Set(); + requestExecuted.SetResult(0); return Task.FromResult(0); }); }); @@ -156,8 +157,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration request.Headers.TryAddWithoutValidation("MS-ASPNETCORE-EVENT", "shutdown"); var response = await server.CreateClient().SendAsync(request); - Assert.False(applicationStoppingFired.WaitOne(TimeSpan.FromSeconds(1))); - Assert.True(requestExecuted.WaitOne(0)); + Assert.False(applicationStoppingFired.Task.IsCompleted); + await requestExecuted.Task.TimeoutAfter(TimeSpan.FromSeconds(1)); Assert.Equal(HttpStatusCode.OK, response.StatusCode); } @@ -167,8 +168,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration [InlineData("/path/iisintegration")] public async Task MiddlewareIgnoresShutdownGivenWrongPath(string path) { - var requestExecuted = new ManualResetEvent(false); - var applicationStoppingFired = new ManualResetEvent(false); + var requestExecuted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var applicationStoppingFired = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var builder = new WebHostBuilder() .UseSetting("TOKEN", "TestToken") .UseSetting("PORT", "12345") @@ -177,11 +178,11 @@ namespace Microsoft.AspNetCore.Server.IISIntegration .Configure(app => { var appLifetime = app.ApplicationServices.GetRequiredService(); - appLifetime.ApplicationStopping.Register(() => applicationStoppingFired.Set()); + appLifetime.ApplicationStopping.Register(() => applicationStoppingFired.SetResult(0)); app.Run(context => { - requestExecuted.Set(); + requestExecuted.SetResult(0); return Task.FromResult(0); }); }); @@ -192,8 +193,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration request.Headers.TryAddWithoutValidation("MS-ASPNETCORE-EVENT", "shutdown"); var response = await server.CreateClient().SendAsync(request); - Assert.False(applicationStoppingFired.WaitOne(TimeSpan.FromSeconds(1))); - Assert.True(requestExecuted.WaitOne(0)); + Assert.False(applicationStoppingFired.Task.IsCompleted); + await requestExecuted.Task.TimeoutAfter(TimeSpan.FromSeconds(1)); Assert.Equal(HttpStatusCode.OK, response.StatusCode); } @@ -203,8 +204,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration [InlineData(null)] public async Task MiddlewareIgnoresShutdownGivenWrongEvent(string shutdownEvent) { - var requestExecuted = new ManualResetEvent(false); - var applicationStoppingFired = new ManualResetEvent(false); + var requestExecuted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var applicationStoppingFired = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var builder = new WebHostBuilder() .UseSetting("TOKEN", "TestToken") .UseSetting("PORT", "12345") @@ -213,11 +214,11 @@ namespace Microsoft.AspNetCore.Server.IISIntegration .Configure(app => { var appLifetime = app.ApplicationServices.GetRequiredService(); - appLifetime.ApplicationStopping.Register(() => applicationStoppingFired.Set()); + appLifetime.ApplicationStopping.Register(() => applicationStoppingFired.SetResult(0)); app.Run(context => { - requestExecuted.Set(); + requestExecuted.SetResult(0); return Task.FromResult(0); }); }); @@ -228,8 +229,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration request.Headers.TryAddWithoutValidation("MS-ASPNETCORE-EVENT", shutdownEvent); var response = await server.CreateClient().SendAsync(request); - Assert.False(applicationStoppingFired.WaitOne(TimeSpan.FromSeconds(1))); - Assert.True(requestExecuted.WaitOne(0)); + Assert.False(applicationStoppingFired.Task.IsCompleted); + await requestExecuted.Task.TimeoutAfter(TimeSpan.FromSeconds(1)); Assert.Equal(HttpStatusCode.OK, response.StatusCode); } diff --git a/src/Tools/dotnet-watch/test/FileWatcherTests.cs b/src/Tools/dotnet-watch/test/FileWatcherTests.cs index 51c1895e05..6b9e8c354d 100644 --- a/src/Tools/dotnet-watch/test/FileWatcherTests.cs +++ b/src/Tools/dotnet-watch/test/FileWatcherTests.cs @@ -6,6 +6,8 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Testing; using Microsoft.DotNet.Watcher.Internal; using Xunit; using Xunit.Abstractions; @@ -19,32 +21,33 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests _output = output; } - private const int DefaultTimeout = 10 * 1000; // 10 sec + private readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(60); + private readonly TimeSpan NegativeTimeout = TimeSpan.FromSeconds(5); private readonly ITestOutputHelper _output; [Theory] [InlineData(true)] [InlineData(false)] - public void NewFile(bool usePolling) + public async Task NewFile(bool usePolling) { - UsingTempDirectory(dir => + await UsingTempDirectory(async dir => { - using (var changedEv = new ManualResetEvent(false)) using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling)) { + var changedEv = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var filesChanged = new HashSet(); watcher.OnFileChange += (_, f) => { filesChanged.Add(f); - changedEv.Set(); + changedEv.TrySetResult(0); }; watcher.EnableRaisingEvents = true; var testFileFullPath = Path.Combine(dir, "foo"); File.WriteAllText(testFileFullPath, string.Empty); - Assert.True(changedEv.WaitOne(DefaultTimeout)); + await changedEv.Task.TimeoutAfter(DefaultTimeout); Assert.Equal(testFileFullPath, filesChanged.Single()); } }); @@ -53,16 +56,16 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests [Theory] [InlineData(true)] [InlineData(false)] - public void ChangeFile(bool usePolling) + public async Task ChangeFile(bool usePolling) { - UsingTempDirectory(dir => + await UsingTempDirectory(async dir => { var testFileFullPath = Path.Combine(dir, "foo"); File.WriteAllText(testFileFullPath, string.Empty); - using (var changedEv = new ManualResetEvent(false)) using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling)) { + var changedEv = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var filesChanged = new HashSet(); EventHandler handler = null; @@ -72,7 +75,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests watcher.OnFileChange -= handler; filesChanged.Add(f); - changedEv.Set(); + changedEv.TrySetResult(0); }; watcher.OnFileChange += handler; @@ -81,10 +84,10 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests // On Unix the file write time is in 1s increments; // if we don't wait, there's a chance that the polling // watcher will not detect the change - Thread.Sleep(1000); + await Task.Delay(1000); File.WriteAllText(testFileFullPath, string.Empty); - Assert.True(changedEv.WaitOne(DefaultTimeout)); + await changedEv.Task.TimeoutAfter(DefaultTimeout); Assert.Equal(testFileFullPath, filesChanged.Single()); } }); @@ -93,18 +96,18 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests [Theory] [InlineData(true)] [InlineData(false)] - public void MoveFile(bool usePolling) + public async Task MoveFile(bool usePolling) { - UsingTempDirectory(dir => + await UsingTempDirectory(async dir => { var srcFile = Path.Combine(dir, "foo"); var dstFile = Path.Combine(dir, "foo2"); File.WriteAllText(srcFile, string.Empty); - using (var changedEv = new ManualResetEvent(false)) using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling)) { + var changedEv = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var filesChanged = new HashSet(); EventHandler handler = null; @@ -117,7 +120,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests watcher.EnableRaisingEvents = false; watcher.OnFileChange -= handler; - changedEv.Set(); + changedEv.TrySetResult(0); } }; @@ -126,7 +129,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests File.Move(srcFile, dstFile); - Assert.True(changedEv.WaitOne(DefaultTimeout)); + await changedEv.Task.TimeoutAfter(DefaultTimeout); Assert.Contains(srcFile, filesChanged); Assert.Contains(dstFile, filesChanged); } @@ -134,9 +137,9 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests } [Fact] - public void FileInSubdirectory() + public async Task FileInSubdirectory() { - UsingTempDirectory(dir => + await UsingTempDirectory(async dir => { var subdir = Path.Combine(dir, "subdir"); Directory.CreateDirectory(subdir); @@ -144,9 +147,9 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests var testFileFullPath = Path.Combine(subdir, "foo"); File.WriteAllText(testFileFullPath, string.Empty); - using (var changedEv = new ManualResetEvent(false)) using (var watcher = FileWatcherFactory.CreateWatcher(dir, true)) { + var changedEv = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var filesChanged = new HashSet(); EventHandler handler = null; @@ -158,7 +161,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests { watcher.EnableRaisingEvents = false; watcher.OnFileChange -= handler; - changedEv.Set(); + changedEv.TrySetResult(0); } }; @@ -168,10 +171,10 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests // On Unix the file write time is in 1s increments; // if we don't wait, there's a chance that the polling // watcher will not detect the change - Thread.Sleep(1000); + await Task.Delay(1000); File.WriteAllText(testFileFullPath, string.Empty); - Assert.True(changedEv.WaitOne(DefaultTimeout)); + await changedEv.Task.TimeoutAfter(DefaultTimeout); Assert.Contains(subdir, filesChanged); Assert.Contains(testFileFullPath, filesChanged); } @@ -181,14 +184,14 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests [Theory] [InlineData(true)] [InlineData(false)] - public void NoNotificationIfDisabled(bool usePolling) + public async Task NoNotificationIfDisabled(bool usePolling) { - UsingTempDirectory(dir => + await UsingTempDirectory(async dir => { using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling)) - using (var changedEv = new ManualResetEvent(false)) { - watcher.OnFileChange += (_, f) => changedEv.Set(); + var changedEv = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + watcher.OnFileChange += (_, f) => changedEv.TrySetResult(0); // Disable watcher.EnableRaisingEvents = false; @@ -198,10 +201,10 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests // On Unix the file write time is in 1s increments; // if we don't wait, there's a chance that the polling // watcher will not detect the change - Thread.Sleep(1000); + await Task.Delay(1000); File.WriteAllText(testFileFullPath, string.Empty); - Assert.False(changedEv.WaitOne(DefaultTimeout / 2)); + await Assert.ThrowsAsync(() => changedEv.Task.TimeoutAfter(NegativeTimeout)); } }); } @@ -209,37 +212,35 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests [Theory] [InlineData(true)] [InlineData(false)] - public void DisposedNoEvents(bool usePolling) + public async Task DisposedNoEvents(bool usePolling) { - UsingTempDirectory(dir => + await UsingTempDirectory(async dir => { - using (var changedEv = new ManualResetEvent(false)) + var changedEv = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling)) { - using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling)) - { - watcher.OnFileChange += (_, f) => changedEv.Set(); - watcher.EnableRaisingEvents = true; - } - - var testFileFullPath = Path.Combine(dir, "foo"); - - // On Unix the file write time is in 1s increments; - // if we don't wait, there's a chance that the polling - // watcher will not detect the change - Thread.Sleep(1000); - File.WriteAllText(testFileFullPath, string.Empty); - - Assert.False(changedEv.WaitOne(DefaultTimeout / 2)); + watcher.OnFileChange += (_, f) => changedEv.TrySetResult(0); + watcher.EnableRaisingEvents = true; } + + var testFileFullPath = Path.Combine(dir, "foo"); + + // On Unix the file write time is in 1s increments; + // if we don't wait, there's a chance that the polling + // watcher will not detect the change + await Task.Delay(1000); + File.WriteAllText(testFileFullPath, string.Empty); + + await Assert.ThrowsAsync(() => changedEv.Task.TimeoutAfter(NegativeTimeout)); }); } [Theory] [InlineData(true)] [InlineData(false)] - public void MultipleFiles(bool usePolling) + public async Task MultipleFiles(bool usePolling) { - UsingTempDirectory(dir => + await UsingTempDirectory(async dir => { File.WriteAllText(Path.Combine(dir, "foo1"), string.Empty); File.WriteAllText(Path.Combine(dir, "foo2"), string.Empty); @@ -249,9 +250,9 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests var testFileFullPath = Path.Combine(dir, "foo3"); - using (var changedEv = new ManualResetEvent(false)) using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling)) { + var changedEv = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var filesChanged = new HashSet(); EventHandler handler = null; @@ -260,7 +261,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests watcher.EnableRaisingEvents = false; watcher.OnFileChange -= handler; filesChanged.Add(f); - changedEv.Set(); + changedEv.TrySetResult(0); }; watcher.OnFileChange += handler; @@ -269,11 +270,11 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests // On Unix the file write time is in 1s increments; // if we don't wait, there's a chance that the polling // watcher will not detect the change - Thread.Sleep(1000); + await Task.Delay(1000); File.WriteAllText(testFileFullPath, string.Empty); - Assert.True(changedEv.WaitOne(DefaultTimeout)); + await changedEv.Task.TimeoutAfter(DefaultTimeout); Assert.Equal(testFileFullPath, filesChanged.Single()); } }); @@ -282,11 +283,11 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests [Theory] [InlineData(true)] [InlineData(false)] - public void MultipleTriggers(bool usePolling) + public async Task MultipleTriggers(bool usePolling) { var filesChanged = new HashSet(); - UsingTempDirectory(dir => + await UsingTempDirectory(async dir => { using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling)) { @@ -294,7 +295,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests for (var i = 0; i < 5; i++) { - AssertFileChangeRaisesEvent(dir, watcher); + await AssertFileChangeRaisesEvent(dir, watcher); } watcher.EnableRaisingEvents = false; @@ -302,55 +303,53 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests }); } - private void AssertFileChangeRaisesEvent(string directory, IFileSystemWatcher watcher) + private async Task AssertFileChangeRaisesEvent(string directory, IFileSystemWatcher watcher) { - using (var semaphoreSlim = new SemaphoreSlim(0)) + var changedEv = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var expectedPath = Path.Combine(directory, Path.GetRandomFileName()); + EventHandler handler = (object _, string f) => { - var expectedPath = Path.Combine(directory, Path.GetRandomFileName()); - EventHandler handler = (object _, string f) => - { - _output.WriteLine("File changed: " + f); - try - { - if (string.Equals(f, expectedPath, StringComparison.OrdinalIgnoreCase)) - { - semaphoreSlim.Release(); - } - } - catch (ObjectDisposedException) - { - // There's a known race condition here: - // even though we tell the watcher to stop raising events and we unsubscribe the handler - // there might be in-flight events that will still process. Since we dispose the reset - // event, this code will fail if the handler executes after Dispose happens. - } - }; - - File.AppendAllText(expectedPath, " "); - - watcher.OnFileChange += handler; + _output.WriteLine("File changed: " + f); try { - // On Unix the file write time is in 1s increments; - // if we don't wait, there's a chance that the polling - // watcher will not detect the change - Thread.Sleep(1000); - File.AppendAllText(expectedPath, " "); - Assert.True(semaphoreSlim.Wait(DefaultTimeout), "Expected a file change event for " + expectedPath); + if (string.Equals(f, expectedPath, StringComparison.OrdinalIgnoreCase)) + { + changedEv.TrySetResult(0); + } } - finally + catch (ObjectDisposedException) { - watcher.OnFileChange -= handler; + // There's a known race condition here: + // even though we tell the watcher to stop raising events and we unsubscribe the handler + // there might be in-flight events that will still process. Since we dispose the reset + // event, this code will fail if the handler executes after Dispose happens. } + }; + + File.AppendAllText(expectedPath, " "); + + watcher.OnFileChange += handler; + try + { + // On Unix the file write time is in 1s increments; + // if we don't wait, there's a chance that the polling + // watcher will not detect the change + await Task.Delay(1000); + File.AppendAllText(expectedPath, " "); + await changedEv.Task.TimeoutAfter(DefaultTimeout); + } + finally + { + watcher.OnFileChange -= handler; } } [Theory] [InlineData(true)] [InlineData(false)] - public void DeleteSubfolder(bool usePolling) + public async Task DeleteSubfolder(bool usePolling) { - UsingTempDirectory(dir => + await UsingTempDirectory(async dir => { var subdir = Path.Combine(dir, "subdir"); Directory.CreateDirectory(subdir); @@ -363,9 +362,9 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests File.WriteAllText(f2, string.Empty); File.WriteAllText(f3, string.Empty); - using (var changedEv = new AutoResetEvent(false)) using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling)) { + var changedEv = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var filesChanged = new HashSet(); EventHandler handler = null; @@ -377,7 +376,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests { watcher.EnableRaisingEvents = false; watcher.OnFileChange -= handler; - changedEv.Set(); + changedEv.TrySetResult(0); } }; @@ -386,7 +385,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests Directory.Delete(subdir, recursive: true); - Assert.True(changedEv.WaitOne(DefaultTimeout)); + await changedEv.Task.TimeoutAfter(DefaultTimeout); Assert.Contains(f1, filesChanged); Assert.Contains(f2, filesChanged); @@ -396,7 +395,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests }); } - private static void UsingTempDirectory(Action action) + private static async Task UsingTempDirectory(Func func) { var tempFolder = Path.Combine(Path.GetTempPath(), $"{nameof(FileWatcherTests)}-{Guid.NewGuid().ToString("N")}"); if (Directory.Exists(tempFolder)) @@ -408,7 +407,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests try { - action(tempFolder); + await func(tempFolder); } finally {