Files
ThothII/harness/tests/test_rest_client.py
marcopanandClaude Opus 4.6 1e4bc11418 fix(embed): fast-fail + auto-restart Ollama on solved-search hang
Embeddings timeout was 120s, causing multi-minute hangs when Ollama was
down during F4/F6/F7 solved-search. Now: connect_timeout=5s across all
HTTP clients (REST + Ollama), read_timeout reduced to 30s for embeddings,
and OllamaEmbeddings auto-restarts the server on ConnectionError before
degrading gracefully.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-07-07 19:49:55 +02:00

116 lines
4.0 KiB
Python

"""L1: rest/client RPC contract (mocked transport — no network).
Verifies the ported RestClient: each rpc carries the X-API-Key header, the right
payload, base_url slash handling, and HTTP/network errors surface as RestError.
Ported (renamed psdwp3->tht) from ChironeWp3/tests/test_rest_client.py.
"""
import pytest
import requests
from tht.config import RestConfig
from tht.rest.client import RestClient, RestError
class FakeResponse:
def __init__(self, payload=None, status=200, text=None):
self._payload = payload
self.status_code = status
self.text = text if text is not None else ("" if payload is None else "json")
@property
def ok(self):
return self.status_code < 400
def json(self):
if self._payload is None:
raise ValueError("no json")
return self._payload
def _client(timeout=30):
return RestClient(RestConfig(base_url="https://h/dwh/", api_key="dwh_k", timeout=timeout))
def _capture(monkeypatch, response):
calls = []
def fake_post(url, json=None, headers=None, timeout=None, verify=None):
calls.append({"url": url, "json": json, "headers": headers,
"timeout": timeout, "verify": verify})
return response
monkeypatch.setattr("tht.rest.client.requests.post", fake_post)
return calls
def test_run_query_payload_and_rows(monkeypatch):
calls = _capture(monkeypatch, FakeResponse([{"x": 1}]))
rows = _client().run_query("SELECT 1 AS x")
assert rows == [{"x": 1}]
c = calls[0]
assert c["url"] == "https://h/dwh/rpc/run_query"
assert c["json"] == {"query_text": "SELECT 1 AS x"}
assert c["headers"]["X-API-Key"] == "dwh_k"
assert c["timeout"] == (5, 30)
def test_explain_query_maps_lines(monkeypatch):
plan = [
{"line": "Aggregate (cost=3747.24..3747.25 rows=1 width=8)"},
{"line": " -> Seq Scan on dim_patient (cost=0.00..3712.97 rows=13706 width=0)"},
]
_capture(monkeypatch, FakeResponse(plan))
lines = _client().explain_query("SELECT count(*) FROM dim_patient")
assert lines == [
"Aggregate (cost=3747.24..3747.25 rows=1 width=8)",
" -> Seq Scan on dim_patient (cost=0.00..3712.97 rows=13706 width=0)",
]
def test_ping(monkeypatch):
calls = _capture(monkeypatch, FakeResponse({"db_connected": True, "role": "postgres"}))
out = _client().ping()
assert out["db_connected"] is True
assert calls[0]["url"] == "https://h/dwh/rpc/ping"
assert calls[0]["json"] == {}
def test_top_values_payload(monkeypatch):
calls = _capture(monkeypatch, FakeResponse([{"value": "MI", "count": 13737}]))
out = _client().top_values("datawarehouse", "dim_patient", "provincia", 1000)
assert out == [{"value": "MI", "count": 13737}]
assert calls[0]["json"] == {
"schema_name": "datawarehouse",
"table_name": "dim_patient",
"column_name": "provincia",
"max_values": 1000,
}
def test_validate_select_ok_and_write(monkeypatch):
_capture(monkeypatch, FakeResponse(status=204))
assert _client().validate_select("SELECT 1") is True
_capture(monkeypatch, FakeResponse({"message": "Only SELECT / WITH statements are allowed"}, status=400))
assert _client().validate_select("DELETE FROM t") is False
def test_http_error_surfaces_message(monkeypatch):
_capture(monkeypatch, FakeResponse({"message": "boom"}, status=400))
with pytest.raises(RestError, match="boom"):
_client().run_query("SELECT bad")
def test_network_error_actionable(monkeypatch):
def boom(*a, **k):
raise requests.ConnectionError("refused")
monkeypatch.setattr("tht.rest.client.requests.post", boom)
with pytest.raises(RestError, match="raggiungibile"):
_client().ping()
def test_base_url_without_trailing_slash(monkeypatch):
calls = _capture(monkeypatch, FakeResponse({"db_connected": True}))
RestClient(RestConfig(base_url="https://h/dwh", api_key="k")).ping()
assert calls[0]["url"] == "https://h/dwh/rpc/ping"