""" Delt testoppsett for backend-integrasjonstestene. Kjøres ALLTID mot en scratch-database (se scripts/run_backend_tests.sh) -- aldri mot ekte teecup_db. Poolen initialiseres per test (funksjonsscope, ikke sesjonsscope) for å unngå event loop-fallgruver med pytest-asyncio -- en full pool-oppstart tar millisekunder og suiten er liten nok til at det ikke koster noe i praksis. Hjelpefunksjonene under (create_user, create_org, ...) setter kun de kolonnene testene faktisk trenger å kontrollere, med fornuftige defaults for resten -- se \\d-utskrift av schema for hvilke felt som er NOT NULL. """ import uuid import pytest_asyncio from app import db as app_db def new_id() -> str: return str(uuid.uuid4()) @pytest_asyncio.fixture async def pool(): await app_db.init_pool() yield await app_db.close_pool() async def create_user(**overrides) -> str: """Egen tilkobling, samme begrunnelse som create_org -- app_user har ingen RLS (ikke org-scopet), så det er trygt/enkelt å ikke kreve en ferdig-åpnet `conn` fra kalleren.""" user_id = overrides.get("id", new_id()) display_name = overrides.get("display_name", f"Testbruker {user_id[:8]}") birth_date = overrides.get("birth_date") email = overrides.get("email", f"{user_id}@pytest.invalid") async with app_db.plain_connection() as conn: await conn.execute( """ INSERT INTO app_user (id, display_name, birth_date, email) VALUES ($1, $2, $3, $4) """, user_id, display_name, birth_date, email, ) return user_id async def create_org(**overrides) -> str: """Egen tilkobling (ikke `conn`-parameter som de andre hjelperne) -- speiler den ekte selvrefererende RLS-bootstrappen i routers/organizations.py::create_organization: `app.current_org` MÅ være satt til organisasjonens EGEN, ennå-ikke-eksisterende id FØR innsettingen, ellers avviser org_self-policyen den (teecup_app er NOSUPERUSER/NOBYPASSRLS, akkurat som i produksjon).""" org_id = overrides.get("id", new_id()) name = overrides.get("name", f"Testklubb {org_id[:8]}") async with app_db.org_connection(org_id) as conn: await conn.execute("INSERT INTO organization (id, name) VALUES ($1, $2)", org_id, name) return org_id async def add_membership(organization_id: str, user_id: str, role: str = "member") -> None: """organization_membership er org-scopet (RLS), samme begrunnelse som create_org over -- må skrives med riktig app.current_org satt.""" async with app_db.org_connection(organization_id) as conn: await conn.execute( "INSERT INTO organization_membership (organization_id, user_id, role) VALUES ($1, $2, $3)", organization_id, user_id, role, ) async def create_round(conn, owner_user_id: str, **overrides) -> str: round_id = overrides.get("id", new_id()) # course_source='teeoff' krever KUN teeoff_facility_slug/teeoff_course_id # (fritekst, ingen FK mot en ekte teeoff-bane) -- enklere for et testfixtur # enn 'custom', som (round_check-constrainten) også krever en ekte rad i # personal_course. await conn.execute( """ INSERT INTO round (id, owner_user_id, course_source, teeoff_facility_slug, teeoff_course_id, course_name_snapshot, tee_name_snapshot, played_at) VALUES ($1, $2, 'teeoff', 'test-facility', 'test-course', 'Testbanen', 'Gul', CURRENT_DATE) """, round_id, owner_user_id, ) return round_id async def create_participant(conn, round_id: str, **overrides) -> str: participant_id = overrides.get("id", new_id()) user_id = overrides.get("user_id") is_owner = overrides.get("is_owner", True) course_handicap_snapshot = overrides.get("course_handicap_snapshot") await conn.execute( """ INSERT INTO round_participant (id, round_id, user_id, is_owner, gender, tee_name_snapshot, course_handicap_snapshot) VALUES ($1, $2, $3, $4, 'x', 'Gul', $5) """, participant_id, round_id, user_id, is_owner, course_handicap_snapshot, ) return participant_id async def create_hole(conn, participant_id: str, hole_number: int, par: int = 4, stroke_index: int = 9, **overrides) -> str: hole_id = overrides.get("id", new_id()) version = overrides.get("version", 1) await conn.execute( """ INSERT INTO round_hole (id, round_participant_id, hole_number, par, stroke_index, version) VALUES ($1, $2, $3, $4, $5, $6) """, hole_id, participant_id, hole_number, par, stroke_index, version, ) return hole_id