"""Migration 032 — the join_requests table (§22.8 S6). Proves: the table exists with its CHECK constraints (scope_type ∈ {project,collection}; role/status enums), the one-open-per-(scope,user) partial unique index holds, and a decided request frees a fresh ask. Template: test_migration_030_global_scope.py. """ from __future__ import annotations import sqlite3 import tempfile from pathlib import Path import pytest from app import db class _Cfg: def __init__(self, path): self.database_path = path def _fresh_db(): d = tempfile.mkdtemp() path = Path(d) / "t.db" db.run_migrations(_Cfg(str(path))) return db.connect(str(path)) def _add_user(conn, uid, login): conn.execute( "INSERT INTO users (id, gitea_id, gitea_login, display_name, role) " "VALUES (?, ?, ?, ?, 'contributor')", (uid, uid, login, login.capitalize()), ) def _request(conn, scope_type="collection", scope_id="features", uid=1, role="contributor"): conn.execute( "INSERT INTO join_requests (scope_type, scope_id, requester_user_id, requested_role) " "VALUES (?, ?, ?, ?)", (scope_type, scope_id, uid, role), ) def test_join_request_row_round_trips(): conn = _fresh_db() _add_user(conn, 1, "ben") _request(conn) row = conn.execute("SELECT * FROM join_requests WHERE requester_user_id = 1").fetchone() assert row["scope_type"] == "collection" assert row["requested_role"] == "contributor" assert row["status"] == "pending" assert row["granted_role"] is None def test_global_scope_type_is_rejected(): conn = _fresh_db() _add_user(conn, 1, "ben") with pytest.raises(sqlite3.IntegrityError): _request(conn, scope_type="global", scope_id="*") def test_bad_role_and_status_rejected(): conn = _fresh_db() _add_user(conn, 1, "ben") with pytest.raises(sqlite3.IntegrityError): _request(conn, role="viewer") with pytest.raises(sqlite3.IntegrityError): conn.execute( "INSERT INTO join_requests (scope_type, scope_id, requester_user_id, requested_role, status) " "VALUES ('project', 'ohm', 1, 'owner', 'maybe')" ) def test_one_open_request_per_scope_user(): conn = _fresh_db() _add_user(conn, 1, "ben") _request(conn) with pytest.raises(sqlite3.IntegrityError): _request(conn) def test_decided_request_frees_a_fresh_ask(): conn = _fresh_db() _add_user(conn, 1, "ben") _request(conn) conn.execute("UPDATE join_requests SET status = 'declined' WHERE requester_user_id = 1") # a second open ask is now allowed _request(conn) n = conn.execute( "SELECT COUNT(*) AS n FROM join_requests WHERE requester_user_id = 1" ).fetchone()["n"] assert n == 2