diff --git a/AspNetCoreSdkTests/TemplateTests.cs b/AspNetCoreSdkTests/TemplateTests.cs index a5a5407b80..4b75454fc7 100644 --- a/AspNetCoreSdkTests/TemplateTests.cs +++ b/AspNetCoreSdkTests/TemplateTests.cs @@ -23,9 +23,9 @@ namespace AspNetCoreSdkTests [TestCaseSource(typeof(TemplateData), nameof(TemplateData.Current))] public void RestoreBuildRunPublish(Template template, NuGetConfig nuGetConfig) { - using (var context = new DotNetContext()) + using (var context = new DotNetContext(template)) { - context.New(template); + context.New(); context.Restore(nuGetConfig); CollectionAssert.AreEquivalent(template.ExpectedObjFilesAfterRestore, context.GetObjFiles()); @@ -43,6 +43,13 @@ namespace AspNetCoreSdkTests context.Publish(); CollectionAssert.AreEquivalent(template.ExpectedFilesAfterPublish, context.GetPublishFiles()); + + if (template.Type == TemplateType.WebApplication) + { + var (httpUrl, httpsUrl) = context.Exec(); + Assert.AreEqual(HttpStatusCode.OK, GetAsync(new Uri(new Uri(httpUrl), template.RelativeUrl)).StatusCode); + Assert.AreEqual(HttpStatusCode.OK, GetAsync(new Uri(new Uri(httpsUrl), template.RelativeUrl)).StatusCode); + } } } diff --git a/AspNetCoreSdkTests/Util/DotNetContext.cs b/AspNetCoreSdkTests/Util/DotNetContext.cs index faed3ed1ea..e3c57cf4c9 100644 --- a/AspNetCoreSdkTests/Util/DotNetContext.cs +++ b/AspNetCoreSdkTests/Util/DotNetContext.cs @@ -11,11 +11,16 @@ namespace AspNetCoreSdkTests.Util { private static readonly TimeSpan _sleepBetweenOutputContains = TimeSpan.FromMilliseconds(100); - private (Process Process, ConcurrentStringBuilder OutputBuilder, ConcurrentStringBuilder ErrorBuilder) _process; + private (Process Process, ConcurrentStringBuilder OutputBuilder, ConcurrentStringBuilder ErrorBuilder) _runProcess; + private (Process Process, ConcurrentStringBuilder OutputBuilder, ConcurrentStringBuilder ErrorBuilder) _execProcess; - public string New(Template template) + public DotNetContext(Template template) { Template = template; } + + public Template Template { get; } + + public string New() { - return DotNetUtil.New(template.Name, Path); + return DotNetUtil.New(Template.Name, Path); } public string Restore(NuGetConfig config) @@ -30,18 +35,35 @@ namespace AspNetCoreSdkTests.Util public (string httpUrl, string httpsUrl) Run() { - _process = DotNetUtil.Run(Path); + _runProcess = DotNetUtil.Run(Path); + return ScrapeUrls(_runProcess); + } + public (string httpUrl, string httpsUrl) Exec() + { + _execProcess = DotNetUtil.Exec(Path, Template.Name); + return ScrapeUrls(_execProcess); + } + + private (string httpUrl, string httpsUrl) ScrapeUrls( + (Process Process, ConcurrentStringBuilder OutputBuilder, ConcurrentStringBuilder ErrorBuilder) process) + { // Extract URLs from output while (true) { - var output = _process.OutputBuilder.ToString(); + var output = process.OutputBuilder.ToString(); if (output.Contains("Application started")) { var httpUrl = Regex.Match(output, @"Now listening on: (http:\S*)").Groups[1].Value; var httpsUrl = Regex.Match(output, @"Now listening on: (https:\S*)").Groups[1].Value; return (httpUrl, httpsUrl); } + else if (process.Process.HasExited) + { + var startInfo = process.Process.StartInfo; + throw new InvalidOperationException( + $"Failed to start process '{startInfo.FileName} {startInfo.Arguments}'" + Environment.NewLine + output); + } else { Thread.Sleep(_sleepBetweenOutputContains); @@ -71,14 +93,20 @@ namespace AspNetCoreSdkTests.Util public override void Dispose() { - // Must stop process to release filehandles before calling base.Dispose() which deletes app dir - if (_process.Process != null) - { - DotNetUtil.StopProcess(_process.Process, _process.OutputBuilder, _process.ErrorBuilder, throwOnError: false); - _process.Process = null; - } + // Must stop processes to release filehandles before calling base.Dispose() which deletes app dir + Dispose(_runProcess); + Dispose(_execProcess); base.Dispose(); } + + private static void Dispose((Process Process, ConcurrentStringBuilder OutputBuilder, ConcurrentStringBuilder ErrorBuilder) process) + { + if (process.Process != null) + { + DotNetUtil.StopProcess(process.Process, process.OutputBuilder, process.ErrorBuilder, throwOnError: false); + process.Process = null; + } + } } } diff --git a/AspNetCoreSdkTests/Util/DotNetUtil.cs b/AspNetCoreSdkTests/Util/DotNetUtil.cs index 7ce70f9729..9ac6790df0 100644 --- a/AspNetCoreSdkTests/Util/DotNetUtil.cs +++ b/AspNetCoreSdkTests/Util/DotNetUtil.cs @@ -9,6 +9,9 @@ namespace AspNetCoreSdkTests.Util { internal static class DotNetUtil { + // Bind to dynamic port 0 to avoid port conflicts during parallel tests + private const string _urls = "--urls http://127.0.0.1:0;https://127.0.0.1:0"; + public static string PublishOutput => "pub"; private static IEnumerable> GetEnvironment(string workingDirectory) @@ -36,8 +39,13 @@ namespace AspNetCoreSdkTests.Util public static (Process Process, ConcurrentStringBuilder OutputBuilder, ConcurrentStringBuilder ErrorBuilder) Run(string workingDirectory) { - // Bind to dynamic port 0 to avoid port conflicts during parallel tests - return StartDotNet("run --no-build --urls http://127.0.0.1:0;https://127.0.0.1:0", workingDirectory, GetEnvironment(workingDirectory)); + return StartDotNet($"run --no-build {_urls}", workingDirectory, GetEnvironment(workingDirectory)); + } + + internal static (Process Process, ConcurrentStringBuilder OutputBuilder, ConcurrentStringBuilder ErrorBuilder) Exec(string workingDirectory, string name) + { + var path = Path.Combine(PublishOutput, $"{name}.dll"); + return StartDotNet($"exec {path} {_urls}", workingDirectory, GetEnvironment(workingDirectory)); } public static string Publish(string workingDirectory)