mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-10 16:04:04 +00:00
97 lines
3.7 KiB
Go
97 lines
3.7 KiB
Go
package store
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/cosmic-clash/cosmic-clash/server/domain"
|
|
)
|
|
|
|
func TestAcceptedMatchSQLPreservesAtomicProposalToMatchBoundary(t *testing.T) {
|
|
checks := map[string][]string{
|
|
AcceptedProposalLockSQL: {"FOR UPDATE", "proposal_id = $1"},
|
|
AcceptedProposalParticipantsSQL: {"response", "ORDER BY player_id", "FOR UPDATE"},
|
|
AcceptedMatchInsertSQL: {"'ALLOCATING'", "ON CONFLICT (match_id) DO NOTHING"},
|
|
AcceptedTicketSQL: {"state = 'ACCEPTED'", "state = 'PROPOSED'", "revision = revision + 1"},
|
|
AcceptedMatchParticipantInsertSQL: {"match_participants", "slot", "team"},
|
|
}
|
|
for query, fragments := range checks {
|
|
for _, fragment := range fragments {
|
|
if !contains(query, fragment) {
|
|
t.Fatalf("query %q missing %q", query, fragment)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAcceptedMatchPlanRejectsInvalidPlansBeforeDatabaseUse(t *testing.T) {
|
|
valid := AcceptedMatchPlan{
|
|
MatchID: "match-1", ProposalID: "proposal-1", Region: "EU", Protocol: 1,
|
|
Players: []MatchPlayer{{PlayerID: "player-a", Team: 0, Slot: 0}, {PlayerID: "player-b", Team: 1, Slot: 3}},
|
|
}
|
|
if !validAcceptedMatchPlan(valid) {
|
|
t.Fatal("valid accepted match plan rejected")
|
|
}
|
|
for name, mutate := range map[string]func(*AcceptedMatchPlan){
|
|
"no second team": func(p *AcceptedMatchPlan) { p.Players[1].Team = 0 },
|
|
"duplicate slot": func(p *AcceptedMatchPlan) { p.Players[1].Slot = 0 },
|
|
"duplicate player": func(p *AcceptedMatchPlan) { p.Players[1].PlayerID = "player-a" },
|
|
"bad region": func(p *AcceptedMatchPlan) { p.Region = "AP" },
|
|
} {
|
|
plan := valid
|
|
plan.Players = append([]MatchPlayer(nil), valid.Players...)
|
|
mutate(&plan)
|
|
if validAcceptedMatchPlan(plan) {
|
|
t.Fatalf("%s plan accepted", name)
|
|
}
|
|
}
|
|
if err := CreateMatchFromAcceptedProposal(nil, nil, valid, time.Now()); err == nil {
|
|
t.Fatal("nil database accepted")
|
|
}
|
|
}
|
|
|
|
func TestAcceptedMatchPromotionHonoursPlaylistSizeInvariant(t *testing.T) {
|
|
if validAcceptedPlaylistCount(domain.Ranked, 5) || !validAcceptedPlaylistCount(domain.Ranked, 6) {
|
|
t.Fatal("ranked accepted-match count invariant is wrong")
|
|
}
|
|
if validAcceptedPlaylistCount(domain.Casual, 1) || !validAcceptedPlaylistCount(domain.Casual, 2) || validAcceptedPlaylistCount("other", 6) {
|
|
t.Fatal("casual accepted-match count invariant is wrong")
|
|
}
|
|
}
|
|
|
|
func TestRankedAcceptedMatchPlanRequiresArenaAfterPlaylistResolution(t *testing.T) {
|
|
plan := AcceptedMatchPlan{MatchID: "match-1", ProposalID: "proposal-1", Region: "EU", Protocol: 1, Players: []MatchPlayer{{PlayerID: "player-a", Team: 0, Slot: 0}, {PlayerID: "player-b", Team: 1, Slot: 3}}}
|
|
if !validAcceptedMatchPlan(plan) {
|
|
t.Fatal("test plan should reach the database playlist guard")
|
|
}
|
|
// CreateMatchFromAcceptedProposal owns the playlist lookup, so a nil DB is
|
|
// the only no-database check available here; the integration suite exercises
|
|
// the resolved ranked branch against PostgreSQL.
|
|
if err := CreateMatchFromAcceptedProposal(nil, nil, plan, time.Now()); err == nil {
|
|
t.Fatal("nil database accepted")
|
|
}
|
|
}
|
|
|
|
func TestMatchPlayersFromTeamsUsesDeterministicTeamSlots(t *testing.T) {
|
|
teams := domain.Teams{
|
|
Team0: []domain.Candidate{{PlayerID: "bravo"}, {PlayerID: "alpha"}},
|
|
Team1: []domain.Candidate{{PlayerID: "delta"}, {PlayerID: "charlie"}},
|
|
}
|
|
players, err := MatchPlayersFromTeams(teams)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
want := []MatchPlayer{
|
|
{PlayerID: "alpha", Team: 0, Slot: 0}, {PlayerID: "bravo", Team: 0, Slot: 1},
|
|
{PlayerID: "charlie", Team: 1, Slot: 3}, {PlayerID: "delta", Team: 1, Slot: 4},
|
|
}
|
|
if len(players) != len(want) {
|
|
t.Fatalf("players = %+v", players)
|
|
}
|
|
for index := range want {
|
|
if players[index] != want[index] {
|
|
t.Fatalf("player %d = %+v, want %+v", index, players[index], want[index])
|
|
}
|
|
}
|
|
}
|