test(docker): fixture ClawHub plugin smoke

This commit is contained in:
Peter Steinberger
2026-04-27 05:38:23 +01:00
parent f83e424a5d
commit fd06aeac04
2 changed files with 173 additions and 0 deletions

View File

@@ -611,6 +611,169 @@ CLAWHUB_PLUGIN_SPEC="${OPENCLAW_PLUGINS_E2E_CLAWHUB_SPEC:-clawhub:openclaw-now4r
CLAWHUB_PLUGIN_ID="${OPENCLAW_PLUGINS_E2E_CLAWHUB_ID:-now4real}"
export CLAWHUB_PLUGIN_SPEC CLAWHUB_PLUGIN_ID
start_clawhub_fixture_server() {
local fixture_dir="$1"
local server_log="$fixture_dir/clawhub-fixture.log"
local server_port_file="$fixture_dir/clawhub-fixture-port"
local server_pid_file="$fixture_dir/clawhub-fixture-pid"
node - <<'NODE' "$server_port_file" >"$server_log" 2>&1 &
const crypto = require("node:crypto");
const http = require("node:http");
const path = require("node:path");
const { createRequire } = require("node:module");
const portFile = process.argv[2];
const requireFromApp = createRequire(path.join(process.cwd(), "package.json"));
const JSZip = requireFromApp("jszip");
const packageName = "openclaw-now4real";
const pluginId = "now4real";
const version = "0.1.2";
async function main() {
const zip = new JSZip();
zip.file(
"package/package.json",
`${JSON.stringify(
{
name: packageName,
version,
openclaw: { extensions: ["./index.js"] },
},
null,
2,
)}\n`,
{ date: new Date(0) },
);
zip.file(
"package/index.js",
`module.exports = {
id: "${pluginId}",
name: "Now 4 Real",
register(api) {
api.registerGatewayMethod("now4real.ping", async () => ({ ok: true }));
},
};
`,
{ date: new Date(0) },
);
zip.file(
"package/openclaw.plugin.json",
`${JSON.stringify(
{
id: pluginId,
configSchema: {
type: "object",
properties: {},
},
},
null,
2,
)}\n`,
{ date: new Date(0) },
);
const archive = await zip.generateAsync({ type: "nodebuffer", compression: "DEFLATE" });
const sha256hash = crypto.createHash("sha256").update(archive).digest("hex");
const json = (response, value) => {
response.writeHead(200, { "content-type": "application/json" });
response.end(`${JSON.stringify(value)}\n`);
};
const server = http.createServer((request, response) => {
const url = new URL(request.url, "http://127.0.0.1");
if (request.method !== "GET") {
response.writeHead(405);
response.end("method not allowed");
return;
}
if (url.pathname === `/api/v1/packages/${encodeURIComponent(packageName)}`) {
json(response, {
package: {
name: packageName,
displayName: "Now 4 Real",
family: "code-plugin",
channel: "official",
isOfficial: true,
runtimeId: pluginId,
latestVersion: version,
createdAt: 0,
updatedAt: 0,
compatibility: {
pluginApiRange: ">=2026.4.11",
minGatewayVersion: "2026.4.11",
},
},
});
return;
}
if (
url.pathname === `/api/v1/packages/${encodeURIComponent(packageName)}/versions/${version}`
) {
json(response, {
version: {
version,
createdAt: 0,
changelog: "Fixture package for Docker plugin E2E.",
sha256hash,
compatibility: {
pluginApiRange: ">=2026.4.11",
minGatewayVersion: "2026.4.11",
},
},
});
return;
}
if (url.pathname === `/api/v1/packages/${encodeURIComponent(packageName)}/download`) {
response.writeHead(200, {
"content-type": "application/zip",
"content-length": String(archive.length),
});
response.end(archive);
return;
}
response.writeHead(404, { "content-type": "text/plain" });
response.end(`not found: ${url.pathname}`);
});
server.listen(0, "127.0.0.1", () => {
require("node:fs").writeFileSync(portFile, String(server.address().port));
});
}
main().catch((error) => {
console.error(error);
process.exit(1);
});
NODE
local server_pid="$!"
echo "$server_pid" > "$server_pid_file"
for _ in $(seq 1 100); do
if [[ -s "$server_port_file" ]]; then
export OPENCLAW_CLAWHUB_URL="http://127.0.0.1:$(cat "$server_port_file")"
trap 'if [[ -f "'"$server_pid_file"'" ]]; then kill "$(cat "'"$server_pid_file"'")" 2>/dev/null || true; fi' EXIT
return 0
fi
if ! kill -0 "$server_pid" 2>/dev/null; then
cat "$server_log"
return 1
fi
sleep 0.1
done
cat "$server_log"
echo "Timed out waiting for ClawHub fixture server." >&2
return 1
}
if [[ -z "${OPENCLAW_CLAWHUB_URL:-}" && -z "${CLAWHUB_URL:-}" ]]; then
# Keep the release-path smoke hermetic; live ClawHub can rate-limit CI.
clawhub_fixture_dir="$(mktemp -d "/tmp/openclaw-clawhub-fixture.XXXXXX")"
start_clawhub_fixture_server "$clawhub_fixture_dir"
fi
node - <<'NODE'
const spec = process.env.CLAWHUB_PLUGIN_SPEC;
if (!spec?.startsWith("clawhub:")) {

View File

@@ -6,6 +6,7 @@ const DOCKER_ALL_SCHEDULER_PATH = "scripts/test-docker-all.mjs";
const DOCKER_E2E_SCENARIOS_PATH = "scripts/lib/docker-e2e-scenarios.mjs";
const INSTALL_E2E_RUNNER_PATH = "scripts/docker/install-sh-e2e/run.sh";
const OPENAI_WEB_SEARCH_MINIMAL_E2E_PATH = "scripts/e2e/openai-web-search-minimal-docker.sh";
const PLUGINS_DOCKER_E2E_PATH = "scripts/e2e/plugins-docker.sh";
const CENTRALIZED_BUILD_SCRIPTS = [
"scripts/docker/setup.sh",
"scripts/e2e/browser-cdp-snapshot-docker.sh",
@@ -95,4 +96,13 @@ describe("docker build helper", () => {
expect(runner).toContain('[...gatewayArgs, "agent", "--params"');
expect(runner).not.toContain('"agent.wait"');
});
it("keeps ClawHub plugin Docker smoke hermetic by default", () => {
const runner = readFileSync(PLUGINS_DOCKER_E2E_PATH, "utf8");
expect(runner).toContain("start_clawhub_fixture_server()");
expect(runner).toContain('OPENCLAW_CLAWHUB_URL="http://127.0.0.1:');
expect(runner).toContain("live ClawHub can rate-limit CI");
expect(runner).toContain('[[ -z "${OPENCLAW_CLAWHUB_URL:-}" && -z "${CLAWHUB_URL:-}" ]]');
});
});