"""Tests for multi-tenant auth (without WhisperX dependency).""" import os import tempfile import unittest from pathlib import Path from fastapi import FastAPI from fastapi.testclient import TestClient from backend.auth.database import bootstrap_from_config, init_db from backend.auth.models import UserContext from backend.auth.routes import admin_router, router as auth_router def _build_test_app() -> FastAPI: app = FastAPI() app.include_router(auth_router) app.include_router(admin_router) return app class AuthTestCase(unittest.TestCase): @classmethod def setUpClass(cls): cls._tmpdir = tempfile.TemporaryDirectory() cls.db_path = Path(cls._tmpdir.name) / "test.db" os.environ["JWT_SECRET"] = "test-secret-key" os.environ["AUTH_ADMIN_PASSWORD"] = "admin123" os.environ["AUTH_DATABASE_PATH"] = str(cls.db_path) config = { "auth": { "database_path": str(cls.db_path), "bootstrap": { "org_slug": "merakom", "org_name": "Test Org", "admin_username": "admin", "default_projects": [ {"slug": "2026", "name": "2026"}, {"slug": "gp-merakom", "name": "GP"}, ], }, } } init_db(config) bootstrap_from_config(config) cls.client = TestClient(_build_test_app()) @classmethod def tearDownClass(cls): cls._tmpdir.cleanup() os.environ.pop("AUTH_DATABASE_PATH", None) def test_login_admin(self): response = self.client.post( "/api/auth/login", json={"org_slug": "merakom", "username": "admin", "password": "admin123"}, ) self.assertEqual(response.status_code, 200) data = response.json() self.assertIn("access_token", data) self.assertTrue(data["user"]["is_admin"]) def test_create_user_and_project_acl(self): admin_login = self.client.post( "/api/auth/login", json={"org_slug": "merakom", "username": "admin", "password": "admin123"}, ).json() headers = {"Authorization": f"Bearer {admin_login['access_token']}"} create_user = self.client.post( "/api/admin/users", headers=headers, json={ "username": "worker", "password": "worker123", "role": "user", "projects": ["2026"], }, ) self.assertEqual(create_user.status_code, 200) user_login = self.client.post( "/api/auth/login", json={"org_slug": "merakom", "username": "worker", "password": "worker123"}, ).json() user_headers = {"Authorization": f"Bearer {user_login['access_token']}"} projects = self.client.get("/api/auth/projects", headers=user_headers).json() slugs = {p["slug"] for p in projects["projects"]} self.assertEqual(slugs, {"2026"}) def test_director_has_all_projects_and_no_admin(self): admin_login = self.client.post( "/api/auth/login", json={"org_slug": "merakom", "username": "admin", "password": "admin123"}, ).json() headers = {"Authorization": f"Bearer {admin_login['access_token']}"} create_director = self.client.post( "/api/admin/users", headers=headers, json={ "username": "director1", "password": "dir123", "role": "director", "projects": [], }, ) self.assertEqual(create_director.status_code, 200) self.assertTrue(create_director.json()["user"]["all_projects_access"]) self.assertFalse(create_director.json()["user"]["is_admin"]) director_login = self.client.post( "/api/auth/login", json={"org_slug": "merakom", "username": "director1", "password": "dir123"}, ).json() d_headers = {"Authorization": f"Bearer {director_login['access_token']}"} projects = self.client.get("/api/auth/projects", headers=d_headers).json() slugs = {p["slug"] for p in projects["projects"]} self.assertEqual(slugs, {"2026", "gp-merakom", "org-gp"}) global_query = self.client.post( "/api/rag/query-global", headers=d_headers, json={"question": "test"}, ) self.assertNotEqual(global_query.status_code, 403) def test_user_creates_personal_project(self): admin_login = self.client.post( "/api/auth/login", json={"org_slug": "merakom", "username": "admin", "password": "admin123"}, ).json() headers = {"Authorization": f"Bearer {admin_login['access_token']}"} self.client.post( "/api/admin/users", headers=headers, json={ "username": "builder", "password": "build123", "role": "user", "projects": [], }, ) user_login = self.client.post( "/api/auth/login", json={"org_slug": "merakom", "username": "builder", "password": "build123"}, ).json() user_headers = {"Authorization": f"Bearer {user_login['access_token']}"} created = self.client.post( "/api/auth/projects", headers=user_headers, json={"slug": "my-gp", "name": "Мой ГП"}, ) self.assertEqual(created.status_code, 200) self.assertEqual(created.json()["project"]["scope"], "personal") self.assertTrue(created.json()["project"]["is_owner"]) projects = self.client.get("/api/auth/projects", headers=user_headers).json() slugs = {p["slug"] for p in projects["projects"]} self.assertEqual(slugs, {"my-gp"}) def test_admin_create_project_normalizes_slug(self): admin_login = self.client.post( "/api/auth/login", json={"org_slug": "merakom", "username": "admin", "password": "admin123"}, ).json() headers = {"Authorization": f"Bearer {admin_login['access_token']}"} created = self.client.post( "/api/admin/projects", headers=headers, json={"slug": "Org-GP!!", "name": "ГП org"}, ) self.assertEqual(created.status_code, 200) self.assertEqual(created.json()["project"]["slug"], "org-gp") def test_task_progress_visible_only_to_owner(self): task = {"org_slug": "merakom", "user_id": 2, "file": "secret.mp3"} owner = UserContext( user_id=2, username="worker", role="user", org_id=1, org_slug="merakom", org_name="Test", ) other = UserContext( user_id=3, username="other", role="user", org_id=1, org_slug="merakom", org_name="Test", ) admin = UserContext( user_id=1, username="admin", role="admin", org_id=1, org_slug="merakom", org_name="Test", ) self.assertTrue(owner.can_see_task(task)) self.assertFalse(other.can_see_task(task)) self.assertTrue(admin.can_see_task(task)) if __name__ == "__main__": unittest.main()