too much for one commit
This commit is contained in:
180
tests/EntKube.Provisioning.Tests/Domain/AppEnvironmentTests.cs
Normal file
180
tests/EntKube.Provisioning.Tests/Domain/AppEnvironmentTests.cs
Normal 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");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user