feat: game lobby service
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
package redisstate_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"galaxy/lobby/internal/adapters/redisstate"
|
||||
"galaxy/lobby/internal/domain/common"
|
||||
"galaxy/lobby/internal/ports"
|
||||
|
||||
"github.com/alicebob/miniredis/v2"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func newGameTurnStatsStore(t *testing.T) (*redisstate.GameTurnStatsStore, *miniredis.Miniredis) {
|
||||
t.Helper()
|
||||
server := miniredis.RunT(t)
|
||||
client := redis.NewClient(&redis.Options{Addr: server.Addr()})
|
||||
t.Cleanup(func() { _ = client.Close() })
|
||||
|
||||
store, err := redisstate.NewGameTurnStatsStore(client)
|
||||
require.NoError(t, err)
|
||||
return store, server
|
||||
}
|
||||
|
||||
func TestGameTurnStatsStoreSaveInitialFreezesValues(t *testing.T) {
|
||||
store, _ := newGameTurnStatsStore(t)
|
||||
ctx := context.Background()
|
||||
gameID := common.GameID("game-stats-1")
|
||||
|
||||
require.NoError(t, store.SaveInitial(ctx, gameID, []ports.PlayerInitialStats{
|
||||
{UserID: "user-a", Planets: 3, Population: 100, ShipsBuilt: 7},
|
||||
}))
|
||||
|
||||
require.NoError(t, store.SaveInitial(ctx, gameID, []ports.PlayerInitialStats{
|
||||
{UserID: "user-a", Planets: 99, Population: 9999, ShipsBuilt: 999},
|
||||
}))
|
||||
|
||||
aggregate, err := store.Load(ctx, gameID)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, aggregate.Players, 1)
|
||||
assert.Equal(t, int64(3), aggregate.Players[0].InitialPlanets)
|
||||
assert.Equal(t, int64(100), aggregate.Players[0].InitialPopulation)
|
||||
assert.Equal(t, int64(7), aggregate.Players[0].InitialShipsBuilt)
|
||||
assert.Equal(t, int64(3), aggregate.Players[0].MaxPlanets)
|
||||
assert.Equal(t, int64(100), aggregate.Players[0].MaxPopulation)
|
||||
assert.Equal(t, int64(7), aggregate.Players[0].MaxShipsBuilt)
|
||||
}
|
||||
|
||||
func TestGameTurnStatsStoreUpdateMaxRaisesOnly(t *testing.T) {
|
||||
store, _ := newGameTurnStatsStore(t)
|
||||
ctx := context.Background()
|
||||
gameID := common.GameID("game-stats-2")
|
||||
|
||||
require.NoError(t, store.SaveInitial(ctx, gameID, []ports.PlayerInitialStats{
|
||||
{UserID: "user-a", Planets: 3, Population: 100, ShipsBuilt: 7},
|
||||
}))
|
||||
|
||||
require.NoError(t, store.UpdateMax(ctx, gameID, []ports.PlayerObservedStats{
|
||||
{UserID: "user-a", Planets: 5, Population: 80, ShipsBuilt: 9},
|
||||
}))
|
||||
|
||||
require.NoError(t, store.UpdateMax(ctx, gameID, []ports.PlayerObservedStats{
|
||||
{UserID: "user-a", Planets: 4, Population: 60, ShipsBuilt: 8},
|
||||
}))
|
||||
|
||||
aggregate, err := store.Load(ctx, gameID)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, aggregate.Players, 1)
|
||||
assert.Equal(t, int64(3), aggregate.Players[0].InitialPlanets)
|
||||
assert.Equal(t, int64(100), aggregate.Players[0].InitialPopulation)
|
||||
assert.Equal(t, int64(7), aggregate.Players[0].InitialShipsBuilt)
|
||||
assert.Equal(t, int64(5), aggregate.Players[0].MaxPlanets)
|
||||
assert.Equal(t, int64(100), aggregate.Players[0].MaxPopulation)
|
||||
assert.Equal(t, int64(9), aggregate.Players[0].MaxShipsBuilt)
|
||||
}
|
||||
|
||||
func TestGameTurnStatsStoreUpdateMaxBeforeSaveInitial(t *testing.T) {
|
||||
store, _ := newGameTurnStatsStore(t)
|
||||
ctx := context.Background()
|
||||
gameID := common.GameID("game-stats-3")
|
||||
|
||||
require.NoError(t, store.UpdateMax(ctx, gameID, []ports.PlayerObservedStats{
|
||||
{UserID: "user-a", Planets: 4, Population: 50, ShipsBuilt: 1},
|
||||
}))
|
||||
|
||||
require.NoError(t, store.SaveInitial(ctx, gameID, []ports.PlayerInitialStats{
|
||||
{UserID: "user-a", Planets: 99, Population: 99, ShipsBuilt: 99},
|
||||
}))
|
||||
|
||||
aggregate, err := store.Load(ctx, gameID)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, aggregate.Players, 1)
|
||||
assert.Equal(t, int64(4), aggregate.Players[0].InitialPlanets)
|
||||
assert.Equal(t, int64(50), aggregate.Players[0].InitialPopulation)
|
||||
assert.Equal(t, int64(1), aggregate.Players[0].InitialShipsBuilt)
|
||||
assert.Equal(t, int64(4), aggregate.Players[0].MaxPlanets)
|
||||
assert.Equal(t, int64(50), aggregate.Players[0].MaxPopulation)
|
||||
assert.Equal(t, int64(1), aggregate.Players[0].MaxShipsBuilt)
|
||||
}
|
||||
|
||||
func TestGameTurnStatsStoreLoadEmpty(t *testing.T) {
|
||||
store, _ := newGameTurnStatsStore(t)
|
||||
gameID := common.GameID("game-stats-empty")
|
||||
|
||||
aggregate, err := store.Load(context.Background(), gameID)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, gameID, aggregate.GameID)
|
||||
assert.Empty(t, aggregate.Players)
|
||||
}
|
||||
|
||||
func TestGameTurnStatsStoreLoadSortsByUserID(t *testing.T) {
|
||||
store, _ := newGameTurnStatsStore(t)
|
||||
ctx := context.Background()
|
||||
gameID := common.GameID("game-stats-sorted")
|
||||
|
||||
require.NoError(t, store.SaveInitial(ctx, gameID, []ports.PlayerInitialStats{
|
||||
{UserID: "user-c", Planets: 1, Population: 1, ShipsBuilt: 1},
|
||||
{UserID: "user-a", Planets: 2, Population: 2, ShipsBuilt: 2},
|
||||
{UserID: "user-b", Planets: 3, Population: 3, ShipsBuilt: 3},
|
||||
}))
|
||||
|
||||
aggregate, err := store.Load(ctx, gameID)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, aggregate.Players, 3)
|
||||
|
||||
got := []string{aggregate.Players[0].UserID, aggregate.Players[1].UserID, aggregate.Players[2].UserID}
|
||||
expected := []string{"user-a", "user-b", "user-c"}
|
||||
require.True(t, sort.StringsAreSorted(got))
|
||||
assert.Equal(t, expected, got)
|
||||
}
|
||||
|
||||
func TestGameTurnStatsStoreDeleteRemovesEverything(t *testing.T) {
|
||||
store, server := newGameTurnStatsStore(t)
|
||||
ctx := context.Background()
|
||||
gameID := common.GameID("game-stats-del")
|
||||
|
||||
require.NoError(t, store.SaveInitial(ctx, gameID, []ports.PlayerInitialStats{
|
||||
{UserID: "user-a", Planets: 1, Population: 1, ShipsBuilt: 1},
|
||||
{UserID: "user-b", Planets: 2, Population: 2, ShipsBuilt: 2},
|
||||
}))
|
||||
|
||||
require.NoError(t, store.Delete(ctx, gameID))
|
||||
|
||||
aggregate, err := store.Load(ctx, gameID)
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, aggregate.Players)
|
||||
|
||||
keyspace := redisstate.Keyspace{}
|
||||
assert.False(t, server.Exists(keyspace.GameTurnStatsByGame(gameID)))
|
||||
assert.False(t, server.Exists(keyspace.GameTurnStat(gameID, "user-a")))
|
||||
assert.False(t, server.Exists(keyspace.GameTurnStat(gameID, "user-b")))
|
||||
}
|
||||
|
||||
func TestGameTurnStatsStoreDeleteIsIdempotent(t *testing.T) {
|
||||
store, _ := newGameTurnStatsStore(t)
|
||||
ctx := context.Background()
|
||||
gameID := common.GameID("game-stats-del-noop")
|
||||
|
||||
require.NoError(t, store.Delete(ctx, gameID))
|
||||
require.NoError(t, store.Delete(ctx, gameID))
|
||||
}
|
||||
|
||||
func TestGameTurnStatsStoreRejectsInvalidInputs(t *testing.T) {
|
||||
store, _ := newGameTurnStatsStore(t)
|
||||
ctx := context.Background()
|
||||
gameID := common.GameID("game-stats-bad")
|
||||
|
||||
err := store.SaveInitial(ctx, gameID, []ports.PlayerInitialStats{
|
||||
{UserID: "", Planets: 1, Population: 1, ShipsBuilt: 1},
|
||||
})
|
||||
assert.Error(t, err)
|
||||
|
||||
err = store.UpdateMax(ctx, gameID, []ports.PlayerObservedStats{
|
||||
{UserID: "user-a", Planets: -1, Population: 1, ShipsBuilt: 1},
|
||||
})
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = store.Load(ctx, common.GameID(""))
|
||||
assert.Error(t, err)
|
||||
}
|
||||
Reference in New Issue
Block a user