import assert from "node:assert/strict" import { randomUUID } from "node:crypto" import { basename, dirname, resolve } from "node:path" import { fileURLToPath } from "node:url" assert.equal(process.env.MMAPP_OWN_MIGRATION_SCHEMA_INVENTORY, "true") const databaseUrl = new URL(process.env.DATABASE_URL ?? "") assert.equal(databaseUrl.hostname, "127.0.0.1"); assert.equal(databaseUrl.pathname, "/postgres") assert(["postgres:", "postgresql:"].includes(databaseUrl.protocol)) assert(process.env.MCP_STATE_DIR && basename(dirname(resolve(process.env.MCP_STATE_DIR))).startsWith("mm-mcp-test-")) const { Pool } = await import("pg") const { pool, closePool } = await import("./index.js") const { applySqlMigrations } = await import("./migrate.js") const { inventoryMigrationDirectory, migrationManifestDigest, MIGRATION_MANIFEST } = await import("./migration-manifest.js") const { captureMigrationSchema, compareMigrationSchemas, MigrationSchemaInventoryError } = await import("./migration-schema-inventory.js") const suffix = randomUUID().replaceAll("-", "").slice(0, 12), names: string[] = [] const identifier = (value: string) => { assert(/^mm_schema_[a-z0-9_]+$/.test(value)); return '"' + value + '"' } const database = async (label: string, template?: string) => { const name = `mm_schema_${suffix}_${label}`; identifier(name) await pool.query(`CREATE DATABASE ${identifier(name)} TEMPLATE ${template ? identifier(template) : "template0"}`) names.push(name) const url = new URL(databaseUrl); url.pathname = "/" + name return { name, connection: new Pool({ connectionString: url.toString(), max: 2 }) } } async function capture(connection: InstanceType, options?: Parameters[1]) { const client = await connection.connect() try { await client.query("BEGIN ISOLATION LEVEL REPEATABLE READ READ ONLY") await client.query("SET LOCAL search_path=pg_catalog") await client.query("SET LOCAL TimeZone='UTC'") await client.query("SET LOCAL DateStyle='ISO, YMD'") await client.query("SET LOCAL statement_timeout='5s'") const result = await captureMigrationSchema(client, options) await client.query("ROLLBACK") return result } catch (error) { await client.query("ROLLBACK").catch(() => {}); throw error } finally { client.release() } } const cases: string[] = [] try { await applySqlMigrations(pool) const inventory = await inventoryMigrationDirectory(fileURLToPath(new URL("../../drizzle/", import.meta.url))) assert.equal(inventory.length, MIGRATION_MANIFEST.length) const reference = await database("reference") let baseline: Awaited> try { await applySqlMigrations(reference.connection) baseline = await capture(reference.connection) assert.equal(baseline.format, "pg18-application-schema-v3") assert(baseline.sections.relations.length >= 89) assert(baseline.sections.columns.length > 500) assert(baseline.sections.constraints.length > 100) assert(baseline.sections.functions.length > 0) assert.deepEqual(compareMigrationSchemas(baseline, await capture(reference.connection)), { equal: true, evidenceOnly: true, enrollmentAuthorized: false, sha256: baseline.sha256 }) cases.push("all36 pinned migrations produce repeatable complete PG18 catalog evidence on an actual checked-out read-only backend") } finally { await reference.connection.end() } const independent = await database("independent") try { await applySqlMigrations(independent.connection) const observed = await capture(independent.connection) try { compareMigrationSchemas(baseline!, observed) } catch (error) { // This reference is built exclusively from the pinned repository SQL; // report field names, not function bodies/default values or user data. const differences = Object.keys(baseline!.sections).flatMap(key => { const section = key as keyof typeof baseline.sections, before = baseline!.sections[section], after = observed.sections[section] if (JSON.stringify(before) === JSON.stringify(after)) return [] return [{ section, beforeRows: before.length, afterRows: after.length, fields: [...new Set(before.flatMap((row, i) => Object.keys(row).filter(field => JSON.stringify(row[field]) !== JSON.stringify(after[i]?.[field]))))] }] }) console.error("Independent schema differences:", JSON.stringify(differences)); throw error } cases.push("independently migrated database with different physical OIDs matches the same exact logical schema") } finally { await independent.connection.end() } const mismatches: [string, string][] = [ ["table", "CREATE TABLE public.mm_schema_extra(id integer)"], ["column-default", "ALTER TABLE public.servers ALTER COLUMN name SET DEFAULT 'owned schema drift'"], ["column-type", "ALTER TABLE public.servers ALTER COLUMN name TYPE varchar(999)"], ["index", "CREATE INDEX mm_schema_index ON public.servers(host)"], ["constraint", "ALTER TABLE public.servers ADD CONSTRAINT mm_schema_port CHECK(port>0) NOT VALID"], ["foreign-key", "ALTER TABLE public.servers ADD CONSTRAINT mm_schema_self FOREIGN KEY(id) REFERENCES public.servers(id) DEFERRABLE INITIALLY DEFERRED"], ["sequence", "ALTER SEQUENCE public.servers_id_seq INCREMENT BY 2"], ["comment", "COMMENT ON TABLE public.servers IS 'owned schema drift'"], ["function", "CREATE FUNCTION public.mm_schema_function() RETURNS integer LANGUAGE sql IMMUTABLE AS 'SELECT 7'"], ["view", "CREATE VIEW public.mm_schema_view AS SELECT id FROM public.servers"], ["partition", "CREATE TABLE public.mm_schema_partitioned(id integer) PARTITION BY RANGE(id); CREATE TABLE public.mm_schema_leaf PARTITION OF public.mm_schema_partitioned FOR VALUES FROM(0) TO(10)"], ["trigger", "CREATE FUNCTION public.mm_schema_trigger_fn() RETURNS trigger LANGUAGE plpgsql AS 'BEGIN RETURN NEW; END'; CREATE TRIGGER mm_schema_trigger BEFORE UPDATE ON public.servers FOR EACH ROW EXECUTE FUNCTION public.mm_schema_trigger_fn()"], ] for (const [label, sql] of mismatches) { const target = await database(label.replaceAll("-", "_"), reference.name) try { await target.connection.query(sql) const observed = await capture(target.connection) assert.throws(() => compareMigrationSchemas(baseline!, observed), MigrationSchemaInventoryError, label) cases.push("actual " + label + " drift differs from the complete captured baseline") } finally { await target.connection.end() } } const unsupported = await database("unsupported", reference.name) try { await unsupported.connection.query("ALTER TABLE public.servers ENABLE ROW LEVEL SECURITY; CREATE POLICY mm_schema_policy ON public.servers USING(true)") await assert.rejects(capture(unsupported.connection), MigrationSchemaInventoryError) cases.push("actual unsupported RLS policy refuses capture rather than disappearing from equality") } finally { await unsupported.connection.end() } const control = await database("control", reference.name) try { await control.connection.query("CREATE SCHEMA mm_control; CREATE TABLE mm_control.mm_schema_private(id integer)") await assert.rejects(capture(control.connection), MigrationSchemaInventoryError) const scoped = await capture(control.connection, { scope: { applicationNamespaces: ["public"], excludedControlNamespaces: ["mm_control"] } }) assert(scoped.sections.namespaces.some(row => row.namespace === "mm_control")) assert(!scoped.sections.relations.some(row => row.namespace === "mm_control")) await control.connection.query("CREATE VIEW public.mm_schema_external_view AS SELECT id FROM mm_control.mm_schema_private") await assert.rejects(capture(control.connection, { scope: { applicationNamespaces: ["public"], excludedControlNamespaces: ["mm_control"] } }), MigrationSchemaInventoryError) cases.push("extra namespace refuses by default; explicit control exclusion is inventoried and application cross-dependency still refuses") } finally { await control.connection.end() } const client = await pool.connect() try { await assert.rejects(captureMigrationSchema(client), MigrationSchemaInventoryError); cases.push("autocommit/read-write connection cannot claim a stable read-only catalog snapshot") } finally { client.release() } console.log("Owned migration schema inventory SQL:", JSON.stringify({ cases: cases.length, names: cases, databases: names.length, actualSql: true, pinnedFiles: inventory.length, manifestDigest: migrationManifestDigest(), logicalSchemaDigest: baseline!.sha256, dispatcherChanged: false, enrollmentAuthorized: false, productionDatabaseTouched: false })) } finally { await closePool() }