package main
import (
"testing"
"time"
"craftdesign.group/quarry/internal/ci"
)
// TestAStepRunningPastTheLimitIsStalled pins quarry#329: a run whose
// claimed task the engine lost keeps a step "running" with no result,
// and the poller must end it rather than show it running forever.
func TestAStepRunningPastTheLimitIsStalled(t *testing.T) {
now := time.Date(2026, 10, 2, 23, 0, 0, 0, time.UTC)
at := func(d time.Duration) string { return now.Add(-d).Format(time.RFC3339Nano) }
run := func(steps map[string]ci.Step) ci.Run { return ci.Run{Status: "running", Steps: steps} }
cases := []struct {
name string
run ci.Run
want bool
}{
{"running past the limit", run(map[string]ci.Step{"test": {Status: "running", StartedAt: at(3 * time.Hour)}}), true},
{"running within the limit", run(map[string]ci.Step{"test": {Status: "running", StartedAt: at(30 * time.Minute)}}), false},
{"no start time", run(map[string]ci.Step{"test": {Status: "running"}}), false},
{"queued, not running", run(map[string]ci.Step{"test": {Status: "queued", StartedAt: at(3 * time.Hour)}}), false},
{"finished run", ci.Run{Status: "completed", Steps: map[string]ci.Step{"test": {Status: "running", StartedAt: at(3 * time.Hour)}}}, false},
}
for _, c := range cases {
if got := stalledRun(c.run, now, 2*time.Hour); got != c.want {
t.Errorf("%s: stalledRun = %v, want %v", c.name, got, c.want)
}
}
}