diff --git a/backend/tests/ops/test_3448_caddy_only_detection.py b/backend/tests/ops/test_3448_caddy_only_detection.py index 3a953a35..570a6eba 100644 --- a/backend/tests/ops/test_3448_caddy_only_detection.py +++ b/backend/tests/ops/test_3448_caddy_only_detection.py @@ -39,6 +39,7 @@ from __future__ import annotations import re import subprocess +import sys from pathlib import Path import pytest @@ -72,6 +73,16 @@ GIT_ENV = { "GIT_CONFIG_SYSTEM": "/dev/null", } +# Эти кейсы гоняют `bash -c <скрипт>` во временном git-репозитории (POSIX shell + +# /dev/null + жёсткий PATH=/usr/bin:/bin:/usr/local/bin). На Windows дочерний +# процесс не стартует (нет POSIX shell на этом PATH); покрытие обеспечивается в +# CI на Linux. Кейсы, которые читают только YAML/строки без subprocess, не +# помечены и обязаны выполняться локально. +posix_only = pytest.mark.skipif( + sys.platform == "win32", + reason="запускает bash-скрипт дочерним процессом; POSIX-only, покрытие в CI (Linux)", +) + def _detect_script() -> str: """Тело шага, который считает изменённые файлы в job `changes`.""" @@ -181,6 +192,7 @@ def _run( return _exec(repo, base_sha if before is None else before, event) +@posix_only def test_merge_with_only_caddy_file_takes_the_fast_path(tmp_path: Path) -> None: """Случай #3448 дословно: мерж, в диффе один файл под caddy/.""" outputs, _ = _run(tmp_path, ("caddy/sites/apps.caddy",)) @@ -193,6 +205,7 @@ def test_merge_with_only_caddy_file_takes_the_fast_path(tmp_path: Path) -> None: assert outputs["frontend"] == "false" +@posix_only def test_caddy_plus_backend_is_a_full_deploy(tmp_path: Path) -> None: """Обратное направление: быстрый путь НЕ должен красть обычный деплой.""" outputs, _ = _run(tmp_path, ("caddy/sites/apps.caddy", "backend/app/main.py")) @@ -203,6 +216,7 @@ def test_caddy_plus_backend_is_a_full_deploy(tmp_path: Path) -> None: assert outputs["backend"] == "true" +@posix_only def test_missing_base_falls_back_to_full_deploy(tmp_path: Path) -> None: """База не разрешилась → полный деплой, а не пустой список. @@ -223,6 +237,7 @@ def test_missing_base_falls_back_to_full_deploy(tmp_path: Path) -> None: assert "деплой полный" in log +@posix_only def test_decision_is_visible_in_the_log(tmp_path: Path) -> None: """Решение печатается: и список файлов, и итоговые флаги. @@ -291,11 +306,13 @@ def _run_guard(repo: Path) -> subprocess.CompletedProcess: ) +@posix_only def test_fast_path_allowed_when_prod_lags_only_by_proxy_config(tmp_path: Path) -> None: proc = _run_guard(_prod_repo(tmp_path, ("caddy/sites/apps.caddy",))) assert proc.returncode == 0, f"законный быстрый путь заблокирован:\n{proc.stdout}{proc.stderr}" +@posix_only def test_fast_path_refuses_when_prod_lags_by_code(tmp_path: Path) -> None: """Прод отстаёт не только по конфигу прокси → перезагрузка прокси запрещена.""" proc = _run_guard(_prod_repo(tmp_path, ("backend/app/main.py", "caddy/sites/apps.caddy"))) @@ -322,6 +339,7 @@ def test_fast_path_takes_the_same_host_lock() -> None: assert "flock -w 900 9" in script, "лок открывается, но не захватывается" +@posix_only @pytest.mark.parametrize( "changed", [("caddy-extra/x.txt",), ("Caddyfile.bak",), ("docs/caddy.md",)] ) @@ -338,6 +356,7 @@ def test_paths_that_merely_start_with_caddy_are_not_the_fast_path( assert outputs["caddy_only"] == "false", f"{changed}: {outputs}" +@posix_only def test_empty_diff_is_not_the_fast_path(tmp_path: Path) -> None: """Пустой дифф (`before` == HEAD, пустой мерж) — не «всё под caddy». @@ -350,6 +369,7 @@ def test_empty_diff_is_not_the_fast_path(tmp_path: Path) -> None: assert "изменённых файлов: 0" in log +@posix_only def test_data_sql_counts_as_backend(tmp_path: Path) -> None: """`data/sql/**` собирает backend-образ: миграции едут в нём.""" outputs, _ = _run(tmp_path, ("data/sql/002.sql",)) @@ -357,6 +377,7 @@ def test_data_sql_counts_as_backend(tmp_path: Path) -> None: assert outputs["caddy_only"] == "false", outputs +@posix_only def test_non_ascii_path_is_classified(tmp_path: Path) -> None: """Кириллица в пути не должна прятать файл от классификации. @@ -370,6 +391,7 @@ def test_non_ascii_path_is_classified(tmp_path: Path) -> None: assert outputs["backend"] == "true", f"кириллический путь потерян: {outputs}\n{log}" +@posix_only def test_multi_commit_push_is_not_truncated(tmp_path: Path) -> None: """Push из нескольких коммитов разбирается целиком, а не по последнему. diff --git a/backend/tests/skip_allowlist.txt b/backend/tests/skip_allowlist.txt index 0c08811c..e77642d9 100644 --- a/backend/tests/skip_allowlist.txt +++ b/backend/tests/skip_allowlist.txt @@ -176,3 +176,29 @@ tests/sql/test_2998_rosreestr_partition_horizon.py::test_schema_01_alone_is_red_ tests/sql/test_2998_rosreestr_partition_horizon.py::test_migration_193_is_idempotent_and_closes_the_gap tests/sql/test_2998_rosreestr_partition_horizon.py::test_partition_exists_for_every_publishable_quarter tests/sql/test_2998_rosreestr_partition_horizon.py::test_partition_exists_one_quarter_ahead + +# ── POSIX-only: тесты запускают дочерний bash-скрипт ─────────────────────────── +# На Windows нет POSIX shell на PATH, которым эти тесты исполняют /bin/bash -c +# <скрипт> или сам shell-скрипт напрямую (шебанг #!/usr/bin/env bash) — процесс +# не стартует. В CI ЭТИ ТЕСТЫ ИДУТ (ubuntu-раннер). Записи нужны только для +# локального прогона на Windows; чисто-логические проверки в тех же файлах +# (читают YAML/строки без subprocess) в этот список НЕ входят и обязаны +# исполняться локально. +tests/ops/test_3448_caddy_only_detection.py::test_merge_with_only_caddy_file_takes_the_fast_path +tests/ops/test_3448_caddy_only_detection.py::test_caddy_plus_backend_is_a_full_deploy +tests/ops/test_3448_caddy_only_detection.py::test_missing_base_falls_back_to_full_deploy +tests/ops/test_3448_caddy_only_detection.py::test_decision_is_visible_in_the_log +tests/ops/test_3448_caddy_only_detection.py::test_fast_path_allowed_when_prod_lags_only_by_proxy_config +tests/ops/test_3448_caddy_only_detection.py::test_fast_path_refuses_when_prod_lags_by_code +tests/ops/test_3448_caddy_only_detection.py::test_paths_that_merely_start_with_caddy_are_not_the_fast_path +tests/ops/test_3448_caddy_only_detection.py::test_empty_diff_is_not_the_fast_path +tests/ops/test_3448_caddy_only_detection.py::test_data_sql_counts_as_backend +tests/ops/test_3448_caddy_only_detection.py::test_non_ascii_path_is_classified +tests/ops/test_3448_caddy_only_detection.py::test_multi_commit_push_is_not_truncated +tests/test_2950_latest_image_revision_gate.py::test_fresh_latest_passes +tests/test_2950_latest_image_revision_gate.py::test_newer_revision_passes +tests/test_2950_latest_image_revision_gate.py::test_stale_latest_fails_after_timeout +tests/test_2950_latest_image_revision_gate.py::test_revision_from_other_component_does_not_cover +tests/test_2950_latest_image_revision_gate.py::test_missing_label_fails +tests/test_2950_latest_image_revision_gate.py::test_registry_error_fails +tests/test_2950_latest_image_revision_gate.py::test_usage_errors_are_distinct diff --git a/backend/tests/test_2950_latest_image_revision_gate.py b/backend/tests/test_2950_latest_image_revision_gate.py index ad75bc28..1138c2ad 100644 --- a/backend/tests/test_2950_latest_image_revision_gate.py +++ b/backend/tests/test_2950_latest_image_revision_gate.py @@ -15,10 +15,20 @@ from __future__ import annotations import os import stat import subprocess +import sys from pathlib import Path import pytest +# Каждый тест в файле запускает scripts/check-latest-image-revision.sh (POSIX shell, +# shebang #!/usr/bin/env bash) дочерним процессом. На Windows нет POSIX shell на PATH, +# чтобы это исполнить, — покрытие обеспечивается в CI на Linux. +pytestmark = pytest.mark.skipif( + sys.platform == "win32", + reason="запускает bash-скрипт (check-latest-image-revision.sh) дочерним процессом; " + "POSIX-only, покрытие в CI (Linux)", +) + КОРЕНЬ = Path(__file__).resolve().parents[2] СКРИПТ = КОРЕНЬ / "scripts" / "check-latest-image-revision.sh"