Source code for src.testing.helpers
"""Test helper functions for creating and destroying test tenants and users.
These are standalone functions (not fixtures) that can be called from
fixtures, factory functions, or test setup code.
Usage::
from src.testing.helpers import create_test_tenant, create_test_user
tenant = create_test_tenant("acme")
user = create_test_user("dev@acme.com")
"""
from __future__ import annotations
import logging
from typing import Any
logger = logging.getLogger(__name__)
[docs]
def create_test_tenant(slug: str = "test-tenant", name: str | None = None) -> Any:
"""Create a test tenant with its storage provisioned.
If a tenant with the given slug already exists, it is reused.
Args:
slug: Tenant slug (must be unique).
name: Tenant display name (defaults to title-cased slug).
Returns:
The created or existing Tenant instance.
"""
from src.module.tenant.models import Tenant
from src.share_kernel.infrastructure.isolation import get_isolation_backend
tenant, created = Tenant.objects.get_or_create(
slug=slug,
defaults={
"name": name or slug.replace("-", " ").title(),
},
)
if created:
backend = get_isolation_backend()
backend.create_tenant_storage(tenant)
logger.info("Created test tenant: %s", slug)
else:
logger.info("Reusing existing test tenant: %s", slug)
return tenant
[docs]
def drop_test_tenant(tenant: Any) -> None:
"""Destroy a test tenant and its storage.
Args:
tenant: The Tenant instance to destroy.
"""
from src.share_kernel.infrastructure.isolation import get_isolation_backend
try:
backend = get_isolation_backend()
backend.destroy_tenant_storage(tenant)
tenant.delete()
logger.info("Dropped test tenant: %s", tenant.slug)
except Exception:
logger.exception("Failed to drop test tenant: %s", tenant.slug)
[docs]
def create_test_user(
email: str = "test@example.com",
password: str = "testpass123",
**kwargs: Any,
) -> Any:
"""Create a test user.
If a user with the given email already exists, it is reused.
Args:
email: User email.
password: User password.
**kwargs: Additional user fields (first_name, last_name, etc.).
Returns:
The created or existing User instance.
"""
from django.contrib.auth import get_user_model
User = get_user_model() # noqa: N806
user, created = User.objects.get_or_create(
email=email,
defaults=kwargs,
)
if created:
user.set_password(password)
user.save()
return user
[docs]
def create_test_membership(
user: Any,
tenant: Any,
roles: list[str] | None = None,
abac_attributes: dict[str, Any] | None = None,
) -> Any:
"""Create a TenantMembership for testing.
Args:
user: The User instance.
tenant: The Tenant instance.
roles: List of role names (default: empty list).
abac_attributes: ABAC attributes dict (default: empty dict).
Returns:
The created TenantMembership instance.
"""
from src.module.tenant.models import TenantMembership
return TenantMembership.objects.create(
user=user,
tenant=tenant,
roles=roles or [],
abac_attributes=abac_attributes or {},
status="active",
)