mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-03 01:40:23 +00:00
fix: stabilize docker e2e lanes
This commit is contained in:
@@ -7,8 +7,16 @@ IMAGE_NAME="openclaw-plugins-e2e"
|
||||
echo "Building Docker image..."
|
||||
docker build -t "$IMAGE_NAME" -f "$ROOT_DIR/scripts/e2e/Dockerfile" "$ROOT_DIR"
|
||||
|
||||
DOCKER_ENV_ARGS=(-e COREPACK_ENABLE_DOWNLOAD_PROMPT=0)
|
||||
if [[ -n "${OPENAI_API_KEY:-}" && "${OPENAI_API_KEY:-}" != "undefined" && "${OPENAI_API_KEY:-}" != "null" ]]; then
|
||||
DOCKER_ENV_ARGS+=(-e OPENAI_API_KEY)
|
||||
fi
|
||||
if [[ -n "${OPENAI_BASE_URL:-}" && "${OPENAI_BASE_URL:-}" != "undefined" && "${OPENAI_BASE_URL:-}" != "null" ]]; then
|
||||
DOCKER_ENV_ARGS+=(-e OPENAI_BASE_URL)
|
||||
fi
|
||||
|
||||
echo "Running plugins Docker E2E..."
|
||||
docker run --rm -e COREPACK_ENABLE_DOWNLOAD_PROMPT=0 -e OPENAI_API_KEY -i "$IMAGE_NAME" bash -s <<'EOF'
|
||||
docker run --rm "${DOCKER_ENV_ARGS[@]}" -i "$IMAGE_NAME" bash -s <<'EOF'
|
||||
set -euo pipefail
|
||||
|
||||
if [ -f dist/index.mjs ]; then
|
||||
@@ -22,6 +30,24 @@ else
|
||||
fi
|
||||
export OPENCLAW_ENTRY
|
||||
|
||||
sanitize_env_string() {
|
||||
local value="${1:-}"
|
||||
if [[ "$value" == "undefined" || "$value" == "null" ]]; then
|
||||
printf ''
|
||||
return
|
||||
fi
|
||||
printf '%s' "$value"
|
||||
}
|
||||
|
||||
export OPENAI_API_KEY="$(sanitize_env_string "${OPENAI_API_KEY:-}")"
|
||||
export OPENAI_BASE_URL="$(sanitize_env_string "${OPENAI_BASE_URL:-}")"
|
||||
if [[ -z "$OPENAI_API_KEY" ]]; then
|
||||
unset OPENAI_API_KEY || true
|
||||
fi
|
||||
if [[ -z "$OPENAI_BASE_URL" ]]; then
|
||||
unset OPENAI_BASE_URL || true
|
||||
fi
|
||||
|
||||
home_dir=$(mktemp -d "/tmp/openclaw-plugins-e2e.XXXXXX")
|
||||
export HOME="$home_dir"
|
||||
BUNDLED_PLUGIN_ROOT_DIR="extensions"
|
||||
@@ -29,6 +55,40 @@ OPENCLAW_PLUGIN_HOME="$HOME/.openclaw/$BUNDLED_PLUGIN_ROOT_DIR"
|
||||
|
||||
gateway_pid=""
|
||||
|
||||
seed_openai_provider_config() {
|
||||
local openai_api_key="$1"
|
||||
local openai_base_url="${2:-}"
|
||||
node - <<'NODE' "$openai_api_key" "$openai_base_url"
|
||||
const fs = require("node:fs");
|
||||
const path = require("node:path");
|
||||
|
||||
const openaiApiKey = process.argv[2];
|
||||
const openaiBaseUrl = process.argv[3];
|
||||
const configPath = path.join(process.env.HOME, ".openclaw", "openclaw.json");
|
||||
const config = fs.existsSync(configPath)
|
||||
? JSON.parse(fs.readFileSync(configPath, "utf8"))
|
||||
: {};
|
||||
const existingOpenAI = config.models?.providers?.openai ?? {};
|
||||
config.models = {
|
||||
...(config.models || {}),
|
||||
providers: {
|
||||
...(config.models?.providers || {}),
|
||||
openai: {
|
||||
...existingOpenAI,
|
||||
baseUrl:
|
||||
typeof existingOpenAI.baseUrl === "string" && existingOpenAI.baseUrl.trim()
|
||||
? existingOpenAI.baseUrl
|
||||
: openaiBaseUrl || "https://api.openai.com/v1",
|
||||
apiKey: openaiApiKey,
|
||||
models: Array.isArray(existingOpenAI.models) ? existingOpenAI.models : [],
|
||||
},
|
||||
},
|
||||
};
|
||||
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
||||
fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`, "utf8");
|
||||
NODE
|
||||
}
|
||||
|
||||
stop_gateway() {
|
||||
if [ -n "${gateway_pid:-}" ] && kill -0 "$gateway_pid" 2>/dev/null; then
|
||||
kill "$gateway_pid" 2>/dev/null || true
|
||||
@@ -162,11 +222,12 @@ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
async function main() {
|
||||
const runId = `plugin-e2e-${randomUUID()}`;
|
||||
const sendResult = callGateway("chat.send", {
|
||||
const sendParams = {
|
||||
sessionKey,
|
||||
message,
|
||||
idempotencyKey: runId,
|
||||
});
|
||||
};
|
||||
const sendResult = callGateway("chat.send", sendParams);
|
||||
if (!sendResult.ok) {
|
||||
throw sendResult.error;
|
||||
}
|
||||
@@ -198,9 +259,39 @@ async function main() {
|
||||
);
|
||||
return;
|
||||
}
|
||||
const statusResult = callGateway("chat.send", sendParams);
|
||||
if (statusResult.ok) {
|
||||
const status = statusResult.value;
|
||||
if (status?.status === "error") {
|
||||
const summary =
|
||||
typeof status.summary === "string" && status.summary.trim()
|
||||
? status.summary.trim()
|
||||
: JSON.stringify(status);
|
||||
throw new Error(`gateway run failed for ${sessionKey}: ${summary}`);
|
||||
}
|
||||
}
|
||||
await sleep(100);
|
||||
}
|
||||
|
||||
const finalHistory = callGateway("chat.history", { sessionKey });
|
||||
const finalStatus = callGateway("chat.send", sendParams);
|
||||
fs.writeFileSync(
|
||||
outputFile,
|
||||
`${JSON.stringify(
|
||||
{
|
||||
sessionKey,
|
||||
runId,
|
||||
error: "timeout",
|
||||
history: finalHistory.ok ? finalHistory.value : null,
|
||||
historyError: finalHistory.ok ? null : String(finalHistory.error),
|
||||
status: finalStatus.ok ? finalStatus.value : null,
|
||||
statusError: finalStatus.ok ? null : String(finalStatus.error),
|
||||
},
|
||||
null,
|
||||
2,
|
||||
)}\n`,
|
||||
"utf8",
|
||||
);
|
||||
throw new Error(`timed out waiting for assistant reply for ${sessionKey}`);
|
||||
}
|
||||
|
||||
@@ -504,7 +595,9 @@ if (process.env.OPENAI_API_KEY) {
|
||||
...(config.agents || {}),
|
||||
defaults: {
|
||||
...(config.agents?.defaults || {}),
|
||||
model: { primary: "openai/gpt-5.4" },
|
||||
// Use the same stable OpenAI family as the installer E2E to avoid
|
||||
// long or reasoning-heavy live turns in this bundle-command smoke.
|
||||
model: { primary: "openai/gpt-4.1-mini" },
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -517,6 +610,10 @@ fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
||||
fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`, "utf8");
|
||||
NODE
|
||||
|
||||
if [ -n "${OPENAI_API_KEY:-}" ]; then
|
||||
seed_openai_provider_config "$OPENAI_API_KEY" "${OPENAI_BASE_URL:-}"
|
||||
fi
|
||||
|
||||
gateway_log="/tmp/openclaw-plugin-command-e2e.log"
|
||||
start_gateway "$gateway_log"
|
||||
wait_for_gateway_health
|
||||
@@ -630,11 +727,17 @@ NODE
|
||||
|
||||
if [ -n "${OPENAI_API_KEY:-}" ]; then
|
||||
echo "Testing Claude bundle command invocation..."
|
||||
run_gateway_chat_json \
|
||||
if ! run_gateway_chat_json \
|
||||
"plugin-e2e-live" \
|
||||
"/office_hours Reply with exactly BUNDLE_OK and nothing else." \
|
||||
/tmp/plugin-command-live.json \
|
||||
60000
|
||||
120000; then
|
||||
echo "Claude bundle command invocation failed; payload dump:"
|
||||
cat /tmp/plugin-command-live.json 2>/dev/null || true
|
||||
echo "Gateway log tail:"
|
||||
tail -n 200 "$gateway_log" || true
|
||||
exit 1
|
||||
fi
|
||||
node - <<'NODE'
|
||||
const fs = require("node:fs");
|
||||
const payload = JSON.parse(fs.readFileSync("/tmp/plugin-command-live.json", "utf8"));
|
||||
|
||||
Reference in New Issue
Block a user