並行競合の統合テスト設計 — 行ロック保持方式でなくバリア同時起動×多反復で再現し、待機は有界タイムアウトにする
データベース
テスト
並行処理
テスト設計
コードレビュー
判断
運用
並行競合(定員超過・二重登録・一度きり消費など)の正しさを統合テストで固めるときの設計。
競合の作り方
- 外部トランザクションで行ロック(FOR UPDATE 等)を保持して競合を作る方式は、他のロック(例: FK の KEY SHARE ロック)と干渉して「検証したいロックの有無」を分離できなくなる。この方式は検証の上棄却する。
- 代わりに start チャネル等のバリアで全ワーカーを同時解放し、多反復(40回等)で競合を再現する。反復ごとにデータを独立させ(新規リソース)、「成功1・敗者4xx・敗者の剥奪リソース未使用」などをアサートする。
- 再現性の担保として、検証対象のロック(例: LockPairForUpdate)を一時除去したら実際にテストが失敗することを実測する(壊して落ちることで偽陰性を排除)。
待機は必ず有界に
- context.Background() と無期限の wg.Wait() は、DB ロックや接続が停止するとテスト全体のタイムアウトまでハングする。反復ごとに context.WithTimeout + cancel の有界待機にする。
- wg リーク・cancel 漏れ・Fatalf の goroutine 安全性(テスト本体の goroutine から呼ぶ)を確認する。