Implements novox/hq ADR 0110 and 0111. The seat set lives in internal/catalogue/seats.go: fourteen seats, each with a scope, what occupying it delivers, and the record that made it one. A test asserts the count and a decision per entry, so changing the set means finding the argument, as the host's vocabulary test does. The first set is every seat already claimed — including the-private-network, which the network module claims from a manifest composed in this repository's code, not from any module.json — plus npm-package-registry (ADR 0109) and git (ADR 0111). A test parses every catalogue manifest and this repository's own and fails on any refused claim, so closing the set refuses nothing in use. ParseManifest now refuses a claim on a seat the mesh does not define, a seat claimed at another scope, and a delivering seat claimed by a module that does not provide what it delivers. A malformed claim is refused once, for being malformed. Resolution: among several providers of a mesh provision, a pin still wins; then the holder of the seat that delivers it; then the only provider; otherwise refused as before. ADR 0009's "never guessed" holds — the seat is the choice made once, mesh-wide, rather than a pin per consumer node. A provider now carries the module it came from, because a provider is a (node, module) pair and the pair is what tells a holder from a neighbour on the same machine. The planner's second pass is now given the first pass's holdings. Without them, a node consuming a seat-delivered provision was refused there, and a refused node's own claims dropped out of what the mesh holds — letting a second holder of one of its seats pass unrefused. `seats [--json]` lists every seat, what it delivers, and each holder, derived from assignments every time and never stored. Unheld seats are listed. A stored claim outside the set — possible for a manifest registered before the set closed, since stored manifests are not re-validated — is shown rather than hidden. `build --self <owner>/<repo>` builds from a repository on the git seat's holder. The clone URL is composed at build time from the holder's node and what it serves for git; the recorded source is the path and the seat (migration 0032), never an address, so a moved forge changes nothing recorded. Nobody holding the seat refuses self-hosted builds and says so; external URLs are unchanged. An address passed with --self is refused rather than recorded as a path. Replaces three foundation tests that defended the builder's carried package binding. The catalogue removed that binding when the builder began requiring the registry through a real grant, so the tests were already failing on main; they now assert the builder requires what the npm seat delivers and carries no copy of its own, and that the forge holds the npm and git seats. Verified: go vet clean; the whole suite passes against a throwaway Postgres (make postgres), the new inventory tests included; gofmt clean apart from cmd/mesh-builder/stdout_test.go, which fails on main too.
109 lines
3.6 KiB
Go
109 lines
3.6 KiB
Go
package main
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/novox/mesh-controller/internal/catalogue"
|
|
)
|
|
|
|
// Defends novox/hq ADR 0111: a build source is on the git seat, or it is external.
|
|
|
|
func forgeHolding(port any) catalogue.World {
|
|
return catalogue.World{
|
|
Held: []catalogue.Held{{Claim: "git", Scope: catalogue.ScopeMesh, Node: "anchor", Module: "gitea"}},
|
|
Offered: map[string][]catalogue.Provider{"git": {
|
|
// A second forge that does not hold the seat, so taking the first one found would be wrong.
|
|
{Node: "archive", At: "archive.internal", Module: "gitea-mirror",
|
|
Serves: map[string]any{"scheme": "http", "port": float64(3000)}},
|
|
{Node: "anchor", At: "anchor.internal", Module: "gitea",
|
|
Serves: map[string]any{"scheme": "http", "port": port}},
|
|
}},
|
|
}
|
|
}
|
|
|
|
func TestARepositoryOnTheSeatIsClonedFromItsHolder(t *testing.T) {
|
|
got, err := clonedFromSeat(forgeHolding(float64(3000)), "git", "novox/mesh-catalog")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got != "http://anchor.internal:3000/novox/mesh-catalog.git" {
|
|
t.Fatalf("cloned from %s", got)
|
|
}
|
|
}
|
|
|
|
func TestAMovedForgeIsFollowedWithoutRewritingAnything(t *testing.T) {
|
|
// The whole point: the node gave the forge another port, and the same recorded path clones
|
|
// from the new one. Nothing recorded contained the old one to be wrong.
|
|
got, err := clonedFromSeat(forgeHolding(float64(3100)), "git", "novox/mesh-catalog")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(got, ":3100/") {
|
|
t.Fatalf("the moved port was not followed: %s", got)
|
|
}
|
|
}
|
|
|
|
func TestWithNobodyHoldingTheSeatASelfHostedBuildIsRefusedAndSaysWhy(t *testing.T) {
|
|
_, err := clonedFromSeat(catalogue.World{}, "git", "novox/mesh-catalog")
|
|
if err == nil {
|
|
t.Fatal("a repository was cloned from a forge the mesh does not have")
|
|
}
|
|
for _, want := range []string{"nobody holds the git seat", "without --self"} {
|
|
if !strings.Contains(err.Error(), want) {
|
|
t.Fatalf("the refusal does not say %q: %v", want, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAnExternalRepositoryIsClonedExactlyAsGiven(t *testing.T) {
|
|
// Unaffected by the seat, held or not: GitHub and GitLab are the ordinary cases.
|
|
given := "https://github.com/someone/something.git"
|
|
got, err := cloneFrom(t.Context(), buildSource{Repository: given})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got != given {
|
|
t.Fatalf("an external repository became %s", got)
|
|
}
|
|
}
|
|
|
|
func TestAHolderOffThePrivateNetworkIsRefused(t *testing.T) {
|
|
world := forgeHolding(float64(3000))
|
|
world.Offered["git"][1].At = ""
|
|
if _, err := clonedFromSeat(world, "git", "novox/mesh-catalog"); err == nil ||
|
|
!strings.Contains(err.Error(), "private network") {
|
|
t.Fatalf("a forge nothing can reach was cloned from: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestAHolderServingNoPortIsRefusedRatherThanGuessed(t *testing.T) {
|
|
// A default port would be the forge's address guessed, which is what this exists to stop.
|
|
if _, err := clonedFromSeat(forgeHolding(nil), "git", "novox/mesh-catalog"); err == nil {
|
|
t.Fatal("a port was guessed for a forge that serves none")
|
|
}
|
|
}
|
|
|
|
func TestAnAddressGivenAsAPathOnTheForgeIsRefused(t *testing.T) {
|
|
for _, bad := range []string{
|
|
"https://github.com/someone/something.git",
|
|
"git@anchor:novox/mesh-catalog.git",
|
|
"/srv/git/mesh-catalog",
|
|
"",
|
|
} {
|
|
if err := onASeat(bad); err == nil {
|
|
t.Errorf("--self accepted %q as a path on the forge", bad)
|
|
}
|
|
}
|
|
if err := onASeat("novox/mesh-catalog"); err != nil {
|
|
t.Errorf("a path on the forge was refused: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestASourceOnTheSeatReadsAsAPathNotAnAddress(t *testing.T) {
|
|
s := buildSource{Repository: "novox/mesh-catalog", Seat: "git"}
|
|
if got := s.String(); got != "novox/mesh-catalog on the git seat" {
|
|
t.Fatalf("read as %q", got)
|
|
}
|
|
}
|