Files
mesh-sdk/go/views/stdio_writer_test.go
T
jschoubben 63a290db3d G B-1 (Go): the tests G added are merged into existing ones as subtests, so mesh-sdk ends G with the tests it started with
unit 302 and integration 34, as at the merge base 45e143f; the buscalls test moves beside busstate's.

Builds: design 47 G §419, §626
Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ
2026-11-11 22:03:15 +01:00

108 lines
3.7 KiB
Go

package views
import (
"context"
"encoding/json"
"strings"
"testing"
stdio "git.novox.be/novox/mesh-sdk/go"
)
type swFinding struct {
Kind string `json:"kind"`
Scope string `json:"scope"`
ID string `json:"id"`
Observer string `json:"observer"`
At string `json:"at"`
Since string `json:"since"`
Subject struct {
Scope string `json:"scope"`
} `json:"subject"`
}
type swCleared struct {
Kind string `json:"kind"`
Scope string `json:"scope"`
ID string `json:"id"`
At string `json:"at"`
Why string `json:"why"`
}
type swStated struct {
At string `json:"at"`
Findings []swFinding `json:"findings"`
Pending []PendingKey `json:"pending"`
}
type swAsked struct {
Ask string `json:"ask"`
}
// A stdio module's writer says each of its events through the module's own publish, acknowledged, under the writer's
// message id, and hears the asks through the module's subscription (design 47 G A-16).
func subStdioWriterPublishesAndListensThroughTheModulesOwnPlumbing(t *testing.T) {
type said struct {
event string
body string
o stdio.EmitOptions
}
var out []said
var subscribed []string
var deliver func(stdio.Envelope) error
w, err := newStdioWriter(WriterConfig[swFinding, swCleared, swStated, swAsked]{
Module: "m", Node: "n1", State: nil, Asked: "mesh.seat.s.event.findings-asked",
Observe: func(context.Context) (Observed[swFinding], error) { return Observed[swFinding]{}, nil },
}, func(event string, body any, o ...stdio.EmitOptions) error {
raw, _ := json.Marshal(body)
out = append(out, said{event, string(raw), o[0]})
return nil
}, func(pattern string, h func(stdio.Envelope) error) error {
subscribed = append(subscribed, pattern)
deliver = h
return nil
})
if err == nil || !strings.Contains(err.Error(), "state") {
t.Fatalf("the writer still needs its state: %v", err)
}
w, err = newStdioWriter(WriterConfig[swFinding, swCleared, swStated, swAsked]{
Module: "m", Node: "n1", State: noState{}, Asked: "mesh.seat.s.event.findings-asked",
Observe: func(context.Context) (Observed[swFinding], error) { return Observed[swFinding]{}, nil },
}, func(event string, body any, o ...stdio.EmitOptions) error {
raw, _ := json.Marshal(body)
out = append(out, said{event, string(raw), o[0]})
return nil
}, func(pattern string, h func(stdio.Envelope) error) error {
subscribed = append(subscribed, pattern)
deliver = h
return nil
})
if err != nil {
t.Fatal(err)
}
if err := w.cfg.Publish(context.Background(), w.subj.Written, []byte(`{"a":1}`), "id-1"); err != nil {
t.Fatal(err)
}
if len(out) != 1 || out[0].event != "finding-written" || out[0].body != `{"a":1}` || out[0].o.MessageID != "id-1" || !out[0].o.Ack {
t.Fatalf("the publish: %+v", out)
}
var heard []string
stop, err := w.cfg.Listen(context.Background(), w.cfg.Asked, func(b []byte) { heard = append(heard, string(b)) })
if err != nil || len(subscribed) != 1 || subscribed[0] != "s.findings-asked" {
t.Fatalf("the listen: %v %v", subscribed, err)
}
_ = deliver(stdio.Envelope{Body: json.RawMessage(`{"ask":"x"}`)})
stop()
_ = deliver(stdio.Envelope{Body: json.RawMessage(`{"ask":"y"}`)})
if len(heard) != 1 || heard[0] != `{"ask":"x"}` {
t.Fatalf("heard %v: a stopped listener hands on nothing", heard)
}
if err := w.cfg.Publish(context.Background(), "obs.event", nil, ""); err == nil {
t.Fatal("a subject of no event form is refused")
}
}
type noState struct{}
func (noState) Get(string) (*stdio.StateEntry, error) { return nil, nil }
func (noState) Put(string, any) (uint64, error) { return 0, nil }
func (noState) Delete(string) error { return nil }
func (noState) Keys() ([]string, error) { return nil, nil }