fix(tests): реальный прогон интеграционных тестов СПОД против Postgres
Прогнал api/tests/integration/test_form2_ahr_satellite_spod_integration.py против живого Postgres (perf/perf/perf на localhost:55432, БД dfip_1906, alembic upgrade head + фикстура) — нашёл и поправил два бага самого теста (фичу/миграцию не трогал): - _find_row не учитывал служебную META-строку (editable/role/user_id без id/header), которую v3.v_form_view добавляет первой в любой лист — KeyError: 'id' на первой же выборке. Теперь ищет только среди INPUT-строк. - test_satellite_spod_phase_gates_non_admin_user делал один тест из "запрет без fact_q4.spod → добавили ключ → разрешено": неадминский 403/400 от isp1 внутри теста вызывает db_ref.rollback() в tests/integration/conftest.py (per-request откат на ошибке), который стирает все несохранённые изменения этого же теста — включая только что созданные строку сателлита и form_phase. Разбил на два независимых теста (test_satellite_spod_rejected_before_phase_includes_spod_column / test_satellite_spod_allowed_once_phase_includes_spod_column), в каждом ровно один запрос, которому разрешено провалиться. pytest tests/integration — 157 passed, 1 failed (pre-existing, не связан: test_backend_calls_form3_add_project_and_add_line_functions, FORM_3/add_project, 400 на /api/v1/projects/.../report/.../line), 4 skipped. Новый файл — 15/15. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
d41668dc27
commit
a5ffd476a6
@ -62,7 +62,12 @@ def _get_sheet_rows(client, admin_tokens, form2_id, sheet) -> list[dict]:
|
||||
|
||||
|
||||
def _find_row(rows: list[dict], predicate) -> dict:
|
||||
# v_form_view prepends a META row ({"editable": [...], "role": ..., ...},
|
||||
# row_type="META", depth=-1) with no "id"/"header" — only INPUT rows carry
|
||||
# satellite/AHR line data.
|
||||
for row in rows:
|
||||
if row.get("row_type") != "INPUT":
|
||||
continue
|
||||
if predicate(row["data"]):
|
||||
return row
|
||||
raise AssertionError("строка не найдена")
|
||||
@ -141,14 +146,22 @@ def test_satellite_spod_rejects_other_quarters(
|
||||
|
||||
|
||||
@pytest.mark.parametrize("sheet", ["AHR_RENT", "AHR_UTILITY", "AHR_SECURITY"])
|
||||
def test_satellite_spod_phase_gates_non_admin_user(
|
||||
def test_satellite_spod_rejected_before_phase_includes_spod_column(
|
||||
client, admin_tokens, isp_tokens, form2_id, sheet
|
||||
):
|
||||
"""DFIP-пользователь (isp1): без 'fact_q4.spod' в этапе — отказ,
|
||||
после появления ключа (как после data-миграции) — успех."""
|
||||
"""DFIP-пользователь (isp1) с этапом, где column_keys ещё не включает
|
||||
'fact_q4.spod' (как до data-миграции): запись отклоняется.
|
||||
|
||||
Note: a failed request (403/400) makes the shared test-session's
|
||||
`_get_db` override call `db_ref.rollback()`, which would wipe out any
|
||||
uncommitted setup done earlier in the *same* test (the satellite line,
|
||||
the phase row) — see conftest.py's `client` fixture. So the "before"
|
||||
and "after" migration scenarios must be two separate tests, each
|
||||
ending in exactly one request that is allowed to fail.
|
||||
"""
|
||||
line_id = _add_satellite_line(client, admin_tokens, form2_id, sheet)
|
||||
|
||||
phase_code = f"spod_test_{sheet.lower()}"
|
||||
phase_code = f"spod_test_before_{sheet.lower()}"
|
||||
create_body = {
|
||||
"budget_form_id": form2_id,
|
||||
"sheet": sheet,
|
||||
@ -173,9 +186,28 @@ def test_satellite_spod_phase_gates_non_admin_user(
|
||||
)
|
||||
assert response.status_code in (400, 403, 409), response.text
|
||||
|
||||
response = client.patch(
|
||||
f"/api/v1/stages/form/{form2_id}/{sheet}/{phase_code}",
|
||||
json={**create_body, "column_keys": ["fact_q4.dec", "fact_q4.spod"]},
|
||||
|
||||
@pytest.mark.parametrize("sheet", ["AHR_RENT", "AHR_UTILITY", "AHR_SECURITY"])
|
||||
def test_satellite_spod_allowed_once_phase_includes_spod_column(
|
||||
client, admin_tokens, isp_tokens, form2_id, sheet
|
||||
):
|
||||
"""DFIP-пользователь (isp1) с этапом, где column_keys уже включает
|
||||
'fact_q4.spod' (как после data-миграции из этого PR): запись проходит."""
|
||||
line_id = _add_satellite_line(client, admin_tokens, form2_id, sheet)
|
||||
|
||||
phase_code = f"spod_test_after_{sheet.lower()}"
|
||||
response = client.post(
|
||||
f"/api/v1/stages/form/{form2_id}",
|
||||
json={
|
||||
"budget_form_id": form2_id,
|
||||
"sheet": sheet,
|
||||
"phase_code": phase_code,
|
||||
"role": "DFIP",
|
||||
"column_keys": ["fact_q4.dec", "fact_q4.spod"],
|
||||
"opens_at": "2020-01-01T00:00:00",
|
||||
"closes_at": "2099-01-01T00:00:00",
|
||||
"direction": None,
|
||||
},
|
||||
headers=_auth_headers(admin_tokens),
|
||||
)
|
||||
assert response.status_code == 200, response.text
|
||||
@ -186,9 +218,3 @@ def test_satellite_spod_phase_gates_non_admin_user(
|
||||
headers=_auth_headers(isp_tokens),
|
||||
)
|
||||
assert response.status_code == 200, response.text
|
||||
|
||||
response = client.delete(
|
||||
f"/api/v1/stages/form/{form2_id}/{sheet}/{phase_code}",
|
||||
headers=_auth_headers(admin_tokens),
|
||||
)
|
||||
assert response.status_code == 200, response.text
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user