ADR 0595 §4, design 25 § 12.2: the bus module hears the accepted verdict as an event with the entries, never reading the indexer's state; AcceptedOf builds the body and EventID names it once per digest and judge.
104 lines
4.4 KiB
Go
104 lines
4.4 KiB
Go
package delivery
|
|
|
|
import (
|
|
"encoding/json"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
)
|
|
|
|
// A verdict on a manifest round-trips, refuses what it cannot be, and a reader takes a missing one as accepted (novox/hq
|
|
// ADR 0578 §1, §3); a modules value carries it.
|
|
func TestAManifestVerdictIsTheContractReadersTake(t *testing.T) {
|
|
at := time.Date(2026, 11, 1, 2, 0, 0, 0, time.UTC)
|
|
refused := ManifestVerdict{Module: "nats", State: VerdictRefused, Problems: []string{"a", "b"}, Judge: "src2:x", At: at}
|
|
data, err := EncodeManifestVerdict(refused)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
back, err := DecodeManifestVerdict(data)
|
|
if err != nil || !back.Same(refused) || back.Judge != "src2:x" || !back.At.Equal(at) {
|
|
t.Fatalf("round trip: %+v %v", back, err)
|
|
}
|
|
if !strings.Contains(back.Why(), "refused the manifest of nats: a; b") {
|
|
t.Fatalf("why: %q", back.Why())
|
|
}
|
|
for name, bad := range map[string]ManifestVerdict{
|
|
"no module": {State: VerdictAccepted, Judge: "j"},
|
|
"no judge": {Module: "m", State: VerdictAccepted},
|
|
"another state": {Module: "m", State: "maybe", Judge: "j"},
|
|
"refused, no problem": {Module: "m", State: VerdictRefused, Judge: "j"},
|
|
"accepted, a problem": {Module: "m", State: VerdictAccepted, Problems: []string{"x"}, Judge: "j"},
|
|
"refused, a warning": {Module: "m", State: VerdictRefused, Problems: []string{"x"}, Warnings: []string{"y"}, Judge: "j"},
|
|
} {
|
|
if _, err := EncodeManifestVerdict(bad); err == nil {
|
|
t.Errorf("%s: encoded", name)
|
|
}
|
|
}
|
|
if refusedTaken, _ := TakeManifestVerdict(nil); refusedTaken {
|
|
t.Fatal("a missing verdict was taken as a refusal")
|
|
}
|
|
if r, p := TakeManifestVerdict(&refused); !r || len(p) != 2 {
|
|
t.Fatalf("a refusal was not taken: %v %v", r, p)
|
|
}
|
|
if k, err := VerdictsKey(strings.Repeat("a", 64)); err != nil || k != strings.Repeat("a", 64) {
|
|
t.Fatalf("key: %q %v", k, err)
|
|
}
|
|
if _, err := VerdictsKey("nats"); err == nil {
|
|
t.Fatal("a key that is no digest")
|
|
}
|
|
m := Module{FP2: "src2:" + strings.Repeat("b", 64), Manifest: strings.Repeat("c", 64), Repository: "novox/x",
|
|
Commit: "c", Verdict: VerdictRefused, Problems: []string{"p"}}
|
|
data, err = EncodeModule(m)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, err := DecodeModule(data)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if r, p := TakeManifestVerdict(got.VerdictOf("x")); !r || p[0] != "p" {
|
|
t.Fatalf("the module's verdict: %+v", got)
|
|
}
|
|
m.Problems = nil
|
|
if _, err := EncodeModule(m); err == nil {
|
|
t.Fatal("a module refused naming no problem was encoded")
|
|
}
|
|
// ADR 0579 §1: an accepted manifest a stricter judge outgrew carries its warnings and is taken as accepted.
|
|
outgrown := ManifestVerdict{Module: "x", State: VerdictAccepted, Warnings: []string{"w"}, Judge: "j"}
|
|
if _, err := EncodeManifestVerdict(outgrown); err != nil || outgrown.Same(ManifestVerdict{Module: "x", State: VerdictAccepted}) {
|
|
t.Fatalf("an outgrown verdict: %v", err)
|
|
}
|
|
m.Verdict, m.Warnings = "", []string{"w"}
|
|
if r, _ := TakeManifestVerdict(m.VerdictOf("x")); r || len(m.VerdictOf("x").Warnings) != 1 {
|
|
t.Fatalf("an outgrown module: %+v", m.VerdictOf("x"))
|
|
}
|
|
|
|
// 1966/AC6: the accepted event of a manifest with two bus-state entries carries both whole, and its id is
|
|
// manifest-accepted-<digest>-<judge>.
|
|
entries := []catalogue.BusStateEntry{
|
|
{Name: "drafts", Storage: catalogue.StorageKeyValue, Template: catalogue.TemplateState,
|
|
Options: map[string]json.RawMessage{catalogue.OptionPastValues: json.RawMessage(`5`)}},
|
|
{Name: "records", Storage: catalogue.StorageLedger, Template: catalogue.TemplateLedger,
|
|
Types: []catalogue.LedgerType{{Name: "decision", Operations: []catalogue.LedgerOperation{{Name: "submit", Effect: catalogue.EffectSetFields}}}}},
|
|
}
|
|
digest := strings.Repeat("d", 64)
|
|
accepted := AcceptedOf(digest, ManifestVerdict{Module: "mesh-knowledge", State: VerdictAccepted, Judge: "src2:j"},
|
|
catalogue.Manifest{Module: "mesh-knowledge", BusState: entries})
|
|
raw, err := json.Marshal(accepted)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var heard ManifestAccepted
|
|
if err := json.Unmarshal(raw, &heard); err != nil || heard.Module != "mesh-knowledge" || heard.Digest != digest ||
|
|
heard.V != Version || !reflect.DeepEqual(heard.BusState, entries) {
|
|
t.Fatalf("the accepted event reads as %+v (%v)", heard, err)
|
|
}
|
|
if id := heard.EventID(); id != "manifest-accepted-"+digest+"-src2:j" {
|
|
t.Fatalf("the accepted event's id is %q", id)
|
|
}
|
|
}
|