From 1ab2921e25f3fc7c26ea75c4107bd04f2504b90c Mon Sep 17 00:00:00 2001 From: Evgeniy Alekseev Date: Mon, 22 Mar 2021 03:47:20 +0300 Subject: [PATCH] alpm tests implementation --- src/ahriman/core/alpm/repo.py | 6 ++- src/ahriman/core/repository/executor.py | 26 +++++++--- tests/ahriman/core/alpm/test_pacman.py | 10 ++++ tests/ahriman/core/alpm/test_repo.py | 65 +++++++++++++++++++++++++ tests/ahriman/core/conftest.py | 27 ++++++++++ tests/conftest.py | 0 tests/testresources/core/ahriman.ini | 46 +++++++++++++++++ tests/testresources/core/logging.ini | 59 ++++++++++++++++++++++ 8 files changed, 229 insertions(+), 10 deletions(-) create mode 100644 tests/ahriman/core/alpm/test_pacman.py create mode 100644 tests/ahriman/core/alpm/test_repo.py create mode 100644 tests/ahriman/core/conftest.py delete mode 100644 tests/conftest.py create mode 100644 tests/testresources/core/ahriman.ini create mode 100644 tests/testresources/core/logging.ini diff --git a/src/ahriman/core/alpm/repo.py b/src/ahriman/core/alpm/repo.py index 87fa2dd8..3839a640 100644 --- a/src/ahriman/core/alpm/repo.py +++ b/src/ahriman/core/alpm/repo.py @@ -68,15 +68,17 @@ class Repo: cwd=self.paths.repository, logger=self.logger) - def remove(self, package: str) -> None: + def remove(self, package: str, filename: str) -> None: """ remove package from repository :param package: package name to remove + :param filename: package filename to remove """ # remove package and signature (if any) from filesystem - for fn in filter(lambda f: f.startswith(package), os.listdir(self.paths.repository)): + for fn in filter(lambda f: f.startswith(filename), os.listdir(self.paths.repository)): full_path = os.path.join(self.paths.repository, fn) os.remove(full_path) + # remove package from registry Repo._check_output( "repo-remove", *self.sign_args, self.repo_path, package, diff --git a/src/ahriman/core/repository/executor.py b/src/ahriman/core/repository/executor.py index e68fe80d..7b6e87cd 100644 --- a/src/ahriman/core/repository/executor.py +++ b/src/ahriman/core/repository/executor.py @@ -73,23 +73,33 @@ class Executor(Cleaner): :param packages: list of package names or bases to rmeove :return: path to repository database """ - def remove_single(package: str) -> None: + def remove_single(package: str, filename: Optional[str]) -> None: + if filename is None: + self.logger.warning(f"could not remove {package} because no filename set") + return try: - self.repo.remove(package) + self.repo.remove(package, filename) except Exception: self.logger.exception(f"could not remove {package}", exc_info=True) requested = set(packages) for local in self.packages(): - if local.base in packages: - to_remove = set(local.packages.keys()) + if local.base in packages or all(package in requested for package in local.packages): + to_remove = { + package: properties.filename + for package, properties in local.packages.items() + } self.reporter.remove(local.base) # we only update status page in case of base removal elif requested.intersection(local.packages.keys()): - to_remove = requested.intersection(local.packages.keys()) + to_remove = { + package: properties.filename + for package, properties in local.packages.items() + if package in requested + } else: - to_remove = set() - for package in to_remove: - remove_single(package) + to_remove = dict() + for package, filename in to_remove.items(): + remove_single(package, filename) return self.repo.repo_path diff --git a/tests/ahriman/core/alpm/test_pacman.py b/tests/ahriman/core/alpm/test_pacman.py new file mode 100644 index 00000000..030fe1a4 --- /dev/null +++ b/tests/ahriman/core/alpm/test_pacman.py @@ -0,0 +1,10 @@ +from ahriman.core.alpm.pacman import Pacman + + +def test_all_packages(pacman: Pacman) -> None: + """ + package list must not be empty + """ + packages = pacman.all_packages() + assert packages + assert "pacman" in packages diff --git a/tests/ahriman/core/alpm/test_repo.py b/tests/ahriman/core/alpm/test_repo.py new file mode 100644 index 00000000..53cce97b --- /dev/null +++ b/tests/ahriman/core/alpm/test_repo.py @@ -0,0 +1,65 @@ +import os +import pytest + +from pytest_mock import MockerFixture +from unittest import mock + +from ahriman.core.alpm.repo import Repo + + +def test_repo_path(repo: Repo) -> None: + """ + name must be something like archive name + """ + assert repo.repo_path.endswith("db.tar.gz") + + +def test_repo_add(repo: Repo, mocker: MockerFixture) -> None: + """ + must call repo-add on package addition + """ + check_output_mock = mocker.patch("ahriman.core.alpm.repo.Repo._check_output") + + repo.add("path") + Repo._check_output.assert_called_once() + assert check_output_mock.call_args[0][0] == "repo-add" + + +def test_repo_remove(repo: Repo, mocker: MockerFixture) -> None: + """ + must call repo-remove on package addition + """ + mocker.patch("os.listdir", return_value=[]) + check_output_mock = mocker.patch("ahriman.core.alpm.repo.Repo._check_output") + + repo.remove("package", "package.pkg.tar.xz") + Repo._check_output.assert_called_once() + assert check_output_mock.call_args[0][0] == "repo-remove" + + +def test_repo_remove_fail_no_file(repo: Repo, mocker: MockerFixture) -> None: + """ + must fail on missing file + """ + mocker.patch("os.listdir", return_value=["package.pkg.tar.xz"]) + mocker.patch("os.remove", side_effect=FileNotFoundError()) + + with pytest.raises(FileNotFoundError): + repo.remove("package", "package.pkg.tar.xz") + + +def test_repo_remove_remove_requested(repo: Repo, mocker: MockerFixture) -> None: + """ + must remove only requested files + """ + packages = ["package.pkg.tar.xz", "package.pkg.tar.xz.sig"] + all_packages = packages + ["valid-package.pkg.tar.xz.sig", "package-valid.pkg.tar.xz.sig"] + + mocker.patch("os.listdir", return_value=all_packages) + remove_mock = mocker.patch("os.remove") + mocker.patch("ahriman.core.alpm.repo.Repo._check_output") + + repo.remove("package", "package.pkg.tar.xz") + removed = [call.call_list()[0][0][0] for call in remove_mock.call_args_list] + to_be_removed = [os.path.join(repo.paths.repository, package) for package in packages] + assert set(removed) == set(to_be_removed) diff --git a/tests/ahriman/core/conftest.py b/tests/ahriman/core/conftest.py new file mode 100644 index 00000000..48a70529 --- /dev/null +++ b/tests/ahriman/core/conftest.py @@ -0,0 +1,27 @@ +from pathlib import Path + +import pytest + +from ahriman.core.alpm.pacman import Pacman +from ahriman.core.alpm.repo import Repo +from ahriman.core.configuration import Configuration +from ahriman.models.repository_paths import RepositoryPaths + + +@pytest.fixture +def configuration(resource_path_root: Path) -> Configuration: + path = resource_path_root / "core" / "ahriman.ini" + return Configuration.from_path(path=str(path), logfile=False) + + +@pytest.fixture +def pacman(configuration: Configuration) -> Pacman: + return Pacman(configuration) + + +@pytest.fixture +def repo(configuration: Configuration) -> Repo: + return Repo( + configuration.get("repository", "name"), + RepositoryPaths(configuration.get("repository", "root"), "x86_64"), + []) diff --git a/tests/conftest.py b/tests/conftest.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/testresources/core/ahriman.ini b/tests/testresources/core/ahriman.ini new file mode 100644 index 00000000..649bb56b --- /dev/null +++ b/tests/testresources/core/ahriman.ini @@ -0,0 +1,46 @@ +[settings] +logging = logging.ini + +[alpm] +aur_url = https://aur.archlinux.org +database = /var/lib/pacman +repositories = core extra community multilib +root = / + +[build] +archbuild_flags = +build_command = extra-x86_64-build +ignore_packages = +makechrootpkg_flags = +makepkg_flags = --skippgpcheck + +[repository] +name = aur-clone +root = /var/lib/ahriman + +[sign] +target = +key = + +[report] +target = + +[html] +path = +homepage = +link_path = +template_path = /usr/share/ahriman/repo-index.jinja2 + +[upload] +target = + +[rsync] +remote = + +[s3] +bucket = + +[web] +host = +port = +templates = /usr/share/ahriman \ No newline at end of file diff --git a/tests/testresources/core/logging.ini b/tests/testresources/core/logging.ini new file mode 100644 index 00000000..42c58d0e --- /dev/null +++ b/tests/testresources/core/logging.ini @@ -0,0 +1,59 @@ +[loggers] +keys = root,builder,build_details,http + +[handlers] +keys = console_handler,build_file_handler,file_handler,http_handler + +[formatters] +keys = generic_format + +[handler_console_handler] +class = StreamHandler +level = DEBUG +formatter = generic_format +args = (sys.stderr,) + +[handler_file_handler] +class = logging.handlers.RotatingFileHandler +level = DEBUG +formatter = generic_format +args = ('/var/log/ahriman/ahriman.log', 'a', 20971520, 20) + +[handler_build_file_handler] +class = logging.handlers.RotatingFileHandler +level = DEBUG +formatter = generic_format +args = ('/var/log/ahriman/build.log', 'a', 20971520, 20) + +[handler_http_handler] +class = logging.handlers.RotatingFileHandler +level = DEBUG +formatter = generic_format +args = ('/var/log/ahriman/http.log', 'a', 20971520, 20) + +[formatter_generic_format] +format = [%(levelname)s %(asctime)s] [%(filename)s:%(lineno)d] [%(funcName)s]: %(message)s +datefmt = + +[logger_root] +level = DEBUG +handlers = file_handler +qualname = root + +[logger_builder] +level = DEBUG +handlers = file_handler +qualname = builder +propagate = 0 + +[logger_build_details] +level = DEBUG +handlers = build_file_handler +qualname = build_details +propagate = 0 + +[logger_http] +level = DEBUG +handlers = http_handler +qualname = http +propagate = 0