Write a node's own composition last, and not in a pass where a module's composition failed (issue 1945)
mesh/delivery merged: source.main moved to novox/mesh-controller@0fff3efd4e0b
mesh/check pass eafd1883f65c on 0fff3efd4e0b | unit 953 run, 171 kept, 2 skipped | integration 1612 run, 232 kept, 7 skipped | over bound: integration…
mesh/delivery merged: source.main moved to novox/mesh-controller@0fff3efd4e0b
mesh/check pass eafd1883f65c on 0fff3efd4e0b | unit 953 run, 171 kept, 2 skipped | integration 1612 run, 232 kept, 7 skipped | over bound: integration…
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
sdkdelivery "git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
)
|
||||
|
||||
// The node's own composition is written last, and not at all in a pass where a module's composition failed: written
|
||||
// without the resources that moved to that module, it would have the node-engine remove them while the module's own
|
||||
// composition is not there to take them (issue 1945, the review's gap 1).
|
||||
func TestTheNodesOwnIsWrittenLastAndNotAfterAModuleFailed(t *testing.T) {
|
||||
own, _ := sdkdelivery.ComposedNodeKey("ace")
|
||||
// "aaa" sorts before "ace.node"... and "zzz" after: the node's own must still come last.
|
||||
a, _ := sdkdelivery.ComposedKey("ace", "aaa", fp2For('a'))
|
||||
z, _ := sdkdelivery.ComposedKey("ace", "zzz", fp2For('b'))
|
||||
file := func(module string) json.RawMessage {
|
||||
return json.RawMessage(`{"id":"` + module + `.f","type":"file","module":"` + module + `","path":"/etc/` + module +
|
||||
`","mode":"0644","content":"x"}`)
|
||||
}
|
||||
comps := map[string]sdkdelivery.Composed{
|
||||
own: {Node: "ace", Resources: []json.RawMessage{}},
|
||||
a: {Node: "ace", Module: "aaa", FP: fp2For('a'), Resources: []json.RawMessage{file("aaa")}},
|
||||
z: {Node: "ace", Module: "zzz", FP: fp2For('b'), Resources: []json.RawMessage{file("zzz")}},
|
||||
}
|
||||
at, _, _, _ := aPlace(t, "ace")
|
||||
wrote, err := writeNodeCompositions(context.Background(), at, comps)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(wrote) != 3 || wrote[2] != own {
|
||||
t.Fatalf("written in the order %v, the node's own last", wrote)
|
||||
}
|
||||
|
||||
// A module's composition that cannot be written: the node's own is not written in that pass.
|
||||
at, _, _, _ = aPlace(t, "ace")
|
||||
broken := comps[z]
|
||||
broken.Resources = []json.RawMessage{file("other")} // a resource of another module: refused
|
||||
comps[z] = broken
|
||||
if _, err := writeNodeCompositions(context.Background(), at, comps); err == nil {
|
||||
t.Fatal("a composition that cannot be written was not said")
|
||||
}
|
||||
if _, rev, _ := readComposed(context.Background(), at.bucket, own); rev != 0 {
|
||||
t.Fatal("the node's own composition was written in a pass where a module's failed")
|
||||
}
|
||||
}
|
||||
|
||||
func fp2For(c byte) string {
|
||||
b := make([]byte, 64)
|
||||
for i := range b {
|
||||
b[i] = c
|
||||
}
|
||||
return sdkdelivery.SourcePrefix2 + string(b)
|
||||
}
|
||||
@@ -321,9 +321,18 @@ func casWrite(ctx context.Context, kv composedBucketsKV, key string, value []byt
|
||||
// writeNodeCompositions writes every composition of a node that differs, and prunes what is no longer kept. It answers
|
||||
// the keys it wrote.
|
||||
func writeNodeCompositions(ctx context.Context, at composedPlace, comps map[string]sdkdelivery.Composed) ([]string, error) {
|
||||
// The modules' compositions first and the node's own last, and the node's own not at all in a pass where a module's
|
||||
// failed: written without the resources that moved to that module, it would have the node-engine remove them while
|
||||
// the module's own composition is not there to take them (issue 1945, the review's gap 1).
|
||||
own, err := sdkdelivery.ComposedNodeKey(at.node)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keys := make([]string, 0, len(comps))
|
||||
for k := range comps {
|
||||
keys = append(keys, k)
|
||||
if k != own {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
}
|
||||
sort.Strings(keys)
|
||||
var wrote []string
|
||||
@@ -338,6 +347,15 @@ func writeNodeCompositions(ctx context.Context, at composedPlace, comps map[stri
|
||||
wrote = append(wrote, key)
|
||||
}
|
||||
}
|
||||
if c, ok := comps[own]; ok {
|
||||
if len(errs) > 0 {
|
||||
errs = append(errs, fmt.Errorf("%s is not written: a module's composition of this pass was not", own))
|
||||
} else if w, err := writeComposed(ctx, at, own, c); err != nil {
|
||||
errs = append(errs, err)
|
||||
} else if w {
|
||||
wrote = append(wrote, own)
|
||||
}
|
||||
}
|
||||
if err := pruneCompositions(ctx, at); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user