too much for one commit
This commit is contained in:
229
tests/EntKube.Provisioning.Tests/Domain/AppTests.cs
Normal file
229
tests/EntKube.Provisioning.Tests/Domain/AppTests.cs
Normal file
@@ -0,0 +1,229 @@
|
||||
using EntKube.Provisioning.Domain;
|
||||
using FluentAssertions;
|
||||
|
||||
namespace EntKube.Provisioning.Tests.Domain;
|
||||
|
||||
public class AppTests
|
||||
{
|
||||
// ─── Create ──────────────────────────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public void Create_WithValidInputs_CreatesActiveApp()
|
||||
{
|
||||
// Arrange — A customer admin creates a new app (e.g. "frontend-portal")
|
||||
// that will eventually be deployed across environments. The app starts
|
||||
// in an Active state and is ready to have environments added.
|
||||
|
||||
Guid tenantId = Guid.NewGuid();
|
||||
Guid customerId = Guid.NewGuid();
|
||||
|
||||
// Act
|
||||
|
||||
App app = App.Create(tenantId, customerId, "Frontend Portal", "frontend-portal", AppType.Deployment);
|
||||
|
||||
// Assert — The app should be active and linked to its customer and tenant.
|
||||
|
||||
app.Id.Should().NotBe(Guid.Empty);
|
||||
app.TenantId.Should().Be(tenantId);
|
||||
app.CustomerId.Should().Be(customerId);
|
||||
app.Name.Should().Be("Frontend Portal");
|
||||
app.Slug.Should().Be("frontend-portal");
|
||||
app.Type.Should().Be(AppType.Deployment);
|
||||
app.Status.Should().Be(AppStatus.Active);
|
||||
app.CreatedAt.Should().BeCloseTo(DateTimeOffset.UtcNow, TimeSpan.FromSeconds(5));
|
||||
app.Environments.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Create_NormalizesSlugToLowerCase()
|
||||
{
|
||||
// Arrange & Act — Slugs should always be lowercase for consistency.
|
||||
|
||||
App app = App.Create(Guid.NewGuid(), Guid.NewGuid(), "My App", "MY-APP", AppType.HelmChart);
|
||||
|
||||
// Assert
|
||||
|
||||
app.Slug.Should().Be("my-app");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Create_WithEmptyTenantId_ThrowsArgumentException()
|
||||
{
|
||||
// Arrange & Act
|
||||
|
||||
Action act = () => App.Create(Guid.Empty, Guid.NewGuid(), "App", "app", AppType.Deployment);
|
||||
|
||||
// Assert
|
||||
|
||||
act.Should().Throw<ArgumentException>()
|
||||
.WithParameterName("tenantId");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Create_WithEmptyCustomerId_ThrowsArgumentException()
|
||||
{
|
||||
// Arrange & Act
|
||||
|
||||
Action act = () => App.Create(Guid.NewGuid(), Guid.Empty, "App", "app", AppType.Deployment);
|
||||
|
||||
// Assert
|
||||
|
||||
act.Should().Throw<ArgumentException>()
|
||||
.WithParameterName("customerId");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Create_WithEmptyName_ThrowsArgumentException()
|
||||
{
|
||||
// Arrange & Act
|
||||
|
||||
Action act = () => App.Create(Guid.NewGuid(), Guid.NewGuid(), "", "app", AppType.Deployment);
|
||||
|
||||
// Assert
|
||||
|
||||
act.Should().Throw<ArgumentException>()
|
||||
.WithParameterName("name");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Create_WithEmptySlug_ThrowsArgumentException()
|
||||
{
|
||||
// Arrange & Act
|
||||
|
||||
Action act = () => App.Create(Guid.NewGuid(), Guid.NewGuid(), "App", "", AppType.Deployment);
|
||||
|
||||
// Assert
|
||||
|
||||
act.Should().Throw<ArgumentException>()
|
||||
.WithParameterName("slug");
|
||||
}
|
||||
|
||||
// ─── Suspend / Activate ──────────────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public void Suspend_SetsStatusToSuspended()
|
||||
{
|
||||
// Arrange — An active app that the admin wants to pause deployments for.
|
||||
|
||||
App app = App.Create(Guid.NewGuid(), Guid.NewGuid(), "App", "app", AppType.Deployment);
|
||||
|
||||
// Act
|
||||
|
||||
app.Suspend();
|
||||
|
||||
// Assert
|
||||
|
||||
app.Status.Should().Be(AppStatus.Suspended);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Activate_SetsStatusToActive()
|
||||
{
|
||||
// Arrange — A previously suspended app being re-enabled.
|
||||
|
||||
App app = App.Create(Guid.NewGuid(), Guid.NewGuid(), "App", "app", AppType.Deployment);
|
||||
app.Suspend();
|
||||
|
||||
// Act
|
||||
|
||||
app.Activate();
|
||||
|
||||
// Assert
|
||||
|
||||
app.Status.Should().Be(AppStatus.Active);
|
||||
}
|
||||
|
||||
// ─── AddEnvironment ──────────────────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public void AddEnvironment_WithValidInputs_CreatesAppEnvironment()
|
||||
{
|
||||
// Arrange — After creating an app, the admin adds it to a specific
|
||||
// environment (e.g. "dev"). This links the app to a cluster and
|
||||
// namespace where it will be deployed.
|
||||
|
||||
App app = App.Create(Guid.NewGuid(), Guid.NewGuid(), "API Service", "api-service", AppType.Deployment);
|
||||
Guid environmentId = Guid.NewGuid();
|
||||
Guid clusterId = Guid.NewGuid();
|
||||
|
||||
// Act
|
||||
|
||||
AppEnvironment env = app.AddEnvironment(environmentId, clusterId, "api-dev");
|
||||
|
||||
// Assert — The environment should be created in Pending state.
|
||||
|
||||
env.Id.Should().NotBe(Guid.Empty);
|
||||
env.EnvironmentId.Should().Be(environmentId);
|
||||
env.ClusterId.Should().Be(clusterId);
|
||||
env.Namespace.Should().Be("api-dev");
|
||||
env.SyncStatus.Should().Be(AppSyncStatus.Pending);
|
||||
app.Environments.Should().HaveCount(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddEnvironment_DuplicateEnvironmentId_ThrowsInvalidOperation()
|
||||
{
|
||||
// Arrange — An app can only be deployed to each environment once.
|
||||
|
||||
App app = App.Create(Guid.NewGuid(), Guid.NewGuid(), "App", "app", AppType.Deployment);
|
||||
Guid environmentId = Guid.NewGuid();
|
||||
app.AddEnvironment(environmentId, Guid.NewGuid(), "app-dev");
|
||||
|
||||
// Act
|
||||
|
||||
Action act = () => app.AddEnvironment(environmentId, Guid.NewGuid(), "app-dev-2");
|
||||
|
||||
// Assert
|
||||
|
||||
act.Should().Throw<InvalidOperationException>()
|
||||
.WithMessage("*already*");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddEnvironment_WithEmptyNamespace_ThrowsArgumentException()
|
||||
{
|
||||
// Arrange & Act
|
||||
|
||||
App app = App.Create(Guid.NewGuid(), Guid.NewGuid(), "App", "app", AppType.Deployment);
|
||||
Action act = () => app.AddEnvironment(Guid.NewGuid(), Guid.NewGuid(), "");
|
||||
|
||||
// Assert
|
||||
|
||||
act.Should().Throw<ArgumentException>()
|
||||
.WithParameterName("ns");
|
||||
}
|
||||
|
||||
// ─── RemoveEnvironment ───────────────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public void RemoveEnvironment_ExistingEnvironment_RemovesIt()
|
||||
{
|
||||
// Arrange — An app deployed to dev that the admin wants to remove.
|
||||
|
||||
App app = App.Create(Guid.NewGuid(), Guid.NewGuid(), "App", "app", AppType.Deployment);
|
||||
Guid environmentId = Guid.NewGuid();
|
||||
app.AddEnvironment(environmentId, Guid.NewGuid(), "app-dev");
|
||||
|
||||
// Act
|
||||
|
||||
app.RemoveEnvironment(environmentId);
|
||||
|
||||
// Assert
|
||||
|
||||
app.Environments.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveEnvironment_NonExistent_ThrowsInvalidOperation()
|
||||
{
|
||||
// Arrange & Act
|
||||
|
||||
App app = App.Create(Guid.NewGuid(), Guid.NewGuid(), "App", "app", AppType.Deployment);
|
||||
Action act = () => app.RemoveEnvironment(Guid.NewGuid());
|
||||
|
||||
// Assert
|
||||
|
||||
act.Should().Throw<InvalidOperationException>()
|
||||
.WithMessage("*not found*");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user