Files
mesh-catalog/modules/mesh-vault/cmd/mesh-vault/placed_test.go
T
jschoubben c9d8950fd0 Every module follows the assigner's new places: the contracts' go/ path, mesh-wants in the delivery contracts, the state and tool assignments (issue 1966)
The legacy key form placement.<node> is gone from the client, so the readers and their fixtures lose it. The check noplacement
now also refuses the assigner's retired names in a manifest.

Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
2026-11-05 22:29:07 +01:00

102 lines
3.8 KiB
Go

package main
import (
"encoding/json"
"os"
"slices"
"strings"
"testing"
assignerclient "git.novox.be/novox/mesh-contracts/go/clients/meshmoduleassignerclient"
placing "git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner"
vaultclient "git.novox.be/novox/mesh-contracts/identity-and-access/go/clients/meshvaultclient"
)
// assignedNodes is the seat mesh-module-assigner's assignments of each node, as the vault reads it.
func assignedNodes(t *testing.T, nodes map[string][]string) AssignerReader {
t.Helper()
values := map[string][]byte{}
for node, modules := range nodes {
p := placing.Assignments{V: vaultclient.Version, Node: node}
for _, m := range modules {
p.Modules = append(p.Modules, placing.PlacedModule{Module: m})
}
// Research 072 row 37: the node key and a key per module.
kv, err := assignerclient.AssignmentsValues(p)
if err != nil {
t.Fatal(err)
}
for k, raw := range kv {
values[k] = raw
}
}
return AssignerReader{
Keys: func() ([]string, error) {
var out []string
for k := range values {
out = append(out, k)
}
return out, nil
},
Read: func(key string) ([]byte, error) { return values[key], nil },
}
}
// 774/AC11 (novox/hq ADR 0561, ADR 0549 §3, §5): with no assignments to read, the vault tells from the seat's
// assignments which node holds the bus and whether a consumer's module stands on its node; while both stand, a module
// either names stands.
func TestTheVaultReadsWhereModulesStandFromAssignments(t *testing.T) {
v := newVault(t, nil)
v.Assigner = assignedNodes(t, map[string][]string{"novox": {"nats", "web"}, "ace": {"shop"}})
if node, err := v.busNode(); err != nil || node != "novox" {
t.Errorf("the bus node from assignments: %q, %v", node, err)
}
asked := func(node, module string) CredentialAsked {
return CredentialAsked{Role: "consumer", Provision: "postgres", Consumer: node, ConsumerModule: module, Provider: "novox"}
}
if why := v.credentialRefusal("ace", asked("ace", "shop"), v.plansOf("ace")); why != "" {
t.Errorf("shop stands on ace by assignments, refused: %s", why)
}
if why := v.credentialRefusal("ace", asked("ace", "web"), v.plansOf("ace")); !strings.Contains(why, "is not on ace") {
t.Errorf("web is not placed on ace, and is answered %q", why)
}
// While both stand, an assignment still names a module assignments does not yet.
v.Askers = Declared{Read: assignments{"ace.web": `{"node":"ace","module":"web"}`}.read, Store: v.Store}
if why := v.credentialRefusal("ace", asked("ace", "web"), v.plansOf("ace")); why != "" {
t.Errorf("web assigned on ace, refused: %s", why)
}
// Two nodes placed with the bus: the vault adopts from neither.
v.Assigner = assignedNodes(t, map[string][]string{"novox": {"nats"}, "ace": {"nats"}})
if _, err := v.busNode(); err == nil || !strings.Contains(err.Error(), "2 nodes") {
t.Errorf("two bus nodes: %v", err)
}
}
// The assigner's tool and views family the vault names are the ones its manifest invokes and consumes; no client names a
// holder (novox/hq ADR 0625 §4).
func TestTheAssignmentsNamesAreTheManifests(t *testing.T) {
raw, err := os.ReadFile("../../module.json")
if err != nil {
t.Fatal(err)
}
var m struct {
Invokes []string `json:"invokes"`
Consumes []string `json:"consumes"`
}
if err := json.Unmarshal(raw, &m); err != nil {
t.Fatal(err)
}
var reads struct {
Reads []string `json:"reads"`
}
_ = json.Unmarshal(raw, &reads)
for _, r := range []string{AssignmentsRead, ProvisionsRead} {
if !slices.Contains(reads.Reads, r) {
t.Errorf("the vault reads %s, its manifest's reads are %v", r, reads.Reads)
}
}
if !slices.Contains(m.Invokes, AssignmentsTool) || !slices.Contains(m.Consumes, AssignmentsViewsEvent) {
t.Errorf("the vault asks %s and follows %s, its manifest invokes %v and consumes %v", AssignmentsTool, AssignmentsViewsEvent, m.Invokes, m.Consumes)
}
}