vojo/apps/ai-bot/concurrency_test.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)
}
}