package delivery import ( "errors" "strings" "testing" "time" ) func passVerdict() Verdict { return Verdict{ Group: "feat/x", Heads: "4b5491557853", Trunk: map[string]string{"novox/mesh-sdk": "aaaa", "novox/mesh-control": "bbbb"}, State: VerdictPass, Levels: map[string]LevelResult{LevelUnit: {Run: 12, Kept: 301}, LevelIntegration: {Run: 3, Kept: 40}}, Took: Took{Queue: 1200, Clone: 800, Unit: 950, IntegrationSetup: 2100, IntegrationRun: 7400, Composition: 3300}, Machines: []string{"ace", "g14", "novox", "shanks"}, SDK: "v0.1.14-0.20261019091011-aa68b67389c9", } } func verdictSamples() map[string]Verdict { running := Verdict{Group: "feat/x", Heads: "4b5491557853", Trunk: map[string]string{"novox/mesh-sdk": "aaaa"}, State: VerdictRunning} failTest := passVerdict() failTest.State, failTest.Failed = VerdictFail, FailedFirst{Test: "novox/mesh-sdk/go/delivery TestHeadsHash"} failTest.Levels = map[string]LevelResult{LevelUnit: {Run: 1}} failMachine := passVerdict() failMachine.State, failMachine.Failed = VerdictFail, FailedFirst{Machine: "ace", Words: "path /etc/x is owned by two modules"} return map[string]Verdict{"running": running, "pass": passVerdict(), "fail by a test": failTest, "fail by a machine": failMachine} } func keptSample() Kept { return Kept{State: VerdictPass, Repository: "novox/mesh-sdk", Package: "git.novox.be/novox/mesh-sdk/go/delivery", Level: LevelUnit, Tests: 41, Took: 190, Toolchain: "1.26.0", At: time.Date(2026, 10, 20, 2, 0, 0, 0, time.UTC)} } // 1359/AC1: the key is .; parsing gives back the group and the hash. func TestCheckerVerdictKey(t *testing.T) { heads := []Head{{Repository: "novox/mesh-sdk", Number: 36, Head: "aaaa"}} hh, _ := HeadsHash(heads) for _, group := range []string{"feat/x", "fix/1.2", "plain", "odd name=1"} { key, err := CheckerVerdictKey(group, hh) if err != nil { t.Fatal(err) } if want := EscapeName(group) + "." + hh; key != want { t.Errorf("key = %q, want %q", key, want) } g, h, err := ParseCheckerVerdictKey(key) if err != nil || g != group || h != hh { t.Errorf("parse(%q) = %q, %q, %v", key, g, h, err) } } if k, _ := CheckerVerdictKey("feat/x", hh); !strings.HasPrefix(k, "feat/x.") { t.Errorf("a group with a slash is not kept readable: %q", k) } if _, err := CheckerVerdictKey("", hh); err == nil { t.Error("an empty group accepted") } for _, bad := range []string{"", "feat/x", "feat/x.", "feat/x.abc", "feat/x." + strings.ToUpper(hh), ".4b5491557853", "a.b.4b5491557853", "feat/x.4b5491557853a"} { if _, _, err := ParseCheckerVerdictKey(bad); err == nil || !strings.Contains(err.Error(), "\""+bad+"\"") { t.Errorf("ParseCheckerVerdictKey(%q) = %v, want a refusal naming it", bad, err) } } if _, err := CheckerVerdictKey("feat/x", "abc"); err == nil || !strings.Contains(err.Error(), "abc") { t.Errorf("a short heads hash: %v", err) } } // 1359/AC2: a verdict in each state round-trips, with times per part in milliseconds, the tests run and kept per level, // the machines composed and the mesh-sdk version composed with. func TestVerdictRoundTrip(t *testing.T) { for name, v := range verdictSamples() { data, err := EncodeVerdict(v) if err != nil { t.Fatalf("%s: %v", name, err) } if !strings.HasPrefix(string(data), `{"v":1,`) { t.Errorf("%s at %s", name, data) } got, err := DecodeVerdict(data) v.V = Version if err != nil || !SameVerdict(got, v) { t.Errorf("%s: %+v %v", name, got, err) } } data, _ := EncodeVerdict(passVerdict()) for _, field := range []string{`"queue":1200`, `"clone":800`, `"unit":950`, `"integration-setup":2100`, `"integration-run":7400`, `"composition":3300`, `"run":12`, `"kept":301`, `"machines":["ace","g14","novox","shanks"]`, `"sdk":"v0.1.14`} { if !strings.Contains(string(data), field) { t.Errorf("the value lacks %s: %s", field, data) } } } // 1359/AC3: a fail that names neither a test nor a machine, and a pass whose levels are missing, are refused. func TestVerdictChecked(t *testing.T) { cases := map[string]struct { edit func(*Verdict) words []string }{ "fail naming nothing": {func(v *Verdict) { v.State, v.Failed = VerdictFail, FailedFirst{} }, []string{"test", "machine"}}, "fail with words only": {func(v *Verdict) { v.State, v.Failed = VerdictFail, FailedFirst{Words: "x"} }, []string{"test", "machine"}}, "pass without levels": {func(v *Verdict) { v.Levels = nil }, []string{"level"}}, "pass without unit": {func(v *Verdict) { delete(v.Levels, LevelUnit) }, []string{"unit"}}, "pass without integration": {func(v *Verdict) { delete(v.Levels, LevelIntegration) }, []string{"integration"}}, "pass naming a failure": {func(v *Verdict) { v.Failed = FailedFirst{Test: "T"} }, []string{"pass"}}, "an unknown state": {func(v *Verdict) { v.State = "maybe" }, []string{"maybe"}}, "an unknown level": {func(v *Verdict) { v.Levels["e2e"] = LevelResult{} }, []string{"e2e"}}, "a negative time": {func(v *Verdict) { v.Took.Clone = -1 }, []string{"clone"}}, "a bad heads hash": {func(v *Verdict) { v.Heads = "xyz" }, []string{"xyz"}}, "no group": {func(v *Verdict) { v.Group = "" }, []string{"group"}}, "a trunk head left empty": {func(v *Verdict) { v.Trunk["novox/mesh-sdk"] = "" }, []string{"novox/mesh-sdk"}}, "a negative count": {func(v *Verdict) { v.Levels[LevelUnit] = LevelResult{Run: -1} }, []string{"unit"}}, } for name, c := range cases { v := passVerdict() c.edit(&v) _, err := EncodeVerdict(v) if err == nil { t.Errorf("%s accepted", name) continue } for _, w := range c.words { if !strings.Contains(err.Error(), w) { t.Errorf("%s: error %q does not name %q", name, err, w) } } } if _, err := DecodeVerdict([]byte(`{"v":1,"group":"g","heads":"4b5491557853","state":"fail"}`)); err == nil { t.Error("decoded a fail naming nothing") } } // 1359/AC4: the kept key is .; a level other than unit or integration, or a digest that is not hex, // is refused, naming it. func TestKeptKey(t *testing.T) { digest := strings.Repeat("ab12", 16) for _, level := range []string{LevelUnit, LevelIntegration} { key, err := KeptKey(level, digest) if err != nil || key != level+"."+digest { t.Fatalf("key = %q, %v", key, err) } l, d, err := ParseKeptKey(key) if err != nil || l != level || d != digest { t.Errorf("parse = %q, %q, %v", l, d, err) } } if _, err := KeptKey("e2e", digest); err == nil || !strings.Contains(err.Error(), "e2e") { t.Errorf("a level e2e: %v", err) } if _, err := KeptKey("", digest); err == nil { t.Error("an empty level accepted") } for _, d := range []string{"", "xyz", "ABCD", "ab 12", "sha256:abcd", "ab12.cd"} { if _, err := KeptKey(LevelUnit, d); err == nil || !strings.Contains(err.Error(), "\""+d+"\"") { t.Errorf("KeptKey(unit, %q) = %v, want a refusal naming it", d, err) } } for _, bad := range []string{"", "unit", "unit.", "e2e." + digest, "unit.xyz", "unit." + digest + ".x", "." + digest} { if _, _, err := ParseKeptKey(bad); err == nil || !strings.Contains(err.Error(), "\""+bad+"\"") { t.Errorf("ParseKeptKey(%q) = %v, want a refusal naming it", bad, err) } } if CheckerVerdictsBucket != "mesh-delivery-checker_verdicts" || CheckerVerdictsHistory != 5 || CheckerKeptBucket != "mesh-delivery-checker_kept" || CheckerKeptHistory != 1 || CheckerModule != "mesh-delivery-checker" { t.Errorf("buckets %s %d %s %d", CheckerVerdictsBucket, CheckerVerdictsHistory, CheckerKeptBucket, CheckerKeptHistory) } } // 1359/AC5: a kept value that is not a pass cannot be encoded; a failure is never kept (ADR 0444 clause 1). func TestAFailureIsNeverKept(t *testing.T) { data, err := EncodeKept(keptSample()) if err != nil { t.Fatal(err) } got, err := DecodeKept(data) want := keptSample() want.V = Version if err != nil || !SameKept(got, want) { t.Errorf("round trip: %+v %v", got, err) } for _, state := range []string{VerdictFail, VerdictRunning, "", "skipped"} { k := keptSample() k.State = state if _, err := EncodeKept(k); err == nil || !strings.Contains(err.Error(), "pass") { t.Errorf("a kept value in state %q: %v", state, err) } } if _, err := DecodeKept([]byte(`{"v":1,"state":"fail","repository":"novox/mesh-sdk","package":"p","level":"unit","tests":1,"took":1,"toolchain":"1.26.0","at":"2026-10-20T02:00:00Z"}`)); err == nil { t.Error("decoded a kept failure") } for name, edit := range map[string]func(*Kept){ "a level e2e": func(k *Kept) { k.Level = "e2e" }, "no package": func(k *Kept) { k.Package = "" }, "a bad repository": func(k *Kept) { k.Repository = "nope" }, "no toolchain": func(k *Kept) { k.Toolchain = "" }, "no time": func(k *Kept) { k.At = time.Time{} }, "negative tests": func(k *Kept) { k.Tests = -1 }, "a negative took": func(k *Kept) { k.Took = -1 }, } { k := keptSample() edit(&k) if _, err := EncodeKept(k); err == nil { t.Errorf("%s accepted", name) } } } // 1359/AC6: a value of another version, or none, is refused with ErrUnknownVersion. func TestCheckerVersions(t *testing.T) { for name, dec := range map[string]func([]byte) error{ "verdict": func(b []byte) error { _, err := DecodeVerdict(b); return err }, "kept": func(b []byte) error { _, err := DecodeKept(b); return err }, } { for _, in := range []string{`{"v":2,"state":"pass"}`, `{"state":"pass"}`} { if err := dec([]byte(in)); !errors.Is(err, ErrUnknownVersion) { t.Errorf("%s decode of %s = %v", name, in, err) } } } }