test(adapter): install adapter import shims via conftest
All checks were successful
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 4s
CI / Adapter unit tests (push) Successful in 58s
CI / Adapter unit tests (pull_request) Successful in 58s
CI / validate (pull_request) Successful in 2m59s
CI / validate (push) Successful in 3m0s
All checks were successful
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 4s
CI / Adapter unit tests (push) Successful in 58s
CI / Adapter unit tests (pull_request) Successful in 58s
CI / validate (pull_request) Successful in 2m59s
CI / validate (push) Successful in 3m0s
CI runner installs only `pytest pytest-asyncio pyyaml`; without the molecule_runtime/a2a/claude_sdk_executor stubs, the new test_provider_resolution.py fails to collect with ModuleNotFoundError. test_adapter_prevalidate.py owned the same shims via a per-file _install_stubs(), but two files maintaining parallel stub copies eventually disagree on shape (BaseAdapter needing install_plugins_via_registry, etc.). Move the shim install + sys.path bump into tests/conftest.py so every test module shares a single canonical stub set, collected before any test imports adapter. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a2c7bf3d3b
commit
f8d7f8f3a8
89
tests/conftest.py
Normal file
89
tests/conftest.py
Normal file
@ -0,0 +1,89 @@
|
||||
"""Shared pytest fixtures + import shims for the adapter test suite.
|
||||
|
||||
`adapter.py` imports at module load:
|
||||
- molecule_runtime.adapters.base (BaseAdapter, AdapterConfig, RuntimeCapabilities)
|
||||
- molecule_runtime.plugins (lazy in setup(), but stubbed proactively)
|
||||
- a2a.server.agent_execution (AgentExecutor)
|
||||
- claude_sdk_executor (lazy in create_executor(), stubbed proactively)
|
||||
|
||||
In production those arrive transitively via molecule-ai-workspace-runtime.
|
||||
The CI runner only installs `pytest pytest-asyncio pyyaml`, so the import
|
||||
chain would fail with ModuleNotFoundError before any test collects —
|
||||
exactly the failure that broke CI on the #180 fix branch (PR #4) and
|
||||
caused the merge wall to block on a green local but red Gitea CI.
|
||||
|
||||
Putting the stub installer here (collected before any test module is
|
||||
imported, per pytest semantics) means every test file can do
|
||||
`from adapter import ...` at module top without a per-file boilerplate
|
||||
copy. It also forces a single shape for the stubs so two files can't
|
||||
silently disagree on whether `BaseAdapter` has
|
||||
`install_plugins_via_registry` (see test_adapter_prevalidate's
|
||||
async-setup tests, which need the method to exist on the parent class).
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import types
|
||||
from dataclasses import dataclass
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
|
||||
@dataclass
|
||||
class _StubRuntimeCapabilities:
|
||||
provides_native_session: bool = False
|
||||
|
||||
|
||||
@dataclass
|
||||
class _StubAdapterConfig:
|
||||
runtime_config: object = None
|
||||
config_path: str = "/tmp/configs"
|
||||
system_prompt: str = ""
|
||||
heartbeat: object = None
|
||||
|
||||
|
||||
class _StubBaseAdapter:
|
||||
async def install_plugins_via_registry(self, *_args, **_kwargs):
|
||||
pass
|
||||
|
||||
|
||||
def _install_stubs() -> None:
|
||||
"""Install the smallest set of import shims that adapter.py needs."""
|
||||
if "molecule_runtime" not in sys.modules:
|
||||
mr = types.ModuleType("molecule_runtime")
|
||||
mr.adapters = types.ModuleType("molecule_runtime.adapters")
|
||||
mr.adapters.base = types.ModuleType("molecule_runtime.adapters.base")
|
||||
mr.adapters.base.BaseAdapter = _StubBaseAdapter
|
||||
mr.adapters.base.AdapterConfig = _StubAdapterConfig
|
||||
mr.adapters.base.RuntimeCapabilities = _StubRuntimeCapabilities
|
||||
mr.plugins = types.ModuleType("molecule_runtime.plugins")
|
||||
mr.plugins.load_plugins = lambda **_kwargs: []
|
||||
sys.modules["molecule_runtime"] = mr
|
||||
sys.modules["molecule_runtime.adapters"] = mr.adapters
|
||||
sys.modules["molecule_runtime.adapters.base"] = mr.adapters.base
|
||||
sys.modules["molecule_runtime.plugins"] = mr.plugins
|
||||
if "a2a" not in sys.modules:
|
||||
a2a = types.ModuleType("a2a")
|
||||
a2a.server = types.ModuleType("a2a.server")
|
||||
a2a.server.agent_execution = types.ModuleType("a2a.server.agent_execution")
|
||||
a2a.server.agent_execution.AgentExecutor = type("AgentExecutor", (), {})
|
||||
sys.modules["a2a"] = a2a
|
||||
sys.modules["a2a.server"] = a2a.server
|
||||
sys.modules["a2a.server.agent_execution"] = a2a.server.agent_execution
|
||||
if "claude_sdk_executor" not in sys.modules:
|
||||
mod = types.ModuleType("claude_sdk_executor")
|
||||
mod.ClaudeSDKExecutor = MagicMock(name="ClaudeSDKExecutor")
|
||||
sys.modules["claude_sdk_executor"] = mod
|
||||
|
||||
|
||||
# Run at conftest import time — pytest collects conftest.py before any
|
||||
# test module, so the stubs are in sys.modules before `from adapter
|
||||
# import ...` ever executes.
|
||||
_install_stubs()
|
||||
|
||||
# adapter.py lives in the parent dir of tests/ (template root). pytest's
|
||||
# `--import-mode=importlib` + tests/pytest.ini anchoring rootdir at
|
||||
# tests/ means the parent isn't on sys.path automatically. Add it here
|
||||
# once so every test file can do `from adapter import ...` cleanly.
|
||||
_PARENT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
if _PARENT_DIR not in sys.path:
|
||||
sys.path.insert(0, _PARENT_DIR)
|
||||
@ -11,6 +11,11 @@ These tests mirror the production failure mode reported by Hongming
|
||||
adapter ignored it entirely, the SDK kept calling the Anthropic API with
|
||||
CLAUDE_CODE_OAUTH_TOKEN, hit the OAuth quota, and the canvas surfaced
|
||||
"Agent error (Exception)" with no clue why.
|
||||
|
||||
Import-shim setup (sys.path + molecule_runtime / a2a / claude_sdk_executor
|
||||
stubs) lives in tests/conftest.py — shared with test_adapter_prevalidate
|
||||
so the two stub installers can't disagree on shape (e.g. BaseAdapter
|
||||
having install_plugins_via_registry).
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
Loading…
Reference in New Issue
Block a user