import sys import tkinter as tk from pathlib import Path from unittest.mock import MagicMock import pytest # Ensure `installer` is importable when tests are invoked directly via `pytest` PROJECT_ROOT = Path(__file__).resolve().parents[2] if str(PROJECT_ROOT) not in sys.path: sys.path.insert(0, str(PROJECT_ROOT)) import installer.ui.screens.cluster as cluster_mod from installer.ui.screens.base import ScreenBaseMixin from installer.ui.screens.cluster import ClusterScreenMixin class _DummyClusterSaveApp(ScreenBaseMixin, ClusterScreenMixin): """Minimal surface to exercise the Cluster Environment screen Save behavior.""" def __init__(self, root: tk.Tk): self.root = root # Canvas is not required by `_validate_and_save_cluster_config`, but other mixins # assume it exists. self.bg_canvas = tk.Canvas(root, width=1, height=1) self._canvas_items = [] self._overlay_widgets = [] self.cluster_env = tk.StringVar(master=root, value="service") self.selected_k3d_cluster = tk.StringVar(master=root, value="") self.selected_kubectx = tk.StringVar(master=root, value="") self.service_namespace = tk.StringVar(master=root, value="knoe-system") self.prod_artifacts_path = tk.StringVar(master=root, value=str(Path.home())) self.k3s_server_url = tk.StringVar(master=root, value="") self.k3s_token = tk.StringVar(master=root, value="") self.supabase_enabled = tk.BooleanVar(master=root, value=False) self.gitops_enabled = tk.BooleanVar(master=root, value=False) self.kerberos_enabled = tk.BooleanVar(master=root, value=False) self.at_rest_encryption_enabled = tk.BooleanVar(master=root, value=False) # Minimal config structure required by `_validate_and_save_cluster_config`. self.prole_cfg_data = { "Initialize Cluster": { "ENVIRONMENT": "service", "K3S_SERVER_URL": "", "K3S_TOKEN": "", }, "Global": { # Keep old/new equal so we don't trigger the namespace cleanup prompt. "SERVICE_NAMESPACE": "knoe-system", }, "Optional Features": {}, "Prod Cluster (k8s)": {}, } self.saved_calls = 0 self.status_check_calls = 0 def _save_prole_cfg(self): self.saved_calls += 1 def _verify_k3s_services(self): self.status_check_calls += 1 def test_cluster_env_save_triggers_status_check(monkeypatch): # Some test modules replace tkinter with MagicMocks at import-time. if isinstance(sys.modules.get("tkinter"), MagicMock): pytest.skip("tkinter is mocked in this test run") # Avoid depending on a real kubeconfig file. monkeypatch.setattr(cluster_mod, "_find_kubeconfig_file", lambda: "/tmp/kubeconfig") # Avoid any real secret handling. monkeypatch.setattr(cluster_mod, "_encrypt_cfg_secret", lambda s: s) root = tk.Tk() root.withdraw() try: app = _DummyClusterSaveApp(root) assert app._validate_and_save_cluster_config() is True assert app.saved_calls == 1 # Requirement: clicking Save should immediately run a status check. assert app.status_check_calls == 1 finally: try: root.destroy() except Exception: pass