Split compositions from the inline body so their large files' objects are put, and refuse a composition naming an object the bucket lacks (issue 1945)

This commit is contained in:
2026-10-25 01:42:28 +02:00
parent b1f758ed71
commit 82c89bec65
3 changed files with 106 additions and 1 deletions
@@ -0,0 +1,58 @@
package main
import (
"context"
"crypto/sha256"
"encoding/hex"
"strings"
"testing"
sdkdecl "git.novox.be/novox/mesh-sdk/go/declaration"
)
// A composition's file over 64 KiB reaches the node by its digest, and its object is in the node's bucket before the
// composition is written (ADR 0539 §4; issue 1945, live on 2026-10-25 at 01:22: novox's node-engine could not fetch
// nats.bus-users, because the body the compositions were split from already named the file by digest, so the writer
// found no content to put, and nothing else put it once sends were gone).
func TestALargeFileOfACompositionHasItsObjectInTheBucket(t *testing.T) {
big := strings.Repeat("user = x\n", sdkdecl.FileReferenceThreshold/8)
declared := sendable{fileReferences: true, Resources: []map[string]any{{"id": "nats.bus-users", "type": "file",
"path": "/var/lib/nats-module/conf/accounts.conf", "mode": "0644", "content": big}}}
body, err := compositionBody(declared)
if err != nil {
t.Fatal(err)
}
comps, _, err := compositionsOf("novox", body, nil, nil, nil)
if err != nil {
t.Fatal(err)
}
at, _, _, _ := aPlace(t, "novox")
if _, err := writeNodeCompositions(context.Background(), at, comps); err != nil {
t.Fatal(err)
}
sum := sha256.Sum256([]byte(big))
if _, ok := at.objects.(fakeObjects)[hex.EncodeToString(sum[:])]; !ok {
t.Fatalf("the object of nats.bus-users is not in the bucket: %d objects", len(at.objects.(fakeObjects)))
}
}
// A composition that names a file by a digest whose object the bucket does not hold is refused, never written: a node
// that read it could not apply it.
func TestACompositionNamingAnObjectTheBucketLacksIsRefused(t *testing.T) {
big := strings.Repeat("user = x\n", sdkdecl.FileReferenceThreshold/8)
declared := sendable{fileReferences: true, Resources: []map[string]any{{"id": "nats.bus-users", "type": "file",
"path": "/var/lib/nats-module/conf/accounts.conf", "mode": "0644", "content": big}}}
body, err := declared.Body() // the body as a send named it: by digest, the content gone
if err != nil {
t.Fatal(err)
}
comps, _, err := compositionsOf("novox", body, nil, nil, nil)
if err != nil {
t.Fatal(err)
}
at, _, _, _ := aPlace(t, "novox")
if _, err := writeNodeCompositions(context.Background(), at, comps); err == nil ||
!strings.Contains(err.Error(), "does not hold") {
t.Fatalf("a composition naming a missing object was written: %v", err)
}
}