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
75 lines
3.0 KiB
Go
75 lines
3.0 KiB
Go
package resolution
|
|
|
|
import (
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
|
|
mcat "git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
)
|
|
|
|
func displayServer(name, display string, claims ...string) mcat.Manifest {
|
|
m := mcat.Manifest{Module: name, Provides: []mcat.Offer{{Name: display, Reach: mcat.ReachMachine}}}
|
|
for _, c := range claims {
|
|
m.Claims = append(m.Claims, mcat.Claim{Name: c})
|
|
}
|
|
return m
|
|
}
|
|
|
|
func windowManager() mcat.Manifest {
|
|
return mcat.Manifest{Module: "i3", Requires: []string{"x11-display"}}
|
|
}
|
|
|
|
// §3: a display is resolved on the requiring module's own node.
|
|
func TestAMachineReachRequirementResolvesToTheProviderOnItsOwnNode(t *testing.T) {
|
|
cat := shelf(windowManager(), displayServer("xorg", "x11-display", mcat.DisplayServerSeat))
|
|
got, err := Resolve(cat, []string{"xorg", "i3"}, workstation(), mcat.World{})
|
|
if err != nil {
|
|
t.Fatalf("i3 beside xorg did not resolve: %v", err)
|
|
}
|
|
if !reflect.DeepEqual(names(got), []string{"xorg", "i3"}) && !reflect.DeepEqual(names(got), []string{"i3", "xorg"}) {
|
|
t.Errorf("resolved %v", names(got))
|
|
}
|
|
}
|
|
|
|
// §3: never answered by installing a provider, and never by another machine's.
|
|
func TestAMachineReachRequirementIsNotPulledInNorAnsweredFromAnotherNode(t *testing.T) {
|
|
cat := shelf(windowManager(),
|
|
displayServer("xorg", "x11-display", mcat.DisplayServerSeat),
|
|
displayServer("xwayland", "x11-display"))
|
|
// Another machine runs xorg and says so to the world; it does not count.
|
|
world := mcat.World{Offered: map[string][]mcat.Provider{
|
|
"x11-display": {{Node: "laptop", At: "laptop.mesh", Module: "xorg"}}}}
|
|
_, err := Resolve(cat, []string{"i3"}, workstation(), world)
|
|
if err == nil {
|
|
t.Fatal("i3 resolved on a machine with no display of its own")
|
|
}
|
|
for _, want := range []string{
|
|
`"x11-display" is wanted by i3`, "usable only on the machine that provides it",
|
|
"assign one to workstation", "xorg (holds node-display-server)", "xwayland",
|
|
} {
|
|
if !strings.Contains(err.Error(), want) {
|
|
t.Errorf("the refusal does not say %q:\n%v", want, err)
|
|
}
|
|
}
|
|
// With a single provider in the catalogue too: one candidate is still not a choice to make
|
|
// for somebody, unlike a node-scoped provision without the machine's reach.
|
|
_, err = Resolve(shelf(windowManager(), displayServer("xorg", "x11-display", mcat.DisplayServerSeat)),
|
|
[]string{"i3"}, workstation(), mcat.World{})
|
|
if err == nil {
|
|
t.Fatal("xorg was pulled in for i3")
|
|
}
|
|
// Not in the first pass, whose refusals take the machine off the network.
|
|
if _, err := Resolve(cat, []string{"i3"}, workstation(), mcat.World{Unchecked: true}); err != nil {
|
|
t.Errorf("the first pass refused: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestACatalogueDisagreeingAboutAProvisionsReachIsRefused(t *testing.T) {
|
|
cat := shelf(windowManager(), displayServer("xorg", "x11-display"), mcat.Manifest{Module: "fake-x", Provides: mcat.Offers("x11-display")})
|
|
_, err := Resolve(cat, []string{"xorg", "i3"}, workstation(), mcat.World{})
|
|
if err == nil || !strings.Contains(err.Error(), `the catalogue disagrees about "x11-display"`) {
|
|
t.Fatalf("a provision with and without the machine's reach gave %v", err)
|
|
}
|
|
}
|