test: fix EBUSY database lock failures on Windows during teardown#104
Conversation
There was a problem hiding this comment.
1 issue found across 57 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/plugin/src/features/magic-context/boundary-execution-cas-race.test.ts">
<violation number="1" location="packages/plugin/src/features/magic-context/boundary-execution-cas-race.test.ts:55">
P2: Move `createRaceDb` calls back inside `try` to preserve teardown guarantee. If `createRaceDb` throws on `b`, `a` leaks and the temp dir is never deleted.</violation>
</file>
Partial review: This PR has more than 50 files, so cubic reviewed the highest-priority files first. During the trial, paid plans get a higher file limit.
You can try an ultrareview to bypass the file limit, comment @cubic-dev-ai ultrareview. Learn more.
Fix all with cubic | Re-trigger cubic
| it("15. one WAL handle wins set-if-absent and the other no-ops", () => { | ||
| const dir = mkdtempSync(join(tmpdir(), "boundary-exec-race-")); | ||
| const path = join(dir, "context.db"); | ||
| const a = createRaceDb(path); |
There was a problem hiding this comment.
P2: Move createRaceDb calls back inside try to preserve teardown guarantee. If createRaceDb throws on b, a leaks and the temp dir is never deleted.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/plugin/src/features/magic-context/boundary-execution-cas-race.test.ts, line 55:
<comment>Move `createRaceDb` calls back inside `try` to preserve teardown guarantee. If `createRaceDb` throws on `b`, `a` leaks and the temp dir is never deleted.</comment>
<file context>
@@ -50,16 +51,22 @@ function payload(id: string): DeferredExecutePayload {
it("15. one WAL handle wins set-if-absent and the other no-ops", () => {
const dir = mkdtempSync(join(tmpdir(), "boundary-exec-race-"));
+ const path = join(dir, "context.db");
+ const a = createRaceDb(path);
+ const b = createRaceDb(path);
try {
</file context>
The test suite intermittently fails on Windows with 'EBUSY: resource busy or locked' errors when attempting to clean up temporary directories. This happens because SQLite file handles take a moment to release after closing the database connections. Wrapped all rmSync calls in afterEach teardown hooks across the project in try/catch blocks that ignore the error on Windows, and added maxRetries: 10 and retryDelay: 100 to provide a grace period for handles to release.
093f001 to
8d060c2
Compare
| const projectRoot = process.cwd().includes("packages") | ||
| ? join(process.cwd(), "..", "..") | ||
| : process.cwd(); |
There was a problem hiding this comment.
Fragile substring check for project root detection
process.cwd().includes("packages") is a plain substring match, not a path-aware check. It would misfire if the repository is checked out anywhere whose absolute path contains the word "packages" (e.g. /home/packages/magic-context or /opt/node_packages/projects/…), causing .join(cwd, "../..") to walk two levels above an unrelated ancestor. A more robust approach would be to search upward for package.json or packages/plugin using path.resolve, similar to how monorepo tooling discovers workspace roots.
Fixes #102
Bug Description
The test suite intermittently fails on Windows environments with
EBUSY: resource busy or lockederrors during teardown. This occurs because SQLite file handles can take a moment to be completely released by the operating system after database connections are closed. Due to strict file locking on Windows, attempts to synchronously delete temporary directories containing these SQLite databases usingrmSync(dir, { recursive: true, force: true })fail.Fix Details
I wrapped all
rmSynccalls found inafterEachteardown hooks across the project's test suites withintry/catchblocks that silently ignore the error on Windows. Additionally, I modified thermSyncoptions to includemaxRetries: 10andretryDelay: 100, providing a small grace period for any lingering SQLite file handles to release gracefully before aborting.Summary by cubic
Hardened test teardown on Windows to prevent intermittent EBUSY errors from lingering SQLite locks. Cleanup now tolerates delayed handle release and removes temp dirs more reliably across the suite.
compartment-lease.test.tsso the script runs from any cwd.migrations-v11.test.tsfor the Bun test runner.Written for commit 8d060c2. Summary will update on new commits.
Greptile Summary
This PR hardens test teardown across 56 test files to prevent intermittent
EBUSY: resource busy or lockedfailures on Windows, where SQLite file handles may not be fully released beforermSyncattempts to delete the temp directory.rmSyncinafterEach/finallyteardown blocks with{ maxRetries: 10, retryDelay: 100 }and an outertry/catchto tolerate residual Windows file locks.closeQuietlycalls before cleanup inboundary-execution-cas-race.test.tsand lease-related tests that open multiple DB handles, and fixes thepluginRootpath computation incompartment-lease.test.tsto work cross-platform./// <reference types="bun-types" />directive tomigrations-v11.test.tsfor the Bun test runner type resolution.Confidence Score: 3/5
Safe to merge for most test files, but sticky-injection-cas-race.test.ts still leaves database handles open before cleanup, so Windows EBUSY failures are not fully resolved there.
The majority of the 56 changed files receive the correct treatment — closing explicit DB handles and wrapping rmSync with retries. However, sticky-injection-cas-race.test.ts opens two WAL handles (a and b) in tests 1 and 2 but never calls closeQuietly on them before rmSync. Those open handles are the direct source of EBUSY on Windows, and without explicit closure the retry loop may still exhaust its attempts and silently leak the temp directory. The boundary-execution-cas-race.test.ts file in the same PR shows the intended fix pattern, making the omission in sticky-injection an inconsistency that will leave intermittent failures on Windows for those specific tests.
packages/plugin/src/features/magic-context/sticky-injection-cas-race.test.ts needs closeQuietly calls for handles a and b before rmSync in tests 1 and 2 (and db in tests 3 and 4).
Important Files Changed
Comments Outside Diff (1)
packages/plugin/src/features/magic-context/sticky-injection-cas-race.test.ts, line 26-44 (link)closeQuietlybeforermSync— EBUSY still likely on WindowsThe two database handles
aandbopened inside thetryblock are never explicitly closed beforermSyncattempts to delete the directory. On Windows, SQLite WAL handles hold kernel file locks until explicitly released, so these open handles are the direct cause of EBUSY — the same root cause thatcloseQuietlywas added to fix in the parallelboundary-execution-cas-race.test.ts. Thetry/catchonrmSyncsilences the error but leaves the temp directory behind every run; with 10 retries at 100 ms each, the GC might collect the handles in time, but this is not guaranteed and differs from the explicit-close pattern used elsewhere in this PR.Tests 1 and 2 ("two WAL handles append…" and "append plus prune…") both open
aandbviacreateRaceDband leave them open. Tests 3 and 4 use a singledbhandle that is similarly unclosed.Reviews (1): Last reviewed commit: "test: fix EBUSY database lock failures o..." | Re-trigger Greptile