// Package testbus is the bus a test runs against: a server of its own, of the release the mesh runs, // started for the one test and gone after it. // // **Why one per test.** The live tests reached one shared bus, and on it they assert, read and remove the // mesh's own objects — streams and consumers with fixed names, because those names are the mesh's. Two // packages at once was one deleting a consumer the other was reading through, and a test left a stream // behind for the next to trip on: the suite passed one package at a time and failed or hung run as Go // runs it, which taught everybody to read a red suite as noise. 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. // // **Why this release.** The server is linked in at the version go.mod pins, and a test beside this one // holds that pin to the release the mesh runs — the catalogue's bus image, and the facts snapshot's when // a merge check has one (novox/hq ADR 0227 rule 9: a version the mesh runs is the one its tests run). // A bus the 2.10 line skipped messages on (issue 266) would have been caught by the tests that ran on it, // had they run on it. // // 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 }