testing: thirty wall-clock sleeps and a hundred `Eventually` polls in tests, zero uses of `testing/synctest` — the standard library's fake clock removes the flake class and the seconds together
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 9
- Forks
- 0
- Avg merge
- 3h 3m
- Merged PRs (30d)
- 509
Description
Observed behavior
At eb8172f, grep -rln 'testing/synctest' --include='*_test.go' pkg cmd | wc -l is 0. The sweep in #1672 counted the other side: unconditional time.Sleep at pkg/flowstate/v1/server/server_test.go:235 (1 s), cmd/flow/workerinternallistener_test.go:207 (2 s), cmd/flow/workershutdown_test.go:284 (1.5 s), pkg/flowstate/v1/plugin/launch_test.go:329 (500 ms), about thirty sleeps in all, and roughly a hundred require.Eventually sites with wall-clock bounds, one of which failed under package-parallel load during this review (flowfile/lsp/requestrace_test.go:194) and is the shape of #1324's CI flake.
testing/synctest shipped in the standard library at Go 1.25. Inside synctest.Test, time is virtual: time.Sleep and timers advance instantly when every goroutine in the bubble is durably blocked, and synctest.Wait replaces polling. A test that today sleeps two seconds to let a listener close runs in microseconds and cannot flake on a slow runner, because "durably blocked" is a fact the runtime knows rather than a timeout the author guessed. The repository already has the discipline on the product side: flowtest's VirtualClock (clock.go:246-278) is the same idea for workflows. The Go tests never got it.
Not every site qualifies: a test that talks to a real Temporal dev server or a real subprocess has goroutines outside the bubble and stays wall-clock. The ones that do qualify are the ones that flake.
Desired outcome
- Every
time.Sleepin a test either moves intosynctest.Testwith the sleep kept as-is (it becomes instant) or carries a one-line comment naming the external process it waits for. require.Eventuallysites whose condition is satisfied by goroutines in the same test move tosynctest.Waitplus a plain assertion.- The LSP request-race tests and the plugin launch tests are the first two conversions, since they are the two that have flaked on record.
tools/vacuityor a smallgo vet-style check reports atime.Sleepin a_test.gofile outsidesynctest.Testwithout the comment, so the count ratchets down and does not come back.
Acceptance criteria
go test ./pkg/flowstate/v1/flowfile/lsp/ ./pkg/flowstate/v1/plugin/wall time drops by the sum of the sleeps removed, stated in the PR.- The converted tests pass under
-count=20 -race -cpu=1, the gate's ordering leg. - The ratchet check runs in the gate.
Constraints and dependencies
- Adjacent: #1672 (the idiom sweep), #1324 (the CI flake), #431 and #246 (closed timing flakes), #477 (deterministic simulation as a tier).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reviewing the listed sleeps in pkg/flowstate/v1/server/server_test.go, cmd/flow/workerinternallistener_test.go, cmd/flow/workershutdown_test.go, pkg/flowstate/v1/plugin/launch_test.go, and flowfile/lsp/requestrace_test.go, then run the two stated package tests. Determine which cases qualify for testing/synctest and inspect tools/vacuity for the ratchet check. Done means qualifying tests use virtual time, exceptions are commented, the -count=20 -race -cpu=1 run passes, and the gate runs the check.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- testing, tooling
- Issue type
- Refactor
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 35/100