gendesign/tradein-mvp/backend/tests/test_house_imv_backfill_browser_flag.py
bot-backend e03c810306
All checks were successful
Deploy Trade-In / changes (push) Successful in 9s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Successful in 27s
Deploy Trade-In / test (push) Successful in 1m23s
Deploy Trade-In / build-backend (push) Successful in 51s
Deploy Trade-In / deploy (push) Successful in 46s
feat(tradein-imv): route IMV backfill через BrowserFetcher.fetch_json за dormant-флагом (#915 Stage 3) (#1916)
2026-06-26 09:54:28 +00:00

98 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""test_house_imv_backfill_browser_flag.py — #915 Stage 3.
Проверяет проводку флага avito_imv_use_browser_fetcher в backfill_house_imv:
- флаг ON → конструируется один BrowserFetcher(source="avito") на весь батч,
и он прокидывается в _process_one_house(browser_fetcher=...).
- флаг OFF → BrowserFetcher НЕ конструируется, browser_fetcher=None (старый путь).
DB и _process_one_house мокаются — реальный камуфокс/curl/Postgres не нужны.
"""
from __future__ import annotations
import os
from typing import Any, ClassVar
from unittest.mock import MagicMock
import pytest
# settings нужен DSN на импорте (как в соседних тестах) — fake-db, статический.
os.environ.setdefault("DATABASE_URL", "postgresql+psycopg://test:test@localhost:5432/test")
from app.services import house_imv_backfill
class _FakeBrowserFetcher:
"""Поддельный async-CM: считает конструкции/входы, возвращает себя из __aenter__."""
instances: ClassVar[list[_FakeBrowserFetcher]] = []
def __init__(self, source: str = "avito", **_: Any) -> None:
self.source = source
self.entered = False
_FakeBrowserFetcher.instances.append(self)
async def __aenter__(self) -> _FakeBrowserFetcher:
self.entered = True
return self
async def __aexit__(self, *_: object) -> None:
return None
def _fake_db_with_one_row() -> MagicMock:
"""MagicMock-Session, чей execute(...).mappings().all() отдаёт один дом."""
db = MagicMock()
row = {"id": 42, "address": "ЕКБ, ул. X, 1", "full_address": None, "lat": 56.8, "lon": 60.6}
db.execute.return_value.mappings.return_value.all.return_value = [row]
return db
async def test_backfill_flag_on_constructs_browser_and_threads_it(
monkeypatch: pytest.MonkeyPatch,
) -> None:
_FakeBrowserFetcher.instances.clear()
monkeypatch.setattr(house_imv_backfill.settings, "avito_imv_use_browser_fetcher", True)
monkeypatch.setattr(house_imv_backfill, "BrowserFetcher", _FakeBrowserFetcher)
captured: dict[str, Any] = {}
async def _fake_process(db: Any, house: dict, *, browser_fetcher: Any = None) -> str:
captured["browser_fetcher"] = browser_fetcher
return "ok"
monkeypatch.setattr(house_imv_backfill, "_process_one_house", _fake_process)
db = _fake_db_with_one_row()
await house_imv_backfill.backfill_house_imv(db, batch_size=10)
# Ровно один BrowserFetcher(source="avito"), вошли в контекст.
assert len(_FakeBrowserFetcher.instances) == 1
bf = _FakeBrowserFetcher.instances[0]
assert bf.source == "avito"
assert bf.entered is True
# И он прокинут в _process_one_house.
assert captured["browser_fetcher"] is bf
async def test_backfill_flag_off_no_browser_and_none_threaded(
monkeypatch: pytest.MonkeyPatch,
) -> None:
_FakeBrowserFetcher.instances.clear()
monkeypatch.setattr(house_imv_backfill.settings, "avito_imv_use_browser_fetcher", False)
monkeypatch.setattr(house_imv_backfill, "BrowserFetcher", _FakeBrowserFetcher)
captured: dict[str, Any] = {}
async def _fake_process(db: Any, house: dict, *, browser_fetcher: Any = None) -> str:
captured["browser_fetcher"] = browser_fetcher
return "ok"
monkeypatch.setattr(house_imv_backfill, "_process_one_house", _fake_process)
db = _fake_db_with_one_row()
await house_imv_backfill.backfill_house_imv(db, batch_size=10)
# Флаг OFF → BrowserFetcher не конструируется, browser_fetcher=None.
assert _FakeBrowserFetcher.instances == []
assert captured["browser_fetcher"] is None