Files
mesh-host/internal/image/image_test.go
jschoubben 121367319d Rename mesh-control -> mesh-controller, substrate -> foundation
One name per thing, per the HQ glossary: the module/container/image/binary/repo
becomes mesh-controller, the seat the-controller, and the store+broker pair the
foundation (embedded base bundles, default template and example lock renamed with
their go:embed directives). No behaviour change — a pure vocabulary rename.

Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
2026-09-16 18:40:40 +02:00

161 lines
6.5 KiB
Go

package image
import (
"archive/tar"
"bytes"
"encoding/json"
"strings"
"testing"
)
// Each test names the decision it defends (novox/hq ADR 0017).
// savedImage builds what `docker save` produces, as far as this package reads it.
func savedImage(t *testing.T, files map[string]string) []byte {
t.Helper()
var buffer bytes.Buffer
writer := tar.NewWriter(&buffer)
for name, content := range files {
header := &tar.Header{Name: name, Mode: 0o644, Size: int64(len(content))}
if err := writer.WriteHeader(header); err != nil {
t.Fatalf("building the fixture: %v", err)
}
if _, err := writer.Write([]byte(content)); err != nil {
t.Fatalf("building the fixture: %v", err)
}
}
if err := writer.Close(); err != nil {
t.Fatalf("building the fixture: %v", err)
}
return buffer.Bytes()
}
func manifest(t *testing.T, config string, tags ...string) string {
t.Helper()
raw, err := json.Marshal([]manifestEntry{{Config: config, RepoTags: tags}})
if err != nil {
t.Fatalf("building the fixture: %v", err)
}
return string(raw)
}
// The archive's own id is read from the FILE, in both layouts `docker save` has used.
//
// **This test used to say that reading it here was what made the load idempotent — that knowing
// the id in advance let the installer ask "do you already hold exactly this". That was wrong.** An
// id is the digest of the image's configuration document, and a runtime rewrites that document as
// it loads, so this is a fact about the archive and not a prediction about any machine. What the
// installer asks a runtime by is the TAG, and what a bundle names is the answer the runtime gives
// back (`internal/bootstrap`.Load).
//
// It is still read and still checked, because it is what says which build somebody embedded — and
// because printing it beside the runtime's answer is how a person sees that the two differ.
func TestTheArchivesOwnIdIsReadFromTheSavedFile(t *testing.T) {
digest := strings.Repeat("a", 64)
// Both layouts `docker save` has used. The older one names the config `<digest>.json`; the OCI
// one names it `blobs/sha256/<digest>`. They carry the same sixty-four characters, and a
// reader that understood only one would work until somebody upgraded their runtime.
for _, config := range []string{digest + ".json", "blobs/sha256/" + digest} {
saved := savedImage(t, map[string]string{"manifest.json": manifest(t, config)})
id, err := ArchiveID(saved)
if err != nil {
t.Fatalf("config %q: %v", config, err)
}
if id != "sha256:"+digest {
t.Errorf("config %q gave id %q, want sha256:%s", config, id, digest)
}
}
}
// The tag is read, and it is not decoration: it is the name the installer asks a runtime by,
// because it is the one thing that survives `docker save` and `docker load` unchanged. The id
// does not.
func TestTheSavedTagsAreRead(t *testing.T) {
saved := savedImage(t, map[string]string{
"manifest.json": manifest(t, strings.Repeat("b", 64)+".json", "mesh-controller:v1"),
})
got := Tags(saved)
if len(got) != 1 || got[0] != "mesh-controller:v1" {
t.Errorf("tags = %v, want [mesh-controller:v1]", got)
}
}
// A tar that is not a saved image is refused with what is wrong, not with a nil id.
//
// Nothing here reaches a bundle any more, but this is still the earliest moment somebody can be
// told they embedded the wrong file — and the alternative is finding out at the load, from a
// container runtime, in a sentence about a tar rather than about what was built.
func TestSomethingThatIsNotASavedImageIsRefused(t *testing.T) {
notAnImage := savedImage(t, map[string]string{"hello": "world"})
if _, err := ArchiveID(notAnImage); err == nil {
t.Error("a tar with no manifest.json was accepted as a saved image")
} else if !strings.Contains(err.Error(), "docker save") {
t.Errorf("the refusal does not say what to embed instead: %v", err)
}
if _, err := ArchiveID([]byte("this is not a tar at all")); err == nil {
t.Error("bytes that are not a tar were accepted")
}
}
// Exactly one image. A bootstrap that chose between several would be the thing that guesses which
// one is the control plane, and it would guess right until the day somebody saved two.
func TestATarHoldingSeveralImagesIsRefused(t *testing.T) {
entries, err := json.Marshal([]manifestEntry{
{Config: strings.Repeat("a", 64) + ".json"},
{Config: strings.Repeat("b", 64) + ".json"},
})
if err != nil {
t.Fatal(err)
}
saved := savedImage(t, map[string]string{"manifest.json": string(entries)})
if _, err := ArchiveID(saved); err == nil {
t.Error("a tar holding two images was accepted")
}
}
// An id is a digest or it is nothing. A truncated one names several images, and which one ran
// would be whichever the runtime matched first — the same reasoning `internal/declaration` gives
// for refusing a short image reference.
func TestAConfigThatIsNotADigestIsRefused(t *testing.T) {
for _, config := range []string{"config.json", "abc.json", "blobs/sha256/" + strings.Repeat("a", 63)} {
saved := savedImage(t, map[string]string{"manifest.json": manifest(t, config)})
if _, err := ArchiveID(saved); err == nil {
t.Errorf("config %q was accepted and is not a digest", config)
}
}
}
// The committed placeholder must read as "carries nothing", so an installer built from a plain
// checkout says so in preflight rather than getting a machine as far as a running store and
// stopping. This is the same guarantee `internal/bundle` makes about a lock file of only comments.
func TestAnInstallerBuiltFromAPlainCheckoutCarriesNothing(t *testing.T) {
if !IsEmpty() {
// Not a failure of this checkout: `make bootstrap` embeds a real image and puts the
// placeholder back, so a real image here means a build was interrupted.
t.Skip("this checkout has a saved image embedded, so there is no placeholder to check")
}
if _, err := Saved(); err == nil {
t.Fatal("an installer carrying only the placeholder reported it carries an image")
}
}
// And "empty" is decided by whether the bytes could be loaded, not by matching the placeholder's
// text. A truncated or corrupted embed is equally unloadable and equally worth refusing early.
func TestEmptyMeansUnloadableRatherThanEqualToThePlaceholder(t *testing.T) {
restore := saved
defer func() { saved = restore }()
saved = []byte("half a tar, cut off")
if !IsEmpty() {
t.Error("bytes that are not a tar were reported as a carried image")
}
saved = savedImage(t, map[string]string{
"manifest.json": manifest(t, strings.Repeat("c", 64)+".json"),
})
if IsEmpty() {
t.Error("a real saved image was reported as no image at all")
}
}