summaryrefslogtreecommitdiffhomepage
path: root/packages
diff options
context:
space:
mode:
authorLuke Parker <[email protected]>2026-02-24 21:59:14 +1000
committerGitHub <[email protected]>2026-02-24 21:59:14 +1000
commita292eddeb516ebf1774e68640b4c62ad284472b2 (patch)
treedc3e468618a68df283f4c129c80e31d3d5bd329d /packages
parent79254c10201a3978ac72ef2a047bb4070efdc41d (diff)
downloadopencode-a292eddeb516ebf1774e68640b4c62ad284472b2.tar.gz
opencode-a292eddeb516ebf1774e68640b4c62ad284472b2.zip
fix(test): harden preload cleanup against Windows EBUSY (#14895)
Diffstat (limited to 'packages')
-rw-r--r--packages/opencode/src/storage/db.ts13
-rw-r--r--packages/opencode/test/preload.ts21
2 files changed, 31 insertions, 3 deletions
diff --git a/packages/opencode/src/storage/db.ts b/packages/opencode/src/storage/db.ts
index 6d7bfd728..f29aac18d 100644
--- a/packages/opencode/src/storage/db.ts
+++ b/packages/opencode/src/storage/db.ts
@@ -33,6 +33,10 @@ export namespace Database {
type Journal = { sql: string; timestamp: number }[]
+ const state = {
+ sqlite: undefined as BunDatabase | undefined,
+ }
+
function time(tag: string) {
const match = /^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/.exec(tag)
if (!match) return 0
@@ -69,6 +73,7 @@ export namespace Database {
log.info("opening database", { path: path.join(Global.Path.data, "opencode.db") })
const sqlite = new BunDatabase(path.join(Global.Path.data, "opencode.db"), { create: true })
+ state.sqlite = sqlite
sqlite.run("PRAGMA journal_mode = WAL")
sqlite.run("PRAGMA synchronous = NORMAL")
@@ -95,6 +100,14 @@ export namespace Database {
return db
})
+ export function close() {
+ const sqlite = state.sqlite
+ if (!sqlite) return
+ sqlite.close()
+ state.sqlite = undefined
+ Client.reset()
+ }
+
export type TxOrDb = Transaction | Client
const ctx = Context.create<{
diff --git a/packages/opencode/test/preload.ts b/packages/opencode/test/preload.ts
index a6d96cf17..41028633e 100644
--- a/packages/opencode/test/preload.ts
+++ b/packages/opencode/test/preload.ts
@@ -3,14 +3,29 @@
import os from "os"
import path from "path"
import fs from "fs/promises"
-import fsSync from "fs"
import { afterAll } from "bun:test"
// Set XDG env vars FIRST, before any src/ imports
const dir = path.join(os.tmpdir(), "opencode-test-data-" + process.pid)
await fs.mkdir(dir, { recursive: true })
-afterAll(() => {
- fsSync.rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 500 })
+afterAll(async () => {
+ const { Database } = await import("../src/storage/db")
+ Database.close()
+ const busy = (error: unknown) =>
+ typeof error === "object" && error !== null && "code" in error && error.code === "EBUSY"
+ const rm = async (left: number): Promise<void> => {
+ Bun.gc(true)
+ await Bun.sleep(100)
+ return fs.rm(dir, { recursive: true, force: true }).catch((error) => {
+ if (!busy(error)) throw error
+ if (left <= 1) throw error
+ return rm(left - 1)
+ })
+ }
+
+ // Windows can keep SQLite WAL handles alive until GC finalizers run, so we
+ // force GC and retry teardown to avoid flaky EBUSY in test cleanup.
+ await rm(30)
})
process.env["XDG_DATA_HOME"] = path.join(dir, "share")