Add guided env setup modal
This commit is contained in:
parent
c9859a5324
commit
8c90306c75
6 changed files with 474 additions and 9 deletions
|
|
@ -3,6 +3,7 @@ from __future__ import annotations
|
|||
import asyncio
|
||||
import time
|
||||
from collections import Counter
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from textual.app import App, ComposeResult
|
||||
|
|
@ -11,8 +12,10 @@ from textual.widgets import Button, Checkbox, Input, Select, Static
|
|||
|
||||
from pve_vm_setup.app import PveVmSetupApp
|
||||
from pve_vm_setup.models.workflow import WorkflowState
|
||||
from pve_vm_setup.screens.env_setup import EnvSetupModal, MissingEnvSetupPromptModal
|
||||
from pve_vm_setup.screens.login import LoginView
|
||||
from pve_vm_setup.screens.wizard import NO_DISK_SELECTED, AutoStartConfirmModal, WizardView
|
||||
from pve_vm_setup.services.factory import ProxmoxServiceFactory
|
||||
from pve_vm_setup.services.fake import FakeProxmoxService
|
||||
from pve_vm_setup.settings import AppSettings
|
||||
|
||||
|
|
@ -85,6 +88,80 @@ async def test_main_app_mounts_wizard_only_after_login() -> None:
|
|||
assert app.focused is app.query_one("#general-name", Input)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_main_app_prompts_for_env_setup_when_no_dotenv_exists(
|
||||
tmp_path: Path, monkeypatch
|
||||
) -> None:
|
||||
home = tmp_path / "home"
|
||||
monkeypatch.chdir(tmp_path)
|
||||
monkeypatch.setenv("HOME", str(home))
|
||||
|
||||
app = PveVmSetupApp(
|
||||
AppSettings.from_env({}, load_dotenv_file=True),
|
||||
prompt_for_missing_env_setup=True,
|
||||
)
|
||||
|
||||
async with app.run_test() as pilot:
|
||||
await pilot.pause()
|
||||
|
||||
assert isinstance(app.screen_stack[-1], MissingEnvSetupPromptModal)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_main_app_can_save_env_setup_and_refresh_login_mode(
|
||||
tmp_path: Path, monkeypatch
|
||||
) -> None:
|
||||
class LiveLikeService(FakeProxmoxService):
|
||||
mode = "live"
|
||||
|
||||
home = tmp_path / "home"
|
||||
config_path = home / ".config" / "pve-vm-setup" / ".env"
|
||||
monkeypatch.chdir(tmp_path)
|
||||
monkeypatch.setenv("HOME", str(home))
|
||||
monkeypatch.delenv("PROXMOX_URL", raising=False)
|
||||
monkeypatch.delenv("PROXMOX_USER", raising=False)
|
||||
|
||||
def create_service(settings: AppSettings):
|
||||
if settings.proxmox_url:
|
||||
return LiveLikeService()
|
||||
return FakeProxmoxService()
|
||||
|
||||
monkeypatch.setattr(ProxmoxServiceFactory, "create", staticmethod(create_service))
|
||||
|
||||
app = PveVmSetupApp(
|
||||
AppSettings.from_env({}, load_dotenv_file=True),
|
||||
prompt_for_missing_env_setup=True,
|
||||
)
|
||||
|
||||
async with app.run_test() as pilot:
|
||||
await pilot.pause()
|
||||
assert isinstance(app.screen_stack[-1], MissingEnvSetupPromptModal)
|
||||
|
||||
app.query_one("#missing-env-setup", Button).press()
|
||||
await pilot.pause()
|
||||
assert isinstance(app.screen_stack[-1], EnvSetupModal)
|
||||
|
||||
app.query_one("#env-proxmox-url", Input).value = "https://pve.example.invalid:8006"
|
||||
app.query_one("#env-proxmox-user", Input).value = "root"
|
||||
app.query_one("#env-setup-save", Button).press()
|
||||
|
||||
for _ in range(10):
|
||||
await pilot.pause(0.05)
|
||||
if not app.screen_stack or not isinstance(app.screen_stack[-1], EnvSetupModal):
|
||||
break
|
||||
|
||||
assert config_path.exists()
|
||||
content = config_path.read_text(encoding="utf-8")
|
||||
assert "PROXMOX_URL=https://pve.example.invalid:8006" in content
|
||||
assert "PROXMOX_USER=root" in content
|
||||
assert "PROXMOX_PASSWORD" not in content
|
||||
|
||||
assert "Mode: live on pve.example.invalid:8006" == str(
|
||||
app.query_one("#mode", Static).renderable
|
||||
)
|
||||
assert app.query_one("#username", Input).value == "root"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_wizard_activation_focuses_first_editable_field() -> None:
|
||||
service = FakeProxmoxService()
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ from pathlib import Path
|
|||
import pytest
|
||||
|
||||
from pve_vm_setup.errors import SettingsError
|
||||
from pve_vm_setup.settings import AppSettings
|
||||
from pve_vm_setup.settings import AppSettings, resolve_dotenv_paths, write_config_dotenv
|
||||
|
||||
|
||||
def test_settings_load_defaults_and_normalize_api_base() -> None:
|
||||
|
|
@ -152,3 +152,37 @@ def test_settings_prefers_environment_over_config_and_current_directory_dotenv(
|
|||
)
|
||||
|
||||
assert settings.proxmox_url == "https://env.example.invalid:8006"
|
||||
|
||||
|
||||
def test_resolve_dotenv_paths_uses_standard_config_location(tmp_path: Path, monkeypatch) -> None:
|
||||
home = tmp_path / "home"
|
||||
monkeypatch.setenv("HOME", str(home))
|
||||
|
||||
paths = resolve_dotenv_paths()
|
||||
|
||||
assert paths.cwd == Path(".env")
|
||||
assert paths.config == home / ".config" / "pve-vm-setup" / ".env"
|
||||
assert paths.any_exists is False
|
||||
|
||||
|
||||
def test_write_config_dotenv_creates_parent_directory_and_skips_blank_values(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
target = tmp_path / "home" / ".config" / "pve-vm-setup" / ".env"
|
||||
|
||||
written_path = write_config_dotenv(
|
||||
{
|
||||
"PROXMOX_URL": "https://pve.example.invalid:8006",
|
||||
"PROXMOX_USER": "root",
|
||||
"PROXMOX_PASSWORD": "",
|
||||
},
|
||||
config_dotenv_path=target,
|
||||
)
|
||||
|
||||
assert written_path == target
|
||||
assert target.exists()
|
||||
assert target.read_text(encoding="utf-8") == (
|
||||
"# Generated by pve-vm-setup\n"
|
||||
"PROXMOX_URL=https://pve.example.invalid:8006\n"
|
||||
"PROXMOX_USER=root\n"
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue