Files
mesh-sdk/go/provisions/provisions_test.go
T

89 lines
4.4 KiB
Go

package provisions
import (
"strings"
"testing"
"time"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// ADR 0570 clauses 1, 2 and 5 (issue 1954 L6-P2): a provision's key is its consumer's node and module, the provision and
// its local name, the provider's entry's key; its value round-trips, names its state and why, and refuses any field the
// layout does not name, so no value rides in it; a plan's key is its node and module.
func TestAProvisionIsAReferenceUnderItsConsumersKey(t *testing.T) {
at := time.Date(2026, 10, 29, 22, 0, 0, 0, time.UTC)
db := Provision{Provision: "postgres-database", Consumer: End{Module: "keycloak", Node: "novox"},
Provider: End{Module: "postgres", Node: "novox"}, DependsOn: []string{"novox.keycloak.secret.db"}, State: Asked,
Reference: &Reference{ID: "provision/postgres/postgres-database", Generation: 2}, At: at}
for _, c := range []struct {
name string
edit func(*Provision)
key string
refused string
}{
{name: "asked, depending on the vault's", key: "novox.keycloak.postgres-database"},
{name: "under a local name", edit: func(p *Provision) { p.Local = "replica" }, key: "novox.keycloak.postgres-database.replica"},
{name: "retiring with the operator's warrant", edit: func(p *Provision) {
p.State, p.Why, p.Ask = Retiring, "keycloak left novox", "a-1"
p.Warrant = &Warrant{Ask: "a-1", Option: "yes", By: "the operator", At: at}
}, key: "novox.keycloak.postgres-database"},
{name: "an unknown state", edit: func(p *Provision) { p.State = "done" }, refused: "one of"},
{name: "failed without why", edit: func(p *Provision) { p.State = Failed }, refused: "says why"},
{name: "a warrant on a provided one", edit: func(p *Provision) { p.State, p.Warrant = Provided, &Warrant{Ask: "a"} }, refused: "only a retiring"},
{name: "no provider", edit: func(p *Provision) { p.Provider = End{} }, refused: "no provider"},
{name: "a dotted consumer", edit: func(p *Provision) { p.Consumer.Module = "a.b" }, refused: "cannot be part"},
{name: "a dependency that is no key", edit: func(p *Provision) { p.DependsOn = []string{"x"} }, refused: "is not"},
} {
p := db
if c.edit != nil {
c.edit(&p)
}
raw, err := Encode(p)
if c.refused != "" {
if err == nil || !strings.Contains(err.Error(), c.refused) {
t.Errorf("%s: %v, want refused saying %q", c.name, err, c.refused)
}
continue
}
back, err := Decode(raw)
key, kerr := back.Key()
if err != nil || kerr != nil || key != c.key || back.V != Version || back.Reference.Generation != 2 {
t.Errorf("%s: read back as %+v under %q, %v %v", c.name, back, key, err, kerr)
}
if node, consumer, provision, local, err := ParseKey(key); err != nil || node != "novox" || consumer != "keycloak" ||
provision != "postgres-database" || local != p.Local {
t.Errorf("%s: %s parses as %s %s %s %s, %v", c.name, key, node, consumer, provision, local, err)
}
}
// A value never rides in a provision: a field the layout does not name is refused.
if _, err := Decode([]byte(`{"v":1,"provision":"p","consumer":{"module":"c","node":"n"},"provider":{"module":"p","node":"n"},` +
`"state":"provided","at":"2026-10-29T22:00:00Z","password":"hunter2"}`)); err == nil {
t.Error("a provision carrying a password was read")
}
plan := Plan{Node: "novox", Module: "restic", Plan: catalogue.Plan{}}
raw, err := EncodePlan(plan)
if err != nil {
t.Fatal(err)
}
if back, err := DecodePlan(raw); err != nil || back.Node != "novox" || back.Module != "restic" {
t.Errorf("a plan read back as %+v, %v", back, err)
}
if k, err := PlanKey("novox", "restic"); k != "novox.restic" || err != nil {
t.Errorf("a plan's key is %q, %v", k, err)
}
// A reference's id is the vault's name as its verb own names it, in each form (the host agent, 2026-10-29).
for form, want := range map[string]string{FormPair: "pair/novox/postgres-database/novox/keycloak", FormShared: "provision/novox/postgres-database",
FormIssued: "provision/novox/postgres-database/novox/keycloak", "none": ""} {
if got := VaultName(form, db); got != want {
t.Errorf("the %s name is %q", form, got)
}
}
if got := VaultName(FormPair, Provision{Provision: "p", Local: "r", Provider: End{Node: "a"}, Consumer: End{Node: "b", Module: "m"}}); got != "pair/a/p/b/m/r" {
t.Errorf("a local name's pair is %q", got)
}
if ProvisionsBucket != "mesh-provisioner_provisions" || PlansRead != "mesh-provisioner.plans" {
t.Errorf("the states are %s and %s", ProvisionsBucket, PlansRead)
}
}