Files
consentos/apps/api/tests/test_models.py
James Cottrill fbf26453f2 feat: initial public release
ConsentOS — a privacy-first cookie consent management platform.

Self-hosted, source-available alternative to OneTrust, Cookiebot, and
CookieYes. Full standards coverage (IAB TCF v2.2, GPP v1, Google
Consent Mode v2, GPC, Shopify Customer Privacy API), multi-tenant
architecture with role-based access, configuration cascade
(system → org → group → site → region), dark-pattern detection in
the scanner, and a tamper-evident consent record audit trail.

This is the initial public release. Prior development history is
retained internally.

See README.md for the feature list, architecture overview, and
quick-start instructions. Licensed under the Elastic Licence 2.0 —
self-host freely; do not resell as a managed service.
2026-04-14 09:18:18 +00:00

167 lines
4.7 KiB
Python

"""Tests for SQLAlchemy model definitions.
These tests verify model structure without needing a database connection.
"""
from sqlalchemy import inspect
from src.models import (
Base,
ConsentRecord,
Cookie,
CookieAllowListEntry,
CookieCategory,
KnownCookie,
Organisation,
ScanJob,
ScanResult,
Site,
SiteConfig,
Translation,
User,
)
def test_all_models_registered_in_metadata():
"""All expected tables should be present in Base.metadata."""
table_names = set(Base.metadata.tables.keys())
expected = {
"organisations",
"users",
"sites",
"site_configs",
"cookie_categories",
"cookies",
"cookie_allow_list",
"known_cookies",
"consent_records",
"scan_jobs",
"scan_results",
"translations",
}
assert expected.issubset(table_names), f"Missing tables: {expected - table_names}"
def test_organisation_columns():
mapper = inspect(Organisation)
column_names = {c.key for c in mapper.columns}
assert "id" in column_names
assert "name" in column_names
assert "slug" in column_names
assert "contact_email" in column_names
assert "billing_plan" in column_names
assert "created_at" in column_names
assert "updated_at" in column_names
assert "deleted_at" in column_names
def test_user_columns_and_fk():
mapper = inspect(User)
column_names = {c.key for c in mapper.columns}
assert "organisation_id" in column_names
assert "email" in column_names
assert "password_hash" in column_names
assert "role" in column_names
def test_site_unique_constraint():
table = Site.__table__
constraint_names = {c.name for c in table.constraints if hasattr(c, "name") and c.name}
assert "uq_sites_org_domain" in constraint_names
def test_site_config_jsonb_fields():
mapper = inspect(SiteConfig)
column_names = {c.key for c in mapper.columns}
for field in ["regional_modes", "gcm_default", "banner_config"]:
assert field in column_names, f"Missing JSONB field: {field}"
def test_cookie_category_columns():
mapper = inspect(CookieCategory)
column_names = {c.key for c in mapper.columns}
assert "tcf_purpose_ids" in column_names
assert "gcm_consent_types" in column_names
assert "is_essential" in column_names
def test_cookie_unique_constraint():
table = Cookie.__table__
constraint_names = {c.name for c in table.constraints if hasattr(c, "name") and c.name}
assert "uq_cookies_site_name_domain_type" in constraint_names
def test_cookie_allow_list_unique_constraint():
table = CookieAllowListEntry.__table__
constraint_names = {c.name for c in table.constraints if hasattr(c, "name") and c.name}
assert "uq_allow_list_site_name_domain" in constraint_names
def test_known_cookie_unique_constraint():
table = KnownCookie.__table__
constraint_names = {c.name for c in table.constraints if hasattr(c, "name") and c.name}
assert "uq_known_cookies_name_domain" in constraint_names
def test_consent_record_columns():
mapper = inspect(ConsentRecord)
column_names = {c.key for c in mapper.columns}
for field in [
"visitor_id",
"action",
"categories_accepted",
"tc_string",
"gcm_state",
"country_code",
"consented_at",
]:
assert field in column_names, f"Missing field: {field}"
def test_scan_job_columns():
mapper = inspect(ScanJob)
column_names = {c.key for c in mapper.columns}
assert "status" in column_names
assert "pages_scanned" in column_names
assert "cookies_found" in column_names
def test_scan_result_columns():
mapper = inspect(ScanResult)
column_names = {c.key for c in mapper.columns}
assert "page_url" in column_names
assert "cookie_name" in column_names
assert "script_source" in column_names
assert "auto_category" in column_names
def test_translation_unique_constraint():
table = Translation.__table__
constraint_names = {c.name for c in table.constraints if hasattr(c, "name") and c.name}
assert "uq_translations_site_locale" in constraint_names
def test_uuid_primary_keys():
"""All models should use UUID primary keys."""
models = [
Organisation,
User,
Site,
SiteConfig,
CookieCategory,
Cookie,
CookieAllowListEntry,
KnownCookie,
ConsentRecord,
ScanJob,
ScanResult,
Translation,
]
for model in models:
mapper = inspect(model)
pk_cols = mapper.primary_key
assert len(pk_cols) == 1, f"{model.__name__} should have exactly one PK column"
assert str(pk_cols[0].type) == "UUID", (
f"{model.__name__} PK should be UUID, got {pk_cols[0].type}"
)