Skip to content

Commit 877ff60

Browse files
authored
[dotnet-watch] Misc test fixes (#45575)
1 parent a262d4c commit 877ff60

File tree

7 files changed

+60
-38
lines changed

7 files changed

+60
-38
lines changed

src/BuiltInTools/dotnet-watch/HotReloadDotNetWatcher.cs

+13-13
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,10 @@ public override async Task WatchAsync(CancellationToken shutdownCancellationToke
121121
};
122122
}
123123

124-
if (!await BuildProjectAsync(rootProjectOptions.ProjectPath, rootProjectOptions.BuildArguments, iterationCancellationToken))
124+
var (buildSucceeded, buildOutput, _) = await BuildProjectAsync(rootProjectOptions.ProjectPath, rootProjectOptions.BuildArguments, iterationCancellationToken);
125+
BuildUtilities.ReportBuildOutput(Context.Reporter, buildOutput, buildSucceeded, projectDisplay: rootProjectOptions.ProjectPath);
126+
if (!buildSucceeded)
125127
{
126-
// error has been reported:
127128
continue;
128129
}
129130

@@ -334,7 +335,12 @@ void FileChangedCallback(ChangedPath change)
334335
var buildResults = await Task.WhenAll(
335336
projectsToRebuild.Values.Select(projectPath => BuildProjectAsync(projectPath, rootProjectOptions.BuildArguments, iterationCancellationToken)));
336337

337-
if (buildResults.All(success => success))
338+
foreach (var (success, output, projectPath) in buildResults)
339+
{
340+
BuildUtilities.ReportBuildOutput(Context.Reporter, output, success, projectPath);
341+
}
342+
343+
if (buildResults.All(result => result.success))
338344
{
339345
break;
340346
}
@@ -815,7 +821,8 @@ await FileWatcher.WaitForFileChangeAsync(
815821
}
816822
}
817823

818-
private async Task<bool> BuildProjectAsync(string projectPath, IReadOnlyList<string> buildArguments, CancellationToken cancellationToken)
824+
private async Task<(bool success, ImmutableArray<OutputLine> output, string projectPath)> BuildProjectAsync(
825+
string projectPath, IReadOnlyList<string> buildArguments, CancellationToken cancellationToken)
819826
{
820827
var buildOutput = new List<OutputLine>();
821828

@@ -834,17 +841,10 @@ private async Task<bool> BuildProjectAsync(string projectPath, IReadOnlyList<str
834841
Arguments = ["build", projectPath, "-consoleLoggerParameters:NoSummary;Verbosity=minimal", .. buildArguments]
835842
};
836843

837-
Context.Reporter.Output($"Building '{projectPath}' ...");
844+
Context.Reporter.Output($"Building {projectPath} ...");
838845

839846
var exitCode = await ProcessRunner.RunAsync(processSpec, Context.Reporter, isUserApplication: false, launchResult: null, cancellationToken);
840-
BuildUtilities.ReportBuildOutput(Context.Reporter, buildOutput, verboseOutput: exitCode == 0);
841-
842-
if (exitCode == 0)
843-
{
844-
Context.Reporter.Output("Build succeeded.");
845-
}
846-
847-
return exitCode == 0;
847+
return (exitCode == 0, buildOutput.ToImmutableArray(), projectPath);
848848
}
849849

850850
private string GetRelativeFilePath(string path)

src/BuiltInTools/dotnet-watch/Internal/MsBuildFileSetFactory.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ internal class MSBuildFileSetFactory(
6363
reporter.Output($"MSBuild output from target '{TargetName}':");
6464
}
6565

