Clean up ManualResetEvent usage in tests (#6961)

This commit is contained in:
Chris Ross 2019-01-28 12:10:16 -08:00 committed by GitHub
parent 65ee89a71e
commit 7d4b6fccff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 378 additions and 442 deletions

View File

@ -77,18 +77,16 @@ Global
{766C394B-ABBB-4624-A071-C806C0A2CD3E}.Release|x64.Build.0 = Release|Any CPU {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.ActiveCfg = Release|Any CPU
{766C394B-ABBB-4624-A071-C806C0A2CD3E}.Release|x86.Build.0 = 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.ActiveCfg = Debug|x86
{BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Debug|Any CPU.Build.0 = Debug|Any CPU {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Debug|x64.ActiveCfg = Debug|x64
{BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Debug|x64.ActiveCfg = Debug|Any CPU {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Debug|x64.Build.0 = Debug|x64
{BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Debug|x64.Build.0 = Debug|Any CPU {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Debug|x86.ActiveCfg = Debug|x86
{BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Debug|x86.ActiveCfg = Debug|Any CPU {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Debug|x86.Build.0 = Debug|x86
{BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Debug|x86.Build.0 = Debug|Any CPU {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Release|Any CPU.ActiveCfg = Release|x86
{BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Release|Any CPU.ActiveCfg = Release|Any CPU {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Release|x64.ActiveCfg = Release|x64
{BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Release|Any CPU.Build.0 = Release|Any CPU {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Release|x64.Build.0 = Release|x64
{BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Release|x64.ActiveCfg = Release|Any CPU {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Release|x86.ActiveCfg = Release|x86
{BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Release|x64.Build.0 = Release|Any CPU {BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Release|x86.Build.0 = Release|x86
{BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Release|x86.ActiveCfg = Release|Any CPU
{BE8D7353-692B-4B5B-ADFD-32632AE758E3}.Release|x86.Build.0 = Release|Any CPU
{AE1F0124-996E-476A-9331-FB789F3D0577}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {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|Any CPU.Build.0 = Debug|Any CPU
{AE1F0124-996E-476A-9331-FB789F3D0577}.Debug|x64.ActiveCfg = Debug|Any CPU {AE1F0124-996E-476A-9331-FB789F3D0577}.Debug|x64.ActiveCfg = Debug|Any CPU

View File

@ -7,9 +7,11 @@ using System.Collections.Generic;
using System.Diagnostics.Tracing; using System.Diagnostics.Tracing;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.HostFiltering; using Microsoft.AspNetCore.HostFiltering;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -28,7 +30,7 @@ namespace Microsoft.AspNetCore.Tests
} }
[Fact] [Fact]
public void WebHostConfiguration_HostFilterOptionsAreReloadable() public async Task WebHostConfiguration_HostFilterOptionsAreReloadable()
{ {
var host = WebHost.CreateDefaultBuilder() var host = WebHost.CreateDefaultBuilder()
.Configure(app => { }) .Configure(app => { })
@ -42,15 +44,15 @@ namespace Microsoft.AspNetCore.Tests
Assert.Contains("*", options.AllowedHosts); Assert.Contains("*", options.AllowedHosts);
var changed = new ManualResetEvent(false); var changed = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
monitor.OnChange(newOptions => monitor.OnChange(newOptions =>
{ {
changed.Set(); changed.SetResult(0);
}); });
config["AllowedHosts"] = "NewHost"; config["AllowedHosts"] = "NewHost";
Assert.True(changed.WaitOne(TimeSpan.FromSeconds(10))); await changed.Task.TimeoutAfter(TimeSpan.FromSeconds(10));
options = monitor.CurrentValue; options = monitor.CurrentValue;
Assert.Contains("NewHost", options.AllowedHosts); Assert.Contains("NewHost", options.AllowedHosts);
} }

View File

@ -14,6 +14,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.TestHost; using Microsoft.AspNetCore.TestHost;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing; using Microsoft.Extensions.Logging.Testing;
@ -460,7 +461,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
[MemberData(nameof(SupportedEncodingsWithBodyLength))] [MemberData(nameof(SupportedEncodingsWithBodyLength))]
public async Task FlushHeaders_SendsHeaders_Compresses(string encoding, int expectedBodyLength) public async Task FlushHeaders_SendsHeaders_Compresses(string encoding, int expectedBodyLength)
{ {
var responseReceived = new ManualResetEvent(false); var responseReceived = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var builder = new WebHostBuilder() var builder = new WebHostBuilder()
.ConfigureServices(services => .ConfigureServices(services =>
@ -470,13 +471,13 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
.Configure(app => .Configure(app =>
{ {
app.UseResponseCompression(); app.UseResponseCompression();
app.Run(context => app.Run(async context =>
{ {
context.Response.Headers[HeaderNames.ContentMD5] = "MD5"; context.Response.Headers[HeaderNames.ContentMD5] = "MD5";
context.Response.ContentType = TextPlain; context.Response.ContentType = TextPlain;
context.Response.Body.Flush(); context.Response.Body.Flush();
Assert.True(responseReceived.WaitOne(TimeSpan.FromSeconds(3))); await responseReceived.Task.TimeoutAfter(TimeSpan.FromSeconds(3));
return context.Response.WriteAsync(new string('a', 100)); await context.Response.WriteAsync(new string('a', 100));
}); });
}); });
@ -487,7 +488,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
request.Headers.AcceptEncoding.ParseAdd(encoding); request.Headers.AcceptEncoding.ParseAdd(encoding);
var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
responseReceived.Set(); responseReceived.SetResult(0);
await response.Content.LoadIntoBufferAsync(); await response.Content.LoadIntoBufferAsync();
@ -498,7 +499,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
[MemberData(nameof(SupportedEncodingsWithBodyLength))] [MemberData(nameof(SupportedEncodingsWithBodyLength))]
public async Task FlushAsyncHeaders_SendsHeaders_Compresses(string encoding, int expectedBodyLength) public async Task FlushAsyncHeaders_SendsHeaders_Compresses(string encoding, int expectedBodyLength)
{ {
var responseReceived = new ManualResetEvent(false); var responseReceived = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var builder = new WebHostBuilder() var builder = new WebHostBuilder()
.ConfigureServices(services => .ConfigureServices(services =>
@ -513,7 +514,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
context.Response.Headers[HeaderNames.ContentMD5] = "MD5"; context.Response.Headers[HeaderNames.ContentMD5] = "MD5";
context.Response.ContentType = TextPlain; context.Response.ContentType = TextPlain;
await context.Response.Body.FlushAsync(); 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)); await context.Response.WriteAsync(new string('a', 100));
}); });
}); });
@ -525,7 +526,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
request.Headers.AcceptEncoding.ParseAdd(encoding); request.Headers.AcceptEncoding.ParseAdd(encoding);
var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
responseReceived.Set(); responseReceived.SetResult(0);
await response.Content.LoadIntoBufferAsync(); await response.Content.LoadIntoBufferAsync();
@ -536,7 +537,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
[MemberData(nameof(SupportedEncodings))] [MemberData(nameof(SupportedEncodings))]
public async Task FlushBody_CompressesAndFlushes(string encoding) public async Task FlushBody_CompressesAndFlushes(string encoding)
{ {
var responseReceived = new ManualResetEvent(false); var responseReceived = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var builder = new WebHostBuilder() var builder = new WebHostBuilder()
.ConfigureServices(services => .ConfigureServices(services =>
@ -546,7 +547,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
.Configure(app => .Configure(app =>
{ {
app.UseResponseCompression(); app.UseResponseCompression();
app.Run(context => app.Run(async context =>
{ {
var feature = context.Features.Get<IHttpBodyControlFeature>(); var feature = context.Features.Get<IHttpBodyControlFeature>();
if (feature != null) if (feature != null)
@ -558,9 +559,8 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
context.Response.ContentType = TextPlain; context.Response.ContentType = TextPlain;
context.Response.Body.Write(new byte[10], 0, 10); context.Response.Body.Write(new byte[10], 0, 10);
context.Response.Body.Flush(); 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); 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); var read = await body.ReadAsync(new byte[100], 0, 100);
Assert.True(read > 0); Assert.True(read > 0);
responseReceived.Set(); responseReceived.SetResult(0);
read = await body.ReadAsync(new byte[100], 0, 100); read = await body.ReadAsync(new byte[100], 0, 100);
Assert.True(read > 0); Assert.True(read > 0);
@ -589,7 +589,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
[MemberData(nameof(SupportedEncodings))] [MemberData(nameof(SupportedEncodings))]
public async Task FlushAsyncBody_CompressesAndFlushes(string encoding) public async Task FlushAsyncBody_CompressesAndFlushes(string encoding)
{ {
var responseReceived = new ManualResetEvent(false); var responseReceived = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var builder = new WebHostBuilder() var builder = new WebHostBuilder()
.ConfigureServices(services => .ConfigureServices(services =>
@ -605,7 +605,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
context.Response.ContentType = TextPlain; context.Response.ContentType = TextPlain;
await context.Response.WriteAsync(new string('a', 10)); await context.Response.WriteAsync(new string('a', 10));
await context.Response.Body.FlushAsync(); 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)); 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); var read = await body.ReadAsync(new byte[100], 0, 100);
Assert.True(read > 0); Assert.True(read > 0);
responseReceived.Set(); responseReceived.SetResult(0);
read = await body.ReadAsync(new byte[100], 0, 100); read = await body.ReadAsync(new byte[100], 0, 100);
Assert.True(read > 0); Assert.True(read > 0);
@ -637,11 +637,11 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
{ {
var responseReceived = new[] var responseReceived = new[]
{ {
new ManualResetEvent(false), new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously),
new ManualResetEvent(false), new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously),
new ManualResetEvent(false), new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously),
new ManualResetEvent(false), new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously),
new ManualResetEvent(false), new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously),
}; };
var builder = new WebHostBuilder() var builder = new WebHostBuilder()
@ -652,7 +652,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
.Configure(app => .Configure(app =>
{ {
app.UseResponseCompression(); app.UseResponseCompression();
app.Run(context => app.Run(async context =>
{ {
context.Response.Headers[HeaderNames.ContentMD5] = "MD5"; context.Response.Headers[HeaderNames.ContentMD5] = "MD5";
context.Response.ContentType = TextPlain; 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.Write(new byte[1], 0, 1);
context.Response.Body.Flush(); 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); var read = await body.ReadAsync(new byte[100], 0, 100);
Assert.True(read > 0); Assert.True(read > 0);
signal.Set(); signal.SetResult(0);
} }
} }
@ -701,11 +700,11 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
{ {
var responseReceived = new[] var responseReceived = new[]
{ {
new ManualResetEvent(false), new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously),
new ManualResetEvent(false), new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously),
new ManualResetEvent(false), new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously),
new ManualResetEvent(false), new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously),
new ManualResetEvent(false), new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously),
}; };
var builder = new WebHostBuilder() var builder = new WebHostBuilder()
@ -726,7 +725,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
{ {
await context.Response.WriteAsync("a"); await context.Response.WriteAsync("a");
await context.Response.Body.FlushAsync(); 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); var read = await body.ReadAsync(new byte[100], 0, 100);
Assert.True(read > 0); Assert.True(read > 0);
signal.Set(); signal.SetResult(0);
} }
} }
@ -918,7 +917,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
[MemberData(nameof(SupportedEncodings))] [MemberData(nameof(SupportedEncodings))]
public async Task Dispose_SyncWriteOrFlushNotCalled(string encoding) public async Task Dispose_SyncWriteOrFlushNotCalled(string encoding)
{ {
var responseReceived = new ManualResetEvent(false); var responseReceived = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var builder = new WebHostBuilder() var builder = new WebHostBuilder()
.ConfigureServices(services => .ConfigureServices(services =>
@ -939,7 +938,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
context.Response.ContentType = TextPlain; context.Response.ContentType = TextPlain;
await context.Response.WriteAsync(new string('a', 10)); await context.Response.WriteAsync(new string('a', 10));
await context.Response.Body.FlushAsync(); 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)); 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); var read = await body.ReadAsync(new byte[100], 0, 100);
Assert.True(read > 0); Assert.True(read > 0);
responseReceived.Set(); responseReceived.SetResult(0);
read = await body.ReadAsync(new byte[100], 0, 100); read = await body.ReadAsync(new byte[100], 0, 100);
Assert.True(read > 0); Assert.True(read > 0);

View File

@ -16,6 +16,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Server.IntegrationTesting; using Microsoft.AspNetCore.Server.IntegrationTesting;
using Microsoft.AspNetCore.Server.IntegrationTesting.Common; using Microsoft.AspNetCore.Server.IntegrationTesting.Common;
using Microsoft.AspNetCore.Testing;
using Microsoft.AspNetCore.Testing.xunit; using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Testing; using Microsoft.Extensions.Logging.Testing;
@ -164,25 +165,25 @@ namespace Microsoft.AspNetCore.StaticFiles
}; };
[Fact] [Fact]
public void ClientDisconnect_Kestrel_NoWriteExceptionThrown() public Task ClientDisconnect_Kestrel_NoWriteExceptionThrown()
{ {
ClientDisconnect_NoWriteExceptionThrown(ServerType.Kestrel); return ClientDisconnect_NoWriteExceptionThrown(ServerType.Kestrel);
} }
[ConditionalFact] [ConditionalFact]
[OSSkipCondition(OperatingSystems.Linux)] [OSSkipCondition(OperatingSystems.Linux)]
[OSSkipCondition(OperatingSystems.MacOSX)] [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 interval = TimeSpan.FromSeconds(15);
var requestReceived = new ManualResetEvent(false); var requestReceived = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var requestCancelled = new ManualResetEvent(false); var requestCancelled = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var responseComplete = new ManualResetEvent(false); var responseComplete = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
Exception exception = null; Exception exception = null;
var builder = new WebHostBuilder() var builder = new WebHostBuilder()
.ConfigureServices(services => services.AddSingleton(LoggerFactory)) .ConfigureServices(services => services.AddSingleton(LoggerFactory))
@ -193,8 +194,8 @@ namespace Microsoft.AspNetCore.StaticFiles
{ {
try try
{ {
requestReceived.Set(); requestReceived.SetResult(0);
Assert.True(requestCancelled.WaitOne(interval), "not cancelled"); await requestCancelled.Task.TimeoutAfter(interval);
Assert.True(context.RequestAborted.WaitHandle.WaitOne(interval), "not aborted"); Assert.True(context.RequestAborted.WaitHandle.WaitOne(interval), "not aborted");
await next(); await next();
} }
@ -202,7 +203,7 @@ namespace Microsoft.AspNetCore.StaticFiles
{ {
exception = ex; exception = ex;
} }
responseComplete.Set(); responseComplete.SetResult(0);
}); });
app.UseStaticFiles(); app.UseStaticFiles();
}); });
@ -220,13 +221,13 @@ namespace Microsoft.AspNetCore.StaticFiles
{ {
// We don't use HttpClient here because it's disconnect behavior varies across platforms. // We don't use HttpClient here because it's disconnect behavior varies across platforms.
var socket = SendSocketRequestAsync(server.GetAddress(), "/TestDocument1MB.txt"); 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.LingerState = new LingerOption(true, 0);
socket.Dispose(); socket.Dispose();
requestCancelled.Set(); requestCancelled.SetResult(0);
Assert.True(responseComplete.WaitOne(interval), "not completed"); await responseComplete.Task.TimeoutAfter(interval);
Assert.Null(exception); Assert.Null(exception);
} }
} }

View File

@ -17,6 +17,7 @@ using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Internal; using Microsoft.Extensions.Internal;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
@ -545,9 +546,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
// Arrange // Arrange
var id = "unique-id"; var id = "unique-id";
var childContent = "some-content"; var childContent = "some-content";
var resetEvent1 = new ManualResetEvent(false); var event1 = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var resetEvent2 = new ManualResetEvent(false); var event2 = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var resetEvent3 = new ManualResetEvent(false); var event3 = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var calls = 0; var calls = 0;
var cache = new MemoryCache(new MemoryCacheOptions()); var cache = new MemoryCache(new MemoryCacheOptions());
@ -560,7 +561,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
getChildContentAsync: (useCachedResult, encoder) => getChildContentAsync: (useCachedResult, encoder) =>
{ {
calls++; calls++;
resetEvent2.Set(); event2.SetResult(0);
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetHtmlContent(childContent); tagHelperContent.SetHtmlContent(childContent);
@ -570,14 +571,14 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
var tagHelperOutput2 = new TagHelperOutput( var tagHelperOutput2 = new TagHelperOutput(
"cache", "cache",
new TagHelperAttributeList(), new TagHelperAttributeList(),
getChildContentAsync: (useCachedResult, encoder) => getChildContentAsync: async (useCachedResult, encoder) =>
{ {
calls++; calls++;
resetEvent3.WaitOne(5000); await event3.Task.TimeoutAfter(TimeSpan.FromSeconds(5));
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetHtmlContent(childContent); tagHelperContent.SetHtmlContent(childContent);
return Task.FromResult<TagHelperContent>(tagHelperContent); return tagHelperContent;
}); });
var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()) var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder())
@ -596,18 +597,18 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
var task1 = Task.Run(async () => var task1 = Task.Run(async () =>
{ {
resetEvent1.WaitOne(5000); await event1.Task.TimeoutAfter(TimeSpan.FromSeconds(5));
await cacheTagHelper1.ProcessAsync(tagHelperContext1, tagHelperOutput1); await cacheTagHelper1.ProcessAsync(tagHelperContext1, tagHelperOutput1);
resetEvent3.Set(); event3.SetResult(0);
}); });
var task2 = Task.Run(async () => var task2 = Task.Run(async () =>
{ {
resetEvent2.WaitOne(5000); await event2.Task.TimeoutAfter(TimeSpan.FromSeconds(5));
await cacheTagHelper2.ProcessAsync(tagHelperContext1, tagHelperOutput2); await cacheTagHelper2.ProcessAsync(tagHelperContext1, tagHelperOutput2);
}); });
resetEvent1.Set(); event1.SetResult(0);
await Task.WhenAll(task1, task2); await Task.WhenAll(task1, task2);
// Assert // Assert
@ -630,9 +631,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
// Arrange // Arrange
var id = "unique-id"; var id = "unique-id";
var childContent = "some-content"; var childContent = "some-content";
var resetEvent1 = new ManualResetEvent(false); var event1 = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var resetEvent2 = new ManualResetEvent(false); var event2 = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var resetEvent3 = new ManualResetEvent(false); var event3 = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var calls = 0; var calls = 0;
var cache = new MemoryCache(new MemoryCacheOptions()); var cache = new MemoryCache(new MemoryCacheOptions());
@ -645,7 +646,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
getChildContentAsync: (useCachedResult, encoder) => getChildContentAsync: (useCachedResult, encoder) =>
{ {
calls++; calls++;
resetEvent2.Set(); event2.SetResult(0);
throw new Exception(); throw new Exception();
}); });
@ -653,14 +654,14 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
var tagHelperOutput2 = new TagHelperOutput( var tagHelperOutput2 = new TagHelperOutput(
"cache", "cache",
new TagHelperAttributeList(), new TagHelperAttributeList(),
getChildContentAsync: (useCachedResult, encoder) => getChildContentAsync: async (useCachedResult, encoder) =>
{ {
calls++; calls++;
resetEvent3.WaitOne(5000); await event3.Task.TimeoutAfter(TimeSpan.FromSeconds(5));
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetHtmlContent(childContent); tagHelperContent.SetHtmlContent(childContent);
return Task.FromResult<TagHelperContent>(tagHelperContent); return tagHelperContent;
}); });
var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()) var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder())
@ -679,18 +680,18 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
var task1 = Task.Run(async () => var task1 = Task.Run(async () =>
{ {
resetEvent1.WaitOne(5000); await event1.Task.TimeoutAfter(TimeSpan.FromSeconds(5));
await Assert.ThrowsAsync<Exception>(() => cacheTagHelper1.ProcessAsync(tagHelperContext1, tagHelperOutput1)); await Assert.ThrowsAsync<Exception>(() => cacheTagHelper1.ProcessAsync(tagHelperContext1, tagHelperOutput1));
resetEvent3.Set(); event3.SetResult(0);
}); });
var task2 = Task.Run(async () => var task2 = Task.Run(async () =>
{ {
resetEvent2.WaitOne(5000); await event2.Task.TimeoutAfter(TimeSpan.FromSeconds(5));
await cacheTagHelper2.ProcessAsync(tagHelperContext2, tagHelperOutput2); await cacheTagHelper2.ProcessAsync(tagHelperContext2, tagHelperOutput2);
}); });
resetEvent1.Set(); event1.SetResult(0);
await Task.WhenAll(task1, task2); await Task.WhenAll(task1, task2);
// Assert // Assert

View File

@ -17,6 +17,7 @@ using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Internal; using Microsoft.Extensions.Internal;
@ -538,9 +539,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
{ {
// Arrange // Arrange
var childContent = "some-content"; var childContent = "some-content";
var resetEvent1 = new ManualResetEvent(false); var event1 = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var resetEvent2 = new ManualResetEvent(false); var event2 = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var resetEvent3 = new ManualResetEvent(false); var event3 = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var calls = 0; var calls = 0;
var formatter = GetFormatter(); var formatter = GetFormatter();
var storage = GetStorage(); var storage = GetStorage();
@ -559,7 +560,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
getChildContentAsync: (useCachedResult, encoder) => getChildContentAsync: (useCachedResult, encoder) =>
{ {
calls++; calls++;
resetEvent2.Set(); event2.SetResult(0);
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetHtmlContent(childContent); tagHelperContent.SetHtmlContent(childContent);
@ -569,14 +570,14 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
var tagHelperOutput2 = new TagHelperOutput( var tagHelperOutput2 = new TagHelperOutput(
"distributed-cache", "distributed-cache",
new TagHelperAttributeList(), new TagHelperAttributeList(),
getChildContentAsync: (useCachedResult, encoder) => getChildContentAsync: async (useCachedResult, encoder) =>
{ {
calls++; calls++;
resetEvent3.WaitOne(5000); await event3.Task.TimeoutAfter(TimeSpan.FromSeconds(5));
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetHtmlContent(childContent); tagHelperContent.SetHtmlContent(childContent);
return Task.FromResult<TagHelperContent>(tagHelperContent); return tagHelperContent;
}); });
var cacheTagHelper1 = new DistributedCacheTagHelper( var cacheTagHelper1 = new DistributedCacheTagHelper(
@ -599,18 +600,18 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
var task1 = Task.Run(async () => var task1 = Task.Run(async () =>
{ {
resetEvent1.WaitOne(5000); await event1.Task.TimeoutAfter(TimeSpan.FromSeconds(5));
await cacheTagHelper1.ProcessAsync(tagHelperContext1, tagHelperOutput1); await cacheTagHelper1.ProcessAsync(tagHelperContext1, tagHelperOutput1);
resetEvent3.Set(); event3.SetResult(0);
}); });
var task2 = Task.Run(async () => var task2 = Task.Run(async () =>
{ {
resetEvent2.WaitOne(5000); await event2.Task.TimeoutAfter(TimeSpan.FromSeconds(5));
await cacheTagHelper2.ProcessAsync(tagHelperContext1, tagHelperOutput2); await cacheTagHelper2.ProcessAsync(tagHelperContext1, tagHelperOutput2);
}); });
resetEvent1.Set(); event1.SetResult(0);
await Task.WhenAll(task1, task2); await Task.WhenAll(task1, task2);
// Assert // Assert
@ -632,9 +633,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
{ {
// Arrange // Arrange
var childContent = "some-content"; var childContent = "some-content";
var resetEvent1 = new ManualResetEvent(false); var event1 = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var resetEvent2 = new ManualResetEvent(false); var event2 = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var resetEvent3 = new ManualResetEvent(false); var event3 = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var calls = 0; var calls = 0;
var formatter = GetFormatter(); var formatter = GetFormatter();
var storage = GetStorage(); var storage = GetStorage();
@ -653,7 +654,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
getChildContentAsync: (useCachedResult, encoder) => getChildContentAsync: (useCachedResult, encoder) =>
{ {
calls++; calls++;
resetEvent2.Set(); event2.SetResult(0);
throw new Exception(); throw new Exception();
}); });
@ -661,14 +662,14 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
var tagHelperOutput2 = new TagHelperOutput( var tagHelperOutput2 = new TagHelperOutput(
"distributed-cache", "distributed-cache",
new TagHelperAttributeList(), new TagHelperAttributeList(),
getChildContentAsync: (useCachedResult, encoder) => getChildContentAsync: async (useCachedResult, encoder) =>
{ {
calls++; calls++;
resetEvent3.WaitOne(5000); await event3.Task.TimeoutAfter(TimeSpan.FromSeconds(5));
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetHtmlContent(childContent); tagHelperContent.SetHtmlContent(childContent);
return Task.FromResult<TagHelperContent>(tagHelperContent); return tagHelperContent;
}); });
var cacheTagHelper1 = new DistributedCacheTagHelper( var cacheTagHelper1 = new DistributedCacheTagHelper(
@ -691,18 +692,18 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
var task1 = Task.Run(async () => var task1 = Task.Run(async () =>
{ {
resetEvent1.WaitOne(5000); await event1.Task.TimeoutAfter(TimeSpan.FromSeconds(5));
await Assert.ThrowsAsync<Exception>(() => cacheTagHelper1.ProcessAsync(tagHelperContext1, tagHelperOutput1)); await Assert.ThrowsAsync<Exception>(() => cacheTagHelper1.ProcessAsync(tagHelperContext1, tagHelperOutput1));
resetEvent3.Set(); event3.SetResult(0);
}); });
var task2 = Task.Run(async () => var task2 = Task.Run(async () =>
{ {
resetEvent2.WaitOne(5000); await event2.Task.TimeoutAfter(TimeSpan.FromSeconds(5));
await cacheTagHelper2.ProcessAsync(tagHelperContext2, tagHelperOutput2); await cacheTagHelper2.ProcessAsync(tagHelperContext2, tagHelperOutput2);
}); });
resetEvent1.Set(); event1.SetResult(0);
await Task.WhenAll(task1, task2); await Task.WhenAll(task1, task2);
// Assert // Assert

View File

@ -8,6 +8,7 @@ using System.Net.Http;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Testing;
using Microsoft.AspNetCore.Testing.xunit; using Microsoft.AspNetCore.Testing.xunit;
using Xunit; using Xunit;
@ -167,7 +168,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
[ConditionalFact] [ConditionalFact]
public async Task AuthTypes_AccessUserInOnCompleted_Success() public async Task AuthTypes_AccessUserInOnCompleted_Success()
{ {
var completed = new ManualResetEvent(false); var completed = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
string userName = null; string userName = null;
var authTypes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM; var authTypes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM;
using (var server = Utilities.CreateDynamicHost(authTypes, DenyAnoymous, out var address, httpContext => using (var server = Utilities.CreateDynamicHost(authTypes, DenyAnoymous, out var address, httpContext =>
@ -178,7 +179,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
httpContext.Response.OnCompleted(() => httpContext.Response.OnCompleted(() =>
{ {
userName = httpContext.User.Identity.Name; userName = httpContext.User.Identity.Name;
completed.Set(); completed.SetResult(0);
return Task.FromResult(0); return Task.FromResult(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); var response = await SendRequestAsync(address, useDefaultCredentials: true);
Assert.Equal(HttpStatusCode.OK, response.StatusCode); 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)); Assert.False(string.IsNullOrEmpty(userName));
} }
} }

View File

@ -9,6 +9,7 @@ using System.Net.Sockets;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Testing;
using Microsoft.AspNetCore.Testing.xunit; using Microsoft.AspNetCore.Testing.xunit;
using Xunit; using Xunit;
@ -20,7 +21,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener
public async Task Server_TokenRegisteredAfterClientDisconnects_CallCanceled() public async Task Server_TokenRegisteredAfterClientDisconnects_CallCanceled()
{ {
var interval = TimeSpan.FromSeconds(1); var interval = TimeSpan.FromSeconds(1);
var canceled = new ManualResetEvent(false); var canceled = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
string address; string address;
using (var server = Utilities.CreateHttpServer(out address)) using (var server = Utilities.CreateHttpServer(out address))
@ -36,11 +37,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener
var ct = context.DisconnectToken; var ct = context.DisconnectToken;
Assert.True(ct.CanBeCanceled, "CanBeCanceled"); Assert.True(ct.CanBeCanceled, "CanBeCanceled");
ct.Register(() => canceled.Set()); ct.Register(() => canceled.SetResult(0));
Assert.True(ct.WaitHandle.WaitOne(interval)); Assert.True(ct.WaitHandle.WaitOne(interval));
Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); Assert.True(ct.IsCancellationRequested, "IsCancellationRequested");
Assert.True(canceled.WaitOne(interval), "canceled"); await canceled.Task.TimeoutAfter(interval);
context.Dispose(); context.Dispose();
} }
@ -51,7 +52,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener
public async Task Server_TokenRegisteredAfterResponseSent_Success() public async Task Server_TokenRegisteredAfterResponseSent_Success()
{ {
var interval = TimeSpan.FromSeconds(1); var interval = TimeSpan.FromSeconds(1);
var canceled = new ManualResetEvent(false); var canceled = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
string address; string address;
using (var server = Utilities.CreateHttpServer(out address)) using (var server = Utilities.CreateHttpServer(out address))
@ -69,11 +70,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener
var ct = context.DisconnectToken; var ct = context.DisconnectToken;
Assert.False(ct.CanBeCanceled, "CanBeCanceled"); Assert.False(ct.CanBeCanceled, "CanBeCanceled");
ct.Register(() => canceled.Set()); ct.Register(() => canceled.SetResult(0));
Assert.False(ct.WaitHandle.WaitOne(interval)); Assert.False(ct.WaitHandle.WaitOne(interval));
Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); 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() public async Task Server_ConnectionCloseHeader_CancellationTokenFires()
{ {
var interval = TimeSpan.FromSeconds(1); var interval = TimeSpan.FromSeconds(1);
var canceled = new ManualResetEvent(false); var canceled = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
string address; string address;
using (var server = Utilities.CreateHttpServer(out address)) using (var server = Utilities.CreateHttpServer(out address))
@ -93,7 +94,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener
var ct = context.DisconnectToken; var ct = context.DisconnectToken;
Assert.True(ct.CanBeCanceled, "CanBeCanceled"); Assert.True(ct.CanBeCanceled, "CanBeCanceled");
Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); Assert.False(ct.IsCancellationRequested, "IsCancellationRequested");
ct.Register(() => canceled.Set()); ct.Register(() => canceled.SetResult(0));
context.Response.Headers["Connection"] = "close"; context.Response.Headers["Connection"] = "close";
@ -102,7 +103,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener
await writer.WriteAsync("Hello World"); await writer.WriteAsync("Hello World");
await writer.FlushAsync(); await writer.FlushAsync();
Assert.True(canceled.WaitOne(interval), "Disconnected"); await canceled.Task.TimeoutAfter(interval);
Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); Assert.True(ct.IsCancellationRequested, "IsCancellationRequested");
var response = await responseTask; var response = await responseTask;

View File

@ -10,6 +10,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Testing;
using Microsoft.AspNetCore.Testing.xunit; using Microsoft.AspNetCore.Testing.xunit;
using Xunit; using Xunit;
@ -104,25 +105,20 @@ namespace Microsoft.AspNetCore.Server.HttpSys
[OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)]
public async Task OpaqueUpgrade_GetUpgrade_Success() public async Task OpaqueUpgrade_GetUpgrade_Success()
{ {
ManualResetEvent waitHandle = new ManualResetEvent(false); var upgraded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
bool? upgraded = null; using (Utilities.CreateHttpServer(out var address, async httpContext =>
string address;
using (Utilities.CreateHttpServer(out address, async httpContext =>
{ {
httpContext.Response.Headers["Upgrade"] = "websocket"; // Win8.1 blocks anything but WebSockets httpContext.Response.Headers["Upgrade"] = "websocket"; // Win8.1 blocks anything but WebSockets
var opaqueFeature = httpContext.Features.Get<IHttpUpgradeFeature>(); var opaqueFeature = httpContext.Features.Get<IHttpUpgradeFeature>();
Assert.NotNull(opaqueFeature); Assert.NotNull(opaqueFeature);
Assert.True(opaqueFeature.IsUpgradableRequest); Assert.True(opaqueFeature.IsUpgradableRequest);
await opaqueFeature.UpgradeAsync(); await opaqueFeature.UpgradeAsync();
upgraded = true; upgraded.SetResult(true);
waitHandle.Set();
})) }))
{ {
using (Stream stream = await SendOpaqueRequestAsync("GET", address)) using (Stream stream = await SendOpaqueRequestAsync("GET", address))
{ {
Assert.True(waitHandle.WaitOne(TimeSpan.FromSeconds(1)), "Timed out"); Assert.True(await upgraded.Task.TimeoutAfter(TimeSpan.FromSeconds(1)));
Assert.True(upgraded.HasValue, "Upgraded not set");
Assert.True(upgraded.Value, "Upgrade failed");
} }
} }
} }
@ -131,10 +127,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys
[OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)]
public async Task OpaqueUpgrade_GetUpgrade_NotAffectedByMaxRequestBodyLimit() public async Task OpaqueUpgrade_GetUpgrade_NotAffectedByMaxRequestBodyLimit()
{ {
ManualResetEvent waitHandle = new ManualResetEvent(false); var upgraded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
bool? upgraded = null; using (Utilities.CreateHttpServer(out var address, async httpContext =>
string address;
using (Utilities.CreateHttpServer(out address, async httpContext =>
{ {
var feature = httpContext.Features.Get<IHttpMaxRequestBodySizeFeature>(); var feature = httpContext.Features.Get<IHttpMaxRequestBodySizeFeature>();
Assert.NotNull(feature); Assert.NotNull(feature);
@ -150,16 +144,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys
Assert.Null(feature.MaxRequestBodySize); Assert.Null(feature.MaxRequestBodySize);
Assert.Throws<InvalidOperationException>(() => feature.MaxRequestBodySize = 12); Assert.Throws<InvalidOperationException>(() => feature.MaxRequestBodySize = 12);
Assert.Equal(15, await stream.ReadAsync(new byte[15], 0, 15)); Assert.Equal(15, await stream.ReadAsync(new byte[15], 0, 15));
upgraded = true; upgraded.SetResult(true);
waitHandle.Set();
}, options => options.MaxRequestBodySize = 10)) }, options => options.MaxRequestBodySize = 10))
{ {
using (Stream stream = await SendOpaqueRequestAsync("GET", address)) using (Stream stream = await SendOpaqueRequestAsync("GET", address))
{ {
stream.Write(new byte[15], 0, 15); stream.Write(new byte[15], 0, 15);
Assert.True(waitHandle.WaitOne(TimeSpan.FromSeconds(10)), "Timed out"); Assert.True(await upgraded.Task.TimeoutAfter(TimeSpan.FromSeconds(10)));
Assert.True(upgraded.HasValue, "Upgraded not set");
Assert.True(upgraded.Value, "Upgrade failed");
} }
} }
} }
@ -169,10 +160,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys
public async Task OpaqueUpgrade_WithOnStarting_CallbackCalled() public async Task OpaqueUpgrade_WithOnStarting_CallbackCalled()
{ {
var callbackCalled = false; var callbackCalled = false;
var waitHandle = new ManualResetEvent(false); var upgraded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
bool? upgraded = null; using (Utilities.CreateHttpServer(out var address, async httpContext =>
string address;
using (Utilities.CreateHttpServer(out address, async httpContext =>
{ {
httpContext.Response.OnStarting(_ => httpContext.Response.OnStarting(_ =>
{ {
@ -184,15 +173,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys
Assert.NotNull(opaqueFeature); Assert.NotNull(opaqueFeature);
Assert.True(opaqueFeature.IsUpgradableRequest); Assert.True(opaqueFeature.IsUpgradableRequest);
await opaqueFeature.UpgradeAsync(); await opaqueFeature.UpgradeAsync();
upgraded = true; upgraded.SetResult(true);
waitHandle.Set();
})) }))
{ {
using (Stream stream = await SendOpaqueRequestAsync("GET", address)) using (Stream stream = await SendOpaqueRequestAsync("GET", address))
{ {
Assert.True(waitHandle.WaitOne(TimeSpan.FromSeconds(1)), "Timed out"); Assert.True(await upgraded.Task.TimeoutAfter(TimeSpan.FromSeconds(1)));
Assert.True(upgraded.HasValue, "Upgraded not set");
Assert.True(upgraded.Value, "Upgrade failed");
Assert.True(callbackCalled, "Callback not called"); Assert.True(callbackCalled, "Callback not called");
} }
} }

View File

@ -10,6 +10,7 @@ using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Testing;
using Microsoft.AspNetCore.Testing.xunit; using Microsoft.AspNetCore.Testing.xunit;
using Xunit; using Xunit;
@ -157,10 +158,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys
[ConditionalFact] [ConditionalFact]
public async Task ResponseBody_WriteContentLengthExtraWritten_Throws() public async Task ResponseBody_WriteContentLengthExtraWritten_Throws()
{ {
var waitHandle = new ManualResetEvent(false); var requestThrew = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
bool? appThrew = null; using (Utilities.CreateHttpServer(out var address, httpContext =>
string address;
using (Utilities.CreateHttpServer(out address, httpContext =>
{ {
try try
{ {
@ -168,13 +167,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys
httpContext.Response.Headers["Content-lenGth"] = " 10 "; httpContext.Response.Headers["Content-lenGth"] = " 10 ";
httpContext.Response.Body.Write(new byte[10], 0, 10); httpContext.Response.Body.Write(new byte[10], 0, 10);
httpContext.Response.Body.Write(new byte[9], 0, 9); httpContext.Response.Body.Write(new byte[9], 0, 9);
appThrew = false; requestThrew.SetResult(false);
} }
catch (Exception) catch (Exception)
{ {
appThrew = true; requestThrew.SetResult(true);
} }
waitHandle.Set();
return Task.FromResult(0); return Task.FromResult(0);
})) }))
{ {
@ -188,9 +186,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
Assert.Null(response.Headers.TransferEncodingChunked); Assert.Null(response.Headers.TransferEncodingChunked);
Assert.Equal(new byte[10], await response.Content.ReadAsByteArrayAsync()); Assert.Equal(new byte[10], await response.Content.ReadAsByteArrayAsync());
Assert.True(waitHandle.WaitOne(100)); Assert.True(await requestThrew.Task.TimeoutAfter(TimeSpan.FromSeconds(10)));
Assert.True(appThrew.HasValue, "appThrew.HasValue");
Assert.True(appThrew.Value, "appThrew.Value");
} }
} }

View File

@ -12,6 +12,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Testing;
using Microsoft.AspNetCore.Testing.xunit; using Microsoft.AspNetCore.Testing.xunit;
using Xunit; using Xunit;
@ -74,34 +75,26 @@ namespace Microsoft.AspNetCore.Server.HttpSys
[ConditionalFact] [ConditionalFact]
public async Task ResponseSendFile_MissingFile_Throws() public async Task ResponseSendFile_MissingFile_Throws()
{ {
var waitHandle = new ManualResetEvent(false); var appThrew = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
bool? appThrew = null; using (Utilities.CreateHttpServer(out var address, httpContext =>
string address;
using (Utilities.CreateHttpServer(out address, httpContext =>
{ {
var sendFile = httpContext.Features.Get<IHttpSendFileFeature>(); var sendFile = httpContext.Features.Get<IHttpSendFileFeature>();
try try
{ {
sendFile.SendFileAsync(string.Empty, 0, null, CancellationToken.None).Wait(); sendFile.SendFileAsync(string.Empty, 0, null, CancellationToken.None).Wait();
appThrew = false; appThrew.SetResult(false);
} }
catch (Exception) catch (Exception)
{ {
appThrew = true; appThrew.SetResult(true);
throw; throw;
} }
finally
{
waitHandle.Set();
}
return Task.FromResult(0); return Task.FromResult(0);
})) }))
{ {
HttpResponseMessage response = await SendRequestAsync(address); HttpResponseMessage response = await SendRequestAsync(address);
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
Assert.True(waitHandle.WaitOne(100)); Assert.True(await appThrew.Task.TimeoutAfter(TimeSpan.FromSeconds(10)));
Assert.True(appThrew.HasValue, "appThrew.HasValue");
Assert.True(appThrew.Value, "appThrew.Value");
} }
} }

View File

@ -8,6 +8,7 @@ using System.Net.Http;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Testing;
using Microsoft.AspNetCore.Testing.xunit; using Microsoft.AspNetCore.Testing.xunit;
using Xunit; using Xunit;
@ -123,21 +124,21 @@ namespace Microsoft.AspNetCore.Server.HttpSys
[ConditionalFact] [ConditionalFact]
public async Task Response_Empty_CallsOnStartingAndOnCompleted() public async Task Response_Empty_CallsOnStartingAndOnCompleted()
{ {
var onStartingCalled = new ManualResetEvent(false); var onStartingCalled = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var onCompletedCalled = new ManualResetEvent(false); var onCompletedCalled = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
string address;
using (Utilities.CreateHttpServer(out address, httpContext => using (Utilities.CreateHttpServer(out var address, httpContext =>
{ {
httpContext.Response.OnStarting(state => httpContext.Response.OnStarting(state =>
{ {
Assert.Same(state, httpContext); Assert.Same(state, httpContext);
onStartingCalled.Set(); onStartingCalled.SetResult(0);
return Task.FromResult(0); return Task.FromResult(0);
}, httpContext); }, httpContext);
httpContext.Response.OnCompleted(state => httpContext.Response.OnCompleted(state =>
{ {
Assert.Same(state, httpContext); Assert.Same(state, httpContext);
onCompletedCalled.Set(); onCompletedCalled.SetResult(0);
return Task.FromResult(0); return Task.FromResult(0);
}, httpContext); }, httpContext);
return Task.FromResult(0); return Task.FromResult(0);
@ -145,29 +146,28 @@ namespace Microsoft.AspNetCore.Server.HttpSys
{ {
var response = await SendRequestAsync(address); var response = await SendRequestAsync(address);
Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.True(onStartingCalled.WaitOne(0)); await onStartingCalled.Task.TimeoutAfter(TimeSpan.FromSeconds(1));
// Fires after the response completes // Fires after the response completes
Assert.True(onCompletedCalled.WaitOne(TimeSpan.FromSeconds(5))); await onCompletedCalled.Task.TimeoutAfter(TimeSpan.FromSeconds(5));
} }
} }
[ConditionalFact] [ConditionalFact]
public async Task Response_OnStartingThrows_StillCallsOnCompleted() public async Task Response_OnStartingThrows_StillCallsOnCompleted()
{ {
var onStartingCalled = new ManualResetEvent(false); var onStartingCalled = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var onCompletedCalled = new ManualResetEvent(false); var onCompletedCalled = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
string address; using (Utilities.CreateHttpServer(out var address, httpContext =>
using (Utilities.CreateHttpServer(out address, httpContext =>
{ {
httpContext.Response.OnStarting(state => httpContext.Response.OnStarting(state =>
{ {
onStartingCalled.Set(); onStartingCalled.SetResult(0);
throw new Exception("Failed OnStarting"); throw new Exception("Failed OnStarting");
}, httpContext); }, httpContext);
httpContext.Response.OnCompleted(state => httpContext.Response.OnCompleted(state =>
{ {
Assert.Same(state, httpContext); Assert.Same(state, httpContext);
onCompletedCalled.Set(); onCompletedCalled.SetResult(0);
return Task.FromResult(0); return Task.FromResult(0);
}, httpContext); }, httpContext);
return Task.FromResult(0); return Task.FromResult(0);
@ -175,29 +175,28 @@ namespace Microsoft.AspNetCore.Server.HttpSys
{ {
var response = await SendRequestAsync(address); var response = await SendRequestAsync(address);
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
Assert.True(onStartingCalled.WaitOne(0)); await onStartingCalled.Task.TimeoutAfter(TimeSpan.FromSeconds(1));
// Fires after the response completes // Fires after the response completes
Assert.True(onCompletedCalled.WaitOne(TimeSpan.FromSeconds(5))); await onCompletedCalled.Task.TimeoutAfter(TimeSpan.FromSeconds(5));
} }
} }
[ConditionalFact] [ConditionalFact]
public async Task Response_OnStartingThrowsAfterWrite_WriteThrowsAndStillCallsOnCompleted() public async Task Response_OnStartingThrowsAfterWrite_WriteThrowsAndStillCallsOnCompleted()
{ {
var onStartingCalled = new ManualResetEvent(false); var onStartingCalled = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var onCompletedCalled = new ManualResetEvent(false); var onCompletedCalled = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
string address; using (Utilities.CreateHttpServer(out var address, httpContext =>
using (Utilities.CreateHttpServer(out address, httpContext =>
{ {
httpContext.Response.OnStarting(state => httpContext.Response.OnStarting(state =>
{ {
onStartingCalled.Set(); onStartingCalled.SetResult(0);
throw new InvalidTimeZoneException("Failed OnStarting"); throw new InvalidTimeZoneException("Failed OnStarting");
}, httpContext); }, httpContext);
httpContext.Response.OnCompleted(state => httpContext.Response.OnCompleted(state =>
{ {
Assert.Same(state, httpContext); Assert.Same(state, httpContext);
onCompletedCalled.Set(); onCompletedCalled.SetResult(0);
return Task.FromResult(0); return Task.FromResult(0);
}, httpContext); }, httpContext);
Assert.Throws<InvalidTimeZoneException>(() => httpContext.Response.Body.Write(new byte[10], 0, 10)); Assert.Throws<InvalidTimeZoneException>(() => httpContext.Response.Body.Write(new byte[10], 0, 10));
@ -206,9 +205,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys
{ {
var response = await SendRequestAsync(address); var response = await SendRequestAsync(address);
Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.True(onStartingCalled.WaitOne(0)); await onStartingCalled.Task.TimeoutAfter(TimeSpan.FromSeconds(1));
// Fires after the response completes // Fires after the response completes
Assert.True(onCompletedCalled.WaitOne(TimeSpan.FromSeconds(5))); await onCompletedCalled.Task.TimeoutAfter(TimeSpan.FromSeconds(5));
} }
} }

View File

@ -69,17 +69,16 @@ namespace Microsoft.AspNetCore.Server.HttpSys
public async Task Server_ShutdownDuringRequest_Success() public async Task Server_ShutdownDuringRequest_Success()
{ {
Task<string> responseTask; Task<string> responseTask;
ManualResetEvent received = new ManualResetEvent(false); var received = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
string address; using (var server = Utilities.CreateHttpServer(out var address, httpContext =>
using (var server = Utilities.CreateHttpServer(out address, httpContext =>
{ {
received.Set(); received.SetResult(0);
httpContext.Response.ContentLength = 11; httpContext.Response.ContentLength = 11;
return httpContext.Response.WriteAsync("Hello World"); return httpContext.Response.WriteAsync("Hello World");
})) }))
{ {
responseTask = SendRequestAsync(address); responseTask = SendRequestAsync(address);
Assert.True(received.WaitOne(10000)); await received.Task.TimeoutAfter(TimeSpan.FromSeconds(10));
await server.StopAsync(new CancellationTokenSource(TimeSpan.FromSeconds(5)).Token); await server.StopAsync(new CancellationTokenSource(TimeSpan.FromSeconds(5)).Token);
} }
string response = await responseTask; string response = await responseTask;
@ -90,21 +89,20 @@ namespace Microsoft.AspNetCore.Server.HttpSys
public async Task Server_DisposeWithoutStopDuringRequest_Aborts() public async Task Server_DisposeWithoutStopDuringRequest_Aborts()
{ {
Task<string> responseTask; Task<string> responseTask;
var received = new ManualResetEvent(false); var received = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var stopped = new ManualResetEvent(false); var stopped = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
string address; using (var server = Utilities.CreateHttpServer(out var address, async httpContext =>
using (var server = Utilities.CreateHttpServer(out address, httpContext =>
{ {
received.Set(); received.SetResult(0);
Assert.True(stopped.WaitOne(TimeSpan.FromSeconds(10))); await stopped.Task.TimeoutAfter(TimeSpan.FromSeconds(10));
httpContext.Response.ContentLength = 11; httpContext.Response.ContentLength = 11;
return httpContext.Response.WriteAsync("Hello World"); await httpContext.Response.WriteAsync("Hello World");
})) }))
{ {
responseTask = SendRequestAsync(address); 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<HttpRequestException>(async () => await responseTask); await Assert.ThrowsAsync<HttpRequestException>(async () => await responseTask);
} }
@ -112,24 +110,21 @@ namespace Microsoft.AspNetCore.Server.HttpSys
public async Task Server_ShutdownDuringLongRunningRequest_TimesOut() public async Task Server_ShutdownDuringLongRunningRequest_TimesOut()
{ {
Task<string> responseTask; Task<string> responseTask;
var received = new ManualResetEvent(false); var received = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
bool? shutdown = null; var shutdown = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var waitForShutdown = new ManualResetEvent(false); using (var server = Utilities.CreateHttpServer(out var address, async httpContext =>
string address;
using (var server = Utilities.CreateHttpServer(out address, httpContext =>
{ {
received.Set(); received.SetResult(0);
shutdown = waitForShutdown.WaitOne(TimeSpan.FromSeconds(15)); await shutdown.Task.TimeoutAfter(TimeSpan.FromSeconds(15));
httpContext.Response.ContentLength = 11; httpContext.Response.ContentLength = 11;
return httpContext.Response.WriteAsync("Hello World"); await httpContext.Response.WriteAsync("Hello World");
})) }))
{ {
responseTask = SendRequestAsync(address); responseTask = SendRequestAsync(address);
Assert.True(received.WaitOne(TimeSpan.FromSeconds(10))); await received.Task.TimeoutAfter(TimeSpan.FromSeconds(10));
Assert.False(shutdown.HasValue);
await server.StopAsync(new CancellationTokenSource(TimeSpan.FromSeconds(5)).Token); await server.StopAsync(new CancellationTokenSource(TimeSpan.FromSeconds(5)).Token);
} }
waitForShutdown.Set(); shutdown.SetResult(0);
await Assert.ThrowsAsync<HttpRequestException>(async () => await responseTask); await Assert.ThrowsAsync<HttpRequestException>(async () => await responseTask);
} }
@ -217,64 +212,59 @@ namespace Microsoft.AspNetCore.Server.HttpSys
[ConditionalFact] [ConditionalFact]
public async Task Server_ClientDisconnects_CallCanceled() public async Task Server_ClientDisconnects_CallCanceled()
{ {
TimeSpan interval = TimeSpan.FromSeconds(10); var interval = TimeSpan.FromSeconds(10);
ManualResetEvent received = new ManualResetEvent(false); var received = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
ManualResetEvent aborted = new ManualResetEvent(false); var aborted = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
ManualResetEvent canceled = new ManualResetEvent(false); var canceled = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
string address; using (Utilities.CreateHttpServer(out var address, async httpContext =>
using (Utilities.CreateHttpServer(out address, httpContext =>
{ {
CancellationToken ct = httpContext.RequestAborted; var ct = httpContext.RequestAborted;
Assert.True(ct.CanBeCanceled, "CanBeCanceled"); Assert.True(ct.CanBeCanceled, "CanBeCanceled");
Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); Assert.False(ct.IsCancellationRequested, "IsCancellationRequested");
ct.Register(() => canceled.Set()); ct.Register(() => canceled.SetResult(0));
received.Set(); received.SetResult(0);
Assert.True(aborted.WaitOne(interval), "Aborted"); await aborted.Task.TimeoutAfter(interval);
Assert.True(ct.WaitHandle.WaitOne(interval), "CT Wait"); Assert.True(ct.WaitHandle.WaitOne(interval), "CT Wait");
Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); Assert.True(ct.IsCancellationRequested, "IsCancellationRequested");
return Task.FromResult(0);
})) }))
{ {
// Note: System.Net.Sockets does not RST the connection by default, it just FINs. // Note: System.Net.Sockets does not RST the connection by default, it just FINs.
// Http.Sys's disconnect notice requires a RST. // Http.Sys's disconnect notice requires a RST.
using (var client = await SendHungRequestAsync("GET", address)) using (var client = await SendHungRequestAsync("GET", address))
{ {
Assert.True(received.WaitOne(interval), "Receive Timeout"); await received.Task.TimeoutAfter(interval);
// Force a RST // Force a RST
client.LingerState = new LingerOption(true, 0); client.LingerState = new LingerOption(true, 0);
} }
aborted.Set(); aborted.SetResult(0);
Assert.True(canceled.WaitOne(interval), "canceled"); await canceled.Task.TimeoutAfter(interval);
} }
} }
[ConditionalFact] [ConditionalFact]
public async Task Server_Abort_CallCanceled() public async Task Server_Abort_CallCanceled()
{ {
TimeSpan interval = TimeSpan.FromSeconds(100); var interval = TimeSpan.FromSeconds(10);
ManualResetEvent received = new ManualResetEvent(false); var received = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
ManualResetEvent aborted = new ManualResetEvent(false); var canceled = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
ManualResetEvent canceled = new ManualResetEvent(false);
string address; using (Utilities.CreateHttpServer(out var address, async httpContext =>
using (Utilities.CreateHttpServer(out address, httpContext =>
{ {
CancellationToken ct = httpContext.RequestAborted; CancellationToken ct = httpContext.RequestAborted;
Assert.True(ct.CanBeCanceled, "CanBeCanceled"); Assert.True(ct.CanBeCanceled, "CanBeCanceled");
Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); Assert.False(ct.IsCancellationRequested, "IsCancellationRequested");
ct.Register(() => canceled.Set()); ct.Register(() => canceled.SetResult(0));
received.Set(); received.SetResult(0);
httpContext.Abort(); httpContext.Abort();
Assert.True(canceled.WaitOne(interval), "Aborted"); await canceled.Task.TimeoutAfter(interval);
Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); Assert.True(ct.IsCancellationRequested, "IsCancellationRequested");
return Task.FromResult(0);
})) }))
{ {
using (var client = await SendHungRequestAsync("GET", address)) using (var client = await SendHungRequestAsync("GET", address))
{ {
Assert.True(received.WaitOne(interval), "Receive Timeout"); await received.Task.TimeoutAfter(interval);
Assert.Throws<IOException>(() => client.GetStream().Read(new byte[10], 0, 10)); Assert.Throws<IOException>(() => client.GetStream().Read(new byte[10], 0, 10));
} }
} }
@ -423,19 +413,18 @@ namespace Microsoft.AspNetCore.Server.HttpSys
public async Task Server_MultipleStopAsyncCallsWaitForRequestsToDrain_Success() public async Task Server_MultipleStopAsyncCallsWaitForRequestsToDrain_Success()
{ {
Task<string> responseTask; Task<string> responseTask;
ManualResetEvent received = new ManualResetEvent(false); var received = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
ManualResetEvent run = new ManualResetEvent(false); var run = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
string address; using (var server = Utilities.CreateHttpServer(out var address, async httpContext =>
using (var server = Utilities.CreateHttpServer(out address, httpContext =>
{ {
received.Set(); received.SetResult(0);
Assert.True(run.WaitOne(TimeSpan.FromSeconds(10))); await run.Task.TimeoutAfter(TimeSpan.FromSeconds(10));
httpContext.Response.ContentLength = 11; httpContext.Response.ContentLength = 11;
return httpContext.Response.WriteAsync("Hello World"); await httpContext.Response.WriteAsync("Hello World");
})) }))
{ {
responseTask = SendRequestAsync(address); 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 cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
var stopTask1 = server.StopAsync(cts.Token); var stopTask1 = server.StopAsync(cts.Token);
@ -446,11 +435,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys
Assert.False(stopTask2.IsCompleted); Assert.False(stopTask2.IsCompleted);
Assert.False(stopTask3.IsCompleted); Assert.False(stopTask3.IsCompleted);
run.Set(); run.SetResult(0);
await Task.WhenAll(stopTask1, stopTask2, stopTask3).TimeoutAfter(TimeSpan.FromSeconds(10)); await Task.WhenAll(stopTask1, stopTask2, stopTask3).TimeoutAfter(TimeSpan.FromSeconds(10));
} }
string response = await responseTask; var response = await responseTask;
Assert.Equal("Hello World", response); Assert.Equal("Hello World", response);
} }
@ -458,19 +447,18 @@ namespace Microsoft.AspNetCore.Server.HttpSys
public async Task Server_MultipleStopAsyncCallsCompleteOnCancellation_SameToken_Success() public async Task Server_MultipleStopAsyncCallsCompleteOnCancellation_SameToken_Success()
{ {
Task<string> responseTask; Task<string> responseTask;
ManualResetEvent received = new ManualResetEvent(false); var received = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
ManualResetEvent run = new ManualResetEvent(false); var run = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
string address; using (var server = Utilities.CreateHttpServer(out var address, async httpContext =>
using (var server = Utilities.CreateHttpServer(out address, httpContext =>
{ {
received.Set(); received.SetResult(0);
Assert.True(run.WaitOne(TimeSpan.FromSeconds(10))); await run.Task.TimeoutAfter(TimeSpan.FromSeconds(10));
httpContext.Response.ContentLength = 11; httpContext.Response.ContentLength = 11;
return httpContext.Response.WriteAsync("Hello World"); await httpContext.Response.WriteAsync("Hello World");
})) }))
{ {
responseTask = SendRequestAsync(address); responseTask = SendRequestAsync(address);
Assert.True(received.WaitOne(TimeSpan.FromSeconds(10))); await received.Task.TimeoutAfter(TimeSpan.FromSeconds(10));
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();
var stopTask1 = server.StopAsync(cts.Token); 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)); await Task.WhenAll(stopTask1, stopTask2, stopTask3).TimeoutAfter(TimeSpan.FromSeconds(10));
run.Set(); run.SetResult(0);
string response = await responseTask; string response = await responseTask;
Assert.Equal("Hello World", response); Assert.Equal("Hello World", response);
@ -496,19 +484,18 @@ namespace Microsoft.AspNetCore.Server.HttpSys
public async Task Server_MultipleStopAsyncCallsCompleteOnSingleCancellation_FirstToken_Success() public async Task Server_MultipleStopAsyncCallsCompleteOnSingleCancellation_FirstToken_Success()
{ {
Task<string> responseTask; Task<string> responseTask;
ManualResetEvent received = new ManualResetEvent(false); var received = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
ManualResetEvent run = new ManualResetEvent(false); var run = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
string address; using (var server = Utilities.CreateHttpServer(out var address, async httpContext =>
using (var server = Utilities.CreateHttpServer(out address, httpContext =>
{ {
received.Set(); received.SetResult(0);
Assert.True(run.WaitOne(TimeSpan.FromSeconds(10))); await run.Task.TimeoutAfter(TimeSpan.FromSeconds(10));
httpContext.Response.ContentLength = 11; httpContext.Response.ContentLength = 11;
return httpContext.Response.WriteAsync("Hello World"); await httpContext.Response.WriteAsync("Hello World");
})) }))
{ {
responseTask = SendRequestAsync(address); responseTask = SendRequestAsync(address);
Assert.True(received.WaitOne(TimeSpan.FromSeconds(10))); await received.Task.TimeoutAfter(TimeSpan.FromSeconds(10));
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();
var stopTask1 = server.StopAsync(cts.Token); 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)); await Task.WhenAll(stopTask1, stopTask2, stopTask3).TimeoutAfter(TimeSpan.FromSeconds(10));
run.Set(); run.SetResult(0);
string response = await responseTask; string response = await responseTask;
Assert.Equal("Hello World", response); Assert.Equal("Hello World", response);
@ -534,19 +521,18 @@ namespace Microsoft.AspNetCore.Server.HttpSys
public async Task Server_MultipleStopAsyncCallsCompleteOnSingleCancellation_SubsequentToken_Success() public async Task Server_MultipleStopAsyncCallsCompleteOnSingleCancellation_SubsequentToken_Success()
{ {
Task<string> responseTask; Task<string> responseTask;
ManualResetEvent received = new ManualResetEvent(false); var received = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
ManualResetEvent run = new ManualResetEvent(false); var run = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
string address; using (var server = Utilities.CreateHttpServer(out var address, async httpContext =>
using (var server = Utilities.CreateHttpServer(out address, httpContext =>
{ {
received.Set(); received.SetResult(0);
Assert.True(run.WaitOne(TimeSpan.FromSeconds(10))); await run.Task.TimeoutAfter(TimeSpan.FromSeconds(10));
httpContext.Response.ContentLength = 11; httpContext.Response.ContentLength = 11;
return httpContext.Response.WriteAsync("Hello World"); await httpContext.Response.WriteAsync("Hello World");
})) }))
{ {
responseTask = SendRequestAsync(address); responseTask = SendRequestAsync(address);
Assert.True(received.WaitOne(10000)); await received.Task.TimeoutAfter(TimeSpan.FromSeconds(10));
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();
var stopTask1 = server.StopAsync(new CancellationTokenSource().Token); 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)); await Task.WhenAll(stopTask1, stopTask2, stopTask3).TimeoutAfter(TimeSpan.FromSeconds(10));
run.Set(); run.SetResult(0);
string response = await responseTask; string response = await responseTask;
Assert.Equal("Hello World", response); Assert.Equal("Hello World", response);
@ -572,21 +558,20 @@ namespace Microsoft.AspNetCore.Server.HttpSys
public async Task Server_DisposeContinuesPendingStopAsyncCalls() public async Task Server_DisposeContinuesPendingStopAsyncCalls()
{ {
Task<string> responseTask; Task<string> responseTask;
ManualResetEvent received = new ManualResetEvent(false); var received = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
ManualResetEvent run = new ManualResetEvent(false); var run = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
string address;
Task stopTask1; Task stopTask1;
Task stopTask2; Task stopTask2;
using (var server = Utilities.CreateHttpServer(out address, httpContext => using (var server = Utilities.CreateHttpServer(out var address, async httpContext =>
{ {
received.Set(); received.SetResult(0);
Assert.True(run.WaitOne(TimeSpan.FromSeconds(10))); await run.Task.TimeoutAfter(TimeSpan.FromSeconds(15));
httpContext.Response.ContentLength = 11; httpContext.Response.ContentLength = 11;
return httpContext.Response.WriteAsync("Hello World"); await httpContext.Response.WriteAsync("Hello World");
})) }))
{ {
responseTask = SendRequestAsync(address); responseTask = SendRequestAsync(address);
Assert.True(received.WaitOne(TimeSpan.FromSeconds(10))); await received.Task.TimeoutAfter(TimeSpan.FromSeconds(10));
stopTask1 = server.StopAsync(new CancellationTokenSource().Token); stopTask1 = server.StopAsync(new CancellationTokenSource().Token);
stopTask2 = 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)); await Task.WhenAll(stopTask1, stopTask2).TimeoutAfter(TimeSpan.FromSeconds(10));
run.SetResult(0);
} }
[ConditionalFact] [ConditionalFact]

View File

@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
@ -160,37 +161,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys
return server; 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) internal static Task<T> WithTimeout<T>(this Task<T> task) => task.TimeoutAfter(DefaultTimeout);
{
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<T> WithTimeout<T>(this Task<T> task) => task.WithTimeout(DefaultTimeout);
internal static async Task<T> WithTimeout<T>(this Task<T> 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.");
}
}
} }
} }

View File

@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http.Features.Authentication; using Microsoft.AspNetCore.Http.Features.Authentication;
using Microsoft.AspNetCore.TestHost; using Microsoft.AspNetCore.TestHost;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Xunit; using Xunit;
@ -81,8 +82,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
[InlineData("/pathBase", "/pathBase/iisintegration", "Shutdown")] [InlineData("/pathBase", "/pathBase/iisintegration", "Shutdown")]
public async Task MiddlewareShutsdownGivenANCMShutdown(string pathBase, string requestPath, string shutdownEvent) public async Task MiddlewareShutsdownGivenANCMShutdown(string pathBase, string requestPath, string shutdownEvent)
{ {
var requestExecuted = new ManualResetEvent(false); var requestExecuted = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var applicationStoppingFired = new ManualResetEvent(false); var applicationStoppingFired = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var builder = new WebHostBuilder() var builder = new WebHostBuilder()
.UseSetting("TOKEN", "TestToken") .UseSetting("TOKEN", "TestToken")
.UseSetting("PORT", "12345") .UseSetting("PORT", "12345")
@ -91,11 +92,11 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
.Configure(app => .Configure(app =>
{ {
var appLifetime = app.ApplicationServices.GetRequiredService<IApplicationLifetime>(); var appLifetime = app.ApplicationServices.GetRequiredService<IApplicationLifetime>();
appLifetime.ApplicationStopping.Register(() => applicationStoppingFired.Set()); appLifetime.ApplicationStopping.Register(() => applicationStoppingFired.SetResult(0));
app.Run(context => app.Run(context =>
{ {
requestExecuted.Set(); requestExecuted.SetResult(0);
return Task.FromResult(0); return Task.FromResult(0);
}); });
}); });
@ -106,8 +107,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
request.Headers.TryAddWithoutValidation("MS-ASPNETCORE-EVENT", shutdownEvent); request.Headers.TryAddWithoutValidation("MS-ASPNETCORE-EVENT", shutdownEvent);
var response = await server.CreateClient().SendAsync(request); var response = await server.CreateClient().SendAsync(request);
Assert.True(applicationStoppingFired.WaitOne(TimeSpan.FromSeconds(5))); await applicationStoppingFired.Task.TimeoutAfter(TimeSpan.FromSeconds(5));
Assert.False(requestExecuted.WaitOne(0)); Assert.False(requestExecuted.Task.IsCompleted);
Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); Assert.Equal(HttpStatusCode.Accepted, response.StatusCode);
} }
@ -131,8 +132,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
[MemberData(nameof(InvalidShutdownMethods))] [MemberData(nameof(InvalidShutdownMethods))]
public async Task MiddlewareIgnoresShutdownGivenWrongMethod(HttpMethod method) public async Task MiddlewareIgnoresShutdownGivenWrongMethod(HttpMethod method)
{ {
var requestExecuted = new ManualResetEvent(false); var requestExecuted = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var applicationStoppingFired = new ManualResetEvent(false); var applicationStoppingFired = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var builder = new WebHostBuilder() var builder = new WebHostBuilder()
.UseSetting("TOKEN", "TestToken") .UseSetting("TOKEN", "TestToken")
.UseSetting("PORT", "12345") .UseSetting("PORT", "12345")
@ -141,11 +142,11 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
.Configure(app => .Configure(app =>
{ {
var appLifetime = app.ApplicationServices.GetRequiredService<IApplicationLifetime>(); var appLifetime = app.ApplicationServices.GetRequiredService<IApplicationLifetime>();
appLifetime.ApplicationStopping.Register(() => applicationStoppingFired.Set()); appLifetime.ApplicationStopping.Register(() => applicationStoppingFired.SetResult(0));
app.Run(context => app.Run(context =>
{ {
requestExecuted.Set(); requestExecuted.SetResult(0);
return Task.FromResult(0); return Task.FromResult(0);
}); });
}); });
@ -156,8 +157,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
request.Headers.TryAddWithoutValidation("MS-ASPNETCORE-EVENT", "shutdown"); request.Headers.TryAddWithoutValidation("MS-ASPNETCORE-EVENT", "shutdown");
var response = await server.CreateClient().SendAsync(request); var response = await server.CreateClient().SendAsync(request);
Assert.False(applicationStoppingFired.WaitOne(TimeSpan.FromSeconds(1))); Assert.False(applicationStoppingFired.Task.IsCompleted);
Assert.True(requestExecuted.WaitOne(0)); await requestExecuted.Task.TimeoutAfter(TimeSpan.FromSeconds(1));
Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.StatusCode);
} }
@ -167,8 +168,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
[InlineData("/path/iisintegration")] [InlineData("/path/iisintegration")]
public async Task MiddlewareIgnoresShutdownGivenWrongPath(string path) public async Task MiddlewareIgnoresShutdownGivenWrongPath(string path)
{ {
var requestExecuted = new ManualResetEvent(false); var requestExecuted = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var applicationStoppingFired = new ManualResetEvent(false); var applicationStoppingFired = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var builder = new WebHostBuilder() var builder = new WebHostBuilder()
.UseSetting("TOKEN", "TestToken") .UseSetting("TOKEN", "TestToken")
.UseSetting("PORT", "12345") .UseSetting("PORT", "12345")
@ -177,11 +178,11 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
.Configure(app => .Configure(app =>
{ {
var appLifetime = app.ApplicationServices.GetRequiredService<IApplicationLifetime>(); var appLifetime = app.ApplicationServices.GetRequiredService<IApplicationLifetime>();
appLifetime.ApplicationStopping.Register(() => applicationStoppingFired.Set()); appLifetime.ApplicationStopping.Register(() => applicationStoppingFired.SetResult(0));
app.Run(context => app.Run(context =>
{ {
requestExecuted.Set(); requestExecuted.SetResult(0);
return Task.FromResult(0); return Task.FromResult(0);
}); });
}); });
@ -192,8 +193,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
request.Headers.TryAddWithoutValidation("MS-ASPNETCORE-EVENT", "shutdown"); request.Headers.TryAddWithoutValidation("MS-ASPNETCORE-EVENT", "shutdown");
var response = await server.CreateClient().SendAsync(request); var response = await server.CreateClient().SendAsync(request);
Assert.False(applicationStoppingFired.WaitOne(TimeSpan.FromSeconds(1))); Assert.False(applicationStoppingFired.Task.IsCompleted);
Assert.True(requestExecuted.WaitOne(0)); await requestExecuted.Task.TimeoutAfter(TimeSpan.FromSeconds(1));
Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.StatusCode);
} }
@ -203,8 +204,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
[InlineData(null)] [InlineData(null)]
public async Task MiddlewareIgnoresShutdownGivenWrongEvent(string shutdownEvent) public async Task MiddlewareIgnoresShutdownGivenWrongEvent(string shutdownEvent)
{ {
var requestExecuted = new ManualResetEvent(false); var requestExecuted = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var applicationStoppingFired = new ManualResetEvent(false); var applicationStoppingFired = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var builder = new WebHostBuilder() var builder = new WebHostBuilder()
.UseSetting("TOKEN", "TestToken") .UseSetting("TOKEN", "TestToken")
.UseSetting("PORT", "12345") .UseSetting("PORT", "12345")
@ -213,11 +214,11 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
.Configure(app => .Configure(app =>
{ {
var appLifetime = app.ApplicationServices.GetRequiredService<IApplicationLifetime>(); var appLifetime = app.ApplicationServices.GetRequiredService<IApplicationLifetime>();
appLifetime.ApplicationStopping.Register(() => applicationStoppingFired.Set()); appLifetime.ApplicationStopping.Register(() => applicationStoppingFired.SetResult(0));
app.Run(context => app.Run(context =>
{ {
requestExecuted.Set(); requestExecuted.SetResult(0);
return Task.FromResult(0); return Task.FromResult(0);
}); });
}); });
@ -228,8 +229,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
request.Headers.TryAddWithoutValidation("MS-ASPNETCORE-EVENT", shutdownEvent); request.Headers.TryAddWithoutValidation("MS-ASPNETCORE-EVENT", shutdownEvent);
var response = await server.CreateClient().SendAsync(request); var response = await server.CreateClient().SendAsync(request);
Assert.False(applicationStoppingFired.WaitOne(TimeSpan.FromSeconds(1))); Assert.False(applicationStoppingFired.Task.IsCompleted);
Assert.True(requestExecuted.WaitOne(0)); await requestExecuted.Task.TimeoutAfter(TimeSpan.FromSeconds(1));
Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.StatusCode);
} }

View File

@ -6,6 +6,8 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Testing;
using Microsoft.DotNet.Watcher.Internal; using Microsoft.DotNet.Watcher.Internal;
using Xunit; using Xunit;
using Xunit.Abstractions; using Xunit.Abstractions;
@ -19,32 +21,33 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
_output = output; _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; private readonly ITestOutputHelper _output;
[Theory] [Theory]
[InlineData(true)] [InlineData(true)]
[InlineData(false)] [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)) using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling))
{ {
var changedEv = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var filesChanged = new HashSet<string>(); var filesChanged = new HashSet<string>();
watcher.OnFileChange += (_, f) => watcher.OnFileChange += (_, f) =>
{ {
filesChanged.Add(f); filesChanged.Add(f);
changedEv.Set(); changedEv.TrySetResult(0);
}; };
watcher.EnableRaisingEvents = true; watcher.EnableRaisingEvents = true;
var testFileFullPath = Path.Combine(dir, "foo"); var testFileFullPath = Path.Combine(dir, "foo");
File.WriteAllText(testFileFullPath, string.Empty); File.WriteAllText(testFileFullPath, string.Empty);
Assert.True(changedEv.WaitOne(DefaultTimeout)); await changedEv.Task.TimeoutAfter(DefaultTimeout);
Assert.Equal(testFileFullPath, filesChanged.Single()); Assert.Equal(testFileFullPath, filesChanged.Single());
} }
}); });
@ -53,16 +56,16 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
[Theory] [Theory]
[InlineData(true)] [InlineData(true)]
[InlineData(false)] [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"); var testFileFullPath = Path.Combine(dir, "foo");
File.WriteAllText(testFileFullPath, string.Empty); File.WriteAllText(testFileFullPath, string.Empty);
using (var changedEv = new ManualResetEvent(false))
using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling)) using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling))
{ {
var changedEv = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var filesChanged = new HashSet<string>(); var filesChanged = new HashSet<string>();
EventHandler<string> handler = null; EventHandler<string> handler = null;
@ -72,7 +75,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
watcher.OnFileChange -= handler; watcher.OnFileChange -= handler;
filesChanged.Add(f); filesChanged.Add(f);
changedEv.Set(); changedEv.TrySetResult(0);
}; };
watcher.OnFileChange += handler; watcher.OnFileChange += handler;
@ -81,10 +84,10 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
// On Unix the file write time is in 1s increments; // On Unix the file write time is in 1s increments;
// if we don't wait, there's a chance that the polling // if we don't wait, there's a chance that the polling
// watcher will not detect the change // watcher will not detect the change
Thread.Sleep(1000); await Task.Delay(1000);
File.WriteAllText(testFileFullPath, string.Empty); File.WriteAllText(testFileFullPath, string.Empty);
Assert.True(changedEv.WaitOne(DefaultTimeout)); await changedEv.Task.TimeoutAfter(DefaultTimeout);
Assert.Equal(testFileFullPath, filesChanged.Single()); Assert.Equal(testFileFullPath, filesChanged.Single());
} }
}); });
@ -93,18 +96,18 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
[Theory] [Theory]
[InlineData(true)] [InlineData(true)]
[InlineData(false)] [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 srcFile = Path.Combine(dir, "foo");
var dstFile = Path.Combine(dir, "foo2"); var dstFile = Path.Combine(dir, "foo2");
File.WriteAllText(srcFile, string.Empty); File.WriteAllText(srcFile, string.Empty);
using (var changedEv = new ManualResetEvent(false))
using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling)) using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling))
{ {
var changedEv = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var filesChanged = new HashSet<string>(); var filesChanged = new HashSet<string>();
EventHandler<string> handler = null; EventHandler<string> handler = null;
@ -117,7 +120,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
watcher.EnableRaisingEvents = false; watcher.EnableRaisingEvents = false;
watcher.OnFileChange -= handler; watcher.OnFileChange -= handler;
changedEv.Set(); changedEv.TrySetResult(0);
} }
}; };
@ -126,7 +129,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
File.Move(srcFile, dstFile); File.Move(srcFile, dstFile);
Assert.True(changedEv.WaitOne(DefaultTimeout)); await changedEv.Task.TimeoutAfter(DefaultTimeout);
Assert.Contains(srcFile, filesChanged); Assert.Contains(srcFile, filesChanged);
Assert.Contains(dstFile, filesChanged); Assert.Contains(dstFile, filesChanged);
} }
@ -134,9 +137,9 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
} }
[Fact] [Fact]
public void FileInSubdirectory() public async Task FileInSubdirectory()
{ {
UsingTempDirectory(dir => await UsingTempDirectory(async dir =>
{ {
var subdir = Path.Combine(dir, "subdir"); var subdir = Path.Combine(dir, "subdir");
Directory.CreateDirectory(subdir); Directory.CreateDirectory(subdir);
@ -144,9 +147,9 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
var testFileFullPath = Path.Combine(subdir, "foo"); var testFileFullPath = Path.Combine(subdir, "foo");
File.WriteAllText(testFileFullPath, string.Empty); File.WriteAllText(testFileFullPath, string.Empty);
using (var changedEv = new ManualResetEvent(false))
using (var watcher = FileWatcherFactory.CreateWatcher(dir, true)) using (var watcher = FileWatcherFactory.CreateWatcher(dir, true))
{ {
var changedEv = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var filesChanged = new HashSet<string>(); var filesChanged = new HashSet<string>();
EventHandler<string> handler = null; EventHandler<string> handler = null;
@ -158,7 +161,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
{ {
watcher.EnableRaisingEvents = false; watcher.EnableRaisingEvents = false;
watcher.OnFileChange -= handler; 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; // On Unix the file write time is in 1s increments;
// if we don't wait, there's a chance that the polling // if we don't wait, there's a chance that the polling
// watcher will not detect the change // watcher will not detect the change
Thread.Sleep(1000); await Task.Delay(1000);
File.WriteAllText(testFileFullPath, string.Empty); File.WriteAllText(testFileFullPath, string.Empty);
Assert.True(changedEv.WaitOne(DefaultTimeout)); await changedEv.Task.TimeoutAfter(DefaultTimeout);
Assert.Contains(subdir, filesChanged); Assert.Contains(subdir, filesChanged);
Assert.Contains(testFileFullPath, filesChanged); Assert.Contains(testFileFullPath, filesChanged);
} }
@ -181,14 +184,14 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
[Theory] [Theory]
[InlineData(true)] [InlineData(true)]
[InlineData(false)] [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 watcher = FileWatcherFactory.CreateWatcher(dir, usePolling))
using (var changedEv = new ManualResetEvent(false))
{ {
watcher.OnFileChange += (_, f) => changedEv.Set(); var changedEv = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
watcher.OnFileChange += (_, f) => changedEv.TrySetResult(0);
// Disable // Disable
watcher.EnableRaisingEvents = false; watcher.EnableRaisingEvents = false;
@ -198,10 +201,10 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
// On Unix the file write time is in 1s increments; // On Unix the file write time is in 1s increments;
// if we don't wait, there's a chance that the polling // if we don't wait, there's a chance that the polling
// watcher will not detect the change // watcher will not detect the change
Thread.Sleep(1000); await Task.Delay(1000);
File.WriteAllText(testFileFullPath, string.Empty); File.WriteAllText(testFileFullPath, string.Empty);
Assert.False(changedEv.WaitOne(DefaultTimeout / 2)); await Assert.ThrowsAsync<TimeoutException>(() => changedEv.Task.TimeoutAfter(NegativeTimeout));
} }
}); });
} }
@ -209,37 +212,35 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
[Theory] [Theory]
[InlineData(true)] [InlineData(true)]
[InlineData(false)] [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<int>(TaskCreationOptions.RunContinuationsAsynchronously);
using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling))
{ {
using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling)) watcher.OnFileChange += (_, f) => changedEv.TrySetResult(0);
{ watcher.EnableRaisingEvents = true;
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));
} }
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<TimeoutException>(() => changedEv.Task.TimeoutAfter(NegativeTimeout));
}); });
} }
[Theory] [Theory]
[InlineData(true)] [InlineData(true)]
[InlineData(false)] [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, "foo1"), string.Empty);
File.WriteAllText(Path.Combine(dir, "foo2"), 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"); var testFileFullPath = Path.Combine(dir, "foo3");
using (var changedEv = new ManualResetEvent(false))
using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling)) using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling))
{ {
var changedEv = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var filesChanged = new HashSet<string>(); var filesChanged = new HashSet<string>();
EventHandler<string> handler = null; EventHandler<string> handler = null;
@ -260,7 +261,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
watcher.EnableRaisingEvents = false; watcher.EnableRaisingEvents = false;
watcher.OnFileChange -= handler; watcher.OnFileChange -= handler;
filesChanged.Add(f); filesChanged.Add(f);
changedEv.Set(); changedEv.TrySetResult(0);
}; };
watcher.OnFileChange += handler; watcher.OnFileChange += handler;
@ -269,11 +270,11 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
// On Unix the file write time is in 1s increments; // On Unix the file write time is in 1s increments;
// if we don't wait, there's a chance that the polling // if we don't wait, there's a chance that the polling
// watcher will not detect the change // watcher will not detect the change
Thread.Sleep(1000); await Task.Delay(1000);
File.WriteAllText(testFileFullPath, string.Empty); File.WriteAllText(testFileFullPath, string.Empty);
Assert.True(changedEv.WaitOne(DefaultTimeout)); await changedEv.Task.TimeoutAfter(DefaultTimeout);
Assert.Equal(testFileFullPath, filesChanged.Single()); Assert.Equal(testFileFullPath, filesChanged.Single());
} }
}); });
@ -282,11 +283,11 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
[Theory] [Theory]
[InlineData(true)] [InlineData(true)]
[InlineData(false)] [InlineData(false)]
public void MultipleTriggers(bool usePolling) public async Task MultipleTriggers(bool usePolling)
{ {
var filesChanged = new HashSet<string>(); var filesChanged = new HashSet<string>();
UsingTempDirectory(dir => await UsingTempDirectory(async dir =>
{ {
using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling)) using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling))
{ {
@ -294,7 +295,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
for (var i = 0; i < 5; i++) for (var i = 0; i < 5; i++)
{ {
AssertFileChangeRaisesEvent(dir, watcher); await AssertFileChangeRaisesEvent(dir, watcher);
} }
watcher.EnableRaisingEvents = false; 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<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var expectedPath = Path.Combine(directory, Path.GetRandomFileName());
EventHandler<string> handler = (object _, string f) =>
{ {
var expectedPath = Path.Combine(directory, Path.GetRandomFileName()); _output.WriteLine("File changed: " + f);
EventHandler<string> 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;
try try
{ {
// On Unix the file write time is in 1s increments; if (string.Equals(f, expectedPath, StringComparison.OrdinalIgnoreCase))
// if we don't wait, there's a chance that the polling {
// watcher will not detect the change changedEv.TrySetResult(0);
Thread.Sleep(1000); }
File.AppendAllText(expectedPath, " ");
Assert.True(semaphoreSlim.Wait(DefaultTimeout), "Expected a file change event for " + expectedPath);
} }
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] [Theory]
[InlineData(true)] [InlineData(true)]
[InlineData(false)] [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"); var subdir = Path.Combine(dir, "subdir");
Directory.CreateDirectory(subdir); Directory.CreateDirectory(subdir);
@ -363,9 +362,9 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
File.WriteAllText(f2, string.Empty); File.WriteAllText(f2, string.Empty);
File.WriteAllText(f3, string.Empty); File.WriteAllText(f3, string.Empty);
using (var changedEv = new AutoResetEvent(false))
using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling)) using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling))
{ {
var changedEv = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var filesChanged = new HashSet<string>(); var filesChanged = new HashSet<string>();
EventHandler<string> handler = null; EventHandler<string> handler = null;
@ -377,7 +376,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
{ {
watcher.EnableRaisingEvents = false; watcher.EnableRaisingEvents = false;
watcher.OnFileChange -= handler; watcher.OnFileChange -= handler;
changedEv.Set(); changedEv.TrySetResult(0);
} }
}; };
@ -386,7 +385,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
Directory.Delete(subdir, recursive: true); Directory.Delete(subdir, recursive: true);
Assert.True(changedEv.WaitOne(DefaultTimeout)); await changedEv.Task.TimeoutAfter(DefaultTimeout);
Assert.Contains(f1, filesChanged); Assert.Contains(f1, filesChanged);
Assert.Contains(f2, filesChanged); Assert.Contains(f2, filesChanged);
@ -396,7 +395,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
}); });
} }
private static void UsingTempDirectory(Action<string> action) private static async Task UsingTempDirectory(Func<string, Task> func)
{ {
var tempFolder = Path.Combine(Path.GetTempPath(), $"{nameof(FileWatcherTests)}-{Guid.NewGuid().ToString("N")}"); var tempFolder = Path.Combine(Path.GetTempPath(), $"{nameof(FileWatcherTests)}-{Guid.NewGuid().ToString("N")}");
if (Directory.Exists(tempFolder)) if (Directory.Exists(tempFolder))
@ -408,7 +407,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
try try
{ {
action(tempFolder); await func(tempFolder);
} }
finally finally
{ {