Split the unit level from the integration level in cmd, builder, link, catalogue, inventory; cheap fixtures for the archive-entry bound, the registry waits and the catalogue copy (issue 895)
This commit is contained in:
@@ -2,15 +2,10 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/novox/mesh-controller/internal/catalogue"
|
||||
snapshot "github.com/novox/mesh-controller/internal/facts"
|
||||
"github.com/novox/mesh-controller/internal/inventory"
|
||||
)
|
||||
|
||||
// A file's text kept as a template file in its module's repository (novox/hq ADR 0349 §2, design 57 package T1,
|
||||
@@ -83,34 +78,6 @@ func TestModuleCheckReadsTemplatesFromTheTreeBesideTheManifest(t *testing.T) {
|
||||
}
|
||||
|
||||
// templatedMesh is catalogueMesh with the notifier on the laptop, registered as built: its text inline.
|
||||
func templatedMesh(t *testing.T) (snapshot.Facts, map[string]string) {
|
||||
t.Helper()
|
||||
open := aMesh(t)
|
||||
ctx := t.Context()
|
||||
manifests := map[string]string{
|
||||
"lemurs": `{"module":"lemurs","version":"1","capabilities":["systemd"],
|
||||
"resources":[{"id":"service","type":"service","unit":"lemurs.service","state":"running","boot":"enabled"}]}`,
|
||||
"notifier": inlineNotifier,
|
||||
}
|
||||
for name, raw := range manifests {
|
||||
m, err := catalogue.ParseManifest([]byte(raw))
|
||||
if err != nil {
|
||||
t.Fatalf("%s: %v", name, err)
|
||||
}
|
||||
if err := open.inventory.RegisterModule(ctx, m, inventory.Source{Repository: "novox/mesh-catalog",
|
||||
Path: "modules/" + name, BuiltFrom: "c0ffee"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := assign(ctx, open, "laptop", name); err != nil {
|
||||
t.Fatalf("assign %s: %v", name, err)
|
||||
}
|
||||
}
|
||||
f, err := gatherFacts(ctx, open, "2.11.17")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return f, manifests
|
||||
}
|
||||
|
||||
// aTemplatedTree is the catalogue's checkout with the notifier's text in files/.
|
||||
func aTemplatedTree(t *testing.T, manifests map[string]string, text string, has bool) string {
|
||||
@@ -126,82 +93,7 @@ func aTemplatedTree(t *testing.T, manifests map[string]string, text string, has
|
||||
|
||||
const notifierTemplate = "modules/notifier/files/notifier.conf"
|
||||
|
||||
func TestTheMergeGateJudgesAChangeToATemplateAlone(t *testing.T) {
|
||||
f, manifests := templatedMesh(t)
|
||||
|
||||
// The module moved to its template, the same text: nothing changes on any machine.
|
||||
v := gateJudged(t, f, aTemplatedTree(t, manifests, "volume = 3\n", true), "modules/notifier/module.json",
|
||||
notifierTemplate)
|
||||
if v.Verdict == "fail" || v.Modules["notifier"] != "" {
|
||||
t.Fatalf("the module moved to its template with the same text reads as a change (%v):\n%s", v.Modules, v.Report())
|
||||
}
|
||||
|
||||
// The template alone changed: its module changed, and composes.
|
||||
v = gateJudged(t, f, aTemplatedTree(t, manifests, "volume = 4\n", true), notifierTemplate)
|
||||
if v.Verdict == "fail" || v.Modules["notifier"] != "changed" {
|
||||
t.Fatalf("a change to the template alone is not a change to its module (%v):\n%s", v.Modules, v.Report())
|
||||
}
|
||||
if v.Width == nil || strings.Join(v.Width.Modules, ",") != "notifier" {
|
||||
t.Fatalf("a change to the template rebuilds %+v, not its module", v.Width)
|
||||
}
|
||||
|
||||
// The template alone changed to text the controller refuses: the pull request fails, naming the module.
|
||||
v = gateJudged(t, f, aTemplatedTree(t, manifests, "store = ${dir:nowhere}\n", true), notifierTemplate)
|
||||
if v.Verdict != "fail" || !strings.Contains(v.Report(), "notifier") {
|
||||
t.Fatalf("a template the controller refuses passed the gate:\n%s", v.Report())
|
||||
}
|
||||
|
||||
// A symlinked files/ fails: nothing is read from outside the tree.
|
||||
tree := aTree(t, withEdit(manifests, "notifier", ""))
|
||||
elsewhere := t.TempDir()
|
||||
if err := os.WriteFile(filepath.Join(elsewhere, "notifier.conf"), []byte("volume = 3\n"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
aTemplatedModule(t, filepath.Join(tree, "modules", "notifier"), templatedNotifier, nil)
|
||||
if err := os.Symlink(elsewhere, filepath.Join(tree, "modules", "notifier", "files")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
v = gateJudged(t, f, tree, notifierTemplate)
|
||||
if v.Verdict != "fail" || !strings.Contains(v.Report(), "files/ is a symlink") {
|
||||
t.Fatalf("a symlinked files/ passed the gate:\n%s", v.Report())
|
||||
}
|
||||
|
||||
// And the template removed from the tree fails, naming it.
|
||||
v = gateJudged(t, f, aTemplatedTree(t, manifests, "", false), notifierTemplate)
|
||||
if v.Verdict != "fail" || !strings.Contains(v.Report(), "files/notifier.conf") {
|
||||
t.Fatalf("a missing template passed the gate:\n%s", v.Report())
|
||||
}
|
||||
}
|
||||
|
||||
// What the gate composes for the module in its template form is what the mesh composes for it inline.
|
||||
func TestTheMergeGateResolvesATemplatedModuleToItsInlineTwin(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := aTemplatedModule(t, dir, templatedNotifier, map[string]string{"files/notifier.conf": "volume = 3\n"})
|
||||
raw, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
m, err := catalogue.ParseManifest(raw)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
texts, err := catalogue.ReadTemplates(m, dir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
resolved, err := standInBuild(m, texts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
inline, err := catalogue.ParseManifest([]byte(inlineNotifier))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if builtAlike(resolved) != builtAlike(inline) {
|
||||
got, _ := json.Marshal(resolved)
|
||||
t.Fatalf("the templated module resolves to %s, not its inline twin", got)
|
||||
}
|
||||
}
|
||||
|
||||
// A module whose files/ is unpacked onto the machine names its own templates directory (issue 731): `module check`
|
||||
// reads its templates from there and says of it exactly what it says of the same module with its text inline.
|
||||
@@ -243,30 +135,3 @@ func TestModuleCheckReadsTemplatesFromTheTemplatesDirectoryTheManifestNames(t *t
|
||||
// Issue 876: the gate judges a moved module that names its templates as registration reads it after a real build,
|
||||
// handed its templates; it refused every such module as "marked moved and names no template". This calls the gate's
|
||||
// own shelf (shelfWithChange), which needs no database.
|
||||
func TestReplay876(t *testing.T) {
|
||||
moved := strings.Replace(templatedNotifier, `"version":"1",`, `"version":"1","moved":true,`, 1)
|
||||
judge := func(manifest string, files map[string]string) (map[string]catalogue.Manifest, []string) {
|
||||
tree := t.TempDir()
|
||||
aTemplatedModule(t, filepath.Join(tree, "modules", "notifier"), manifest, files)
|
||||
out, failures, err := shelfWithChange(map[string]catalogue.Manifest{}, nil, snapshot.Facts{},
|
||||
"novox/mesh-catalog", tree, map[string]string{}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return out, failures
|
||||
}
|
||||
out, failures := judge(moved, map[string]string{"files/notifier.conf": "volume = 3\n"})
|
||||
if len(failures) > 0 {
|
||||
t.Fatalf("a moved module naming its templates was refused: %v", failures)
|
||||
}
|
||||
if h := out["notifier"].Handed; h == nil || h.Templates["conf"] != "notifier.conf" {
|
||||
t.Fatalf("the gate did not hand the moved module its templates: %+v", h)
|
||||
}
|
||||
|
||||
// A moved module naming no template is still refused.
|
||||
none := strings.Replace(strings.Replace(moved, `"template":"files/notifier.conf"`,
|
||||
`"content":"volume = 3\n"`, 1), `"build":{"artifacts":[{"name":"files","kind":"archive","from":"files"}]},`, "", 1)
|
||||
if _, failures := judge(none, nil); len(failures) != 1 || !strings.Contains(failures[0], "names no template") {
|
||||
t.Fatalf("a moved module naming no template was not refused: %v", failures)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user