test(db): isolate default sqlite path under vitest

This commit is contained in:
ciat-777
2026-03-14 22:27:02 +08:00
parent b834a9bef8
commit c037ea866e
2 changed files with 84 additions and 1 deletions
+44
View File
@@ -0,0 +1,44 @@
import { afterEach, describe, expect, it, vi } from 'vitest';
import { tmpdir } from 'node:os';
import { resolve } from 'node:path';
type DbModule = typeof import('./index.js');
describe('sqlite default path resolution', () => {
let dbModule: DbModule | null = null;
afterEach(async () => {
if (dbModule) {
await dbModule.closeDbConnections();
dbModule = null;
}
delete process.env.DATA_DIR;
delete process.env.DB_URL;
vi.resetModules();
});
it('uses an isolated temp sqlite path under vitest when no db env is configured', async () => {
delete process.env.DATA_DIR;
delete process.env.DB_URL;
vi.resetModules();
dbModule = await import('./index.js');
const sqlitePath = dbModule.__dbProxyTestUtils.resolveSqlitePath();
const sharedRepoPath = resolve('./data/hub.db');
expect(sqlitePath).not.toBe(sharedRepoPath);
expect(sqlitePath).toContain(tmpdir());
expect(sqlitePath).toContain('metapi-vitest');
});
it('still honors explicit DATA_DIR when provided', async () => {
process.env.DATA_DIR = resolve(tmpdir(), 'metapi-explicit-data-dir');
delete process.env.DB_URL;
vi.resetModules();
dbModule = await import('./index.js');
const sqlitePath = dbModule.__dbProxyTestUtils.resolveSqlitePath();
expect(sqlitePath).toBe(resolve(process.env.DATA_DIR, 'hub.db'));
});
});
+40 -1
View File
@@ -12,7 +12,9 @@ import { ensureSharedIndexSchemaCompatibility } from './sharedIndexSchemaCompati
import { config } from '../config.js';
import { ensureRuntimeDatabaseReady } from '../runtimeDatabaseBootstrap.js';
import { mkdirSync } from 'fs';
import { tmpdir } from 'os';
import { dirname, resolve } from 'path';
import { threadId } from 'worker_threads';
export type RuntimeDbDialect = 'sqlite' | 'mysql' | 'postgres';
type SqlMethod = 'all' | 'get' | 'run' | 'values' | 'execute';
@@ -42,7 +44,13 @@ let proxyLogBillingDetailsColumnAvailable: boolean | null = null;
function resolveSqlitePath(): string {
const raw = (config.dbUrl || '').trim();
if (!raw) return resolve(`${config.dataDir}/hub.db`);
if (!raw) {
const isolatedVitestPath = resolveVitestSqlitePath();
if (isolatedVitestPath) {
return isolatedVitestPath;
}
return resolve(`${config.dataDir}/hub.db`);
}
if (raw === ':memory:') return raw;
if (raw.startsWith('file://')) {
const parsed = new URL(raw);
@@ -54,6 +62,35 @@ function resolveSqlitePath(): string {
return resolve(raw);
}
function isVitestRuntime(): boolean {
if ((process.env.VITEST_POOL_ID || '').trim()) {
return true;
}
if ((process.env.VITEST_WORKER_ID || '').trim()) {
return true;
}
const runtimeArgs = [...process.argv, ...process.execArgv]
.map((value) => String(value || '').toLowerCase());
return runtimeArgs.some((value) => value.includes('vitest'));
}
function resolveVitestSqlitePath(): string | null {
if (!isVitestRuntime()) {
return null;
}
if ((process.env.DB_URL || '').trim()) {
return null;
}
if ((process.env.DATA_DIR || '').trim()) {
return null;
}
const workerTag = process.env.VITEST_POOL_ID
|| process.env.VITEST_WORKER_ID
|| `${process.pid}-${threadId}`;
return resolve(tmpdir(), `metapi-vitest-${workerTag}`, 'hub.db');
}
function requireSqliteConnection(): Database.Database {
if (!sqliteConnection) {
throw new Error('SQLite connection is not initialized');
@@ -993,4 +1030,6 @@ export async function switchRuntimeDatabase(nextDialect: RuntimeDbDialect, nextD
export const __dbProxyTestUtils = {
wrapQueryLike,
shouldWrapObject,
resolveSqlitePath,
resolveVitestSqlitePath,
};