129 lines
4.2 KiB
Python
129 lines
4.2 KiB
Python
|
|
"""Unit tests for decision API routes."""
|
||
|
|
import pytest
|
||
|
|
from httpx import ASGITransport, AsyncClient
|
||
|
|
from sqlalchemy import Engine
|
||
|
|
from sqlmodel import SQLModel, Session, create_engine
|
||
|
|
|
||
|
|
from models.user import User
|
||
|
|
from models.decision import ListingDecision # noqa: F401 - needed for table creation
|
||
|
|
from api.auth import get_current_user, User as AuthUser
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.fixture
|
||
|
|
def decision_engine() -> Engine:
|
||
|
|
engine = create_engine(
|
||
|
|
"sqlite:///:memory:",
|
||
|
|
echo=False,
|
||
|
|
connect_args={"check_same_thread": False},
|
||
|
|
)
|
||
|
|
SQLModel.metadata.create_all(engine)
|
||
|
|
with Session(engine) as session:
|
||
|
|
session.add(User(id=1, email="test@example.com"))
|
||
|
|
session.commit()
|
||
|
|
yield engine # type: ignore[misc]
|
||
|
|
SQLModel.metadata.drop_all(engine)
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.fixture
|
||
|
|
async def client(decision_engine: Engine) -> AsyncClient:
|
||
|
|
import database
|
||
|
|
import api.app as api_app
|
||
|
|
import api.decision_routes as decision_routes_mod
|
||
|
|
import api.poi_routes as poi_routes_mod
|
||
|
|
|
||
|
|
app = api_app.app
|
||
|
|
mock_user = AuthUser(
|
||
|
|
sub="test-user-id", email="test@example.com", name="Test User"
|
||
|
|
)
|
||
|
|
app.dependency_overrides[get_current_user] = lambda: mock_user
|
||
|
|
|
||
|
|
original_db = database.engine
|
||
|
|
original_app = api_app.engine
|
||
|
|
original_decision = decision_routes_mod.engine
|
||
|
|
original_poi = poi_routes_mod.engine
|
||
|
|
database.engine = decision_engine
|
||
|
|
api_app.engine = decision_engine
|
||
|
|
decision_routes_mod.engine = decision_engine
|
||
|
|
poi_routes_mod.engine = decision_engine
|
||
|
|
|
||
|
|
transport = ASGITransport(app=app)
|
||
|
|
async with AsyncClient(transport=transport, base_url="http://test") as c:
|
||
|
|
yield c # type: ignore[misc]
|
||
|
|
|
||
|
|
database.engine = original_db
|
||
|
|
api_app.engine = original_app
|
||
|
|
decision_routes_mod.engine = original_decision
|
||
|
|
poi_routes_mod.engine = original_poi
|
||
|
|
app.dependency_overrides.clear()
|
||
|
|
|
||
|
|
|
||
|
|
class TestDecisionRoutes:
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_set_decision(self, client: AsyncClient) -> None:
|
||
|
|
resp = await client.put(
|
||
|
|
"/api/decisions/100",
|
||
|
|
json={"decision": "liked", "listing_type": "RENT"},
|
||
|
|
)
|
||
|
|
assert resp.status_code == 200
|
||
|
|
data = resp.json()
|
||
|
|
assert data["decision"] == "liked"
|
||
|
|
assert data["listing_id"] == 100
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_get_decisions(self, client: AsyncClient) -> None:
|
||
|
|
await client.put(
|
||
|
|
"/api/decisions/100",
|
||
|
|
json={"decision": "liked", "listing_type": "RENT"},
|
||
|
|
)
|
||
|
|
resp = await client.get("/api/decisions")
|
||
|
|
assert resp.status_code == 200
|
||
|
|
data = resp.json()
|
||
|
|
assert len(data) == 1
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_delete_decision(self, client: AsyncClient) -> None:
|
||
|
|
await client.put(
|
||
|
|
"/api/decisions/100",
|
||
|
|
json={"decision": "liked", "listing_type": "RENT"},
|
||
|
|
)
|
||
|
|
resp = await client.delete(
|
||
|
|
"/api/decisions/100", params={"listing_type": "RENT"}
|
||
|
|
)
|
||
|
|
assert resp.status_code == 200
|
||
|
|
assert resp.json()["success"] is True
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_delete_nonexistent_returns_404(
|
||
|
|
self, client: AsyncClient
|
||
|
|
) -> None:
|
||
|
|
resp = await client.delete(
|
||
|
|
"/api/decisions/999", params={"listing_type": "RENT"}
|
||
|
|
)
|
||
|
|
assert resp.status_code == 404
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_invalid_decision_returns_400(
|
||
|
|
self, client: AsyncClient
|
||
|
|
) -> None:
|
||
|
|
resp = await client.put(
|
||
|
|
"/api/decisions/100",
|
||
|
|
json={"decision": "maybe", "listing_type": "RENT"},
|
||
|
|
)
|
||
|
|
assert resp.status_code == 400
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_update_decision(self, client: AsyncClient) -> None:
|
||
|
|
await client.put(
|
||
|
|
"/api/decisions/100",
|
||
|
|
json={"decision": "liked", "listing_type": "RENT"},
|
||
|
|
)
|
||
|
|
resp = await client.put(
|
||
|
|
"/api/decisions/100",
|
||
|
|
json={"decision": "disliked", "listing_type": "RENT"},
|
||
|
|
)
|
||
|
|
assert resp.status_code == 200
|
||
|
|
assert resp.json()["decision"] == "disliked"
|
||
|
|
# Still only one decision
|
||
|
|
resp2 = await client.get("/api/decisions")
|
||
|
|
assert len(resp2.json()) == 1
|