项目文件夹

文件
wehub-resource-sync 3a28426bf4
Check Migrations / Check for duplicate migration numbers (push) Failing after 1s
Lint and Format Check / lint-and-format (push) Failing after 0s
CI Pre-merge Check / CI Pre-merge Check (push) Failing after 2m17s
chore: import upstream snapshot with attribution
2026-07-13 12:23:40 +08:00

89 行
3.6 KiB
TypeScript

import {
getConnections as getInsforgeConnections,
seed,
type GetConnectionResult,
} from 'insforge-test';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const ROOT = path.resolve(__dirname, '..', '..', '..');
const MIGRATIONS = path.join(ROOT, 'backend/src/infra/database/migrations');
const migrationFiles = fs
.readdirSync(MIGRATIONS)
.filter((f) => f.endsWith('.sql'))
.sort()
.map((f) => path.join(MIGRATIONS, f));
/**
* Pre-configured getConnections() for InsForge integration tests.
*
* Seeds the test database by running the full InsForge migration chain
* (db-init.sql + migrations 000–048) so the test schema matches production.
*
* pg_cron can only be installed in the database named by cron.database_name
* (the Docker image hardcodes "insforge"), but pgsql-test creates isolated
* databases with random names. A stub cron schema provides the table and
* function signatures that later migrations reference. The real pgcrypto
* and http extensions are installed normally.
*
* CREATE EXTENSION statements are stripped from migration files because
* extensions are handled in the pre-seed step above.
*/
export const getConnections = (
opts: Parameters<typeof getInsforgeConnections>[0] = {}
): Promise<GetConnectionResult> =>
getInsforgeConnections(opts, [
// 1. Bootstrap roles and event triggers
seed.sqlfile([path.join(ROOT, 'deploy/docker-init/db/db-init.sql')]),
// 2. Install real extensions + stub pg_cron
//
// pgcrypto and http are real extensions from the Docker image.
//
// pg_cron cannot be installed here because CREATE EXTENSION pg_cron
// only works in the database named by cron.database_name (hardcoded
// to "insforge" in postgresql.conf), and pgsql-test creates isolated
// databases with random names. We stub the cron schema because
// migrations 024 and 041 execute DO $$ blocks at migration time
// that SELECT FROM cron.job and PERFORM cron.schedule()/unschedule().
seed.fn(async (ctx) => {
await ctx.pg.query(`
CREATE EXTENSION IF NOT EXISTS pgcrypto;
CREATE EXTENSION IF NOT EXISTS http;
CREATE SCHEMA IF NOT EXISTS cron;
CREATE TABLE IF NOT EXISTS cron.job (
jobid bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
schedule text NOT NULL,
command text NOT NULL,
nodename text DEFAULT 'localhost',
nodeport int DEFAULT 5432,
database text DEFAULT current_database(),
username text DEFAULT current_user,
active boolean DEFAULT true,
jobname text
);
CREATE FUNCTION cron.schedule(cron_schedule text, command text)
RETURNS bigint LANGUAGE sql AS $$ SELECT 0::bigint $$;
CREATE FUNCTION cron.schedule(job_name text, cron_schedule text, command text)
RETURNS bigint LANGUAGE sql AS $$ SELECT 0::bigint $$;
CREATE FUNCTION cron.unschedule(job_id bigint)
RETURNS boolean LANGUAGE sql AS $$ SELECT true $$;
CREATE FUNCTION cron.unschedule(job_name text)
RETURNS boolean LANGUAGE sql AS $$ SELECT true $$;
`);
}),
// 3. Run the full migration chain (000–048), stripping CREATE EXTENSION
// statements since extensions are already installed or stubbed above.
seed.fn(async (ctx) => {
for (const file of migrationFiles) {
const sql = fs
.readFileSync(file, 'utf8')
.replace(/^CREATE EXTENSION IF NOT EXISTS \S+;$/gm, '');
await ctx.pg.query(sql);
}
}),
]);