package main import ( "sync" "testing" ) // TestSingleFlightClaim documents the per-room single-flight invariant the async // refactor relies on: at most one generation per room at a time, the claim is // independent per room, and a release re-arms the room. handleEvent takes this claim // synchronously in transaction order, so the FIRST message for a room wins and later // ones are dropped until release (never the reverse). func TestSingleFlightClaim(t *testing.T) { b := &Bot{inflight: make(map[string]bool)} if !b.tryClaim("!a") { t.Fatal("first claim on !a should win") } if b.tryClaim("!a") { t.Fatal("second claim on !a must fail while in flight") } if !b.tryClaim("!b") { t.Fatal("a different room must claim independently") } b.release("!a") if !b.tryClaim("!a") { t.Fatal("after release !a must be claimable again") } } // TestSingleFlightClaimExactlyOneWinner runs many goroutines racing for the same // room and asserts EXACTLY ONE wins the claim — the property that prevents two // concurrent generations (double xAI spend) for one room. Run under -race. func TestSingleFlightClaimExactlyOneWinner(t *testing.T) { b := &Bot{inflight: make(map[string]bool)} const n = 64 var wins int64 var mu sync.Mutex var wg sync.WaitGroup wg.Add(n) for i := 0; i < n; i++ { go func() { defer wg.Done() if b.tryClaim("!room") { mu.Lock() wins++ mu.Unlock() } }() } wg.Wait() if wins != 1 { t.Fatalf("exactly one goroutine must win the claim, got %d", wins) } } // TestLRUSetConcurrentAddOnce asserts the dedup set's check-and-insert is atomic: // with many goroutines racing on the same id, Add returns true exactly once. This is // the in-memory half of markSeen, now called from concurrent per-room goroutines. // Run under -race. func TestLRUSetConcurrentAddOnce(t *testing.T) { s := newLRUSet(1000) const n = 64 var trues int64 var mu sync.Mutex var wg sync.WaitGroup wg.Add(n) for i := 0; i < n; i++ { go func() { defer wg.Done() if s.Add("$evt") { mu.Lock() trues++ mu.Unlock() } }() } wg.Wait() if trues != 1 { t.Fatalf("Add must return true exactly once for one id, got %d", trues) } }