Skip to content
7 changes: 3 additions & 4 deletions src/Aspire.Hosting.Redis/RedisBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -417,14 +417,13 @@ public static IResourceBuilder<RedisInsightResource> WithDataBindMount(this IRes
/// Configures the password that the Redis resource is used.
/// </summary>
/// <param name="builder">The resource builder.</param>
/// <param name="password">The parameter used to provide the password for the Redis resource.</param>
/// <param name="password">The parameter used to provide the password for the Redis resource. If <see langword="null"/>, no password will be configured.</param>
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<RedisResource> WithPassword(this IResourceBuilder<RedisResource> builder, IResourceBuilder<ParameterResource> password)
public static IResourceBuilder<RedisResource> WithPassword(this IResourceBuilder<RedisResource> builder, IResourceBuilder<ParameterResource>? password)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(password);

builder.Resource.SetPassword(password.Resource);
builder.Resource.SetPassword(password?.Resource);
return builder;
}

Expand Down
4 changes: 1 addition & 3 deletions src/Aspire.Hosting.Redis/RedisResource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,8 @@ public ReferenceExpression ConnectionStringExpression
return BuildConnectionString().GetValueAsync(cancellationToken);
}

internal void SetPassword(ParameterResource password)
internal void SetPassword(ParameterResource? password)
{
ArgumentNullException.ThrowIfNull(password);

PasswordParameter = password;
}
}
81 changes: 73 additions & 8 deletions tests/Aspire.Hosting.Redis.Tests/AddRedisTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public async Task RedisCreatesConnectionStringWithDefaultPassword()
}

[Fact]
public async Task VerifyWithoutPasswordManifest()
public async Task VerifyDefaultManifest()
{
using var builder = TestDistributedApplicationBuilder.Create();
var redis = builder.AddRedis("redis");
Expand Down Expand Up @@ -161,6 +161,37 @@ public async Task VerifyWithoutPasswordManifest()
Assert.Equal(expectedManifest, manifest.ToString());
}

[Fact]
public async Task VerifyWithoutPasswordManifest()
{
using var builder = TestDistributedApplicationBuilder.Create();
var redis = builder.AddRedis("redis").WithPassword(null);

var manifest = await ManifestUtils.GetManifest(redis.Resource);

var expectedManifest = $$"""
{
"type": "container.v0",
"connectionString": "{redis.bindings.tcp.host}:{redis.bindings.tcp.port}",
"image": "{{RedisContainerImageTags.Registry}}/{{RedisContainerImageTags.Image}}:{{RedisContainerImageTags.Tag}}",
"entrypoint": "/bin/sh",
"args": [
"-c",
"redis-server"
],
"bindings": {
"tcp": {
"scheme": "tcp",
"protocol": "tcp",
"transport": "tcp",
"targetPort": 6379
}
}
}
""";
Assert.Equal(expectedManifest, manifest.ToString());
}

[Fact]
public async Task VerifyWithPasswordManifest()
{
Expand Down Expand Up @@ -260,6 +291,7 @@ public async Task WithRedisInsightProducesCorrectEnvironmentVariables()
var builder = DistributedApplication.CreateBuilder();
var redis1 = builder.AddRedis("myredis1").WithRedisInsight();
var redis2 = builder.AddRedis("myredis2").WithRedisInsight();
var redis3 = builder.AddRedis("myredis3").WithRedisInsight().WithPassword(null);
using var app = builder.Build();

// Add fake allocated endpoints.
Expand Down Expand Up @@ -311,6 +343,21 @@ public async Task WithRedisInsightProducesCorrectEnvironmentVariables()
{
Assert.Equal("RI_REDIS_PASSWORD2", item.Key);
Assert.Equal(redis2.Resource.PasswordParameter!.Value, item.Value);
},
(item) =>
{
Assert.Equal("RI_REDIS_HOST3", item.Key);
Assert.Equal(redis3.Resource.Name, item.Value);
},
(item) =>
{
Assert.Equal("RI_REDIS_PORT3", item.Key);
Assert.Equal($"{redis3.Resource.PrimaryEndpoint.TargetPort!.Value}", item.Value);
},
(item) =>
{
Assert.Equal("RI_REDIS_ALIAS3", item.Key);
Assert.Equal(redis3.Resource.Name, item.Value);
});

}
Expand Down Expand Up @@ -391,26 +438,44 @@ public void VerifyRedisResourceWithHostPort()
Assert.Equal(1000, endpoint.Port);
}

