"""Тесты статических инвариантов compose-файлов стенда (задача #21). Проверяют то, что иначе выяснилось бы только на Docker-хосте: порт 8080, монтирования /config и /data, healthcheck, capabilities, privileged netns-раннер. Работают без Docker — только PyYAML (см. requirements-dev.txt). """ from __future__ import annotations import pathlib import unittest import validate_compose HERE = pathlib.Path(__file__).resolve().parent ROOT = HERE.parents[1] @unittest.skipUnless(validate_compose.yaml is not None, "нужен PyYAML (make venv)") class ComposeManifestsTest(unittest.TestCase): def test_dev_compose_matches_acceptance_criteria(self) -> None: errors, _ = validate_compose.validate(require_dockerfile=False) self.assertEqual([], errors, "compose-файлы стенда нарушают инварианты AC #21") def test_dev_compose_publishes_app_port_to_host(self) -> None: doc = validate_compose.load(validate_compose.DEV) ports = " ".join(str(p) for p in doc["services"]["awg-dash"]["ports"]) self.assertIn(":8080", ports, "наружу должен публиковаться контейнерный порт приложения 8080") def test_dev_compose_mounts_state_directories(self) -> None: doc = validate_compose.load(validate_compose.DEV) targets = validate_compose._mount_targets(doc["services"]["awg-dash"]) self.assertIn("/config", targets) self.assertIn("/data", targets) def test_healthcheck_hits_api_v1_health(self) -> None: doc = validate_compose.load(validate_compose.DEV) test_cmd = validate_compose.jsonish(doc["services"]["awg-dash"]["healthcheck"]["test"]) self.assertIn("/api/v1/health", test_cmd) def test_test_compose_runs_netns_harness_privileged(self) -> None: doc = validate_compose.load(validate_compose.TEST) svc = doc["services"]["netns"] self.assertTrue(svc["privileged"]) self.assertIn("tests/netns/run.sh", " ".join(svc["entrypoint"])) def test_stub_override_is_labelled_dev_only(self) -> None: text = validate_compose.STUB.read_text(encoding="utf-8") self.assertIn("api_stub.py", text) self.assertIn("DEV", text.upper()) def test_netns_harness_entrypoints_exist(self) -> None: for rel in ( "tests/netns/run.sh", "tests/netns/topology.sh", "tests/netns/lib.sh", "tests/netns/probe.py", "tests/netns/mock_wg_endpoint.py", "tests/netns/leak_sink.py", "deploy/api_stub.py", "deploy/verify-dev-stand.sh", ): with self.subTest(rel=rel): self.assertTrue((ROOT / rel).exists(), f"нет файла {rel}") if __name__ == "__main__": unittest.main(verbosity=2)