using EntKube.Provisioning.Domain; using FluentAssertions; namespace EntKube.Provisioning.Tests.Domain; public class ServiceInstanceTests { [Fact] public void Provision_WithValidInputs_CreatesInstanceInPendingState() { // Arrange & Act — Request provisioning of a MinIO instance. Guid clusterId = Guid.NewGuid(); ServiceInstance instance = ServiceInstance.Provision( clusterId, ServiceType.MinIO, "tenant-storage", "minio-system"); // Assert — Starts pending until the reconciler deploys it. instance.Id.Should().NotBe(Guid.Empty); instance.ClusterId.Should().Be(clusterId); instance.ServiceType.Should().Be(ServiceType.MinIO); instance.Name.Should().Be("tenant-storage"); instance.Namespace.Should().Be("minio-system"); instance.DesiredState.Should().Be(ServiceState.Running); instance.CurrentState.Should().Be(ServiceState.Pending); } [Fact] public void Provision_WithEmptyName_ThrowsArgumentException() { // Arrange & Act Action act = () => ServiceInstance.Provision(Guid.NewGuid(), ServiceType.MinIO, "", "ns"); // Assert act.Should().Throw() .WithParameterName("name"); } [Fact] public void MarkRunning_UpdatesCurrentState() { // Arrange ServiceInstance instance = ServiceInstance.Provision(Guid.NewGuid(), ServiceType.CloudNativePG, "db", "cnpg-system"); // Act instance.MarkRunning(); // Assert instance.CurrentState.Should().Be(ServiceState.Running); instance.LastReconcileAt.Should().NotBeNull(); } [Fact] public void RequestDecommission_SetsDesiredStateToDecommissioned() { // Arrange ServiceInstance instance = ServiceInstance.Provision(Guid.NewGuid(), ServiceType.Keycloak, "auth", "keycloak-system"); instance.MarkRunning(); // Act — Tenant admin decides to tear down this service. instance.RequestDecommission(); // Assert — Desired state changes but current state remains until reconciler acts. instance.DesiredState.Should().Be(ServiceState.Decommissioned); instance.CurrentState.Should().Be(ServiceState.Running); } }