The live tests reached one shared bus and assert, read and remove the mesh's own objects by their fixed names, so packages run in parallel deleted what each other read and the suite passed only one package at a time; a red suite read as noise. internal/testbus starts a server per test, linked in at the nats-server release go.mod pins, and a test holds that pin to the catalogue's bus image and to the facts snapshot's bus when there is one, so the tests never run a bus the mesh does not. The waiter test read a timing (the most connections held at one look) and now reads the state it means (the fewest held across the wait). make check runs the packages in parallel under the race detector, with a timeout.
78 lines
3.0 KiB
Go
78 lines
3.0 KiB
Go
// 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
|
|
}
|