Start adding configuration reload tests (#1212)
This commit is contained in:
parent
f1c1f82e8b
commit
d725972355
|
|
@ -47,8 +47,9 @@ PrintDebugHeader()
|
|||
RETURN_LAST_ERROR_IF(!VerQueryValue(verData.data(), _T("\\StringFileInfo\\040904b0\\FileDescription"), &pvProductName, &iProductNameLen));
|
||||
|
||||
// Major, minor are stored in dwFileVersionMS field and patch, build in dwFileVersionLS field as pair of 32 bit numbers
|
||||
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, "Initializing logs for %S. File Version: %d.%d.%d.%d. Description: %S",
|
||||
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, "Initializing logs for %S. ProcessId: %d. File Version: %d.%d.%d.%d. Description: %S",
|
||||
path,
|
||||
GetCurrentProcessId(),
|
||||
( verInfo->dwFileVersionMS >> 16 ) & 0xffff,
|
||||
( verInfo->dwFileVersionMS >> 0 ) & 0xffff,
|
||||
( verInfo->dwFileVersionLS >> 16 ) & 0xffff,
|
||||
|
|
|
|||
|
|
@ -123,47 +123,61 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
|
|||
|
||||
private void GetLogsFromFile()
|
||||
{
|
||||
// Handle cases where debug file is redirected by test
|
||||
var debugLogLocations = new List<string>();
|
||||
if (IISDeploymentParameters.HandlerSettings.ContainsKey("debugFile"))
|
||||
try
|
||||
{
|
||||
debugLogLocations.Add(IISDeploymentParameters.HandlerSettings["debugFile"]);
|
||||
}
|
||||
|
||||
if (DeploymentParameters.EnvironmentVariables.ContainsKey("ASPNETCORE_MODULE_DEBUG_FILE"))
|
||||
{
|
||||
debugLogLocations.Add(DeploymentParameters.EnvironmentVariables["ASPNETCORE_MODULE_DEBUG_FILE"]);
|
||||
}
|
||||
|
||||
// default debug file name
|
||||
debugLogLocations.Add("aspnetcore-debug.log");
|
||||
|
||||
foreach (var debugLogLocation in debugLogLocations)
|
||||
{
|
||||
if (string.IsNullOrEmpty(debugLogLocation))
|
||||
// Handle cases where debug file is redirected by test
|
||||
var debugLogLocations = new List<string>();
|
||||
if (IISDeploymentParameters.HandlerSettings.ContainsKey("debugFile"))
|
||||
{
|
||||
continue;
|
||||
debugLogLocations.Add(IISDeploymentParameters.HandlerSettings["debugFile"]);
|
||||
}
|
||||
|
||||
var file = Path.Combine(DeploymentParameters.PublishedApplicationRootPath, debugLogLocation);
|
||||
if (File.Exists(file))
|
||||
if (DeploymentParameters.EnvironmentVariables.ContainsKey("ASPNETCORE_MODULE_DEBUG_FILE"))
|
||||
{
|
||||
var lines = File.ReadAllLines(file);
|
||||
if (!lines.Any())
|
||||
debugLogLocations.Add(DeploymentParameters.EnvironmentVariables["ASPNETCORE_MODULE_DEBUG_FILE"]);
|
||||
}
|
||||
|
||||
// default debug file name
|
||||
debugLogLocations.Add("aspnetcore-debug.log");
|
||||
|
||||
foreach (var debugLogLocation in debugLogLocations)
|
||||
{
|
||||
if (string.IsNullOrEmpty(debugLogLocation))
|
||||
{
|
||||
Logger.LogInformation("Debug log file found but was empty");
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var line in lines)
|
||||
var file = Path.Combine(DeploymentParameters.PublishedApplicationRootPath, debugLogLocation);
|
||||
if (File.Exists(file))
|
||||
{
|
||||
Logger.LogInformation(line);
|
||||
var lines = File.ReadAllLines(file);
|
||||
if (!lines.Any())
|
||||
{
|
||||
Logger.LogInformation($"Debug log file {file} found but was empty");
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var line in lines)
|
||||
{
|
||||
Logger.LogInformation(line);
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ANCM V1 does not support logs
|
||||
if (DeploymentParameters.AncmVersion == AncmVersion.AspNetCoreModuleV2)
|
||||
{
|
||||
throw new InvalidOperationException($"Unable to find non-empty debug log files. Tried: {string.Join(", ", debugLogLocations)}");
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (File.Exists(_debugLogFile))
|
||||
{
|
||||
File.Delete(_debugLogFile);
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Not able to find non-empty debug log files. Tried: {string.Join(", ", debugLogLocations)}");
|
||||
}
|
||||
|
||||
public void StartIIS(Uri uri, string contentRoot)
|
||||
|
|
@ -339,6 +353,12 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
|
|||
throw new InvalidOperationException("Site not stopped yet");
|
||||
}
|
||||
|
||||
if (appPool.WorkerProcesses.Any(wp => wp.State == WorkerProcessState.Running ||
|
||||
wp.State == WorkerProcessState.Stopping))
|
||||
{
|
||||
throw new InvalidOperationException("WorkerProcess not stopped yet");
|
||||
}
|
||||
|
||||
if (!HostProcess.HasExited)
|
||||
{
|
||||
throw new InvalidOperationException("Site is stopped but host process is not");
|
||||
|
|
|
|||
|
|
@ -82,7 +82,6 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
|||
}
|
||||
|
||||
[ConditionalFact]
|
||||
[RequiresIIS(IISCapability.ShutdownToken)]
|
||||
public async Task AppOfflineDroppedWhileSiteFailedToStartInRequestHandler_SiteStops_InProcess()
|
||||
{
|
||||
var deploymentResult = await DeployApp(HostingModel.InProcess);
|
||||
|
|
@ -95,7 +94,8 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
|||
Assert.Contains("500.30", await result.Content.ReadAsStringAsync());
|
||||
|
||||
AddAppOffline(deploymentResult.ContentRoot);
|
||||
AssertStopsProcess(deploymentResult);
|
||||
|
||||
await deploymentResult.AssertRecycledAsync(() => AssertAppOffline(deploymentResult));
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
|
|
@ -130,7 +130,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
|||
}
|
||||
catch
|
||||
{
|
||||
AssertStopsProcess(deploymentResult);
|
||||
deploymentResult.AssertWorkerProcessStop();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -139,18 +139,16 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
|||
}
|
||||
|
||||
[ConditionalFact]
|
||||
[RequiresIIS(IISCapability.ShutdownToken)]
|
||||
public async Task AppOfflineDroppedWhileSiteRunning_SiteShutsDown_InProcess()
|
||||
{
|
||||
var deploymentResult = await AssertStarts(HostingModel.InProcess);
|
||||
|
||||
AddAppOffline(deploymentResult.ContentRoot);
|
||||
|
||||
AssertStopsProcess(deploymentResult);
|
||||
await deploymentResult.AssertRecycledAsync(() => AssertAppOffline(deploymentResult));
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
[RequiresIIS(IISCapability.ShutdownToken)]
|
||||
public async Task AppOfflineDroppedWhileSiteRunning_SiteShutsDown_OutOfProcess()
|
||||
{
|
||||
var deploymentResult = await AssertStarts(HostingModel.OutOfProcess);
|
||||
|
|
@ -245,28 +243,10 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
|||
|
||||
private async Task AssertAppOffline(IISDeploymentResult deploymentResult, string expectedResponse = "The app is offline.")
|
||||
{
|
||||
HttpResponseMessage response = null;
|
||||
|
||||
for (var i = 0; i < 5 && response?.StatusCode != HttpStatusCode.ServiceUnavailable; i++)
|
||||
{
|
||||
// Keep retrying until app_offline is present.
|
||||
response = await deploymentResult.HttpClient.GetAsync("HelloWorld");
|
||||
await Task.Delay(RetryDelay);
|
||||
}
|
||||
|
||||
Assert.Equal(HttpStatusCode.ServiceUnavailable, response.StatusCode);
|
||||
|
||||
var response = await deploymentResult.HttpClient.RetryRequestAsync("HelloWorld", r => r.StatusCode == HttpStatusCode.ServiceUnavailable);
|
||||
Assert.Equal(expectedResponse, await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
private void AssertStopsProcess(IISDeploymentResult deploymentResult)
|
||||
{
|
||||
var hostShutdownToken = deploymentResult.HostShutdownToken;
|
||||
|
||||
Assert.True(hostShutdownToken.WaitHandle.WaitOne(TimeoutExtensions.DefaultTimeout));
|
||||
Assert.True(hostShutdownToken.IsCancellationRequested);
|
||||
}
|
||||
|
||||
private async Task<IISDeploymentResult> AssertStarts(HostingModel hostingModel)
|
||||
{
|
||||
var deploymentResult = await DeployApp(hostingModel);
|
||||
|
|
@ -278,14 +258,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
|||
|
||||
private static async Task AssertRunning(IISDeploymentResult deploymentResult)
|
||||
{
|
||||
HttpResponseMessage response = null;
|
||||
|
||||
for (var i = 0; i < 5 && response?.IsSuccessStatusCode != true; i++)
|
||||
{
|
||||
response = await deploymentResult.HttpClient.GetAsync("HelloWorld");
|
||||
await Task.Delay(RetryDelay);
|
||||
}
|
||||
|
||||
var response = await deploymentResult.HttpClient.RetryRequestAsync("HelloWorld", r => r.IsSuccessStatusCode);
|
||||
var responseText = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal("Hello World", responseText);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
// 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.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
|
||||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||
{
|
||||
[Collection(PublishedSitesCollection.Name)]
|
||||
public class ConfigurationChangeTests : IISFunctionalTestBase
|
||||
{
|
||||
private readonly PublishedSitesFixture _fixture;
|
||||
|
||||
public ConfigurationChangeTests(PublishedSitesFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task ConfigurationChangeStopsInProcess()
|
||||
{
|
||||
var deploymentParameters = _fixture.GetBaseDeploymentParameters(HostingModel.InProcess, publish: true);
|
||||
|
||||
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||
|
||||
await deploymentResult.AssertStarts();
|
||||
|
||||
// Just "touching" web.config should be enough
|
||||
deploymentResult.ModifyWebConfig(element => {});
|
||||
|
||||
await deploymentResult.AssertRecycledAsync();
|
||||
}
|
||||
|
||||
[ConditionalTheory]
|
||||
[InlineData(AncmVersion.AspNetCoreModule)]
|
||||
[InlineData(AncmVersion.AspNetCoreModuleV2)]
|
||||
public async Task ConfigurationChangeForcesChildProcessRestart(AncmVersion version)
|
||||
{
|
||||
var deploymentParameters = _fixture.GetBaseDeploymentParameters(HostingModel.OutOfProcess, publish: true);
|
||||
deploymentParameters.AncmVersion = version;
|
||||
|
||||
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||
|
||||
var processBefore = await deploymentResult.HttpClient.GetStringAsync("/ProcessId");
|
||||
|
||||
// Just "touching" web.config should be enough
|
||||
deploymentResult.ModifyWebConfig(element => {});
|
||||
|
||||
// Have to retry here to allow ANCM to receive notification and react to it
|
||||
// Verify that worker process gets restarted with new process id
|
||||
await deploymentResult.HttpClient.RetryRequestAsync("/ProcessId", async r => await r.Content.ReadAsStringAsync() != processBefore);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
|
@ -18,6 +17,9 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
{
|
||||
public static class Helpers
|
||||
{
|
||||
private static readonly TimeSpan RetryRequestDelay = TimeSpan.FromMilliseconds(100);
|
||||
private static readonly int RetryRequestCount = 5;
|
||||
|
||||
public static string GetTestWebSitePath(string name)
|
||||
{
|
||||
return Path.Combine(TestPathUtilities.GetSolutionRootDirectory("IISIntegration"),"test", "WebSites", name);
|
||||
|
|
@ -26,9 +28,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
public static string GetInProcessTestSitesPath() => GetTestWebSitePath("InProcessWebSite");
|
||||
|
||||
public static string GetOutOfProcessTestSitesPath() => GetTestWebSitePath("OutOfProcessWebSite");
|
||||
|
||||
|
||||
public static async Task AssertStarts(IISDeploymentResult deploymentResult, string path = "/HelloWorld")
|
||||
public static async Task AssertStarts(this IISDeploymentResult deploymentResult, string path = "/HelloWorld")
|
||||
{
|
||||
var response = await deploymentResult.HttpClient.GetAsync(path);
|
||||
|
||||
|
|
@ -73,5 +74,64 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
fileInfo.CopyTo(destFileName);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ModifyWebConfig(this DeploymentResult deploymentResult, Action<XElement> action)
|
||||
{
|
||||
var webConfigPath = Path.Combine(deploymentResult.ContentRoot, "web.config");
|
||||
var document = XDocument.Load(webConfigPath);
|
||||
|
||||
document.Save(webConfigPath);
|
||||
}
|
||||
|
||||
public static Task<HttpResponseMessage> RetryRequestAsync(this HttpClient client, string uri, Func<HttpResponseMessage, bool> predicate)
|
||||
{
|
||||
return RetryRequestAsync(client, uri, message => Task.FromResult(predicate(message)));
|
||||
}
|
||||
|
||||
public static async Task<HttpResponseMessage> RetryRequestAsync(this HttpClient client, string uri, Func<HttpResponseMessage, Task<bool>> predicate)
|
||||
{
|
||||
HttpResponseMessage response = await client.GetAsync(uri);
|
||||
|
||||
for (var i = 0; i < RetryRequestCount && !await predicate(response); i++)
|
||||
{
|
||||
// Keep retrying until app_offline is present.
|
||||
response = await client.GetAsync(uri);
|
||||
await Task.Delay(RetryRequestDelay);
|
||||
}
|
||||
|
||||
if (!await predicate(response))
|
||||
{
|
||||
throw new InvalidOperationException($"Didn't get response that satisfies predicate after {RetryRequestCount} retries");
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public static void AssertWorkerProcessStop(this IISDeploymentResult deploymentResult)
|
||||
{
|
||||
var hostProcess = deploymentResult.HostProcess;
|
||||
Assert.True(hostProcess.WaitForExit((int)TimeoutExtensions.DefaultTimeout.TotalMilliseconds));
|
||||
|
||||
if (deploymentResult.DeploymentParameters.ServerType == ServerType.IISExpress)
|
||||
{
|
||||
Assert.Equal(0, hostProcess.ExitCode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static async Task AssertRecycledAsync(this IISDeploymentResult deploymentResult, Func<Task> verificationAction = null)
|
||||
{
|
||||
if (deploymentResult.DeploymentParameters.HostingModel != HostingModel.InProcess)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
deploymentResult.AssertWorkerProcessStop();
|
||||
if (deploymentResult.DeploymentParameters.ServerType == ServerType.IIS)
|
||||
{
|
||||
verificationAction = verificationAction ?? (() => deploymentResult.AssertStarts());
|
||||
await verificationAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue