Skip to content

test: make timing-sensitive tests deterministic - #1330

Merged
Dumbris merged 3 commits into
smart-mcp-proxy:mainfrom
lux-liang:fix/1163-hermetic-flake-tests
Sep 21, 2026
Merged

Dumbris merged 3 commits into
smart-mcp-proxy:mainfrom
lux-liang:fix/1163-hermetic-flake-tests

Conversation

@lux-liang

Copy link
Copy Markdown
Contributor

Summary

  • inject the Docker info runner so resolver tests can assert the selected executable without starting a subprocess
  • keep the production Docker timeout and command behavior unchanged
  • replace the wall-clock masking assertion with deterministic correctness coverage and a benchmark for performance tracking

Closes #1163

Verification

  • go test ./internal/upstream -run '^TestCheckDockerAvailability_(UsesShellwrapResolver|FallbackOnResolverFailure)$' -count=100
  • go test -race ./internal/upstream -run '^TestCheckDockerAvailability_(UsesShellwrapResolver|FallbackOnResolverFailure)$' -count=100
  • go test ./internal/security -run '^TestMaskText(HandlesAPayloadFullOfSecrets|MasksBeyondTheDetectionCap)$' -count=20
  • go test -race ./internal/security -run '^TestMaskTextHandlesAPayloadFullOfSecrets$' -count=10
  • go test ./internal/upstream ./internal/security
  • go test -race ./internal/upstream ./internal/security
  • go vet ./internal/upstream ./internal/security
  • golangci-lint run --new-from-rev=origin/main ./internal/upstream/... ./internal/security/...

@codecov-commenter

codecov-commenter commented Sep 21, 2026

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 66.66667% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/upstream/manager.go 66.66% 0 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

Dumbris and others added 2 commits September 21, 2026 14:02
… rewrite

Code review of the deflaking changes found the hermeticity fixes dropped
guarantees rather than relocating them:

- runDockerInfo's real exec.CommandContext(...).Run() invocation shape had
  zero test coverage (both docker-recovery tests injected a fake runner).
  Add TestRunDockerInfo_ExecutesResolvedBinary and
  TestRunDockerInfo_PropagatesNonZeroExit, which exercise the real subprocess
  path directly and hermetically (no PATH tricks, no wall clock beyond a
  generous timeout).
- The quadratic-time regression guard for MaskText was replaced by a
  benchmark nothing in CI ever runs. Add
  TestMaskTextScalesLinearlyOnAPayloadFullOfSecrets, which compares relative
  growth across payload sizes instead of an absolute wall-clock ceiling, so
  it stays sensitive to a real O(n^2) regression without the flakiness that
  motivated removing the original timing assertion.
- Unify the two DI idioms checkDockerAvailability used for sibling fakes
  (dockerResolverFn package var vs dockerInfoRunner struct field with a
  nil-fallback) into one: dockerInfoRunnerFn, a package var mirroring
  dockerResolverFn. Removes the dead nil-fallback branch entirely.
- Drop the leftover t.Setenv("PATH", ...) and stale comment in
  TestCheckDockerAvailability_UsesShellwrapResolver — the injected runner
  never execs, so PATH was no longer load-bearing for that test.
- Extract secretsPayload() so the correctness test, the new complexity
  guard, and the benchmark build the same payload shape instead of three
  copies that could silently drift apart.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… validate full argv

Cross-review (codex/gpt-5.6-sol) round 1 finding: the fake docker script only
checked $1 == "info", so it would still exit 0 if the --format flag or the Go
template string were deleted or corrupted, silently defeating the test's
stated purpose of catching that exact regression. Require all three arguments
match exactly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Dumbris Dumbris changed the title Make timing-sensitive tests deterministic test: make timing-sensitive tests deterministic Sep 21, 2026
@Dumbris

Dumbris commented Sep 21, 2026

Copy link
Copy Markdown
Member

Thanks for tackling the flaky tests here, @lux-liang — the deflaking approach (injecting the docker command runner, moving the perf check off wall-clock) is exactly right for the CI-stability problem.

I pushed two small follow-up commits on top to close a couple of test-coverage gaps a review surfaced:

  • The real exec.CommandContext invocation shape in runDockerInfo had no test coverage after the DI rewrite (both docker-recovery tests now inject a fake runner) — added TestRunDockerInfo_ExecutesResolvedBinary / TestRunDockerInfo_PropagatesNonZeroExit, which exercise the real subprocess hermetically.
  • The quadratic-time regression guard for MaskText moved to a Benchmark that nothing in CI actually runs — added TestMaskTextScalesLinearlyOnAPayloadFullOfSecrets, a relative-growth comparison (not an absolute wall-clock ceiling) so it stays sensitive to a real O(n²) regression without reintroducing the flakiness you were fixing.
  • Also unified the two DI idioms checkDockerAvailability was using into one, and cleaned up a couple of now-dead bits of test setup.

Everything's been cross-model reviewed clean and stress-tested under -race/-shuffle. Nice work — thanks again!

@Dumbris
Dumbris merged commit 31311ed into smart-mcp-proxy:main Sep 21, 2026
41 of 42 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Flaky: TestCheckDockerAvailability_UsesShellwrapResolver times out at its 2s budget under load

3 participants