package catalogue import ( "encoding/json" "os" "path/filepath" "regexp" "strings" "testing" ) // Defends novox/hq ADR 0110: a seat is a module assignment from a closed set. // The set is closed, and changing it is a decision. // // **The count is asserted, and every entry names the record that made it a seat**, so the next // person changing the set finds the argument rather than a number to edit — the pattern the host's // vocabulary test follows. If this fails because a seat was added, the fix is a record in novox/hq // and a row in to-be 26, not a new number here. func TestTheSeatsAreAClosedSetAndEachNamesItsDecision(t *testing.T) { record := regexp.MustCompile(`^novox/hq ADR \d{4}$`) seen := map[string]bool{} delivered := map[string]string{} for _, s := range Seats() { if seen[s.Name] { t.Errorf("%s is in the set twice", s.Name) } seen[s.Name] = true if !record.MatchString(s.Decision) { t.Errorf("%s names %q as its decision; every seat names the record that made it one", s.Name, s.Decision) } switch s.Scope { case ScopeNode, ScopeSite, ScopeMesh: default: t.Errorf("%s is held per %q, which is not a scope", s.Name, s.Scope) } if s.Delivers != "" { // Two seats answering for one provision would put the question "which one?" back, // which is the question a seat exists to answer. if other, twice := delivered[s.Delivers]; twice { t.Errorf("%s and %s both deliver %q", other, s.Name, s.Delivers) } delivered[s.Delivers] = s.Name } } if len(Seats()) != 14 { t.Errorf("the mesh defines %d seats rather than 14; the set is closed, so a change here is "+ "a decision (novox/hq ADR 0110): %s", len(Seats()), seatNames()) } } func claimed(claims string) []byte { return []byte(`{"module":"thing","version":"1","provides":[{"name":"npm-package-registry","scope":"mesh"}],"claims":` + claims + `}`) } func TestAClaimOnASeatTheMeshDoesNotDefineIsRefused(t *testing.T) { _, err := ParseManifest(claimed(`[{"name":"the-anything","scope":"node"}]`)) if err == nil { t.Fatal("a module invented a seat by claiming it") } if !strings.Contains(err.Error(), "the-anything") || !strings.Contains(err.Error(), "not a seat") { t.Fatalf("the refusal does not say the seat is unknown: %v", err) } // And it says what the seats are, because "no" without the list sends somebody reading code. if !strings.Contains(err.Error(), "the-packet-filter") { t.Fatalf("the refusal does not list the seats: %v", err) } } func TestASeatClaimedAtAnotherScopeIsRefused(t *testing.T) { _, err := ParseManifest(claimed(`[{"name":"npm-package-registry","scope":"node"}]`)) if err == nil { t.Fatal("a mesh seat was held per node") } if !strings.Contains(err.Error(), "mesh seat") { t.Fatalf("the refusal does not say which scope the seat is: %v", err) } } func TestADeliveringSeatIsOnlyHeldByAModuleThatProvides(t *testing.T) { // Holding it makes the module the mesh's answer for the provision. A module that cannot answer // would be the answer anyway, and every consumer would be sent to it. raw := []byte(`{"module":"thing","version":"1","claims":[{"name":"git","scope":"mesh"}]}`) _, err := ParseManifest(raw) if err == nil { t.Fatal("a module holding the git seat need not provide git") } if !strings.Contains(err.Error(), `does not provide "git"`) { t.Fatalf("the refusal does not say what is missing: %v", err) } } func TestAClaimThatIsMalformedIsRefusedOnceForThat(t *testing.T) { // Not a second time for being unknown: one mistake, one line. _, err := ParseManifest(claimed(`[{"name":"Not A Name","scope":"node"}]`)) if err == nil { t.Fatal("a malformed claim was accepted") } if strings.Contains(err.Error(), "not a seat") { t.Fatalf("a malformed claim was also called unknown: %v", err) } } // Every module in use claims a seat in the set, so closing it refuses nothing that runs. // // Read from the catalogue beside this checkout and from this repository's own manifest, the two // places a manifest lives (ADR 0069). The private-network module's manifest is composed in code, // and its claim is checked where it is composed. func TestEveryManifestInUseClaimsASeatTheMeshDefines(t *testing.T) { paths, _ := filepath.Glob("../../../mesh-catalog/modules/*/module.json") if len(paths) == 0 { t.Skip("the catalogue is not beside this checkout") } paths = append(paths, "../../module.json") var checked int for _, path := range paths { raw, err := os.ReadFile(path) if err != nil { t.Fatal(err) } // Leniently, so a manifest refused for something unrelated is not reported as a seat // problem, and the seat check below is the only thing this test holds a module to. var m Manifest if err := json.Unmarshal(raw, &m); err != nil { t.Fatalf("%s: %v", path, err) } for _, problem := range claimProblems(m) { t.Errorf("%s: %s", path, problem) } checked += len(m.Claims) } if checked == 0 { t.Fatal("no claims were checked, so this proved nothing") } } // The holder of a seat answers among several providers. func registryShelf() map[string]Manifest { return shelf( Manifest{Module: "gitea", Version: "1", Provides: FromAnywhere("npm-package-registry"), Claims: []Claim{{Name: "npm-package-registry", Scope: ScopeMesh}}}, Manifest{Module: "verdaccio", Version: "1", Provides: FromAnywhere("npm-package-registry")}, Manifest{Module: "builder", Version: "1", Requires: []string{"npm-package-registry"}}, ) } func twoRegistries() map[string][]Provider { return map[string][]Provider{"npm-package-registry": { {Node: "anchor", At: "anchor.internal", Module: "gitea"}, {Node: "archive", At: "archive.internal", Module: "verdaccio"}, }} } func giteaHoldsTheSeat() []Held { return []Held{{Claim: "npm-package-registry", Scope: ScopeMesh, Node: "anchor", Module: "gitea"}} } func TestTheSeatsHolderAnswersWhenSeveralProvide(t *testing.T) { // The whole point: a second registry beside the holder harms nothing, and nobody pins. got, err := Resolve(registryShelf(), []string{"builder"}, reachable(), World{Offered: twoRegistries(), Held: giteaHoldsTheSeat()}) if err != nil { t.Fatal(err) } if len(got.Needs) != 1 || got.Needs[0].From != "anchor" { t.Fatalf("the seat's holder did not answer: %v", got.Needs) } } func TestAPinStillWinsOverTheSeat(t *testing.T) { // A consumer coupled to one provider's contents has said so, and the seat does not overrule it. got, err := Resolve(registryShelf(), []string{"builder"}, reachable(), World{Offered: twoRegistries(), Held: giteaHoldsTheSeat(), Pinned: map[string]string{"npm-package-registry": "archive"}}) if err != nil { t.Fatal(err) } if len(got.Needs) != 1 || got.Needs[0].From != "archive" { t.Fatalf("the pin was overruled by the seat: %v", got.Needs) } } func TestWithTheSeatUnheldSeveralProvidersAreStillRefused(t *testing.T) { // No seat held is no choice made, and ADR 0009's rule stands: never guessed. _, err := Resolve(registryShelf(), []string{"builder"}, reachable(), World{Offered: twoRegistries()}) if err == nil { t.Fatal("one of two registries was picked with nobody holding the seat") } if !strings.Contains(err.Error(), "pin") { t.Fatalf("the refusal does not say how to choose: %v", err) } } func TestTheHolderIsTheModuleNotTheMachine(t *testing.T) { // Two modules on one machine could provide the same thing; only the one holding the seat // answers. A holder matched by node alone would send consumers to whichever came first. providers := []Provider{ {Node: "anchor", At: "anchor.internal", Module: "verdaccio"}, {Node: "anchor", At: "anchor.internal", Module: "gitea"}, } holder, held := HolderAmong("npm-package-registry", providers, giteaHoldsTheSeat()) if !held || holder.Module != "gitea" { t.Fatalf("the holder was not told apart from a neighbour: %+v", holder) } }