teecup/tests/test_round_groups.py

218 lines
8.4 KiB
Python
Raw Permalink Normal View History

"""
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
async def test_shotgun_mode_gives_all_groups_the_same_tee_time(pool):
"""Migrasjon 088, ADR-096 -- intervallet er meningsløst i shotgun,
alle grupper går ut SAMTIDIG uansett sequence."""
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-19T08:00:00", tee_interval_minutes=10, start_mode="shotgun",
),
organization_id=org_id,
)
result = await save_round_groups(
tournament_id, round_id,
SaveRoundGroupsIn(groups=[
RoundGroupIn(sequence=1, start_hole=5, round_participant_ids=[rp_ids[0], rp_ids[1]]),
RoundGroupIn(sequence=2, start_hole=1, round_participant_ids=[rp_ids[2], rp_ids[3]]),
]),
organization_id=org_id,
)
# Begge grupper går ut kl 08:00, uavhengig av sequence/intervall.
for g in result.groups:
assert g.tee_time is not None and "08:00" in g.tee_time
# Vises sortert etter STARTHULL (1 før 5), ikke etter sequence (1 før 2).
assert [g.start_hole for g in result.groups] == [1, 5]
async def test_consecutive_mode_still_sorts_by_sequence_not_start_hole(pool):
"""Regresjonsvern -- start_hole (uansett verdi, normalt None) skal
IKKE påvirke rekkefølgen når runden fortsatt er 'consecutive'."""
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-19T08:00:00", tee_interval_minutes=10),
organization_id=org_id,
)
result = 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 [g.sequence for g in result.groups] == [1, 2]
assert "08:00" in result.groups[0].tee_time
assert "08:10" in result.groups[1].tee_time