teecup/tests/test_tournament_hole_stats.py

187 lines
6.5 KiB
Python
Raw Permalink Normal View History

"""
Full statistikkdybde + optimistisk versjonssjekk 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 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"