Documentation
¶
Overview ¶
Package treeguard fails a test binary that leaves a file behind in the directory it ran in.
`go test` runs a package's binary in that package's *source* directory, so a test that writes to a relative path writes into the checked-out tree. Nothing reports it: the write succeeds, the test passes, and the file sits there until a later `git add -A` commits it into a change that never meant to create it. That has happened twice in this repository with one file.
The guard is a before-and-after listing around the whole run. It cannot say which test wrote the file — the run is over by the time it looks — but naming the file is enough to find the writer, and turning a silent success into a failed package is the whole point: an unnoticed stray becomes a red build before it can reach anyone else's commit.
What it does *not* cover is a write outside the package directory. A test that needs a filesystem should take a directory from the framework, which takes it away again; this exists for the case where nobody remembered to.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Run ¶
Run runs the package's tests and returns the status the binary should exit with. A package guards itself with
func TestMain(m *testing.M) { os.Exit(treeguard.Run(m)) }
and the status is m.Run's unless the run left something behind, in which case a passing package still fails.
The parameter is the one method *testing.M offers here rather than the type itself, so this package's own tests can hand it a run that leaves a file — which is the case that matters and the one a real *testing.M cannot be asked to perform.
func Temp ¶
Temp gives a run a temporary directory of its own and fails it if anything is left there. A package guards itself with
func TestMain(m *testing.M) { os.Exit(treeguard.Temp(m).Run()) }
and composes it with the other wrappers the way childguard.Wrap composes.
Why this is not Run with a different directory ¶
Run counts *files*, and says so: a directory a test makes and empties again has left nothing behind, and reporting it would make the guard cry wolf in a source tree where git does not record an empty directory anyway.
The leak this is for is an empty directory and nothing else. A process substitution makes one under the shell's TMPDIR to hold its named pipes; the pipes go as soon as the command that named them ends, and for a long time nothing removed what was left. 10,585 accumulated in /tmp in one working session and 4,188 more in the two days after they were swept by hand (#1284). Run, pointed at TMPDIR, would have reported none of them — which is the point worth writing down: the guard that was already here could not have caught this, so the answer was to teach it the case rather than to leave a second guard somewhere else that knows one thing this one does not.
So an entry of any kind counts here, and a directory is named rather than descended into: what is inside a stray is the writer's business, and the report wants one line per thing left behind.
What it covers ¶
A whole run, not a test. It cannot say which test leaked — the run is over by the time it looks — but a package that starts shells is a small enough haystack, and turning a silent success into a failed package is the whole point. The suites that start shells are where a leak reaches a *binary*: interp's own tests each hand their Runner a TMPDIR the framework takes away again, so a leak there is invisible, and a leak in a shipped shell is permanent.
A run killed by a signal leaves the scratch directory behind, and a SIGKILLed one cannot do otherwise. That is the same hole every cleanup has and it is not worth pretending about.
Types ¶
This section is empty.