| File: Commands\SdkDumpCommandTests.cs | Web Access |
| Project: src\tests\Aspire.Cli.Tests\Aspire.Cli.Tests.csproj (Aspire.Cli.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.Commands; using Aspire.Cli.Tests.Utils; using Microsoft.AspNetCore.InternalTesting; using Microsoft.Extensions.DependencyInjection; using Microsoft.DotNet.RemoteExecutor; namespace Aspire.Cli.Tests.Commands; public class SdkDumpCommandTests(ITestOutputHelper outputHelper) { private static readonly RemoteInvokeOptions s_remoteInvokeOptions = new() { StartInfo = { RedirectStandardOutput = true } }; [Fact] public async Task SdkDumpWithHelpReturnsZero() { using var workspace = TemporaryWorkspace.Create(outputHelper); var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); var provider = services.BuildServiceProvider(); var command = provider.GetRequiredService<RootCommand>(); var result = command.Parse("sdk dump --help"); var exitCode = await result.InvokeAsync().DefaultTimeout(); Assert.Equal(0, exitCode); } [Theory] [InlineData("json")] [InlineData("Json")] [InlineData("JSON")] [InlineData("ci")] [InlineData("Ci")] [InlineData("pretty")] [InlineData("Pretty")] public void ParsesFormatOptionWithoutErrors(string format) { using var workspace = TemporaryWorkspace.Create(outputHelper); var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); var provider = services.BuildServiceProvider(); var command = provider.GetRequiredService<RootCommand>(); var result = command.Parse($"sdk dump --format {format}"); Assert.Empty(result.Errors); } [Fact] public async Task SdkDumpWithNonexistentCsprojReturnsFailedToFindProject() { using var workspace = TemporaryWorkspace.Create(outputHelper); var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); var provider = services.BuildServiceProvider(); var command = provider.GetRequiredService<RootCommand>(); var result = command.Parse("sdk dump /nonexistent/path/to/integration.csproj"); var exitCode = await result.InvokeAsync().DefaultTimeout(); Assert.Equal(ExitCodeConstants.FailedToFindProject, exitCode); } [Fact] public async Task SdkDumpWithEmptyPackageNameReturnsInvalidCommand() { using var workspace = TemporaryWorkspace.Create(outputHelper); var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); var provider = services.BuildServiceProvider(); var command = provider.GetRequiredService<RootCommand>(); var result = command.Parse("sdk dump @13.2.0"); var exitCode = await result.InvokeAsync().DefaultTimeout(); Assert.Equal(ExitCodeConstants.InvalidCommand, exitCode); } [Fact] public async Task SdkDumpWithEmptyVersionReturnsInvalidCommand() { using var workspace = TemporaryWorkspace.Create(outputHelper); var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); var provider = services.BuildServiceProvider(); var command = provider.GetRequiredService<RootCommand>(); var result = command.Parse("sdk dump Aspire.Hosting.Redis@"); var exitCode = await result.InvokeAsync().DefaultTimeout(); Assert.Equal(ExitCodeConstants.InvalidCommand, exitCode); } [Fact] public async Task SdkDumpWithInvalidVersionFormatReturnsInvalidCommand() { using var workspace = TemporaryWorkspace.Create(outputHelper); var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); var provider = services.BuildServiceProvider(); var command = provider.GetRequiredService<RootCommand>(); var result = command.Parse("sdk dump Aspire.Hosting.Redis@not-a-version!!!"); var exitCode = await result.InvokeAsync().DefaultTimeout(); Assert.Equal(ExitCodeConstants.InvalidCommand, exitCode); } [Fact] public async Task SdkDumpWithInvalidArgumentFormatReturnsInvalidCommand() { using var workspace = TemporaryWorkspace.Create(outputHelper); var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); var provider = services.BuildServiceProvider(); var command = provider.GetRequiredService<RootCommand>(); var result = command.Parse("sdk dump some-random-string"); var exitCode = await result.InvokeAsync().DefaultTimeout(); Assert.Equal(ExitCodeConstants.InvalidCommand, exitCode); } [Fact] public void ParsesValidPackageFormatWithoutErrors() { using var workspace = TemporaryWorkspace.Create(outputHelper); var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); var provider = services.BuildServiceProvider(); var command = provider.GetRequiredService<RootCommand>(); var result = command.Parse("sdk dump Aspire.Hosting.Redis@13.2.0"); Assert.Empty(result.Errors); } [Fact] public void ParsesMultipleMixedArgumentsWithoutErrors() { using var workspace = TemporaryWorkspace.Create(outputHelper); var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); var provider = services.BuildServiceProvider(); var command = provider.GetRequiredService<RootCommand>(); var result = command.Parse("sdk dump Aspire.Hosting.Redis@13.2.0 Aspire.Hosting.PostgreSQL@13.2.0"); Assert.Empty(result.Errors); } [Fact] public void ParsesPreReleaseVersionWithoutErrors() { using var workspace = TemporaryWorkspace.Create(outputHelper); var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); var provider = services.BuildServiceProvider(); var command = provider.GetRequiredService<RootCommand>(); var result = command.Parse("sdk dump Aspire.Hosting.Redis@13.2.0-preview.1"); Assert.Empty(result.Errors); } [Fact] public async Task SdkDumpWithDoubleAtSignReturnsInvalidCommand() { using var workspace = TemporaryWorkspace.Create(outputHelper); var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); var provider = services.BuildServiceProvider(); var command = provider.GetRequiredService<RootCommand>(); // LastIndexOf('@') splits as "Aspire.Hosting.Redis@" and "13.2.0" // The @ in the package name part triggers format validation var result = command.Parse("sdk dump Aspire.Hosting.Redis@@13.2.0"); var exitCode = await result.InvokeAsync().DefaultTimeout(); // "Aspire.Hosting.Redis@" is not a valid semver, so it should fail version validation Assert.Equal(ExitCodeConstants.InvalidCommand, exitCode); } [Fact] public void SdkDumpCi_ForHostingProject_DoesNotEmitWarnings() { // Assertions and skips inside the callback are surfaced back to the parent test process. using var result = RemoteExecutor.Invoke(async (baseDirectory) => { var repoRoot = TryFindRepoRoot(baseDirectory); if (repoRoot is null) { Assert.Skip($"Could not find Aspire.slnx starting from '{baseDirectory}'."); return; } var projectPath = Path.Combine(repoRoot, "src", "Aspire.Hosting", "Aspire.Hosting.csproj"); Assert.True(File.Exists(projectPath), $"Could not find Aspire.Hosting project at '{projectPath}'."); var tempDirectory = Path.Combine(Path.GetTempPath(), "aspire-sdk-dump-tests", $"{Guid.NewGuid():N}"); Directory.CreateDirectory(tempDirectory); var outputPath = Path.Combine(tempDirectory, "capabilities.txt"); try { Environment.CurrentDirectory = repoRoot; Environment.SetEnvironmentVariable("ASPIRE_REPO_ROOT", repoRoot); Environment.SetEnvironmentVariable(CliConfigNames.NoLogo, "true"); Environment.SetEnvironmentVariable("DOTNET_CLI_TELEMETRY_OPTOUT", "true"); Environment.SetEnvironmentVariable("DOTNET_SKIP_FIRST_TIME_EXPERIENCE", "true"); Environment.SetEnvironmentVariable("DOTNET_GENERATE_ASPNET_CERTIFICATE", "false"); var exitCode = await Program.Main(["sdk", "dump", "--format", "ci", "--output", outputPath, projectPath]).DefaultTimeout(TestConstants.LongTimeoutTimeSpan); Assert.Equal(ExitCodeConstants.Success, exitCode); var output = await File.ReadAllTextAsync(outputPath); Assert.NotEmpty(output); var warningLines = output .Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries) .Where(line => line.Contains("warning:", StringComparison.OrdinalIgnoreCase)) .ToArray(); Console.WriteLine($"Warnings: {warningLines.Length}"); foreach (var warningLine in warningLines) { Console.WriteLine(warningLine); } Assert.Empty(warningLines); } finally { if (Directory.Exists(tempDirectory)) { Directory.Delete(tempDirectory, recursive: true); } } }, AppContext.BaseDirectory, options: s_remoteInvokeOptions); outputHelper.WriteLine(result.Process.StandardOutput.ReadToEnd()); } private static string? TryFindRepoRoot(string startPath) { var currentDirectory = new DirectoryInfo(startPath); while (currentDirectory is not null) { if (File.Exists(Path.Combine(currentDirectory.FullName, "Aspire.slnx"))) { return currentDirectory.FullName; } currentDirectory = currentDirectory.Parent; } return null; } }