picatz / picatz/flowstate

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

Open
#1,706 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement testing
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.Sleep in a test either moves into synctest.Test with the sleep kept as-is (it becomes instant) or carries a one-line comment naming the external process it waits for.
  • require.Eventually sites whose condition is satisfied by goroutines in the same test move to synctest.Wait plus 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/vacuity or a small go vet-style check reports a time.Sleep in a _test.go file outside synctest.Test without 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.