test(providers): exercise fire, not ResponseHeaderTimeout, in the leak test

TestWatchdogBody_NoBlockingGoroutineLeak_AcrossManyRequests drove its
timed-out iterations against a server that never wrote headers. That
hits Transport.ResponseHeaderTimeout inside client.Do and returns
before a response ever exists, so watchdogBody.fire never runs and the
test could not have caught a leak in fire itself.

The mutation-verification pass (manually adding a permanently blocked
goroutine to fire, then reverting) confirmed this: the test passed
even with that goroutine present. Fixing the stalling server to write
headers first, mirroring the mid-body-stall tests above it, makes
fire run on every iteration. Re-running the same mutation now fails
the test as intended.
This commit is contained in:
2026-08-23 01:41:02 +01:00
parent 503fc33933
commit 057c061326
+12 -1
View File
@@ -577,7 +577,18 @@ func TestWatchdogBody_NoBlockingGoroutineLeak_AcrossManyRequests(t *testing.T) {
}))
defer fastSrv.Close()
hangSrv, release := newStallingServer(nil)
// prewrite sends headers before stalling: a "never sends headers" hang
// is caught by Transport.ResponseHeaderTimeout, in a *http.Client.Do
// error, and never even constructs a watchdogBody — this test is
// specifically about the WATCHDOG's own goroutine, so its hang must
// stall AFTER headers, the same shape as the mid-body-stall tests
// above, to actually invoke fire() on every one of the iterations
// below.
hangSrv, release := newStallingServer(func(w http.ResponseWriter) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.(http.Flusher).Flush()
})
runtime.GC()
baseline := runtime.NumGoroutine()