Files
flow/tests/test_service_bootstrap.py

141 lines
4.7 KiB
Python

"""Tests for BootstrapService."""
import pytest
from flow.core.config import AppConfig, FlowContext
from flow.core.console import Console
from flow.core.errors import FlowError
from flow.core.platform import PlatformInfo
from flow.core.runtime import SystemRuntime
from flow.app.bootstrap import BootstrapService
def _make_ctx(manifest=None):
return FlowContext(
config=AppConfig(),
manifest=manifest or {},
platform=PlatformInfo(),
console=Console(color=False),
runtime=SystemRuntime(),
)
class TestBootstrapService:
def test_show_profile(self, capsys):
manifest = {
"profiles": {
"work": {
"os": "linux",
"hostname": "dev",
"packages": ["fd"],
},
},
"packages": [{"name": "fd", "type": "pkg"}],
}
ctx = _make_ctx(manifest)
svc = BootstrapService(ctx)
svc.show("work")
output = capsys.readouterr().out
assert "work" in output
def test_unknown_profile_raises(self):
ctx = _make_ctx({"profiles": {}})
svc = BootstrapService(ctx)
with pytest.raises(FlowError, match="Unknown profile"):
svc.run("missing")
def test_list_profiles(self, capsys):
manifest = {
"profiles": {
"work": {"os": "linux", "hostname": "dev"},
"personal": {"os": "linux"},
},
}
ctx = _make_ctx(manifest)
svc = BootstrapService(ctx)
svc.list_profiles()
output = capsys.readouterr().out
assert "work" in output
assert "personal" in output
def test_list_profiles_empty(self, capsys):
ctx = _make_ctx({})
svc = BootstrapService(ctx)
svc.list_profiles()
assert "No profiles" in capsys.readouterr().out
def test_run_preserves_profile_package_overrides(self, monkeypatch):
captured = {}
class StubPackageService:
def __init__(self, ctx):
pass
def install(self, packages, *, dry_run=False):
captured["packages"] = packages
monkeypatch.setattr("flow.app.packages.PackageService", StubPackageService)
monkeypatch.setattr("flow.app.dotfiles.DotfilesService.link", lambda self, profile=None: None)
manifest = {
"profiles": {
"linux-auto": {
"os": "linux",
"packages": [{
"name": "docker",
"post-install": "sudo groupadd docker || true",
}],
},
},
"packages": [{"name": "docker", "type": "pkg", "sources": {"apt": "docker-ce"}}],
}
ctx = _make_ctx(manifest)
BootstrapService(ctx).run("linux-auto")
assert captured["packages"][0].post_install == "sudo groupadd docker || true"
def test_unknown_phase_raises(self):
from flow.domain.bootstrap.models import BootstrapAction, BootstrapPlan
manifest = {"profiles": {"work": {"os": "linux"}}}
ctx = _make_ctx(manifest)
svc = BootstrapService(ctx)
# Forge an action with a phase the dispatcher doesn't handle.
# The trailing raise in _execute_action is the single source of
# truth for unhandled phases — adding a phase to VALID_PHASES
# without a handler should surface here.
action = BootstrapAction.__new__(BootstrapAction)
object.__setattr__(action, "phase", "no-such-phase")
object.__setattr__(action, "description", "")
object.__setattr__(action, "commands", ())
object.__setattr__(action, "needs_sudo", False)
plan = BootstrapPlan(profile="work", actions=(), packages_to_install=())
with pytest.raises(FlowError, match="Unhandled bootstrap phase"):
svc._execute_action(action, plan, "work")
def test_run_uses_dotfiles_profile_override(self, monkeypatch):
captured = {}
monkeypatch.setattr("flow.app.packages.PackageService.install", lambda self, packages, dry_run=False: None)
class StubDotfilesService:
def __init__(self, ctx):
pass
def link(self, profile=None):
captured["profile"] = profile
monkeypatch.setattr("flow.app.dotfiles.DotfilesService", StubDotfilesService)
manifest = {
"profiles": {
"linux-auto": {
"os": "linux",
"dotfiles-profile": "linux-work",
},
},
}
ctx = _make_ctx(manifest)
BootstrapService(ctx).run("linux-auto")
assert captured["profile"] == "linux-work"