Files
ColaFlow/colaflow-api/tests/Modules/Identity/ColaFlow.Modules.Identity.Domain.Tests/Aggregates/TenantTests.cs
Yaojia Wang 1f66b25f30
Some checks failed
Code Coverage / Generate Coverage Report (push) Has been cancelled
Tests / Run Tests (9.0.x) (push) Has been cancelled
Tests / Docker Build Test (push) Has been cancelled
Tests / Test Summary (push) Has been cancelled
In progress
2025-11-03 14:00:24 +01:00

211 lines
6.8 KiB
C#

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<TenantCreatedEvent>();
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<TenantActivatedEvent>();
}
[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<TenantSuspendedEvent>();
}
[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<TenantCancelledEvent>();
}
[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<InvalidOperationException>()
.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<SsoConfiguredEvent>();
}
[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<InvalidOperationException>()
.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<TenantPlanUpgradedEvent>();
}
[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<InvalidOperationException>()
.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<SsoDisabledEvent>();
}
}