The control plane's manifest existed twice: at the root of its repository, read whenever the mesh rebuilds it from source, and as a copy in the catalogue, read by genesis. Nothing kept them equal, and the first rebuild replaced the mesh's record with the repository's shape while every later push was refused (novox/hq 04-ISSUES/072). The builder's one-shot result already carries the manifest it built, artifact resolved to the image; step 3 keeps it and step 9 registers it, re-pinning the built image's bare id to the reference the registry assigned. The catalogue is still read for the registry's and the builder's manifests and for phase two.
96 lines
4.7 KiB
Go
96 lines
4.7 KiB
Go
package bootstrap
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// An installer that carries a builder and was told nothing refuses, and says what is missing.
|
|
//
|
|
// **Exercised rather than assumed.** This is the refusal that stands between a person and a
|
|
// machine left holding a store, a broker and no control plane — the failure the whole preflight
|
|
// exists to prevent — and a refusal nothing tests is a refusal nobody has read.
|
|
func TestAnInstallerWithNothingToBuildRefuses(t *testing.T) {
|
|
err := Source{}.Check()
|
|
if err == nil {
|
|
t.Fatal("a source naming no repository was accepted; nothing would have been built")
|
|
}
|
|
for _, want := range []string{"--source", "--source-ref"} {
|
|
if !strings.Contains(err.Error(), want) {
|
|
t.Errorf("the refusal does not name %s, so it does not say how to fix it: %v", want, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// A repository without a commit refuses too, because a branch is somebody else's moving target.
|
|
func TestABranchIsNotACommit(t *testing.T) {
|
|
err := Source{Repository: "https://example.invalid/mesh-controller.git"}.Check()
|
|
if err == nil {
|
|
t.Fatal("a source with no ref was accepted; genesis would have built whatever a branch pointed at")
|
|
}
|
|
if !strings.Contains(err.Error(), "--source-ref") {
|
|
t.Errorf("the refusal does not name the flag that fixes it: %v", err)
|
|
}
|
|
}
|
|
|
|
// And a repository with a commit is enough.
|
|
func TestARepositoryAndACommitIsEnough(t *testing.T) {
|
|
if err := (Source{Repository: "https://example.invalid/mesh-controller.git", Ref: "a1b2c3d4"}).Check(); err != nil {
|
|
t.Fatalf("a repository and a commit were refused: %v", err)
|
|
}
|
|
}
|
|
|
|
// **The build hands over the manifest, and the installer registers that one.** The control plane
|
|
// used to have two manifests — one at the root of its repository, which the mesh reads whenever
|
|
// it rebuilds the control plane from source, and a copy in the catalogue, which genesis read — and
|
|
// nothing kept them equal (novox/hq 04-ISSUES/072). The builder already reports the manifest it
|
|
// built, artifact resolved to the image; genesis takes it from there and reads no second copy.
|
|
func TestTheBuildHandsOverTheManifestTheMeshWillHold(t *testing.T) {
|
|
manifest := `{"module":"mesh-controller","version":"1","resources":[` +
|
|
`{"id":"server","type":"container","name":"mesh-controller","image":"` + builtImage + `"}]}`
|
|
runtime := &asked{answer: func(string, []string) (string, error) {
|
|
return `{"module":"mesh-controller","commit":"a1b2c3d4","manifest":` + manifest +
|
|
`,"made":[{"name":"server","kind":"image","reference":"` + builtImage + `"}]}` + "\n", nil
|
|
}}
|
|
built, err := BuildControlPlane(context.Background(), runtime.run, "mesh-builder:test",
|
|
Source{Repository: "https://example.invalid/mesh-controller.git", Ref: "a1b2c3d4"}, false, func(string) {})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if built.Image != builtImage {
|
|
t.Errorf("the built image is %q", built.Image)
|
|
}
|
|
if string(built.Manifest) != manifest {
|
|
t.Errorf("the manifest handed over is not the one the builder reported:\n%s", built.Manifest)
|
|
}
|
|
}
|
|
|
|
// A result without a manifest is a build the installer cannot finish, and it is refused beside the
|
|
// builder that said it rather than at step 9 with a message about a missing file.
|
|
func TestABuildReportingNoManifestIsRefused(t *testing.T) {
|
|
runtime := &asked{answer: func(string, []string) (string, error) {
|
|
return `{"module":"mesh-controller","commit":"a1b2c3d4",` +
|
|
`"made":[{"name":"server","kind":"image","reference":"` + builtImage + `"}]}`, nil
|
|
}}
|
|
_, err := BuildControlPlane(context.Background(), runtime.run, "mesh-builder:test",
|
|
Source{Repository: "https://example.invalid/mesh-controller.git", Ref: "a1b2c3d4"}, false, func(string) {})
|
|
if err == nil || !strings.Contains(err.Error(), "no manifest") {
|
|
t.Fatalf("a build reporting no manifest was accepted, or refused for another reason: %v", err)
|
|
}
|
|
}
|
|
|
|
// And a manifest that does not name the image the build produced describes some other build.
|
|
func TestABuildWhoseManifestNamesAnotherImageIsRefused(t *testing.T) {
|
|
runtime := &asked{answer: func(string, []string) (string, error) {
|
|
return `{"module":"mesh-controller","commit":"a1b2c3d4","manifest":{"module":"mesh-controller",` +
|
|
`"resources":[{"id":"server","type":"container","image":"sha256:` + strings.Repeat("9", 64) + `"}]},` +
|
|
`"made":[{"name":"server","kind":"image","reference":"` + builtImage + `"}]}`, nil
|
|
}}
|
|
_, err := BuildControlPlane(context.Background(), runtime.run, "mesh-builder:test",
|
|
Source{Repository: "https://example.invalid/mesh-controller.git", Ref: "a1b2c3d4"}, false, func(string) {})
|
|
if err == nil || !strings.Contains(err.Error(), "does not name that image") {
|
|
t.Fatalf("a manifest naming another image was accepted, or refused for another reason: %v", err)
|
|
}
|
|
}
|