prole/tests/test_install_logic.py
chrisfu ec50f82cc8 refactor: deduplicate installer business logic & split screens.py into package
Separation of concerns: merge silent/UI actions & modularize screens.

ProleInstallerBase (actions.py): Created shared base class with 37 deduplicated methods previously duplicated between ProleSilentInstaller and ProleInstaller. Namespace, environment, secret, deployment, port-forward, authority/repair, image, and logging helpers now defined once. Subclasses override _get_input() to bridge their data-access layers.

screens.py -> screens/ package (18 mixin modules): Split 10,234-line monolithic screens.py into focused mixin modules: base, navigation, welcome, dependencies, network, environment, database, cluster, services, security, ollama, supabase, docker, build, packaging, deploy, validate, cfg. __init__.py composes ProleInstaller from all mixins and re-exports has_display(), main() for full backward compatibility.

All 37 tests pass with no regressions.
2026-02-20 14:43:20 -08:00

65 lines
2.5 KiB
Python

import sys
from unittest.mock import patch, MagicMock
# Mock tkinter and other GUI/macOS specific imports before they are imported in install.py
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['objc'] = MagicMock()
import os
import pytest
from pathlib import Path
# Now import install.py after mocking
import install
from install import ProleInstaller
@pytest.fixture
def installer(tmp_path):
# Mocking os.environ to avoid messing with real env
with patch.dict(os.environ, {}, clear=True):
# We need to mock ProleInstaller.__init__ because it creates GUI elements
with patch.object(ProleInstaller, '__init__', return_value=None):
ins = ProleInstaller()
return ins
def test_resolve_prole_home_default(installer):
with patch.dict(os.environ, {}, clear=True):
# Path.home() might vary, so we just check it ends with .prole if no env var
home = installer.resolve_prole_home()
assert home.name == ".prole"
def test_resolve_prole_home_env(installer):
custom_home = "/tmp/custom_prole"
with patch.dict(os.environ, {'PROLE_HOME': custom_home}):
home = installer.resolve_prole_home()
assert str(home) == custom_home
def test_env_defaults(installer):
with patch.dict(os.environ, {}, clear=True), \
patch.object(installer, '_read_existing_env', return_value={}):
defaults = installer._env_defaults()
assert 'PROLE_HOME' in defaults
assert defaults['PROLE_HOME'].endswith('.prole')
assert defaults['PROLE_CONF'].endswith('.prole/conf')
def test_read_existing_env_no_file(installer, tmp_path):
# Ensure neither PROLE_HOME nor the default location has an env.sh for this test
with patch.dict(os.environ, {'PROLE_HOME': str(tmp_path)}):
with patch('pathlib.Path.home', return_value=tmp_path / "fake_home"):
env = installer._read_existing_env()
assert env == {}
def test_read_existing_env_with_file(installer, tmp_path):
env_sh = tmp_path / "env.sh"
env_sh.write_text('export VAR1="val1"\nVAR2=val2\n# comment\n')
with patch.dict(os.environ, {'PROLE_HOME': str(tmp_path)}):
with patch('pathlib.Path.home', return_value=tmp_path / "fake_home"):
env = installer._read_existing_env()
assert env.get('VAR1') == "val1"
assert env.get('VAR2') == "val2"