repository component tests

This commit is contained in:
2021-03-26 04:21:19 +03:00
parent fc29689ef9
commit 83084a318d
30 changed files with 565 additions and 81 deletions

View File

@ -31,6 +31,21 @@ def package_ahriman(package_description_ahriman: PackageDescription) -> Package:
packages=packages)
@pytest.fixture
def package_python_schedule(
package_description_python_schedule: PackageDescription,
package_description_python2_schedule: PackageDescription) -> Package:
packages = {
"python-schedule": package_description_python_schedule,
"python2-schedule": package_description_python2_schedule
}
return Package(
base="python-schedule",
version="1.0.0-2",
aur_url="https://aur.archlinux.org",
packages=packages)
@pytest.fixture
def package_description_ahriman() -> PackageDescription:
return PackageDescription(
@ -40,6 +55,24 @@ def package_description_ahriman() -> PackageDescription:
installed_size=4200000)
@pytest.fixture
def package_description_python_schedule() -> PackageDescription:
return PackageDescription(
archive_size=4201,
build_date=421,
filename="python-schedule-1.0.0-2-any.pkg.tar.zst",
installed_size=4200001)
@pytest.fixture
def package_description_python2_schedule() -> PackageDescription:
return PackageDescription(
archive_size=4202,
build_date=422,
filename="python2-schedule-1.0.0-2-any.pkg.tar.zst",
installed_size=4200002)
@pytest.fixture
def repository_paths() -> RepositoryPaths:
return RepositoryPaths(

View File

@ -21,6 +21,9 @@ def test_fetch_existing(mocker: MockerFixture) -> None:
mock.call("git", "fetch", "origin", "master",
exception=pytest.helpers.anyvar(int),
cwd=local, logger=pytest.helpers.anyvar(int)),
mock.call("git", "checkout", "--force", "master",
exception=pytest.helpers.anyvar(int),
cwd=local, logger=pytest.helpers.anyvar(int)),
mock.call("git", "reset", "--hard", "origin/master",
exception=pytest.helpers.anyvar(int),
cwd=local, logger=pytest.helpers.anyvar(int))
@ -40,6 +43,9 @@ def test_fetch_new(mocker: MockerFixture) -> None:
mock.call("git", "clone", "remote", str(local),
exception=pytest.helpers.anyvar(int),
logger=pytest.helpers.anyvar(int)),
mock.call("git", "checkout", "--force", "master",
exception=pytest.helpers.anyvar(int),
cwd=local, logger=pytest.helpers.anyvar(int)),
mock.call("git", "reset", "--hard", "origin/master",
exception=pytest.helpers.anyvar(int),
cwd=local, logger=pytest.helpers.anyvar(int))

View File

View File

View File

@ -0,0 +1,49 @@
import pytest
from pytest_mock import MockerFixture
from ahriman.core.configuration import Configuration
from ahriman.core.repository.cleaner import Cleaner
from ahriman.core.repository.executor import Executor
from ahriman.core.repository.properties import Properties
from ahriman.core.repository.repository import Repository
from ahriman.core.repository.update_handler import UpdateHandler
@pytest.fixture
def cleaner(configuration: Configuration, mocker: MockerFixture) -> Cleaner:
mocker.patch("pathlib.Path.mkdir")
return Cleaner("x86_64", configuration)
@pytest.fixture
def executor(configuration: Configuration, mocker: MockerFixture) -> Executor:
mocker.patch("pathlib.Path.mkdir")
mocker.patch("ahriman.core.repository.cleaner.Cleaner.clear_build")
mocker.patch("ahriman.core.repository.cleaner.Cleaner.clear_cache")
mocker.patch("ahriman.core.repository.cleaner.Cleaner.clear_chroot")
mocker.patch("ahriman.core.repository.cleaner.Cleaner.clear_manual")
mocker.patch("ahriman.core.repository.cleaner.Cleaner.clear_packages")
return Executor("x86_64", configuration)
@pytest.fixture
def repository(configuration: Configuration, mocker: MockerFixture) -> Repository:
mocker.patch("pathlib.Path.mkdir")
return Repository("x86_64", configuration)
@pytest.fixture
def properties(configuration: Configuration) -> Properties:
return Properties("x86_64", configuration)
@pytest.fixture
def update_handler(configuration: Configuration, mocker: MockerFixture) -> UpdateHandler:
mocker.patch("pathlib.Path.mkdir")
mocker.patch("ahriman.core.repository.cleaner.Cleaner.clear_build")
mocker.patch("ahriman.core.repository.cleaner.Cleaner.clear_cache")
mocker.patch("ahriman.core.repository.cleaner.Cleaner.clear_chroot")
mocker.patch("ahriman.core.repository.cleaner.Cleaner.clear_manual")
mocker.patch("ahriman.core.repository.cleaner.Cleaner.clear_packages")
return UpdateHandler("x86_64", configuration)

View File

@ -0,0 +1,68 @@
import shutil
from pathlib import Path
from pytest_mock import MockerFixture
from unittest import mock
from ahriman.core.repository.cleaner import Cleaner
def _mock_clear(mocker: MockerFixture) -> None:
mocker.patch("pathlib.Path.iterdir", return_value=[Path("a"), Path("b"), Path("c")])
mocker.patch("shutil.rmtree")
def _mock_clear_check() -> None:
shutil.rmtree.assert_has_calls([
mock.call(Path("a")),
mock.call(Path("b")),
mock.call(Path("c"))
])
def test_clear_build(cleaner: Cleaner, mocker: MockerFixture) -> None:
"""
must remove directories with sources
"""
_mock_clear(mocker)
cleaner.clear_build()
_mock_clear_check()
def test_clear_cache(cleaner: Cleaner, mocker: MockerFixture) -> None:
"""
must remove every cached sources
"""
_mock_clear(mocker)
cleaner.clear_cache()
_mock_clear_check()
def test_clear_chroot(cleaner: Cleaner, mocker: MockerFixture) -> None:
"""
must clear chroot
"""
_mock_clear(mocker)
cleaner.clear_chroot()
_mock_clear_check()
def test_clear_manual(cleaner: Cleaner, mocker: MockerFixture) -> None:
"""
must clear directory with manual packages
"""
_mock_clear(mocker)
cleaner.clear_manual()
_mock_clear_check()
def test_clear_packages(cleaner: Cleaner, mocker: MockerFixture) -> None:
"""
must delete built packages
"""
mocker.patch("ahriman.core.repository.cleaner.Cleaner.packages_built",
return_value=[Path("a"), Path("b"), Path("c")])
mocker.patch("pathlib.Path.unlink")
cleaner.clear_packages()
Path.unlink.assert_has_calls([mock.call(), mock.call(), mock.call()])

View File

@ -0,0 +1,189 @@
from pathlib import Path
from unittest import mock
from pytest_mock import MockerFixture
from ahriman.core.repository.executor import Executor
from ahriman.models.package import Package
def test_process_build(executor: Executor, package_ahriman: Package, mocker: MockerFixture) -> None:
"""
must run build process
"""
mocker.patch("ahriman.core.repository.executor.Executor.packages_built", return_value=[package_ahriman])
mocker.patch("ahriman.core.build_tools.task.Task.build", return_value=[Path(package_ahriman.base)])
mocker.patch("ahriman.core.build_tools.task.Task.init")
move_mock = mocker.patch("shutil.move")
watcher_client_mock = mocker.patch("ahriman.core.watcher.client.Client.set_building")
# must return list of built packages
assert executor.process_build([package_ahriman]) == [package_ahriman]
# must move files (once)
move_mock.assert_called_once()
# must update status
watcher_client_mock.assert_called_once()
# must clear directory
from ahriman.core.repository.cleaner import Cleaner
Cleaner.clear_build.assert_called_once()
def test_process_build_failure(executor: Executor, package_ahriman: Package, mocker: MockerFixture) -> None:
"""
must run correct process failed builds
"""
mocker.patch("ahriman.core.repository.executor.Executor.packages_built")
mocker.patch("ahriman.core.build_tools.task.Task.build", return_value=[Path(package_ahriman.base)])
mocker.patch("ahriman.core.build_tools.task.Task.init")
mocker.patch("shutil.move", side_effect=Exception())
watcher_client_mock = mocker.patch("ahriman.core.watcher.client.Client.set_failed")
executor.process_build([package_ahriman])
watcher_client_mock.assert_called_once()
def test_process_remove_base(executor: Executor, package_ahriman: Package, mocker: MockerFixture) -> None:
"""
must run remove process for whole base
"""
mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_ahriman])
repo_remove_mock = mocker.patch("ahriman.core.alpm.repo.Repo.remove")
watcher_client_mock = mocker.patch("ahriman.core.watcher.client.Client.remove")
executor.process_remove([package_ahriman.base])
# must remove via alpm wrapper
repo_remove_mock.assert_called_once()
# must update status
watcher_client_mock.assert_called_once()
def test_process_remove_base_multiple(executor: Executor, package_python_schedule: Package,
mocker: MockerFixture) -> None:
"""
must run remove process for whole base with multiple packages
"""
mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_python_schedule])
repo_remove_mock = mocker.patch("ahriman.core.alpm.repo.Repo.remove")
watcher_client_mock = mocker.patch("ahriman.core.watcher.client.Client.remove")
executor.process_remove([package_python_schedule.base])
# must remove via alpm wrapper
repo_remove_mock.assert_has_calls([
mock.call(package, Path(props.filename))
for package, props in package_python_schedule.packages.items()
], any_order=True)
# must update status
watcher_client_mock.assert_called_once()
def test_process_remove_base_single(executor: Executor, package_python_schedule: Package,
mocker: MockerFixture) -> None:
"""
must run remove process for single package in base
"""
mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_python_schedule])
repo_remove_mock = mocker.patch("ahriman.core.alpm.repo.Repo.remove")
watcher_client_mock = mocker.patch("ahriman.core.watcher.client.Client.remove")
executor.process_remove(["python2-schedule"])
# must remove via alpm wrapper
repo_remove_mock.assert_called_once()
# must not update status
watcher_client_mock.assert_not_called()
def test_process_remove_nothing(executor: Executor, package_ahriman: Package, package_python_schedule: Package,
mocker: MockerFixture) -> None:
"""
must not remove anything if it was not requested
"""
mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_ahriman])
repo_remove_mock = mocker.patch("ahriman.core.alpm.repo.Repo.remove")
executor.process_remove([package_python_schedule.base])
repo_remove_mock.assert_not_called()
def test_process_report_auto(executor: Executor, mocker: MockerFixture) -> None:
"""
must process report in auto mode if no targets supplied
"""
config_getlist_mock = mocker.patch("ahriman.core.configuration.Configuration.getlist")
executor.process_report(None)
config_getlist_mock.assert_called_once()
def test_process_sync_auto(executor: Executor, mocker: MockerFixture) -> None:
"""
must process sync in auto mode if no targets supplied
"""
config_getlist_mock = mocker.patch("ahriman.core.configuration.Configuration.getlist")
executor.process_sync(None)
config_getlist_mock.assert_called_once()
def test_process_update(executor: Executor, package_ahriman: Package, mocker: MockerFixture) -> None:
"""
must run update process
"""
mocker.patch("ahriman.models.package.Package.load", return_value=package_ahriman)
move_mock = mocker.patch("shutil.move")
repo_add_mock = mocker.patch("ahriman.core.alpm.repo.Repo.add")
sign_package_mock = mocker.patch("ahriman.core.sign.gpg.GPG.sign_package", side_effect=lambda fn, _: [fn])
watcher_client_mock = mocker.patch("ahriman.core.watcher.client.Client.set_success")
# must return complete
assert executor.process_update([Path(package.filename) for package in package_ahriman.packages.values()])
# must move files (once)
move_mock.assert_called_once()
# must sign package
sign_package_mock.assert_called_once()
# must add package
repo_add_mock.assert_called_once()
# must update status
watcher_client_mock.assert_called_once()
# must clear directory
from ahriman.core.repository.cleaner import Cleaner
Cleaner.clear_packages.assert_called_once()
def test_process_update_group(executor: Executor, package_python_schedule: Package,
mocker: MockerFixture) -> None:
"""
must group single packages under one base
"""
mocker.patch("shutil.move")
mocker.patch("ahriman.models.package.Package.load", return_value=package_python_schedule)
repo_add_mock = mocker.patch("ahriman.core.alpm.repo.Repo.add")
watcher_client_mock = mocker.patch("ahriman.core.watcher.client.Client.set_success")
executor.process_update([Path(package.filename) for package in package_python_schedule.packages.values()])
repo_add_mock.assert_has_calls([
mock.call(executor.paths.repository / package.filename)
for package in package_python_schedule.packages.values()
], any_order=True)
watcher_client_mock.assert_called_with(package_python_schedule)
def test_process_update_failed(executor: Executor, package_ahriman: Package, mocker: MockerFixture) -> None:
"""
must process update for failed package
"""
mocker.patch("shutil.move", side_effect=Exception())
mocker.patch("ahriman.models.package.Package.load", return_value=package_ahriman)
watcher_client_mock = mocker.patch("ahriman.core.watcher.client.Client.set_failed")
executor.process_update([Path(package.filename) for package in package_ahriman.packages.values()])
watcher_client_mock.assert_called_once()
def test_process_update_failed_on_load(executor: Executor, package_ahriman: Package, mocker: MockerFixture) -> None:
"""
must process update even with failed package load
"""
mocker.patch("shutil.move")
mocker.patch("ahriman.models.package.Package.load", side_effect=Exception())
assert executor.process_update([Path(package.filename) for package in package_ahriman.packages.values()])

