mesh/merge-gate head 32bd8b5d5fb2 merged into trunk c2ec0a601acb — pass: builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step; every …
mesh/repo-check head 32bd8b5d5fb2 merged into trunk c2ec0a601acb — fail: its merge-check.sh failed: --- FAIL: TestNoReaderAnswersEmptyForAnError (2.20s)
mesh/delivery-group group fix/a-module-moves-only-when-its-program-changes rejected: a member's own check failed
mesh/delivery superseded: a newer head of the same pull request
A one-sentence change in a package mesh-builder imports but never reaches moved build-agent. A merge check now compares each module it builds with the build the mesh holds, the whole image without file times, labels or creation time, and a walk is cut without a module every check of its pull requests found the same, while the mesh still holds that build. A comparison that fails moves the module as before.
127 lines
5.2 KiB
Go
127 lines
5.2 KiB
Go
package builder
|
|
|
|
import (
|
|
"archive/tar"
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/novox/mesh-controller/internal/catalogue"
|
|
)
|
|
|
|
// aFilesystem is a filesystem tarball of files, each written at the time given.
|
|
func aFilesystem(t *testing.T, at time.Time, files map[string]string) []byte {
|
|
t.Helper()
|
|
var buf bytes.Buffer
|
|
tw := tar.NewWriter(&buf)
|
|
for _, name := range []string{"usr/local/bin/mesh-builder", "etc/apk/world"} {
|
|
body, ok := files[name]
|
|
if !ok {
|
|
continue
|
|
}
|
|
if err := tw.WriteHeader(&tar.Header{Name: name, Mode: 0o755, Size: int64(len(body)), ModTime: at,
|
|
Typeflag: tar.TypeReg}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := tw.Write([]byte(body)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
if err := tw.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return buf.Bytes()
|
|
}
|
|
|
|
// anEngine answers the container engine's commands for images by reference: each image's filesystem and labels.
|
|
func anEngine(images map[string][]byte, labels map[string]string, failing string) Runner {
|
|
created := map[string]string{}
|
|
return func(_ context.Context, _ string, name string, args ...string) (string, error) {
|
|
joined := strings.Join(args, " ")
|
|
ref := args[len(args)-1]
|
|
if failing != "" && strings.Contains(joined, failing) {
|
|
return "", fmt.Errorf("the engine refused %s", joined)
|
|
}
|
|
switch {
|
|
case args[0] == "pull", args[0] == "rm":
|
|
return "", nil
|
|
case args[0] == "image":
|
|
return fmt.Sprintf(`linux/amd64/ {"Entrypoint":["/usr/local/bin/mesh-builder"],"Labels":{"commit":%q}}`,
|
|
labels[ref]), nil
|
|
case args[0] == "create":
|
|
id := fmt.Sprintf("container%04d", len(created))
|
|
created[id] = ref
|
|
return id + "\n", nil
|
|
case args[0] == "export":
|
|
return "", os.WriteFile(args[2], images[created[ref]], 0o600)
|
|
}
|
|
return "", fmt.Errorf("unexpected %s %s", name, joined)
|
|
}
|
|
}
|
|
|
|
// TestAModuleWhoseProgramDidNotChangeIsSaidUnchanged is novox/hq issue 721: mesh-controller #335 changed one sentence
|
|
// in a package mesh-builder imports and never reaches, and build-agent moved. Built again, its image differs only in
|
|
// the files' times and its commit label, and the check says it is the same as the build the mesh holds.
|
|
func TestAModuleWhoseProgramDidNotChangeIsSaidUnchanged(t *testing.T) {
|
|
held := map[string]string{"build-agent/agent": "store/build-agent@sha256:aaaa"}
|
|
made := []catalogue.Built{{Name: "agent", Kind: "image", Reference: "scratch/build-agent@sha256:bbbb"}}
|
|
files := map[string]string{"usr/local/bin/mesh-builder": "the same program", "etc/apk/world": "docker-cli\ngit\n"}
|
|
images := map[string][]byte{
|
|
"store/build-agent@sha256:aaaa": aFilesystem(t, time.Unix(1000, 0), files),
|
|
"scratch/build-agent@sha256:bbbb": aFilesystem(t, time.Unix(2000, 0), files),
|
|
}
|
|
labels := map[string]string{"store/build-agent@sha256:aaaa": "a5500f73", "scratch/build-agent@sha256:bbbb": "c2ec0a60"}
|
|
same, against, err := sameAsHeld(context.Background(), anEngine(images, labels, ""), t.TempDir(), "build-agent",
|
|
made, held)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.HasPrefix(same, "unchanged: its program is the same as running build agent") ||
|
|
against["agent"] != held["build-agent/agent"] {
|
|
t.Fatalf("an image the same but for its times and labels is not said unchanged: %q %v", same, against)
|
|
}
|
|
|
|
// **Any file differing moves it**, not only its program.
|
|
changed := map[string]string{"usr/local/bin/mesh-builder": "the same program", "etc/apk/world": "docker-cli\ngit\ncurl\n"}
|
|
images["scratch/build-agent@sha256:bbbb"] = aFilesystem(t, time.Unix(2000, 0), changed)
|
|
if same, _, err := sameAsHeld(context.Background(), anEngine(images, labels, ""), t.TempDir(), "build-agent", made,
|
|
held); err != nil || same != "" {
|
|
t.Fatalf("an image with another file is said unchanged: %q %v", same, err)
|
|
}
|
|
|
|
// **A comparison that fails says nothing**, and the module moves.
|
|
images["scratch/build-agent@sha256:bbbb"] = aFilesystem(t, time.Unix(2000, 0), files)
|
|
if same, _, err := sameAsHeld(context.Background(), anEngine(images, labels, "export"), t.TempDir(), "build-agent",
|
|
made, held); err == nil || same != "" {
|
|
t.Fatalf("a comparison that failed said %q, %v", same, err)
|
|
}
|
|
|
|
// No held build, or an artifact that is not an image: nothing compared.
|
|
if same, _, _ := sameAsHeld(context.Background(), anEngine(images, labels, ""), t.TempDir(), "build-agent", made,
|
|
nil); same != "" {
|
|
t.Fatalf("a module the mesh holds no build of is said unchanged: %q", same)
|
|
}
|
|
archive := []catalogue.Built{{Name: "agent", Kind: "archive", Reference: "scratch/build-agent@sha256:bbbb"}}
|
|
if same, _, _ := sameAsHeld(context.Background(), anEngine(images, labels, ""), t.TempDir(), "build-agent",
|
|
archive, held); same != "" {
|
|
t.Fatalf("an archive is said unchanged without being compared: %q", same)
|
|
}
|
|
}
|
|
|
|
// TestAnImageWithAnotherEntrypointIsNotTheSame: the configuration counts, but for its labels.
|
|
func TestAnImageWithAnotherEntrypointIsNotTheSame(t *testing.T) {
|
|
a, err := configContent(`linux/amd64/ {"Entrypoint":["/a"],"Labels":{"commit":"1"}}`)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
b, _ := configContent(`linux/amd64/ {"Labels":{"commit":"2"},"Entrypoint":["/a"]}`)
|
|
c, _ := configContent(`linux/amd64/ {"Entrypoint":["/b"],"Labels":{"commit":"1"}}`)
|
|
if a != b || a == c {
|
|
t.Fatalf("labels count, or the entrypoint does not: %q %q %q", a, b, c)
|
|
}
|
|
}
|