Files
pad/internal/store/testing_helpers.go
T
xarmian c2351d861d fix(ci): lower test-only bcrypt cost + re-enable -race on PRs (BUG-1371) (#513)
The full `internal/server` test suite under `-race` had grown past the
30m CI timeout, failing every push to main since ~TASK-1354. Diagnosis:
bcrypt at the production cost (12) takes ~3s per call under the race
detector, and dozens of tests now bootstrap a user via the loopback
HTTP path (`bootstrapFirstUser` → `store.CreateUser` →
`bcrypt.GenerateFromPassword`). Cumulative cost dominated the budget.

Two coordinated changes:

1. Lower bcrypt cost in test binaries. `bcryptCost` becomes a package
   var (still package-private), and a new `SetBcryptCostForTesting`
   helper lets each test binary's `TestMain` drop it to
   `bcrypt.MinCost`. Production stays at 12 — only the test process
   ever mutates the value.

2. Re-enable `-race` on pull requests. The `if: github.ref ==
   'refs/heads/main'` gate was originally a GitHub Actions minutes
   cost-control; the repo is public now, so PR minutes are free, and
   we'd rather catch race regressions on the contributing branch than
   after merge.

Measured impact:
- `go test -race ./internal/server`: 1800s timeout → 830s (13m51s).
- `go test ./internal/store`: 808s → 35s.
- `go test ./internal/server`: 192s → 60s.

The 30m timeout stays — it's headroom for genuine deadlocks, which
would still hit the goroutine-dump panic the way BUG-851 did.

Prior art: BUG-851 (10m → 30m bump, ipRateLimiter goroutine drain).
This is a different cause (bcrypt cumulative time) so the fix is
different.
2026-05-12 10:01:14 -04:00

24 lines
1.0 KiB
Go

package store
// SetBcryptCostForTesting overrides the bcrypt cost used by CreateUser
// and UpdateUser for the lifetime of a test binary. It returns a
// restore function — call it from TestMain (or defer it) to leave
// the package state clean, though process exit also suffices since
// the override is local to the test binary.
//
// Why this exists: under the race detector, bcrypt.GenerateFromPassword
// at the production cost (12) takes ~3s per call. The internal/server
// and internal/store test suites bootstrap dozens of users each; the
// cumulative cost exceeded the 30m CI -race timeout (BUG-1371). Tests
// that don't care about hash strength call this once per binary in
// TestMain to drop the cost to bcrypt.MinCost (= 4), which restores
// the race step to well under the timeout.
//
// Production code MUST NOT call this. The "ForTesting" suffix is the
// grep signal — any non-test caller is a bug.
func SetBcryptCostForTesting(cost int) func() {
prev := bcryptCost
bcryptCost = cost
return func() { bcryptCost = prev }
}