Exemple #1
0
        public async Task RunIndividualTestCase(H2SpecTestCase testCase)
        {
            var memoryPoolFactory = new DiagnosticMemoryPoolFactory(allowLateReturn: true);

            var hostBuilder = TransportSelector.GetWebHostBuilder(memoryPoolFactory.Create)
                              .UseKestrel(options =>
            {
                options.Listen(IPAddress.Loopback, 0, listenOptions =>
                {
                    listenOptions.Protocols = HttpProtocols.Http2;
                    if (testCase.Https)
                    {
                        listenOptions.UseHttps(TestResources.TestCertificatePath, "testPassword");
                    }
                });
            })
                              .ConfigureServices(AddTestLogging)
                              .Configure(ConfigureHelloWorld);

            using (var host = hostBuilder.Build())
            {
                await host.StartAsync();

                H2SpecCommands.RunTest(testCase.Id, host.GetPort(), testCase.Https, Logger);
            }
        }
Exemple #2
0
        public async Task GracefulTurnsAbortiveIfRequestsDoNotFinish()
        {
            var requestStarted   = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously);
            var requestUnblocked = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously);

            var memoryPoolFactory = new DiagnosticMemoryPoolFactory(allowLateReturn: true);

            var testContext = new TestServiceContext(LoggerFactory)
            {
                MemoryPoolFactory = memoryPoolFactory.Create,
                ExpectedConnectionMiddlewareCount = 1
            };

            TestApplicationErrorLogger.ThrowOnUngracefulShutdown = false;

            // Abortive shutdown leaves one request hanging
            using (var server = new TestServer(async context =>
            {
                requestStarted.SetResult(null);
                await requestUnblocked.Task.DefaultTimeout();
                await context.Response.WriteAsync("hello world " + context.Request.Protocol);
            },
                                               testContext,
                                               kestrelOptions =>
            {
                kestrelOptions.Listen(IPAddress.Loopback, 0, listenOptions =>
                {
                    listenOptions.Protocols = HttpProtocols.Http2;
                    listenOptions.UseHttps(_x509Certificate2);
                });
            },
                                               _ => { }))
            {
                var requestTask = Client.GetStringAsync($"https://localhost:{server.Port}/");
                Assert.False(requestTask.IsCompleted);
                await requestStarted.Task.DefaultTimeout();

                // Wait for the graceful shutdown log before canceling the token passed to StopAsync and triggering an ungraceful shutdown.
                // Otherwise, graceful shutdown might be skipped causing there to be no corresponding log. https://github.com/aspnet/AspNetCore/issues/6556
                var closingMessageTask = TestApplicationErrorLogger.WaitForMessage(m => m.Message.Contains("is closing.")).DefaultTimeout();

                var cts            = new CancellationTokenSource();
                var stopServerTask = server.StopAsync(cts.Token).DefaultTimeout();

                await closingMessageTask;
                cts.Cancel();
                await stopServerTask;
            }

            Assert.Contains(TestApplicationErrorLogger.Messages, m => m.Message.Contains("is closing."));
            Assert.Contains(TestApplicationErrorLogger.Messages, m => m.Message.Contains("is closed. The last processed stream ID was 1."));
            Assert.Contains(TestApplicationErrorLogger.Messages, m => m.Message.Contains("Some connections failed to close gracefully during server shutdown."));
            Assert.DoesNotContain(TestApplicationErrorLogger.Messages, m => m.Message.Contains("Request finished in"));

            requestUnblocked.SetResult(null);

            await memoryPoolFactory.WhenAllBlocksReturned(TestConstants.DefaultTimeout);
        }
        public async Task GracefulTurnsAbortiveIfRequestsDoNotFinish()
        {
            var requestStarted   = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously);
            var requestUnblocked = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously);

            var memoryPoolFactory = new DiagnosticMemoryPoolFactory(allowLateReturn: true);

            var testContext = new TestServiceContext(LoggerFactory)
            {
                MemoryPoolFactory = memoryPoolFactory.Create
            };

            TestApplicationErrorLogger.ThrowOnUngracefulShutdown = false;

            // Abortive shutdown leaves one request hanging
            using (var server = new TestServer(async context =>
            {
                requestStarted.SetResult(null);
                await requestUnblocked.Task.DefaultTimeout();
                await context.Response.WriteAsync("hello world " + context.Request.Protocol);
            },
                                               testContext,
                                               kestrelOptions =>
            {
                kestrelOptions.Listen(IPAddress.Loopback, 0, listenOptions =>
                {
                    listenOptions.Protocols = HttpProtocols.Http2;
                    listenOptions.UseHttps(_x509Certificate2);
                });
            },
                                               _ => { }))
            {
                var requestTask = Client.GetStringAsync($"https://localhost:{server.Port}/");
                Assert.False(requestTask.IsCompleted);
                await requestStarted.Task.DefaultTimeout();

                await server.StopAsync(new CancellationToken(true)).DefaultTimeout();
            }

            Assert.Contains(TestApplicationErrorLogger.Messages, m => m.Message.Contains("is closing."));
            Assert.Contains(TestApplicationErrorLogger.Messages, m => m.Message.Contains("is closed. The last processed stream ID was 1."));
            Assert.Contains(TestApplicationErrorLogger.Messages, m => m.Message.Contains("Some connections failed to close gracefully during server shutdown."));
            Assert.DoesNotContain(TestApplicationErrorLogger.Messages, m => m.Message.Contains("Request finished in"));

            requestUnblocked.SetResult(null);

            await memoryPoolFactory.WhenAllBlocksReturned(TestConstants.DefaultTimeout);
        }
