diff --git a/test/DeploymentHelpers/Common/DeploymentResult.cs b/test/DeploymentHelpers/Common/DeploymentResult.cs index 25c2729905..b0ea83de2f 100644 --- a/test/DeploymentHelpers/Common/DeploymentResult.cs +++ b/test/DeploymentHelpers/Common/DeploymentResult.cs @@ -1,4 +1,6 @@ -namespace DeploymentHelpers +using System.Threading; + +namespace DeploymentHelpers { /// /// Result of a deployment. @@ -20,5 +22,10 @@ /// Original deployment parameters used for this deployment. /// public DeploymentParameters DeploymentParameters { get; set; } + + /// + /// Triggered when the host process dies or pulled down. + /// + public CancellationToken HostShutdownToken { get; set; } } } \ No newline at end of file diff --git a/test/DeploymentHelpers/Common/RetryHelper.cs b/test/DeploymentHelpers/Common/RetryHelper.cs index 0e98960189..106b97282c 100644 --- a/test/DeploymentHelpers/Common/RetryHelper.cs +++ b/test/DeploymentHelpers/Common/RetryHelper.cs @@ -8,12 +8,28 @@ namespace DeploymentHelpers { public class RetryHelper { - public static void RetryRequest(Func retryBlock, ILogger logger, int retryCount = 12) + /// + /// Retries every 1 sec for 60 times by default. + /// + /// + /// + /// + /// + public static void RetryRequest( + Func retryBlock, + ILogger logger, + CancellationToken cancellationToken = default(CancellationToken), + int retryCount = 60) { for (int retry = 0; retry < retryCount; retry++) { try { + if (cancellationToken.IsCancellationRequested) + { + break; + } + logger.LogWarning("Retry count {retryCount}..", retry + 1); var response = retryBlock(); @@ -41,7 +57,7 @@ namespace DeploymentHelpers ) { logger.LogWarning("Failed to complete the request : {0}.", exception.InnerException.Message); - Thread.Sleep(7 * 1000); //Wait for a while before retry. + Thread.Sleep(1 * 1000); //Wait for a while before retry. } } } diff --git a/test/DeploymentHelpers/Deployers/ApplicationDeployer.cs b/test/DeploymentHelpers/Deployers/ApplicationDeployer.cs index 9c25a351d2..a04e3f6124 100644 --- a/test/DeploymentHelpers/Deployers/ApplicationDeployer.cs +++ b/test/DeploymentHelpers/Deployers/ApplicationDeployer.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.IO; using System.Text; using System.Text.RegularExpressions; +using System.Threading; using Microsoft.Framework.Logging; namespace DeploymentHelpers @@ -171,6 +172,18 @@ namespace DeploymentHelpers } } + protected void TriggerHostShutdown(CancellationTokenSource hostShutdownSource) + { + try + { + hostShutdownSource.Cancel(); + } + catch (Exception) + { + // Suppress errors. + } + } + public abstract void Dispose(); } } \ No newline at end of file diff --git a/test/DeploymentHelpers/Deployers/IISDeployer.cs b/test/DeploymentHelpers/Deployers/IISDeployer.cs index 2e1c85f3a1..fc0e5d1bae 100644 --- a/test/DeploymentHelpers/Deployers/IISDeployer.cs +++ b/test/DeploymentHelpers/Deployers/IISDeployer.cs @@ -2,6 +2,7 @@ using System; using System.IO; using System.Linq; +using System.Threading; using System.Xml; using Microsoft.Framework.Logging; using Microsoft.Web.Administration; @@ -14,6 +15,7 @@ namespace DeploymentHelpers public class IISDeployer : ApplicationDeployer { private IISApplication _application; + private CancellationTokenSource _hostShutdownToken = new CancellationTokenSource(); public IISDeployer(DeploymentParameters startParameters, ILogger logger) : base(startParameters, logger) @@ -49,7 +51,8 @@ namespace DeploymentHelpers WebRootLocation = DeploymentParameters.ApplicationPath, DeploymentParameters = DeploymentParameters, // Accomodate the vdir name. - ApplicationBaseUri = new UriBuilder(Uri.UriSchemeHttp, "localhost", _application.Port, _application.VirtualDirectoryName).Uri.AbsoluteUri + "/" + ApplicationBaseUri = new UriBuilder(Uri.UriSchemeHttp, "localhost", _application.Port, _application.VirtualDirectoryName).Uri.AbsoluteUri + "/", + HostShutdownToken = _hostShutdownToken.Token }; } @@ -84,6 +87,8 @@ namespace DeploymentHelpers if (_application != null) { _application.StopAndDeleteAppPool(); + Logger.LogError("Application pool was shutdown successfully."); + TriggerHostShutdown(_hostShutdownToken); } CleanPublishedOutput(); diff --git a/test/DeploymentHelpers/Deployers/IISExpressDeployer.cs b/test/DeploymentHelpers/Deployers/IISExpressDeployer.cs index 1378f9c17b..f686cda17a 100644 --- a/test/DeploymentHelpers/Deployers/IISExpressDeployer.cs +++ b/test/DeploymentHelpers/Deployers/IISExpressDeployer.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics; using System.IO; +using System.Threading; using Microsoft.Framework.Logging; using Microsoft.Framework.Runtime; using Microsoft.Framework.Runtime.Infrastructure; @@ -29,18 +30,19 @@ namespace DeploymentHelpers } // Launch the host process. - _hostProcess = StartHeliosHost(); + var hostExitToken = StartHeliosHost(); return new DeploymentResult { WebRootLocation = DeploymentParameters.ApplicationPath, DeploymentParameters = DeploymentParameters, // Right now this works only for urls like http://localhost:5001/. Does not work for http://localhost:5001/subpath. - ApplicationBaseUri = DeploymentParameters.ApplicationBaseUriHint + ApplicationBaseUri = DeploymentParameters.ApplicationBaseUriHint, + HostShutdownToken = hostExitToken }; } - private Process StartHeliosHost() + private CancellationToken StartHeliosHost() { if (!string.IsNullOrWhiteSpace(DeploymentParameters.ApplicationHostConfigTemplateContent)) { @@ -96,16 +98,21 @@ namespace DeploymentHelpers startInfo.Environment["DNX_APPBASE"] = DeploymentParameters.ApplicationPath; #endif - var hostProcess = Process.Start(startInfo); - if (hostProcess.HasExited) + _hostProcess = Process.Start(startInfo); + var hostExitTokenSource = new CancellationTokenSource(); + _hostProcess.Exited += (sender, e) => { - Logger.LogError("Host process {processName} exited with code {exitCode} or failed to start.", startInfo.FileName, hostProcess.ExitCode); + TriggerHostShutdown(hostExitTokenSource); + }; + + if (_hostProcess.HasExited) + { + Logger.LogError("Host process {processName} exited with code {exitCode} or failed to start.", startInfo.FileName, _hostProcess.ExitCode); throw new Exception("Failed to start host"); } - Logger.LogInformation("Started iisexpress. Process Id : {processId}", hostProcess.Id); - - return hostProcess; + Logger.LogInformation("Started iisexpress. Process Id : {processId}", _hostProcess.Id); + return hostExitTokenSource.Token; } private void CopyAspNetLoader() diff --git a/test/DeploymentHelpers/Deployers/MonoDeployer.cs b/test/DeploymentHelpers/Deployers/MonoDeployer.cs index 67bfbb65fa..e98fe5c849 100644 --- a/test/DeploymentHelpers/Deployers/MonoDeployer.cs +++ b/test/DeploymentHelpers/Deployers/MonoDeployer.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.IO; using System.Linq; +using System.Threading; using Microsoft.Framework.Logging; namespace DeploymentHelpers @@ -37,17 +38,18 @@ namespace DeploymentHelpers } // Launch the host process. - _hostProcess = StartMonoHost(); + var hostExitToken = StartMonoHost(); return new DeploymentResult { WebRootLocation = DeploymentParameters.ApplicationPath, DeploymentParameters = DeploymentParameters, - ApplicationBaseUri = DeploymentParameters.ApplicationBaseUriHint + ApplicationBaseUri = DeploymentParameters.ApplicationBaseUriHint, + HostShutdownToken = hostExitToken }; } - private Process StartMonoHost() + private CancellationToken StartMonoHost() { if (DeploymentParameters.ServerType != ServerType.Kestrel) { @@ -66,16 +68,23 @@ namespace DeploymentHelpers RedirectStandardInput = true }; - var hostProcess = Process.Start(startInfo); - Logger.LogInformation("Started {0}. Process Id : {1}", hostProcess.MainModule.FileName, hostProcess.Id); - - if (hostProcess.HasExited) + _hostProcess = Process.Start(startInfo); + var hostExitTokenSource = new CancellationTokenSource(); + _hostProcess.Exited += (sender, e) => { - Logger.LogError("Host process {processName} exited with code {exitCode} or failed to start.", startInfo.FileName, hostProcess.ExitCode); + Logger.LogError("Host process {processName} exited with code {exitCode}.", startInfo.FileName, _hostProcess.ExitCode); + TriggerHostShutdown(hostExitTokenSource); + }; + + Logger.LogInformation("Started {0}. Process Id : {1}", _hostProcess.MainModule.FileName, _hostProcess.Id); + + if (_hostProcess.HasExited) + { + Logger.LogError("Host process {processName} exited with code {exitCode} or failed to start.", startInfo.FileName, _hostProcess.ExitCode); throw new Exception("Failed to start host"); } - return hostProcess; + return hostExitTokenSource.Token; } public override void Dispose() diff --git a/test/DeploymentHelpers/Deployers/SelfHostDeployer.cs b/test/DeploymentHelpers/Deployers/SelfHostDeployer.cs index 2142189633..6ddc9a1569 100644 --- a/test/DeploymentHelpers/Deployers/SelfHostDeployer.cs +++ b/test/DeploymentHelpers/Deployers/SelfHostDeployer.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics; using System.IO; +using System.Threading; using Microsoft.Framework.Logging; namespace DeploymentHelpers @@ -27,17 +28,18 @@ namespace DeploymentHelpers } // Launch the host process. - _hostProcess = StartSelfHost(); + var hostExitToken = StartSelfHost(); return new DeploymentResult { WebRootLocation = DeploymentParameters.ApplicationPath, DeploymentParameters = DeploymentParameters, - ApplicationBaseUri = DeploymentParameters.ApplicationBaseUriHint + ApplicationBaseUri = DeploymentParameters.ApplicationBaseUriHint, + HostShutdownToken = hostExitToken }; } - private Process StartSelfHost() + private CancellationToken StartSelfHost() { var commandName = DeploymentParameters.ServerType == ServerType.WebListener ? "web" : "kestrel"; Logger.LogInformation("Executing dnx.exe {appPath} {command} --server.urls {url}", DeploymentParameters.ApplicationPath, commandName, DeploymentParameters.ApplicationBaseUriHint); @@ -52,15 +54,21 @@ namespace DeploymentHelpers AddEnvironmentVariablesToProcess(startInfo); - var hostProcess = Process.Start(startInfo); - if (hostProcess.HasExited) + _hostProcess = Process.Start(startInfo); + var hostExitTokenSource = new CancellationTokenSource(); + _hostProcess.Exited += (sender, e) => { - Logger.LogError("Host process {processName} exited with code {exitCode} or failed to start.", startInfo.FileName, hostProcess.ExitCode); + TriggerHostShutdown(hostExitTokenSource); + }; + + if (_hostProcess.HasExited) + { + Logger.LogError("Host process {processName} exited with code {exitCode} or failed to start.", startInfo.FileName, _hostProcess.ExitCode); throw new Exception("Failed to start host"); } - Logger.LogInformation("Started {fileName}. Process Id : {processId}", startInfo.FileName, hostProcess.Id); - return hostProcess; + Logger.LogInformation("Started {fileName}. Process Id : {processId}", startInfo.FileName, _hostProcess.Id); + return hostExitTokenSource.Token; } public override void Dispose() diff --git a/test/E2ETests/NtlmAuthentationTest.cs b/test/E2ETests/NtlmAuthentationTest.cs index 4555637c74..4bce69f22d 100644 --- a/test/E2ETests/NtlmAuthentationTest.cs +++ b/test/E2ETests/NtlmAuthentationTest.cs @@ -70,7 +70,7 @@ namespace E2ETests { response = httpClient.GetAsync(string.Empty).Result; return response; - }, logger: logger); + }, logger: logger, cancellationToken: deploymentResult.HostShutdownToken); logger.LogInformation("[Time]: Approximate time taken for application initialization : '{t}' seconds", stopwatch.Elapsed.TotalSeconds); diff --git a/test/E2ETests/OpenIdConnectTests.cs b/test/E2ETests/OpenIdConnectTests.cs index e88f52de7c..debc2f9fde 100644 --- a/test/E2ETests/OpenIdConnectTests.cs +++ b/test/E2ETests/OpenIdConnectTests.cs @@ -79,7 +79,7 @@ namespace E2ETests { response = httpClient.GetAsync(string.Empty).Result; return response; - }, logger: logger); + }, logger: logger, cancellationToken: deploymentResult.HostShutdownToken); logger.LogInformation("[Time]: Approximate time taken for application initialization : '{t}' seconds", stopwatch.Elapsed.TotalSeconds); diff --git a/test/E2ETests/PublishAndRunTests.cs b/test/E2ETests/PublishAndRunTests.cs index c543c522fc..6ddcb23228 100644 --- a/test/E2ETests/PublishAndRunTests.cs +++ b/test/E2ETests/PublishAndRunTests.cs @@ -102,7 +102,7 @@ namespace E2ETests { response = httpClient.GetAsync(string.Empty).Result; return response; - }, logger: logger); + }, logger: logger, cancellationToken: deploymentResult.HostShutdownToken); logger.LogInformation("[Time]: Approximate time taken for application initialization : '{t}' seconds", stopwatch.Elapsed.TotalSeconds); diff --git a/test/E2ETests/SmokeTests.cs b/test/E2ETests/SmokeTests.cs index f3989390c4..26aef4143a 100644 --- a/test/E2ETests/SmokeTests.cs +++ b/test/E2ETests/SmokeTests.cs @@ -171,7 +171,7 @@ namespace E2ETests { response = httpClient.GetAsync(string.Empty).Result; return response; - }, logger: logger); + }, logger: logger, cancellationToken: deploymentResult.HostShutdownToken); logger.LogInformation("[Time]: Approximate time taken for application initialization : '{t}' seconds", stopwatch.Elapsed.TotalSeconds);