Every method of builds, build requests, rollouts, merges and assignments reads and writes the chain alone: the else branches that read the tables, the movers and MoveChain with their tests, chain_moved reads, ChainReads and the flags that switched a kind, the store's assignments mirror (KeepAssignmentPlans needs none of it: it uses only the AssignmentMirrored type, mirrors.go, and AssignmentValues, provisioning.go) and its tick, the move code of the controller's start, and ForTest's chain_moved row. The listed store tests of the move go with their functions; the tests of the readers, requests, assignments and plans that lived beside them stay in chain_store_test.go. Tests that replayed old data migrations over the build, assignment and pin tables are removed with the tables. The static test that no plan is written but through SavePlansMoving now reads the plan's chain path.
102 lines
3.8 KiB
Go
102 lines
3.8 KiB
Go
//go:build integration
|
|
|
|
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/novox/mesh-controller/internal/broker"
|
|
"github.com/novox/mesh-controller/internal/catalogue"
|
|
"github.com/novox/mesh-controller/internal/inventory"
|
|
"github.com/novox/mesh-controller/internal/link"
|
|
)
|
|
|
|
func TestAModulePulledInIsHandedOnAMachineThatCanTakeItAndMirrored(t *testing.T) {
|
|
open := aMesh(t)
|
|
ctx := t.Context()
|
|
inv := open.inventory
|
|
client := aClientModule()
|
|
moved, kept := aBot("moved-bot", true), aBot("kept-bot", false)
|
|
moved.Provides = []catalogue.Offer{{Name: "moved-bot-api"}}
|
|
kept.Provides = []catalogue.Offer{{Name: "kept-bot-api"}}
|
|
desk := catalogue.Manifest{Module: "desk", Version: "1", Requires: []string{"moved-bot-api", "kept-bot-api"}}
|
|
for _, m := range []catalogue.Manifest{client, moved, kept, desk} {
|
|
register(t, open, m)
|
|
}
|
|
for _, m := range []string{client.Module, desk.Module} {
|
|
if _, err := assign(ctx, open, "laptop", m); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
if err := issueProvisionerClient(ctx, inv, client, "laptop", broker.Broker{Fingerprint: "ab"}, "10.0.0.1:4222"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := inv.RecordHealth(ctx, inventory.NodeHealth{Node: "laptop", Contract: link.HandedContract,
|
|
SaidAt: time.Now()}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
plan, settings, err := planFor(ctx, open, "laptop")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if plan.RequiredBy("moved-bot") != "desk" || plan.RequiredBy("kept-bot") != "desk" {
|
|
t.Fatalf("the bots are on laptop because %v", plan.Because)
|
|
}
|
|
declared, err := declarationFor(ctx, open, "laptop", plan, settings)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var movedToken, keptToken, movedConf map[string]any
|
|
for _, r := range declared.Resources {
|
|
switch r["id"] {
|
|
case "moved-bot.needs-token":
|
|
movedToken = r
|
|
case "kept-bot.needs-token":
|
|
keptToken = r
|
|
case "moved-bot.conf":
|
|
movedConf = r
|
|
}
|
|
}
|
|
if movedToken == nil || movedToken["sealed"] != nil || movedToken["owner-at-runtime"] != "owned" {
|
|
t.Fatalf("the pulled-in moved module's secret file is sent as %v: placed, with no value", movedToken)
|
|
}
|
|
if movedConf == nil || movedConf["content"] != nil || movedConf["owner-at-runtime"] != "owned" {
|
|
t.Fatalf("the pulled-in moved module's templated file is sent as %v: placed, with no text", movedConf)
|
|
}
|
|
if keptToken == nil || keptToken["sealed"] == nil {
|
|
t.Fatalf("the pulled-in module not moved has its secret sent as %v: sealed, as before", keptToken)
|
|
}
|
|
if _, held, err := inv.ModuleSecretIfIssued(ctx, "laptop", "moved-bot", "token"); err != nil || held {
|
|
t.Fatalf("the send made the pulled-in handed module's secret in the controller's store (held %v, %v)", held, err)
|
|
}
|
|
if _, has := declared.plans["kept-bot"]; has || len(declared.plans) != 1 {
|
|
t.Fatalf("the send hands %v", declared.plans)
|
|
}
|
|
|
|
record, err := inv.NodeByName(ctx, "laptop")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := inv.RecordSentWith(ctx, record.ID, "first", nil, 0, 0, inventory.Send{Digest: "first",
|
|
Provisioning: sentRecordOf(ctx, declared).plans}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
inv.SetProvisioningPlans(inv.SentProvisioningPlans)
|
|
mirror := inv.PlanValuesForTest(t)
|
|
var value inventory.AssignmentMirrored
|
|
if err := json.Unmarshal(mirror["laptop.moved-bot"], &value); err != nil {
|
|
t.Fatalf("no value for the pulled-in module: %s (%v)", mirror["laptop.moved-bot"], err)
|
|
}
|
|
if value.RequiredBy != "desk" || !value.Assigned.IsZero() || value.Provisioning == nil ||
|
|
len(value.Provisioning.Files) != 1 || value.Provisioning.Files[0].Path != "/etc/moved-bot/bot.conf" ||
|
|
len(value.Provisioning.Secrets) != 1 || value.Provisioning.Secrets[0].Name != "token" {
|
|
t.Fatalf("the pulled-in module is mirrored as %s", mirror["laptop.moved-bot"])
|
|
}
|
|
if _, has := mirror["laptop.kept-bot"]; has {
|
|
t.Fatalf("a pulled-in module not handed is mirrored: %s", mirror["laptop.kept-bot"])
|
|
}
|
|
}
|