[Fact]
public async Task VerifyRedisResourceWithPassword()
[Theory]
[InlineData(false)]
[InlineData(true)]
public async Task VerifyRedisResourceWithPassword(bool withPassword)
{
using var builder = TestDistributedApplicationBuilder.Create();

var password = "p@ssw0rd1";
var pass = builder.AddParameter("pass", password);
var redis = builder
.AddRedis("myRedis")
.WithPassword(pass)
.WithEndpoint("tcp", e => e.AllocatedEndpoint = new AllocatedEndpoint(e, "localhost", 5001));

var password = "p@ssw0rd1";
if (withPassword)
{
var pass = builder.AddParameter("pass", password);
redis.WithPassword(pass);
}
else
{
redis.WithPassword(null);
}

using var app = builder.Build();
var appModel = app.Services.GetRequiredService<DistributedApplicationModel>();
var containerResource = Assert.Single(appModel.Resources.OfType<RedisResource>());

var connectionStringResource = Assert.Single(appModel.Resources.OfType<IResourceWithConnectionString>());
var connectionString = await connectionStringResource.GetConnectionStringAsync(default);
Assert.Equal("{myRedis.bindings.tcp.host}:{myRedis.bindings.tcp.port},password={pass.value}", connectionStringResource.ConnectionStringExpression.ValueExpression);
Assert.StartsWith($"localhost:5001,password={password}", connectionString);
if (withPassword)
{
Assert.Equal("{myRedis.bindings.tcp.host}:{myRedis.bindings.tcp.port},password={pass.value}", connectionStringResource.ConnectionStringExpression.ValueExpression);
Assert.Equal($"localhost:5001,password={password}", connectionString);
}
else
{
Assert.Equal("{myRedis.bindings.tcp.host}:{myRedis.bindings.tcp.port}", connectionStringResource.ConnectionStringExpression.ValueExpression);
Assert.Equal($"localhost:5001", connectionString);
}
}

[Fact]
Expand Down
11 changes: 9 additions & 2 deletions tests/Aspire.Hosting.Redis.Tests/RedisFunctionalTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ public async Task VerifyWithRedisInsightImportDatabases()
IResourceBuilder<RedisInsightResource>? redisInsightBuilder = null;
var redis2 = builder.AddRedis("redis-2").WithRedisInsight(c => redisInsightBuilder = c);
Assert.NotNull(redisInsightBuilder);
var redis3 = builder.AddRedis("redis-3").WithPassword(null);

using var app = builder.Build();

Expand Down Expand Up @@ -169,13 +170,19 @@ public async Task VerifyWithRedisInsightImportDatabases()
Assert.Equal(redis2.Resource.Name, db.Name);
Assert.Equal(redis2.Resource.Name, db.Host);
Assert.Equal(redis2.Resource.PrimaryEndpoint.TargetPort, db.Port);
},
db =>
{
Assert.Equal(redis3.Resource.Name, db.Name);
Assert.Equal(redis3.Resource.Name, db.Host);
Assert.Equal(redis3.Resource.PrimaryEndpoint.TargetPort, db.Port);
});

foreach (var db in databases)
{
var cts2 = new CancellationTokenSource(TimeSpan.FromSeconds(2));
var testConnectionResponse = await client.GetAsync($"/api/databases/test/{db.Id}", cts2.Token);
response.EnsureSuccessStatusCode();
var testConnectionResponse = await client.GetAsync($"/api/databases/{db.Id}/connect", cts2.Token);
testConnectionResponse.EnsureSuccessStatusCode();
}
}

Expand Down