Files
TheRock/rocm-systems/experimental/python/perfxpert/tests/e2e/test_opencode_session.py
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

112 lines
3.8 KiB
Python

"""E2E: opencode session — real MCP call through perfxpert-mcp.
Requires:
- perfxpert-code installed (entry point)
- perfxpert-mcp installed (entry point)
- bundled patched opencode binary available
- Any LLM provider configured, OR --no-llm / air-gap mode
Skips gracefully if the opencode binary isn't available.
"""
import os
import subprocess
import pytest
@pytest.fixture
def opencode_available():
try:
from perfxpert.cli.opencode_launcher import resolve_opencode_binary
resolve_opencode_binary()
return True
except Exception:
return False
def test_perfxpert_code_launches_if_opencode_available(opencode_available):
if not opencode_available:
pytest.skip("opencode binary not available on this system")
# Smoke: perfxpert-code must print our AMD banner to stderr BEFORE handing
# off to opencode's interactive TUI. opencode is an alternate-screen
# renderer that doesn't exit on stdin "exit\n", so we start it with Popen,
# wait briefly for the banner, then kill it. We only assert the banner
# emerged — proving the launcher ran.
import signal
proc = subprocess.Popen(
["perfxpert-code"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env={**os.environ, "PERFXPERT_CODE_NO_BANNER": "0"},
start_new_session=True, # so we can kill the whole process group
)
try:
import time as _t
_t.sleep(1.5)
finally:
try:
os.killpg(proc.pid, signal.SIGKILL)
except (ProcessLookupError, PermissionError):
proc.kill()
try:
_, stderr = proc.communicate(timeout=5)
except subprocess.TimeoutExpired:
proc.terminate()
_, stderr = proc.communicate(timeout=5)
assert b"AMD ROCm PerfXpert" in stderr
def test_mcp_server_accepts_a_call_from_shell(opencode_available):
"""Verify perfxpert-mcp at least starts and can receive an initialization message."""
if not opencode_available:
pytest.skip("opencode binary not available on this system")
import json
import select
# Start perfxpert-mcp with stdio
p = subprocess.Popen(
["perfxpert-mcp"],
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
)
try:
# Send an MCP initialize request (simplified; real MCP uses JSON-RPC framing)
init = json.dumps({
"jsonrpc": "2.0", "id": 1, "method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {"name": "perfxpert-e2e", "version": "1.0"},
},
}) + "\n"
p.stdin.write(init.encode("utf-8"))
p.stdin.flush()
ready, _, _ = select.select([p.stdout], [], [], 5)
assert ready, "perfxpert-mcp did not respond to initialize within 5s"
response_line = p.stdout.readline().decode("utf-8").strip()
response = json.loads(response_line)
assert "result" in response or "error" in response
finally:
if p.stdin and not p.stdin.closed:
p.stdin.close()
if p.poll() is None:
p.terminate()
try:
p.wait(timeout=2)
except subprocess.TimeoutExpired:
p.kill()
p.wait(timeout=2)
# NOTE: The test_end_to_end_interactive_session was a flaky pexpect-based TUI test.
# It has been replaced by test_perfxpert_code_live_mcp.py::test_perfxpert_code_calls_mcp_and_returns_expected_value
# which uses the non-interactive `perfxpert-code run` path and is more robust.
# Both tests verify the same contract:
# launcher → opencode → MCP → Python brain → response
# but the live-MCP version avoids pexpect's alternate-screen fragility.