Add metrics, request logs, and graceful shutdown
ci / test (pull_request) Successful in 9s

This commit is contained in:
2026-07-21 18:03:43 +00:00
parent 4d30598e6b
commit efb0cb0447
8 changed files with 230 additions and 10 deletions
+19
View File
@@ -106,6 +106,25 @@ test("GET /loc accepts api_key query param as an unsafe fallback", async () => {
assert.equal(response.body.lineCount, 5);
});
test("GET /metrics is authenticated and exposes Prometheus counters", async () => {
const app = createApp({ ...baseConfig, apiKey: "secret" }, {
getHealth: () => ({ cacheEntries: 0, inFlight: 0, maxConcurrentScans: 4, activeScans: 0, queuedScans: 0 }),
getPublicKey: async () => "ssh-ed25519 AAAA",
getDefaultKeyName: () => "loc_via_git_ed25519",
count: async () => {
throw new Error("not used");
}
});
const unauthenticated = await request(app).get("/metrics");
const authenticated = await request(app).get("/metrics").set("x-api-key", "secret");
assert.equal(unauthenticated.status, 401);
assert.equal(authenticated.status, 200);
assert.match(authenticated.text, /loc_via_git_http_requests_total/);
assert.match(authenticated.text, /loc_via_git_scans_total 0/);
});
test("GET /loc/diff returns aggregate and language deltas", async () => {
const app = createApp(baseConfig, {
getHealth: () => ({ cacheEntries: 0, inFlight: 0, maxConcurrentScans: 4, activeScans: 0, queuedScans: 0 }),
+25 -2
View File
@@ -18,9 +18,10 @@ async function createHarness(options = {}) {
import { appendFileSync, cpSync } from "node:fs";
const args = process.argv.slice(2);
const command = args.includes("clone") ? "clone" : args.includes("rev-parse") ? "rev-parse" : "other";
appendFileSync(process.env.LOC_TEST_CLONE_LOG, args.join(" ") + "\\n");
if (command === "clone") {
appendFileSync(process.env.LOC_TEST_CLONE_LOG, "clone\\n");
if (process.env.LOC_TEST_HANG === "1") setInterval(() => {}, 1000);
if (process.env.LOC_TEST_FAIL === "1") process.exit(2);
cpSync(process.env.LOC_TEST_FIXTURE, args.at(-1), { recursive: true });
} else if (command === "rev-parse") {
process.stdout.write("fixture-commit\\n");
@@ -67,6 +68,7 @@ if (command === "clone") {
delete process.env.LOC_TEST_FIXTURE;
delete process.env.LOC_TEST_CLONE_LOG;
delete process.env.LOC_TEST_HANG;
delete process.env.LOC_TEST_FAIL;
await rm(root, { recursive: true, force: true });
}
};
@@ -86,7 +88,28 @@ test("scans fixture repositories, caches duplicate work, and cleans clone direct
assert.equal(first.commit, "fixture-commit");
assert.equal(second.lineCount, 2);
assert.equal(third.cached, true);
assert.equal((await readFile(harness.cloneLog, "utf8")).trim().split("\n").length, 1);
const commands = await readFile(harness.cloneLog, "utf8");
assert.equal(commands.split("\n").filter((line) => line.includes(" clone ")).length, 1);
assert.deepEqual(await readdir(harness.config.tempRoot), []);
} finally {
await harness.cleanup();
}
});
test("checks out requested refs and cleans up failed clones", async () => {
const harness = await createHarness();
try {
await writeFile(path.join(harness.fixture, "main.ts"), "export {};\n");
await harness.service.count({ repo: "https://example.test/demo.git", ref: "release-1", sshKey: null });
const commands = await readFile(harness.cloneLog, "utf8");
assert.match(commands, /fetch --depth 1 origin release-1/);
assert.match(commands, /checkout FETCH_HEAD/);
process.env.LOC_TEST_FAIL = "1";
await assert.rejects(
harness.service.count({ repo: "https://example.test/failure.git", ref: null, sshKey: null }),
{ statusCode: 400 }
);
assert.deepEqual(await readdir(harness.config.tempRoot), []);
} finally {
await harness.cleanup();
+47
View File
@@ -0,0 +1,47 @@
import assert from "node:assert/strict";
import { spawn } from "node:child_process";
import net from "node:net";
import test from "node:test";
async function getFreePort() {
const server = net.createServer();
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
const address = server.address();
if (!address || typeof address === "string") {
throw new Error("Could not allocate test port");
}
await new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve()));
return address.port;
}
test("server shuts down cleanly after SIGTERM", async () => {
const port = await getFreePort();
const child = spawn(process.execPath, ["dist/server.js"], {
cwd: process.cwd(),
env: { ...process.env, PORT: String(port), SSH_KEYS_DIR: `/tmp/loc-via-git-keys-${port}`, TMP_DIR: `/tmp/loc-via-git-${port}` },
stdio: ["ignore", "pipe", "pipe"]
});
let output = "";
child.stdout.on("data", (chunk) => {
output += chunk.toString();
});
try {
await new Promise((resolve, reject) => {
const timeout = setTimeout(() => reject(new Error(`Server did not start: ${output}`)), 2_000);
const interval = setInterval(() => {
if (output.includes("server_started")) {
clearTimeout(timeout);
clearInterval(interval);
resolve();
}
}, 10);
});
child.kill("SIGTERM");
const code = await new Promise((resolve) => child.once("exit", resolve));
assert.equal(code, 0);
assert.match(output, /shutdown_complete/);
} finally {
child.kill("SIGKILL");
}
});