Skip to content
quarry Artifact [b9dbeb2f80]
Login

Artifact [b9dbeb2f80]

Artifact b9dbeb2f805acea083e2786a65534d966f4c9dfdc616077c5a481df4b8d8e8fc:


package oltp

import (
	"testing"
	"time"
)

// A SCHEDULED MINUTE IS CLAIMED ONCE, WHOEVER ASKS AND HOWEVER OFTEN;
// A LATER MINUTE IS A NEW CLAIM, AN EARLIER ONE NEVER IS.
func TestAScheduledMinuteIsClaimedOnce(t *testing.T) {
	db := tokenDB(t, "alpha")
	m := time.Date(2026, 10, 3, 3, 0, 0, 0, time.UTC)
	claim := func(at time.Time) bool {
		ok, err := db.ClaimSchedule("alpha", "ci/nightly.yml", at)
		if err != nil {
			t.Fatal(err)
		}
		return ok
	}
	if !claim(m) || claim(m) || claim(m.Add(-time.Hour)) {
		t.Errorf("FAIL: a minute was claimed twice, or an earlier one after it")
	}
	if !claim(m.Add(24 * time.Hour)) {
		t.Errorf("FAIL: the next day's minute was refused")
	}
	if ok, _ := db.ClaimSchedule("alpha", "ci/other.yml", m); !ok {
		t.Errorf("FAIL: another workflow's minute was refused")
	}
	t.Log("ok: one claim per (repository, workflow, minute), never backwards")
}

// A scheduled run still going is found by its pipeline; a push run is not.
func TestAScheduledRunStillGoingIsFound(t *testing.T) {
	db := tokenDB(t, "alpha")
	db.AddCIRun(CIRun{RunID: "s1", Repo: "alpha", Checkin: "t", Workflow: "w", Pipeline: "ci/nightly.yml", Status: "running"})
	db.AddCIRun(CIRun{RunID: "p1", Repo: "alpha", Checkin: "t", Workflow: "w", Pipeline: "ci/test.yml", Status: "running"})
	db.RecordCIRunStart("s1", "schedule", "", nil)
	db.RecordCIRunStart("p1", "push", "dev", nil)
	if !db.ScheduleRunning("alpha", "ci/nightly.yml") || db.ScheduleRunning("alpha", "ci/test.yml") {
		t.Errorf("FAIL: ScheduleRunning misread the runs")
	}
	if runs, _ := db.CIRuns("alpha", 10); len(runs) != 2 || (runs[0].Event == "" && runs[1].Event == "") {
		t.Errorf("FAIL: CIRuns carries no event: %+v", runs)
	}
	db.CompleteCIRun("s1", "succeeded", "")
	if db.ScheduleRunning("alpha", "ci/nightly.yml") {
		t.Errorf("FAIL: a finished scheduled run still counts as running")
	}
	t.Log("ok: a still-running scheduled run is found; the event rides on the run list")
}

// A scheduled run older than its jobs' timeout (at most six hours) no
// longer blocks the next fire, however it is still listed.
func TestAStaleScheduledRunDoesNotBlock(t *testing.T) {
	db := tokenDB(t, "alpha")
	db.AddCIRun(CIRun{RunID: "s1", Repo: "alpha", Checkin: "t", Workflow: "w", Pipeline: "ci/nightly.yml", Status: "running"})
	db.RecordCIRunStart("s1", "schedule", "", map[string]RunJobGrant{"build": {Letters: "go", Timeout: 30}})
	if !db.ScheduleRunning("alpha", "ci/nightly.yml") {
		t.Fatalf("FAIL: a fresh scheduled run does not block")
	}
	db.w.Exec(`UPDATE ci_run SET started = ? WHERE run_id = 's1'`, time.Now().Add(-31*time.Minute).UTC().Format(time.RFC3339))
	if db.ScheduleRunning("alpha", "ci/nightly.yml") {
		t.Errorf("FAIL: a run past its 30-minute timeout still blocks")
	}
	db.AddCIRun(CIRun{RunID: "s2", Repo: "alpha", Checkin: "t", Workflow: "w", Pipeline: "ci/weekly.yml", Status: "running"})
	db.RecordCIRunStart("s2", "schedule", "", map[string]RunJobGrant{"build": {Letters: "go"}})
	db.w.Exec(`UPDATE ci_run SET started = ? WHERE run_id = 's2'`, time.Now().Add(-5*time.Hour).UTC().Format(time.RFC3339))
	if !db.ScheduleRunning("alpha", "ci/weekly.yml") {
		t.Errorf("FAIL: a run with no stated timeout stopped blocking before six hours")
	}
	db.w.Exec(`UPDATE ci_run SET started = ? WHERE run_id = 's2'`, time.Now().Add(-7*time.Hour).UTC().Format(time.RFC3339))
	if db.ScheduleRunning("alpha", "ci/weekly.yml") {
		t.Errorf("FAIL: a run older than six hours still blocks")
	}
	t.Log("ok: a scheduled run blocks only within its timeout, six hours at most")
}

// A claimed minute that did not start is kept with its reason.
func TestAScheduleFailureIsKept(t *testing.T) {
	db := tokenDB(t, "alpha")
	m := time.Date(2026, 10, 3, 3, 0, 0, 0, time.UTC)
	db.ClaimSchedule("alpha", "ci/nightly.yml", m)
	db.ScheduleFailed("alpha", "ci/nightly.yml", m, "engine unreachable")
	why, at := db.LastScheduleFailure("alpha", "ci/nightly.yml")
	if why != "engine unreachable" || !at.Equal(m) {
		t.Errorf("FAIL: last failure %q at %s", why, at)
	}
	db.ScheduleFailed("alpha", "ci/nightly.yml", m.Add(time.Hour), "")
	if why, _ := db.LastScheduleFailure("alpha", "ci/nightly.yml"); why != "" {
		t.Errorf("FAIL: a later start left the failure %q", why)
	}
	t.Log("ok: the last failed minute and its reason are kept")
}