Exemple #4
0
    public async Task ServerShutsDownGracefullyWhenMaxRequestBufferSizeExceeded()
    {
        // Parameters
        var data = new byte[_dataLength];
        var bytesWrittenTimeout         = TimeSpan.FromMilliseconds(100);
        var bytesWrittenPollingInterval = TimeSpan.FromMilliseconds(bytesWrittenTimeout.TotalMilliseconds / 10);
        var maxSendSize = 4096;

        var startReadingRequestBody          = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
        var clientFinishedSendingRequestBody = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
        var lastBytesWritten = DateTime.MaxValue;

        var memoryPoolFactory = new DiagnosticMemoryPoolFactory(allowLateReturn: true);

        using (var host = await StartHost(16 * 1024, data, false, startReadingRequestBody, clientFinishedSendingRequestBody, memoryPoolFactory.Create))
        {
            var port = host.GetPort();
            using (var socket = CreateSocket(port))
                using (var stream = new NetworkStream(socket))
                {
                    await WritePostRequestHeaders(stream, data.Length);

                    var bytesWritten = 0;

                    Func <Task> sendFunc = async() =>
                    {
                        while (bytesWritten < data.Length)
                        {
                            var size = Math.Min(data.Length - bytesWritten, maxSendSize);
                            await stream.WriteAsync(data, bytesWritten, size).ConfigureAwait(false);

                            bytesWritten    += size;
                            lastBytesWritten = DateTime.Now;
                        }

                        clientFinishedSendingRequestBody.TrySetResult();
                    };

                    var ignore = sendFunc();

                    // The minimum is (maxRequestBufferSize - maxSendSize + 1), since if bytesWritten is
                    // (maxRequestBufferSize - maxSendSize) or smaller, the client should be able to
                    // complete another send.
                    var minimumExpectedBytesWritten = (16 * 1024) - maxSendSize + 1;

                    // The maximum is harder to determine, since there can be OS-level buffers in both the client
                    // and server, which allow the client to send more than maxRequestBufferSize before getting
                    // paused.  We assume the combined buffers are smaller than the difference between
                    // data.Length and maxRequestBufferSize.
                    var maximumExpectedBytesWritten = data.Length - 1;

                    // Block until the send task has gone a while without writing bytes AND
                    // the bytes written exceeds the minimum expected.  This indicates the server buffer
                    // is full.
                    //
                    // If the send task is paused before the expected number of bytes have been
                    // written, keep waiting since the pause may have been caused by something else
                    // like a slow machine.
                    while ((DateTime.Now - lastBytesWritten) < bytesWrittenTimeout ||
                           bytesWritten < minimumExpectedBytesWritten)
                    {
                        await Task.Delay(bytesWrittenPollingInterval);
                    }

                    // Verify the number of bytes written before the client was paused.
                    Assert.InRange(bytesWritten, minimumExpectedBytesWritten, maximumExpectedBytesWritten);

                    // Dispose host prior to closing connection to verify the server doesn't throw during shutdown
                    // if a connection no longer has alloc and read callbacks configured.
                    try
                    {
                        await host.StopAsync();
                    }
                    // Remove when https://github.com/dotnet/runtime/issues/40290 is fixed
                    catch (OperationCanceledException)
                    {
                    }
                    host.Dispose();
                }
        }
        // Allow appfunc to unblock
        startReadingRequestBody.SetResult();
        clientFinishedSendingRequestBody.SetResult();
        await memoryPoolFactory.WhenAllBlocksReturned(TestConstants.DefaultTimeout);
    }
