Tests that read ../../../mesh-catalog or ../../../mesh-host gave a verdict that depended on what sat beside the checkout: a stale or dirty sibling failed them on a desktop, and a missing one skipped them unseen. They now read the clone the build seat puts in MESH_CHECK_BESIDE, failing when it is absent there, and elsewhere a copy captured at a named commit. The skip had hidden that the builder test read a module retired by ADR 0190. The systemd reading test no longer counts the machine's own environment.d.
156 lines
5.2 KiB
Go
156 lines
5.2 KiB
Go
package catalogue
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/novox/mesh-controller/internal/beside"
|
|
)
|
|
|
|
// TestEveryCatalogueManifestParses runs the real catalogue through the real gate.
|
|
//
|
|
// Not a fixture: the point is whether the manifests as written are accepted by the control plane that
|
|
// will read them, and a copy of one manifest proves nothing about the other seventy-one.
|
|
// catalogueRoot is the catalogue these checks run over: in a merge check the clone the build seat put
|
|
// beside this one, elsewhere the copy captured in testdata/beside (internal/beside). A check that only
|
|
// ran when somebody remembered a variable was a check nobody ran (novox/hq issue 134), and one that read
|
|
// whatever checkout sat beside judged the machine, not the change (novox/hq issue 432): it never skips.
|
|
func catalogueRoot(t *testing.T) string {
|
|
t.Helper()
|
|
return beside.Dir(t, "mesh-catalog")
|
|
}
|
|
|
|
func TestEveryCatalogueManifestParses(t *testing.T) {
|
|
root := catalogueRoot(t)
|
|
found, err := filepath.Glob(filepath.Join(root, "modules", "*", "module.json"))
|
|
if err != nil || len(found) == 0 {
|
|
t.Fatalf("no manifests under %s: %v", root, err)
|
|
}
|
|
named, routed := 0, 0
|
|
for _, p := range found {
|
|
raw, err := os.ReadFile(p)
|
|
if err != nil {
|
|
t.Fatalf("%s: %v", p, err)
|
|
}
|
|
m, err := ParseManifest(raw)
|
|
if err != nil {
|
|
t.Errorf("%s: %v", filepath.Base(filepath.Dir(p)), err)
|
|
continue
|
|
}
|
|
for _, l := range m.Listens {
|
|
if l.Name != "" {
|
|
named++
|
|
}
|
|
}
|
|
for port := range RoutedPorts(m) {
|
|
_ = port
|
|
routed++
|
|
}
|
|
}
|
|
t.Logf("%d manifests, %d named endpoints, %d routed endpoints resolved", len(found), named, routed)
|
|
if named == 0 {
|
|
t.Fatal("no endpoint in the catalogue is named, so this proved nothing")
|
|
}
|
|
}
|
|
|
|
// TestNoCatalogueManifestNamesAnInstallation is ADR 0112's check, run over the real catalogue: no
|
|
// definition names a domain or a public address the mesh acts on, and every value that must for now
|
|
// carries its reason (novox/hq ADR 0155, issue 134). The list it prints is the one that shrinks.
|
|
func TestNoCatalogueManifestNamesAnInstallation(t *testing.T) {
|
|
root := catalogueRoot(t)
|
|
found, err := filepath.Glob(filepath.Join(root, "modules", "*", "module.json"))
|
|
if err != nil || len(found) == 0 {
|
|
t.Fatalf("no manifests under %s: %v", root, err)
|
|
}
|
|
var named []string
|
|
for _, p := range found {
|
|
raw, err := os.ReadFile(p)
|
|
if err != nil {
|
|
t.Fatalf("%s: %v", p, err)
|
|
}
|
|
m, err := ParseManifest(raw)
|
|
if err != nil {
|
|
t.Errorf("%s: %v", p, err)
|
|
continue
|
|
}
|
|
named = append(named, InstallationProblems(m)...)
|
|
}
|
|
if len(named) > 0 {
|
|
t.Fatalf("%d value(s) name an installation:\n %s", len(named), strings.Join(named, "\n "))
|
|
}
|
|
}
|
|
|
|
// TestEveryCatalogueModuleDeclaresItsData is ADR 0233's check over the real catalogue (it replaced ADR
|
|
// 0214's store list): every provider that grants says what it keeps for its consumers, nothing writes a
|
|
// backup line by hand, every directory a container writes is declared, and every irreplaceable item is
|
|
// backed up — so a store added is a store backed up, without a list of stores to keep in step.
|
|
func TestEveryCatalogueModuleDeclaresItsData(t *testing.T) {
|
|
root := catalogueRoot(t)
|
|
found, err := filepath.Glob(filepath.Join(root, "modules", "*", "module.json"))
|
|
if err != nil || len(found) == 0 {
|
|
t.Fatalf("no manifests under %s: %v", root, err)
|
|
}
|
|
shelf := Shelf{}
|
|
granting := 0
|
|
for _, p := range found {
|
|
raw, err := os.ReadFile(p)
|
|
if err != nil {
|
|
t.Fatalf("%s: %v", p, err)
|
|
}
|
|
m, err := ParseManifest(raw)
|
|
if err != nil {
|
|
continue // TestEveryCatalogueManifestParses says why
|
|
}
|
|
if len(m.Grants) > 0 {
|
|
granting++
|
|
}
|
|
shelf[m.Module] = m
|
|
}
|
|
for _, problem := range DataProblems(shelf) {
|
|
t.Error(problem)
|
|
}
|
|
if granting == 0 {
|
|
t.Fatal("no module in the catalogue grants a provision, so this proved nothing")
|
|
}
|
|
}
|
|
|
|
// TestEveryCatalogueIdentityFitsWhatItRequires is ADR 0225's check over the real catalogue: every
|
|
// module's identity, on the longest machine name, fits the bound of every provision it wants. An
|
|
// overflow fails here, in the pull request that introduces it, rather than on the provider's machine
|
|
// the first time a real machine's name meets the module's (issue 263).
|
|
func TestEveryCatalogueIdentityFitsWhatItRequires(t *testing.T) {
|
|
root := catalogueRoot(t)
|
|
found, err := filepath.Glob(filepath.Join(root, "modules", "*", "module.json"))
|
|
if err != nil || len(found) == 0 {
|
|
t.Fatalf("no manifests under %s: %v", root, err)
|
|
}
|
|
shelf := Shelf{}
|
|
for _, p := range found {
|
|
raw, err := os.ReadFile(p)
|
|
if err != nil {
|
|
t.Fatalf("%s: %v", p, err)
|
|
}
|
|
m, err := ParseManifest(raw)
|
|
if err != nil {
|
|
t.Fatalf("%s: %v", p, err)
|
|
}
|
|
shelf[m.Module] = m
|
|
}
|
|
for _, p := range IdentityProblems(shelf, DefaultLongestMachine) {
|
|
t.Error(p)
|
|
}
|
|
// The night it was found: the resolver provision bounds nothing, and the object store still 20.
|
|
if dns, ok := shelf["dnsmasq"]; ok {
|
|
if b := dns.IdentityBoundOf("wildcard-resolution"); b.Bounded() {
|
|
t.Errorf("the resolver provision bounds its consumers' identities: %+v", b)
|
|
}
|
|
}
|
|
if store, ok := shelf["minio"]; ok {
|
|
if b := store.IdentityBoundOf("s3-bucket"); b.Max != 20 {
|
|
t.Errorf("the object store's access key is not bounded at 20: %+v", b)
|
|
}
|
|
}
|
|
}
|