Fresh history cut from cynarAI/evoo antigravity-handoff/project-timeline (Voice First + project timeline). Brand docs/titles as evOo; keep @rakazo/* packages as tech debt. Excludes node_modules, caches, secrets, voice blobs.
197 lines
7.8 KiB
TypeScript
197 lines
7.8 KiB
TypeScript
import { spawnSync } from "node:child_process";
|
|
import { mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import path from "node:path";
|
|
import { afterEach, describe, expect, it } from "vitest";
|
|
import {
|
|
DEFAULT_DESKTOP_ENV,
|
|
desktopControlCommand,
|
|
desktopUrl,
|
|
ensureScreenCommand,
|
|
interactiveScreenCommand,
|
|
MAX_DESKTOP_DISPLAY,
|
|
managedDesktopCommand,
|
|
releaseDesktopCommand,
|
|
resetDesktopRuntimeCommand,
|
|
screenPorts,
|
|
shellQuote,
|
|
stopExtraScreenCommand,
|
|
} from "./desktop-runtime.js";
|
|
|
|
const roots: string[] = [];
|
|
afterEach(() => {
|
|
for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true });
|
|
});
|
|
const env = {
|
|
homeDir: "/home/user",
|
|
workspaceDir: "/home/user/work",
|
|
browserProfilesDir: "/home/user/work/.browser-profiles",
|
|
displayStart: 20,
|
|
portStart: 6100,
|
|
};
|
|
|
|
function fixture() {
|
|
const root = mkdtempSync(path.join(tmpdir(), "desktop-runtime-test-"));
|
|
roots.push(root);
|
|
const run = (script: string, failLifecycle = false) =>
|
|
spawnSync(
|
|
"bash",
|
|
[
|
|
"-eu",
|
|
"-c",
|
|
[
|
|
// Lifecycle processes are stubbed here; the opt-in Docker smoke runs the real commands.
|
|
"flock() { :; }",
|
|
`bash() { return ${failLifecycle ? 1 : 0}; }`,
|
|
script
|
|
.replaceAll("/tmp/rakazo/desktop-assignments", root)
|
|
.replaceAll("/tmp/rakazo", root),
|
|
].join("\n"),
|
|
],
|
|
{ encoding: "utf8", timeout: 5000 },
|
|
);
|
|
const ensure = (bot: string, lease = "run:1", fail = false) =>
|
|
run(managedDesktopCommand(bot, lease, env, `view-${bot}`), fail);
|
|
const release = (bot: string, lease = "run:1", fail = false) =>
|
|
run(releaseDesktopCommand(bot, lease, env), fail);
|
|
return { root, run, ensure, release };
|
|
}
|
|
|
|
describe("shared Linux desktop lifecycle", () => {
|
|
it("allocates live slots past 1000 bots, keeps assignments across callers, and rejects stale leases", () => {
|
|
const f = fixture();
|
|
expect(f.ensure("a").stdout).toContain("RAKAZO_DESKTOP=0:view-a");
|
|
expect(f.ensure("b").stdout).toContain("RAKAZO_DESKTOP=1:view-b");
|
|
expect(f.ensure("a", "new:2").stdout).toContain("RAKAZO_DESKTOP=0:view-a");
|
|
expect(f.ensure("a", "run:1").status).toBe(75);
|
|
expect(f.release("a", "run:3").status).toBe(75);
|
|
expect(f.release("a", "new:1").status).toBe(75);
|
|
for (let i = 2; i < 1000; i++)
|
|
writeFileSync(path.join(f.root, `seed-${i}.slot`), `${i}\nseed:1\nunused\n`);
|
|
expect(f.ensure("bot-1000").stdout).toContain("RAKAZO_DESKTOP=1000:view-bot-1000");
|
|
expect(f.release("a", "new:2").status).toBe(0);
|
|
expect(f.ensure("c").stdout).toContain("RAKAZO_DESKTOP=0:view-c");
|
|
expect(f.ensure("b").stdout).toContain("RAKAZO_DESKTOP=1:view-b");
|
|
});
|
|
|
|
it("reserves failed startup and teardown slots until a successful retry", () => {
|
|
const f = fixture();
|
|
expect(f.ensure("a", "run:1", true).status).toBe(1);
|
|
expect(f.ensure("b").stdout).toContain("RAKAZO_DESKTOP=1:view-b");
|
|
expect(f.ensure("a").stdout).toContain("RAKAZO_DESKTOP=0:view-a");
|
|
expect(f.release("a", "run:1", true).status).toBe(1);
|
|
expect(f.ensure("c").stdout).toContain("RAKAZO_DESKTOP=2:view-c");
|
|
expect(f.release("a").status).toBe(0);
|
|
expect(f.ensure("d").stdout).toContain("RAKAZO_DESKTOP=0:view-d");
|
|
});
|
|
|
|
it("does not create a screen on control release and keeps newer fences", () => {
|
|
const f = fixture();
|
|
expect(f.run(desktopControlCommand("missing", "run:1", env, false, "token")).status).toBe(0);
|
|
expect(readdirSync(f.root).filter((name) => name.endsWith(".slot"))).toEqual([]);
|
|
expect(f.ensure("a", "new:2").status).toBe(0);
|
|
expect(f.run(desktopControlCommand("a", "old:1", env, true, "token")).status).toBe(75);
|
|
const slot = readdirSync(f.root).find((name) => name.endsWith(".slot"))!;
|
|
expect(readFileSync(path.join(f.root, slot), "utf8")).toContain("new:2");
|
|
});
|
|
|
|
it.each([DEFAULT_DESKTOP_ENV, env])(
|
|
"generates valid shell for every lifecycle operation ($displayStart)",
|
|
(environment) => {
|
|
for (const command of [
|
|
ensureScreenCommand(0, "bot's id", "token", environment),
|
|
ensureScreenCommand(1, "bot's id", "token", environment),
|
|
managedDesktopCommand("bot's id", "run:1", environment, "token"),
|
|
releaseDesktopCommand("bot's id", "run:1", environment),
|
|
desktopControlCommand("bot's id", "run:1", environment, true, "token"),
|
|
interactiveScreenCommand(false, "token", screenPorts(1, environment)),
|
|
stopExtraScreenCommand(1, "bot's id", environment),
|
|
]) {
|
|
const result = spawnSync("bash", ["-n", "-c", command], { encoding: "utf8" });
|
|
expect(result.stderr).toBe("");
|
|
expect(result.status).toBe(0);
|
|
}
|
|
},
|
|
);
|
|
|
|
it("skips damaged assignments while reserving their live display markers", () => {
|
|
const f = fixture();
|
|
writeFileSync(path.join(f.root, "empty.slot"), "");
|
|
writeFileSync(path.join(f.root, "invalid.slot"), "broken\nlease:1\ntoken\n");
|
|
writeFileSync(
|
|
path.join(f.root, "browser-profile-20"),
|
|
"/home/user/work/.browser-profiles/live",
|
|
);
|
|
expect(f.ensure("a").stdout).toContain("RAKAZO_DESKTOP=1:view-a");
|
|
expect(f.ensure("b").stdout).toContain("RAKAZO_DESKTOP=2:view-b");
|
|
expect(f.ensure("a").stdout).toContain("RAKAZO_DESKTOP=1:view-a");
|
|
});
|
|
|
|
it("continues resetting valid displays after invalid or out-of-range markers", () => {
|
|
const f = fixture();
|
|
for (const display of ["019", "19", "20", "22", "99999", "invalid"])
|
|
writeFileSync(path.join(f.root, `browser-profile-${display}`), "fixture");
|
|
const record = path.join(f.root, "stopped");
|
|
const result = spawnSync(
|
|
"bash",
|
|
[
|
|
"-eu",
|
|
"-c",
|
|
[
|
|
"pkill() { :; }; sleep() { :; }",
|
|
`bash() { printf '%s\\n' "$5" >>${shellQuote(record)}; }`,
|
|
resetDesktopRuntimeCommand(env).replaceAll("/tmp/rakazo", f.root),
|
|
].join("\n"),
|
|
],
|
|
{ encoding: "utf8", timeout: 5000 },
|
|
);
|
|
expect(result.status, result.stderr).toBe(0);
|
|
expect(readFileSync(record, "utf8")).toBe("0\n2\n");
|
|
});
|
|
|
|
it("stops only the selected VNC transport and keeps the shared gateway", () => {
|
|
const command = stopExtraScreenCommand(1, "a", env);
|
|
const patterns = [...command.matchAll(/pkill -f '([^']+)'/g)].map(
|
|
(match) => new RegExp(match[1]!),
|
|
);
|
|
for (const pattern of patterns) {
|
|
expect(`/bin/bash -c ${shellQuote(command)}`).not.toMatch(pattern);
|
|
expect(
|
|
"/usr/bin/python3 /usr/local/bin/websockify --web=/opt/noVNC 0.0.0.0:6100",
|
|
).not.toMatch(pattern);
|
|
}
|
|
expect(
|
|
patterns.some((pattern) =>
|
|
pattern.test(
|
|
"/usr/bin/x11vnc -display :21 -rfbport 0 -unixsock /tmp/rakazo/sockets/view-21-token -forever",
|
|
),
|
|
),
|
|
).toBe(true);
|
|
});
|
|
|
|
it("uses one published gateway and distinct private ports across 1000 desktops", () => {
|
|
const ports = new Set<number>();
|
|
for (let index = 0; index < 1000; index++) {
|
|
const layout = screenPorts(index, env);
|
|
expect(layout.viewPort).toBe("6100");
|
|
expect(layout.controlPort).toBe("6100");
|
|
expect(ports.has(layout.debugPort)).toBe(false);
|
|
ports.add(layout.debugPort);
|
|
}
|
|
expect(screenPorts(MAX_DESKTOP_DISPLAY - env.displayStart, env).debugPort).toBeLessThanOrEqual(
|
|
65535,
|
|
);
|
|
for (const index of [-1, 0.5, Number.POSITIVE_INFINITY, MAX_DESKTOP_DISPLAY]) {
|
|
expect(() => screenPorts(index, env)).toThrow("invalid desktop index");
|
|
}
|
|
});
|
|
|
|
it("keeps provider authentication while adding the per-lease websocket capability", () => {
|
|
const url = new URL(
|
|
desktopUrl("https://desktop.test/vnc.html?_token=provider-key", "view-key"),
|
|
);
|
|
expect(url.searchParams.get("_token")).toBe("provider-key");
|
|
expect(url.searchParams.get("path")).toBe("websockify?_token=provider-key&token=view-key");
|
|
});
|
|
});
|