/** * The acceptance test: a stranger with no keys, no account and no environment. * * This is CONTRACT.md §5.1 written as code, because it is the thing two * independent server designs got wrong in the same way — a weather source that * defaults to a provider needing a contact string, and a hard failure when it is * absent. The last test in this file starts the real entry point under a * genuinely empty environment and asks it for its health, which is the same * assertion the `docker compose up` CI job makes from outside. */ import assert from "node:assert/strict"; import { spawn } from "node:child_process"; import { after, describe, it } from "node:test"; import { buildApp } from "../app.ts"; import { loadConfig } from "../config.ts"; import type { FlightsBody, HealthBody, MarkersBody, WeatherBody, } from "../../../src/server/wire.ts"; /** `loadConfig({})` is exactly what `env -i` produces, minus the process. */ function emptyEnvApp() { const config = loadConfig({}); config.logLevel = "silent"; return buildApp(config); } describe("a box handed nothing", () => { it("defaults every source to its keyless setting and reports no demotions", () => { const config = loadConfig({}); assert.equal(config.weather.source, "none"); assert.equal(config.flights.source, "sim"); assert.equal(config.markers.source, "none"); assert.equal(config.auth.mode, "none"); assert.equal(config.host, "127.0.0.1"); assert.equal(config.port, 8431); assert.deepEqual(config.degraded, []); }); it("answers health", async () => { const app = emptyEnvApp(); after(() => app.close()); const res = await app.inject({ method: "GET", url: "/api/v1/health" }); assert.equal(res.statusCode, 200); const body = res.json(); assert.equal(body.ok, true); assert.equal(body.auth.mode, "none"); assert.equal(body.auth.entryUrl, null); assert.deepEqual(body.degraded, []); }); it("serves a synthetic clear day rather than failing on a missing contact", async () => { const app = emptyEnvApp(); after(() => app.close()); const res = await app.inject({ method: "GET", url: "/api/v1/weather" }); assert.equal(res.statusCode, 200); const body = res.json(); assert.equal(body.synthetic, true); assert.equal(body.source, "none"); assert.equal(body.condition, "clear"); }); it("serves the simulated sky as a plan, not as positions", async () => { const app = emptyEnvApp(); after(() => app.close()); const body = (await app.inject({ method: "GET", url: "/api/v1/flights" })).json(); assert.equal(body.mode, "plan"); assert.equal(body.source, "sim"); assert.ok(body.mode === "plan" && body.routes.length > 0); // A fixed origin, so a restart does not teleport every aircraft. assert.ok(body.mode === "plan" && body.t0 < Date.now()); }); it("serves no markers and says so, rather than 404ing the route", async () => { const app = emptyEnvApp(); after(() => app.close()); const res = await app.inject({ method: "GET", url: "/api/v1/markers" }); assert.equal(res.statusCode, 200); assert.deepEqual(res.json().markers, []); }); it("has no offices", async () => { const app = emptyEnvApp(); after(() => app.close()); const res = await app.inject({ method: "GET", url: "/api/v1/offices/anything" }); assert.equal(res.statusCode, 404); }); }); describe("cache-control is fail-closed", () => { it("stamps private, no-store on anything that did not opt in", async () => { const app = emptyEnvApp(); after(() => app.close()); const health = await app.inject({ method: "GET", url: "/api/v1/health" }); assert.equal(health.headers["cache-control"], "private, no-store"); const missing = await app.inject({ method: "GET", url: "/api/v1/nope" }); assert.equal(missing.statusCode, 404); assert.equal(missing.headers["cache-control"], "private, no-store"); }); it("lets a route opt in explicitly", async () => { const app = emptyEnvApp(); after(() => app.close()); const res = await app.inject({ method: "GET", url: "/api/v1/flights" }); assert.match(String(res.headers["cache-control"]), /^public, max-age=\d+$/); }); it("refuses to opt in when the request carried a credential", async () => { const app = emptyEnvApp(); after(() => app.close()); const res = await app.inject({ method: "GET", url: "/api/v1/flights", headers: { authorization: "Bearer something" }, }); assert.equal(res.headers["cache-control"], "private, no-store"); }); }); describe("the real process under env -i", () => { it("boots and answers health with no environment at all", async () => { const entry = new URL("../index.ts", import.meta.url).pathname; // A genuinely empty environment: no PATH, no HOME, no TERA_*. `execPath` is // absolute, so the child needs nothing from the parent to start. const child = spawn(process.execPath, [entry], { env: {}, stdio: "ignore" }); after(() => child.kill("SIGKILL")); const url = "http://127.0.0.1:8431/api/v1/health"; const deadline = Date.now() + 15_000; let body: HealthBody | null = null; while (Date.now() < deadline && body === null) { try { const res = await fetch(url); if (res.ok) body = (await res.json()) as HealthBody; } catch { await new Promise((resolve) => setTimeout(resolve, 200)); } } assert.ok(body !== null, "the server never answered on 127.0.0.1:8431"); assert.equal(body.ok, true); assert.equal(body.service, "tera-api"); }); });