Spaces:
Runtime error
Runtime error
| """Test helpers — an httpx.MockTransport-based recorder. | |
| Tests assert on exact method/url/body/headers without any real network or | |
| global monkey-patching. ``httpx.MockTransport`` is the idiomatic, native way | |
| to test an httpx-based client. | |
| """ | |
| from __future__ import annotations | |
| import json | |
| from dataclasses import dataclass, field | |
| from typing import Any, Callable | |
| import httpx | |
| class RecordedCall: | |
| method: str | |
| url: str | |
| headers: dict[str, str] | |
| body: Any | |
| class MockBackend: | |
| """A scripted backend. Raises if a call doesn't match a route.""" | |
| calls: list[RecordedCall] = field(default_factory=list) | |
| routes: list[tuple[str, str, Callable[[RecordedCall], httpx.Response]]] = field(default_factory=list) | |
| fallback: Callable[[RecordedCall], httpx.Response] | None = None | |
| def on( | |
| self, | |
| method: str, | |
| path_prefix: str, | |
| status: int = 200, | |
| body: Any = None, | |
| ) -> "MockBackend": | |
| def responder(_: RecordedCall) -> httpx.Response: | |
| if status in (204, 100, 304) or body is None: | |
| return httpx.Response(status, content=b"") | |
| return httpx.Response(status, content=json.dumps(body).encode(), headers={"content-type": "application/json"}) | |
| self.routes.append((method.upper(), path_prefix, responder)) | |
| return self | |
| def as_transport(self) -> httpx.MockTransport: | |
| def handler(request: httpx.Request) -> httpx.Response: | |
| method = request.method.upper() | |
| url = str(request.url) | |
| body: Any = None | |
| if request.content: | |
| try: | |
| body = json.loads(request.content) | |
| except ValueError: | |
| body = request.content.decode(errors="replace") | |
| call = RecordedCall(method=method, url=url, headers=dict(request.headers), body=body) | |
| self.calls.append(call) | |
| # Most-specific (longest) matching prefix wins, so a nested route like | |
| # "/catalog/products" is preferred over "/catalog" regardless of | |
| # registration order. | |
| matches = [(pp, resp) for m, pp, resp in self.routes if m == method and pp in url] | |
| if matches: | |
| _, responder = max(matches, key=lambda pair: len(pair[0])) | |
| return responder(call) | |
| if self.fallback is not None: | |
| return self.fallback(call) | |
| raise AssertionError(f"MockBackend: no route for {method} {url}") | |
| return httpx.MockTransport(handler) | |
| def last_call(self) -> RecordedCall: | |
| return self.calls[-1] | |
| def make_client(backend: MockBackend, base_url: str = "http://localhost:2785", api_key: str = "owa_k1_test"): | |
| from openwa import OpenWAClient | |
| return OpenWAClient(base_url=base_url, api_key=api_key, transport=backend.as_transport()) | |