The controller tells mesh-config what a pull request declares, asks the approved held values with each check, and the build agent and merge gate lay them over the change's composition only: a key the trunk does not declare yet can then be approved before the merge (ADR 0502).
86 lines
3.4 KiB
Go
86 lines
3.4 KiB
Go
package main
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
snapshot "git.novox.be/novox/mesh-sdk/go/facts"
|
|
)
|
|
|
|
func heldGateFacts() snapshot.Facts {
|
|
return snapshot.Facts{Machines: []snapshot.Machine{
|
|
{Name: snapshot.Pseudonym("machine", "ace"), Roles: []string{"the build node"}, Assigned: []string{"n8n"},
|
|
Settings: []snapshot.Settings{{Module: "n8n", Values: map[string]any{"port": 5678.0}}}},
|
|
{Name: snapshot.Pseudonym("machine", "g14")},
|
|
}}
|
|
}
|
|
|
|
var heldShelf = map[string]catalogue.Manifest{"n8n": {Module: "n8n"}}
|
|
|
|
// 1826/AC3: a held value is laid in its node's layer of its module, beside what the layer holds, and said.
|
|
func TestAHeldValueIsLaidOverItsNodesLayerAndSaid(t *testing.T) {
|
|
f := heldGateFacts()
|
|
got, notes := layHeld(f, []heldValue{{Pull: "novox/mesh-catalog#434", Node: "ace", Module: "n8n", Key: "media-gid",
|
|
Value: []byte("2000"), Approved: "the operator"}}, heldShelf)
|
|
layer := got.Machines[0].Settings[0].Values
|
|
if layer["media-gid"] != 2000.0 || layer["port"] != 5678.0 {
|
|
t.Fatalf("the layer holds %v", layer)
|
|
}
|
|
if _, has := f.Machines[0].Settings[0].Values["media-gid"]; has {
|
|
t.Fatal("the snapshot given was changed")
|
|
}
|
|
if len(notes) != 1 || !strings.Contains(notes[0], "composed with 1 value(s) held for novox/mesh-catalog#434") ||
|
|
!strings.Contains(notes[0], "media-gid=2000") || !strings.Contains(notes[0], "approved by the operator") ||
|
|
strings.Contains(notes[0], "ace") {
|
|
t.Fatalf("said %q", notes)
|
|
}
|
|
}
|
|
|
|
// 1826/AC3: a machine with no layer of the module gets one.
|
|
func TestAHeldValueMakesTheLayerAMachineLacks(t *testing.T) {
|
|
got, _ := layHeld(heldGateFacts(), []heldValue{{Pull: "p", Node: "g14", Module: "n8n", Key: "k", Value: []byte(`"x"`)}}, heldShelf)
|
|
s := got.Machines[1].Settings
|
|
if len(s) != 1 || s[0].Module != "n8n" || s[0].Values["k"] != "x" {
|
|
t.Fatalf("layers %+v", s)
|
|
}
|
|
}
|
|
|
|
// 1826/AC3: a held value for a machine or a module the snapshot or the change does not hold is said, never laid.
|
|
func TestAHeldValueForWhatIsNotHeldIsSaidNotLaid(t *testing.T) {
|
|
f := heldGateFacts()
|
|
got, notes := layHeld(f, []heldValue{
|
|
{Pull: "p", Node: "nowhere", Module: "n8n", Key: "k", Value: []byte("1")},
|
|
{Pull: "p", Node: "ace", Module: "ghost", Key: "k", Value: []byte("1")},
|
|
}, heldShelf)
|
|
if len(notes) != 2 || !strings.Contains(notes[0], "holds no machine") || !strings.Contains(notes[1], "defines no module ghost") {
|
|
t.Fatalf("said %q", notes)
|
|
}
|
|
if _, has := got.Machines[0].Settings[0].Values["k"]; has {
|
|
t.Fatal("laid")
|
|
}
|
|
}
|
|
|
|
// 1826/AC3: none held lays nothing and says nothing; the file is read and refuses a value without a node.
|
|
func TestNoHeldValuesLayNothingAndTheFileIsRead(t *testing.T) {
|
|
if got, notes := layHeld(heldGateFacts(), nil, heldShelf); len(notes) != 0 || len(got.Machines) != 2 {
|
|
t.Fatalf("%v %v", got, notes)
|
|
}
|
|
dir := t.TempDir()
|
|
good := filepath.Join(dir, "good.json")
|
|
os.WriteFile(good, []byte(`[{"pull":"p","node":"ace","module":"n8n","key":"k","value":1}]`), 0o644)
|
|
if h, err := readHeld(good); err != nil || len(h) != 1 || h[0].Key != "k" {
|
|
t.Fatalf("%v %v", h, err)
|
|
}
|
|
bad := filepath.Join(dir, "bad.json")
|
|
os.WriteFile(bad, []byte(`[{"pull":"p","module":"n8n","key":"k","value":1}]`), 0o644)
|
|
if _, err := readHeld(bad); err == nil {
|
|
t.Fatal("a value without a node was read")
|
|
}
|
|
if h, err := readHeld(""); h != nil || err != nil {
|
|
t.Fatalf("%v %v", h, err)
|
|
}
|
|
}
|