View File

@ -0,0 +1,14 @@
from pytest_mock import MockerFixture
from ahriman.core.configuration import Configuration
from ahriman.core.repository.properties import Properties
def test_create_tree_on_load(configuration: Configuration, mocker: MockerFixture) -> None:
"""
must create tree on load
"""
create_tree_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.create_tree")
Properties("x86_64", configuration)
create_tree_mock.assert_called_once()

View File

@ -0,0 +1,34 @@
from pathlib import Path
from pytest_mock import MockerFixture
from ahriman.core.repository.repository import Repository
from ahriman.models.package import Package
def test_packages(package_ahriman: Package, package_python_schedule: Package,
repository: Repository, mocker: MockerFixture) -> None:
"""
must return all packages grouped by package base
"""
single_packages = [
Package(base=package_python_schedule.base,
version=package_python_schedule.version,
aur_url=package_python_schedule.aur_url,
packages={package: props})
for package, props in package_python_schedule.packages.items()
] + [package_ahriman]
mocker.patch("pathlib.Path.iterdir",
return_value=[Path("a.pkg.tar.xz"), Path("b.pkg.tar.xz"), Path("c.pkg.tar.xz")])
mocker.patch("ahriman.models.package.Package.load", side_effect=single_packages)
packages = repository.packages()
assert len(packages) == 2
assert {package.base for package in packages} == {package_ahriman.base, package_python_schedule.base}
archives = sum([list(package.packages.keys()) for package in packages], start=[])
assert len(archives) == 3
expected = set(package_ahriman.packages.keys())
expected.update(package_python_schedule.packages.keys())
assert set(archives) == expected

