package catalogue import ( "strings" "testing" ) // Genesis assigns the build agent before the package registry exists (novox/hq ADR 0336, issue 121), // judged over the real catalogue. Genesis's step 13 was refused with "nothing provides // \"npm-package-registry\", wanted by build-agent": the forge genesis raises at its packages step is a // container, not the gitea module, and provides nothing. // agentBuilt is the build agent as the mesh holds it once built: its image pinned. func agentBuilt(t *testing.T) Manifest { t.Helper() agent := catalogueManifest(t, "build-agent") built, err := agent.Resolve([]Built{{Name: "server", Kind: ArtifactImage, Reference: "mesh-builder@sha256:" + strings.Repeat("a", 64)}}) if err != nil { t.Fatalf("the build agent does not resolve against its own build: %v", err) } return built } func TestGenesisAssignsTheBuildAgentWithNothingProvidingTheRegistry(t *testing.T) { agent := agentBuilt(t) if !agent.IsOptional("npm-package-registry") { t.Fatalf("the build agent's npm-package-registry is hard (ADR 0336 §1): %v", agent.Requires) } if agent.IsOptional("artifact-store") { t.Fatal("the build agent's artifact-store is optional; it stays hard") } store := map[string][]Provider{"artifact-store": { {Node: "anchor", At: "anchor.internal", Module: "distribution", Serves: map[string]any{"port": float64(5000)}}}} books := shelf(agent, catalogueManifest(t, "gitea"), catalogueManifest(t, "distribution")) // Genesis's node at step 13: the store answers, nothing provides the registry. got, err := Resolve(books, []string{"build-agent"}, reachable(), World{Offered: store}) if err != nil { t.Fatalf("assigning the build agent with no registry was refused: %v", err) } if have := strings.Join(names(got), " "); have != "build-agent" { t.Fatalf("assigning the build agent put %s on the machine; nothing is installed for the registry", have) } if len(got.Absent) != 1 || got.Absent[0] != (Absent{Consumer: "build-agent", Requirement: "npm-package-registry"}) { t.Fatalf("the registry is not listed unbound for the build agent: %+v", got.Absent) } out, err := got.Declaration(Rendering{ArtifactStore: "anchor.internal:5000", Needed: map[string]map[string]string{"build-agent": {"broker": "sealed-broker"}}}) if err != nil { t.Fatalf("the build agent does not compose with the registry unbound: %v", err) } for _, id := range []string{"build-agent." + BoundID("npm-package-registry"), "build-agent." + SecretID("npm-package-registry"), "build-agent." + NeedID("genesis-package-registry")} { if fileNamed(out, id) != nil { t.Errorf("%s was delivered with the registry unbound and no genesis document given", id) } } // The genesis document, once the installer seals it at the packages step (ADR 0336 §3). out, err = got.Declaration(Rendering{ArtifactStore: "anchor.internal:5000", Needed: map[string]map[string]string{"build-agent": {"broker": "sealed-broker", "genesis-package-registry": "sealed-genesis"}}}) if err != nil { t.Fatal(err) } doc := fileNamed(out, "build-agent."+NeedID("genesis-package-registry")) if doc == nil || doc["sealed"] != "sealed-genesis" || !strings.HasSuffix(doc["path"].(string), "/genesis-package-registry.json") { t.Fatalf("the genesis document is not delivered where the agent reads it: %v", doc) } // The gitea module assigned: the requirement binds, with no act on the build agent (ADR 0336 §2). registry := map[string][]Provider{"artifact-store": store["artifact-store"], "npm-package-registry": { {Node: "anchor", At: "anchor.internal", Module: "gitea", Serves: map[string]any{"port": float64(3000), "scheme": "http", "npm-path": "/api/packages/novox/npm/"}}}} bound, err := Resolve(books, []string{"build-agent"}, reachable(), World{Offered: registry}) if err != nil { t.Fatal(err) } if n := boundFrom(t, bound, "build-agent", "npm-package-registry"); n.Module != "gitea" { t.Fatalf("bound to %s", n.Module) } if len(bound.Absent) != 0 { t.Fatalf("the registry is still listed unbound once gitea is assigned: %+v", bound.Absent) } }