| File: TestServices\ComposeTestApplication.cs | Web Access |
| Project: src\tests\Aspire.Hosting.Native.Core.Tests\Aspire.Hosting.Native.Core.Tests.csproj (Aspire.Hosting.Native.Core.Tests) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Concurrent; using Aspire.Hosting.Native.Authoring; using NativeIntegrations.DockerCompose; namespace Aspire.Hosting.Native.Core.Tests.TestServices; internal static class ComposeTestApplication { internal static DistributedApplicationBuilder Create(string root, Action<IResourceBuilder<DockerComposeEnvironmentResource>>? configure = null) { var builder = DistributedApplication.CreateBuilder(["--operation=publish"], new() { ApplicationRoot = root }); var environment = builder.AddDockerComposeEnvironment("compose").WithDashboard(false); configure?.Invoke(environment); var password = builder.AddConfiguredParameter("cache-password", secret: true); var cache = builder.AddContainer("cache", "redis:7.4-alpine") .WithEnvironment("REDIS_PASSWORD", password) .WithEntrypoint("/bin/sh") .WithArgs("-c", "exec redis-server --requirepass \"$REDIS_PASSWORD\" --appendonly yes --appendfsync always --dir /data") .WithEndpoint("tcp", 6379, "redis") .WithVolume("cache-data", "/data") .WithComputeEnvironment(environment) .PublishAsDockerComposeService(new DockerComposeServiceOptions { Healthcheck = new(["CMD-SHELL", "REDISCLI_AUTH=\"$REDIS_PASSWORD\" redis-cli ping | grep -q PONG"], "1s", "3s", 30) }); cache.WithConnectionString(ReferenceExpression.Create("redis://:", password.AsReference().EncodeUri(), "@", cache.GetEndpoint("tcp").HostAndPort)); builder.AddExecutable("web", Path.Combine(root, "deployment-only", "node"), Path.Combine(root, "web")) .WithArgs("server.mts") .WithReference(cache) .WithEndpoint("http", 8080, "http") .WithExternalHttpEndpoints() .WaitFor(cache) .WithComputeEnvironment(environment) .PublishAsDockerComposeService(new DockerComposeServiceOptions { Image = "aspire-v2-compose-csharp-test:local", Build = new("./web", "./web/Dockerfile"), Healthcheck = new(["CMD", "node", "-e", "fetch('http://127.0.0.1:8080/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"], "1s", "3s", 30) }); return builder; } } internal sealed class ComposeTestRunner { internal ConcurrentQueue<(string Executable, string[] Arguments, DockerCommandOptions Options)> Calls { get; } = new(); internal string Status { get; set; } = """ [ {"Service":"cache","State":"running","Health":"healthy","Publishers":[]}, {"Service":"web","State":"running","Health":"healthy","Publishers":[{"URL":"127.0.0.1","TargetPort":8080,"PublishedPort":49152,"Protocol":"tcp"}]} ] """; internal string? ApplyFailure { get; set; } internal Task<DockerCommandResult> RunAsync(string executable, IReadOnlyList<string> arguments, DockerCommandOptions options) { Calls.Enqueue((executable, arguments.ToArray(), options)); if (arguments.Contains("up") && ApplyFailure is { } failure) { return Task.FromResult(new DockerCommandResult(1, "", failure)); } var stdout = arguments.Contains("version") ? "2.40.3" : arguments.Contains("ps") ? Status : "{}"; return Task.FromResult(new DockerCommandResult(0, stdout, "")); } }