test: add plugin docker e2e
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
### Changes
|
||||
- Plugins: add extension loader (tools/RPC/CLI/services), discovery paths, config schema, and Control UI labels; ship voice-call plugin stub + skill.
|
||||
- Docs: add plugins doc + cross-links from tools/skills/gateway config.
|
||||
- Tests: add Docker plugin loader smoke test.
|
||||
- Build: set pnpm minimum release age to 2880 minutes (2 days). (#718) — thanks @dan-dr.
|
||||
- macOS: prompt to install the global `clawdbot` CLI when missing in local mode; install via `clawd.bot/install-cli.sh` (no onboarding) and use external launchd/CLI instead of the embedded gateway runtime.
|
||||
- Docs: add gog calendar event color IDs from `gog calendar colors`. (#715) — thanks @mjrussell.
|
||||
|
||||
@@ -298,6 +298,7 @@ These run `pnpm test:live` inside the repo Docker image, mounting your local con
|
||||
- Gateway + dev agent: `pnpm test:docker:live-gateway` (script: `scripts/test-live-gateway-models-docker.sh`)
|
||||
- Onboarding wizard (TTY, full scaffolding): `pnpm test:docker:onboard` (script: `scripts/e2e/onboard-docker.sh`)
|
||||
- Gateway networking (two containers, WS auth + health): `pnpm test:docker:gateway-network` (script: `scripts/e2e/gateway-network-docker.sh`)
|
||||
- Plugins (custom extension load + registry smoke): `pnpm test:docker:plugins` (script: `scripts/e2e/plugins-docker.sh`)
|
||||
|
||||
Useful env vars:
|
||||
|
||||
|
||||
@@ -104,8 +104,9 @@
|
||||
"test:docker:live-gateway": "bash scripts/test-live-gateway-models-docker.sh",
|
||||
"test:docker:qr": "bash scripts/e2e/qr-import-docker.sh",
|
||||
"test:docker:doctor-switch": "bash scripts/e2e/doctor-install-switch-docker.sh",
|
||||
"test:docker:plugins": "bash scripts/e2e/plugins-docker.sh",
|
||||
"test:docker:cleanup": "bash scripts/test-cleanup-docker.sh",
|
||||
"test:docker:all": "pnpm test:docker:live-models && pnpm test:docker:live-gateway && pnpm test:docker:onboard && pnpm test:docker:gateway-network && pnpm test:docker:qr && pnpm test:docker:doctor-switch && pnpm test:docker:cleanup",
|
||||
"test:docker:all": "pnpm test:docker:live-models && pnpm test:docker:live-gateway && pnpm test:docker:onboard && pnpm test:docker:gateway-network && pnpm test:docker:qr && pnpm test:docker:doctor-switch && pnpm test:docker:plugins && pnpm test:docker:cleanup",
|
||||
"test:all": "pnpm lint && pnpm build && pnpm test && pnpm test:e2e && pnpm test:live && pnpm test:docker:all",
|
||||
"test:install:e2e": "bash scripts/test-install-sh-e2e-docker.sh",
|
||||
"test:install:e2e:openai": "CLAWDBOT_E2E_MODELS=openai bash scripts/test-install-sh-e2e-docker.sh",
|
||||
|
||||
64
scripts/e2e/plugins-docker.sh
Executable file
64
scripts/e2e/plugins-docker.sh
Executable file
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
IMAGE_NAME="clawdbot-plugins-e2e"
|
||||
|
||||
echo "Building Docker image..."
|
||||
docker build -t "$IMAGE_NAME" -f "$ROOT_DIR/scripts/e2e/Dockerfile" "$ROOT_DIR"
|
||||
|
||||
echo "Running plugins Docker E2E..."
|
||||
docker run --rm -t "$IMAGE_NAME" bash -lc '
|
||||
set -euo pipefail
|
||||
|
||||
home_dir=$(mktemp -d "/tmp/clawdbot-plugins-e2e.XXXXXX")
|
||||
export HOME="$home_dir"
|
||||
mkdir -p "$HOME/.clawdbot/extensions"
|
||||
|
||||
cat > "$HOME/.clawdbot/extensions/demo-plugin.js" <<'"'"'JS'"'"'
|
||||
module.exports = {
|
||||
id: "demo-plugin",
|
||||
name: "Demo Plugin",
|
||||
description: "Docker E2E demo plugin",
|
||||
register(api) {
|
||||
api.registerTool(() => null, { name: "demo_tool" });
|
||||
api.registerGatewayMethod("demo.ping", async () => ({ ok: true }));
|
||||
api.registerCli(() => {}, { commands: ["demo"] });
|
||||
api.registerService({ id: "demo-service", start: () => {} });
|
||||
},
|
||||
};
|
||||
JS
|
||||
|
||||
node dist/index.js plugins list --json > /tmp/plugins.json
|
||||
|
||||
node - <<'"'"'NODE'"'"'
|
||||
const fs = require("node:fs");
|
||||
|
||||
const data = JSON.parse(fs.readFileSync("/tmp/plugins.json", "utf8"));
|
||||
const plugin = (data.plugins || []).find((entry) => entry.id === "demo-plugin");
|
||||
if (!plugin) throw new Error("plugin not found");
|
||||
if (plugin.status !== "loaded") {
|
||||
throw new Error(`unexpected status: ${plugin.status}`);
|
||||
}
|
||||
|
||||
const assertIncludes = (list, value, label) => {
|
||||
if (!Array.isArray(list) || !list.includes(value)) {
|
||||
throw new Error(`${label} missing: ${value}`);
|
||||
}
|
||||
};
|
||||
|
||||
assertIncludes(plugin.toolNames, "demo_tool", "tool");
|
||||
assertIncludes(plugin.gatewayMethods, "demo.ping", "gateway method");
|
||||
assertIncludes(plugin.cliCommands, "demo", "cli command");
|
||||
assertIncludes(plugin.services, "demo-service", "service");
|
||||
|
||||
const diagErrors = (data.diagnostics || []).filter((diag) => diag.level === "error");
|
||||
if (diagErrors.length > 0) {
|
||||
throw new Error(`diagnostics errors: ${diagErrors.map((diag) => diag.message).join("; ")}`);
|
||||
}
|
||||
|
||||
console.log("ok");
|
||||
NODE
|
||||
'
|
||||
|
||||
echo "OK"
|
||||
@@ -153,7 +153,7 @@ export function registerPluginsCli(program: Command) {
|
||||
plugins: {
|
||||
...cfg.plugins,
|
||||
entries: {
|
||||
...(cfg.plugins?.entries ?? {}),
|
||||
...cfg.plugins?.entries,
|
||||
[id]: {
|
||||
...(
|
||||
cfg.plugins?.entries as
|
||||
@@ -182,7 +182,7 @@ export function registerPluginsCli(program: Command) {
|
||||
plugins: {
|
||||
...cfg.plugins,
|
||||
entries: {
|
||||
...(cfg.plugins?.entries ?? {}),
|
||||
...cfg.plugins?.entries,
|
||||
[id]: {
|
||||
...(
|
||||
cfg.plugins?.entries as
|
||||
|
||||
Reference in New Issue
Block a user