forked from phenom/healer-man
144 lines
6.1 KiB
JavaScript
144 lines
6.1 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { EventEmitter } from "node:events";
|
|
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
import { createServer } from "node:http";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { PassThrough } from "node:stream";
|
|
import test from "node:test";
|
|
import { createLocalBalanceLabApi } from "./local-balance-lab-api.mjs";
|
|
|
|
test("serves loopback-only local Balance Lab jobs without account authentication", async () => {
|
|
const directory = mkdtempSync(path.join(os.tmpdir(), "healer-man-local-balance-gui-"));
|
|
const spawnProcess = (_executable, args) => {
|
|
const child = new EventEmitter();
|
|
child.stdout = new PassThrough();
|
|
child.stderr = new PassThrough();
|
|
child.kill = () => child.emit("close", null);
|
|
const outputDir = args[args.indexOf("--output-dir") + 1];
|
|
setImmediate(() => {
|
|
mkdirSync(outputDir, { recursive: true });
|
|
writeFileSync(path.join(outputDir, "suite-report.json"), JSON.stringify({
|
|
summary: { partyConfigurations: 1, bosses: 1, runs: 1, classSpecs: 5, classAbilities: 5 },
|
|
}));
|
|
child.stdout.write("Party 1/1: wow-party-001\n");
|
|
child.stdout.end();
|
|
child.stderr.end();
|
|
child.emit("close", 0);
|
|
});
|
|
return child;
|
|
};
|
|
const api = createLocalBalanceLabApi({
|
|
dataDir: directory,
|
|
projectRoot: directory,
|
|
spawnProcess,
|
|
runtimeProbe: () => ({ available: true, executable: "python-test", version: "Python 3.test", error: null }),
|
|
});
|
|
const server = createServer((request, response) => {
|
|
void api.handle(request, response).then((handled) => {
|
|
if (!handled) response.writeHead(404).end();
|
|
});
|
|
});
|
|
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
|
|
const origin = `http://127.0.0.1:${server.address().port}`;
|
|
try {
|
|
const runtime = await (await fetch(`${origin}/api/local/balance-lab/runtime`)).json();
|
|
assert.equal(runtime.runtime.available, true);
|
|
const startedResponse = await fetch(`${origin}/api/local/balance-lab/jobs`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({
|
|
source: "wow", level: 20, partyConfigurations: 1, simulationsPerParty: 1,
|
|
durationSeconds: 5, partySeed: 1, bossCategory: "all",
|
|
bossKeys: ["stormwind-stockade/entry-1717"],
|
|
}),
|
|
});
|
|
assert.equal(startedResponse.status, 202);
|
|
const started = (await startedResponse.json()).job;
|
|
assert.equal(started.requestedBy, "Local GUI");
|
|
await new Promise((resolve) => setImmediate(resolve));
|
|
const jobs = await (await fetch(`${origin}/api/local/balance-lab/jobs`)).json();
|
|
assert.equal(jobs.jobs[0].status, "complete");
|
|
const artifact = await fetch(`${origin}/api/local/balance-lab/jobs/${started.id}/artifacts/suite-report.json`);
|
|
assert.equal(artifact.status, 200);
|
|
assert.equal((await artifact.json()).summary.runs, 1);
|
|
assert.equal((await fetch(`${origin}/api/not-local-balance-lab`)).status, 404);
|
|
} finally {
|
|
await new Promise((resolve) => server.close(resolve));
|
|
api.close();
|
|
rmSync(directory, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("persists revisioned local companion readiness and recovers from a corrupt policy file", async () => {
|
|
const directory = mkdtempSync(path.join(os.tmpdir(), "healer-man-local-readiness-"));
|
|
const open = async () => {
|
|
const api = createLocalBalanceLabApi({
|
|
dataDir: directory,
|
|
projectRoot: directory,
|
|
runtimeProbe: () => ({ available: true, executable: "python-test", version: "Python 3.test", error: null }),
|
|
});
|
|
const server = createServer((request, response) => {
|
|
void api.handle(request, response).then((handled) => {
|
|
if (!handled) response.writeHead(404).end();
|
|
});
|
|
});
|
|
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
|
|
return {
|
|
api,
|
|
server,
|
|
origin: `http://127.0.0.1:${server.address().port}`,
|
|
close: async () => {
|
|
await new Promise((resolve) => server.close(resolve));
|
|
api.close();
|
|
},
|
|
};
|
|
};
|
|
try {
|
|
const first = await open();
|
|
const initial = await (await fetch(`${first.origin}/api/local/balance-lab/companion-spec-readiness`)).json();
|
|
const configured = {
|
|
...initial.config,
|
|
statuses: { ...initial.config.statuses, "paladin:retribution": "beta" },
|
|
};
|
|
const savedResponse = await fetch(`${first.origin}/api/local/balance-lab/companion-spec-readiness`, {
|
|
method: "PUT",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ expectedRevision: 0, config: configured }),
|
|
});
|
|
assert.equal(savedResponse.status, 200);
|
|
assert.equal((await savedResponse.json()).revision, 1);
|
|
const staleResponse = await fetch(`${first.origin}/api/local/balance-lab/companion-spec-readiness`, {
|
|
method: "PUT",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ expectedRevision: 0, config: configured }),
|
|
});
|
|
assert.equal(staleResponse.status, 409);
|
|
const invalidResponse = await fetch(`${first.origin}/api/local/balance-lab/companion-spec-readiness`, {
|
|
method: "PUT",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({
|
|
expectedRevision: 1,
|
|
config: { ...configured, statuses: { ...configured.statuses, "warrior:protection": "needs-testing" } },
|
|
}),
|
|
});
|
|
assert.equal(invalidResponse.status, 400);
|
|
await first.close();
|
|
|
|
const second = await open();
|
|
const restored = await (await fetch(`${second.origin}/api/local/balance-lab/companion-spec-readiness`)).json();
|
|
assert.equal(restored.revision, 1);
|
|
assert.equal(restored.config.statuses["paladin:retribution"], "beta");
|
|
await second.close();
|
|
|
|
writeFileSync(path.join(directory, "companion-spec-readiness.json"), "{not-json");
|
|
const third = await open();
|
|
const fallback = await (await fetch(`${third.origin}/api/local/balance-lab/companion-spec-readiness`)).json();
|
|
assert.equal(fallback.revision, 0);
|
|
assert.equal(fallback.config.statuses["warrior:protection"], "ready");
|
|
await third.close();
|
|
} finally {
|
|
rmSync(directory, { recursive: true, force: true });
|
|
}
|
|
});
|