Skip to content

test(chat): deflake Copilot exec retry attempt-count assertions#4895

Open
devantler wants to merge 1 commit into
mainfrom
claude/elastic-spence-e0a54d
Open

test(chat): deflake Copilot exec retry attempt-count assertions#4895
devantler wants to merge 1 commit into
mainfrom
claude/elastic-spence-e0a54d

Conversation

@devantler
Copy link
Copy Markdown
Contributor

What

Makes TestRunCopilotCmdWithRetry deterministic by settling the freshly written test script before the timed/counted exec. Touches only pkg/cli/cmd/chat/chat_exec_retry_test.go.

Why

Two subtests — returns nil and runs once on success and does not retry a non-ETXTBSY failure — write a shell script with os.WriteFile and immediately exec it, asserting attempts == 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 execve returns a genuine transient ETXTBSY ("text file busy"). runCopilotCmdWithRetry correctly retries ETXTBSY, so attempts becomes 2 and 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 writeSettledExecutable helper that 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. This keeps the strong, intent-revealing attempts == 1 assertion intact rather than loosening it.

The same flaky pattern affected both attempts == 1 subtests, so both now use the settled helper. On macOS (ETXTBSY on 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/ — pass
  • go test -run TestRunCopilotCmdWithRetry -count=50 ./pkg/cli/cmd/chat/ — pass (run twice)
  • go test -race ./pkg/cli/cmd/chat/ — pass
  • golangci-lint run — the changed file is clean (remaining goconst findings are pre-existing in chat_test.go/chat_additional_test.go, untouched here)

Note: this host is macOS, so the local 50× run confirms correctness/no-regression but cannot reproduce the Linux ETXTBSY race. The determinism guarantee on Linux rests on the write-fd reasoning above: the script's sole write fd is closed when os.WriteFile returns, so one clean exec proves no write fd remains.

🤖 Generated with Claude Code

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>
Copilot AI review requested due to automatic review settings May 26, 2026 21:22
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 writeSettledExecutable helper that retries exec until non-ETXTBSY result.
  • Use the new helper in the two subtests asserting an exact attempt count.

@devantler devantler marked this pull request as ready for review May 26, 2026 21:25
@github-actions
Copy link
Copy Markdown
Contributor

MegaLinter analysis: Error

❌ COPYPASTE / jscpd - 7 errors
Clone found (typescript):
 - vsce/src/mcp/schemaClient.ts [325:18 - 332:33] (7 lines, 56 tokens)
   vsce/src/mcp/schemaClient.ts [309:20 - 316:26]

Clone found (typescript):
 - vsce/src/ksail/clusters.ts [381:34 - 390:46] (9 lines, 59 tokens)
   vsce/src/ksail/clusters.ts [361:35 - 370:47]

Clone found (typescript):
 - vsce/src/ksail/clusters.ts [406:44 - 415:46] (9 lines, 61 tokens)
   vsce/src/ksail/clusters.ts [341:33 - 350:48]

Clone found (typescript):
 - vsce/src/ksail/clusters.ts [426:36 - 435:48] (9 lines, 59 tokens)
   vsce/src/ksail/clusters.ts [361:35 - 370:47]

Clone found (typescript):
 - vsce/src/commands/prompts.ts [658:29 - 669:3] (11 lines, 55 tokens)
   vsce/src/commands/prompts.ts [201:8 - 211:3]

Clone found (go):
 - pkg/svc/tenant/argocd.go [400:61 - 413:37] (13 lines, 99 tokens)
   pkg/fsutil/configmanager/talos/manager.go [228:64 - 241:37]

Clone found (typescript):
 - vsce/src/extension.ts [162:46 - 173:18] (11 lines, 59 tokens)
   vsce/src/extension.ts [140:39 - 151:5]

┌────────────┬────────────────┬─────────────┬──────────────┬──────────────┬──────────────────┬───────────────────┐
│ Format     │ Files analyzed │ Total lines │ Total tokens │ Clones found │ Duplicated lines │ Duplicated tokens │
├────────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ toml       │ 6              │ 64          │ 277          │ 0            │ 0 (0%)           │ 0 (0%)            │
├────────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ go         │ 590            │ 97657       │ 640469       │ 1            │ 13 (0.01%)       │ 99 (0.02%)        │
├────────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ markdown   │ 7              │ 302         │ 638          │ 0            │ 0 (0%)           │ 0 (0%)            │
├────────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ typescript │ 23             │ 4084        │ 22492        │ 6            │ 56 (1.37%)       │ 349 (1.55%)       │
├────────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ javascript │ 15             │ 1108        │ 9310         │ 0            │ 0 (0%)           │ 0 (0%)            │
├────────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ tsx        │ 12             │ 1781        │ 14802        │ 0            │ 0 (0%)           │ 0 (0%)            │
├────────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ css        │ 2              │ 45          │ 148          │ 0            │ 0 (0%)           │ 0 (0%)            │
├────────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ smarty     │ 1              │ 63          │ 1039         │ 0            │ 0 (0%)           │ 0 (0%)            │
├────────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ bash       │ 2              │ 52          │ 164          │ 0            │ 0 (0%)           │ 0 (0%)            │
├────────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ Total:     │ 658            │ 105156      │ 689339       │ 7            │ 69 (0.07%)       │ 448 (0.06%)       │
└────────────┴────────────────┴─────────────┴──────────────┴──────────────┴──────────────────┴───────────────────┘
Found 7 clones.
HTML report saved to megalinter-reports/copy-paste/html/
ERROR: jscpd found too many duplicates (0.07%) over threshold (0%)
Error: ERROR: jscpd found too many duplicates (0.07%) over threshold (0%)
    at ThresholdReporter.report (/node-deps/node_modules/@jscpd/finder/dist/index.js:615:13)
    at /node-deps/node_modules/@jscpd/finder/dist/index.js:109:18
    at Array.forEach (<anonymous>)
    at /node-deps/node_modules/@jscpd/finder/dist/index.js:108:22
    at async /node-deps/node_modules/jscpd/dist/bin/jscpd.js:9:5
❌ REPOSITORY / osv-scanner - 1 error
Scanning dir .
Starting filesystem walk for root: /
Scanned docs/package-lock.json file and found 549 packages
Scanned desktop/go.mod file and found 401 packages
Scanned web/ui/package-lock.json file and found 187 packages
Scanned go.mod file and found 965 packages
Scanned vsce/package-lock.json file and found 592 packages
End status: 307 dirs visited, 2028 inodes visited, 5 Extract calls, 105.169029ms elapsed, 105.169229ms wall time
Filtered 1 local/unscannable package/s from the scan.
Failed to run code analysis (govulncheck) on 'desktop/go.mod' because govulncheck: loading packages: 
There are errors with the provided package patterns:

-: # github.com/webview/webview_go
# [pkg-config --cflags  -- gtk+-3.0 webkit2gtk-4.0]
Package gtk+-3.0 was not found in the pkg-config search path.
Perhaps you should add the directory containing `gtk+-3.0.pc'
to the PKG_CONFIG_PATH environment variable
Package 'gtk+-3.0' not found
Package 'webkit2gtk-4.0' not found
/go/pkg/mod/github.com/webview/webview_go@v0.0.0-20240831120633-6173450d4dd6/webview.go:26:8: could not import C (no metadata for C)
desktop/main.go:64:42: cannot use webview.HintNone (constant unknown with invalid type) as webview.Hint value in argument to view.SetSize

For details on package patterns, see https://pkg.go.dev/cmd/go#hdr-Package_lists_and_patterns.

(the Go toolchain is required)
❌ ACTION / zizmor - 1 error
INFO zizmor: 🌈 zizmor v1.25.0
fatal: no audit was performed
'artipacked' audit failed on file://.github/workflows/cd.yaml

Caused by:
    0: error in 'artipacked' audit
    1: couldn't list tags for actions/checkout
    2: request error while accessing GitHub API
    3: HTTP status client error (401 Unauthorized) for url (https://github.com/actions/checkout.git/git-upload-pack)


[ZizmorLinter] Zizmor failed to reach the GitHub API.
To allow zizmor to use GITHUB_TOKEN, add the following to your .mega-linter.yml:
ACTION_ZIZMOR_UNSECURED_ENV_VARIABLES:
  - GITHUB_TOKEN

✅ Linters with no issues

actionlint, 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 SECURITY_SUGGESTIONS: false)

See detailed reports in MegaLinter artifacts

MegaLinter is graciously provided by OX Security
Show us your support by starring ⭐ the repository

@devantler devantler enabled auto-merge May 26, 2026 21:35
@github-code-quality
Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: Go

Go / code-coverage/go

The 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.
File 4aa03bb +/-
pkg/cli/cmd/wor...load/gen/gen.go 96%
pkg/notify/progress.go 94%
pkg/svc/image/exporter.go 92%
pkg/fsutil/conf...alos/configs.go 86%
pkg/cli/cmd/cipher/cipher.go 79%
internal/contro...r_controller.go 79%
pkg/fsutil/gene...os/generator.go 78%
pkg/cli/ui/chat/model.go 70%
pkg/cli/cmd/cluster/cluster.go 55%
pkg/cli/cmd/wor...oad/workload.go 52%

Code Coverage is in Public Preview. Learn more and provide us with your feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: 🫴 Ready

Development

Successfully merging this pull request may close these issues.

2 participants