Files
mesh-sdk/go/process/chunks_integration_test.go
T
jschoubben 5fa64be894 Revert the revert of G's mesh-sdk merge (#191): G's sdk stands again over reader release 3
Main reverted G's half merge (#189, reverted by 8afc3eb in #191) and then took the reader release's S1-S5, which
copied G's code. G's form holds where they differ (process_bus.go, seats.go, state.go and their tests); the
release's kept names stay so main's callers keep building: SeatViewPrefix beside SeatReadPrefix, and QueueInvoke's
empty strings on not-ok (with its test TestQueueInvoke). The tree differs from G's head f30dee54 only by those and
the release's two tests (objects cap option, seat states and stream kinds).

Builds: design 47 G (the milestone's sdk part, as at f30dee54)

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
2026-11-13 12:49:56 +01:00

72 lines
2.7 KiB
Go

//go:build integration
package process
import (
"bytes"
"context"
"encoding/base64"
"encoding/json"
"errors"
"strings"
"testing"
"github.com/nats-io/nats.go"
"git.novox.be/novox/mesh-sdk/go/buscalls"
"git.novox.be/novox/mesh-sdk/go/testbus"
)
// Design 47 G A-291: a process receives a seat verb's chunked answer through one helper: it subscribes to the call's chunks
// before it asks, acknowledges each, and answers the whole body (CallChunks into a writer, CallFile as the member file);
// an answer accept refuses takes no chunk.
func TestAProcessReceivesAChunkedSeatAnswerWhole(t *testing.T) {
url := testbus.URL(t)
holder, err := nats.Connect(url)
if err != nil {
t.Fatal(err)
}
defer holder.Close()
body := []byte(strings.Repeat("0123456789", 2*buscalls.SeatChunkBytes/10+7)) // three chunks
of := int64((len(body) + buscalls.SeatChunkBytes - 1) / buscalls.SeatChunkBytes)
sub, err := holder.Subscribe("mesh.seat.node-build-go.call.output.ace.>", func(m *nats.Msg) {
var in struct{ Ask, Call string }
_ = json.Unmarshal(m.Data, &in)
answer, _ := json.Marshal(map[string]any{"result": map[string]any{"ask": in.Ask, "chunks": of}})
_ = m.Respond(answer)
go func() {
_ = buscalls.SeatChunks{Seat: "node-build-go", Verb: "output", Call: in.Call}.Send(holder, body, buscalls.SeatAckWithin, t.Logf)
}()
})
if err != nil {
t.Fatal(err)
}
defer func() { _ = sub.Unsubscribe() }()
_ = holder.Flush()
nc, err := nats.Connect(url)
if err != nil {
t.Fatal(err)
}
c := &Conn{nc: nc, account: Account{User: "novox.mesh-delivery-checker"}}
defer c.Close()
var got bytes.Buffer
answer, err := c.CallChunks(context.Background(), "seat:node-build-go.output@ace", "c1", map[string]any{"ask": "a1", "call": "c1"}, nil, &got)
if err != nil || !bytes.Equal(got.Bytes(), body) || !strings.Contains(string(answer), `"ask":"a1"`) {
t.Fatalf("answered %s and %d bytes (%v), want the verb's answer and the whole %d bytes", answer, got.Len(), err, len(body))
}
raw, err := c.CallFile("seat:node-build-go.output@ace", map[string]any{"ask": "a2", "call": "c2"})
var file struct{ Ask, File string }
if err != nil || json.Unmarshal(raw, &file) != nil || file.Ask != "a2" {
t.Fatalf("CallFile answered %.80s, %v", raw, err)
}
if whole, _ := base64.StdEncoding.DecodeString(file.File); !bytes.Equal(whole, body) {
t.Fatalf("CallFile's file holds %d bytes, want %d", len(whole), len(body))
}
refused := errors.New("too large for this disk")
got.Reset()
if _, err := c.CallChunks(context.Background(), "seat:node-build-go.output@ace", "c3", map[string]any{"ask": "a3", "call": "c3"},
func(json.RawMessage) error { return refused }, &got); !errors.Is(err, refused) || got.Len() != 0 {
t.Fatalf("an answer accept refused: %v, %d bytes taken", err, got.Len())
}
}