/** * @file Tests server/compat-sqlite.js, the node:sqlite stand-in a plugin * install runs on (better-sqlite3 has no native build there): every * better-sqlite3 API the server uses — `function`, `pluck`, `readonly` / * `fileMustExist` — and a real `server/db.js` boot in a child process with * better-sqlite3 blocked, since the rest of the suite only ever runs on * better-sqlite3 and a missing method there crashes the dashboard at start. * @author Nguyễn Ngọc Trí Vĩ */ const { describe, it, after } = require("node:test"); const assert = require("node:assert/strict"); const fs = require("fs"); const os = require("os"); const path = require("path"); const { spawnSync } = require("child_process"); const Database = require("../compat-sqlite"); const TMP = fs.mkdtempSync(path.join(os.tmpdir(), "agenthub-compat-")); after(() => fs.rmSync(TMP, { recursive: true, force: true })); describe("compat-sqlite", () => { it("registers a SQL function like better-sqlite3's db.function", () => { const db = new Database(":memory:"); db.function("twice", { deterministic: true }, (s) => `${s}${s}`); db.function("one", () => 1); assert.equal(db.prepare("SELECT twice('ab') AS v, one() AS o").get().v, "abab"); db.close(); }); it("pluck() returns the first column from get, all and iterate", () => { const db = new Database(":memory:"); db.exec("CREATE TABLE t (a, b); INSERT INTO t VALUES (1, 'x'), (2, 'y');"); const s = db.prepare("SELECT a, b FROM t ORDER BY a").pluck(); assert.equal(s.get(), 1); assert.deepEqual(s.all(), [1, 2]); assert.deepEqual([...s.iterate()], [1, 2]); assert.equal(db.prepare("SELECT a FROM t WHERE a = 9").pluck().get(), undefined); db.close(); }); it("boots server/db.js and its trim/sweep paths with better-sqlite3 unavailable", () => { const block = path.join(TMP, "no-bs3.js"); fs.writeFileSync( block, `const M = require("module"); const load = M._load; M._load = function (r, ...a) { if (r === "better-sqlite3") throw new Error("blocked"); return load.call(this, r, ...a); };` ); const script = ` const { db, Database } = require("./server/db"); if (Database !== require("./server/compat-sqlite")) throw new Error("not on compat"); const big = JSON.stringify({ tool_input: { content: "x".repeat(20000) } }); db.prepare("INSERT INTO sessions (id) VALUES ('s1')").run(); db.prepare("INSERT INTO events (session_id, event_type, tool_name, data) VALUES ('s1', 'PreToolUse', 'Write', ?)").run(big); require("./server/lib/event-payload").sweepEventPayloads(db).then((r) => { const len = db.prepare("SELECT length(trim_event_data(?)) AS n").get(big).n; console.log(JSON.stringify({ swept: r.rows >= 0, trimmedShorter: len < big.length })); process.exit(0); });`; const r = spawnSync(process.execPath, ["-r", block, "-e", script], { cwd: path.join(__dirname, "..", ".."), env: { ...process.env, DASHBOARD_DB_PATH: path.join(TMP, "boot.db"), AGENTHUB_PRICING_SYNC: "0", }, encoding: "utf8", timeout: 60_000, }); assert.equal(r.status, 0, r.stderr); assert.deepEqual(JSON.parse(r.stdout.trim().split("\n").pop()), { swept: true, trimmedShorter: true, }); }); });