Skip to content

test(openai): set Gin mode once per package - #179

Merged
kaitranntt merged 3 commits into
kaitranntt:mainfrom
warelik:fix/gin-testmode-race
Aug 19, 2026
Merged

test(openai): set Gin mode once per package#179
kaitranntt merged 3 commits into
kaitranntt:mainfrom
warelik:fix/gin-testmode-race

Conversation

@warelik

@warelik warelik commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Port the accepted CPA gin test-mode race fix to CPAPlus. Sets gin.TestMode once in a package-level TestMain and removes 59 per-test gin.SetMode(gin.TestMode) calls across 9 test files in sdk/api/handlers/openai.

Why (race)

The per-test gin.SetMode(gin.TestMode) calls race under parallel tests: parallel tests write the package-global gin mode (gin package mode var) while other parallel tests read it through gin.New / gin.CreateTestContext. The result is a data race flagged by go test -race.

Reproduced pre-fix (unmodified base, this branch's base 4823235a)

go test -race -count=2 -run 'TestPrepareCodexMultiAgentV2ToolsAtResponsesBoundary$|TestResponsesPreparesCodexMultiAgentV2ToolsForHTTPAndSSE|TestPrepareCodexMultiAgentV2ToolsAtResponsesBoundarySkipsOtherClients' ./sdk/api/handlers/openai/

WARNING: DATA RACE
Write at 0x... by goroutine 20:
  gin.SetMode() gin@v1.10.1/mode.go:72
  openai.TestPrepareCodexMultiAgentV2ToolsAtResponsesBoundarySkipsOtherClients() openai_responses_multi_agent_test.go:186
Previous write at 0x... by goroutine 18:
  gin.SetMode() gin@v1.10.1/mode.go:72
  openai.TestPrepareCodexMultiAgentV2ToolsAtResponsesBoundary() openai_responses_multi_agent_test.go:26
--- FAIL: <3 parallel tests> race detected during execution of test

Change

  • Add sdk/api/handlers/openai/gin_testmode_test.go — package openai, TestMain that calls gin.SetMode(gin.TestMode) once before os.Exit(m.Run()).
  • Remove all per-test gin.SetMode(gin.TestMode) calls (write-write race source) from:
    • gitlab_duo_handler_test.go (2)
    • openai_images_handlers_test.go (1)
    • openai_responses_compact_test.go (3)
    • openai_responses_handlers_stream_error_test.go (5)
    • openai_responses_handlers_stream_test.go (2)
    • openai_responses_multi_agent_test.go (3)
    • openai_responses_signature_test.go (2)
    • openai_responses_websocket_test.go (35)
    • openai_videos_handlers_test.go (6)
  • All 3 t.Parallel() and all gin imports preserved (still used by gin.New/gin.CreateTestContext).

Stat: 10 files changed, 18 insertions(+), 59 deletions(-).

Verification (all green)

  • Post-fix focused race -count=3 (the 3 parallel multi-agent tests): ok, no DATA RACE.
  • Full package race -count=1: ok.
  • Package normal: ok.
  • Full go test ./...: exit 0.
  • go build ./...: exit 0.
  • go vet ./sdk/api/handlers/openai/: exit 0.
  • gofmt clean; git diff --check clean.
  • Invariant: exactly 1 TestMain, exactly 1 real gin.SetMode(gin.TestMode) (in TestMain), zero per-test calls.

Functionally isolated from #175 (author-failover-recovery) — different branch (fix/gin-testmode-race), test-infrastructure only, no production code.

Mirror

CPA: router-for-me/CLIProxyAPI#4948 (identical changes)

Per-test gin.SetMode(gin.TestMode) calls race under parallel tests: concurrent
writes to the package-global gin mode while other parallel tests read it via
gin.New/CreateTestContext. Set it once in TestMain instead and drop the 59
per-test calls.
@warelik

warelik commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

Evidence — race fixed, plus CI build check classification

Change (accepted CPA port, functionally isolated to openai tests)

  • New sdk/api/handlers/openai/gin_testmode_test.go: package openai, TestMain calls gin.SetMode(gin.TestMode) once.
  • Removed 59 per-test gin.SetMode(gin.TestMode) calls across 9 test files (all in sdk/api/handlers/openai/).
  • Stat: 10 files changed, 18 insertions(+), 59 deletions(-). Zero production/non-openai changes.

Pre-fix race (reproduced on unmodified base 4823235a)

go test -race -count=2 on the 3 parallel multi-agent tests → WARNING: DATA RACE
(write-write on gin.SetMode, mode.go:72, at multi_agent_test.go:26/134/186); all 3 FAIL.

Post-fix verification (all green)

  • Focused race -count=3 (the 3 parallel tests): ok, no DATA RACE.
  • Full openai package race -count=1: ok. Package normal: ok.
  • Full go test ./...: exit 0. go build ./...: exit 0. go vet ./sdk/api/handlers/openai/: exit 0.
  • gofmt clean; git diff --check clean.
  • Invariant: exactly 1 TestMain, exactly 1 real gin.SetMode(gin.TestMode) (in TestMain), zero per-test calls, 3 t.Parallel unchanged.

Build CHECK failure is unrelated (pre-existing flake)

build run 31718293427 failed at go test ./... on:
internal/runtime/executor/websocket_session_target_test.go:286: second request error = websocket: close 1006 (abnormal closure): unexpected EOF
(subtest TestWebsocketRetryBindFailureClearsActiveSessionState/Codex_nonstream).

  • This PR touches only sdk/api/handlers/openai/; internal/runtime/executor is unchanged (git diff --name-only HEAD~1 HEAD).
  • That test uses raw websocket/httptest (never gin), so no shared global/gin-mode coupling, and my change lives in a different test binary package.
  • Standalone repro does NOT reproduce:
    • PR head -count=1: ok
    • PR head -count=5: ok (0.753s)
    • Clean base 4823235a (disposable worktree): ok (0.823s)
  • The test forces a past write deadline (SetWriteDeadline(now.Add(-1s))) to induce a write failure, then races active-session recovery — timing-sensitive under full parallel load.

Recommended for maintainer: re-run the build check (or confirm as known flake). No code/test change was made to mask it.

@warelik

warelik commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

W ARELIK added 2 commits August 15, 2026 08:39
No code change. Previous build run failed on a transient
websocket close 1006 unexpected EOF in the test environment.
No code change. TestWebsocketRetryBindFailureClearsActiveSessionState
passes 30/30 locally; CI failure is a timing-sensitive flake.
@kaitranntt
kaitranntt merged commit cec9ee0 into kaitranntt:main Aug 19, 2026
2 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.

2 participants