Files
triggershell/tests/test_bootstrap.py
T

110 lines
3.3 KiB
Python
Raw Normal View History

2026-08-15 18:37:30 +02:00
from pathlib import Path
from unittest.mock import patch
import pytest
from triggershell.bootstrap import (
BootstrapError,
check_node,
ensure_dependencies_installed,
needs_build,
record_build_stamp,
)
def _completed(stdout: str = "", returncode: int = 0):
class Result:
pass
result = Result()
result.stdout = stdout
result.returncode = returncode
return result
def test_check_node_missing_raises() -> None:
with patch("triggershell.bootstrap.shutil.which", return_value=None):
with pytest.raises(BootstrapError, match="not found"):
check_node()
def test_check_node_too_old_raises() -> None:
with patch("triggershell.bootstrap.shutil.which", return_value="/usr/bin/node"):
with patch("triggershell.bootstrap.subprocess.run", return_value=_completed("v18.0.0\n")):
with pytest.raises(BootstrapError, match="18"):
check_node()
def test_check_node_ok() -> None:
with patch("triggershell.bootstrap.shutil.which", return_value="/usr/bin/node"):
with patch("triggershell.bootstrap.subprocess.run", return_value=_completed("v20.11.0\n")):
assert check_node() == "20.11.0"
def test_ensure_dependencies_installed_skips_when_stamp_matches(tmp_path: Path) -> None:
app_dir = tmp_path / "app"
app_dir.mkdir()
lockfile = app_dir / "pnpm-lock.yaml"
lockfile.write_text("lockfile contents")
node_modules = app_dir / "node_modules"
node_modules.mkdir()
import hashlib
stamp = node_modules / ".triggershell-install-stamp"
stamp.write_text(hashlib.sha256(lockfile.read_bytes()).hexdigest())
with patch("triggershell.bootstrap.subprocess.run") as run:
ensure_dependencies_installed(app_dir)
run.assert_not_called()
def test_ensure_dependencies_installed_runs_when_stale(tmp_path: Path) -> None:
app_dir = tmp_path / "app"
app_dir.mkdir()
(app_dir / "pnpm-lock.yaml").write_text("v1")
with patch("triggershell.bootstrap.subprocess.run", return_value=_completed(returncode=0)) as run:
ensure_dependencies_installed(app_dir)
run.assert_called_once()
def test_needs_build_true_when_no_stamp(tmp_path: Path) -> None:
app_dir = tmp_path / "app"
(app_dir / "src").mkdir(parents=True)
config_path = tmp_path / "triggershell.config.yaml"
config_path.write_text("scripts: []")
assert needs_build(app_dir, config_path) is True
def test_needs_build_false_after_stamp_recorded(tmp_path: Path) -> None:
app_dir = tmp_path / "app"
(app_dir / "src").mkdir(parents=True)
config_path = tmp_path / "triggershell.config.yaml"
config_path.write_text("scripts: []")
record_build_stamp(app_dir, config_path)
assert needs_build(app_dir, config_path) is False
def test_needs_build_true_after_config_touched(tmp_path: Path) -> None:
import os
import time
app_dir = tmp_path / "app"
(app_dir / "src").mkdir(parents=True)
config_path = tmp_path / "triggershell.config.yaml"
config_path.write_text("scripts: []")
record_build_stamp(app_dir, config_path)
assert needs_build(app_dir, config_path) is False
time.sleep(0.01)
config_path.write_text("scripts: []\n# touched")
future = time.time() + 5
os.utime(config_path, (future, future))
assert needs_build(app_dir, config_path) is True