Documentation
¶
Overview ¶
Package daemontest boots a real rysh daemon for tests.
Almost every test in this tree exercises a handler by calling it directly, which is fast and right for logic but blind to a whole class of defect: the path from `rysh <verb>` through NATS into a live WorkspaceActor and back. Design 021's exit-status work found five handlers that reported success when they should have failed, and NOT ONE of them was catchable that way — they were paths where a named target does not exist, or where a handler delegates to a `handleCLI*`, prints its error and drops it. They were found by a human running ~50 commands against a daemon by hand, which is not a regression test.
This package is that sweep, automated.
Isolation ¶
A test daemon must never touch the sessions a developer is actually using. Three things guarantee that, and all three matter:
- Every session gets its own temp directory holding its own rysh.config.yaml. rysh state is project-local and derived from the config file's location, so the session registry, the KV buckets and the JetStream data all land inside that directory and vanish with it.
- The NATS port is 0, i.e. kernel-assigned. Two test daemons — or a test daemon and a developer's — can never collide on a fixed port.
- Session names carry the pid and a counter, so a crashed run cannot leave a record that a later run adopts.
Cost ¶
The package runs in about 40 seconds: ~8s to build the binary once, ~12s booting daemons, and ~14s of CLI round-trips at roughly 150ms each. That is in line with internal/actors and is the price of testing the real path, so it runs in the default `go test ./...` rather than hiding behind a build tag — a suite nobody runs catches nothing. `go test -short` skips it for quick local iteration.
Booting a daemon costs a second or two, so the default is one shared session per test binary (Shared), reused by every test that only needs to ASK the daemon things. A test that mutates the workspace in a way others would notice takes its own with Fresh.
What this does NOT cover ¶
The daemon is a separate process, so `go test -race` instruments the test binary and not the daemon. A data race inside the WorkspaceActor is invisible here — that is what the in-process tests in internal/actors are for. These tests check behaviour across the wire, not memory safety behind it.
Index ¶
- func Binary(t *testing.T) string
- func Main(m *testing.M) int
- type Session
- func (s *Session) CLI(t *testing.T, args ...string) (string, int)
- func (s *Session) Exec(t *testing.T, command string) (string, int)
- func (s *Session) MustFail(t *testing.T, command string) string
- func (s *Session) MustSucceed(t *testing.T, command string) string
- func (s *Session) Script(t *testing.T, src string, args ...string) (string, int)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Binary ¶
Binary builds cmd/rysh once per test process and returns the path.
It builds rather than reusing an installed rysh on purpose: the point is to test THIS tree, and a stale binary on PATH would quietly test something else.
func Main ¶
Main runs a package's tests and then stops the shared session, if one was booted. A package that uses Shared must call it:
func TestMain(m *testing.M) { os.Exit(daemontest.Main(m)) }
Without it the shared daemon outlives the test binary. Nothing would break — its name and port are unique and its state is in a temp directory — but a stray daemon per test run is exactly the kind of litter that makes people stop running a suite.
Types ¶
type Session ¶
type Session struct {
// Name is the session name, unique to this test process.
Name string
// Dir is the temp directory holding the session's config and all its state.
Dir string
// Config is the absolute path of the session's rysh.config.yaml.
Config string
// Bin is the rysh binary under test.
Bin string
}
Session is a running rysh daemon and the CLI binary that drives it.
func Fresh ¶
Fresh boots a session used only by this test and stops it when the test ends. Use it when the test mutates the workspace in a way another test would see.
func Shared ¶
Shared returns the session shared by every test in this binary, booting it on first use. Use it for anything that only reads.
func (*Session) CLI ¶
CLI runs an arbitrary rysh subcommand against this session's config, for tests that drive a verb other than exec/script.
func (*Session) MustSucceed ¶
MustSucceed asserts a command exits 0, and returns its output.