Files
mesh-sdk/go/catalogue/seats_test.go
T

105 lines
4.0 KiB
Go

package catalogue
import (
"strings"
"testing"
)
// Defends novox/hq ADR 0110: a seat is a module assignment from a closed set.
func claimed(claims string) []byte {
return []byte(`{"module":"thing","version":"1","provides":[{"name":"npm-package-registry","scope":"mesh","credential":{"form":"none"}}],"claims":` + claims + `}`)
}
// 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]Chosen{"npm-package-registry": {Node: "archive", Module: "verdaccio"}}})
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)
}
}
// The working set is loaded from the store, and an empty load never erases it (novox/hq ADR 0122).
func TestUseSeatsReplacesTheSetButNeverEmptiesIt(t *testing.T) {
before := Seats()
defer UseSeats(DefaultSeats()) // restore for other tests, whatever this leaves it as
// An empty load (store not seeded, or unreadable) leaves the compiled defaults in force.
UseSeats(nil)
if len(Seats()) != len(before) {
t.Fatalf("an empty load changed the set from %d to %d seats", len(before), len(Seats()))
}
// A non-empty load replaces it — this is how a rename in the store reaches the lookups.
UseSeats([]Seat{{Name: "node-firewall", Scope: ScopeNode, Decision: "novox/hq ADR 0122"}})
if _, known := SeatNamed("node-firewall"); !known {
t.Fatal("the loaded set did not replace the working set")
}
if len(Seats()) != 1 {
t.Fatalf("the working set is %d seats, not the one that was loaded", len(Seats()))
}
}