from __future__ import annotations from collections.abc import Iterator from contextlib import contextmanager from uuid import uuid4 import pytest from ragcore_sdk import RAGCoreAPIError, RAGCoreClient from conftest import build_search_app, run_app @contextmanager def _client(app: object, *, token: str = "sdk-test-token") -> Iterator[RAGCoreClient]: # noqa: S107 with run_app(app) as base_url, RAGCoreClient(base_url=base_url, token=token) as client: # type: ignore[arg-type] yield client def test_search_returns_typed_results() -> None: fixture = build_search_app() with _client(fixture.app) as client: response = client.search(query="refund", requested_space_ids=[fixture.space_id]) assert response.effective_space_ids == [fixture.space_id] assert response.results[0].citation.excerpt_sha256 assert response.results[0].rank == 1 assert response.degraded is False def test_search_out_of_scope_space_narrows_silently_to_empty() -> None: fixture = build_search_app() forbidden_space = uuid4() with _client(fixture.app) as client: response = client.search(query="refund", requested_space_ids=[forbidden_space]) assert response.effective_space_ids == [] assert response.results == [] def test_search_validation_error_raises_typed_problem() -> None: fixture = build_search_app() with _client(fixture.app) as client, pytest.raises(RAGCoreAPIError) as excinfo: client.search(query=" ") problem = excinfo.value.problem assert problem.status == 422 assert problem.code == "VALIDATION_ERROR" assert problem.trace_id assert problem.errors def test_bearer_token_never_appears_in_client_repr_or_error_message() -> None: fixture = build_search_app() secret_token = "super-secret-bearer-value-should-never-leak" with _client(fixture.app, token=secret_token) as client: assert secret_token not in repr(client) with pytest.raises(RAGCoreAPIError) as excinfo: client.search(query=" ") assert secret_token not in str(excinfo.value) problem = excinfo.value.problem for field in problem.__slots__: assert secret_token not in repr(getattr(problem, field))