from __future__ import annotations from pathlib import Path from knoe.ui.screens.cfg import ConfigMixin class _Var: def __init__(self, value: str): self._value = value def get(self) -> str: return self._value class _DummyCfgApp(ConfigMixin): def __init__( self, conf_dir: Path, kubectx: str, *, mode: str = "k3d", cluster_env: str = "dev", service_namespace_input: str = "knoe-system", resolved_service_namespace: str = "knoe-system", existing_global: dict | None = None, ): self._conf_dir = conf_dir self._cfg_path_override = conf_dir / "knoe.cfg" self._mode = mode self._resolved_service_namespace = resolved_service_namespace # Minimal surface required by ConfigMixin._save_knoe_cfg self.cluster_env = _Var(cluster_env) self.selected_kubectx = _Var(kubectx) self.db_username = _Var("knoe-db") self.db_password = _Var("secret") self.db_namespace = _Var("knoe-system") self.cnpg_cluster_name = _Var("knoe-db") self.db_host_port = _Var("5432") self.supabase_pv_node = _Var("") self.supabase_pv_base_dir = _Var("") self.gitops_node_selector = _Var("") self.argocd_node_selector = _Var("") self.k3s_server_url = _Var("") self.k3s_token = _Var("") self.prod_artifacts_path = _Var(str(conf_dir)) self.service_namespace = _Var(service_namespace_input) self.knoe_cfg_data = { "Global": dict(existing_global or {}), "Initialize Cluster": {}, "Dev Cluster (k3d)": {}, "Service Cluster (k3s)": {}, "Prod Cluster (k8s)": {}, } def _resolve_knoe_conf_dir(self) -> Path: return self._conf_dir def _deployment_mode(self) -> str: return self._mode def _get_service_namespace(self) -> str: return self._resolved_service_namespace def _secret_cfg_value(self, _section: str, _key: str, value: str, *_args) -> str: return value def _save_ansible_knoe_vault(self, _db_password: str): return None def _sanitize_sections_for_cfg(self, sections: dict) -> dict: return sections def _sync_port_forward_mappings(self): # Not relevant for this unit test; avoids requiring optional-feature vars. return None def _collect_input_snapshot(self) -> dict: return {} def test_save_knoe_cfg_persists_kubecontext(tmp_path, monkeypatch): # Avoid touching real env activation during unit test. import knoe.ui.screens.cfg as cfg_mod monkeypatch.setattr(cfg_mod.knoe_conf, "activate_environment", lambda *_a, **_k: None) app = _DummyCfgApp(conf_dir=tmp_path, kubectx="k3d-knoe-system") app._save_knoe_cfg() text = (tmp_path / "knoe.cfg").read_text(encoding="utf-8") assert "KUBECONTEXT" in text assert "k3d-knoe-system" in text def test_save_knoe_cfg_service_mode_drops_generated_localhost_values( tmp_path, monkeypatch ): import knoe.ui.screens.cfg as cfg_mod monkeypatch.setattr(cfg_mod.knoe_conf, "activate_environment", lambda *_a, **_k: None) app = _DummyCfgApp( conf_dir=tmp_path, kubectx="", mode="k3s", cluster_env="service", service_namespace_input="", resolved_service_namespace="knoe-system", existing_global={ "SERVICE_HOSTNAME": "k3d.localhost", "API_SERVICE_ENDPOINT": "http://localhost:8081", "PROLE_OPENTOFU_URL": "http://127.0.0.1:8080", }, ) app._save_knoe_cfg() text = (tmp_path / "knoe.cfg").read_text(encoding="utf-8") assert "SERVICE_HOSTNAME" not in text assert "API_SERVICE_ENDPOINT" not in text assert "localhost" not in text assert "SERVICE_NAMESPACE" not in text def test_save_knoe_cfg_service_mode_keeps_explicit_service_namespace( tmp_path, monkeypatch ): import knoe.ui.screens.cfg as cfg_mod monkeypatch.setattr(cfg_mod.knoe_conf, "activate_environment", lambda *_a, **_k: None) app = _DummyCfgApp( conf_dir=tmp_path, kubectx="", mode="k3s", cluster_env="service", service_namespace_input="explicit-ns", resolved_service_namespace="explicit-ns", ) app._save_knoe_cfg() text = (tmp_path / "knoe.cfg").read_text(encoding="utf-8") assert "SERVICE_NAMESPACE = explicit-ns" in text def test_save_knoe_cfg_service_mode_repeated_saves_remain_clean(tmp_path, monkeypatch): import knoe.ui.screens.cfg as cfg_mod monkeypatch.setattr(cfg_mod.knoe_conf, "activate_environment", lambda *_a, **_k: None) app = _DummyCfgApp( conf_dir=tmp_path, kubectx="", mode="k3s", cluster_env="service", service_namespace_input="", resolved_service_namespace="knoe-system", existing_global={ "SERVICE_HOSTNAME": "k3d.localhost", "API_SERVICE_ENDPOINT": "http://localhost:8081", }, ) app._save_knoe_cfg() first = (tmp_path / "knoe.cfg").read_text(encoding="utf-8") app._save_knoe_cfg() second = (tmp_path / "knoe.cfg").read_text(encoding="utf-8") for text in (first, second): assert "SERVICE_HOSTNAME" not in text assert "API_SERVICE_ENDPOINT" not in text assert "localhost" not in text