From 3b93510aad6e37828bf0322c5d85cca0f94bae18 Mon Sep 17 00:00:00 2001 From: Evgeniy Alekseev Date: Tue, 30 Mar 2021 01:42:01 +0300 Subject: [PATCH] add more tests --- src/ahriman/application/handlers/dump.py | 8 +- src/ahriman/core/repository/executor.py | 4 +- src/ahriman/core/upload/rsync.py | 6 +- src/ahriman/core/upload/s3.py | 6 +- .../core/upload/{uploader.py => upload.py} | 12 +-- src/ahriman/models/package.py | 2 +- ...e_desciption.py => package_description.py} | 0 .../application/handlers/test_handler_dump.py | 5 +- tests/ahriman/conftest.py | 2 +- tests/ahriman/core/report/test_html.py | 16 +++ tests/ahriman/core/report/test_report.py | 27 ++++++ tests/ahriman/core/upload/test_rsync.py | 16 +++ tests/ahriman/core/upload/test_s3.py | 16 +++ tests/ahriman/core/upload/test_uploader.py | 36 +++++++ tests/ahriman/models/conftest.py | 34 ++++++- tests/ahriman/models/test_package.py | 97 ++++++++++++++++++- .../ahriman/models/test_package_desciption.py | 14 ++- .../models/package_ahriman_srcinfo | 34 +++++++ 18 files changed, 311 insertions(+), 24 deletions(-) rename src/ahriman/core/upload/{uploader.py => upload.py} (88%) rename src/ahriman/models/{package_desciption.py => package_description.py} (100%) create mode 100644 tests/testresources/models/package_ahriman_srcinfo diff --git a/src/ahriman/application/handlers/dump.py b/src/ahriman/application/handlers/dump.py index 5791158d..3b17daca 100644 --- a/src/ahriman/application/handlers/dump.py +++ b/src/ahriman/application/handlers/dump.py @@ -30,6 +30,8 @@ class Dump(Handler): dump config handler """ + _print = print + @classmethod def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, config: Configuration) -> None: """ @@ -40,7 +42,7 @@ class Dump(Handler): """ config_dump = config.dump(architecture) for section, values in sorted(config_dump.items()): - print(f"[{section}]") + Dump._print(f"[{section}]") for key, value in sorted(values.items()): - print(f"{key} = {value}") - print() + Dump._print(f"{key} = {value}") + Dump._print() diff --git a/src/ahriman/core/repository/executor.py b/src/ahriman/core/repository/executor.py index 10c17d14..3f3d4a89 100644 --- a/src/ahriman/core/repository/executor.py +++ b/src/ahriman/core/repository/executor.py @@ -25,7 +25,7 @@ from typing import Dict, Iterable, List, Optional from ahriman.core.build_tools.task import Task from ahriman.core.report.report import Report from ahriman.core.repository.cleaner import Cleaner -from ahriman.core.upload.uploader import Uploader +from ahriman.core.upload.upload import Upload from ahriman.models.package import Package @@ -118,7 +118,7 @@ class Executor(Cleaner): if targets is None: targets = self.config.getlist("upload", "target") for target in targets: - Uploader.run(self.architecture, self.config, target, self.paths.repository) + Upload.run(self.architecture, self.config, target, self.paths.repository) def process_update(self, packages: Iterable[Path]) -> Path: """ diff --git a/src/ahriman/core/upload/rsync.py b/src/ahriman/core/upload/rsync.py index 65434765..93eeafaf 100644 --- a/src/ahriman/core/upload/rsync.py +++ b/src/ahriman/core/upload/rsync.py @@ -20,11 +20,11 @@ from pathlib import Path from ahriman.core.configuration import Configuration -from ahriman.core.upload.uploader import Uploader +from ahriman.core.upload.upload import Upload from ahriman.core.util import check_output -class Rsync(Uploader): +class Rsync(Upload): """ rsync wrapper :ivar remote: remote address to sync @@ -38,7 +38,7 @@ class Rsync(Uploader): :param architecture: repository architecture :param config: configuration instance """ - Uploader.__init__(self, architecture, config) + Upload.__init__(self, architecture, config) section = config.get_section_name("rsync", architecture) self.remote = config.get(section, "remote") diff --git a/src/ahriman/core/upload/s3.py b/src/ahriman/core/upload/s3.py index f483d952..392cf421 100644 --- a/src/ahriman/core/upload/s3.py +++ b/src/ahriman/core/upload/s3.py @@ -20,11 +20,11 @@ from pathlib import Path from ahriman.core.configuration import Configuration -from ahriman.core.upload.uploader import Uploader +from ahriman.core.upload.upload import Upload from ahriman.core.util import check_output -class S3(Uploader): +class S3(Upload): """ aws-cli wrapper :ivar bucket: full bucket name @@ -38,7 +38,7 @@ class S3(Uploader): :param architecture: repository architecture :param config: configuration instance """ - Uploader.__init__(self, architecture, config) + Upload.__init__(self, architecture, config) section = config.get_section_name("s3", architecture) self.bucket = config.get(section, "bucket") diff --git a/src/ahriman/core/upload/uploader.py b/src/ahriman/core/upload/upload.py similarity index 88% rename from src/ahriman/core/upload/uploader.py rename to src/ahriman/core/upload/upload.py index d9266143..18bbc26c 100644 --- a/src/ahriman/core/upload/uploader.py +++ b/src/ahriman/core/upload/upload.py @@ -26,7 +26,7 @@ from ahriman.core.exceptions import SyncFailed from ahriman.models.upload_settings import UploadSettings -class Uploader: +class Upload: """ base remote sync class :ivar architecture: repository architecture @@ -56,17 +56,17 @@ class Uploader: provider = UploadSettings.from_option(target) if provider == UploadSettings.Rsync: from ahriman.core.upload.rsync import Rsync - uploader: Uploader = Rsync(architecture, config) + upload: Upload = Rsync(architecture, config) elif provider == UploadSettings.S3: from ahriman.core.upload.s3 import S3 - uploader = S3(architecture, config) + upload = S3(architecture, config) else: - uploader = Uploader(architecture, config) + upload = Upload(architecture, config) try: - uploader.sync(path) + upload.sync(path) except Exception: - uploader.logger.exception(f"remote sync failed for {provider.name}") + upload.logger.exception(f"remote sync failed for {provider.name}") raise SyncFailed() def sync(self, path: Path) -> None: diff --git a/src/ahriman/models/package.py b/src/ahriman/models/package.py index 3692dd55..d2a05fbd 100644 --- a/src/ahriman/models/package.py +++ b/src/ahriman/models/package.py @@ -31,7 +31,7 @@ from typing import Any, Dict, List, Optional, Set, Type, Union from ahriman.core.alpm.pacman import Pacman from ahriman.core.exceptions import InvalidPackageInfo from ahriman.core.util import check_output -from ahriman.models.package_desciption import PackageDescription +from ahriman.models.package_description import PackageDescription from ahriman.models.repository_paths import RepositoryPaths diff --git a/src/ahriman/models/package_desciption.py b/src/ahriman/models/package_description.py similarity index 100% rename from src/ahriman/models/package_desciption.py rename to src/ahriman/models/package_description.py diff --git a/tests/ahriman/application/handlers/test_handler_dump.py b/tests/ahriman/application/handlers/test_handler_dump.py index c2ae9434..6e113efc 100644 --- a/tests/ahriman/application/handlers/test_handler_dump.py +++ b/tests/ahriman/application/handlers/test_handler_dump.py @@ -11,7 +11,10 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc must run command """ mocker.patch("pathlib.Path.mkdir") - application_mock = mocker.patch("ahriman.core.configuration.Configuration.dump") + print_mock = mocker.patch("ahriman.application.handlers.dump.Dump._print") + application_mock = mocker.patch("ahriman.core.configuration.Configuration.dump", + return_value=configuration.dump("x86_64")) Dump.run(args, "x86_64", configuration) application_mock.assert_called_once() + print_mock.assert_called() diff --git a/tests/ahriman/conftest.py b/tests/ahriman/conftest.py index cd99799b..3a301906 100644 --- a/tests/ahriman/conftest.py +++ b/tests/ahriman/conftest.py @@ -7,7 +7,7 @@ from typing import Any, Type, TypeVar from ahriman.core.configuration import Configuration from ahriman.core.status.watcher import Watcher from ahriman.models.package import Package -from ahriman.models.package_desciption import PackageDescription +from ahriman.models.package_description import PackageDescription from ahriman.models.repository_paths import RepositoryPaths T = TypeVar("T") diff --git a/tests/ahriman/core/report/test_html.py b/tests/ahriman/core/report/test_html.py index e69de29b..075ea1ca 100644 --- a/tests/ahriman/core/report/test_html.py +++ b/tests/ahriman/core/report/test_html.py @@ -0,0 +1,16 @@ +from pytest_mock import MockerFixture + +from ahriman.core.configuration import Configuration +from ahriman.core.report.html import HTML +from ahriman.models.package import Package + + +def test_generate(configuration: Configuration, package_ahriman: Package, mocker: MockerFixture) -> None: + """ + must generate report + """ + write_mock = mocker.patch("pathlib.Path.write_text") + + report = HTML("x86_64", configuration) + report.generate([package_ahriman]) + write_mock.assert_called_once() diff --git a/tests/ahriman/core/report/test_report.py b/tests/ahriman/core/report/test_report.py index e69de29b..c53bf649 100644 --- a/tests/ahriman/core/report/test_report.py +++ b/tests/ahriman/core/report/test_report.py @@ -0,0 +1,27 @@ +import pytest + +from pathlib import Path +from pytest_mock import MockerFixture + +from ahriman.core.configuration import Configuration +from ahriman.core.exceptions import ReportFailed +from ahriman.core.report.report import Report +from ahriman.models.report_settings import ReportSettings + + +def test_report_failure(configuration: Configuration, mocker: MockerFixture) -> None: + """ + must raise ReportFailed on errors + """ + mocker.patch("ahriman.core.report.html.HTML.generate", side_effect=Exception()) + with pytest.raises(ReportFailed): + Report.run("x86_64", configuration, ReportSettings.HTML.name, Path("path")) + + +def test_report_html(configuration: Configuration, mocker: MockerFixture) -> None: + """ + must generate html report + """ + report_mock = mocker.patch("ahriman.core.report.html.HTML.generate") + Report.run("x86_64", configuration, ReportSettings.HTML.name, Path("path")) + report_mock.assert_called_once() diff --git a/tests/ahriman/core/upload/test_rsync.py b/tests/ahriman/core/upload/test_rsync.py index e69de29b..71c6977d 100644 --- a/tests/ahriman/core/upload/test_rsync.py +++ b/tests/ahriman/core/upload/test_rsync.py @@ -0,0 +1,16 @@ +from pathlib import Path +from pytest_mock import MockerFixture + +from ahriman.core.configuration import Configuration +from ahriman.core.upload.rsync import Rsync + + +def test_sync(configuration: Configuration, mocker: MockerFixture) -> None: + """ + must run sync command + """ + check_output_mock = mocker.patch("ahriman.core.upload.rsync.Rsync._check_output") + + upload = Rsync("x86_64", configuration) + upload.sync(Path("path")) + check_output_mock.assert_called_once() diff --git a/tests/ahriman/core/upload/test_s3.py b/tests/ahriman/core/upload/test_s3.py index e69de29b..c5b35821 100644 --- a/tests/ahriman/core/upload/test_s3.py +++ b/tests/ahriman/core/upload/test_s3.py @@ -0,0 +1,16 @@ +from pathlib import Path +from pytest_mock import MockerFixture + +from ahriman.core.configuration import Configuration +from ahriman.core.upload.s3 import S3 + + +def test_sync(configuration: Configuration, mocker: MockerFixture) -> None: + """ + must run sync command + """ + check_output_mock = mocker.patch("ahriman.core.upload.s3.S3._check_output") + + upload = S3("x86_64", configuration) + upload.sync(Path("path")) + check_output_mock.assert_called_once() diff --git a/tests/ahriman/core/upload/test_uploader.py b/tests/ahriman/core/upload/test_uploader.py index e69de29b..1e1c5140 100644 --- a/tests/ahriman/core/upload/test_uploader.py +++ b/tests/ahriman/core/upload/test_uploader.py @@ -0,0 +1,36 @@ +import pytest + +from pathlib import Path +from pytest_mock import MockerFixture + +from ahriman.core.configuration import Configuration +from ahriman.core.exceptions import SyncFailed +from ahriman.core.upload.upload import Upload +from ahriman.models.upload_settings import UploadSettings + + +def test_upload_failure(configuration: Configuration, mocker: MockerFixture) -> None: + """ + must raise SyncFailed on errors + """ + mocker.patch("ahriman.core.upload.rsync.Rsync.sync", side_effect=Exception()) + with pytest.raises(SyncFailed): + Upload.run("x86_64", configuration, UploadSettings.Rsync.name, Path("path")) + + +def test_upload_rsync(configuration: Configuration, mocker: MockerFixture) -> None: + """ + must upload via rsync + """ + upload_mock = mocker.patch("ahriman.core.upload.rsync.Rsync.sync") + Upload.run("x86_64", configuration, UploadSettings.Rsync.name, Path("path")) + upload_mock.assert_called_once() + + +def test_upload_s3(configuration: Configuration, mocker: MockerFixture) -> None: + """ + must upload via s3 + """ + upload_mock = mocker.patch("ahriman.core.upload.s3.S3.sync") + Upload.run("x86_64", configuration, UploadSettings.S3.name, Path("path")) + upload_mock.assert_called_once() diff --git a/tests/ahriman/models/conftest.py b/tests/ahriman/models/conftest.py index cef09533..504e095b 100644 --- a/tests/ahriman/models/conftest.py +++ b/tests/ahriman/models/conftest.py @@ -1,8 +1,10 @@ import pytest +from unittest.mock import MagicMock, PropertyMock + from ahriman.models.build_status import BuildStatus, BuildStatusEnum from ahriman.models.package import Package -from ahriman.models.package_desciption import PackageDescription +from ahriman.models.package_description import PackageDescription @pytest.fixture @@ -17,3 +19,33 @@ def package_tpacpi_bat_git() -> Package: version="3.1.r12.g4959b52-1", aur_url="https://aur.archlinux.org", packages={"tpacpi-bat-git": PackageDescription()}) + + +@pytest.fixture +def pyalpm_handle(pyalpm_package_ahriman: MagicMock) -> MagicMock: + mock = MagicMock() + mock.handle.load_pkg.return_value = pyalpm_package_ahriman + return mock + + +@pytest.fixture +def pyalpm_package_ahriman(package_ahriman: Package) -> MagicMock: + mock = MagicMock() + type(mock).base = PropertyMock(return_value=package_ahriman.base) + type(mock).name = PropertyMock(return_value=package_ahriman.base) + type(mock).version = PropertyMock(return_value=package_ahriman.version) + return mock + + +@pytest.fixture +def pyalpm_package_description_ahriman(package_description_ahriman: PackageDescription) -> MagicMock: + mock = MagicMock() + type(mock).arch = PropertyMock(return_value=package_description_ahriman.architecture) + type(mock).builddate = PropertyMock(return_value=package_description_ahriman.build_date) + type(mock).desc = PropertyMock(return_value=package_description_ahriman.description) + type(mock).groups = PropertyMock(return_value=package_description_ahriman.groups) + type(mock).isize = PropertyMock(return_value=package_description_ahriman.installed_size) + type(mock).licenses = PropertyMock(return_value=package_description_ahriman.licenses) + type(mock).size = PropertyMock(return_value=package_description_ahriman.archive_size) + type(mock).url = PropertyMock(return_value=package_description_ahriman.url) + return mock diff --git a/tests/ahriman/models/test_package.py b/tests/ahriman/models/test_package.py index c8201f4a..e6847232 100644 --- a/tests/ahriman/models/test_package.py +++ b/tests/ahriman/models/test_package.py @@ -1,6 +1,10 @@ +import pytest + from pathlib import Path from pytest_mock import MockerFixture +from unittest.mock import MagicMock, PropertyMock +from ahriman.core.exceptions import InvalidPackageInfo from ahriman.models.package import Package from ahriman.models.repository_paths import RepositoryPaths @@ -72,6 +76,44 @@ def test_web_url(package_ahriman: Package) -> None: assert package_ahriman.base in package_ahriman.web_url +def test_from_archive(package_ahriman: Package, pyalpm_handle: MagicMock, mocker: MockerFixture) -> None: + """ + must construct package from alpm library + """ + mocker.patch("ahriman.models.package_description.PackageDescription.from_package", + return_value=package_ahriman.packages[package_ahriman.base]) + assert Package.from_archive(Path("path"), pyalpm_handle, package_ahriman.aur_url) == package_ahriman + + +def test_from_aur(package_ahriman: Package, mocker: MockerFixture) -> None: + """ + must construct package from aur + """ + mock = MagicMock() + type(mock).name = PropertyMock(return_value=package_ahriman.base) + type(mock).package_base = PropertyMock(return_value=package_ahriman.base) + type(mock).version = PropertyMock(return_value=package_ahriman.version) + mocker.patch("aur.info", return_value=mock) + + package = Package.from_aur(package_ahriman.base, package_ahriman.aur_url) + assert package_ahriman.base == package.base + assert package_ahriman.version == package.version + assert package_ahriman.packages.keys() == package.packages.keys() + + +def test_from_build(package_ahriman: Package, mocker: MockerFixture, resource_path_root: Path) -> None: + """ + must construct package from srcinfo + """ + srcinfo = (resource_path_root / "models" / "package_ahriman_srcinfo").read_text() + mocker.patch("pathlib.Path.read_text", return_value=srcinfo) + + package = Package.from_build(Path("path"), package_ahriman.aur_url) + assert package_ahriman.packages.keys() == package.packages.keys() + package_ahriman.packages = package.packages # we are not going to test PackageDescription here + assert package_ahriman == package + + def test_from_json_view_1(package_ahriman: Package) -> None: """ must construct same object from json @@ -98,12 +140,64 @@ def test_dependencies_with_version(mocker: MockerFixture, resource_path_root: Pa must load correct list of dependencies with version """ srcinfo = (resource_path_root / "models" / "package_yay_srcinfo").read_text() - mocker.patch("pathlib.Path.read_text", return_value=srcinfo) assert Package.dependencies(Path("path")) == {"git", "go", "pacman"} +def test_full_version() -> None: + """ + must construct full version + """ + assert Package.full_version("1", "r2388.d30e3201", "1") == "1:r2388.d30e3201-1" + assert Package.full_version(None, "0.12.1", "1") == "0.12.1-1" + + +def test_load_from_archive(package_ahriman: Package, pyalpm_handle: MagicMock, mocker: MockerFixture) -> None: + """ + must load package from package archive + """ + mocker.patch("pathlib.Path.is_file", return_value=True) + load_mock = mocker.patch("ahriman.models.package.Package.from_archive") + + Package.load(Path("path"), pyalpm_handle, package_ahriman.aur_url) + load_mock.assert_called_once() + + +def test_load_from_aur(package_ahriman: Package, pyalpm_handle: MagicMock, mocker: MockerFixture) -> None: + """ + must load package from AUR + """ + load_mock = mocker.patch("ahriman.models.package.Package.from_aur") + + Package.load(Path("path"), pyalpm_handle, package_ahriman.aur_url) + load_mock.assert_called_once() + + +def test_load_from_build(package_ahriman: Package, pyalpm_handle: MagicMock, mocker: MockerFixture) -> None: + """ + must load package from build directory + """ + mocker.patch("pathlib.Path.is_dir", return_value=True) + load_mock = mocker.patch("ahriman.models.package.Package.from_build") + + Package.load(Path("path"), pyalpm_handle, package_ahriman.aur_url) + load_mock.assert_called_once() + + +def test_load_failure(package_ahriman: Package, pyalpm_handle: MagicMock, mocker: MockerFixture) -> None: + """ + must raise InvalidPackageInfo on exception + """ + mocker.patch("pathlib.Path.is_dir", side_effect=InvalidPackageInfo("exception!")) + with pytest.raises(InvalidPackageInfo): + Package.load(Path("path"), pyalpm_handle, package_ahriman.aur_url) + + mocker.patch("pathlib.Path.is_dir", side_effect=Exception()) + with pytest.raises(InvalidPackageInfo): + Package.load(Path("path"), pyalpm_handle, package_ahriman.aur_url) + + def test_actual_version(package_ahriman: Package, repository_paths: RepositoryPaths) -> None: """ must return same actual_version as version is @@ -117,7 +211,6 @@ def test_actual_version_vcs(package_tpacpi_bat_git: Package, repository_paths: R must return valid actual_version for VCS package """ srcinfo = (resource_path_root / "models" / "package_tpacpi-bat-git_srcinfo").read_text() - mocker.patch("ahriman.models.package.Package._check_output", return_value=srcinfo) mocker.patch("ahriman.core.build_tools.task.Task.fetch") diff --git a/tests/ahriman/models/test_package_desciption.py b/tests/ahriman/models/test_package_desciption.py index 5808f752..4fb020e5 100644 --- a/tests/ahriman/models/test_package_desciption.py +++ b/tests/ahriman/models/test_package_desciption.py @@ -1,4 +1,6 @@ -from ahriman.models.package_desciption import PackageDescription +from unittest.mock import MagicMock + +from ahriman.models.package_description import PackageDescription def test_filepath(package_description_ahriman: PackageDescription) -> None: @@ -15,3 +17,13 @@ def test_filepath_empty(package_description_ahriman: PackageDescription) -> None """ package_description_ahriman.filename = None assert package_description_ahriman.filepath is None + + +def test_from_package(package_description_ahriman: PackageDescription, + pyalpm_package_description_ahriman: MagicMock) -> None: + """ + must construct description from package object + """ + package_description = PackageDescription.from_package(pyalpm_package_description_ahriman, + package_description_ahriman.filepath) + assert package_description_ahriman == package_description diff --git a/tests/testresources/models/package_ahriman_srcinfo b/tests/testresources/models/package_ahriman_srcinfo new file mode 100644 index 00000000..40dababa --- /dev/null +++ b/tests/testresources/models/package_ahriman_srcinfo @@ -0,0 +1,34 @@ +pkgbase = ahriman + pkgdesc = ArcHlinux ReposItory MANager + pkgver = 0.12.1 + pkgrel = 1 + url = https://github.com/arcan1s/ahriman + arch = any + license = GPL3 + makedepends = python-pip + depends = devtools + depends = git + depends = pyalpm + depends = python-aur + depends = python-srcinfo + optdepends = aws-cli: sync to s3 + optdepends = breezy: -bzr packages support + optdepends = darcs: -darcs packages support + optdepends = gnupg: package and repository sign + optdepends = mercurial: -hg packages support + optdepends = python-aiohttp: web server + optdepends = python-aiohttp-jinja2: web server + optdepends = python-jinja: html report generation + optdepends = python-requests: web server + optdepends = rsync: sync by using rsync + optdepends = subversion: -svn packages support + backup = etc/ahriman.ini + backup = etc/ahriman.ini.d/logging.ini + source = https://github.com/arcan1s/ahriman/releases/download/0.12.1/ahriman-0.12.1-src.tar.xz + source = ahriman.sysusers + source = ahriman.tmpfiles + sha512sums = 8acc57f937d587ca665c29092cadddbaf3ba0b80e870b80d1551e283aba8f21306f9030a26fec8c71ab5863316f5f5f061b7ddc63cdff9e6d5a885f28ef1893d + sha512sums = 13718afec2c6786a18f0b223ef8e58dccf0688bca4cdbe203f14071f5031ed20120eb0ce38b52c76cfd6e8b6581a9c9eaa2743eb11abbaca637451a84c33f075 + sha512sums = 55b20f6da3d66e7bbf2add5d95a3b60632df121717d25a993e56e737d14f51fe063eb6f1b38bd81cc32e05db01c0c1d80aaa720c45cde87f238d8b46cdb8cbc4 + +pkgname = ahriman