gendesign/backend/tests/workers/test_opportunity_harvest.py
bot-backend 34616042cf
All checks were successful
CI / changes (push) Successful in 6s
CI / changes (pull_request) Successful in 7s
CI / backend-tests (push) Successful in 5m49s
CI / backend-tests (pull_request) Successful in 5m47s
feat(sf): opportunity-ЗУ harvest → ird_overlays (future-supply, #1086)
2026-06-06 22:23:09 +03:00

118 lines
4.2 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.

"""Тесты harvest_opportunity_overlays (#1086) — НСПД opportunity-harvest → ird_overlays.
Сеть/БД не дёргаются: мокаем NSPDClient + SessionLocal, проверяем grid-walk по opportunity-слоям,
layer_kind='opportunity_*', skip пустого квартала, commit/close. Движок общий с ird_harvest.
"""
from __future__ import annotations
from contextlib import contextmanager
from typing import Any
from app.workers.tasks import opportunity_harvest
class _Feat:
def __init__(self, geometry: dict[str, Any] | None, properties: dict[str, Any]) -> None:
self.geometry = geometry
self.properties = properties
class _SearchRes:
def __init__(self, feat: _Feat | None) -> None:
self.first = feat
class _FakeClient:
"""NSPDClient-двойник: квартал → полигон (3857), grid-walk → 1 фича на слой."""
def __init__(self, *a: Any, **kw: Any) -> None:
self.grid_calls: list[int] = []
def search_by_cad(self, cad: str, thematic_id: int = 1) -> _SearchRes:
ring = [[0, 0], [100, 0], [100, 100], [0, 100], [0, 0]]
geom = {"type": "Polygon", "coordinates": [ring]}
return _SearchRes(_Feat(geom, {"cad": cad}))
def get_features_in_bbox_grid(self, layer_id: int, bbox: Any, **kw: Any) -> list[_Feat]:
self.grid_calls.append(layer_id)
return [
_Feat(
{"type": "Polygon", "coordinates": [[[1, 1], [2, 1], [2, 2], [1, 1]]]},
{
"geom_data_id": 2000 + layer_id,
"reg_numb_border": "66:41:0204016:10",
"category": 36940,
"subcategory": 5,
},
)
]
class _FakeDB:
"""Session-двойник: пишет execute-вызовы, begin_nested как no-op CM."""
def __init__(self) -> None:
self.executed: list[tuple[Any, dict[str, Any] | None]] = []
self.committed = False
self.closed = False
@contextmanager
def begin_nested(self) -> Any:
yield
def execute(self, sql: Any, params: dict[str, Any] | None = None) -> Any:
self.executed.append((sql, params))
return None
def commit(self) -> None:
self.committed = True
def close(self) -> None:
self.closed = True
def _patch(monkeypatch: Any, db: _FakeDB) -> _FakeClient:
client = _FakeClient()
monkeypatch.setattr(opportunity_harvest, "NSPDClient", lambda *a, **kw: client)
monkeypatch.setattr(opportunity_harvest, "SessionLocal", lambda: db)
return client
def test_harvest_explicit_quarters_all_opportunity_layers(monkeypatch: Any) -> None:
"""1 квартал × N opportunity-слоёв → upsert по фиче на слой; layer_kind='opportunity_*'."""
db = _FakeDB()
client = _patch(monkeypatch, db)
n_layers = len(opportunity_harvest.OPPORTUNITY_LAYER_KINDS)
result = opportunity_harvest.harvest_opportunity_overlays(quarters=["66:41:0204016"])
assert result == {"quarters": 1, "features": n_layers}
assert len(client.grid_calls) == n_layers
assert len(db.executed) == n_layers
assert db.committed is True
assert db.closed is True
kinds = {params["layer_kind"] for _, params in db.executed if params}
assert kinds == set(opportunity_harvest.OPPORTUNITY_LAYER_KINDS.values())
assert all(k.startswith("opportunity_") for k in kinds)
def test_harvest_skips_empty_quarter(monkeypatch: Any) -> None:
"""Квартал без геометрии в НСПД → 0 кварталов/фич, без падения."""
db = _FakeDB()
client = _patch(monkeypatch, db)
monkeypatch.setattr(client, "search_by_cad", lambda cad, thematic_id=1: _SearchRes(None))
result = opportunity_harvest.harvest_opportunity_overlays(quarters=["66:41:9999999"])
assert result == {"quarters": 0, "features": 0}
assert db.executed == []
assert db.committed is True
def test_krt_layer_registered() -> None:
"""ККР (37430) добавлен в LAYERS и в opportunity-набор (#1086)."""
from app.services.scrapers.nspd_client import LAYERS
assert LAYERS["krt_territories"] == 37430
assert "krt_territories" in opportunity_harvest.OPPORTUNITY_LAYER_KINDS