teecup/tests/test_round_groups.py
Erol Haagenrud 9a9fcc84c0 Utslagsgrupper for individuelle turneringer: hvem spiller med hvem (ADR-088)
Tradisjonelt utslag (samme starthull, staggerte klokkeslett med fast
intervall), manuell gruppesammensetning med et forslag å justere, fast
gruppestørrelse. Fire ekte bugs funnet og fikset før utrulling via egen
scratch-verifisering (FK-korrupsjon, str/datetime-mismatch, tidssone,
React state). Migrasjon 084 lagt til, men IKKE anvendt mot ekte
teecup_db ennå -- venter på bekreftelse.
2026-08-18 15:43:39 +02:00

164 lines
6.3 KiB
Python

"""
Utslagsgrupper (migrasjon 084, 2026-08-18, ADR-088): hvem spiller med
hvem, klokka når -- for individuelle turneringer. Bruker: "Jeg må jo
kunne bulksjekke hvem som skal spille fra hvor, med hvem, klokka når?"
Design bekreftet: tradisjonelt utslag (samme starthull, staggerte
klokkeslett med fast intervall), manuell gruppesammensetning med et
forslag å justere, fast gruppestørrelse.
"""
from app.routers.individual_tournaments import (
RoundGroupIn,
SaveRoundGroupsIn,
SuggestGroupsIn,
TournamentRoundUpdate,
list_round_groups,
save_round_groups,
suggest_round_groups,
update_round,
)
from tests.conftest import (
create_org,
create_course,
create_player,
create_tee,
create_tournament,
create_tournament_participant,
create_tournament_round,
create_tournament_round_participant,
)
import app.db as app_db
async def _setup(org_id, n_players=5):
tournament_id = await create_tournament(org_id, name="Gruppe-turnering")
course_id = await create_course(org_id, name="Gruppe Links")
tee_id = await create_tee(org_id, course_id)
async with app_db.org_connection(org_id) as conn:
await conn.execute(
"UPDATE tournament SET format_type = 'individual', scoring_method = 'stroke_gross' WHERE id = $1",
tournament_id,
)
round_id = await create_tournament_round(org_id, tournament_id, course_id, sequence=1)
rp_ids = []
for i in range(n_players):
player_id = await create_player(org_id, display_name=f"Spiller {i:02d}")
tp_id = await create_tournament_participant(org_id, tournament_id, player_id)
rp_ids.append(await create_tournament_round_participant(org_id, round_id, tp_id, tee_id))
return tournament_id, round_id, rp_ids
async def test_update_round_sets_scheduling_fields(pool):
org_id = await create_org()
tournament_id, round_id, _ = await _setup(org_id, n_players=1)
updated = await update_round(
tournament_id, round_id,
TournamentRoundUpdate(scheduled_at="2026-08-19T10:00:00", tee_interval_minutes=10, start_hole=1),
organization_id=org_id,
)
assert updated.tee_interval_minutes == 10
assert updated.start_hole == 1
assert "2026-08-19" in (updated.scheduled_at or "")
async def test_suggest_round_groups_chunks_by_size_and_computes_tee_times_without_saving(pool):
org_id = await create_org()
tournament_id, round_id, rp_ids = await _setup(org_id, n_players=5)
await update_round(
tournament_id, round_id,
TournamentRoundUpdate(scheduled_at="2026-08-19T10:00:00", tee_interval_minutes=10),
organization_id=org_id,
)
suggestion = await suggest_round_groups(
tournament_id, round_id, SuggestGroupsIn(group_size=2), organization_id=org_id
)
assert [len(g.participants) for g in suggestion.groups] == [2, 2, 1]
assert [g.sequence for g in suggestion.groups] == [1, 2, 3]
assert suggestion.groups[0].tee_time is not None and "10:00" in suggestion.groups[0].tee_time
assert suggestion.groups[1].tee_time is not None and "10:10" in suggestion.groups[1].tee_time
assert suggestion.groups[2].tee_time is not None and "10:20" in suggestion.groups[2].tee_time
# Alle grupper i forslaget er usaved (id=None).
assert all(g.id is None for g in suggestion.groups)
# Ingenting skal faktisk ha blitt lagret av selve forslaget.
saved = await list_round_groups(tournament_id, round_id, organization_id=org_id)
assert saved.groups == []
assert len(saved.ungrouped) == 5
async def test_save_round_groups_persists_and_fully_replaces_previous(pool):
org_id = await create_org()
tournament_id, round_id, rp_ids = await _setup(org_id, n_players=4)
await update_round(
tournament_id, round_id,
TournamentRoundUpdate(scheduled_at="2026-08-19T10:00:00", tee_interval_minutes=10),
organization_id=org_id,
)
first = await save_round_groups(
tournament_id, round_id,
SaveRoundGroupsIn(groups=[
RoundGroupIn(sequence=1, round_participant_ids=[rp_ids[0], rp_ids[1]]),
RoundGroupIn(sequence=2, round_participant_ids=[rp_ids[2], rp_ids[3]]),
]),
organization_id=org_id,
)
assert len(first.groups) == 2
assert len(first.ungrouped) == 0
# Lagre på nytt med en HELT ANNEN sammensetning -- skal erstatte, ikke legge til.
second = await save_round_groups(
tournament_id, round_id,
SaveRoundGroupsIn(groups=[
RoundGroupIn(sequence=1, round_participant_ids=[rp_ids[0], rp_ids[2], rp_ids[3]]),
]),
organization_id=org_id,
)
assert len(second.groups) == 1
assert len(second.groups[0].participants) == 3
assert len(second.ungrouped) == 1
assert second.ungrouped[0].round_participant_id == rp_ids[1]
async with app_db.org_connection(org_id) as conn:
group_count = await conn.fetchval(
"SELECT count(*) FROM tournament_round_group WHERE tournament_round_id = $1", round_id
)
assert group_count == 1 # den gamle gruppen faktisk slettet, ikke bare "løsrevet"
async def test_save_round_groups_leaves_unlisted_participants_ungrouped(pool):
org_id = await create_org()
tournament_id, round_id, rp_ids = await _setup(org_id, n_players=3)
result = await save_round_groups(
tournament_id, round_id,
SaveRoundGroupsIn(groups=[RoundGroupIn(sequence=1, round_participant_ids=[rp_ids[0]])]),
organization_id=org_id,
)
assert len(result.groups) == 1
assert {p.round_participant_id for p in result.ungrouped} == {rp_ids[1], rp_ids[2]}
async def test_group_tee_time_override_wins_over_computed(pool):
org_id = await create_org()
tournament_id, round_id, rp_ids = await _setup(org_id, n_players=2)
await update_round(
tournament_id, round_id,
TournamentRoundUpdate(scheduled_at="2026-08-19T10:00:00", tee_interval_minutes=10),
organization_id=org_id,
)
result = await save_round_groups(
tournament_id, round_id,
SaveRoundGroupsIn(groups=[
RoundGroupIn(sequence=1, tee_time_override="2026-08-19T09:15:00", round_participant_ids=rp_ids),
]),
organization_id=org_id,
)
assert result.groups[0].tee_time is not None
assert "09:15" in result.groups[0].tee_time # override, IKKE den utledede 10:00