""" Full statistikkdybde + optimistisk versjonssjekk på tournament_round_hole (migrasjon 075, ADR-071) -- speiler test_concurrency_version_check.py sitt mønster for round_hole, men gjennom individual_tournaments.py sin egen update_hole (self-only autorisasjon, upsert i stedet for ren UPDATE siden raden ikke finnes før første score). """ import pytest from fastapi import HTTPException from app.auth import CurrentUser from app.routers.individual_tournaments import ( HoleUpdate, TournamentParticipantCreate, add_tournament_participant, update_hole, ) from tests.conftest import ( add_membership, create_org, create_org_hole, create_course, create_player, create_tee, create_tournament, create_tournament_participant, create_tournament_round, create_tournament_round_participant, create_user, ) async def _setup_tournament(par=4): org_id = await create_org() user_id = await create_user() await add_membership(org_id, user_id, role="owner") tournament_id = await create_tournament(org_id) course_id = await create_course(org_id) for n in range(1, 19): await create_org_hole( org_id, course_id, hole_number=n, par=par if n == 1 else 4, stroke_index=n, ) tee_id = await create_tee(org_id, course_id) tournament_round_id = await create_tournament_round(org_id, tournament_id, course_id) player_id = await create_player(org_id, user_id=user_id) tp_id = await create_tournament_participant(org_id, tournament_id, player_id) rp_id = await create_tournament_round_participant(org_id, tournament_round_id, tp_id, tee_id) return org_id, user_id, tournament_id, tournament_round_id, rp_id async def test_update_succeeds_and_increments_version(pool): org_id, user_id, tournament_id, round_id, rp_id = await _setup_tournament() user = CurrentUser(user_id=user_id) out = await update_hole( tournament_id, round_id, rp_id, 1, HoleUpdate(gross_strokes=5, putts=2, expected_version=None), organization_id=org_id, user=user, ) assert out.gross_strokes == 5 assert out.putts == 2 assert out.version == 1 async def test_stale_version_is_rejected_with_409(pool): org_id, user_id, tournament_id, round_id, rp_id = await _setup_tournament() user = CurrentUser(user_id=user_id) # Første innsending -- raden finnes ikke fra før, INSERT-grenen treffes # ubetinget uansett expected_version. Hullet er nå versjon 1. await update_hole( tournament_id, round_id, rp_id, 1, HoleUpdate(gross_strokes=4, expected_version=None), organization_id=org_id, user=user, ) # "Enhet 1" leser versjon 1, skriver -- lykkes, hullet er nå versjon 2. await update_hole( tournament_id, round_id, rp_id, 1, HoleUpdate(gross_strokes=4, expected_version=1), organization_id=org_id, user=user, ) # "Enhet 2" leste OGSÅ versjon 1 (før enhet 1 sin skriving nådde den). with pytest.raises(HTTPException) as exc_info: await update_hole( tournament_id, round_id, rp_id, 1, HoleUpdate(gross_strokes=6, expected_version=1), organization_id=org_id, user=user, ) assert exc_info.value.status_code == 409 assert exc_info.value.detail["code"] == "STALE_VERSION" async def test_expected_version_none_bypasses_check(pool): org_id, user_id, tournament_id, round_id, rp_id = await _setup_tournament() user = CurrentUser(user_id=user_id) await update_hole( tournament_id, round_id, rp_id, 1, HoleUpdate(gross_strokes=4, expected_version=None), organization_id=org_id, user=user, ) await update_hole( tournament_id, round_id, rp_id, 1, HoleUpdate(gross_strokes=4, expected_version=1), organization_id=org_id, user=user, ) # Hullet er nå versjon 2 -- men klienten sender ingen forventet versjon. out = await update_hole( tournament_id, round_id, rp_id, 1, HoleUpdate(gross_strokes=7, expected_version=None), organization_id=org_id, user=user, ) assert out.gross_strokes == 7 assert out.version == 3 async def test_first_write_succeeds_regardless_of_expected_version(pool): """Raden finnes ikke før første score -- INSERT-grenen er ubetinget, så selv en helt feil expected_version må IKKE blokkere en fersk innsending (ulikt round_hole, der raden alltid finnes fra rundestart).""" org_id, user_id, tournament_id, round_id, rp_id = await _setup_tournament() user = CurrentUser(user_id=user_id) out = await update_hole( tournament_id, round_id, rp_id, 1, HoleUpdate(gross_strokes=5, expected_version=99), organization_id=org_id, user=user, ) assert out.gross_strokes == 5 assert out.version == 1 async def test_full_stat_fields_round_trip(pool): org_id, user_id, tournament_id, round_id, rp_id = await _setup_tournament(par=4) user = CurrentUser(user_id=user_id) out = await update_hole( tournament_id, round_id, rp_id, 1, HoleUpdate( gross_strokes=4, putts=1, club_off_tee="Driver", tee_shot_result="fairway", approach_result="hit", chip_count=0, bunker_shot_count=1, penalty_strokes=0, first_putt_distance_bucket="<3m", anyway_strokes=0, expected_version=None, ), organization_id=org_id, user=user, ) assert out.putts == 1 assert out.club_off_tee == "Driver" assert out.tee_shot_result == "fairway" assert out.approach_result == "hit" assert out.bunker_shot_count == 1 assert out.first_putt_distance_bucket == "<3m" async def test_stat_level_defaults_to_strokes_only_and_is_settable_on_create(pool): org_id = await create_org() user_id = await create_user() await add_membership(org_id, user_id, role="owner") tournament_id = await create_tournament(org_id) player_id = await create_player(org_id, user_id=user_id) default_out = await add_tournament_participant( tournament_id, TournamentParticipantCreate(player_id=player_id), organization_id=org_id, ) assert default_out.stat_level == "strokes_only" player_id_2 = await create_player(org_id) full_out = await add_tournament_participant( tournament_id, TournamentParticipantCreate(player_id=player_id_2, stat_level="full"), organization_id=org_id, ) assert full_out.stat_level == "full"