Files
mesh-sdk/go/process/fixture_integration_test.go
T
jschoubben 57d2f31f05 Let a module's code announce the states it keeps, in Go and TypeScript (issue 1790, S10, ADR 0495 §2 §5)
process.Conn.Keeps, stdio.Keeps and the TypeScript keeps publish the announcement on
the module's own subject; afterwards a state the code did not announce is refused at
the call, so announcement and code cannot drift. The package goes to 0.1.15 for keeps.
2026-10-22 17:42:24 +02:00

102 lines
3.7 KiB
Go

//go:build integration
package process
import (
"context"
"testing"
"time"
"github.com/nats-io/nats-server/v2/server"
"github.com/nats-io/nats.go"
"github.com/nats-io/nats.go/jetstream"
)
// sendUser and sendPassword are mesh-mail's process "send" on novox, as mesh-controller would mint it
// (mesh-controller internal/broker/process_grants_test.go mailSenderProcess, Principal.Username).
const (
sendUser = "novox.mesh-mail.send"
sendPassword = "the-pw"
adminUser = "admin"
adminPass = "admin-pw"
)
// sendGrants is the process principal mailSenderProcess's whole publish set, copied from
// mesh-controller internal/broker/process_grants_test.go (TestAProcessIsGrantedExactlyItsBusDeclaration,
// "dumped from a passing run... 16 subjects, correct today"), since this package may not import the
// controller: the exact grant the controller composes for novox.mesh-mail.send.
var sendGrants = []string{
"$JS.ACK.MAIL_SENDS.novox_mesh-mail_send.>",
"$JS.API.CONSUMER.CREATE.KV_mesh-mail_sends.>",
"$JS.API.CONSUMER.DELETE.KV_mesh-mail_sends.>",
"$JS.API.CONSUMER.INFO.MAIL_SENDS.novox_mesh-mail_send",
"$JS.API.CONSUMER.MSG.NEXT.MAIL_SENDS.novox_mesh-mail_send",
"$JS.API.DIRECT.GET.KV_mesh-mail_sends.>",
"$JS.API.DIRECT.GET.KV_messenger_asks.$KV.messenger_asks.mesh-mail.>",
"$JS.API.STREAM.INFO.KV_mesh-mail_sends",
"$JS.FC.KV_mesh-mail_sends.>",
"$KV.mesh-mail_sends.>",
"mesh.mod.mesh-mail.event.mail.send.failed",
"mesh.mod.mesh-mail.event.mail.send.sent",
"mesh.mod.mesh-mail.event.states",
"mesh.seat.operator-channel.call.tell.*.novox~mesh-mail~send",
"mesh.seat.operator-channel.call.tell.novox~mesh-mail~send",
"mesh.seat.operator-channel.tool.tell",
"mesh.seat.operator-channel.tool.tell.*",
}
// grantedSendProcess is a test bus with JetStream, with two users: novox.mesh-mail.send, permissioned to
// exactly sendGrants and its own inbox (nats-server server.Options Users with Permissions, as
// mesh-controller's cmd/mesh-controller/process_live_test.go composes accounts for a real bus — copied as
// literal grants here since this package may not import the controller); and an unrestricted admin for the
// test's own setup (creating streams and buckets, standing in for the holder and the runtime).
func grantedSendProcess(t *testing.T) (url string, account Account) {
t.Helper()
opts := &server.Options{Host: "127.0.0.1", Port: server.RANDOM_PORT, JetStream: true, StoreDir: t.TempDir(),
NoLog: true, NoSigs: true,
Users: []*server.User{
{Username: adminUser, Password: adminPass},
{Username: sendUser, Password: sendPassword, Permissions: &server.Permissions{
Publish: &server.SubjectPermission{Allow: sendGrants},
Subscribe: &server.SubjectPermission{Allow: []string{"_INBOX." + sendUser + ".>"}},
}},
},
}
s, err := server.NewServer(opts)
if err != nil {
t.Fatalf("a granted test bus could not be made: %v", err)
}
go s.Start()
if !s.ReadyForConnections(10 * time.Second) {
s.Shutdown()
t.Fatal("a granted test bus did not come up within 10s")
}
t.Cleanup(func() {
s.Shutdown()
s.WaitForShutdown()
})
url = s.ClientURL()
return url, Account{URL: url, Node: "novox", Module: "mesh-mail", User: sendUser, Password: sendPassword}
}
// adminJS is the test's own unrestricted connection to url, for setting up fixtures.
func adminJS(t *testing.T, url string) (*nats.Conn, jetstream.JetStream) {
t.Helper()
nc, err := nats.Connect(url, nats.UserInfo(adminUser, adminPass), nats.CustomInboxPrefix("_INBOX."+adminUser))
if err != nil {
t.Fatal(err)
}
t.Cleanup(nc.Close)
js, err := jetstream.New(nc)
if err != nil {
t.Fatal(err)
}
return nc, js
}
func ctxFor(t *testing.T) context.Context {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
t.Cleanup(cancel)
return ctx
}