94 lines
4.1 KiB
Go
94 lines
4.1 KiB
Go
package main
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/novox/mesh-controller/internal/catalogue"
|
|
"github.com/novox/mesh-controller/internal/conditions"
|
|
)
|
|
|
|
// novox/hq issue 273, ADR 0232: a consumer of a provision that keeps its data moves only by a pin.
|
|
|
|
func storeManifests() []catalogue.Manifest {
|
|
return []catalogue.Manifest{
|
|
{Module: "store", Version: "1",
|
|
Provides: []catalogue.Offer{{Name: "postgres-database", Scope: catalogue.ScopeMesh}},
|
|
Claims: []catalogue.Claim{{Name: "mesh-store", Scope: catalogue.ScopeMesh}},
|
|
Serves: map[string]map[string]any{"postgres-database": {"port": 5432}},
|
|
Grants: map[string]string{"postgres-database": "/var/lib/mesh/store/grants"}},
|
|
{Module: "resolver", Version: "1",
|
|
Provides: []catalogue.Offer{{Name: "wildcard-resolution", Scope: catalogue.ScopeMesh}},
|
|
Claims: []catalogue.Claim{{Name: "mesh-dns-resolver", Scope: catalogue.ScopeMesh}}},
|
|
{Module: "network", Version: "1", Requires: []string{"wildcard-resolution"}},
|
|
{Module: "board", Version: "1", Requires: []string{"postgres-database"}},
|
|
}
|
|
}
|
|
|
|
func need(t *testing.T, plan catalogue.Resolution, consumer, provision string) catalogue.Needed {
|
|
t.Helper()
|
|
for _, n := range plan.Needs {
|
|
if n.For == consumer && n.Name == provision {
|
|
return n
|
|
}
|
|
}
|
|
t.Fatalf("no %s for %s: %+v", provision, consumer, plan.Needs)
|
|
return catalogue.Needed{}
|
|
}
|
|
|
|
// The incident through the stores: the laptop runs its own store and a consumer of it, the anchor's
|
|
// store holds the mesh's seat. The consumer stays beside its data, the resolver follows its seat, the
|
|
// binding is recorded as sent, and a pin — only a pin — moves it, said before the push that carries it.
|
|
|
|
// What one machine's resolution says against its record.
|
|
func TestBindingFindingsSayAKeptMoveAndAMoveNothingAskedFor(t *testing.T) {
|
|
home, anchor := catalogue.Chosen{Node: "home", Module: "store"}, catalogue.Chosen{Node: "anchor", Module: "store"}
|
|
plan := catalogue.Resolution{Node: "laptop",
|
|
Kept: []catalogue.KeptBinding{{Machine: "laptop", Consumer: "board", Provision: "postgres-database",
|
|
Bound: home, Would: anchor}},
|
|
Needs: []catalogue.Needed{
|
|
{Name: "postgres-database", For: "board", From: "home", Module: "store", KeepsData: true},
|
|
{Name: "postgres-database", For: "game", From: "anchor", Module: "store", KeepsData: true},
|
|
{Name: "wildcard-resolution", For: "network", From: "anchor", Module: "resolver"},
|
|
}}
|
|
bound := map[string]map[string]catalogue.Chosen{
|
|
"board": {"postgres-database": home},
|
|
"game": {"postgres-database": home},
|
|
"network": {"wildcard-resolution": {Node: "home", Module: "resolver"}},
|
|
}
|
|
found := linted(bindingFindings(plan, bound, nil))
|
|
if len(found) != 2 {
|
|
t.Fatalf("found %+v", found)
|
|
}
|
|
kept, moved := found[0], found[1]
|
|
if kept.Kind != kindBindingKept || kept.Severity != conditions.Urgent || kept.Machine != "laptop" ||
|
|
!strings.Contains(kept.Summary, "would move board's postgres-database from home/store to anchor/store") ||
|
|
!strings.Contains(kept.Summary, "its data is on home/store") ||
|
|
!strings.Contains(kept.Summary, "`pin laptop postgres-database anchor store` to confirm a move (and move the data first)") {
|
|
t.Errorf("kept: %+v", kept)
|
|
}
|
|
if moved.Kind != kindBindingMoved || moved.Severity != conditions.Urgent ||
|
|
!strings.Contains(moved.Summary, "game's postgres-database would be sent anchor/store") {
|
|
t.Errorf("moved: %+v", moved)
|
|
}
|
|
if kept.Key() == moved.Key() {
|
|
t.Error("two consumers, one condition")
|
|
}
|
|
}
|
|
|
|
// A push says the move it refused, and raises its condition at once.
|
|
func TestAPushSaysAKeptMoveAndRaisesItsCondition(t *testing.T) {
|
|
k, _ := withConditionsInMemory(t)
|
|
reportKept(t.Context(), catalogue.Resolution{Node: "laptop", Kept: []catalogue.KeptBinding{{Machine: "laptop",
|
|
Consumer: "board", Provision: "postgres-database", Bound: catalogue.Chosen{Node: "home", Module: "store"},
|
|
Would: catalogue.Chosen{Node: "anchor", Module: "store"}}}})
|
|
open, err := k.Open(t.Context())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(open) != 1 || open[0].Kind != kindBindingKept || open[0].Severity != conditions.Urgent ||
|
|
open[0].Source != probeBindingsID {
|
|
t.Fatalf("raised %+v", open)
|
|
}
|
|
}
|