103 lines
3.4 KiB
JavaScript
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);
|
|
});
|