Files
mesh-catalog/modules/mesh-knowledge/cmd/mesh-knowledge/withdraw_test.go
T
jochen 684e8801c4
mesh/merge-gate head 684e8801c420 merged into trunk 3395af96bc34 — pass: builds mesh-knowledge → novox; no bus step; every machine composes with the change…
mesh/repo-check head 684e8801c420 merged into trunk 3395af96bc34 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered
Take the ask back on the router when withdrawing a record (issue 1081, review round 1)
WithdrawRecord only ended the waiting ask locally; the router kept it open, so
the operator still saw Approve/Decline for a withdrawn record and an answer to
it was dropped silently. It now also publishes a cancel on the router's
subject once the withdraw is saved, as the controller's asker does; a cancel
the router cannot be told of is logged and the withdraw still stands. The
module's existing "uses": ["operator-channel"] already grants this; no manifest
change needed, since the ask and cancel subjects are both under that seat.
2026-10-18 00:09:16 +02:00

124 lines
4.1 KiB
Go

package main
// Withdraw (novox/hq issue 1081): the operator's decision that a reserved or proposed record is dropped, so its
// number stays spent and the record stops asking anything of anyone.
import (
"context"
"strings"
"testing"
)
func TestAReservedRecordIsWithdrawnAtOnce(t *testing.T) {
eachStore(t, func(t *testing.T, s Store) {
w := imported(t, s)
n := w.reserved(t, "author@test")
key := Key{KindDecision, n}
out, err := w.k.WithdrawRecord("operator@shanks", key, "never proposed")
if err != nil {
t.Fatal(err)
}
if out.Status != StatusWithdrawn || out.Record != key.String() {
t.Fatalf("%+v", out)
}
e := mustGet(t, w.k.Store, key)
if e.Current.Status != StatusWithdrawn {
t.Fatalf("status %q", e.Current.Status)
}
})
}
func TestAProposedRecordNeedingTheOperatorIsWithdrawnWithItsAskEndedAndItsReviewCleared(t *testing.T) {
eachStore(t, func(t *testing.T, s Store) {
w := imported(t, s)
n := w.reserved(t, "author@test")
key := Key{KindDecision, n}
p := valid(n)
p.NeedsOperator = true
p.Brief = &Brief{Headline: "a test record that needs the operator", Summary: "the operator is asked, then the proposal is withdrawn."}
if _, err := w.k.Propose("author@test", p); err != nil {
t.Fatal(err)
}
w.reviewAll(t)
before := mustGet(t, w.k.Store, key)
if before.Current.Status != StatusProposed || before.Current.Ask == nil || before.Current.Ask.Said != AskWaiting {
t.Fatalf("not waiting for the operator: %+v", before.Current)
}
why := "replaced by research on moving designs into the knowledge base"
out, err := w.k.WithdrawRecord("operator@shanks", key, why)
if err != nil {
t.Fatal(err)
}
if out.Status != StatusWithdrawn {
t.Fatalf("status %q", out.Status)
}
after := mustGet(t, w.k.Store, key)
if after.Current.Status != StatusWithdrawn {
t.Fatalf("status %q", after.Current.Status)
}
if after.Versions != before.Versions+1 {
t.Fatalf("versions %d, want %d", after.Versions, before.Versions+1)
}
if after.Current.Ask == nil || after.Current.Ask.Said == AskWaiting {
t.Fatalf("the waiting ask was not ended: %+v", after.Current.Ask)
}
if !contains(w.router.cancelled, before.Current.Ask.ID) {
t.Fatalf("the router was not told to take back the ask %s: cancelled %v", before.Current.Ask.ID, w.router.cancelled)
}
if after.Current.Judging != nil {
t.Fatalf("a pending review was not cleared: %+v", after.Current.Judging)
}
vs, err := w.k.Store.Versions(context.Background(), key)
if err != nil {
t.Fatal(err)
}
last := vs[len(vs)-1]
if last.By != "operator@shanks" || !strings.Contains(last.Why, why) {
t.Fatalf("the new version is not by the caller with the why: %+v", last)
}
})
}
func TestAnAcceptedRecordRefusesWithdrawNamingWhy(t *testing.T) {
eachStore(t, func(t *testing.T, s Store) {
w := imported(t, s)
n := w.reserved(t, "author@test")
key := Key{KindDecision, n}
w.accepted(t, "author@test", valid(n))
if _, err := w.k.WithdrawRecord("operator@shanks", key, "no longer wanted"); err == nil || !strings.Contains(err.Error(), "accepted") {
t.Fatalf("err %v", err)
}
e := mustGet(t, w.k.Store, key)
if e.Current.Status != StatusAccepted {
t.Fatalf("an accepted record was changed: %q", e.Current.Status)
}
})
}
func TestAWithdrawnRecordRefusesWithdrawAgain(t *testing.T) {
eachStore(t, func(t *testing.T, s Store) {
w := imported(t, s)
n := w.reserved(t, "author@test")
key := Key{KindDecision, n}
if _, err := w.k.WithdrawRecord("operator@shanks", key, "first"); err != nil {
t.Fatal(err)
}
if _, err := w.k.WithdrawRecord("operator@shanks", key, "again"); err == nil || !strings.Contains(err.Error(), "withdrawn") {
t.Fatalf("err %v", err)
}
})
}
func TestWithdrawNeedsWhyAndRefusesARecordItHoldsNoneOf(t *testing.T) {
eachStore(t, func(t *testing.T, s Store) {
w := imported(t, s)
n := w.reserved(t, "author@test")
if _, err := w.k.WithdrawRecord("operator@shanks", Key{KindDecision, n}, " "); err == nil {
t.Fatal("an empty why was accepted")
}
if _, err := w.k.WithdrawRecord("operator@shanks", Key{KindDecision, 999999}, "why"); err == nil {
t.Fatal("a record it holds none of was accepted")
}
})
}