66-
BuildUtilities.ReportBuildOutput(reporter, capturedOutput, verboseOutput: success);
66+
BuildUtilities.ReportBuildOutput(reporter, capturedOutput, success, projectDisplay: null);
6767
if (!success)
6868
{
6969
return null;

src/BuiltInTools/dotnet-watch/Internal/ProcessRunner.cs

+9
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,15 @@ public static async Task<int> RunAsync(ProcessSpec processSpec, IReporter report
8787
try
8888
{
8989
await process.WaitForExitAsync(processTerminationToken);
90+
91+
// ensures that all process output has been reported:
92+
try
93+
{
94+
process.WaitForExit();
95+
}
96+
catch
97+
{
98+
}
9099
}
91100
catch (OperationCanceledException)
92101
{

src/BuiltInTools/dotnet-watch/Utilities/BuildUtilities.cs

+14-3
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,25 @@ namespace Microsoft.DotNet.Watch;
77

88
internal static partial class BuildUtilities
99
{
10+
private const string BuildEmoji = "🔨";
1011
private static readonly Regex s_buildDiagnosticRegex = GetBuildDiagnosticRegex();
1112

1213
[GeneratedRegex(@"[^:]+: (error|warning) [A-Za-z]+[0-9]+: .+")]
1314
private static partial Regex GetBuildDiagnosticRegex();
1415

15-
public static void ReportBuildOutput(IReporter reporter, IEnumerable<OutputLine> buildOutput, bool verboseOutput)
16+
public static void ReportBuildOutput(IReporter reporter, IEnumerable<OutputLine> buildOutput, bool success, string? projectDisplay)
1617
{
17-
const string BuildEmoji = "🔨";
18+
if (projectDisplay != null)
19+
{
20+
if (success)
21+
{
22+
reporter.Output($"Build succeeded: {projectDisplay}", BuildEmoji);
23+
}
24+
else
25+
{
26+
reporter.Output($"Build failed: {projectDisplay}", BuildEmoji);
27+
}
28+
}
1829

1930
foreach (var (line, isError) in buildOutput)
2031
{
@@ -33,7 +44,7 @@ public static void ReportBuildOutput(IReporter reporter, IEnumerable<OutputLine>
3344
reporter.Warn(line);
3445
}
3546
}
36-
else if (verboseOutput)
47+
else if (success)
3748
{
3849
reporter.Verbose(line, BuildEmoji);
3950
}

test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs

+21-20
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ class AppUpdateHandler
248248
await App.AssertOutputLineStartsWith("Updated");
249249

250250
await App.WaitUntilOutputContains(
251-
"dotnet watch ⚠ [WatchHotReloadApp (net9.0)] Expected to find a static method 'ClearCache' or 'UpdateApplication' on type 'AppUpdateHandler, WatchHotReloadApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' but neither exists.");
251+
$"dotnet watch ⚠ [WatchHotReloadApp ({ToolsetInfo.CurrentTargetFramework})] Expected to find a static method 'ClearCache' or 'UpdateApplication' on type 'AppUpdateHandler, WatchHotReloadApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' but neither exists.");
252252
}
253253

254254
[Theory]
@@ -287,11 +287,11 @@ class AppUpdateHandler
287287

288288
await App.AssertOutputLineStartsWith("Updated");
289289

290-
await App.WaitUntilOutputContains("dotnet watch ⚠ [WatchHotReloadApp (net9.0)] Exception from 'System.Action`1[System.Type[]]': System.InvalidOperationException: Bug!");
290+
await App.WaitUntilOutputContains($"dotnet watch ⚠ [WatchHotReloadApp ({ToolsetInfo.CurrentTargetFramework})] Exception from 'System.Action`1[System.Type[]]': System.InvalidOperationException: Bug!");
291291

292292
if (verbose)
293293
{
294-
await App.WaitUntilOutputContains("dotnet watch 🕵️ [WatchHotReloadApp (net9.0)] Deltas applied.");
294+
await App.WaitUntilOutputContains($"dotnet watch 🕵️ [WatchHotReloadApp ({ToolsetInfo.CurrentTargetFramework})] Deltas applied.");
295295
}
296296
else
297297
{
@@ -347,7 +347,7 @@ public async Task BlazorWasm(bool projectSpecifiesCapabilities)
347347
""";
348348

349349
UpdateSourceFile(Path.Combine(testAsset.Path, "Pages", "Index.razor"), newSource);
350-
await App.AssertOutputLineStartsWith(MessageDescriptor.HotReloadSucceeded, "blazorwasm (net9.0)");
350+
await App.AssertOutputLineStartsWith(MessageDescriptor.HotReloadSucceeded, $"blazorwasm ({ToolsetInfo.CurrentTargetFramework})");
351351

352352
// check project specified capapabilities:
353353
if (projectSpecifiesCapabilities)
@@ -410,8 +410,8 @@ public async Task Razor_Component_ScopedCssAndStaticAssets()
410410
await App.AssertOutputLineStartsWith("dotnet watch 🔥 Hot reload change handled");
411411

412412
App.AssertOutputContains($"dotnet watch ⌚ Handling file change event for scoped css file {scopedCssPath}.");
413-
App.AssertOutputContains($"dotnet watch ⌚ [RazorClassLibrary (net9.0)] No refresh server.");
414-
App.AssertOutputContains($"dotnet watch ⌚ [RazorApp (net9.0)] Refreshing browser.");
413+
App.AssertOutputContains($"dotnet watch ⌚ [RazorClassLibrary ({ToolsetInfo.CurrentTargetFramework})] No refresh server.");
414+
App.AssertOutputContains($"dotnet watch ⌚ [RazorApp ({ToolsetInfo.CurrentTargetFramework})] Refreshing browser.");
415415
App.AssertOutputContains($"dotnet watch 🔥 Hot reload of scoped css succeeded.");
416416
App.AssertOutputContains($"dotnet watch ⌚ No C# changes to apply.");
417417
App.Process.ClearOutput();
@@ -422,7 +422,7 @@ public async Task Razor_Component_ScopedCssAndStaticAssets()
422422
await App.AssertOutputLineStartsWith("dotnet watch 🔥 Hot reload change handled");
423423

424424
App.AssertOutputContains($"dotnet watch ⌚ Sending static file update request for asset 'app.css'.");
425-
App.AssertOutputContains($"dotnet watch ⌚ [RazorApp (net9.0)] Refreshing browser.");
425+
App.AssertOutputContains($"dotnet watch ⌚ [RazorApp ({ToolsetInfo.CurrentTargetFramework})] Refreshing browser.");
426426
App.AssertOutputContains($"dotnet watch 🔥 Hot Reload of static files succeeded.");
427427
App.AssertOutputContains($"dotnet watch ⌚ No C# changes to apply.");
428428
App.Process.ClearOutput();
@@ -620,6 +620,7 @@ public static void PrintDirectoryName([CallerFilePathAttribute] string filePath
620620
[Fact]
621621
public async Task Aspire()
622622
{
623+
var tfm = ToolsetInfo.CurrentTargetFramework;
623624
var testAsset = TestAssets.CopyTestAsset("WatchAspire")
624625
.WithSource();
625626

@@ -645,8 +646,8 @@ public async Task Aspire()
645646
await App.AssertOutputLineStartsWith("dotnet watch 🔥 Hot reload change handled");
646647

647648
App.AssertOutputContains("Using Aspire process launcher.");
648-
App.AssertOutputContains(MessageDescriptor.HotReloadSucceeded, "WatchAspire.AppHost (net9.0)");
649-
App.AssertOutputContains(MessageDescriptor.HotReloadSucceeded, "WatchAspire.ApiService (net9.0)");
649+
App.AssertOutputContains(MessageDescriptor.HotReloadSucceeded, $"WatchAspire.AppHost ({tfm})");
650+
App.AssertOutputContains(MessageDescriptor.HotReloadSucceeded, $"WatchAspire.ApiService ({tfm})");
650651

651652
// Only one browser should be launched (dashboard). The child process shouldn't launch a browser.
652653
Assert.Equal(1, App.Process.Output.Count(line => line.StartsWith("dotnet watch ⌚ Launching browser: ")));
@@ -672,16 +673,16 @@ public async Task Aspire()
672673
// We don't have means to gracefully terminate process on Windows, see https://github.com/dotnet/runtime/issues/109432
673674
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
674675
{
675-
App.AssertOutputContains("dotnet watch ❌ [WatchAspire.ApiService (net9.0)] Exited with error code -1");
676+
App.AssertOutputContains($"dotnet watch ❌ [WatchAspire.ApiService ({tfm})] Exited with error code -1");
676677
}
677678
else
678679
{
679680
// Unix process may return exit code = 128 + SIGTERM
680-
// dotnet watch ❌ [WatchAspire.ApiService (net9.0)] Exited with error code 143
681-
App.AssertOutputContains("[WatchAspire.ApiService (net9.0)] Exited");
681+
// Exited with error code 143
682+
App.AssertOutputContains($"[WatchAspire.ApiService ({tfm})] Exited");
682683
}
683684

684-
App.AssertOutputContains($"dotnet watch ⌚ Building '{serviceProjectPath}' ...");
685+
App.AssertOutputContains($"dotnet watch ⌚ Building {serviceProjectPath} ...");
685686
App.AssertOutputContains("error CS0246: The type or namespace name 'WeatherForecast' could not be found");
686687
App.Process.ClearOutput();
687688

@@ -690,9 +691,9 @@ public async Task Aspire()
690691
serviceSourcePath,
691692
originalSource.Replace("WeatherForecast", "WeatherForecast2"));
692693

693-
await App.AssertOutputLineStartsWith("dotnet watch ⌚ [WatchAspire.ApiService (net9.0)] Capabilities");
694+
await App.AssertOutputLineStartsWith($"dotnet watch ⌚ [WatchAspire.ApiService ({tfm})] Capabilities");
694695

695-
App.AssertOutputContains("dotnet watch Build succeeded.");
696+
App.AssertOutputContains($"dotnet watch 🔨 Build succeeded: {serviceProjectPath}");
696697
App.AssertOutputContains("dotnet watch 🔥 Project baselines updated.");
697698
App.AssertOutputContains($"dotnet watch ⭐ Starting project: {serviceProjectPath}");
698699

@@ -703,15 +704,15 @@ public async Task Aspire()
703704
// We don't have means to gracefully terminate process on Windows, see https://github.com/dotnet/runtime/issues/109432
704705
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
705706
{
706-
await App.AssertOutputLineStartsWith("dotnet watch ❌ [WatchAspire.ApiService (net9.0)] Exited with error code -1");
707-
await App.AssertOutputLineStartsWith("dotnet watch ❌ [WatchAspire.AppHost (net9.0)] Exited with error code -1");
707+
await App.AssertOutputLineStartsWith($"dotnet watch ❌ [WatchAspire.ApiService ({tfm})] Exited with error code -1");
708+
await App.AssertOutputLineStartsWith($"dotnet watch ❌ [WatchAspire.AppHost ({tfm})] Exited with error code -1");
708709
}
709710
else
710711
{
711712
// Unix process may return exit code = 128 + SIGTERM
712-
// dotnet watch ❌ [WatchAspire.ApiService (net9.0)] Exited with error code 143
713-
await App.AssertOutputLine(line => line.Contains("[WatchAspire.ApiService (net9.0)] Exited"), failure: _ => false);
714-
await App.AssertOutputLine(line => line.Contains("[WatchAspire.AppHost (net9.0)] Exited"), failure: _ => false);
713+
// Exited with error code 143
714+
await App.AssertOutputLine(line => line.Contains($"[WatchAspire.ApiService ({tfm})] Exited"), failure: _ => false);
715+
await App.AssertOutputLine(line => line.Contains($"[WatchAspire.AppHost ({tfm})] Exited"), failure: _ => false);
715716
}
716717

717718
await App.AssertOutputLineStartsWith("dotnet watch ⭐ Waiting for server to shutdown ...");

test/dotnet-watch.Tests/Utilities/AwaitableProcess.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ private void OnData(object sender, DataReceivedEventArgs args)
129129
line = line.StripTerminalLoggerProgressIndicators();
130130
}
131131

132-
WriteTestOutput($"{DateTime.Now}: post: '{line}'");
132+
WriteTestOutput(line);
133133
_source.Post(line);
134134
}
135135

test/dotnet-watch.Tests/Watch/Utilities/WatchableApp.cs

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public async ValueTask WaitUntilOutputContains(string message)
4242
{
4343
if (!Process.Output.Any(line => line.Contains(message)))
4444
{
45+
Logger.WriteLine($"[TEST] Test waiting for output: '{message}'");
4546
_ = await AssertOutputLine(line => line.Contains(message));
4647
}
4748
}

0 commit comments

Comments
 (0)