fix(test): drain coalesceRestart goroutines before t.Cleanup (Class H, #170) #39
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "fix/170-goroutine-bleed-test-isolation"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes Task #170 (Class H — Go test goroutine bleed across t.Run boundaries).
Summary
drainCoalesceGoroutine(t, wsID, cycle)test helper that spawnscoalesceRestarton a goroutine matching the production callsite shape (go h.RestartByID(...)) and registers at.Cleanupwithsync.WaitGroup.Waitso the test cannot return while a goroutine is still draining.TestCoalesceRestart_PanicInCycleClearsStateto use the helper. Previously it calledcoalesceRestartsynchronously, which never exercised the production goroutine-survival contract.TestCoalesceRestart_DrainHelperWaitsForGoroutineExitas the deterministic regression guard for the Class H bleed.Why the bleed mattered
With the synchronous test, a future refactor that swapped to
go coalesceRestart(...)would silently let a panicking goroutine outlive the test. In production-shape tests (sqlmock-using neighbours), the goroutine'srunRestartCyclecallsLogActivityto writekind=DELEGATION_FAILED/kind=WORKSPACE_PROVISION_FAILEDrows. AftermockDB.Close()runs int.Cleanup, that INSERT lands in the next test's sqlmock connection asINSERT-not-expected— surface-symptom that the brief flagged onTestPooledWithEICTunnel_PreservesFnErr.Regression-guard contract
TestCoalesceRestart_DrainHelperWaitsForGoroutineExit:t.Runthen panics.t.Runreturns, asserts elapsed >= 150ms (proves the Wait barrier engaged).close(exited)ran (proves the panic-recovery defer chain ran on the goroutine).state.runningwas cleared (sticky-running guard).Mutation-tested: removing
t.Cleanup(wg.Wait)makes the test fail deterministically with elapsed < 300µs.Per saved-memory
feedback_assert_exact_not_substring: regression test asserts an exact-shape contract (elapsed >= blockFor), not a substring-in-output, so it discriminates between "drain works" and "drain skipped".Test plan
go test -race -run "TestCoalesceRestart" -count=10 ./workspace-server/internal/handlers/...— 10/10 passgo test ./workspace-server/internal/handlers/...— full handlers suite greengo vet ./workspace-server/internal/handlers/...— cleant.Cleanup(wg.Wait)removed)Coordination
Scope is
workspace_restart_coalesce_test.goonly — no overlap with sister agents on #173 (workspace-server/Dockerfile.tenant+ publish workflow) or #168 (Class G post-suspension URL audit).🤖 Generated with Claude Code