package inventory import ( "context" "encoding/json" "strings" "testing" "github.com/novox/mesh-controller/internal/catalogue" ) // A build kept from before ADR 0326 §3 is still read and composed (novox/hq issue 574). betterbird's // builds from before mesh-catalog 8f80cd4 declare a preference and own a mergeable file that names no // keys: refused where a definition is written, but a machine still runs that build and a rollback may // put it back, so reading it again — ManifestAt, which a walk, the gate and a release compose from — // must not refuse it. func TestAStoredBuildWithASilentMergeableFileIsStillReadAndComposed(t *testing.T) { inv := fresh(t) ctx := context.Background() manifest, err := json.Marshal(map[string]any{ "module": "mail-client", "version": "1", "settings": map[string]any{"prefs": map[string]any{ "kind": catalogue.KindPreference, "default": "// none", "why": "its own defaults until a machine names one"}}, "resources": []any{ map[string]any{"id": "user-js", "type": "file", "path": "/var/lib/mail-client/user.js", "mode": "0644", "content": "${setting:prefs}\n"}, map[string]any{"id": "accounts", "type": "file", "path": "/var/lib/mail-client/accounts.json", "mode": "0600", "merge": "json", "content": "{\"accounts\": {}}\n"}, }, }) if err != nil { t.Fatal(err) } b := aBuild("before-574", "mail-client", "") b.Manifest = manifest if err := inv.RecordBuild(ctx, b); err != nil { t.Fatal(err) } m, found, err := inv.ManifestAt(ctx, "mail-client", b.Commit) if err != nil || !found { t.Fatalf("the stored build is not read again: found %v, %v", found, err) } if written := catalogue.WrittenSettingsProblems(m); len(written) != 1 { t.Fatalf("the rule this build predates should name its accounts file where it is written: %v", written) } // And composed, in today's form: the accounts file still takes its layer's keys. with := catalogue.Rendering{Settings: catalogue.SettingsBy{"mail-client": {{From: "workstation", Values: map[string]any{"accounts": map[string]any{"work": map[string]any{"email": "a@example.invalid"}}}}}}} if err := catalogue.JudgeSettings(m, with.Settings["mail-client"], false); err != nil { t.Fatalf("the stored build's settings do not compose: %v", err) } out, err := catalogue.Resolution{Node: "workstation", Modules: []catalogue.Manifest{m}}.Declaration(with) if err != nil { t.Fatalf("the stored build is not composed: %v", err) } for _, r := range out { if r["id"] == "mail-client.accounts" { if content, _ := r["content"].(string); !strings.Contains(content, "a@example.invalid") { t.Fatalf("the accounts file did not take its layer: %v", content) } return } } t.Fatalf("the accounts file was not composed: %v", out) }