111 lines
4.0 KiB
Python
111 lines
4.0 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
|
|
def run_cli(tmp_path: Path, *args: str) -> subprocess.CompletedProcess[str]:
|
|
env = os.environ.copy()
|
|
for key in tuple(env):
|
|
if key.startswith("NEXUS_"):
|
|
env.pop(key)
|
|
env["NEXUS_HOME"] = str(tmp_path / "state")
|
|
env["NEXUS_CONFIG_DIR"] = str(tmp_path / "config")
|
|
return subprocess.run(
|
|
[sys.executable, "-m", "management.cli", *args],
|
|
cwd=ROOT,
|
|
env=env,
|
|
text=True,
|
|
capture_output=True,
|
|
timeout=30,
|
|
check=False,
|
|
)
|
|
|
|
|
|
def test_help_exposes_portable_command_tree(tmp_path):
|
|
result = run_cli(tmp_path, "--help")
|
|
assert result.returncode == 0, result.stderr
|
|
for command in ("init", "config", "provider", "doctor", "serve", "models", "chat"):
|
|
assert command in result.stdout
|
|
|
|
|
|
def test_legacy_cli_spellings_remain_compatible():
|
|
from management.cli import _normalize_legacy_argv
|
|
|
|
assert _normalize_legacy_argv(["start", "-b"]) == ["start", "backend"]
|
|
assert _normalize_legacy_argv(["stop", "--ai"]) == ["stop", "ai"]
|
|
assert _normalize_legacy_argv(["logs", "-m", "--follow"]) == ["logs", "memory", "--follow"]
|
|
assert _normalize_legacy_argv(["backup", "full"]) == ["backup", "--full"]
|
|
assert _normalize_legacy_argv(["restore", "-f"]) == ["restore"]
|
|
assert _normalize_legacy_argv(["help"]) == ["--help"]
|
|
|
|
|
|
def test_init_uses_external_state_and_seeds_playbooks(tmp_path):
|
|
result = run_cli(tmp_path, "init", "--json")
|
|
assert result.returncode == 0, result.stderr
|
|
payload = json.loads(result.stdout)
|
|
assert Path(payload["state_dir"]) == (tmp_path / "state").resolve()
|
|
assert payload["seeded_playbooks"] == len(list((ROOT / "data" / "playbooks").glob("*.yaml")))
|
|
assert len(list((tmp_path / "state" / "data" / "playbooks").glob("*.yaml"))) > 0
|
|
|
|
|
|
def test_config_persists_validated_values(tmp_path):
|
|
set_result = run_cli(tmp_path, "config", "set", "backend_port", "8123", "--json")
|
|
assert set_result.returncode == 0, set_result.stderr
|
|
|
|
get_result = run_cli(tmp_path, "config", "get", "backend_port", "--json")
|
|
assert get_result.returncode == 0, get_result.stderr
|
|
assert json.loads(get_result.stdout)["backend_port"] == 8123
|
|
|
|
invalid = run_cli(tmp_path, "config", "set", "backend_port", "70000")
|
|
assert invalid.returncode == 2
|
|
assert "between 1 and 65535" in invalid.stderr
|
|
|
|
|
|
def test_remote_provider_configuration_is_explicit(tmp_path):
|
|
result = run_cli(
|
|
tmp_path, "provider", "use", "remote", "--url", "http://phone-lan:11434", "--json"
|
|
)
|
|
assert result.returncode == 0, result.stderr
|
|
payload = json.loads(result.stdout)
|
|
assert payload["provider"] == "ollama-remote"
|
|
assert payload["url"] == "http://phone-lan:11434"
|
|
|
|
values = json.loads((tmp_path / "config" / "config.json").read_text(encoding="utf-8"))
|
|
assert values["provider"] == "ollama-remote"
|
|
|
|
show = run_cli(tmp_path, "provider", "show", "--json")
|
|
assert show.returncode == 0, show.stderr
|
|
assert json.loads(show.stdout)["url"] == "http://phone-lan:11434"
|
|
|
|
|
|
def test_serve_rejects_invalid_ports_before_startup(tmp_path):
|
|
result = run_cli(tmp_path, "serve", "--port", "0")
|
|
assert result.returncode == 2
|
|
assert "between 1 and 65535" in result.stderr
|
|
|
|
|
|
def test_remote_provider_is_never_stopped_or_force_killed(monkeypatch):
|
|
from management import ncp
|
|
|
|
killed_ports = []
|
|
killed_patterns = []
|
|
monkeypatch.setattr(ncp.settings, "manage_ollama", False)
|
|
monkeypatch.setattr(ncp.settings, "ollama_host", "http://remote.test:11434")
|
|
monkeypatch.setattr(ncp, "kill_port", lambda port: killed_ports.append(port) or False)
|
|
monkeypatch.setattr(
|
|
ncp, "kill_matching", lambda patterns, force=False: killed_patterns.extend(patterns) or 0
|
|
)
|
|
|
|
ncp.stop_ollama()
|
|
ncp.cmd_kill()
|
|
|
|
assert 11434 not in killed_ports
|
|
assert "ollama serve" not in killed_patterns
|