openclaw / src /node-host /linux-node-plugin.integration.test.ts
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
fcd8223 verified
Raw
History Blame Contribute Delete
4.93 kB
import fs from "node:fs";
import path from "node:path";
import { afterEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { reconcileNodePairingOnConnect } from "../gateway/node-connect-reconcile.js";
import { resetPluginLoaderTestStateForTest } from "../plugins/loader.test-fixtures.js";
import { setActivePluginRegistry } from "../plugins/runtime.js";
import { listRegisteredNodeHostCapsAndCommands } from "./plugin-node-host.js";
import {
getNodeHostPluginRegistry,
resetNodeHostPluginRegistry,
} from "./plugin-node-host.test-support.js";
import { prepareNodeHostRuntime } from "./runtime.js";
const LINUX_NODE_COMMANDS = [
"camera.clip",
"camera.list",
"camera.snap",
"location.get",
"system.notify",
] as const;
function resetPluginState(): void {
resetPluginLoaderTestStateForTest();
resetNodeHostPluginRegistry();
}
const tempBundledRoots: string[] = [];
function createLinuxNodeBundledRoot(): string {
// Keep workspace dependencies resolvable from the copied integration package.
const root = fs.mkdtempSync(path.resolve(".linux-node-plugin-test-"));
try {
// Bundled discovery requires the package itself to stay inside its physical root.
fs.cpSync(path.resolve("extensions/linux-node"), path.join(root, "linux-node"), {
recursive: true,
});
} catch (error) {
fs.rmSync(root, { force: true, recursive: true });
throw error;
}
tempBundledRoots.push(root);
return root;
}
afterEach(() => {
vi.restoreAllMocks();
vi.unstubAllEnvs();
resetPluginState();
for (const root of tempBundledRoots.splice(0)) {
fs.rmSync(root, { force: true, recursive: true });
}
});
describe("linux-node node-host integration", () => {
it("loads and advertises enabled commands through the node-host runtime", async () => {
resetPluginState();
const platformDescriptor = Object.getOwnPropertyDescriptor(process, "platform");
if (!platformDescriptor) {
throw new Error("process.platform descriptor unavailable");
}
const bundledRoot = createLinuxNodeBundledRoot();
Object.defineProperty(process, "platform", { ...platformDescriptor, value: "linux" });
const fakeBinDir = path.resolve(".artifacts", "linux-node-test-bin");
const originalAccessSync = fs.accessSync.bind(fs);
vi.spyOn(fs, "accessSync").mockImplementation((candidate, mode) => {
if (path.dirname(path.resolve(String(candidate))) === fakeBinDir) {
return;
}
return originalAccessSync(candidate, mode);
});
vi.stubEnv("PATH", `${fakeBinDir}${path.delimiter}${process.env.PATH ?? ""}`);
vi.stubEnv("OPENCLAW_BUNDLED_PLUGINS_DIR", bundledRoot);
vi.stubEnv("OPENCLAW_TEST_TRUST_BUNDLED_PLUGINS_DIR", "1");
vi.stubEnv("OPENCLAW_DISABLE_BUNDLED_PLUGINS", undefined);
const config: OpenClawConfig = {
gateway: {
nodes: {
commands: { allow: ["camera.snap", "camera.clip"] },
},
},
nodeHost: { skills: { enabled: false } },
plugins: {
allow: ["linux-node"],
entries: {
"linux-node": {
enabled: true,
config: {
notify: { enabled: true },
camera: { enabled: true },
location: { enabled: true },
},
},
},
},
};
try {
const prepared = await prepareNodeHostRuntime({ config, env: process.env });
const registered = listRegisteredNodeHostCapsAndCommands({ config, env: process.env });
expect(registered.commands, JSON.stringify(getNodeHostPluginRegistry()?.diagnostics)).toEqual(
LINUX_NODE_COMMANDS,
);
expect(registered.caps).toEqual(["camera", "location"]);
expect(prepared.manifest.commands).toEqual(expect.arrayContaining([...LINUX_NODE_COMMANDS]));
const requestPairing = vi.fn();
setActivePluginRegistry(getNodeHostPluginRegistry()!);
const reconciliation = await reconcileNodePairingOnConnect({
cfg: config,
connectParams: {
minProtocol: 1,
maxProtocol: 1,
client: {
id: "node-host",
version: "test",
platform: "linux",
deviceFamily: "Linux",
mode: "node",
},
caps: registered.caps,
commands: registered.commands,
},
pairedNode: {
nodeId: "node-host",
createdAtMs: 1,
approvedAtMs: 1,
caps: registered.caps,
commands: registered.commands,
},
requestPairing,
});
expect(reconciliation.declaredCommands).toEqual(LINUX_NODE_COMMANDS);
expect(reconciliation.effectiveCommands).toEqual(LINUX_NODE_COMMANDS);
expect(requestPairing).not.toHaveBeenCalled();
} finally {
Object.defineProperty(process, "platform", platformDescriptor);
}
});
});