mirror of
https://github.com/dredx/prole.git
synced 2026-09-24 19:24:32 +00:00
- Add Cluster Nodes spreadsheet screen for host/service placement (Primary Host vs Enabled Here) - Wire navigation to show Cluster Nodes after Cluster Environment (multi-node, non-k3d) - Update screen registry/base helpers and related layout/navigation tests - Refresh port mappings and config fixtures
109 lines
3.6 KiB
Python
109 lines
3.6 KiB
Python
import sys
|
|
from unittest.mock import patch, MagicMock
|
|
import pytest
|
|
from pathlib import Path
|
|
|
|
# Mock tkinter and other GUI/macOS specific imports
|
|
sys.modules["tkinter"] = MagicMock()
|
|
sys.modules["tkinter.ttk"] = MagicMock()
|
|
sys.modules["tkinter.scrolledtext"] = MagicMock()
|
|
sys.modules["tkinter.messagebox"] = MagicMock()
|
|
sys.modules["Foundation"] = MagicMock()
|
|
sys.modules["AppKit"] = MagicMock()
|
|
sys.modules["PIL"] = MagicMock()
|
|
sys.modules["PIL.Image"] = MagicMock()
|
|
sys.modules["PIL.ImageTk"] = MagicMock()
|
|
|
|
import install
|
|
from install import ProleInstaller
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_installer(tmp_path):
|
|
test_cfg_src = Path(__file__).parent / "fixtures" / "test-prole.cfg"
|
|
cfg_path = tmp_path / "prole.cfg"
|
|
cfg_path.write_text(test_cfg_src.read_text())
|
|
|
|
with patch("install.tk.Tk"), patch("install.tk.Frame"), patch(
|
|
"install.tk.Canvas"
|
|
), patch("install.tk.Label"), patch("install.tk.Button"), patch(
|
|
"install.tk.Entry"
|
|
) as mock_entry, patch(
|
|
"install.tk.StringVar"
|
|
), patch(
|
|
"install.tk.BooleanVar"
|
|
), patch(
|
|
"install.tk.IntVar"
|
|
), patch(
|
|
"install.ttk.Style"
|
|
), patch(
|
|
"install.Path.exists", return_value=True
|
|
), patch(
|
|
"install.Path.mkdir"
|
|
), patch.object(
|
|
ProleInstaller, "_save_env_to_file"
|
|
), patch.object(
|
|
ProleInstaller, "_save_prole_cfg"
|
|
), patch.object(
|
|
ProleInstaller, "_save_ansible_prole_vault"
|
|
), patch.object(
|
|
ProleInstaller, "_after_env_saved"
|
|
), patch(
|
|
"threading.Thread"
|
|
):
|
|
|
|
mock_entry.return_value.get.return_value.strip.return_value = "mock_val"
|
|
root = MagicMock()
|
|
root.winfo_screenwidth.return_value = 1920
|
|
root.winfo_screenheight.return_value = 1080
|
|
|
|
app = ProleInstaller(root, config_path=str(cfg_path))
|
|
app.bg_canvas.winfo_width.return_value = 1000
|
|
# Ensure deterministic gating for the Cluster Nodes screen (multi-node, non-k3d).
|
|
try:
|
|
app.cluster_env.get.return_value = "prole-service-cluster"
|
|
except Exception:
|
|
pass
|
|
app.ansible_topology = {
|
|
"domain": "prole.org",
|
|
"hosts": {"merlin": "10.0.0.10", "myrddin": "10.0.0.11"},
|
|
"groups": {"k3s_hosts": ["merlin", "myrddin"]},
|
|
}
|
|
return app
|
|
|
|
|
|
def test_init_cluster_next_goes_to_cluster_nodes(mock_installer):
|
|
mock_installer.show_page("init_cluster")
|
|
|
|
with (
|
|
patch.object(mock_installer, "_cluster_ready_for_navigation", return_value=True),
|
|
patch.object(mock_installer, "_validate_and_save_cluster_config", return_value=True),
|
|
patch.object(mock_installer, "_run_service_layer_overlay") as mock_overlay,
|
|
):
|
|
mock_installer.on_next()
|
|
# Service-layer overlay gating has been removed; placement happens in Cluster Nodes.
|
|
mock_overlay.assert_not_called()
|
|
assert mock_installer.pages[mock_installer.page_index][0] == "cluster_nodes"
|
|
|
|
|
|
def test_cluster_nodes_next_proceeds_to_database_options(mock_installer):
|
|
mock_installer.show_page("cluster_nodes")
|
|
mock_installer._cluster_nodes_current_policy = {
|
|
"hosts": {},
|
|
"services": {},
|
|
}
|
|
|
|
with patch.object(
|
|
mock_installer,
|
|
"_validate_and_save_cluster_nodes_policy",
|
|
return_value=True,
|
|
):
|
|
mock_installer.on_next()
|
|
assert mock_installer.pages[mock_installer.page_index][0] == "database_options"
|
|
|
|
|
|
def test_cluster_nodes_prev_goes_back_to_cluster_environment(mock_installer):
|
|
mock_installer.show_page("cluster_nodes")
|
|
mock_installer.on_prev()
|
|
assert mock_installer.pages[mock_installer.page_index][0] == "init_cluster"
|