Fix App_offline and start adding tests (#953)
This commit is contained in:
parent
cd81cfc243
commit
306ab78b88
|
|
@ -118,6 +118,8 @@ APPLICATION_MANAGER::GetOrCreateApplicationInfo(
|
|||
}
|
||||
|
||||
*ppApplicationInfo = pApplicationInfo;
|
||||
pApplicationInfo->StartMonitoringAppOffline();
|
||||
|
||||
pApplicationInfo = NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
Loading…
Reference in New Issue