View File

@ -0,0 +1,124 @@
from pytest_mock import MockerFixture
from ahriman.core.repository.update_handler import UpdateHandler
from ahriman.models.package import Package
def test_updates_aur(update_handler: UpdateHandler, package_ahriman: Package,
mocker: MockerFixture) -> None:
"""
must provide updates with status watcher updates
"""
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True)
mocker.patch("ahriman.models.package.Package.load", return_value=package_ahriman)
watcher_client_mock = mocker.patch("ahriman.core.watcher.client.Client.set_pending")
assert update_handler.updates_aur([], False) == [package_ahriman]
watcher_client_mock.assert_called_once()
def test_updates_aur_failed(update_handler: UpdateHandler, package_ahriman: Package,
mocker: MockerFixture) -> None:
"""
must update status watcher via client for failed load
"""
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
mocker.patch("ahriman.models.package.Package.load", side_effect=Exception())
watcher_client_mock = mocker.patch("ahriman.core.watcher.client.Client.set_failed")
update_handler.updates_aur([], False)
watcher_client_mock.assert_called_once()
def test_updates_aur_filter(update_handler: UpdateHandler, package_ahriman: Package, package_python_schedule: Package,
mocker: MockerFixture) -> None:
"""
must provide updates only for filtered packages
"""
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages",
return_value=[package_ahriman, package_python_schedule])
mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True)
package_load_mock = mocker.patch("ahriman.models.package.Package.load", return_value=package_ahriman)
assert update_handler.updates_aur([package_ahriman.base], False) == [package_ahriman]
package_load_mock.assert_called_once()
def test_updates_aur_ignore(update_handler: UpdateHandler, package_ahriman: Package,
mocker: MockerFixture) -> None:
"""
must skip ignore packages
"""
mocker.patch("ahriman.core.configuration.Configuration.getlist", return_value=[package_ahriman.base])
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
package_load_mock = mocker.patch("ahriman.models.package.Package.load")
update_handler.updates_aur([], False)
package_load_mock.assert_not_called()
def test_updates_aur_ignore_vcs(update_handler: UpdateHandler, package_ahriman: Package,
mocker: MockerFixture) -> None:
"""
must skip VCS packages check if requested
"""
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
mocker.patch("ahriman.models.package.Package.is_vcs", return_value=True)
package_is_outdated_mock = mocker.patch("ahriman.models.package.Package.is_outdated")
update_handler.updates_aur([], True)
package_is_outdated_mock.assert_not_called()
def test_updates_manual_clear(update_handler: UpdateHandler, mocker: MockerFixture) -> None:
"""
requesting manual updates must clear packages directory
"""
mocker.patch("pathlib.Path.iterdir", return_value=[])
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages")
update_handler.updates_manual()
from ahriman.core.repository.cleaner import Cleaner
Cleaner.clear_manual.assert_called_once()
def test_updates_manual_status_known(update_handler: UpdateHandler, package_ahriman: Package,
mocker: MockerFixture) -> None:
"""
must create record for known package via reporter
"""
mocker.patch("pathlib.Path.iterdir", return_value=[package_ahriman.base])
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
mocker.patch("ahriman.models.package.Package.load", return_value=package_ahriman)
watcher_client_mock = mocker.patch("ahriman.core.watcher.client.Client.set_pending")
update_handler.updates_manual()
watcher_client_mock.assert_called_once()
def test_updates_manual_status_unknown(update_handler: UpdateHandler, package_ahriman: Package,
mocker: MockerFixture) -> None:
"""
must create record for unknown package via reporter
"""
mocker.patch("pathlib.Path.iterdir", return_value=[package_ahriman.base])
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[])
mocker.patch("ahriman.models.package.Package.load", return_value=package_ahriman)
watcher_client_mock = mocker.patch("ahriman.core.watcher.client.Client.set_unknown")
update_handler.updates_manual()
watcher_client_mock.assert_called_once()
def test_updates_manual_with_failures(update_handler: UpdateHandler, package_ahriman: Package,
mocker: MockerFixture) -> None:
"""
must process through the packages with failure
"""
mocker.patch("pathlib.Path.iterdir", return_value=[package_ahriman.base])
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[])
mocker.patch("ahriman.models.package.Package.load", side_effect=Exception())
assert update_handler.updates_manual() == []

