Skip to content

fix(lint): serialize Configure() and isolate test registry mutations#755

Merged
morgo merged 1 commit into
block:mainfrom
morgo:fix-lint-test-isolation
May 1, 2026
Merged

fix(lint): serialize Configure() and isolate test registry mutations#755
morgo merged 1 commit into
block:mainfrom
morgo:fix-lint-test-isolation

Conversation

@morgo
Copy link
Copy Markdown
Collaborator

@morgo morgo commented May 1, 2026

Summary

Two related global-state issues in pkg/lint:

  1. Race in RunLinters() (fixes data race: global linter singletons mutated concurrently by Configure() #747) — held the registry as a reader while calling Configure() on globally-registered linter singletons, which mutates fields like raiseError, allowedTypes, charsets. Concurrent callers (parallel migration tests) raced on those fields under -race. Promoted to a writer lock so Configure()+Lint() are serialized; in production RunLinters has no concurrent callers, so the extra serialization is free.

  2. Test pollution from bare Reset() — tests called Reset() to wipe the registry for isolation but never restored the init() snapshot, so subsequent tests in the same binary saw a partial registry. With -count=2, TestPlanChanges_MultiStatementSameTable failed because HasFKLinter was no longer registered. Added a resetForTest(t) helper that captures the init() snapshot once and restores it via t.Cleanup. Migrated existing call sites; TestReset itself still uses bare Reset() since it directly tests the wipe semantics.

Test plan

  • go test -race ./pkg/lint/ -count=5 — passes
  • go test -race -run "TestLintOnly|TestLintNoViolations" -count=20 ./pkg/migration/ — passes (was the racing pair from data race: global linter singletons mutated concurrently by Configure() #747)
  • go test -race -run "TestLint" ./pkg/migration/ -count=3 — passes
  • go test ./pkg/lint/ -count=2 — passes (was failing on main due to test pollution)
  • golangci-lint run ./pkg/lint/... — clean

Fixes #747

🤖 Generated with Claude Code

Two related global-state issues in pkg/lint:

1. RunLinters() held the registry as a reader while calling Configure()
   on globally-registered linter singletons, which mutates fields like
   raiseError, allowedTypes, and charsets. Concurrent callers (e.g.
   parallel migration tests) raced on those fields. Promote to a writer
   lock so Configure+Lint is serialized — RunLinters has no concurrent
   callers in production. Fixes block#747.

2. Tests called Reset() to wipe the registry for isolation but never
   restored the init() snapshot, polluting later tests in the same
   binary. With -count=2, TestPlanChanges_MultiStatementSameTable failed
   because HasFKLinter was no longer registered. Add a resetForTest(t)
   helper that captures the init() snapshot once and restores it via
   t.Cleanup, and migrate the existing Reset() call sites.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@morgo morgo force-pushed the fix-lint-test-isolation branch from a00317c to f0038c3 Compare May 1, 2026 12:56
@morgo morgo merged commit fa47499 into block:main May 1, 2026
12 checks passed
@morgo morgo deleted the fix-lint-test-isolation branch May 1, 2026 13:14
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.

data race: global linter singletons mutated concurrently by Configure()

2 participants