Files
TREK/server/tests/unit/db/database-lazy-open.test.ts
T
Maurice be016f180e test(server): seed the session, lease and rollback specs through the factories
The specs written alongside the session, transaction and lifecycle work
still seeded and read with raw statements. They go through the ORM
factories now; the few that test SQL below the ORM carry a test-sql-allow
reason. The raw SQL baseline holds 177 statements in 6 files.
2026-10-08 19:05:04 +02:00

82 lines
3.1 KiB
TypeScript

/**
* db/database.ts opens the connection on first use, not at import.
*
* It used to call initDb() at module load, so importing anything that reached
* it opened the database: index.ts had to defer loading the app until a
* first-boot restore had put the backup's file in place. The connection is now
* opened by its first reader (the ORM's first connect inside buildApp(), driven
* by DatabaseLifecycle), and a connection closed on purpose for a restore stays
* closed until it is reopened.
*
* The cases share the module's one connection and run in order.
*/
import { describe, expect, it, vi } from 'vitest';
const opened = vi.hoisted(() => ({ count: 0 }));
vi.mock('../../../src/db/connection', async (importOriginal) => {
const actual = await importOriginal<typeof import('../../../src/db/connection')>();
return {
...actual,
openDatabase: (...args: Parameters<typeof actual.openDatabase>) => {
opened.count++;
return actual.openDatabase(...args);
},
};
});
import { closeDb, db, getRawConnection, openDb, registerReinitializeHook, reinitialize } from '../../../src/db/database';
describe('db/database.ts connection lifecycle', () => {
it('DBOPEN-001: importing the module opens nothing', () => {
expect(opened.count).toBe(0);
});
it('DBOPEN-002: the first reader opens it once, with the pragmas applied', () => {
const handle = getRawConnection();
expect(getRawConnection()).toBe(handle);
expect(opened.count).toBe(1);
expect(handle.pragma('foreign_keys', { simple: true })).toBe(1);
expect(handle.pragma('busy_timeout', { simple: true })).toBe(5000);
// The Proxy reads through to the same handle.
expect(db.open).toBe(true);
});
it('DBOPEN-003: a connection closed on purpose stays closed instead of quietly reopening', () => {
const log = vi.spyOn(console, 'log').mockImplementation(() => undefined);
try {
closeDb();
} finally {
log.mockRestore();
}
expect(() => getRawConnection()).toThrow('Database connection is not available (restore in progress?)');
// test-sql-allow: tests that the raw db proxy itself refuses a statement while the connection is closed; no ORM is involved.
expect(() => db.prepare('SELECT 1')).toThrow('Database connection is not available (restore in progress?)');
expect(opened.count).toBe(1);
});
it('DBOPEN-004: openDb() reopens it, and opening an open connection is a no-op', () => {
openDb();
openDb();
expect(opened.count).toBe(2);
expect(getRawConnection().open).toBe(true);
});
it('DBOPEN-005: reinitialize() swaps in a fresh handle and then runs the registered hook', async () => {
const before = getRawConnection();
const seen: boolean[] = [];
registerReinitializeHook(async () => {
seen.push(getRawConnection() !== before && getRawConnection().open);
});
const log = vi.spyOn(console, 'log').mockImplementation(() => undefined);
try {
await reinitialize();
} finally {
log.mockRestore();
}
expect(before.open).toBe(false);
expect(seen).toEqual([true]);
expect(opened.count).toBe(3);
});
});