108 lines
4.1 KiB
Python
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
|