示例#1
0
        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
        }
示例#2
0
        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());
        }
示例#3
0
        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);
        }
示例#4
0
        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);
        }
示例#7
0
        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);
        }
示例#8
0
        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();
            }
        }
示例#9
0
        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));
        }
示例#10
0
        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);
        }
示例#12
0
        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));
        }
示例#13
0
        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);
        }
示例#15
0
        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);
        }
示例#16
0
        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();
        }
示例#17
0
        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));
        }
示例#18
0
        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()));
        }