package bundle import ( "errors" "strings" "testing" "github.com/novox/mesh-host/internal/declaration" ) // declarationParse is the parser Load uses, named here so the test reads as the assertion it is. func declarationParse(raw []byte) (any, error) { return declaration.Parse(raw) } func TestADefaultBuildCarriesNothingAndSaysSo(t *testing.T) { // The important one. A host built without a bundle that applied nothing and reported // success would look exactly like a host that raised a first node — and the difference // would surface as a mesh that never came up, with nothing to point at. if !IsEmpty("arch") { t.Fatal("the default build claims to carry a substrate") } _, err := Load("arch") if !errors.Is(err, ErrEmpty) { t.Fatalf("an empty bundle did not refuse: %v", err) } if !strings.Contains(err.Error(), "would look exactly like applying something") { t.Errorf("the refusal does not say why it matters: %v", err) } } func TestCommentsAreNotContent(t *testing.T) { // The placeholder is a comment. If comments counted as content, every default build would // claim to carry a substrate and then fail to parse it — the right outcome for the wrong // reason, and a confusing error at the worst moment. if got := stripComments([]byte("// a\n{\"a\":1}\n // b\n")); strings.Contains(string(got), "//") { t.Errorf("comments survived stripping: %q", got) } } func TestOnlyWholeLineCommentsAreStripped(t *testing.T) { // Anything cleverer would have to know where strings begin and end. A parser that // half-understands its input is worse than one that does not try — a path containing a // double slash is ordinary, and losing half of it would be silent. raw := []byte(`{"path":"https://example.invalid/a"}`) if got := string(stripComments(raw)); got != string(raw) { t.Errorf("a slash inside a string was treated as a comment: %q", got) } } func TestABundleWithContentIsParsedByTheSameParserTheLinkWillUse(t *testing.T) { // A bundle that reaches a machine and is then refused by the host carrying it would be a // build-time mistake found at the worst possible moment. real := []byte(`// pinned {"declaration":1,"resources":[{"id":"d","type":"directory","path":"/etc/mesh"}]}`) stripped := stripComments(real) if strings.Contains(string(stripped), "pinned") { t.Fatal("the comment survived") } if !strings.Contains(string(stripped), "declaration") { t.Fatal("the declaration did not survive") } } func TestWhatValidatesIsWhatIsApplied(t *testing.T) { // Found on a real machine. `mesh-host bundle` validated the carried bundle through Load, // which strips comments; `reconcile` handed the RAW bytes to the parser, which does not. // So the command whose whole job is to check the bundle said yes, and the command that // uses it said no — two paths to one artefact, disagreeing. // // There is now one path. This asserts the property that made the bug possible cannot // return: whatever Load accepts is what gets applied, byte for byte. annotated := []byte("// a comment\n" + `{"declaration":1,"resources":[{"id":"d","type":"directory","path":"/etc/mesh"}]}`) if _, err := parseFor(annotated); err != nil { t.Fatalf("an annotated bundle was refused: %v", err) } } // parseFor mirrors what Load does to arbitrary bytes, so the test can exercise the path // without rebuilding the binary with a different embedded file. func parseFor(raw []byte) (any, error) { return declarationParse(stripComments(raw)) } func TestEverySystemHasABundleAndAndroidsRefuses(t *testing.T) { // The bundle's contents are per system even though its mechanism is not (novox/hq ADR // 0060), so a host must find one built for it — and a host built for a system with no // bundle at all must say that rather than behave like an empty one. for _, system := range []string{"arch", "alpine", "android"} { if _, err := Load(system); err == nil { t.Errorf("%s: a placeholder bundle loaded as if it had contents", system) } else if !errors.Is(err, ErrEmpty) { t.Errorf("%s: refused for the wrong reason: %v", system, err) } } if _, err := Load("debian"); err == nil { t.Error("a bundle was loaded for a system nobody has built") } else if errors.Is(err, ErrEmpty) { t.Error("an unbuilt system was reported as an empty bundle; those are different things") } } func TestAndroidsBundleSaysWhyThereIsNone(t *testing.T) { // Not a placeholder waiting to be filled in. An android host implements neither `package` // nor `container` nor `service`, so every step of the bootstrap is a shape it does not // have — a partial host can JOIN a mesh and cannot BE the first node. text := string(Raw("android")) for _, want := range []string{"cannot raise a mesh", "JOIN", "first node"} { if !strings.Contains(text, want) { t.Errorf("the android bundle does not explain itself; missing %q", want) } } }