E2E Integration #236
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: E2E Integration | |
| # Validates that the plugin works end-to-end against the latest published | |
| # OpenClaw release. Installs OpenClaw fresh, builds and installs the plugin | |
| # from source, starts the gateway with a mock LLM + mock Opik server, runs | |
| # a real agent turn, and asserts that traces and spans were exported. | |
| # | |
| # This catches regressions caused by OpenClaw plugin lifecycle changes that | |
| # unit tests cannot detect. | |
| permissions: | |
| contents: read | |
| on: | |
| push: | |
| branches: [main] | |
| paths: | |
| - ".github/workflows/e2e.yml" | |
| - "index.ts" | |
| - "openclaw.plugin.json" | |
| - "src/**" | |
| - ".scripts/**" | |
| - "package.json" | |
| - "package-lock.json" | |
| - "tsconfig.json" | |
| - "tsconfig.build.json" | |
| pull_request: | |
| branches: [main] | |
| paths: | |
| - ".github/workflows/e2e.yml" | |
| - "index.ts" | |
| - "openclaw.plugin.json" | |
| - "src/**" | |
| - ".scripts/**" | |
| - "package.json" | |
| - "package-lock.json" | |
| - "tsconfig.json" | |
| - "tsconfig.build.json" | |
| schedule: | |
| - cron: '0 6 * * *' # daily at 6am UTC — catches new OpenClaw releases breaking the plugin | |
| workflow_dispatch: | |
| jobs: | |
| e2e: | |
| name: E2E against OpenClaw ${{ matrix.openclaw-version }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| openclaw-version: | |
| - latest | |
| env: | |
| E2E_RESULT_FILE: e2e-result.json | |
| E2E_LLM_RESULT_FILE: e2e-llm-result.json | |
| E2E_OPIK_JOURNAL_FILE: e2e-opik-journal.json | |
| E2E_LLM_JOURNAL_FILE: e2e-llm-journal.json | |
| E2E_EXPECTED_OPIK_PROJECT: e2e-test | |
| OPENCLAW_GATEWAY_TOKEN: e2e-test-token | |
| steps: | |
| - name: Checkout plugin source | |
| uses: actions/checkout@v6 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: "22.x" | |
| cache: "npm" | |
| - name: Setup npm | |
| run: npm install -g npm@11.6.2 | |
| - name: Setup npm global prefix for caching | |
| run: | | |
| npm config set prefix ~/.npm-global | |
| echo "$HOME/.npm-global/bin" >> $GITHUB_PATH | |
| - name: Resolve OpenClaw version | |
| id: openclaw-version | |
| run: | | |
| if [ "${{ matrix.openclaw-version }}" = "latest" ]; then | |
| version="$(npm view openclaw version)" | |
| else | |
| version="${{ matrix.openclaw-version }}" | |
| fi | |
| echo "value=$version" >> "$GITHUB_OUTPUT" | |
| echo "Resolved OpenClaw version: $version" | |
| - name: Cache OpenClaw install | |
| id: cache-openclaw | |
| uses: actions/cache@v5 | |
| with: | |
| path: ~/.npm-global | |
| key: openclaw-${{ steps.openclaw-version.outputs.value }}-${{ runner.os }}-${{ runner.arch }} | |
| - name: Install OpenClaw (${{ steps.openclaw-version.outputs.value }}) | |
| if: steps.cache-openclaw.outputs.cache-hit != 'true' | |
| run: npm install -g openclaw@${{ steps.openclaw-version.outputs.value }} | |
| - name: Print OpenClaw version | |
| run: openclaw --version | |
| - name: Cache plugin dependencies | |
| id: cache-node-modules | |
| uses: actions/cache@v5 | |
| with: | |
| path: node_modules | |
| key: node-modules-${{ runner.os }}-node22-${{ hashFiles('package-lock.json') }} | |
| - name: Install plugin dependencies | |
| if: steps.cache-node-modules.outputs.cache-hit != 'true' | |
| run: npm ci | |
| - name: Build plugin tarball | |
| run: npm pack | |
| - name: Write OpenClaw config | |
| run: | | |
| mkdir -p ~/.openclaw/agents/main/sessions | |
| cat > ~/.openclaw/openclaw.json << 'EOF' | |
| { | |
| "gateway": { | |
| "mode": "local", | |
| "bind": "loopback", | |
| "auth": { "mode": "token", "token": "e2e-test-token" }, | |
| "port": 18789 | |
| }, | |
| "agents": { | |
| "defaults": { | |
| "model": { | |
| "primary": "mock-openai/gpt-4o-mini" | |
| } | |
| } | |
| }, | |
| "models": { | |
| "mode": "merge", | |
| "providers": { | |
| "mock-openai": { | |
| "baseUrl": "http://127.0.0.1:18790/v1", | |
| "apiKey": "mock-key", | |
| "authHeader": true, | |
| "api": "openai-responses", | |
| "models": [ | |
| { | |
| "id": "gpt-4o-mini", | |
| "name": "Mock GPT-4o Mini", | |
| "reasoning": false, | |
| "input": ["text"], | |
| "cost": { | |
| "input": 0, | |
| "output": 0, | |
| "cacheRead": 0, | |
| "cacheWrite": 0 | |
| }, | |
| "contextWindow": 128000, | |
| "maxTokens": 16384 | |
| } | |
| ] | |
| } | |
| } | |
| }, | |
| "plugins": { | |
| "allow": ["opik-openclaw"], | |
| "entries": { | |
| "opik-openclaw": { | |
| "enabled": true, | |
| "hooks": { | |
| "allowConversationAccess": true | |
| }, | |
| "config": { | |
| "enabled": true, | |
| "apiUrl": "http://127.0.0.1:18791", | |
| "apiKey": "mock-key", | |
| "projectName": "e2e-test", | |
| "workspaceName": "default" | |
| } | |
| } | |
| } | |
| } | |
| } | |
| EOF | |
| - name: Install plugin from tarball | |
| run: openclaw plugins install ./opik-opik-openclaw-*.tgz | |
| - name: Start mock Opik server | |
| run: | | |
| node .scripts/mock-opik-server.mjs > mock-opik.log 2>&1 & | |
| echo $! > mock-opik.pid | |
| env: | |
| MOCK_OPIK_PORT: "18791" | |
| - name: Start mock LLM server | |
| run: | | |
| node .scripts/mock-llm-server.mjs > mock-llm.log 2>&1 & | |
| echo $! > mock-llm.pid | |
| env: | |
| MOCK_LLM_PORT: "18790" | |
| - name: Wait for mock servers to be ready | |
| run: | | |
| for i in $(seq 1 10); do | |
| curl -sf http://127.0.0.1:18791/health > /dev/null 2>&1 && \ | |
| curl -sf http://127.0.0.1:18790/v1/models > /dev/null 2>&1 && break | |
| sleep 1 | |
| done | |
| - name: Start OpenClaw gateway | |
| run: | | |
| openclaw gateway run > gateway.log 2>&1 & | |
| echo $! > gateway.pid | |
| - name: Wait for gateway to be ready | |
| run: | | |
| for i in $(seq 1 15); do | |
| openclaw health > /dev/null 2>&1 && break | |
| sleep 1 | |
| done | |
| openclaw health | |
| - name: Run agent turn | |
| run: | | |
| set -o pipefail | |
| openclaw agent --agent main --message "ping" --deliver 2>&1 | tee agent-output.log | |
| if grep -q "falling back to embedded" agent-output.log; then | |
| echo "[e2e] FAIL: gateway turn fell back to embedded mode" | |
| exit 1 | |
| fi | |
| timeout-minutes: 2 | |
| - name: Stop gateway and flush traces | |
| run: | | |
| openclaw gateway stop || true | |
| if [ -f gateway.pid ]; then | |
| kill "$(cat gateway.pid)" > /dev/null 2>&1 || true | |
| fi | |
| sleep 2 | |
| - name: Stop mock servers and collect results | |
| run: | | |
| if [ -f mock-opik.pid ]; then | |
| kill "$(cat mock-opik.pid)" > /dev/null 2>&1 || true | |
| fi | |
| if [ -f mock-llm.pid ]; then | |
| kill "$(cat mock-llm.pid)" > /dev/null 2>&1 || true | |
| fi | |
| sleep 1 | |
| - name: Assert E2E results | |
| run: node .scripts/check-e2e-result.mjs | |
| - name: Upload E2E result on failure | |
| if: failure() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: e2e-debug | |
| path: | | |
| e2e-result.json | |
| e2e-llm-result.json | |
| e2e-opik-journal.json | |
| e2e-llm-journal.json | |
| agent-output.log | |
| gateway.log | |
| mock-opik.log | |
| mock-llm.log | |
| if-no-files-found: ignore |