-
Notifications
You must be signed in to change notification settings - Fork 816
React to SIGTERM exit code change #1289
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
51bd6e3
Port IntegrationTesting
Tratcher d1753d0
Port functional tests
Tratcher 6fcfaeb
Remove unused class
Tratcher 32ef94a
Remove unused helper
Tratcher f8941a0
Reset exit code
Tratcher 503b6f9
Cleaned up, rebased
Tratcher c95e5b5
Remove extra constructor
Tratcher 7c2b436
TrySetResult
Tratcher File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
129 changes: 129 additions & 0 deletions
129
src/Hosting/IntegrationTesting/src/ApplicationPublisher.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
// 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.Diagnostics; | ||
using System.IO; | ||
using System.Runtime.InteropServices; | ||
using System.Threading.Tasks; | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace Microsoft.Extensions.Hosting.IntegrationTesting | ||
{ | ||
public class ApplicationPublisher | ||
{ | ||
public string ApplicationPath { get; } | ||
|
||
public ApplicationPublisher(string applicationPath) | ||
{ | ||
ApplicationPath = applicationPath; | ||
} | ||
|
||
public static readonly string DotnetCommandName = "dotnet"; | ||
|
||
public virtual Task<PublishedApplication> Publish(DeploymentParameters deploymentParameters, ILogger logger) | ||
{ | ||
var publishDirectory = CreateTempDirectory(); | ||
using (logger.BeginScope("dotnet-publish")) | ||
{ | ||
if (string.IsNullOrEmpty(deploymentParameters.TargetFramework)) | ||
{ | ||
throw new Exception($"A target framework must be specified in the deployment parameters for applications that require publishing before deployment"); | ||
} | ||
|
||
var parameters = $"publish " | ||
+ $" --output \"{publishDirectory.FullName}\"" | ||
+ $" --framework {deploymentParameters.TargetFramework}" | ||
+ $" --configuration {deploymentParameters.Configuration}" | ||
+ $" /p:TargetArchitecture={deploymentParameters.RuntimeArchitecture}" | ||
+ " --no-restore"; | ||
|
||
if (deploymentParameters.ApplicationType == ApplicationType.Standalone) | ||
{ | ||
parameters += $" --runtime {GetRuntimeIdentifier(deploymentParameters)}"; | ||
} | ||
else | ||
{ | ||
// Workaround for https://github.com/aspnet/websdk/issues/422 | ||
parameters += " -p:UseAppHost=false"; | ||
} | ||
|
||
parameters += $" {deploymentParameters.AdditionalPublishParameters}"; | ||
|
||
var startInfo = new ProcessStartInfo | ||
{ | ||
FileName = DotnetCommandName, | ||
Arguments = parameters, | ||
UseShellExecute = false, | ||
CreateNoWindow = true, | ||
RedirectStandardError = true, | ||
RedirectStandardOutput = true, | ||
WorkingDirectory = deploymentParameters.ApplicationPath, | ||
}; | ||
|
||
ProcessHelpers.AddEnvironmentVariablesToProcess(startInfo, deploymentParameters.PublishEnvironmentVariables, logger); | ||
|
||
var hostProcess = new Process() { StartInfo = startInfo }; | ||
|
||
logger.LogInformation($"Executing command {DotnetCommandName} {parameters}"); | ||
|
||
hostProcess.StartAndCaptureOutAndErrToLogger("dotnet-publish", logger); | ||
|
||
// A timeout is passed to Process.WaitForExit() for two reasons: | ||
// | ||
// 1. When process output is read asynchronously, WaitForExit() without a timeout blocks until child processes | ||
// are killed, which can cause hangs due to MSBuild NodeReuse child processes started by dotnet.exe. | ||
// With a timeout, WaitForExit() returns when the parent process is killed and ignores child processes. | ||
// https://stackoverflow.com/a/37983587/102052 | ||
// | ||
// 2. If "dotnet publish" does hang indefinitely for some reason, tests should fail fast with an error message. | ||
const int timeoutMinutes = 5; | ||
if (hostProcess.WaitForExit(milliseconds: timeoutMinutes * 60 * 1000)) | ||
{ | ||
if (hostProcess.ExitCode != 0) | ||
{ | ||
var message = $"{DotnetCommandName} publish exited with exit code : {hostProcess.ExitCode}"; | ||
logger.LogError(message); | ||
throw new Exception(message); | ||
} | ||
} | ||
else | ||
{ | ||
var message = $"{DotnetCommandName} publish failed to exit after {timeoutMinutes} minutes"; | ||
logger.LogError(message); | ||
throw new Exception(message); | ||
} | ||
|
||
logger.LogInformation($"{DotnetCommandName} publish finished with exit code : {hostProcess.ExitCode}"); | ||
} | ||
|
||
return Task.FromResult(new PublishedApplication(publishDirectory.FullName, logger)); | ||
} | ||
|
||
private static string GetRuntimeIdentifier(DeploymentParameters deploymentParameters) | ||
{ | ||
var architecture = deploymentParameters.RuntimeArchitecture; | ||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) | ||
{ | ||
return "win-" + architecture; | ||
} | ||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) | ||
{ | ||
return "linux-" + architecture; | ||
} | ||
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) | ||
{ | ||
return "osx-" + architecture; | ||
} | ||
throw new InvalidOperationException("Unrecognized operation system platform"); | ||
} | ||
|
||
protected static DirectoryInfo CreateTempDirectory() | ||
{ | ||
var tempPath = Path.GetTempPath() + Guid.NewGuid().ToString("N"); | ||
var target = new DirectoryInfo(tempPath); | ||
target.Create(); | ||
return target; | ||
} | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
src/Hosting/IntegrationTesting/src/Common/ApplicationType.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// 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. | ||
|
||
namespace Microsoft.Extensions.Hosting.IntegrationTesting | ||
{ | ||
public enum ApplicationType | ||
{ | ||
/// <summary> | ||
/// Does not target a specific platform. Requires the matching runtime to be installed. | ||
/// </summary> | ||
Portable, | ||
|
||
/// <summary> | ||
/// All dlls are published with the app for x-copy deploy. Net461 requires this because ASP.NET Core is not in the GAC. | ||
/// </summary> | ||
Standalone | ||
} | ||
} |
157 changes: 157 additions & 0 deletions
157
src/Hosting/IntegrationTesting/src/Common/DeploymentParameters.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
// 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.Collections.Generic; | ||
using System.IO; | ||
using System.Reflection; | ||
|
||
namespace Microsoft.Extensions.Hosting.IntegrationTesting | ||
{ | ||
/// <summary> | ||
/// Parameters to control application deployment. | ||
/// </summary> | ||
public class DeploymentParameters | ||
{ | ||
public DeploymentParameters() | ||
{ | ||
var configAttribute = Assembly.GetCallingAssembly().GetCustomAttribute<AssemblyConfigurationAttribute>(); | ||
if (configAttribute != null && !string.IsNullOrEmpty(configAttribute.Configuration)) | ||
{ | ||
Configuration = configAttribute.Configuration; | ||
} | ||
} | ||
|
||
public DeploymentParameters(TestVariant variant) | ||
{ | ||
var configAttribute = Assembly.GetCallingAssembly().GetCustomAttribute<AssemblyConfigurationAttribute>(); | ||
if (configAttribute != null && !string.IsNullOrEmpty(configAttribute.Configuration)) | ||
{ | ||
Configuration = configAttribute.Configuration; | ||
} | ||
|
||
TargetFramework = variant.Tfm; | ||
ApplicationType = variant.ApplicationType; | ||
RuntimeArchitecture = variant.Architecture; | ||
} | ||
|
||
/// <summary> | ||
/// Creates an instance of <see cref="DeploymentParameters"/>. | ||
/// </summary> | ||
/// <param name="applicationPath">Source code location of the target location to be deployed.</param> | ||
/// <param name="runtimeFlavor">Flavor of the clr to run against.</param> | ||
/// <param name="runtimeArchitecture">Architecture of the runtime to be used.</param> | ||
public DeploymentParameters( | ||
string applicationPath, | ||
RuntimeFlavor runtimeFlavor, | ||
RuntimeArchitecture runtimeArchitecture) | ||
{ | ||
if (string.IsNullOrEmpty(applicationPath)) | ||
{ | ||
throw new ArgumentException("Value cannot be null.", nameof(applicationPath)); | ||
} | ||
|
||
if (!Directory.Exists(applicationPath)) | ||
{ | ||
throw new DirectoryNotFoundException(string.Format("Application path {0} does not exist.", applicationPath)); | ||
} | ||
|
||
ApplicationPath = applicationPath; | ||
ApplicationName = new DirectoryInfo(ApplicationPath).Name; | ||
RuntimeFlavor = runtimeFlavor; | ||
|
||
var configAttribute = Assembly.GetCallingAssembly().GetCustomAttribute<AssemblyConfigurationAttribute>(); | ||
if (configAttribute != null && !string.IsNullOrEmpty(configAttribute.Configuration)) | ||
{ | ||
Configuration = configAttribute.Configuration; | ||
} | ||
} | ||
|
||
public DeploymentParameters(DeploymentParameters parameters) | ||
{ | ||
foreach (var propertyInfo in typeof(DeploymentParameters).GetProperties()) | ||
{ | ||
if (propertyInfo.CanWrite) | ||
{ | ||
propertyInfo.SetValue(this, propertyInfo.GetValue(parameters)); | ||
} | ||
} | ||
|
||
foreach (var kvp in parameters.EnvironmentVariables) | ||
{ | ||
EnvironmentVariables.Add(kvp); | ||
} | ||
|
||
foreach (var kvp in parameters.PublishEnvironmentVariables) | ||
{ | ||
PublishEnvironmentVariables.Add(kvp); | ||
} | ||
} | ||
|
||
public ApplicationPublisher ApplicationPublisher { get; set; } | ||
|
||
public RuntimeFlavor RuntimeFlavor { get; set; } | ||
|
||
public RuntimeArchitecture RuntimeArchitecture { get; set; } = RuntimeArchitecture.x64; | ||
|
||
public string EnvironmentName { get; set; } | ||
|
||
public string ApplicationPath { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets the name of the application. This is used to execute the application when deployed. | ||
/// Defaults to the file name of <see cref="ApplicationPath"/>. | ||
/// </summary> | ||
public string ApplicationName { get; set; } | ||
|
||
public string TargetFramework { get; set; } | ||
|
||
/// <summary> | ||
/// Configuration under which to build (ex: Release or Debug) | ||
/// </summary> | ||
public string Configuration { get; set; } = "Debug"; | ||
|
||
/// <summary> | ||
/// Space separated command line arguments to be passed to dotnet-publish | ||
/// </summary> | ||
public string AdditionalPublishParameters { get; set; } | ||
|
||
/// <summary> | ||
/// To publish the application before deployment. | ||
/// </summary> | ||
public bool PublishApplicationBeforeDeployment { get; set; } | ||
|
||
public bool PreservePublishedApplicationForDebugging { get; set; } = false; | ||
|
||
public bool StatusMessagesEnabled { get; set; } = true; | ||
|
||
public ApplicationType ApplicationType { get; set; } | ||
|
||
public string PublishedApplicationRootPath { get; set; } | ||
|
||
/// <summary> | ||
/// Environment variables to be set before starting the host. | ||
/// Not applicable for IIS Scenarios. | ||
/// </summary> | ||
public IDictionary<string, string> EnvironmentVariables { get; } = new Dictionary<string, string>(); | ||
|
||
/// <summary> | ||
/// Environment variables used when invoking dotnet publish. | ||
/// </summary> | ||
public IDictionary<string, string> PublishEnvironmentVariables { get; } = new Dictionary<string, string>(); | ||
|
||
/// <summary> | ||
/// For any application level cleanup to be invoked after performing host cleanup. | ||
/// </summary> | ||
public Action<DeploymentParameters> UserAdditionalCleanup { get; set; } | ||
|
||
public override string ToString() | ||
{ | ||
return string.Format( | ||
"[Variation] :: Runtime={0}, Arch={1}, Publish={2}", | ||
RuntimeFlavor, | ||
RuntimeArchitecture, | ||
PublishApplicationBeforeDeployment); | ||
} | ||
} | ||
} |
47 changes: 47 additions & 0 deletions
47
src/Hosting/IntegrationTesting/src/Common/DeploymentResult.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// 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.Net.Http; | ||
using System.Threading; | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace Microsoft.Extensions.Hosting.IntegrationTesting | ||
{ | ||
/// <summary> | ||
/// Result of a deployment. | ||
/// </summary> | ||
public class DeploymentResult | ||
JunTaoLuo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
private readonly ILoggerFactory _loggerFactory; | ||
|
||
/// <summary> | ||
/// The folder where the application is hosted. This path can be different from the | ||
/// original application source location if published before deployment. | ||
/// </summary> | ||
public string ContentRoot { get; } | ||
|
||
/// <summary> | ||
/// Original deployment parameters used for this deployment. | ||
/// </summary> | ||
public DeploymentParameters DeploymentParameters { get; } | ||
|
||
/// <summary> | ||
/// Triggered when the host process dies or pulled down. | ||
/// </summary> | ||
public CancellationToken HostShutdownToken { get; } | ||
|
||
public DeploymentResult(ILoggerFactory loggerFactory, DeploymentParameters deploymentParameters) | ||
: this(loggerFactory, deploymentParameters: deploymentParameters, contentRoot: string.Empty, hostShutdownToken: CancellationToken.None) | ||
{ } | ||
|
||
public DeploymentResult(ILoggerFactory loggerFactory, DeploymentParameters deploymentParameters, string contentRoot, CancellationToken hostShutdownToken) | ||
{ | ||
_loggerFactory = loggerFactory; | ||
|
||
ContentRoot = contentRoot; | ||
DeploymentParameters = deploymentParameters; | ||
HostShutdownToken = hostShutdownToken; | ||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.