tenant-engine/tests/test_lifecycle_domain.py

89 lines
2.7 KiB
Python
Raw Normal View History

from datetime import UTC, datetime
import pytest
from tenant_engine.domain import (
EmptyUpdateError,
ImmutableFieldError,
InvalidLifecycleTransitionError,
Tenant,
TenantLifecycle,
)
NOW = datetime(2026, 8, 10, 12, 0, tzinfo=UTC)
def _tenant() -> Tenant:
return Tenant.create(
tenant_id="t-1", identifier="tenant:friendly:binky", display_name="Binky", created_at=NOW
)
def test_new_tenant_is_active_at_version_one() -> None:
tenant = _tenant()
assert tenant.lifecycle is TenantLifecycle.ACTIVE
assert tenant.version == 1
assert tenant.is_active
def test_metadata_update_bumps_version_and_keeps_identity() -> None:
tenant = _tenant().with_metadata({"display_name": "Binky Ltd"}, at=NOW)
assert tenant.display_name == "Binky Ltd"
assert tenant.version == 2
assert tenant.updated_at == NOW
assert tenant.tenant_id == "t-1"
assert tenant.identifier == "tenant:friendly:binky"
assert tenant.grouping == "friendly"
def test_update_rejects_identifier_mutation() -> None:
with pytest.raises(ImmutableFieldError):
_tenant().with_metadata({"identifier": "tenant:large:other"}, at=NOW)
def test_update_rejects_unknown_field() -> None:
with pytest.raises(ImmutableFieldError):
_tenant().with_metadata({"nickname": "binks"}, at=NOW)
def test_update_rejects_empty_change_set() -> None:
with pytest.raises(EmptyUpdateError):
_tenant().with_metadata({}, at=NOW)
def test_update_rejects_no_op_change() -> None:
with pytest.raises(EmptyUpdateError):
_tenant().with_metadata({"display_name": "Binky"}, at=NOW)
def test_retire_is_reversible_and_preserves_identity() -> None:
retired = _tenant().retire(at=NOW)
assert retired.lifecycle is TenantLifecycle.RETIRED
assert retired.retired_at == NOW
assert retired.version == 2
assert retired.identifier == "tenant:friendly:binky"
reactivated = retired.reactivate(at=NOW)
assert reactivated.lifecycle is TenantLifecycle.ACTIVE
assert reactivated.reactivated_at == NOW
assert reactivated.retired_at == NOW # retirement history is not erased
assert reactivated.version == 3
def test_double_retirement_is_an_invalid_transition() -> None:
retired = _tenant().retire(at=NOW)
with pytest.raises(InvalidLifecycleTransitionError):
retired.retire(at=NOW)
def test_reactivating_an_active_tenant_is_an_invalid_transition() -> None:
with pytest.raises(InvalidLifecycleTransitionError):
_tenant().reactivate(at=NOW)
def test_metadata_update_denied_while_retired() -> None:
retired = _tenant().retire(at=NOW)
with pytest.raises(InvalidLifecycleTransitionError):
retired.with_metadata({"display_name": "Binky Ltd"}, at=NOW)