156 lines
5.4 KiB
Go
156 lines
5.4 KiB
Go
//go:build integration
|
|
|
|
package inventory
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/novox/mesh-controller/internal/catalogue"
|
|
)
|
|
|
|
// A seat's holder is a row, changed as one act (novox/hq ADR 0131). What these pin is the shape of
|
|
// that row's life: it needs an assignment to point at, it is replaced rather than added to, and it
|
|
// goes when the assignment does — so a seat never points at something that is not running anywhere.
|
|
|
|
func twoBrokersOnTwoNodes(t *testing.T) (*Inventory, context.Context) {
|
|
t.Helper()
|
|
old := catalogue.Manifest{Module: "old-broker", Version: "1",
|
|
Provides: []catalogue.Offer{{Name: "mesh-bus", Scope: catalogue.ScopeMesh}},
|
|
Claims: []catalogue.Claim{{Name: "mesh-broker", Scope: catalogue.ScopeMesh}}}
|
|
new := catalogue.Manifest{Module: "new-broker", Version: "1",
|
|
Provides: []catalogue.Offer{{Name: "mesh-bus", Scope: catalogue.ScopeMesh}},
|
|
Claims: []catalogue.Claim{{Name: "mesh-broker", Scope: catalogue.ScopeMesh}}}
|
|
inv, ctx := aMeshWith(t, old, new)
|
|
// The holding references the seat's row, which `migrate` seeds on a real mesh.
|
|
if _, err := inv.SeedSeats(ctx, catalogue.DefaultSeats()); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, n := range []string{"anchor", "laptop"} {
|
|
if _, err := inv.AddNode(ctx, n); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
if _, err := inv.Assign(ctx, "anchor", "old-broker"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := inv.Assign(ctx, "laptop", "new-broker"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return inv, ctx
|
|
}
|
|
|
|
func TestAHandoverIsOneRowReplacedNotOneAdded(t *testing.T) {
|
|
inv, ctx := twoBrokersOnTwoNodes(t)
|
|
|
|
if err := inv.HoldSeat(ctx, "mesh-broker", catalogue.ScopeMesh, "anchor", "old-broker"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := inv.HoldSeat(ctx, "mesh-broker", catalogue.ScopeMesh, "laptop", "new-broker"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
held, err := inv.Holdings(ctx)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(held) != 1 || held[0].Node != "laptop" || held[0].Module != "new-broker" || held[0].Scope != catalogue.ScopeMesh {
|
|
t.Fatalf("after a handover the seat is not held by exactly the new holder: %+v", held)
|
|
}
|
|
}
|
|
|
|
func TestASeatCannotBeHandedToSomethingNotAssigned(t *testing.T) {
|
|
inv, ctx := twoBrokersOnTwoNodes(t)
|
|
// new-broker is assigned to laptop, not anchor.
|
|
if err := inv.HoldSeat(ctx, "mesh-broker", catalogue.ScopeMesh, "anchor", "new-broker"); err == nil {
|
|
t.Fatal("a seat was handed to a module not assigned where it was named")
|
|
}
|
|
}
|
|
|
|
func TestUnassigningTheHolderTakesTheHoldingWithIt(t *testing.T) {
|
|
inv, ctx := twoBrokersOnTwoNodes(t)
|
|
if err := inv.HoldSeat(ctx, "mesh-broker", catalogue.ScopeMesh, "laptop", "new-broker"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := inv.Unassign(ctx, "laptop", "new-broker"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
held, err := inv.Holdings(ctx)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(held) != 0 {
|
|
t.Fatalf("the holding outlived the assignment it pointed at: %+v", held)
|
|
}
|
|
}
|
|
|
|
func TestAMachinesMembershipIsOneRowReplacedAndGoesWithTheMachine(t *testing.T) {
|
|
inv, ctx := twoBrokersOnTwoNodes(t)
|
|
if err := inv.PutBusMembership(ctx, "anchor", "first"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := inv.PutBusMembership(ctx, "anchor", "second"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, err := inv.BusMemberships(ctx)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got["anchor"] != "second" || len(got) != 1 {
|
|
t.Fatalf("a re-told membership did not replace the first: %v", got)
|
|
}
|
|
}
|
|
|
|
// A replicated seat has several holders on record (novox/hq ADR 0223): each is added beside the
|
|
// others, adding one twice changes nothing, a handover still leaves exactly one, and unassigning one
|
|
// takes only its own row.
|
|
func TestAReplicatedSeatHasSeveralHoldersOnRecord(t *testing.T) {
|
|
resolver := catalogue.Manifest{Module: "resolver", Version: "1",
|
|
Provides: []catalogue.Offer{{Name: "wildcard-resolution", Scope: catalogue.ScopeMesh}},
|
|
Claims: []catalogue.Claim{{Name: "mesh-dns-resolver", Scope: catalogue.ScopeMesh}}}
|
|
inv, ctx := aMeshWith(t, resolver)
|
|
if _, err := inv.SeedSeats(ctx, catalogue.DefaultSeats()); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, n := range []string{"anchor", "home"} {
|
|
if _, err := inv.AddNode(ctx, n); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := inv.Assign(ctx, n, "resolver"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
if err := inv.HoldSeat(ctx, "mesh-dns-resolver", catalogue.ScopeMesh, "anchor", "resolver"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for range 2 {
|
|
if err := inv.AddSeatHolder(ctx, "mesh-dns-resolver", catalogue.ScopeMesh, "home", "resolver"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
held, err := inv.Holdings(ctx)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(held) != 2 || held[0].Node != "anchor" || held[1].Node != "home" {
|
|
t.Fatalf("the two holders are not both on record, once each: %+v", held)
|
|
}
|
|
if err := inv.Unassign(ctx, "home", "resolver"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if held, _ = inv.Holdings(ctx); len(held) != 1 || held[0].Node != "anchor" {
|
|
t.Fatalf("unassigning one holder took more or less than its own row: %+v", held)
|
|
}
|
|
if _, err := inv.Assign(ctx, "home", "resolver"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := inv.AddSeatHolder(ctx, "mesh-dns-resolver", catalogue.ScopeMesh, "home", "resolver"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := inv.HoldSeat(ctx, "mesh-dns-resolver", catalogue.ScopeMesh, "home", "resolver"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if held, _ = inv.Holdings(ctx); len(held) != 1 || held[0].Node != "home" {
|
|
t.Fatalf("a handover left other holders on record: %+v", held)
|
|
}
|
|
}
|