Commit b3faeff
fix(tests): retry rmdir to clear Windows EBUSY flake in updater-integration (#7728)
* fix(tests): retry rmdir to clear Windows EBUSY flake in updater-integration
The Windows backend-test job has been intermittently red on `crash-loop
guard: bootCount=3 forces immediate rollback` (and other cases in
`updater-integration.ts`) with:
Error: EBUSY: resource busy or locked, rmdir
'C:\Users\RUNNER~1\AppData\Local\Temp\updater-it-...'
Each `it()` builds a temp git repo via `execSync('git ...')` and cleans
up in a `try…finally` with `fs.rm(dir, {recursive: true, force: true})`.
On Windows, git child processes can briefly hold file handles after
exit (NTFS lazy-release / antivirus scan / pack-file handles), so the
first rmdir attempt hits EBUSY. `fs.rm`'s default `maxRetries` is 0, so
there is no recovery and the test errors out.
Hoist the cleanup to a single `cleanupTmp()` helper that passes
`maxRetries: 10, retryDelay: 100` (a built-in `fs.rm` capability since
Node 14.14). On Linux/macOS this is a no-op — there's nothing to retry.
On Windows it absorbs the transient lock.
No production code touched.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(tests): poll for rollback terminal state instead of 250ms sleep
Windows CI failure on this branch surfaced a *second* flake in the same
file (`crash-loop guard: bootCount=3 forces immediate rollback`):
TypeError: Cannot read properties of undefined (reading 'execution')
at updater-integration.ts:230
`checkPendingVerification` kicks off `performRollback` as fire-and-forget
(`void performRollback(s, deps).catch(...)`), and the test waits a flat
250 ms before asserting `states.at(-1)!.execution.status === 'rolled-back'`.
On Linux 250 ms is plenty. On Windows, git checkout + spawned-process
bookkeeping regularly push past that — so `saveState` hasn't fired yet
and `states` is empty.
This race was previously masked: the test's `finally` ran `fs.rm`,
which threw EBUSY against handles still held by the in-flight rollback,
and JS's "finally-throws-override-try-throws" semantics meant mocha
reported the EBUSY rather than the underlying TypeError. The retry-rm
patch on this branch unmasked it.
Replace the flat sleep with condition-based polling (25 ms tick, 10 s
ceiling) for a terminal state (`rolled-back` | `rollback-failed`). The
existing `assert.equal(... 'rolled-back')` still runs, giving a clean
diff if rollback landed on the failure side instead. Linux runtime
drops 329 ms → 104 ms because the poll exits as soon as the state
lands.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent c7100e0 commit b3faeff
1 file changed
Lines changed: 22 additions & 7 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
15 | 21 | | |
16 | 22 | | |
17 | 23 | | |
| |||
94 | 100 | | |
95 | 101 | | |
96 | 102 | | |
97 | | - | |
| 103 | + | |
98 | 104 | | |
99 | 105 | | |
100 | 106 | | |
| |||
140 | 146 | | |
141 | 147 | | |
142 | 148 | | |
143 | | - | |
| 149 | + | |
144 | 150 | | |
145 | 151 | | |
146 | 152 | | |
| |||
182 | 188 | | |
183 | 189 | | |
184 | 190 | | |
185 | | - | |
| 191 | + | |
186 | 192 | | |
187 | 193 | | |
188 | 194 | | |
| |||
219 | 225 | | |
220 | 226 | | |
221 | 227 | | |
222 | | - | |
223 | | - | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
224 | 239 | | |
225 | 240 | | |
226 | 241 | | |
227 | 242 | | |
228 | | - | |
| 243 | + | |
229 | 244 | | |
230 | 245 | | |
231 | 246 | | |
| |||
259 | 274 | | |
260 | 275 | | |
261 | 276 | | |
262 | | - | |
| 277 | + | |
263 | 278 | | |
264 | 279 | | |
265 | 280 | | |
0 commit comments