178 lines
5.1 KiB
Go
178 lines
5.1 KiB
Go
package game
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestStatusIsKnown(t *testing.T) {
|
|
for _, status := range []Status{
|
|
StatusDraft,
|
|
StatusEnrollmentOpen,
|
|
StatusReadyToStart,
|
|
StatusStarting,
|
|
StatusStartFailed,
|
|
StatusRunning,
|
|
StatusPaused,
|
|
StatusFinished,
|
|
StatusCancelled,
|
|
} {
|
|
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, StatusFinished.IsTerminal())
|
|
assert.True(t, StatusCancelled.IsTerminal())
|
|
|
|
for _, status := range []Status{
|
|
StatusDraft,
|
|
StatusEnrollmentOpen,
|
|
StatusReadyToStart,
|
|
StatusStarting,
|
|
StatusStartFailed,
|
|
StatusRunning,
|
|
StatusPaused,
|
|
} {
|
|
assert.Falsef(t, status.IsTerminal(), "expected %q non-terminal", status)
|
|
}
|
|
}
|
|
|
|
func TestTriggerIsKnown(t *testing.T) {
|
|
for _, trigger := range []Trigger{
|
|
TriggerCommand,
|
|
TriggerManual,
|
|
TriggerDeadline,
|
|
TriggerGap,
|
|
TriggerRuntimeEvent,
|
|
TriggerExternalBlock,
|
|
} {
|
|
assert.Truef(t, trigger.IsKnown(), "expected %q known", trigger)
|
|
}
|
|
|
|
assert.False(t, Trigger("").IsKnown())
|
|
assert.False(t, Trigger("bogus").IsKnown())
|
|
}
|
|
|
|
func TestTransitionHappyPathsCoverFrozenTable(t *testing.T) {
|
|
cases := []struct {
|
|
from Status
|
|
to Status
|
|
triggers []Trigger
|
|
}{
|
|
{StatusDraft, StatusEnrollmentOpen, []Trigger{TriggerCommand}},
|
|
{StatusEnrollmentOpen, StatusReadyToStart, []Trigger{TriggerManual, TriggerDeadline, TriggerGap}},
|
|
{StatusReadyToStart, StatusStarting, []Trigger{TriggerCommand}},
|
|
{StatusStarting, StatusRunning, []Trigger{TriggerRuntimeEvent}},
|
|
{StatusStarting, StatusPaused, []Trigger{TriggerRuntimeEvent}},
|
|
{StatusStarting, StatusStartFailed, []Trigger{TriggerRuntimeEvent}},
|
|
{StatusStartFailed, StatusReadyToStart, []Trigger{TriggerCommand}},
|
|
{StatusRunning, StatusPaused, []Trigger{TriggerCommand}},
|
|
{StatusRunning, StatusFinished, []Trigger{TriggerRuntimeEvent}},
|
|
{StatusPaused, StatusRunning, []Trigger{TriggerCommand}},
|
|
{StatusPaused, StatusFinished, []Trigger{TriggerRuntimeEvent}},
|
|
{StatusDraft, StatusCancelled, []Trigger{TriggerCommand, TriggerExternalBlock}},
|
|
{StatusEnrollmentOpen, StatusCancelled, []Trigger{TriggerCommand, TriggerExternalBlock}},
|
|
{StatusReadyToStart, StatusCancelled, []Trigger{TriggerCommand, TriggerExternalBlock}},
|
|
{StatusStartFailed, StatusCancelled, []Trigger{TriggerCommand, TriggerExternalBlock}},
|
|
{StatusStarting, StatusCancelled, []Trigger{TriggerExternalBlock}},
|
|
{StatusRunning, StatusCancelled, []Trigger{TriggerExternalBlock}},
|
|
{StatusPaused, StatusCancelled, []Trigger{TriggerExternalBlock}},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
for _, trigger := range tc.triggers {
|
|
t.Run(string(tc.from)+"->"+string(tc.to)+"/"+string(trigger), func(t *testing.T) {
|
|
require.NoError(t, Transition(tc.from, tc.to, trigger))
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTransitionRejectsUnknownPair(t *testing.T) {
|
|
err := Transition(StatusDraft, StatusRunning, TriggerCommand)
|
|
|
|
require.Error(t, err)
|
|
assert.True(t, errors.Is(err, ErrInvalidTransition))
|
|
|
|
var typed *InvalidTransitionError
|
|
require.True(t, errors.As(err, &typed))
|
|
assert.Equal(t, StatusDraft, typed.From)
|
|
assert.Equal(t, StatusRunning, typed.To)
|
|
assert.Equal(t, TriggerCommand, typed.Trigger)
|
|
}
|
|
|
|
func TestTransitionRejectsWrongTrigger(t *testing.T) {
|
|
err := Transition(StatusDraft, StatusEnrollmentOpen, TriggerDeadline)
|
|
|
|
require.Error(t, err)
|
|
assert.True(t, errors.Is(err, ErrInvalidTransition))
|
|
}
|
|
|
|
func TestTransitionRejectsUnknownStatusOrTrigger(t *testing.T) {
|
|
require.Error(t, Transition(Status("bogus"), StatusEnrollmentOpen, TriggerCommand))
|
|
require.Error(t, Transition(StatusDraft, Status("bogus"), TriggerCommand))
|
|
require.Error(t, Transition(StatusDraft, StatusEnrollmentOpen, Trigger("bogus")))
|
|
}
|
|
|
|
func TestTransitionsOutOfTerminalStatusAllRejected(t *testing.T) {
|
|
triggers := []Trigger{
|
|
TriggerCommand,
|
|
TriggerManual,
|
|
TriggerDeadline,
|
|
TriggerGap,
|
|
TriggerRuntimeEvent,
|
|
TriggerExternalBlock,
|
|
}
|
|
|
|
for _, from := range []Status{StatusFinished, StatusCancelled} {
|
|
for _, to := range []Status{
|
|
StatusDraft,
|
|
StatusEnrollmentOpen,
|
|
StatusReadyToStart,
|
|
StatusStarting,
|
|
StatusStartFailed,
|
|
StatusRunning,
|
|
StatusPaused,
|
|
StatusFinished,
|
|
StatusCancelled,
|
|
} {
|
|
for _, trigger := range triggers {
|
|
if from == to {
|
|
continue
|
|
}
|
|
err := Transition(from, to, trigger)
|
|
require.Errorf(t, err, "%s->%s via %s should be rejected", from, to, trigger)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAllowedTransitionsSnapshotMatchesTable(t *testing.T) {
|
|
snapshot := AllowedTransitions()
|
|
|
|
count := 0
|
|
for _, inner := range snapshot {
|
|
count += len(inner)
|
|
}
|
|
assert.Equal(t, len(allowedTransitions), count)
|
|
|
|
for key, triggers := range allowedTransitions {
|
|
inner, ok := snapshot[key.from]
|
|
require.Truef(t, ok, "expected from=%s in snapshot", key.from)
|
|
|
|
list, ok := inner[key.to]
|
|
require.Truef(t, ok, "expected to=%s under from=%s", key.to, key.from)
|
|
|
|
for trigger := range triggers {
|
|
assert.Containsf(t, list, trigger, "missing trigger %q for %s->%s", trigger, key.from, key.to)
|
|
}
|
|
}
|
|
}
|