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
95 lines
3.7 KiB
Go
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)
|
|
}
|
|
}
|