v0.11.0 harden persistence and prepare game replays
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"chess/internal/server/core"
|
||||
)
|
||||
|
||||
func TestWaitRegistryDeliversNotificationToCallerAndRemovesWaiter(t *testing.T) {
|
||||
registry := NewWaitRegistry()
|
||||
notify := registry.RegisterWait("game-1", 0, context.Background())
|
||||
|
||||
registry.NotifyGame("game-1", 1, core.StateOngoing)
|
||||
select {
|
||||
case <-notify:
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("game update was consumed before reaching the caller")
|
||||
}
|
||||
select {
|
||||
case _, ok := <-notify:
|
||||
if ok {
|
||||
t.Fatal("completed notification channel returned another value")
|
||||
}
|
||||
default:
|
||||
t.Fatal("completed notification channel was not closed")
|
||||
}
|
||||
|
||||
registry.mu.RLock()
|
||||
remaining := len(registry.waiters["game-1"])
|
||||
registry.mu.RUnlock()
|
||||
if remaining != 0 {
|
||||
t.Fatalf("completed waiter remains registered: %d", remaining)
|
||||
}
|
||||
if err := registry.Shutdown(time.Second); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWaitRegistryCompletionAndShutdownAreConcurrentAndIdempotent(t *testing.T) {
|
||||
registry := NewWaitRegistry()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
notify := registry.RegisterWait("game-1", 0, ctx)
|
||||
|
||||
var callers sync.WaitGroup
|
||||
callers.Add(3)
|
||||
go func() {
|
||||
defer callers.Done()
|
||||
registry.NotifyGame("game-1", 1, core.StateOngoing)
|
||||
}()
|
||||
go func() {
|
||||
defer callers.Done()
|
||||
registry.RemoveGame("game-1")
|
||||
}()
|
||||
go func() {
|
||||
defer callers.Done()
|
||||
cancel()
|
||||
}()
|
||||
callers.Wait()
|
||||
|
||||
select {
|
||||
case <-notify:
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("concurrent completion did not notify caller")
|
||||
}
|
||||
if err := registry.Shutdown(time.Second); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := registry.Shutdown(time.Second); err != nil {
|
||||
t.Fatalf("second shutdown failed: %v", err)
|
||||
}
|
||||
|
||||
afterShutdown := registry.RegisterWait("game-2", 0, context.Background())
|
||||
select {
|
||||
case <-afterShutdown:
|
||||
default:
|
||||
t.Fatal("registration after shutdown did not return a closed signal")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user