diff --git a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.Directory.Changed.cs b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.Directory.Changed.cs index e89158982d92c7..bef5def6c97bcb 100644 --- a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.Directory.Changed.cs +++ b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.Directory.Changed.cs @@ -7,7 +7,6 @@ namespace System.IO.Tests { - [ActiveIssue("https://github.com/dotnet/runtime/issues/103584", TestPlatforms.Windows)] public class Directory_Changed_Tests : FileSystemWatcherTest { [Fact] diff --git a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.Directory.Create.cs b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.Directory.Create.cs index d3777d6aaf6a7e..023cc679eb32b3 100644 --- a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.Directory.Create.cs +++ b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.Directory.Create.cs @@ -6,7 +6,6 @@ namespace System.IO.Tests { - [ActiveIssue("https://github.com/dotnet/runtime/issues/103584", TestPlatforms.Windows)] public class Directory_Create_Tests : FileSystemWatcherTest { [Fact] diff --git a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.Directory.Delete.cs b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.Directory.Delete.cs index 638eda424c3ed8..a30e355acccf69 100644 --- a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.Directory.Delete.cs +++ b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.Directory.Delete.cs @@ -7,7 +7,6 @@ namespace System.IO.Tests { - [ActiveIssue("https://github.com/dotnet/runtime/issues/103584", TestPlatforms.Windows)] public class Directory_Delete_Tests : FileSystemWatcherTest { [Fact] diff --git a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.Directory.Move.cs b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.Directory.Move.cs index da63b362e08aac..4d1640733e2b6c 100644 --- a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.Directory.Move.cs +++ b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.Directory.Move.cs @@ -9,7 +9,6 @@ namespace System.IO.Tests { - [ActiveIssue("https://github.com/dotnet/runtime/issues/103584", TestPlatforms.Windows)] public class Directory_Move_Tests : FileSystemWatcherTest { [Fact] diff --git a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.Directory.NotifyFilter.cs b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.Directory.NotifyFilter.cs index cf0677e01634be..2a692ad6056cb6 100644 --- a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.Directory.NotifyFilter.cs +++ b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.Directory.NotifyFilter.cs @@ -9,7 +9,6 @@ namespace System.IO.Tests { - [ActiveIssue("https://github.com/dotnet/runtime/issues/103584", TestPlatforms.Windows)] public partial class Directory_NotifyFilter_Tests : FileSystemWatcherTest { [LibraryImport("advapi32.dll", EntryPoint = "SetNamedSecurityInfoW", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)] diff --git a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.Changed.cs b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.Changed.cs index db3c4043ee1f02..44b41c3778e201 100644 --- a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.Changed.cs +++ b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.Changed.cs @@ -6,7 +6,6 @@ namespace System.IO.Tests { - [ActiveIssue("https://github.com/dotnet/runtime/issues/103584", TestPlatforms.Windows)] public class File_Changed_Tests : FileSystemWatcherTest { [Fact] diff --git a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.Create.cs b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.Create.cs index b02f07ecd046cd..5c36caf0a38fd1 100644 --- a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.Create.cs +++ b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.Create.cs @@ -10,7 +10,6 @@ namespace System.IO.Tests { - [ActiveIssue("https://github.com/dotnet/runtime/issues/103584", TestPlatforms.Windows)] public class File_Create_Tests : FileSystemWatcherTest { [Fact] diff --git a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.Delete.cs b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.Delete.cs index 0a3b3ed1a3d100..ac076e4fd2202b 100644 --- a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.Delete.cs +++ b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.Delete.cs @@ -8,7 +8,6 @@ namespace System.IO.Tests { - [ActiveIssue("https://github.com/dotnet/runtime/issues/103584", TestPlatforms.Windows)] public class File_Delete_Tests : FileSystemWatcherTest { [Fact] diff --git a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.Move.cs b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.Move.cs index 428dd0a47f7ecd..2a2a26a5767571 100644 --- a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.Move.cs +++ b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.Move.cs @@ -8,7 +8,6 @@ namespace System.IO.Tests { - [ActiveIssue("https://github.com/dotnet/runtime/issues/103584", TestPlatforms.Windows)] public class File_Move_Tests : FileSystemWatcherTest { [Fact] diff --git a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.NotifyFilter.cs b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.NotifyFilter.cs index 74f48d1402f95d..80c37d1b8a061f 100644 --- a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.NotifyFilter.cs +++ b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.NotifyFilter.cs @@ -11,7 +11,6 @@ namespace System.IO.Tests { - [ActiveIssue("https://github.com/dotnet/runtime/issues/103584", TestPlatforms.Windows)] public partial class File_NotifyFilter_Tests : FileSystemWatcherTest { [LibraryImport("advapi32.dll", EntryPoint = "SetNamedSecurityInfoW", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)] diff --git a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.InternalBufferSize.cs b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.InternalBufferSize.cs index 07a3e3c24bb91c..6df52a9395793e 100644 --- a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.InternalBufferSize.cs +++ b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.InternalBufferSize.cs @@ -8,7 +8,6 @@ namespace System.IO.Tests { - [ActiveIssue("https://github.com/dotnet/runtime/issues/103584", TestPlatforms.Windows)] public class InternalBufferSizeTests : FileSystemWatcherTest { // FSW works by calling ReadDirectoryChanges asynchronously, processing the changes diff --git a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.SymbolicLink.cs b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.SymbolicLink.cs index a0874f6b3afdb7..258a123acea01c 100644 --- a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.SymbolicLink.cs +++ b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.SymbolicLink.cs @@ -58,7 +58,7 @@ public void FileSystemWatcher_DirectorySymbolicLink_TargetsSelf_Fails() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/103584", TestPlatforms.Windows)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/53366", TestPlatforms.Windows)] public void FileSystemWatcher_SymbolicLink_TargetsDirectory_Create() { // Arrange @@ -123,7 +123,7 @@ public void FileSystemWatcher_SymbolicLink_TargetsDirectory_Create_IncludeSubdir [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/70450", TestPlatforms.OSX)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/103584", TestPlatforms.Windows)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/53366", TestPlatforms.Windows)] public void FileSystemWatcher_SymbolicLink_IncludeSubdirectories_DoNotDereferenceChildLink() { // Arrange diff --git a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.cs b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.cs index f2525543ce2ec4..9f0dce0d70a47f 100644 --- a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.cs +++ b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.cs @@ -170,7 +170,6 @@ public void BeginInit_PausesEnableRaisingEvents() [Theory] [InlineData(true)] [InlineData(false)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/103584", TestPlatforms.Windows)] public void EndInit_ResumesPausedEnableRaisingEvents(bool setBeforeBeginInit) { FileSystemWatcherTest.Execute(() => diff --git a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.unit.cs b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.unit.cs index 7b60c4041eb872..b5109503e4b6cb 100644 --- a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.unit.cs +++ b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.unit.cs @@ -258,7 +258,6 @@ public void FileSystemWatcher_IncludeSubdirectories() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/103584", TestPlatforms.Windows)] public void FileSystemWatcher_InternalBufferSize() { FileSystemWatcher watcher = new FileSystemWatcher(); @@ -363,7 +362,6 @@ public void FileSystemWatcher_OnCreated() [Fact] [PlatformSpecific(TestPlatforms.OSX | TestPlatforms.Windows)] // Casing matters on Linux - [ActiveIssue("https://github.com/dotnet/runtime/issues/103584", TestPlatforms.Windows)] public void FileSystemWatcher_OnCreatedWithMismatchedCasingGivesExpectedFullPath() { using (var fsw = new FileSystemWatcher(TestDirectory)) @@ -456,7 +454,6 @@ public void FileSystemWatcher_OnRenamed() [Fact] [PlatformSpecific(TestPlatforms.Windows)] // Unix FSW don't trigger on a file rename. - [ActiveIssue("https://github.com/dotnet/runtime/issues/103584", TestPlatforms.Windows)] public void FileSystemWatcher_Windows_OnRenameGivesExpectedFullPath() { string file = CreateTestFile(TestDirectory, "file"); @@ -570,7 +567,6 @@ public void FileSystemWatcher_StopCalledOnBackgroundThreadDoesNotDeadlock() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/103584", TestPlatforms.Windows)] public void FileSystemWatcher_WatchingAliasedFolderResolvesToRealPathWhenWatching() { string dir = CreateTestDirectory(TestDirectory, "dir"); @@ -934,7 +930,6 @@ public void SetAndGetFiltersProperty() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/103584", TestPlatforms.Windows)] public void FileSystemWatcher_File_Delete_MultipleFilters() { // Check delete events against multiple filters @@ -959,7 +954,6 @@ public void FileSystemWatcher_File_Delete_MultipleFilters() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/103584", TestPlatforms.Windows)] public void FileSystemWatcher_Directory_Create_MultipleFilters() { FileSystemWatcherTest.Execute(() => @@ -976,15 +970,14 @@ public void FileSystemWatcher_Directory_Create_MultipleFilters() watcher.Filters.Add(Path.GetFileName(directoryOne)); watcher.Filters.Add(Path.GetFileName(directoryTwo)); - ExpectEvent(watcher, WatcherChangeTypes.Created, () => Directory.CreateDirectory(directoryOne), cleanup: null, expectedPath: directoryOne); - ExpectEvent(watcher, WatcherChangeTypes.Created, () => Directory.CreateDirectory(directoryTwo), cleanup: null, expectedPath: directoryTwo); - ExpectNoEvent(watcher, WatcherChangeTypes.Created, () => Directory.CreateDirectory(directoryThree), cleanup: null, expectedPath: directoryThree); + ExpectEvent(watcher, WatcherChangeTypes.Created, () => Directory.CreateDirectory(directoryOne), cleanup: () => { if (Directory.Exists(directoryOne)) Directory.Delete(directoryOne); }, expectedPath: directoryOne); + ExpectEvent(watcher, WatcherChangeTypes.Created, () => Directory.CreateDirectory(directoryTwo), cleanup: () => { if (Directory.Exists(directoryTwo)) Directory.Delete(directoryTwo); }, expectedPath: directoryTwo); + ExpectNoEvent(watcher, WatcherChangeTypes.Created, () => Directory.CreateDirectory(directoryThree), cleanup: () => { if (Directory.Exists(directoryThree)) Directory.Delete(directoryThree); }, expectedPath: directoryThree); } }, maxAttempts: DefaultAttemptsForExpectedEvent, backoffFunc: (iteration) => RetryDelayMilliseconds, retryWhen: e => e is XunitException); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/103584", TestPlatforms.Windows)] public void FileSystemWatcher_Directory_Create_Filter_Ctor() { FileSystemWatcherTest.Execute(() => @@ -1000,15 +993,14 @@ public void FileSystemWatcher_Directory_Create_Filter_Ctor() { watcher.Filters.Add(Path.GetFileName(directoryTwo)); - ExpectEvent(watcher, WatcherChangeTypes.Created, () => Directory.CreateDirectory(directoryOne), cleanup: null, expectedPath: directoryOne); - ExpectEvent(watcher, WatcherChangeTypes.Created, () => Directory.CreateDirectory(directoryTwo), cleanup: null, expectedPath: directoryTwo); - ExpectNoEvent(watcher, WatcherChangeTypes.Created, () => Directory.CreateDirectory(directoryThree), cleanup: null, expectedPath: directoryThree); + ExpectEvent(watcher, WatcherChangeTypes.Created, () => Directory.CreateDirectory(directoryOne), cleanup: () => { if (Directory.Exists(directoryOne)) Directory.Delete(directoryOne); }, expectedPath: directoryOne); + ExpectEvent(watcher, WatcherChangeTypes.Created, () => Directory.CreateDirectory(directoryTwo), cleanup: () => { if (Directory.Exists(directoryTwo)) Directory.Delete(directoryTwo); }, expectedPath: directoryTwo); + ExpectNoEvent(watcher, WatcherChangeTypes.Created, () => Directory.CreateDirectory(directoryThree), cleanup: () => { if (Directory.Exists(directoryThree)) Directory.Delete(directoryThree); }, expectedPath: directoryThree); } }, maxAttempts: DefaultAttemptsForExpectedEvent, backoffFunc: (iteration) => RetryDelayMilliseconds, retryWhen: e => e is XunitException); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/103584", TestPlatforms.Windows)] public void FileSystemWatcher_Directory_Delete_MultipleFilters() { using var tempDir = new TempDirectory(); @@ -1028,7 +1020,6 @@ public void FileSystemWatcher_Directory_Delete_MultipleFilters() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/103584", TestPlatforms.Windows)] public void FileSystemWatcher_File_Create_MultipleFilters() { FileSystemWatcherTest.Execute(() => @@ -1043,15 +1034,14 @@ public void FileSystemWatcher_File_Create_MultipleFilters() watcher.Filters.Add(fileOne.Name); watcher.Filters.Add(fileTwo.Name); - ExpectEvent(watcher, WatcherChangeTypes.Created, () => fileOne.Create().Dispose(), cleanup: null, expectedPath: fileOne.FullName); - ExpectEvent(watcher, WatcherChangeTypes.Created, () => fileTwo.Create().Dispose(), cleanup: null, expectedPath: fileTwo.FullName); - ExpectNoEvent(watcher, WatcherChangeTypes.Created, () => fileThree.Create().Dispose(), cleanup: null, expectedPath: fileThree.FullName); + ExpectEvent(watcher, WatcherChangeTypes.Created, () => fileOne.Create().Dispose(), cleanup: () => fileOne.Delete(), expectedPath: fileOne.FullName); + ExpectEvent(watcher, WatcherChangeTypes.Created, () => fileTwo.Create().Dispose(), cleanup: () => fileTwo.Delete(), expectedPath: fileTwo.FullName); + ExpectNoEvent(watcher, WatcherChangeTypes.Created, () => fileThree.Create().Dispose(), cleanup: () => fileThree.Delete(), expectedPath: fileThree.FullName); } }, maxAttempts: DefaultAttemptsForExpectedEvent, backoffFunc: (iteration) => RetryDelayMilliseconds, retryWhen: e => e is XunitException); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsMultithreadingSupported))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/103584", TestPlatforms.Windows)] public void FileSystemWatcher_ModifyFiltersConcurrentWithEvents() { FileSystemWatcherTest.Execute(() => @@ -1079,9 +1069,9 @@ public void FileSystemWatcher_ModifyFiltersConcurrentWithEvents() thread.IsBackground = true; thread.Start(); - ExpectEvent(watcher, WatcherChangeTypes.Created, () => fileOne.Create().Dispose(), cleanup: null, expectedPath: fileOne.FullName); - ExpectEvent(watcher, WatcherChangeTypes.Created, () => fileTwo.Create().Dispose(), cleanup: null, expectedPath: fileTwo.FullName); - ExpectNoEvent(watcher, WatcherChangeTypes.Created, () => fileThree.Create().Dispose(), cleanup: null, expectedPath: fileThree.FullName); + ExpectEvent(watcher, WatcherChangeTypes.Created, () => fileOne.Create().Dispose(), cleanup: () => fileOne.Delete(), expectedPath: fileOne.FullName); + ExpectEvent(watcher, WatcherChangeTypes.Created, () => fileTwo.Create().Dispose(), cleanup: () => fileTwo.Delete(), expectedPath: fileTwo.FullName); + ExpectNoEvent(watcher, WatcherChangeTypes.Created, () => fileThree.Create().Dispose(), cleanup: () => fileThree.Delete(), expectedPath: fileThree.FullName); cts.Cancel(); waitForThread(); @@ -1103,7 +1093,6 @@ public DangerousFileSystemWatcherTests(ITestOutputHelper output) [PlatformSpecific(TestPlatforms.Linux)] // Reads MaxUsersWatches from Linux OS files [OuterLoop("This test will use all available watchers and can cause failures in other concurrent tests or system processes.")] [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/103584", TestPlatforms.Windows)] public void FileSystemWatcher_CreateManyConcurrentWatches() { int maxUserWatches = int.Parse(File.ReadAllText("/proc/sys/fs/inotify/max_user_watches")); diff --git a/src/libraries/System.IO.FileSystem.Watcher/tests/Utility/FileSystemWatcherTest.cs b/src/libraries/System.IO.FileSystem.Watcher/tests/Utility/FileSystemWatcherTest.cs index c4dca309f24231..dffe75be379228 100644 --- a/src/libraries/System.IO.FileSystem.Watcher/tests/Utility/FileSystemWatcherTest.cs +++ b/src/libraries/System.IO.FileSystem.Watcher/tests/Utility/FileSystemWatcherTest.cs @@ -21,15 +21,25 @@ public abstract partial class FileSystemWatcherTest : FileCleanupTestBase // going to fail the test. If we don't expect an event to occur, then we need // to keep the timeout short, as in a successful run we'll end up waiting for // the entire timeout specified. - public const int WaitForExpectedEventTimeout = 1000; // ms to wait for an event to happen + public const int WaitForExpectedEventTimeout = 5000; // ms to wait for an event to happen public const int LongWaitTimeout = 50000; // ms to wait for an event that takes a longer time than the average operation - public const int SubsequentExpectedWait = 10; // ms to wait for checks that occur after the first. - public const int WaitForExpectedEventTimeout_NoRetry = 3000;// ms to wait for an event that isn't surrounded by a retry. - public const int WaitForUnexpectedEventTimeout = 150; // ms to wait for a non-expected event. + public const int SubsequentExpectedWait = 2000; // ms to wait for checks that occur after the first. + public const int WaitForExpectedEventTimeout_NoRetry = 15000;// ms to wait for an event that isn't surrounded by a retry. + public const int WaitForUnexpectedEventTimeout = 500; // ms to wait for a non-expected event. public const int DefaultAttemptsForExpectedEvent = 3; // Number of times an expected event should be retried if failing. public const int DefaultAttemptsForUnExpectedEvent = 2; // Number of times an unexpected event should be retried if failing. public const int RetryDelayMilliseconds = 500; // ms to wait when retrying after failure + // Waits for the specified duration unless the test runner signals cancellation, + // in which case it throws OperationCanceledException to fail the test immediately. + private static void WaitUnlessCancelled(int milliseconds) + { + // Replace with TestContext.Current.CancellationToken when migrated to xunit v3 (#125019). + CancellationToken token = CancellationToken.None; + token.WaitHandle.WaitOne(milliseconds); + token.ThrowIfCancellationRequested(); + } + /// /// Watches the Changed WatcherChangeType and unblocks the returned AutoResetEvent when a /// Changed event is thrown by the watcher. @@ -192,13 +202,22 @@ public static void ExpectEvent(FileSystemWatcher watcher, WatcherChangeTypes exp // Most intermittent failures in FSW are caused by either a shortage of resources (e.g. inotify instances) // or by insufficient time to execute (e.g. CI gets bogged down). Immediately re-running a failed test // won't resolve the first issue, so we wait a little while hoping that things clear up for the next run. - Thread.Sleep(RetryDelayMilliseconds); + WaitUnlessCancelled(RetryDelayMilliseconds); } - result = ExecuteAndVerifyEvents(newWatcher, expectedEvents, action, attemptsCompleted == attempts, expectedPaths, timeout); + // Use progressively longer timeouts on retries. The first attempt uses the base timeout + // for fast failure in normal conditions. Subsequent attempts increase the timeout linearly + // with the attempt count to tolerate transient delays (thread pool starvation, slow CI machines, etc.). + int effectiveTimeout = timeout * attemptsCompleted; - if (cleanup != null) - cleanup(); + try + { + result = ExecuteAndVerifyEvents(newWatcher, expectedEvents, action, attemptsCompleted == attempts, expectedPaths, effectiveTimeout); + } + finally + { + cleanup?.Invoke(); + } } } @@ -259,7 +278,7 @@ public static void Execute(Action test, int maxAttempts = 5, Func back Debug.WriteLine($"RetryHelper: retrying {testName} {i}th time of {maxAttempts}: got {lastException.Message}"); } - Thread.Sleep((backoffFunc ?? s_defaultBackoffFunc)(i)); + WaitUnlessCancelled((backoffFunc ?? s_defaultBackoffFunc)(i)); } } @@ -272,13 +291,17 @@ public static void Execute(Action test, int maxAttempts = 5, Func back /// The Action that will trigger events. /// Optional. Undoes the action and cleans up the watcher so the test may be run again if necessary. /// Optional. Adds path verification to all expected events. - public static void ExpectNoEvent(FileSystemWatcher watcher, WatcherChangeTypes unExpectedEvents, Action action, Action cleanup = null, string expectedPath = null, int timeout = WaitForExpectedEventTimeout) + public static void ExpectNoEvent(FileSystemWatcher watcher, WatcherChangeTypes unExpectedEvents, Action action, Action cleanup = null, string expectedPath = null, int timeout = WaitForUnexpectedEventTimeout) { - bool result = ExecuteAndVerifyEvents(watcher, unExpectedEvents, action, false, expectedPath == null ? null : new string[] { expectedPath }, timeout); - Assert.False(result, "Expected Event occurred"); - - if (cleanup != null) - cleanup(); + try + { + bool result = ExecuteAndVerifyEvents(watcher, unExpectedEvents, action, false, expectedPath == null ? null : new string[] { expectedPath }, timeout); + Assert.False(result, "Expected Event occurred"); + } + finally + { + cleanup?.Invoke(); + } } /// @@ -404,7 +427,7 @@ public static bool TryErrorEvent(FileSystemWatcher watcher, Action action, Actio // Most intermittent failures in FSW are caused by either a shortage of resources (e.g. inotify instances) // or by insufficient time to execute (e.g. CI gets bogged down). Immediately re-running a failed test // won't resolve the first issue, so we wait a little while hoping that things clear up for the next run. - Thread.Sleep(500); + WaitUnlessCancelled(500); } AutoResetEvent errorOccurred = new AutoResetEvent(false); @@ -431,7 +454,7 @@ public static bool TryErrorEvent(FileSystemWatcher watcher, Action action, Actio } action(); - result = errorOccurred.WaitOne(WaitForExpectedEventTimeout); + result = errorOccurred.WaitOne(WaitForExpectedEventTimeout * attemptsCompleted); watcher.EnableRaisingEvents = false; cleanup(); } @@ -532,7 +555,7 @@ internal static List ExpectEvents(FileSystemWatcher watcher, int exp try { action(); - eventsOccurred.WaitOne(new TimeSpan(0, 0, 5)); + eventsOccurred.WaitOne(WaitForExpectedEventTimeout_NoRetry); } finally {