fix(sf): verify=False для екатеринбург.рф (CA Минцифры) + синтетический CI-тест КРТ-парсера (ревью #1126)
All checks were successful
CI / changes (push) Successful in 6s
CI / changes (pull_request) Successful in 5s
CI / backend-tests (pull_request) Successful in 6m24s
CI / backend-tests (push) Successful in 6m22s

This commit is contained in:
bot-backend 2026-06-07 14:22:26 +03:00
parent d966b968fd
commit c087bd74b1
2 changed files with 64 additions and 1 deletions

View file

@ -70,7 +70,12 @@ def fetch_krt_page() -> str:
Сеть отделена от парсинга для testability.
Raises: httpx.HTTPError при недоступности сервера.
"""
with httpx.Client(headers=_HEADERS, timeout=30, follow_redirects=True) as client:
with httpx.Client(
headers=_HEADERS,
timeout=30,
follow_redirects=True,
verify=False, # CA Минцифры РФ — нет в certifi. Аналог ekburg_permits.py #242.
) as client:
resp = client.get(KRT_URL)
resp.raise_for_status()
logger.info(

View file

@ -139,6 +139,64 @@ class TestEmptyAndGarbage:
assert parse_krt_page(html) == []
# ── Синтетический блок: площадка без застройщика / договора / цен ─────────────
# Имитирует площадки «в работе» (только geography + технические параметры).
# Не требует локального дампа — всегда исполняется в CI.
_BABUSHKINA_BLOCK = textwrap.dedent(
"""\
<h2><strong>2024 год</strong></h2>
<p>&nbsp;<strong>1. КРТ жилой застройки в районе ул. Бабушкина:</strong></p>
<p>Площадь территории: 5,10 га;<br />\
Градостроительный потенциал: 120 000 кв. м;<br />\
Всего многоквартирных домов: 18;<br />\
3. Издано Постановление Администрации города Екатеринбурга от 15.01.2024 42 \
&laquo;О комплексном развитии территории&raquo;.</p>
<p><strong>Стадия реализации: проектирование</strong></p>
"""
)
class TestParseBabushkinaBlock:
"""Синтетический тест: площадка без застройщика, договора и цен аукциона.
Не зависит от локального дампа всегда запускается в CI.
"""
@pytest.fixture(scope="class")
def site(self):
sites = parse_krt_page(_BABUSHKINA_BLOCK)
assert sites, "parse_krt_page вернул пустой список для синтетического блока"
return sites[0]
def test_parses_exactly_one_site(self):
"""Синтетический блок содержит ровно одну площадку."""
assert len(parse_krt_page(_BABUSHKINA_BLOCK)) == 1
def test_developer_is_none(self, site):
"""Застройщик не указан → None."""
assert site.developer_name is None
def test_contract_number_is_none(self, site):
"""Договор не заключён → None."""
assert site.contract_number is None
def test_area_ha_filled(self, site):
"""Площадь территории заполнена."""
assert site.area_ha == pytest.approx(5.10, rel=1e-3)
def test_gradpotential_filled(self, site):
"""Градостроительный потенциал заполнен."""
assert site.gradpotential_sqm == pytest.approx(120000.0, rel=1e-3)
def test_district_filled(self, site):
"""Район извлечён из названия блока."""
assert site.district is not None
assert "Бабушкина" in site.district
def test_krt_kind(self, site):
assert site.krt_kind == "жилой застройки"
class TestMultiSiteCountFromDump:
"""Проверка количества площадок из реального дампа страницы."""