Exemple #5
0
    // This is inherently flaky and is relying on helix retry to pass consistently
    public async Task LargeUpload(long?maxRequestBufferSize, bool connectionAdapter, bool expectPause)
    {
        // Parameters
        var data = new byte[_dataLength];
        var bytesWrittenTimeout         = TimeSpan.FromMilliseconds(100);
        var bytesWrittenPollingInterval = TimeSpan.FromMilliseconds(bytesWrittenTimeout.TotalMilliseconds / 10);
        var maxSendSize = 4096;

        var startReadingRequestBody          = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
        var clientFinishedSendingRequestBody = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
        var lastBytesWritten = DateTime.MaxValue;

        var memoryPoolFactory = new DiagnosticMemoryPoolFactory(allowLateReturn: true);

        using (var host = await StartHost(maxRequestBufferSize, data, connectionAdapter, startReadingRequestBody, clientFinishedSendingRequestBody, memoryPoolFactory.Create))
        {
            var port = host.GetPort();
            using (var socket = CreateSocket(port))
                using (var stream = new NetworkStream(socket))
                {
                    await WritePostRequestHeaders(stream, data.Length);

                    var bytesWritten = 0;

                    Func <Task> sendFunc = async() =>
                    {
                        while (bytesWritten < data.Length)
                        {
                            var size = Math.Min(data.Length - bytesWritten, maxSendSize);
                            await stream.WriteAsync(data, bytesWritten, size).ConfigureAwait(false);

                            bytesWritten    += size;
                            lastBytesWritten = DateTime.Now;
                        }

                        Assert.Equal(data.Length, bytesWritten);
                        clientFinishedSendingRequestBody.TrySetResult();
                    };

                    var sendTask = sendFunc();

                    if (expectPause)
                    {
                        // The minimum is (maxRequestBufferSize - maxSendSize + 1), since if bytesWritten is
                        // (maxRequestBufferSize - maxSendSize) or smaller, the client should be able to
                        // complete another send.
                        var minimumExpectedBytesWritten = maxRequestBufferSize.Value - maxSendSize + 1;

                        // The maximum is harder to determine, since there can be OS-level buffers in both the client
                        // and server, which allow the client to send more than maxRequestBufferSize before getting
                        // paused.  We assume the combined buffers are smaller than the difference between
                        // data.Length and maxRequestBufferSize.
                        var maximumExpectedBytesWritten = data.Length - 1;

                        // Block until the send task has gone a while without writing bytes AND
                        // the bytes written exceeds the minimum expected.  This indicates the server buffer
                        // is full.
                        //
                        // If the send task is paused before the expected number of bytes have been
                        // written, keep waiting since the pause may have been caused by something else
                        // like a slow machine.
                        while ((DateTime.Now - lastBytesWritten) < bytesWrittenTimeout ||
                               bytesWritten < minimumExpectedBytesWritten)
                        {
                            await Task.Delay(bytesWrittenPollingInterval);
                        }

                        // Verify the number of bytes written before the client was paused.
                        Assert.InRange(bytesWritten, minimumExpectedBytesWritten, maximumExpectedBytesWritten);

                        // Tell server to start reading request body
                        startReadingRequestBody.TrySetResult();

                        // Wait for sendTask to finish sending the remaining bytes
                        await sendTask;
                    }
                    else
                    {
                        // Ensure all bytes can be sent before the server starts reading
                        await sendTask;

                        // Tell server to start reading request body
                        startReadingRequestBody.TrySetResult();
                    }

                    await AssertStreamContains(stream, $"bytesRead: {data.Length}");
                }
            await host.StopAsync();
        }

        await memoryPoolFactory.WhenAllBlocksReturned(TestConstants.DefaultTimeout);
    }