'use strict'; // Importing through the UI and then recompiling — the path a browser actually // takes. It is exercised over HTTP because the bug it guards against lived in the // wiring between the two handlers, not in either one: `/api/import` set // `session.area` but never installed `session.context.compileFresh`, which is only // wired when the server is started with an area on the command line. So every // UI-imported session answered "请先导入 OSM 文件" to `/api/compile` — breaking // "保存并重新生成", and later making a successful direct-edit save report a failed // regeneration. const assert = require('assert/strict'); const fs = require('fs'); const http = require('http'); const os = require('os'); const path = require('path'); const { startWorkbench } = require('../workbench/server'); const PORT = 8899; const dataRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'workbench-import-compile-')); const osm = fs.readFileSync(path.join(__dirname, 'fixtures', 'fengshu-er-road.osm')); function request(options, body) { return new Promise((resolve, reject) => { const call = http.request({ host: '127.0.0.1', port: PORT, ...options }, (response) => { const chunks = []; response.on('data', (chunk) => chunks.push(chunk)); response.on('end', () => resolve({ status: response.statusCode, body: JSON.parse(Buffer.concat(chunks).toString('utf8')) }), ); }); call.on('error', reject); if (body) call.write(body); call.end(); }); } function multipart(field, filename, contents) { const boundary = '----roadcompilertest'; return { boundary, body: Buffer.concat([ Buffer.from( `--${boundary}\r\nContent-Disposition: form-data; name="${field}"; filename="${filename}"\r\n` + 'Content-Type: application/xml\r\n\r\n', ), contents, Buffer.from(`\r\n--${boundary}--\r\n`), ]), }; } const server = startWorkbench({ port: PORT, dataRoot, repoRoot: process.cwd() }); async function run() { const upload = multipart('file', 'fengshu-er-road.osm', osm); const imported = await request( { method: 'POST', path: '/api/import', headers: { 'Content-Type': `multipart/form-data; boundary=${upload.boundary}`, 'Content-Length': upload.body.length, }, }, upload.body, ); assert.equal(imported.status, 200, `import failed: ${JSON.stringify(imported.body).slice(0, 200)}`); assert.ok(imported.body.areaId, 'import must report the area it created'); // The regression: this used to answer 400 "请先导入 OSM 文件" even though the // import above had just succeeded. const compiled = await request({ method: 'POST', path: '/api/compile' }); assert.equal(compiled.status, 200, `compile after import failed: ${JSON.stringify(compiled.body).slice(0, 200)}`); assert.ok(compiled.body.compiled, 'compile must return the recompiled state'); assert.ok(compiled.body.compiled.model.roads.length > 0, 'the recompile must still produce roads'); // And it must stay repeatable, since saving a direct edit now recompiles. const again = await request({ method: 'POST', path: '/api/compile' }); assert.equal(again.status, 200, 'a second recompile must also succeed'); } run() .then(() => { console.log('workbench import/compile tests passed'); }) .catch((error) => { console.error(error); process.exitCode = 1; }) .finally(() => { server.close(); fs.rmSync(dataRoot, { recursive: true, force: true }); });