molecule-sdk-python/tests/conftest.py
Molecule AI SDK-Dev 66502e669a fix(tests): add conftest.py + fix test_call_peer_errors.py broken imports
- tests/conftest.py: added FakeResponse, client fixture, tmp_token_dir fixture,
  and _CaptureHandler (stubs for integration tests)
- tests/test_call_peer_errors.py: rewrote all tests to use existing client.py
  patterns (MagicMock session) instead of non-existent httpx fixtures.
  Removed mocker/http_mock/conftest fixtures that don't exist in this repo.
  12 tests now cover: timeout, connection error, 4xx/5xx errors, empty body,
  JSON-RPC envelope format, auth headers, direct→proxy fallback path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 18:18:10 +00:00

110 lines
3.1 KiB
Python

"""Pytest fixtures and helpers for molecule_agent tests.
All fixtures are pytest-scoped unless noted. No live platform required —
all HTTP is mocked via ``unittest.mock``.
"""
from __future__ import annotations
import stat
from pathlib import Path
from typing import Any
from unittest.mock import MagicMock
import pytest
from molecule_agent import RemoteAgentClient
# ---------------------------------------------------------------------------
# FakeResponse — minimal requests-shaped response
# ---------------------------------------------------------------------------
class FakeResponse:
"""Minimal stand-in for ``requests.Response``."""
def __init__(
self,
status_code: int = 200,
json_body: Any = None,
text: str = "",
) -> None:
self.status_code = status_code
self._json = json_body
self.text = text
def json(self) -> Any:
return self._json
def raise_for_status(self) -> None:
if self.status_code >= 400:
import requests
raise requests.HTTPError(f"HTTP {self.status_code}")
# ---------------------------------------------------------------------------
# Fixtures
# ---------------------------------------------------------------------------
@pytest.fixture
def tmp_token_dir(tmp_path: Path) -> Path:
return tmp_path / "molecule-token-cache"
@pytest.fixture
def client(tmp_token_dir: Path) -> RemoteAgentClient:
"""RemoteAgentClient with a MagicMock session for unit tests."""
session = MagicMock()
return RemoteAgentClient(
workspace_id="ws-test-123",
platform_url="http://platform.test",
agent_card={"name": "test-agent"},
token_dir=tmp_token_dir,
session=session,
)
# ---------------------------------------------------------------------------
# _CaptureHandler — minimal HTTP mock for integration tests
# ---------------------------------------------------------------------------
class _CaptureHandler:
"""Thread-local registry of HTTP stubs for use in integration tests.
Registered stubs are checked in order (last-registered first); the first
matching (method, path) pair wins. Unmatched requests raise
``RuntimeError("no stub for {method} {path}")``.
Usage::
_CaptureHandler.clear()
_CaptureHandler.stub("GET", "/foo", 200, {}, "body")
with some_client:
result = await some_client.get("/foo")
"""
_stubs: list[tuple[str, str, int, dict[str, str], str]] = []
@classmethod
def clear(cls) -> None:
cls._stubs.clear()
@classmethod
def stub(
cls,
method: str,
path: str,
status: int,
headers: dict[str, str],
body: str,
) -> None:
cls._stubs.append((method, path, status, headers, body))
@classmethod
def handle(cls, method: str, url: str, **kwargs: Any) -> FakeResponse:
for m, p, status, headers, body in reversed(cls._stubs):
if m == method and p in url:
return FakeResponse(status, json_body={}, text=body)
raise RuntimeError(f"no stub for {method} {url}")