slow • Over 5min per Go version, 10+ minutes total, nothing cached between runs • I needed mikro working with Go 1.24 • Only two versions supported at a time, 1.25 coming in August [July as of writing] • Found caching plug-in for Drone CI • Easy win: Cache GOPATH ✓ • Bigger win: Cache GOCACHE... cut CI time in half! • Pleasant surprise: tests started caching too 🥳 • Go compiler knows test dependencies, skips unchanged tests • Muthu, while reviewing, asked: "What about integration tests?" • Because they might get cached and they depend on code the compiler doesn't know about, the cache will never get invalidated, so we can't cache them • …and how do I fi nd a way that has as few changes as possible? So it can work across foodpanda
tests will re-run, safe, no test speedup except for build cache 2. --count=1 • Common but manual approach, you'll see this online, not ideal for our situation (8+ places in mikro which has several go.mods) 3. Environment variables • Elegant, precise, can be little to no work, but requires thoughtful test design
t.Helper() _ = os.Getenv("DRONE_COMMIT_SHA") // Cache invalidation } func TestAPIIntegration(t *testing.T) { // Marks test as integration test integrationtesting.IsIntegrationTest(t) // Your actual test }
SHA: DRONE_COMMIT_SHA, GITHUB_SHA, ... • Go tracks env vars used during tests, different values = cache invalidation (same for fi les) • Reading the variable is enough - you don't need to use it • Package-level invalidation, if any test reads the variable, the entire package cache is invalidated • Keep integration tests in separate packages so unit tests stay cached
docs weren't clear about scope • I didn't trust that it would just work, software rarely do, what's the scope? One test? Package? Sub-packages? Would reading env var invalidate all packages? • Found the testlog package - how Go tracks dependencies • Built an experiment to validate assumptions about scope and boundaries • Because I’d rather show it working, than be theoretical
di ff erent scenarios • Main package with one read through os.Getenv, and tests in several fi les that don’t read • Direct read, I call os.Getenv in this package • External library read, through a func in another Go module • No env vars, to verify that caching isn't a ff ected • 9 scenarios tested, full experiment • What I was trying to learn: What are the boundaries?
I already knew that Go runs packages in parallel, so this fi ts • ✅ Library calls count too • ✅ Package listing is either all (./...) or any list you give it • ❌ go test with no args = no cache • ❌ File-level targeting = no cache
/drone/src/.go/go-build-cache GOPATH: /drone/src/.go GOPRIVATE: github.com/deliveryhero steps: - name: validate-drone-environment # … cut for space … - name: restore-cache image: meltwater/drone-cache pull: true settings: archive_format: gzip cache_key: go-{{ hashFiles "go.mod" "go.sum" }} mount: - .go restore: true Setup where to cache, the meltwater/drone-cache plugin will only work in your working dir
/drone/src/.go/go-build-cache GOPATH: /drone/src/.go GOPRIVATE: github.com/deliveryhero steps: - name: validate-drone-environment # … cut for space … - name: restore-cache image: meltwater/drone-cache pull: true settings: archive_format: gzip cache_key: go-{{ hashFiles "go.mod" "go.sum" }} mount: - .go restore: true Create a hash based on the go.mod and go.sum fi les, so when either changes then clear the cache and start over.
space … - name: save-cache image: meltwater/drone-cache pull: true settings: archive_format: gzip cache_key: go-{{ hashFiles "go.mod" "go.sum" }} mount: - .go override: false rebuild: true depends_on: - ci-cd The setup on CI After: post-test And only do this after the ci-cd step has fi nished green
mikro speci fi cally: I chose the simple go clean -testcache approach • Fast enough already, didn't know tests well enough to optimize further • Go's philosophy: Simple, predictable solutions that just work • No complexity - they built testing concerns into the language itself • Experiment available: github.com/gaqzi/experiment-go-test-caching • sanitarium.se/blog/2025/07/07/working-with-gos-test-cache-on-ci/