mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-11 19:03:43 +00:00
feat(multiplayer): apply initial connect outcomes durably
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cosmic-clash/cosmic-clash/server/domain"
|
||||
)
|
||||
|
||||
func TestInitialConnectSQLPreservesAtomicNoShowReconciliation(t *testing.T) {
|
||||
for query, fragments := range map[string][]string{
|
||||
initialConnectIdempotencyInsertSQL: {"ON CONFLICT", "payload_digest"},
|
||||
initialConnectMatchLockSQL: {"FOR UPDATE", "match_id = $1"},
|
||||
initialConnectParticipantsSQL: {"participation_active", "FOR UPDATE"},
|
||||
initialConnectDeactivateSQL: {"abandoned_at", "participation_active = FALSE"},
|
||||
initialConnectPenaltySQL: {"INITIAL_CONNECT_NO_SHOW", "ON CONFLICT"},
|
||||
initialConnectOutboxSQL: {"state_changed", "revision", "ON CONFLICT"},
|
||||
} {
|
||||
for _, fragment := range fragments {
|
||||
if !contains(query, fragment) {
|
||||
t.Fatalf("query %q missing %q", query, fragment)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitialConnectPlanValidationRejectsIncompleteOrForgedPlans(t *testing.T) {
|
||||
participants := []initialConnectParticipant{
|
||||
{PlayerID: "p0", TicketID: "t0", Team: 0, ConnectedAt: validTime(100), Active: true},
|
||||
{PlayerID: "p1", TicketID: "t1", Team: 1, Active: true},
|
||||
}
|
||||
plan := domain.InitialConnectPlan{
|
||||
Action: domain.InitialConnectStartWithBot, MatchState: domain.Live,
|
||||
Connected: []string{"p0"},
|
||||
NoShows: []domain.Abandonment{{PlayerID: "p1", Cooldown: time.Minute, AbandonedAt: time.Unix(100, 0)}},
|
||||
CasualLineup: []domain.CasualSlot{
|
||||
{Slot: 0, Team: 0, PlayerID: "p0"}, {Slot: 1, Team: 1, PlayerID: "bot-1", IsBot: true},
|
||||
{Slot: 2, Team: 0, PlayerID: "bot-2", IsBot: true}, {Slot: 3, Team: 1, PlayerID: "bot-3", IsBot: true},
|
||||
{Slot: 4, Team: 0, PlayerID: "bot-4", IsBot: true}, {Slot: 5, Team: 1, PlayerID: "bot-5", IsBot: true},
|
||||
},
|
||||
}
|
||||
if err := validateInitialConnectPlan(plan, participants, domain.Casual); err != nil {
|
||||
t.Fatalf("valid plan rejected: %v", err)
|
||||
}
|
||||
plan.CasualLineup[1].Team = 0
|
||||
if err := validateInitialConnectPlan(plan, participants, domain.Casual); err == nil {
|
||||
t.Fatal("team-swapped lineup accepted")
|
||||
}
|
||||
}
|
||||
|
||||
func validTime(unix int64) (result sql.NullTime) {
|
||||
result.Time = time.Unix(unix, 0)
|
||||
result.Valid = true
|
||||
return result
|
||||
}
|
||||
Reference in New Issue
Block a user