Repository Public
1// V8 hardening (C): the shared test-database helper. Names are unique per checkout and per run; a database is created empty2// and dropped again; nothing but spw_t_* databases can ever be dropped by it.3import { readdirSync, readFileSync } from 'node:fs';4import path from 'node:path';5import postgres from 'postgres';6import { describe, expect, it } from 'vitest';7import { createTestDb, dropTestDbs, newRunId, REPO_ROOT, runId, TEST_DB_PREFIX, testDbName } from './test-db.ts';89describe('test databases', () => {10 it('a name carries the run id (start time, checkout hash, random) and the label; two runs never share one', () => {11 expect(process.env.SPW_TEST_RUN, 'vitest global setup sets the run id').toMatch(/^[0-9a-z]+_[0-9a-f]{8}$/);12 expect(runId()).toBe(process.env.SPW_TEST_RUN);13 expect(testDbName('api')).toBe(`${TEST_DB_PREFIX}${process.env.SPW_TEST_RUN}_api`);14 const a = newRunId(), b = newRunId();15 expect(a).not.toBe(b);16 expect(a.split('_')[1]!.slice(0, 4)).toBe(b.split('_')[1]!.slice(0, 4)); // same checkout: same path hash17 expect(testDbName('x'.repeat(30)).length).toBeLessThanOrEqual(63); // PostgreSQL's identifier limit18 for (const bad of ['', 'UPPER', 'a-b', 'a b', 'x'.repeat(31), 'a;drop']) expect(() => testDbName(bad), bad).toThrow(/label/);19 });2021 it('creates an empty database, drops it, and never matches a database outside the prefix', async () => {22 const db = await createTestDb('helper_selftest'), sql = postgres(db.url, { max: 1, onnotice: () => {} });23 expect((await sql`select count(*)::int as n from information_schema.tables where table_schema = 'public'`)[0]!.n).toBe(0);24 await sql`create table t (x int)`; await sql.end();25 const again = await createTestDb('helper_selftest'), sql2 = postgres(again.url, { max: 1, onnotice: () => {} }); // same label: recreated empty26 expect((await sql2`select count(*)::int as n from information_schema.tables where table_schema = 'public'`)[0]!.n).toBe(0);27 await sql2.end();28 await db.drop();29 const admin = postgres('postgres:///postgres', { max: 1, onnotice: () => {} });30 expect(await admin`select 1 from pg_database where datname = ${db.name}`).toHaveLength(0);31 await admin.end();32 const seen: string[] = [];33 await dropTestDbs((n) => { seen.push(n); return false; });34 for (const n of seen) expect(n.startsWith(TEST_DB_PREFIX)).toBe(true);35 }, 180_000);3637 // v10 integration: the convention is CHECKED, so a test file merged from another branch cannot bring a fixed name back38 // (bridge-sol.test.ts and derivatives-gmx.test.ts arrived from `main` with spw_test_cctp_sol / spw_deriv_gmx_test).39 it('no test file of the vitest suite names a database itself: every one comes from this helper', () => {40 const files: string[] = [];41 const walk = (dir: string): void => { for (const e of readdirSync(dir, { withFileTypes: true })) { if (e.name === 'node_modules' || e.name === 'fixtures') continue; const p = path.join(dir, e.name); if (e.isDirectory()) walk(p); else if (/\.(ts|mts)$/.test(e.name)) files.push(p); } };42 for (const group of ['packages', 'services', 'apps']) for (const pkg of readdirSync(path.join(REPO_ROOT, group), { withFileTypes: true })) {43 const dir = path.join(REPO_ROOT, group, pkg.name, 'test'); try { walk(dir); } catch { /* a package without tests */ }44 }45 expect(files.length).toBeGreaterThan(100);46 const offenders: string[] = [];47 for (const f of files) {48 const rel = path.relative(REPO_ROOT, f); if (rel === 'services/api/test/test-db.ts' || rel === 'services/api/test/test-db.test.ts') continue;49 const code = readFileSync(f, 'utf8').replace(/\/\*[\s\S]*?\*\//g, '').replace(/(^|\s)\/\/.*$/gm, '$1'); // comments may still tell the history50 // a literal database name in a URL (not the placeholder of files that never query, not a name interpolated from the helper), a database created or dropped by hand, an admin connection, a legacy name51 for (const m of code.matchAll(/postgres(?:ql)?:\/\/\/?([A-Za-z0-9_$\{\}.:@-]*)/g)) if (/^[A-Za-z0-9_]+$/.test(m[1]!) && m[1] !== 'unused') offenders.push(`${rel}: ${m[0]}`);52 if (/create database|drop database|\bcreatedb\b|\bdropdb\b/i.test(code)) offenders.push(`${rel}: creates or drops a database itself`);53 for (const m of code.matchAll(/['"`](spw_[a-z0-9_]*test[a-z0-9_]*)['"`]/g)) offenders.push(`${rel}: fixed name ${m[1]}`);54 for (const m of code.matchAll(/\b(?:useDatabase|useTestDatabase|createTestDb|testDbName|alertsWorld)\(\s*['"`]([^'"`]*)['"`]/g)) if (/^spw_|_test$/.test(m[1]!)) offenders.push(`${rel}: label ${m[1]} looks like a fixed database name`);55 }56 expect(offenders).toEqual([]);57 });58});59