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.
87 lines
2.7 KiB
Go
87 lines
2.7 KiB
Go
package catalogue
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/novox/mesh-controller/internal/beside"
|
|
)
|
|
|
|
// **The showcase module is parsed by the real parser, in the real test suite.**
|
|
//
|
|
// A module that exercises every capability is only worth having if something checks it still does.
|
|
// Written as a test rather than a script so it runs whenever anything about manifests changes —
|
|
// which is exactly when a module using all of it would quietly stop being valid.
|
|
func TestTheShowcaseModuleIsAValidManifest(t *testing.T) {
|
|
raw, err := os.ReadFile(filepath.Join(beside.Catalogue(t), "showcase", "module.json"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
m, err := ParseManifest(raw)
|
|
if err != nil {
|
|
t.Fatalf("the module that exercises everything does not parse:\n%v", err)
|
|
}
|
|
|
|
// Every resource kind a MODULE may use, actually in it.
|
|
//
|
|
// Two of the host's eleven are deliberately absent, and the reasons are worth keeping:
|
|
//
|
|
// - `action` is refused to modules outright. The link may not carry a command to run (ADR
|
|
// 0005), so a module that needs something done ships a program that reads what the mesh
|
|
// delivered and reconciles — which is what a run-once `process` is.
|
|
// - `service` puts an EXISTING unit into a state and deliberately installs none, which is
|
|
// right for software that ships its own unit. A module whose code the mesh built has no
|
|
// such unit until the mesh writes one, and that is a `process`.
|
|
kinds := map[string]bool{}
|
|
for _, r := range m.Resources {
|
|
kind, _ := r["type"].(string)
|
|
kinds[kind] = true
|
|
}
|
|
for _, want := range []string{
|
|
"access", "archive", "container", "directory", "file", "network", "package",
|
|
"process", "user",
|
|
} {
|
|
if !kinds[want] {
|
|
t.Errorf("showcase no longer exercises %q", want)
|
|
}
|
|
}
|
|
|
|
// And all three ways a module's own code can run, which is the thing most easily lost.
|
|
var stays, once, scheduled bool
|
|
for _, r := range m.Resources {
|
|
if kind, _ := r["type"].(string); kind != "process" {
|
|
continue
|
|
}
|
|
switch {
|
|
case r["run-once"] == true:
|
|
once = true
|
|
case r["schedule"] != nil:
|
|
scheduled = true
|
|
default:
|
|
stays = true
|
|
}
|
|
}
|
|
if !stays || !once || !scheduled {
|
|
t.Errorf("showcase does not exercise all three process modes: stays=%v once=%v scheduled=%v",
|
|
stays, once, scheduled)
|
|
}
|
|
|
|
// And the artifact kinds, including the one that compiles.
|
|
var bundle, archive, upstream bool
|
|
for _, a := range m.Build.Artifacts {
|
|
switch a.Kind {
|
|
case ArtifactBundle:
|
|
bundle = true
|
|
case ArtifactArchive:
|
|
archive = true
|
|
case ArtifactUpstream:
|
|
upstream = true
|
|
}
|
|
}
|
|
if !bundle || !archive || !upstream {
|
|
t.Errorf("showcase does not exercise every artifact kind: bundle=%v archive=%v upstream=%v",
|
|
bundle, archive, upstream)
|
|
}
|
|
}
|