Skip to content
quarry Artifact [0510f69a4c]
Login

Artifact [0510f69a4c]

Artifact 0510f69a4c98edc690e663a42b1af0067e9e4fa623d2e0b8d95c7a1bc86a20e1:


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)
		}
	}
}