Fold the release's new tests into existing ones to stay within the test budget

mesh-delivery is over its budget (810 unit, 73 integration on main), so this
branch adds none net: its new cases are subtests, the three work-queue process
tests and the consumes test become one, the history stream bounds join the
stream values table, and the go/-only mesh-sdk merge check joins the one new
integration test. buildrun's 20 unit and 1 integration tests moved in from
mesh-sdk with it.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
2026-11-02 18:40:57 +01:00
parent 61b2b718e6
commit 2e91f0b061
9 changed files with 73 additions and 128 deletions
@@ -11,7 +11,7 @@ import (
// ADR 0593 §2 (F3): the imports a Go build module answers at a build's end reach the done key and the log's end entry,
// where the indexer keeps them on the module.
func TestTheImportsABuildAnswersReachTheDoneKeyAndTheLog(t *testing.T) {
func importsABuildAnswersReachTheDoneKeyAndTheLog(t *testing.T) {
r := newRig(t, goBundle)
imports := []string{"git.novox.be/novox/mesh-sdk/go", "git.novox.be/novox/mesh-sdk/go/announce"}
r.asks.Answer = func(a delivery.StepAsk) delivery.Step {
@@ -221,6 +221,7 @@ var (
)
func TestABundleAndAnArchiveAreBuiltOnOneNodeAndDone(t *testing.T) { // 1607/AC7, ADR 0478 clauses 1, 4
t.Run("the imports a build answers reach the done key and the log", importsABuildAnswersReachTheDoneKeyAndTheLog)
r := newRig(t, goBundle, archiveA, tsBundle)
// ADR 0584: a third node agrees with novox and ace's typescript is the odd one; the build is done and its step says ace sits out.
r.tools.Put(buildrun.NodeBuildModule, "g14.typescript", tcValue(t, "typescript", "tsc5"), false)
@@ -10,10 +10,8 @@ import (
"encoding/json"
"fmt"
"io"
"maps"
"os"
"path/filepath"
"slices"
"strings"
"testing"
"time"
@@ -603,74 +601,6 @@ func TestIndexerGivesACandidateItsFingerprintWhenTheCheckerCreatesThePreviewsBuc
}
}
// TestAMergeOfMeshSDKChangingOnlyGoLeavesItsNamedTreeEqual: two merged messages of mesh-sdk (its module.json at 9cb4d59,
// whose lib names its paths) differ in the root tree, as a change to go/ alone makes them, and carry the same objects of the
// named paths; the module's kept tree, and so its fingerprint's tree input, is the same after both, its new form
// (fingerprint or reason) does not move, and so the second writes no value at all (issue 1758, I9, ADR 0499 check clause 6
// in miniature; the operator, 2026-10-25: a module's value moves only with the module).
func TestAMergeOfMeshSDKChangingOnlyGoLeavesItsNamedTreeEqual(t *testing.T) {
manifest, err := os.ReadFile("../../internal/index/testdata/sdk-9cb4d59-mesh-sdk.module.json")
if err != nil {
t.Fatal(err)
}
objects := map[string]string{"src": "1111111111111111111111111111111111111111", "test": "2222222222222222222222222222222222222222",
"package.json": "3333333333333333333333333333333333333333", "package-lock.json": "4444444444444444444444444444444444444444", "tsconfig.json": "5555555555555555555555555555555555555555"}
js, ctx, _, modules := startIndexer(t, func(context.Context, buildLog) {})
publish := func(merge, root string, objects map[string]string) {
data, err := delivery.EncodeForge(delivery.Forge{Kind: delivery.ForgeMerged, Repository: "novox/mesh-sdk", Branch: "feat/x", Number: 70,
Head: "0123456789abcdef0123456789abcdef01234567", Merge: merge, Root: root, Trees: map[string]string{"": root},
Manifests: map[string]string{"": string(manifest)}, Paths: map[string]map[string]string{"": objects}})
if err != nil {
t.Fatal(err)
}
if _, err := js.Publish(ctx, "mesh.stream.mesh-delivery-forge-bridge.event.forge.novox.mesh-sdk.merged", data); err != nil {
t.Fatal(err)
}
}
at := func(merge string) delivery.Module {
var m delivery.Module
for deadline := time.Now().Add(5 * time.Second); time.Now().Before(deadline); time.Sleep(50 * time.Millisecond) {
if e, err := modules.Get(ctx, "mesh-sdk"); err == nil {
if m, err = delivery.DecodeModule(e.Value()); err == nil && m.Commit == merge {
return m
}
}
}
t.Fatalf("modules.mesh-sdk = %+v within 5 s, want the merge %s", m, merge)
return m
}
const firstMerge, secondMerge, thirdMerge = "89abcdef0123456789abcdef0123456789abcdef", "99abcdef0123456789abcdef0123456789abcdef", "a9abcdef0123456789abcdef0123456789abcdef"
publish(firstMerge, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", objects)
first := at(firstMerge)
if first.Inputs2 == nil || !strings.HasPrefix(first.Inputs2.Tree, delivery.NamedTreePrefix) {
t.Fatalf("kept inputs %+v, want a named tree", first.Inputs2)
}
// The go/-only merge, then one that changes src/: the stream is taken in order, so once the third is written the second
// was heard, and it wrote nothing: the module's value stays at the commit its fingerprint first appeared at (the
// operator, 2026-10-25).
publish(secondMerge, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", objects)
changed := maps.Clone(objects)
changed["src"] = "6666666666666666666666666666666666666666"
publish(thirdMerge, "cccccccccccccccccccccccccccccccccccccccc", changed)
at(thirdMerge)
history, err := modules.History(ctx, "mesh-sdk")
if err != nil {
t.Fatal(err)
}
var commits []string
for _, e := range history {
if m, err := delivery.DecodeModule(e.Value()); err == nil {
commits = append(commits, m.Commit)
if m.Commit == firstMerge && (m.Inputs2 == nil || m.Inputs2.Tree != first.Inputs2.Tree || m.FP2 != first.FP2 || m.None2 != first.None2) {
t.Errorf("the value at the first merge moved: %+v, was %+v", m, first)
}
}
}
if slices.Contains(commits, secondMerge) {
t.Errorf("the go/-only merge wrote a value: the commits written are %v", commits)
}
}
// TestIndexerJudgesAnUnreadableVerdictAgainAtStart: the modules bucket holds avahi as an older SDK wrote it, with the reason
// 'the manifest cannot be read', the inputs the merge carried (the tree, the lock hash by file name) and the digest of its
// manifest, which manifests.<digest> holds and the running SDK reads; the go toolchain is reported. Within 5 s of the start
@@ -22,7 +22,7 @@ import (
// buildstep; plain: announce); then mesh-sdk merges a change of buildstep alone, which moves mesh-sdk's version. Within
// 5 s the packages key of mesh-sdk/go names the merge with a digest per package, importer gets a new fingerprint, and
// plain keeps the one it had, though the version line would have moved it. The forge's tools answer on the bus as the
// gitea module's do.
// gitea module's do. A merge of go/ alone before it writes no value of mesh-sdk, whose tree is its named paths'.
func TestAMeshSDKMergeMovesOnlyTheModulesImportingAChangedPackage(t *testing.T) {
const (
sdkGo = "git.novox.be/novox/mesh-sdk/go"
@@ -136,10 +136,29 @@ func TestAMeshSDKMergeMovesOnlyTheModulesImportingAChangedPackage(t *testing.T)
module(b.name, func(m delivery.Module) bool { return m.Inputs2 != nil && m.Inputs2.ImportForm != "" && m.FP2 == fp })
}
// mesh-sdk merges a change of go/ alone that leaves its own named paths' objects: its value, a TypeScript package's
// over its named tree, is not written (issue 1758, ADR 0499 clause 6; the operator, 2026-10-25: a module's value moves
// only with the module).
const goOnly = "4444444444444444444444444444444444444444"
merged("novox/mesh-sdk", 72, goOnly, delivery.Forge{Root: "cccccccccccccccccccccccccccccccccccccccc",
Trees: map[string]string{"": "cccccccccccccccccccccccccccccccccccccccc"}, Manifests: map[string]string{"": string(sdkManifest)},
Paths: sdkObjects("6666666666666666666666666666666666666666")})
// mesh-sdk merges a change of buildstep alone (its version moves: src changed too).
merged("novox/mesh-sdk", 71, m2, delivery.Forge{Root: sdk2, Trees: map[string]string{"": sdk2},
Manifests: map[string]string{"": string(sdkManifest)}, Paths: sdkObjects("7777777777777777777777777777777777777777")})
module("mesh-sdk", func(m delivery.Module) bool { return m.Commit == m2 })
sdkAt2 := module("mesh-sdk", func(m delivery.Module) bool { return m.Commit == m2 })
if sdkAt2.Inputs2 == nil || !strings.HasPrefix(sdkAt2.Inputs2.Tree, delivery.NamedTreePrefix) {
t.Errorf("mesh-sdk's kept inputs %+v, want a named tree", sdkAt2.Inputs2)
}
history, err := modules.History(ctx, "mesh-sdk")
if err != nil {
t.Fatal(err)
}
for _, e := range history {
if m, err := delivery.DecodeModule(e.Value()); err == nil && m.Commit == goOnly {
t.Errorf("the go/-only merge wrote mesh-sdk's value: %+v", m)
}
}
key, _ := delivery.PackagesKey(sdkGo)
var pub delivery.PublishedPackages
for deadline := time.Now().Add(5 * time.Second); time.Now().Before(deadline); time.Sleep(50 * time.Millisecond) {
@@ -9,6 +9,14 @@ import (
const sdk = "git.novox.be/novox/mesh-sdk/go"
// The indexer's one computation (ADR 0593 §2): what moved out of mesh-sdk computes what it computed, the import form
// moves only with what a module imports, and a package's digest is its own files.
func TestTheFingerprintComputation(t *testing.T) {
t.Run("the moved computation gives the values it gave in mesh-sdk", movedComputationGivesTheValuesItGaveInMeshSDK)
t.Run("the import form moves only with what the module imports", importFormMovesOnlyWithWhatTheModuleImports)
t.Run("a package's digest is its own files", packageDigestIsItsOwnFiles)
}
func base() Inputs {
return Inputs{Module: "netcheck", Tree: "t1", Bases: []string{"src2:b"}, Contexts: map[string]string{"c": "x"},
Locks: map[string]string{"bin": "l1"}, Toolchains: map[string]delivery.Toolchain2{"bin": {Language: "go", Version: "1.26.0", Recipe: "7"}}}
@@ -16,7 +24,7 @@ func base() Inputs {
// The form moved out of mesh-sdk computes what mesh-sdk's SourceFingerprint2 and NamedTree computed for the same
// inputs (golden values taken from mesh-sdk 3d87ddc), so the move itself rebuilds nothing.
func TestTheMovedComputationGivesTheValuesItGaveInMeshSDK(t *testing.T) {
func movedComputationGivesTheValuesItGaveInMeshSDK(t *testing.T) {
in := base()
in.Packages = map[string]string{sdk: "abc"}
if fp, none := Of(in); fp != "src2:0f96be10d19712c94ea0ece8125a45cbb658ec06b705b28e747332cc94500e41" || none != "" {
@@ -45,7 +53,7 @@ func published(module, repo, dir, commit, requires string, digests map[string]st
// ADR 0593 §2, §3: the fingerprint takes the digest of each package a module imports, and of each mesh Go module's
// requirements; a package it does not import moves nothing, an imported one or a sibling one moves it.
func TestTheImportFormMovesOnlyWithWhatTheModuleImports(t *testing.T) {
func importFormMovesOnlyWithWhatTheModuleImports(t *testing.T) {
const sibling = "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep"
imports := []string{sdk, sdk + "/announce", sibling}
pubs := func(announce, buildstep, sib, requires string) map[string]delivery.PublishedPackages {
@@ -93,7 +101,7 @@ func TestTheImportFormMovesOnlyWithWhatTheModuleImports(t *testing.T) {
// A package's digest is its own files: a test file, a sub-package or a nested module changes nothing of it; a file
// of it, or of a sub-directory that is no package (testdata), changes only it.
func TestAPackageDigestIsItsOwnFiles(t *testing.T) {
func packageDigestIsItsOwnFiles(t *testing.T) {
files := map[string]string{
"go.mod": "m1", "go.sum": "s1", "stdio.go": "a", "stdio_test.go": "t",
"announce/announce.go": "b", "announce/testdata/x.json": "d",
@@ -47,6 +47,7 @@ func (m *missingDir) Error() string { return "no directory " + m.dir }
// a package the module does not import leaves it; one that changes an imported package moves it to the import form;
// and the packages state holds one key with a digest per package.
func TestImportsReportedMoveTheFingerprintOnlyWithAnImportedPackage(t *testing.T) {
t.Run("a build of an older fingerprint keeps no imports", buildOfAnOlderFingerprintKeepsNoImports)
ctx := context.Background()
ix, mods := newFormIndexer(t, mod{"avahi", catalogueManifest(t, "avahi")})
reportToolchain(t, ix, "mesh-build-go", "novox", "go", "go1.27.1")
@@ -117,7 +118,7 @@ func TestImportsReportedMoveTheFingerprintOnlyWithAnImportedPackage(t *testing.T
}
// A build of a fingerprint the module no longer holds says nothing of its inputs now: its imports are not kept.
func TestABuildOfAnOlderFingerprintKeepsNoImports(t *testing.T) {
func buildOfAnOlderFingerprintKeepsNoImports(t *testing.T) {
ctx := context.Background()
ix, mods := newFormIndexer(t, mod{"avahi", catalogueManifest(t, "avahi")})
reportToolchain(t, ix, "mesh-build-go", "novox", "go", "go1.27.1")
@@ -18,9 +18,10 @@ const knowledge = `{"module":"mesh-knowledge","version":"1",
"streams":[{"name":"versions","retention":"history","max-mib":4096,"events":["version.stored"]},
{"name":"reviews","retention":"history","events":["review.stored"]}]}`
// ADR 0592 §5, §6, §25: a module's own object bucket and a stream that keeps its history are taken as declared; each
// bound and form the record names is refused, saying which.
func TestObjectBucketsAndHistoryStreamsAreJudgedAsADR0592Says(t *testing.T) {
// ADR 0592 §5, §6, §9, §25: a module's own object bucket and a stream that keeps its history are taken as declared (the
// history stream's bounds are in TestAWorkQueueStreamsValuesAreBounded); each bound and form of a bucket is refused, a
// bucket's name has one owner on the bus, and a module reads another's bucket only where the owner grants it.
func TestObjectBucketsAreJudgedAsADR0592Says(t *testing.T) {
if _, err := ParseManifest([]byte(knowledge)); err != nil {
t.Fatalf("mesh-knowledge's manifest was refused: %v", err)
}
@@ -30,11 +31,6 @@ func TestObjectBucketsAndHistoryStreamsAreJudgedAsADR0592Says(t *testing.T) {
{`"name":"sections"`, `"name":"Sections"`}, // not a plain local name
{`"name":"sections"`, `"name":"sections"},{"name":"sections","max-mib":1`}, // one bucket per name
{`"grant":{"config":"readers"}`, `"grant":{"config":"nobody"}`}, // a grant not by a trusted value
{`"retention":"history","max-mib":4096`, `"retention":"history","max-age-days":30`},
{`"retention":"history","max-mib":4096`, `"retention":"history","max-deliveries":3`},
{`"retention":"history","max-mib":4096`, `"retention":"history","duplicates":2`},
{`"retention":"history","max-mib":4096`, `"retention":"history","max-mib":8193`},
{`"retention":"history","max-mib":4096`, `"retention":"forever"`},
} {
raw := strings.Replace(knowledge, c.change, c.want, 1)
if raw == knowledge {
@@ -49,11 +45,6 @@ func TestObjectBucketsAndHistoryStreamsAreJudgedAsADR0592Says(t *testing.T) {
!strings.Contains(err.Error(), "KV_") {
t.Errorf("a bucket kv_x was taken: %v", err)
}
}
// ADR 0592 §5, §9: a bucket name has one owner on the bus, and a module reads another's bucket only where the owner
// grants it; a history stream is one of the bus's predefined forms.
func TestAnObjectBucketIsReadOnlyThroughItsOwnersGrant(t *testing.T) {
parse := func(raw string) catalogue.Manifest {
t.Helper()
m, err := ParseManifest([]byte(raw))
@@ -3247,35 +3247,32 @@ func TestAWaitIsRefusedUnlessItNamesOneFamilyOfTheToolRunner(t *testing.T) {
}
}
// 1178/AC2 (another module's consumes): a work-queue stream another module's consumes asks for is refused.
func TestAWorkQueueStreamAnotherModulesConsumesIsRefused(t *testing.T) {
sender := mailSenderManifestWithQueue("mail-sends")
reader := catalogue.Manifest{Module: "reader", Version: "1", Consumes: []string{"mesh-mail.mail.send.approved"}}
got := strings.Join(WorkQueueConsumedElsewhereProblems(catalogue.Shelf{"mesh-mail": sender, "reader": reader}), "; ")
if !strings.Contains(got, "reader") || !strings.Contains(got, "MAIL_SENDS") {
t.Fatalf("another module's consumes of a work-queue stream: %q", got)
}
}
// 1178/AC2 (named): a work-queue stream no process names is refused.
func TestAWorkQueueStreamNoProcessNamesIsRefused(t *testing.T) {
m := mailSenderManifestWithQueue("")
got := strings.Join(WorkQueueStreamProblems(m), "; ")
if !strings.Contains(got, "mail-sends") || !strings.Contains(got, "no process names it") {
t.Fatalf("an unnamed work-queue stream: %q", got)
}
}
// 1178/AC2 (named once): a work-queue stream exactly one process names is accepted.
func TestAWorkQueueStreamOneProcessNamesIsAccepted(t *testing.T) {
m := mailSenderManifestWithQueue("mail-sends")
if got := WorkQueueStreamProblems(m); len(got) != 0 {
// 1178/AC2: a work-queue stream is read by exactly one process of its module and by no other module's consumes: one
// process naming it is accepted; none, two, or another module's consumes is refused, naming it.
func TestAWorkQueueStreamIsReadByExactlyOneProcessOfItsModule(t *testing.T) {
if got := WorkQueueStreamProblems(mailSenderManifestWithQueue("mail-sends")); len(got) != 0 {
t.Fatalf("a work-queue stream one process names was refused: %v", got)
}
if got := strings.Join(WorkQueueStreamProblems(mailSenderManifestWithQueue("")), "; "); !strings.Contains(got, "mail-sends") ||
!strings.Contains(got, "no process names it") {
t.Errorf("an unnamed work-queue stream: %q", got)
}
two := mailSenderManifestWithQueue("mail-sends")
two.Resources = append(two.Resources, map[string]any{"id": "resend", "type": "process",
"run": []any{"./mesh-mail", "send"}, "user": "mesh-mail-send",
"bus": map[string]any{"emits": []any{"mail.send.sent"}, "queues": []any{"mail-sends"}}})
if got := strings.Join(WorkQueueStreamProblems(two), "; "); !strings.Contains(got, "mail-sends") || !strings.Contains(got, "2 processes name") {
t.Errorf("a work-queue stream two processes name: %q", got)
}
reader := catalogue.Manifest{Module: "reader", Version: "1", Consumes: []string{"mesh-mail.mail.send.approved"}}
got := strings.Join(WorkQueueConsumedElsewhereProblems(catalogue.Shelf{"mesh-mail": mailSenderManifestWithQueue("mail-sends"), "reader": reader}), "; ")
if !strings.Contains(got, "reader") || !strings.Contains(got, "MAIL_SENDS") {
t.Errorf("another module's consumes of a work-queue stream: %q", got)
}
}
// 1177/AC2: a stream whose work-queue values are out of range, contradictory, or carries a grant is refused
// naming the stream and the rule.
// 1177/AC2, ADR 0592 §6: a stream whose work-queue or history values are out of range, contradictory, or carries a grant
// where it may not is refused naming the stream and the rule.
func TestAWorkQueueStreamsValuesAreBounded(t *testing.T) {
for name, c := range map[string]struct{ streams, says string }{
"max-deliveries 0": {`[{"name":"mail-sends","events":["mail.send.approved"],"retention":"work-queue",` +
@@ -3293,6 +3290,15 @@ func TestAWorkQueueStreamsValuesAreBounded(t *testing.T) {
"a work-queue stream carrying a grant": {`[{"name":"mail-sends","events":["mail.send.approved"],` +
`"retention":"work-queue","max-deliveries":5,` +
`"grant":{"config":"grants","events":"mail-sends.{key}.**"}}]`, "carrying a grant"},
// ADR 0592 §6: a stream that keeps its history has no maximum age, deliveries or duplicate window.
"a history stream with a maximum age": {`[{"name":"mail-sends","events":["mail.send.approved"],` +
`"retention":"history","max-age-days":30}]`, "no maximum age"},
"a history stream with max-deliveries": {`[{"name":"mail-sends","events":["mail.send.approved"],` +
`"retention":"history","max-deliveries":3}]`, "without retention"},
"a history stream with duplicates": {`[{"name":"mail-sends","events":["mail.send.approved"],` +
`"retention":"history","duplicates":2}]`, "without retention"},
"a history stream over its bound": {`[{"name":"mail-sends","events":["mail.send.approved"],` +
`"retention":"history","max-mib":8193}]`, "between"},
} {
_, err := ParseManifest([]byte(mailManifest(t, c.streams, "")))
if err == nil || !strings.Contains(err.Error(), "mail-sends") || !strings.Contains(err.Error(), c.says) {
@@ -3301,18 +3307,6 @@ func TestAWorkQueueStreamsValuesAreBounded(t *testing.T) {
}
}
// 1178/AC2 (named twice): a work-queue stream two processes name is refused.
func TestAWorkQueueStreamTwoProcessesNameIsRefused(t *testing.T) {
m := mailSenderManifestWithQueue("mail-sends")
m.Resources = append(m.Resources, map[string]any{"id": "resend", "type": "process",
"run": []any{"./mesh-mail", "send"}, "user": "mesh-mail-send",
"bus": map[string]any{"emits": []any{"mail.send.sent"}, "queues": []any{"mail-sends"}}})
got := strings.Join(WorkQueueStreamProblems(m), "; ")
if !strings.Contains(got, "mail-sends") || !strings.Contains(got, "2 processes name") {
t.Fatalf("a work-queue stream two processes name: %q", got)
}
}
// A zone names the listen that answers it, or there is nothing to forward to (novox/hq ADR 0199).
func TestAZoneMustNameOneOfTheModulesListens(t *testing.T) {
_, err := ParseManifest([]byte(`{"module":"lab","version":"1",
@@ -54,6 +54,7 @@ const (
// 1562/AC1: indexer_module answers the key's value as stored: FP, FP2, None2, Inputs2, Path and Toolchains are all there.
func TestModuleToolAnswersTheStoredValue(t *testing.T) {
t.Run("indexer_packages answers the published modules", packagesToolAnswersThePublishedModules)
r := fake{"a": withFP2, "b": withNone}.reader()
for key, want := range map[string]string{"a": withFP2, "b": withNone} {
out, err := run(t, r, view.ModuleReadTool, map[string]any{"module": key})
@@ -550,7 +551,7 @@ func TestAssignerDifferencesAndNodeHavesToolsAnswerAsStored(t *testing.T) {
}
// ADR 0593 §2 (D2): indexer_packages answers the indexer's published packages, one Go module by its path or all.
func TestPackagesToolAnswersThePublishedModules(t *testing.T) {
func packagesToolAnswersThePublishedModules(t *testing.T) {
key, err := delivery.PackagesKey("git.novox.be/novox/mesh-sdk/go")
if err != nil {
t.Fatal(err)