79 lines
2.7 KiB
Go
79 lines
2.7 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"testing"
|
|
|
|
sdkdelivery "git.novox.be/novox/mesh-sdk/go/delivery"
|
|
"github.com/nats-io/nats.go/jetstream"
|
|
)
|
|
|
|
// raceKV is a digests bucket in which another writer writes its composition and digest just before this writer reads
|
|
// the digest key: what two take-ins composing one node at once do.
|
|
type raceKV struct {
|
|
*fakeComposedKV
|
|
before func()
|
|
}
|
|
|
|
func (r *raceKV) Get(ctx context.Context, key string) (jetstream.KeyValueEntry, error) {
|
|
if r.before != nil {
|
|
b := r.before
|
|
r.before = nil
|
|
b()
|
|
}
|
|
return r.fakeComposedKV.Get(ctx, key)
|
|
}
|
|
|
|
// The digest kept beside a composition is always the digest of the composition the bucket holds: when another writer
|
|
// writes its composition and its digest between this writer's composition and its digest, this writer's digest must not
|
|
// win, or the assigner's want names a composition the bucket no longer holds and the node applies nothing (issue 1945,
|
|
// live on 2026-10-25: shanks' node-tools composition had digest 575a5c96, its want named a36e63c8).
|
|
func TestTheDigestKeptIsTheDigestOfTheCompositionHeld(t *testing.T) {
|
|
at, _, _, _ := aPlace(t, "shanks")
|
|
key, _ := sdkdelivery.ComposedKey("shanks", "node-tools", fp2Of('a'))
|
|
file := func(content string) json.RawMessage {
|
|
return json.RawMessage(`{"id":"node-tools.f","type":"file","module":"node-tools","path":"/etc/nt","mode":"0644","content":"` +
|
|
content + `"}`)
|
|
}
|
|
ours := sdkdelivery.Composed{Node: "shanks", Module: "node-tools", FP: fp2Of('a'), Resources: []json.RawMessage{file("ours")}}
|
|
theirs := sdkdelivery.Composed{Node: "shanks", Module: "node-tools", FP: fp2Of('a'), Resources: []json.RawMessage{file("theirs")}}
|
|
race := &raceKV{fakeComposedKV: at.digests.(*fakeComposedKV)}
|
|
at.digests = race
|
|
race.before = func() {
|
|
// The other writer: its composition over ours, then its digest.
|
|
other := at
|
|
other.digests = race.fakeComposedKV
|
|
if _, err := writeComposed(context.Background(), other, key, theirs); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
if _, err := writeComposed(context.Background(), at, key, ours); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
held, _, err := readComposed(context.Background(), at.bucket, key)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
heldDigest, _ := sdkdelivery.ComposedDigestOf(held)
|
|
e, err := race.fakeComposedKV.Get(context.Background(), key)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
kept, err := sdkdelivery.DecodeComposedDigest(e.Value())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if kept.Digest != heldDigest {
|
|
t.Fatalf("the digest kept is %s and the composition held has %s", kept.Digest, heldDigest)
|
|
}
|
|
}
|
|
|
|
func fp2Of(c byte) string {
|
|
b := make([]byte, 64)
|
|
for i := range b {
|
|
b[i] = c
|
|
}
|
|
return sdkdelivery.SourcePrefix2 + string(b)
|
|
}
|