test(db): isolate default sqlite path under vitest
This commit is contained in:
@@ -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
@@ -12,7 +12,9 @@ import { ensureSharedIndexSchemaCompatibility } from './sharedIndexSchemaCompati
|
|||||||
import { config } from '../config.js';
|
import { config } from '../config.js';
|
||||||
import { ensureRuntimeDatabaseReady } from '../runtimeDatabaseBootstrap.js';
|
import { ensureRuntimeDatabaseReady } from '../runtimeDatabaseBootstrap.js';
|
||||||
import { mkdirSync } from 'fs';
|
import { mkdirSync } from 'fs';
|
||||||
|
import { tmpdir } from 'os';
|
||||||
import { dirname, resolve } from 'path';
|
import { dirname, resolve } from 'path';
|
||||||
|
import { threadId } from 'worker_threads';
|
||||||
|
|
||||||
export type RuntimeDbDialect = 'sqlite' | 'mysql' | 'postgres';
|
export type RuntimeDbDialect = 'sqlite' | 'mysql' | 'postgres';
|
||||||
type SqlMethod = 'all' | 'get' | 'run' | 'values' | 'execute';
|
type SqlMethod = 'all' | 'get' | 'run' | 'values' | 'execute';
|
||||||
@@ -42,7 +44,13 @@ let proxyLogBillingDetailsColumnAvailable: boolean | null = null;
|
|||||||
|
|
||||||
function resolveSqlitePath(): string {
|
function resolveSqlitePath(): string {
|
||||||
const raw = (config.dbUrl || '').trim();
|
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 === ':memory:') return raw;
|
||||||
if (raw.startsWith('file://')) {
|
if (raw.startsWith('file://')) {
|
||||||
const parsed = new URL(raw);
|
const parsed = new URL(raw);
|
||||||
@@ -54,6 +62,35 @@ function resolveSqlitePath(): string {
|
|||||||
return resolve(raw);
|
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 {
|
function requireSqliteConnection(): Database.Database {
|
||||||
if (!sqliteConnection) {
|
if (!sqliteConnection) {
|
||||||
throw new Error('SQLite connection is not initialized');
|
throw new Error('SQLite connection is not initialized');
|
||||||
@@ -993,4 +1030,6 @@ export async function switchRuntimeDatabase(nextDialect: RuntimeDbDialect, nextD
|
|||||||
export const __dbProxyTestUtils = {
|
export const __dbProxyTestUtils = {
|
||||||
wrapQueryLike,
|
wrapQueryLike,
|
||||||
shouldWrapObject,
|
shouldWrapObject,
|
||||||
|
resolveSqlitePath,
|
||||||
|
resolveVitestSqlitePath,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user