Files
tracer-cloud--opensre/tests/e2e/openclaw/infrastructure_sdk/fault_injection.py
T
wehub-resource-sync 4b6817381b
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
CI / coverage-report (push) Has been cancelled
CI / test-kubernetes (push) Has been cancelled
CI / should-run-thorough (push) Has been cancelled
CI / test-thorough (cloudwatch-demo) (push) Has been cancelled
CI / test-thorough (flink-ecs) (push) Has been cancelled
CI / test-thorough (upstream-lambda) (push) Has been cancelled
CI / test-thorough (prefect-ecs-fargate) (push) Has been cancelled
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Has been cancelled
Benchmark image — build + push to ECR (any adapter) / build + push (push) Has been cancelled
CI / quality (ubuntu-latest) (push) Has been cancelled
CI / test (tools-runtime) (push) Has been cancelled
CI / test (e2e-general) (push) Has been cancelled
CI / test (cli-runtime) (push) Has been cancelled
CI / test (e2e-provider-and-openclaw) (push) Has been cancelled
CI / test (integrations-and-misc) (push) Has been cancelled
Release / verify (push) Has been cancelled
Release / build-python-dist (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Has been cancelled
Release / publish-release (push) Has been cancelled
Release / publish-main-release (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Has been cancelled
Release / prepare (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Has been cancelled
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:10:45 +08:00

100 lines
4.3 KiB
Python

"""Fault injectors for the OpenClaw end-to-end test suite.
Each scenario gets its own injector. They're independent — issues #5
(sleeping tool call → timeout) and #6 (wrong endpoint) can be
implemented in parallel after :func:`inject_gateway_down` (this PR
/ #3) lands.
Each injector takes a previously booted :class:`OpenClawHandle` and
mutates the state so the next ``use_case.drive_openclaw_conversation``
call hits the broken path. Injectors are idempotent — safe to call on
handles that are already in the target state (e.g. ``inject_gateway_down``
on a handle booted with ``with_gateway=False``).
"""
from __future__ import annotations
import sys
from integrations.openclaw import OpenClawConfig
from tests.e2e.openclaw.infrastructure_sdk.local import OpenClawHandle, teardown_openclaw
# Port + URL of OpenClaw's Control UI / Gateway service. ``opensre``
# users sometimes mistake this for the MCP bridge endpoint —
# :func:`integrations.openclaw._is_probable_openclaw_control_ui_url`
# detects that misconfiguration and the wrong-endpoint scenario asserts
# the hint propagates through to the RCA output.
_CONTROL_UI_URL = "http://127.0.0.1:18789/"
# Short timeout for the sleeping-tool scenario: long enough that a
# healthy fixture would respond, short enough that an unresponsive
# tool fails within seconds. Tests asserting the timeout fires use
# this same value so the expected error is reproducible.
_SLEEPING_TOOL_TIMEOUT_SECONDS = 2.0
def inject_gateway_down(handle: OpenClawHandle) -> None:
"""Ensure the OpenClaw Gateway is **not** running on this handle.
Tears down the Gateway process if the handle has one. When called on
a bare handle (booted via ``with_gateway=False``) this is a no-op.
After this call, any ``openclaw mcp serve`` bridge spawned by an MCP
client will fail to reach a Gateway — surfacing the
``Connection closed`` / ``ECONNREFUSED`` failure mode that
:func:`integrations.openclaw._looks_like_openclaw_gateway_unavailable`
detects.
"""
teardown_openclaw(handle)
# Clear handle fields so downstream callers see an unambiguously
# "Gateway down" handle even if they re-inspect after the call.
handle.gateway_pid = None
handle.extra["fault"] = "gateway_down"
def inject_sleeping_tool_call(handle: OpenClawHandle) -> None:
"""Reconfigure the handle so the use_case driver targets a Python
stdio MCP fixture whose only tool sleeps instead of returning.
Used to verify OpenSRE's tool-call timeout behavior — the
orchestrator must surface a useful "tool timed out" error rather
than blocking the investigation pipeline indefinitely.
:func:`integrations.openclaw._call_tool_async` wraps
``session.call_tool(...)`` with :func:`asyncio.wait_for` so
``OpenClawConfig.timeout_seconds`` applies uniformly across all
transports (stdio / sse / streamable-http).
"""
fixture_path = "tests.e2e.openclaw.fixtures.sleeping_mcp_server"
handle.extra["openclaw_config"] = OpenClawConfig(
mode="stdio",
command=sys.executable,
args=("-m", fixture_path),
timeout_seconds=_SLEEPING_TOOL_TIMEOUT_SECONDS,
integration_id="openclaw-e2e-sleeping-tool",
)
handle.extra["fault"] = "tool_call_timeout"
def inject_wrong_endpoint(handle: OpenClawHandle) -> None:
"""Reconfigure the handle so the use_case driver targets OpenClaw's
Control UI / Gateway port (18789) instead of the MCP bridge.
A common user-side misconfiguration: pasting the Gateway URL into
the MCP integration config. ``validate_openclaw_config`` detects
this via :func:`integrations.openclaw._is_probable_openclaw_control_ui_url`
and returns the canonical "Use mode `stdio` with command `openclaw`
and args `mcp serve`" hint. This injector stashes the matching
misconfigured config on ``handle.extra`` so the use_case driver
picks it up via :data:`tests.e2e.openclaw.use_case.HANDLE_CONFIG_KEY`.
No process is spawned and no Gateway interaction happens — the
failure surfaces from config validation alone, which is the entire
point of the scenario.
"""
handle.extra["openclaw_config"] = OpenClawConfig(
mode="streamable-http",
url=_CONTROL_UI_URL,
timeout_seconds=10.0,
integration_id="openclaw-e2e-wrong-endpoint",
)
handle.extra["fault"] = "wrong_endpoint"