Files
MikrotikManager/backend/scripts/test-routing-controller-baseline.mjs
T

68 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 } 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 directory = await mkdtemp(join(root, 'tmp/routing-controller-baseline-owned-')), 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') || !directory.includes('routing-controller-baseline-owned-')) 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