fix: make SQLite migrations and e2e reproducible
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
// Full fresh-DB proof, including concurrent runners and failure/signal cleanup.
|
||||
const assert = require('node:assert/strict');
|
||||
const { spawn } = require('node:child_process');
|
||||
const {
|
||||
mkdtempSync,
|
||||
writeFileSync,
|
||||
readFileSync,
|
||||
existsSync,
|
||||
} = require('node:fs');
|
||||
const { tmpdir } = require('node:os');
|
||||
const { join, resolve } = require('node:path');
|
||||
const cwd = resolve(__dirname, '..');
|
||||
const evidence = mkdtempSync(join(tmpdir(), 'wealthledger-sqlite-regression-'));
|
||||
const sentinel = join(evidence, 'user.db');
|
||||
writeFileSync(sentinel, 'fictional user database: must never be opened');
|
||||
const before = readFileSync(sentinel);
|
||||
const databases = new Set();
|
||||
async function check(name, overrides = {}, signal) {
|
||||
const child = spawn(process.execPath, ['test/sqlite.cjs', '--all'], {
|
||||
cwd,
|
||||
env: {
|
||||
...process.env,
|
||||
DATABASE_URL: `file:${sentinel}`,
|
||||
RUST_LOG: 'warn',
|
||||
LOG_LEVEL: 'error',
|
||||
...overrides,
|
||||
},
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
});
|
||||
let log = '';
|
||||
let sent = false;
|
||||
child.stdout.on('data', (chunk) => {
|
||||
log += chunk;
|
||||
if (signal && !sent && log.includes('SQLite ')) {
|
||||
sent = true;
|
||||
child.kill(signal);
|
||||
}
|
||||
});
|
||||
child.stderr.on('data', (chunk) => {
|
||||
log += chunk;
|
||||
});
|
||||
const code = await new Promise((resolve, reject) => {
|
||||
child.once('error', reject);
|
||||
child.once('close', resolve);
|
||||
});
|
||||
writeFileSync(join(evidence, `${name}.log`), log);
|
||||
const dirs = [...log.matchAll(/^SQLite .+: (.+)$/gm)].map(
|
||||
(match) => match[1],
|
||||
);
|
||||
assert.ok(dirs.length > 0, 'runner must allocate a database');
|
||||
for (const dir of dirs) {
|
||||
assert.ok(!databases.has(dir), 'runners must never share databases');
|
||||
databases.add(dir);
|
||||
assert.ok(!existsSync(dir), `runner must clean up ${dir}`);
|
||||
}
|
||||
assert.deepEqual(
|
||||
readFileSync(sentinel),
|
||||
before,
|
||||
'user database must be untouched',
|
||||
);
|
||||
const expected =
|
||||
signal === 'SIGINT'
|
||||
? 130
|
||||
: signal === 'SIGTERM'
|
||||
? 143
|
||||
: overrides.PRISMA_SCHEMA_ENGINE_BINARY
|
||||
? 1
|
||||
: 0;
|
||||
assert.equal(code, expected, `See ${name}.log`);
|
||||
console.log(`PASS ${name}: ${dirs.length} isolated databases`);
|
||||
}
|
||||
(async () => {
|
||||
console.log(`Evidence: ${evidence}`);
|
||||
for (let i = 1; i <= 3; i++) await check(`sequential-${i}`);
|
||||
const parallel = await Promise.allSettled([
|
||||
check('parallel-1'),
|
||||
check('parallel-2', { RUST_LOG: 'error' }),
|
||||
]);
|
||||
for (const result of parallel)
|
||||
if (result.status === 'rejected') throw result.reason;
|
||||
await check('migration-failure', {
|
||||
PRISMA_SCHEMA_ENGINE_BINARY: join(evidence, 'missing-engine'),
|
||||
});
|
||||
await check('sigint', {}, 'SIGINT');
|
||||
await check('sigterm', {}, 'SIGTERM');
|
||||
console.log(`PASS regression: ${evidence}`);
|
||||
})().catch((error) => {
|
||||
console.error(error);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
Reference in New Issue
Block a user