package ci
import (
"slices"
"testing"
)
// A PUSH OF SEVERAL CHECK-INS ON ONE BRANCH LAUNCHES ITS TIP, IN EITHER
// ARRIVAL ORDER, AND THE TIP'S RUN IS NEVER CANCELLED BY ITS PARENT.
//
// The trigger takes a round's check-ins by arrival (#314), and one push
// can deliver the tip before its parent. The parent launching second
// used to supersede every running build on the branch, the tip's
// included, leaving the branch's verdict on an old check-in and none on
// its tip (e0a264f69bc8, cancelled by 16e797279bf8's launch).
func TestAPushOfSeveralCheckinsLaunchesTheTipAndKeepsIt(t *testing.T) {
for _, order := range [][]string{{"b4", "b5"}, {"b5", "b4"}} {
srv, started, cancelled := cancellingEngine(t)
e := New(srv.URL)
st := &fakeStore{mark: map[string]string{"alpha": "old"}}
repo := landingRepo()
repo.parents = map[string][]string{"b5": {"b4"}}
for _, h := range order {
repo.news = append(repo.news, Checkin{Hash: h, Branch: "feat"})
}
if err := Trigger(e, st, "alpha", repo, "http://x/r/alpha"); err != nil {
t.Fatal(err)
}
if got := started(); !slices.Equal(got, []string{"b5 ci/quarry.json"}) {
t.Errorf("FAIL: arrival %v started %v; want the tip's run only", order, got)
}
if got := cancelled(); len(got) != 0 {
t.Errorf("FAIL: arrival %v cancelled %v; want nothing", order, got)
}
}
t.Log("ok: the tip runs and stays running whichever check-in arrived first")
}
// AN OLDER CHECK-IN ARRIVING AFTER THE TIP DOES NOT CANCEL THE TIP'S
// RUN; A DESCENDANT STILL SUPERSEDES ITS ANCESTOR'S.
func TestSupersedeStopsOnlyAncestors(t *testing.T) {
srv, started, cancelled := cancellingEngine(t)
e := New(srv.URL)
st := &fakeStore{mark: map[string]string{"alpha": "old"}}
repo := landingRepo()
repo.parents = map[string][]string{"b5": {"b4"}, "b6": {"b5"}}
round := func(news ...Checkin) {
repo.news = news
if err := Trigger(e, st, "alpha", repo, "http://x/r/alpha"); err != nil {
t.Fatal(err)
}
}
round(Checkin{Hash: "b5", Branch: "feat"})
round(Checkin{Hash: "b4", Branch: "feat"}) // the parent, arriving late
if got := started(); !slices.Equal(got, []string{"b4 ci/quarry.json", "b5 ci/quarry.json"}) {
t.Fatalf("FAIL: started %v", got)
}
if got := cancelled(); len(got) != 0 {
t.Fatalf("FAIL: the late parent cancelled %v; want the tip's run left alone", got)
}
round(Checkin{Hash: "b6", Branch: "feat"})
started()
if got := cancelled(); !slices.Equal(got, []string{"b4 ci/quarry.json", "b5 ci/quarry.json"}) {
t.Fatalf("FAIL: the new tip cancelled %v; want both its ancestors' runs", got)
}
t.Log("ok: supersede reaches back, never forward")
}