Documentation
¶
Overview ¶
Package testguard refuses to let a unit test reach a real host.
THE HURT. A unit test in the certify verb's first cut ran the REAL workloads on a bench and reached a real store, because the local-runner seam defaulted to the real thing when nothing injected a fake. Nobody wrote a hostname in the test: the test constructed production code, production code constructed its own default, and the default was an `exec.Command("ssh", …)`. The `net` class test reads test files for a real hostname and could not see this, because the host was never in the test's text -- it was in the default two packages away.
THE GUARD. Every seam in this tree that reaches a host calls RefuseHosts with the command line it is about to run. When NOVA_TEST_NO_HOST is 1 -- which `make test` sets, so every run of the suite carries it -- that call panics and names the command, so the defect is the test that constructed the real thing rather than a bench that was busy, a key that was missing or a flake nobody could reproduce. When the variable is unset the call is one atomic load and a return: no allocation, no lookup, nothing to pay on a production path that is about to spawn ssh anyway.
A TEST THAT WANTS A CHILD. A fake `ssh` written into t.TempDir() and put on PATH is not a host, and this package can see that for itself: a program that resolves INSIDE a temp directory (GOTMPDIR included) is a fake, a program that resolves to /usr/bin/ssh is the fleet. So the tests that already fake the seam that way -- and the tools they run as child processes, which inherit the variable -- keep working untouched. A test whose fake lives anywhere else says so out loud with `defer testguard.AllowHosts()()`.
Every seam this package guards is held by TestNoTestReachesAHostThroughAnUnfakedSeam in internal/ci, which reads the tree and refuses a seam that does not call it.
Index ¶
Constants ¶
const EnvNoHost = "NOVA_TEST_NO_HOST"
EnvNoHost is the variable that turns the guard on. `make test` sets it to "1" for every tier, and ci.yml reaches the same targets through make, so a test running anywhere on the CI path runs under the guard.
Variables ¶
This section is empty.
Functions ¶
func AllowHosts ¶
func AllowHosts() func()
AllowHosts opens a scope in which a seam may run a child, and returns the function that closes it. The one honest use is a test that has installed its own fake on PATH:
defer testguard.AllowHosts()()
The scope is process-wide for its duration, so a test that opens one must not run in parallel with a test relying on the guard. That is a narrowing, written down rather than left to be discovered: the guard catches the UNFAKED seam, and a test that fakes a seam declares it.
func RefuseHosts ¶
RefuseHosts is what every ssh/scp/rsync seam in this tree calls with the command line it is about to run. Under the guard, and outside an AllowHosts scope, it panics naming that command line; otherwise it returns immediately.
It panics rather than returning an error on purpose. An error would travel up a path that already handles "the bench was unreachable" and would be reported as exactly that -- an infrastructure story for a code defect. A panic names the test, the seam and the command in one stack, which is the cheapest possible read of the hurt above.
Types ¶
type Guard ¶
type Guard struct {
// contains filtered or unexported fields
}
Guard holds the state and seams for refusing host calls in tests.
func (*Guard) AllowHosts ¶
func (g *Guard) AllowHosts() func()
AllowHosts opens a scope in which a seam may run a child, and returns the function that closes it.
func (*Guard) RefuseHosts ¶
RefuseHosts is what every ssh/scp/rsync seam in this tree calls with the command line it is about to run. Under the guard, and outside an AllowHosts scope, it panics naming that command line; otherwise it returns immediately.
It panics rather than returning an error on purpose. An error would travel up a path that already handles "the bench was unreachable" and would be reported as exactly that -- an infrastructure story for a code defect. A panic names the test, the seam and the command in one stack, which is the cheapest possible read of the hurt above.