delivery.BuildLogEntry gains out-of-step, an end's alone, as the build module's test step answers it, so the indexer reads the field from the entry, not the raw message, and its trunk finding can be raised once the builder writes it. Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
117 lines
5.1 KiB
Go
117 lines
5.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+`"]}`), &answer); err != nil || len(answer.Imports) != 1 {
|
|
t.Fatalf("build answer imports: %v, %v", err, answer.Imports)
|
|
}
|
|
if err := CheckImports([]string{"fmt"}); err == nil {
|
|
t.Error("CheckImports takes a standard package")
|
|
}
|
|
}
|
|
|
|
func slicesClone(d []PackageDigest) []PackageDigest { return append([]PackageDigest(nil), d...) }
|