Files
gh-christianlouis-dmarq/backend/app/tests/test_workspaces.py
T
2026-05-23 19:05:55 +02:00

108 lines
4.1 KiB
Python

from fastapi.testclient import TestClient
from sqlalchemy.orm import Session
from app.models.domain import Domain
from app.models.mail_source import MailSource
from app.models.user import User
from app.models.workspace import Workspace
from app.services.workspaces import (
DEFAULT_WORKSPACE_SLUG,
assign_default_workspace_to_unscoped_rows,
get_or_create_default_workspace,
normalize_workspace_slug,
resolve_workspace,
workspace_domain_query,
workspace_mail_source_query,
workspace_user_query,
)
def test_default_workspace_claims_legacy_rows(db_session: Session):
"""Existing single-tenant rows are attached to the default workspace."""
domain = Domain(name="legacy.example", active=True)
source = MailSource(name="Legacy inbox", method="IMAP", enabled=True)
user = User(email="operator@example.com")
db_session.add_all([domain, source, user])
db_session.commit()
workspace = assign_default_workspace_to_unscoped_rows(db_session)
db_session.refresh(domain)
db_session.refresh(source)
db_session.refresh(user)
assert workspace.slug == DEFAULT_WORKSPACE_SLUG
assert domain.workspace_id == workspace.id
assert source.workspace_id == workspace.id
assert user.workspace_id == workspace.id
def test_workspace_scoped_queries_exclude_other_tenants(db_session: Session):
"""Default scoped queries only return rows owned by that workspace."""
default = get_or_create_default_workspace(db_session)
other = Workspace(slug="client-two", name="Client Two", active=True)
db_session.add(other)
db_session.flush()
db_session.add_all(
[
Domain(name="default.example", workspace_id=default.id, active=True),
Domain(name="client-two.example", workspace_id=other.id, active=True),
MailSource(name="default inbox", method="IMAP", workspace_id=default.id),
MailSource(name="client two inbox", method="IMAP", workspace_id=other.id),
User(email="default@example.com", workspace_id=default.id),
User(email="client-two@example.com", workspace_id=other.id),
]
)
db_session.commit()
assert [row.name for row in workspace_domain_query(db_session, default).all()] == [
"default.example"
]
assert [row.name for row in workspace_mail_source_query(db_session, default).all()] == [
"default inbox"
]
assert [row.email for row in workspace_user_query(db_session, default).all()] == [
"default@example.com"
]
def test_workspace_resolution_and_slug_validation(db_session: Session):
"""Workspace lookup supports default, id, and normalized slug paths."""
default = resolve_workspace(db_session)
other = Workspace(slug="client-two", name="Client Two", active=True)
db_session.add(other)
db_session.commit()
db_session.refresh(other)
assert normalize_workspace_slug(" Client Two!! ") == "client-two"
assert resolve_workspace(db_session).id == default.id
assert resolve_workspace(db_session, workspace_id=other.id).id == other.id
assert resolve_workspace(db_session, slug="Client Two").id == other.id
def test_domain_api_defaults_to_default_workspace(
authed_client: TestClient,
db_session: Session,
):
"""Domain API creates and lists rows inside the default workspace boundary."""
other = Workspace(slug="client-two", name="Client Two", active=True)
db_session.add(other)
db_session.flush()
db_session.add(Domain(name="other.example", workspace_id=other.id, active=True))
db_session.commit()
created = authed_client.post(
"/api/v1/domains/domains",
json={"name": "Default.Example", "description": "Default tenant"},
)
assert created.status_code == 201
workspace = get_or_create_default_workspace(db_session)
domain = db_session.query(Domain).filter(Domain.name == "default.example").first()
assert domain.workspace_id == workspace.id
listed = authed_client.get("/api/v1/domains/domains")
assert listed.status_code == 200
names = {item["name"] for item in listed.json()}
assert "default.example" in names
assert "other.example" not in names