From 5ff8316ebff8c35943e72596ffc122f31d3b2937 Mon Sep 17 00:00:00 2001 From: Michael Simons Date: Tue, 16 Jun 2026 10:54:01 -0500 Subject: [PATCH 1/3] Fix flaky DeleteSubfolder test by waiting for expected events The TestOperation method previously signaled completion when it received any N unique events (where N = expectedChanges.Length). On Linux with polling, deleting a subdirectory can emit extra events like (subdir, Update) or (subdir, Delete) in addition to the expected file-level delete events. These spurious events filled the count quota before all expected events arrived, causing the assertion to fail. Fix: Change completion condition to wait until all expected events are present in the collected set (subset check), and change the assertion to verify all expected events were observed while tolerating extra OS events. Fixes #49233 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../dotnet-watch.Tests/FileWatcher/FileWatcherTests.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/dotnet-watch.Tests/FileWatcher/FileWatcherTests.cs b/test/dotnet-watch.Tests/FileWatcher/FileWatcherTests.cs index c61c14c6d473..56959df546b5 100644 --- a/test/dotnet-watch.Tests/FileWatcher/FileWatcherTests.cs +++ b/test/dotnet-watch.Tests/FileWatcher/FileWatcherTests.cs @@ -40,6 +40,7 @@ private async Task TestOperation( } var operationCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var expectedSet = new HashSet(expectedChanges); var filesChanged = new HashSet(); EventHandler handler = null; @@ -47,14 +48,14 @@ private async Task TestOperation( { if (filesChanged.Add(f)) { - output.WriteLine($"Observed new {f.Kind}: '{f.Path}' ({filesChanged.Count} out of {expectedChanges.Length})"); + output.WriteLine($"Observed new {f.Kind}: '{f.Path}' ({filesChanged.Count} changes, {expectedSet.Count(e => filesChanged.Contains(e))} out of {expectedChanges.Length} expected)"); } else { output.WriteLine($"Already seen {f.Kind}: '{f.Path}'"); } - if (filesChanged.Count == expectedChanges.Length) + if (expectedSet.IsSubsetOf(filesChanged)) { watcher.EnableRaisingEvents = false; watcher.OnFileChange -= handler; @@ -78,7 +79,10 @@ private async Task TestOperation( var task = operationCompletionSource.Task; await (Debugger.IsAttached ? task : task.TimeoutAfter(DefaultTimeout)); - AssertEx.SequenceEqual(expectedChanges, filesChanged.OrderBy(x => x.Path)); + // Verify all expected changes were observed (extra events from the OS are acceptable) + var missing = expectedSet.Except(filesChanged).ToArray(); + Assert.True(missing.Length == 0, + $"Expected changes not observed: {string.Join(", ", missing.Select(m => $"{m.Kind}: '{m.Path}'"))}\nActual changes: {string.Join(", ", filesChanged.OrderBy(x => x.Path).Select(m => $"{m.Kind}: '{m.Path}'"))}"); } private sealed class TestFileWatcher(ILogger logger) From c6054d1291fcff3de549ff5673101dbe6e5f9347 Mon Sep 17 00:00:00 2001 From: Michael Simons Date: Tue, 16 Jun 2026 11:56:19 -0500 Subject: [PATCH 2/3] Sort missing changes for deterministic failure messages Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- test/dotnet-watch.Tests/FileWatcher/FileWatcherTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/dotnet-watch.Tests/FileWatcher/FileWatcherTests.cs b/test/dotnet-watch.Tests/FileWatcher/FileWatcherTests.cs index 56959df546b5..fb3ca8c9ee8e 100644 --- a/test/dotnet-watch.Tests/FileWatcher/FileWatcherTests.cs +++ b/test/dotnet-watch.Tests/FileWatcher/FileWatcherTests.cs @@ -80,7 +80,7 @@ private async Task TestOperation( await (Debugger.IsAttached ? task : task.TimeoutAfter(DefaultTimeout)); // Verify all expected changes were observed (extra events from the OS are acceptable) - var missing = expectedSet.Except(filesChanged).ToArray(); + var missing = expectedSet.Except(filesChanged).OrderBy(x => x.Path).ToArray(); Assert.True(missing.Length == 0, $"Expected changes not observed: {string.Join(", ", missing.Select(m => $"{m.Kind}: '{m.Path}'"))}\nActual changes: {string.Join(", ", filesChanged.OrderBy(x => x.Path).Select(m => $"{m.Kind}: '{m.Path}'"))}"); } From c2c20151be6dc69b4385acc1381d6d79b4ca028f Mon Sep 17 00:00:00 2001 From: Michael Simons Date: Tue, 16 Jun 2026 11:57:32 -0500 Subject: [PATCH 3/3] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- test/dotnet-watch.Tests/FileWatcher/FileWatcherTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/test/dotnet-watch.Tests/FileWatcher/FileWatcherTests.cs b/test/dotnet-watch.Tests/FileWatcher/FileWatcherTests.cs index fb3ca8c9ee8e..5fa9aa520fd3 100644 --- a/test/dotnet-watch.Tests/FileWatcher/FileWatcherTests.cs +++ b/test/dotnet-watch.Tests/FileWatcher/FileWatcherTests.cs @@ -41,6 +41,7 @@ private async Task TestOperation( var operationCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var expectedSet = new HashSet(expectedChanges); + Assert.True(expectedSet.Count == expectedChanges.Length, "expectedChanges must not contain duplicates."); var filesChanged = new HashSet(); EventHandler handler = null;