public void RealFile_RenameFromTrackedFileName_IsTracked() { // Arrange var testLogger = new TestLogger(logToConsole: true, logThreadId: true); var testDir = CreateTestSpecificDirectory(); var filePathToMonitor = Path.Combine(testDir, "settingsFile.txt"); File.WriteAllText(filePathToMonitor, "contents"); using (var singleFileMonitor = new SingleFileMonitor(filePathToMonitor, testLogger)) { var testWrapper = new WaitableFileMonitor(singleFileMonitor); testWrapper.EventCount.Should().Be(0); // Act: rename the file from the tracked name var renamedFile = Path.ChangeExtension(filePathToMonitor, "moved"); File.Move(filePathToMonitor, renamedFile); testWrapper.WaitForEventAndThrowIfMissing(); testWrapper.EventCount.Should().Be(1); } }
public void CriticalExceptions_AreNotSuppressed() { // Arrange var directoryMock = new Mock<IDirectory>(); directoryMock.Setup(x => x.Exists(It.IsAny<string>())).Returns(true); var watcherFactoryMock = CreateFactoryAndWatcherMocks(out var watcherMock); Action act = () => { watcherMock.Raise(x => x.Changed += null, new FileSystemEventArgs(WatcherChangeTypes.Changed, "", "")); }; var testLogger = new TestLogger(); using (var fileMonitor = new SingleFileMonitor(watcherFactoryMock.Object, directoryMock.Object, "c:\\dummy\\file.txt", testLogger)) { fileMonitor.FileChanged += (s, args) => throw new StackOverflowException("YYY critical exception"); // Act and assert act.Should().ThrowExactly<StackOverflowException>().And.Message.Should().Be("YYY critical exception"); } }
public void NonCriticalExceptions_AreSuppressed() { // Arrange var directoryMock = new Mock<IDirectory>(); directoryMock.Setup(x => x.Exists(It.IsAny<string>())).Returns(true); var watcherFactoryMock = CreateFactoryAndWatcherMocks(out var watcherMock); var testLogger = new TestLogger(); using (var fileMonitor = new SingleFileMonitor(watcherFactoryMock.Object, directoryMock.Object, "c:\\dummy\\file.txt", testLogger)) { fileMonitor.FileChanged += (s, args) => throw new InvalidOperationException("XXX non-critical exception"); // Act watcherMock .Raise(x => x.Changed += null, new FileSystemEventArgs(WatcherChangeTypes.Changed, "", "")); // Assert testLogger.AssertPartialOutputStringExists("XXX non-critical exception"); fileMonitor.MonitoredFilePath.Should().Be("c:\\dummy\\file.txt"); } }
public void OnlyRaisesEventsIfHasListeners() { // Arrange var testDir = CreateTestSpecificDirectory(); var filePathToMonitor = Path.Combine(testDir, "settingsFile.txt"); EventHandler dummyHandler = (sender, args) => { }; using (var singleFileMonitor = new SingleFileMonitor(filePathToMonitor, new TestLogger())) { singleFileMonitor.MonitoredFilePath.Should().Be(filePathToMonitor); // 1. Nothing registered -> underlying wrapper should not be raising events singleFileMonitor.FileWatcherIsRaisingEvents.Should().BeFalse(); // 2. Register a listener -> start monitoring singleFileMonitor.FileChanged += dummyHandler; singleFileMonitor.FileWatcherIsRaisingEvents.Should().BeTrue(); // 3. Unregister the listener -> stop monitoring singleFileMonitor.FileChanged -= dummyHandler; singleFileMonitor.FileWatcherIsRaisingEvents.Should().BeFalse(); } }
public WaitableFileMonitor(SingleFileMonitor singleFileMonitor) { this.singleFileMonitor = singleFileMonitor; this.singleFileMonitor.FileChanged += OnFileChanged; }
public void RealFile_MultipleOperations_NoDuplicates() { // Repeated file operations will raise lots of events. // We don't want duplicates. // Arrange var testLogger = new TestLogger(logToConsole: true, logThreadId: true); var testDir = CreateTestSpecificDirectory(); var filePathToMonitor = Path.Combine(testDir, "settingsFile.txt"); int totalEventCount = 0; for (int i = 0; i < 100; i++) { TestContext.WriteLine($"Iteration: {i}"); // Cleanup if (File.Exists(filePathToMonitor)) { File.Delete(filePathToMonitor); } testBody(); } // We might lose some events if they happen too close together, but we should never // have more events than there are logical file operations. // There are 5 operations per iteration -> expecting close to 500. TestContext.WriteLine($"Number of recorded events: {totalEventCount}"); totalEventCount.Should().BeInRange(340, 500); void testBody() { const int pauseBetweenOpsInMs = 125; using (var singleFileMonitor = new SingleFileMonitor(filePathToMonitor, testLogger)) { var testWrapper = new WaitableFileMonitor(singleFileMonitor); testWrapper.EventCount.Should().Be(0); // 1. Create the file File.WriteAllText(filePathToMonitor, "initial text"); testWrapper.PauseForEvent(pauseBetweenOpsInMs); // 2. Amend the file File.AppendAllText(filePathToMonitor, " more text"); testWrapper.PauseForEvent(pauseBetweenOpsInMs); // 3. Rename from the tracked name var renamedFile = Path.ChangeExtension(filePathToMonitor, "moved"); File.Move(filePathToMonitor, renamedFile); testWrapper.PauseForEvent(pauseBetweenOpsInMs); // 4. Rename back to the tracked name File.Move(renamedFile, filePathToMonitor); testWrapper.PauseForEvent(pauseBetweenOpsInMs); // 5. Delete File.Delete(filePathToMonitor); testWrapper.PauseForEvent(pauseBetweenOpsInMs); totalEventCount += testWrapper.EventCount; } }; }