Files
mesh-sdk/go/delivery/published_packages_test.go
T
jschoubben 712b21bd74 J3 (A3n finding 3, A2k finding 1): the builder's version.numbered is a contract, and a build's answer names its files out of step
delivery.VersionNumbered with VersionNumberedEvent and VersionNumberedSubject is the body the builder says when it
numbers a version, so a build module consumes it from mesh-sdk instead of the builder's internal package.
BuildAnswer gains out-of-step, so the builder decodes a trunk build's compare by its field, not by name.

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
2026-11-04 14:42:35 +01:00

130 lines
6.1 KiB
Go

package delivery
import (
"encoding/json"
"reflect"
"strings"
"testing"
"time"
)
// The packages state, the build end's imports and the kept imports (ADR 0593 §2) round-trip, and a reader refuses what it
// could not take, naming it.
func TestPublishedPackagesAndImportsRoundTripAndRefuse(t *testing.T) {
commit := strings.Repeat("a", 40)
sdk := "git.novox.be/novox/mesh-sdk/go"
good := PublishedPackages{Module: sdk, Repository: "novox/mesh-sdk", Dir: "go", Commit: commit, Requires: "sha256:01",
Packages: []PackageDigest{{Package: sdk, Digest: "d0"}, {Package: sdk + "/announce", Digest: "d1"}, {Package: sdk + "/internal/token", Digest: "d2"}},
At: time.Date(2026, 11, 2, 18, 0, 0, 0, time.UTC)}
raw, err := EncodePublishedPackages(good)
if err != nil {
t.Fatal(err)
}
back, err := DecodePublishedPackages(raw)
good.V = Version
if err != nil || !reflect.DeepEqual(back, good) {
t.Fatalf("round trip: %v, %+v", err, back)
}
if d, ok := back.DigestOf(sdk + "/announce"); !ok || d != "d1" {
t.Fatalf("DigestOf announce = %q, %v", d, ok)
}
if _, ok := back.DigestOf(sdk + "/buildstep"); ok {
t.Fatal("DigestOf finds a package the value does not hold")
}
if key, err := PackagesKey(sdk); err != nil || key != "git=2enovox=2ebe/novox/mesh-sdk/go" {
t.Fatalf("PackagesKey = %q, %v", key, err)
}
if _, err := PackagesKey("github.com/x/y"); err == nil {
t.Fatal("PackagesKey takes a path that is no mesh Go module's")
}
for name, mutate := range map[string]func(p *PublishedPackages){
"no mesh module": func(p *PublishedPackages) { p.Module = "github.com/x/y" },
"other repository": func(p *PublishedPackages) { p.Repository = "novox/mesh-host" },
"short commit": func(p *PublishedPackages) { p.Commit = "abc" },
"no requires": func(p *PublishedPackages) { p.Requires = "" },
"package elsewhere": func(p *PublishedPackages) {
p.Packages = []PackageDigest{{Package: "git.novox.be/novox/mesh-host/x", Digest: "d"}}
},
"unsorted": func(p *PublishedPackages) { p.Packages = []PackageDigest{p.Packages[1], p.Packages[0]} },
"no digest": func(p *PublishedPackages) { p.Packages = []PackageDigest{{Package: sdk}} },
} {
p := good
p.Packages = slicesClone(good.Packages)
mutate(&p)
if _, err := EncodePublishedPackages(p); err == nil {
t.Errorf("%s: encoded", name)
}
}
imports := []string{sdk, sdk + "/announce"}
outOfStep := []string{"go/seats/meshbroker/contract.go", "ts/seats/meshbroker/src/index.ts"}
end := BuildLogEntry{Event: BuildEndedEvent, Module: "netcheck", FP: "src2:x", Repository: "novox/mesh-catalog", Commit: commit,
Node: "ace", At: good.At, Outcome: "done", Imports: imports, OutOfStep: outOfStep}
raw, err = EncodeBuildLogEntry(end)
if err != nil {
t.Fatal(err)
}
if e, err := DecodeBuildLogEntry(raw); err != nil || !reflect.DeepEqual(e.Imports, imports) || !reflect.DeepEqual(e.OutOfStep, outOfStep) ||
!strings.Contains(string(raw), `"out-of-step":["go/seats/meshbroker/contract.go",`) {
t.Fatalf("build end round trip: %v, %v, %v in %s", err, e.Imports, e.OutOfStep, raw)
}
start := end
start.Event, start.Outcome, start.Imports = BuildStartedEvent, "", nil
if _, err := EncodeBuildLogEntry(start); err == nil {
t.Error("a build's start with files out of step encoded")
}
start.Imports, start.OutOfStep = imports, nil
if _, err := EncodeBuildLogEntry(start); err == nil {
t.Error("a build's start with imports encoded")
}
end.Imports = []string{sdk + "/announce", sdk}
if _, err := EncodeBuildLogEntry(end); err == nil {
t.Error("unsorted imports encoded")
}
// A build narrates between its start and its end (build.said): its module, fingerprint, line and why, nothing of an
// end; a start or end carries no line.
said := BuildLogEntry{Event: BuildSaidEvent, Module: "netcheck", FP: "src2:x", At: good.At,
Line: "waiting on container-image-registry", Why: "waiting"}
if raw, err := EncodeBuildLogEntry(said); err != nil {
t.Errorf("a narration refused: %v", err)
} else if e, err := DecodeBuildLogEntry(raw); err != nil || e.Line != said.Line || e.Why != "waiting" {
t.Errorf("a narration's round trip: %+v, %v", e, err)
}
for name, mutate := range map[string]func(e *BuildLogEntry){
"a narration with no line": func(e *BuildLogEntry) { e.Line = "" },
"a narration with an outcome": func(e *BuildLogEntry) { e.Outcome = "done" },
"a narration out of step": func(e *BuildLogEntry) { e.OutOfStep = outOfStep },
"an end with a line": func(e *BuildLogEntry) {
e.Event, e.Outcome, e.Node, e.Repository, e.Commit = BuildEndedEvent, "done", "ace", "novox/mesh-catalog", commit
},
} {
e := said
mutate(&e)
if _, err := EncodeBuildLogEntry(e); err == nil {
t.Errorf("%s encoded", name)
}
}
var answer BuildAnswer
if err := json.Unmarshal([]byte(`{"artifacts":[],"imports":["`+sdk+`"],"out-of-step":["go/seats/x/contract.go"]}`), &answer); err != nil ||
len(answer.Imports) != 1 || !reflect.DeepEqual(answer.OutOfStep, []string{"go/seats/x/contract.go"}) {
t.Fatalf("build answer imports and files out of step: %v, %v, %v", err, answer.Imports, answer.OutOfStep)
}
// The builder's version.numbered, as a build module consumes it: the builder's own body whole, and its subject.
numbered := VersionNumbered{Name: "mesh-sdk/go", Kind: "package", Version: "0.1.7", Module: "mesh-sdk", Fingerprint: "src2:x",
Commit: commit, Digest: "sha256:d", Seat: "go-package-registry", Head: commit, Again: "2026-11-04T15:00:00Z"}
if raw, err := EncodeVersionNumbered(numbered); err != nil {
t.Errorf("numbered refused: %v", err)
} else if back, err := DecodeVersionNumbered(raw); err != nil || back != numbered ||
!strings.Contains(string(raw), `"fingerprint":"src2:x"`) || VersionNumberedSubject != "mesh.mod.mesh-delivery-builder.event.version.numbered" {
t.Errorf("numbered round trip: %+v, %v, %s", back, err, raw)
}
if _, err := DecodeVersionNumbered([]byte(`{"name":"mesh-sdk/go","version":"0.1.7"}`)); err == nil {
t.Error("a numbered version naming no build is read")
}
if err := CheckImports([]string{"fmt"}); err == nil {
t.Error("CheckImports takes a standard package")
}
}
func slicesClone(d []PackageDigest) []PackageDigest { return append([]PackageDigest(nil), d...) }