Co-authored-by: luna <clawy@reversed.dev> Co-committed-by: luna <clawy@reversed.dev>
This commit was merged in pull request #2.
This commit is contained in:
@@ -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 }),
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { mkdir, mkdtemp, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import test from "node:test";
|
||||
|
||||
import { KeyManager } from "../dist/services/key-manager.js";
|
||||
import { RepoCounterService } from "../dist/services/repo-counter.js";
|
||||
|
||||
async function createHarness(options = {}) {
|
||||
const root = await mkdtemp(path.join(os.tmpdir(), "loc-via-git-test-"));
|
||||
const fixture = path.join(root, "fixture");
|
||||
const bin = path.join(root, "bin");
|
||||
const cloneLog = path.join(root, "clone-log");
|
||||
await mkdir(fixture, { recursive: true });
|
||||
await mkdir(bin);
|
||||
await writeFile(path.join(bin, "git"), `#!/usr/bin/env node
|
||||
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") {
|
||||
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");
|
||||
}
|
||||
`, { mode: 0o755 });
|
||||
|
||||
const config = {
|
||||
allowedGitHosts: ["example.test"],
|
||||
apiKey: "",
|
||||
cacheSweepIntervalMs: 60_000,
|
||||
cacheTtlMs: 60_000,
|
||||
cloneTimeoutMs: 100,
|
||||
defaultSshKeyName: "",
|
||||
generateSshKeyIfMissing: false,
|
||||
maxConcurrentScans: 2,
|
||||
maxFilesPerScan: 100,
|
||||
maxFileSizeBytes: 1024 * 1024,
|
||||
maxScanBytes: 1024 * 1024,
|
||||
port: 3000,
|
||||
rateLimitMax: 30,
|
||||
rateLimitWindowMs: 60_000,
|
||||
sshKeysDir: path.join(root, "keys"),
|
||||
tempRoot: path.join(root, "tmp"),
|
||||
trustProxy: false,
|
||||
...options
|
||||
};
|
||||
const originalPath = process.env.PATH;
|
||||
process.env.PATH = `${bin}:${originalPath}`;
|
||||
process.env.LOC_TEST_FIXTURE = fixture;
|
||||
process.env.LOC_TEST_CLONE_LOG = cloneLog;
|
||||
const keyManager = new KeyManager(config);
|
||||
const service = new RepoCounterService(config, keyManager);
|
||||
await keyManager.initialize();
|
||||
await service.initialize();
|
||||
|
||||
return {
|
||||
cloneLog,
|
||||
config,
|
||||
fixture,
|
||||
root,
|
||||
service,
|
||||
async cleanup() {
|
||||
process.env.PATH = originalPath;
|
||||
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 });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
test("scans fixture repositories, caches duplicate work, and cleans clone directories", async () => {
|
||||
const harness = await createHarness();
|
||||
try {
|
||||
await writeFile(path.join(harness.fixture, "main.ts"), "const value = 1;\n\nexport { value };\n");
|
||||
await mkdir(path.join(harness.fixture, "dist"));
|
||||
await writeFile(path.join(harness.fixture, "dist", "bundle.min.js"), "ignored\n");
|
||||
|
||||
const request = { repo: "https://example.test/demo.git", ref: null, sshKey: null };
|
||||
const [first, second] = await Promise.all([harness.service.count(request), harness.service.count(request)]);
|
||||
const third = await harness.service.count(request);
|
||||
|
||||
assert.equal(first.commit, "fixture-commit");
|
||||
assert.equal(second.lineCount, 2);
|
||||
assert.equal(third.cached, true);
|
||||
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();
|
||||
}
|
||||
});
|
||||
|
||||
test("rejects oversized files and still removes the temporary clone", async () => {
|
||||
const harness = await createHarness({ maxFileSizeBytes: 10 });
|
||||
try {
|
||||
await writeFile(path.join(harness.fixture, "large.ts"), "export const value = 123;\n");
|
||||
await assert.rejects(
|
||||
harness.service.count({ repo: "https://example.test/demo.git", ref: null, sshKey: null }),
|
||||
{ statusCode: 413 }
|
||||
);
|
||||
assert.deepEqual(await readdir(harness.config.tempRoot), []);
|
||||
} finally {
|
||||
await harness.cleanup();
|
||||
}
|
||||
});
|
||||
|
||||
test("times out stalled clones and rejects unsupported repository URLs", async () => {
|
||||
const harness = await createHarness({ cloneTimeoutMs: 50 });
|
||||
try {
|
||||
process.env.LOC_TEST_HANG = "1";
|
||||
await assert.rejects(
|
||||
harness.service.count({ repo: "https://example.test/demo.git", ref: null, sshKey: null }),
|
||||
{ statusCode: 504 }
|
||||
);
|
||||
await assert.rejects(
|
||||
harness.service.count({ repo: "file:///private/repo", ref: null, sshKey: null }),
|
||||
{ statusCode: 400 }
|
||||
);
|
||||
} finally {
|
||||
await harness.cleanup();
|
||||
}
|
||||
});
|
||||
@@ -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");
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user