Files
mesh-host/internal/link/witnessing_nats_test.go
T
jschoubben ff4dc71ce4 Witness the node tools alone: the controller's lease names no build any more
The controller ended by its unassignment (issue 1126, ADR 0590), so no build is judged by the lease: the lease
witness, its contract and the direct get the witness asked it with are removed, and its tests now prove each rollback
path on the node tools' PING.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-02 11:22:21 +01:00

66 lines
2.1 KiB
Go

package link
import (
"context"
"errors"
"os"
"testing"
"time"
"github.com/nats-io/nats.go"
)
// What a witness asks, asked of a real server with the grants the mesh composes (novox/hq to-be 45 §8):
// whether the PING works as the subject named, and whether a host without them
// is told apart — "cannot ask", never "the build did not answer". See testdata/witness-grants.conf.
func TestNatsWitnessAsksWhatItIsGranted(t *testing.T) {
url := os.Getenv("MESH_TEST_NATS_GRANTS")
if url == "" {
t.Skip("MESH_TEST_NATS_GRANTS unset")
}
dial := func(user, password, inbox string) *nats.Conn {
t.Helper()
conn, err := nats.Connect(url, nats.UserInfo(user, password), nats.CustomInboxPrefix(inbox))
if err != nil {
t.Fatal(err)
}
t.Cleanup(conn.Close)
return conn
}
anchor := &natsLink{conn: dial("node.anchor", "a", "_INBOX.node.anchor")}
bare := &natsLink{conn: dial("node.bare", "b", "_INBOX.node.bare")}
ask := func() (context.Context, context.CancelFunc) {
return context.WithTimeout(context.Background(), 2*time.Second)
}
// No runtime on the bus: not there to answer.
ctx, cancel := ask()
if err := anchor.Ping(ctx, "node-tools", "anchor"); !errors.Is(err, ErrNoAnswer) {
t.Fatalf("a PING nobody serves is %v, want no answer", err)
}
cancel()
// The runtime, answering as the services protocol does.
runtime := dial("runtime", "r", "_INBOX.runtime")
sub, err := runtime.Subscribe("$SRV.PING.node-tools.anchor", func(m *nats.Msg) {
_ = m.Respond([]byte(`{"type":"io.nats.micro.v1.ping_response","name":"node-tools","id":"anchor","version":"0.1.0"}`))
})
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = sub.Unsubscribe() })
if err := runtime.Flush(); err != nil {
t.Fatal(err)
}
ctx, cancel = ask()
if err := anchor.Ping(ctx, "node-tools", "anchor"); err != nil {
t.Fatalf("this machine's runtime answered and the witness heard %v", err)
}
cancel()
// And a host not granted the PING cannot ask, though the runtime is there.
ctx, cancel = ask()
if err := bare.Ping(ctx, "node-tools", "anchor"); !errors.Is(err, ErrCannotAsk) {
t.Fatalf("a host without the grant heard %v, want it unable to ask", err)
}
cancel()
}