82 lines
2.1 KiB
Go
82 lines
2.1 KiB
Go
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)
|
|
}
|
|
}
|