View File

@ -10,21 +10,6 @@ def build_status_failed() -> BuildStatus:
return BuildStatus(BuildStatusEnum.Failed, 42)
@pytest.fixture
def package_python_schedule(
package_description_python_schedule: PackageDescription,
package_description_python2_schedule: PackageDescription) -> Package:
packages = {
"python-schedule": package_description_python_schedule,
"python2-schedule": package_description_python2_schedule
}
return Package(
base="python-schedule",
version="1.0.0-2",
aur_url="https://aur.archlinux.org",
packages=packages)
@pytest.fixture
def package_tpacpi_bat_git() -> Package:
return Package(
@ -32,21 +17,3 @@ 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 package_description_python_schedule() -> PackageDescription:
return PackageDescription(
archive_size=4201,
build_date=421,
filename="python-schedule-1.0.0-2-any.pkg.tar.zst",
installed_size=4200001)
@pytest.fixture
def package_description_python2_schedule() -> PackageDescription:
return PackageDescription(
archive_size=4202,
build_date=422,
filename="python2-schedule-1.0.0-2-any.pkg.tar.zst",
installed_size=4200002)

View File

@ -41,6 +41,4 @@ remote =
bucket =
[web]
host =
port =
templates = /usr/share/ahriman

View File

@ -17,19 +17,19 @@ args = (sys.stderr,)
class = logging.handlers.RotatingFileHandler
level = DEBUG
formatter = generic_format
args = ('/var/log/ahriman/ahriman.log', 'a', 20971520, 20)
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)
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)
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