test(lbug): cover checkpoint drain lifecycle

This commit is contained in:
evolution 2026-05-12 00:10:58 +08:00
parent 57306ad5c2
commit 924554e36f
2 changed files with 83 additions and 1 deletions

View file

@ -11,6 +11,13 @@ import path from 'path';
import { describe, expect, it } from 'vitest';
import { createTempDir } from '../helpers/test-db.js';
/**
* LadybugDB's native Windows file lock can outlive Database.close() for
* same-process close/reopen cycles. Keep true reopen coverage on POSIX and
* cover ordering deterministically in lbug-checkpoint-lifecycle.test.ts.
*/
const itLbugReopen = process.platform === 'win32' ? it.skip : it;
describe('safeClose — close + reopen does not surface lock errors', () => {
it('survives 10 sequential open/close/reopen cycles on the same path', async () => {
const tmp = await createTempDir('gitnexus-lbug-close-cycle-');
@ -39,7 +46,7 @@ describe('safeClose — close + reopen does not surface lock errors', () => {
}
});
it('flushes WAL when switching between two database paths in one process', async () => {
itLbugReopen('flushes WAL when switching between two database paths in one process', async () => {
const repoA = await createTempDir('gitnexus-lbug-switch-a-');
const repoB = await createTempDir('gitnexus-lbug-switch-b-');
const dbPathA = path.join(repoA.dbPath, 'lbug');

View file

@ -0,0 +1,75 @@
import { afterEach, describe, expect, it, vi } from 'vitest';
describe('lbug adapter CHECKPOINT lifecycle', () => {
afterEach(() => {
vi.doUnmock('../../src/core/lbug/lbug-config.js');
vi.doUnmock('../../src/core/lbug/extension-loader.js');
vi.resetModules();
vi.clearAllMocks();
});
it('drains and closes CHECKPOINT result before closing connection and database handles', async () => {
vi.resetModules();
const events: string[] = [];
const checkpointResult = {
getAll: vi.fn(async () => {
events.push('checkpoint:getAll');
return [];
}),
close: vi.fn(() => {
events.push('checkpoint:close');
}),
};
const genericResult = {
getAll: vi.fn(async () => []),
close: vi.fn(),
};
const conn = {
query: vi.fn(async (sql: string) => {
if (sql === 'CHECKPOINT') {
events.push('checkpoint:query');
return checkpointResult;
}
return genericResult;
}),
close: vi.fn(async () => {
events.push('conn:close');
}),
};
const db = {
close: vi.fn(async () => {
events.push('db:close');
}),
};
vi.doMock('../../src/core/lbug/lbug-config.js', () => ({
openLbugConnection: vi.fn(async () => ({ db, conn })),
closeLbugConnection: vi.fn(async () => {}),
isDbBusyError: vi.fn((err: unknown) => String(err).toLowerCase().includes('lock')),
isOpenRetryExhausted: vi.fn(() => false),
waitForWindowsHandleRelease: vi.fn(async () => true),
}));
vi.doMock('../../src/core/lbug/extension-loader.js', () => ({
extensionManager: {
ensure: vi.fn(async () => true),
getCapabilities: vi.fn(() => []),
reset: vi.fn(),
},
}));
const adapter = await import('../../src/core/lbug/lbug-adapter.js');
await adapter.initLbug('/tmp/gitnexus-lbug-checkpoint-lifecycle/lbug');
events.length = 0;
await adapter.closeLbug();
expect(events).toEqual([
'checkpoint:query',
'checkpoint:getAll',
'checkpoint:close',
'conn:close',
'db:close',
]);
});
});