| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758 |
- import test from 'node:test';
- import assert from 'node:assert/strict';
- import { createServer } from 'node:http';
- import { spawn } from 'node:child_process';
- import { once } from 'node:events';
- test('本地预览资料与行业均读受控上游,拒绝写命令、不透传凭据、错误不回退旧库', async () => {
- const received = [];
- const upstream = createServer(async (req, res) => {
- const chunks = [];for await (const c of req) chunks.push(c);
- const body = JSON.parse(Buffer.concat(chunks));received.push({ path: req.url, headers: req.headers, body });
- res.writeHead(body.generation === 'stale' ? 409 : 200, { 'content-type': 'application/json' });
- res.end(JSON.stringify(body.generation === 'stale'
- ? { ok: false, error: { code: 'LIBRARY_VERSION_CHANGED' } }
- : { ok: true, generation: 'unified-test-generation', readOnly: true, databaseWrites: 0 }));
- });
- await new Promise(resolve => upstream.listen(0, '127.0.0.1', resolve));
- const upstreamUrl = `http://127.0.0.1:${upstream.address().port}`;
- const reserve = createServer();await new Promise(resolve => reserve.listen(0, '127.0.0.1', resolve));
- const port = reserve.address().port;await new Promise(resolve => reserve.close(resolve));
- const env = { ...process.env };
- for (const k of ['KSF_UNIFIED_DB_CONFIG', 'KSF_LIBRARY_REGISTRY', 'KSF_VOC_DB', 'KSF_INDUSTRY_SNAPSHOT']) delete env[k];
- env.KSF_LIBRARY_REMOTE_URL = upstreamUrl + '/api/library';env.KSF_INDUSTRY_REMOTE_URL = upstreamUrl + '/api/industry';
- const child = spawn(process.execPath, ['src/dev/serve.mjs', '--port', String(port)], { env, windowsHide: true, stdio: ['ignore', 'pipe', 'pipe'] });
- try {
- await new Promise((resolve, reject) => {
- const timer = setTimeout(() => reject(Error('preview startup timeout')), 15000);
- child.on('exit', code => { clearTimeout(timer);reject(Error('preview exited ' + code)); });
- child.on('error', e => { clearTimeout(timer);reject(e); });
- child.stdout.on('data', part => { if (String(part).includes('KF dev server')) { clearTimeout(timer);resolve(); } });
- });
- const base = `http://127.0.0.1:${port}`;
- const send = (path, body) => fetch(base + path, { method: 'POST', headers: {
- 'content-type': 'application/json', authorization: 'Bearer must-stay-local', 'x-parse-master-key': 'must-stay-local',
- }, body: JSON.stringify(body) });
- const info = await (await fetch(base + '/__dev/info')).json();
- assert.equal(info.librarySource, 'production-readonly');assert.equal(info.industrySource, 'production-readonly');
- for (const [route, op] of [['/api/library', 'summary'], ['/api/industry', 'contract'], ['/api/industry', 'plan']]) {
- const response = await send(route, { op, filters: { platform: 'jd' } });
- const data = await response.json();assert.equal(response.status, 200);assert.equal(data.generation, 'unified-test-generation');assert.equal(data.localPreview, true);
- assert.equal(received.at(-1).path, route);assert.equal(received.at(-1).headers.authorization, undefined);
- assert.equal(received.at(-1).headers['x-parse-master-key'], undefined);assert.equal(received.at(-1).body.filters.platform, 'jd');
- }
- const count = received.length;
- for (const route of ['/api/library', '/api/industry']) {
- assert.equal((await send(route, { op: 'apply' })).status, 400);
- assert.equal((await send(route, [])).status, 400);
- assert.equal((await fetch(base + route)).status, 405);
- assert.equal((await fetch(base + route, { method: 'POST', body: 'x'.repeat(24001) })).status, 413);
- }
- assert.equal(received.length, count);
- const failed = await send('/api/industry', { op: 'contract', generation: 'stale' });
- assert.equal(failed.status, 409);assert.equal((await failed.json()).error.code, 'LIBRARY_VERSION_CHANGED');
- } finally {
- if (child.exitCode === null) { const exited = once(child, 'exit');child.kill();await exited; }
- await new Promise(resolve => upstream.close(resolve));
- }
- });
|