Files
pkgmgr/tests/unit/pkgmgr/installers/os_packages/test_rpm_spec.py
Kevin Veen-Birkenbach 16a9d55d4f Refactor pkgmgr installers, introduce capability-based execution, and replace manifest layer
References:
- Current ChatGPT conversation: https://chatgpt.com/share/6935d6d7-0ae4-800f-988a-44a50c17ba48
- Extended discussion: https://chatgpt.com/share/6935d734-fd84-800f-9755-290902b8cee8

Summary:
This commit performs a major cleanup and modernization of the installation pipeline:

1. Introduced a new capability-detection subsystem:
   - Capabilities (python-runtime, make-install, nix-flake) are detected per installer/layer.
   - Installers run only when they add new capabilities.
   - Prevents duplicated work such as Python installers running when Nix already provides the runtime.

2. Removed deprecated pkgmgr.yml manifest installer:
   - Dependency resolution is now delegated entirely to real package managers (Nix, pip, make, distro build tools).
   - Simplifies layering and avoids unnecessary recursion.

3. Reworked OS-specific installers:
   - Arch PKGBUILD now uses 'makepkg --syncdeps --cleanbuild --install --noconfirm'.
   - Debian installer now builds proper .deb packages via dpkg-buildpackage + installs them.
   - RPM installer now builds packages using rpmbuild and installs them via rpm.

4. Switched from remote GitHub flakes to local-flake execution:
   - Wrapper now executes: nix run /usr/lib/package-manager#pkgmgr
   - Avoids lock-file write attempts and improves reliability in CI.

5. Added bash -i based integration test:
   - Correctly sources ~/.bashrc and evaluates alias + venv activation.
   - ‘pkgmgr --help’ is now printed for debugging without failing tests.

6. Updated unit tests across all installers:
   - Removed references to manifest installer.
   - Adjusted expectations for new behaviors (makepkg, dpkg-buildpackage, rpmbuild).
   - Added capability subsystem tests.

7. Improved flake.nix packaging logic:
   - The entire project source tree is copied into the runtime closure.
   - pkgmgr wrapper now executes runpy inside the packaged directory.

Together, these changes create a predictable, layered, capability-driven installer pipeline with consistent behavior across Arch, Debian, RPM, Nix, and Python layers.
2025-12-07 20:36:39 +01:00

94 lines
2.9 KiB
Python

# tests/unit/pkgmgr/installers/os_packages/test_rpm_spec.py
import unittest
from unittest.mock import patch
from pkgmgr.context import RepoContext
from pkgmgr.installers.os_packages.rpm_spec import RpmSpecInstaller
class TestRpmSpecInstaller(unittest.TestCase):
def setUp(self):
self.repo = {"name": "repo"}
self.ctx = RepoContext(
repo=self.repo,
identifier="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 = RpmSpecInstaller()
@patch("glob.glob", return_value=["/tmp/repo/test.spec"])
@patch("shutil.which")
def test_supports_true(self, mock_which, mock_glob):
def which_side_effect(name):
if name == "rpmbuild":
return "/usr/bin/rpmbuild"
if name == "dnf":
return "/usr/bin/dnf"
return None
mock_which.side_effect = which_side_effect
self.assertTrue(self.installer.supports(self.ctx))
@patch("glob.glob", return_value=[])
@patch("shutil.which")
def test_supports_false_missing_spec(self, mock_which, mock_glob):
mock_which.return_value = "/usr/bin/rpmbuild"
self.assertFalse(self.installer.supports(self.ctx))
@patch("pkgmgr.installers.os_packages.rpm_spec.run_command")
@patch("glob.glob")
@patch("shutil.which")
def test_run_builds_and_installs_rpms(
self,
mock_which,
mock_glob,
mock_run_command,
):
# glob.glob wird zweimal benutzt: einmal für *.spec, einmal für gebaute RPMs
def glob_side_effect(pattern, recursive=False):
if pattern.endswith("*.spec"):
return ["/tmp/repo/package-manager.spec"]
if "rpmbuild/RPMS" in pattern:
return ["/home/user/rpmbuild/RPMS/x86_64/package-manager-0.1.1.rpm"]
return []
mock_glob.side_effect = glob_side_effect
def which_side_effect(name):
if name == "rpmbuild":
return "/usr/bin/rpmbuild"
if name == "dnf":
return "/usr/bin/dnf"
if name == "rpm":
return "/usr/bin/rpm"
return None
mock_which.side_effect = which_side_effect
self.installer.run(self.ctx)
cmds = [c[0][0] for c in mock_run_command.call_args_list]
# 1) builddep
self.assertTrue(any("builddep -y" in cmd for cmd in cmds))
# 2) rpmbuild -ba
self.assertTrue(any(cmd.startswith("rpmbuild -ba ") for cmd in cmds))
# 3) rpm -i …
self.assertTrue(any(cmd.startswith("sudo rpm -i ") for cmd in cmds))
if __name__ == "__main__":
unittest.main()