Files
mesh-tools/node-tools/internal/bus/chunked_test.go
T

76 lines
2.6 KiB
Go

package bus_test
import (
"encoding/base64"
"encoding/json"
"testing"
"github.com/nats-io/nats.go"
"git.novox.be/novox/mesh-sdk/go/buscalls"
mt "github.com/novox/mesh-tools/node-tools/internal/meshtest"
)
// Design 47 G A-249, §681: the runner asks a chunked verb with a call token of its own, receives the chunks the answer counts
// (each acknowledged before the next) and answers the verb's own answer with the whole file, so the asker receives none.
func TestAChunkedSeatAnswerIsReceivedByTheRunnerAndHandedWhole(t *testing.T) {
url := mt.URL(t)
holder := dial(t, url, "mesh-delivery-indexer", "anchor", "")
asker := dial(t, url, "mesh-build-go", "anchor", "")
raw, err := nats.Connect(url)
if err != nil {
t.Fatal(err)
}
t.Cleanup(raw.Close)
file := make([]byte, buscalls.SeatChunkBytes*2+5)
for i := range file {
file[i] = byte(i)
}
// the holder's process: answers the count, then sends each chunk and waits for its acknowledgement
stop, err := holder.Handle("seat:mesh-catalog.input", func(body json.RawMessage) (any, error) {
var in struct{ Call, Digest string }
if err := json.Unmarshal(body, &in); err != nil || in.Call == "" {
t.Errorf("the verb was asked with no call token: %s (%v)", body, err)
return nil, err
}
send := buscalls.SeatChunks{Seat: "mesh-catalog", Verb: "input", Call: in.Call}
go func() {
for n := int64(1); n <= 3; n++ {
end := min(int64(len(file)), n*buscalls.SeatChunkBytes)
data, _ := json.Marshal(buscalls.SeatChunk{N: n, Of: 3, Data: file[(n-1)*buscalls.SeatChunkBytes : end]})
ackSub, _ := raw.SubscribeSync(send.Ack(n))
_ = raw.Flush()
if err := raw.Publish(send.Chunk(n), data); err != nil {
return
}
m, err := ackSub.NextMsg(buscalls.SeatAckWithin)
if err != nil {
t.Errorf("chunk %d not acknowledged: %v", n, err)
return
}
_ = m.Respond([]byte("{}"))
}
}()
return map[string]any{"digest": in.Digest, "chunks": 3}, nil
})
if err != nil {
t.Fatal(err)
}
defer stop()
got, err := asker.AskAsChunked("mesh-build-go", "seat:mesh-catalog.input", map[string]any{"digest": "d1"})
if err != nil {
t.Fatal(err)
}
var ans struct {
Digest string `json:"digest"`
Chunks int `json:"chunks"`
File string `json:"file"`
}
if err := json.Unmarshal(got.Result, &ans); err != nil || ans.Digest != "d1" || ans.Chunks != 3 {
t.Fatalf("the answer %s: %v", got.Result, err)
}
if body, err := base64.StdEncoding.DecodeString(ans.File); err != nil || string(body) != string(file) {
t.Errorf("the file handed is %d bytes, want the %d sent: %v", len(body), len(file), err)
}
}