fix(test): harden preload cleanup against Windows EBUSY (#14895)
This commit is contained in:
@@ -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<{
|
||||
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user