too much for one commit

This commit is contained in:
Nils Blomgren
2026-05-13 14:01:32 +02:00
parent a96dd33039
commit 328d494530
394 changed files with 98104 additions and 78 deletions

View File

@@ -0,0 +1,180 @@
using EntKube.Provisioning.Domain;
using FluentAssertions;
namespace EntKube.Provisioning.Tests.Domain;
public class AppEnvironmentTests
{
// ─── ConfigureDeployment ─────────────────────────────────────────────
[Fact]
public void ConfigureDeployment_WithValidSpec_SetsDeploymentSpec()
{
// Arrange — After adding an environment, the admin configures
// the deployment details: which container image, how many replicas,
// port mappings, and routing. This is the equivalent of writing
// deployment.yaml + service.yaml + httproute.yaml by hand.
App app = App.Create(Guid.NewGuid(), Guid.NewGuid(), "API", "api", AppType.Deployment);
AppEnvironment env = app.AddEnvironment(Guid.NewGuid(), Guid.NewGuid(), "api-dev");
DeploymentSpec spec = new(
Image: "registry.example.com/api",
Tag: "v1.2.3",
Replicas: 2,
ContainerPort: 8080,
ServicePort: 80,
HostName: "api.dev.example.com",
PathPrefix: "/",
EnvironmentVariables: new Dictionary<string, string> { ["ASPNETCORE_ENVIRONMENT"] = "Development" },
Resources: new ResourceSpec("100m", "500m", "128Mi", "512Mi"));
// Act
env.ConfigureDeployment(spec);
// Assert
env.DeploymentSpec.Should().NotBeNull();
env.DeploymentSpec!.Image.Should().Be("registry.example.com/api");
env.DeploymentSpec.Tag.Should().Be("v1.2.3");
env.DeploymentSpec.Replicas.Should().Be(2);
env.DeploymentSpec.ContainerPort.Should().Be(8080);
env.DeploymentSpec.ServicePort.Should().Be(80);
env.DeploymentSpec.HostName.Should().Be("api.dev.example.com");
env.DeploymentSpec.Resources.Should().NotBeNull();
env.SyncStatus.Should().Be(AppSyncStatus.Pending, "changing config resets sync to pending");
}
// ─── ConfigureHelmRelease ────────────────────────────────────────────
[Fact]
public void ConfigureHelmRelease_WithValidSpec_SetsHelmSpec()
{
// Arrange — For a Helm-type app, the admin points to a Helm chart
// repository, selects the chart and version, and provides a values.yaml.
// This is the equivalent of `helm install` with custom values.
App app = App.Create(Guid.NewGuid(), Guid.NewGuid(), "Redis", "redis", AppType.HelmChart);
AppEnvironment env = app.AddEnvironment(Guid.NewGuid(), Guid.NewGuid(), "redis-dev");
HelmReleaseSpec spec = new(
RepoUrl: "https://charts.bitnami.com/bitnami",
ChartName: "redis",
ChartVersion: "18.6.1",
ValuesYaml: "replica:\n replicaCount: 3");
// Act
env.ConfigureHelmRelease(spec);
// Assert
env.HelmReleaseSpec.Should().NotBeNull();
env.HelmReleaseSpec!.RepoUrl.Should().Be("https://charts.bitnami.com/bitnami");
env.HelmReleaseSpec.ChartName.Should().Be("redis");
env.HelmReleaseSpec.ChartVersion.Should().Be("18.6.1");
env.HelmReleaseSpec.ValuesYaml.Should().Contain("replicaCount: 3");
env.SyncStatus.Should().Be(AppSyncStatus.Pending);
}
// ─── Secrets ─────────────────────────────────────────────────────────
[Fact]
public void AddSecret_WithValidInputs_AddsSecretReference()
{
// Arrange — Secrets for an app environment are stored in the vault.
// Here we add a reference that maps a Kubernetes secret key name
// to the vault path where the actual secret value lives.
App app = App.Create(Guid.NewGuid(), Guid.NewGuid(), "API", "api", AppType.Deployment);
AppEnvironment env = app.AddEnvironment(Guid.NewGuid(), Guid.NewGuid(), "api-dev");
// Act
env.AddSecret("DATABASE_URL", "database-connection-string");
// Assert
env.Secrets.Should().HaveCount(1);
env.Secrets[0].Name.Should().Be("DATABASE_URL");
env.Secrets[0].VaultKey.Should().Be("database-connection-string");
env.SyncStatus.Should().Be(AppSyncStatus.Pending, "adding a secret resets sync");
}
[Fact]
public void AddSecret_DuplicateName_ThrowsInvalidOperation()
{
// Arrange — Each secret name must be unique within an environment.
App app = App.Create(Guid.NewGuid(), Guid.NewGuid(), "API", "api", AppType.Deployment);
AppEnvironment env = app.AddEnvironment(Guid.NewGuid(), Guid.NewGuid(), "api-dev");
env.AddSecret("DATABASE_URL", "db-conn-string");
// Act
Action act = () => env.AddSecret("DATABASE_URL", "another-path");
// Assert
act.Should().Throw<InvalidOperationException>()
.WithMessage("*already exists*");
}
[Fact]
public void RemoveSecret_ExistingSecret_RemovesIt()
{
// Arrange
App app = App.Create(Guid.NewGuid(), Guid.NewGuid(), "API", "api", AppType.Deployment);
AppEnvironment env = app.AddEnvironment(Guid.NewGuid(), Guid.NewGuid(), "api-dev");
env.AddSecret("DATABASE_URL", "db-conn-string");
// Act
env.RemoveSecret("DATABASE_URL");
// Assert
env.Secrets.Should().BeEmpty();
env.SyncStatus.Should().Be(AppSyncStatus.Pending);
}
// ─── Sync Status ─────────────────────────────────────────────────────
[Fact]
public void MarkSynced_UpdatesSyncStatus()
{
// Arrange — The reconciler successfully deployed the app.
App app = App.Create(Guid.NewGuid(), Guid.NewGuid(), "API", "api", AppType.Deployment);
AppEnvironment env = app.AddEnvironment(Guid.NewGuid(), Guid.NewGuid(), "api-dev");
// Act
env.MarkSynced();
// Assert
env.SyncStatus.Should().Be(AppSyncStatus.Synced);
env.LastSyncAt.Should().NotBeNull();
}
[Fact]
public void MarkError_SetsSyncStatusAndMessage()
{
// Arrange — Something went wrong during deployment.
App app = App.Create(Guid.NewGuid(), Guid.NewGuid(), "API", "api", AppType.Deployment);
AppEnvironment env = app.AddEnvironment(Guid.NewGuid(), Guid.NewGuid(), "api-dev");
// Act
env.MarkError("ImagePullBackOff: registry.example.com/api:v1.2.3");
// Assert
env.SyncStatus.Should().Be(AppSyncStatus.Error);
env.SyncStatusMessage.Should().Contain("ImagePullBackOff");
}
}