#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ dry_run.py — Локальная проверка логики без Docker/SSH """ import sys import os # Добавляем корень проекта _PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) if _PROJECT_ROOT not in sys.path: sys.path.insert(0, _PROJECT_ROOT) errors = [] def check(msg, ok): if not ok: errors.append(msg) print(f" FAIL: {msg}") else: print(f" OK: {msg}") print("=== DRY-RUN: Проверка импортов ===") try: from core import state check("state модуль импортируется", True) except Exception as e: check(f"state импорт: {e}", False) try: from core.fsm import FSM check("FSM класс доступен", True) except Exception as e: check(f"FSM импорт: {e}", False) try: from core.color import menu, prompt check("color модуль доступен", True) except Exception as e: check(f"color импорт: {e}", False) try: from discover.docker import discover_docker, get_container_pid check("discover.docker доступен", True) except Exception as e: check(f"discover.docker: {e}", False) try: from discover.nginx import discover_nginx check("discover.nginx доступен", True) except Exception as e: check(f"discover.nginx: {e}", False) try: from transfer.transfer import do_transfer check("transfer.transfer доступен", True) except Exception as e: check(f"transfer.transfer: {e}", False) try: from transfer.ssh import list_private_keys check("transfer.ssh доступен", True) except Exception as e: check(f"transfer.ssh: {e}", False) try: from manifest.manifest import build_manifest, save_manifest check("manifest доступен", True) except Exception as e: check(f"manifest: {e}", False) print("\n=== DRY-RUN: Проверка FSM ===") # Проверим что SOURCE_STEPS содержит все нужные шаги fsm_s = FSM(mode="source") check("SOURCE_STEPS содержит TRANSFER", "TRANSFER" in fsm_s.steps) check("SOURCE_STEPS содержит DONE", "DONE" in fsm_s.steps) fsm_t = FSM(mode="target") check("TARGET_STEPS содержит DONE", "DONE" in fsm_t.steps) print("\n=== DRY-RUN: Проверка state.json ===") state.load_state() check("State загружается без ошибок", True) state.set_stage("INIT", mode=None) check("State сохраняется", True) print("\n=== DRY-RUN: Проверка reset_state ===") state.mark_completed("SOURCE_DISCOVER") state.set_stage("SOURCE_PACK", archive_path="/tmp/test.tar.gz") state.reset_state(mode="source") st = state.load_state() check("reset_state очищает completed_steps", len(st.get("completed_steps", [])) == 0) check("reset_stage после reset = INIT", st.get("stage") == "INIT") print("\n=== DRY-RUN: Проверка manifest ===") manifest = build_manifest( docker_data={"container_name":"test","image":"img","status":"running","compose_file":"/tmp/compose.yml","env_file":None,"mounts":[],"ports":{},"networks":[],"host_config":{},"labels":{}}, nginx_data=[], sidecars=[], host_network={}, systemd_units=[], cron_jobs=[], extra_hints=[], ) check("Manifest содержит service.name", manifest["service"]["name"] == "test") check("Manifest содержит docker.compose_file", manifest["docker"]["compose_file"] == "/tmp/compose.yml") print("\n=== DRY-RUN: Проверка transfer без host ===") st = state.load_state() state.save_state({**st, "archive_path":None, "target_host":None, "target_user":None, "target_port":22}) try: do_transfer() check("do_transfer без archive_path — бросил RuntimeError", False) except RuntimeError as e: check("do_transfer без archive_path — RuntimeError", "Архив не найден" in str(e)) except Exception as e: check(f"do_transfer без archive_path — неожиданная ошибка: {e}", False) # Проверка ssh key discovery (без файловой системы) try: keys = list_private_keys() check("list_private_keys не падает", True) except Exception as e: check(f"list_private_keys: {e}", False) print("\n=== DRY-RUN: ИТОГ ===") if errors: print(f"FAIL: {len(errors)} проверок не прошло:") for e in errors: print(f" - {e}") sys.exit(1) else: print("Все проверки прошли успешно!") sys.exit(0)