File: AddNatsTests.cs
Web Access
Project: src\tests\Aspire.Hosting.Nats.Tests\Aspire.Hosting.Nats.Tests.csproj (Aspire.Hosting.Nats.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.Net.Sockets;
using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Tests.Utils;
using Aspire.Hosting.Utils;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
 
namespace Aspire.Hosting.Nats.Tests;
 
public class AddNatsTests
{
    [Fact]
    public void AddNatsAddsGeneratedPasswordParameterWithUserSecretsParameterDefaultInRunMode()
    {
        using var appBuilder = TestDistributedApplicationBuilder.Create();
 
        var nats = appBuilder.AddNats("nats");
        Assert.Equal("Aspire.Hosting.ApplicationModel.UserSecretsParameterDefault", nats.Resource.PasswordParameter!.Default?.GetType().FullName);
    }
 
    [Fact]
    public void AddNatsDoesNotAddGeneratedPasswordParameterWithUserSecretsParameterDefaultInPublishMode()
    {
        using var appBuilder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish);
 
        var nats = appBuilder.AddNats("nats");
 
        Assert.NotEqual("Aspire.Hosting.ApplicationModel.UserSecretsParameterDefault", nats.Resource.PasswordParameter!.Default?.GetType().FullName);
    }
 
    [Fact]
    public async Task AddNatsSetsDefaultUserNameAndPasswordAndIncludesThemInConnectionString()
    {
        var appBuilder = DistributedApplication.CreateBuilder();
 
        var nats = appBuilder.AddNats("nats")
            .WithEndpoint("tcp", e => e.AllocatedEndpoint = new AllocatedEndpoint(e, "localhost", 4222));
 
        Assert.NotNull(nats.Resource.PasswordParameter);
        Assert.False(string.IsNullOrEmpty(nats.Resource.PasswordParameter!.Value));
 
        using var app = appBuilder.Build();
 
        var appModel = app.Services.GetRequiredService<DistributedApplicationModel>();
 
        var natsResource = Assert.Single(appModel.Resources.OfType<NatsServerResource>());
        var connectionStringResource = natsResource as IResourceWithConnectionString;
        Assert.NotNull(connectionStringResource);
        var connectionString = await connectionStringResource.GetConnectionStringAsync();
 
        Assert.Equal($"nats://nats:{natsResource.PasswordParameter?.Value}@localhost:4222", connectionString);
        Assert.Equal("nats://nats:{nats-password.value}@{nats.bindings.tcp.host}:{nats.bindings.tcp.port}", connectionStringResource.ConnectionStringExpression.ValueExpression);
    }
 
    [Fact]
    public async Task AddNatsSetsUserNameAndPasswordAndIncludesThemInConnection()
    {
        var appBuilder = DistributedApplication.CreateBuilder();
        var userParameters = appBuilder.AddParameter("user", "usr");
        var passwordParameters = appBuilder.AddParameter("pass", "password");
 
        var nats = appBuilder.AddNats("nats", userName: userParameters, password: passwordParameters)
            .WithEndpoint("tcp", e => e.AllocatedEndpoint = new AllocatedEndpoint(e, "localhost", 4222));
 
        Assert.NotNull(nats.Resource.UserNameParameter);
        Assert.NotNull(nats.Resource.PasswordParameter);
 
        Assert.Equal("usr", nats.Resource.UserNameParameter!.Value);
        Assert.Equal("password", nats.Resource.PasswordParameter!.Value);
 
        using var app = appBuilder.Build();
 
        var appModel = app.Services.GetRequiredService<DistributedApplicationModel>();
 
        var connectionStringResource = Assert.Single(appModel.Resources.OfType<NatsServerResource>()) as IResourceWithConnectionString;
        var connectionString = await connectionStringResource.GetConnectionStringAsync();
 
        Assert.Equal("nats://usr:password@localhost:4222", connectionString);
        Assert.Equal("nats://{user.value}:{pass.value}@{nats.bindings.tcp.host}:{nats.bindings.tcp.port}", connectionStringResource.ConnectionStringExpression.ValueExpression);
    }
 
    [Fact]
    public async Task AddNatsContainerWithDefaultsAddsAnnotationMetadata()
    {
        var appBuilder = DistributedApplication.CreateBuilder();
 
        appBuilder.AddNats("nats");
 
        using var app = appBuilder.Build();
 
        var appModel = app.Services.GetRequiredService<DistributedApplicationModel>();
 
        var containerResource = Assert.Single(appModel.Resources.OfType<NatsServerResource>());
        Assert.Equal("nats", containerResource.Name);
 
        var endpoint = Assert.Single(containerResource.Annotations.OfType<EndpointAnnotation>());
        Assert.Equal(4222, endpoint.TargetPort);
        Assert.False(endpoint.IsExternal);
        Assert.Equal("tcp", endpoint.Name);
        Assert.Null(endpoint.Port);
        Assert.Equal(ProtocolType.Tcp, endpoint.Protocol);
        Assert.Equal("tcp", endpoint.Transport);
        Assert.Equal("tcp", endpoint.UriScheme);
 
        var containerAnnotation = Assert.Single(containerResource.Annotations.OfType<ContainerImageAnnotation>());
        Assert.Equal(NatsContainerImageTags.Tag, containerAnnotation.Tag);
        Assert.Equal(NatsContainerImageTags.Image, containerAnnotation.Image);
        Assert.Equal(NatsContainerImageTags.Registry, containerAnnotation.Registry);
 
        var args = await ArgumentEvaluator.GetArgumentListAsync(containerResource);
 
        Assert.Collection(args,
            arg => Assert.Equal("--user", arg),
            arg => Assert.Equal("nats", arg),
            arg => Assert.Equal("--pass", arg),
            arg => Assert.False(string.IsNullOrEmpty(arg))
        );
    }
 
    [Fact]
    public async Task AddNatsContainerAddsAnnotationMetadata()
    {
        var path = OperatingSystem.IsWindows() ? @"C:\tmp\dev-data" : "/tmp/dev-data";
 
        var appBuilder = DistributedApplication.CreateBuilder();
        var user = appBuilder.AddParameter("user", "usr");
        var pass = appBuilder.AddParameter("pass", "pass");
 
        appBuilder.AddNats("nats", 1234, user, pass).WithJetStream().WithDataBindMount(path);
 
        using var app = appBuilder.Build();
 
        var appModel = app.Services.GetRequiredService<DistributedApplicationModel>();
 
        var containerResource = Assert.Single(appModel.Resources.OfType<NatsServerResource>());
        Assert.Equal("nats", containerResource.Name);
 
        var mountAnnotation = Assert.Single(containerResource.Annotations.OfType<ContainerMountAnnotation>());
        Assert.Equal(path, mountAnnotation.Source);
        Assert.Equal("/var/lib/nats", mountAnnotation.Target);
 
        var endpoint = Assert.Single(containerResource.Annotations.OfType<EndpointAnnotation>());
        Assert.Equal(4222, endpoint.TargetPort);
        Assert.False(endpoint.IsExternal);
        Assert.Equal("tcp", endpoint.Name);
        Assert.Equal(1234, endpoint.Port);
        Assert.Equal(ProtocolType.Tcp, endpoint.Protocol);
        Assert.Equal("tcp", endpoint.Transport);
        Assert.Equal("tcp", endpoint.UriScheme);
 
        var containerAnnotation = Assert.Single(containerResource.Annotations.OfType<ContainerImageAnnotation>());
        Assert.Equal(NatsContainerImageTags.Tag, containerAnnotation.Tag);
        Assert.Equal(NatsContainerImageTags.Image, containerAnnotation.Image);
        Assert.Equal(NatsContainerImageTags.Registry, containerAnnotation.Registry);
 
        var args = await ArgumentEvaluator.GetArgumentListAsync(containerResource);
 
        Assert.Collection(args,
            arg => Assert.Equal("--user", arg),
            arg => Assert.Equal("usr", arg),
            arg => Assert.Equal("--pass", arg),
            arg => Assert.Equal("pass", arg),
            arg => Assert.Equal("-js", arg),
            arg => Assert.Equal("-sd", arg),
            arg => Assert.Equal("/var/lib/nats", arg)
        );
    }
 
    [Fact]
    public void WithNatsContainerOnMultipleResources()
    {
        using var builder = TestDistributedApplicationBuilder.Create();
        builder.AddNats("nats1");
        builder.AddNats("nats2");
 
        Assert.Equal(2, builder.Resources.OfType<NatsServerResource>().Count());
    }
 
    [Fact]
    public async Task VerifyManifest()
    {
        using var builder = TestDistributedApplicationBuilder.Create();
        var nats = builder.AddNats("nats");
 
        var manifest = await ManifestUtils.GetManifest(nats.Resource);
 
        var expectedManifest = $$"""
            {
              "type": "container.v0",
              "connectionString": "nats://nats:{nats-password.value}@{nats.bindings.tcp.host}:{nats.bindings.tcp.port}",
              "image": "{{NatsContainerImageTags.Registry}}/{{NatsContainerImageTags.Image}}:{{NatsContainerImageTags.Tag}}",
              "args": [
                "--user",
                "nats",
                "--pass",
                "{nats-password.value}"
              ],
              "bindings": {
                "tcp": {
                  "scheme": "tcp",
                  "protocol": "tcp",
                  "transport": "tcp",
                  "targetPort": 4222
                }
              }
            }
            """;
 
        Assert.Equal(expectedManifest, manifest.ToString());
    }
 
    [Fact]
    public async Task VerifyManifestWihtParameters()
    {
        using var builder = TestDistributedApplicationBuilder.Create();
        var userNameParameter = builder.AddParameter("user");
        var passwordParameter = builder.AddParameter("pass");
 
        var nats = builder.AddNats("nats", userName: userNameParameter, password: passwordParameter)
            .WithJetStream();
 
        var manifest = await ManifestUtils.GetManifest(nats.Resource);
 
        var expectedManifest = $$"""
            {
              "type": "container.v0",
              "connectionString": "nats://{user.value}:{pass.value}@{nats.bindings.tcp.host}:{nats.bindings.tcp.port}",
              "image": "{{NatsContainerImageTags.Registry}}/{{NatsContainerImageTags.Image}}:{{NatsContainerImageTags.Tag}}",
              "args": [
                "--user",
                "{user.value}",
                "--pass",
                "{pass.value}",
                "-js"
              ],
              "bindings": {
                "tcp": {
                  "scheme": "tcp",
                  "protocol": "tcp",
                  "transport": "tcp",
                  "targetPort": 4222
                }
              }
            }
            """;
        Assert.Equal(expectedManifest, manifest.ToString());
 
        nats = builder.AddNats("nats2", userName: userNameParameter);
 
        manifest = await ManifestUtils.GetManifest(nats.Resource);
 
        expectedManifest = $$"""
            {
              "type": "container.v0",
              "connectionString": "nats://{user.value}:{nats2-password.value}@{nats2.bindings.tcp.host}:{nats2.bindings.tcp.port}",
              "image": "{{NatsContainerImageTags.Registry}}/{{NatsContainerImageTags.Image}}:{{NatsContainerImageTags.Tag}}",
              "args": [
                "--user",
                "{user.value}",
                "--pass",
                "{nats2-password.value}"
              ],
              "bindings": {
                "tcp": {
                  "scheme": "tcp",
                  "protocol": "tcp",
                  "transport": "tcp",
                  "targetPort": 4222
                }
              }
            }
            """;
        Assert.Equal(expectedManifest, manifest.ToString());
 
        nats = builder.AddNats("nats3", password: passwordParameter);
 
        manifest = await ManifestUtils.GetManifest(nats.Resource);
 
        expectedManifest = $$"""
            {
              "type": "container.v0",
              "connectionString": "nats://nats:{pass.value}@{nats3.bindings.tcp.host}:{nats3.bindings.tcp.port}",
              "image": "{{NatsContainerImageTags.Registry}}/{{NatsContainerImageTags.Image}}:{{NatsContainerImageTags.Tag}}",
              "args": [
                "--user",
                "nats",
                "--pass",
                "{pass.value}"
              ],
              "bindings": {
                "tcp": {
                  "scheme": "tcp",
                  "protocol": "tcp",
                  "transport": "tcp",
                  "targetPort": 4222
                }
              }
            }
            """;
        Assert.Equal(expectedManifest, manifest.ToString());
    }
}