mirror of
https://github.com/dredx/prole.git
synced 2026-09-24 19:44:33 +00:00
- Add build-context helper to copy Docker context safely (ignore runtime data, keep symlinks) - Update UI and core actions to use ~/.prole/build and shared copy helper - Add/adjust tests and scripts; introduce knoe ops helpers and update manifests Co-authored-by: Junie <junie@jetbrains.com>
131 lines
4.6 KiB
Python
131 lines
4.6 KiB
Python
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 knoe.ui.screens.cluster as cluster_mod
|
|
from knoe.ui.screens.base import ScreenBaseMixin
|
|
from knoe.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
|
|
|
|
|
|
def test_cluster_env_prod_artifacts_dir_expands_prole_home_from_cfg(monkeypatch, tmp_path):
|
|
# 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")
|
|
|
|
# Ensure `$PROLE_HOME` is NOT available as an OS env var; it must come from config.
|
|
monkeypatch.delenv("PROLE_HOME", raising=False)
|
|
monkeypatch.chdir(tmp_path)
|
|
|
|
root = tk.Tk()
|
|
root.withdraw()
|
|
try:
|
|
app = _DummyClusterSaveApp(root)
|
|
|
|
# Switch to prod so the artifacts directory is validated/created.
|
|
app.cluster_env.set("prod")
|
|
|
|
# Provide PROLE_HOME via config data only.
|
|
prole_home = tmp_path / "prole-home"
|
|
prole_home.mkdir(parents=True, exist_ok=True)
|
|
app.prole_cfg_data.setdefault("System Environment", {})["PROLE_HOME"] = str(
|
|
prole_home
|
|
)
|
|
|
|
# Use a path expression that previously would create a literal `$PROLE_HOME` dir.
|
|
app.prod_artifacts_path.set("$PROLE_HOME/staging")
|
|
|
|
assert app._validate_and_save_cluster_config() is True
|
|
|
|
assert (prole_home / "staging").is_dir()
|
|
assert not (tmp_path / "$PROLE_HOME" / "staging").exists()
|
|
finally:
|
|
try:
|
|
root.destroy()
|
|
except Exception:
|
|
pass
|