Skip to content

Commit 91f9c5e

Browse files
committed
[dotnet-watch] Misc test fixes (#45575)
1 parent e058dd7 commit 91f9c5e

File tree

7 files changed

+61
-42
lines changed

7 files changed

+61
-42
lines changed

src/BuiltInTools/dotnet-watch/HotReloadDotNetWatcher.cs

Lines changed: 13 additions & 13 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 9 additions & 0 deletions
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

Lines changed: 14 additions & 3 deletions
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

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -249,9 +249,8 @@ class AppUpdateHandler
249249

250250
await App.AssertOutputLineStartsWith("Updated");
251251

252-
AssertEx.Contains(
253-
"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.",
254-
App.Process.Output);
252+
await App.WaitUntilOutputContains(
253+
$"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.");
255254
}
256255

257256
[Theory]
@@ -290,13 +289,11 @@ class AppUpdateHandler
290289

291290
await App.AssertOutputLineStartsWith("Updated");
292291

293-
AssertEx.Contains(
294-
"dotnet watch ⚠ [WatchHotReloadApp (net9.0)] Exception from 'System.Action`1[System.Type[]]': System.InvalidOperationException: Bug!",
295-
App.Process.Output);
292+
await App.WaitUntilOutputContains($"dotnet watch ⚠ [WatchHotReloadApp ({ToolsetInfo.CurrentTargetFramework})] Exception from 'System.Action`1[System.Type[]]': System.InvalidOperationException: Bug!");
296293

