| File: ConfigHealingTests.cs | Web Access |
| Project: src\tests\Aspire.Cli.EndToEnd.Tests\Aspire.Cli.EndToEnd.Tests.csproj (Aspire.Cli.EndToEnd.Tests) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Cli.EndToEnd.Tests.Helpers; using Aspire.Cli.Tests.Utils; using Hex1b.Automation; using Hex1b.Input; using Xunit; namespace Aspire.Cli.EndToEnd.Tests; /// <summary> /// End-to-end tests verifying that the CLI heals a corrupted aspire.config.json /// (invalid apphost path, JSON comments) by auto-detecting the correct apphost /// and updating the config file. /// </summary> public sealed class ConfigHealingTests(ITestOutputHelper output) { /// <summary> /// Verifies that when aspire.config.json has an invalid apphost path and JSON comments, /// the CLI auto-detects the correct apphost, runs it successfully, and updates ("heals") /// the config file with the correct path. /// </summary> [Fact] public async Task InvalidAppHostPathWithComments_IsHealedOnRun() { var repoRoot = CliE2ETestHelpers.GetRepoRoot(); var installMode = CliE2ETestHelpers.DetectDockerInstallMode(repoRoot); var workspace = TemporaryWorkspace.Create(output); using var terminal = CliE2ETestHelpers.CreateDockerTestTerminal( repoRoot, installMode, output, mountDockerSocket: true, workspace: workspace); var pendingRun = terminal.RunAsync(TestContext.Current.CancellationToken); var counter = new SequenceCounter(); var auto = new Hex1bTerminalAutomator(terminal, defaultTimeout: TimeSpan.FromSeconds(500)); await auto.PrepareDockerEnvironmentAsync(counter, workspace); await auto.InstallAspireCliInDockerAsync(installMode, counter); // 1. Create a starter project await auto.AspireNewAsync("HealTest", counter, useRedisCache: false); // 2. Overwrite aspire.config.json with an invalid apphost path and a JSON comment var configFilePath = Path.Combine( workspace.WorkspaceRoot.FullName, "HealTest", "aspire.config.json"); var malformedConfig = """ { // This comment should be handled gracefully "appHost": { "path": "nonexistent/path/to/AppHost.csproj" // this path doesn't exist }, "channel": "stable" } """; File.WriteAllText(configFilePath, malformedConfig); // 3. Change into the project directory and run aspire run // The CLI should detect the invalid path, find the real apphost, // update the config, and start the app successfully await auto.TypeAsync("cd HealTest"); await auto.EnterAsync(); await auto.WaitForSuccessPromptAsync(counter); await auto.TypeAsync("aspire run"); await auto.EnterAsync(); await auto.WaitUntilTextAsync("Press CTRL+C to stop the apphost and exit.", timeout: TimeSpan.FromMinutes(3)); await auto.Ctrl().KeyAsync(Hex1bKey.C); await auto.WaitForSuccessPromptAsync(counter); // 4. Verify the config file was healed (host-side file check) if (!File.Exists(configFilePath)) { throw new InvalidOperationException( $"Config file does not exist after healing: {configFilePath}"); } var content = File.ReadAllText(configFilePath); // The healed config should contain a valid apphost path // (pointing to the actual AppHost project) if (!content.Contains("HealTest.AppHost")) { throw new InvalidOperationException( $"Config file was not healed with correct AppHost path. Content:\n{content}"); } // The invalid path should no longer be present if (content.Contains("nonexistent/path")) { throw new InvalidOperationException( $"Config file still contains invalid path after healing. Content:\n{content}"); } await auto.TypeAsync("exit"); await auto.EnterAsync(); await pendingRun; } }