Files
chess/internal/server/service/waiter_test.go
T

82 lines
1.9 KiB
Go

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")
}
}