79 lines
2.9 KiB
JavaScript
79 lines
2.9 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { spawn } from "node:child_process";
|
|
import { once } from "node:events";
|
|
import { mkdtemp, rm } from "node:fs/promises";
|
|
import { createServer } from "node:net";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
|
|
const root = await mkdtemp(join(tmpdir(), "nodedc-map-gateway-zone-source-smoke-"));
|
|
const port = await freePort();
|
|
let child;
|
|
|
|
try {
|
|
child = spawn(process.execPath, ["src/server.mjs"], {
|
|
cwd: new URL("..", import.meta.url),
|
|
env: {
|
|
...process.env,
|
|
PORT: String(port),
|
|
MAP_CACHE_DIR: join(root, "cache"),
|
|
MAP_GATEWAY_ALLOW_ANONYMOUS: "true",
|
|
MAP_CACHE_MODE: "readwrite",
|
|
CESIUM_ION_TOKEN: "",
|
|
},
|
|
stdio: ["ignore", "pipe", "pipe"],
|
|
});
|
|
|
|
await waitForGateway(port, child);
|
|
const route = `http://127.0.0.1:${port}/internal/zone-sources/v1/profiles/moscow-pmd-slow-zones/current`;
|
|
const response = await fetch(route);
|
|
assert.equal(response.status, 200);
|
|
assert.match(response.headers.get("etag") || "", /^"sha256:[a-f0-9]{64}"$/);
|
|
const generation = await response.json();
|
|
assert.equal(generation.schemaVersion, "nodedc.zone-source-generation/v2");
|
|
assert.equal(generation.authorityId, "moscow-department-of-transport");
|
|
assert.equal(generation.datasetId, "pmd-slow-zones");
|
|
assert.equal(generation.complete, true);
|
|
assert.equal(generation.zones.length, 903);
|
|
assert.equal(generation.metadata.scheduleRowCount, 6335);
|
|
|
|
const head = await fetch(route, { method: "HEAD" });
|
|
assert.equal(head.status, 200);
|
|
assert.equal(await head.text(), "");
|
|
const cached = await fetch(route, { headers: { "If-None-Match": response.headers.get("etag") } });
|
|
assert.equal(cached.status, 304);
|
|
console.log("ok: immutable Department zone source is served with stable digest and cache semantics");
|
|
} finally {
|
|
if (child && !child.killed) {
|
|
child.kill("SIGTERM");
|
|
await once(child, "exit").catch(() => undefined);
|
|
}
|
|
await rm(root, { recursive: true, force: true });
|
|
}
|
|
|
|
async function freePort() {
|
|
const server = createServer();
|
|
server.listen(0, "127.0.0.1");
|
|
await once(server, "listening");
|
|
const address = server.address();
|
|
assert(address && typeof address === "object");
|
|
const selected = address.port;
|
|
server.close();
|
|
await once(server, "close");
|
|
return selected;
|
|
}
|
|
|
|
async function waitForGateway(selectedPort, processHandle) {
|
|
let output = "";
|
|
processHandle.stderr.on("data", (chunk) => { output += String(chunk); });
|
|
for (let attempt = 0; attempt < 80; attempt += 1) {
|
|
if (processHandle.exitCode !== null) throw new Error(`gateway_exited:${processHandle.exitCode}:${output}`);
|
|
try {
|
|
const response = await fetch(`http://127.0.0.1:${selectedPort}/healthz`);
|
|
if (response.ok) return;
|
|
} catch { /* service is still starting */ }
|
|
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
}
|
|
throw new Error(`gateway_start_timeout:${output}`);
|
|
}
|