too much for one commit
This commit is contained in:
275
tests/EntKube.Provisioning.Tests/Domain/PrometheusStackTests.cs
Normal file
275
tests/EntKube.Provisioning.Tests/Domain/PrometheusStackTests.cs
Normal file
@@ -0,0 +1,275 @@
|
||||
using EntKube.Provisioning.Domain;
|
||||
using FluentAssertions;
|
||||
|
||||
namespace EntKube.Provisioning.Tests.Domain;
|
||||
|
||||
public class PrometheusStackTests
|
||||
{
|
||||
private readonly Guid clusterId = Guid.NewGuid();
|
||||
private readonly Guid environmentId = Guid.NewGuid();
|
||||
|
||||
// ─── Creation ───────────────────────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public void Create_WithValidInputs_CreatesStackInPendingState()
|
||||
{
|
||||
// Arrange & Act — An operator provisions a new Prometheus stack on a cluster.
|
||||
// Prometheus is per-cluster: each cluster gets its own metrics collector.
|
||||
|
||||
PrometheusStack stack = PrometheusStack.Create(clusterId, environmentId, "prod-prometheus", "monitoring");
|
||||
|
||||
// Assert — The stack should be in a Pending state, with sensible defaults
|
||||
// for Prometheus retention, replicas, and Alertmanager.
|
||||
|
||||
stack.Id.Should().NotBe(Guid.Empty);
|
||||
stack.ClusterId.Should().Be(clusterId);
|
||||
stack.EnvironmentId.Should().Be(environmentId);
|
||||
stack.Name.Should().Be("prod-prometheus");
|
||||
stack.Namespace.Should().Be("monitoring");
|
||||
stack.Status.Should().Be(PrometheusStackStatus.Pending);
|
||||
stack.CreatedAt.Should().BeCloseTo(DateTimeOffset.UtcNow, TimeSpan.FromSeconds(5));
|
||||
|
||||
// Prometheus defaults
|
||||
|
||||
stack.Prometheus.Should().NotBeNull();
|
||||
stack.Prometheus.Retention.Should().Be("30d");
|
||||
stack.Prometheus.Replicas.Should().Be(2);
|
||||
stack.Prometheus.StorageSize.Should().Be("50Gi");
|
||||
|
||||
// Alertmanager defaults
|
||||
|
||||
stack.Alertmanager.Should().NotBeNull();
|
||||
stack.Alertmanager.Enabled.Should().BeTrue();
|
||||
stack.Alertmanager.Replicas.Should().Be(2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Create_WithEmptyName_ThrowsArgumentException()
|
||||
{
|
||||
// Arrange & Act — A Prometheus stack must have a name.
|
||||
|
||||
Action act = () => PrometheusStack.Create(clusterId, environmentId, "", "monitoring");
|
||||
|
||||
// Assert
|
||||
|
||||
act.Should().Throw<ArgumentException>()
|
||||
.WithParameterName("name");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Create_WithEmptyNamespace_ThrowsArgumentException()
|
||||
{
|
||||
// Arrange & Act — A Prometheus stack must have a namespace.
|
||||
|
||||
Action act = () => PrometheusStack.Create(clusterId, environmentId, "prod-prometheus", "");
|
||||
|
||||
// Assert
|
||||
|
||||
act.Should().Throw<ArgumentException>()
|
||||
.WithParameterName("ns");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Create_WithEmptyClusterId_ThrowsArgumentException()
|
||||
{
|
||||
// Arrange & Act — A Prometheus stack must belong to a cluster.
|
||||
|
||||
Action act = () => PrometheusStack.Create(Guid.Empty, environmentId, "prod-prometheus", "monitoring");
|
||||
|
||||
// Assert
|
||||
|
||||
act.Should().Throw<ArgumentException>()
|
||||
.WithParameterName("clusterId");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Create_WithEmptyEnvironmentId_ThrowsArgumentException()
|
||||
{
|
||||
// Arrange & Act — A Prometheus stack must belong to an environment.
|
||||
|
||||
Action act = () => PrometheusStack.Create(clusterId, Guid.Empty, "prod-prometheus", "monitoring");
|
||||
|
||||
// Assert
|
||||
|
||||
act.Should().Throw<ArgumentException>()
|
||||
.WithParameterName("environmentId");
|
||||
}
|
||||
|
||||
// ─── Prometheus Configuration ─────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public void ConfigurePrometheus_UpdatesRetentionAndReplicas()
|
||||
{
|
||||
// Arrange — Start with a Prometheus stack using defaults.
|
||||
|
||||
PrometheusStack stack = PrometheusStack.Create(clusterId, environmentId, "prod-prometheus", "monitoring");
|
||||
|
||||
// Act — The operator increases retention to 90 days and scales to 3 replicas.
|
||||
|
||||
stack.ConfigurePrometheus(retention: "90d", replicas: 3, storageSize: "100Gi", retentionSize: "90GB");
|
||||
|
||||
// Assert — Prometheus settings should reflect the new configuration.
|
||||
|
||||
stack.Prometheus.Retention.Should().Be("90d");
|
||||
stack.Prometheus.Replicas.Should().Be(3);
|
||||
stack.Prometheus.StorageSize.Should().Be("100Gi");
|
||||
stack.Prometheus.RetentionSize.Should().Be("90GB");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConfigurePrometheus_WithInvalidReplicas_ThrowsArgumentException()
|
||||
{
|
||||
// Arrange
|
||||
|
||||
PrometheusStack stack = PrometheusStack.Create(clusterId, environmentId, "prod-prometheus", "monitoring");
|
||||
|
||||
// Act & Assert — Zero replicas doesn't make sense for Prometheus.
|
||||
|
||||
Action act = () => stack.ConfigurePrometheus(replicas: 0);
|
||||
|
||||
act.Should().Throw<ArgumentException>()
|
||||
.WithParameterName("replicas");
|
||||
}
|
||||
|
||||
// ─── Alertmanager Configuration ─────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public void ConfigureAlertmanager_UpdatesReplicasAndEnablement()
|
||||
{
|
||||
// Arrange
|
||||
|
||||
PrometheusStack stack = PrometheusStack.Create(clusterId, environmentId, "prod-prometheus", "monitoring");
|
||||
|
||||
// Act — The operator disables Alertmanager for a dev cluster.
|
||||
|
||||
stack.ConfigureAlertmanager(enabled: false, replicas: 1);
|
||||
|
||||
// Assert
|
||||
|
||||
stack.Alertmanager.Enabled.Should().BeFalse();
|
||||
stack.Alertmanager.Replicas.Should().Be(1);
|
||||
}
|
||||
|
||||
// ─── Ingress (Prometheus + Alertmanager) ────────────────────────
|
||||
|
||||
[Fact]
|
||||
public void ConfigureIngress_SetsPrometheusAndAlertmanagerRouting()
|
||||
{
|
||||
// Arrange — Publish Prometheus and Alertmanager via Gateway API.
|
||||
|
||||
PrometheusStack stack = PrometheusStack.Create(clusterId, environmentId, "prod-prometheus", "monitoring");
|
||||
|
||||
// Act
|
||||
|
||||
IngressConfiguration ingress = new(
|
||||
Enabled: true,
|
||||
Provider: IngressProvider.GatewayApi,
|
||||
PrometheusHostname: "prometheus.prod01.example.com",
|
||||
AlertmanagerHostname: "alertmanager.prod01.example.com",
|
||||
TlsEnabled: true,
|
||||
TlsCertificateMode: TlsCertificateMode.Manual,
|
||||
TlsSecretName: "monitoring-tls");
|
||||
|
||||
stack.ConfigureIngress(ingress);
|
||||
|
||||
// Assert
|
||||
|
||||
stack.Ingress.Should().NotBeNull();
|
||||
stack.Ingress!.Enabled.Should().BeTrue();
|
||||
stack.Ingress.Provider.Should().Be(IngressProvider.GatewayApi);
|
||||
stack.Ingress.PrometheusHostname.Should().Be("prometheus.prod01.example.com");
|
||||
stack.Ingress.AlertmanagerHostname.Should().Be("alertmanager.prod01.example.com");
|
||||
stack.Ingress.TlsEnabled.Should().BeTrue();
|
||||
stack.Ingress.TlsCertificateMode.Should().Be(TlsCertificateMode.Manual);
|
||||
stack.Ingress.TlsSecretName.Should().Be("monitoring-tls");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConfigureIngress_WithCertManager_DoesNotRequireSecretName()
|
||||
{
|
||||
// Arrange
|
||||
|
||||
PrometheusStack stack = PrometheusStack.Create(clusterId, environmentId, "prod-prometheus", "monitoring");
|
||||
|
||||
// Act — cert-manager with Let's Encrypt handles certificates automatically.
|
||||
|
||||
IngressConfiguration ingress = new(
|
||||
Enabled: true,
|
||||
Provider: IngressProvider.GatewayApi,
|
||||
PrometheusHostname: "prometheus.example.com",
|
||||
AlertmanagerHostname: "alertmanager.example.com",
|
||||
TlsEnabled: true,
|
||||
TlsCertificateMode: TlsCertificateMode.CertManager,
|
||||
TlsSecretName: null,
|
||||
ClusterIssuer: "letsencrypt-prod");
|
||||
|
||||
stack.ConfigureIngress(ingress);
|
||||
|
||||
// Assert
|
||||
|
||||
stack.Ingress!.TlsCertificateMode.Should().Be(TlsCertificateMode.CertManager);
|
||||
stack.Ingress.TlsSecretName.Should().BeNull();
|
||||
stack.Ingress.ClusterIssuer.Should().Be("letsencrypt-prod");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DisableIngress_ClearsIngressConfig()
|
||||
{
|
||||
// Arrange
|
||||
|
||||
PrometheusStack stack = PrometheusStack.Create(clusterId, environmentId, "prod-prometheus", "monitoring");
|
||||
|
||||
IngressConfiguration ingress = new(
|
||||
Enabled: true,
|
||||
Provider: IngressProvider.GatewayApi,
|
||||
PrometheusHostname: "prometheus.example.com",
|
||||
AlertmanagerHostname: null,
|
||||
TlsEnabled: true,
|
||||
TlsCertificateMode: TlsCertificateMode.Manual,
|
||||
TlsSecretName: "tls-secret");
|
||||
|
||||
stack.ConfigureIngress(ingress);
|
||||
|
||||
// Act
|
||||
|
||||
stack.DisableIngress();
|
||||
|
||||
// Assert
|
||||
|
||||
stack.Ingress.Should().BeNull();
|
||||
}
|
||||
|
||||
// ─── Lifecycle ──────────────────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public void MarkRunning_SetsStatusToRunning()
|
||||
{
|
||||
// Arrange
|
||||
|
||||
PrometheusStack stack = PrometheusStack.Create(clusterId, environmentId, "prod-prometheus", "monitoring");
|
||||
|
||||
// Act
|
||||
|
||||
stack.MarkRunning();
|
||||
|
||||
// Assert
|
||||
|
||||
stack.Status.Should().Be(PrometheusStackStatus.Running);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MarkDegraded_SetsStatusToDegraded()
|
||||
{
|
||||
// Arrange
|
||||
|
||||
PrometheusStack stack = PrometheusStack.Create(clusterId, environmentId, "prod-prometheus", "monitoring");
|
||||
|
||||
// Act
|
||||
|
||||
stack.MarkDegraded();
|
||||
|
||||
// Assert
|
||||
|
||||
stack.Status.Should().Be(PrometheusStackStatus.Degraded);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user