package main import ( "strings" "testing" "github.com/novox/mesh-controller/internal/catalogue" ) // A seat nobody ever handed over is held by whichever assignment happened to be alone — and the // day a second module able to hold it is assigned, both claimed, both were refused, and the first // one's machine stopped resolving (novox/hq 04-ISSUES/170). The mesh now writes the derived holder // down before it acts, so the second assignment stands beside the holder on record. func aSeatedStore() catalogue.Manifest { return catalogue.Manifest{Module: "store", Version: "1", Provides: []catalogue.Offer{{Name: "postgres-database", Scope: catalogue.ScopeMesh}}, Serves: map[string]map[string]any{"postgres-database": {"port": 5432}}, Claims: []catalogue.Claim{{Name: "mesh-store", Scope: catalogue.ScopeMesh}}} } func TestASecondEligibleHolderStandsBesideTheOneHeldByBeingAlone(t *testing.T) { open := aMesh(t) ctx := t.Context() // Every deploy seeds the mesh's own seats; a record is a row against one of them. if _, err := open.inventory.SeedSeats(ctx, catalogue.DefaultSeats()); err != nil { t.Fatal(err) } register(t, open, aSeatedStore()) if _, err := assign(ctx, open, "anchor", "store"); err != nil { t.Fatal(err) } said, err := assign(ctx, open, "laptop", "store") if err != nil { t.Fatalf("a second store, eligible for the seat, was refused:\n%s\n%v", said, err) } if strings.Contains(said, "cannot be worked out") { t.Fatalf("assigning a second store unsettled the first one's machine:\n%s", said) } if !strings.Contains(said, "recorded store on anchor as the standing holder of mesh-store") { t.Fatalf("the holder by derivation was not written down:\n%s", said) } holdings, err := open.inventory.Holdings(ctx) if err != nil { t.Fatal(err) } var found bool for _, h := range holdings { if h.Claim == "mesh-store" { found = true if h.Node != "anchor" || h.Module != "store" { t.Fatalf("mesh-store is recorded on %s/%s, not on the one that held it", h.Node, h.Module) } } } if !found { t.Fatalf("mesh-store has no holder on record after assigning: %v", holdings) } // And the record decides from here: the anchor's plan holds the seat, the laptop's does not. for node, holds := range map[string]bool{"anchor": true, "laptop": false} { plan, _, err := planFor(ctx, open, node) if err != nil { t.Fatalf("%s no longer resolves: %v", node, err) } var claimed bool for _, c := range plan.Claims { if c.Claim == "mesh-store" { claimed = true } } if claimed != holds { t.Fatalf("%s holds mesh-store: %v, want %v", node, claimed, holds) } } } func TestAHolderOnRecordIsNotRewrittenByDerivation(t *testing.T) { open := aMesh(t) ctx := t.Context() if _, err := open.inventory.SeedSeats(ctx, catalogue.DefaultSeats()); err != nil { t.Fatal(err) } register(t, open, aSeatedStore()) for _, node := range []string{"anchor", "laptop"} { if _, err := assign(ctx, open, node, "store"); err != nil { t.Fatal(err) } } // A person hands the seat to the laptop. From here the record decides, and what the mesh // derives must never write over it. if err := open.inventory.HoldSeat(ctx, "mesh-store", catalogue.ScopeMesh, "laptop", "store"); err != nil { t.Fatal(err) } said, err := recordDerivedHolders(ctx, open) if err != nil { t.Fatal(err) } if len(said) != 0 { t.Fatalf("a seat on record was written again from derivation: %v", said) } holdings, _ := open.inventory.Holdings(ctx) for _, h := range holdings { if h.Claim == "mesh-store" && h.Node != "laptop" { t.Fatalf("the record moved to %s", h.Node) } } }