When cmdtest.Check runs inside go test, successful package test results may
be reused from the Go package test cache.
The key constraint: go test only keys cached results off what the test
process itself observes (via internal "testlog" actions like getenv, stat,
open, and chdir). Dependencies used only by subprocesses do not
automatically influence the cache key.
The internal/gocachehazards package contains end-to-end tests demonstrating
these behaviors.
There are two competing goals when using transcript under go test caching:
- Avoid false cache hits (a test is reused from cache even though an input changed), since that means missed test coverage.
- Preserve cache hits when possible, since it speeds up iteration.
In practice, the tool-under-test binary often changes frequently, which busts the cache and makes the second goal less important. False cache hits are most likely when iterating on data files (configs, fixtures) without changing the tool binary.
Transcript tries to make common dependencies visible to the test process:
- Environment variable expansions in the transcript shell consult
os.LookupEnvsogo testcan recordgetenvactions. - Input redirections like
< config.jsonare opened by the transcript shell in the test process, sogo testcan recordopenactions for them. % depcauses the test process tostatfile dependencies andgetenvenv dependencies, so changes invalidate cached results.% depusesstatrather thanopenfor file deps to avoid Go's "open too new" caching cutoff for freshly modified files.
Declare a file dependency:
% dep config.json
Declare an environment variable dependency:
% dep '$PATH'
Declare a set of dependencies from a depfile:
% dep < deps.txt
Depfiles are line-oriented data files (no shell expansion). See
docs/reference.md for the depfile format.
It's tempting to generate a depfile during a transcript run and then declare it
with % dep < ..., but don't do this if you care about go test caching.
% dep < deps.txt necessarily opens deps.txt (because of the <
redirection).
If the depfile was just written or modified, Go's "open too new" cutoff can
refuse to cache the package test result.
Prefer stable depfiles (checked in, or otherwise not rewritten on every test run) when caching matters.
- Prefer explicit dependencies.
% depis the reliable way to avoid false cache hits when subprocesses read inputs. - Declare subprocess-read inputs:
% dep config.json% dep < deps.txt(depfile)
- Keep dependencies under the module root.
go testintentionally ignores file dependencies outside the module root when computing cache keys. - Keep the tool-under-test binary under the module root (for example
./bin) and add that directory toPATH. - If you want cache hits while iterating on data files, avoid rebuilding the
tool on every
go testrun. - Avoid patterns that force the test process to
opena freshly-written file when you care about caching. For example, ifdeps.txtis generated during the test run,% dep < deps.txtmay trip Go's "open too new" rule.
These hazards are demonstrated in internal/gocachehazards/hazards_test.go.
If $FOO expansions do not call os.LookupEnv("FOO"), changing FOO may not
invalidate the go test cache. Transcript fixes this by using os.LookupEnv
for expansions in the shell runner.
If a subprocess reads dep.txt, go test will not automatically notice,
regardless of whether dep.txt is passed as an argument or discovered
indirectly (via env vars, config files, wrapper scripts, etc).
Declare subprocess inputs with % dep dep.txt so the test process stats the
file.
If your tool binary lives outside the module root (for example
/usr/local/bin), changes to the tool may not invalidate the go test cache.
Keep the tool binary under the module root and reference it via PATH.
go test intentionally ignores file deps outside the module root for caching.
This cannot be fixed in transcript; keep deps under the module root.
If the test process opens a very recently modified regular file, go test
can refuse to cache the run. % dep uses stat for file deps, but % dep < deps.txt still opens the depfile due to <. Prefer stable depfiles.
- Deps outside module root are ignored by
go testcaching. - Executables found on
PATHoutside module root are ignored bygo testcaching. - If the test process
opens a very recently modified file,go testcan refuse to cache the run.