ADR 0593 §7: the composer with its refusals leaves mesh-sdk, so mesh-sdk carries no composition rule. The catalogue functions only the node-engine's composition reaches (Resolve, Resolution's Compose, Declaration, DataItems, LeftOut, Rules and the rest, the settings, placeholder and template refusals, the rendering helpers) are copied with their tests into internal/compose/resolution; a method of a mesh-sdk shape becomes a function taking it first. The composition calls its own copies, and the captured catalogue its tests read lives here now, shared by mesh-compose's tests. Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
109 lines
3.8 KiB
Go
109 lines
3.8 KiB
Go
package resolution
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
|
|
mcat "git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
)
|
|
|
|
const barTemplate = `{{if eq .shows "battery"}}[[block]]
|
|
block = "battery"
|
|
{{with .options}}{{with .device}}device = {{quote .}}
|
|
{{end}}{{end}}{{else if eq .shows "command"}}[[block]]
|
|
block = "custom"
|
|
command = {{quote .options.command}}
|
|
interval = {{.options.interval}}
|
|
{{else if eq .shows "state"}}[[block]]
|
|
block = "custom"
|
|
command = {{quote (printf "show %s %s" .options.state (or .options.key .machine))}}
|
|
{{end}}`
|
|
|
|
func barHolder() mcat.Manifest {
|
|
place := func(bar string) string {
|
|
return "own-first\n${contribution:node-bar:block:bar=" + bar + ",place=resources}" +
|
|
"own-middle\n${contribution:node-bar:block:bar=" + bar + ",place=status}own-last\n"
|
|
}
|
|
return mcat.Manifest{Module: "a-bar", Claims: []mcat.Claim{{Name: mcat.BarSeat, Renders: map[string]string{mcat.BarKindBlock: barTemplate}}},
|
|
Resources: []map[string]any{
|
|
{"id": "bottom", "type": "file", "path": "/b", "content": place("bottom")},
|
|
{"id": "top", "type": "file", "path": "/t", "content": place("top")},
|
|
}}
|
|
}
|
|
|
|
func block(data string) mcat.SeatContribution {
|
|
var d map[string]any
|
|
if err := json.Unmarshal([]byte(data), &d); err != nil {
|
|
panic(err)
|
|
}
|
|
return mcat.SeatContribution{Seat: mcat.BarSeat, Kind: mcat.BarKindBlock, Data: d}
|
|
}
|
|
|
|
func composedFile(t *testing.T, r mcat.Resolution, id string) string {
|
|
t.Helper()
|
|
out, err := Declaration(r, mcat.Rendering{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, res := range out {
|
|
if res["id"] == id {
|
|
return res["content"].(string)
|
|
}
|
|
}
|
|
t.Fatalf("%s was not composed", id)
|
|
return ""
|
|
}
|
|
|
|
func TestResolveCarriesTheMachinesCapabilities(t *testing.T) {
|
|
node := workstation()
|
|
node.Capabilities["battery"] = true
|
|
r, err := Resolve(shelf(mcat.Manifest{Module: "a"}), []string{"a"}, node, mcat.World{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !r.Capabilities["battery"] || !r.Capabilities["seat"] {
|
|
t.Fatalf("the resolution carries %v, not the node's %v", r.Capabilities, node.Capabilities)
|
|
}
|
|
}
|
|
|
|
func TestAPieceTheHolderCannotRenderIsLeftOutAndNamedNotTheMachine(t *testing.T) {
|
|
// A shows the shape gained after the holder's template was written: built here, past the check.
|
|
power := mcat.Manifest{Module: "power", Contributions: []mcat.SeatContribution{
|
|
block(`{"bar":"bottom","place":"status","shows":"gpu"}`),
|
|
block(`{"bar":"bottom","place":"status","shows":"battery"}`),
|
|
}}
|
|
r := mcat.Resolution{Node: "n", Account: "op", Modules: []mcat.Manifest{barHolder(), power}}
|
|
c, err := Compose(r, mcat.Rendering{})
|
|
if err != nil {
|
|
t.Fatalf("one piece failed the whole machine: %v", err)
|
|
}
|
|
if len(c.Unplaced) != 1 || !strings.Contains(c.Unplaced[0], "power's node-bar:block") ||
|
|
!strings.Contains(c.Unplaced[0], "shows=gpu") || !strings.Contains(c.Unplaced[0], "renders nothing") {
|
|
t.Fatalf("unplaced: %v", c.Unplaced)
|
|
}
|
|
for _, res := range c.Resources {
|
|
if res["id"] == "a-bar.bottom" && !strings.Contains(res["content"].(string), `block = "battery"`) {
|
|
t.Fatalf("the piece beside it was lost too: %s", res["content"])
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAnOfferedBlockMakesNoDependencyOnTheBar(t *testing.T) {
|
|
power := mcat.Manifest{Module: "power", Contributions: []mcat.SeatContribution{
|
|
block(`{"bar":"bottom","place":"status","shows":"battery"}`),
|
|
{Seat: mcat.HotkeysSeat, Kind: "trigger", Content: "x"},
|
|
}}
|
|
for _, seat := range DependsOn(nil, power) {
|
|
if seat == mcat.BarSeat {
|
|
t.Fatalf("a block made the power module depend on the bar: %v", DependsOn(nil, power))
|
|
}
|
|
}
|
|
// And on a machine with no bar it is placed nowhere, and nothing fails.
|
|
r := mcat.Resolution{Node: "server", Account: "op", Capabilities: map[string]bool{"battery": true},
|
|
Modules: []mcat.Manifest{hotkeysHolder(), power}}
|
|
if _, err := Declaration(r, mcat.Rendering{}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|