extend timeout and more logging (#183)

This commit is contained in:
Andrew Stanton-Nurse 2017-06-09 11:26:06 -07:00 committed by GitHub
parent de8b7e7d3c
commit f34e87042c
4 changed files with 97 additions and 28 deletions

View File

@ -1,6 +1,7 @@
using System; using System;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Runtime.Loader;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -11,6 +12,7 @@ namespace AutobahnTestApp
{ {
public static void Main(string[] args) public static void Main(string[] args)
{ {
var scenarioName = "Unknown";
var config = new ConfigurationBuilder() var config = new ConfigurationBuilder()
.AddCommandLine(args) .AddCommandLine(args)
.Build(); .Build();
@ -24,6 +26,7 @@ namespace AutobahnTestApp
if (string.Equals(builder.GetSetting("server"), "Microsoft.AspNetCore.Server.HttpSys", System.StringComparison.Ordinal)) if (string.Equals(builder.GetSetting("server"), "Microsoft.AspNetCore.Server.HttpSys", System.StringComparison.Ordinal))
{ {
scenarioName = "HttpSysServer";
Console.WriteLine("Using HttpSys server"); Console.WriteLine("Using HttpSys server");
builder.UseHttpSys(); builder.UseHttpSys();
} }
@ -31,6 +34,7 @@ namespace AutobahnTestApp
{ {
// ANCM is hosting the process. // ANCM is hosting the process.
// The port will not yet be configured at this point, but will also not require HTTPS. // The port will not yet be configured at this point, but will also not require HTTPS.
scenarioName = "AspNetCoreModule";
Console.WriteLine("Detected ANCM, using Kestrel"); Console.WriteLine("Detected ANCM, using Kestrel");
builder.UseKestrel(); builder.UseKestrel();
} }
@ -55,15 +59,27 @@ namespace AutobahnTestApp
{ {
if (uri.Scheme.Equals("https", StringComparison.OrdinalIgnoreCase)) if (uri.Scheme.Equals("https", StringComparison.OrdinalIgnoreCase))
{ {
scenarioName = "Kestrel(SSL)";
var certPath = Path.Combine(AppContext.BaseDirectory, "TestResources", "testCert.pfx"); var certPath = Path.Combine(AppContext.BaseDirectory, "TestResources", "testCert.pfx");
Console.WriteLine($"Using SSL with certificate: {certPath}"); Console.WriteLine($"Using SSL with certificate: {certPath}");
listenOptions.UseHttps(certPath, "testPassword"); listenOptions.UseHttps(certPath, "testPassword");
} }
else
{
scenarioName = "Kestrel(NonSSL)";
}
}); });
}); });
} }
var host = builder.Build(); var host = builder.Build();
AppDomain.CurrentDomain.UnhandledException += (_, a) =>
{
Console.WriteLine($"Unhandled exception (Scenario: {scenarioName}): {a.ExceptionObject.ToString()}");
};
Console.WriteLine($"Starting Server for Scenario: {scenarioName}");
host.Run(); host.Run();
} }
} }

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Net.WebSockets; using System.Net.WebSockets;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -22,8 +22,10 @@ namespace AutobahnTestApp
if (context.WebSockets.IsWebSocketRequest) if (context.WebSockets.IsWebSocketRequest)
{ {
logger.LogInformation("Received WebSocket request"); logger.LogInformation("Received WebSocket request");
var webSocket = await context.WebSockets.AcceptWebSocketAsync(); using (var webSocket = await context.WebSockets.AcceptWebSocketAsync())
await Echo(webSocket); {
await Echo(webSocket, context.RequestAborted);
}
} }
else else
{ {
@ -35,16 +37,16 @@ namespace AutobahnTestApp
} }
private async Task Echo(WebSocket webSocket) private async Task Echo(WebSocket webSocket, CancellationToken cancellationToken)
{ {
var buffer = new byte[1024 * 4]; var buffer = new byte[1024 * 4];
var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None); var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), cancellationToken);
while (!result.CloseStatus.HasValue) while (!result.CloseStatus.HasValue)
{ {
await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None); await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, cancellationToken);
result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None); result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), cancellationToken);
} }
await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None); await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, cancellationToken);
} }
} }
} }

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -16,6 +16,7 @@ namespace Microsoft.AspNetCore.WebSockets.ConformanceTest.Autobahn
public class AutobahnTester : IDisposable public class AutobahnTester : IDisposable
{ {
private readonly List<IApplicationDeployer> _deployers = new List<IApplicationDeployer>(); private readonly List<IApplicationDeployer> _deployers = new List<IApplicationDeployer>();
private readonly List<DeploymentResult> _deployments = new List<DeploymentResult>();
private readonly List<AutobahnExpectations> _expectations = new List<AutobahnExpectations>(); private readonly List<AutobahnExpectations> _expectations = new List<AutobahnExpectations>();
private readonly ILoggerFactory _loggerFactory; private readonly ILoggerFactory _loggerFactory;
private readonly ILogger _logger; private readonly ILogger _logger;
@ -35,6 +36,10 @@ namespace Microsoft.AspNetCore.WebSockets.ConformanceTest.Autobahn
var specFile = Path.GetTempFileName(); var specFile = Path.GetTempFileName();
try try
{ {
// Start pinging the servers to see that they're still running
var pingCts = new CancellationTokenSource();
var pinger = new Timer(state => Pinger((CancellationToken)state), pingCts.Token, TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(10));
Spec.WriteJson(specFile); Spec.WriteJson(specFile);
// Run the test (write something to the console so people know this will take a while...) // Run the test (write something to the console so people know this will take a while...)
@ -44,6 +49,8 @@ namespace Microsoft.AspNetCore.WebSockets.ConformanceTest.Autobahn
{ {
throw new Exception("wstest failed"); throw new Exception("wstest failed");
} }
pingCts.Cancel();
} }
finally finally
{ {
@ -63,6 +70,42 @@ namespace Microsoft.AspNetCore.WebSockets.ConformanceTest.Autobahn
} }
} }
// Async void! It's OK here because we are running in a timer. We're just using async void to chain continuations.
// There's nobody to await this, hence async void.
private async void Pinger(CancellationToken token)
{
try
{
while (!token.IsCancellationRequested)
{
try
{
foreach (var deployment in _deployments)
{
if (token.IsCancellationRequested)
{
return;
}
var resp = await deployment.HttpClient.GetAsync("/ping", token);
if (!resp.IsSuccessStatusCode)
{
_logger.LogWarning("Non-successful response when pinging {url}: {statusCode} {reasonPhrase}", deployment.ApplicationBaseUri, resp.StatusCode, resp.ReasonPhrase);
}
}
}
catch (OperationCanceledException)
{
// We don't want to throw when the token fires, just stop.
}
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error while pinging servers");
}
}
public void Verify(AutobahnResult result) public void Verify(AutobahnResult result)
{ {
var failures = new StringBuilder(); var failures = new StringBuilder();
@ -104,6 +147,7 @@ namespace Microsoft.AspNetCore.WebSockets.ConformanceTest.Autobahn
var deployer = ApplicationDeployerFactory.Create(parameters, _loggerFactory); var deployer = ApplicationDeployerFactory.Create(parameters, _loggerFactory);
var result = await deployer.DeployAsync(); var result = await deployer.DeployAsync();
_deployers.Add(deployer); _deployers.Add(deployer);
_deployments.Add(result);
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
var handler = new HttpClientHandler(); var handler = new HttpClientHandler();
@ -114,7 +158,7 @@ namespace Microsoft.AspNetCore.WebSockets.ConformanceTest.Autobahn
// See https://github.com/dotnet/corefx/issues/9728 // See https://github.com/dotnet/corefx/issues/9728
handler.ServerCertificateCustomValidationCallback = (_, __, ___, ____) => true; handler.ServerCertificateCustomValidationCallback = (_, __, ___, ____) => true;
} }
var client = new HttpClient(handler); var client = result.CreateHttpClient(handler);
// Make sure the server works // Make sure the server works
var resp = await RetryHelper.RetryRequest(() => var resp = await RetryHelper.RetryRequest(() =>

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.IntegrationTesting; using Microsoft.AspNetCore.Server.IntegrationTesting;
using Microsoft.AspNetCore.Testing.xunit; using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.AspNetCore.WebSockets.ConformanceTest.Autobahn; using Microsoft.AspNetCore.WebSockets.ConformanceTest.Autobahn;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing; using Microsoft.Extensions.Logging.Testing;
using Xunit.Abstractions; using Xunit.Abstractions;
@ -14,6 +15,8 @@ namespace Microsoft.AspNetCore.WebSockets.ConformanceTest
{ {
public class AutobahnTests : LoggedTest public class AutobahnTests : LoggedTest
{ {
private static readonly TimeSpan TestTimeout = TimeSpan.FromMinutes(3);
public AutobahnTests(ITestOutputHelper output) : base(output) public AutobahnTests(ITestOutputHelper output) : base(output)
{ {
} }
@ -26,6 +29,7 @@ namespace Microsoft.AspNetCore.WebSockets.ConformanceTest
{ {
using (StartLog(out var loggerFactory)) using (StartLog(out var loggerFactory))
{ {
var logger = loggerFactory.CreateLogger<AutobahnTests>();
var reportDir = Environment.GetEnvironmentVariable("AUTOBAHN_SUITES_REPORT_DIR"); var reportDir = Environment.GetEnvironmentVariable("AUTOBAHN_SUITES_REPORT_DIR");
var outDir = !string.IsNullOrEmpty(reportDir) ? var outDir = !string.IsNullOrEmpty(reportDir) ?
reportDir : reportDir :
@ -44,28 +48,31 @@ namespace Microsoft.AspNetCore.WebSockets.ConformanceTest
.ExcludeCase("9.*", "12.*", "13.*"); .ExcludeCase("9.*", "12.*", "13.*");
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromMinutes(5)); // These tests generally complete in just over 1 minute. cts.CancelAfter(TestTimeout); // These tests generally complete in just over 1 minute.
AutobahnResult result; using (cts.Token.Register(() => logger.LogError("Test run is taking longer than maximum duration of {timeoutMinutes:0.00} minutes. Aborting...", TestTimeout.TotalMinutes)))
using (var tester = new AutobahnTester(loggerFactory, spec))
{ {
await tester.DeployTestAndAddToSpec(ServerType.Kestrel, ssl: false, environment: "ManagedSockets", cancellationToken: cts.Token); AutobahnResult result;
using (var tester = new AutobahnTester(loggerFactory, spec))
// Windows-only WebListener tests, and Kestrel SSL tests (due to: https://github.com/aspnet/WebSockets/issues/102)
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{ {
await tester.DeployTestAndAddToSpec(ServerType.Kestrel, ssl: true, environment: "ManagedSockets", cancellationToken: cts.Token); await tester.DeployTestAndAddToSpec(ServerType.Kestrel, ssl: false, environment: "ManagedSockets", cancellationToken: cts.Token);
if (IsWindows8OrHigher()) // Windows-only WebListener tests, and Kestrel SSL tests (due to: https://github.com/aspnet/WebSockets/issues/102)
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{ {
// WebListener occasionally gives a non-strict response on 3.2. IIS Express seems to have the same behavior. Wonder if it's related to HttpSys? await tester.DeployTestAndAddToSpec(ServerType.Kestrel, ssl: true, environment: "ManagedSockets", cancellationToken: cts.Token);
// For now, just allow the non-strict response, it's not a failure.
await tester.DeployTestAndAddToSpec(ServerType.WebListener, ssl: false, environment: "ManagedSockets", cancellationToken: cts.Token);
}
}
result = await tester.Run(cts.Token); if (IsWindows8OrHigher())
tester.Verify(result); {
// WebListener occasionally gives a non-strict response on 3.2. IIS Express seems to have the same behavior. Wonder if it's related to HttpSys?
// For now, just allow the non-strict response, it's not a failure.
await tester.DeployTestAndAddToSpec(ServerType.WebListener, ssl: false, environment: "ManagedSockets", cancellationToken: cts.Token);
}
}
result = await tester.Run(cts.Token);
tester.Verify(result);
}
} }
// If it hasn't been cancelled yet, cancel the token just to be sure // If it hasn't been cancelled yet, cancel the token just to be sure