- internal/model: единый источник статусов задачи (Status, TraceStatus, машина переходов), без зависимости от storage. - internal/storage: совместимый мост (type Status = model.Status, re-export констант) — внешний код не меняется. - internal/events: шина событий (fan-out, блокирующий Publish с гарантией порядка), события задач/трейсов, отдельная логовая шина + LogWriter, Publisher/NilPublisher для внедрения в Core/Worker. - docs/ui-spec.md: спецификация десктопного UI (Fyne).
50 lines
1.3 KiB
Go
50 lines
1.3 KiB
Go
package model
|
|
|
|
import "testing"
|
|
|
|
func TestValidTransitions(t *testing.T) {
|
|
cases := []struct {
|
|
from, to Status
|
|
want bool
|
|
}{
|
|
{StatusDraft, StatusCollecting, true},
|
|
{StatusDraft, StatusRunning, false},
|
|
{StatusReady, StatusApproved, true},
|
|
{StatusApproved, StatusRunning, true},
|
|
{StatusRunning, StatusSuccess, true},
|
|
{StatusRunning, StatusClosed, false},
|
|
{StatusSuccess, StatusClosed, true},
|
|
{StatusClosed, StatusDraft, false},
|
|
}
|
|
|
|
for _, c := range cases {
|
|
if got := IsValidTransition(c.from, c.to); got != c.want {
|
|
t.Errorf("IsValidTransition(%q, %q) = %v, want %v", c.from, c.to, got, c.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestIsTerminal(t *testing.T) {
|
|
terminal := []Status{StatusSuccess, StatusCancelled, StatusAborted, StatusClosed}
|
|
for _, s := range terminal {
|
|
if !IsTerminal(s) {
|
|
t.Errorf("IsTerminal(%q) = false, want true", s)
|
|
}
|
|
}
|
|
nonTerminal := []Status{StatusDraft, StatusReady, StatusRunning, StatusCollecting, StatusApproved, StatusFailed, StatusTimeout}
|
|
for _, s := range nonTerminal {
|
|
if IsTerminal(s) {
|
|
t.Errorf("IsTerminal(%q) = true, want false", s)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAllStatusesCoverage(t *testing.T) {
|
|
seen := make(map[Status]bool)
|
|
for _, s := range AllStatuses {
|
|
seen[s] = true
|
|
}
|
|
if len(seen) != 11 {
|
|
t.Fatalf("AllStatuses has %d unique statuses, want 11", len(seen))
|
|
}
|
|
} |