Release 6 deletes the plans: the walk half of the holder, the controller port, the carry-over of the former module and the verbs times, what-if, release, stop and retire-history go; the table holds proposed, ready, rejected, merged, held and closed; the delivery's status and view name the source revision the merge moved.
127 lines
4.7 KiB
Go
127 lines
4.7 KiB
Go
package main
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// novox/hq issue 1726: a delivery made from a check's verdict that arrived before its pull request's head was heard
|
|
// (transition "its verdict arrived before its head was heard", as mesh-controller#419 at a47476252772 was) holds no base,
|
|
// branch, title, URLs or review record. The ready pass skipped it in silence, so no Approve was ever asked, and the
|
|
// announcement of the same head, heard later, filled none of it.
|
|
|
|
const verdictFirstBody = "Fixes a bug.\n\nReviewed-by: reviewer@shanks at " + readyHead + "\n"
|
|
|
|
// verdictFirst is the live shape: the verdict heard, the head not, and the delivery ready.
|
|
func verdictFirst(t *testing.T) (*world, string) {
|
|
w := newWorld(t)
|
|
w.op.auto = false
|
|
id := IDOf("novox/app", readyHead)
|
|
w.h.Checked(judgedAt("novox/app", 419, readyHead, "pass", "t1t1t1t1t1t1"))
|
|
w.settleAll()
|
|
d := w.delivery(id)
|
|
if d.State != Ready || d.Base != "" || d.Branch != "" || d.Title != "" || d.HTMLURL != "" {
|
|
t.Fatalf("not the live shape: %s base %q branch %q title %q", d.State, d.Base, d.Branch, d.Title)
|
|
}
|
|
return w, id
|
|
}
|
|
|
|
func TestADeliveryWithoutItsHeadSaysWhatItWaitsForAndAsksNoOne(t *testing.T) {
|
|
w, id := verdictFirst(t)
|
|
if n := len(w.op.open()); n != 0 {
|
|
t.Fatalf("an ask was made for a delivery with no base: %d", n)
|
|
}
|
|
d := w.delivery(id)
|
|
if d.Ready == nil || !strings.Contains(d.Ready.Waits, "announcement") {
|
|
t.Fatalf("it does not say what it waits for: %+v", d.Ready)
|
|
}
|
|
shown, err := w.h.Show(id)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if waits, _ := shown.(map[string]any)["waits"].(string); !strings.Contains(waits, "announcement") {
|
|
t.Fatalf("show waits %q", waits)
|
|
}
|
|
}
|
|
|
|
func TestAnAnnouncementFillsADeliveryMadeFromItsVerdictAndTheOperatorIsAsked(t *testing.T) {
|
|
w, id := verdictFirst(t)
|
|
p := pr("novox/app", 419, readyHead, "fix/x", "src/a.go")
|
|
p.Title, p.Body, p.CloneURL = "Fix x", verdictFirstBody, "https://forge.invalid/novox/app.git"
|
|
w.h.PullUpdated(p)
|
|
w.settleAll()
|
|
d := w.delivery(id)
|
|
if d.Base != "main" || d.Branch != "fix/x" || d.Title != "Fix x" || d.HTMLURL == "" || d.CloneURL == "" ||
|
|
d.ReviewedBy != "reviewer@shanks" || len(d.Paths) != 1 {
|
|
t.Fatalf("the announcement did not fill the delivery: %+v", d)
|
|
}
|
|
if n := len(w.op.open()); n != 1 {
|
|
t.Fatalf("the operator was asked %d times; wanted once", n)
|
|
}
|
|
if d.Ready.Waits != "" && !strings.Contains(d.Ready.Waits, "Approve") {
|
|
t.Fatalf("still waits: %q", d.Ready.Waits)
|
|
}
|
|
}
|
|
|
|
func TestADeliveryWithoutItsHeadPastItsBoundIsStalled(t *testing.T) {
|
|
w, id := verdictFirst(t)
|
|
if s := w.h.Stalled(); len(s) != 0 {
|
|
t.Fatalf("stalled before its bound: %+v", s)
|
|
}
|
|
w.later(headHeardBound + time.Minute)
|
|
w.settleAll()
|
|
var found bool
|
|
for _, l := range w.h.Stalled() {
|
|
if l.ID == id && strings.Contains(l.Says, "announcement") {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Fatalf("not stalled past its bound: %+v", w.h.Stalled())
|
|
}
|
|
}
|
|
|
|
// A head asked, then a push whose verdict is heard before its head: the announcement of the new head supersedes the old
|
|
// one exactly as a first announcement does, so one Approve stands, for the new head.
|
|
func TestAnAnnouncementFillingAVerdictFirstHeadSupersedesTheOlderHeadAndItsAsk(t *testing.T) {
|
|
w := newWorld(t)
|
|
w.op.auto = false
|
|
a, b := IDOf("novox/app", readyHead), IDOf("novox/app", pushed)
|
|
w.h.PullUpdated(pr("novox/app", 419, readyHead, "fix/x", "src/a.go"))
|
|
w.h.Checked(judgedAt("novox/app", 419, readyHead, "pass", "t1t1t1t1t1t1"))
|
|
w.settleAll()
|
|
if n := len(w.op.open()); n != 1 {
|
|
t.Fatalf("head A: %d asks open; wanted 1", n)
|
|
}
|
|
w.h.Checked(judgedAt("novox/app", 419, pushed, "pass", "t1t1t1t1t1t1"))
|
|
w.settleAll()
|
|
w.h.PullUpdated(pr("novox/app", 419, pushed, "fix/x", "src/a.go"))
|
|
w.settleAll()
|
|
if got := w.delivery(a); got.NewerHead != pushed || got.State != Closed {
|
|
t.Fatalf("head A is %s with newer head %q; wanted closed by %s", got.State, got.NewerHead, pushed)
|
|
}
|
|
if got := w.delivery(b); got.Base != "main" || got.Branch != "fix/x" {
|
|
t.Fatalf("head B not filled: %+v", got)
|
|
}
|
|
if n := len(w.op.open()); n != 1 {
|
|
t.Fatalf("%d asks open; wanted one, for the new head", n)
|
|
}
|
|
}
|
|
|
|
// A description edit is a natural trigger too: it fills a delivery made from its verdict.
|
|
func TestAnEditOfThePullRequestFillsADeliveryMadeFromItsVerdict(t *testing.T) {
|
|
w, id := verdictFirst(t)
|
|
p := pr("novox/app", 419, readyHead, "fix/x")
|
|
p.Title, p.Body = "Fix x", verdictFirstBody
|
|
w.h.PullEdited(p)
|
|
w.settleAll()
|
|
d := w.delivery(id)
|
|
if d.Base != "main" || d.Branch != "fix/x" || d.Title != "Fix x" || d.ReviewedBy != "reviewer@shanks" {
|
|
t.Fatalf("the edit did not fill the delivery: %+v", d)
|
|
}
|
|
if n := len(w.op.open()); n != 1 {
|
|
t.Fatalf("the operator was asked %d times; wanted once", n)
|
|
}
|
|
}
|