using ColaFlow.Modules.Identity.Domain.Aggregates.Tenants; using ColaFlow.Modules.Identity.Domain.Aggregates.Tenants.Events; using FluentAssertions; using Xunit; namespace ColaFlow.Modules.Identity.Domain.Tests.Aggregates; public sealed class TenantTests { [Fact] public void Create_ShouldSucceed() { // Arrange var name = TenantName.Create("Acme Corporation"); var slug = TenantSlug.Create("acme"); // Act var tenant = Tenant.Create(name, slug); // Assert tenant.Should().NotBeNull(); tenant.Id.Should().NotBe(Guid.Empty); tenant.Name.Value.Should().Be("Acme Corporation"); tenant.Slug.Value.Should().Be("acme"); tenant.Status.Should().Be(TenantStatus.Active); tenant.Plan.Should().Be(SubscriptionPlan.Free); tenant.CreatedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(1)); } [Fact] public void Create_ShouldRaiseTenantCreatedEvent() { // Arrange var name = TenantName.Create("Acme Corporation"); var slug = TenantSlug.Create("acme"); // Act var tenant = Tenant.Create(name, slug); // Assert tenant.DomainEvents.Should().ContainSingle(); tenant.DomainEvents.Should().ContainItemsAssignableTo(); var domainEvent = tenant.DomainEvents.First() as TenantCreatedEvent; domainEvent.Should().NotBeNull(); domainEvent!.TenantId.Should().Be(tenant.Id); domainEvent.Slug.Should().Be("acme"); } [Fact] public void Activate_ShouldChangeStatus() { // Arrange var tenant = Tenant.Create(TenantName.Create("Test"), TenantSlug.Create("test")); tenant.Suspend("Payment failed"); tenant.ClearDomainEvents(); // Act tenant.Activate(); // Assert tenant.Status.Should().Be(TenantStatus.Active); tenant.SuspendedAt.Should().BeNull(); tenant.SuspensionReason.Should().BeNull(); tenant.DomainEvents.Should().ContainSingle(); tenant.DomainEvents.Should().ContainItemsAssignableTo(); } [Fact] public void Suspend_ShouldChangeStatus() { // Arrange var tenant = Tenant.Create(TenantName.Create("Test"), TenantSlug.Create("test")); tenant.ClearDomainEvents(); // Act tenant.Suspend("Payment failed"); // Assert tenant.Status.Should().Be(TenantStatus.Suspended); tenant.SuspendedAt.Should().NotBeNull(); tenant.SuspendedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(1)); tenant.SuspensionReason.Should().Be("Payment failed"); tenant.DomainEvents.Should().ContainSingle(); tenant.DomainEvents.Should().ContainItemsAssignableTo(); } [Fact] public void Cancel_ShouldChangeStatus() { // Arrange var tenant = Tenant.Create(TenantName.Create("Test"), TenantSlug.Create("test")); tenant.ClearDomainEvents(); // Act tenant.Cancel(); // Assert tenant.Status.Should().Be(TenantStatus.Cancelled); tenant.DomainEvents.Should().ContainSingle(); tenant.DomainEvents.Should().ContainItemsAssignableTo(); } [Fact] public void CancelledTenant_CannotBeActivated() { // Arrange var tenant = Tenant.Create(TenantName.Create("Test"), TenantSlug.Create("test")); tenant.Cancel(); // Act & Assert var act = () => tenant.Activate(); act.Should().Throw() .WithMessage("Cannot activate cancelled tenant"); } [Fact] public void ConfigureSso_ShouldSucceed_ForProfessionalPlan() { // Arrange var tenant = Tenant.Create(TenantName.Create("Test"), TenantSlug.Create("test")); tenant.UpgradePlan(SubscriptionPlan.Professional); tenant.ClearDomainEvents(); var ssoConfig = SsoConfiguration.CreateOidc( SsoProvider.AzureAD, "https://login.microsoftonline.com/tenant-id", "client-id", "client-secret"); // Act tenant.ConfigureSso(ssoConfig); // Assert tenant.SsoConfig.Should().NotBeNull(); tenant.SsoConfig!.Provider.Should().Be(SsoProvider.AzureAD); tenant.DomainEvents.Should().ContainSingle(); tenant.DomainEvents.Should().ContainItemsAssignableTo(); } [Fact] public void ConfigureSso_ShouldThrow_ForFreePlan() { // Arrange var tenant = Tenant.Create(TenantName.Create("Test"), TenantSlug.Create("test")); var ssoConfig = SsoConfiguration.CreateOidc( SsoProvider.AzureAD, "https://login.microsoftonline.com/tenant-id", "client-id", "client-secret"); // Act & Assert var act = () => tenant.ConfigureSso(ssoConfig); act.Should().Throw() .WithMessage("SSO is only available for Professional and Enterprise plans"); } [Fact] public void UpgradePlan_ShouldIncreaseResourceLimits() { // Arrange var tenant = Tenant.Create(TenantName.Create("Test"), TenantSlug.Create("test")); tenant.ClearDomainEvents(); // Act tenant.UpgradePlan(SubscriptionPlan.Professional); // Assert tenant.Plan.Should().Be(SubscriptionPlan.Professional); tenant.MaxUsers.Should().Be(100); tenant.MaxProjects.Should().Be(100); tenant.MaxStorageGB.Should().Be(100); tenant.DomainEvents.Should().ContainSingle(); tenant.DomainEvents.Should().ContainItemsAssignableTo(); } [Fact] public void UpgradePlan_ShouldThrow_WhenDowngrading() { // Arrange var tenant = Tenant.Create(TenantName.Create("Test"), TenantSlug.Create("test"), SubscriptionPlan.Professional); // Act & Assert var act = () => tenant.UpgradePlan(SubscriptionPlan.Free); act.Should().Throw() .WithMessage("New plan must be higher than current plan"); } [Fact] public void DisableSso_ShouldSucceed() { // Arrange var tenant = Tenant.Create(TenantName.Create("Test"), TenantSlug.Create("test")); tenant.UpgradePlan(SubscriptionPlan.Enterprise); var ssoConfig = SsoConfiguration.CreateOidc( SsoProvider.Google, "https://accounts.google.com", "client-id", "client-secret"); tenant.ConfigureSso(ssoConfig); tenant.ClearDomainEvents(); // Act tenant.DisableSso(); // Assert tenant.SsoConfig.Should().BeNull(); tenant.DomainEvents.Should().ContainSingle(); tenant.DomainEvents.Should().ContainItemsAssignableTo(); } }