Files
AriWeb-Suite/test/e2e.test.mjs
T

46 lines
3.4 KiB
JavaScript

/**
* test/e2e.test.mjs — 로컬 종단 간 검증 진입점.
*
* 실제 HAL·포털·Node Agent 프로세스와 가짜 Webmaker/AriMail/메일 서버를 띄우고 test/e2e/flows/*.mjs 의 흐름을 순서대로 실행한 뒤
* docs/verification/local-e2e-<날짜>.md/.json 에 흐름별 판정과 결함을 기록한다.
* ARIWEB_E2E=0 건너뜀
* ARIWEB_E2E_FLOWS=a,b 특정 흐름 그룹만(파일 이름)
* ARIWEB_E2E_STRICT=1 'failed' 판정이 있으면 종료 코드 1(기본은 보고서만 쓰고 통과 — 결함은 보고서가 알린다)
* ARIWEB_E2E_KEEP=1 임시 디렉터리 보존
* 전체 5분 안에 끝나도록 흐름마다 시간 제한을 둔다.
*/
import { test, ok, done } from '../lib/test.mjs';
import { readdirSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { bootEnv } from './e2e/boot.mjs';
import { createReport } from './e2e/report.mjs';
if (process.env.ARIWEB_E2E === '0') { console.log(' (ARIWEB_E2E=0 — 로컬 종단 간 검증 건너뜀)'); done(); }
else {
const HERE = dirname(fileURLToPath(import.meta.url)); const report = createReport(); const startedAt = Date.now(); const log = (...a) => console.log(' ', ...a);
const only = (process.env.ARIWEB_E2E_FLOWS || '').split(',').map((s) => s.trim()).filter(Boolean);
const files = readdirSync(join(HERE, 'e2e', 'flows')).filter((f) => f.endsWith('.mjs')).sort().filter((f) => !only.length || only.some((o) => f.includes(o)));
let env = null; const state = {};
await test('환경 기동: HAL·Agent 4대·포털·가짜 서비스', async () => {
env = await bootEnv({ log }); report.env.agents = env.agents.length; report.env.ports = env.ports; report.env.mailServerRegistered = env.mailServerRegistered; report.env.node = process.version;
ok(env.hal.proc.exited === null, 'HAL 실행 중'); ok(env.portal.proc.exited === null, '포털 실행 중');
const h = await env.ops.get('/api/health'); ok(h.json.bootstrap.complete, '부트스트랩 완료: ' + JSON.stringify(h.json.bootstrap));
if (!env.mailServerRegistered) report.bug({ title: '운영자 중계로 AriMail 서버 등록 실패', file: 'portal/mail/api.mjs', route: 'POST /ops/api/portal/mail/servers → /internal/ops/mail/servers', expected: '200 server', actual: env.mailServerResponse, repro: 'boot.mjs 의 AriMail 서버 등록' });
});
for (const f of files) {
await test(`흐름 그룹 ${f}`, async () => {
if (!env) throw new Error('환경 없음'); const mod = await import(join(HERE, 'e2e', 'flows', f));
const budget = Number(mod.BUDGET_MS || 60000); let timer; const timeout = new Promise((_, rej) => { timer = setTimeout(() => rej(new Error(`흐름 그룹 ${f} 시간 초과(${budget}ms)`)), budget); });
try { await Promise.race([mod.run({ env, report, state, log }), timeout]); } finally { clearTimeout(timer); }
log(`${f}: ${Math.round((Date.now() - startedAt) / 1000)}s 경과`);
});
}
await test('보고서 기록', async () => {
const out = report.write(join(HERE, '..', 'docs', 'verification')); log(`보고서: ${out.md}`); log('요약: ' + JSON.stringify(out.summary)); log('결함: ' + report.bugs.length + '건');
if (process.env.ARIWEB_E2E_STRICT === '1') ok(out.summary.failed === 0, `failed 판정 ${out.summary.failed}건`);
});
if (env) await env.stop();
done();
}