mesh/delivery merged: source.main moved to novox/mesh-catalog@02597b66d7de
mesh/check checking 3c6f2dc274a9 on 457c60972c59
189 lines
7.9 KiB
Go
189 lines
7.9 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// The forge's answer for novox/mesh-delivery#5, read from gitea.gitea_get_pull_request on 2026-10-27 (shortened): merged, closed,
|
|
// its merge commit and moment. mesh-delivery's checks carries the same `pull` block and no `delivery` block for it.
|
|
const forgePullMerged = `{"pull":{"base":"main","head":"feat/delivery-parts","merged":true,"merged_at":"2026-10-19T18:05:16Z",` +
|
|
`"merge_commit_sha":"1325c8b452c8fa65c478af6815887870a1f42e7b","number":5,"state":"closed"}}`
|
|
|
|
func TestAPullRequestWithNoFixRecordLearnsItsMerge(t *testing.T) {
|
|
mergedAt := time.Date(2026, 10, 19, 18, 5, 16, 0, time.UTC)
|
|
merged := Delivery{Pulled: true, Merged: true, MergedAs: "1325c8b452c8fa65c478af6815887870a1f42e7b", MergedAt: &mergedAt, Repository: "novox/mesh-catalog"}
|
|
closed := Delivery{Pulled: true, Closed: true}
|
|
open := Delivery{Pulled: true}
|
|
for _, c := range []struct {
|
|
name string
|
|
delivery Delivery
|
|
deliveryEr error
|
|
forge *Delivery
|
|
forgeEr error
|
|
want string // the delivery line after learning
|
|
wantErr bool
|
|
}{
|
|
{name: "mesh-delivery's pull says merged", delivery: merged, want: "fix merged, not delivered: mesh-catalog#50"},
|
|
{name: "mesh-delivery cannot, the forge says merged", deliveryEr: errors.New("down"), forge: &merged,
|
|
want: "fix merged, not delivered: mesh-catalog#50"},
|
|
{name: "mesh-delivery says nothing of the pull, the forge says merged", forge: &merged, want: "fix merged, not delivered: mesh-catalog#50"},
|
|
{name: "closed without merging is withdrawn", delivery: closed, want: "fix withdrawn: mesh-catalog#50 closed without merging"},
|
|
{name: "still open stays unheard", delivery: open, want: "nothing heard from the delivery of mesh-catalog#50"},
|
|
{name: "a forge that cannot say leaves it", forgeEr: errors.New("forge down"), want: "nothing heard from the delivery of mesh-catalog#50"},
|
|
{name: "neither can say", deliveryEr: errors.New("down"), forgeEr: errors.New("forge down"), want: "nothing heard from the delivery of mesh-catalog#50", wantErr: true},
|
|
} {
|
|
t.Run(c.name, func(t *testing.T) {
|
|
h := newHarness(t)
|
|
n := fixIssue(t, h, "mesh-catalog#50")
|
|
h.Deliveries = func(string, string) (Delivery, error) { return c.delivery, c.deliveryEr }
|
|
h.Pull = func(string, string) (Delivery, error) {
|
|
if c.forge != nil {
|
|
return *c.forge, nil
|
|
}
|
|
return Delivery{}, errOr(c.forgeEr)
|
|
}
|
|
_, err := h.LearnFixes(n)
|
|
if (err != nil) != c.wantErr {
|
|
t.Fatalf("error %v, wanted error %v", err, c.wantErr)
|
|
}
|
|
if v, _ := h.View(n); v.Delivery != c.want {
|
|
t.Fatalf("%q, wanted %q", v.Delivery, c.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func errOr(e error) error {
|
|
if e == nil {
|
|
return errors.New("the forge has no such pull request")
|
|
}
|
|
return e
|
|
}
|
|
|
|
// A fix merged before the tracker heard deliveries: the delivered event itself learns its merge and covers it, a resolved issue's
|
|
// included; and the sweep learns it with no event.
|
|
func TestAFixMergedBeforeTheTrackerHeardDeliveriesIsDeliveredByTheNextEventOfItsRepository(t *testing.T) {
|
|
mergedAs := "1325c8b452c8fa65c478af6815887870a1f42e7b"
|
|
forge := func(string, string) (Delivery, error) {
|
|
return Delivery{Pulled: true, Merged: true, MergedAs: mergedAs, Repository: "novox/mesh-catalog"}, nil
|
|
}
|
|
contains := func(_, _, commit, in string) (bool, error) {
|
|
return commit == mergedAs && in == "ffffffffffff0000", nil
|
|
}
|
|
heads := map[string]string{"novox/mesh-catalog": "ffffffffffff0000"}
|
|
delivered := "delivered to every machine it should reach"
|
|
|
|
h := newHarness(t)
|
|
n := fixIssue(t, h, "mesh-catalog#51")
|
|
h.Pull, h.Contains = forge, contains
|
|
viewSays(t, h, 30, "", heads)
|
|
if v, _ := h.View(n); v.Delivery != delivered {
|
|
t.Fatalf("the event did not cover the old fix: %q", v.Delivery)
|
|
}
|
|
if f := fixOf(get(t, h, n), "mesh-catalog#51"); f == nil || f.MergedAs != mergedAs || f.Repository != "novox/mesh-catalog" || f.MergedAt != nil && f.MergedAt.IsZero() {
|
|
t.Fatalf("fix %+v", f)
|
|
}
|
|
|
|
// A resolved issue is learned by the sweep, which then waits for the next event, not for ever.
|
|
h2 := newHarness(t)
|
|
m := fixIssue(t, h2, "mesh-catalog#52")
|
|
if _, err := h2.Move(MoveAsk{Number: m, Status: StatusResolved, FixedBy: []string{"mesh-catalog#52"}}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if v, _ := h2.View(m); !strings.HasPrefix(v.Delivery, "nothing heard") {
|
|
t.Fatalf("before: %q", v.Delivery)
|
|
}
|
|
h2.Pull, h2.Contains = forge, contains
|
|
if _, err := h2.Sweep(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if v, _ := h2.View(m); v.Delivery != "fix merged, not delivered: mesh-catalog#52" {
|
|
t.Fatalf("after the sweep: %q", v.Delivery)
|
|
}
|
|
viewSays(t, h2, 31, "", heads)
|
|
if v, _ := h2.View(m); v.Delivery != delivered {
|
|
t.Fatalf("after the event: %q", v.Delivery)
|
|
}
|
|
}
|
|
|
|
func TestTheForgesRealPullAnswerIsReadAsMerged(t *testing.T) {
|
|
var out struct {
|
|
Pull pullFacts `json:"pull"`
|
|
}
|
|
if err := json.Unmarshal([]byte(forgePullMerged), &out); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var d Delivery
|
|
d.fromPull(out.Pull, "novox/mesh-delivery")
|
|
if !d.Pulled || !d.Merged || d.Closed || d.MergedAs != "1325c8b452c8fa65c478af6815887870a1f42e7b" ||
|
|
d.MergedAt == nil || d.MergedAt.Format(time.RFC3339) != "2026-10-19T18:05:16Z" || d.Repository != "novox/mesh-delivery" {
|
|
t.Fatalf("%+v", d)
|
|
}
|
|
}
|
|
|
|
// A merge learned late is kept as of the moment it was learned: the stuck bound runs from then, so an old merge raises no
|
|
// false warning in the sweep that learned it; and an issue closed before its fix was timed keeps no fix time when a late
|
|
// delivery covers it.
|
|
func TestALearnedOldMergeRaisesNoStuckWarningAndTimesNoClosedIssue(t *testing.T) {
|
|
h := newHarness(t)
|
|
now := clocked(h)
|
|
note := ¬ified{}
|
|
h.Notify = note.notify
|
|
old := now.Add(-10 * 24 * time.Hour)
|
|
mergedAs := "1325c8b452c8fa65c478af6815887870a1f42e7b"
|
|
h.Pull = func(string, string) (Delivery, error) {
|
|
return Delivery{Pulled: true, Merged: true, MergedAs: mergedAs, MergedAt: &old, Repository: "novox/mesh-catalog"}, nil
|
|
}
|
|
h.Contains = func(_, _, commit, _ string) (bool, error) { return commit == mergedAs, nil }
|
|
open := fixIssue(t, h, "mesh-catalog#60")
|
|
closed := fixIssue(t, h, "mesh-catalog#61")
|
|
if _, err := h.Move(MoveAsk{Number: closed, Status: StatusResolved, FixedBy: []string{"mesh-catalog#61"}}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := h.Sweep(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(note.said) != 0 || noted(get(t, h, open), "Stuck: the fix") {
|
|
t.Fatalf("a learned old merge was said stuck in the sweep that learned it: %q", note.said)
|
|
}
|
|
if f := fixOf(get(t, h, open), "mesh-catalog#60"); f == nil || f.MergedAt == nil || !f.MergedAt.Equal(old) {
|
|
t.Fatalf("the forge's merge moment is kept: %+v", f)
|
|
}
|
|
*now = now.Add(3 * time.Hour)
|
|
if _, err := h.Sweep(); err != nil || len(note.said) != 1 {
|
|
t.Fatalf("not delivered 3 hours after it was learned: %q %v", note.said, err)
|
|
}
|
|
viewSays(t, h, 40, "", map[string]string{"novox/mesh-catalog": "ffffffffffff0000"})
|
|
if v, _ := h.View(closed); v.Delivery != "delivered to every machine it should reach" || get(t, h, closed).FixTime != nil {
|
|
t.Fatalf("closed issue: %q, fix time %+v", v.Delivery, get(t, h, closed).FixTime)
|
|
}
|
|
}
|
|
|
|
// Pull requests that cannot be learned (still open) do not starve the others: the one asked longest ago goes first.
|
|
func TestTheSweepAsksTheLeastRecentlyAskedPullRequestFirst(t *testing.T) {
|
|
h := newHarness(t)
|
|
var stuck []uint64
|
|
for i := 0; i < MostSweepAsks+2; i++ {
|
|
stuck = append(stuck, fixIssue(t, h, "mesh-catalog#"+itoa(70+i)))
|
|
}
|
|
last := fixIssue(t, h, "mesh-catalog#99")
|
|
h.Pull = func(_, number string) (Delivery, error) {
|
|
if number == "99" {
|
|
return Delivery{Pulled: true, Merged: true, MergedAs: "1325c8b452c8fa65c478af6815887870a1f42e7b"}, nil
|
|
}
|
|
return Delivery{Pulled: true}, nil // still open
|
|
}
|
|
for i := 0; i < 4; i++ {
|
|
if _, err := h.Sweep(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
if v, _ := h.View(last); !strings.HasPrefix(v.Delivery, "fix merged") {
|
|
t.Fatalf("starved by pull requests that cannot be learned: %q (%d of them)", v.Delivery, len(stuck))
|
|
}
|
|
}
|