import { expect, tap } from '@git.zone/tstest/tapbundle'; import * as smartdb from '../ts/index.js'; import { MongoClient, Db } from 'mongodb'; import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; let tmpDir: string; let localDb: smartdb.LocalSmartDb; let client: MongoClient; let db: Db; let dataPath: string; let corruptedSize: number; function makeTmpDir(): string { return fs.mkdtempSync(path.join(os.tmpdir(), 'smartdb-crash-test-')); } function cleanTmpDir(dir: string): void { if (fs.existsSync(dir)) { fs.rmSync(dir, { recursive: true, force: true }); } } async function startAndConnect(): Promise { localDb = new smartdb.LocalSmartDb({ folderPath: tmpDir }); const info = await localDb.start(); client = new MongoClient(info.connectionUri, { directConnection: true, serverSelectionTimeoutMS: 5000, }); await client.connect(); db = client.db('crashtest'); } tap.test('crash-recovery: create baseline data', async () => { tmpDir = makeTmpDir(); await startAndConnect(); await db.collection('docs').insertMany([ { key: 'a', value: 1 }, { key: 'b', value: 2 }, { key: 'c', value: 3 }, ]); await client.close(); await localDb.stop(); dataPath = path.join(tmpDir, 'crashtest', 'docs', 'data.rdb'); expect(fs.existsSync(dataPath)).toBeTrue(); }); tap.test('crash-recovery: append a torn final record', async () => { const data = fs.readFileSync(dataPath); const partialRecord = data.subarray(64, 94); expect(partialRecord.length).toEqual(30); fs.appendFileSync(dataPath, partialRecord); corruptedSize = fs.statSync(dataPath).size; expect(corruptedSize).toEqual(data.length + partialRecord.length); }); tap.test('crash-recovery: restart truncates invalid tail and preserves valid records', async () => { await startAndConnect(); const repairedSize = fs.statSync(dataPath).size; expect(repairedSize < corruptedSize).toBeTrue(); const docs = await db.collection('docs').find({}).sort({ key: 1 }).toArray(); expect(docs.map(doc => doc.key)).toEqual(['a', 'b', 'c']); }); tap.test('crash-recovery: future writes remain durable after tail repair', async () => { await db.collection('docs').insertOne({ key: 'd', value: 4 }); expect(await db.collection('docs').countDocuments()).toEqual(4); await client.close(); await localDb.stop(); await startAndConnect(); const docs = await db.collection('docs').find({}).sort({ key: 1 }).toArray(); expect(docs.map(doc => doc.key)).toEqual(['a', 'b', 'c', 'd']); }); tap.test('crash-recovery: cleanup', async () => { await client.close(); await localDb.stop(); cleanTmpDir(tmpDir); }); export default tap.start();