69 lines
5.5 KiB
JavaScript
69 lines
5.5 KiB
JavaScript
import EmbeddedPostgres from 'embedded-postgres'
|
|
import { createRequire } from 'node:module'
|
|
import { mkdir, mkdtemp, readdir, readFile, writeFile, cp, rm } from 'node:fs/promises'
|
|
import { resolve, join, relative, dirname, basename } from 'node:path'
|
|
import { randomBytes, createHash } from 'node:crypto'
|
|
import { createServer } from 'node:net'
|
|
import { spawn } from 'node:child_process'
|
|
|
|
const allowed = new Set(['--default-scoped', '--main-only', '--check-only'])
|
|
if (process.argv.slice(2).some(arg => !allowed.has(arg)) || new Set(process.argv.slice(2)).size !== process.argv.slice(2).length || process.argv.includes('--default-scoped') && process.argv.includes('--main-only')) throw new Error('Usage: node backend/scripts/test-routing-controller-baseline.mjs [--default-scoped | --main-only] [--check-only]')
|
|
const root = resolve(import.meta.dirname, '../..'), require = createRequire(import.meta.url), ts = require('typescript')
|
|
const mode = process.argv.includes('--default-scoped') ? 'default-scoped' : process.argv.includes('--main-only') ? 'main-only' : 'main-and-forward-rounds'
|
|
const target = join(root, 'backend/src/modules/mcp/routing-controller-active-writer.ts')
|
|
await readFile(target)
|
|
await readFile(join(root, 'backend/src/modules/mcp/routing-main-transition.ts'))
|
|
await readFile(join(root, 'backend/src/modules/mcp/routing-controller-baseline-acceptance.ts'))
|
|
if (process.argv.includes('--check-only')) { console.log(JSON.stringify({ mode, sourcePresent: true, acceptanceExecuted: false, productionApplied: false })); process.exit(0) }
|
|
await mkdir(join(root, 'tmp'), { recursive: true })
|
|
const ownedPrefix = 'mm-mcp-test-routing-controller-baseline-'
|
|
const directory = await mkdtemp(join(root, 'tmp', ownedPrefix)), output = join(directory, 'dist'), sourcePins = []
|
|
const hash = buffer => createHash('sha256').update(buffer).digest('hex')
|
|
async function compile(sourceDirectory) {
|
|
for (const entry of await readdir(sourceDirectory, { withFileTypes: true })) {
|
|
const path = join(sourceDirectory, entry.name)
|
|
if (entry.isDirectory()) { await compile(path); continue }
|
|
const name = relative(join(root, 'backend/src'), path).replaceAll('\\', '/')
|
|
if (name.endsWith('.test.ts') || name.endsWith('.d.ts')) continue
|
|
const bytes = await readFile(path), emitted = join(output, name.replace(/\.ts$/, '.js'))
|
|
await mkdir(dirname(emitted), { recursive: true })
|
|
await writeFile(emitted, name.endsWith('.ts') ? ts.transpileModule(bytes.toString('utf8'), { compilerOptions: { target: ts.ScriptTarget.ES2022, module: ts.ModuleKind.ESNext, esModuleInterop: true, resolveJsonModule: true } }).outputText : bytes)
|
|
sourcePins.push({ path: name, sourceSha256: hash(bytes), emittedSha256: hash(await readFile(emitted)) })
|
|
}
|
|
}
|
|
await writeFile(join(directory, 'package.json'), '{"type":"module"}')
|
|
await compile(join(root, 'backend/src'))
|
|
await cp(join(root, 'backend/drizzle'), join(directory, 'drizzle'), { recursive: true })
|
|
await writeFile(join(directory, 'snapshot-manifest.json'), JSON.stringify({ mode, productionApplied: false, wholeMutableWorktreeFrozen: false, sourcePins }, null, 2))
|
|
const listener = createServer()
|
|
await new Promise(resolve => listener.listen(0, '127.0.0.1', resolve))
|
|
const port = listener.address().port
|
|
await new Promise(resolve => listener.close(resolve))
|
|
const password = randomBytes(24).toString('hex')
|
|
const postgres = new EmbeddedPostgres({ databaseDir: join(directory, 'pg'), port, user: 'mcp_test', password,
|
|
persistent: true, createPostgresUser: false, initdbFlags: ['--encoding=UTF8'], postgresFlags: ['-h', '127.0.0.1'], onLog: () => {}, onError: () => {} })
|
|
let exitCode = 1, log = ''
|
|
console.log(`Owned routing baseline acceptance: ${directory}; mode=${mode}`)
|
|
try {
|
|
await postgres.initialise(); await postgres.start()
|
|
const retained = Object.fromEntries(['SystemRoot', 'WINDIR', 'TEMP', 'TMP', 'PATH', 'Path', 'LOCALAPPDATA', 'APPDATA'].filter(key => process.env[key]).map(key => [key, process.env[key]]))
|
|
exitCode = await new Promise((resolve, reject) => {
|
|
const child = spawn(process.execPath, [join(output, 'test/routing-controller-baseline-acceptance-main.js')], { cwd: directory, windowsHide: true,
|
|
env: { ...retained, DATABASE_URL: `postgresql://mcp_test:${password}@127.0.0.1:${port}/postgres`, DATABASE_PATH: join(directory, 'no-legacy.sqlite'),
|
|
MCP_STATE_DIR: join(directory, 'state'), NODE_ENV: 'test', AUTH_REQUIRED: 'true', AUTH_JWT_SECRET: 'routing-baseline-test-only', MCP_PUBLIC_URL: 'http://localhost:8000/mcp',
|
|
MMAPP_ROUTING_BASELINE_OWN_SQL: 'true', MMAPP_ROUTING_BASELINE_MODE: mode } })
|
|
child.stdout.on('data', bytes => { process.stdout.write(bytes); log += bytes }); child.stderr.on('data', bytes => { process.stderr.write(bytes); log += bytes })
|
|
child.once('error', reject); child.once('exit', code => resolve(code ?? 1))
|
|
})
|
|
} finally {
|
|
await writeFile(join(directory, 'runtime.log'), log)
|
|
// embedded-postgres waits for a new exit event; avoid waiting again if its
|
|
// owned child has already exited. This never targets another database.
|
|
if (postgres.process?.exitCode === null) await postgres.stop()
|
|
if (dirname(resolve(directory)) !== resolve(root, 'tmp') || !basename(directory).startsWith(ownedPrefix)) throw new Error('Owned routing cleanup boundary changed')
|
|
await rm(join(directory, 'pg'), { recursive: true, force: true, maxRetries: 20, retryDelay: 100 })
|
|
console.log('Owned routing PostgreSQL stopped and its data removed; snapshot/log evidence retained')
|
|
}
|
|
console.log(JSON.stringify({ runDirectory: directory, mode, exitCode, productionApplied: false }))
|
|
process.exitCode = exitCode
|