public async Task RestartProcessThatTerminatesAfterFileChange() { var testAsset = _testAssetsManager.CopyTestAsset(AppName) .WithSource() .Path; using var app = new WatchableApp(testAsset, _output); await app.StartWatcherAsync(); var processIdentifier = await app.GetProcessIdentifier(); await app.HasExited(); // process should exit after run await app.IsWaitingForFileChange(); var fileToChange = Path.Combine(app.SourceDirectory, "Program.cs"); try { File.SetLastWriteTime(fileToChange, DateTime.Now); await app.HasRestarted(); } catch { // retry File.SetLastWriteTime(fileToChange, DateTime.Now); await app.HasRestarted(); } var processIdentifier2 = await app.GetProcessIdentifier(); Assert.NotEqual(processIdentifier, processIdentifier2); await app.HasExited(); // process should exit after run }
public async Task RunsWithRestoreIfCsprojChanges() { var testAsset = _testAssetsManager.CopyTestAsset(AppName) .WithSource() .Path; using var app = new WatchableApp(testAsset, _logger); app.DotnetWatchArgs.Add("--verbose"); await app.StartWatcherAsync(arguments : new[] { "wait" }); var source = Path.Combine(app.SourceDirectory, "KitchenSink.csproj"); const string messagePrefix = "watch : Running dotnet with the following arguments: run"; // Verify that the first run does not use --no-restore Assert.Contains(app.Process.Output, p => string.Equals(messagePrefix + " -- wait", p.Trim())); File.SetLastWriteTime(source, DateTime.Now); var message = await app.Process.GetOutputLineStartsWithAsync(messagePrefix, TimeSpan.FromMinutes(2)); // csproj changed. Do not expect a --no-restore Assert.Equal(messagePrefix + " -- wait", message.Trim()); await app.HasRestarted(); // regular file changed after csproj changes. Should use --no-restore File.SetLastWriteTime(Path.Combine(app.SourceDirectory, "Program.cs"), DateTime.Now); message = await app.Process.GetOutputLineStartsWithAsync(messagePrefix, TimeSpan.FromMinutes(2)); Assert.Equal(messagePrefix + " --no-restore -- wait", message.Trim()); }
public async Task RestartProcessOnFileChange() { var testAsset = _testAssetsManager.CopyTestAsset(AppName) .WithSource() .Path; using var app = new WatchableApp(testAsset, _output); await app.StartWatcherAsync(new[] { "--no-exit" }); var processIdentifier = await app.GetProcessIdentifier(); // Then wait for it to restart when we change a file var fileToChange = Path.Combine(app.SourceDirectory, "Program.cs"); var programCs = File.ReadAllText(fileToChange); File.WriteAllText(fileToChange, programCs); await app.HasRestarted(); Assert.DoesNotContain(app.Process.Output, l => l.StartsWith("Exited with error code")); var processIdentifier2 = await app.GetProcessIdentifier(); Assert.NotEqual(processIdentifier, processIdentifier2); }
public async Task Run_WithHotReloadEnabled_DoesNotReadConsoleIn_InNonInteractiveMode() { var testAsset = _testAssetsManager.CopyTestAsset("WatchAppWithLaunchSettings") .WithSource() .Path; using var app = new WatchableApp(testAsset, _logger) { EnvironmentVariables = { ["READ_INPUT"] = "true", }, }; app.DotnetWatchArgs.Add("--verbose"); app.DotnetWatchArgs.Add("--non-interactive"); await app.StartWatcherAsync(); var standardInput = app.Process.Process.StandardInput; var inputString = "This is a test input"; await standardInput.WriteLineAsync(inputString).WaitAsync(TimeSpan.FromSeconds(10)); await app.Process.GetOutputLineAsync($"Echo: {inputString}", TimeSpan.FromSeconds(10)); }
public async Task ChangeCompiledFile(bool usePollingWatcher) { var testAsset = _testAssetsManager.CopyTestAsset(AppName, identifier: usePollingWatcher.ToString()) .WithSource() .Path; using var app = new WatchableApp(testAsset, _logger); app.UsePollingWatcher = usePollingWatcher; await app.StartWatcherAsync().TimeoutAfter(DefaultTimeout); var types = await GetCompiledAppDefinedTypes(app).TimeoutAfter(DefaultTimeout); Assert.Equal(2, types); var fileToChange = Path.Combine(app.SourceDirectory, "include", "Foo.cs"); var programCs = File.ReadAllText(fileToChange); File.WriteAllText(fileToChange, programCs); await app.HasRestarted().TimeoutAfter(DefaultTimeout); types = await GetCompiledAppDefinedTypes(app).TimeoutAfter(DefaultTimeout); Assert.Equal(2, types); }
public async Task ListsFiles() { var testAsset = _testAssetsManager.CopyTestAsset(AppName) .WithSource() .Path; using var app = new WatchableApp(testAsset, _logger); app.Prepare(); app.Start(new[] { "--list" }); var cts = new CancellationTokenSource(); cts.CancelAfter(TimeSpan.FromSeconds(30)); var lines = await app.Process.GetAllOutputLinesAsync(cts.Token).TimeoutAfter(DefaultTimeout); var files = lines.Where(l => !l.StartsWith("watch :")); AssertEx.EqualFileList( testAsset, new[] { "Program.cs", "include/Foo.cs", "WatchGlobbingApp.csproj", }, files); }
public async Task RunsWithIterationEnvVariable() { var testAsset = _testAssetsManager.CopyTestAsset(AppName) .WithSource() .Path; using var app = new WatchableApp(testAsset, _logger); await app.StartWatcherAsync(); var source = Path.Combine(app.SourceDirectory, "Program.cs"); var contents = File.ReadAllText(source); const string messagePrefix = "DOTNET_WATCH_ITERATION = "; var message = await app.Process.GetOutputLineStartsWithAsync(messagePrefix, TimeSpan.FromMinutes(2)); var count = int.Parse(message.Substring(messagePrefix.Length), CultureInfo.InvariantCulture); Assert.Equal(1, count); await app.IsWaitingForFileChange(); File.SetLastWriteTime(source, DateTime.Now); await app.HasRestarted(TimeSpan.FromMinutes(1)); message = await app.Process.GetOutputLineStartsWithAsync(messagePrefix, TimeSpan.FromMinutes(2)); count = int.Parse(message.Substring(messagePrefix.Length), CultureInfo.InvariantCulture); Assert.Equal(2, count); }
public async Task RunsWithNoRestoreOnOrdinaryFileChanges() { var testAsset = _testAssetsManager.CopyTestAsset(AppName) .WithSource() .Path; using var app = new WatchableApp(testAsset, _logger); app.DotnetWatchArgs.Add("--verbose"); await app.StartWatcherAsync(arguments : new[] { "wait" }); var source = Path.Combine(app.SourceDirectory, "Program.cs"); const string messagePrefix = "watch : Running dotnet with the following arguments: run"; // Verify that the first run does not use --no-restore Assert.Contains(app.Process.Output, p => string.Equals(messagePrefix + " -- wait", p.Trim())); for (var i = 0; i < 3; i++) { File.SetLastWriteTime(source, DateTime.Now); var message = await app.Process.GetOutputLineStartsWithAsync(messagePrefix, TimeSpan.FromMinutes(2)); Assert.Equal(messagePrefix + " --no-restore -- wait", message.Trim()); await app.HasRestarted(); } }
public async Task Run_WithHotReloadEnabled_ReadsLaunchSettings() { var testAsset = _testAssetsManager.CopyTestAsset("WatchAppWithLaunchSettings") .WithSource() .Path; using var app = new WatchableApp(testAsset, _logger); app.DotnetWatchArgs.Add("--verbose"); await app.StartWatcherAsync(); await app.Process.GetOutputLineAsyncWithConsoleHistoryAsync("Environment: Development", TimeSpan.FromSeconds(10)); }
public async Task LaunchesBrowserOnStart() { var expected = "watch : Launching browser: https://localhost:5001/"; var testAsset = _testAssetsManager.CopyTestAsset(AppName) .WithSource() .Path; using var app = new WatchableApp(testAsset, _logger); app.DotnetWatchArgs.Add("--verbose"); await app.StartWatcherAsync(); // Verify we launched the browser. await app.Process.GetOutputLineStartsWithAsync(expected, TimeSpan.FromMinutes(2)); }
public async Task RenameCompiledFile() { var testAsset = _testAssetsManager.CopyTestAsset(AppName) .WithSource() .Path; using var app = new WatchableApp(testAsset, _logger); await app.StartWatcherAsync().TimeoutAfter(DefaultTimeout); var oldFile = Path.Combine(app.SourceDirectory, "include", "Foo.cs"); var newFile = Path.Combine(app.SourceDirectory, "include", "Foo_new.cs"); File.Move(oldFile, newFile); await app.HasRestarted().TimeoutAfter(DefaultTimeout); }
public async Task UsesBrowserSpecifiedInEnvironment() { var launchBrowserMessage = "watch : Launching browser: mycustombrowser.bat https://localhost:5001/"; var testAsset = _testAssetsManager.CopyTestAsset(AppName) .WithSource() .Path; using var app = new WatchableApp(testAsset, _logger); app.EnvironmentVariables.Add("DOTNET_WATCH_BROWSER_PATH", "mycustombrowser.bat"); app.DotnetWatchArgs.Add("--verbose"); await app.StartWatcherAsync(); // Verify we launched the browser. await app.Process.GetOutputLineStartsWithAsync(launchBrowserMessage, TimeSpan.FromMinutes(2)); }
public async Task RunsWithDotnetWatchEnvVariable() { Assert.True(string.IsNullOrEmpty(Environment.GetEnvironmentVariable("DOTNET_WATCH")), "DOTNET_WATCH cannot be set already when this test is running"); var testAsset = _testAssetsManager.CopyTestAsset(AppName) .WithSource() .Path; using var app = new WatchableApp(testAsset, _logger); await app.StartWatcherAsync(); const string messagePrefix = "DOTNET_WATCH = "; var message = await app.Process.GetOutputLineStartsWithAsync(messagePrefix, TimeSpan.FromMinutes(2)); var envValue = message.Substring(messagePrefix.Length); Assert.Equal("1", envValue); }
public async Task ChangeExcludedFile() { var testAsset = _testAssetsManager.CopyTestAsset(AppName) .WithSource() .Path; using var app = new WatchableApp(testAsset, _logger); await app.StartWatcherAsync().TimeoutAfter(DefaultTimeout); var changedFile = Path.Combine(app.SourceDirectory, "exclude", "Baz.cs"); File.WriteAllText(changedFile, ""); var restart = app.HasRestarted(); var finished = await Task.WhenAny(Task.Delay(TimeSpan.FromSeconds(5)), restart); Assert.NotSame(restart, finished); }
public async Task ConsoleCancelKey() { var console = new TestConsole(_output); var testAsset = _testAssetsManager.CopyTestAsset(AppName) .WithSource() .Path; using var watchableApp = new WatchableApp(testAsset, _output); using var app = new Program(console, testAsset); var run = app.RunAsync(new[] { "run" }); await console.CancelKeyPressSubscribed.TimeoutAfter(TimeSpan.FromSeconds(30)); console.ConsoleCancelKey(); var exitCode = await run.TimeoutAfter(TimeSpan.FromSeconds(30)); Assert.Contains("Shutdown requested. Press Ctrl+C again to force exit.", console.GetOutput()); Assert.Equal(0, exitCode); }
public async Task ChangeFileInDependency() { var testAssetsManager = new TestAssetsManager(_logger); var testAsset = testAssetsManager.CopyTestAsset("WatchAppWithProjectDeps") .WithSource() .Path; var projectDir = Path.Combine(testAsset, "AppWithDeps"); var dependencyDir = Path.Combine(testAsset, "Dependency"); using var app = new WatchableApp(projectDir, _logger); await app.StartWatcherAsync(); var fileToChange = Path.Combine(dependencyDir, "Foo.cs"); var programCs = File.ReadAllText(fileToChange); File.WriteAllText(fileToChange, programCs); await app.HasRestarted(); }
public async Task Run_WithHotReloadEnabled_ReadsLaunchSettings_WhenUsingProjectOption() { var testAsset = _testAssetsManager.CopyTestAsset("WatchAppWithLaunchSettings") .WithSource() .Path; var directoryInfo = new DirectoryInfo(testAsset); using var app = new WatchableApp(testAsset, _logger) { // Configure the working directory to be one level above the test app directory. WorkingDirectory = Path.GetFullPath(directoryInfo.Parent.FullName), }; app.DotnetWatchArgs.Add("--verbose"); app.DotnetWatchArgs.Add("--project"); app.DotnetWatchArgs.Add(Path.Combine(directoryInfo.Name, "WatchAppWithLaunchSettings.csproj")); await app.StartWatcherAsync(); await app.Process.GetOutputLineAsyncWithConsoleHistoryAsync("Environment: Development", TimeSpan.FromSeconds(10)); }
public async Task RefreshesBrowserOnChange() { var launchBrowserMessage = "watch : Launching browser: https://localhost:5001/"; var refreshBrowserMessage = "watch : Reloading browser"; var testAsset = _testAssetsManager.CopyTestAsset(AppName) .WithSource() .Path; using var app = new WatchableApp(testAsset, _logger); app.DotnetWatchArgs.Add("--verbose"); var source = Path.Combine(app.SourceDirectory, "Program.cs"); await app.StartWatcherAsync(); // Verify we launched the browser. await app.Process.GetOutputLineStartsWithAsync(launchBrowserMessage, TimeSpan.FromMinutes(2)); // Make a file change and verify we reloaded the browser. File.SetLastWriteTime(source, DateTime.Now); await app.Process.GetOutputLineStartsWithAsync(refreshBrowserMessage, TimeSpan.FromMinutes(2)); }
public async Task DeleteSourceFolder() { var testAsset = _testAssetsManager.CopyTestAsset(AppName) .WithSource() .Path; using var app = new WatchableApp(testAsset, _logger); await app.StartWatcherAsync().TimeoutAfter(DefaultTimeout); var types = await GetCompiledAppDefinedTypes(app).TimeoutAfter(DefaultTimeout); Assert.Equal(2, types); var folderToDelete = Path.Combine(app.SourceDirectory, "include"); Directory.Delete(folderToDelete, recursive: true); await app.HasRestarted().TimeoutAfter(DefaultTimeout); types = await GetCompiledAppDefinedTypes(app).TimeoutAfter(DefaultTimeout); Assert.Equal(1, types); }
public async Task DeleteCompiledFile() { var testAsset = _testAssetsManager.CopyTestAsset(AppName) .WithSource() .Path; using var app = new WatchableApp(testAsset, _logger); await app.StartWatcherAsync().TimeoutAfter(DefaultTimeout); var types = await GetCompiledAppDefinedTypes(app).TimeoutAfter(DefaultTimeout); Assert.Equal(2, types); var fileToChange = Path.Combine(app.SourceDirectory, "include", "Foo.cs"); File.Delete(fileToChange); await app.HasRestarted().TimeoutAfter(DefaultTimeout); types = await GetCompiledAppDefinedTypes(app).TimeoutAfter(DefaultTimeout); Assert.Equal(1, types); }
private async Task <int> GetCompiledAppDefinedTypes(WatchableApp app) { var definedTypesMessage = await app.Process.GetOutputLineStartsWithAsync("Defined types = ", TimeSpan.FromSeconds(30)); return(int.Parse(definedTypesMessage.Split('=').Last())); }