diff --git a/Hosting.sln b/Hosting.sln index e00cee06..96a30a67 100644 --- a/Hosting.sln +++ b/Hosting.sln @@ -1,7 +1,6 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.24720.0 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E0497F39-AFFB-4819-A116-E39E361915AB}" EndProject @@ -32,6 +31,10 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SampleStartups", "samples\S EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Hosting.WindowsServices", "src\Microsoft.AspNetCore.Hosting.WindowsServices\Microsoft.AspNetCore.Hosting.WindowsServices.xproj", "{03148731-EA95-40A2-BAE8-A12315EA1748}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Hosting.FunctionalTests", "test\Microsoft.AspNetCore.Hosting.FunctionalTests\Microsoft.AspNetCore.Hosting.FunctionalTests.xproj", "{FC578F4E-171C-4F82-B301-3ABF6318D082}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Hosting.TestSites", "test\Microsoft.AspNetCore.Hosting.TestSites\Microsoft.AspNetCore.Hosting.TestSites.xproj", "{542D4600-B232-4B17-A08C-E31EBFA0D74E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -142,6 +145,30 @@ Global {03148731-EA95-40A2-BAE8-A12315EA1748}.Release|Mixed Platforms.Build.0 = Release|Any CPU {03148731-EA95-40A2-BAE8-A12315EA1748}.Release|x86.ActiveCfg = Release|Any CPU {03148731-EA95-40A2-BAE8-A12315EA1748}.Release|x86.Build.0 = Release|Any CPU + {FC578F4E-171C-4F82-B301-3ABF6318D082}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FC578F4E-171C-4F82-B301-3ABF6318D082}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FC578F4E-171C-4F82-B301-3ABF6318D082}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {FC578F4E-171C-4F82-B301-3ABF6318D082}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {FC578F4E-171C-4F82-B301-3ABF6318D082}.Debug|x86.ActiveCfg = Debug|Any CPU + {FC578F4E-171C-4F82-B301-3ABF6318D082}.Debug|x86.Build.0 = Debug|Any CPU + {FC578F4E-171C-4F82-B301-3ABF6318D082}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FC578F4E-171C-4F82-B301-3ABF6318D082}.Release|Any CPU.Build.0 = Release|Any CPU + {FC578F4E-171C-4F82-B301-3ABF6318D082}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {FC578F4E-171C-4F82-B301-3ABF6318D082}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {FC578F4E-171C-4F82-B301-3ABF6318D082}.Release|x86.ActiveCfg = Release|Any CPU + {FC578F4E-171C-4F82-B301-3ABF6318D082}.Release|x86.Build.0 = Release|Any CPU + {542D4600-B232-4B17-A08C-E31EBFA0D74E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {542D4600-B232-4B17-A08C-E31EBFA0D74E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {542D4600-B232-4B17-A08C-E31EBFA0D74E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {542D4600-B232-4B17-A08C-E31EBFA0D74E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {542D4600-B232-4B17-A08C-E31EBFA0D74E}.Debug|x86.ActiveCfg = Debug|Any CPU + {542D4600-B232-4B17-A08C-E31EBFA0D74E}.Debug|x86.Build.0 = Debug|Any CPU + {542D4600-B232-4B17-A08C-E31EBFA0D74E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {542D4600-B232-4B17-A08C-E31EBFA0D74E}.Release|Any CPU.Build.0 = Release|Any CPU + {542D4600-B232-4B17-A08C-E31EBFA0D74E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {542D4600-B232-4B17-A08C-E31EBFA0D74E}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {542D4600-B232-4B17-A08C-E31EBFA0D74E}.Release|x86.ActiveCfg = Release|Any CPU + {542D4600-B232-4B17-A08C-E31EBFA0D74E}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -156,5 +183,7 @@ Global {3DA89347-6731-4366-80C4-548F24E8607B} = {E0497F39-AFFB-4819-A116-E39E361915AB} {485B6745-7648-400A-A969-F68FCF194E46} = {9C7520A0-F2EB-411C-8BB2-80B39C937217} {03148731-EA95-40A2-BAE8-A12315EA1748} = {E0497F39-AFFB-4819-A116-E39E361915AB} + {FC578F4E-171C-4F82-B301-3ABF6318D082} = {FEB39027-9158-4DE2-997F-7ADAEF8188D0} + {542D4600-B232-4B17-A08C-E31EBFA0D74E} = {FEB39027-9158-4DE2-997F-7ADAEF8188D0} EndGlobalSection EndGlobal diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting/Deployers/SelfHostDeployer.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting/Deployers/SelfHostDeployer.cs index 7148c6fb..d7764c02 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting/Deployers/SelfHostDeployer.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting/Deployers/SelfHostDeployer.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting /// public class SelfHostDeployer : ApplicationDeployer { - private Process _hostProcess; + public Process HostProcess { get; private set; } public SelfHostDeployer(DeploymentParameters deploymentParameters, ILogger logger) : base(deploymentParameters, logger) @@ -103,32 +103,32 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting AddEnvironmentVariablesToProcess(startInfo, DeploymentParameters.EnvironmentVariables); - _hostProcess = new Process() { StartInfo = startInfo }; - _hostProcess.ErrorDataReceived += (sender, dataArgs) => { Logger.LogError(dataArgs.Data ?? string.Empty); }; - _hostProcess.OutputDataReceived += (sender, dataArgs) => { Logger.LogInformation(dataArgs.Data ?? string.Empty); }; - _hostProcess.EnableRaisingEvents = true; + HostProcess = new Process() { StartInfo = startInfo }; + HostProcess.ErrorDataReceived += (sender, dataArgs) => { Logger.LogError(dataArgs.Data ?? string.Empty); }; + HostProcess.OutputDataReceived += (sender, dataArgs) => { Logger.LogInformation(dataArgs.Data ?? string.Empty); }; + HostProcess.EnableRaisingEvents = true; var hostExitTokenSource = new CancellationTokenSource(); - _hostProcess.Exited += (sender, e) => + HostProcess.Exited += (sender, e) => { TriggerHostShutdown(hostExitTokenSource); }; - _hostProcess.Start(); - _hostProcess.BeginErrorReadLine(); - _hostProcess.BeginOutputReadLine(); + HostProcess.Start(); + HostProcess.BeginErrorReadLine(); + HostProcess.BeginOutputReadLine(); - if (_hostProcess.HasExited) + if (HostProcess.HasExited) { - 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} 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); + Logger.LogInformation("Started {fileName}. Process Id : {processId}", startInfo.FileName, HostProcess.Id); return hostExitTokenSource.Token; } public override void Dispose() { - ShutDownIfAnyHostProcess(_hostProcess); + ShutDownIfAnyHostProcess(HostProcess); if (DeploymentParameters.PublishApplicationBeforeDeployment) { diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting/project.json b/src/Microsoft.AspNetCore.Server.IntegrationTesting/project.json index 98b6d395..a7e2cb5e 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting/project.json +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting/project.json @@ -32,6 +32,7 @@ "type": "build", "version": "1.1.0-*" }, + "Microsoft.Extensions.PlatformAbstractions": "1.1.0-*", "NETStandard.Library": "1.6.1-*" }, "frameworks": { diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting/xunit/TestProjectHelpers.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting/xunit/TestProjectHelpers.cs new file mode 100644 index 00000000..76a3dc6d --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting/xunit/TestProjectHelpers.cs @@ -0,0 +1,32 @@ +// 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.PlatformAbstractions; + +namespace Microsoft.AspNetCore.Server.IntegrationTesting.xunit +{ + public class TestProjectHelpers + { + public static string GetProjectRoot() + { + var applicationBasePath = PlatformServices.Default.Application.ApplicationBasePath; + + var directoryInfo = new DirectoryInfo(applicationBasePath); + do + { + var projectFileInfo = new FileInfo(Path.Combine(directoryInfo.FullName, "project.json")); + if (projectFileInfo.Exists) + { + return projectFileInfo.DirectoryName; + } + + directoryInfo = directoryInfo.Parent; + } + while (directoryInfo.Parent != null); + + throw new Exception($"Project root could not be found using {applicationBasePath}"); + } + } + } diff --git a/test/Microsoft.AspNetCore.Hosting.FunctionalTests/Microsoft.AspNetCore.Hosting.FunctionalTests.xproj b/test/Microsoft.AspNetCore.Hosting.FunctionalTests/Microsoft.AspNetCore.Hosting.FunctionalTests.xproj new file mode 100644 index 00000000..3e17cac8 --- /dev/null +++ b/test/Microsoft.AspNetCore.Hosting.FunctionalTests/Microsoft.AspNetCore.Hosting.FunctionalTests.xproj @@ -0,0 +1,17 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + fc578f4e-171c-4f82-b301-3abf6318d082 + .\obj + .\bin\ + + + 2.0 + + + \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Hosting.FunctionalTests/ShutdownTests.cs b/test/Microsoft.AspNetCore.Hosting.FunctionalTests/ShutdownTests.cs new file mode 100644 index 00000000..c794cbc9 --- /dev/null +++ b/test/Microsoft.AspNetCore.Hosting.FunctionalTests/ShutdownTests.cs @@ -0,0 +1,94 @@ +// 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.Net.Http; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Server.IntegrationTesting; +using Microsoft.AspNetCore.Server.IntegrationTesting.xunit; +using Microsoft.AspNetCore.Testing.xunit; +using Microsoft.Extensions.Logging; +using Xunit; +using Xunit.Sdk; + +namespace Microsoft.AspNetCore.Hosting.FunctionalTests +{ + public class ShutdownTests + { + [ConditionalFact] + [OSSkipCondition(OperatingSystems.Windows)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public void ShutdownTest() + { + var logger = new LoggerFactory() + .AddConsole() + .CreateLogger(nameof(ShutdownTest)); + + string applicationPath = Path.Combine(TestProjectHelpers.GetProjectRoot(), "..", + "Microsoft.AspNetCore.Hosting.TestSites"); + + var deploymentParameters = new DeploymentParameters( + applicationPath, + ServerType.Kestrel, + RuntimeFlavor.CoreClr, + RuntimeArchitecture.x64) + { + EnvironmentName = "Shutdown", + TargetFramework = "netcoreapp1.1", + ApplicationType = ApplicationType.Portable, + PublishApplicationBeforeDeployment = true + }; + + using (var deployer = new SelfHostDeployer(deploymentParameters, logger)) + { + deployer.Deploy(); + + // Wait for application to start + System.Threading.Thread.Sleep(1000); + + string output = string.Empty; + deployer.HostProcess.OutputDataReceived += (sender, args) => output += args.Data + '\n'; + + SendSIGINT(deployer.HostProcess.Id); + + WaitForExitOrKill(deployer.HostProcess); + + output = output.Trim('\n'); + + Assert.Equal(output, "Application is shutting down...\n" + + "Stopping firing\n" + + "Stopping end\n" + + "Stopped firing\n" + + "Stopped end"); + } + } + + + private static void SendSIGINT(int processId) + { + var startInfo = new ProcessStartInfo + { + FileName = "kill", + Arguments = processId.ToString(), + RedirectStandardOutput = true, + UseShellExecute = false + }; + + var process = Process.Start(startInfo); + WaitForExitOrKill(process); + } + + private static void WaitForExitOrKill(Process process) + { + process.WaitForExit(1000); + if (!process.HasExited) + { + process.Kill(); + } + + Assert.Equal(0, process.ExitCode); + } + } +} diff --git a/test/Microsoft.AspNetCore.Hosting.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Hosting.FunctionalTests/project.json new file mode 100644 index 00000000..0abc059b --- /dev/null +++ b/test/Microsoft.AspNetCore.Hosting.FunctionalTests/project.json @@ -0,0 +1,34 @@ +{ + "buildOptions": { + "warningsAsErrors": true, + "keyFile": "../../tools/Key.snk", + "copyToOutput": { + "include": [ + "testroot/**/*" + ] + } + }, + "publishOptions": { + "include": [ + "testroot/**/*" + ] + }, + "dependencies": { + "dotnet-test-xunit": "2.2.0-*", + "Microsoft.AspNetCore.Server.IntegrationTesting": "0.2.0-*", + "Microsoft.AspNetCore.Hosting": "1.1.0-*", + "Microsoft.Extensions.Logging.Console": "1.1.0-*", + "xunit": "2.2.0-*" + }, + "frameworks": { + "netcoreapp1.1": { + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.1.0-*", + "type": "platform" + } + } + } + }, + "testRunner": "xunit" +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Hosting.TestSites/.Program.cs.swp b/test/Microsoft.AspNetCore.Hosting.TestSites/.Program.cs.swp new file mode 100644 index 00000000..ef1c7881 Binary files /dev/null and b/test/Microsoft.AspNetCore.Hosting.TestSites/.Program.cs.swp differ diff --git a/test/Microsoft.AspNetCore.Hosting.TestSites/Microsoft.AspNetCore.Hosting.TestSites.xproj b/test/Microsoft.AspNetCore.Hosting.TestSites/Microsoft.AspNetCore.Hosting.TestSites.xproj new file mode 100644 index 00000000..05732b74 --- /dev/null +++ b/test/Microsoft.AspNetCore.Hosting.TestSites/Microsoft.AspNetCore.Hosting.TestSites.xproj @@ -0,0 +1,17 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 542d4600-b232-4b17-a08c-e31ebfa0d74e + .\obj + .\bin\ + + + 2.0 + + + \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Hosting.TestSites/Program.cs b/test/Microsoft.AspNetCore.Hosting.TestSites/Program.cs new file mode 100644 index 00000000..33332152 --- /dev/null +++ b/test/Microsoft.AspNetCore.Hosting.TestSites/Program.cs @@ -0,0 +1,44 @@ +// 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 Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using System.Threading; +using Microsoft.AspNetCore.Hosting.Server; +using Microsoft.AspNetCore.Http.Features; + +namespace ServerComparison.TestSites +{ + public static class Program + { + public static void Main(string[] args) + { + var config = new ConfigurationBuilder() + .AddCommandLine(args) + .Build(); + + var builder = new WebHostBuilder() + .UseServer(new NoopServer()) + .UseConfiguration(config) + .UseStartup("Microsoft.AspNetCore.Hosting.TestSites"); + + var host = builder.Build(); + + host.Run(); + } + } + + public class NoopServer : IServer + { + public void Dispose() + { + } + + public IFeatureCollection Features { get; } = new FeatureCollection(); + + public void Start(IHttpApplication application) + { + } + } +} + diff --git a/test/Microsoft.AspNetCore.Hosting.TestSites/StartupShutdown.cs b/test/Microsoft.AspNetCore.Hosting.TestSites/StartupShutdown.cs new file mode 100644 index 00000000..b8a5b8b7 --- /dev/null +++ b/test/Microsoft.AspNetCore.Hosting.TestSites/StartupShutdown.cs @@ -0,0 +1,37 @@ +// 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 Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; + +namespace Microsoft.AspNetCore.Hosting.TestSites +{ + public class StartupShutdown + { + public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IApplicationLifetime lifetime) + { + lifetime.ApplicationStopping.Register(() => + { + Console.WriteLine("Stopping firing"); + System.Threading.Thread.Sleep(200); + Console.WriteLine("Stopping end"); + }); + lifetime.ApplicationStopped.Register(() => + { + Console.WriteLine("Stopped firing"); + System.Threading.Thread.Sleep(200); + Console.WriteLine("Stopped end"); + }); + + + loggerFactory.AddConsole(minLevel: LogLevel.Warning); + + app.Run(context => + { + return context.Response.WriteAsync("Hello World"); + }); + } + } +} diff --git a/test/Microsoft.AspNetCore.Hosting.TestSites/project.json b/test/Microsoft.AspNetCore.Hosting.TestSites/project.json new file mode 100644 index 00000000..5dc04cc3 --- /dev/null +++ b/test/Microsoft.AspNetCore.Hosting.TestSites/project.json @@ -0,0 +1,23 @@ +{ + "version": "1.1.0-*", + "dependencies": { + "Microsoft.AspNetCore.Hosting": "1.1.0-*", + "Microsoft.Extensions.Configuration": "1.1.0-*", + "Microsoft.Extensions.Configuration.CommandLine": "1.1.0-*", + "Microsoft.Extensions.Logging.Console": "1.1.0-*" + }, + "buildOptions": { + "emitEntryPoint": true + }, + "frameworks": { + "net451": {}, + "netcoreapp1.1": { + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.1.0-*", + "type": "platform" + } + } + } + } +}