297294
if (verbose)
298295
{
299-
AssertEx.Contains("dotnet watch 🕵️ [WatchHotReloadApp (net9.0)] Deltas applied.", App.Process.Output);
296+
await App.WaitUntilOutputContains($"dotnet watch 🕵️ [WatchHotReloadApp ({ToolsetInfo.CurrentTargetFramework})] Deltas applied.");
300297
}
301298
else
302299
{
@@ -352,7 +349,7 @@ public async Task BlazorWasm(bool projectSpecifiesCapabilities)
352349
""";
353350

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

357354
// check project specified capapabilities:
358355
if (projectSpecifiesCapabilities)
@@ -415,8 +412,8 @@ public async Task Razor_Component_ScopedCssAndStaticAssets()
415412
await App.AssertOutputLineStartsWith("dotnet watch 🔥 Hot reload change handled");
416413

417414
App.AssertOutputContains($"dotnet watch ⌚ Handling file change event for scoped css file {scopedCssPath}.");
418-
App.AssertOutputContains($"dotnet watch ⌚ [RazorClassLibrary (net9.0)] No refresh server.");
419-
App.AssertOutputContains($"dotnet watch ⌚ [RazorApp (net9.0)] Refreshing browser.");
415+
App.AssertOutputContains($"dotnet watch ⌚ [RazorClassLibrary ({ToolsetInfo.CurrentTargetFramework})] No refresh server.");
416+
App.AssertOutputContains($"dotnet watch ⌚ [RazorApp ({ToolsetInfo.CurrentTargetFramework})] Refreshing browser.");
420417
App.AssertOutputContains($"dotnet watch 🔥 Hot reload of scoped css succeeded.");
421418
App.AssertOutputContains($"dotnet watch ⌚ No C# changes to apply.");
422419
App.Process.ClearOutput();
@@ -427,7 +424,7 @@ public async Task Razor_Component_ScopedCssAndStaticAssets()
427424
await App.AssertOutputLineStartsWith("dotnet watch 🔥 Hot reload change handled");
428425

429426
App.AssertOutputContains($"dotnet watch ⌚ Sending static file update request for asset 'app.css'.");
430-
App.AssertOutputContains($"dotnet watch ⌚ [RazorApp (net9.0)] Refreshing browser.");
427+
App.AssertOutputContains($"dotnet watch ⌚ [RazorApp ({ToolsetInfo.CurrentTargetFramework})] Refreshing browser.");
431428
App.AssertOutputContains($"dotnet watch 🔥 Hot Reload of static files succeeded.");
432429
App.AssertOutputContains($"dotnet watch ⌚ No C# changes to apply.");
433430
App.Process.ClearOutput();
@@ -625,6 +622,7 @@ public static void PrintDirectoryName([CallerFilePathAttribute] string filePath
625622
[Fact(Skip = "https://github.com/dotnet/sdk/issues/42850")]
626623
public async Task Aspire()
627624
{
625+
var tfm = ToolsetInfo.CurrentTargetFramework;
628626
var testAsset = TestAssets.CopyTestAsset("WatchAspire")
629627
.WithSource();
630628

@@ -650,8 +648,8 @@ public async Task Aspire()
650648
await App.AssertOutputLineStartsWith("dotnet watch 🔥 Hot reload change handled");
651649

652650
App.AssertOutputContains("Using Aspire process launcher.");
653-
App.AssertOutputContains(MessageDescriptor.HotReloadSucceeded, "WatchAspire.AppHost (net10.0)");
654-
App.AssertOutputContains(MessageDescriptor.HotReloadSucceeded, "WatchAspire.ApiService (net10.0)");
651+
App.AssertOutputContains(MessageDescriptor.HotReloadSucceeded, $"WatchAspire.AppHost ({tfm})");
652+
App.AssertOutputContains(MessageDescriptor.HotReloadSucceeded, $"WatchAspire.ApiService ({tfm})");
655653

656654
// Only one browser should be launched (dashboard). The child process shouldn't launch a browser.
657655
Assert.Equal(1, App.Process.Output.Count(line => line.StartsWith("dotnet watch ⌚ Launching browser: ")));
@@ -677,16 +675,16 @@ public async Task Aspire()
677675
// We don't have means to gracefully terminate process on Windows, see https://github.com/dotnet/runtime/issues/109432
678676
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
679677
{
680-
App.AssertOutputContains("dotnet watch ❌ [WatchAspire.ApiService (net9.0)] Exited with error code -1");
678+
App.AssertOutputContains($"dotnet watch ❌ [WatchAspire.ApiService ({tfm})] Exited with error code -1");
681679
}
682680
else
683681
{
684682
// Unix process may return exit code = 128 + SIGTERM
685-
// dotnet watch ❌ [WatchAspire.ApiService (net9.0)] Exited with error code 143
686-
App.AssertOutputContains("[WatchAspire.ApiService (net9.0)] Exited");
683+
// Exited with error code 143
684+
App.AssertOutputContains($"[WatchAspire.ApiService ({tfm})] Exited");
687685
}
688686

689-
App.AssertOutputContains($"dotnet watch ⌚ Building '{serviceProjectPath}' ...");
687+
App.AssertOutputContains($"dotnet watch ⌚ Building {serviceProjectPath} ...");
690688
App.AssertOutputContains("error CS0246: The type or namespace name 'WeatherForecast' could not be found");
691689
App.Process.ClearOutput();
692690

@@ -695,9 +693,9 @@ public async Task Aspire()
695693
serviceSourcePath,
696694
originalSource.Replace("WeatherForecast", "WeatherForecast2"));
697695

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

700-
App.AssertOutputContains("dotnet watch Build succeeded.");
698+
App.AssertOutputContains($"dotnet watch 🔨 Build succeeded: {serviceProjectPath}");
701699
App.AssertOutputContains("dotnet watch 🔥 Project baselines updated.");
702700
App.AssertOutputContains($"dotnet watch ⭐ Starting project: {serviceProjectPath}");
703701

@@ -708,15 +706,15 @@ public async Task Aspire()
708706
// We don't have means to gracefully terminate process on Windows, see https://github.com/dotnet/runtime/issues/109432
709707
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
710708
{
711-
await App.AssertOutputLineStartsWith("dotnet watch ❌ [WatchAspire.ApiService (net9.0)] Exited with error code -1");
712-
await App.AssertOutputLineStartsWith("dotnet watch ❌ [WatchAspire.AppHost (net9.0)] Exited with error code -1");
709+
await App.AssertOutputLineStartsWith($"dotnet watch ❌ [WatchAspire.ApiService ({tfm})] Exited with error code -1");
710+
await App.AssertOutputLineStartsWith($"dotnet watch ❌ [WatchAspire.AppHost ({tfm})] Exited with error code -1");
713711
}
714712
else
715713
{
716714
// Unix process may return exit code = 128 + SIGTERM
717-
// dotnet watch ❌ [WatchAspire.ApiService (net9.0)] Exited with error code 143
718-
await App.AssertOutputLine(line => line.Contains("[WatchAspire.ApiService (net9.0)] Exited"), failure: _ => false);
719-
await App.AssertOutputLine(line => line.Contains("[WatchAspire.AppHost (net9.0)] Exited"), failure: _ => false);
715+
// Exited with error code 143
716+
await App.AssertOutputLine(line => line.Contains($"[WatchAspire.ApiService ({tfm})] Exited"), failure: _ => false);
717+
await App.AssertOutputLine(line => line.Contains($"[WatchAspire.AppHost ({tfm})] Exited"), failure: _ => false);
720718
}
721719

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

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ private void OnData(object sender, DataReceivedEventArgs args)
131131
line = line.StripTerminalLoggerProgressIndicators();
132132
}
133133

134-
WriteTestOutput($"{DateTime.Now}: post: '{line}'");
134+
WriteTestOutput(line);
135135
_source.Post(line);
136136
}
137137

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public async ValueTask WaitUntilOutputContains(string message)
4444
{
4545
if (!Process.Output.Any(line => line.Contains(message)))
4646
{
47+
Logger.WriteLine($"[TEST] Test waiting for output: '{message}'");
4748
_ = await AssertOutputLine(line => line.Contains(message));
4849
}
4950
}

0 commit comments

Comments
 (0)