test(tradein): assert config kwarg on cian price-history fetch_detail call (#2306)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 7s
CI / changes (pull_request) Successful in 8s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 1m40s

code-reviewer flagged that neither the new parity test nor
test_backfill_wave2.py's 3 cian_price_history tests would catch a
regression if config=RealScraperConfig() were accidentally dropped from
the fetch_detail call in cian_price_history.py (the proxy-footgun fix
from the #2306 migration) — mock_fetch.assert_called_once() doesn't
check kwargs.

Strengthens all 3 tests (saves_changes / skips_no_changes /
handles_fetch_none) to assert isinstance(call_kwargs["config"],
RealScraperConfig). Manually verified the guard actually catches the
regression: temporarily removed config= from cian_price_history.py:110,
confirmed all 3 tests fail, restored the fix, confirmed they pass again.
This commit is contained in:
bot-backend 2026-07-04 00:27:08 +03:00
parent db3afa3176
commit 88b93435fc

View file

@ -235,6 +235,7 @@ async def test_backfill_yandex_addresses_error_on_non_200():
async def test_cian_price_history_saves_changes():
"""Happy path: fetch returns DetailEnrichment with price_changes → saved."""
from app.services.cian_price_history import backfill_cian_price_history
from app.services.scraper_adapters import RealScraperConfig
from app.services.scrapers.cian_detail import DetailEnrichment
enrichment = DetailEnrichment(
@ -277,6 +278,12 @@ async def test_cian_price_history_saves_changes():
assert result.saved == 2 # 2 price_changes
assert result.errors == 0
mock_fetch.assert_called_once()
# #2306 regression guard: kit fetch_detail silently drops the Cian proxy
# (direct connection, #806 ban risk) unless config=RealScraperConfig() is
# passed at the call site — assert_called_once() alone wouldn't catch someone
# dropping that kwarg later.
_, call_kwargs = mock_fetch.call_args
assert isinstance(call_kwargs.get("config"), RealScraperConfig)
mock_save.assert_called_once()
@ -284,6 +291,7 @@ async def test_cian_price_history_saves_changes():
async def test_cian_price_history_skips_no_changes():
"""Fetch succeeds but no price_changes → skipped (not error)."""
from app.services.cian_price_history import backfill_cian_price_history
from app.services.scraper_adapters import RealScraperConfig
from app.services.scrapers.cian_detail import DetailEnrichment
enrichment = DetailEnrichment(cian_id=111, price_changes=[])
@ -296,7 +304,7 @@ async def test_cian_price_history_skips_no_changes():
"app.services.cian_price_history.fetch_detail",
new_callable=AsyncMock,
return_value=enrichment,
),
) as mock_fetch,
patch("app.services.cian_price_history.save_detail_enrichment") as mock_save,
patch("app.services.cian_price_history.get_scraper_delay", return_value=0.0),
):
@ -309,12 +317,16 @@ async def test_cian_price_history_skips_no_changes():
assert result.skipped == 1
assert result.saved == 0
mock_save.assert_not_called()
# #2306 regression guard — see test_cian_price_history_saves_changes.
_, call_kwargs = mock_fetch.call_args
assert isinstance(call_kwargs.get("config"), RealScraperConfig)
@pytest.mark.asyncio
async def test_cian_price_history_handles_fetch_none():
"""fetch_detail returns None → errors+1, no crash."""
from app.services.cian_price_history import backfill_cian_price_history
from app.services.scraper_adapters import RealScraperConfig
mock_db = MagicMock()
rows = [{"id": 30, "source_url": "https://ekb.cian.ru/sale/flat/999/"}]
@ -324,7 +336,7 @@ async def test_cian_price_history_handles_fetch_none():
"app.services.cian_price_history.fetch_detail",
new_callable=AsyncMock,
return_value=None,
),
) as mock_fetch,
patch("app.services.cian_price_history.get_scraper_delay", return_value=0.0),
):
mock_mappings = MagicMock()
@ -335,6 +347,9 @@ async def test_cian_price_history_handles_fetch_none():
assert result.errors == 1
assert result.saved == 0
# #2306 regression guard — see test_cian_price_history_saves_changes.
_, call_kwargs = mock_fetch.call_args
assert isinstance(call_kwargs.get("config"), RealScraperConfig)
# ============================================================================