Add TestApplication to allow publish output caching (#1511)
This commit is contained in:
Родитель
446b64c199
Коммит
658906bf7c
|
@ -4,34 +4,34 @@
|
|||
</PropertyGroup>
|
||||
<PropertyGroup Label="Package Versions">
|
||||
<InternalAspNetCoreSdkPackageVersion>2.2.0-preview1-17102</InternalAspNetCoreSdkPackageVersion>
|
||||
<MicrosoftAspNetCoreHttpAbstractionsPackageVersion>2.2.0-preview1-34823</MicrosoftAspNetCoreHttpAbstractionsPackageVersion>
|
||||
<MicrosoftAspNetCoreHttpExtensionsPackageVersion>2.2.0-preview1-34823</MicrosoftAspNetCoreHttpExtensionsPackageVersion>
|
||||
<MicrosoftAspNetCoreHttpFeaturesPackageVersion>2.2.0-preview1-34823</MicrosoftAspNetCoreHttpFeaturesPackageVersion>
|
||||
<MicrosoftAspNetCoreHttpPackageVersion>2.2.0-preview1-34823</MicrosoftAspNetCoreHttpPackageVersion>
|
||||
<MicrosoftAspNetCoreOwinPackageVersion>2.2.0-preview1-34823</MicrosoftAspNetCoreOwinPackageVersion>
|
||||
<MicrosoftAspNetCoreTestingPackageVersion>2.2.0-preview1-34823</MicrosoftAspNetCoreTestingPackageVersion>
|
||||
<MicrosoftExtensionsConfigurationAbstractionsPackageVersion>2.2.0-preview1-34823</MicrosoftExtensionsConfigurationAbstractionsPackageVersion>
|
||||
<MicrosoftExtensionsConfigurationBinderPackageVersion>2.2.0-preview1-34823</MicrosoftExtensionsConfigurationBinderPackageVersion>
|
||||
<MicrosoftExtensionsConfigurationCommandLinePackageVersion>2.2.0-preview1-34823</MicrosoftExtensionsConfigurationCommandLinePackageVersion>
|
||||
<MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>2.2.0-preview1-34823</MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>
|
||||
<MicrosoftExtensionsConfigurationFileExtensionsPackageVersion>2.2.0-preview1-34823</MicrosoftExtensionsConfigurationFileExtensionsPackageVersion>
|
||||
<MicrosoftExtensionsConfigurationJsonPackageVersion>2.2.0-preview1-34823</MicrosoftExtensionsConfigurationJsonPackageVersion>
|
||||
<MicrosoftExtensionsConfigurationPackageVersion>2.2.0-preview1-34823</MicrosoftExtensionsConfigurationPackageVersion>
|
||||
<MicrosoftExtensionsDependencyInjectionAbstractionsPackageVersion>2.2.0-preview1-34823</MicrosoftExtensionsDependencyInjectionAbstractionsPackageVersion>
|
||||
<MicrosoftExtensionsDependencyInjectionPackageVersion>2.2.0-preview1-34823</MicrosoftExtensionsDependencyInjectionPackageVersion>
|
||||
<MicrosoftExtensionsDiagnosticAdapterPackageVersion>2.2.0-preview1-34823</MicrosoftExtensionsDiagnosticAdapterPackageVersion>
|
||||
<MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>2.2.0-preview1-34823</MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>
|
||||
<MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>2.2.0-preview1-34823</MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>
|
||||
<MicrosoftExtensionsFileProvidersPhysicalPackageVersion>2.2.0-preview1-34823</MicrosoftExtensionsFileProvidersPhysicalPackageVersion>
|
||||
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>2.2.0-preview1-34823</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
|
||||
<MicrosoftExtensionsLoggingConsolePackageVersion>2.2.0-preview1-34823</MicrosoftExtensionsLoggingConsolePackageVersion>
|
||||
<MicrosoftExtensionsLoggingPackageVersion>2.2.0-preview1-34823</MicrosoftExtensionsLoggingPackageVersion>
|
||||
<MicrosoftExtensionsLoggingTestingPackageVersion>2.2.0-preview1-34823</MicrosoftExtensionsLoggingTestingPackageVersion>
|
||||
<MicrosoftExtensionsOptionsPackageVersion>2.2.0-preview1-34823</MicrosoftExtensionsOptionsPackageVersion>
|
||||
<MicrosoftExtensionsProcessSourcesPackageVersion>2.2.0-preview1-34823</MicrosoftExtensionsProcessSourcesPackageVersion>
|
||||
<MicrosoftExtensionsRazorViewsSourcesPackageVersion>2.2.0-preview1-34823</MicrosoftExtensionsRazorViewsSourcesPackageVersion>
|
||||
<MicrosoftExtensionsStackTraceSourcesPackageVersion>2.2.0-preview1-34823</MicrosoftExtensionsStackTraceSourcesPackageVersion>
|
||||
<MicrosoftExtensionsTypeNameHelperSourcesPackageVersion>2.2.0-preview1-34823</MicrosoftExtensionsTypeNameHelperSourcesPackageVersion>
|
||||
<MicrosoftAspNetCoreHttpAbstractionsPackageVersion>2.2.0-preview1-34825</MicrosoftAspNetCoreHttpAbstractionsPackageVersion>
|
||||
<MicrosoftAspNetCoreHttpExtensionsPackageVersion>2.2.0-preview1-34825</MicrosoftAspNetCoreHttpExtensionsPackageVersion>
|
||||
<MicrosoftAspNetCoreHttpFeaturesPackageVersion>2.2.0-preview1-34825</MicrosoftAspNetCoreHttpFeaturesPackageVersion>
|
||||
<MicrosoftAspNetCoreHttpPackageVersion>2.2.0-preview1-34825</MicrosoftAspNetCoreHttpPackageVersion>
|
||||
<MicrosoftAspNetCoreOwinPackageVersion>2.2.0-preview1-34825</MicrosoftAspNetCoreOwinPackageVersion>
|
||||
<MicrosoftAspNetCoreTestingPackageVersion>2.2.0-preview1-34825</MicrosoftAspNetCoreTestingPackageVersion>
|
||||
<MicrosoftExtensionsConfigurationAbstractionsPackageVersion>2.2.0-preview1-34825</MicrosoftExtensionsConfigurationAbstractionsPackageVersion>
|
||||
<MicrosoftExtensionsConfigurationBinderPackageVersion>2.2.0-preview1-34825</MicrosoftExtensionsConfigurationBinderPackageVersion>
|
||||
<MicrosoftExtensionsConfigurationCommandLinePackageVersion>2.2.0-preview1-34825</MicrosoftExtensionsConfigurationCommandLinePackageVersion>
|
||||
<MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>2.2.0-preview1-34825</MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>
|
||||
<MicrosoftExtensionsConfigurationFileExtensionsPackageVersion>2.2.0-preview1-34825</MicrosoftExtensionsConfigurationFileExtensionsPackageVersion>
|
||||
<MicrosoftExtensionsConfigurationJsonPackageVersion>2.2.0-preview1-34825</MicrosoftExtensionsConfigurationJsonPackageVersion>
|
||||
<MicrosoftExtensionsConfigurationPackageVersion>2.2.0-preview1-34825</MicrosoftExtensionsConfigurationPackageVersion>
|
||||
<MicrosoftExtensionsDependencyInjectionAbstractionsPackageVersion>2.2.0-preview1-34825</MicrosoftExtensionsDependencyInjectionAbstractionsPackageVersion>
|
||||
<MicrosoftExtensionsDependencyInjectionPackageVersion>2.2.0-preview1-34825</MicrosoftExtensionsDependencyInjectionPackageVersion>
|
||||
<MicrosoftExtensionsDiagnosticAdapterPackageVersion>2.2.0-preview1-34825</MicrosoftExtensionsDiagnosticAdapterPackageVersion>
|
||||
<MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>2.2.0-preview1-34825</MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>
|
||||
<MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>2.2.0-preview1-34825</MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>
|
||||
<MicrosoftExtensionsFileProvidersPhysicalPackageVersion>2.2.0-preview1-34825</MicrosoftExtensionsFileProvidersPhysicalPackageVersion>
|
||||
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>2.2.0-preview1-34825</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
|
||||
<MicrosoftExtensionsLoggingConsolePackageVersion>2.2.0-preview1-34825</MicrosoftExtensionsLoggingConsolePackageVersion>
|
||||
<MicrosoftExtensionsLoggingPackageVersion>2.2.0-preview1-34825</MicrosoftExtensionsLoggingPackageVersion>
|
||||
<MicrosoftExtensionsLoggingTestingPackageVersion>2.2.0-preview1-34825</MicrosoftExtensionsLoggingTestingPackageVersion>
|
||||
<MicrosoftExtensionsOptionsPackageVersion>2.2.0-preview1-34825</MicrosoftExtensionsOptionsPackageVersion>
|
||||
<MicrosoftExtensionsProcessSourcesPackageVersion>2.2.0-preview1-34825</MicrosoftExtensionsProcessSourcesPackageVersion>
|
||||
<MicrosoftExtensionsRazorViewsSourcesPackageVersion>2.2.0-preview1-34825</MicrosoftExtensionsRazorViewsSourcesPackageVersion>
|
||||
<MicrosoftExtensionsStackTraceSourcesPackageVersion>2.2.0-preview1-34825</MicrosoftExtensionsStackTraceSourcesPackageVersion>
|
||||
<MicrosoftExtensionsTypeNameHelperSourcesPackageVersion>2.2.0-preview1-34825</MicrosoftExtensionsTypeNameHelperSourcesPackageVersion>
|
||||
<MicrosoftNETCoreApp20PackageVersion>2.0.9</MicrosoftNETCoreApp20PackageVersion>
|
||||
<MicrosoftNETCoreApp21PackageVersion>2.1.2</MicrosoftNETCoreApp21PackageVersion>
|
||||
<MicrosoftNETCoreApp22PackageVersion>2.2.0-preview1-26618-02</MicrosoftNETCoreApp22PackageVersion>
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
// 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.AspNetCore.Server.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}"
|
||||
+ (deploymentParameters.RestoreOnPublish
|
||||
? string.Empty
|
||||
: " --no-restore -p:VerifyMatchingImplicitPackageVersion=false");
|
||||
// Set VerifyMatchingImplicitPackageVersion to disable errors when Microsoft.NETCore.App's version is overridden externally
|
||||
// This verification doesn't matter if we are skipping restore during tests.
|
||||
|
||||
if (deploymentParameters.ApplicationType == ApplicationType.Standalone)
|
||||
{
|
||||
parameters += $" --runtime {GetRuntimeIdentifier(deploymentParameters)}";
|
||||
}
|
||||
|
||||
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 "win7-" + 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
// 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.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
||||
{
|
||||
public class CachingApplicationPublisher: ApplicationPublisher, IDisposable
|
||||
{
|
||||
private readonly Dictionary<DotnetPublishParameters, PublishedApplication> _publishCache = new Dictionary<DotnetPublishParameters, PublishedApplication>();
|
||||
|
||||
public CachingApplicationPublisher(string applicationPath) : base(applicationPath)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<PublishedApplication> Publish(DeploymentParameters deploymentParameters, ILogger logger)
|
||||
{
|
||||
if (ApplicationPath != deploymentParameters.ApplicationPath)
|
||||
{
|
||||
throw new InvalidOperationException("ApplicationPath mismatch");
|
||||
}
|
||||
|
||||
if (deploymentParameters.PublishEnvironmentVariables.Any())
|
||||
{
|
||||
throw new InvalidOperationException("DeploymentParameters.PublishEnvironmentVariables not supported");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(deploymentParameters.PublishedApplicationRootPath))
|
||||
{
|
||||
throw new InvalidOperationException("DeploymentParameters.PublishedApplicationRootPath not supported");
|
||||
}
|
||||
|
||||
if (deploymentParameters.RestoreOnPublish)
|
||||
{
|
||||
throw new InvalidOperationException("DeploymentParameters.RestoreOnPublish not supported");
|
||||
}
|
||||
|
||||
var dotnetPublishParameters = new DotnetPublishParameters
|
||||
{
|
||||
TargetFramework = deploymentParameters.TargetFramework,
|
||||
Configuration = deploymentParameters.Configuration,
|
||||
ApplicationType = deploymentParameters.ApplicationType,
|
||||
RuntimeArchitecture = deploymentParameters.RuntimeArchitecture
|
||||
};
|
||||
|
||||
if (!_publishCache.TryGetValue(dotnetPublishParameters, out var publishedApplication))
|
||||
{
|
||||
publishedApplication = await base.Publish(deploymentParameters, logger);
|
||||
_publishCache.Add(dotnetPublishParameters, publishedApplication);
|
||||
}
|
||||
|
||||
return new PublishedApplication(CopyPublishedOutput(publishedApplication, logger), logger);
|
||||
}
|
||||
|
||||
private string CopyPublishedOutput(PublishedApplication application, ILogger logger)
|
||||
{
|
||||
var target = CreateTempDirectory();
|
||||
|
||||
var source = new DirectoryInfo(application.Path);
|
||||
CopyFiles(source, target, logger);
|
||||
return target.FullName;
|
||||
}
|
||||
|
||||
public static void CopyFiles(DirectoryInfo source, DirectoryInfo target, ILogger logger)
|
||||
{
|
||||
foreach (DirectoryInfo directoryInfo in source.GetDirectories())
|
||||
{
|
||||
CopyFiles(directoryInfo, target.CreateSubdirectory(directoryInfo.Name), logger);
|
||||
}
|
||||
|
||||
logger.LogDebug($"Processing {target.FullName}");
|
||||
foreach (FileInfo fileInfo in source.GetFiles())
|
||||
{
|
||||
logger.LogDebug($" Copying {fileInfo.Name}");
|
||||
var destFileName = Path.Combine(target.FullName, fileInfo.Name);
|
||||
fileInfo.CopyTo(destFileName);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var publishedApp in _publishCache.Values)
|
||||
{
|
||||
publishedApp.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private struct DotnetPublishParameters
|
||||
{
|
||||
public string TargetFramework { get; set; }
|
||||
public string Configuration { get; set; }
|
||||
public ApplicationType ApplicationType { get; set; }
|
||||
public RuntimeArchitecture RuntimeArchitecture { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -99,6 +99,8 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
|||
}
|
||||
}
|
||||
|
||||
public ApplicationPublisher ApplicationPublisher { get; set; }
|
||||
|
||||
public ServerType ServerType { get; set; }
|
||||
|
||||
public RuntimeFlavor RuntimeFlavor { get; set; }
|
||||
|
|
|
@ -20,12 +20,10 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
|||
{
|
||||
public static readonly string DotnetCommandName = "dotnet";
|
||||
|
||||
// This is the argument that separates the dotnet arguments for the args being passed to the
|
||||
// app being run when running dotnet run
|
||||
public static readonly string DotnetArgumentSeparator = "--";
|
||||
|
||||
private readonly Stopwatch _stopwatch = new Stopwatch();
|
||||
|
||||
private PublishedApplication _publishedApplication;
|
||||
|
||||
public ApplicationDeployer(DeploymentParameters deploymentParameters, ILoggerFactory loggerFactory)
|
||||
{
|
||||
DeploymentParameters = deploymentParameters;
|
||||
|
@ -82,78 +80,9 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
|||
|
||||
protected void DotnetPublish(string publishRoot = null)
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
DeploymentParameters.PublishedApplicationRootPath = publishRoot ?? Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
|
||||
var parameters = $"publish "
|
||||
+ $" --output \"{DeploymentParameters.PublishedApplicationRootPath}\""
|
||||
+ $" --framework {DeploymentParameters.TargetFramework}"
|
||||
+ $" --configuration {DeploymentParameters.Configuration}"
|
||||
+ (DeploymentParameters.RestoreOnPublish
|
||||
? string.Empty
|
||||
: " --no-restore -p:VerifyMatchingImplicitPackageVersion=false");
|
||||
// Set VerifyMatchingImplicitPackageVersion to disable errors when Microsoft.NETCore.App's version is overridden externally
|
||||
// This verification doesn't matter if we are skipping restore during tests.
|
||||
|
||||
if (DeploymentParameters.ApplicationType == ApplicationType.Standalone)
|
||||
{
|
||||
parameters += $" --runtime {GetRuntimeIdentifier()}";
|
||||
}
|
||||
|
||||
parameters += $" {DeploymentParameters.AdditionalPublishParameters}";
|
||||
|
||||
var startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = DotnetCommandName,
|
||||
Arguments = parameters,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true,
|
||||
RedirectStandardError = true,
|
||||
RedirectStandardOutput = true,
|
||||
WorkingDirectory = DeploymentParameters.ApplicationPath,
|
||||
};
|
||||
|
||||
AddEnvironmentVariablesToProcess(startInfo, DeploymentParameters.PublishEnvironmentVariables);
|
||||
|
||||
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}");
|
||||
}
|
||||
var publisher = DeploymentParameters.ApplicationPublisher ?? new ApplicationPublisher(DeploymentParameters.ApplicationPath);
|
||||
_publishedApplication = publisher.Publish(DeploymentParameters, Logger).GetAwaiter().GetResult();
|
||||
DeploymentParameters.PublishedApplicationRootPath = _publishedApplication.Path;
|
||||
}
|
||||
|
||||
protected void CleanPublishedOutput()
|
||||
|
@ -168,11 +97,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
|||
}
|
||||
else
|
||||
{
|
||||
RetryHelper.RetryOperation(
|
||||
() => Directory.Delete(DeploymentParameters.PublishedApplicationRootPath, true),
|
||||
e => Logger.LogWarning($"Failed to delete directory : {e.Message}"),
|
||||
retryCount: 3,
|
||||
retryDelayMilliseconds: 100);
|
||||
_publishedApplication.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -219,26 +144,8 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
|||
protected void AddEnvironmentVariablesToProcess(ProcessStartInfo startInfo, IDictionary<string, string> environmentVariables)
|
||||
{
|
||||
var environment = startInfo.Environment;
|
||||
SetEnvironmentVariable(environment, "ASPNETCORE_ENVIRONMENT", DeploymentParameters.EnvironmentName);
|
||||
|
||||
foreach (var environmentVariable in environmentVariables)
|
||||
{
|
||||
SetEnvironmentVariable(environment, environmentVariable.Key, environmentVariable.Value);
|
||||
}
|
||||
}
|
||||
|
||||
protected void SetEnvironmentVariable(IDictionary<string, string> environment, string name, string value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
Logger.LogInformation("Removing environment variable {name}", name);
|
||||
environment.Remove(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogInformation("SET {name}={value}", name, value);
|
||||
environment[name] = value;
|
||||
}
|
||||
ProcessHelpers.SetEnvironmentVariable(environment, "ASPNETCORE_ENVIRONMENT", DeploymentParameters.EnvironmentName, Logger);
|
||||
ProcessHelpers.AddEnvironmentVariablesToProcess(startInfo, environmentVariables, Logger);
|
||||
}
|
||||
|
||||
protected void InvokeUserApplicationCleanup()
|
||||
|
@ -286,26 +193,5 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
|||
}
|
||||
|
||||
public abstract void Dispose();
|
||||
|
||||
private string GetRuntimeIdentifier()
|
||||
{
|
||||
var architecture = DeploymentParameters.RuntimeArchitecture;
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
return "win7-" + architecture;
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
return "linux-" + architecture;
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
return "osx-" + architecture;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Unrecognized operation system platform");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
// 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.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
||||
{
|
||||
internal class ProcessHelpers
|
||||
{
|
||||
public static void AddEnvironmentVariablesToProcess(ProcessStartInfo startInfo, IDictionary<string, string> environmentVariables, ILogger logger)
|
||||
{
|
||||
var environment = startInfo.Environment;
|
||||
|
||||
foreach (var environmentVariable in environmentVariables)
|
||||
{
|
||||
SetEnvironmentVariable(environment, environmentVariable.Key, environmentVariable.Value, logger);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetEnvironmentVariable(IDictionary<string, string> environment, string name, string value, ILogger logger)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
logger.LogInformation("Removing environment variable {name}", name);
|
||||
environment.Remove(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogInformation("SET {name}={value}", name, value);
|
||||
environment[name] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
// 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 Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
||||
{
|
||||
public class PublishedApplication: IDisposable
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public string Path { get; }
|
||||
|
||||
public PublishedApplication(string path, ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
Path = path;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
RetryHelper.RetryOperation(
|
||||
() => Directory.Delete(Path, true),
|
||||
e => _logger.LogWarning($"Failed to delete directory : {e.Message}"),
|
||||
retryCount: 3,
|
||||
retryDelayMilliseconds: 100);
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче