test(chat): deflake Copilot exec retry attempt-count assertions#4895
test(chat): deflake Copilot exec retry attempt-count assertions#4895devantler wants to merge 1 commit into
Conversation
TestRunCopilotCmdWithRetry's "runs once on success" and "does not retry a non-ETXTBSY failure" subtests write a shell script with os.WriteFile and immediately exec it, asserting attempts == 1. Under heavy parallel load on Linux CI, a concurrent fork can momentarily inherit the still-open write fd to the freshly written file, so the first execve returns a genuine transient ETXTBSY. runCopilotCmdWithRetry correctly retries it, inflating attempts to 2 and intermittently failing the required Test check on unrelated PRs. Add writeSettledExecutable, which writes the script and then execs it until a launch returns a non-ETXTBSY result. The file's only write fd comes from the single os.WriteFile, so once any exec succeeds no process holds a write fd and every subsequent exec is deterministic — keeping the exact attempts == 1 assertion intact rather than loosening it. On macOS (no ETXTBSY enforcement on exec) the loop returns after one exec, so there is no added cost there. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Deflakes TestRunCopilotCmdWithRetry by pre-settling freshly written test scripts before timing the attempts == 1 exec assertions, avoiding transient ETXTBSY races on Linux CI.
Changes:
- Add
writeSettledExecutablehelper that retries exec until non-ETXTBSYresult. - Use the new helper in the two subtests asserting an exact attempt count.
❌MegaLinter analysis: Error❌ COPYPASTE / jscpd - 7 errors❌ REPOSITORY / osv-scanner - 1 error❌ ACTION / zizmor - 1 error✅ Linters with no issuesactionlint, bash-exec, git_diff, hadolint, jsonlint, lychee, markdown-table-formatter, markdownlint, prettier, prettier, shellcheck, shfmt, stylelint, syft, trivy-sbom, trufflehog, v8r, v8r, yamllint Notices📣 MegaLinter 9.5.0 is out! Discover the new features and security recommendations in the release announcement. (Skip this info by defining See detailed reports in MegaLinter artifacts
|
Code Coverage OverviewLanguages: Go Go / code-coverage/goThe overall coverage in the branch is 55%. Coverage data for the branch is not yet available. Show a code coverage summary of the most covered files.
Code Coverage is in Public Preview. Learn more and provide us with your feedback. |

What
Makes
TestRunCopilotCmdWithRetrydeterministic by settling the freshly written test script before the timed/counted exec. Touches onlypkg/cli/cmd/chat/chat_exec_retry_test.go.Why
Two subtests —
returns nil and runs once on successanddoes not retry a non-ETXTBSY failure— write a shell script withos.WriteFileand immediately exec it, assertingattempts == 1.Under heavy parallel load on Linux CI runners, a concurrent fork in another test can momentarily inherit the still-open write fd to the freshly written file, so the first
execvereturns a genuine transientETXTBSY("text file busy").runCopilotCmdWithRetrycorrectly retriesETXTBSY, soattemptsbecomes2and the exact-count assertion fails. This intermittently blocks the required 🧪 Test check on unrelated PRs.This is a pre-existing flake, unrelated to any feature work.
How
Adds a
writeSettledExecutablehelper that writes the script and then execs it until a launch returns a non-ETXTBSYresult. The file's only write fd comes from the singleos.WriteFile, so once any exec succeeds no process holds a write fd and every subsequent exec is deterministic. This keeps the strong, intent-revealingattempts == 1assertion intact rather than loosening it.The same flaky pattern affected both
attempts == 1subtests, so both now use the settled helper. On macOS (ETXTBSYon exec of a write-open file isn't enforced) the loop returns after a single exec, so there's no added cost there; it only absorbs the race on Linux, which is where CI both hits the flake and measures coverage.Verification
go build+go vet ./pkg/cli/cmd/chat/— passgo test -run TestRunCopilotCmdWithRetry -count=50 ./pkg/cli/cmd/chat/— pass (run twice)go test -race ./pkg/cli/cmd/chat/— passgolangci-lint run— the changed file is clean (remaininggoconstfindings are pre-existing inchat_test.go/chat_additional_test.go, untouched here)🤖 Generated with Claude Code