Give every module the announcement test, on an exported test bus (issue 1790, S11, ADR 0495 §5)
announcetest.Check starts the module against a bus of the test's own and holds its announcement equal to what its code declares; testbus leaves internal/ so a module's own integration tests can start it.
This commit is contained in:
@@ -1,74 +0,0 @@
|
||||
// Package testbus is the bus an integration test of the SDK's Go binding runs against: a server of
|
||||
// its own, of the release go.mod pins, started for the one test and gone after it.
|
||||
//
|
||||
// **Why one per test.** A test that reaches a shared bus asserts, reads and removes objects by fixed
|
||||
// name — a stream, a consumer — and two tests at once would step on each other's: one deleting what
|
||||
// the other is reading, one leaving a stream behind for the next to trip on. A server per test makes
|
||||
// every test start from nothing and leave nothing, so the suite is the same run in any order, at any
|
||||
// parallelism, under the race detector, on a workstation or on the build seat.
|
||||
//
|
||||
// **No catalogue pin check.** mesh-controller's testbus also checks the server's release against the
|
||||
// catalogue's bus image and the mesh's facts snapshot (novox/hq ADR 0227 rule 9) — the SDK has no
|
||||
// catalogue of its own to check against, so that test is left out here. Only the version this
|
||||
// module's go.mod pins (and go/vendor holds) is what these tests run.
|
||||
//
|
||||
// A person may still point a run at a bus of their own — another release, a lab's — with
|
||||
// MESH_TEST_NATS_EXTERNAL=1 and MESH_TEST_NATS; then the run is theirs to serialise.
|
||||
package testbus
|
||||
|
||||
import (
|
||||
"os"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/nats-io/nats-server/v2/server"
|
||||
)
|
||||
|
||||
// Version is the release of the server the tests run.
|
||||
const Version = server.VERSION
|
||||
|
||||
// URL is the bus of this test alone: started at its first ask, the same one at every ask after — a
|
||||
// test that dials twice, or hands the address to the code it tests, reaches one bus — and shut down
|
||||
// when the test ends.
|
||||
func URL(t testing.TB) string {
|
||||
t.Helper()
|
||||
if os.Getenv("MESH_TEST_NATS_EXTERNAL") == "1" {
|
||||
if url := os.Getenv("MESH_TEST_NATS"); url != "" {
|
||||
return url
|
||||
}
|
||||
t.Fatal("MESH_TEST_NATS_EXTERNAL=1 and MESH_TEST_NATS names no bus")
|
||||
}
|
||||
if url, ok := buses.Load(t); ok {
|
||||
return url.(string)
|
||||
}
|
||||
url := Start(t).ClientURL()
|
||||
buses.Store(t, url)
|
||||
t.Cleanup(func() { buses.Delete(t) })
|
||||
return url
|
||||
}
|
||||
|
||||
// buses are the running tests' buses, by test.
|
||||
var buses sync.Map
|
||||
|
||||
// Start is a server with JetStream, for this test alone: on loopback, on a port the system chooses, its
|
||||
// store in the test's own directory.
|
||||
func Start(t testing.TB) *server.Server {
|
||||
t.Helper()
|
||||
opts := &server.Options{Host: "127.0.0.1", Port: server.RANDOM_PORT, JetStream: true, StoreDir: t.TempDir(),
|
||||
NoLog: true, NoSigs: true}
|
||||
s, err := server.NewServer(opts)
|
||||
if err != nil {
|
||||
t.Fatalf("a bus for this test could not be made: %v", err)
|
||||
}
|
||||
go s.Start()
|
||||
if !s.ReadyForConnections(30 * time.Second) {
|
||||
s.Shutdown()
|
||||
t.Fatal("a bus for this test did not come up within 30s")
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
s.Shutdown()
|
||||
s.WaitForShutdown()
|
||||
})
|
||||
return s
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
//go:build integration
|
||||
|
||||
package testbus
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/nats-io/nats.go"
|
||||
"github.com/nats-io/nats.go/jetstream"
|
||||
)
|
||||
|
||||
// 1175/AC3, 1171/AC1: a JetStream bus of this test alone answers a publish and a key-value create.
|
||||
func TestBusAnswersPublishAndKeyValueCreate(t *testing.T) {
|
||||
conn, err := nats.Connect(URL(t))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
js, err := jetstream.New(conn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ctx := context.Background()
|
||||
|
||||
if _, err := js.CreateStream(ctx, jetstream.StreamConfig{Name: "EVENTS", Subjects: []string{"mesh.>"}}); err != nil {
|
||||
t.Fatalf("the bus did not answer a stream create: %v", err)
|
||||
}
|
||||
ack, err := js.Publish(ctx, "mesh.test", []byte("hello"))
|
||||
if err != nil {
|
||||
t.Fatalf("the bus did not answer a publish: %v", err)
|
||||
}
|
||||
if ack.Stream != "EVENTS" {
|
||||
t.Errorf("published into %q, want EVENTS", ack.Stream)
|
||||
}
|
||||
|
||||
kv, err := js.CreateKeyValue(ctx, jetstream.KeyValueConfig{Bucket: "TESTKV"})
|
||||
if err != nil {
|
||||
t.Fatalf("the bus did not answer a key-value create: %v", err)
|
||||
}
|
||||
if _, err := kv.Put(ctx, "k", []byte("v")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
entry, err := kv.Get(ctx, "k")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(entry.Value()) != "v" {
|
||||
t.Errorf("read back %q, want %q", entry.Value(), "v")
|
||||
}
|
||||
}
|
||||
|
||||
// 1175/AC3, 1171/AC1: the bus is gone when the test that started it ends.
|
||||
func TestBusGoneWhenItsTestEnds(t *testing.T) {
|
||||
var url string
|
||||
t.Run("one", func(t *testing.T) {
|
||||
url = URL(t)
|
||||
conn, err := nats.Connect(url)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
conn.Close()
|
||||
})
|
||||
if _, err := nats.Connect(url, nats.Timeout(time.Second)); err == nil {
|
||||
t.Fatal("the subtest's bus still answers now that the subtest has ended")
|
||||
}
|
||||
}
|
||||
|
||||
// 1175/AC3: two tests never share a bus.
|
||||
func TestEveryTestHasABusOfItsOwn(t *testing.T) {
|
||||
seen := map[string]bool{}
|
||||
for i := 0; i < 2; i++ {
|
||||
t.Run("one", func(t *testing.T) {
|
||||
url := URL(t)
|
||||
if seen[url] {
|
||||
t.Fatalf("two tests were handed %s", url)
|
||||
}
|
||||
seen[url] = true
|
||||
})
|
||||
}
|
||||
// Asked twice, one test reaches one bus.
|
||||
if a, b := URL(t), URL(t); a != b {
|
||||
t.Errorf("one test was handed two buses: %s and %s", a, b)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user