Files
cad-atlas/internal/atlas/runs_test.go
T
mathiasandClaude Opus 4.8 995e428eba
CD / Detect unsubstituted template (push) Successful in 0s
CD / Lint / Test / Vet (push) Successful in 4s
CD / Build & Import (push) Successful in 14s
CD / Deploy via GitOps (push) Has been skipped
feat(atlas): Phase C — recent-runs timeline
A strip of the last 12 runs (aggregate pass/fail/running per run) below the
substrate ribbon, coloured, newest-first, run # on hover. Parsed from the same
Gitea /actions/tasks fetch (RecentRuns, test-first; State refactored to share
the aggregate). No new RBAC. Hidden when no live data.

Verified: build/vet/lint(0)/test green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 07:45:59 +02:00

97 lines
3.1 KiB
Go

package atlas_test
import (
"testing"
"git.d-ma.be/mathias/cad-atlas/internal/atlas"
)
func TestLatestRunJobs_GroupsNewestRunReversedToPipelineOrder(t *testing.T) {
// Gitea returns tasks newest-first (deploy finished last → appears first).
tasks := []byte(`{"workflow_runs":[
{"run_number":28,"name":"Deploy via GitOps","status":"success","head_sha":"633ba153f26abc","display_title":"feat: x"},
{"run_number":28,"name":"Build & Import","status":"success"},
{"run_number":28,"name":"Lint / Test / Vet","status":"success"},
{"run_number":27,"name":"Deploy via GitOps","status":"failure"}
]}`)
s, err := atlas.LatestRunJobs(tasks)
if err != nil {
t.Fatalf("LatestRunJobs: %v", err)
}
if s.Number != 28 || s.SHA != "633ba153f26abc" || s.Title != "feat: x" {
t.Fatalf("summary = %+v", s)
}
// only run 28's jobs, reversed to pipeline order (Lint → Build → Deploy)
got := []string{}
for _, j := range s.Jobs {
got = append(got, j.Name)
}
want := []string{"Lint / Test / Vet", "Build & Import", "Deploy via GitOps"}
if len(got) != 3 || got[0] != want[0] || got[2] != want[2] {
t.Fatalf("jobs = %v, want %v", got, want)
}
if s.State() != "success" {
t.Fatalf("state = %q, want success", s.State())
}
}
func TestRunSummary_StateFailsIfAnyJobFailed(t *testing.T) {
s := atlas.RunSummary{Jobs: []atlas.Job{
{Status: "success"}, {Status: "completed", Conclusion: "failure"},
}}
if s.State() != "failure" {
t.Fatalf("state = %q, want failure", s.State())
}
}
func TestRunNodes_SummaryThenPerJobColoured(t *testing.T) {
s := atlas.RunSummary{Number: 28, SHA: "633ba153f26", Title: "feat: x", Jobs: []atlas.Job{
{Name: "Lint / Test / Vet", Status: "success"},
{Name: "Deploy via GitOps", Status: "failure"},
}}
nodes := atlas.RunNodes(s)
if len(nodes) != 3 {
t.Fatalf("want 3 nodes (summary + 2 jobs), got %d", len(nodes))
}
if nodes[0].Title != "▶ run #28 · failure" || nodes[0].Pill != "var(--coral)" {
t.Fatalf("summary node = %+v", nodes[0])
}
if nodes[1].Title != "Lint / Test / Vet" || nodes[1].Pill != "var(--green)" {
t.Fatalf("job node 1 = %+v", nodes[1])
}
if nodes[2].Pill != "var(--coral)" {
t.Fatalf("failed job pill = %q", nodes[2].Pill)
}
}
func TestRecentRuns_GroupsRunsNewestFirstWithAggregateState(t *testing.T) {
tasks := []byte(`{"workflow_runs":[
{"run_number":28,"name":"Deploy","status":"success"},
{"run_number":28,"name":"Build","status":"success"},
{"run_number":27,"name":"Deploy","status":"completed","conclusion":"failure"},
{"run_number":26,"name":"Build","status":"running"},
{"run_number":25,"name":"Deploy","status":"success"}
]}`)
dots, err := atlas.RecentRuns(tasks, 3)
if err != nil {
t.Fatalf("RecentRuns: %v", err)
}
if len(dots) != 3 {
t.Fatalf("want 3 dots (capped), got %d: %+v", len(dots), dots)
}
want := []atlas.RunDot{{28, "success"}, {27, "failure"}, {26, "running"}}
for i := range want {
if dots[i] != want[i] {
t.Fatalf("dot[%d] = %+v, want %+v", i, dots[i], want[i])
}
}
}
func TestLatestRunJobs_ErrorsWhenEmpty(t *testing.T) {
if _, err := atlas.LatestRunJobs([]byte(`{"workflow_runs":[]}`)); err == nil {
t.Fatal("expected error on empty, got nil")
}
}