ai agent
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
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);
|
||||
});
|
||||
Reference in New Issue
Block a user