Files
galaxy-game/lobby/internal/adapters/racenamestub/directory_test.go
T
2026-04-25 23:20:55 +02:00

79 lines
1.8 KiB
Go

package racenamestub_test
import (
"context"
"errors"
"strconv"
"sync"
"sync/atomic"
"testing"
"time"
"galaxy/lobby/internal/adapters/racenamestub"
"galaxy/lobby/internal/ports"
"galaxy/lobby/internal/ports/racenamedirtest"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestDirectoryContract(t *testing.T) {
racenamedirtest.Run(t, func(now func() time.Time) ports.RaceNameDirectory {
var opts []racenamestub.Option
if now != nil {
opts = append(opts, racenamestub.WithClock(now))
}
directory, err := racenamestub.NewDirectory(opts...)
require.NoError(t, err)
return directory
})
}
func TestReserveConcurrentUniquenessInvariant(t *testing.T) {
t.Parallel()
const goroutines = 64
const raceName = "SolarPilot"
const gameID = "game-concurrency"
ctx := context.Background()
directory, err := racenamestub.NewDirectory()
require.NoError(t, err)
var (
successCount atomic.Int32
takenCount atomic.Int32
waitGroup sync.WaitGroup
start = make(chan struct{})
)
waitGroup.Add(goroutines)
for index := range goroutines {
userID := "user-" + strconv.Itoa(index)
go func(userID string) {
defer waitGroup.Done()
<-start
err := directory.Reserve(ctx, gameID, userID, raceName)
switch {
case err == nil:
successCount.Add(1)
case errors.Is(err, ports.ErrNameTaken):
takenCount.Add(1)
default:
t.Errorf("unexpected error: %v", err)
}
}(userID)
}
close(start)
waitGroup.Wait()
assert.Equal(t, int32(1), successCount.Load())
assert.Equal(t, int32(goroutines-1), takenCount.Load())
availability, err := directory.Check(ctx, raceName, "user-missing")
require.NoError(t, err)
assert.True(t, availability.Taken)
assert.Equal(t, ports.KindReservation, availability.Kind)
}