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
102 lines
3.8 KiB
Go
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)
|
|
}
|
|
}
|