The assigner's state and verb placement are assignments, with its events, tools, views and every caller; the assigner copies the retired state at its start (issue 1966)
Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
@@ -5,8 +5,8 @@ go 1.26.0
|
||||
require (
|
||||
git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshwatchdogs v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-contracts/go/clients/meshmoduleassignerclient v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-delivery/sdk v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-sdk/go v0.0.0-00010101000000-000000000000
|
||||
github.com/nats-io/nats.go v1.54.0
|
||||
|
||||
@@ -4,9 +4,9 @@ package buildrun
|
||||
// builder checks them against it) and from the build seats' states: a bucket is `<holder module>_<state>`, and no contract
|
||||
// names a holder (novox/hq ADR 0625 §4, ADR 0634 §1).
|
||||
const (
|
||||
// PlacementBucket is the assigner's state placement, which the toolchain gate reads for the placing of a build module.
|
||||
AssignerModule = "mesh-delivery-assigner"
|
||||
PlacementBucket = AssignerModule + "_placement"
|
||||
// AssignmentsBucket is the assigner's state assignments, which the toolchain gate reads for the placing of a build module.
|
||||
AssignerModule = "mesh-delivery-assigner"
|
||||
AssignmentsBucket = AssignerModule + "_assignments"
|
||||
)
|
||||
|
||||
// StepsBucket is the bucket of a build module's state steps.
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
"github.com/nats-io/nats.go/jetstream"
|
||||
|
||||
"git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient"
|
||||
"git.novox.be/novox/mesh-contracts/go/clients/meshmoduleassignerclient"
|
||||
"git.novox.be/novox/mesh-delivery/sdk/buildstep"
|
||||
"git.novox.be/novox/mesh-sdk/go/process"
|
||||
)
|
||||
@@ -23,12 +23,12 @@ import (
|
||||
// ace.typescript at v26.12.0, and every Node fingerprint said "builders disagree").
|
||||
//
|
||||
// ToolchainGate stands between the toolchains buckets and what takes their entries in (the indexer's PutToolchain, a
|
||||
// ToolchainSet): an entry is passed on only while the placement (the seat mesh-placement's state `placement`, held by
|
||||
// the assigner, PlacementBucket, read by meshmoduleassignerclient.Placed; ADR 0567, ADR 0549 §3) places its build module on
|
||||
// its node, and only once it was written since that placement; it is passed on as deleted otherwise, said once, and
|
||||
// passed on when its node writes it again. A report written before the placement is one an earlier run of the module
|
||||
// ToolchainSet): an entry is passed on only while the assignments (the seat mesh-module-assigner's state `assignments`, held by
|
||||
// the assigner, AssignmentsBucket, read by meshmoduleassignerclient.Placed; ADR 0567, ADR 0549 §3) places its build module on
|
||||
// its node, and only once it was written since that assignments; it is passed on as deleted otherwise, said once, and
|
||||
// passed on when its node writes it again. A report written before the assignments is one an earlier run of the module
|
||||
// left (issue 1940, 2026-10-25 20:56: mesh-build-node put on ace again brought ace.typescript v26.12.0 of 2026-10-23
|
||||
// back into the agreement before the module ran there). Until the placement is settled, and while no node's placement
|
||||
// back into the agreement before the module ran there). Until the assignments is settled, and while no node's assignments
|
||||
// is held (before the assigner's adopt writes the first one, or where the state cannot be read), every entry is passed
|
||||
// on. Builders that run and report different versions still disagree: that refusal is the guard of novox/hq ADR 0465,
|
||||
// and it stays.
|
||||
@@ -41,11 +41,11 @@ type ToolchainGate struct {
|
||||
forward func(module, key string, value []byte, deleted bool) bool // answers whether it changed what it holds
|
||||
logf func(format string, a ...any)
|
||||
placed *meshmoduleassignerclient.Placed
|
||||
known bool // the placement is settled
|
||||
known bool // the assignments is settled
|
||||
raw map[string]map[string][]byte // module -> toolchains key -> value, as the bucket holds it
|
||||
left map[string]string // <module>/<key> -> why it was said left out, so each reason is said once
|
||||
// OnPlaced is told, outside the gate's lock, once the placement's history is read and after each revision of it
|
||||
// FollowPlacement hears from then on (the counted nodes, Nodes, may have changed). Nil tells nobody.
|
||||
// OnPlaced is told, outside the gate's lock, once the assignments's history is read and after each revision of it
|
||||
// FollowAssignments hears from then on (the counted nodes, Nodes, may have changed). Nil tells nobody.
|
||||
OnPlaced func()
|
||||
}
|
||||
|
||||
@@ -75,28 +75,28 @@ func (g *ToolchainGate) Toolchain(module, key string, value []byte, deleted bool
|
||||
return g.pass(module, key)
|
||||
}
|
||||
|
||||
// Placement takes one revision of the seat mesh-placement's placement in (at is when the bus wrote it) and answers whether what it
|
||||
// Assignments takes one revision of the seat mesh-module-assigner's assignments in (at is when the bus wrote it) and answers whether what it
|
||||
// passed on changed. A value that does not read is said, and places nothing on its node.
|
||||
func (g *ToolchainGate) Placement(key string, value []byte, deleted bool, at time.Time) bool {
|
||||
func (g *ToolchainGate) Assignments(key string, value []byte, deleted bool, at time.Time) bool {
|
||||
g.mu.Lock()
|
||||
defer g.mu.Unlock()
|
||||
was := g.placed.Seeded()
|
||||
node, changed, err := g.placed.Put(key, value, deleted, at)
|
||||
if err != nil {
|
||||
g.logf("%s: %v (issue 1940)", PlacementBucket, err)
|
||||
g.logf("%s: %v (issue 1940)", AssignmentsBucket, err)
|
||||
}
|
||||
if !g.known {
|
||||
return false
|
||||
}
|
||||
if was != g.placed.Seeded() {
|
||||
// The first placement came, or the last went: every report's standing changed.
|
||||
// The first assignments came, or the last went: every report's standing changed.
|
||||
return g.all()
|
||||
}
|
||||
return g.again(node, changed)
|
||||
}
|
||||
|
||||
// Nodes are the nodes the placement places any module on, sorted: the nodes the mesh counts (a node leaves the count
|
||||
// when the placement no longer names it; ADR 0624 §1). None until the placement is read.
|
||||
// Nodes are the nodes the assignments places any module on, sorted: the nodes the mesh counts (a node leaves the count
|
||||
// when the assignments no longer names it; ADR 0624 §1). None until the assignments is read.
|
||||
func (g *ToolchainGate) Nodes() []string {
|
||||
var out []string
|
||||
for node, modules := range g.placed.ByNode() {
|
||||
@@ -108,8 +108,8 @@ func (g *ToolchainGate) Nodes() []string {
|
||||
return out
|
||||
}
|
||||
|
||||
// Settled says the placement's history is read: from now on only the reports of placed nodes pass, once a node's
|
||||
// placement is held. It answers whether what it passed on changed.
|
||||
// Settled says the assignments's history is read: from now on only the reports of placed nodes pass, once a node's
|
||||
// assignments is held. It answers whether what it passed on changed.
|
||||
func (g *ToolchainGate) Settled() bool {
|
||||
g.mu.Lock()
|
||||
defer g.mu.Unlock()
|
||||
@@ -144,7 +144,7 @@ func (g *ToolchainGate) again(node string, modules []string) bool {
|
||||
return changed
|
||||
}
|
||||
|
||||
// pass hands one key on as it stands: its value when its node is placed and wrote it since (or the placement is not
|
||||
// pass hands one key on as it stands: its value when its node is placed and wrote it since (or the assignments is not
|
||||
// known), deleted otherwise. The caller holds mu.
|
||||
func (g *ToolchainGate) pass(module, key string) bool {
|
||||
value, held := g.raw[module][key]
|
||||
@@ -183,24 +183,24 @@ func (g *ToolchainGate) leftOut(module, node string, value []byte) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// FollowPlacement reads the seat mesh-placement's placement with its history into gate, says it settled, and follows it; changed
|
||||
// FollowAssignments reads the seat mesh-module-assigner's assignments with its history into gate, says it settled, and follows it; changed
|
||||
// is told whenever what the gate passes on changed. Where the state cannot be read or watched (not there, or this part
|
||||
// may not read it) it says so and the gate passes every report on: not fatal, since an indexer, builder or checker that
|
||||
// stops for it stops every delivery (issue 1945). An error of the watch after that ends on the channel.
|
||||
func FollowPlacement(ctx context.Context, js process.BucketOpener, gate *ToolchainGate, changed func(context.Context), logf func(string, ...any)) (<-chan error, error) {
|
||||
func FollowAssignments(ctx context.Context, js process.BucketOpener, gate *ToolchainGate, changed func(context.Context), logf func(string, ...any)) (<-chan error, error) {
|
||||
errs := make(chan error, 1)
|
||||
kv, err := js.KeyValue(ctx, PlacementBucket)
|
||||
kv, err := js.KeyValue(ctx, AssignmentsBucket)
|
||||
if err != nil {
|
||||
logf("the state %s cannot be read, so every node's toolchain report counts, a build node's the catalogue does not place too (issue 1940): %v", PlacementBucket, err)
|
||||
logf("the state %s cannot be read, so every node's toolchain report counts, a build node's the catalogue does not place too (issue 1940): %v", AssignmentsBucket, err)
|
||||
return errs, nil
|
||||
}
|
||||
w, err := kv.WatchAll(ctx, jetstream.IncludeHistory())
|
||||
if err != nil {
|
||||
logf("the state %s cannot be watched, so every node's toolchain report counts, a build node's the catalogue does not place too (issue 1940): %v", PlacementBucket, err)
|
||||
logf("the state %s cannot be watched, so every node's toolchain report counts, a build node's the catalogue does not place too (issue 1940): %v", AssignmentsBucket, err)
|
||||
return errs, nil
|
||||
}
|
||||
put := func(e jetstream.KeyValueEntry) bool {
|
||||
return gate.Placement(e.Key(), e.Value(), e.Operation() != jetstream.KeyValuePut, e.Created())
|
||||
return gate.Assignments(e.Key(), e.Value(), e.Operation() != jetstream.KeyValuePut, e.Created())
|
||||
}
|
||||
for settled := false; !settled; {
|
||||
select {
|
||||
@@ -209,7 +209,7 @@ func FollowPlacement(ctx context.Context, js process.BucketOpener, gate *Toolcha
|
||||
return errs, ctx.Err()
|
||||
case e, ok := <-w.Updates():
|
||||
if !ok {
|
||||
return errs, errors.New("the watch of " + PlacementBucket + " ended before it settled")
|
||||
return errs, errors.New("the watch of " + AssignmentsBucket + " ended before it settled")
|
||||
}
|
||||
if e == nil {
|
||||
settled = true
|
||||
@@ -233,7 +233,7 @@ func FollowPlacement(ctx context.Context, js process.BucketOpener, gate *Toolcha
|
||||
return
|
||||
case e, ok := <-w.Updates():
|
||||
if !ok {
|
||||
errs <- errors.New("the watch of " + PlacementBucket + " ended")
|
||||
errs <- errors.New("the watch of " + AssignmentsBucket + " ended")
|
||||
return
|
||||
}
|
||||
if e != nil && put(e) {
|
||||
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
|
||||
"github.com/nats-io/nats.go/jetstream"
|
||||
|
||||
"git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient"
|
||||
"git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner"
|
||||
"git.novox.be/novox/mesh-contracts/go/clients/meshmoduleassignerclient"
|
||||
"git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner"
|
||||
"git.novox.be/novox/mesh-delivery/sdk/buildstep"
|
||||
)
|
||||
|
||||
@@ -27,14 +27,14 @@ func gateReport(t *testing.T, node, version string, at time.Time) (string, []byt
|
||||
return key, value
|
||||
}
|
||||
|
||||
// placing is a value of the state `placement` placing modules on node.
|
||||
// placing is a value of the state `assignments` placing modules on node.
|
||||
func placing(t *testing.T, node string, modules ...string) (string, []byte) {
|
||||
t.Helper()
|
||||
p := meshmoduleassigner.Placement{Node: node}
|
||||
p := meshmoduleassigner.Assignments{Node: node}
|
||||
for _, m := range modules {
|
||||
p.Modules = append(p.Modules, meshmoduleassigner.PlacedModule{Module: m})
|
||||
}
|
||||
values, err := meshmoduleassignerclient.PlacementValues(p)
|
||||
values, err := meshmoduleassignerclient.AssignmentsValues(p)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -42,29 +42,14 @@ func placing(t *testing.T, node string, modules ...string) (string, []byte) {
|
||||
return key, values[key]
|
||||
}
|
||||
|
||||
// placingLegacy is placing in the form before, `placement.<node>` (research 072 row 37).
|
||||
func placingLegacy(t *testing.T, node string, modules ...string) (string, []byte) {
|
||||
t.Helper()
|
||||
p := meshmoduleassigner.Placement{Node: node}
|
||||
for _, m := range modules {
|
||||
p.Modules = append(p.Modules, meshmoduleassigner.PlacedModule{Module: m})
|
||||
}
|
||||
key, _ := meshmoduleassignerclient.LegacyKey(node)
|
||||
value, err := meshmoduleassignerclient.EncodePlacement(p)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return key, value
|
||||
}
|
||||
|
||||
func agreedOf(set *ToolchainSet) (string, string) {
|
||||
tc, none := buildstep.AgreedToolchain(set.Entries("typescript"))
|
||||
return tc.Version, none
|
||||
}
|
||||
|
||||
// Issue 1940, the gate over the catalogue's placement (issue 774, ADR 0549 §3): a build node's report counts only while
|
||||
// the placement places its build module on its node, and only once written since; before the placement is settled, and
|
||||
// while no node's placement is held, every report counts. The live cases: mesh-build-node taken off ace left
|
||||
// Issue 1940, the gate over the catalogue's assignments (issue 774, ADR 0549 §3): a build node's report counts only while
|
||||
// the assignments places its build module on its node, and only once written since; before the assignments is settled, and
|
||||
// while no node's assignments is held, every report counts. The live cases: mesh-build-node taken off ace left
|
||||
// ace.typescript at v26.12.0 against v26.12.1 on the three others; put on ace again, its report of 2026-10-23 06:29 came
|
||||
// back before the module ran there.
|
||||
func TestToolchainGate(t *testing.T) {
|
||||
@@ -78,7 +63,7 @@ func TestToolchainGate(t *testing.T) {
|
||||
for _, node := range three {
|
||||
if seeded {
|
||||
key, value := placing(t, node, NodeBuildModule)
|
||||
gate.Placement(key, value, false, old.Add(-time.Hour))
|
||||
gate.Assignments(key, value, false, old.Add(-time.Hour))
|
||||
}
|
||||
key, value := gateReport(t, node, "v26.12.1", placed.Add(time.Minute))
|
||||
gate.Toolchain(NodeBuildModule, key, value, false)
|
||||
@@ -91,10 +76,10 @@ func TestToolchainGate(t *testing.T) {
|
||||
key, value := gateReport(t, "ace", "v26.12.0", old)
|
||||
gate.Toolchain(NodeBuildModule, key, value, false)
|
||||
if a := buildstep.ToolchainAgreement(set.Entries("typescript")); len(a.SittingOut) != 1 || a.SittingOut[0].Node != "ace" { // ADR 0584: the majority is agreed, ace's report counts as the one that sits out
|
||||
t.Fatalf("before the placement is settled every report counts; got %+v", a)
|
||||
t.Fatalf("before the assignments is settled every report counts; got %+v", a)
|
||||
}
|
||||
k, v := placing(t, "ace", GoBuildModule) // another build module on ace: no matter
|
||||
gate.Placement(k, v, false, old)
|
||||
gate.Assignments(k, v, false, old)
|
||||
if !gate.Settled() {
|
||||
t.Fatal("settling left ace's report out, so what was passed on changed")
|
||||
}
|
||||
@@ -109,13 +94,13 @@ func TestToolchainGate(t *testing.T) {
|
||||
}
|
||||
// Placed on ace with a report written since: it counts, and the builders really disagree.
|
||||
k, v = placing(t, "ace", GoBuildModule, NodeBuildModule)
|
||||
gate.Placement(k, v, false, old.Add(-time.Minute))
|
||||
gate.Assignments(k, v, false, old.Add(-time.Minute))
|
||||
if a := buildstep.ToolchainAgreement(set.Entries("typescript")); a.Toolchain.Version != "v26.12.1" || len(a.SittingOut) != 1 || a.SittingOut[0].Version != "v26.12.0" {
|
||||
t.Fatalf("builders that run different versions: the majority is agreed and ace sits out; got %+v", a)
|
||||
}
|
||||
// Taken off ace again (its key deleted): its report goes again.
|
||||
if !gate.Placement(k, nil, true, placed) {
|
||||
t.Fatal("taking ace's placement away passed nothing on")
|
||||
if !gate.Assignments(k, nil, true, placed) {
|
||||
t.Fatal("taking ace's assignments away passed nothing on")
|
||||
}
|
||||
if v, none := agreedOf(set); v != "v26.12.1" || none != "" {
|
||||
t.Fatalf("got %q, %q", v, none)
|
||||
@@ -132,26 +117,26 @@ func TestToolchainGate(t *testing.T) {
|
||||
at time.Time // when ace wrote its report
|
||||
counts bool
|
||||
}{
|
||||
{"a report left before the placement", old, false},
|
||||
{"a report written since the placement", placed.Add(30 * time.Second), true},
|
||||
{"a report left before the assignments", old, false},
|
||||
{"a report written since the assignments", placed.Add(30 * time.Second), true},
|
||||
} {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
gate, set, said := start(t, true)
|
||||
k, v := placing(t, "ace") // ace's key, first heard placing nothing
|
||||
gate.Placement(k, v, false, old.Add(-time.Hour))
|
||||
gate.Assignments(k, v, false, old.Add(-time.Hour))
|
||||
gate.Settled()
|
||||
k, v = placing(t, "ace", NodeBuildModule)
|
||||
if gate.Placement(k, v, false, placed) {
|
||||
t.Fatal("a placement with no report passed something on")
|
||||
if gate.Assignments(k, v, false, placed) {
|
||||
t.Fatal("assignments with no report passed something on")
|
||||
}
|
||||
key, value := gateReport(t, "ace", "v26.12.0", c.at)
|
||||
if got := gate.Toolchain(NodeBuildModule, key, value, false); got != c.counts {
|
||||
t.Fatalf("ace's report passed on: %v, want %v", got, c.counts)
|
||||
}
|
||||
// ace's placement written again with another module beside: its standing does not move, nothing is said again.
|
||||
// ace's assignments written again with another module beside: its standing does not move, nothing is said again.
|
||||
k, v = placing(t, "ace", GoBuildModule, NodeBuildModule)
|
||||
if gate.Placement(k, v, false, placed.Add(time.Minute)) {
|
||||
t.Fatal("the same placement of mesh-build-node changed what was passed on")
|
||||
if gate.Assignments(k, v, false, placed.Add(time.Minute)) {
|
||||
t.Fatal("the same assignments of mesh-build-node changed what was passed on")
|
||||
}
|
||||
if c.counts {
|
||||
return
|
||||
@@ -169,47 +154,38 @@ func TestToolchainGate(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("no placement held: every report counts", func(t *testing.T) {
|
||||
t.Run("no assignments held: every report counts", func(t *testing.T) {
|
||||
gate, set, _ := start(t, false)
|
||||
key, value := gateReport(t, "ace", "v26.12.0", old)
|
||||
gate.Toolchain(NodeBuildModule, key, value, false)
|
||||
gate.Settled()
|
||||
if n := len(set.Entries("typescript")); n != 4 {
|
||||
t.Fatalf("before the first placement file every report counts; got %d", n)
|
||||
t.Fatalf("before the first assignments file every report counts; got %d", n)
|
||||
}
|
||||
k, v := placing(t, "g14", NodeBuildModule)
|
||||
if !gate.Placement(k, v, false, old.Add(-time.Hour)) || len(set.Entries("typescript")) != 1 {
|
||||
t.Fatalf("the first placement leaves every node it does not place out; got %d", len(set.Entries("typescript")))
|
||||
if !gate.Assignments(k, v, false, old.Add(-time.Hour)) || len(set.Entries("typescript")) != 1 {
|
||||
t.Fatalf("the first assignments leaves every node it does not place out; got %d", len(set.Entries("typescript")))
|
||||
}
|
||||
if !gate.Placement(k, nil, true, placed) || len(set.Entries("typescript")) != 4 {
|
||||
t.Fatal("the last placement gone: every report counts again")
|
||||
if !gate.Assignments(k, nil, true, placed) || len(set.Entries("typescript")) != 4 {
|
||||
t.Fatal("the last assignments gone: every report counts again")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("the history: a module in the first revision heard of a key stands since before it", func(t *testing.T) {
|
||||
p := meshmoduleassignerclient.NewPlaced()
|
||||
// ace in the form before, then converted: its module stands since before, the legacy key read no more.
|
||||
k, v := placingLegacy(t, "ace", NodeBuildModule)
|
||||
// ace's node key is the first revision heard of it: its module stands since before.
|
||||
k, v := placing(t, "ace", NodeBuildModule)
|
||||
p.Put(k, v, false, old)
|
||||
k, v = placing(t, "ace", NodeBuildModule)
|
||||
if _, changed, err := p.Put(k, v, false, placed); len(changed) != 0 || err != nil {
|
||||
t.Errorf("the conversion of ace's key changed %v, %v", changed, err)
|
||||
}
|
||||
if _, changed, _ := p.Put("ace."+NodeBuildModule, []byte("{}"), false, placed); len(changed) != 0 {
|
||||
t.Errorf("a module key says which modules stand: %v", changed)
|
||||
}
|
||||
if k, v := placingLegacy(t, "ace"); true {
|
||||
if _, changed, _ := p.Put(k, v, false, placed); len(changed) != 0 {
|
||||
t.Errorf("the legacy key is read after the node key: %v", changed)
|
||||
}
|
||||
}
|
||||
k2, v2 := placing(t, "g14")
|
||||
p.Put(k2, v2, false, old)
|
||||
k2, v2 = placing(t, "g14", NodeBuildModule)
|
||||
if _, changed, _ := p.Put(k2, v2, false, placed); strings.Join(changed, ",") != NodeBuildModule {
|
||||
t.Errorf("a module placed says changed %v", changed)
|
||||
}
|
||||
if _, _, err := p.Put("placement.novox", []byte("not json"), false, old); err == nil {
|
||||
if _, _, err := p.Put("novox.node", []byte("not json"), false, old); err == nil {
|
||||
t.Error("a value that does not read was not said")
|
||||
}
|
||||
if s, ok := p.Since("ace", NodeBuildModule); !ok || !s.IsZero() {
|
||||
@@ -223,14 +199,14 @@ func TestToolchainGate(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("a placement the bus refuses is said, and the part goes on", func(t *testing.T) {
|
||||
t.Run("assignments the bus refuses is said, and the part goes on", func(t *testing.T) {
|
||||
var logs bytes.Buffer
|
||||
logger := log.New(&logs, "", 0)
|
||||
refused := errors.New("nats: permissions violation for publish to $JS.API.CONSUMER.CREATE.KV_mesh-delivery-assigner_placement")
|
||||
refused := errors.New("nats: permissions violation for publish to $JS.API.CONSUMER.CREATE.KV_mesh-delivery-assigner_assignments")
|
||||
gate, _, _ := start(t, false)
|
||||
for _, bus := range []refusingBus{{err: refused}, {refuseOpen: true, err: refused}} {
|
||||
if _, err := FollowPlacement(context.Background(), bus, gate, func(context.Context) {}, logger.Printf); err != nil {
|
||||
t.Errorf("a refused placement stopped the start: %v", err)
|
||||
if _, err := FollowAssignments(context.Background(), bus, gate, func(context.Context) {}, logger.Printf); err != nil {
|
||||
t.Errorf("a refused assignments stopped the start: %v", err)
|
||||
}
|
||||
}
|
||||
if !strings.Contains(logs.String(), "cannot be watched") || !strings.Contains(logs.String(), "cannot be read") {
|
||||
|
||||
@@ -303,7 +303,7 @@ func startBedWith(t *testing.T, closed bool) *bed {
|
||||
viewstest.Serve(t, ctx, js, ctl, indexerModule, st, indexerModule+".indexer_read_"+st, readers...)
|
||||
}
|
||||
b.packages = viewstest.Serve(t, ctx, js, ctl, indexerModule, meshcatalog.StatePackages, indexerModule+".indexer_read_packages", readers...)
|
||||
viewstest.Serve(t, ctx, js, ctl, assignerModule, "placement", assignerModule+".assigner_read_placement", readers...)
|
||||
viewstest.Serve(t, ctx, js, ctl, assignerModule, "assignments", assignerModule+".assigner_read_assignments", readers...)
|
||||
b.builds = mk(builds.BuilderBuildsBucket, builds.BuilderBuildsHistory)
|
||||
b.instances = mk(instancesBucket, 1)
|
||||
// The tag asks and their bounds (design 51 *Tagged versions*): the bounds declared key-ttl, so an ended bound leaves the
|
||||
|
||||
@@ -72,7 +72,7 @@ func run(ctx context.Context, getenv func(string) string, logOut io.Writer) erro
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// The indexer's modules, manifests, candidates and packages and the assigner's placement are their owners' states, read by the
|
||||
// The indexer's modules, manifests, candidates and packages and the assigner's assignments are their owners' states, read by the
|
||||
// first view of their read tools and then their views families, never their buckets (ADR 0615 §1, DLV-M1). An owner that
|
||||
// is down never holds the start: each is read on a goroutine once its first view is answered, and until then the
|
||||
// unanswered first view is the builder's finding.
|
||||
@@ -105,7 +105,7 @@ func run(ctx context.Context, getenv func(string) string, logOut io.Writer) erro
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
placement, err := reader.Follow(assignerModule, "placement", assignerModule+".assigner_read_placement")
|
||||
assignments, err := reader.Follow(assignerModule, "assignments", assignerModule+".assigner_read_assignments")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -258,11 +258,11 @@ func run(ctx context.Context, getenv func(string) string, logOut io.Writer) erro
|
||||
// The toolchains first, so a build that starts from the first modules value finds the nodes.
|
||||
watch := newToolchainWatch(ctx, js, tools, b.NodesChanged, logger)
|
||||
// Only the toolchain reports of nodes the catalogue places the build module on count (issue 1940, ADR 0549 §3): the
|
||||
// placement is settled first, so the toolchains settle through the gate already knowing it.
|
||||
// assignments is settled first, so the toolchains settle through the gate already knowing it.
|
||||
gate := buildrun.NewToolchainGate([]string{buildrun.GoBuildModule, buildrun.NodeBuildModule}, tools.Put, logger.Printf)
|
||||
watch.put = gate.Toolchain
|
||||
// What each counted node's engine reads (ADR 0618 §2, ADR 0624 §1): asked through the node-engine seat's verb as the
|
||||
// builder's own account, for every node the placement names, and kept in the state engine-reads once it is bound.
|
||||
// builder's own account, for every node the assignments names, and kept in the state engine-reads once it is bound.
|
||||
reads := newEngineReads(calls.CallOn, gate, logger.Printf)
|
||||
// The old reference form's window over them (DLV-B9), kept in the state old-form once it is bound; builder_old_form
|
||||
// reads it and drops a retired node by hand.
|
||||
@@ -288,20 +288,20 @@ func run(ctx context.Context, getenv func(string) string, logOut io.Writer) erro
|
||||
})
|
||||
gate.OnPlaced = reads.placed
|
||||
b.Forms = reads.built
|
||||
// Until the placement's first view is answered the gate passes every report on, as before the placement is settled.
|
||||
placementErrs := make(chan error, 1)
|
||||
// Until the assignments's first view is answered the gate passes every report on, as before the assignments is settled.
|
||||
assignmentsErrs := make(chan error, 1)
|
||||
go func() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-placement.Follower().Ready():
|
||||
case <-assignments.Follower().Ready():
|
||||
}
|
||||
pe, err := buildrun.FollowPlacement(ctx, reader, gate, b.NodesChanged, logger.Printf)
|
||||
pe, err := buildrun.FollowAssignments(ctx, reader, gate, b.NodesChanged, logger.Printf)
|
||||
if err != nil {
|
||||
placementErrs <- err
|
||||
assignmentsErrs <- err
|
||||
return
|
||||
}
|
||||
placementErrs <- <-pe
|
||||
assignmentsErrs <- <-pe
|
||||
}()
|
||||
if err := watch.start(); err != nil {
|
||||
return err
|
||||
@@ -456,7 +456,7 @@ func run(ctx context.Context, getenv func(string) string, logOut io.Writer) erro
|
||||
return nil
|
||||
case err := <-errs:
|
||||
return err
|
||||
case err := <-placementErrs:
|
||||
case err := <-assignmentsErrs:
|
||||
return err
|
||||
case err := <-watch.errs:
|
||||
return err
|
||||
|
||||
@@ -16,7 +16,7 @@ const (
|
||||
|
||||
// indexerModule is the holder of the states modules, manifests, candidates and packages the builder follows.
|
||||
indexerModule = "mesh-delivery-indexer"
|
||||
// assignerModule is the holder of the state placement.
|
||||
// assignerModule is the holder of the state assignments.
|
||||
assignerModule = buildrun.AssignerModule
|
||||
|
||||
// sourceBucket is the gate's state source (reads: mesh-delivery-gate.source), the heads a candidate's base names.
|
||||
|
||||
@@ -33,7 +33,7 @@ func TestTheNamesAreTheManifests(t *testing.T) {
|
||||
}
|
||||
}
|
||||
for _, view := range []string{indexerModule + ".views.modules", indexerModule + ".views.manifests", indexerModule + ".views.candidates",
|
||||
indexerModule + ".views.packages", assignerModule + ".views.placement"} {
|
||||
indexerModule + ".views.packages", assignerModule + ".views.assignments"} {
|
||||
if !slices.Contains(m.Consumes, view) {
|
||||
t.Errorf("the builder follows %s, its manifest consumes %v", view, m.Consumes)
|
||||
}
|
||||
@@ -41,7 +41,7 @@ func TestTheNamesAreTheManifests(t *testing.T) {
|
||||
for want, got := range map[string]string{
|
||||
"mesh-delivery-gate_source": sourceBucket, "mesh-build-go_steps": buildrun.StepsBucket("mesh-build-go"),
|
||||
"mesh-build-node_toolchains": buildrun.ToolchainsBucket("mesh-build-node"), "mesh-delivery-indexer_packages": packagesBucket,
|
||||
"mesh-delivery-assigner_placement": buildrun.PlacementBucket,
|
||||
"mesh-delivery-assigner_assignments": buildrun.AssignmentsBucket,
|
||||
} {
|
||||
if want != got {
|
||||
t.Errorf("a bucket is %q, want %q", got, want)
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
)
|
||||
|
||||
// oldForm keeps the old reference form's window (design 51 *Every build keeps the old reference form*, DLV-B9) in the
|
||||
// state old-form: stepped on every change of what the counted nodes state, of the placement, on a hand drop and at each
|
||||
// state old-form: stepped on every change of what the counted nodes state, of the assignments, on a hand drop and at each
|
||||
// build key written, never on a timer. A node holding it seven days is the finding old-form-held; its close is said once
|
||||
// as version.old-form-closed and in the builder's log.
|
||||
type oldForm struct {
|
||||
@@ -84,7 +84,7 @@ func (o *oldForm) dropped() map[string]bool {
|
||||
}
|
||||
|
||||
// step moves the window to what counted states.
|
||||
// named is every node the read named (the placement's nodes before any is dropped), counted the statements of those
|
||||
// named is every node the read named (the assignments's nodes before any is dropped), counted the statements of those
|
||||
// still counted: a read naming no node judges nothing (window.StepWindow), so it never closes the window.
|
||||
func (o *oldForm) step(ctx context.Context, named []string, counted map[string][]string) {
|
||||
o.mu.Lock()
|
||||
@@ -106,7 +106,7 @@ func (o *oldForm) step(ctx context.Context, named []string, counted map[string][
|
||||
n, next.Since[n].Format(time.RFC3339)),
|
||||
headline: "A node holds the old reference form",
|
||||
explanation: "The builder writes an older reference form into every build key while a counted node's engine reads none of the newest (ADR 0624 §1); this node has held it seven days.",
|
||||
resolved: "The node's engine states the newest form, the node leaves the placement, or it is dropped as retired.",
|
||||
resolved: "The node's engine states the newest form, the node leaves the assignments, or it is dropped as retired.",
|
||||
needs: "builder_old_form shows the window; a retired node is dropped there by hand; builder_engine_reads asks the node again."})
|
||||
}
|
||||
o.overdue = overdue
|
||||
|
||||
@@ -10,14 +10,14 @@ import (
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds"
|
||||
"git.novox.be/novox/mesh-sdk/go/process"
|
||||
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/buildrun"
|
||||
"git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient/enginereads"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/buildrun"
|
||||
)
|
||||
|
||||
// EngineReadsState is the builder's state of what each counted node's engine states it reads (novox/hq ADR 0618 §2, ADR
|
||||
// 0624 §1): one key `<node>`, written from the node-engine seat's verb manifest-reads at the builder's start, on the
|
||||
// seat's event manifest-reads-changed for that node, and when a person asks again (builder_engine_reads); a node that
|
||||
// is away keeps its last statement, and its key is removed when the placement no longer names the node. A counted node
|
||||
// is away keeps its last statement, and its key is removed when the assignments no longer names the node. A counted node
|
||||
// with no key reads as stating the baseline: its first forms. No node's record is read in its place.
|
||||
const EngineReadsState = "engine-reads"
|
||||
|
||||
@@ -43,7 +43,7 @@ func newEngineReads(call enginereads.Caller, gate *buildrun.ToolchainGate, logf
|
||||
}
|
||||
|
||||
// stepWindow moves the old form's window to what the counted nodes state now (design 51 *Every build keeps the old
|
||||
// reference form*): on a statement's change, the placement's and a hand drop, and at each build key written.
|
||||
// reference form*): on a statement's change, the assignments's and a hand drop, and at each build key written.
|
||||
func (r *engineReads) stepWindow() {
|
||||
if r.window == nil {
|
||||
return
|
||||
@@ -56,7 +56,7 @@ func (r *engineReads) stepWindow() {
|
||||
r.window.step(ctx, r.named(), counted)
|
||||
}
|
||||
|
||||
// named are the nodes the placement names, none dropped: what the window's step judges a read by.
|
||||
// named are the nodes the assignments names, none dropped: what the window's step judges a read by.
|
||||
func (r *engineReads) named() []string {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
@@ -86,7 +86,7 @@ func (r *engineReads) bind(ctx context.Context, kv jetstream.KeyValue, errs chan
|
||||
}
|
||||
}
|
||||
|
||||
// placed takes the placement in: a node it names newly is asked, one it no longer names is forgotten, key and all. The
|
||||
// placed takes the assignments in: a node it names newly is asked, one it no longer names is forgotten, key and all. The
|
||||
// first call asks every counted node (the builder's start).
|
||||
func (r *engineReads) placed() {
|
||||
nodes := r.gate.Nodes()
|
||||
@@ -96,7 +96,7 @@ func (r *engineReads) placed() {
|
||||
r.mu.Unlock()
|
||||
for _, node := range nodes {
|
||||
if first || !slices.Contains(before, node) {
|
||||
r.keeper.AskNode(node, "counted: the placement names it")
|
||||
r.keeper.AskNode(node, "counted: the assignments names it")
|
||||
}
|
||||
}
|
||||
for _, node := range before {
|
||||
|
||||
@@ -20,15 +20,15 @@ import (
|
||||
"github.com/nats-io/nats.go"
|
||||
"github.com/nats-io/nats.go/jetstream"
|
||||
|
||||
"git.novox.be/novox/mesh-contracts/go/clients/meshmoduleassignerclient"
|
||||
"git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient/enginereads"
|
||||
"git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner"
|
||||
"git.novox.be/novox/mesh-contracts/go/seats/nodeengine"
|
||||
"git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient"
|
||||
"git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner"
|
||||
sweep "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshartifactsweep"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/buildrun"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds/forms"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-forge-bridge/forgemsg"
|
||||
"git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient/enginereads"
|
||||
|
||||
"mesh-delivery-builder/internal/build"
|
||||
"mesh-delivery-builder/internal/versions"
|
||||
@@ -36,7 +36,7 @@ import (
|
||||
|
||||
// 1945 (a part exits at start for a bucket it works without): a bus that refuses every toolchains bucket leaves the
|
||||
// watch unstarted and the part running, said; a refused bucket it cannot work without is an error naming the bucket and
|
||||
// its grant. The gate over the seat's placement, and its refusal, are mesh-sdk's (buildrun.ToolchainGate,
|
||||
// its grant. The gate over the seat's assignments, and its refusal, are mesh-sdk's (buildrun.ToolchainGate,
|
||||
// issue 774).
|
||||
func TestARefusedBucketIsSaidAndThePartGoesOn(t *testing.T) {
|
||||
t.Run("a floor's wake is heard on the events consumer (design 51 The floor)", aFloorsWakeIsHeard)
|
||||
@@ -69,28 +69,28 @@ func TestARefusedBucketIsSaidAndThePartGoesOn(t *testing.T) {
|
||||
t.Run("ADR 0624: the counted nodes' engine reads", theCountedNodesEngineReads)
|
||||
}
|
||||
|
||||
// theCountedNodesEngineReads: the builder asks the node-engine seat's verb of every node the placement names; a node away
|
||||
// theCountedNodesEngineReads: the builder asks the node-engine seat's verb of every node the assignments names; a node away
|
||||
// and never asked has no statement and reads as the baseline's first forms, with no node record read in its place; an
|
||||
// away node keeps its last statement; a node the placement no longer names leaves the count, its key removed; and
|
||||
// away node keeps its last statement; a node the assignments no longer names leaves the count, its key removed; and
|
||||
// builder_engine_reads drops one node's key.
|
||||
func theCountedNodesEngineReads(t *testing.T) {
|
||||
gate := buildrun.NewToolchainGate(nil, func(string, string, []byte, bool) bool { return false }, t.Logf)
|
||||
place := func(nodes ...string) {
|
||||
for _, node := range []string{"n1", "n2"} {
|
||||
pl := meshmoduleassigner.Placement{Node: node}
|
||||
pl := meshmoduleassigner.Assignments{Node: node}
|
||||
if slices.Contains(nodes, node) {
|
||||
pl.Modules = []meshmoduleassigner.PlacedModule{{Module: "web"}}
|
||||
}
|
||||
values, err := meshmoduleassignerclient.PlacementValues(pl)
|
||||
values, err := meshmoduleassignerclient.AssignmentsValues(pl)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for key, raw := range values {
|
||||
gate.Placement(key, raw, false, time.Now())
|
||||
gate.Assignments(key, raw, false, time.Now())
|
||||
}
|
||||
if !slices.Contains(nodes, node) {
|
||||
key, _ := meshmoduleassignerclient.ModuleKey(node, "web")
|
||||
gate.Placement(key, nil, true, time.Now())
|
||||
gate.Assignments(key, nil, true, time.Now())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -125,7 +125,7 @@ func theCountedNodesEngineReads(t *testing.T) {
|
||||
if _, counted = r.forms(); !slices.Equal(counted["n2"], []string{"form:new"}) || r.keeper.Statements()["n2"].Answered {
|
||||
t.Errorf("away again, n2 reads %v (%+v)", counted["n2"], r.keeper.Statements()["n2"])
|
||||
}
|
||||
// n2 retired: it leaves the placement, and its key goes.
|
||||
// n2 retired: it leaves the assignments, and its key goes.
|
||||
place("n1")
|
||||
r.placed()
|
||||
if _, counted = r.forms(); len(counted) != 1 || kept["n2"] != nil {
|
||||
|
||||
@@ -10,8 +10,8 @@ require (
|
||||
git.novox.be/novox/mesh-delivery/contracts/go/seats/npmpackageregistry v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-delivery/contracts/go/seats/ociartifactregistry v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-contracts/go/clients/meshmoduleassignerclient v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-delivery/contracts/go/clients/meshdeliveryclient v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-delivery/contracts/go/seats/meshdelivery v0.0.0-00010101000000-000000000000
|
||||
|
||||
@@ -18,8 +18,8 @@ import (
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/buildrun"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds"
|
||||
sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds/forms"
|
||||
sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep"
|
||||
repotrunk "git.novox.be/novox/mesh-delivery/sdk/trunk"
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
|
||||
@@ -92,7 +92,7 @@ type Builder struct {
|
||||
// Tags answers a check's build's tag from the kept tag asks; nil numbers no check's build.
|
||||
Tags TagOf
|
||||
// Forms answers what each node's engine states it reads (ADR 0618 §2, ADR 0624 §1): present, the nodes whose engine
|
||||
// answered when last asked, and counted, every node the placement names, present or away, a node with no statement
|
||||
// answered when last asked, and counted, every node the assignments names, present or away, a node with no statement
|
||||
// stating nothing (the baseline's first forms). A done key names each artifact in the forms these keep, the oldest in
|
||||
// its single reference, and its needs. Nil: no node states anything, and the first forms are kept.
|
||||
Forms func() (present, counted map[string][]string)
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
// builder's state engine-reads; this is only the window over them: open while a counted node-engine, present or away,
|
||||
// reads of some artifact kind none of the newest form the builder knows for it, so an older form stays in new build keys
|
||||
// for it; closed, said once with `old-form-closed` and a log line, when none does. It moves on what moves a statement
|
||||
// (the node-engine seat's verb `manifest-reads` and its event `manifest-reads-changed`), the placement, a hand drop and
|
||||
// (the node-engine seat's verb `manifest-reads` and its event `manifest-reads-changed`), the assignments, a hand drop and
|
||||
// each build key written; never on a timer.
|
||||
|
||||
// OldFormState is the builder's state of the window: one key, OldFormKey, an OldFormWindow. builder_old_form reads it.
|
||||
@@ -94,7 +94,7 @@ const FindingAfter = 7 * 24 * time.Hour
|
||||
|
||||
// Step moves the window by mesh-sdk's one window rule (window.StepWindow): named is every counted node the read named,
|
||||
// those dropped by hand included, and holding those of them holding the window (Holding). A read naming no node (no
|
||||
// placement read yet, an empty node_haves) judges nothing, so it never closes the window. It answers the new window,
|
||||
// assignments read yet, an empty node_haves) judges nothing, so it never closes the window. It answers the new window,
|
||||
// whether it closed in this step (so the builder says `old-form-closed` and its log line once), and the nodes holding it
|
||||
// past FindingAfter (the finding, cleared for every other node).
|
||||
func (w OldFormWindow) Step(named, holding []string, now time.Time) (next OldFormWindow, closed bool, overdue []string) {
|
||||
@@ -146,7 +146,7 @@ const OldFormDescription = "The old reference form's window (design 51 *Every bu
|
||||
"the counted nodes, present or away, whose node-engine reads an older reference form alone and since when (a node holding it seven days " +
|
||||
"is the builder's finding " + OldFormHeld + "), when it last closed and who held it then, and the retired nodes dropped from the count by " +
|
||||
"hand. With drop (a node) and why, drops that retired node from the count by hand, a hand act the builder answers; a node still placed " +
|
||||
"leaves the count by itself only when the placement no longer names it. builder_engine_reads shows what each node's engine states."
|
||||
"leaves the count by itself only when the assignments no longer names it. builder_engine_reads shows what each node's engine states."
|
||||
|
||||
// AnswerOldForm is builder_old_form's read: the window as the state holds it.
|
||||
func AnswerOldForm(r Reader) (OldFormWindow, error) {
|
||||
|
||||
@@ -365,7 +365,7 @@ func TestTheBuildersVersions(t *testing.T) {
|
||||
t.Error("a drop with no why is taken")
|
||||
}
|
||||
// Security-upgrade F3 (review round 1), by mesh-sdk's window.StepWindow: a read naming no node (an empty
|
||||
// node_haves, the placement not read yet) never closes the window, and its holder's seven days still count.
|
||||
// node_haves, the assignments not read yet) never closes the window, and its holder's seven days still count.
|
||||
if held, shut, late := w.Step(nil, nil, t0.Add(FindingAfter+time.Minute)); shut || !held.Open || !reflect.DeepEqual(late, []string{"c"}) {
|
||||
t.Fatalf("a read naming no node: %+v closed=%v overdue %v, want the window open and c overdue", held, shut, late)
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ func TestManifestDeclarations(t *testing.T) { // 1607/AC1
|
||||
// 1887/A4c: the builder chooses no node, so it reads neither presence nor have, invokes no build module's tool and
|
||||
// holds no capacity; it puts asks on the three build seats and reads their steps (ADR 0525 §1, §4, §5).
|
||||
if want := []string{"mesh-build-go.steps", "mesh-build-go.toolchains", "mesh-build-image.steps", "mesh-build-node.steps", "mesh-build-node.toolchains",
|
||||
"mesh-delivery-assigner.placement", "mesh-delivery-gate.source"}; !reflect.DeepEqual(sorted(m.Reads), want) {
|
||||
"mesh-delivery-assigner.assignments", "mesh-delivery-gate.source"}; !reflect.DeepEqual(sorted(m.Reads), want) {
|
||||
t.Errorf("reads = %v, want %v", m.Reads, want)
|
||||
}
|
||||
if want := []string{"node-build-go", "node-build-image", "node-build-node"}; !reflect.DeepEqual(sorted(m.Uses), want) {
|
||||
@@ -111,18 +111,18 @@ func TestManifestDeclarations(t *testing.T) { // 1607/AC1
|
||||
// 1937/AC3: the builder asks the controller whether the artifact store still holds a done key's blobs (held), and no
|
||||
// other tool; it holds no capacity.
|
||||
// 1955/L7 (ADR 0571 §2): the seat mesh-artifact-sweep's held, the controller's `held` is no longer asked (issue 1955).
|
||||
// DLV-M1 (ADR 0615 §1): the indexer's modules, manifests and candidates and the assigner's placement are asked by their
|
||||
// DLV-M1 (ADR 0615 §1): the indexer's modules, manifests and candidates and the assigner's assignments are asked by their
|
||||
// read tools and followed by their views families, never read; so are the indexer's packages, whose names a package is
|
||||
// numbered under (design 32).
|
||||
for _, r := range m.Reads {
|
||||
// The toolchain gate follows the assigner's placement through meshmoduleassignerclient (buildrun.PlacementBucket), so
|
||||
// The toolchain gate follows the assigner's assignments through meshmoduleassignerclient (buildrun.AssignmentsBucket), so
|
||||
// it declares that one read, as the console and route-proxy do; everything else of theirs is asked by tools.
|
||||
if strings.HasPrefix(r, "mesh-delivery-indexer.") || (strings.HasPrefix(r, "mesh-delivery-assigner.") && r != "mesh-delivery-assigner.placement") {
|
||||
if strings.HasPrefix(r, "mesh-delivery-indexer.") || (strings.HasPrefix(r, "mesh-delivery-assigner.") && r != "mesh-delivery-assigner.assignments") {
|
||||
t.Errorf("reads %s: the indexer's and the assigner's state is read by their tools and views families alone", r)
|
||||
}
|
||||
}
|
||||
// Design 51 *The floor*: the floor's three sources, the registry seats' versions, bridge_tags and indexer_requirements.
|
||||
if want := []string{"mesh-delivery-assigner.assigner_read_placement", "mesh-delivery-forge-bridge.bridge_tags", "mesh-delivery-indexer.indexer_read_candidates", "mesh-delivery-indexer.indexer_read_manifests",
|
||||
if want := []string{"mesh-delivery-assigner.assigner_read_assignments", "mesh-delivery-forge-bridge.bridge_tags", "mesh-delivery-indexer.indexer_read_candidates", "mesh-delivery-indexer.indexer_read_manifests",
|
||||
"mesh-delivery-indexer.indexer_read_modules", "mesh-delivery-indexer.indexer_read_packages", "mesh-delivery-indexer.indexer_requirements", "seat:container-image-registry.remove", "seat:container-image-registry.versions",
|
||||
"seat:go-package-registry.remove", "seat:go-package-registry.versions", "seat:mesh-artifact-sweep.held", "seat:mesh-hand-acts.hand-act", "seat:node-engine.manifest-reads", "seat:npm-package-registry.remove",
|
||||
"seat:npm-package-registry.versions", "seat:oci-artifact-registry.remove", "seat:oci-artifact-registry.versions"}; !reflect.DeepEqual(sorted(m.Invokes), want) || len(m.Config) != 0 {
|
||||
@@ -137,7 +137,7 @@ func TestManifestDeclarations(t *testing.T) { // 1607/AC1
|
||||
if want := []string{"container-image-registry.kept", "container-image-registry.published", "container-image-registry.refused", "container-image-registry.removed",
|
||||
"go-package-registry.kept", "go-package-registry.published", "go-package-registry.refused", "go-package-registry.removed",
|
||||
"mesh-artifact-sweep.artifacts-gone", "mesh-build-go.toolchain.reported", "mesh-build-node.toolchain.reported", "mesh-catalog.manifest-accepted",
|
||||
"mesh-conditions.condition-cleared", "mesh-delivery-assigner.views.placement", "mesh-delivery-checker.tag-wanted", "mesh-delivery-forge-bridge.forge.**",
|
||||
"mesh-conditions.condition-cleared", "mesh-delivery-assigner.views.assignments", "mesh-delivery-checker.tag-wanted", "mesh-delivery-forge-bridge.forge.**",
|
||||
"mesh-delivery-indexer.views.candidates", "mesh-delivery-indexer.views.manifests", "mesh-delivery-indexer.views.modules",
|
||||
"mesh-delivery-indexer.views.packages", "node-engine.manifest-reads-changed",
|
||||
"npm-package-registry.kept", "npm-package-registry.published", "npm-package-registry.refused", "npm-package-registry.removed",
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
"oci-artifact-registry.published",
|
||||
"oci-artifact-registry.refused",
|
||||
"oci-artifact-registry.removed",
|
||||
"mesh-delivery-assigner.views.placement",
|
||||
"mesh-delivery-assigner.views.assignments",
|
||||
"mesh-delivery-indexer.views.candidates",
|
||||
"mesh-delivery-indexer.views.manifests",
|
||||
"mesh-delivery-indexer.views.modules",
|
||||
@@ -72,7 +72,7 @@
|
||||
"seat:npm-package-registry.versions",
|
||||
"seat:oci-artifact-registry.remove",
|
||||
"seat:oci-artifact-registry.versions",
|
||||
"mesh-delivery-assigner.assigner_read_placement",
|
||||
"mesh-delivery-assigner.assigner_read_assignments",
|
||||
"mesh-delivery-indexer.indexer_read_candidates",
|
||||
"mesh-delivery-indexer.indexer_read_manifests",
|
||||
"mesh-delivery-indexer.indexer_read_modules",
|
||||
@@ -103,7 +103,7 @@
|
||||
"mesh-build-image.steps",
|
||||
"mesh-build-node.steps",
|
||||
"mesh-build-node.toolchains",
|
||||
"mesh-delivery-assigner.placement",
|
||||
"mesh-delivery-assigner.assignments",
|
||||
"mesh-delivery-gate.source"
|
||||
],
|
||||
"uses": [
|
||||
|
||||
Reference in New Issue
Block a user