import test from 'node:test' import assert from 'node:assert/strict' import { createRequire } from 'node:module' import { mkdtempSync, rmSync, writeFileSync, existsSync, mkdirSync, symlinkSync } from 'node:fs' import { tmpdir } from 'node:os' import { resolve, join } from 'node:path' import { spawnSync } from 'node:child_process' import { fixtureDatabaseConstructor } from '../bench/fixture.mjs' const root = resolve(import.meta.dirname, '../..') const Database = createRequire(join(root, 'packages/db/package.json'))('better-sqlite3') const script = join(root, 'deploy/docker/evofw/sqlite-backup.mjs') test('online backup includes committed WAL and restore verifies before offline replacement', () => { const directory = mkdtempSync(join(tmpdir(), 'evofw-backup-test-')) let db try { // Isolated pnpm-shaped tree: the dependency is a sibling of the real package, // never a top-level dependency reachable from its logical symlink location. const store = join(directory, 'virtual-store/node_modules') const realPackage = join(store, '@evofw/db') mkdirSync(realPackage, { recursive: true }) writeFileSync(join(realPackage, 'package.json'), '{"name":"@evofw/db"}') mkdirSync(join(directory, 'node_modules/@evofw'), { recursive: true }) const actualDependency = createRequire(join(root, 'packages/db/package.json')).resolve('better-sqlite3/package.json') symlinkSync(resolve(actualDependency, '..'), join(store, 'better-sqlite3'), 'junction') symlinkSync(realPackage, join(directory, 'node_modules/@evofw/db'), 'junction') const env = { ...process.env } delete env.NODE_PATH const run = (...args) => spawnSync(process.execPath, [script, ...args], { cwd: directory, encoding: 'utf8', env }) assert.throws(() => createRequire(join(directory, 'node_modules/@evofw/db/package.json'))('better-sqlite3'), { code: 'MODULE_NOT_FOUND' }) const previousDirectory = process.cwd() try { process.chdir(directory); assert.equal(fixtureDatabaseConstructor(), Database) } finally { process.chdir(previousDirectory) } const source = join(directory, 'source.db') const backup = join(directory, 'backup.db') const restored = join(directory, 'restored.db') db = new Database(source) db.pragma('journal_mode = WAL') db.exec('CREATE TABLE records(id INTEGER PRIMARY KEY, value TEXT); INSERT INTO records VALUES(1,\'committed WAL\')') assert.ok(existsSync(`${source}-wal`)) const result = run('backup', source, backup) assert.equal(result.status, 0, result.stderr) const snapshot = new Database(backup, { readonly: true }) assert.equal(snapshot.prepare('SELECT value FROM records').get().value, 'committed WAL') snapshot.close() assert.notEqual(run('backup', source, backup).status, 0, 'never overwrite an existing backup') assert.notEqual(run('restore', backup, restored).status, 0, 'offline declaration required') writeFileSync(restored, 'old offline data') writeFileSync(`${restored}-wal`, 'stale') writeFileSync(`${restored}-shm`, 'stale') const recovery = run('restore', backup, restored, '--offline') assert.equal(recovery.status, 0, recovery.stderr) assert.ok(!existsSync(`${restored}-wal`)) const recovered = new Database(restored, { readonly: true }) assert.equal(recovered.prepare('SELECT value FROM records').get().value, 'committed WAL') recovered.close() const invalid = join(directory, 'invalid.db') writeFileSync(invalid, 'not sqlite') assert.notEqual(run('restore', invalid, restored, '--offline').status, 0) const preserved = new Database(restored, { readonly: true }) assert.equal(preserved.prepare('SELECT count(*) AS n FROM records').get().n, 1) preserved.close() } finally { db?.close() rmSync(directory, { recursive: true, force: true }) } })