too much for one commit
This commit is contained in:
@@ -0,0 +1,181 @@
|
||||
using EntKube.Clusters.Domain;
|
||||
using EntKube.Clusters.Features.AdoptCluster;
|
||||
using EntKube.Clusters.Features.AdoptCluster.DeployComponent;
|
||||
using EntKube.Clusters.Infrastructure;
|
||||
using EntKube.SharedKernel.Domain;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
|
||||
namespace EntKube.Clusters.Tests.Features;
|
||||
|
||||
public class DeployComponentHandlerTests
|
||||
{
|
||||
private readonly InMemoryClusterRepository repository;
|
||||
private readonly Mock<IComponentInstaller> kyvernoInstaller;
|
||||
private readonly Mock<IComponentInstaller> policiesInstaller;
|
||||
private readonly DeployComponentHandler handler;
|
||||
|
||||
public DeployComponentHandlerTests()
|
||||
{
|
||||
repository = new InMemoryClusterRepository();
|
||||
kyvernoInstaller = new Mock<IComponentInstaller>();
|
||||
policiesInstaller = new Mock<IComponentInstaller>();
|
||||
|
||||
kyvernoInstaller.Setup(i => i.ComponentName).Returns("kyverno");
|
||||
policiesInstaller.Setup(i => i.ComponentName).Returns("security-policies");
|
||||
|
||||
List<IComponentInstaller> installers = new() { kyvernoInstaller.Object, policiesInstaller.Object };
|
||||
handler = new DeployComponentHandler(repository, installers, Microsoft.Extensions.Logging.Abstractions.NullLogger<DeployComponentHandler>.Instance);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HandleAsync_ClusterNotFound_ReturnsFailure()
|
||||
{
|
||||
// Arrange
|
||||
|
||||
DeployComponentRequest request = new("kyverno");
|
||||
|
||||
// Act
|
||||
|
||||
Result<InstallResult> result = await handler.HandleAsync(Guid.NewGuid(), request);
|
||||
|
||||
// Assert
|
||||
|
||||
result.IsFailure.Should().BeTrue();
|
||||
result.Error.Should().Contain("not found");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HandleAsync_ClusterNotConnected_ReturnsFailure()
|
||||
{
|
||||
// Arrange — Cluster is Pending, can't deploy to it.
|
||||
|
||||
KubernetesCluster cluster = KubernetesCluster.Register(
|
||||
"pending-cluster", "https://k8s.dev:6443", "kubeconfig-data", Guid.NewGuid(), "ctx", Guid.NewGuid());
|
||||
await repository.AddAsync(cluster);
|
||||
|
||||
DeployComponentRequest request = new("kyverno");
|
||||
|
||||
// Act
|
||||
|
||||
Result<InstallResult> result = await handler.HandleAsync(cluster.Id, request);
|
||||
|
||||
// Assert
|
||||
|
||||
result.IsFailure.Should().BeTrue();
|
||||
result.Error.Should().Contain("connected");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HandleAsync_UnknownComponent_ReturnsFailureWithAvailable()
|
||||
{
|
||||
// Arrange — Requesting a component that has no installer.
|
||||
|
||||
KubernetesCluster cluster = KubernetesCluster.Register(
|
||||
"test-cluster", "https://k8s.test:6443", "kubeconfig-data", Guid.NewGuid(), "ctx", Guid.NewGuid());
|
||||
cluster.MarkConnected();
|
||||
await repository.AddAsync(cluster);
|
||||
|
||||
DeployComponentRequest request = new("nonexistent-thing");
|
||||
|
||||
// Act
|
||||
|
||||
Result<InstallResult> result = await handler.HandleAsync(cluster.Id, request);
|
||||
|
||||
// Assert — Should list available installers.
|
||||
|
||||
result.IsFailure.Should().BeTrue();
|
||||
result.Error.Should().Contain("kyverno");
|
||||
result.Error.Should().Contain("security-policies");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HandleAsync_ValidComponent_DelegatesToInstaller()
|
||||
{
|
||||
// Arrange — Deploy Kyverno on a connected cluster.
|
||||
|
||||
KubernetesCluster cluster = KubernetesCluster.Register(
|
||||
"prod-cluster", "https://k8s.prod:6443", "kubeconfig-data", Guid.NewGuid(), "prod-ctx", Guid.NewGuid());
|
||||
cluster.MarkConnected();
|
||||
await repository.AddAsync(cluster);
|
||||
|
||||
kyvernoInstaller.Setup(i => i.InstallAsync(cluster, It.IsAny<ComponentInstallOptions>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new InstallResult(
|
||||
Success: true,
|
||||
ComponentName: "kyverno",
|
||||
Message: "Kyverno 3.3.4 installed successfully",
|
||||
Actions: new List<string> { "Helm install/upgrade kyverno v3.3.4" }));
|
||||
|
||||
DeployComponentRequest request = new("kyverno", Version: "3.3.4");
|
||||
|
||||
// Act
|
||||
|
||||
Result<InstallResult> result = await handler.HandleAsync(cluster.Id, request);
|
||||
|
||||
// Assert — Should succeed and return installer output.
|
||||
|
||||
result.IsSuccess.Should().BeTrue();
|
||||
result.Value!.Success.Should().BeTrue();
|
||||
result.Value.ComponentName.Should().Be("kyverno");
|
||||
result.Value.Actions.Should().Contain("Helm install/upgrade kyverno v3.3.4");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HandleAsync_InstallerFails_ReturnsFailure()
|
||||
{
|
||||
// Arrange — The installer encounters an error (e.g., helm timeout).
|
||||
|
||||
KubernetesCluster cluster = KubernetesCluster.Register(
|
||||
"flaky-cluster", "https://k8s.flaky:6443", "kubeconfig-data", Guid.NewGuid(), "ctx", Guid.NewGuid());
|
||||
cluster.MarkConnected();
|
||||
await repository.AddAsync(cluster);
|
||||
|
||||
kyvernoInstaller.Setup(i => i.InstallAsync(cluster, It.IsAny<ComponentInstallOptions>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new InstallResult(
|
||||
Success: false,
|
||||
ComponentName: "kyverno",
|
||||
Message: "Helm failed (exit 1): timed out waiting for condition",
|
||||
Actions: new List<string> { "Error: timed out" }));
|
||||
|
||||
DeployComponentRequest request = new("kyverno");
|
||||
|
||||
// Act
|
||||
|
||||
Result<InstallResult> result = await handler.HandleAsync(cluster.Id, request);
|
||||
|
||||
// Assert
|
||||
|
||||
result.IsFailure.Should().BeTrue();
|
||||
result.Error.Should().Contain("timed out");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HandleAsync_PassesOptionsToInstaller()
|
||||
{
|
||||
// Arrange — Deploy security policies with custom parameters.
|
||||
|
||||
KubernetesCluster cluster = KubernetesCluster.Register(
|
||||
"config-cluster", "https://k8s.cfg:6443", "kubeconfig-data", Guid.NewGuid(), "ctx", Guid.NewGuid());
|
||||
cluster.MarkConnected();
|
||||
await repository.AddAsync(cluster);
|
||||
|
||||
ComponentInstallOptions? capturedOptions = null;
|
||||
policiesInstaller.Setup(i => i.InstallAsync(cluster, It.IsAny<ComponentInstallOptions>(), It.IsAny<CancellationToken>()))
|
||||
.Callback<KubernetesCluster, ComponentInstallOptions, CancellationToken>((_, opts, _) => capturedOptions = opts)
|
||||
.ReturnsAsync(new InstallResult(true, "security-policies", "Done", new List<string>()));
|
||||
|
||||
DeployComponentRequest request = new(
|
||||
"security-policies",
|
||||
Parameters: new Dictionary<string, string> { ["validationAction"] = "Enforce" });
|
||||
|
||||
// Act
|
||||
|
||||
await handler.HandleAsync(cluster.Id, request);
|
||||
|
||||
// Assert — The installer received the custom parameters.
|
||||
|
||||
capturedOptions.Should().NotBeNull();
|
||||
capturedOptions!.Parameters.Should().ContainKey("validationAction");
|
||||
capturedOptions.Parameters!["validationAction"].Should().Be("Enforce");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user