Files
mesh-catalog/modules/mesh-config/cmd/mesh-config/takeover_test.go
T
jschoubben a73b02ea30 Drop the keeper's and config's take-over verbs with the controller's sources
mesh-sdk drops compare, take-over and hand-back from the keeper's and
config's seats (ADR 0590): there is no controller to compare with or hand
back to. mesh-conditions loses those verbs, its take-over key and asks;
mesh-config reads its own sources always and pull-declares is gone; and
mesh-hand-acts no longer names the controller's log (issue 1126).

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-02 12:29:56 +01:00

95 lines
3.7 KiB
Go

package main
import (
"encoding/json"
"strings"
"testing"
"git.novox.be/novox/mesh-sdk/go/delivery"
)
// The trunk's manifests aMesh declares.
const (
claudeDeclared = `{"module":"claude-code","settings":{
"managed":{"kind":"","default":{},"why":"","type":"object","description":"managed settings","trusted":true,"predefined":"agent-managed-settings"}}}`
oldDeclared = `{"module":"old","settings":{"workers":{"kind":"preference","default":4,"why":"two per core"}}}`
)
// anAgreeingMesh is aProposingMesh with the indexer's predefined list in place and no open pull request.
func anAgreeingMesh(t *testing.T) (*Config, *memStore, *standIn) {
t.Helper()
c, m, r := aProposingMesh(t)
indexerList(t, m, "aaaaaaaaaaaa", `{"agent-managed-settings":{"type":"object","description":"managed settings","trusted":true},
"font-size":{"type":"number","description":"text size, in points","minimum":6,"maximum":72}}`)
if _, err := c.Reconcile(); err != nil {
t.Fatal(err)
}
return c, m, r
}
// indexerList is the indexer's `predefined.list` at a commit.
func indexerList(t *testing.T, m *memStore, commit, list string) {
t.Helper()
raw, _ := json.Marshal(delivery.PredefinedKept{V: 1, Commit: commit, List: json.RawMessage(list)})
m.mirror(t, IndexerPredefinedRead, delivery.PredefinedListKey, string(raw))
}
// candidate is the indexer's config candidate of a pull request.
func candidate(t *testing.T, m *memStore, pull, head, declares string) {
t.Helper()
key, err := delivery.ConfigCandidateKey(pull)
if err != nil {
t.Fatal(err)
}
m.mirror(t, CandidatesRead, key, `{"v":1,"pull":"`+pull+`","head":"`+head+`","declares":`+declares+`}`)
}
// ADR 0590 (issue 1126): config reads its own sources always, with no take-over: declared is written once per
// manifest, pull-declares is refused naming the indexer's candidates, and the list and a pull request's config come from
// the indexer. compare, take-over and hand-back went with the controller.
func TestConfigReadsItsOwnSourcesAlways(t *testing.T) {
c, m, _ := anAgreeingMesh(t)
steps := []struct {
name string
do func() (string, error)
want string // what the answer or the error says
}{
{"declared is written when it differs, and once", func() (string, error) {
_ = m.Delete(DeclaredState, "dunst")
first, err := c.Reconcile()
again, _ := c.Reconcile()
return strings.Join(first.Declared, ",") + "|" + strings.Join(again.Declared, ","), err
}, "dunst|"},
{"pull-declares refused, naming the indexer", func() (string, error) {
_, err := c.PullDeclares(Call{Caller: ControllerCaller, Pull: "novox/mesh-catalog#8", Head: "h1",
Declares: map[string]any{}})
return "", err
}, "config-candidates"},
{"the list comes from the indexer", func() (string, error) {
indexerList(t, m, "cccccccccccc", `{"font-size":{"type":"number","description":"text size","minimum":6,"maximum":72},
"agent-managed-settings":{"type":"object","description":"managed settings","trusted":true},
"theme":{"type":"string","description":"the desktop's theme"}}`)
res, err := c.Reconcile()
return res.Published, err
}, "theme"},
{"a pull request's config comes from the indexer", func() (string, error) {
candidate(t, m, "novox/mesh-catalog#9", "h9", `{"dunst":{"gap":{"kind":"","type":"number","default":2}}}`)
res, err := c.Reconcile()
return strings.Join(res.Candidates, "; "), err
}, "from the indexer"},
}
for _, s := range steps {
got, err := s.do()
text := got
if err != nil {
text = err.Error()
}
if !strings.Contains(text, s.want) {
t.Errorf("%s: said %q, want %q", s.name, text, s.want)
}
}
if sw, _ := c.source(); sw.Source != SourceIndexer {
t.Errorf("the source is %q", sw.Source)
}
}