256 lines
9.6 KiB
C#
256 lines
9.6 KiB
C#
using EntKube.Provisioning.Domain;
|
|
using EntKube.Provisioning.Features.MinioInstances;
|
|
using EntKube.Provisioning.Features.MinioInstances.AdoptMinioInstance;
|
|
using EntKube.Provisioning.Features.PostgresClusters;
|
|
using EntKube.Provisioning.Features.PostgresClusters.CreatePostgresCluster;
|
|
using EntKube.Provisioning.Infrastructure;
|
|
using EntKube.SharedKernel.Domain;
|
|
using FluentAssertions;
|
|
using Moq;
|
|
|
|
namespace EntKube.Provisioning.Tests.Features;
|
|
|
|
/// <summary>
|
|
/// Tests for MinIO adoption and its integration with CNPG cluster provisioning.
|
|
/// MinIO must be adopted before CNPG clusters can be created — the create flow
|
|
/// resolves the MinIO details by reference (cluster ID) rather than raw values.
|
|
/// </summary>
|
|
public class MinioAdoptionTests
|
|
{
|
|
private readonly InMemoryMinioInstanceRepository minioRepository;
|
|
private readonly InMemoryPostgresClusterRepository pgRepository;
|
|
private readonly Mock<IMinioClient> minioClient;
|
|
private readonly Mock<ICnpgClusterClient> cnpgClient;
|
|
|
|
public MinioAdoptionTests()
|
|
{
|
|
minioRepository = new InMemoryMinioInstanceRepository();
|
|
pgRepository = new InMemoryPostgresClusterRepository();
|
|
minioClient = new Mock<IMinioClient>();
|
|
cnpgClient = new Mock<ICnpgClusterClient>();
|
|
}
|
|
|
|
// ─── Adopt MinIO ──────────────────────────────────────────────────────────
|
|
|
|
[Fact]
|
|
public async Task AdoptMinio_WithDiscoveredTenant_CreatesRunningInstance()
|
|
{
|
|
// Arrange — The K8s cluster has an existing MinIO tenant running.
|
|
|
|
minioClient.Setup(c => c.DiscoverMinioAsync(
|
|
It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(new DiscoveredMinioInstance(
|
|
Name: "platform-minio",
|
|
Namespace: "minio-system",
|
|
Endpoint: "minio.minio-system.svc:9000",
|
|
ConsoleEndpoint: "minio-console.minio-system.svc:9001",
|
|
CredentialsSecret: "minio-root-credentials",
|
|
TotalCapacity: "1Ti",
|
|
UsedCapacity: "250Gi",
|
|
Buckets: new List<string> { "loki-logs", "velero-backups" }));
|
|
|
|
AdoptMinioInstanceHandler handler = new(minioRepository, minioClient.Object);
|
|
|
|
AdoptMinioInstanceRequest request = new(
|
|
ClusterId: Guid.NewGuid(),
|
|
KubeConfig: "config",
|
|
ContextName: "ctx");
|
|
|
|
// Act
|
|
|
|
Result<Guid> result = await handler.HandleAsync(request);
|
|
|
|
// Assert — MinIO adopted and stored with all discovered details.
|
|
|
|
result.IsSuccess.Should().BeTrue();
|
|
result.Value.Should().NotBe(Guid.Empty);
|
|
|
|
IReadOnlyList<MinioInstance> all = await minioRepository.GetAllAsync();
|
|
all.Should().HaveCount(1);
|
|
all[0].Name.Should().Be("platform-minio");
|
|
all[0].Endpoint.Should().Be("minio.minio-system.svc:9000");
|
|
all[0].Status.Should().Be(MinioInstanceStatus.Running);
|
|
all[0].Buckets.Should().Contain("loki-logs");
|
|
all[0].Buckets.Should().Contain("velero-backups");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task AdoptMinio_NoTenantFound_ReturnsFailure()
|
|
{
|
|
// Arrange — No MinIO tenant on this cluster.
|
|
|
|
minioClient.Setup(c => c.DiscoverMinioAsync(
|
|
It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync((DiscoveredMinioInstance?)null);
|
|
|
|
AdoptMinioInstanceHandler handler = new(minioRepository, minioClient.Object);
|
|
|
|
AdoptMinioInstanceRequest request = new(Guid.NewGuid(), "config", "ctx");
|
|
|
|
// Act
|
|
|
|
Result<Guid> result = await handler.HandleAsync(request);
|
|
|
|
// Assert
|
|
|
|
result.IsFailure.Should().BeTrue();
|
|
result.Error.Should().Contain("No MinIO");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task AdoptMinio_AlreadyAdopted_ReturnsExistingId()
|
|
{
|
|
// Arrange — MinIO was already adopted for this cluster.
|
|
|
|
Guid clusterId = Guid.NewGuid();
|
|
|
|
MinioInstance existing = MinioInstance.Adopt(
|
|
clusterId, "platform-minio", "minio-system",
|
|
"minio:9000", null, "secret", "500Gi", null, null);
|
|
await minioRepository.AddAsync(existing);
|
|
|
|
minioClient.Setup(c => c.DiscoverMinioAsync(
|
|
It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(new DiscoveredMinioInstance(
|
|
"platform-minio", "minio-system", "minio:9000",
|
|
null, "secret", "500Gi", null, null));
|
|
|
|
AdoptMinioInstanceHandler handler = new(minioRepository, minioClient.Object);
|
|
|
|
AdoptMinioInstanceRequest request = new(clusterId, "config", "ctx");
|
|
|
|
// Act
|
|
|
|
Result<Guid> result = await handler.HandleAsync(request);
|
|
|
|
// Assert — Returns the existing ID without creating a duplicate.
|
|
|
|
result.IsSuccess.Should().BeTrue();
|
|
result.Value.Should().Be(existing.Id);
|
|
|
|
IReadOnlyList<MinioInstance> all = await minioRepository.GetAllAsync();
|
|
all.Should().HaveCount(1);
|
|
}
|
|
|
|
// ─── CNPG Create with MinIO Reference ─────────────────────────────────────
|
|
|
|
[Fact]
|
|
public async Task CreatePostgresCluster_WithMinioInstanceId_ResolvesMinioConfig()
|
|
{
|
|
// Arrange — An adopted MinIO instance exists. When creating a CNPG cluster,
|
|
// we reference it by the cluster ID instead of providing raw details.
|
|
|
|
Guid clusterId = Guid.NewGuid();
|
|
|
|
MinioInstance minio = MinioInstance.Adopt(
|
|
clusterId, "platform-minio", "minio-system",
|
|
"minio.minio-system.svc:9000", null,
|
|
"minio-root-credentials", "1Ti", null,
|
|
new List<string> { "cnpg-backups" });
|
|
await minioRepository.AddAsync(minio);
|
|
|
|
CreatePostgresClusterHandler handler = new(pgRepository, cnpgClient.Object, minioRepository);
|
|
|
|
CreatePostgresClusterRequest request = new(
|
|
EnvironmentId: Guid.NewGuid(),
|
|
ClusterId: clusterId,
|
|
Name: "prod-db",
|
|
Namespace: "cnpg-system",
|
|
PostgresVersion: "16.4",
|
|
Instances: 3,
|
|
StorageSize: "50Gi",
|
|
KubeConfig: "config",
|
|
ContextName: "ctx",
|
|
MinioEndpoint: null,
|
|
MinioBucket: "cnpg-backups",
|
|
MinioCredentialsSecret: null);
|
|
|
|
// Act
|
|
|
|
Result<Guid> result = await handler.HandleAsync(request);
|
|
|
|
// Assert — MinIO details resolved from the adopted instance.
|
|
|
|
result.IsSuccess.Should().BeTrue();
|
|
|
|
IReadOnlyList<PostgresCluster> clusters = await pgRepository.GetAllAsync();
|
|
clusters.Should().HaveCount(1);
|
|
clusters[0].BackupConfig!.MinioEndpoint.Should().Be("minio.minio-system.svc:9000");
|
|
clusters[0].BackupConfig.CredentialsSecret.Should().Be("minio-root-credentials");
|
|
clusters[0].BackupConfig.Bucket.Should().Be("cnpg-backups");
|
|
|
|
cnpgClient.Verify(c => c.CreateClusterAsync(
|
|
"config", "ctx",
|
|
It.Is<CnpgClusterSpec>(s =>
|
|
s.MinioEndpoint == "minio.minio-system.svc:9000" &&
|
|
s.MinioCredentialsSecret == "minio-root-credentials"),
|
|
It.IsAny<CancellationToken>()), Times.Once);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CreatePostgresCluster_NoMinioAdopted_CreatesWithoutBackup()
|
|
{
|
|
// Arrange — No MinIO adopted for this cluster, and no explicit endpoint provided.
|
|
// The cluster should still be created, just without backup configuration.
|
|
|
|
CreatePostgresClusterHandler handler = new(pgRepository, cnpgClient.Object, minioRepository);
|
|
|
|
CreatePostgresClusterRequest request = new(
|
|
EnvironmentId: Guid.NewGuid(),
|
|
ClusterId: Guid.NewGuid(),
|
|
Name: "prod-db",
|
|
Namespace: "cnpg-system",
|
|
PostgresVersion: "16.4",
|
|
Instances: 3,
|
|
StorageSize: "50Gi",
|
|
KubeConfig: "config",
|
|
ContextName: "ctx",
|
|
MinioEndpoint: null,
|
|
MinioBucket: "backups",
|
|
MinioCredentialsSecret: null);
|
|
|
|
// Act
|
|
|
|
Result<Guid> result = await handler.HandleAsync(request);
|
|
|
|
// Assert — Cluster is created successfully without backup.
|
|
|
|
result.IsSuccess.Should().BeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CreatePostgresCluster_WithExplicitMinioDetails_StillWorks()
|
|
{
|
|
// Arrange — Explicit MinIO details provided (bypass adoption lookup).
|
|
|
|
CreatePostgresClusterHandler handler = new(pgRepository, cnpgClient.Object, minioRepository);
|
|
|
|
CreatePostgresClusterRequest request = new(
|
|
EnvironmentId: Guid.NewGuid(),
|
|
ClusterId: Guid.NewGuid(),
|
|
Name: "prod-db",
|
|
Namespace: "cnpg-system",
|
|
PostgresVersion: "16.4",
|
|
Instances: 3,
|
|
StorageSize: "50Gi",
|
|
KubeConfig: "config",
|
|
ContextName: "ctx",
|
|
MinioEndpoint: "custom-minio:9000",
|
|
MinioBucket: "custom-bucket",
|
|
MinioCredentialsSecret: "custom-secret");
|
|
|
|
// Act
|
|
|
|
Result<Guid> result = await handler.HandleAsync(request);
|
|
|
|
// Assert — Explicit values used directly.
|
|
|
|
result.IsSuccess.Should().BeTrue();
|
|
|
|
IReadOnlyList<PostgresCluster> clusters = await pgRepository.GetAllAsync();
|
|
clusters[0].BackupConfig!.MinioEndpoint.Should().Be("custom-minio:9000");
|
|
clusters[0].BackupConfig.Bucket.Should().Be("custom-bucket");
|
|
clusters[0].BackupConfig.CredentialsSecret.Should().Be("custom-secret");
|
|
}
|
|
}
|