Fix App_offline and start adding tests (#953)

This commit is contained in:
Justin Kotalik 2018-06-21 16:35:11 -07:00 committed by GitHub
parent cd81cfc243
commit 306ab78b88
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 146 additions and 6 deletions

View File

@ -118,6 +118,8 @@ APPLICATION_MANAGER::GetOrCreateApplicationInfo(
}
*ppApplicationInfo = pApplicationInfo;
pApplicationInfo->StartMonitoringAppOffline();
pApplicationInfo = NULL;
}

View File

@ -232,14 +232,18 @@ IN_PROCESS_APPLICATION::Recycle(
if (!m_pHttpServer->IsCommandLineLaunch())
{
// IIS scenario.
// notify IIS first so that new request will be routed to new worker process
// We don't actually handle any shutdown logic here.
// Instead, we notify IIS that the process needs to be recycled, which will call
// ApplicationManager->Shutdown(). This will call shutdown on the application.
m_pHttpServer->RecycleProcess(L"AspNetCore InProcess Recycle Process on Demand");
}
else
{
// IISExpress scenario
// Shutdown the managed application and call exit to terminate current process
// Try to graceful shutdown the managed application
// and call exit to terminate current process
ShutDown();
exit(0);
}
}

View File

@ -118,8 +118,8 @@ OUT_OF_PROCESS_APPLICATION::SetWebsocketStatus(
IHttpContext* pHttpContext
)
{
// Even though the applicationhost.config file contains the websocket element,
// the websocket module may still not be enabled.
// Even though the applicationhost.config file contains the websocket element,
// the websocket module may still not be enabled.
PCWSTR pszTempWebsocketValue;
DWORD cbLength;
HRESULT hr;

View File

@ -0,0 +1,135 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using IISIntegration.FunctionalTests.Utilities;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests;
using Microsoft.AspNetCore.Server.IntegrationTesting;
using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.Extensions.Logging;
using Xunit;
namespace IISIntegration.FunctionalTests.Inprocess
{
[SkipIfIISExpressSchemaMissingInProcess]
public class AppOfflineTests : IISFunctionalTestBase
{
[ConditionalFact]
public async Task AppOfflineDroppedWhileSiteIsDown_SiteReturns503()
{
var deploymentResult = await DeployApp();
AddAppOffline(deploymentResult.DeploymentResult.ContentRoot);
await AssertAppOffline(deploymentResult);
}
[ConditionalFact]
public async Task AppOfflineDroppedWhileSiteIsDown_CustomResponse()
{
var expectedResponse = "The app is offline.";
var deploymentResult = await DeployApp();
AddAppOffline(deploymentResult.DeploymentResult.ContentRoot, expectedResponse);
await AssertAppOffline(deploymentResult, expectedResponse);
}
[ConditionalFact]
public async Task AppOfflineDroppedWhileSiteRunning_SiteShutsDown()
{
var deploymentResult = await AssertStarts();
AddAppOffline(deploymentResult.DeploymentResult.ContentRoot);
await AssertStopsProcess(deploymentResult);
}
[ConditionalFact]
public async Task AppOfflineDropped_CanRemoveAppOfflineAfterAddingAndSiteWorks()
{
var deploymentResult = await DeployApp();
AddAppOffline(deploymentResult.DeploymentResult.ContentRoot);
await AssertAppOffline(deploymentResult);
RemoveAppOffline(deploymentResult.DeploymentResult.ContentRoot);
var response = await deploymentResult.HttpClient.GetAsync("HelloWorld");
}
private async Task<IISDeploymentResult> DeployApp()
{
var deploymentParameters = Helpers.GetBaseDeploymentParameters();
return await DeployAsync(deploymentParameters);
}
private void AddAppOffline(string appPath, string content = "")
{
File.WriteAllText(Path.Combine(appPath, "app_offline.htm"), content);
}
private void RemoveAppOffline(string appPath)
{
RetryHelper.RetryOperation(
() => File.Delete(Path.Combine(appPath, "app_offline.htm")),
e => Logger.LogError($"Failed to remove app_offline : {e.Message}"),
retryCount: 3,
retryDelayMilliseconds: 100);
}
private async Task AssertAppOffline(IISDeploymentResult deploymentResult, string expectedResponse = "")
{
var response = await deploymentResult.HttpClient.GetAsync("HelloWorld");
for (var i = 0; response.IsSuccessStatusCode && i < 5; i++)
{
// Keep retrying until app_offline is present.
response = await deploymentResult.HttpClient.GetAsync("HelloWorld");
}
Assert.Equal(HttpStatusCode.ServiceUnavailable, response.StatusCode);
Assert.Equal(expectedResponse, await response.Content.ReadAsStringAsync());
}
private async Task AssertStopsProcess(IISDeploymentResult deploymentResult)
{
try
{
var response = await deploymentResult.RetryingHttpClient.GetAsync("HelloWorld");
}
catch (HttpRequestException)
{
// dropping app_offline will kill the process
}
var hostShutdownToken = deploymentResult.DeploymentResult.HostShutdownToken;
Assert.True(hostShutdownToken.WaitHandle.WaitOne(millisecondsTimeout: 1000));
Assert.True(hostShutdownToken.IsCancellationRequested);
}
private async Task<IISDeploymentResult> AssertStarts()
{
var deploymentParameters = Helpers.GetBaseDeploymentParameters();
var deploymentResult = await DeployAsync(deploymentParameters);
var response = await deploymentResult.RetryingHttpClient.GetAsync("HelloWorld");
var responseText = await response.Content.ReadAsStringAsync();
Assert.Equal("Hello World", responseText);
return deploymentResult;
}
}
}

View File

@ -95,7 +95,6 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
Assert.Equal("Hello World", responseText);
}
public static TestMatrix TestVariants
=> TestMatrix.ForServers(ServerType.IISExpress)
.WithTfms(Tfm.NetCoreApp22)

View File

@ -22,7 +22,7 @@ namespace IISIntegration.FunctionalTests.Inprocess
[ConditionalFact]
[OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, "https://github.com/aspnet/IISIntegration/issues/866")]
public async Task Test()
public async Task SingleProcessTestServer_HelloWorld()
{
var helloWorld = "Hello World";
var expectedPath = "/Path";