Files
openclaw/test/scripts/docker-plugin-selection.test.ts
Peter Steinberger a238dead67 fix(docker): package selected external plugins in source-built images (#103629)
* build(docker): package selected external plugins

* test(docker): auto-clean plugin fixture

* fix(docker): preserve selected image provenance

* fix(docker): accept manifest-only plugin selections

* fix(docker): resolve selected plugin manifest ids

* fix(docker): isolate resolved plugin selection
2026-07-10 13:00:50 +01:00

63 lines
2.4 KiB
TypeScript

import { spawnSync } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { afterEach, describe, expect, it } from "vitest";
import { useAutoCleanupTempDirTracker } from "../helpers/temp-dir.js";
const repoRoot = path.resolve(fileURLToPath(new URL("../..", import.meta.url)));
const selectorScript = path.join(repoRoot, "scripts/lib/docker-plugin-selection.mjs");
const tempDirs = useAutoCleanupTempDirTracker(afterEach);
function writePlugin(extensionsRoot: string, dirName: string, manifestId?: string) {
const pluginDir = path.join(extensionsRoot, dirName);
fs.mkdirSync(pluginDir, { recursive: true });
fs.writeFileSync(path.join(pluginDir, "package.json"), `${JSON.stringify({ name: dirName })}\n`);
if (manifestId) {
fs.writeFileSync(
path.join(pluginDir, "openclaw.plugin.json"),
`${JSON.stringify({ id: manifestId })}\n`,
);
}
}
function runSelector(extensionsRoot: string, selection: string) {
return spawnSync(process.execPath, [selectorScript, extensionsRoot, selection], {
encoding: "utf8",
});
}
describe("Docker plugin selection", () => {
it("resolves manifest ids and source directory names deterministically", () => {
const extensionsRoot = tempDirs.make("openclaw-docker-plugin-selection-");
writePlugin(extensionsRoot, "source-only");
writePlugin(extensionsRoot, "provider-source", "provider-id");
const result = runSelector(
extensionsRoot,
"source-only,provider-id provider-source,provider-id",
);
expect(result.status).toBe(0);
expect(result.stderr).toBe("");
expect(result.stdout).toBe("provider-source\nsource-only\n");
});
it("fails closed for unknown, invalid, and ambiguous ids", () => {
const extensionsRoot = tempDirs.make("openclaw-docker-plugin-selection-errors-");
writePlugin(extensionsRoot, "shared");
writePlugin(extensionsRoot, "other-source", "shared");
for (const [selection, message] of [
["missing-plugin", "unknown OPENCLAW_EXTENSIONS plugin id: missing-plugin"],
["../invalid", "invalid OPENCLAW_EXTENSIONS plugin id: ../invalid"],
["shared", "ambiguous OPENCLAW_EXTENSIONS plugin id: shared"],
] as const) {
const result = runSelector(extensionsRoot, selection);
expect(result.status).toBe(1);
expect(result.stdout).toBe("");
expect(result.stderr).toContain(message);
}
});
});