Files
galaxy-game/gamemaster/internal/domain/runtime/model_test.go
T
2026-05-03 07:59:03 +02:00

131 lines
3.8 KiB
Go

package runtime
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func validRunningRecord() RuntimeRecord {
created := time.Date(2026, 4, 27, 12, 0, 0, 0, time.UTC)
started := created.Add(time.Minute)
updated := started.Add(time.Minute)
next := updated.Add(time.Hour)
return RuntimeRecord{
GameID: "game-1",
Status: StatusRunning,
EngineEndpoint: "http://galaxy-game-1:8080",
CurrentImageRef: "ghcr.io/galaxy/game:v1.2.3",
CurrentEngineVersion: "v1.2.3",
TurnSchedule: "0 18 * * *",
CurrentTurn: 0,
NextGenerationAt: &next,
CreatedAt: created,
UpdatedAt: updated,
StartedAt: &started,
}
}
func TestStatusIsKnown(t *testing.T) {
for _, status := range AllStatuses() {
assert.True(t, status.IsKnown(), "want known: %q", status)
}
assert.False(t, Status("exotic").IsKnown())
assert.False(t, Status("").IsKnown())
}
func TestStatusIsTerminal(t *testing.T) {
assert.True(t, StatusFinished.IsTerminal())
for _, status := range AllStatuses() {
if status == StatusFinished {
continue
}
assert.False(t, status.IsTerminal(), "%q must not be terminal", status)
}
}
func TestAllStatusesStable(t *testing.T) {
first := AllStatuses()
second := AllStatuses()
assert.Equal(t, first, second)
assert.Len(t, first, 7)
}
func TestRuntimeRecordValidateHappy(t *testing.T) {
require.NoError(t, validRunningRecord().Validate())
}
func TestRuntimeRecordValidateAcceptsStarting(t *testing.T) {
record := validRunningRecord()
record.Status = StatusStarting
record.StartedAt = nil
record.NextGenerationAt = nil
assert.NoError(t, record.Validate())
}
func TestRuntimeRecordValidateRequiresFinishedAt(t *testing.T) {
record := validRunningRecord()
record.Status = StatusFinished
record.FinishedAt = nil
assert.Error(t, record.Validate())
finished := record.UpdatedAt.Add(time.Minute)
record.FinishedAt = &finished
assert.NoError(t, record.Validate())
}
func TestRuntimeRecordValidateRequiresStoppedAtForStopped(t *testing.T) {
record := validRunningRecord()
record.Status = StatusStopped
assert.Error(t, record.Validate())
stopped := record.UpdatedAt.Add(time.Minute)
record.StoppedAt = &stopped
assert.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 image ref", func(r *RuntimeRecord) { r.CurrentImageRef = "" }},
{"empty engine version", func(r *RuntimeRecord) { r.CurrentEngineVersion = "" }},
{"empty turn schedule", func(r *RuntimeRecord) { r.TurnSchedule = "" }},
{"negative turn", func(r *RuntimeRecord) { r.CurrentTurn = -1 }},
{"zero created at", func(r *RuntimeRecord) { r.CreatedAt = time.Time{} }},
{"zero updated at", func(r *RuntimeRecord) { r.UpdatedAt = time.Time{} }},
{"updated before created", func(r *RuntimeRecord) {
r.UpdatedAt = r.CreatedAt.Add(-time.Minute)
}},
{"started before created", func(r *RuntimeRecord) {
before := r.CreatedAt.Add(-time.Minute)
r.StartedAt = &before
}},
{"running missing started at", func(r *RuntimeRecord) { r.StartedAt = nil }},
{"starting with started at", func(r *RuntimeRecord) {
r.Status = StatusStarting
// keep StartedAt set
}},
{"zero next generation at", func(r *RuntimeRecord) {
zero := time.Time{}
r.NextGenerationAt = &zero
}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
record := validRunningRecord()
tt.mutate(&record)
assert.Error(t, record.Validate())
})
}
}