diff --git a/src/SourceBuild/tarball/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/DotNetHelper.cs b/src/SourceBuild/tarball/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/DotNetHelper.cs index ba011b06c..7c263e080 100644 --- a/src/SourceBuild/tarball/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/DotNetHelper.cs +++ b/src/SourceBuild/tarball/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/DotNetHelper.cs @@ -79,14 +79,25 @@ internal class DotNetHelper } } - public void ExecuteCmd(string args, string? workingDirectory = null) + public void ExecuteCmd(string args, string? workingDirectory = null, Action? additionalProcessConfigCallback = null, int expectedExitCode = 0, int millisecondTimeout = -1) { + Action configureProcess = (Process process, string? workingDirectory) => { + ConfigureProcess(process, workingDirectory); + + if (additionalProcessConfigCallback != null) + { + additionalProcessConfigCallback(process); + } + }; + (Process Process, string StdOut, string StdErr) executeResult = ExecuteHelper.ExecuteProcess( DotNetPath, args, OutputHelper, - configure: (process) => ConfigureProcess(process, workingDirectory)); - ExecuteHelper.ValidateExitCode(executeResult); + configure: (process) => configureProcess(process, workingDirectory), + millisecondTimeout: millisecondTimeout); + + ExecuteHelper.ValidateExitCode(executeResult, expectedExitCode); } public static void ConfigureProcess(Process process, string? workingDirectory, bool setPath = false) @@ -170,18 +181,14 @@ internal class DotNetHelper public void ExecuteRunWeb(string projectName) { - (Process Process, string StdOut, string StdErr) executeResult = ExecuteHelper.ExecuteProcess( - DotNetPath, + ExecuteCmd( $"run {GetBinLogOption(projectName, "run")}", - OutputHelper, - configure: configureProcess, + GetProjectDirectory(projectName), + additionalProcessConfigCallback: processConfigCallback, millisecondTimeout: 30000); - ExecuteHelper.ValidateExitCode(executeResult); - void configureProcess(Process process) + void processConfigCallback(Process process) { - ConfigureProcess(process, GetProjectDirectory(projectName)); - process.OutputDataReceived += new DataReceivedEventHandler((sender, e) => { if (e.Data?.Contains("Application started. Press Ctrl+C to shut down.") ?? false) diff --git a/src/SourceBuild/tarball/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/DotNetWatchTests.cs b/src/SourceBuild/tarball/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/DotNetWatchTests.cs new file mode 100644 index 000000000..183311037 --- /dev/null +++ b/src/SourceBuild/tarball/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/DotNetWatchTests.cs @@ -0,0 +1,60 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using System.IO; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.DotNet.SourceBuild.SmokeTests; + +public class DotNetWatchTests : SmokeTests +{ + public DotNetWatchTests(ITestOutputHelper outputHelper) : base(outputHelper) { } + + [Fact] + public void WatchTests() + { + string projectDirectory = DotNetHelper.ExecuteNew(DotNetTemplate.Console.GetName(), nameof(DotNetWatchTests)); + bool outputChanged = false; + + // We expect an exit code of 143 (128 + 15, i.e. SIGTERM) because we are killing the process manually + DotNetHelper.ExecuteCmd( + "watch run", + workingDirectory: projectDirectory, + additionalProcessConfigCallback: processConfigCallback, + expectedExitCode: 143, + millisecondTimeout: 30000); + + Assert.True(outputChanged); + + void processConfigCallback(Process process) + { + const string waitingString = "Waiting for a file to change before restarting dotnet..."; + const string expectedString = "Hello from dotnet watch!"; + + bool fileChanged = false; + + process.OutputDataReceived += new DataReceivedEventHandler((sender, e) => + { + if (e.Data?.Contains(waitingString) ?? false) + { + if (!fileChanged) { + OutputHelper.WriteLine("Program started, changing file on disk to trigger restart..."); + File.WriteAllText( + Path.Combine(projectDirectory, "Program.cs"), + File.ReadAllText(Path.Combine(projectDirectory, "Program.cs")).Replace("Hello, World!", expectedString)); + fileChanged = true; + } + } + else if (e.Data?.Contains(expectedString) ?? false) + { + outputChanged = true; + OutputHelper.WriteLine("Successfully re-ran program after code change."); + ExecuteHelper.ExecuteProcessValidateExitCode("kill", $"-s TERM {process.Id}", OutputHelper); + } + }); + } + } +} diff --git a/src/SourceBuild/tarball/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/ExecuteHelper.cs b/src/SourceBuild/tarball/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/ExecuteHelper.cs index 5c135b3fe..4a7b87750 100644 --- a/src/SourceBuild/tarball/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/ExecuteHelper.cs +++ b/src/SourceBuild/tarball/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/ExecuteHelper.cs @@ -84,9 +84,9 @@ internal static class ExecuteHelper return result.StdOut; } - public static void ValidateExitCode((Process Process, string StdOut, string StdErr) result) + public static void ValidateExitCode((Process Process, string StdOut, string StdErr) result, int expectedExitCode = 0) { - if (result.Process.ExitCode != 0) + if (result.Process.ExitCode != expectedExitCode) { ProcessStartInfo startInfo = result.Process.StartInfo; string msg = $"Failed to execute {startInfo.FileName} {startInfo.Arguments}" +