You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
go test -race is documented in AGENTS.md and run in CI, but the race detector only flags races on code that executes. The concurrent surface of this codebase is currently unexercised by any test:
StatsdSender (statsd.go) is a goroutine spawned from main that reads forever from a package-global queue chan string of capacity 100. The producers — Increment / Count / Timer / Gauge — write to the same channel from any goroutine, including from inside Destination.Check(). There is no test that runs these concurrently.
MonitorLoop (connectivity.go) spawns len(destinations) goroutines that each call dest.Monitor() in an infinite time.Sleep-loop. No test.
WaitLoop uses a sync.WaitGroup over goroutine-per-destination. No test.
Why this is a real test-engineering problem, not "more tests"
A passing -race build today is a false signal. It says "no races were observed in the code paths we ran," but the only goroutines that the test binary ever spins up are the testing framework's own. The repo's concurrency is currently certified by code review alone.
A handful of small, hermetic tests would change that:
Statsd consumer test — spin up a UDP listener on 127.0.0.1:0, point a *Config at it, run StatsdSender in a goroutine, send N metrics from M goroutines, assert all N arrive and the strings match the wire format. Exercises both the goroutine and the format functions referenced in the other test issue.
WaitLoop test — pass a slice of destinations where each WaitFor is replaced by a hermetic stub (requires a small refactor for testability — pass a func() bool or an interface), then drive the loop and verify wg.Wait() returns.
The current design — package-global queue, StatsdSender(*Config) with no shutdown signal, Destination.Monitor() with an infinite loop and unmockable time.Sleep — is not amenable to any of the above. Each of these tests forces a small testability seam:
queue → an injectable channel or a *StatsdEmitter struct.
StatsdSender → accept a context.Context for cancellation (aligns with AGENTS.md's context.Context plumbing guidance).
Monitor / WaitFor → accept an injectable sleeper/clock or a max-iteration count, or factor the loop body into a separately testable function.
Refs #24 (umbrella). Refs #11 (statsd back-pressure — this would be the regression test). Refs #17 (lifecycle — drain-on-shutdown test belongs there).
go test -raceis documented in AGENTS.md and run in CI, but the race detector only flags races on code that executes. The concurrent surface of this codebase is currently unexercised by any test:StatsdSender(statsd.go) is a goroutine spawned frommainthat reads forever from a package-globalqueue chan stringof capacity 100. The producers —Increment/Count/Timer/Gauge— write to the same channel from any goroutine, including from insideDestination.Check(). There is no test that runs these concurrently.MonitorLoop(connectivity.go) spawnslen(destinations)goroutines that each calldest.Monitor()in an infinitetime.Sleep-loop. No test.WaitLoopuses async.WaitGroupover goroutine-per-destination. No test.queuechannel blocks producers when full (Statsd emitter can stall checks when statsd is down; opens a new connection per metric #11 documents the production hazard). A test that fills the queue with statsd down would expose the back-pressure deadlock the bug describes — that's the closing test for Statsd emitter can stall checks when statsd is down; opens a new connection per metric #11 once it's fixed.Why this is a real test-engineering problem, not "more tests"
A passing
-racebuild today is a false signal. It says "no races were observed in the code paths we ran," but the only goroutines that the test binary ever spins up are the testing framework's own. The repo's concurrency is currently certified by code review alone.A handful of small, hermetic tests would change that:
queueto capacity with no consumer, then callIncrementand assert it blocks (use adonechannel +selectwith timeout). This is the regression test for Statsd emitter can stall checks when statsd is down; opens a new connection per metric #11.127.0.0.1:0, point a*Configat it, runStatsdSenderin a goroutine, send N metrics from M goroutines, assert all N arrive and the strings match the wire format. Exercises both the goroutine and the format functions referenced in the other test issue.WaitLooptest — pass a slice of destinations where eachWaitForis replaced by a hermetic stub (requires a small refactor for testability — pass afunc() boolor an interface), then drive the loop and verifywg.Wait()returns.Prerequisites
The current design — package-global
queue,StatsdSender(*Config)with no shutdown signal,Destination.Monitor()with an infinite loop and unmockabletime.Sleep— is not amenable to any of the above. Each of these tests forces a small testability seam:queue→ an injectable channel or a*StatsdEmitterstruct.StatsdSender→ accept acontext.Contextfor cancellation (aligns with AGENTS.md'scontext.Contextplumbing guidance).Monitor/WaitFor→ accept an injectable sleeper/clock or a max-iteration count, or factor the loop body into a separately testable function.Refs #24 (umbrella). Refs #11 (statsd back-pressure — this would be the regression test). Refs #17 (lifecycle — drain-on-shutdown test belongs there).