Refactor pkgmgr into modular installer pipeline with Nix flake support, PKGBUILD build workflow, local Nix cache, and full test suite restructuring.

See conversation: https://chatgpt.com/share/69332519-7ff4-800f-bc21-7fcd24a66c10
This commit is contained in:
Kevin Veen-Birkenbach
2025-12-05 19:32:42 +01:00
parent 341ec1179e
commit f5475d86e2
35 changed files with 1684 additions and 524 deletions

View File

View File

@@ -1,4 +1,3 @@
# tests/test_integration_install_all_shallow.py
"""
Integration test: install all configured repositories using
--clone-mode shallow (HTTPS shallow clone) and --no-verification.

View File

@@ -1,129 +0,0 @@
# tests/test_install_repos.py
import os
import unittest
from unittest.mock import patch, MagicMock, mock_open
from pkgmgr.install_repos import install_repos
class TestInstallRepos(unittest.TestCase):
def setUp(self):
self.repo = {
"provider": "github.com",
"account": "user",
"repository": "repo",
}
self.selected = [self.repo]
self.base_dir = "/tmp/repos"
self.bin_dir = "/tmp/bin"
self.all_repos = self.selected
@patch("pkgmgr.install_repos.clone_repos")
@patch("pkgmgr.install_repos.os.path.exists")
@patch("pkgmgr.install_repos.get_repo_dir")
@patch("pkgmgr.install_repos.get_repo_identifier")
def test_calls_clone_repos_with_clone_mode(
self,
mock_get_repo_identifier,
mock_get_repo_dir,
mock_exists,
mock_clone_repos,
):
mock_get_repo_identifier.return_value = "github.com/user/repo"
mock_get_repo_dir.return_value = "/tmp/repos/user/repo"
# Repo-Verzeichnis existiert nicht -> soll geklont werden
mock_exists.return_value = False
install_repos(
self.selected,
self.base_dir,
self.bin_dir,
self.all_repos,
no_verification=True,
preview=False,
quiet=True,
clone_mode="shallow",
update_dependencies=False,
)
mock_clone_repos.assert_called_once()
args, kwargs = mock_clone_repos.call_args
# clone_mode ist letztes Argument
self.assertEqual(args[-1], "shallow")
@patch("pkgmgr.install_repos.run_command")
@patch("pkgmgr.install_repos.open", new_callable=mock_open, create=True)
@patch("pkgmgr.install_repos.yaml.safe_load")
@patch("pkgmgr.install_repos.os.path.exists")
@patch("pkgmgr.install_repos.create_ink")
@patch("pkgmgr.install_repos.verify_repository")
@patch("pkgmgr.install_repos.get_repo_dir")
@patch("pkgmgr.install_repos.get_repo_identifier")
def test_pkgmgr_requirements_propagate_clone_mode(
self,
mock_get_repo_identifier,
mock_get_repo_dir,
mock_verify,
mock_create_ink,
mock_exists,
mock_safe_load,
mock_open_file,
mock_run_command,
):
mock_get_repo_identifier.return_value = "github.com/user/repo"
repo_dir = "/tmp/repos/user/repo"
mock_get_repo_dir.return_value = repo_dir
# exists() muss True für repo_dir & requirements.yml liefern,
# sonst werden die Anforderungen nie verarbeitet.
def exists_side_effect(path):
if path == repo_dir:
return True
if path == os.path.join(repo_dir, "requirements.yml"):
return True
# requirements.txt und Makefile sollen "nicht existieren"
return False
mock_exists.side_effect = exists_side_effect
mock_verify.return_value = (True, [], "hash", "key")
# requirements.yml enthält pkgmgr-Dependencies
mock_safe_load.return_value = {
"pkgmgr": ["github.com/other/account/dep"],
}
commands = []
def run_command_side_effect(cmd, cwd=None, preview=False):
commands.append((cmd, cwd, preview))
mock_run_command.side_effect = run_command_side_effect
install_repos(
self.selected,
self.base_dir,
self.bin_dir,
self.all_repos,
no_verification=False,
preview=False,
quiet=True,
clone_mode="shallow",
update_dependencies=False,
)
# Prüfen, dass ein pkgmgr install Befehl mit --clone-mode shallow gebaut wurde
pkgmgr_install_cmds = [
c for (c, cwd, preview) in commands if "pkgmgr install" in c
]
self.assertTrue(
pkgmgr_install_cmds,
f"No pkgmgr install command was executed. Commands seen: {commands}",
)
cmd = pkgmgr_install_cmds[0]
self.assertIn("--clone-mode shallow", cmd)
if __name__ == "__main__":
unittest.main()

View File

@@ -1,19 +0,0 @@
# tests/test_main.py
import unittest
import main
class TestMainModule(unittest.TestCase):
def test_proxy_commands_defined(self):
"""
Basic sanity check: main.py should define PROXY_COMMANDS
with git/docker/docker compose entries.
"""
self.assertTrue(hasattr(main, "PROXY_COMMANDS"))
self.assertIn("git", main.PROXY_COMMANDS)
self.assertIn("docker", main.PROXY_COMMANDS)
self.assertIn("docker compose", main.PROXY_COMMANDS)
if __name__ == "__main__":
unittest.main()

0
tests/unit/__init__.py Normal file
View File

View File

View File

View File

@@ -0,0 +1,71 @@
# tests/unit/pkgmgr/installers/test_ansible_requirements.py
import os
import unittest
from unittest.mock import patch, mock_open
from pkgmgr.context import RepoContext
from pkgmgr.installers.ansible_requirements import AnsibleRequirementsInstaller
class TestAnsibleRequirementsInstaller(unittest.TestCase):
def setUp(self):
self.repo = {"name": "test-repo"}
self.ctx = RepoContext(
repo=self.repo,
identifier="test-id",
repo_dir="/tmp/repo",
repositories_base_dir="/tmp",
bin_dir="/bin",
all_repos=[self.repo],
no_verification=False,
preview=False,
quiet=False,
clone_mode="ssh",
update_dependencies=False,
)
self.installer = AnsibleRequirementsInstaller()
@patch("os.path.exists", return_value=True)
def test_supports_true_when_requirements_exist(self, mock_exists):
self.assertTrue(self.installer.supports(self.ctx))
mock_exists.assert_called_with(os.path.join(self.ctx.repo_dir, "requirements.yml"))
@patch("os.path.exists", return_value=False)
def test_supports_false_when_requirements_missing(self, mock_exists):
self.assertFalse(self.installer.supports(self.ctx))
@patch("pkgmgr.installers.ansible_requirements.run_command")
@patch("tempfile.NamedTemporaryFile")
@patch(
"builtins.open",
new_callable=mock_open,
read_data="""
collections:
- name: community.docker
roles:
- src: geerlingguy.docker
""",
)
@patch("os.path.exists", return_value=True)
def test_run_installs_collections_and_roles(
self, mock_exists, mock_file, mock_tmp, mock_run_command
):
# Fake temp file name
mock_tmp().__enter__().name = "/tmp/req.yml"
self.installer.run(self.ctx)
cmds = [call[0][0] for call in mock_run_command.call_args_list]
self.assertIn(
"ansible-galaxy collection install -r /tmp/req.yml",
cmds,
)
self.assertIn(
"ansible-galaxy role install -r /tmp/req.yml",
cmds,
)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,97 @@
# tests/unit/pkgmgr/installers/test_aur.py
import os
import unittest
from unittest.mock import patch, mock_open
from pkgmgr.context import RepoContext
from pkgmgr.installers.aur import AurInstaller, AUR_CONFIG_FILENAME
class TestAurInstaller(unittest.TestCase):
def setUp(self):
self.repo = {"name": "test-repo"}
self.ctx = RepoContext(
repo=self.repo,
identifier="test-id",
repo_dir="/tmp/repo",
repositories_base_dir="/tmp",
bin_dir="/bin",
all_repos=[self.repo],
no_verification=False,
preview=False,
quiet=False,
clone_mode="ssh",
update_dependencies=False,
)
self.installer = AurInstaller()
@patch("shutil.which", return_value="/usr/bin/pacman")
@patch("os.path.exists", return_value=True)
@patch(
"builtins.open",
new_callable=mock_open,
read_data="""
helper: yay
packages:
- aurutils
- name: some-aur-only-tool
reason: "Test tool"
""",
)
def test_supports_true_when_arch_and_aur_config_present(
self, mock_file, mock_exists, mock_which
):
self.assertTrue(self.installer.supports(self.ctx))
mock_which.assert_called_with("pacman")
mock_exists.assert_called_with(os.path.join(self.ctx.repo_dir, AUR_CONFIG_FILENAME))
@patch("shutil.which", return_value=None)
def test_supports_false_when_not_arch(self, mock_which):
self.assertFalse(self.installer.supports(self.ctx))
@patch("shutil.which", return_value="/usr/bin/pacman")
@patch("os.path.exists", return_value=False)
def test_supports_false_when_no_config(self, mock_exists, mock_which):
self.assertFalse(self.installer.supports(self.ctx))
@patch("shutil.which", side_effect=lambda name: "/usr/bin/pacman" if name == "pacman" else "/usr/bin/yay")
@patch("pkgmgr.installers.aur.run_command")
@patch(
"builtins.open",
new_callable=mock_open,
read_data="""
helper: yay
packages:
- aurutils
- some-aur-only-tool
""",
)
@patch("os.path.exists", return_value=True)
def test_run_installs_packages_with_helper(
self, mock_exists, mock_file, mock_run_command, mock_which
):
self.installer.run(self.ctx)
cmd = mock_run_command.call_args[0][0]
self.assertTrue(cmd.startswith("yay -S --noconfirm "))
self.assertIn("aurutils", cmd)
self.assertIn("some-aur-only-tool", cmd)
@patch("shutil.which", return_value="/usr/bin/pacman")
@patch(
"builtins.open",
new_callable=mock_open,
read_data="packages: []",
)
@patch("os.path.exists", return_value=True)
def test_run_skips_when_no_packages(
self, mock_exists, mock_file, mock_which
):
with patch("pkgmgr.installers.aur.run_command") as mock_run_command:
self.installer.run(self.ctx)
mock_run_command.assert_not_called()
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,43 @@
# tests/unit/pkgmgr/installers/test_base.py
import unittest
from pkgmgr.installers.base import BaseInstaller
from pkgmgr.context import RepoContext
class DummyInstaller(BaseInstaller):
def __init__(self, supports_value: bool = True):
self._supports_value = supports_value
self.ran_with = None
def supports(self, ctx: RepoContext) -> bool:
return self._supports_value
def run(self, ctx: RepoContext) -> None:
self.ran_with = ctx
class TestBaseInstaller(unittest.TestCase):
def test_dummy_installer_supports_and_run(self):
ctx = RepoContext(
repo={},
identifier="id",
repo_dir="/tmp/repo",
repositories_base_dir="/tmp",
bin_dir="/bin",
all_repos=[],
no_verification=False,
preview=False,
quiet=False,
clone_mode="ssh",
update_dependencies=False,
)
inst = DummyInstaller(supports_value=True)
self.assertTrue(inst.supports(ctx))
self.assertIsNone(inst.ran_with)
inst.run(ctx)
self.assertIs(inst.ran_with, ctx)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,51 @@
# tests/unit/pkgmgr/installers/test_makefile_installer.py
import os
import unittest
from unittest.mock import patch
from pkgmgr.context import RepoContext
from pkgmgr.installers.makefile import MakefileInstaller
class TestMakefileInstaller(unittest.TestCase):
def setUp(self):
self.repo = {"name": "test-repo"}
self.ctx = RepoContext(
repo=self.repo,
identifier="test-id",
repo_dir="/tmp/repo",
repositories_base_dir="/tmp",
bin_dir="/bin",
all_repos=[self.repo],
no_verification=False,
preview=False,
quiet=False,
clone_mode="ssh",
update_dependencies=False,
)
self.installer = MakefileInstaller()
@patch("os.path.exists", return_value=True)
def test_supports_true_when_makefile_exists(self, mock_exists):
self.assertTrue(self.installer.supports(self.ctx))
mock_exists.assert_called_with(os.path.join(self.ctx.repo_dir, "Makefile"))
@patch("os.path.exists", return_value=False)
def test_supports_false_when_makefile_missing(self, mock_exists):
self.assertFalse(self.installer.supports(self.ctx))
@patch("pkgmgr.installers.makefile.run_command")
@patch("os.path.exists", return_value=True)
def test_run_executes_make_install(self, mock_exists, mock_run_command):
self.installer.run(self.ctx)
cmd = mock_run_command.call_args[0][0]
self.assertEqual(cmd, "make install")
self.assertEqual(
mock_run_command.call_args[1].get("cwd"),
self.ctx.repo_dir,
)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,64 @@
import os
import unittest
from unittest import mock
from unittest.mock import patch
from pkgmgr.context import RepoContext
from pkgmgr.installers.nix_flake import NixFlakeInstaller
class TestNixFlakeInstaller(unittest.TestCase):
def setUp(self):
self.repo = {"name": "test-repo"}
self.ctx = RepoContext(
repo=self.repo,
identifier="test-id",
repo_dir="/tmp/repo",
repositories_base_dir="/tmp",
bin_dir="/bin",
all_repos=[self.repo],
no_verification=False,
preview=False,
quiet=False,
clone_mode="ssh",
update_dependencies=False,
)
self.installer = NixFlakeInstaller()
@patch("shutil.which", return_value="/usr/bin/nix")
@patch("os.path.exists", return_value=True)
def test_supports_true_when_nix_and_flake_exist(self, mock_exists, mock_which):
self.assertTrue(self.installer.supports(self.ctx))
mock_which.assert_called_with("nix")
mock_exists.assert_called_with(os.path.join(self.ctx.repo_dir, "flake.nix"))
@patch("shutil.which", return_value=None)
@patch("os.path.exists", return_value=True)
def test_supports_false_when_nix_missing(self, mock_exists, mock_which):
self.assertFalse(self.installer.supports(self.ctx))
@patch("os.path.exists", return_value=True)
@patch("shutil.which", return_value="/usr/bin/nix")
@mock.patch("pkgmgr.installers.nix_flake.run_command")
def test_run_tries_pkgmgr_then_default(self, mock_run_command, mock_which, mock_exists):
cmds = []
def side_effect(cmd, cwd=None, preview=False, *args, **kwargs):
cmds.append(cmd)
return None
mock_run_command.side_effect = side_effect
self.installer.run(self.ctx)
self.assertIn(
f"nix profile install {self.ctx.repo_dir}#pkgmgr",
cmds,
)
self.assertIn(
f"nix profile install {self.ctx.repo_dir}#default",
cmds,
)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,65 @@
# tests/unit/pkgmgr/installers/test_pkgbuild.py
import os
import unittest
from unittest.mock import patch
from pkgmgr.context import RepoContext
from pkgmgr.installers.pkgbuild import PkgbuildInstaller
class TestPkgbuildInstaller(unittest.TestCase):
def setUp(self):
self.repo = {"name": "test-repo"}
self.ctx = RepoContext(
repo=self.repo,
identifier="test-id",
repo_dir="/tmp/repo",
repositories_base_dir="/tmp",
bin_dir="/bin",
all_repos=[self.repo],
no_verification=False,
preview=False,
quiet=False,
clone_mode="ssh",
update_dependencies=False,
)
self.installer = PkgbuildInstaller()
@patch("os.path.exists", return_value=True)
@patch("shutil.which", return_value="/usr/bin/pacman")
def test_supports_true_when_pacman_and_pkgbuild_exist(self, mock_which, mock_exists):
self.assertTrue(self.installer.supports(self.ctx))
mock_which.assert_called_with("pacman")
mock_exists.assert_called_with(os.path.join(self.ctx.repo_dir, "PKGBUILD"))
@patch("os.path.exists", return_value=False)
@patch("shutil.which", return_value="/usr/bin/pacman")
def test_supports_false_when_pkgbuild_missing(self, mock_which, mock_exists):
self.assertFalse(self.installer.supports(self.ctx))
@patch("pkgmgr.installers.pkgbuild.run_command")
@patch("subprocess.check_output", return_value="python\ngit\n")
@patch("os.path.exists", return_value=True)
@patch("shutil.which", return_value="/usr/bin/pacman")
def test_run_installs_all_packages_and_uses_clean_bash(
self, mock_which, mock_exists, mock_check_output, mock_run_command
):
self.installer.run(self.ctx)
# Check subprocess.check_output arguments (clean shell)
args, kwargs = mock_check_output.call_args
cmd_list = args[0]
self.assertEqual(cmd_list[0], "bash")
self.assertIn("--noprofile", cmd_list)
self.assertIn("--norc", cmd_list)
# Check that pacman is called with the extracted packages
cmd = mock_run_command.call_args[0][0]
self.assertTrue(cmd.startswith("sudo pacman -S --noconfirm "))
self.assertIn("python", cmd)
self.assertIn("git", cmd)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,87 @@
# tests/unit/pkgmgr/installers/test_pkgmgr_manifest.py
import os
import unittest
from unittest.mock import patch, mock_open
from pkgmgr.context import RepoContext
from pkgmgr.installers.pkgmgr_manifest import PkgmgrManifestInstaller
class TestPkgmgrManifestInstaller(unittest.TestCase):
def setUp(self):
self.repo = {"name": "test-repo"}
self.ctx = RepoContext(
repo=self.repo,
identifier="test-id",
repo_dir="/tmp/repo",
repositories_base_dir="/tmp",
bin_dir="/bin",
all_repos=[self.repo],
no_verification=False,
preview=False,
quiet=False,
clone_mode="ssh",
update_dependencies=True,
)
self.installer = PkgmgrManifestInstaller()
@patch("os.path.exists", return_value=True)
def test_supports_true_when_manifest_exists(self, mock_exists):
self.assertTrue(self.installer.supports(self.ctx))
manifest_path = os.path.join(self.ctx.repo_dir, "pkgmgr.yml")
mock_exists.assert_called_with(manifest_path)
@patch("os.path.exists", return_value=False)
def test_supports_false_when_manifest_missing(self, mock_exists):
self.assertFalse(self.installer.supports(self.ctx))
@patch("pkgmgr.installers.pkgmgr_manifest.run_command")
@patch("builtins.open", new_callable=mock_open, read_data="""
version: 1
author: "Kevin"
url: "https://example.com"
description: "Test repo"
dependencies:
- repository: github:user/repo1
version: main
reason: "Core dependency"
- repository: github:user/repo2
""")
@patch("os.path.exists", return_value=True)
def test_run_installs_dependencies_and_pulls_when_update_enabled(
self, mock_exists, mock_file, mock_run_command
):
self.installer.run(self.ctx)
# First call: pkgmgr pull github:user/repo1 github:user/repo2
# Then calls to pkgmgr install ...
cmds = [call_args[0][0] for call_args in mock_run_command.call_args_list]
self.assertIn(
"pkgmgr pull github:user/repo1 github:user/repo2",
cmds,
)
self.assertIn(
"pkgmgr install github:user/repo1 --version main --dependencies --clone-mode ssh",
cmds,
)
# For repo2: no version but dependencies + clone_mode
self.assertIn(
"pkgmgr install github:user/repo2 --dependencies --clone-mode ssh",
cmds,
)
@patch("pkgmgr.installers.pkgmgr_manifest.run_command")
@patch("builtins.open", new_callable=mock_open, read_data="{}")
@patch("os.path.exists", return_value=True)
def test_run_no_dependencies_no_command_called(
self, mock_exists, mock_file, mock_run_command
):
self.ctx.update_dependencies = True
self.installer.run(self.ctx)
mock_run_command.assert_not_called()
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,71 @@
# tests/unit/pkgmgr/installers/test_python_installer.py
import os
import unittest
from unittest.mock import patch
from pkgmgr.context import RepoContext
from pkgmgr.installers.python import PythonInstaller
class TestPythonInstaller(unittest.TestCase):
def setUp(self):
self.repo = {"name": "test-repo"}
self.ctx = RepoContext(
repo=self.repo,
identifier="test-id",
repo_dir="/tmp/repo",
repositories_base_dir="/tmp",
bin_dir="/bin",
all_repos=[self.repo],
no_verification=False,
preview=False,
quiet=False,
clone_mode="ssh",
update_dependencies=False,
)
self.installer = PythonInstaller()
@patch("os.path.exists", side_effect=lambda path: path.endswith("pyproject.toml"))
def test_supports_true_when_pyproject_exists(self, mock_exists):
self.assertTrue(self.installer.supports(self.ctx))
@patch("os.path.exists", side_effect=lambda path: path.endswith("requirements.txt"))
def test_supports_true_when_requirements_exists(self, mock_exists):
self.assertTrue(self.installer.supports(self.ctx))
@patch("os.path.exists", return_value=False)
def test_supports_false_when_no_python_files(self, mock_exists):
self.assertFalse(self.installer.supports(self.ctx))
@patch("pkgmgr.installers.python.run_command")
@patch(
"os.path.exists",
side_effect=lambda path: path.endswith("pyproject.toml")
)
def test_run_installs_project_from_pyproject(self, mock_exists, mock_run_command):
self.installer.run(self.ctx)
cmd = mock_run_command.call_args[0][0]
self.assertIn("pip install .", cmd)
self.assertEqual(
mock_run_command.call_args[1].get("cwd"),
self.ctx.repo_dir,
)
@patch("pkgmgr.installers.python.run_command")
@patch(
"os.path.exists",
side_effect=lambda path: path.endswith("requirements.txt")
)
def test_run_installs_dependencies_from_requirements(self, mock_exists, mock_run_command):
self.installer.run(self.ctx)
cmd = mock_run_command.call_args[0][0]
self.assertIn("pip install -r requirements.txt", cmd)
self.assertEqual(
mock_run_command.call_args[1].get("cwd"),
self.ctx.repo_dir,
)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,36 @@
import unittest
from pkgmgr.context import RepoContext
class TestRepoContext(unittest.TestCase):
def test_repo_context_fields_are_stored(self):
repo = {"name": "test-repo"}
ctx = RepoContext(
repo=repo,
identifier="test-id",
repo_dir="/tmp/test",
repositories_base_dir="/tmp",
bin_dir="/usr/local/bin",
all_repos=[repo],
no_verification=True,
preview=False,
quiet=True,
clone_mode="ssh",
update_dependencies=True,
)
self.assertEqual(ctx.repo, repo)
self.assertEqual(ctx.identifier, "test-id")
self.assertEqual(ctx.repo_dir, "/tmp/test")
self.assertEqual(ctx.repositories_base_dir, "/tmp")
self.assertEqual(ctx.bin_dir, "/usr/local/bin")
self.assertEqual(ctx.all_repos, [repo])
self.assertTrue(ctx.no_verification)
self.assertFalse(ctx.preview)
self.assertTrue(ctx.quiet)
self.assertEqual(ctx.clone_mode, "ssh")
self.assertTrue(ctx.update_dependencies)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,122 @@
from pkgmgr.run_command import run_command
import unittest
from unittest.mock import patch, MagicMock
from pkgmgr.context import RepoContext
import pkgmgr.install_repos as install_module
class DummyInstaller:
"""Simple installer for testing orchestration."""
def __init__(self):
self.calls = []
def supports(self, ctx: RepoContext) -> bool:
# Always support to verify that the pipeline runs
return True
def run(self, ctx: RepoContext) -> None:
self.calls.append(ctx.identifier)
class TestInstallReposOrchestration(unittest.TestCase):
@patch("pkgmgr.install_repos.create_ink")
@patch("pkgmgr.install_repos.verify_repository")
@patch("pkgmgr.install_repos.get_repo_dir")
@patch("pkgmgr.install_repos.get_repo_identifier")
@patch("pkgmgr.install_repos.clone_repos")
def test_install_repos_runs_pipeline_for_each_repo(
self,
mock_clone_repos,
mock_get_repo_identifier,
mock_get_repo_dir,
mock_verify_repository,
mock_create_ink,
):
repo1 = {"name": "repo1"}
repo2 = {"name": "repo2"}
selected_repos = [repo1, repo2]
all_repos = selected_repos
# Return identifiers and directories
mock_get_repo_identifier.side_effect = ["id1", "id2"]
mock_get_repo_dir.side_effect = ["/tmp/repo1", "/tmp/repo2"]
# Simulate verification success: (ok, errors, commit, key)
mock_verify_repository.return_value = (True, [], "commit", "key")
# Ensure directories exist (no cloning)
with patch("os.path.exists", return_value=True):
dummy_installer = DummyInstaller()
# Monkeypatch INSTALLERS for this test
old_installers = install_module.INSTALLERS
install_module.INSTALLERS = [dummy_installer]
try:
install_module.install_repos(
selected_repos=selected_repos,
repositories_base_dir="/tmp",
bin_dir="/bin",
all_repos=all_repos,
no_verification=False,
preview=False,
quiet=False,
clone_mode="ssh",
update_dependencies=False,
)
finally:
install_module.INSTALLERS = old_installers
# Check that installers ran with both identifiers
self.assertEqual(dummy_installer.calls, ["id1", "id2"])
self.assertEqual(mock_create_ink.call_count, 2)
self.assertEqual(mock_verify_repository.call_count, 2)
@patch("pkgmgr.install_repos.verify_repository")
@patch("pkgmgr.install_repos.get_repo_dir")
@patch("pkgmgr.install_repos.get_repo_identifier")
@patch("pkgmgr.install_repos.clone_repos")
def test_install_repos_skips_on_failed_verification(
self,
mock_clone_repos,
mock_get_repo_identifier,
mock_get_repo_dir,
mock_verify_repository,
):
repo = {"name": "repo1", "verified": True}
selected_repos = [repo]
all_repos = selected_repos
mock_get_repo_identifier.return_value = "id1"
mock_get_repo_dir.return_value = "/tmp/repo1"
# Verification fails: ok=False, with error list
mock_verify_repository.return_value = (False, ["sig error"], None, None)
dummy_installer = DummyInstaller()
with patch("os.path.exists", return_value=True), \
patch("pkgmgr.install_repos.create_ink") as mock_create_ink, \
patch("builtins.input", return_value="n"):
old_installers = install_module.INSTALLERS
install_module.INSTALLERS = [dummy_installer]
try:
install_module.install_repos(
selected_repos=selected_repos,
repositories_base_dir="/tmp",
bin_dir="/bin",
all_repos=all_repos,
no_verification=False,
preview=False,
quiet=False,
clone_mode="ssh",
update_dependencies=False,
)
finally:
install_module.INSTALLERS = old_installers
# No installer run and no create_ink when user declines
self.assertEqual(dummy_installer.calls, [])
mock_create_ink.assert_not_called()
if __name__ == "__main__":
unittest.main()