The provider held on its machine is composed apart, so no module of the composed set serves the provision; its
manifest's served values reached the consumer's binding raw and the binding refused the consumer for a
${bound:route:name-web} it does not require (the group check of 8a80e8e86858 on novox, mesh-build-node beside a held
gitea). Each such key is now left out and said on the need, as a provider elsewhere leaves it out (ADR 0346).
Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
142 lines
5.9 KiB
Go
142 lines
5.9 KiB
Go
package resolution
|
|
|
|
import (
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
|
|
mcat "git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
)
|
|
|
|
const aRegistryForge = `{"module":"forge","version":"1","requires":["route"],
|
|
"provides":[{"name":"npm-package-registry","scope":"mesh"}],
|
|
"contributes":{"route":{"web":{"label":"git","port":3000}}},
|
|
"serves":{"npm-package-registry":{"scheme":"http","port":3000,"npm-path":"/api/packages/novox/npm/",
|
|
"public-root":"https://${bound:route:name-web}/api/packages/novox/npm/"}}}`
|
|
|
|
func aForgeManifest(t *testing.T) mcat.Manifest {
|
|
t.Helper()
|
|
m, err := decodeForTest([]byte(aRegistryForge))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return m
|
|
}
|
|
|
|
func TestAProviderServesItsOwnComposedName(t *testing.T) {
|
|
m := aForgeManifest(t)
|
|
r := mcat.Resolution{Node: "home", PublicDomain: "example.org"}
|
|
got, said, err := ServedOwnNames(r, m, "npm-package-registry", m.Serves["npm-package-registry"], nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got["public-root"] != "https://git.example.org/api/packages/novox/npm/" || len(said) != 0 {
|
|
t.Fatalf("the public root is the route's composed name: %v, said %v", got, said)
|
|
}
|
|
if got["npm-path"] != "/api/packages/novox/npm/" || got["port"] != float64(3000) {
|
|
t.Fatalf("the rest is served as it was: %v", got)
|
|
}
|
|
if m.Serves["npm-package-registry"]["public-root"] != "https://${bound:route:name-web}/api/packages/novox/npm/" {
|
|
t.Fatal("the manifest's own map was rewritten")
|
|
}
|
|
}
|
|
|
|
// On the provider's own machine the consumer is served the same name (ADR 0346 §2).
|
|
func TestAConsumerBesideTheProviderIsServedItsName(t *testing.T) {
|
|
m := aForgeManifest(t)
|
|
consumer := mcat.Manifest{Module: "lab", Version: "1", Requires: []string{"npm-package-registry"},
|
|
Binds: map[string]string{"npm-package-registry": "/var/lib/lab/package-registry.json"}}
|
|
node := workstation()
|
|
node.PublicDomain = "example.org"
|
|
got, err := Resolve(shelf(minimalRouteProxy(), m, consumer), []string{"route-proxy", "forge", "lab"}, node, mcat.World{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
served, answered, err := resolutionServedOnThisMachine(got, "npm-package-registry", mcat.Rendering{})
|
|
if err != nil || !answered {
|
|
t.Fatalf("answered %v: %v", answered, err)
|
|
}
|
|
if served["public-root"] != "https://git.example.org/api/packages/novox/npm/" {
|
|
t.Fatalf("served beside the provider: %v", served)
|
|
}
|
|
out, err := Declaration(got, mcat.Rendering{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var binding string
|
|
for _, r := range out {
|
|
if r["path"] == "/var/lib/lab/package-registry.json" {
|
|
binding, _ = r["content"].(string)
|
|
}
|
|
}
|
|
if !strings.Contains(binding, `"public-root": "https://git.example.org/api/packages/novox/npm/"`) &&
|
|
!strings.Contains(binding, `"public-root":"https://git.example.org/api/packages/novox/npm/"`) {
|
|
t.Fatalf("the consumer's binding carries the name:\n%s", binding)
|
|
}
|
|
if strings.Contains(binding, "${bound:") {
|
|
t.Fatalf("a placeholder reached the consumer:\n%s", binding)
|
|
}
|
|
// Issue 1921 (the group check of 8a80e8e86858, novox): the provider held on this machine (composed apart, as what runs
|
|
// of it) is not in the composed set, so none of its own names is composed here. The consumer beside it is told
|
|
// what it serves without the keys that name them, each said on the need, never the placeholder: its binding refused
|
|
// the consumer with "has a file that says ${bound:route:name-web}, and lab does not require route".
|
|
held, err := Resolve(shelf(minimalRouteProxy(), m, consumer), []string{"route-proxy", "forge", "lab"}, node, mcat.World{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
held.Modules = slices.DeleteFunc(slices.Clone(held.Modules), func(m mcat.Manifest) bool { return m.Module == "forge" })
|
|
out, err = Declaration(held, mcat.Rendering{})
|
|
if err != nil {
|
|
t.Fatalf("a consumer beside a held provider: %v", err)
|
|
}
|
|
for _, r := range out {
|
|
if c, _ := r["content"].(string); r["path"] == "/var/lib/lab/package-registry.json" && (strings.Contains(c, "${bound:") || !strings.Contains(c, "npm-path")) {
|
|
t.Fatalf("the binding beside a held provider:\n%s", c)
|
|
}
|
|
}
|
|
for _, n := range held.Needs {
|
|
if n.Name == "npm-package-registry" && (len(n.LeftOut) != 1 || !strings.Contains(n.LeftOut[0], `"public-root"`)) {
|
|
t.Fatalf("the need beside a held provider says not what was left out: %+v", n)
|
|
}
|
|
}
|
|
}
|
|
|
|
// From another machine, the provider's served values carry what that machine composed, and a key it
|
|
// left out is said on the consumer's need (ADR 0346 §2, §3).
|
|
func TestAConsumerElsewhereIsToldWhatTheProviderLeftOut(t *testing.T) {
|
|
consumer := mcat.Manifest{Module: "lab", Version: "1", Requires: []string{"npm-package-registry"},
|
|
Binds: map[string]string{"npm-package-registry": "/var/lib/lab/package-registry.json"}}
|
|
node := workstation()
|
|
node.At = "workstation.internal"
|
|
world := mcat.World{Offered: map[string][]mcat.Provider{"npm-package-registry": {{Node: "home", At: "home.internal",
|
|
Module: "forge", Serves: map[string]any{"port": 3000},
|
|
LeftOut: []string{`forge serves npm-package-registry without "public-root"`}}}}}
|
|
got, err := Resolve(shelf(aForgeManifest(t), consumer), []string{"lab"}, node, world)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, n := range got.Needs {
|
|
if n.Name == "npm-package-registry" {
|
|
if len(n.LeftOut) != 1 {
|
|
t.Fatalf("the need carries what was left out: %+v", n)
|
|
}
|
|
return
|
|
}
|
|
}
|
|
t.Fatalf("no need: %+v", got.Needs)
|
|
}
|
|
|
|
// The provider's contributions file carries no own name on a consumer's entry (ADR 0346 §4): only what
|
|
// is derived for that consumer is there (ADR 0202 §5), and the provider reads its own names in its files.
|
|
func TestAProvidersOwnNameIsNotOnItsConsumersEntry(t *testing.T) {
|
|
m := aForgeManifest(t)
|
|
r := mcat.Resolution{Node: "home", PublicDomain: "example.org", Modules: []mcat.Manifest{m}}
|
|
derived, err := resolutionDerivedFor(r, "npm-package-registry", "lab_home", "lab", "", nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if derived != nil {
|
|
t.Fatalf("a consumer's entry carries only what was derived for it: %v", derived)
|
|
}
|
|
}
|