Files
mesh-catalog/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/settle_test.go
T

114 lines
4.6 KiB
Go

package main
import (
"strings"
"testing"
"time"
"git.novox.be/novox/mesh-sdk/go/asks"
sdk "git.novox.be/novox/mesh-sdk/go/delivery"
)
// 1280 (novox/hq ADR 0556 clause 5): settle writes one ask for several deliveries held for a merge without a passing check and
// moves none of them; it refuses, asking nothing, a delivery held for another reason and one not held, naming why; the
// operator's Leave keeps them held, and Settle, asked again under a new asking, moves each to merged with the operator's words.
func TestSettleAsksTheOperatorOnceAndMovesOnlyOnTheAnswer(t *testing.T) {
w := newWorld(t)
w.op.auto = false
merged := w.now.Add(-time.Hour)
put := func(id string, state State, why string) *Delivery {
repo, commit, _ := strings.Cut(id, "@")
d := &Delivery{ID: id, Repository: repo, Commit: commit, Number: len(id), Title: "a fix", State: state, Since: merged,
MergedAs: "m" + commit, MergedAt: merged, HeldWhy: why}
w.h.mu.Lock()
w.h.keep(d)
w.h.mu.Unlock()
return d
}
a := put("novox/web@aaaaaaaaaaaa", Held, HeldUnchecked)
b := put("novox/sdk@bbbbbbbbbbbb", Held, HeldUnchecked)
put("novox/web@cccccccccccc", Held, "a conflict on the trunk")
put("novox/web@dddddddddddd", Merged, "")
for ids, words := range map[string]string{
"novox/web@aaaaaaaaaaaa novox/web@cccccccccccc": "held for another reason",
"novox/web@aaaaaaaaaaaa novox/web@dddddddddddd": "not held",
"novox/web@aaaaaaaaaaaa novox/web@eeeeeeeeeeee": "no such delivery",
} {
if _, err := w.h.Settle(strings.Fields(ids), "on every machine since 10-25", aPerson); err == nil || !strings.Contains(err.Error(), words) {
t.Errorf("settle %s: %v, want refused naming %q", ids, err, words)
}
}
if _, err := w.h.Settle([]string{a.ID}, " ", aPerson); err == nil {
t.Error("a settle with no why was asked")
}
if w.op.count() != 0 {
t.Fatalf("a refused settle asked the operator: %d asks", w.op.count())
}
out, err := w.h.Settle([]string{b.ID, a.ID}, "on every machine since 10-25", aPerson)
if err != nil {
t.Fatal(err)
}
key, _ := out["asked"].(string)
if open := w.op.open(); len(open) != 1 || open[0] != key || w.op.count() != 1 {
t.Fatalf("asks open %v (asked %d), want the one key %s", open, w.op.count(), key)
}
ask := w.op.ask(key)
heads := map[string]string{a.ID: a.Commit, b.ID: b.Commit}
group := sdk.SettleGroup([]string{a.ID, b.ID})
for _, o := range ask.Options {
if want, _ := asks.ActDigest(settleAct(group, ask.ID, o.ID, heads)); o.Binds != want {
t.Errorf("the option %s binds %s, not mesh-delivery.settle of these heads", o.ID, o.Binds)
}
}
w.h.hearAsks()
if a.State != Held || b.State != Held {
t.Fatalf("moved before an answer: %s, %s", a.State, b.State)
}
w.op.answer(key, OptionLeave)
w.h.hearAsks()
if a.State != Held || a.Settle == nil || a.Settle.Answer != OptionLeave {
t.Fatalf("after Leave: %s %+v", a.State, a.Settle)
}
// Asked again: a new asking of the same key, under its own id.
if _, err := w.h.Settle([]string{a.ID, b.ID}, "asked again", aPerson); err != nil {
t.Fatal(err)
}
if again := w.op.ask(key); again.ID == ask.ID || a.Settle.Asking != 2 {
t.Fatalf("asked again under %s (asking %d), want a new id", again.ID, a.Settle.Asking)
}
// An answer under a settle key no delivery waits for moves nothing.
other, _ := sdk.MergeAskKey(sdk.SettleGroup([]string{"novox/web@ffffffffffff"}), []sdk.Head{{Repository: "novox/web", Number: 1, Head: "ffffffffffff"}})
w.h.mu.Lock()
w.h.settled(other, sdk.Answer{Option: OptionSettle, Warrant: "x@now", Words: "chose Settle"})
w.h.mu.Unlock()
if a.State != Held || b.State != Held || !strings.Contains(w.logbuf.String(), "covers no delivery") {
t.Fatalf("an answer for other ids moved %s, %s", a.State, b.State)
}
w.op.answer(key, OptionSettle)
w.h.hearAsks()
w.h.mu.Lock()
cancels := len(w.h.cancels)
w.h.mu.Unlock()
if cancels == 0 {
t.Error("the answered settle ask is not taken away")
}
for _, d := range []*Delivery{a, b} {
last := d.Transitions[len(d.Transitions)-1]
if d.State != Merged || last.Event != EvSettled || last.By != "the operator" || !strings.Contains(last.Why, "chose Settle") {
t.Errorf("%s after Settle: %s, %+v", d.ID, d.State, last)
}
}
// A settle ask nobody answers within its bound is taken away; its delivery stays held.
c := put("novox/web@999999999999", Held, HeldUnchecked)
if _, err := w.h.Settle([]string{c.ID}, "once more", aPerson); err != nil {
t.Fatal(err)
}
w.later(AskLasts + time.Minute)
w.h.mu.Lock()
w.h.endStaleSettles()
w.h.mu.Unlock()
if c.State != Held || c.Settle.Answer != "lapsed" {
t.Errorf("a lapsed settle ask: %s %+v", c.State, c.Settle)
}
}