152 lines
7.0 KiB
Go
152 lines
7.0 KiB
Go
package main
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// novox/hq issue 783: mesh-catalog commit b5417c28 was pushed while #305 (from branch adr-359-mesh-mail-733) was
|
|
// open, so this owner recorded its delivery as #305's. #305 then closed unmerged (its base branch had been
|
|
// deleted), and #315, opened from the same branch and head, merged it as 0914a33f. The delivery stayed stopped
|
|
// ("the pull request closed unmerged"), though it recorded merged_as 0914a33f: a rule did not hold — a delivery
|
|
// keyed by commit follows the pull request that merges that commit, and a closed duplicate does not end it — and
|
|
// the walk that carried the merge waited 64 minutes for this owner's word until a person's `plans go` released it.
|
|
//
|
|
// A delivery stopped only because its pull request closed unmerged, with no merge recorded, does not end its
|
|
// commit's delivery for another pull request with the same head: it is started over, under the same id, for the
|
|
// pull request that announces or merges it next.
|
|
|
|
const (
|
|
head783, merge783 = "d305d305d305d305", "d315d315d315d315"
|
|
head783b, merge783b = "d306d306d306d306", "d316d316d316d316"
|
|
head783c = "d307d307d307d307"
|
|
head783d, merge783d = "d308d308d308d308", "d318d318d318d318"
|
|
catalog783 = "novox/mesh-catalog"
|
|
branch783 = "adr-359-mesh-mail-733"
|
|
)
|
|
|
|
// TestADeliveryStoppedByAClosedDuplicateFollowsThePullRequestThatMergesItsCommit is the issue's own shape: #305
|
|
// announced, closed unmerged (stopped); #315 announced from the same head, checked and readied; #315 merges it,
|
|
// and the walk that answers that merge is let go — the delivery follows #315, never stuck on #305's stop.
|
|
func TestADeliveryStoppedByAClosedDuplicateFollowsThePullRequestThatMergesItsCommit(t *testing.T) {
|
|
w := newWorld(t)
|
|
id := IDOf(catalog783, head783)
|
|
|
|
w.h.PullUpdated(pr(catalog783, 305, head783, branch783, "src/a.go"))
|
|
w.h.PullClosed(pr(catalog783, 305, head783, branch783))
|
|
if w.state(id) != Stopped {
|
|
t.Fatalf("#305 closed unmerged left it %s; want stopped", w.state(id))
|
|
}
|
|
|
|
w.h.PullUpdated(pr(catalog783, 315, head783, branch783, "src/a.go"))
|
|
if d := w.delivery(id); d.State == Stopped || d.Number != 315 {
|
|
t.Fatalf("#315, the same head, left it %s, Number %d; want started over for #315, not stopped", d.State, d.Number)
|
|
}
|
|
if d := w.delivery(id); !strings.Contains(d.Transitions[len(d.Transitions)-1].Why, "#305 with the same head closed unmerged") {
|
|
t.Fatalf("the start-over's transition names what it replaces: %q", d.Transitions[len(d.Transitions)-1].Why)
|
|
}
|
|
|
|
w.h.Checked(verdict(catalog783, 315, head783, "pass"))
|
|
if d := w.delivery(id); d.State != Ready {
|
|
t.Fatalf("a passing verdict for #315 left it %s", d.State)
|
|
}
|
|
|
|
walk := w.ctl.put(aWalk("plan-783", catalog783, merge783, true))
|
|
w.h.WalkMoved(walk)
|
|
w.h.PullMerged(merged(catalog783, 315, head783, merge783))
|
|
if d := w.delivery(id); d.State != Published || d.Number != 315 {
|
|
t.Fatalf("#315's merge left it %s, Number %d; want published under #315", d.State, d.Number)
|
|
}
|
|
|
|
w.settleAll()
|
|
if len(w.ctl.delivers) != 1 || w.ctl.delivers[0] != "plan-783" {
|
|
t.Fatalf("the walk that answers #315's merge was not let go: %v", w.ctl.delivers)
|
|
}
|
|
if d := w.delivery(id); d.State != Delivering {
|
|
t.Fatalf("let go, it is %s; want delivering", d.State)
|
|
}
|
|
}
|
|
|
|
// TestAMergeWithoutAnAnnouncementStartsOverAStoppedDuplicateToo is decision 4: the merging pull request is never
|
|
// announced on its own (heard only as `pull.merged`) — the start-over happens in PullMerged itself, not only in
|
|
// PullUpdated, so a merge heard without the open announcement is not lost either.
|
|
func TestAMergeWithoutAnAnnouncementStartsOverAStoppedDuplicateToo(t *testing.T) {
|
|
w := newWorld(t)
|
|
id := IDOf(catalog783, head783b)
|
|
|
|
w.h.PullUpdated(pr(catalog783, 306, head783b, branch783+"-b", "src/b.go"))
|
|
w.h.PullClosed(pr(catalog783, 306, head783b, branch783+"-b"))
|
|
if w.state(id) != Stopped {
|
|
t.Fatalf("#306 closed unmerged left it %s; want stopped", w.state(id))
|
|
}
|
|
|
|
walk := w.ctl.put(aWalk("plan-783b", catalog783, merge783b, true))
|
|
w.h.WalkMoved(walk)
|
|
m := merged(catalog783, 316, head783b, merge783b)
|
|
m.HeadChecks = map[string]string{"mesh/merge-gate": "success", "mesh/repo-check": "success"}
|
|
w.h.PullMerged(m)
|
|
if d := w.delivery(id); d.State == Stopped || d.Number != 316 {
|
|
t.Fatalf("#316's merge, heard with no announcement of its own, left it %s, Number %d; want started over for #316",
|
|
d.State, d.Number)
|
|
}
|
|
|
|
w.settleAll()
|
|
if len(w.ctl.delivers) != 1 || w.ctl.delivers[0] != "plan-783b" {
|
|
t.Fatalf("the walk that answers #316's merge was not let go: %v", w.ctl.delivers)
|
|
}
|
|
}
|
|
|
|
// TestAStoppedDeliveryAnnouncedAgainByItsOwnPullRequestStaysStopped guards decision 3's "any other stopped
|
|
// delivery ... is untouched": the same pull request announced again after its own close is the ordinary
|
|
// 'announced again' path, never a start-over, and stays stopped.
|
|
func TestAStoppedDeliveryAnnouncedAgainByItsOwnPullRequestStaysStopped(t *testing.T) {
|
|
w := newWorld(t)
|
|
id := IDOf(catalog783, head783c)
|
|
|
|
w.h.PullUpdated(pr(catalog783, 307, head783c, branch783+"-c", "src/c.go"))
|
|
w.h.PullClosed(pr(catalog783, 307, head783c, branch783+"-c"))
|
|
if w.state(id) != Stopped {
|
|
t.Fatalf("#307 closed unmerged left it %s; want stopped", w.state(id))
|
|
}
|
|
|
|
w.h.PullUpdated(pr(catalog783, 307, head783c, branch783+"-c", "src/c.go"))
|
|
if d := w.delivery(id); d.State != Stopped || d.Number != 307 {
|
|
t.Fatalf("#307 announced again by itself left it %s, Number %d; want it to stay stopped", d.State, d.Number)
|
|
}
|
|
}
|
|
|
|
// TestAMergeHeardLongAfterStartingOverAStoppedDuplicateIsHistoryLikeAnyOtherReplayedMerge is review round 1's
|
|
// decision: a delivery started over from a merge heard without its open announcement (as in decision 4, above)
|
|
// takes FromForge exactly as a first-heard merge does, so one replayed from the bus's history long after it
|
|
// happened still falls under the history rule (novox/hq issue 313) and is never held for a person.
|
|
func TestAMergeHeardLongAfterStartingOverAStoppedDuplicateIsHistoryLikeAnyOtherReplayedMerge(t *testing.T) {
|
|
w := newWorld(t)
|
|
id := IDOf(catalog783, head783d)
|
|
|
|
w.h.PullUpdated(pr(catalog783, 308, head783d, branch783+"-d", "src/d.go"))
|
|
w.h.PullClosed(pr(catalog783, 308, head783d, branch783+"-d"))
|
|
if w.state(id) != Stopped {
|
|
t.Fatalf("#308 closed unmerged left it %s; want stopped", w.state(id))
|
|
}
|
|
|
|
m := merged(catalog783, 318, head783d, merge783d)
|
|
m.MergedAt = w.now.Add(-historyLate - time.Minute).UTC().Format(time.RFC3339)
|
|
w.h.PullMerged(m)
|
|
|
|
d := w.delivery(id)
|
|
if d.State == Stopped || d.Number != 318 {
|
|
t.Fatalf("#318's merge, heard long after it happened with no announcement of its own, left it %s, Number %d; "+
|
|
"want started over for #318", d.State, d.Number)
|
|
}
|
|
if !d.FromForge {
|
|
t.Fatal("a merge heard without its own announcement is made from the forge's word: FromForge is false")
|
|
}
|
|
if d.History == "" {
|
|
t.Fatalf("a merge heard %s after it happened is history, never held for a person; History is empty", historyLate+time.Minute)
|
|
}
|
|
if d.State == Held {
|
|
t.Fatalf("history is never held for a person; state is %s, HeldWhy %q", d.State, d.HeldWhy)
|
|
}
|
|
}
|