mesh/merge-gate head 4b2eac702ab1 merged into trunk 221fe5a60d1f — pass: the change touches no module of the mesh's graph
mesh/repo-check head 4b2eac702ab1 merged into trunk 221fe5a60d1f — pass: THE CHANGE ALTERS ITS OWN CHECK (merge-check.sh): feat/57-config-and-provisioning'…
mesh/delivery delivered
So the release branch carries what main gained, and the store-tests drop check passes again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
141 lines
5.6 KiB
Go
141 lines
5.6 KiB
Go
package builder
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http/httptest"
|
|
"runtime"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// A built image's bases are linked into its repository before it is pushed (novox/hq issue 694): a
|
|
// runtime keeping containerd's image store may not hold a base layer it never had to fetch, and its push
|
|
// asks this machine only for what the repository lacks.
|
|
|
|
// aBaseForThisMachine puts an index into the registry under `repository`: one manifest for this
|
|
// machine's platform, one for another, and answers the index's digest and each manifest's blobs.
|
|
func aBaseForThisMachine(t *testing.T, dst *aRegistryOfRepositories, repository string) (string, []string, []string) {
|
|
t.Helper()
|
|
put := func(arch string) (string, []string) {
|
|
config := []byte(`{"architecture":"` + arch + `"}`)
|
|
layer := []byte(arch + " layer bytes")
|
|
for _, b := range [][]byte{config, layer} {
|
|
dst.blobs[digestOf(b)] = b
|
|
dst.link(repository, digestOf(b))
|
|
}
|
|
m, _ := json.Marshal(map[string]any{
|
|
"schemaVersion": 2, "mediaType": mediaManifestOCI,
|
|
"config": map[string]any{"mediaType": "application/vnd.oci.image.config.v1+json", "digest": digestOf(config), "size": len(config)},
|
|
"layers": []map[string]any{{"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", "digest": digestOf(layer), "size": len(layer)}},
|
|
})
|
|
dst.manifests[repository+"@"+digestOf(m)] = m
|
|
return digestOf(m), []string{digestOf(config), digestOf(layer)}
|
|
}
|
|
other := "s390x"
|
|
if runtime.GOARCH == other {
|
|
other = "amd64"
|
|
}
|
|
mine, mineBlobs := put(runtime.GOARCH)
|
|
theirs, theirBlobs := put(other)
|
|
index, _ := json.Marshal(map[string]any{
|
|
"schemaVersion": 2, "mediaType": mediaIndexOCI,
|
|
"manifests": []map[string]any{
|
|
{"mediaType": mediaManifestOCI, "digest": mine, "size": 1, "platform": map[string]string{"os": runtime.GOOS, "architecture": runtime.GOARCH}},
|
|
{"mediaType": mediaManifestOCI, "digest": theirs, "size": 1, "platform": map[string]string{"os": "linux", "architecture": other}},
|
|
},
|
|
})
|
|
dst.manifests[repository+"@"+digestOf(index)] = index
|
|
return digestOf(index), mineBlobs, theirBlobs
|
|
}
|
|
|
|
func TestABuildsBaseIsLinkedIntoItsRepositoryBeforeThePush(t *testing.T) {
|
|
dst := newRegistryOfRepositories()
|
|
server := httptest.NewServer(dst.handler())
|
|
defer server.Close()
|
|
address := strings.TrimPrefix(server.URL, "http://")
|
|
r := Registry{Address: address}
|
|
|
|
const from = "upstream/docker.io/library/golang"
|
|
index, mine, theirs := aBaseForThisMachine(t, dst, from)
|
|
bases := []string{
|
|
address + "/" + from + "@" + index,
|
|
// Not bases this registry holds: a package version, a tag, an image held nowhere here.
|
|
"@novox/mesh-sdk@1.2.3",
|
|
"golang:1-alpine",
|
|
"elsewhere.invalid/thing@sha256:" + strings.Repeat("e", 64),
|
|
}
|
|
n, err := r.LendBases(context.Background(), "mesh-tools-go/build", bases)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// Every blob of this machine's platform is in the image's repository, so a push asks this machine's
|
|
// store for none of them; another platform's are not, since nothing built here stands on them.
|
|
for _, blob := range mine {
|
|
if !dst.links["mesh-tools-go/build"][blob] {
|
|
t.Fatalf("the base's blob %s is not in the image's repository", blob)
|
|
}
|
|
}
|
|
for _, blob := range theirs {
|
|
if dst.links["mesh-tools-go/build"][blob] {
|
|
t.Fatalf("another platform's blob %s was linked", blob)
|
|
}
|
|
}
|
|
if n != len(mine) || dst.mounts != len(mine) || dst.uploads != 0 {
|
|
t.Fatalf("%d linked, %d mounts, %d uploads; want %d mounts and no bytes moved", n, dst.mounts, dst.uploads, len(mine))
|
|
}
|
|
|
|
// Asked again, nothing is mounted twice.
|
|
if n, err := r.LendBases(context.Background(), "mesh-tools-go/build", bases); err != nil || n != 0 {
|
|
t.Fatalf("a second lending mounted %d: %v", n, err)
|
|
}
|
|
}
|
|
|
|
// A registry that will not mount is said, not hidden: the push is still tried, from the store.
|
|
func TestABaseTheRegistryWillNotMountIsAnError(t *testing.T) {
|
|
dst := newRegistryOfRepositories()
|
|
dst.noMount = true
|
|
server := httptest.NewServer(dst.handler())
|
|
defer server.Close()
|
|
address := strings.TrimPrefix(server.URL, "http://")
|
|
index, _, _ := aBaseForThisMachine(t, dst, "upstream/thing")
|
|
_, err := Registry{Address: address}.LendBases(context.Background(), "hello/server",
|
|
[]string{address + "/upstream/thing@" + index})
|
|
if err == nil || !strings.Contains(err.Error(), "did not mount") {
|
|
t.Fatalf("a refused mount passed silently: %v", err)
|
|
}
|
|
}
|
|
|
|
// lending records what a build lent, and when, against the push.
|
|
type lending struct {
|
|
*mirroring
|
|
order []string
|
|
}
|
|
|
|
func (l *lending) LendBases(_ context.Context, repository string, bases []string) (int, error) {
|
|
l.order = append(l.order, "lend "+repository+" "+strings.Join(bases, " "))
|
|
return len(bases), nil
|
|
}
|
|
|
|
func (l *lending) PublishImage(ctx context.Context, localTag, repository string) (string, error) {
|
|
l.order = append(l.order, "push "+repository)
|
|
return l.mirroring.PublishImage(ctx, localTag, repository)
|
|
}
|
|
|
|
func TestAnImageIsPushedOnlyAfterItsBasesAreLent(t *testing.T) {
|
|
r, workspace := aRepository(t, anImage, map[string]string{"modules/bus/Dockerfile": "ARG BASE\nFROM ${BASE}"})
|
|
r.contents["modules/bus/module.json"] = anImage
|
|
l := &lending{mirroring: &mirroring{recorded: r, at: "127.0.0.1:5000"}}
|
|
if _, err := Build(context.Background(), r.run, l, "https://forge.invalid/catalogue.git", "modules/bus", "", workspace,
|
|
nil, Npmrc{}, GitCredential{}, nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
want := []string{
|
|
"lend bus/server 127.0.0.1:5000/upstream/docker.io/vendor/server@sha256:" + strings.Repeat("1", 64),
|
|
"push bus/server",
|
|
}
|
|
if strings.Join(l.order, "\n") != strings.Join(want, "\n") {
|
|
t.Fatalf("the build did:\n%s\nwant:\n%s", strings.Join(l.order, "\n"), strings.Join(want, "\n"))
|
|
}
|
|
}
|