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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
@ -160,37 +161,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys
return server;
}
internal static Task WithTimeout(this Task task) => task.WithTimeout(DefaultTimeout);
internal static Task WithTimeout(this Task task) => task.TimeoutAfter(DefaultTimeout);
internal static async Task WithTimeout(this Task task, TimeSpan timeout)
{
var completedTask = await Task.WhenAny(task, Task.Delay(timeout));
if (completedTask == task)
{
await task;
return;
}
else
{
throw new TimeoutException("The task has timed out.");
}
}
internal static Task<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.");
}
}
internal static Task<T> WithTimeout<T>(this Task<T> task) => task.TimeoutAfter(DefaultTimeout);
}
}

View File

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

View File

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