leaktest
A small Go package that detects leaked goroutines in tests by diffing stack snapshots taken before and after each test runs.
Repository Health
Technical Analysis
Leaktest is a small, dependency-free Go package that detects goroutine leaks in tests by taking a snapshot of running goroutines before a test runs and comparing it against another snapshot taken afterward. It was refactored out of the goroutine leak detector originally found in Go’s own net/http tests and in the CockroachDB source tree, then packaged as a standalone, reusable module.
Rather than failing on the first mismatch, leaktest polls at a configurable interval (TickerInterval, default 50ms) for up to a timeout (default 5 seconds, a custom duration via CheckTimeout, or an existing context.Context via CheckContext) before reporting any goroutines still running that weren’t present in the original snapshot. It automatically filters out uninteresting goroutines — the test runner itself, the garbage collector, signal handlers, and HTTP keep-alive read/write loops — so failures point at genuine leaks rather than testing-framework noise.
What You Get
- A single
leaktest.Check(t)call that returns a deferred function to run at test end - Configurable timeout and polling interval via
CheckTimeoutand the package-levelTickerIntervalvariable - Context-aware leak checking via
CheckContextfor tying into an existing deadline - Built-in exclusion list for runtime, testing, and HTTP keep-alive goroutines to avoid false positives
Common Use Cases
- Detecting goroutines left running by background workers, pollers, or timers after a test completes
- Verifying HTTP clients correctly close keep-alive connections instead of leaking read/write-loop goroutines
- Bounding leak checks to an existing test’s context deadline with
CheckContext - Confirming mutex, channel, and worker-pool cleanup paths release all spawned goroutines in table-driven tests
Under The Hood
Architecture
The package is a single file (leaktest.go) with a flat, funnel-shaped call graph: the three exported entry points (Check, CheckTimeout, CheckContext) all resolve into CheckContext, which snapshots goroutine IDs via interestingGoroutines, then polls leakedGoroutines against a time.Ticker until either the diff clears or the context is cancelled; parsing and filtering live in unexported helpers (interestingGoroutine, a goroutineByID sort type), and a separate leaktest_utils_test.go supplies an httptest-based keep-alive server used only by the test suite. There’s no dependency injection, no internal layering, and no state beyond a single package-level TickerInterval variable — appropriate given the narrow, single-purpose scope.
Tech Stack
Standard library only: context, fmt, runtime, sort, strconv, strings, and time in the implementation, plus net/http/net/http/httptest in tests. There is no go.mod — the repo predates mandatory Go modules and hasn’t been updated to adopt one, though it still resolves fine as a tagged import path for module-aware consumers. CI is a .travis.yml running go test -race with coverage uploaded to Codecov across Go 1.8 through tip; there’s no Makefile, linter config, or release automation beyond git tags.
Code Quality
Test coverage is genuinely thorough for the package’s size: table-driven cases in leaktest_test.go cover leaking and non-leaking scenarios (infinite loops, blocked selects, mutex contention, HTTP keep-alives with and without DisableKeepAlives), plus dedicated tests for timeout behavior, context cancellation, and the internal stack-parsing logic (TestInterestingGoroutine) including malformed-input error paths. Error handling returns explicit error values from parsing rather than panicking, and naming is clear and idiomatic. There’s no linter configuration and no generics/modern type-safety features, consistent with a package last touched before those became standard, but the -race flag in CI is a meaningful quality signal for concurrency-focused code.
What Makes It Unique
Leaktest doesn’t invent a new detection technique — it’s a direct, tidied-up extraction of the leak-checking pattern already used internally by Go’s own net/http tests and by CockroachDB, repackaged so other projects can import it directly instead of copy-pasting the pattern. Its main design contributions are the poll-with-timeout loop (versus a single point-in-time diff) and the explicit, hand-maintained exclusion list for runtime/testing/HTTP-internal goroutines. It has been inactive since 2020 and predates more actively maintained successors in the same space (e.g. go.uber.org/goleak), so it’s a solid, narrowly-scoped utility rather than a novel one.
Used by 2 apps in this directory
Gotify
Monitoring · Developer Tools
A lightweight, self-hosted push notification server that sends and receives messages in real time over WebSocket, with a sleek web UI and a native Go plugin system.
Weaviate
Databases · Search
Open-source vector database combining semantic search, hybrid queries, RAG, and image search in a single cloud-native system built for production scale.