chore(#3051): снять новые тесты — до живой проверки функционала тесты не пишем
Some checks failed
CI Trade-In / changes (pull_request) Successful in 7s
CI / changes (pull_request) Failing after 9s
CI Trade-In / browser-tests (pull_request) Has been skipped
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 5m7s
Some checks failed
CI Trade-In / changes (pull_request) Successful in 7s
CI / changes (pull_request) Failing after 9s
CI Trade-In / browser-tests (pull_request) Has been skipped
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 5m7s
В существующем test_rosreestr_dedup_key оставлена только правка, без которой он падает после параметризации (литералы region_code=66 / doc_type='ДКП' ушли из SQL живого импорта). Новый тест-файл и добавленная функция сняты: поведение ещё не проверено на живом импорте, тест зафиксировал бы догадку.
This commit is contained in:
parent
cfe529fd14
commit
476fb9b77a
2 changed files with 1 additions and 167 deletions
|
|
@ -1,148 +0,0 @@
|
|||
"""#3051 п.3 + п.6: doc_type в deals и параметризация региона/типа документа на импорте.
|
||||
|
||||
ЗАЧЕМ: для Москвы в источнике за 2024 лежат 30 627 ДДУ с медианой 112 743 ₽/м² против
|
||||
107 005 ДКП с медианой 256 250 — это цены котлована. Тип сделки терялся при загрузке
|
||||
(в deals не приезжал вовсе), а фильтры `region_code = 66` и `doc_type = 'ДКП'` стояли
|
||||
литералами, поэтому регион 77 было не подключить, не правя код. Тесты фиксируют, что
|
||||
параметры реально доезжают до bind-словаря, дефолты воспроизводят прежнее поведение,
|
||||
а doc_type пишется в deals.
|
||||
|
||||
Чисто-юнит: ассертим SQL-текст import_rosreestr_dkp (inspect.getsource) + текст миграции
|
||||
288, плюс вызываем функцию с моком Session, чтобы увидеть фактические bind-параметры.
|
||||
Живой FDW / БД не нужны.
|
||||
"""
|
||||
|
||||
import inspect
|
||||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
# Как в test_rosreestr_dedup_key.py: Settings требует DATABASE_URL до импорта.
|
||||
os.environ.setdefault("DATABASE_URL", "postgresql+psycopg://test:test@localhost:5432/test")
|
||||
|
||||
from app.services import scheduler
|
||||
|
||||
_SQL_DIR = Path(__file__).resolve().parents[1] / "data" / "sql"
|
||||
_MIGRATION_288 = _SQL_DIR / "288_deals_doc_type.sql"
|
||||
_IMPORT_SRC = inspect.getsource(scheduler.import_rosreestr_dkp)
|
||||
|
||||
|
||||
# ── SQL-форма импорта ────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
def test_import_filters_region_and_doc_type_via_bind_params() -> None:
|
||||
"""Оба фильтра — bind-параметры, литералов 66 / 'ДКП' в SQL больше нет."""
|
||||
assert "region_code = CAST(:region_code AS int)" in _IMPORT_SRC
|
||||
assert "doc_type = ANY(CAST(:doc_types AS text[]))" in _IMPORT_SRC
|
||||
assert "WHERE region_code = 66" not in _IMPORT_SRC
|
||||
assert "AND doc_type = 'ДКП'" not in _IMPORT_SRC
|
||||
# psycopg v3: ни один bind-параметр не приводится через :name::type.
|
||||
assert not re.search(r":\w+::", _IMPORT_SRC)
|
||||
|
||||
|
||||
def test_import_writes_doc_type_into_deals() -> None:
|
||||
"""doc_type едет из SELECT в список колонок INSERT, в VALUES и в ON CONFLICT."""
|
||||
assert "doc_type AS doc_type" in _IMPORT_SRC
|
||||
assert "deal_date, doc_type" in _IMPORT_SRC
|
||||
assert "CAST(:doc_type AS text)" in _IMPORT_SRC
|
||||
# Переопубликованный квартал может исправить тип документа — обновляем.
|
||||
assert "doc_type = EXCLUDED.doc_type" in _IMPORT_SRC
|
||||
assert "IS DISTINCT FROM EXCLUDED.doc_type" in _IMPORT_SRC
|
||||
assert '"doc_type": row["doc_type"]' in _IMPORT_SRC
|
||||
|
||||
|
||||
def test_import_keeps_dedup_key_shape_unchanged() -> None:
|
||||
"""Ключ дедупа НЕ зависит от типа документа — иначе осиротели бы старые строки.
|
||||
|
||||
id уникален в источнике сам по себе; префикс 'ros:dkp:' остаётся историческим
|
||||
именем формата (см. миграцию 077, которая уже конвертировала все строки).
|
||||
"""
|
||||
assert "'ros:dkp:' || CAST(id AS text) AS dedup_hash" in _IMPORT_SRC
|
||||
assert "ON CONFLICT (dedup_hash) DO UPDATE SET" in _IMPORT_SRC
|
||||
|
||||
|
||||
# ── фактические bind-параметры (вызов с моком) ───────────────────────────────
|
||||
|
||||
|
||||
def _capture_select_params(params: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Прогоняет import_rosreestr_dkp до первого SELECT из FDW и возвращает его binds.
|
||||
|
||||
Мок Session: cleanup-DELETE и _resume_dkp_cursor получают пустые результаты,
|
||||
первый батч — пустой список, поэтому цикл завершается сразу после SELECT.
|
||||
"""
|
||||
captured: list[dict[str, Any]] = []
|
||||
|
||||
def _execute(stmt: Any, binds: Any = None, *a: Any, **kw: Any) -> MagicMock:
|
||||
sql = str(stmt)
|
||||
if "FROM gendesign_rosreestr_deals" in sql and isinstance(binds, dict):
|
||||
captured.append(binds)
|
||||
result = MagicMock()
|
||||
result.fetchall.return_value = []
|
||||
result.fetchone.return_value = None
|
||||
result.mappings.return_value.all.return_value = []
|
||||
result.scalar.return_value = None
|
||||
return result
|
||||
|
||||
db = MagicMock()
|
||||
db.execute.side_effect = _execute
|
||||
|
||||
monkeys = {
|
||||
"is_cancelled": False,
|
||||
}
|
||||
orig_is_cancelled = scheduler.runs_mod.is_cancelled
|
||||
orig_mark_done = scheduler.runs_mod.mark_done
|
||||
orig_heartbeat = scheduler.kit_runs.update_heartbeat
|
||||
try:
|
||||
scheduler.runs_mod.is_cancelled = lambda *a, **kw: monkeys["is_cancelled"] # type: ignore[assignment]
|
||||
scheduler.runs_mod.mark_done = lambda *a, **kw: None # type: ignore[assignment]
|
||||
scheduler.kit_runs.update_heartbeat = lambda *a, **kw: None # type: ignore[assignment]
|
||||
scheduler.import_rosreestr_dkp(db, 1, params)
|
||||
finally:
|
||||
scheduler.runs_mod.is_cancelled = orig_is_cancelled # type: ignore[assignment]
|
||||
scheduler.runs_mod.mark_done = orig_mark_done # type: ignore[assignment]
|
||||
scheduler.kit_runs.update_heartbeat = orig_heartbeat # type: ignore[assignment]
|
||||
|
||||
assert captured, "SELECT из gendesign_rosreestr_deals не выполнился"
|
||||
return captured[0]
|
||||
|
||||
|
||||
def test_defaults_preserve_current_production_behaviour() -> None:
|
||||
"""Без параметров — ровно прежний скоуп: Свердловская обл., только ДКП."""
|
||||
binds = _capture_select_params({})
|
||||
assert binds["region_code"] == 66
|
||||
assert binds["doc_types"] == ["ДКП"]
|
||||
|
||||
|
||||
def test_params_override_region_and_doc_types() -> None:
|
||||
"""Москва + оба типа документа приходят из params, а не из кода."""
|
||||
binds = _capture_select_params({"region_code": 77, "doc_types": ["ДКП", "ДДУ"]})
|
||||
assert binds["region_code"] == 77
|
||||
assert binds["doc_types"] == ["ДКП", "ДДУ"]
|
||||
|
||||
|
||||
def test_region_code_accepts_string_from_jsonb_params() -> None:
|
||||
"""default_params прилетают из jsonb — строковый регион не должен ломать CAST."""
|
||||
binds = _capture_select_params({"region_code": "77"})
|
||||
assert binds["region_code"] == 77
|
||||
assert isinstance(binds["region_code"], int)
|
||||
|
||||
|
||||
# ── миграция 288 ─────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
def test_migration_288_adds_column_backfills_and_sets_schedule_region() -> None:
|
||||
"""288: idempotent-колонка, бэкфилл только rosreestr-строк, явный регион в расписании."""
|
||||
assert _MIGRATION_288.is_file(), f"missing migration: {_MIGRATION_288}"
|
||||
sql = _MIGRATION_288.read_text("utf-8")
|
||||
assert "ALTER TABLE deals ADD COLUMN IF NOT EXISTS doc_type text" in sql
|
||||
# Бэкфилл корректен ровно потому, что всё загруженное прошло фильтр ДКП.
|
||||
assert "SET doc_type = 'ДКП'" in sql
|
||||
assert "WHERE source = 'rosreestr'" in sql
|
||||
assert "AND doc_type IS NULL" in sql
|
||||
# Явный region_code в расписании вместо неявного дефолта в коде.
|
||||
assert "UPDATE scrape_schedules" in sql
|
||||
assert "'{\"region_code\": 66}'::jsonb" in sql
|
||||
assert "source = 'rosreestr_dkp_import'" in sql
|
||||
assert "BEGIN;" in sql and "COMMIT;" in sql
|
||||
|
|
@ -156,7 +156,7 @@ def test_migration_077_shared_filter_matches_live_import() -> None:
|
|||
ЕКБ-строки под EKB-only scope того времени; живой импорт расширен на всю
|
||||
Свердловскую область, поэтому city-фильтр из живого импорта СНЯТ намеренно;
|
||||
- region_code / doc_type: в живом импорте это ПАРАМЕТРЫ (#3051), их совпадение
|
||||
с 077 проверяется через дефолты — см. тест ниже.
|
||||
с 077 проверяется дефолтами params.get(..., 66) / ["ДКП"] в самом импорте.
|
||||
Остальные клозы обязаны совпадать байт-в-байт, иначе 077 конвертировал бы не тот
|
||||
набор строк.
|
||||
"""
|
||||
|
|
@ -174,24 +174,6 @@ def test_migration_077_shared_filter_matches_live_import() -> None:
|
|||
assert "doc_type = 'ДКП'" in sql
|
||||
|
||||
|
||||
def test_live_import_parametrized_region_and_doc_type_keep_077_defaults() -> None:
|
||||
"""#3051: регион и типы документов — bind-параметры, но ДЕФОЛТЫ = скоуп 077.
|
||||
|
||||
Литералы `region_code = 66` / `doc_type = 'ДКП'` ушли из SQL живого импорта
|
||||
(иначе регион 77 не подключить), но дефолты обязаны воспроизводить ровно тот
|
||||
набор строк, который 077 когда-то backfill'ил, — иначе штатный прогон молча
|
||||
сменил бы скоуп.
|
||||
"""
|
||||
# В SQL — параметры, не литералы.
|
||||
assert "region_code = CAST(:region_code AS int)" in _IMPORT_SRC
|
||||
assert "doc_type = ANY(CAST(:doc_types AS text[]))" in _IMPORT_SRC
|
||||
assert "region_code = 66" not in _IMPORT_BODY
|
||||
assert "doc_type = 'ДКП'" not in _IMPORT_BODY.split("params.get", 1)[-1].split("SELECT", 1)[0]
|
||||
# Дефолты — прежнее поведение.
|
||||
assert 'params.get("region_code", 66)' in _IMPORT_SRC
|
||||
assert 'params.get("doc_types") or ["ДКП"]' in _IMPORT_SRC
|
||||
|
||||
|
||||
def test_live_import_dropped_ekb_city_filter() -> None:
|
||||
"""Живой импорт БОЛЬШЕ не фильтрует по городу — Mera расширена на всю обл. 66.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue