//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.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 }