fix: ruff lint + format fixes in tests, ESLint fixes in frontend
This commit is contained in:
@@ -5,12 +5,10 @@ from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
from httpx import ASGITransport, AsyncClient
|
||||
from httpx import AsyncClient
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.database import Base, get_db
|
||||
from app.main import app
|
||||
from app.models.retouch import RetouchResult, RetouchStatus
|
||||
from app.models.retouch import RetouchStatus
|
||||
from app.models.vehicle import Vehicle
|
||||
from app.services import retouch_service, price_compare_service
|
||||
|
||||
@@ -83,7 +81,9 @@ class TestRetouchService:
|
||||
assert "red" in prompt
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_upload_retouch_file_success(self, db_session: AsyncSession, tmp_path):
|
||||
async def test_upload_retouch_file_success(
|
||||
self, db_session: AsyncSession, tmp_path
|
||||
):
|
||||
with patch.object(retouch_service.settings, "UPLOAD_DIR", str(tmp_path)):
|
||||
result = await retouch_service.upload_retouch_file(
|
||||
db=db_session,
|
||||
@@ -132,12 +132,16 @@ class TestRetouchService:
|
||||
async def test_list_results_with_data(self, db_session: AsyncSession, tmp_path):
|
||||
with patch.object(retouch_service.settings, "UPLOAD_DIR", str(tmp_path)):
|
||||
await retouch_service.upload_retouch_file(
|
||||
db=db_session, file_bytes=_fake_image(),
|
||||
file_name="img1.png", mime_type="image/png",
|
||||
db=db_session,
|
||||
file_bytes=_fake_image(),
|
||||
file_name="img1.png",
|
||||
mime_type="image/png",
|
||||
)
|
||||
await retouch_service.upload_retouch_file(
|
||||
db=db_session, file_bytes=_fake_image(),
|
||||
file_name="img2.png", mime_type="image/png",
|
||||
db=db_session,
|
||||
file_bytes=_fake_image(),
|
||||
file_name="img2.png",
|
||||
mime_type="image/png",
|
||||
)
|
||||
await db_session.commit()
|
||||
items, total = await retouch_service.list_results(db_session)
|
||||
@@ -150,13 +154,17 @@ class TestRetouchService:
|
||||
):
|
||||
with patch.object(retouch_service.settings, "UPLOAD_DIR", str(tmp_path)):
|
||||
await retouch_service.upload_retouch_file(
|
||||
db=db_session, file_bytes=_fake_image(),
|
||||
file_name="img1.png", mime_type="image/png",
|
||||
db=db_session,
|
||||
file_bytes=_fake_image(),
|
||||
file_name="img1.png",
|
||||
mime_type="image/png",
|
||||
vehicle_id=test_vehicle.id,
|
||||
)
|
||||
await retouch_service.upload_retouch_file(
|
||||
db=db_session, file_bytes=_fake_image(),
|
||||
file_name="img2.png", mime_type="image/png",
|
||||
db=db_session,
|
||||
file_bytes=_fake_image(),
|
||||
file_name="img2.png",
|
||||
mime_type="image/png",
|
||||
)
|
||||
await db_session.commit()
|
||||
items, total = await retouch_service.list_results(
|
||||
@@ -171,20 +179,22 @@ class TestRetouchService:
|
||||
"""Test process_retouch with mocked Flux.1-Pro call."""
|
||||
with patch.object(retouch_service.settings, "UPLOAD_DIR", str(tmp_path)):
|
||||
result = await retouch_service.upload_retouch_file(
|
||||
db=db_session, file_bytes=_fake_image(),
|
||||
file_name="truck.png", mime_type="image/png",
|
||||
db=db_session,
|
||||
file_bytes=_fake_image(),
|
||||
file_name="truck.png",
|
||||
mime_type="image/png",
|
||||
)
|
||||
await db_session.commit()
|
||||
|
||||
# Mock the _call_flux_pro function to return fake retouched bytes
|
||||
retouched_bytes = b"\x89PNG\r\n\x1a\n" + b"\xFF" * 1016
|
||||
retouched_bytes = b"\x89PNG\r\n\x1a\n" + b"\xff" * 1016
|
||||
with patch.object(
|
||||
retouch_service, "_call_flux_pro",
|
||||
new_callable=AsyncMock, return_value=retouched_bytes,
|
||||
retouch_service,
|
||||
"_call_flux_pro",
|
||||
new_callable=AsyncMock,
|
||||
return_value=retouched_bytes,
|
||||
):
|
||||
processed = await retouch_service.process_retouch(
|
||||
db_session, result.id
|
||||
)
|
||||
processed = await retouch_service.process_retouch(db_session, result.id)
|
||||
await db_session.commit()
|
||||
|
||||
assert processed.status == RetouchStatus.completed.value
|
||||
@@ -197,19 +207,20 @@ class TestRetouchService:
|
||||
"""Test process_retouch sets failed status on OpenRouter error."""
|
||||
with patch.object(retouch_service.settings, "UPLOAD_DIR", str(tmp_path)):
|
||||
result = await retouch_service.upload_retouch_file(
|
||||
db=db_session, file_bytes=_fake_image(),
|
||||
file_name="truck.png", mime_type="image/png",
|
||||
db=db_session,
|
||||
file_bytes=_fake_image(),
|
||||
file_name="truck.png",
|
||||
mime_type="image/png",
|
||||
)
|
||||
await db_session.commit()
|
||||
|
||||
with patch.object(
|
||||
retouch_service, "_call_flux_pro",
|
||||
retouch_service,
|
||||
"_call_flux_pro",
|
||||
new_callable=AsyncMock,
|
||||
side_effect=Exception("OpenRouter unavailable"),
|
||||
):
|
||||
processed = await retouch_service.process_retouch(
|
||||
db_session, result.id
|
||||
)
|
||||
processed = await retouch_service.process_retouch(db_session, result.id)
|
||||
await db_session.commit()
|
||||
|
||||
assert processed.status == RetouchStatus.failed.value
|
||||
@@ -227,7 +238,9 @@ class TestRetouchService:
|
||||
async def test_call_flux_pro_no_api_key(self):
|
||||
"""Test _call_flux_pro raises ValueError when no API key configured."""
|
||||
with patch.object(retouch_service.settings, "OPENROUTER_API_KEY", ""):
|
||||
with pytest.raises(ValueError, match="OPENROUTER_API_KEY is not configured"):
|
||||
with pytest.raises(
|
||||
ValueError, match="OPENROUTER_API_KEY is not configured"
|
||||
):
|
||||
await retouch_service._call_flux_pro(
|
||||
image_bytes=b"fake-image",
|
||||
mime_type="image/png",
|
||||
@@ -235,9 +248,12 @@ class TestRetouchService:
|
||||
)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_call_flux_pro_success_data_uri(self, db_session: AsyncSession, tmp_path):
|
||||
async def test_call_flux_pro_success_data_uri(
|
||||
self, db_session: AsyncSession, tmp_path
|
||||
):
|
||||
"""Test _call_flux_pro with mocked httpx returning base64 data URI."""
|
||||
import base64 as b64mod
|
||||
|
||||
retouched = b"\x89PNG\r\n\x1a\nretouched-data"
|
||||
b64_retouched = b64mod.b64encode(retouched).decode("utf-8")
|
||||
|
||||
@@ -245,11 +261,7 @@ class TestRetouchService:
|
||||
mock_response.raise_for_status = MagicMock()
|
||||
mock_response.json.return_value = {
|
||||
"choices": [
|
||||
{
|
||||
"message": {
|
||||
"content": f"data:image/png;base64,{b64_retouched}"
|
||||
}
|
||||
}
|
||||
{"message": {"content": f"data:image/png;base64,{b64_retouched}"}}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -259,7 +271,10 @@ class TestRetouchService:
|
||||
mock_client.__aexit__ = AsyncMock(return_value=None)
|
||||
|
||||
with patch.object(retouch_service.settings, "OPENROUTER_API_KEY", "test-key"):
|
||||
with patch("app.services.retouch_service.httpx.AsyncClient", return_value=mock_client):
|
||||
with patch(
|
||||
"app.services.retouch_service.httpx.AsyncClient",
|
||||
return_value=mock_client,
|
||||
):
|
||||
result = await retouch_service._call_flux_pro(
|
||||
image_bytes=b"fake-image",
|
||||
mime_type="image/png",
|
||||
@@ -268,9 +283,12 @@ class TestRetouchService:
|
||||
assert result == retouched
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_call_flux_pro_success_list_content(self, db_session: AsyncSession, tmp_path):
|
||||
async def test_call_flux_pro_success_list_content(
|
||||
self, db_session: AsyncSession, tmp_path
|
||||
):
|
||||
"""Test _call_flux_pro with content as list of parts."""
|
||||
import base64 as b64mod
|
||||
|
||||
retouched = b"\x89PNG\r\n\x1a\nlist-content"
|
||||
b64_retouched = b64mod.b64encode(retouched).decode("utf-8")
|
||||
|
||||
@@ -282,7 +300,12 @@ class TestRetouchService:
|
||||
"message": {
|
||||
"content": [
|
||||
{"type": "text", "text": "Here is the image"},
|
||||
{"type": "image_url", "image_url": {"url": f"data:image/png;base64,{b64_retouched}"}},
|
||||
{
|
||||
"type": "image_url",
|
||||
"image_url": {
|
||||
"url": f"data:image/png;base64,{b64_retouched}"
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -295,7 +318,10 @@ class TestRetouchService:
|
||||
mock_client.__aexit__ = AsyncMock(return_value=None)
|
||||
|
||||
with patch.object(retouch_service.settings, "OPENROUTER_API_KEY", "test-key"):
|
||||
with patch("app.services.retouch_service.httpx.AsyncClient", return_value=mock_client):
|
||||
with patch(
|
||||
"app.services.retouch_service.httpx.AsyncClient",
|
||||
return_value=mock_client,
|
||||
):
|
||||
result = await retouch_service._call_flux_pro(
|
||||
image_bytes=b"fake-image",
|
||||
mime_type="image/png",
|
||||
@@ -309,13 +335,7 @@ class TestRetouchService:
|
||||
mock_response = MagicMock()
|
||||
mock_response.raise_for_status = MagicMock()
|
||||
mock_response.json.return_value = {
|
||||
"choices": [
|
||||
{
|
||||
"message": {
|
||||
"content": "Sorry, I cannot process this image."
|
||||
}
|
||||
}
|
||||
]
|
||||
"choices": [{"message": {"content": "Sorry, I cannot process this image."}}]
|
||||
}
|
||||
|
||||
mock_client = AsyncMock()
|
||||
@@ -325,7 +345,10 @@ class TestRetouchService:
|
||||
|
||||
original = b"original-image-bytes"
|
||||
with patch.object(retouch_service.settings, "OPENROUTER_API_KEY", "test-key"):
|
||||
with patch("app.services.retouch_service.httpx.AsyncClient", return_value=mock_client):
|
||||
with patch(
|
||||
"app.services.retouch_service.httpx.AsyncClient",
|
||||
return_value=mock_client,
|
||||
):
|
||||
result = await retouch_service._call_flux_pro(
|
||||
image_bytes=original,
|
||||
mime_type="image/png",
|
||||
@@ -341,9 +364,7 @@ class TestPriceCompareService:
|
||||
async def test_compare_prices_success(
|
||||
self, db_session: AsyncSession, test_vehicle: Vehicle
|
||||
):
|
||||
result = await price_compare_service.compare_prices(
|
||||
db_session, test_vehicle.id
|
||||
)
|
||||
result = await price_compare_service.compare_prices(db_session, test_vehicle.id)
|
||||
assert result.vehicle_id == test_vehicle.id
|
||||
assert len(result.comparable_listings) > 0
|
||||
assert result.average_price is not None
|
||||
@@ -355,17 +376,13 @@ class TestPriceCompareService:
|
||||
@pytest.mark.asyncio
|
||||
async def test_compare_prices_vehicle_not_found(self, db_session: AsyncSession):
|
||||
with pytest.raises(ValueError, match="not found"):
|
||||
await price_compare_service.compare_prices(
|
||||
db_session, uuid.uuid4()
|
||||
)
|
||||
await price_compare_service.compare_prices(db_session, uuid.uuid4())
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_compare_prices_listings_have_correct_make_model(
|
||||
self, db_session: AsyncSession, test_vehicle: Vehicle
|
||||
):
|
||||
result = await price_compare_service.compare_prices(
|
||||
db_session, test_vehicle.id
|
||||
)
|
||||
result = await price_compare_service.compare_prices(db_session, test_vehicle.id)
|
||||
for listing in result.comparable_listings:
|
||||
assert listing.make == test_vehicle.make
|
||||
assert listing.model == test_vehicle.model
|
||||
@@ -375,10 +392,10 @@ class TestPriceCompareService:
|
||||
async def test_compare_prices_average_calculation(
|
||||
self, db_session: AsyncSession, test_vehicle: Vehicle
|
||||
):
|
||||
result = await price_compare_service.compare_prices(
|
||||
db_session, test_vehicle.id
|
||||
)
|
||||
expected_avg = sum(l.price for l in result.comparable_listings) / len(result.comparable_listings)
|
||||
result = await price_compare_service.compare_prices(db_session, test_vehicle.id)
|
||||
expected_avg = sum(
|
||||
listing.price for listing in result.comparable_listings
|
||||
) / len(result.comparable_listings)
|
||||
assert abs(result.average_price - round(expected_avg, 2)) < 0.01
|
||||
|
||||
|
||||
@@ -447,8 +464,10 @@ class TestRetouchRouter:
|
||||
"""GET /retouch/results/:id returns 200 with completed status."""
|
||||
with patch.object(retouch_service.settings, "UPLOAD_DIR", str(tmp_path)):
|
||||
result = await retouch_service.upload_retouch_file(
|
||||
db=db_session, file_bytes=_fake_image(),
|
||||
file_name="truck.png", mime_type="image/png",
|
||||
db=db_session,
|
||||
file_bytes=_fake_image(),
|
||||
file_name="truck.png",
|
||||
mime_type="image/png",
|
||||
)
|
||||
result.status = RetouchStatus.completed.value
|
||||
result.retouched_file_path = str(tmp_path / "retouched.png")
|
||||
@@ -468,8 +487,10 @@ class TestRetouchRouter:
|
||||
"""GET /retouch/results/:id before completion returns 200 with processing status."""
|
||||
with patch.object(retouch_service.settings, "UPLOAD_DIR", str(tmp_path)):
|
||||
result = await retouch_service.upload_retouch_file(
|
||||
db=db_session, file_bytes=_fake_image(),
|
||||
file_name="truck.png", mime_type="image/png",
|
||||
db=db_session,
|
||||
file_bytes=_fake_image(),
|
||||
file_name="truck.png",
|
||||
mime_type="image/png",
|
||||
)
|
||||
result.status = RetouchStatus.processing.value
|
||||
await db_session.commit()
|
||||
@@ -487,8 +508,10 @@ class TestRetouchRouter:
|
||||
"""GET /retouch/results/:id with failed status returns 200 + error."""
|
||||
with patch.object(retouch_service.settings, "UPLOAD_DIR", str(tmp_path)):
|
||||
result = await retouch_service.upload_retouch_file(
|
||||
db=db_session, file_bytes=_fake_image(),
|
||||
file_name="truck.png", mime_type="image/png",
|
||||
db=db_session,
|
||||
file_bytes=_fake_image(),
|
||||
file_name="truck.png",
|
||||
mime_type="image/png",
|
||||
)
|
||||
result.status = RetouchStatus.failed.value
|
||||
result.error_message = "OpenRouter unavailable"
|
||||
|
||||
Reference in New Issue
Block a user