Files
Ra3ModXmlExt/test/agentEndpoint.test.mjs
T
2026-09-10 17:03:10 +02:00

103 lines
3.4 KiB
JavaScript

import { test } from "node:test";
import assert from "node:assert/strict";
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { dirname, join } from "node:path";
import {
clearEndpoint,
clearEndpointForProject,
endpointPathForProject,
isProcessAlive,
readEndpoint,
readEndpointForProject,
sameProject,
writeEndpoint,
writeEndpointForProject,
} from "../out/agent/endpoint.js";
const PROJECT_A = "D:/Mods/ExampleA";
const PROJECT_B = "D:/Mods/ExampleB";
test("endpoint file round-trips and clears", async () => {
const home = mkdtempSync(join(tmpdir(), "ra3-endpoint-test-"));
try {
await writeEndpoint(
{ url: "http://127.0.0.1:12345", token: "abc", projectDir: PROJECT_A },
home,
);
const loaded = await readEndpoint(home);
assert.equal(loaded?.url, "http://127.0.0.1:12345");
assert.equal(loaded?.token, "abc");
await clearEndpoint(home);
assert.equal(await readEndpoint(home), null);
} finally {
rmSync(home, { recursive: true, force: true });
}
});
test("per-project endpoints do not shadow each other", async () => {
const home = mkdtempSync(join(tmpdir(), "ra3-endpoint-multi-"));
try {
// Two "windows" enable agent access for different projects.
await writeEndpointForProject(
PROJECT_A,
{ url: "http://127.0.0.1:1111", token: "token-a", processId: process.pid },
home,
);
await writeEndpointForProject(
PROJECT_B,
{ url: "http://127.0.0.1:2222", token: "token-b", processId: process.pid },
home,
);
const a = await readEndpointForProject(PROJECT_A, home);
const b = await readEndpointForProject(PROJECT_B, home);
assert.equal(a?.url, "http://127.0.0.1:1111");
assert.ok(sameProject(a.projectDir, PROJECT_A));
assert.equal(b?.url, "http://127.0.0.1:2222");
assert.ok(sameProject(b.projectDir, PROJECT_B));
// Clearing one project must not disturb the other.
await clearEndpointForProject(PROJECT_A, home);
assert.equal(await readEndpointForProject(PROJECT_A, home), null);
assert.equal((await readEndpointForProject(PROJECT_B, home))?.token, "token-b");
} finally {
rmSync(home, { recursive: true, force: true });
}
});
test("a per-project endpoint recording another project is rejected", async () => {
const home = mkdtempSync(join(tmpdir(), "ra3-endpoint-mismatch-"));
try {
const file = endpointPathForProject(PROJECT_A, home);
// Simulate a stale/edited file that claims to serve a different project.
mkdirSync(dirname(file), { recursive: true });
writeFileSync(
file,
JSON.stringify({
url: "http://127.0.0.1:3333",
token: "t",
projectDir: PROJECT_B,
}),
);
assert.equal(await readEndpointForProject(PROJECT_A, home), null);
} finally {
rmSync(home, { recursive: true, force: true });
}
});
test("isProcessAlive detects dead pids and trusts unknown ones", () => {
assert.equal(isProcessAlive(process.pid), true);
assert.equal(isProcessAlive(undefined), true);
assert.equal(isProcessAlive(0), true);
assert.equal(isProcessAlive(NaN), true);
// Not a valid Windows PID, so it cannot correspond to a running process.
assert.equal(isProcessAlive(0x7fffffff), false);
});
test("sameProject is case-insensitive", () => {
assert.equal(sameProject("D:/Mods/Example", "d:/mods/example"), true);
assert.equal(sameProject("D:/Mods/Example", "D:/Mods/Other"), false);
});