Files
devx/tests/unit/test_fast_molecule.py
T
emil 11c4a1fc9e
Post-merge / detect-and-configure (push) Failing after 18s
Post-merge / release-and-maintain (push) Skipped
DEVX-155: Replace pr_review with spec-driven CI gates and pr-review skill
2026-08-24 20:39:09 +00:00

83 lines
3.4 KiB
Python

"""Unit tests for devx.ci.fast_molecule."""
from pathlib import Path
from unittest.mock import MagicMock, patch
from click.testing import CliRunner
from devx.ci.fast_molecule import (
build_molecule_commands,
cli,
get_molecule_scenarios,
)
class TestGetMoleculeScenarios:
def test_finds_scenarios(self, tmp_path: Path) -> None:
roles_dir = tmp_path / "ansible" / "roles" / "myrole" / "molecule"
roles_dir.mkdir(parents=True)
(roles_dir / "default").mkdir()
(roles_dir / "default" / "molecule.yml").write_text("name: default")
(roles_dir / "full").mkdir()
(roles_dir / "full" / "molecule.yml").write_text("name: full")
(roles_dir / "no_scenario").mkdir() # No molecule.yml
scenarios = get_molecule_scenarios("myrole", str(tmp_path / "ansible" / "roles"))
assert sorted(scenarios) == ["default", "full"]
def test_returns_empty_when_no_molecule_dir(self, tmp_path: Path) -> None:
scenarios = get_molecule_scenarios("nonexistent", str(tmp_path / "ansible" / "roles"))
assert scenarios == []
class TestBuildMoleculeCommands:
def test_builds_commands_for_roles(self, tmp_path: Path) -> None:
roles_dir = tmp_path / "ansible" / "roles"
for role in ["role_a", "role_b"]:
mol_dir = roles_dir / role / "molecule" / "default"
mol_dir.mkdir(parents=True)
(mol_dir / "molecule.yml").write_text("name: default")
commands = build_molecule_commands({"role_a", "role_b"}, str(roles_dir))
assert len(commands) == 2
assert all("molecule test -s default" in c for c in commands)
assert all("--destroy=never" in c for c in commands)
assert all("ubuntu-2604" in c for c in commands)
def test_empty_when_no_scenarios(self, tmp_path: Path) -> None:
commands = build_molecule_commands({"nonexistent"}, str(tmp_path / "ansible" / "roles"))
assert commands == []
def test_empty_when_no_roles(self) -> None:
assert build_molecule_commands(set()) == []
class TestCli:
@patch("devx.ci.fast_molecule.get_changed_files")
def test_no_changes(self, mock_get: MagicMock) -> None:
mock_get.return_value = []
runner = CliRunner()
result = runner.invoke(cli, ["--base", "origin/master", "--head", "HEAD"])
assert result.exit_code == 0
assert "No files changed" in result.output
@patch("devx.ci.fast_molecule.detect_changed_roles")
@patch("devx.ci.fast_molecule.get_changed_files")
def test_no_ansible_changes(self, mock_get: MagicMock, mock_detect: MagicMock) -> None:
mock_get.return_value = ["src/main.py", "README.md"]
mock_detect.return_value = set()
runner = CliRunner()
result = runner.invoke(cli, ["--base", "origin/master", "--head", "HEAD"])
assert result.exit_code == 0
assert "No Ansible roles changed" in result.output
@patch("devx.ci.fast_molecule.detect_changed_roles")
@patch("devx.ci.fast_molecule.get_changed_files")
def test_detects_changed_roles(self, mock_get: MagicMock, mock_detect: MagicMock) -> None:
mock_get.return_value = ["ansible/roles/sso_bridge/tasks/main.yml"]
mock_detect.return_value = {"sso_bridge"}
runner = CliRunner()
result = runner.invoke(cli, ["--base", "origin/master", "--head", "HEAD"])
assert result.exit_code == 0
assert "sso_bridge" in result.output