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

152 lines
4.1 KiB
Go

package app
import (
"context"
"net"
"net/http"
"testing"
"time"
"galaxy/lobby/internal/api/internalhttp"
"galaxy/lobby/internal/api/publichttp"
"galaxy/lobby/internal/config"
"github.com/alicebob/miniredis/v2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// newTestConfig builds a valid Config that listens on ephemeral ports and a
// miniredis instance provided by redisServer.
func newTestConfig(t *testing.T, redisAddr string) config.Config {
t.Helper()
reserve := func() string {
listener, err := net.Listen("tcp", "127.0.0.1:0")
require.NoError(t, err)
addr := listener.Addr().String()
require.NoError(t, listener.Close())
return addr
}
cfg := config.DefaultConfig()
cfg.Redis.Addr = redisAddr
cfg.UserService.BaseURL = "http://127.0.0.1:1"
cfg.GM.BaseURL = "http://127.0.0.1:1"
cfg.PublicHTTP.Addr = reserve()
cfg.InternalHTTP.Addr = reserve()
return cfg
}
func TestNewRuntimeValidatesContext(t *testing.T) {
t.Parallel()
_, err := NewRuntime(nil, config.Config{}, nil) //nolint:staticcheck // test exercises the nil-context guard.
require.Error(t, err)
require.Contains(t, err.Error(), "nil context")
}
func TestNewRuntimeRejectsInvalidConfig(t *testing.T) {
t.Parallel()
_, err := NewRuntime(context.Background(), config.Config{}, nil)
require.Error(t, err)
require.Contains(t, err.Error(), "new lobby runtime")
}
func TestNewRuntimeSucceedsWithMiniredis(t *testing.T) {
redisServer := miniredis.RunT(t)
runtime, err := NewRuntime(context.Background(), newTestConfig(t, redisServer.Addr()), nil)
require.NoError(t, err)
require.NotNil(t, runtime)
t.Cleanup(func() { _ = runtime.Close() })
assert.NotNil(t, runtime.PublicServer())
assert.NotNil(t, runtime.InternalServer())
}
func TestNewRuntimeWiresRaceNameDirectory(t *testing.T) {
redisServer := miniredis.RunT(t)
runtime, err := NewRuntime(context.Background(), newTestConfig(t, redisServer.Addr()), nil)
require.NoError(t, err)
t.Cleanup(func() { _ = runtime.Close() })
require.NotNil(t, runtime.wiring)
assert.NotNil(t, runtime.wiring.raceNameDirectory)
}
func TestNewRuntimeFailsWhenRedisUnreachable(t *testing.T) {
t.Parallel()
cfg := newTestConfig(t, "127.0.0.1:1") // guaranteed unreachable
cfg.Redis.OperationTimeout = 100 * time.Millisecond
_, err := NewRuntime(context.Background(), cfg, nil)
require.Error(t, err)
require.Contains(t, err.Error(), "ping redis")
}
func TestRuntimeCloseIsIdempotent(t *testing.T) {
redisServer := miniredis.RunT(t)
runtime, err := NewRuntime(context.Background(), newTestConfig(t, redisServer.Addr()), nil)
require.NoError(t, err)
require.NoError(t, runtime.Close())
require.NoError(t, runtime.Close())
}
func TestRuntimeRunServesProbesAndStopsOnCancel(t *testing.T) {
redisServer := miniredis.RunT(t)
cfg := newTestConfig(t, redisServer.Addr())
runtime, err := NewRuntime(context.Background(), cfg, nil)
require.NoError(t, err)
t.Cleanup(func() { _ = runtime.Close() })
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
runErr := make(chan error, 1)
go func() {
runErr <- runtime.Run(ctx)
}()
require.Eventually(t, func() bool {
return runtime.PublicServer().Addr() != "" && runtime.InternalServer().Addr() != ""
}, 2*time.Second, 10*time.Millisecond)
for _, probe := range []struct {
label string
url string
}{
{"public healthz", "http://" + runtime.PublicServer().Addr() + publichttp.HealthzPath},
{"public readyz", "http://" + runtime.PublicServer().Addr() + publichttp.ReadyzPath},
{"internal healthz", "http://" + runtime.InternalServer().Addr() + internalhttp.HealthzPath},
{"internal readyz", "http://" + runtime.InternalServer().Addr() + internalhttp.ReadyzPath},
} {
resp, err := http.Get(probe.url)
require.NoError(t, err, probe.label)
_ = resp.Body.Close()
assert.Equal(t, http.StatusOK, resp.StatusCode, probe.label)
}
cancel()
select {
case err := <-runErr:
require.NoError(t, err)
case <-time.After(3 * time.Second):
t.Fatal("runtime did not stop after cancel")
}
}
func TestRuntimeRunNilContext(t *testing.T) {
t.Parallel()
var runtime *Runtime
require.Error(t, runtime.Run(context.Background()))
}