stage 2 of 8 for issue 1389
This commit is contained in:
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/compose"
|
||||
"github.com/novox/mesh-controller/internal/inventory"
|
||||
)
|
||||
|
||||
// A declaration as the SDK composes it is the one the controller sends, byte for byte, whatever it carries: the body is the
|
||||
@@ -38,39 +37,28 @@ func TestASendableIsTheComposedDeclarationByteForByte(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// 1386: what a send records as carried is what the controller's own carriedOn recorded.
|
||||
// 1386: what a send records as carried: the current build of each module it carries, the build a module left out of it was last
|
||||
// sent (when that is known), and a module kept at the build the machine runs at that one. (The controller's carriedOn recorded
|
||||
// the same; mesh-sdk's node_test TestAModuleLeftOutKeepsTheBuildItWasLastSent holds the left-out case.)
|
||||
func TestWhatASendRecordsAsCarriedIsWhatTheControllerRecorded(t *testing.T) {
|
||||
plan := catalogue.Resolution{Modules: []catalogue.Manifest{{Module: "postgres"}, {Module: "files"}, {Module: "cache"}}}
|
||||
current := map[string]inventory.CurrentBuild{"postgres": {Commit: "p2"}, "files": {Commit: "f2"}, "cache": {Commit: "c2"}}
|
||||
leftOut := map[string]string{"cache": "a setting cannot compose"}
|
||||
for name, c := range map[string]struct {
|
||||
sent map[string]string
|
||||
known bool
|
||||
kept map[string]string
|
||||
want map[string]string
|
||||
}{
|
||||
"nothing sent": {},
|
||||
"sent and kept": {sent: map[string]string{"postgres": "p1", "cache": "c1", "files": "f1"}, known: true, kept: map[string]string{"postgres": "p1"}},
|
||||
"sent but not known": {sent: map[string]string{"cache": "c1"}},
|
||||
"kept a module not in": {known: true, kept: map[string]string{"mail": "m1"}},
|
||||
"nothing sent": {want: map[string]string{"postgres": "p2", "files": "f2"}},
|
||||
"sent and kept": {sent: map[string]string{"postgres": "p1", "cache": "c1", "files": "f1"}, known: true,
|
||||
kept: map[string]string{"postgres": "p1"}, want: map[string]string{"postgres": "p1", "files": "f2", "cache": "c1"}},
|
||||
"sent but not known": {sent: map[string]string{"cache": "c1"}, want: map[string]string{"postgres": "p2", "files": "f2"}},
|
||||
"kept a module not in": {known: true, kept: map[string]string{"mail": "m1"}, want: map[string]string{"postgres": "p2", "files": "f2"}},
|
||||
} {
|
||||
var names []string
|
||||
for _, m := range plan.Modules {
|
||||
names = append(names, m.Module)
|
||||
}
|
||||
before := c.sent
|
||||
if !c.known {
|
||||
before = nil
|
||||
}
|
||||
want := carriedBuilds(names, leftOut, current, before)
|
||||
for m, was := range c.kept {
|
||||
if _, carried := want[m]; carried {
|
||||
want[m] = was
|
||||
}
|
||||
}
|
||||
in := compose.Input{CurrentBuilds: map[string]string{"postgres": "p2", "files": "f2", "cache": "c2"}}
|
||||
node := compose.Node{SentBuilds: c.sent, SentKnown: c.known, KeptBuilds: c.kept}
|
||||
if got := buildsOf(in, node, plan, leftOut); !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("%s: a send records %v, the controller recorded %v", name, got, want)
|
||||
if got := buildsOf(in, node, plan, leftOut); !reflect.DeepEqual(got, c.want) {
|
||||
t.Errorf("%s: a send records %v, want %v", name, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,21 +127,17 @@ type snapshotFacts = snapshot.Facts
|
||||
func toldEveryMachine(t *testing.T, open *stores, served map[string]map[string]any, on map[string][]string) map[string]string {
|
||||
t.Helper()
|
||||
ctx := t.Context()
|
||||
gens, err := generators(ctx, open)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
shelf, err := open.inventory.Catalogue(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
told := map[string]string{}
|
||||
for _, node := range fourMachines {
|
||||
plan, settings, err := planFor(ctx, open, node)
|
||||
plan, _, err := resolveNode(ctx, open, node)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: %v", node, err)
|
||||
}
|
||||
with, _, err := renderingFor(ctx, open, node, plan, settings, gens, Allocating)
|
||||
with, err := madeAndRendered(ctx, open, node)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: %v", node, err)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"github.com/novox/mesh-controller/internal/conditions"
|
||||
"github.com/novox/mesh-controller/internal/inventory"
|
||||
"github.com/novox/mesh-controller/internal/link"
|
||||
)
|
||||
|
||||
// The core's own credentials, sealed by the vault (novox/hq ADR 0349 §16, issue 755; the lead's decision on issue 755,
|
||||
@@ -40,15 +39,6 @@ import (
|
||||
// the vault and the machine, cleared by the first send the vault answers whole. Only a machine with no sealing key, or
|
||||
// one whose key cannot be read, leaves its module out.
|
||||
|
||||
// engineOpensVaultBox says whether a machine's node-engine opens the vault's box, by its own newest statement.
|
||||
func engineOpensVaultBox(ctx context.Context, inv *inventory.Inventory, node string) (bool, error) {
|
||||
stated, had, err := inv.HealthOf(ctx, node)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return had && stated.Contract >= link.VaultBoxContract, nil
|
||||
}
|
||||
|
||||
// coreAnswer is the vault's `get` answer as the controller reads it: the name, the generation and the box, never
|
||||
// opened.
|
||||
type coreAnswer struct {
|
||||
@@ -121,7 +111,7 @@ func sealingKeyPEM(raw string) (string, error) {
|
||||
// own seal where nothing was kept; on any other question, the kept box, or a stand-in the next send asks for. Pure: what to keep and what to
|
||||
// say is answered, not done.
|
||||
func coreBoxesOf(node, sealingKey string, core map[string][]string, kept map[string]map[string]inventory.CoreBox,
|
||||
choosing Choosing, ask coreAsk) coreBoxes {
|
||||
allocating bool, ask coreAsk) coreBoxes {
|
||||
out := coreBoxes{sealed: map[string]map[string]json.RawMessage{}, notPlaced: map[string]string{}}
|
||||
modules := make([]string, 0, len(core))
|
||||
for m := range core {
|
||||
@@ -143,7 +133,7 @@ func coreBoxesOf(node, sealingKey string, core map[string][]string, kept map[str
|
||||
for _, name := range core[module] {
|
||||
k, has := kept[module][name]
|
||||
valid := has && k.SealedTo == sealingKey && len(k.Box) > 0
|
||||
if choosing != Allocating {
|
||||
if !allocating {
|
||||
if valid {
|
||||
boxes[name] = k.Box
|
||||
} else {
|
||||
@@ -218,10 +208,10 @@ var coreVault = func(ctx context.Context) coreAsk {
|
||||
|
||||
// coreBoxesFor is coreBoxesOf for one machine, read from and kept in the store, and said on a send.
|
||||
func coreBoxesFor(ctx context.Context, inv *inventory.Inventory, node string, modules []catalogue.Manifest,
|
||||
handed func(catalogue.Manifest) bool, choosing Choosing) (coreBoxes, error) {
|
||||
handed func(catalogue.Manifest) bool, allocating bool) (coreBoxes, error) {
|
||||
core := coreModulesOf(modules, handed)
|
||||
if len(core) == 0 {
|
||||
if choosing == Allocating {
|
||||
if allocating {
|
||||
settleVaultSilent(ctx, node)
|
||||
}
|
||||
return coreBoxes{}, nil
|
||||
@@ -235,16 +225,16 @@ func coreBoxesFor(ctx context.Context, inv *inventory.Inventory, node string, mo
|
||||
return coreBoxes{}, err
|
||||
}
|
||||
var ask coreAsk
|
||||
if choosing == Allocating {
|
||||
if allocating {
|
||||
ask = coreVault(ctx)
|
||||
}
|
||||
out := coreBoxesOf(node, key, core, kept, choosing, ask)
|
||||
out := coreBoxesOf(node, key, core, kept, allocating, ask)
|
||||
for _, b := range out.keep {
|
||||
if err := inv.KeepCoreBox(ctx, node, b); err != nil {
|
||||
return coreBoxes{}, err
|
||||
}
|
||||
}
|
||||
if choosing == Allocating {
|
||||
if allocating {
|
||||
sayVaultSilent(ctx, node, out)
|
||||
}
|
||||
return out, nil
|
||||
|
||||
@@ -96,7 +96,7 @@ func TestASilentVaultHoldsTheKeptBoxAndSaysSo(t *testing.T) {
|
||||
func TestACoreModuleFirstPlacedWhileTheVaultIsSilentIsSealedByTheController(t *testing.T) {
|
||||
open, vault := aCoreMesh(t, link.VaultBoxContract)
|
||||
vault.silent = errors.New("no responders")
|
||||
plan, settings, err := planFor(t.Context(), open, "laptop")
|
||||
plan, settings, err := resolveNode(t.Context(), open, "laptop")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ func TestReplay908(t *testing.T) {
|
||||
key := "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8="
|
||||
core := map[string][]string{"nats": {"password"}}
|
||||
ask := func(name, publicKey string) (coreAnswer, error) { return coreAnswer{}, errors.New("no responders") }
|
||||
got := coreBoxesOf("novox", key, core, nil, Allocating, ask)
|
||||
got := coreBoxesOf("novox", key, core, nil, true, ask)
|
||||
if _, sealed := got.sealed["nats"]; sealed || len(got.notPlaced) != 0 {
|
||||
t.Fatalf("nats is vault-sealed %v or not placed %v", got.sealed, got.notPlaced)
|
||||
}
|
||||
@@ -81,7 +81,7 @@ func TestReplay908(t *testing.T) {
|
||||
}
|
||||
// A kept box is still carried while the vault is silent.
|
||||
kept := map[string]map[string]inventory.CoreBox{"nats": {"password": {SealedTo: key, Box: json.RawMessage(`{"v":1}`)}}}
|
||||
got = coreBoxesOf("novox", key, core, kept, Allocating, ask)
|
||||
got = coreBoxesOf("novox", key, core, kept, true, ask)
|
||||
if string(got.sealed["nats"]["password"]) != `{"v":1}` || len(got.byController) != 0 {
|
||||
t.Fatalf("the kept box was not held: %+v", got)
|
||||
}
|
||||
@@ -99,17 +99,17 @@ func TestOnlyASendAsksTheVault(t *testing.T) {
|
||||
t.Fatal("the vault was asked by a question that is not a send")
|
||||
return coreAnswer{}, nil
|
||||
}
|
||||
for _, choosing := range []Choosing{Reading, Foreseeing} {
|
||||
if got := coreBoxesOf("anchor", key, core, kept, choosing, never); string(got.sealed["nats"]["broker"]) != `{"v":1}` {
|
||||
for _, allocating := range []bool{false} {
|
||||
if got := coreBoxesOf("anchor", key, core, kept, allocating, never); string(got.sealed["nats"]["broker"]) != `{"v":1}` {
|
||||
t.Errorf("read %s", got.sealed["nats"]["broker"])
|
||||
}
|
||||
if got := coreBoxesOf("anchor", key, core, nil, choosing, never); string(got.sealed["nats"]["broker"]) !=
|
||||
if got := coreBoxesOf("anchor", key, core, nil, allocating, never); string(got.sealed["nats"]["broker"]) !=
|
||||
string(catalogue.ForeseenVaultBox) {
|
||||
t.Errorf("with none kept, read %s", got.sealed["nats"]["broker"])
|
||||
}
|
||||
}
|
||||
// A box kept for another key of the machine is never carried.
|
||||
other := coreBoxesOf("anchor", aPublicKey(t), core, kept, Allocating,
|
||||
other := coreBoxesOf("anchor", aPublicKey(t), core, kept, true,
|
||||
func(string, string) (coreAnswer, error) { return coreAnswer{}, errors.New("silent") })
|
||||
if _, vaultSealed := other.sealed["nats"]; vaultSealed || !reflect.DeepEqual(other.byController, []string{"nats"}) {
|
||||
t.Fatalf("a box sealed to the machine's old key was carried: %+v", other)
|
||||
|
||||
@@ -40,7 +40,7 @@ func TestAssigningAModuleThatSpeaksOnTheBusNamesItsCredential(t *testing.T) {
|
||||
}
|
||||
|
||||
// And the push refuses to send it, naming the same verb, rather than sealing a placeholder.
|
||||
plan, settings, err := planFor(ctx, open, "laptop")
|
||||
plan, settings, err := resolveNode(ctx, open, "laptop")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -42,12 +42,8 @@ func TestAMachineIsSentTheEpochOnlyOnceItSaysItReadsOne(t *testing.T) {
|
||||
if err := inv.RecordReadsEpoch(ctx, anchor.ID, true); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
gens, err := generators(ctx, open)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
d := &bodiesDelivery{recordedDelivery: recordedDelivery{inv: inv}, bodies: map[string][]byte{}}
|
||||
if _, err := sendRound(ctx, open, []string{"anchor", "laptop"}, composeForPush(open, gens), d, "", nil); err != nil {
|
||||
if _, err := sendRound(ctx, open, []string{"anchor", "laptop"}, composeForPush(open), d, "", nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
carried := func(node string) (epoch float64, has bool) {
|
||||
@@ -89,12 +85,8 @@ func TestNothingIsComposedOrSentWithoutTheLease(t *testing.T) {
|
||||
was := epochForActs
|
||||
epochForActs = func(context.Context) (uint64, error) { return 0, errors.New("this controller lost the lease") }
|
||||
t.Cleanup(func() { epochForActs = was })
|
||||
gens, err := generators(ctx, open)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
d := &bodiesDelivery{recordedDelivery: recordedDelivery{inv: open.inventory}, bodies: map[string][]byte{}}
|
||||
refused, err := sendRound(ctx, open, []string{"anchor"}, composeForPush(open, gens), d, "", nil)
|
||||
refused, err := sendRound(ctx, open, []string{"anchor"}, composeForPush(open), d, "", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -14,8 +14,6 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/validate"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/compose"
|
||||
snapshot "git.novox.be/novox/mesh-sdk/go/facts"
|
||||
@@ -504,41 +502,6 @@ func declarationFacts(ctx context.Context, open *stores, node string, gensErr er
|
||||
return d
|
||||
}
|
||||
|
||||
// composedAndValidated composes one machine's declaration — as a push would (Allocating) or as the next
|
||||
// push will without making anything (Foreseeing) — with the order it was last sent, and runs the
|
||||
// node-engine's own validator over the body. An error is that it did not compose; problems are what the
|
||||
// validator refuses.
|
||||
func composedAndValidated(ctx context.Context, open *stores, node string, gens map[string]catalogue.Generator,
|
||||
choosing Choosing) (sendable, []string, error) {
|
||||
plan, settings, err := planFor(ctx, open, node)
|
||||
if err != nil {
|
||||
return sendable{}, nil, err
|
||||
}
|
||||
declared, err := declarationWith(ctx, open, node, plan, settings, gens, choosing)
|
||||
if err != nil {
|
||||
return sendable{}, nil, err
|
||||
}
|
||||
record, err := open.inventory.NodeByName(ctx, node)
|
||||
if err != nil {
|
||||
return sendable{}, nil, err
|
||||
}
|
||||
if declared.Sequence, err = open.inventory.Sequence(ctx, record.ID); err != nil {
|
||||
return sendable{}, nil, err
|
||||
}
|
||||
if declared.Epoch, err = open.inventory.SentEpoch(ctx, record.ID); err != nil {
|
||||
return sendable{}, nil, err
|
||||
}
|
||||
// And the generation it was last sent, as the would-send is (novox/hq issue 234).
|
||||
if declared.Generation, err = open.inventory.SentGeneration(ctx, record.ID); err != nil {
|
||||
return sendable{}, nil, err
|
||||
}
|
||||
body, err := declared.Body()
|
||||
if err != nil {
|
||||
return sendable{}, nil, err
|
||||
}
|
||||
return declared, validate.Declaration(body), nil
|
||||
}
|
||||
|
||||
// resourceNames are a declaration's resources as `type:id`, sorted.
|
||||
func resourceNames(resources []map[string]any) []string {
|
||||
out := make([]string, 0, len(resources))
|
||||
|
||||
@@ -42,12 +42,8 @@ func aMeshWithSecrets(t *testing.T) (*stores, []string) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// A push's worth of composition, which makes the pair credential the consumer is sent.
|
||||
gens, err := generators(ctx, open)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, node := range []string{"laptop", "anchor"} {
|
||||
if _, _, err := composedAndValidated(ctx, open, node, gens, Allocating); err != nil {
|
||||
if _, err := composeSend(ctx, open, node); err != nil {
|
||||
t.Fatalf("%s does not compose: %v", node, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -103,18 +102,6 @@ func senderOf(caller string) string {
|
||||
return fmt.Sprintf("%s (pid %d on %s, build %s)", caller, os.Getpid(), host, version)
|
||||
}
|
||||
|
||||
// namedModules are the modules a declaration names: its machine's set, less what was left out of it.
|
||||
func namedModules(plan catalogue.Resolution, leftOut map[string]string) []string {
|
||||
out := make([]string, 0, len(plan.Modules))
|
||||
for _, m := range plan.Modules {
|
||||
if _, left := leftOut[m.Module]; !left {
|
||||
out = append(out, m.Module)
|
||||
}
|
||||
}
|
||||
sort.Strings(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// heardGenerationRefusal keeps a machine's refusal of a send for its generation, so S20 names its sender
|
||||
// and says it (novox/hq issue 234): on the send it refused or — when the mesh has no record of sending that
|
||||
// sequence — as a refusal of its own, naming the sender as unknown. Either way S20 is raised: a refusal the
|
||||
|
||||
@@ -35,7 +35,7 @@ func TestAConsumerPinnedBackIsNoLongerGrantedByTheProviderItLeft(t *testing.T) {
|
||||
if err := inv.PinProvision(ctx, "laptop", "postgres-database", "anchor", "store"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
plan, _, err := planFor(ctx, open, "laptop")
|
||||
plan, _, err := resolveNode(ctx, open, "laptop")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -45,7 +45,7 @@ func TestAConsumerPinnedBackIsNoLongerGrantedByTheProviderItLeft(t *testing.T) {
|
||||
if err := inv.RecordBindings(ctx, "laptop", boundToData(plan, nil)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
grants, _, unbound, err := grantsFor(ctx, open, "anchor")
|
||||
grants, _, unbound, err := grantsOf(ctx, open, "anchor")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -57,7 +57,7 @@ func TestAConsumerPinnedBackIsNoLongerGrantedByTheProviderItLeft(t *testing.T) {
|
||||
if err := inv.PinProvision(ctx, "laptop", "postgres-database", "laptop", "store"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
plan, _, err = planFor(ctx, open, "laptop")
|
||||
plan, _, err = resolveNode(ctx, open, "laptop")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -76,7 +76,7 @@ func TestAConsumerPinnedBackIsNoLongerGrantedByTheProviderItLeft(t *testing.T) {
|
||||
}
|
||||
|
||||
// The store it left: no longer granted, and said.
|
||||
grants, _, unbound, err = grantsFor(ctx, open, "anchor")
|
||||
grants, _, unbound, err = grantsOf(ctx, open, "anchor")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -87,7 +87,7 @@ func TestAConsumerPinnedBackIsNoLongerGrantedByTheProviderItLeft(t *testing.T) {
|
||||
strings.Join(unbound[0].BoundTo, ",") != "laptop" {
|
||||
t.Fatalf("the consumer that moved is not the one said: %+v", unbound)
|
||||
}
|
||||
planned, settings, err := planFor(ctx, open, "anchor")
|
||||
planned, settings, err := resolveNode(ctx, open, "anchor")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -105,7 +105,7 @@ func TestAConsumerPinnedBackIsNoLongerGrantedByTheProviderItLeft(t *testing.T) {
|
||||
}
|
||||
|
||||
// The store it is bound to: granted.
|
||||
grants, _, unbound, err = grantsFor(ctx, open, "laptop")
|
||||
grants, _, unbound, err = grantsOf(ctx, open, "laptop")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -131,7 +131,7 @@ func TestAConsumerWhoseResolutionCannotBeReadIsNotWithdrawn(t *testing.T) {
|
||||
t.Fatalf("assign %s %s: %v", a[0], a[1], err)
|
||||
}
|
||||
}
|
||||
if _, _, err := planFor(ctx, open, "laptop"); err != nil {
|
||||
if _, _, err := resolveNode(ctx, open, "laptop"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -144,10 +144,10 @@ func TestAConsumerWhoseResolutionCannotBeReadIsNotWithdrawn(t *testing.T) {
|
||||
if err := inv.RecordSealingKey(ctx, laptop.ID, "not a key"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, _, err := planFor(ctx, open, "laptop"); err == nil || unresolvable(err) {
|
||||
if _, _, err := resolveNode(ctx, open, "laptop"); err == nil || unresolvable(err) {
|
||||
t.Fatalf("the seam this test relies on moved: %v", err)
|
||||
}
|
||||
grants, _, unbound, err := grantsFor(ctx, open, "anchor")
|
||||
grants, _, unbound, err := grantsOf(ctx, open, "anchor")
|
||||
if err == nil {
|
||||
t.Fatalf("an unreadable consumer was answered: grants %+v, unbound %+v", grants, unbound)
|
||||
}
|
||||
|
||||
@@ -66,15 +66,11 @@ func TestTheGrantsStepSendsTheUserListAndNothingElse(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
plan, settings, err := planFor(under, open, "anchor")
|
||||
plan, _, err := resolveNode(under, open, "anchor")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
gens, err := generators(under, open)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
declared, err := declarationWith(under, open, "anchor", plan, settings, gens, Allocating)
|
||||
declared, err := composeSend(under, open, "anchor")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"github.com/novox/mesh-controller/internal/inventory"
|
||||
)
|
||||
|
||||
@@ -265,11 +264,9 @@ func flushBehind(ctx context.Context, open *stores, nodes []inventory.Node, hand
|
||||
|
||||
// composeForPush is how a push composes one machine: its set resolved, what it cannot host and what
|
||||
// is left out of it said, and its declaration allocated.
|
||||
func composeForPush(open *stores, gens map[string]catalogue.Generator) func(held context.Context, node string) (sendable, error) {
|
||||
func composeForPush(open *stores) func(held context.Context, node string) (sendable, error) {
|
||||
return func(held context.Context, node string) (sendable, error) {
|
||||
// Read afresh for each machine: the send before it made and recorded things. gens is the private network the
|
||||
// controller's own composition took; the SDK's is computed from the same Input.
|
||||
_ = gens
|
||||
// Read afresh for each machine: the send before it made and recorded things.
|
||||
held = freshInput(held)
|
||||
plan, _, err := resolveNode(held, open, node)
|
||||
if err != nil {
|
||||
|
||||
@@ -28,11 +28,7 @@ func TestANamedPushLeavesAMachineAPolicyHoldsBack(t *testing.T) {
|
||||
if err := inv.SetUpgradeOf(ctx, "resolver", inventory.Upgrade{Why: "each machine checked by hand"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
gens, err := generators(ctx, open)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
compose := composeForPush(open, gens)
|
||||
compose := composeForPush(open)
|
||||
d := &recordedDelivery{inv: inv}
|
||||
if _, err := sendRound(ctx, open, []string{"anchor", "laptop"}, compose, d, "", nil); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -134,11 +130,7 @@ func TestANamedPushStillSendsAConsequenceNothingHolds(t *testing.T) {
|
||||
if _, err := inv.Assign(ctx, "laptop", "resolver"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
gens, err := generators(ctx, open)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
compose := composeForPush(open, gens)
|
||||
compose := composeForPush(open)
|
||||
d := &recordedDelivery{inv: inv}
|
||||
if _, err := sendRound(ctx, open, []string{"anchor", "laptop"}, compose, d, "", nil); err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -3,7 +3,6 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -99,22 +98,6 @@ func TestAPlanWaitingOnItsFirstMachineHoldsTheRest(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// A send records the build of each module it carried; a module left out of it keeps the build it
|
||||
// was last sent, since the machine keeps that one.
|
||||
func TestASendCarriesTheCurrentBuildsAndALeftOutModuleKeepsItsOwn(t *testing.T) {
|
||||
current := map[string]inventory.CurrentBuild{"a": {Commit: "a2"}, "b": {Commit: "b2"}, "c": {}}
|
||||
got := carriedBuilds([]string{"a", "b", "c"}, map[string]string{"b": "a setting does not compose"},
|
||||
current, map[string]string{"a": "a1", "b": "b1"})
|
||||
if want := map[string]string{"a": "a2", "b": "b1", "c": ""}; !reflect.DeepEqual(got, want) {
|
||||
t.Fatalf("carried %v, wanted %v", got, want)
|
||||
}
|
||||
// Not known before: the left-out module is not recorded at all, so it reads as never sent.
|
||||
got = carriedBuilds([]string{"a", "b"}, map[string]string{"b": "x"}, current, nil)
|
||||
if want := map[string]string{"a": "a2"}; !reflect.DeepEqual(got, want) {
|
||||
t.Fatalf("carried %v, wanted %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// recordedDelivery sends nothing and records each send as the mesh does, so the next comparison
|
||||
// reads the machine as current — and writes down which machines it declared.
|
||||
type recordedDelivery struct {
|
||||
|
||||
@@ -63,7 +63,7 @@ func TestASecondEligibleHolderStandsBesideTheOneHeldByBeingAlone(t *testing.T) {
|
||||
|
||||
// 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)
|
||||
plan, _, err := resolveNode(ctx, open, node)
|
||||
if err != nil {
|
||||
t.Fatalf("%s no longer resolves: %v", node, err)
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ func TestAnOverflowingConsumerNeverRefusesItsProvidersMachine(t *testing.T) {
|
||||
}
|
||||
|
||||
// The consumer's machine resolves, and says which of its modules no provider will grant.
|
||||
consumer, _, err := planFor(ctx, open, "laptop")
|
||||
consumer, _, err := resolveNode(ctx, open, "laptop")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -42,7 +42,7 @@ func TestAnOverflowingConsumerNeverRefusesItsProvidersMachine(t *testing.T) {
|
||||
|
||||
// The provider's machine composes. Under ADR 0049's one bound this was a refusal naming
|
||||
// networkmanager, and no push to the provider could go through.
|
||||
plan, settings, err := planFor(ctx, open, "anchor")
|
||||
plan, settings, err := resolveNode(ctx, open, "anchor")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -53,7 +53,7 @@ func TestAnOverflowingConsumerNeverRefusesItsProvidersMachine(t *testing.T) {
|
||||
if len(declared.withheld) != 1 || declared.withheld[0].Identity != "mesh_laptop_photoalbum" {
|
||||
t.Fatalf("the overflowing consumer is not the one withheld: %+v", declared.withheld)
|
||||
}
|
||||
grants, _, _, err := grantsFor(ctx, open, "anchor")
|
||||
grants, _, _, err := grantsOf(ctx, open, "anchor")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ func TestReplay201(t *testing.T) {
|
||||
t.Fatalf("the send keeps the newer controller there: %v %v", keeps, err)
|
||||
}
|
||||
shelf := map[string]catalogue.Manifest{"mesh-controller": {Module: "mesh-controller", Version: "old"}}
|
||||
if _, err := keepRecorded(keepingRecorded(judged), open, "anchor", shelf); err != nil || shelf["mesh-controller"].Version != "1" {
|
||||
if err := applyKept(keepingRecorded(judged), open, "anchor", keeps, shelf); err != nil || shelf["mesh-controller"].Version != "1" {
|
||||
t.Fatalf("the send composes the kept build's manifest: %+v %v", shelf, err)
|
||||
}
|
||||
key := coreDowngradeObservation(lease.ComponentController, "anchor", "").Key()
|
||||
|
||||
Reference in New Issue
Block a user