实现本地三节点 K3s 同构环境、脱敏生产快照、Gemini 图片和多参考图视频协议模拟、统一验收报告及故障注入。\n\n新增 Worker 容量控制器、资源与连接预算、任务恢复保护,并将生产验收拆分为 validation 执行和人工 CAS 放量。\n\n验证包括 Go 全量测试、PostgreSQL HTTP 集成测试、go vet、OpenAPI、ShellCheck、前端检查、迁移及发布脚本测试。
125 lines
4.5 KiB
JavaScript
125 lines
4.5 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import { execFileSync } from 'node:child_process';
|
|
import { mkdtempSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import { join, resolve } from 'node:path';
|
|
|
|
const root = resolve(import.meta.dirname, '../..');
|
|
const temporary = mkdtempSync(join(tmpdir(), 'easyai-acceptance-report-'));
|
|
const reports = join(temporary, 'reports');
|
|
mkdirSync(reports);
|
|
const releaseSha = 'a'.repeat(40);
|
|
const digest = `sha256:${'b'.repeat(64)}`;
|
|
const configHash = 'c'.repeat(64);
|
|
const snapshotHash = 'd'.repeat(64);
|
|
const runID = '00000000-0000-4000-8000-000000000001';
|
|
const writeJSON = (path, value) => writeFileSync(path, `${JSON.stringify(value)}\n`, { mode: 0o600 });
|
|
|
|
const runtime = join(temporary, 'runtime.json');
|
|
const snapshot = join(temporary, 'snapshot.json');
|
|
const artifact = join(temporary, 'artifact.json');
|
|
const output = join(temporary, 'acceptance-report.json');
|
|
const partialOutput = join(temporary, 'acceptance-report.partial.json');
|
|
const productionPartial = join(temporary, 'production-summary.partial.json');
|
|
const mergedPartialOutput = join(temporary, 'acceptance-report.production-partial.json');
|
|
writeJSON(runtime, {
|
|
schemaVersion: 'acceptance-runtime/v1',
|
|
runId: runID,
|
|
releaseSha,
|
|
apiImageDigest: digest,
|
|
workerImageDigest: digest,
|
|
snapshotConfigHash: configHash,
|
|
snapshotSha256: snapshotHash,
|
|
apiKeys: ['must-not-be-copied'],
|
|
runToken: 'must-not-be-copied'
|
|
});
|
|
writeJSON(snapshot, {
|
|
schemaVersion: 'acceptance-snapshot/v1',
|
|
source: { releaseSha: 'e'.repeat(40), configHash },
|
|
snapshotSha256: snapshotHash
|
|
});
|
|
writeJSON(artifact, {
|
|
schemaVersion: 'acceptance-artifact-smoke/v1',
|
|
releaseSha,
|
|
apiImageDigest: digest,
|
|
passed: true,
|
|
secretSafe: true
|
|
});
|
|
writeJSON(join(reports, 'load.json'), {
|
|
schemaVersion: 'acceptance-load-report/v1',
|
|
profile: 'simulated-smoke',
|
|
passed: true,
|
|
secretSafe: true,
|
|
phases: [],
|
|
startedAt: '2026-01-01T00:00:00Z',
|
|
finishedAt: '2026-01-01T00:01:00Z'
|
|
});
|
|
|
|
execFileSync('node', [
|
|
join(root, 'scripts/acceptance/report.mjs'),
|
|
'build-local',
|
|
'--runtime', runtime,
|
|
'--snapshot', snapshot,
|
|
'--reports', reports,
|
|
'--artifact', artifact,
|
|
'--api-digest', digest,
|
|
'--certified-profile', 'P24',
|
|
'--output', output
|
|
]);
|
|
const report = JSON.parse(readFileSync(output, 'utf8'));
|
|
assert.equal(report.schemaVersion, 'acceptance-report/v1');
|
|
assert.equal(report.stages.localNative.status, 'passed');
|
|
assert.equal(report.stages.amd64Artifact.status, 'passed');
|
|
assert.equal(report.promotion.ready, false);
|
|
assert.equal(readFileSync(output, 'utf8').includes('must-not-be-copied'), false);
|
|
execFileSync('node', [join(root, 'scripts/acceptance/report.mjs'), 'validate', '--input', output]);
|
|
|
|
execFileSync('node', [
|
|
join(root, 'scripts/acceptance/report.mjs'),
|
|
'build-local-partial',
|
|
'--runtime', runtime,
|
|
'--snapshot', snapshot,
|
|
'--reports', reports,
|
|
'--certified-profile', 'P24',
|
|
'--failure-phase', 'capacity_p28_round_2',
|
|
'--output', partialOutput
|
|
]);
|
|
const partialReport = JSON.parse(readFileSync(partialOutput, 'utf8'));
|
|
assert.equal(partialReport.stages.localNative.status, 'failed');
|
|
assert.equal(partialReport.stages.localNative.failurePhase, 'capacity_p28_round_2');
|
|
assert.equal(partialReport.stages.amd64Artifact.status, 'not-run');
|
|
assert.equal(partialReport.promotion.ready, false);
|
|
assert.equal(readFileSync(partialOutput, 'utf8').includes('must-not-be-copied'), false);
|
|
execFileSync('node', [join(root, 'scripts/acceptance/report.mjs'), 'validate', '--input', partialOutput]);
|
|
|
|
writeJSON(productionPartial, {
|
|
releaseSha,
|
|
apiImageDigest: digest,
|
|
snapshotConfigHash: configHash,
|
|
snapshotSha256: snapshotHash,
|
|
stableCapacityProfile: 'P24',
|
|
realCanaryPassed: false,
|
|
gates: [
|
|
{
|
|
id: 'workflow_interrupted',
|
|
passed: false,
|
|
detail: 'production acceptance interrupted by signal'
|
|
}
|
|
],
|
|
passed: false
|
|
});
|
|
execFileSync('node', [
|
|
join(root, 'scripts/acceptance/report.mjs'),
|
|
'merge-production',
|
|
'--local-report', output,
|
|
'--production-summary', productionPartial,
|
|
'--output', mergedPartialOutput
|
|
]);
|
|
const mergedPartial = JSON.parse(readFileSync(mergedPartialOutput, 'utf8'));
|
|
assert.equal(mergedPartial.stages.onlineSimulation.status, 'failed');
|
|
assert.equal(mergedPartial.stages.realCanary.status, 'failed');
|
|
assert.equal(mergedPartial.promotion.ready, false);
|
|
assert.equal(mergedPartial.promotion.trafficMode, 'validation');
|
|
assert.equal(mergedPartial.gates.at(-1).id, 'workflow_interrupted');
|
|
execFileSync('node', [join(root, 'scripts/acceptance/report.mjs'), 'validate', '--input', mergedPartialOutput]);
|