package catalogue import ( "strings" "testing" ) // A build is recorded by what it is; where it is pushed is composed where it is used (novox/hq // 04-ISSUES/102). var digest = "sha256:" + strings.Repeat("d", 64) func TestAReferenceIsRecordedWithoutTheStoresAddress(t *testing.T) { cases := map[string]string{ "anchor.internal:5100/gitea/server@" + digest: ArtifactStoreScheme + "gitea/server@" + digest, "localhost:5000/gitea/server@" + digest: ArtifactStoreScheme + "gitea/server@" + digest, "http://anchor.internal:5100/v2/gitea/config/blobs/" + digest: ArtifactStoreScheme + "gitea/config/blobs/" + digest, ArtifactStoreScheme + "gitea/server@" + digest: ArtifactStoreScheme + "gitea/server@" + digest, digest: digest, "@novox/sdk@1.2.3": "@novox/sdk@1.2.3", "gitea/gitea@" + digest: "gitea/gitea@" + digest, "https://registry.example/v2/gitea/config/blobs/" + digest: "https://registry.example/v2/gitea/config/blobs/" + digest, } for announced, want := range cases { if got := Recorded(announced); got != want { t.Errorf("Recorded(%q) = %q, want %q", announced, got, want) } } } func TestARecordedReferenceIsRoutedThroughTheStoreAsItIsNow(t *testing.T) { if got := Routed(ArtifactStoreScheme+"gitea/server@"+digest, "anchor.internal:5101"); got != "anchor.internal:5101/gitea/server@"+digest { t.Errorf("an image is fetched as %q", got) } if got := Routed(ArtifactStoreScheme+"gitea/config/blobs/"+digest, "anchor.internal:5101"); got != "http://anchor.internal:5101/v2/gitea/config/blobs/"+digest { t.Errorf("an archive is fetched as %q", got) } if got := Routed("gitea/gitea@"+digest, "anchor.internal:5101"); got != "gitea/gitea@"+digest { t.Errorf("a reference that is not the store's was routed: %q", got) } // One recorded before references were kept without their address follows the store too. if got := Rerouted("anchor.internal:5100/gitea/server@"+digest, "anchor.internal:5101"); got != "anchor.internal:5101/gitea/server@"+digest { t.Errorf("a reference recorded with the old address stays there: %q", got) } } // **The address is composed into a declaration, and the record never carries it.** func TestAnImageTheMeshBuiltIsRoutedThroughTheStoreWhenDeclared(t *testing.T) { m := Manifest{Module: "gitea", Version: "1", Resources: []map[string]any{ {"id": "server", "type": "container", "name": "mesh-gitea", "artifact": "server"}, {"id": "config", "type": "archive", "path": "/etc/gitea", "artifact": "config"}, {"id": "cache", "type": "container", "name": "mesh-gitea-cache", "image": "valkey/valkey@" + digest}, }, Build: &Build{Artifacts: []Artifact{ {Name: "server", Kind: ArtifactImage, From: "Dockerfile"}, {Name: "config", Kind: ArtifactArchive, From: "config"}, }}} resolved, err := m.Resolve([]Built{ {Name: "server", Kind: ArtifactImage, Reference: ArtifactStoreScheme + "gitea/server@" + digest}, {Name: "config", Kind: ArtifactArchive, Reference: ArtifactStoreScheme + "gitea/config/blobs/" + digest, Digest: digest}, }) if err != nil { t.Fatal(err) } r := Resolution{Node: "anchor", Modules: []Manifest{resolved}} out, err := r.Declaration(Rendering{ArtifactStore: "anchor.internal:5101"}) if err != nil { t.Fatal(err) } if got := fileNamed(out, "gitea.server")["image"]; got != "anchor.internal:5101/gitea/server@"+digest { t.Errorf("the image the mesh built is fetched as %v", got) } if got := fileNamed(out, "gitea.config")["source"]; got != "http://anchor.internal:5101/v2/gitea/config/blobs/"+digest { t.Errorf("the archive the mesh built is fetched from %v", got) } if got := fileNamed(out, "gitea.cache")["image"]; got != "valkey/valkey@"+digest { t.Errorf("an image from a public registry was routed through the store: %v", got) } // The manifest the mesh holds still says what it is, not where it was fetched from. if got := resolved.Resources[0]["image"]; got != ArtifactStoreScheme+"gitea/server@"+digest { t.Errorf("composing wrote the address into the catalogue's copy: %v", got) } // And the store moves: the same record, another address, without a rebuild. out, err = r.Declaration(Rendering{ArtifactStore: "laptop.internal:5000"}) if err != nil { t.Fatal(err) } if got := fileNamed(out, "gitea.server")["image"]; got != "laptop.internal:5000/gitea/server@"+digest { t.Errorf("after the store moved, the image is still fetched as %v", got) } } func TestAnImageInTheStoreWithNoStoreToFetchItFromIsRefused(t *testing.T) { m := Manifest{Module: "gitea", Version: "1", Resources: []map[string]any{ {"id": "server", "type": "container", "name": "mesh-gitea", "image": ArtifactStoreScheme + "gitea/server@" + digest}, }} _, err := Resolution{Node: "anchor", Modules: []Manifest{m}}.Declaration(Rendering{}) if err == nil || !strings.Contains(err.Error(), "no artifact store") { t.Fatalf("a reference nothing can fetch was sent to a machine: %v", err) } } // **A reference recorded with an address before this follows the store too** — when the mesh // built it. A module running an image straight from a public registry under its own name is left // exactly where it says: `quay.io/keycloak/keycloak` is not the mesh's, whatever it is called. func TestAReferenceRecordedWithAnAddressFollowsTheStoreWhenTheMeshBuiltIt(t *testing.T) { m := Manifest{Module: "keycloak", Version: "1", Resources: []map[string]any{ {"id": "server", "type": "container", "name": "mesh-keycloak", "image": "anchor.internal:5100/keycloak/server@" + digest}, {"id": "upstream", "type": "container", "name": "mesh-keycloak-upstream", "image": "quay.io/keycloak/keycloak@" + digest}, }} r := Resolution{Node: "anchor", Modules: []Manifest{m}} out, err := r.Declaration(Rendering{ ArtifactStore: "anchor.internal:5101", Built: map[string]bool{"keycloak/server": true}, }) if err != nil { t.Fatal(err) } if got := fileNamed(out, "keycloak.server")["image"]; got != "anchor.internal:5101/keycloak/server@"+digest { t.Errorf("an image the mesh built, recorded with the old address, is fetched as %v", got) } if got := fileNamed(out, "keycloak.upstream")["image"]; got != "quay.io/keycloak/keycloak@"+digest { t.Errorf("a public image was re-routed through the store: %v", got) } // Nothing known to be built: nothing re-routed, nothing refused. out, err = r.Declaration(Rendering{ArtifactStore: "anchor.internal:5101"}) if err != nil { t.Fatal(err) } if got := fileNamed(out, "keycloak.server")["image"]; got != "anchor.internal:5100/keycloak/server@"+digest { t.Errorf("with no build record, a reference was rewritten: %v", got) } }