forked from wangziqi/gongxue-base
test: write stable launch persona evidence
This commit is contained in:
48
scripts/launch-persona-smoke-test.js
Normal file
48
scripts/launch-persona-smoke-test.js
Normal file
@@ -0,0 +1,48 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import path from 'node:path';
|
||||
import { parseCliArgs } from './launch-persona-smoke.js';
|
||||
|
||||
const repoRoot = process.cwd();
|
||||
|
||||
const writeOnly = parseCliArgs(['--write', 'docs/refactor/launch-artifacts/launch-persona-smoke.json']);
|
||||
assert.equal(
|
||||
writeOnly.writePath,
|
||||
path.resolve(repoRoot, 'docs/refactor/launch-artifacts/launch-persona-smoke.json'),
|
||||
'--write should resolve stable JSON evidence paths from the repo root',
|
||||
);
|
||||
assert.equal(writeOnly.writeMdPath, '', '--write should not imply a stable Markdown report path');
|
||||
|
||||
const equalsForm = parseCliArgs([
|
||||
'--output-dir=docs/refactor/launch-artifacts',
|
||||
'--write=docs/refactor/launch-artifacts/launch-persona-smoke.json',
|
||||
'--write-md=docs/refactor/launch-artifacts/launch-persona-smoke.md',
|
||||
'--json',
|
||||
]);
|
||||
assert.equal(
|
||||
equalsForm.outputDir,
|
||||
path.resolve(repoRoot, 'docs/refactor/launch-artifacts'),
|
||||
'--output-dir should resolve stable report directories',
|
||||
);
|
||||
assert.equal(
|
||||
equalsForm.writePath,
|
||||
path.resolve(repoRoot, 'docs/refactor/launch-artifacts/launch-persona-smoke.json'),
|
||||
'--write= should resolve stable JSON evidence paths',
|
||||
);
|
||||
assert.equal(
|
||||
equalsForm.writeMdPath,
|
||||
path.resolve(repoRoot, 'docs/refactor/launch-artifacts/launch-persona-smoke.md'),
|
||||
'--write-md= should resolve stable Markdown evidence paths',
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
() => parseCliArgs(['--write']),
|
||||
/requires a file path value/,
|
||||
'--write without a value should fail fast',
|
||||
);
|
||||
assert.throws(
|
||||
() => parseCliArgs(['--unknown']),
|
||||
/Unknown launch persona smoke option/,
|
||||
'unknown options should fail fast instead of silently dropping evidence paths',
|
||||
);
|
||||
|
||||
console.log('[PASS] launch persona smoke cli options');
|
||||
@@ -4,11 +4,16 @@ import { spawn } from 'node:child_process';
|
||||
import fs from 'node:fs/promises';
|
||||
import net from 'node:net';
|
||||
import path from 'node:path';
|
||||
import { pathToFileURL } from 'node:url';
|
||||
import pg from 'pg';
|
||||
|
||||
const DEFAULT_DATABASE_URL = 'postgresql://postgres:postgres@127.0.0.1:54322/postgres';
|
||||
const cliOptions = parseCliArgs(process.argv.slice(2));
|
||||
const databaseUrl = process.env.DATABASE_URL || DEFAULT_DATABASE_URL;
|
||||
const outputDir = process.env.LAUNCH_SMOKE_OUTPUT_DIR || 'docs/refactor/launch-artifacts';
|
||||
const outputDir =
|
||||
cliOptions.outputDir || resolvePathOption(process.env.LAUNCH_SMOKE_OUTPUT_DIR || 'docs/refactor/launch-artifacts');
|
||||
const stableJsonPath = cliOptions.writePath || resolvePathOption(process.env.LAUNCH_SMOKE_WRITE_PATH || '');
|
||||
const stableMdPath = cliOptions.writeMdPath || resolvePathOption(process.env.LAUNCH_SMOKE_WRITE_MD_PATH || '');
|
||||
const startServer = boolEnv('LAUNCH_SMOKE_START_SERVER', !process.env.LAUNCH_SMOKE_API_BASE);
|
||||
const fixedPort = Number(process.env.LAUNCH_SMOKE_API_PORT || 0) || 0;
|
||||
const authMode = normalizeAuthMode(process.env.LAUNCH_SMOKE_AUTH_MODE || 'app_session');
|
||||
@@ -29,6 +34,62 @@ let serverProcess = null;
|
||||
let serverLogs = '';
|
||||
let authTokens = {};
|
||||
|
||||
function resolvePathOption(value) {
|
||||
if (!value) return '';
|
||||
return path.isAbsolute(value) ? value : path.resolve(process.cwd(), value);
|
||||
}
|
||||
|
||||
function readValueArg(argv, index, flag) {
|
||||
const value = argv[index + 1];
|
||||
if (!value || value.startsWith('--')) throw new Error(`${flag} requires a file path value.`);
|
||||
return value;
|
||||
}
|
||||
|
||||
function parseCliArgs(argv = []) {
|
||||
const options = {
|
||||
outputDir: '',
|
||||
writePath: '',
|
||||
writeMdPath: '',
|
||||
};
|
||||
|
||||
for (let index = 0; index < argv.length; index += 1) {
|
||||
const arg = argv[index];
|
||||
if (arg === '--json') {
|
||||
continue;
|
||||
}
|
||||
if (arg === '--output-dir') {
|
||||
options.outputDir = resolvePathOption(readValueArg(argv, index, arg));
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
if (arg.startsWith('--output-dir=')) {
|
||||
options.outputDir = resolvePathOption(arg.slice('--output-dir='.length));
|
||||
continue;
|
||||
}
|
||||
if (arg === '--write') {
|
||||
options.writePath = resolvePathOption(readValueArg(argv, index, arg));
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
if (arg.startsWith('--write=')) {
|
||||
options.writePath = resolvePathOption(arg.slice('--write='.length));
|
||||
continue;
|
||||
}
|
||||
if (arg === '--write-md') {
|
||||
options.writeMdPath = resolvePathOption(readValueArg(argv, index, arg));
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
if (arg.startsWith('--write-md=')) {
|
||||
options.writeMdPath = resolvePathOption(arg.slice('--write-md='.length));
|
||||
continue;
|
||||
}
|
||||
throw new Error(`Unknown launch persona smoke option: ${arg}`);
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
function boolEnv(key, fallback) {
|
||||
const value = process.env[key];
|
||||
if (value === undefined || value === '') return fallback;
|
||||
@@ -483,7 +544,8 @@ async function writeReport(report) {
|
||||
await fs.mkdir(outputDir, { recursive: true });
|
||||
const jsonPath = path.join(outputDir, `launch-persona-smoke-${shanghaiStamp()}.json`);
|
||||
const mdPath = jsonPath.replace(/\.json$/, '.md');
|
||||
await fs.writeFile(jsonPath, `${JSON.stringify(report, null, 2)}\n`, 'utf8');
|
||||
const jsonPayload = `${JSON.stringify(report, null, 2)}\n`;
|
||||
await fs.writeFile(jsonPath, jsonPayload, 'utf8');
|
||||
const lines = [
|
||||
'# 上线前角色旅程烟测报告',
|
||||
'',
|
||||
@@ -498,8 +560,19 @@ async function writeReport(report) {
|
||||
'说明:该脚本会写入少量 `launch_persona_smoke` 测试权益、练习 session、答题和收藏记录。生产环境仅建议在灰度/演练租户运行。',
|
||||
'',
|
||||
];
|
||||
await fs.writeFile(mdPath, `${lines.join('\n')}\n`, 'utf8');
|
||||
return { jsonPath, mdPath };
|
||||
const mdPayload = `${lines.join('\n')}\n`;
|
||||
await fs.writeFile(mdPath, mdPayload, 'utf8');
|
||||
|
||||
if (stableJsonPath) {
|
||||
await fs.mkdir(path.dirname(stableJsonPath), { recursive: true });
|
||||
await fs.writeFile(stableJsonPath, jsonPayload, 'utf8');
|
||||
}
|
||||
if (stableMdPath) {
|
||||
await fs.mkdir(path.dirname(stableMdPath), { recursive: true });
|
||||
await fs.writeFile(stableMdPath, mdPayload, 'utf8');
|
||||
}
|
||||
|
||||
return { jsonPath, mdPath, stableJsonPath, stableMdPath };
|
||||
}
|
||||
|
||||
async function runStep(name, fn) {
|
||||
@@ -543,6 +616,8 @@ async function main() {
|
||||
console.log(`[launch-smoke] status=${report.status}`);
|
||||
console.log(`[launch-smoke] wrote ${files.jsonPath}`);
|
||||
console.log(`[launch-smoke] wrote ${files.mdPath}`);
|
||||
if (files.stableJsonPath) console.log(`[launch-smoke] wrote ${files.stableJsonPath}`);
|
||||
if (files.stableMdPath) console.log(`[launch-smoke] wrote ${files.stableMdPath}`);
|
||||
if (report.status !== 'pass') process.exitCode = 1;
|
||||
} finally {
|
||||
await pool.end();
|
||||
@@ -550,9 +625,13 @@ async function main() {
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(error => {
|
||||
console.error(error);
|
||||
if (serverLogs) console.error(serverLogs);
|
||||
stopServer();
|
||||
process.exit(1);
|
||||
});
|
||||
if (process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) {
|
||||
main().catch(error => {
|
||||
console.error(error);
|
||||
if (serverLogs) console.error(serverLogs);
|
||||
stopServer();
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
export { parseCliArgs };
|
||||
|
||||
Reference in New Issue
Block a user