public async Task Token_Callbacks_Are_Async_And_TokenNotAffected_By_Exceptions() { var fileName = Guid.NewGuid().ToString(); var fileLocation = Path.Combine(Path.GetTempPath(), fileName); File.WriteAllText(fileLocation, "Content"); var provider = new PhysicalFileProvider(Path.GetTempPath()); var changeToken = provider.Watch(fileName); changeToken.RegisterChangeCallback(async _ => { await Task.Delay(10 * 1000); throw new Exception("Callback throwing exception"); }, null); File.AppendAllText(fileLocation, "UpdatedContent"); // Wait for callback to be fired. await Task.Delay(WaitTimeForTokenToFire); Assert.True(changeToken.HasChanged); // Verify file system watcher is stable. int callbackCount = 0; var changeTokenAfterCallbackException = provider.Watch(fileName); changeTokenAfterCallbackException.RegisterChangeCallback(_ => { callbackCount++; }, null); File.AppendAllText(fileLocation, "UpdatedContent"); // Wait for callback to be fired. await Task.Delay(WaitTimeForTokenToFire); Assert.True(changeToken.HasChanged); Assert.Equal(1, callbackCount); File.Delete(fileLocation); }
public async Task Trigger_Fired_On_Directory_Name_Change() { var provider = new PhysicalFileProvider(Path.GetTempPath()); var oldDirectoryName = Guid.NewGuid().ToString(); var newDirectoryName = Guid.NewGuid().ToString(); var oldDirectoryFullPath = Path.Combine(Path.GetTempPath(), oldDirectoryName); var newDirectoryFullPath = Path.Combine(Path.GetTempPath(), newDirectoryName); Directory.CreateDirectory(oldDirectoryFullPath); var oldDirectoryTrigger = provider.Watch("**/" + oldDirectoryName); var newDirectoryTrigger = provider.Watch("**/" + newDirectoryName); var oldTriggers = new List<IExpirationTrigger>(); var newTriggers = new List<IExpirationTrigger>(); oldTriggers.Add(provider.Watch(Path.Combine("**", oldDirectoryName, "*.txt"))); newTriggers.Add(provider.Watch(Path.Combine("**", newDirectoryName, "*.txt"))); for (int i = 0; i < 5; i++) { var fileName = string.Format("test{0}.txt", i); File.WriteAllText(Path.Combine(oldDirectoryFullPath, fileName), "test content"); oldTriggers.Add(provider.Watch(Path.Combine("**", oldDirectoryName, fileName))); newTriggers.Add(provider.Watch(Path.Combine("**", newDirectoryName, fileName))); } await Task.Delay(2 * 100); // Give it a while before trying rename. Directory.Move(oldDirectoryFullPath, newDirectoryFullPath); // Wait for triggers to fire. await Task.Delay(WAIT_TIME_FOR_TRIGGER_TO_FIRE); oldDirectoryTrigger.IsExpired.ShouldBe(true); newDirectoryTrigger.IsExpired.ShouldBe(true); oldTriggers.All(t => t.IsExpired).ShouldBe(true); newTriggers.All(t => t.IsExpired).ShouldBe(true); newDirectoryTrigger = provider.Watch(newDirectoryName); newTriggers = new List<IExpirationTrigger>(); newTriggers.Add(provider.Watch(Path.Combine("**", newDirectoryName, "*.txt"))); for (int i = 0; i < 5; i++) { var fileName = string.Format("test{0}.txt", i); newTriggers.Add(provider.Watch(Path.Combine("**", newDirectoryName, fileName))); } Directory.Delete(newDirectoryFullPath, true); // Wait for triggers to fire. await Task.Delay(WAIT_TIME_FOR_TRIGGER_TO_FIRE); newDirectoryTrigger.IsExpired.ShouldBe(true); newTriggers.All(t => t.IsExpired).ShouldBe(true); }
public async Task Triggers_With_Regular_Expression_Pointing_To_SubFolder() { var subFolderName = Guid.NewGuid().ToString(); var pattern1 = "**/*"; var pattern2 = string.Format("{0}/**/*.cshtml", subFolderName); var root = Path.GetTempPath(); var fileName = Guid.NewGuid().ToString(); var subFolder = Path.Combine(root, subFolderName); Directory.CreateDirectory(subFolder); int pattern1TriggerCount = 0, pattern2TriggerCount = 0; var provider = new PhysicalFileProvider(root); var trigger1 = provider.Watch(pattern1); trigger1.RegisterExpirationCallback(_ => { pattern1TriggerCount++; }, null); var trigger2 = provider.Watch(pattern2); trigger2.RegisterExpirationCallback(_ => { pattern2TriggerCount++; }, null); File.WriteAllText(Path.Combine(root, fileName + ".cshtml"), "Content"); await Task.Delay(WAIT_TIME_FOR_TRIGGER_TO_FIRE); pattern1TriggerCount.ShouldBe(1); pattern2TriggerCount.ShouldBe(0); trigger1 = provider.Watch(pattern1); trigger1.RegisterExpirationCallback(_ => { pattern1TriggerCount++; }, null); // Register this trigger again. var trigger3 = provider.Watch(pattern2); trigger3.RegisterExpirationCallback(_ => { pattern2TriggerCount++; }, null); trigger3.ShouldBe(trigger2); File.WriteAllText(Path.Combine(subFolder, fileName + ".cshtml"), "Content"); await Task.Delay(WAIT_TIME_FOR_TRIGGER_TO_FIRE); pattern1TriggerCount.ShouldBe(2); pattern2TriggerCount.ShouldBe(2); Directory.Delete(subFolder, true); File.Delete(Path.Combine(root, fileName + ".cshtml")); }
public async Task Triggers_With_Path_Not_Ending_With_Slash() { var provider = new PhysicalFileProvider(Path.GetTempPath()); string directoryName = Guid.NewGuid().ToString(); string fileName = Guid.NewGuid().ToString(); int triggerCount = 0; // Matches file/directory with this name. var fileTrigger = provider.Watch("/" + directoryName); fileTrigger.RegisterExpirationCallback(_ => { triggerCount++; }, null); Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), directoryName)); await Task.Delay(WAIT_TIME_FOR_TRIGGER_TO_FIRE); triggerCount.ShouldBe(1); // Matches file/directory with this name. fileTrigger = provider.Watch("/" + fileName); fileTrigger.RegisterExpirationCallback(_ => { triggerCount++; }, null); File.WriteAllText(Path.Combine(Path.GetTempPath(), fileName), "Content"); await Task.Delay(WAIT_TIME_FOR_TRIGGER_TO_FIRE); triggerCount.ShouldBe(2); }
public async Task Trigger_Fired_For_File_Or_Directory_Create_And_Delete() { var root = Path.GetTempPath(); var provider = new PhysicalFileProvider(root); string fileName = Guid.NewGuid().ToString(); string directoryName = Guid.NewGuid().ToString(); int triggerCount = 0; var fileTrigger = provider.Watch(fileName); fileTrigger.RegisterExpirationCallback(_ => { triggerCount++; }, null); var directoryTrigger = provider.Watch(directoryName); directoryTrigger.RegisterExpirationCallback(_ => { triggerCount++; }, null); fileTrigger.ShouldNotBe(directoryTrigger); File.WriteAllText(Path.Combine(root, fileName), "Content"); Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), directoryName)); // Wait for triggers to fire. await Task.Delay(WAIT_TIME_FOR_TRIGGER_TO_FIRE); triggerCount.ShouldBe(2); fileTrigger.IsExpired.ShouldBe(true); directoryTrigger.IsExpired.ShouldBe(true); fileTrigger = provider.Watch(fileName); fileTrigger.RegisterExpirationCallback(_ => { triggerCount++; }, null); directoryTrigger = provider.Watch(directoryName); directoryTrigger.RegisterExpirationCallback(_ => { triggerCount++; }, null); File.Delete(Path.Combine(root, fileName)); Directory.Delete(Path.Combine(Path.GetTempPath(), directoryName)); // Wait for triggers to fire. await Task.Delay(WAIT_TIME_FOR_TRIGGER_TO_FIRE); triggerCount.ShouldBe(4); }
public async Task ModifyContent_And_Delete_File_Succeeds_And_Callsback_Registered_Triggers() { var fileName = Guid.NewGuid().ToString(); var fileLocation = Path.Combine(Path.GetTempPath(), fileName); File.WriteAllText(fileLocation, "OldContent"); var provider = new PhysicalFileProvider(Path.GetTempPath()); var fileInfo = provider.GetFileInfo(fileName); fileInfo.Length.ShouldBe(new FileInfo(fileInfo.PhysicalPath).Length); fileInfo.Exists.ShouldBe(true); IExpirationTrigger trigger3 = null, trigger4 = null; var trigger1 = provider.Watch(fileName); var trigger2 = provider.Watch(fileName); // Valid trigger1 created. trigger1.ShouldNotBe(null); trigger1.IsExpired.ShouldBe(false); trigger1.ActiveExpirationCallbacks.ShouldBe(true); // Valid trigger2 created. trigger2.ShouldNotBe(null); trigger2.IsExpired.ShouldBe(false); trigger2.ActiveExpirationCallbacks.ShouldBe(true); // Trigger is the same for a specific file. trigger1.ShouldBe(trigger2); trigger1.RegisterExpirationCallback(state => { var infoFromState = state as IFileInfo; trigger3 = provider.Watch(infoFromState.Name); trigger3.ShouldNotBe(null); trigger3.RegisterExpirationCallback(_ => { }, null); trigger3.IsExpired.ShouldBe(false); }, state: fileInfo); trigger2.RegisterExpirationCallback(state => { var infoFromState = state as IFileInfo; trigger4 = provider.Watch(infoFromState.Name); trigger4.ShouldNotBe(null); trigger4.RegisterExpirationCallback(_ => { }, null); trigger4.IsExpired.ShouldBe(false); }, state: fileInfo); // Write new content. File.WriteAllText(fileLocation, "OldContent + NewContent"); fileInfo.Exists.ShouldBe(true); // Wait for callbacks to be fired. await Task.Delay(WAIT_TIME_FOR_TRIGGER_TO_FIRE); trigger1.IsExpired.ShouldBe(true); trigger2.IsExpired.ShouldBe(true); // Trigger is the same for a specific file. trigger3.ShouldBe(trigger4); // A new trigger is created. trigger3.ShouldNotBe(trigger1); // Delete the file and verify file info is updated. File.Delete(fileLocation); fileInfo = provider.GetFileInfo(fileName); fileInfo.Exists.ShouldBe(false); new FileInfo(fileLocation).Exists.ShouldBe(false); // Wait for callbacks to be fired. await Task.Delay(WAIT_TIME_FOR_TRIGGER_TO_FIRE); trigger3.IsExpired.ShouldBe(true); trigger4.IsExpired.ShouldBe(true); }
public async Task Trigger_With_MultipleFiles() { var fileName1 = Guid.NewGuid().ToString(); var fileName2 = Guid.NewGuid().ToString(); var fileLocation1 = Path.Combine(Path.GetTempPath(), fileName1); var fileLocation2 = Path.Combine(Path.GetTempPath(), fileName2); File.WriteAllText(fileLocation1, "Content1"); File.WriteAllText(fileLocation2, "Content2"); var provider = new PhysicalFileProvider(Path.GetTempPath()); int invocationCount1 = 0, invocationCount2 = 0; var trigger1 = provider.Watch(fileName1); trigger1.RegisterExpirationCallback(_ => { invocationCount1++; }, null); var trigger2 = provider.Watch(fileName2); trigger2.RegisterExpirationCallback(_ => { invocationCount2++; }, null); trigger1.ShouldNotBe(null); trigger1.IsExpired.ShouldNotBe(true); trigger1.ActiveExpirationCallbacks.ShouldBe(true); trigger2.ShouldNotBe(null); trigger2.IsExpired.ShouldNotBe(true); trigger2.ActiveExpirationCallbacks.ShouldBe(true); trigger1.ShouldNotBe(trigger2); File.AppendAllText(fileLocation1, "Update1"); File.AppendAllText(fileLocation2, "Update2"); // Wait for callbacks to be fired. await Task.Delay(WAIT_TIME_FOR_TRIGGER_TO_FIRE); invocationCount1.ShouldBe(1); invocationCount2.ShouldBe(1); trigger1.IsExpired.ShouldBe(true); trigger2.IsExpired.ShouldBe(true); File.Delete(fileLocation1); File.Delete(fileLocation2); // Callbacks not invoked on expired triggers. invocationCount1.ShouldBe(1); invocationCount2.ShouldBe(1); }
public async Task FileTrigger_NotTriggered_After_Expiry() { var fileName = Guid.NewGuid().ToString(); var fileLocation = Path.Combine(Path.GetTempPath(), fileName); File.WriteAllText(fileLocation, "Content"); var provider = new PhysicalFileProvider(Path.GetTempPath()); var expirationTrigger = provider.Watch(fileName); int invocationCount = 0; expirationTrigger.RegisterExpirationCallback(_ => { invocationCount++; }, null); // Callback expected for this change. File.AppendAllText(fileLocation, "UpdatedContent1"); // Callback not expected for this change. File.AppendAllText(fileLocation, "UpdatedContent2"); // Wait for callbacks to be fired. await Task.Delay(WAIT_TIME_FOR_TRIGGER_TO_FIRE); invocationCount.ShouldBe(1); File.Delete(fileLocation); }
public async Task Tokens_With_Path_Ending_With_Slash() { var provider = new PhysicalFileProvider(Path.GetTempPath()); string fileName = Guid.NewGuid().ToString(); string folderName = Guid.NewGuid().ToString(); int tokenCount = 0; var filetoken = provider.Watch("/" + folderName + "/"); filetoken.RegisterChangeCallback(_ => { tokenCount++; }, null); var folderPath = Path.Combine(Path.GetTempPath(), folderName); Directory.CreateDirectory(folderPath); File.WriteAllText(Path.Combine(folderPath, fileName), "Content"); await Task.Delay(WaitTimeForTokenToFire); Assert.Equal(1, tokenCount); filetoken = provider.Watch("/" + folderName + "/"); filetoken.RegisterChangeCallback(_ => { tokenCount++; }, null); File.AppendAllText(Path.Combine(folderPath, fileName), "UpdatedContent"); await Task.Delay(WaitTimeForTokenToFire); Assert.Equal(2, tokenCount); filetoken = provider.Watch("/" + folderName + "/"); filetoken.RegisterChangeCallback(_ => { tokenCount++; }, null); File.Delete(Path.Combine(folderPath, fileName)); await Task.Delay(WaitTimeForTokenToFire); Assert.Equal(3, tokenCount); }
public async Task Token_Fired_For_File_Or_Directory_Create_And_Delete() { var root = Path.GetTempPath(); var provider = new PhysicalFileProvider(root); string fileName = Guid.NewGuid().ToString(); string directoryName = Guid.NewGuid().ToString(); int tokenCount = 0; var filetoken = provider.Watch(fileName); filetoken.RegisterChangeCallback(_ => { tokenCount++; }, null); var directorytoken = provider.Watch(directoryName); directorytoken.RegisterChangeCallback(_ => { tokenCount++; }, null); Assert.NotEqual(directorytoken, filetoken); File.WriteAllText(Path.Combine(root, fileName), "Content"); Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), directoryName)); // Wait for tokens to fire. await Task.Delay(WaitTimeForTokenToFire); Assert.Equal(2, tokenCount); Assert.True(filetoken.HasChanged); Assert.True(directorytoken.HasChanged); filetoken = provider.Watch(fileName); filetoken.RegisterChangeCallback(_ => { tokenCount++; }, null); directorytoken = provider.Watch(directoryName); directorytoken.RegisterChangeCallback(_ => { tokenCount++; }, null); File.Delete(Path.Combine(root, fileName)); Directory.Delete(Path.Combine(Path.GetTempPath(), directoryName)); // Wait for tokens to fire. await Task.Delay(WaitTimeForTokenToFire); Assert.Equal(4, tokenCount); }
public void Token_For_AbsolutePath_Filters() { var provider = new PhysicalFileProvider(Path.GetTempPath()); var path = Path.Combine(Path.GetTempPath(), "filename"); var token = provider.Watch(path); Assert.Same(NoopChangeToken.Singleton, token); }
public void Token_For_Whitespace_Filters() { var provider = new PhysicalFileProvider(Path.GetTempPath()); var token = provider.Watch(" "); Assert.False(token.HasChanged); Assert.True(token.ActiveChangeCallbacks); }
public void Token_For_Empty_Filter() { var provider = new PhysicalFileProvider(Path.GetTempPath()); var token = provider.Watch(string.Empty); Assert.False(token.HasChanged); Assert.True(token.ActiveChangeCallbacks); }
public void Token_For_Null_Filter() { var provider = new PhysicalFileProvider(Path.GetTempPath()); var token = provider.Watch(null); Assert.Same(NoopChangeToken.Singleton, token); }
public async Task ModifyContent_And_Delete_File_Succeeds_And_Callsback_RegisteredTokens() { var fileName = Guid.NewGuid().ToString(); var fileLocation = Path.Combine(Path.GetTempPath(), fileName); File.WriteAllText(fileLocation, "OldContent"); var provider = new PhysicalFileProvider(Path.GetTempPath()); var fileInfo = provider.GetFileInfo(fileName); Assert.Equal(new FileInfo(fileInfo.PhysicalPath).Length, fileInfo.Length); Assert.True(fileInfo.Exists); var token1 = provider.Watch(fileName); var token2 = provider.Watch(fileName); // Valid token1 created. Assert.NotNull(token1); Assert.False(token1.HasChanged); Assert.True(token1.ActiveChangeCallbacks); // Valid token2 created. Assert.NotNull(token2); Assert.False(token2.HasChanged); Assert.True(token2.ActiveChangeCallbacks); // token is the same for a specific file. Assert.Equal(token2, token1); IChangeToken token3 = null; IChangeToken token4 = null; token1.RegisterChangeCallback(state => { var infoFromState = state as IFileInfo; token3 = provider.Watch(infoFromState.Name); Assert.NotNull(token3); token3.RegisterChangeCallback(_ => { }, null); Assert.False(token3.HasChanged); }, state: fileInfo); token2.RegisterChangeCallback(state => { var infoFromState = state as IFileInfo; token4 = provider.Watch(infoFromState.Name); Assert.NotNull(token4); token4.RegisterChangeCallback(_ => { }, null); Assert.False(token4.HasChanged); }, state: fileInfo); // Write new content. File.WriteAllText(fileLocation, "OldContent + NewContent"); Assert.True(fileInfo.Exists); // Wait for callbacks to be fired. await Task.Delay(WaitTimeForTokenToFire); Assert.True(token1.HasChanged); Assert.True(token2.HasChanged); // token is the same for a specific file. Assert.Same(token4, token3); // A new token is created. Assert.NotEqual(token1, token3); // Delete the file and verify file info is updated. File.Delete(fileLocation); fileInfo = provider.GetFileInfo(fileName); Assert.False(fileInfo.Exists); Assert.False(new FileInfo(fileLocation).Exists); // Wait for callbacks to be fired. await Task.Delay(WaitTimeForTokenToFire); Assert.True(token3.HasChanged); Assert.True(token4.HasChanged); }
public async Task Tokens_With_Path_Not_Ending_With_Slash() { var provider = new PhysicalFileProvider(Path.GetTempPath()); string directoryName = Guid.NewGuid().ToString(); string fileName = Guid.NewGuid().ToString(); int tokenCount = 0; // Matches file/directory with this name. var filetoken = provider.Watch("/" + directoryName); filetoken.RegisterChangeCallback(_ => { tokenCount++; }, null); Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), directoryName)); await Task.Delay(WaitTimeForTokenToFire); Assert.Equal(1, tokenCount); // Matches file/directory with this name. filetoken = provider.Watch("/" + fileName); filetoken.RegisterChangeCallback(_ => { tokenCount++; }, null); File.WriteAllText(Path.Combine(Path.GetTempPath(), fileName), "Content"); await Task.Delay(WaitTimeForTokenToFire); Assert.Equal(2, tokenCount); }
public async Task Createdtrigger_Same_For_A_File_And_Callsback_AllRegisteredTriggers_OnChange() { var fileName = Guid.NewGuid().ToString(); var fileLocation = Path.Combine(Path.GetTempPath(), fileName); File.WriteAllText(fileLocation, "Content"); var provider = new PhysicalFileProvider(Path.GetTempPath()); var count = 10; var tasks = new List<Task>(count); var triggers = new IExpirationTrigger[count]; var callbackResults = new bool[count]; for (int i = 0; i < count; i++) { tasks.Add(new Task(index => { var expirationTrigger = provider.Watch(fileName); triggers[(int)index] = expirationTrigger; expirationTrigger.ShouldNotBe(null); expirationTrigger.IsExpired.ShouldNotBe(true); expirationTrigger.RegisterExpirationCallback(_ => { callbackResults[(int)index] = true; }, index); }, state: i)); } // Simulating multiple concurrent requests to the same file. Parallel.ForEach(tasks, task => task.Start()); await Task.WhenAll(tasks); File.AppendAllText(fileLocation, "UpdatedContent"); // Some warm up time for the callbacks to be fired. await Task.Delay(WAIT_TIME_FOR_TRIGGER_TO_FIRE); for (int index = 1; index < count; index++) { triggers[index].ShouldBe(triggers[index - 1]); } callbackResults.All(c => c == true).ShouldBe(true); File.Delete(fileLocation); }
public async Task Tokens_With_Regular_Expression_Filters() { var pattern1 = "**/*"; var pattern2 = "*.cshtml"; var root = Path.GetTempPath(); var fileName = Guid.NewGuid().ToString(); var subFolder = Path.Combine(root, Guid.NewGuid().ToString()); Directory.CreateDirectory(subFolder); int pattern1tokenCount = 0, pattern2tokenCount = 0; Action<object> callback1 = _ => { pattern1tokenCount++; }; Action<object> callback2 = _ => { pattern2tokenCount++; }; var provider = new PhysicalFileProvider(root); var token1 = provider.Watch(pattern1); token1.RegisterChangeCallback(callback1, null); var token2 = provider.Watch(pattern2); token2.RegisterChangeCallback(callback2, null); File.WriteAllText(Path.Combine(root, fileName + ".cshtml"), "Content"); await Task.Delay(WaitTimeForTokenToFire); Assert.Equal(1, pattern1tokenCount); Assert.Equal(1, pattern2tokenCount); token1 = provider.Watch(pattern1); token1.RegisterChangeCallback(callback1, null); token2 = provider.Watch(pattern2); token2.RegisterChangeCallback(callback2, null); File.WriteAllText(Path.Combine(subFolder, fileName + ".txt"), "Content"); await Task.Delay(WaitTimeForTokenToFire); Assert.Equal(2, pattern1tokenCount); Assert.Equal(1, pattern2tokenCount); Directory.Delete(subFolder, true); File.Delete(Path.Combine(root, fileName + ".cshtml")); }
public void Trigger_Is_FileName_Case_Insensitive() { var fileName = Guid.NewGuid().ToString() + 'A'; var fileLocation = Path.Combine(Path.GetTempPath(), fileName); File.WriteAllText(fileLocation, "Content"); var provider = new PhysicalFileProvider(Path.GetTempPath()); var expirationTrigger = provider.Watch(fileName); var lowerCaseExpirationTrigger = provider.Watch(fileName.ToLowerInvariant()); expirationTrigger.ShouldBe(lowerCaseExpirationTrigger); File.Delete(fileLocation); }
public async Task Tokens_With_Regular_Expression_Pointing_To_SubFolder() { var subFolderName = Guid.NewGuid().ToString(); var pattern1 = "**/*"; var pattern2 = string.Format("{0}/**/*.cshtml", subFolderName); var root = Path.GetTempPath(); var fileName = Guid.NewGuid().ToString(); var subFolder = Path.Combine(root, subFolderName); Directory.CreateDirectory(subFolder); int pattern1tokenCount = 0, pattern2tokenCount = 0; var provider = new PhysicalFileProvider(root); var token1 = provider.Watch(pattern1); token1.RegisterChangeCallback(_ => { pattern1tokenCount++; }, null); var token2 = provider.Watch(pattern2); token2.RegisterChangeCallback(_ => { pattern2tokenCount++; }, null); File.WriteAllText(Path.Combine(root, fileName + ".cshtml"), "Content"); await Task.Delay(WaitTimeForTokenToFire); Assert.Equal(1, pattern1tokenCount); Assert.Equal(0, pattern2tokenCount); token1 = provider.Watch(pattern1); token1.RegisterChangeCallback(_ => { pattern1tokenCount++; }, null); // Register this token again. var token3 = provider.Watch(pattern2); token3.RegisterChangeCallback(_ => { pattern2tokenCount++; }, null); Assert.Equal(token2, token3); File.WriteAllText(Path.Combine(subFolder, fileName + ".cshtml"), "Content"); await Task.Delay(WaitTimeForTokenToFire); Assert.Equal(2, pattern1tokenCount); Assert.Equal(2, pattern2tokenCount); Directory.Delete(subFolder, true); File.Delete(Path.Combine(root, fileName + ".cshtml")); }
public async Task Trigger_Callbacks_Are_Async_And_TriggerNotAffected_By_Exceptions() { var fileName = Guid.NewGuid().ToString(); var fileLocation = Path.Combine(Path.GetTempPath(), fileName); File.WriteAllText(fileLocation, "Content"); var provider = new PhysicalFileProvider(Path.GetTempPath()); var expirationTrigger = provider.Watch(fileName); expirationTrigger.RegisterExpirationCallback(async _ => { await Task.Delay(10 * 1000); throw new Exception("Callback throwing exception"); }, null); File.AppendAllText(fileLocation, "UpdatedContent"); // Wait for callback to be fired. await Task.Delay(WAIT_TIME_FOR_TRIGGER_TO_FIRE); expirationTrigger.IsExpired.ShouldBe(true); // Verify file system watcher is stable. int callbackCount = 0; var expirationTriggerAfterCallbackException = provider.Watch(fileName); expirationTriggerAfterCallbackException.RegisterExpirationCallback(_ => { callbackCount++; }, null); File.AppendAllText(fileLocation, "UpdatedContent"); // Wait for callback to be fired. await Task.Delay(WAIT_TIME_FOR_TRIGGER_TO_FIRE); expirationTrigger.IsExpired.ShouldBe(true); callbackCount.ShouldBe(1); File.Delete(fileLocation); }
public void Tokens_With_Forward_And_Backward_Slash() { var provider = new PhysicalFileProvider(Path.GetTempPath()); var token1 = provider.Watch("/a/b"); var token2 = provider.Watch("a/b"); var token3 = provider.Watch(@"a\b"); Assert.Equal(token2, token1); Assert.Equal(token3, token2); Assert.True(token1.ActiveChangeCallbacks); Assert.True(token2.ActiveChangeCallbacks); Assert.True(token3.ActiveChangeCallbacks); Assert.False(token1.HasChanged); Assert.False(token2.HasChanged); Assert.False(token3.HasChanged); }
public void Trigger_For_Null_Empty_Whitespace_Filters() { var provider = new PhysicalFileProvider(Path.GetTempPath()); var trigger = provider.Watch(null); trigger.IsExpired.ShouldBe(false); trigger.ActiveExpirationCallbacks.ShouldBe(false); trigger = provider.Watch(string.Empty); trigger.IsExpired.ShouldBe(false); trigger.ActiveExpirationCallbacks.ShouldBe(true); // White space. trigger = provider.Watch(" "); trigger.IsExpired.ShouldBe(false); trigger.ActiveExpirationCallbacks.ShouldBe(true); // Absolute path. trigger = provider.Watch(Path.Combine(Path.GetTempPath() + "filename")); trigger.IsExpired.ShouldBe(false); trigger.ActiveExpirationCallbacks.ShouldBe(false); }
public async Task Token_Fired_On_Directory_Name_Change() { var provider = new PhysicalFileProvider(Path.GetTempPath()); var oldDirectoryName = Guid.NewGuid().ToString(); var newDirectoryName = Guid.NewGuid().ToString(); var oldDirectoryFullPath = Path.Combine(Path.GetTempPath(), oldDirectoryName); var newDirectoryFullPath = Path.Combine(Path.GetTempPath(), newDirectoryName); Directory.CreateDirectory(oldDirectoryFullPath); var oldDirectorytoken = provider.Watch("**/" + oldDirectoryName); var newDirectorytoken = provider.Watch("**/" + newDirectoryName); var oldtokens = new List<IChangeToken>(); var newtokens = new List<IChangeToken>(); oldtokens.Add(provider.Watch(Path.Combine("**", oldDirectoryName, "*.txt"))); newtokens.Add(provider.Watch(Path.Combine("**", newDirectoryName, "*.txt"))); for (int i = 0; i < 5; i++) { var fileName = string.Format("test{0}.txt", i); File.WriteAllText(Path.Combine(oldDirectoryFullPath, fileName), "test content"); oldtokens.Add(provider.Watch(Path.Combine("**", oldDirectoryName, fileName))); newtokens.Add(provider.Watch(Path.Combine("**", newDirectoryName, fileName))); } await Task.Delay(2 * 100); // Give it a while before trying rename. Directory.Move(oldDirectoryFullPath, newDirectoryFullPath); // Wait for tokens to fire. await Task.Delay(WaitTimeForTokenToFire); Assert.True(oldDirectorytoken.HasChanged); Assert.True(newDirectorytoken.HasChanged); oldtokens.ForEach(t => Assert.True(t.HasChanged)); newtokens.ForEach(t => Assert.True(t.HasChanged)); newDirectorytoken = provider.Watch(newDirectoryName); newtokens = new List<IChangeToken>(); newtokens.Add(provider.Watch(Path.Combine("**", newDirectoryName, "*.txt"))); for (int i = 0; i < 5; i++) { var fileName = string.Format("test{0}.txt", i); newtokens.Add(provider.Watch(Path.Combine("**", newDirectoryName, fileName))); } Directory.Delete(newDirectoryFullPath, true); // Wait for tokens to fire. await Task.Delay(WaitTimeForTokenToFire); Assert.True(newDirectorytoken.HasChanged); newtokens.ForEach(t => Assert.True(t.HasChanged)); }
public async Task Triggers_With_Path_Ending_With_Slash() { var provider = new PhysicalFileProvider(Path.GetTempPath()); string fileName = Guid.NewGuid().ToString(); string folderName = Guid.NewGuid().ToString(); int triggerCount = 0; var fileTrigger = provider.Watch("/" + folderName + "/"); fileTrigger.RegisterExpirationCallback(_ => { triggerCount++; }, null); var folderPath = Path.Combine(Path.GetTempPath(), folderName); Directory.CreateDirectory(folderPath); File.WriteAllText(Path.Combine(folderPath, fileName), "Content"); await Task.Delay(WAIT_TIME_FOR_TRIGGER_TO_FIRE); triggerCount.ShouldBe(1); fileTrigger = provider.Watch("/" + folderName + "/"); fileTrigger.RegisterExpirationCallback(_ => { triggerCount++; }, null); File.AppendAllText(Path.Combine(folderPath, fileName), "UpdatedContent"); await Task.Delay(WAIT_TIME_FOR_TRIGGER_TO_FIRE); triggerCount.ShouldBe(2); fileTrigger = provider.Watch("/" + folderName + "/"); fileTrigger.RegisterExpirationCallback(_ => { triggerCount++; }, null); File.Delete(Path.Combine(folderPath, fileName)); await Task.Delay(WAIT_TIME_FOR_TRIGGER_TO_FIRE); triggerCount.ShouldBe(3); }
public async Task Tokens_NotFired_For_FileNames_Starting_With_Period() { var root = Path.GetTempPath(); var fileNameStartingWithPeriod = Path.Combine(root, "." + Guid.NewGuid().ToString()); File.WriteAllText(fileNameStartingWithPeriod, "Content"); var provider = new PhysicalFileProvider(Path.GetTempPath()); var tokenFileNameStartingPeriod = provider.Watch(Path.GetFileName(fileNameStartingWithPeriod)); Assert.False(tokenFileNameStartingPeriod.HasChanged); File.WriteAllText(fileNameStartingWithPeriod, "Updated Contents"); // Wait for tokens to fire. await Task.Delay(WaitTimeForTokenToFire); Assert.False(tokenFileNameStartingPeriod.HasChanged); }
public async Task Triggers_With_Regular_Expression_Filters() { var pattern1 = "**/*"; var pattern2 = "*.cshtml"; var root = Path.GetTempPath(); var fileName = Guid.NewGuid().ToString(); var subFolder = Path.Combine(root, Guid.NewGuid().ToString()); Directory.CreateDirectory(subFolder); int pattern1TriggerCount = 0, pattern2TriggerCount = 0; Action<object> callback1 = _ => { pattern1TriggerCount++; }; Action<object> callback2 = _ => { pattern2TriggerCount++; }; var provider = new PhysicalFileProvider(root); var trigger1 = provider.Watch(pattern1); trigger1.RegisterExpirationCallback(callback1, null); var trigger2 = provider.Watch(pattern2); trigger2.RegisterExpirationCallback(callback2, null); File.WriteAllText(Path.Combine(root, fileName + ".cshtml"), "Content"); await Task.Delay(WAIT_TIME_FOR_TRIGGER_TO_FIRE); pattern1TriggerCount.ShouldBe(1); pattern2TriggerCount.ShouldBe(1); trigger1 = provider.Watch(pattern1); trigger1.RegisterExpirationCallback(callback1, null); trigger2 = provider.Watch(pattern2); trigger2.RegisterExpirationCallback(callback2, null); File.WriteAllText(Path.Combine(subFolder, fileName + ".txt"), "Content"); await Task.Delay(WAIT_TIME_FOR_TRIGGER_TO_FIRE); pattern1TriggerCount.ShouldBe(2); pattern2TriggerCount.ShouldBe(1); Directory.Delete(subFolder, true); File.Delete(Path.Combine(root, fileName + ".cshtml")); }
public async Task Tokens_NotFired_For_Hidden_And_System_Files() { var root = Path.GetTempPath(); var hiddenFileName = Path.Combine(root, Guid.NewGuid().ToString()); File.WriteAllText(hiddenFileName, "Content"); var systemFileName = Path.Combine(root, Guid.NewGuid().ToString()); File.WriteAllText(systemFileName, "Content"); var fileInfo = new FileInfo(hiddenFileName); File.SetAttributes(hiddenFileName, fileInfo.Attributes | FileAttributes.Hidden); fileInfo = new FileInfo(systemFileName); File.SetAttributes(systemFileName, fileInfo.Attributes | FileAttributes.System); var provider = new PhysicalFileProvider(Path.GetTempPath()); var hiddenFiletoken = provider.Watch(Path.GetFileName(hiddenFileName)); var systemFiletoken = provider.Watch(Path.GetFileName(systemFileName)); Assert.False(hiddenFiletoken.HasChanged); Assert.False(systemFiletoken.HasChanged); File.AppendAllText(hiddenFileName, "Appending text"); File.AppendAllText(systemFileName, "Appending text"); // Wait for tokens to fire. await Task.Delay(WaitTimeForTokenToFire); Assert.False(hiddenFiletoken.HasChanged); Assert.False(systemFiletoken.HasChanged); }
public void Triggers_With_Forward_And_Backward_Slash() { var provider = new PhysicalFileProvider(Path.GetTempPath()); var trigger1 = provider.Watch("/a/b"); var trigger2 = provider.Watch("a/b"); var trigger3 = provider.Watch(@"a\b"); trigger1.ShouldBe(trigger2); trigger2.ShouldBe(trigger3); trigger1.ActiveExpirationCallbacks.ShouldBe(true); trigger2.ActiveExpirationCallbacks.ShouldBe(true); trigger3.ActiveExpirationCallbacks.ShouldBe(true); trigger1.IsExpired.ShouldBe(false); trigger2.IsExpired.ShouldBe(false); trigger3.IsExpired.ShouldBe(false); }
public async Task Triggers_NotFired_For_FileNames_Starting_With_Period_And_Hidden_Files() { var root = Path.GetTempPath(); var hiddenFileName = Path.Combine(root, Guid.NewGuid().ToString()); File.WriteAllText(hiddenFileName, "Content"); var systemFileName = Path.Combine(root, Guid.NewGuid().ToString()); File.WriteAllText(systemFileName, "Content"); var fileNameStartingWithPeriod = Path.Combine(root, "." + Guid.NewGuid().ToString()); File.WriteAllText(fileNameStartingWithPeriod, "Content"); var fileInfo = new FileInfo(hiddenFileName); File.SetAttributes(hiddenFileName, fileInfo.Attributes | FileAttributes.Hidden); fileInfo = new FileInfo(systemFileName); File.SetAttributes(systemFileName, fileInfo.Attributes | FileAttributes.System); var provider = new PhysicalFileProvider(Path.GetTempPath()); var hiddenFileTrigger = provider.Watch(Path.GetFileName(hiddenFileName)); var triggerFileNameStartingPeriod = provider.Watch(Path.GetFileName(fileNameStartingWithPeriod)); var systemFileTrigger = provider.Watch(Path.GetFileName(systemFileName)); hiddenFileTrigger.IsExpired.ShouldBe(false); triggerFileNameStartingPeriod.IsExpired.ShouldBe(false); systemFileTrigger.IsExpired.ShouldBe(false); File.AppendAllText(hiddenFileName, "Appending text"); File.WriteAllText(fileNameStartingWithPeriod, "Updated Contents"); File.AppendAllText(systemFileName, "Appending text"); // Wait for triggers to fire. await Task.Delay(WAIT_TIME_FOR_TRIGGER_TO_FIRE); hiddenFileTrigger.IsExpired.ShouldBe(false); triggerFileNameStartingPeriod.IsExpired.ShouldBe(false); systemFileTrigger.IsExpired.ShouldBe(false); }
public async Task ModifyContent_And_Delete_File_Succeeds_And_Callsback_Registered_Triggers() { var fileName = Guid.NewGuid().ToString(); var fileLocation = Path.Combine(Path.GetTempPath(), fileName); File.WriteAllText(fileLocation, "OldContent"); var provider = new PhysicalFileProvider(Path.GetTempPath()); var fileInfo = provider.GetFileInfo(fileName); Assert.Equal(new FileInfo(fileInfo.PhysicalPath).Length, fileInfo.Length); Assert.True(fileInfo.Exists); IExpirationTrigger trigger3 = null, trigger4 = null; var trigger1 = provider.Watch(fileName); var trigger2 = provider.Watch(fileName); // Valid trigger1 created. Assert.NotNull(trigger1); Assert.False(trigger1.IsExpired); Assert.True(trigger1.ActiveExpirationCallbacks); // Valid trigger2 created. Assert.NotNull(trigger2); Assert.False(trigger2.IsExpired); Assert.True(trigger2.ActiveExpirationCallbacks); // Trigger is the same for a specific file. Assert.Equal(trigger2, trigger1); trigger1.RegisterExpirationCallback(state => { var infoFromState = state as IFileInfo; trigger3 = provider.Watch(infoFromState.Name); Assert.NotNull(trigger3); trigger3.RegisterExpirationCallback(_ => { }, null); Assert.False(trigger3.IsExpired); }, state: fileInfo); trigger2.RegisterExpirationCallback(state => { var infoFromState = state as IFileInfo; trigger4 = provider.Watch(infoFromState.Name); Assert.NotNull(trigger4); trigger4.RegisterExpirationCallback(_ => { }, null); Assert.False(trigger4.IsExpired); }, state: fileInfo); // Write new content. File.WriteAllText(fileLocation, "OldContent + NewContent"); Assert.True(fileInfo.Exists); // Wait for callbacks to be fired. await Task.Delay(WAIT_TIME_FOR_TRIGGER_TO_FIRE); Assert.True(trigger1.IsExpired); Assert.True(trigger2.IsExpired); // Trigger is the same for a specific file. Assert.Equal(trigger4, trigger3); // A new trigger is created. Assert.NotEqual(trigger1, trigger3); // Delete the file and verify file info is updated. File.Delete(fileLocation); fileInfo = provider.GetFileInfo(fileName); Assert.False(fileInfo.Exists); Assert.False(new FileInfo(fileLocation).Exists); // Wait for callbacks to be fired. await Task.Delay(WAIT_TIME_FOR_TRIGGER_TO_FIRE); Assert.True(trigger3.IsExpired); Assert.True(trigger4.IsExpired); }