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.
91 lines
3.3 KiB
Go
91 lines
3.3 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// **A step that waits on the clock says when it is looked at again** (novox/hq ADR 0406 §1, issue 975): there is no
|
|
// tick to find it, so each grace, bound and retry is registered (lookAt) when a look meets it, and the one timer fires
|
|
// a look for the earliest. A look that meets nothing waiting registers nothing.
|
|
|
|
func (w *world) wantedAt() (time.Time, string) {
|
|
w.h.wanted.mu.Lock()
|
|
defer w.h.wanted.mu.Unlock()
|
|
return w.h.wanted.at, w.h.wanted.step
|
|
}
|
|
|
|
func TestALookThatMeetsNothingWaitingOnTheClockWantsNoOtherLook(t *testing.T) {
|
|
w := newWorld(t)
|
|
w.h.PullUpdated(pr("novox/app", 7, readyHead, "feat/x", "src/a.go"))
|
|
w.h.Checked(judgedAt("novox/app", 7, readyHead, "pass", "t1t1t1t1t1t1"))
|
|
w.h.React()
|
|
if at, step := w.wantedAt(); !at.IsZero() {
|
|
t.Fatalf("a look with nothing waiting on the clock wants another at %s for %q", at, step)
|
|
}
|
|
}
|
|
|
|
func TestAProposedDeliveryWhoseHeadHoldsAPassingMeshCheckAtTheForgeAdoptsItAndAsksNoCheck(t *testing.T) {
|
|
w := newWorld(t)
|
|
w.h.PullUpdated(pr("novox/app", 7, readyHead, "feat/x", "src/a.go"))
|
|
id := IDOf("novox/app", readyHead)
|
|
op := openPull("novox/app", 7, readyHead)
|
|
op.Required = []string{ctxCheck}
|
|
op.Checks = map[string]HeadCheck{ctxCheck: {State: "success", Description: "pass " + readyHead[:12] + " | the checker's"}}
|
|
w.forge.open = []OpenPull{op}
|
|
w.h.React()
|
|
w.settleAll()
|
|
if d := w.delivery(id); d.Check == nil || !d.Check.Passes() || d.State != Ready {
|
|
t.Fatalf("the standing verdict was not adopted: %+v (%s)", d.Check, d.State)
|
|
}
|
|
}
|
|
|
|
// 1144/AC3: no timer asks a refused merge again; only an event does (here, mergeAgainNow called directly).
|
|
func TestAMergeTheForgeRefusedIsAskedAgainOnlyOnAnEventWithNoTimer(t *testing.T) {
|
|
w := newWorld(t)
|
|
w.h.PullUpdated(pr("novox/app", 7, readyHead, "feat/x", "src/a.go"))
|
|
w.h.Checked(judgedAt("novox/app", 7, readyHead, "pass", "t1t1t1t1t1t1"))
|
|
w.forge.refuse = errors.New("the forge refused gitea_merge_pull_request: not mergeable yet")
|
|
w.forge.open = []OpenPull{openPull("novox/app", 7, readyHead)}
|
|
w.h.wantForge()
|
|
w.settleAll()
|
|
if len(w.forge.merges) != 1 {
|
|
t.Fatalf("merges %v", w.forge.merges)
|
|
}
|
|
if at, step := w.wantedAt(); !at.IsZero() {
|
|
t.Fatalf("the refused merge wants a timer at %s for %q; it waits for the next event", at, step)
|
|
}
|
|
w.forge.refuse = nil
|
|
w.settleAll()
|
|
if len(w.forge.merges) != 1 {
|
|
t.Fatalf("asked again at a look with no event: %v", w.forge.merges)
|
|
}
|
|
again := w.delivery(IDOf("novox/app", readyHead))
|
|
w.h.mu.Lock()
|
|
w.h.mergeAgainNow(again)
|
|
w.h.mu.Unlock()
|
|
w.settleAll()
|
|
if len(w.forge.merges) != 2 || w.delivery(IDOf("novox/app", readyHead)).Ready.Merged == nil {
|
|
t.Fatalf("the refused merge was not asked again at the timer: %v", w.forge.merges)
|
|
}
|
|
}
|
|
|
|
func TestAnEffectTheBusCouldNotTakeIsTriedAgainAtItsTimeByTheTimerAlone(t *testing.T) {
|
|
w := newWorld(t)
|
|
w.owed.down = true
|
|
w.h.PullUpdated(pr("novox/app", 7, readyHead, "feat/x", "src/a.go"))
|
|
w.h.React()
|
|
at, step := w.wantedAt()
|
|
if at.IsZero() || !strings.Contains(step, "owed") || at.After(w.now.Add(retryFirst)) {
|
|
t.Fatalf("the look wanted at %s for %q; wanted within %s for the owed effect", at, step, retryFirst)
|
|
}
|
|
w.owed.down = false
|
|
w.later(retryFirst + time.Second)
|
|
w.h.React()
|
|
if len(w.forge.notes) == 0 {
|
|
t.Fatal("the owed effect was not tried again at its time")
|
|
}
|
|
}
|