package runtime import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestStatusIsKnown(t *testing.T) { for _, status := range AllStatuses() { assert.Truef(t, status.IsKnown(), "expected %q known", status) } assert.False(t, Status("").IsKnown()) assert.False(t, Status("unknown").IsKnown()) } func TestStatusIsTerminal(t *testing.T) { assert.True(t, StatusRemoved.IsTerminal()) for _, status := range []Status{StatusRunning, StatusStopped} { assert.Falsef(t, status.IsTerminal(), "expected %q non-terminal", status) } } func TestAllStatuses(t *testing.T) { statuses := AllStatuses() assert.ElementsMatch(t, []Status{StatusRunning, StatusStopped, StatusRemoved}, statuses, ) statuses[0] = "tampered" assert.Equal(t, StatusRunning, AllStatuses()[0], "AllStatuses must return an independent slice") } func runningRecord() RuntimeRecord { created := time.Date(2026, 4, 27, 12, 0, 0, 0, time.UTC) started := created.Add(time.Second) return RuntimeRecord{ GameID: "game-test", Status: StatusRunning, CurrentContainerID: "container-1", CurrentImageRef: "galaxy/game:1.0.0", EngineEndpoint: "http://galaxy-game-game-test:8080", StatePath: "/var/lib/galaxy/games/game-test", DockerNetwork: "galaxy-net", StartedAt: &started, LastOpAt: started, CreatedAt: created, } } func TestRuntimeRecordValidateRunningHappy(t *testing.T) { require.NoError(t, runningRecord().Validate()) } func TestRuntimeRecordValidateStoppedHappy(t *testing.T) { record := runningRecord() stopped := record.StartedAt.Add(time.Minute) record.Status = StatusStopped record.StoppedAt = &stopped record.LastOpAt = stopped require.NoError(t, record.Validate()) } func TestRuntimeRecordValidateRemovedHappy(t *testing.T) { record := runningRecord() stopped := record.StartedAt.Add(time.Minute) removed := stopped.Add(time.Minute) record.Status = StatusRemoved record.StoppedAt = &stopped record.RemovedAt = &removed record.CurrentContainerID = "" record.LastOpAt = removed require.NoError(t, record.Validate()) } func TestRuntimeRecordValidateRejects(t *testing.T) { tests := []struct { name string mutate func(*RuntimeRecord) }{ {"empty game id", func(r *RuntimeRecord) { r.GameID = "" }}, {"unknown status", func(r *RuntimeRecord) { r.Status = "exotic" }}, {"empty engine endpoint", func(r *RuntimeRecord) { r.EngineEndpoint = "" }}, {"empty state path", func(r *RuntimeRecord) { r.StatePath = "" }}, {"empty docker network", func(r *RuntimeRecord) { r.DockerNetwork = "" }}, {"zero last op at", func(r *RuntimeRecord) { r.LastOpAt = time.Time{} }}, {"zero created at", func(r *RuntimeRecord) { r.CreatedAt = time.Time{} }}, {"last op at before created at", func(r *RuntimeRecord) { r.LastOpAt = r.CreatedAt.Add(-time.Second) }}, {"running without container id", func(r *RuntimeRecord) { r.CurrentContainerID = "" }}, {"running without image ref", func(r *RuntimeRecord) { r.CurrentImageRef = "" }}, {"running without started at", func(r *RuntimeRecord) { r.StartedAt = nil }}, {"started at before created at", func(r *RuntimeRecord) { before := r.CreatedAt.Add(-time.Second) r.StartedAt = &before }}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { record := runningRecord() tt.mutate(&record) assert.Error(t, record.Validate()) }) } } func TestRuntimeRecordValidateRejectsStoppedWithoutStoppedAt(t *testing.T) { record := runningRecord() record.Status = StatusStopped record.StoppedAt = nil assert.Error(t, record.Validate()) } func TestRuntimeRecordValidateRejectsStoppedBeforeStarted(t *testing.T) { record := runningRecord() stopped := record.StartedAt.Add(-time.Second) record.Status = StatusStopped record.StoppedAt = &stopped assert.Error(t, record.Validate()) } func TestRuntimeRecordValidateRejectsRemovedWithoutRemovedAt(t *testing.T) { record := runningRecord() record.Status = StatusRemoved record.RemovedAt = nil assert.Error(t, record.Validate()) } func TestRuntimeRecordValidateRejectsRemovedBeforeCreated(t *testing.T) { record := runningRecord() before := record.CreatedAt.Add(-time.Second) record.Status = StatusRemoved record.RemovedAt = &before assert.Error(t, record.Validate()) }