83 lines
2.7 KiB
Python
83 lines
2.7 KiB
Python
"""Integration tests for POST /api/search/build."""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
|
|
@pytest.fixture
|
|
def client(tmp_path):
|
|
"""TestClient with a fresh DB and mocked LLMRouter/category cache."""
|
|
import os
|
|
os.environ["SNIPE_DB"] = str(tmp_path / "snipe.db")
|
|
# Import app AFTER setting SNIPE_DB so the DB path is picked up
|
|
from api.main import app
|
|
return TestClient(app, raise_server_exceptions=False)
|
|
|
|
|
|
def _good_llm_response() -> str:
|
|
return json.dumps({
|
|
"base_query": "RTX 3080",
|
|
"must_include_mode": "groups",
|
|
"must_include": "rtx|geforce, 3080",
|
|
"must_exclude": "mining",
|
|
"max_price": 300.0,
|
|
"min_price": None,
|
|
"condition": ["used"],
|
|
"category_id": "27386",
|
|
"explanation": "Used RTX 3080 under $300.",
|
|
})
|
|
|
|
|
|
def test_build_endpoint_success(client):
|
|
with patch("api.main._get_query_translator") as mock_get_t:
|
|
mock_t = MagicMock()
|
|
from app.llm.query_translator import SearchParamsResponse
|
|
mock_t.translate.return_value = SearchParamsResponse(
|
|
base_query="RTX 3080",
|
|
must_include_mode="groups",
|
|
must_include="rtx|geforce, 3080",
|
|
must_exclude="mining",
|
|
max_price=300.0,
|
|
min_price=None,
|
|
condition=["used"],
|
|
category_id="27386",
|
|
explanation="Used RTX 3080 under $300.",
|
|
)
|
|
mock_get_t.return_value = mock_t
|
|
resp = client.post(
|
|
"/api/search/build",
|
|
json={"natural_language": "used RTX 3080 under $300 no mining"},
|
|
)
|
|
assert resp.status_code == 200
|
|
data = resp.json()
|
|
assert data["base_query"] == "RTX 3080"
|
|
assert data["explanation"] == "Used RTX 3080 under $300."
|
|
|
|
|
|
def test_build_endpoint_llm_unavailable(client):
|
|
with patch("api.main._get_query_translator") as mock_get_t:
|
|
mock_get_t.return_value = None # no translator configured
|
|
resp = client.post(
|
|
"/api/search/build",
|
|
json={"natural_language": "GPU"},
|
|
)
|
|
assert resp.status_code == 503
|
|
|
|
|
|
def test_build_endpoint_bad_json(client):
|
|
with patch("api.main._get_query_translator") as mock_get_t:
|
|
from app.llm.query_translator import QueryTranslatorError
|
|
mock_t = MagicMock()
|
|
mock_t.translate.side_effect = QueryTranslatorError("unparseable", raw="garbage output")
|
|
mock_get_t.return_value = mock_t
|
|
resp = client.post(
|
|
"/api/search/build",
|
|
json={"natural_language": "GPU"},
|
|
)
|
|
assert resp.status_code == 422
|
|
assert "raw" in resp.json()["detail"]
|