mirror of
https://github.com/arcan1s/ahriman.git
synced 2026-07-14 23:01:09 +00:00
reorder tests
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.application.application_packages import ApplicationPackages
|
||||
from ahriman.application.application.application_properties import ApplicationProperties
|
||||
from ahriman.application.application.application_repository import ApplicationRepository
|
||||
from ahriman.application.application.updates_iterator import FixedUpdatesIterator, UpdatesIterator
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.repository import Repository
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def application_packages(configuration: Configuration, database: SQLite, repository: Repository,
|
||||
mocker: MockerFixture) -> ApplicationPackages:
|
||||
"""
|
||||
fixture for application with package functions
|
||||
|
||||
Args:
|
||||
configuration(Configuration): configuration fixture
|
||||
database(SQLite): database fixture
|
||||
repository(Repository): repository fixture
|
||||
mocker(MockerFixture): mocker object
|
||||
|
||||
Returns:
|
||||
ApplicationPackages: application test instance
|
||||
"""
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
|
||||
_, repository_id = configuration.check_loaded()
|
||||
return ApplicationPackages(repository_id, configuration, report=False)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def application_properties(configuration: Configuration, database: SQLite, repository: Repository,
|
||||
mocker: MockerFixture) -> ApplicationProperties:
|
||||
"""
|
||||
fixture for application with properties only
|
||||
|
||||
Args:
|
||||
configuration(Configuration): configuration fixture
|
||||
database(SQLite): database fixture
|
||||
repository(Repository): repository fixture
|
||||
mocker(MockerFixture): mocker object
|
||||
|
||||
Returns:
|
||||
ApplicationProperties: application test instance
|
||||
"""
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
|
||||
_, repository_id = configuration.check_loaded()
|
||||
return ApplicationProperties(repository_id, configuration, report=False)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def application_repository(configuration: Configuration, database: SQLite, repository: Repository,
|
||||
mocker: MockerFixture) -> ApplicationRepository:
|
||||
"""
|
||||
fixture for application with repository functions
|
||||
|
||||
Args:
|
||||
configuration(Configuration): configuration fixture
|
||||
database(SQLite): database fixture
|
||||
repository(Repository): repository fixture
|
||||
mocker(MockerFixture): mocker object
|
||||
|
||||
Returns:
|
||||
ApplicationRepository: application test instance
|
||||
"""
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
|
||||
_, repository_id = configuration.check_loaded()
|
||||
return ApplicationRepository(repository_id, configuration, report=False)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fixed_updates_iterator(application: Application) -> FixedUpdatesIterator:
|
||||
"""
|
||||
fixture for fixed updates iterator
|
||||
|
||||
Args:
|
||||
application(Application): application fixture
|
||||
|
||||
Returns:
|
||||
FixedUpdatesIterator: fixed updates iterator test instance
|
||||
"""
|
||||
return FixedUpdatesIterator(application, 1)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def updates_iterator(application: Application) -> UpdatesIterator:
|
||||
"""
|
||||
fixture for chunk bases updates iterator
|
||||
|
||||
Args:
|
||||
application(Application): application fixture
|
||||
|
||||
Returns:
|
||||
UpdatesIterator: updates iterator test instance
|
||||
"""
|
||||
return UpdatesIterator(application, 1)
|
||||
@@ -0,0 +1,164 @@
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
from typing import Any
|
||||
from unittest.mock import MagicMock, call as MockCall
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.core.tree import Leaf, Tree
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
def test_known_packages(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must return not empty list of known packages
|
||||
"""
|
||||
mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[package_ahriman])
|
||||
packages = application._known_packages()
|
||||
assert len(packages) > 1
|
||||
assert package_ahriman.base in packages
|
||||
|
||||
|
||||
def test_on_result(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must call on_result trigger function
|
||||
"""
|
||||
mocker.patch("ahriman.core.repository.Repository.packages", return_value=[package_ahriman])
|
||||
triggers_mock = mocker.patch("ahriman.core.triggers.TriggerLoader.on_result")
|
||||
|
||||
application.on_result(Result())
|
||||
triggers_mock.assert_called_once_with(Result(), [package_ahriman])
|
||||
|
||||
|
||||
def test_on_start(application: Application, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must call on_start trigger function
|
||||
"""
|
||||
triggers_mock = mocker.patch("ahriman.core.triggers.TriggerLoader.on_start")
|
||||
|
||||
application.on_start()
|
||||
triggers_mock.assert_called_once_with()
|
||||
|
||||
|
||||
def test_on_stop(application: Application, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must call on_stop trigger function
|
||||
"""
|
||||
triggers_mock = mocker.patch("ahriman.core.triggers.TriggerLoader.on_stop")
|
||||
|
||||
application.on_stop()
|
||||
triggers_mock.assert_called_once_with()
|
||||
|
||||
|
||||
def test_print_updates(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must print updates
|
||||
"""
|
||||
tree = Tree([Leaf(package_ahriman)])
|
||||
mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[package_ahriman])
|
||||
mocker.patch("ahriman.core.tree.Tree.resolve", return_value=tree.levels())
|
||||
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
|
||||
application.print_updates([package_ahriman], log_fn=print)
|
||||
print_mock.assert_called_once_with(verbose=True, log_fn=print, separator=" -> ")
|
||||
|
||||
|
||||
def test_with_dependencies(application: Application, package_ahriman: Package, package_python_schedule: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must append list of missing dependencies
|
||||
"""
|
||||
def create_package_mock(package_base) -> MagicMock:
|
||||
mock = MagicMock()
|
||||
mock.base = package_base
|
||||
mock.depends_build = []
|
||||
mock.packages_full = [package_base]
|
||||
return mock
|
||||
|
||||
def get_package(name: str | Path, *args: Any, **kwargs: Any) -> Package:
|
||||
name = name if isinstance(name, str) else name.name
|
||||
return packages[name]
|
||||
|
||||
package_python_schedule.packages = {
|
||||
package_python_schedule.base: package_python_schedule.packages[package_python_schedule.base]
|
||||
}
|
||||
package_ahriman.packages[package_ahriman.base].depends = ["devtools", "python", package_python_schedule.base]
|
||||
package_ahriman.packages[package_ahriman.base].make_depends = ["python-build", "python-installer"]
|
||||
|
||||
packages = {
|
||||
package_ahriman.base: package_ahriman,
|
||||
package_python_schedule.base: package_python_schedule,
|
||||
"python": create_package_mock("python"),
|
||||
"python-installer": create_package_mock("python-installer"),
|
||||
}
|
||||
|
||||
mocker.patch("pathlib.Path.is_dir", autospec=True, side_effect=lambda p: p.name == "python")
|
||||
package_aur_mock = mocker.patch("ahriman.models.package.Package.from_aur", side_effect=get_package)
|
||||
package_local_mock = mocker.patch("ahriman.models.package.Package.from_build", side_effect=get_package)
|
||||
packages_mock = mocker.patch("ahriman.application.application.Application._known_packages",
|
||||
return_value={"devtools", "python-build", "python-pytest"})
|
||||
status_client_mock = mocker.patch("ahriman.core.status.Client.set_unknown")
|
||||
|
||||
result = application.with_dependencies([package_ahriman], process_dependencies=True)
|
||||
assert {package.base: package for package in result} == packages
|
||||
package_aur_mock.assert_has_calls([
|
||||
MockCall(package_python_schedule.base, package_ahriman.packager, include_provides=True),
|
||||
MockCall("python-installer", package_ahriman.packager, include_provides=True),
|
||||
], any_order=True)
|
||||
package_local_mock.assert_has_calls([
|
||||
MockCall(application.repository.paths.cache_for("python"), "x86_64", package_ahriman.packager),
|
||||
], any_order=True)
|
||||
packages_mock.assert_called_once_with()
|
||||
|
||||
status_client_mock.assert_has_calls([
|
||||
MockCall(package_python_schedule),
|
||||
MockCall(packages["python"]),
|
||||
MockCall(packages["python-installer"]),
|
||||
], any_order=True)
|
||||
|
||||
|
||||
def test_with_dependencies_exception(application: Application, package_ahriman: Package,
|
||||
package_python_schedule: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip packages if exception occurs
|
||||
"""
|
||||
def create_package_mock(package_base) -> MagicMock:
|
||||
mock = MagicMock()
|
||||
mock.base = package_base
|
||||
mock.depends_build = []
|
||||
mock.packages_full = [package_base]
|
||||
return mock
|
||||
|
||||
package_python_schedule.packages = {
|
||||
package_python_schedule.base: package_python_schedule.packages[package_python_schedule.base]
|
||||
}
|
||||
package_ahriman.packages[package_ahriman.base].depends = ["devtools", "python", package_python_schedule.base]
|
||||
package_ahriman.packages[package_ahriman.base].make_depends = ["python-build", "python-installer"]
|
||||
|
||||
packages = {
|
||||
package_ahriman.base: package_ahriman,
|
||||
package_python_schedule.base: package_python_schedule,
|
||||
"python": create_package_mock("python"),
|
||||
"python-installer": create_package_mock("python-installer"),
|
||||
}
|
||||
|
||||
mocker.patch("pathlib.Path.is_dir", autospec=True, side_effect=lambda p: p.name == "python")
|
||||
mocker.patch("ahriman.models.package.Package.from_aur", side_effect=lambda *args: packages[args[0]])
|
||||
mocker.patch("ahriman.models.package.Package.from_build", side_effect=Exception)
|
||||
mocker.patch("ahriman.application.application.Application._known_packages",
|
||||
return_value={"devtools", "python-build", "python-pytest"})
|
||||
|
||||
assert not application.with_dependencies([package_ahriman], process_dependencies=True)
|
||||
|
||||
|
||||
def test_with_dependencies_skip(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip processing of dependencies
|
||||
"""
|
||||
packages_mock = mocker.patch("ahriman.application.application.Application._known_packages")
|
||||
|
||||
assert application.with_dependencies([package_ahriman], process_dependencies=False) == [package_ahriman]
|
||||
packages_mock.assert_not_called()
|
||||
|
||||
assert application.with_dependencies([], process_dependencies=True) == []
|
||||
packages_mock.assert_not_called()
|
||||
@@ -0,0 +1,236 @@
|
||||
import pytest
|
||||
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from ahriman.application.application.application_packages import ApplicationPackages
|
||||
from ahriman.core.exceptions import UnknownPackageError
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.package_description import PackageDescription
|
||||
from ahriman.models.package_source import PackageSource
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
def test_add_archive(application_packages: ApplicationPackages, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must add package from archive
|
||||
"""
|
||||
is_file_mock = mocker.patch("pathlib.Path.is_file", return_value=True)
|
||||
copy_mock = mocker.patch("shutil.copy")
|
||||
|
||||
application_packages._add_archive(package_ahriman.base)
|
||||
is_file_mock.assert_called_once_with()
|
||||
copy_mock.assert_called_once_with(
|
||||
Path(package_ahriman.base), application_packages.repository.paths.packages / package_ahriman.base)
|
||||
|
||||
|
||||
def test_add_archive_missing(application_packages: ApplicationPackages, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise UnknownPackageError on unknown path
|
||||
"""
|
||||
mocker.patch("pathlib.Path.is_file", return_value=False)
|
||||
with pytest.raises(UnknownPackageError):
|
||||
application_packages._add_archive("package")
|
||||
|
||||
|
||||
def test_add_aur(application_packages: ApplicationPackages, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must add package from AUR
|
||||
"""
|
||||
mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman)
|
||||
build_queue_mock = mocker.patch("ahriman.core.database.SQLite.build_queue_insert")
|
||||
status_client_mock = mocker.patch("ahriman.core.status.Client.set_unknown")
|
||||
|
||||
application_packages._add_aur(package_ahriman.base, "packager")
|
||||
build_queue_mock.assert_called_once_with(package_ahriman)
|
||||
status_client_mock.assert_called_once_with(package_ahriman)
|
||||
|
||||
|
||||
def test_add_directory(application_packages: ApplicationPackages, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must add packages from directory
|
||||
"""
|
||||
is_dir_mock = mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||
filename = package_ahriman.packages[package_ahriman.base].filepath
|
||||
iterdir_mock = mocker.patch("pathlib.Path.iterdir", return_value=[filename])
|
||||
add_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._add_archive")
|
||||
|
||||
application_packages._add_directory(package_ahriman.base)
|
||||
is_dir_mock.assert_called_once_with()
|
||||
iterdir_mock.assert_called_once_with()
|
||||
add_mock.assert_called_once_with(str(filename))
|
||||
|
||||
|
||||
def test_add_directory_missing(application_packages: ApplicationPackages, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise UnknownPackageError on unknown directory path
|
||||
"""
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||
with pytest.raises(UnknownPackageError):
|
||||
application_packages._add_directory("package")
|
||||
|
||||
|
||||
def test_add_local(application_packages: ApplicationPackages, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must add package from local sources
|
||||
"""
|
||||
mocker.patch("ahriman.models.package.Package.from_build", return_value=package_ahriman)
|
||||
is_dir_mock = mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||
init_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.init")
|
||||
copytree_mock = mocker.patch("shutil.copytree")
|
||||
build_queue_mock = mocker.patch("ahriman.core.database.SQLite.build_queue_insert")
|
||||
|
||||
application_packages._add_local(package_ahriman.base, "packager")
|
||||
is_dir_mock.assert_called_once_with()
|
||||
copytree_mock.assert_called_once_with(
|
||||
Path(package_ahriman.base),
|
||||
application_packages.repository.paths.cache_for(package_ahriman.base),
|
||||
dirs_exist_ok=True)
|
||||
init_mock.assert_called_once_with(application_packages.repository.paths.cache_for(package_ahriman.base))
|
||||
build_queue_mock.assert_called_once_with(package_ahriman)
|
||||
|
||||
|
||||
def test_add_local_cache(application_packages: ApplicationPackages, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must add package from local source if there is cache
|
||||
"""
|
||||
mocker.patch("ahriman.models.package.Package.from_build", return_value=package_ahriman)
|
||||
mocker.patch("pathlib.Path.is_dir", autospec=True,
|
||||
side_effect=lambda p: p.is_relative_to(application_packages.repository.paths.cache))
|
||||
init_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.init")
|
||||
copytree_mock = mocker.patch("shutil.copytree")
|
||||
build_queue_mock = mocker.patch("ahriman.core.database.SQLite.build_queue_insert")
|
||||
|
||||
application_packages._add_local(package_ahriman.base, "packager")
|
||||
copytree_mock.assert_not_called()
|
||||
init_mock.assert_not_called()
|
||||
build_queue_mock.assert_called_once_with(package_ahriman)
|
||||
|
||||
|
||||
def test_add_local_missing(application_packages: ApplicationPackages, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise UnknownPackageError if package wasn't found
|
||||
"""
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||
with pytest.raises(UnknownPackageError):
|
||||
application_packages._add_local("package", "packager")
|
||||
|
||||
|
||||
def test_add_remote(application_packages: ApplicationPackages, package_description_ahriman: PackageDescription,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must add package from remote source
|
||||
"""
|
||||
response_mock = MagicMock()
|
||||
response_mock.iter_content.return_value = ["chunk"]
|
||||
open_mock = mocker.patch("pathlib.Path.open")
|
||||
request_mock = mocker.patch("requests.get", return_value=response_mock)
|
||||
url = f"https://host/{package_description_ahriman.filename}"
|
||||
|
||||
application_packages._add_remote(url)
|
||||
open_mock.assert_called_once_with("wb")
|
||||
request_mock.assert_called_once_with(url, stream=True, timeout=None)
|
||||
response_mock.raise_for_status.assert_called_once_with()
|
||||
|
||||
|
||||
def test_add_remote_missing(application_packages: ApplicationPackages, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise UnknownPackageError if remote package wasn't found
|
||||
"""
|
||||
mocker.patch("requests.get", side_effect=Exception)
|
||||
with pytest.raises(UnknownPackageError):
|
||||
application_packages._add_remote("url")
|
||||
|
||||
|
||||
def test_add_repository(application_packages: ApplicationPackages, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must add package from official repository
|
||||
"""
|
||||
mocker.patch("ahriman.models.package.Package.from_official", return_value=package_ahriman)
|
||||
build_queue_mock = mocker.patch("ahriman.core.database.SQLite.build_queue_insert")
|
||||
status_client_mock = mocker.patch("ahriman.core.status.Client.set_unknown")
|
||||
|
||||
application_packages._add_repository(package_ahriman.base, "packager")
|
||||
build_queue_mock.assert_called_once_with(package_ahriman)
|
||||
status_client_mock.assert_called_once_with(package_ahriman)
|
||||
|
||||
|
||||
def test_add_add_archive(application_packages: ApplicationPackages, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must add package from archive via add function
|
||||
"""
|
||||
add_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._add_archive")
|
||||
|
||||
application_packages.add([package_ahriman.base], PackageSource.Archive, "packager")
|
||||
add_mock.assert_called_once_with(package_ahriman.base, "packager")
|
||||
|
||||
|
||||
def test_add_add_aur(application_packages: ApplicationPackages, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must add package from AUR via add function
|
||||
"""
|
||||
add_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._add_aur")
|
||||
|
||||
application_packages.add([package_ahriman.base], PackageSource.AUR, "packager")
|
||||
add_mock.assert_called_once_with(package_ahriman.base, "packager")
|
||||
|
||||
|
||||
def test_add_add_directory(application_packages: ApplicationPackages, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must add packages from directory via add function
|
||||
"""
|
||||
add_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._add_directory")
|
||||
|
||||
application_packages.add([package_ahriman.base], PackageSource.Directory, "packager")
|
||||
add_mock.assert_called_once_with(package_ahriman.base, "packager")
|
||||
|
||||
|
||||
def test_add_add_local(application_packages: ApplicationPackages, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must add package from local sources via add function
|
||||
"""
|
||||
add_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._add_local")
|
||||
|
||||
application_packages.add([package_ahriman.base], PackageSource.Local, "packager")
|
||||
add_mock.assert_called_once_with(package_ahriman.base, "packager")
|
||||
|
||||
|
||||
def test_add_add_remote(application_packages: ApplicationPackages, package_description_ahriman: PackageDescription,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must add package from remote source via add function
|
||||
"""
|
||||
add_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._add_remote")
|
||||
url = f"https://host/{package_description_ahriman.filename}"
|
||||
|
||||
application_packages.add([url], PackageSource.Remote, "packager")
|
||||
add_mock.assert_called_once_with(url, "packager")
|
||||
|
||||
|
||||
def test_on_result(application_packages: ApplicationPackages) -> None:
|
||||
"""
|
||||
must raise NotImplemented for missing finalize method
|
||||
"""
|
||||
with pytest.raises(NotImplementedError):
|
||||
application_packages.on_result(Result())
|
||||
|
||||
|
||||
def test_remove(application_packages: ApplicationPackages, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must remove package
|
||||
"""
|
||||
executor_mock = mocker.patch("ahriman.core.repository.executor.Executor.process_remove", return_value=Result())
|
||||
on_result_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages.on_result")
|
||||
|
||||
application_packages.remove([])
|
||||
executor_mock.assert_called_once_with([])
|
||||
on_result_mock.assert_called_once_with(Result())
|
||||
@@ -0,0 +1,15 @@
|
||||
from ahriman.application.application.application_properties import ApplicationProperties
|
||||
|
||||
|
||||
def test_architecture(application_properties: ApplicationProperties) -> None:
|
||||
"""
|
||||
must return repository architecture
|
||||
"""
|
||||
assert application_properties.architecture == application_properties.repository_id.architecture
|
||||
|
||||
|
||||
def test_reporter(application_properties: ApplicationProperties) -> None:
|
||||
"""
|
||||
must have reporter attribute
|
||||
"""
|
||||
assert application_properties.reporter
|
||||
@@ -0,0 +1,404 @@
|
||||
import pytest
|
||||
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest.mock import call as MockCall
|
||||
|
||||
from ahriman.application.application.application_repository import ApplicationRepository
|
||||
from ahriman.core.exceptions import UnknownPackageError
|
||||
from ahriman.core.tree import Leaf, Tree
|
||||
from ahriman.models.changes import Changes
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.packagers import Packagers
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
def test_changes(application_repository: ApplicationRepository, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must generate changes for the packages
|
||||
"""
|
||||
changes = Changes("sha", "change")
|
||||
hashes_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_get", return_value=changes)
|
||||
changes_mock = mocker.patch("ahriman.core.repository.Repository.package_changes", return_value=changes)
|
||||
report_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_update")
|
||||
|
||||
application_repository.changes([package_ahriman])
|
||||
hashes_mock.assert_called_once_with(package_ahriman.base)
|
||||
changes_mock.assert_called_once_with(package_ahriman, changes.last_commit_sha)
|
||||
report_mock.assert_called_once_with(package_ahriman.base, changes)
|
||||
|
||||
|
||||
def test_changes_skip(application_repository: ApplicationRepository, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip change generation if no last commit sha has been found
|
||||
"""
|
||||
changes_mock = mocker.patch("ahriman.core.repository.Repository.package_changes")
|
||||
report_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_update")
|
||||
|
||||
application_repository.changes([package_ahriman])
|
||||
changes_mock.assert_not_called()
|
||||
report_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_changes_no_update(application_repository: ApplicationRepository, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip update if package_changes returns None (no new commits)
|
||||
"""
|
||||
changes = Changes("sha", "change")
|
||||
mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_get", return_value=changes)
|
||||
mocker.patch("ahriman.core.repository.Repository.package_changes", return_value=None)
|
||||
report_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_update")
|
||||
|
||||
application_repository.changes([package_ahriman])
|
||||
report_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_clean_cache(application_repository: ApplicationRepository, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must clean cache directory
|
||||
"""
|
||||
clear_mock = mocker.patch("ahriman.core.repository.Repository.clear_cache")
|
||||
application_repository.clean(cache=True, chroot=False, manual=False, packages=False, pacman=False)
|
||||
clear_mock.assert_called_once_with()
|
||||
|
||||
|
||||
def test_clean_chroot(application_repository: ApplicationRepository, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must clean chroot directory
|
||||
"""
|
||||
clear_mock = mocker.patch("ahriman.core.repository.Repository.clear_chroot")
|
||||
application_repository.clean(cache=False, chroot=True, manual=False, packages=False, pacman=False)
|
||||
clear_mock.assert_called_once_with()
|
||||
|
||||
|
||||
def test_clean_manual(application_repository: ApplicationRepository, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must clean manual directory
|
||||
"""
|
||||
clear_mock = mocker.patch("ahriman.core.repository.Repository.clear_queue")
|
||||
application_repository.clean(cache=False, chroot=False, manual=True, packages=False, pacman=False)
|
||||
clear_mock.assert_called_once_with()
|
||||
|
||||
|
||||
def test_clean_packages(application_repository: ApplicationRepository, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must clean packages directory
|
||||
"""
|
||||
clear_mock = mocker.patch("ahriman.core.repository.Repository.clear_packages")
|
||||
application_repository.clean(cache=False, chroot=False, manual=False, packages=True, pacman=False)
|
||||
clear_mock.assert_called_once_with()
|
||||
|
||||
|
||||
def test_clean_pacman(application_repository: ApplicationRepository, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must clean pacman directory
|
||||
"""
|
||||
clear_mock = mocker.patch("ahriman.core.repository.Repository.clear_pacman")
|
||||
application_repository.clean(cache=False, chroot=False, manual=False, packages=False, pacman=True)
|
||||
clear_mock.assert_called_once_with()
|
||||
|
||||
|
||||
def test_on_result(application_repository: ApplicationRepository) -> None:
|
||||
"""
|
||||
must raise NotImplemented for missing finalize method
|
||||
"""
|
||||
with pytest.raises(NotImplementedError):
|
||||
application_repository.on_result(Result())
|
||||
|
||||
|
||||
def test_sign(application_repository: ApplicationRepository, package_ahriman: Package, package_python_schedule: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must sign world
|
||||
"""
|
||||
mocker.patch("ahriman.core.repository.repository.Repository.packages",
|
||||
return_value=[package_ahriman, package_python_schedule])
|
||||
sign_package_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process_sign_package")
|
||||
sign_repository_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process_sign_repository")
|
||||
on_result_mock = mocker.patch(
|
||||
"ahriman.application.application.application_repository.ApplicationRepository.on_result")
|
||||
|
||||
application_repository.sign([])
|
||||
sign_package_mock.assert_has_calls([
|
||||
MockCall(pytest.helpers.anyvar(int), None),
|
||||
MockCall(pytest.helpers.anyvar(int), None),
|
||||
MockCall(pytest.helpers.anyvar(int), None),
|
||||
])
|
||||
sign_repository_mock.assert_called_once_with(application_repository.repository.repo.repo_path)
|
||||
on_result_mock.assert_called_once_with(Result())
|
||||
|
||||
|
||||
def test_sign_skip(application_repository: ApplicationRepository, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip sign packages with empty filename
|
||||
"""
|
||||
package_ahriman.packages[package_ahriman.base].filename = None
|
||||
mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[package_ahriman])
|
||||
mocker.patch("ahriman.application.application.application_repository.ApplicationRepository.update")
|
||||
mocker.patch("ahriman.application.application.application_repository.ApplicationRepository.on_result")
|
||||
|
||||
application_repository.sign([])
|
||||
|
||||
|
||||
def test_unknown_no_aur(application_repository: ApplicationRepository, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must return empty list in case if there is locally stored PKGBUILD
|
||||
"""
|
||||
mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[package_ahriman])
|
||||
mocker.patch("ahriman.models.package.Package.from_aur", side_effect=UnknownPackageError(package_ahriman.base))
|
||||
mocker.patch("ahriman.models.package.Package.from_build", return_value=package_ahriman)
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||
mocker.patch("ahriman.core.build_tools.sources.Sources.has_remotes", return_value=False)
|
||||
|
||||
assert not application_repository.unknown()
|
||||
|
||||
|
||||
def test_unknown_no_aur_no_local(application_repository: ApplicationRepository, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must return list of packages missing in aur and in local storage
|
||||
"""
|
||||
mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[package_ahriman])
|
||||
mocker.patch("ahriman.models.package.Package.from_aur", side_effect=UnknownPackageError(package_ahriman.base))
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||
|
||||
packages = application_repository.unknown()
|
||||
assert packages == list(package_ahriman.packages.keys())
|
||||
|
||||
|
||||
def test_unknown_no_local(application_repository: ApplicationRepository, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must return empty list in case if there is package in AUR
|
||||
"""
|
||||
mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[package_ahriman])
|
||||
mocker.patch("ahriman.models.package.Package.from_aur")
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||
|
||||
assert not application_repository.unknown()
|
||||
|
||||
|
||||
def test_update(application_repository: ApplicationRepository, package_ahriman: Package, result: Result,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must process package updates
|
||||
"""
|
||||
paths = [package.filepath for package in package_ahriman.packages.values()]
|
||||
tree = Tree([Leaf(package_ahriman)])
|
||||
prebuilt_result = Result()
|
||||
|
||||
resolve_mock = mocker.patch("ahriman.application.application.workers.local_updater.LocalUpdater.partition",
|
||||
return_value=tree.levels())
|
||||
mocker.patch("ahriman.core.repository.repository.Repository.packages_built", return_value=paths)
|
||||
build_mock = mocker.patch("ahriman.application.application.workers.local_updater.LocalUpdater.update",
|
||||
return_value=result)
|
||||
update_mock = mocker.patch("ahriman.core.repository.Repository.process_update", return_value=prebuilt_result)
|
||||
on_result_mock = mocker.patch(
|
||||
"ahriman.application.application.application_repository.ApplicationRepository.on_result")
|
||||
|
||||
application_repository.update([package_ahriman], Packagers("username"), bump_pkgrel=True)
|
||||
resolve_mock.assert_called_once_with([package_ahriman])
|
||||
build_mock.assert_called_once_with([package_ahriman], Packagers("username"), bump_pkgrel=True)
|
||||
update_mock.assert_called_once_with(paths, Packagers("username"))
|
||||
on_result_mock.assert_has_calls([MockCall(prebuilt_result), MockCall(result)])
|
||||
|
||||
|
||||
def test_update_prebuilt_filter(application_repository: ApplicationRepository, package_ahriman: Package, result: Result,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must filter out packages which were successfully prebuilt
|
||||
"""
|
||||
paths = [package.filepath for package in package_ahriman.packages.values()]
|
||||
|
||||
resolve_mock = mocker.patch("ahriman.application.application.workers.local_updater.LocalUpdater.partition",
|
||||
return_value=[])
|
||||
mocker.patch("ahriman.core.repository.repository.Repository.packages_built", return_value=paths)
|
||||
mocker.patch("ahriman.core.repository.Repository.process_update", return_value=result)
|
||||
mocker.patch("ahriman.application.application.application_repository.ApplicationRepository.on_result")
|
||||
|
||||
application_repository.update([package_ahriman], Packagers("username"), bump_pkgrel=True)
|
||||
resolve_mock.assert_called_once_with([])
|
||||
|
||||
|
||||
def test_update_empty(application_repository: ApplicationRepository, package_ahriman: Package, result: Result,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip updating repository if no packages supplied
|
||||
"""
|
||||
tree = Tree([Leaf(package_ahriman)])
|
||||
|
||||
mocker.patch("ahriman.application.application.workers.Updater.partition", return_value=tree.levels())
|
||||
mocker.patch("ahriman.core.repository.Repository.packages_built", return_value=[])
|
||||
mocker.patch("ahriman.application.application.workers.local_updater.LocalUpdater.update", return_value=result)
|
||||
mocker.patch("ahriman.application.application.application_repository.ApplicationRepository.on_result")
|
||||
update_mock = mocker.patch("ahriman.core.repository.Repository.process_update")
|
||||
|
||||
application_repository.update([package_ahriman])
|
||||
update_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_updates_all(application_repository: ApplicationRepository, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must get updates for all
|
||||
"""
|
||||
path = Path("local")
|
||||
mocker.patch("ahriman.core.repository.package_info.PackageInfo.packages_built", return_value=[path])
|
||||
updates_built_mock = mocker.patch("ahriman.core.repository.package_info.PackageInfo.load_archives")
|
||||
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur",
|
||||
return_value=[package_ahriman])
|
||||
updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local")
|
||||
updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual")
|
||||
updates_deps_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_dependencies")
|
||||
|
||||
application_repository.updates([], aur=True, local=True, manual=True, vcs=True, check_files=True)
|
||||
updates_built_mock.assert_called_once_with([path])
|
||||
updates_aur_mock.assert_called_once_with([], vcs=True)
|
||||
updates_local_mock.assert_called_once_with(vcs=True)
|
||||
updates_manual_mock.assert_called_once_with()
|
||||
updates_deps_mock.assert_called_once_with([])
|
||||
|
||||
|
||||
def test_updates_disabled(application_repository: ApplicationRepository, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must get updates without anything
|
||||
"""
|
||||
path = Path("local")
|
||||
mocker.patch("ahriman.core.repository.package_info.PackageInfo.packages_built", return_value=[path])
|
||||
updates_built_mock = mocker.patch("ahriman.core.repository.package_info.PackageInfo.load_archives")
|
||||
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur")
|
||||
updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local")
|
||||
updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual")
|
||||
updates_deps_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_dependencies")
|
||||
|
||||
application_repository.updates([], aur=False, local=False, manual=False, vcs=True, check_files=False)
|
||||
updates_built_mock.assert_called_once_with([path])
|
||||
updates_aur_mock.assert_not_called()
|
||||
updates_local_mock.assert_not_called()
|
||||
updates_manual_mock.assert_not_called()
|
||||
updates_deps_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_updates_no_aur(application_repository: ApplicationRepository, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must get updates without aur
|
||||
"""
|
||||
path = Path("local")
|
||||
mocker.patch("ahriman.core.repository.package_info.PackageInfo.packages_built", return_value=[path])
|
||||
updates_built_mock = mocker.patch("ahriman.core.repository.package_info.PackageInfo.load_archives")
|
||||
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur")
|
||||
updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local")
|
||||
updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual")
|
||||
updates_deps_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_dependencies")
|
||||
|
||||
application_repository.updates([], aur=False, local=True, manual=True, vcs=True, check_files=True)
|
||||
updates_built_mock.assert_called_once_with([path])
|
||||
updates_aur_mock.assert_not_called()
|
||||
updates_local_mock.assert_called_once_with(vcs=True)
|
||||
updates_manual_mock.assert_called_once_with()
|
||||
updates_deps_mock.assert_called_once_with([])
|
||||
|
||||
|
||||
def test_updates_no_local(application_repository: ApplicationRepository, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must get updates without local packages
|
||||
"""
|
||||
path = Path("local")
|
||||
mocker.patch("ahriman.core.repository.package_info.PackageInfo.packages_built", return_value=[path])
|
||||
updates_built_mock = mocker.patch("ahriman.core.repository.package_info.PackageInfo.load_archives")
|
||||
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur")
|
||||
updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local")
|
||||
updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual")
|
||||
updates_deps_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_dependencies")
|
||||
|
||||
application_repository.updates([], aur=True, local=False, manual=True, vcs=True, check_files=True)
|
||||
updates_built_mock.assert_called_once_with([path])
|
||||
updates_aur_mock.assert_called_once_with([], vcs=True)
|
||||
updates_local_mock.assert_not_called()
|
||||
updates_manual_mock.assert_called_once_with()
|
||||
updates_deps_mock.assert_called_once_with([])
|
||||
|
||||
|
||||
def test_updates_no_manual(application_repository: ApplicationRepository, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must get updates without manual
|
||||
"""
|
||||
path = Path("local")
|
||||
mocker.patch("ahriman.core.repository.package_info.PackageInfo.packages_built", return_value=[path])
|
||||
updates_built_mock = mocker.patch("ahriman.core.repository.package_info.PackageInfo.load_archives")
|
||||
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur")
|
||||
updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local")
|
||||
updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual")
|
||||
updates_deps_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_dependencies")
|
||||
|
||||
application_repository.updates([], aur=True, local=True, manual=False, vcs=True, check_files=True)
|
||||
updates_built_mock.assert_called_once_with([path])
|
||||
updates_aur_mock.assert_called_once_with([], vcs=True)
|
||||
updates_local_mock.assert_called_once_with(vcs=True)
|
||||
updates_manual_mock.assert_not_called()
|
||||
updates_deps_mock.assert_called_once_with([])
|
||||
|
||||
|
||||
def test_updates_no_vcs(application_repository: ApplicationRepository, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must get updates without VCS
|
||||
"""
|
||||
path = Path("local")
|
||||
mocker.patch("ahriman.core.repository.package_info.PackageInfo.packages_built", return_value=[path])
|
||||
updates_built_mock = mocker.patch("ahriman.core.repository.package_info.PackageInfo.load_archives")
|
||||
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur")
|
||||
updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local")
|
||||
updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual")
|
||||
updates_deps_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_dependencies")
|
||||
|
||||
application_repository.updates([], aur=True, local=True, manual=True, vcs=False, check_files=True)
|
||||
updates_built_mock.assert_called_once_with([path])
|
||||
updates_aur_mock.assert_called_once_with([], vcs=False)
|
||||
updates_local_mock.assert_called_once_with(vcs=False)
|
||||
updates_manual_mock.assert_called_once_with()
|
||||
updates_deps_mock.assert_called_once_with([])
|
||||
|
||||
|
||||
def test_updates_no_check_files(application_repository: ApplicationRepository, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must get updates without checking broken links
|
||||
"""
|
||||
path = Path("local")
|
||||
mocker.patch("ahriman.core.repository.package_info.PackageInfo.packages_built", return_value=[path])
|
||||
updates_built_mock = mocker.patch("ahriman.core.repository.package_info.PackageInfo.load_archives")
|
||||
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur")
|
||||
updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local")
|
||||
updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual")
|
||||
updates_deps_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_dependencies")
|
||||
|
||||
application_repository.updates([], aur=True, local=True, manual=True, vcs=True, check_files=False)
|
||||
updates_built_mock.assert_called_once_with([path])
|
||||
updates_aur_mock.assert_called_once_with([], vcs=True)
|
||||
updates_local_mock.assert_called_once_with(vcs=True)
|
||||
updates_manual_mock.assert_called_once_with()
|
||||
updates_deps_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_updates_with_filter(application_repository: ApplicationRepository, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must get updates with filter
|
||||
"""
|
||||
path = Path("local")
|
||||
mocker.patch("ahriman.core.repository.package_info.PackageInfo.packages_built", return_value=[path])
|
||||
updates_built_mock = mocker.patch("ahriman.core.repository.package_info.PackageInfo.load_archives")
|
||||
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur")
|
||||
updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local")
|
||||
updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual")
|
||||
updates_deps_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_dependencies")
|
||||
|
||||
application_repository.updates(["filter"], aur=True, local=True, manual=True, vcs=True, check_files=True)
|
||||
updates_built_mock.assert_called_once_with([path])
|
||||
updates_aur_mock.assert_called_once_with(["filter"], vcs=True)
|
||||
updates_local_mock.assert_called_once_with(vcs=True)
|
||||
updates_manual_mock.assert_called_once_with()
|
||||
updates_deps_mock.assert_called_once_with(["filter"])
|
||||
@@ -0,0 +1,74 @@
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest.mock import call as MockCall
|
||||
|
||||
from ahriman.application.application.updates_iterator import FixedUpdatesIterator, UpdatesIterator
|
||||
from ahriman.models.package import Package
|
||||
|
||||
|
||||
def test_select_packages(updates_iterator: UpdatesIterator, package_ahriman: Package,
|
||||
package_python_schedule: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must return next partition
|
||||
"""
|
||||
mocker.patch("ahriman.core.repository.Repository.packages",
|
||||
return_value=[package_ahriman, package_python_schedule])
|
||||
|
||||
assert updates_iterator.select_packages() == ([package_python_schedule.base], 2)
|
||||
assert updates_iterator.select_packages() == ([package_python_schedule.base], 2)
|
||||
|
||||
|
||||
def test_select_packages_empty(updates_iterator: UpdatesIterator, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must return None for empty repository
|
||||
"""
|
||||
mocker.patch("ahriman.core.repository.Repository.packages", return_value=[])
|
||||
assert updates_iterator.select_packages() == (None, 1)
|
||||
|
||||
|
||||
def test_select_packages_cycle(updates_iterator: UpdatesIterator, package_ahriman: Package,
|
||||
package_python_schedule: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must cycle over partitions
|
||||
"""
|
||||
mocker.patch("ahriman.core.repository.Repository.packages",
|
||||
return_value=[package_ahriman, package_python_schedule])
|
||||
|
||||
assert updates_iterator.select_packages() == ([package_python_schedule.base], 2)
|
||||
updates_iterator.updated_packages.add(package_python_schedule.base)
|
||||
|
||||
assert updates_iterator.select_packages() == ([package_ahriman.base], 2)
|
||||
updates_iterator.updated_packages.add(package_ahriman.base)
|
||||
|
||||
assert updates_iterator.select_packages() == ([package_python_schedule.base], 2)
|
||||
assert not updates_iterator.updated_packages
|
||||
|
||||
|
||||
def test_iter(updates_iterator: UpdatesIterator) -> None:
|
||||
"""
|
||||
must return self as iterator
|
||||
"""
|
||||
assert iter(updates_iterator) == updates_iterator
|
||||
|
||||
|
||||
def test_next(updates_iterator: UpdatesIterator, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must return next chunk to update
|
||||
"""
|
||||
mocker.patch("ahriman.application.application.updates_iterator.UpdatesIterator.select_packages",
|
||||
side_effect=[([package_ahriman.base], 2), (None, 2), StopIteration])
|
||||
sleep_mock = mocker.patch("time.sleep")
|
||||
|
||||
updates = list(updates_iterator)
|
||||
assert updates == [[package_ahriman.base], None]
|
||||
sleep_mock.assert_has_calls([MockCall(0.5), MockCall(0.5)])
|
||||
|
||||
|
||||
def test_fixed_updates_iterator(fixed_updates_iterator: FixedUpdatesIterator, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must always return empty package list
|
||||
"""
|
||||
assert fixed_updates_iterator.select_packages() == ([], 1)
|
||||
|
||||
mocker.patch("ahriman.core.repository.Repository.packages", return_value=[package_ahriman])
|
||||
assert fixed_updates_iterator.select_packages() == ([], 1)
|
||||
@@ -0,0 +1,48 @@
|
||||
import pytest
|
||||
|
||||
from ahriman.application.application.workers import Updater
|
||||
from ahriman.application.application.workers.local_updater import LocalUpdater
|
||||
from ahriman.application.application.workers.remote_updater import RemoteUpdater
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.models.worker import Worker
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def local_updater(repository: Repository) -> LocalUpdater:
|
||||
"""
|
||||
local updater fixture
|
||||
|
||||
Args:
|
||||
repository(Repository): repository fixture
|
||||
|
||||
Returns:
|
||||
LocalUpdater: local updater test instance
|
||||
"""
|
||||
return LocalUpdater(repository)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def remote_updater(configuration: Configuration) -> RemoteUpdater:
|
||||
"""
|
||||
local updater fixture
|
||||
|
||||
Args:
|
||||
configuration(Configuration): configuration fixture
|
||||
|
||||
Returns:
|
||||
RemoteUpdater: remote updater test instance
|
||||
"""
|
||||
_, repository_id = configuration.check_loaded()
|
||||
return RemoteUpdater([Worker("remote1"), Worker("remote2")], repository_id, configuration)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def updater() -> Updater:
|
||||
"""
|
||||
empty updater fixture
|
||||
|
||||
Returns:
|
||||
Updater: empty updater test instance
|
||||
"""
|
||||
return Updater()
|
||||
@@ -0,0 +1,30 @@
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.application.workers.local_updater import LocalUpdater
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.packagers import Packagers
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
def test_partition(local_updater: LocalUpdater, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must partition as tree resolution
|
||||
"""
|
||||
resolve_mock = mocker.patch("ahriman.core.tree.Tree.resolve")
|
||||
local_updater.partition([])
|
||||
resolve_mock.assert_called_once_with([])
|
||||
|
||||
|
||||
def test_update(local_updater: LocalUpdater, package_ahriman: Package, result: Result,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must process package updates
|
||||
"""
|
||||
paths = [package.filepath for package in package_ahriman.packages.values()]
|
||||
mocker.patch("ahriman.core.repository.Repository.packages_built", return_value=paths)
|
||||
build_mock = mocker.patch("ahriman.core.repository.Repository.process_build", return_value=result)
|
||||
update_mock = mocker.patch("ahriman.core.repository.Repository.process_update", return_value=result)
|
||||
|
||||
assert local_updater.update([package_ahriman], Packagers("username"), bump_pkgrel=True) == result
|
||||
build_mock.assert_called_once_with([package_ahriman], Packagers("username"), bump_pkgrel=True)
|
||||
update_mock.assert_called_once_with(paths, Packagers("username"))
|
||||
@@ -0,0 +1,83 @@
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.application.workers.remote_updater import RemoteUpdater
|
||||
from ahriman.core.http import SyncAhrimanClient
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.packagers import Packagers
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
def test_clients(remote_updater: RemoteUpdater) -> None:
|
||||
"""
|
||||
must return map of clients
|
||||
"""
|
||||
worker = remote_updater.workers[0]
|
||||
client = SyncAhrimanClient()
|
||||
remote_updater._clients.append((worker, client))
|
||||
|
||||
assert remote_updater.clients == {worker: client}
|
||||
|
||||
|
||||
def test_update_url(remote_updater: RemoteUpdater) -> None:
|
||||
"""
|
||||
must generate update url correctly
|
||||
"""
|
||||
worker = remote_updater.workers[0]
|
||||
assert remote_updater._update_url(worker).startswith(worker.address)
|
||||
assert remote_updater._update_url(worker).endswith("/api/v1/service/add")
|
||||
|
||||
|
||||
def test_next_worker(remote_updater: RemoteUpdater) -> None:
|
||||
"""
|
||||
must return next not used worker
|
||||
"""
|
||||
assert remote_updater.next_worker()[0] == remote_updater.workers[0]
|
||||
assert len(remote_updater.clients) == 1
|
||||
assert remote_updater.workers[0] in remote_updater.clients
|
||||
|
||||
assert remote_updater.next_worker()[0] == remote_updater.workers[1]
|
||||
assert remote_updater.workers[1] in remote_updater.clients
|
||||
assert len(remote_updater.clients) == 2
|
||||
|
||||
|
||||
def test_next_worker_cycle(remote_updater: RemoteUpdater) -> None:
|
||||
"""
|
||||
must return first used worker if no free workers left
|
||||
"""
|
||||
worker1, client1 = remote_updater.next_worker()
|
||||
worker2, client2 = remote_updater.next_worker()
|
||||
|
||||
assert remote_updater.next_worker() == (worker1, client1)
|
||||
assert remote_updater.next_worker() == (worker2, client2)
|
||||
assert remote_updater.next_worker() == (worker1, client1)
|
||||
|
||||
|
||||
def test_partition(remote_updater: RemoteUpdater, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must partition as tree partition
|
||||
"""
|
||||
resolve_mock = mocker.patch("ahriman.core.tree.Tree.partition")
|
||||
remote_updater.partition([])
|
||||
resolve_mock.assert_called_once_with([], count=2)
|
||||
|
||||
|
||||
def test_update(remote_updater: RemoteUpdater, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must process remote package updates
|
||||
"""
|
||||
worker, client = remote_updater.next_worker()
|
||||
worker_mock = mocker.patch("ahriman.application.application.workers.remote_updater.RemoteUpdater.next_worker",
|
||||
return_value=(worker, client))
|
||||
request_mock = mocker.patch("ahriman.core.http.SyncAhrimanClient.make_request")
|
||||
|
||||
assert remote_updater.update([package_ahriman], Packagers("username"), bump_pkgrel=True) == Result()
|
||||
worker_mock.assert_called_once_with()
|
||||
request_mock.assert_called_once_with("POST", remote_updater._update_url(worker),
|
||||
params=remote_updater.repository_id.query(),
|
||||
json={
|
||||
"increment": False,
|
||||
"packager": "username",
|
||||
"packages": [package_ahriman.base],
|
||||
"patches": [],
|
||||
"refresh": True,
|
||||
})
|
||||
@@ -0,0 +1,50 @@
|
||||
import pytest
|
||||
|
||||
from ahriman.application.application.workers import Updater
|
||||
from ahriman.application.application.workers.local_updater import LocalUpdater
|
||||
from ahriman.application.application.workers.remote_updater import RemoteUpdater
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.models.worker import Worker
|
||||
|
||||
|
||||
def test_load(configuration: Configuration, repository: Repository) -> None:
|
||||
"""
|
||||
must load local updater if empty worker list is set
|
||||
"""
|
||||
_, repository_id = configuration.check_loaded()
|
||||
assert isinstance(Updater.load(repository_id, configuration, repository), LocalUpdater)
|
||||
assert isinstance(Updater.load(repository_id, configuration, repository, []), LocalUpdater)
|
||||
|
||||
|
||||
def test_load_from_option(configuration: Configuration, repository: Repository) -> None:
|
||||
"""
|
||||
must load remote updater if nonempty worker list is set
|
||||
"""
|
||||
_, repository_id = configuration.check_loaded()
|
||||
assert isinstance(Updater.load(repository_id, configuration, repository, [Worker("remote")]), RemoteUpdater)
|
||||
|
||||
|
||||
def test_load_from_configuration(configuration: Configuration, repository: Repository) -> None:
|
||||
"""
|
||||
must load remote updater from settings
|
||||
"""
|
||||
configuration.set_option("build", "workers", "remote")
|
||||
_, repository_id = configuration.check_loaded()
|
||||
assert isinstance(Updater.load(repository_id, configuration, repository), RemoteUpdater)
|
||||
|
||||
|
||||
def test_partition(updater: Updater) -> None:
|
||||
"""
|
||||
must raise not implemented error for missing partition method
|
||||
"""
|
||||
with pytest.raises(NotImplementedError):
|
||||
updater.partition([])
|
||||
|
||||
|
||||
def test_update(updater: Updater) -> None:
|
||||
"""
|
||||
must raise not implemented error for missing update method
|
||||
"""
|
||||
with pytest.raises(NotImplementedError):
|
||||
updater.update([])
|
||||
@@ -0,0 +1,83 @@
|
||||
import argparse
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.ahriman import _parser
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.help_formatter import _HelpFormatter
|
||||
from ahriman.application.lock import Lock
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.repository import Repository
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def application(configuration: Configuration, repository: Repository, database: SQLite,
|
||||
mocker: MockerFixture) -> Application:
|
||||
"""
|
||||
fixture for application
|
||||
|
||||
Args:
|
||||
configuration(Configuration): configuration fixture
|
||||
database(SQLite): database fixture
|
||||
repository(Repository): repository fixture
|
||||
mocker(MockerFixture): mocker object
|
||||
|
||||
Returns:
|
||||
Application: application test instance
|
||||
"""
|
||||
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
_, repository_id = configuration.check_loaded()
|
||||
return Application(repository_id, configuration, report=False)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def args() -> argparse.Namespace:
|
||||
"""
|
||||
fixture for command line arguments
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: command line arguments test instance
|
||||
"""
|
||||
return argparse.Namespace(architecture=None, lock=None, force=False, unsafe=False, report=False,
|
||||
repository=None, repository_id=None, wait_timeout=-1)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def formatter() -> _HelpFormatter:
|
||||
"""
|
||||
fixture for help message formatter
|
||||
|
||||
Returns:
|
||||
_HelpFormatter: help message formatter test instance
|
||||
"""
|
||||
return _HelpFormatter("ahriman")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def lock(args: argparse.Namespace, configuration: Configuration) -> Lock:
|
||||
"""
|
||||
fixture for file lock
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
configuration(Configuration): configuration fixture
|
||||
|
||||
Returns:
|
||||
Lock: file lock test instance
|
||||
"""
|
||||
_, repository_id = configuration.check_loaded()
|
||||
return Lock(args, repository_id, configuration)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def parser() -> argparse.ArgumentParser:
|
||||
"""
|
||||
fixture for command line arguments parser
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: command line arguments parser test instance
|
||||
"""
|
||||
return _parser()
|
||||
@@ -0,0 +1,211 @@
|
||||
import argparse
|
||||
import pytest
|
||||
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.exceptions import ExitCode, MissingArchitectureError, MultipleArchitecturesError
|
||||
from ahriman.models.log_handler import LogHandler
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
def test_call(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must call inside lock
|
||||
"""
|
||||
args.configuration = Path("")
|
||||
args.log_handler = LogHandler.Console
|
||||
args.quiet = False
|
||||
args.report = False
|
||||
mocker.patch("ahriman.application.handlers.handler.Handler.run")
|
||||
configuration_mock = mocker.patch("ahriman.core.configuration.Configuration.from_path", return_value=configuration)
|
||||
log_handler_mock = mocker.patch("ahriman.core.log.log_loader.LogLoader.handler", return_value=args.log_handler)
|
||||
log_load_mock = mocker.patch("ahriman.core.log.log_loader.LogLoader.load")
|
||||
enter_mock = mocker.patch("ahriman.application.lock.Lock.__enter__")
|
||||
exit_mock = mocker.patch("ahriman.application.lock.Lock.__exit__")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
assert Handler.call(args, repository_id)
|
||||
configuration_mock.assert_called_once_with(args.configuration, repository_id)
|
||||
log_handler_mock.assert_called_once_with(args.log_handler)
|
||||
log_load_mock.assert_called_once_with(
|
||||
repository_id,
|
||||
configuration,
|
||||
args.log_handler,
|
||||
quiet=args.quiet,
|
||||
report=args.report)
|
||||
enter_mock.assert_called_once_with()
|
||||
exit_mock.assert_called_once_with(None, None, None)
|
||||
|
||||
|
||||
def test_call_exception(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must process exception
|
||||
"""
|
||||
args.configuration = Path("")
|
||||
args.quiet = False
|
||||
mocker.patch("ahriman.core.configuration.Configuration.from_path", side_effect=Exception)
|
||||
logging_mock = mocker.patch("logging.Logger.exception")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
assert not Handler.call(args, repository_id)
|
||||
logging_mock.assert_called_once_with(pytest.helpers.anyvar(str, strict=True))
|
||||
|
||||
|
||||
def test_call_exit_code(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must process exitcode exception
|
||||
"""
|
||||
args.configuration = Path("")
|
||||
args.quiet = False
|
||||
mocker.patch("ahriman.core.configuration.Configuration.from_path", side_effect=ExitCode)
|
||||
logging_mock = mocker.patch("logging.Logger.exception")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
assert not Handler.call(args, repository_id)
|
||||
logging_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_execute(args: argparse.Namespace, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run execution in multiple processes
|
||||
"""
|
||||
ids = [
|
||||
RepositoryId("i686", "aur"),
|
||||
RepositoryId("x86_64", "aur"),
|
||||
]
|
||||
mocker.patch("ahriman.application.handlers.handler.Handler.repositories_extract", return_value=ids)
|
||||
starmap_mock = mocker.patch("multiprocessing.pool.Pool.starmap")
|
||||
|
||||
Handler.execute(args)
|
||||
starmap_mock.assert_called_once_with(Handler.call, [(args, repository_id) for repository_id in ids])
|
||||
|
||||
|
||||
def test_execute_multiple_not_supported(args: argparse.Namespace, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise an exception if multiple architectures are not supported by the handler
|
||||
"""
|
||||
args.command = "web"
|
||||
mocker.patch("ahriman.application.handlers.handler.Handler.repositories_extract", return_value=[
|
||||
RepositoryId("i686", "aur"),
|
||||
RepositoryId("x86_64", "aur"),
|
||||
])
|
||||
mocker.patch.object(Handler, "ALLOW_MULTI_ARCHITECTURE_RUN", False)
|
||||
|
||||
with pytest.raises(MultipleArchitecturesError):
|
||||
Handler.execute(args)
|
||||
|
||||
|
||||
def test_execute_single(args: argparse.Namespace, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run execution in current process if only one architecture supplied
|
||||
"""
|
||||
mocker.patch("ahriman.application.handlers.handler.Handler.repositories_extract", return_value=[
|
||||
RepositoryId("x86_64", "aur"),
|
||||
])
|
||||
starmap_mock = mocker.patch("multiprocessing.pool.Pool.starmap")
|
||||
|
||||
Handler.execute(args)
|
||||
starmap_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration) -> None:
|
||||
"""
|
||||
must raise NotImplemented for missing method
|
||||
"""
|
||||
_, repository_id = configuration.check_loaded()
|
||||
with pytest.raises(NotImplementedError):
|
||||
Handler.run(args, repository_id, configuration, report=True)
|
||||
|
||||
|
||||
def test_check_status() -> None:
|
||||
"""
|
||||
must raise exception in case if predicate is True and enabled
|
||||
"""
|
||||
Handler.check_status(False, True)
|
||||
Handler.check_status(False, False)
|
||||
Handler.check_status(False, lambda: True)
|
||||
Handler.check_status(False, lambda: False)
|
||||
|
||||
Handler.check_status(True, True)
|
||||
with pytest.raises(ExitCode):
|
||||
Handler.check_status(True, False)
|
||||
Handler.check_status(True, lambda: True)
|
||||
with pytest.raises(ExitCode):
|
||||
Handler.check_status(True, lambda: False)
|
||||
|
||||
|
||||
def test_repositories_extract(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must generate list of available repositories based on flags
|
||||
"""
|
||||
args.architecture = "arch"
|
||||
args.configuration = configuration.path
|
||||
args.repository = "repo"
|
||||
mocker.patch("ahriman.core.configuration.Configuration.load", new=lambda self, _: self.copy_from(configuration))
|
||||
extract_mock = mocker.patch("ahriman.core.repository.Explorer.repositories_extract",
|
||||
return_value=[RepositoryId("arch", "repo")])
|
||||
|
||||
assert Handler.repositories_extract(args) == [RepositoryId("arch", "repo")]
|
||||
extract_mock.assert_called_once_with(pytest.helpers.anyvar(Configuration, True), args.repository, args.architecture)
|
||||
|
||||
|
||||
def test_repositories_extract_empty(args: argparse.Namespace, configuration: Configuration,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise exception if no available architectures found
|
||||
"""
|
||||
args.command = "config"
|
||||
args.configuration = configuration.path
|
||||
mocker.patch("ahriman.core.configuration.Configuration.load", new=lambda self, _: self.copy_from(configuration))
|
||||
mocker.patch("ahriman.core.repository.Explorer.repositories_extract", return_value=[])
|
||||
|
||||
with pytest.raises(MissingArchitectureError):
|
||||
Handler.repositories_extract(args)
|
||||
|
||||
|
||||
def test_repositories_extract_systemd(args: argparse.Namespace, configuration: Configuration,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must extract repository list for systemd units
|
||||
"""
|
||||
args.configuration = configuration.path
|
||||
args.repository_id = "i686/some/repo/name"
|
||||
mocker.patch("ahriman.core.configuration.Configuration.load", new=lambda self, _: self.copy_from(configuration))
|
||||
extract_mock = mocker.patch("ahriman.core.repository.Explorer.repositories_extract",
|
||||
return_value=[RepositoryId("i686", "some-repo-name")])
|
||||
|
||||
assert Handler.repositories_extract(args) == [RepositoryId("i686", "some-repo-name")]
|
||||
extract_mock.assert_called_once_with(pytest.helpers.anyvar(Configuration, True), "some-repo-name", "i686")
|
||||
|
||||
|
||||
def test_repositories_extract_systemd_with_dash(args: argparse.Namespace, configuration: Configuration,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must extract repository list by using dash separated identifier
|
||||
"""
|
||||
args.configuration = configuration.path
|
||||
args.repository_id = "i686-some-repo-name"
|
||||
mocker.patch("ahriman.core.configuration.Configuration.load", new=lambda self, _: self.copy_from(configuration))
|
||||
extract_mock = mocker.patch("ahriman.core.repository.Explorer.repositories_extract",
|
||||
return_value=[RepositoryId("i686", "some-repo-name")])
|
||||
|
||||
assert Handler.repositories_extract(args) == [RepositoryId("i686", "some-repo-name")]
|
||||
extract_mock.assert_called_once_with(pytest.helpers.anyvar(Configuration, True), "some-repo-name", "i686")
|
||||
|
||||
|
||||
def test_repositories_extract_systemd_legacy(args: argparse.Namespace, configuration: Configuration,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must extract repository list for systemd units in legacy format
|
||||
"""
|
||||
args.configuration = configuration.path
|
||||
args.repository_id = "i686"
|
||||
mocker.patch("ahriman.core.configuration.Configuration.load", new=lambda self, _: self.copy_from(configuration))
|
||||
extract_mock = mocker.patch("ahriman.core.repository.Explorer.repositories_extract",
|
||||
return_value=[RepositoryId("i686", "aur")])
|
||||
|
||||
assert Handler.repositories_extract(args) == [RepositoryId("i686", "aur")]
|
||||
extract_mock.assert_called_once_with(pytest.helpers.anyvar(Configuration, True), None, "i686")
|
||||
@@ -0,0 +1,85 @@
|
||||
import argparse
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.add import Add
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.models.package_source import PackageSource
|
||||
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.package = ["ahriman"]
|
||||
args.now = False
|
||||
args.refresh = 0
|
||||
args.source = PackageSource.Auto
|
||||
args.username = "username"
|
||||
args.variable = None
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
|
||||
perform_mock = mocker.patch("ahriman.application.handlers.add.Add.perform_action")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Add.run(args, repository_id, configuration, report=False)
|
||||
on_start_mock.assert_called_once_with()
|
||||
perform_mock.assert_called_once_with(pytest.helpers.anyvar(int), args)
|
||||
|
||||
|
||||
def test_perform_action(args: argparse.Namespace, application: Application, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must perform add action
|
||||
"""
|
||||
args = _default_args(args)
|
||||
application_mock = mocker.patch("ahriman.application.application.Application.add")
|
||||
update_mock = mocker.patch("ahriman.application.handlers.update.Update.perform_action")
|
||||
|
||||
Add.perform_action(application, args)
|
||||
application_mock.assert_called_once_with(args.package, args.source, args.username)
|
||||
update_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_perform_action_with_patches(args: argparse.Namespace, application: Application, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must perform add action and insert temporary patches
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.variable = ["KEY=VALUE"]
|
||||
mocker.patch("ahriman.application.application.Application.add")
|
||||
patches_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_update")
|
||||
|
||||
Add.perform_action(application, args)
|
||||
patches_mock.assert_called_once_with(args.package[0], PkgbuildPatch("KEY", "VALUE"))
|
||||
|
||||
|
||||
def test_perform_action_with_updates(args: argparse.Namespace, application: Application, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must perform add action with updates after
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.now = True
|
||||
mocker.patch("ahriman.application.application.Application.add")
|
||||
update_mock = mocker.patch("ahriman.application.handlers.update.Update.perform_action")
|
||||
|
||||
Add.perform_action(application, args)
|
||||
update_mock.assert_called_once_with(application, args)
|
||||
@@ -0,0 +1,84 @@
|
||||
import argparse
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.handlers.archives import Archives
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.models.action import Action
|
||||
from ahriman.models.package import Package
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.action = Action.List
|
||||
args.exit_code = False
|
||||
args.info = False
|
||||
args.package = "package"
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
application_mock = mocker.patch("ahriman.core.repository.package_info.PackageInfo.package_archives",
|
||||
return_value=[package_ahriman])
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Archives.run(args, repository_id, configuration, report=False)
|
||||
application_mock.assert_called_once_with(args.package)
|
||||
check_mock.assert_called_once_with(False, True)
|
||||
print_mock.assert_called_once_with(verbose=False, log_fn=pytest.helpers.anyvar(int), separator=": ")
|
||||
|
||||
|
||||
def test_run_empty_exception(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise ExitCode exception on empty archives result
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.exit_code = True
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
mocker.patch("ahriman.core.repository.package_info.PackageInfo.package_archives", return_value=[])
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Archives.run(args, repository_id, configuration, report=False)
|
||||
check_mock.assert_called_once_with(True, False)
|
||||
|
||||
|
||||
def test_imply_with_report(args: argparse.Namespace, configuration: Configuration, database: SQLite,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must create application object with native reporting
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
|
||||
load_mock = mocker.patch("ahriman.core.repository.Repository.load")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Archives.run(args, repository_id, configuration, report=False)
|
||||
load_mock.assert_called_once_with(repository_id, configuration, database, report=True, refresh_pacman_database=0)
|
||||
|
||||
|
||||
def test_disallow_multi_architecture_run() -> None:
|
||||
"""
|
||||
must not allow multi architecture run
|
||||
"""
|
||||
assert not Archives.ALLOW_MULTI_ARCHITECTURE_RUN
|
||||
@@ -0,0 +1,63 @@
|
||||
import argparse
|
||||
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from ahriman.application.handlers.backup import Backup
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.path = Path("result.tar.gz")
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.application.handlers.backup.Backup.get_paths", return_value=[Path("path")])
|
||||
tarfile = MagicMock()
|
||||
add_mock = tarfile.__enter__.return_value = MagicMock()
|
||||
mocker.patch("ahriman.application.handlers.backup.tarfile.open", return_value=tarfile)
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Backup.run(args, repository_id, configuration, report=False)
|
||||
add_mock.add.assert_called_once_with(Path("path"))
|
||||
|
||||
|
||||
def test_get_paths(configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must get paths to be archived
|
||||
"""
|
||||
# gnupg export mock
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||
mocker.patch.object(RepositoryPaths, "root_owner", (42, 42))
|
||||
getpwuid_mock = mocker.patch("ahriman.application.handlers.backup.getpwuid", return_value=MagicMock())
|
||||
# well database does not exist so we override it
|
||||
database_mock = mocker.patch("ahriman.core.database.SQLite.database_path", return_value=configuration.path)
|
||||
|
||||
paths = Backup.get_paths(configuration)
|
||||
getpwuid_mock.assert_called_once_with(42)
|
||||
database_mock.assert_called_once_with(configuration)
|
||||
assert configuration.path in paths
|
||||
assert all(path.exists() for path in paths if path.name not in (".gnupg", "cache"))
|
||||
|
||||
|
||||
def test_disallow_multi_architecture_run() -> None:
|
||||
"""
|
||||
must not allow multi architecture run
|
||||
"""
|
||||
assert not Backup.ALLOW_MULTI_ARCHITECTURE_RUN
|
||||
@@ -0,0 +1,98 @@
|
||||
import argparse
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.handlers.change import Change
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.models.action import Action
|
||||
from ahriman.models.changes import Changes
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.action = Action.List
|
||||
args.exit_code = False
|
||||
args.package = "package"
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
application_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_get",
|
||||
return_value=Changes("sha", "change"))
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Change.run(args, repository_id, configuration, report=False)
|
||||
application_mock.assert_called_once_with(args.package)
|
||||
check_mock.assert_called_once_with(False, True)
|
||||
print_mock.assert_called_once_with(verbose=True, log_fn=pytest.helpers.anyvar(int), separator="")
|
||||
|
||||
|
||||
def test_run_empty_exception(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise ExitCode exception on empty changes result
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.exit_code = True
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_get", return_value=Changes())
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Change.run(args, repository_id, configuration, report=False)
|
||||
check_mock.assert_called_once_with(True, False)
|
||||
|
||||
|
||||
def test_run_remove(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must remove package changes
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.action = Action.Remove
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
update_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_update")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Change.run(args, repository_id, configuration, report=False)
|
||||
update_mock.assert_called_once_with(args.package, Changes())
|
||||
|
||||
|
||||
def test_imply_with_report(args: argparse.Namespace, configuration: Configuration, database: SQLite,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must create application object with native reporting
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
|
||||
load_mock = mocker.patch("ahriman.core.repository.Repository.load")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Change.run(args, repository_id, configuration, report=False)
|
||||
load_mock.assert_called_once_with(repository_id, configuration, database, report=True, refresh_pacman_database=0)
|
||||
|
||||
|
||||
def test_disallow_multi_architecture_run() -> None:
|
||||
"""
|
||||
must not allow multi architecture run
|
||||
"""
|
||||
assert not Change.ALLOW_MULTI_ARCHITECTURE_RUN
|
||||
@@ -0,0 +1,41 @@
|
||||
import argparse
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.handlers.clean import Clean
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.repository import Repository
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.cache = False
|
||||
args.chroot = False
|
||||
args.manual = False
|
||||
args.packages = False
|
||||
args.pacman = False
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
application_mock = mocker.patch("ahriman.application.application.Application.clean")
|
||||
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Clean.run(args, repository_id, configuration, report=False)
|
||||
application_mock.assert_called_once_with(cache=False, chroot=False, manual=False, packages=False, pacman=False)
|
||||
on_start_mock.assert_called_once_with()
|
||||
@@ -0,0 +1,110 @@
|
||||
import argparse
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.copy import Copy
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.models.build_status import BuildStatusEnum
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.package_source import PackageSource
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.source = "source"
|
||||
args.package = ["ahriman"]
|
||||
args.exit_code = False
|
||||
args.remove = False
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
database: SQLite, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
mocker.patch("ahriman.core.repository.Repository.packages", return_value=[package_ahriman])
|
||||
application_mock = mocker.patch("ahriman.application.handlers.copy.Copy.copy_package")
|
||||
update_mock = mocker.patch("ahriman.application.application.Application.update")
|
||||
remove_mock = mocker.patch("ahriman.application.application.Application.remove")
|
||||
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Copy.run(args, repository_id, configuration, report=False)
|
||||
application_mock.assert_called_once_with(package_ahriman, pytest.helpers.anyvar(int), pytest.helpers.anyvar(int))
|
||||
update_mock.assert_called_once_with([])
|
||||
remove_mock.assert_not_called()
|
||||
on_start_mock.assert_called_once_with()
|
||||
|
||||
|
||||
def test_run_remove(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
database: SQLite, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command and remove packages afterward
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.remove = True
|
||||
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
mocker.patch("ahriman.core.repository.Repository.packages", return_value=[package_ahriman])
|
||||
mocker.patch("ahriman.application.handlers.copy.Copy.copy_package")
|
||||
mocker.patch("ahriman.application.application.Application.update")
|
||||
remove_mock = mocker.patch("ahriman.application.application.Application.remove")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Copy.run(args, repository_id, configuration, report=False)
|
||||
remove_mock.assert_called_once_with(args.package)
|
||||
|
||||
|
||||
def test_run_empty_exception(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
database: SQLite, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise ExitCode exception on empty result
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.exit_code = True
|
||||
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
mocker.patch("ahriman.core.repository.Repository.packages", return_value=[])
|
||||
mocker.patch("ahriman.application.application.Application.update")
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Copy.run(args, repository_id, configuration, report=False)
|
||||
check_mock.assert_called_once_with(True, [])
|
||||
|
||||
|
||||
def test_copy_package(package_ahriman: Package, application: Application, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must copy package between repositories and its metadata
|
||||
"""
|
||||
add_mock = mocker.patch("ahriman.application.application.Application.add")
|
||||
changes_get_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_get")
|
||||
changes_update_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_update")
|
||||
deps_get_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_dependencies_get")
|
||||
deps_update_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_dependencies_update")
|
||||
package_update_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_update")
|
||||
path = application.repository.paths.repository / package_ahriman.packages[package_ahriman.base].filename
|
||||
|
||||
Copy.copy_package(package_ahriman, application, application)
|
||||
add_mock.assert_called_once_with([str(path)], PackageSource.Archive)
|
||||
changes_get_mock.assert_called_once_with(package_ahriman.base)
|
||||
changes_update_mock.assert_called_once_with(package_ahriman.base, changes_get_mock.return_value)
|
||||
deps_get_mock.assert_called_once_with(package_ahriman.base)
|
||||
deps_update_mock.assert_called_once_with(package_ahriman.base, deps_get_mock.return_value)
|
||||
package_update_mock.assert_called_once_with(package_ahriman, BuildStatusEnum.Pending)
|
||||
@@ -0,0 +1,78 @@
|
||||
import argparse
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.handlers.daemon import Daemon
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.models.package import Package
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.interval = 60 * 60 * 12
|
||||
args.partitions = True
|
||||
args.refresh = 0
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, package_ahriman: Package, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
run_mock = mocker.patch("ahriman.application.handlers.update.Update.run")
|
||||
iter_mock = mocker.patch("ahriman.application.application.updates_iterator.UpdatesIterator.__iter__",
|
||||
return_value=iter([[package_ahriman.base]]))
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Daemon.run(args, repository_id, configuration, report=True)
|
||||
args.package = [package_ahriman.base]
|
||||
run_mock.assert_called_once_with(args, repository_id, configuration, report=True)
|
||||
iter_mock.assert_called_once_with()
|
||||
|
||||
|
||||
def test_run_no_partitions(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command without partitioning
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.partitions = False
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
run_mock = mocker.patch("ahriman.application.handlers.update.Update.run")
|
||||
iter_mock = mocker.patch("ahriman.application.application.updates_iterator.UpdatesIterator.__iter__",
|
||||
return_value=iter([[]]))
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Daemon.run(args, repository_id, configuration, report=True)
|
||||
run_mock.assert_called_once_with(args, repository_id, configuration, report=True)
|
||||
iter_mock.assert_called_once_with()
|
||||
|
||||
|
||||
def test_run_no_updates(args: argparse.Namespace, configuration: Configuration, package_ahriman: Package,
|
||||
repository: Repository, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip empty update list
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
run_mock = mocker.patch("ahriman.application.handlers.update.Update.run")
|
||||
iter_mock = mocker.patch("ahriman.application.application.updates_iterator.UpdatesIterator.__iter__",
|
||||
return_value=iter([[package_ahriman.base], None]))
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Daemon.run(args, repository_id, configuration, report=True)
|
||||
args.package = [package_ahriman.base]
|
||||
run_mock.assert_called_once_with(args, repository_id, configuration, report=True)
|
||||
iter_mock.assert_called_once_with()
|
||||
@@ -0,0 +1,88 @@
|
||||
import argparse
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.handlers.dump import Dump
|
||||
from ahriman.core.configuration import Configuration
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.info = False
|
||||
args.key = None
|
||||
args.section = None
|
||||
args.secure = True
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
application_mock = mocker.patch("ahriman.core.configuration.Configuration.dump",
|
||||
return_value=configuration.dump())
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Dump.run(args, repository_id, configuration, report=False)
|
||||
application_mock.assert_called_once_with()
|
||||
print_mock.assert_called()
|
||||
|
||||
|
||||
def test_run_info(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command with info
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.info = True
|
||||
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Dump.run(args, repository_id, configuration, report=False)
|
||||
print_mock.assert_called()
|
||||
|
||||
|
||||
def test_run_section(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command with filter by section
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.section = "settings"
|
||||
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Dump.run(args, repository_id, configuration, report=False)
|
||||
print_mock.assert_called_once_with(verbose=False, log_fn=pytest.helpers.anyvar(int), separator=" = ")
|
||||
|
||||
|
||||
def test_run_section_key(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command with filter by section and key
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.section = "settings"
|
||||
args.key = "include"
|
||||
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
application_mock = mocker.patch("ahriman.core.configuration.Configuration.dump")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Dump.run(args, repository_id, configuration, report=False)
|
||||
application_mock.assert_not_called()
|
||||
print_mock.assert_called_once_with(verbose=False, log_fn=pytest.helpers.anyvar(int), separator=": ")
|
||||
|
||||
|
||||
def test_disallow_multi_architecture_run() -> None:
|
||||
"""
|
||||
must not allow multi architecture run
|
||||
"""
|
||||
assert not Dump.ALLOW_MULTI_ARCHITECTURE_RUN
|
||||
@@ -0,0 +1,54 @@
|
||||
import argparse
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.ahriman import _parser
|
||||
from ahriman.application.handlers.help import Help
|
||||
from ahriman.core.configuration import Configuration
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.parser = _parser
|
||||
args.subcommand = None
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
parse_mock = mocker.patch("argparse.ArgumentParser.parse_args")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Help.run(args, repository_id, configuration, report=False)
|
||||
parse_mock.assert_called_once_with(["--help"])
|
||||
|
||||
|
||||
def test_run_command(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command for specific subcommand
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.subcommand = "aur-search"
|
||||
parse_mock = mocker.patch("argparse.ArgumentParser.parse_args")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Help.run(args, repository_id, configuration, report=False)
|
||||
parse_mock.assert_called_once_with(["aur-search", "--help"])
|
||||
|
||||
|
||||
def test_disallow_multi_architecture_run() -> None:
|
||||
"""
|
||||
must not allow multi architecture run
|
||||
"""
|
||||
assert not Help.ALLOW_MULTI_ARCHITECTURE_RUN
|
||||
@@ -0,0 +1,53 @@
|
||||
import argparse
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.handlers.hold import Hold
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.models.action import Action
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.package = ["ahriman"]
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.action = Action.Update
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
hold_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_hold_update")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Hold.run(args, repository_id, configuration, report=False)
|
||||
hold_mock.assert_called_once_with("ahriman", enabled=True)
|
||||
|
||||
|
||||
def test_run_remove(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must remove held status
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.action = Action.Remove
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
hold_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_hold_update")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Hold.run(args, repository_id, configuration, report=False)
|
||||
hold_mock.assert_called_once_with("ahriman", enabled=False)
|
||||
@@ -0,0 +1,43 @@
|
||||
import argparse
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.handlers.key_import import KeyImport
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.repository import Repository
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.key = "0xE989490C"
|
||||
args.key_server = "keyserver.ubuntu.com"
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
application_mock = mocker.patch("ahriman.core.sign.gpg.GPG.key_import")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
KeyImport.run(args, repository_id, configuration, report=False)
|
||||
application_mock.assert_called_once_with(args.key_server, args.key)
|
||||
|
||||
|
||||
def test_disallow_multi_architecture_run() -> None:
|
||||
"""
|
||||
must not allow multi architecture run
|
||||
"""
|
||||
assert not KeyImport.ALLOW_MULTI_ARCHITECTURE_RUN
|
||||
@@ -0,0 +1,232 @@
|
||||
import argparse
|
||||
import pytest
|
||||
import sys
|
||||
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.patch import Patch
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.models.action import Action
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.package = "ahriman"
|
||||
args.exit_code = False
|
||||
args.remove = False
|
||||
args.track = ["*.diff", "*.patch"]
|
||||
args.variable = None
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.action = Action.Update
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
patch_mock = mocker.patch("ahriman.application.handlers.patch.Patch.patch_create_from_diff",
|
||||
return_value=(args.package, PkgbuildPatch(None, "patch")))
|
||||
application_mock = mocker.patch("ahriman.application.handlers.patch.Patch.patch_set_create")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Patch.run(args, repository_id, configuration, report=False)
|
||||
patch_mock.assert_called_once_with(args.package, repository_id.architecture, args.track)
|
||||
application_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.package, PkgbuildPatch(None, "patch"))
|
||||
|
||||
|
||||
def test_run_function(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command with patch function flag
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.action = Action.Update
|
||||
args.patch = "patch"
|
||||
args.variable = "version"
|
||||
patch = PkgbuildPatch(args.variable, args.patch)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
patch_mock = mocker.patch("ahriman.application.handlers.patch.Patch.patch_create_from_function",
|
||||
return_value=patch)
|
||||
application_mock = mocker.patch("ahriman.application.handlers.patch.Patch.patch_set_create")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Patch.run(args, repository_id, configuration, report=False)
|
||||
patch_mock.assert_called_once_with(args.variable, args.patch)
|
||||
application_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.package, patch)
|
||||
|
||||
|
||||
def test_run_list(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command with list flag
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.action = Action.List
|
||||
args.variable = ["version"]
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
application_mock = mocker.patch("ahriman.application.handlers.patch.Patch.patch_set_list")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Patch.run(args, repository_id, configuration, report=False)
|
||||
application_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.package, ["version"], False)
|
||||
|
||||
|
||||
def test_run_remove(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command with remove flag
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.action = Action.Remove
|
||||
args.variable = ["version"]
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
application_mock = mocker.patch("ahriman.application.handlers.patch.Patch.patch_set_remove")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Patch.run(args, repository_id, configuration, report=False)
|
||||
application_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.package, ["version"])
|
||||
|
||||
|
||||
def test_patch_create_from_diff(package_ahriman: Package, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must create patch from directory tree diff
|
||||
"""
|
||||
patch = PkgbuildPatch(None, "patch")
|
||||
path = Path("local")
|
||||
mocker.patch("pathlib.Path.mkdir")
|
||||
package_mock = mocker.patch("ahriman.models.package.Package.from_build", return_value=package_ahriman)
|
||||
sources_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.patch_create", return_value=patch.value)
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
assert Patch.patch_create_from_diff(path, repository_id.architecture, ["*.diff"]) == (package_ahriman.base, patch)
|
||||
package_mock.assert_called_once_with(path, repository_id.architecture, None)
|
||||
sources_mock.assert_called_once_with(path, "*.diff")
|
||||
|
||||
|
||||
def test_patch_create_from_function(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must create function patch from file
|
||||
"""
|
||||
patch = PkgbuildPatch("version", "patch")
|
||||
read_mock = mocker.patch("pathlib.Path.read_text", return_value=patch.value)
|
||||
|
||||
assert Patch.patch_create_from_function(patch.key, Path("local")) == patch
|
||||
read_mock.assert_called_once_with(encoding="utf8")
|
||||
|
||||
|
||||
def test_patch_create_from_function_stdin(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must create function patch from stdin
|
||||
"""
|
||||
patch = PkgbuildPatch("version", "This is a patch")
|
||||
mocker.patch.object(sys, "stdin", patch.value.splitlines())
|
||||
assert Patch.patch_create_from_function(patch.key, None) == patch
|
||||
|
||||
|
||||
def test_patch_create_from_function_strip(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must remove spaces at the beginning and at the end of the line
|
||||
"""
|
||||
patch = PkgbuildPatch("version", "This is a patch")
|
||||
mocker.patch.object(sys, "stdin", ["\n"] + patch.value.splitlines() + ["\n"])
|
||||
assert Patch.patch_create_from_function(patch.key, None) == patch
|
||||
|
||||
|
||||
def test_patch_create_from_function_array(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must correctly read array variable
|
||||
"""
|
||||
patch = PkgbuildPatch("version", ["array", "patch"])
|
||||
mocker.patch("pathlib.Path.read_text", return_value=f"({" ".join(patch.value)})")
|
||||
assert Patch.patch_create_from_function(patch.key, Path("local")) == patch
|
||||
|
||||
|
||||
def test_patch_set_list(application: Application, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must list available patches for the command
|
||||
"""
|
||||
get_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_get",
|
||||
return_value=[PkgbuildPatch(None, "patch"), PkgbuildPatch("version", "value")])
|
||||
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
|
||||
Patch.patch_set_list(application, "ahriman", ["version"], False)
|
||||
get_mock.assert_called_once_with("ahriman", None)
|
||||
print_mock.assert_called_once_with(verbose=True, log_fn=pytest.helpers.anyvar(int), separator=" = ")
|
||||
check_mock.assert_called_once_with(False, [PkgbuildPatch(key='version', value='value')])
|
||||
|
||||
|
||||
def test_patch_set_list_all(application: Application, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must list all available patches for the command
|
||||
"""
|
||||
get_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_get",
|
||||
return_value=[PkgbuildPatch(None, "patch")])
|
||||
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
|
||||
Patch.patch_set_list(application, "ahriman", None, False)
|
||||
get_mock.assert_called_once_with("ahriman", None)
|
||||
print_mock.assert_called_once_with(verbose=True, log_fn=pytest.helpers.anyvar(int), separator=" = ")
|
||||
check_mock.assert_called_once_with(False, [PkgbuildPatch(key=None, value='patch')])
|
||||
|
||||
|
||||
def test_patch_set_list_empty_exception(application: Application, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise ExitCode exception on empty patch list
|
||||
"""
|
||||
mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_get", return_value={})
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
|
||||
Patch.patch_set_list(application, "ahriman", [], True)
|
||||
check_mock.assert_called_once_with(True, [])
|
||||
|
||||
|
||||
def test_patch_set_create(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must create patch set for the package
|
||||
"""
|
||||
create_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_update")
|
||||
Patch.patch_set_create(application, package_ahriman.base, PkgbuildPatch("version", package_ahriman.version))
|
||||
create_mock.assert_called_once_with(package_ahriman.base, PkgbuildPatch("version", package_ahriman.version))
|
||||
|
||||
|
||||
def test_patch_set_remove(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must remove patch set for the package
|
||||
"""
|
||||
remove_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_remove")
|
||||
Patch.patch_set_remove(application, package_ahriman.base, ["version"])
|
||||
remove_mock.assert_called_once_with(package_ahriman.base, "version")
|
||||
|
||||
|
||||
def test_patch_set_remove_all(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must remove all patches for the package
|
||||
"""
|
||||
remove_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_remove")
|
||||
Patch.patch_set_remove(application, package_ahriman.base, None)
|
||||
remove_mock.assert_called_once_with(package_ahriman.base, None)
|
||||
|
||||
|
||||
def test_disallow_multi_architecture_run() -> None:
|
||||
"""
|
||||
must not allow multi architecture run
|
||||
"""
|
||||
assert not Patch.ALLOW_MULTI_ARCHITECTURE_RUN
|
||||
@@ -0,0 +1,100 @@
|
||||
import argparse
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.handlers.pkgbuild import Pkgbuild
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.models.action import Action
|
||||
from ahriman.models.changes import Changes
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.action = Action.List
|
||||
args.exit_code = False
|
||||
args.package = "package"
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
application_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_get",
|
||||
return_value=Changes("sha", "change", "pkgbuild content"))
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Pkgbuild.run(args, repository_id, configuration, report=False)
|
||||
application_mock.assert_called_once_with(args.package)
|
||||
check_mock.assert_called_once_with(False, True)
|
||||
print_mock.assert_called_once_with(verbose=True, log_fn=pytest.helpers.anyvar(int), separator="")
|
||||
|
||||
|
||||
def test_run_empty_exception(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise ExitCode exception on empty pkgbuild result
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.exit_code = True
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_get", return_value=Changes())
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Pkgbuild.run(args, repository_id, configuration, report=False)
|
||||
check_mock.assert_called_once_with(True, False)
|
||||
|
||||
|
||||
def test_run_remove(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must remove package pkgbuild
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.action = Action.Remove
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
changes = Changes("sha", "change", "pkgbuild content")
|
||||
mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_get", return_value=changes)
|
||||
update_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_update")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Pkgbuild.run(args, repository_id, configuration, report=False)
|
||||
update_mock.assert_called_once_with(args.package, Changes("sha", "change", None))
|
||||
|
||||
|
||||
def test_imply_with_report(args: argparse.Namespace, configuration: Configuration, database: SQLite,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must create application object with native reporting
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
|
||||
load_mock = mocker.patch("ahriman.core.repository.Repository.load")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Pkgbuild.run(args, repository_id, configuration, report=False)
|
||||
load_mock.assert_called_once_with(repository_id, configuration, database, report=True, refresh_pacman_database=0)
|
||||
|
||||
|
||||
def test_disallow_multi_architecture_run() -> None:
|
||||
"""
|
||||
must not allow multi architecture run
|
||||
"""
|
||||
assert not Pkgbuild.ALLOW_MULTI_ARCHITECTURE_RUN
|
||||
@@ -0,0 +1,198 @@
|
||||
import argparse
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest.mock import call as MockCall
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.rebuild import Rebuild
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.models.build_status import BuildStatus, BuildStatusEnum
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.packagers import Packagers
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.depends_on = None
|
||||
args.dry_run = False
|
||||
args.from_database = False
|
||||
args.exit_code = False
|
||||
args.increment = True
|
||||
args.status = None
|
||||
args.username = "username"
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, package_ahriman: Package, configuration: Configuration,
|
||||
repository: Repository, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
result = Result()
|
||||
result.add_updated(package_ahriman)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
extract_mock = mocker.patch("ahriman.application.handlers.rebuild.Rebuild.extract_packages",
|
||||
return_value=[package_ahriman])
|
||||
application_packages_mock = mocker.patch("ahriman.core.repository.repository.Repository.packages_depend_on",
|
||||
return_value=[package_ahriman])
|
||||
application_mock = mocker.patch("ahriman.application.application.Application.update", return_value=result)
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Rebuild.run(args, repository_id, configuration, report=False)
|
||||
extract_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.status, from_database=args.from_database)
|
||||
application_packages_mock.assert_called_once_with([package_ahriman], None)
|
||||
application_mock.assert_called_once_with([package_ahriman], Packagers(args.username), bump_pkgrel=args.increment)
|
||||
check_mock.assert_has_calls([MockCall(False, [package_ahriman]), MockCall(False, True)])
|
||||
on_start_mock.assert_called_once_with()
|
||||
|
||||
|
||||
def test_run_extract_packages(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command from database
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.from_database = True
|
||||
args.dry_run = True
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
mocker.patch("ahriman.application.application.Application.add")
|
||||
mocker.patch("ahriman.application.application.Application.print_updates")
|
||||
extract_mock = mocker.patch("ahriman.application.handlers.rebuild.Rebuild.extract_packages", return_value=[])
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Rebuild.run(args, repository_id, configuration, report=False)
|
||||
extract_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.status, from_database=args.from_database)
|
||||
|
||||
|
||||
def test_run_dry_run(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command without update itself
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.dry_run = True
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
mocker.patch("ahriman.application.handlers.rebuild.Rebuild.extract_packages", return_value=[package_ahriman])
|
||||
application_mock = mocker.patch("ahriman.application.application.Application.update")
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
print_mock = mocker.patch("ahriman.application.application.Application.print_updates")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Rebuild.run(args, repository_id, configuration, report=False)
|
||||
application_mock.assert_not_called()
|
||||
check_mock.assert_called_once_with(False, [package_ahriman])
|
||||
print_mock.assert_called_once_with([package_ahriman], log_fn=pytest.helpers.anyvar(int))
|
||||
|
||||
|
||||
def test_run_filter(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command with depends on filter
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.depends_on = ["python-aur"]
|
||||
mocker.patch("ahriman.application.application.Application.update")
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
mocker.patch("ahriman.application.handlers.rebuild.Rebuild.extract_packages", return_value=[])
|
||||
application_packages_mock = mocker.patch("ahriman.core.repository.repository.Repository.packages_depend_on")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Rebuild.run(args, repository_id, configuration, report=False)
|
||||
application_packages_mock.assert_called_once_with([], ["python-aur"])
|
||||
|
||||
|
||||
def test_run_without_filter(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command for all packages if no filter supplied
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.application.application.Application.update")
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
mocker.patch("ahriman.application.handlers.rebuild.Rebuild.extract_packages", return_value=[])
|
||||
application_packages_mock = mocker.patch("ahriman.core.repository.repository.Repository.packages_depend_on")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Rebuild.run(args, repository_id, configuration, report=False)
|
||||
application_packages_mock.assert_called_once_with([], None)
|
||||
|
||||
|
||||
def test_run_update_empty_exception(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise ExitCode exception on empty update list
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.exit_code = True
|
||||
args.dry_run = True
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
mocker.patch("ahriman.application.handlers.rebuild.Rebuild.extract_packages")
|
||||
mocker.patch("ahriman.core.repository.repository.Repository.packages_depend_on", return_value=[])
|
||||
mocker.patch("ahriman.application.application.Application.print_updates")
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Rebuild.run(args, repository_id, configuration, report=False)
|
||||
check_mock.assert_called_once_with(True, [])
|
||||
|
||||
|
||||
def test_run_build_empty_exception(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise ExitCode exception on empty update result
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.exit_code = True
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
mocker.patch("ahriman.application.handlers.rebuild.Rebuild.extract_packages")
|
||||
mocker.patch("ahriman.core.repository.repository.Repository.packages_depend_on", return_value=[package_ahriman])
|
||||
mocker.patch("ahriman.application.application.Application.update", return_value=Result())
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Rebuild.run(args, repository_id, configuration, report=False)
|
||||
check_mock.assert_has_calls([MockCall(True, [package_ahriman]), MockCall(True, False)])
|
||||
|
||||
|
||||
def test_extract_packages(application: Application, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must extract packages from database
|
||||
"""
|
||||
packages_mock = mocker.patch("ahriman.core.repository.repository.Repository.packages")
|
||||
Rebuild.extract_packages(application, None, from_database=False)
|
||||
packages_mock.assert_called_once_with()
|
||||
|
||||
|
||||
def test_extract_packages_by_status(application: Application, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must extract packages from database and filter them by status
|
||||
"""
|
||||
packages_mock = mocker.patch("ahriman.core.database.SQLite.packages_get", return_value=[
|
||||
("package1", BuildStatus(BuildStatusEnum.Success)),
|
||||
("package2", BuildStatus(BuildStatusEnum.Failed)),
|
||||
])
|
||||
assert Rebuild.extract_packages(application, BuildStatusEnum.Failed, from_database=True) == ["package2"]
|
||||
packages_mock.assert_called_once_with(application.repository_id)
|
||||
|
||||
|
||||
def test_extract_packages_from_database(application: Application, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must extract packages from database
|
||||
"""
|
||||
packages_mock = mocker.patch("ahriman.core.database.SQLite.packages_get")
|
||||
Rebuild.extract_packages(application, None, from_database=True)
|
||||
packages_mock.assert_called_once_with(application.repository_id)
|
||||
@@ -0,0 +1,27 @@
|
||||
import argparse
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.handlers.reload import Reload
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.repository import Repository
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
run_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.configuration_reload")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Reload.run(args, repository_id, configuration, report=False)
|
||||
run_mock.assert_called_once_with()
|
||||
|
||||
|
||||
def test_disallow_multi_architecture_run() -> None:
|
||||
"""
|
||||
must not allow multi architecture run
|
||||
"""
|
||||
assert not Reload.ALLOW_MULTI_ARCHITECTURE_RUN
|
||||
@@ -0,0 +1,37 @@
|
||||
import argparse
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.handlers.remove import Remove
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.repository import Repository
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.package = []
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
application_mock = mocker.patch("ahriman.application.application.Application.remove")
|
||||
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Remove.run(args, repository_id, configuration, report=False)
|
||||
application_mock.assert_called_once_with([])
|
||||
on_start_mock.assert_called_once_with()
|
||||
@@ -0,0 +1,62 @@
|
||||
import argparse
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.handlers.remove_unknown import RemoveUnknown
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.models.package import Package
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.dry_run = False
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, package_ahriman: Package, configuration: Configuration,
|
||||
repository: Repository, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
application_mock = mocker.patch("ahriman.application.application.Application.unknown",
|
||||
return_value=[package_ahriman])
|
||||
remove_mock = mocker.patch("ahriman.application.application.Application.remove")
|
||||
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
RemoveUnknown.run(args, repository_id, configuration, report=False)
|
||||
application_mock.assert_called_once_with()
|
||||
remove_mock.assert_called_once_with([package_ahriman])
|
||||
on_start_mock.assert_called_once_with()
|
||||
|
||||
|
||||
def test_run_dry_run(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run simplified command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.dry_run = True
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
application_mock = mocker.patch("ahriman.application.application.Application.unknown",
|
||||
return_value=[package_ahriman])
|
||||
remove_mock = mocker.patch("ahriman.application.application.Application.remove")
|
||||
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
RemoveUnknown.run(args, repository_id, configuration, report=False)
|
||||
application_mock.assert_called_once_with()
|
||||
remove_mock.assert_not_called()
|
||||
print_mock.assert_called_once_with(verbose=False, log_fn=pytest.helpers.anyvar(int), separator=": ")
|
||||
@@ -0,0 +1,37 @@
|
||||
import argparse
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.handlers.repositories import Repositories
|
||||
from ahriman.core.configuration import Configuration
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.configuration = None # doesn't matter actually
|
||||
args.id_only = False
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
_, repository_id = configuration.check_loaded()
|
||||
application_mock = mocker.patch("ahriman.application.handlers.handler.Handler.repositories_extract",
|
||||
return_value=[repository_id])
|
||||
|
||||
Repositories.run(args, repository_id, configuration, report=False)
|
||||
application_mock.assert_called_once_with(pytest.helpers.anyvar(int))
|
||||
print_mock.assert_called_once_with(verbose=not args.id_only, log_fn=pytest.helpers.anyvar(int), separator=": ")
|
||||
@@ -0,0 +1,44 @@
|
||||
import argparse
|
||||
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from ahriman.application.handlers.restore import Restore
|
||||
from ahriman.core.configuration import Configuration
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.path = Path("result.tar.gz")
|
||||
args.output = Path.cwd()
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
tarfile = MagicMock()
|
||||
extract_mock = tarfile.__enter__.return_value = MagicMock()
|
||||
mocker.patch("ahriman.application.handlers.restore.tarfile.open", return_value=tarfile)
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Restore.run(args, repository_id, configuration, report=False)
|
||||
extract_mock.extractall.assert_called_once_with(path=args.output, filter="data")
|
||||
|
||||
|
||||
def test_disallow_multi_architecture_run() -> None:
|
||||
"""
|
||||
must not allow multi architecture run
|
||||
"""
|
||||
assert not Restore.ALLOW_MULTI_ARCHITECTURE_RUN
|
||||
@@ -0,0 +1,113 @@
|
||||
import argparse
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.rollback import Rollback
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.exceptions import UnknownPackageError
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.models.package import Package
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.package = "ahriman"
|
||||
args.version = "1.0.0-1"
|
||||
args.hold = False
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, repository: Repository, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
artifacts = [package.filepath for package in package_ahriman.packages.values()]
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
|
||||
load_mock = mocker.patch("ahriman.application.handlers.rollback.Rollback.package_load",
|
||||
return_value=package_ahriman)
|
||||
artifacts_mock = mocker.patch("ahriman.application.handlers.rollback.Rollback.package_artifacts",
|
||||
return_value=artifacts)
|
||||
perform_mock = mocker.patch("ahriman.application.handlers.add.Add.perform_action")
|
||||
hold_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_hold_update")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Rollback.run(args, repository_id, configuration, report=False)
|
||||
on_start_mock.assert_called_once_with()
|
||||
load_mock.assert_called_once_with(pytest.helpers.anyvar(int), package_ahriman.base, args.version)
|
||||
artifacts_mock.assert_called_once_with(pytest.helpers.anyvar(int), package_ahriman)
|
||||
perform_mock.assert_called_once_with(pytest.helpers.anyvar(int), args)
|
||||
hold_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_run_hold(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must hold package after rollback
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.hold = True
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
mocker.patch("ahriman.application.application.Application.on_start")
|
||||
mocker.patch("ahriman.application.handlers.rollback.Rollback.package_load", return_value=package_ahriman)
|
||||
mocker.patch("ahriman.application.handlers.rollback.Rollback.package_artifacts", return_value=[])
|
||||
mocker.patch("ahriman.application.handlers.add.Add.perform_action")
|
||||
hold_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_hold_update")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Rollback.run(args, repository_id, configuration, report=False)
|
||||
hold_mock.assert_called_once_with(package_ahriman.base, enabled=True)
|
||||
|
||||
|
||||
def test_package_artifacts(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must return package artifacts
|
||||
"""
|
||||
artifacts = [package.filepath for package in package_ahriman.packages.values()]
|
||||
lookup_mock = mocker.patch("ahriman.core.repository.Repository.package_archives_lookup", return_value=artifacts)
|
||||
|
||||
assert Rollback.package_artifacts(application, package_ahriman) == artifacts
|
||||
lookup_mock.assert_called_once_with(package_ahriman)
|
||||
|
||||
|
||||
def test_package_artifacts_empty(application: Application, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise UnknownPackageError if no artifacts found
|
||||
"""
|
||||
mocker.patch("ahriman.core.repository.Repository.package_archives_lookup", return_value=[])
|
||||
with pytest.raises(UnknownPackageError):
|
||||
Rollback.package_artifacts(application, package_ahriman)
|
||||
|
||||
|
||||
def test_package_load(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must load package from reporter
|
||||
"""
|
||||
package_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_get",
|
||||
return_value=[(package_ahriman, None)])
|
||||
|
||||
result = Rollback.package_load(application, package_ahriman.base, "2.0.0-1")
|
||||
assert result.version == "2.0.0-1"
|
||||
package_mock.assert_called_once_with(package_ahriman.base)
|
||||
|
||||
|
||||
def test_package_load_unknown(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise UnknownPackageError if package not found
|
||||
"""
|
||||
mocker.patch("ahriman.core.status.local_client.LocalClient.package_get", return_value=[])
|
||||
with pytest.raises(UnknownPackageError):
|
||||
Rollback.package_load(application, package_ahriman.base, package_ahriman.version)
|
||||
@@ -0,0 +1,71 @@
|
||||
import argparse
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.ahriman import _parser
|
||||
from ahriman.application.handlers.run import Run
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.exceptions import ExitCode
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.command = ["help"]
|
||||
args.parser = _parser
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
application_mock = mocker.patch("ahriman.application.handlers.run.Run.run_command")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Run.run(args, repository_id, configuration, report=False)
|
||||
application_mock.assert_called_once_with(["help"], pytest.helpers.anyvar(int))
|
||||
|
||||
|
||||
def test_run_failed(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run commands until success
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.command = ["help", "config"]
|
||||
application_mock = mocker.patch("ahriman.application.handlers.run.Run.run_command", return_value=False)
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
with pytest.raises(ExitCode):
|
||||
Run.run(args, repository_id, configuration, report=False)
|
||||
application_mock.assert_called_once_with(["help"], pytest.helpers.anyvar(int))
|
||||
|
||||
|
||||
def test_run_command(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must correctly run external command
|
||||
"""
|
||||
# because of dynamic load we need to patch exact instance of the object
|
||||
parser = _parser()
|
||||
subparser = next((action for action in parser._actions if isinstance(action, argparse._SubParsersAction)), None)
|
||||
action = subparser.choices["help"]
|
||||
execute_mock = mocker.patch.object(action.get_default("handler"), "execute")
|
||||
|
||||
Run.run_command(["help"], parser)
|
||||
execute_mock.assert_called_once_with(pytest.helpers.anyvar(int))
|
||||
|
||||
|
||||
def test_disallow_multi_architecture_run() -> None:
|
||||
"""
|
||||
must not allow multi architecture run
|
||||
"""
|
||||
assert not Run.ALLOW_MULTI_ARCHITECTURE_RUN
|
||||
@@ -0,0 +1,147 @@
|
||||
import argparse
|
||||
import dataclasses
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest.mock import call as MockCall
|
||||
|
||||
from ahriman.application.handlers.search import Search
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.exceptions import OptionError
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.models.aur_package import AURPackage
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.search = ["ahriman"]
|
||||
args.exit_code = False
|
||||
args.info = False
|
||||
args.sort_by = "name"
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
aur_package_ahriman: AURPackage, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
aur_search_mock = mocker.patch("ahriman.core.alpm.remote.AUR.multisearch", return_value=[aur_package_ahriman])
|
||||
official_search_mock = mocker.patch("ahriman.core.alpm.remote.Official.multisearch",
|
||||
return_value=[aur_package_ahriman])
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Search.run(args, repository_id, configuration, report=False)
|
||||
aur_search_mock.assert_called_once_with("ahriman")
|
||||
official_search_mock.assert_called_once_with("ahriman")
|
||||
check_mock.assert_called_once_with(False, True)
|
||||
print_mock.assert_has_calls([
|
||||
MockCall(verbose=False, log_fn=pytest.helpers.anyvar(int), separator=": "),
|
||||
MockCall(verbose=False, log_fn=pytest.helpers.anyvar(int), separator=": "),
|
||||
])
|
||||
|
||||
|
||||
def test_run_empty_exception(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise ExitCode exception on empty result list
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.exit_code = True
|
||||
mocker.patch("ahriman.core.alpm.remote.AUR.multisearch", return_value=[])
|
||||
mocker.patch("ahriman.core.alpm.remote.Official.multisearch", return_value=[])
|
||||
mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Search.run(args, repository_id, configuration, report=False)
|
||||
check_mock.assert_called_once_with(True, False)
|
||||
|
||||
|
||||
def test_run_sort(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
aur_package_ahriman: AURPackage, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command with sorting
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.alpm.remote.AUR.multisearch", return_value=[aur_package_ahriman])
|
||||
mocker.patch("ahriman.core.alpm.remote.Official.multisearch", return_value=[])
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
sort_mock = mocker.patch("ahriman.application.handlers.search.Search.sort")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Search.run(args, repository_id, configuration, report=False)
|
||||
sort_mock.assert_has_calls([
|
||||
MockCall([], "name"), MockCall().__iter__(),
|
||||
MockCall([aur_package_ahriman], "name"), MockCall().__iter__()
|
||||
])
|
||||
|
||||
|
||||
def test_run_sort_by(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
aur_package_ahriman: AURPackage, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command with sorting by specified field
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.sort_by = "field"
|
||||
mocker.patch("ahriman.core.alpm.remote.AUR.multisearch", return_value=[aur_package_ahriman])
|
||||
mocker.patch("ahriman.core.alpm.remote.Official.multisearch", return_value=[])
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
sort_mock = mocker.patch("ahriman.application.handlers.search.Search.sort")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Search.run(args, repository_id, configuration, report=False)
|
||||
sort_mock.assert_has_calls([
|
||||
MockCall([], "field"), MockCall().__iter__(),
|
||||
MockCall([aur_package_ahriman], "field"), MockCall().__iter__()
|
||||
])
|
||||
|
||||
|
||||
def test_sort(aur_package_ahriman: AURPackage) -> None:
|
||||
"""
|
||||
must sort package list
|
||||
"""
|
||||
another = dataclasses.replace(aur_package_ahriman, name="1", package_base="base")
|
||||
# sort by name
|
||||
assert Search.sort([aur_package_ahriman, another], "name") == [another, aur_package_ahriman]
|
||||
# sort by another field
|
||||
assert Search.sort([aur_package_ahriman, another], "package_base") == [aur_package_ahriman, another]
|
||||
# sort by field with the same values
|
||||
assert Search.sort([aur_package_ahriman, another], "version") == [another, aur_package_ahriman]
|
||||
|
||||
|
||||
def test_sort_exception(aur_package_ahriman: AURPackage) -> None:
|
||||
"""
|
||||
must raise an exception on unknown sorting field
|
||||
"""
|
||||
with pytest.raises(OptionError):
|
||||
Search.sort([aur_package_ahriman], "random_field")
|
||||
|
||||
|
||||
def test_disallow_multi_architecture_run() -> None:
|
||||
"""
|
||||
must not allow multi architecture run
|
||||
"""
|
||||
assert not Search.ALLOW_MULTI_ARCHITECTURE_RUN
|
||||
|
||||
|
||||
def test_sort_fields(aur_package_ahriman: AURPackage) -> None:
|
||||
"""
|
||||
must store valid field list which are allowed to be used for sorting
|
||||
"""
|
||||
expected = {field.name for field in dataclasses.fields(AURPackage)}
|
||||
assert all(field in expected for field in Search.SORT_FIELDS)
|
||||
assert all(not isinstance(getattr(aur_package_ahriman, field), list) for field in Search.SORT_FIELDS)
|
||||
@@ -0,0 +1,68 @@
|
||||
import argparse
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman import __version__
|
||||
from ahriman.application.handlers.service_updates import ServiceUpdates
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.models.package import Package
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.exit_code = False
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
package_ahriman.version = "0.0.0-1"
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
package_mock = mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman)
|
||||
application_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
ServiceUpdates.run(args, repository_id, configuration, report=False)
|
||||
package_mock.assert_called_once_with(package_ahriman.base, None)
|
||||
application_mock.assert_called_once_with(verbose=True, log_fn=pytest.helpers.anyvar(int), separator=" -> ")
|
||||
check_mock.assert_called_once_with(args.exit_code, False)
|
||||
|
||||
|
||||
def test_run_skip(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must do not perform any actions if package is up-to-date
|
||||
"""
|
||||
package_ahriman.version = f"{__version__}-1"
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman)
|
||||
application_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
ServiceUpdates.run(args, repository_id, configuration, report=False)
|
||||
application_mock.assert_not_called()
|
||||
check_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_disallow_multi_architecture_run() -> None:
|
||||
"""
|
||||
must not allow multi architecture run
|
||||
"""
|
||||
assert not ServiceUpdates.ALLOW_MULTI_ARCHITECTURE_RUN
|
||||
@@ -0,0 +1,286 @@
|
||||
import argparse
|
||||
import pytest
|
||||
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
from typing import Any
|
||||
from unittest.mock import call as MockCall
|
||||
from urllib.parse import quote_plus as url_encode
|
||||
|
||||
from ahriman.application.handlers.setup import Setup
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.exceptions import MissingArchitectureError
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
from ahriman.models.sign_settings import SignSettings
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.architecture = "x86_64"
|
||||
args.build_as_user = "ahriman"
|
||||
args.from_configuration = Path("/usr/share/devtools/pacman.conf.d/extra.conf")
|
||||
args.generate_salt = True
|
||||
args.makeflags_jobs = True
|
||||
args.mirror = "mirror"
|
||||
args.multilib = True
|
||||
args.packager = "ahriman bot <ahriman@example.com>"
|
||||
args.repository = "aur"
|
||||
args.server = None
|
||||
args.sign_key = "key"
|
||||
args.sign_target = [SignSettings.Packages]
|
||||
args.web_port = 8080
|
||||
args.web_unix_socket = Path("/var/lib/ahriman/ahriman-web.sock")
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
database: SQLite, repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
ahriman_configuration_mock = mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_ahriman")
|
||||
devtools_configuration_mock = mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_devtools")
|
||||
makepkg_configuration_mock = mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_makepkg")
|
||||
sudo_configuration_mock = mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_sudo")
|
||||
executable_mock = mocker.patch("ahriman.application.handlers.setup.Setup.executable_create")
|
||||
init_mock = mocker.patch("ahriman.core.alpm.repo.Repo.init")
|
||||
owner_guard_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.preserve_owner")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Setup.run(args, repository_id, configuration, report=False)
|
||||
owner_guard_mock.assert_called_once_with()
|
||||
ahriman_configuration_mock.assert_called_once_with(args, repository_id, configuration)
|
||||
devtools_configuration_mock.assert_called_once_with(
|
||||
repository_id, args.from_configuration, args.mirror, args.multilib, f"file://{repository_paths.repository}")
|
||||
makepkg_configuration_mock.assert_called_once_with(args.packager, args.makeflags_jobs, repository_paths)
|
||||
sudo_configuration_mock.assert_called_once_with(repository_paths, repository_id)
|
||||
executable_mock.assert_called_once_with(repository_paths, repository_id)
|
||||
init_mock.assert_called_once_with()
|
||||
|
||||
|
||||
def test_run_no_architecture_or_repository(configuration: Configuration) -> None:
|
||||
"""
|
||||
must raise MissingArchitectureError if either architecture or repository are not supplied
|
||||
"""
|
||||
_, repository_id = configuration.check_loaded()
|
||||
|
||||
args = argparse.Namespace(architecture=None, command="service-setup", repository=None)
|
||||
with pytest.raises(MissingArchitectureError):
|
||||
Setup.run(args, repository_id, configuration, report=False)
|
||||
|
||||
args = argparse.Namespace(architecture=[repository_id.architecture], command="service-setup", repository=None)
|
||||
with pytest.raises(MissingArchitectureError):
|
||||
Setup.run(args, repository_id, configuration, report=False)
|
||||
|
||||
args = argparse.Namespace(architecture=None, command="service-setup", repository=[repository_id.name])
|
||||
with pytest.raises(MissingArchitectureError):
|
||||
Setup.run(args, repository_id, configuration, report=False)
|
||||
|
||||
|
||||
def test_run_with_server(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
database: SQLite, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command with server specified
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.server = "server"
|
||||
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_ahriman")
|
||||
mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_makepkg")
|
||||
mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_sudo")
|
||||
mocker.patch("ahriman.application.handlers.setup.Setup.executable_create")
|
||||
mocker.patch("ahriman.core.alpm.repo.Repo.init")
|
||||
devtools_configuration_mock = mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_devtools")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Setup.run(args, repository_id, configuration, report=False)
|
||||
devtools_configuration_mock.assert_called_once_with(
|
||||
repository_id, args.from_configuration, args.mirror, args.multilib, "server")
|
||||
|
||||
|
||||
def test_build_command(repository_id: RepositoryId) -> None:
|
||||
"""
|
||||
must generate correct build command name
|
||||
"""
|
||||
path = Path("local")
|
||||
|
||||
build_command = Setup.build_command(path, repository_id)
|
||||
assert build_command.name == f"{repository_id.name}-{repository_id.architecture}-build"
|
||||
assert build_command.parent == path
|
||||
|
||||
|
||||
def test_configuration_create_ahriman(args: argparse.Namespace, configuration: Configuration,
|
||||
repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must create configuration for the service
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("pathlib.Path.open")
|
||||
set_option_mock = mocker.patch("ahriman.core.configuration.Configuration.set_option")
|
||||
write_mock = mocker.patch("ahriman.core.configuration.Configuration.write")
|
||||
remove_mock = mocker.patch("pathlib.Path.unlink", autospec=True)
|
||||
_, repository_id = configuration.check_loaded()
|
||||
command = Setup.build_command(repository_paths.root, repository_id)
|
||||
|
||||
Setup.configuration_create_ahriman(args, repository_id, configuration)
|
||||
set_option_mock.assert_has_calls([
|
||||
MockCall(Configuration.section_name("build", repository_id.name, repository_id.architecture), "build_command",
|
||||
str(command)),
|
||||
MockCall("repository", "name", repository_id.name),
|
||||
MockCall(Configuration.section_name("build", repository_id.name, repository_id.architecture),
|
||||
"makechrootpkg_flags", f"-U {args.build_as_user}"),
|
||||
MockCall(Configuration.section_name(
|
||||
"alpm", repository_id.name, repository_id.architecture), "mirror", args.mirror),
|
||||
MockCall(Configuration.section_name("sign", repository_id.name, repository_id.architecture), "target",
|
||||
" ".join([target.name.lower() for target in args.sign_target])),
|
||||
MockCall(Configuration.section_name("sign", repository_id.name, repository_id.architecture), "key",
|
||||
args.sign_key),
|
||||
MockCall("web", "port", str(args.web_port)),
|
||||
MockCall("status", "address", f"http://127.0.0.1:{str(args.web_port)}"),
|
||||
MockCall("web", "unix_socket", str(args.web_unix_socket)),
|
||||
MockCall("status", "address", f"http+unix://{url_encode(str(args.web_unix_socket))}"),
|
||||
MockCall("auth", "salt", pytest.helpers.anyvar(str, strict=True)),
|
||||
])
|
||||
write_mock.assert_called_once_with(pytest.helpers.anyvar(int))
|
||||
remove_mock.assert_called_once_with(configuration.include / "00-setup-overrides.ini", missing_ok=True)
|
||||
|
||||
|
||||
def test_configuration_create_ahriman_no_multilib(args: argparse.Namespace, configuration: Configuration,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must create configuration for the service without multilib repository
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.multilib = False
|
||||
mocker.patch("pathlib.Path.open")
|
||||
mocker.patch("ahriman.core.configuration.Configuration.write")
|
||||
set_option_mock = mocker.patch("ahriman.core.configuration.Configuration.set_option")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Setup.configuration_create_ahriman(args, repository_id, configuration)
|
||||
set_option_mock.assert_has_calls([
|
||||
MockCall(Configuration.section_name("alpm", repository_id.name, repository_id.architecture), "mirror",
|
||||
args.mirror),
|
||||
]) # non-strict check called intentionally
|
||||
|
||||
|
||||
def test_configuration_create_devtools(args: argparse.Namespace, configuration: Configuration,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must create configuration for the devtools
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("pathlib.Path.open")
|
||||
mocker.patch("ahriman.core.configuration.Configuration.set")
|
||||
add_section_mock = mocker.patch("ahriman.core.configuration.Configuration.add_section")
|
||||
write_mock = mocker.patch("ahriman.core.configuration.Configuration.write")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Setup.configuration_create_devtools(repository_id, args.from_configuration, None, args.multilib, "server")
|
||||
add_section_mock.assert_has_calls([MockCall("multilib"), MockCall(repository_id.name)])
|
||||
write_mock.assert_called_once_with(pytest.helpers.anyvar(int))
|
||||
|
||||
|
||||
def test_configuration_create_devtools_mirror(args: argparse.Namespace, configuration: Configuration,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must create configuration for the devtools with mirror set explicitly
|
||||
"""
|
||||
def get(section: str, key: str, **kwargs: Any) -> Any:
|
||||
if section == "core" and key == "Include":
|
||||
return str(Setup.MIRRORLIST_PATH)
|
||||
return kwargs["fallback"]
|
||||
|
||||
args = _default_args(args)
|
||||
mocker.patch("pathlib.Path.open")
|
||||
mocker.patch("ahriman.core.configuration.Configuration.set")
|
||||
mocker.patch("ahriman.core.configuration.Configuration.write")
|
||||
mocker.patch("ahriman.core.configuration.Configuration.sections", return_value=["core", "extra"])
|
||||
get_mock = mocker.patch("ahriman.core.configuration.Configuration.get", side_effect=get)
|
||||
remove_option_mock = mocker.patch("ahriman.core.configuration.Configuration.remove_option")
|
||||
set_option_mock = mocker.patch("ahriman.core.configuration.Configuration.set_option")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Setup.configuration_create_devtools(repository_id, args.from_configuration, args.mirror, args.multilib, "server")
|
||||
get_mock.assert_has_calls([MockCall("core", "Include", fallback=None), MockCall("extra", "Include", fallback=None)])
|
||||
remove_option_mock.assert_called_once_with("core", "Include")
|
||||
set_option_mock.assert_has_calls([MockCall("core", "Server", args.mirror)]) # non-strict check called intentionally
|
||||
|
||||
|
||||
def test_configuration_create_devtools_no_multilib(args: argparse.Namespace, configuration: Configuration,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must create configuration for the devtools without multilib
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("pathlib.Path.open")
|
||||
mocker.patch("ahriman.core.configuration.Configuration.set")
|
||||
write_mock = mocker.patch("ahriman.core.configuration.Configuration.write")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Setup.configuration_create_devtools(repository_id, args.from_configuration, args.mirror, False, "server")
|
||||
write_mock.assert_called_once_with(pytest.helpers.anyvar(int))
|
||||
|
||||
|
||||
def test_configuration_create_makepkg(args: argparse.Namespace, repository_paths: RepositoryPaths,
|
||||
passwd: Any, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must create makepkg configuration
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.application.handlers.setup.getpwuid", return_value=passwd)
|
||||
write_text_mock = mocker.patch("pathlib.Path.write_text", autospec=True)
|
||||
|
||||
Setup.configuration_create_makepkg(args.packager, args.makeflags_jobs, repository_paths)
|
||||
write_text_mock.assert_called_once_with(
|
||||
Path("home") / ".makepkg.conf", pytest.helpers.anyvar(str, True), encoding="utf8")
|
||||
|
||||
|
||||
def test_configuration_create_sudo(configuration: Configuration, repository_paths: RepositoryPaths,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must create sudo configuration
|
||||
"""
|
||||
chmod_text_mock = mocker.patch("pathlib.Path.chmod")
|
||||
write_text_mock = mocker.patch("pathlib.Path.write_text")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Setup.configuration_create_sudo(repository_paths, repository_id)
|
||||
chmod_text_mock.assert_called_once_with(0o400)
|
||||
write_text_mock.assert_called_once_with(pytest.helpers.anyvar(str, True), encoding="utf8")
|
||||
|
||||
|
||||
def test_executable_create(configuration: Configuration, repository_paths: RepositoryPaths,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must create executable
|
||||
"""
|
||||
symlink_mock = mocker.patch("pathlib.Path.symlink_to")
|
||||
unlink_mock = mocker.patch("pathlib.Path.unlink")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Setup.executable_create(repository_paths, repository_id)
|
||||
symlink_mock.assert_called_once_with(Setup.ARCHBUILD_COMMAND_PATH)
|
||||
unlink_mock.assert_called_once_with(missing_ok=True)
|
||||
|
||||
|
||||
def test_disallow_multi_architecture_run() -> None:
|
||||
"""
|
||||
must not allow multi architecture run
|
||||
"""
|
||||
assert not Setup.ALLOW_MULTI_ARCHITECTURE_RUN
|
||||
@@ -0,0 +1,78 @@
|
||||
import argparse
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.handlers.shell import Shell
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.repository import Repository
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.code = None
|
||||
args.verbose = False
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
application_mock = mocker.patch("ahriman.application.interactive_shell.InteractiveShell.interact")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Shell.run(args, repository_id, configuration, report=False)
|
||||
application_mock.assert_called_once_with()
|
||||
|
||||
|
||||
def test_run_eval(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command via eval
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.code = """print("hello world")"""
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
application_mock = mocker.patch("ahriman.application.interactive_shell.InteractiveShell.runcode")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Shell.run(args, repository_id, configuration, report=False)
|
||||
application_mock.assert_called_once_with(args.code)
|
||||
|
||||
|
||||
def test_run_verbose(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command with verbose option
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.verbose = True
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
read_mock = mocker.patch("pathlib.Path.read_text", return_value="")
|
||||
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
application_mock = mocker.patch("ahriman.application.interactive_shell.InteractiveShell.interact")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Shell.run(args, repository_id, configuration, report=False)
|
||||
application_mock.assert_called_once_with()
|
||||
read_mock.assert_called_once_with(encoding="utf8")
|
||||
print_mock.assert_called_once_with(verbose=False, log_fn=pytest.helpers.anyvar(int), separator=": ")
|
||||
|
||||
|
||||
def test_disallow_multi_architecture_run() -> None:
|
||||
"""
|
||||
must not allow multi architecture run
|
||||
"""
|
||||
assert not Shell.ALLOW_MULTI_ARCHITECTURE_RUN
|
||||
@@ -0,0 +1,35 @@
|
||||
import argparse
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.handlers.sign import Sign
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.repository import Repository
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.package = []
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
application_mock = mocker.patch("ahriman.application.application.Application.sign")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Sign.run(args, repository_id, configuration, report=False)
|
||||
application_mock.assert_called_once_with([])
|
||||
@@ -0,0 +1,203 @@
|
||||
import argparse
|
||||
import pytest
|
||||
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest.mock import call as MockCall
|
||||
|
||||
from ahriman.application.handlers.statistics import Statistics
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.core.utils import pretty_datetime, utcnow
|
||||
from ahriman.models.event import Event, EventType
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.repository_stats import RepositoryStats
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.chart = None
|
||||
args.event = EventType.PackageUpdated
|
||||
args.from_date = None
|
||||
args.limit = -1
|
||||
args.offset = 0
|
||||
args.package = None
|
||||
args.to_date = None
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
events = [Event("1", "1"), Event("2", "2")]
|
||||
stats = RepositoryStats(bases=1, packages=2, archive_size=3, installed_size=4)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
events_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.event_get", return_value=events)
|
||||
stats_mock = mocker.patch("ahriman.core.status.client.Client.statistics", return_value=stats)
|
||||
application_mock = mocker.patch("ahriman.application.handlers.statistics.Statistics.stats_per_package")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Statistics.run(args, repository_id, configuration, report=False)
|
||||
events_mock.assert_called_once_with(args.event, args.package, None, None, args.limit, args.offset)
|
||||
stats_mock.assert_called_once_with()
|
||||
application_mock.assert_called_once_with(args.event, events, args.chart)
|
||||
|
||||
|
||||
def test_run_for_package(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command for specific package
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.package = package_ahriman.base
|
||||
events = [Event("1", "1"), Event("2", "2")]
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
events_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.event_get", return_value=events)
|
||||
application_mock = mocker.patch("ahriman.application.handlers.statistics.Statistics.stats_for_package")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Statistics.run(args, repository_id, configuration, report=False)
|
||||
events_mock.assert_called_once_with(args.event, args.package, None, None, args.limit, args.offset)
|
||||
application_mock.assert_called_once_with(args.event, events, args.chart)
|
||||
|
||||
|
||||
def test_run_convert_from_date(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must convert from date
|
||||
"""
|
||||
args = _default_args(args)
|
||||
date = utcnow()
|
||||
args.from_date = date.isoformat()
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
mocker.patch("ahriman.application.handlers.statistics.Statistics.stats_per_package")
|
||||
events_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.event_get", return_value=[])
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Statistics.run(args, repository_id, configuration, report=False)
|
||||
events_mock.assert_called_once_with(args.event, args.package, date.timestamp(), None, args.limit, args.offset)
|
||||
|
||||
|
||||
def test_run_convert_to_date(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must convert to date
|
||||
"""
|
||||
args = _default_args(args)
|
||||
date = utcnow()
|
||||
args.to_date = date.isoformat()
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
mocker.patch("ahriman.application.handlers.statistics.Statistics.stats_per_package")
|
||||
events_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.event_get", return_value=[])
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Statistics.run(args, repository_id, configuration, report=False)
|
||||
events_mock.assert_called_once_with(args.event, args.package, None, date.timestamp(), args.limit, args.offset)
|
||||
|
||||
|
||||
def test_event_stats(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must print event stats
|
||||
"""
|
||||
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
events = [Event("event", "1"), Event("event", "2", took=42.0)]
|
||||
|
||||
Statistics.event_stats("event", events)
|
||||
print_mock.assert_called_once_with(verbose=True, log_fn=pytest.helpers.anyvar(int), separator=": ")
|
||||
|
||||
|
||||
def test_plot_packages(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must plot chart for packages
|
||||
"""
|
||||
plot_mock = mocker.patch("matplotlib.pyplot.bar")
|
||||
save_mock = mocker.patch("matplotlib.pyplot.savefig")
|
||||
local = Path("local")
|
||||
|
||||
Statistics.plot_packages("event", {"1": 1, "2": 2}, local)
|
||||
plot_mock.assert_called_once_with(["1", "2"], [1, 2])
|
||||
save_mock.assert_called_once_with(local)
|
||||
|
||||
|
||||
def test_plot_times(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must plot chart for durations
|
||||
"""
|
||||
plot_mock = mocker.patch("matplotlib.pyplot.plot")
|
||||
save_mock = mocker.patch("matplotlib.pyplot.savefig")
|
||||
local = Path("local")
|
||||
|
||||
Statistics.plot_times("event", [
|
||||
Event("", "", created=1, took=2),
|
||||
Event("", "", created=3, took=4),
|
||||
], local)
|
||||
plot_mock.assert_called_once_with((pretty_datetime(1), pretty_datetime(3)), (2, 4))
|
||||
save_mock.assert_called_once_with(local)
|
||||
|
||||
|
||||
def test_stats_for_package(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must print statistics for the package
|
||||
"""
|
||||
events = [Event("event", "1"), Event("event", "1")]
|
||||
events_mock = mocker.patch("ahriman.application.handlers.statistics.Statistics.event_stats")
|
||||
chart_plot = mocker.patch("ahriman.application.handlers.statistics.Statistics.plot_times")
|
||||
|
||||
Statistics.stats_for_package("event", events, None)
|
||||
events_mock.assert_called_once_with("event", events)
|
||||
chart_plot.assert_not_called()
|
||||
|
||||
|
||||
def test_stats_for_package_with_chart(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must generate chart for package stats
|
||||
"""
|
||||
local = Path("local")
|
||||
events = [Event("event", "1"), Event("event", "1")]
|
||||
mocker.patch("ahriman.application.handlers.statistics.Statistics.event_stats")
|
||||
chart_plot = mocker.patch("ahriman.application.handlers.statistics.Statistics.plot_times")
|
||||
|
||||
Statistics.stats_for_package("event", events, local)
|
||||
chart_plot.assert_called_once_with("event", events, local)
|
||||
|
||||
|
||||
def test_stats_per_package(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must print statistics per package
|
||||
"""
|
||||
events = [Event("event", "1"), Event("event", "2"), Event("event", "1")]
|
||||
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
events_mock = mocker.patch("ahriman.application.handlers.statistics.Statistics.event_stats")
|
||||
chart_plot = mocker.patch("ahriman.application.handlers.statistics.Statistics.plot_packages")
|
||||
|
||||
Statistics.stats_per_package("event", events, None)
|
||||
print_mock.assert_has_calls([
|
||||
MockCall(verbose=True, log_fn=pytest.helpers.anyvar(int), separator=": "),
|
||||
MockCall(verbose=True, log_fn=pytest.helpers.anyvar(int), separator=": "),
|
||||
])
|
||||
events_mock.assert_called_once_with("event", events)
|
||||
chart_plot.assert_not_called()
|
||||
|
||||
|
||||
def test_stats_per_package_with_chart(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must print statistics per package with chart
|
||||
"""
|
||||
local = Path("local")
|
||||
events = [Event("event", "1"), Event("event", "2"), Event("event", "1")]
|
||||
mocker.patch("ahriman.application.handlers.statistics.Statistics.event_stats")
|
||||
chart_plot = mocker.patch("ahriman.application.handlers.statistics.Statistics.plot_packages")
|
||||
|
||||
Statistics.stats_per_package("event", events, local)
|
||||
chart_plot.assert_called_once_with("event", {"1": 2, "2": 1}, local)
|
||||
@@ -0,0 +1,152 @@
|
||||
import argparse
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest.mock import call as MockCall
|
||||
|
||||
from ahriman.application.handlers.status import Status
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.models.build_status import BuildStatus, BuildStatusEnum
|
||||
from ahriman.models.package import Package
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.ahriman = True
|
||||
args.exit_code = False
|
||||
args.info = False
|
||||
args.package = []
|
||||
args.status = None
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
package_ahriman: Package, package_python_schedule: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
packages = [
|
||||
(package_ahriman, BuildStatus(BuildStatusEnum.Success)),
|
||||
(package_python_schedule, BuildStatus(BuildStatusEnum.Failed)),
|
||||
]
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
application_mock = mocker.patch("ahriman.core.status.Client.status_get")
|
||||
packages_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_get", return_value=packages)
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Status.run(args, repository_id, configuration, report=False)
|
||||
application_mock.assert_called_once_with()
|
||||
packages_mock.assert_called_once_with(None)
|
||||
check_mock.assert_called_once_with(False, packages)
|
||||
print_mock.assert_has_calls([
|
||||
MockCall(verbose=False, log_fn=pytest.helpers.anyvar(int), separator=": ")
|
||||
for _ in range(3)
|
||||
])
|
||||
|
||||
|
||||
def test_run_empty_exception(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise ExitCode exception on empty status result
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.exit_code = True
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
mocker.patch("ahriman.core.status.Client.status_get")
|
||||
mocker.patch("ahriman.core.status.local_client.LocalClient.package_get", return_value=[])
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Status.run(args, repository_id, configuration, report=False)
|
||||
check_mock.assert_called_once_with(True, [])
|
||||
|
||||
|
||||
def test_run_verbose(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command with detailed info
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.info = True
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
mocker.patch("ahriman.core.status.local_client.LocalClient.package_get",
|
||||
return_value=[(package_ahriman, BuildStatus(BuildStatusEnum.Success))])
|
||||
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Status.run(args, repository_id, configuration, report=False)
|
||||
print_mock.assert_has_calls([
|
||||
MockCall(verbose=True, log_fn=pytest.helpers.anyvar(int), separator=": ")
|
||||
for _ in range(2)
|
||||
])
|
||||
|
||||
|
||||
def test_run_with_package_filter(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command with package filter
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.package = [package_ahriman.base]
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
packages_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_get",
|
||||
return_value=[(package_ahriman, BuildStatus(BuildStatusEnum.Success))])
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Status.run(args, repository_id, configuration, report=False)
|
||||
packages_mock.assert_called_once_with(package_ahriman.base)
|
||||
|
||||
|
||||
def test_run_by_status(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
package_ahriman: Package, package_python_schedule: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must filter packages by status
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.status = BuildStatusEnum.Failed
|
||||
mocker.patch("ahriman.core.status.local_client.LocalClient.package_get",
|
||||
return_value=[(package_ahriman, BuildStatus(BuildStatusEnum.Success)),
|
||||
(package_python_schedule, BuildStatus(BuildStatusEnum.Failed))])
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Status.run(args, repository_id, configuration, report=False)
|
||||
print_mock.assert_has_calls([
|
||||
MockCall(verbose=False, log_fn=pytest.helpers.anyvar(int), separator=": ")
|
||||
for _ in range(2)
|
||||
])
|
||||
|
||||
|
||||
def test_imply_with_report(args: argparse.Namespace, configuration: Configuration, database: SQLite,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must create application object with native reporting
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
|
||||
load_mock = mocker.patch("ahriman.core.repository.Repository.load")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Status.run(args, repository_id, configuration, report=False)
|
||||
load_mock.assert_called_once_with(repository_id, configuration, database, report=True, refresh_pacman_database=0)
|
||||
|
||||
|
||||
def test_disallow_multi_architecture_run() -> None:
|
||||
"""
|
||||
must not allow multi architecture run
|
||||
"""
|
||||
assert not Status.ALLOW_MULTI_ARCHITECTURE_RUN
|
||||
@@ -0,0 +1,93 @@
|
||||
import argparse
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.handlers.status_update import StatusUpdate
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.models.action import Action
|
||||
from ahriman.models.build_status import BuildStatusEnum
|
||||
from ahriman.models.package import Package
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.package = None
|
||||
args.action = Action.Update
|
||||
args.status = BuildStatusEnum.Success
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
update_self_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.status_update")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
StatusUpdate.run(args, repository_id, configuration, report=False)
|
||||
update_self_mock.assert_called_once_with(args.status)
|
||||
|
||||
|
||||
def test_run_packages(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command with specified packages
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.package = ["package"]
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
update_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_status_update")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
StatusUpdate.run(args, repository_id, configuration, report=False)
|
||||
update_mock.assert_called_once_with("package", args.status)
|
||||
|
||||
|
||||
def test_run_remove(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must remove package from status page
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.package = [package_ahriman.base]
|
||||
args.action = Action.Remove
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
update_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_remove")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
StatusUpdate.run(args, repository_id, configuration, report=False)
|
||||
update_mock.assert_called_once_with(package_ahriman.base)
|
||||
|
||||
|
||||
def test_imply_with_report(args: argparse.Namespace, configuration: Configuration, database: SQLite,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must create application object with native reporting
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
|
||||
load_mock = mocker.patch("ahriman.core.repository.Repository.load")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
StatusUpdate.run(args, repository_id, configuration, report=False)
|
||||
load_mock.assert_called_once_with(repository_id, configuration, database, report=True, refresh_pacman_database=0)
|
||||
|
||||
|
||||
def test_disallow_multi_architecture_run() -> None:
|
||||
"""
|
||||
must not allow multi architecture run
|
||||
"""
|
||||
assert not StatusUpdate.ALLOW_MULTI_ARCHITECTURE_RUN
|
||||
@@ -0,0 +1,54 @@
|
||||
import argparse
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest.mock import call as MockCall
|
||||
|
||||
from ahriman.application.handlers.structure import Structure
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.models.package import Package
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.partitions = 1
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
mocker.patch("ahriman.core.repository.Repository.packages", return_value=[package_ahriman])
|
||||
packages_mock = mocker.patch("ahriman.core.tree.Tree.partition", return_value=[[package_ahriman]])
|
||||
application_mock = mocker.patch("ahriman.core.tree.Tree.resolve", return_value=[[package_ahriman]])
|
||||
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Structure.run(args, repository_id, configuration, report=False)
|
||||
packages_mock.assert_called_once_with([package_ahriman], count=args.partitions)
|
||||
application_mock.assert_called_once_with([package_ahriman])
|
||||
print_mock.assert_has_calls([
|
||||
MockCall(verbose=False, log_fn=pytest.helpers.anyvar(int), separator=": "),
|
||||
MockCall(verbose=True, log_fn=pytest.helpers.anyvar(int), separator=" "),
|
||||
MockCall(verbose=False, log_fn=pytest.helpers.anyvar(int), separator=": "),
|
||||
])
|
||||
|
||||
|
||||
def test_disallow_multi_architecture_run() -> None:
|
||||
"""
|
||||
must not allow multi architecture run
|
||||
"""
|
||||
assert not Structure.ALLOW_MULTI_ARCHITECTURE_RUN
|
||||
@@ -0,0 +1,74 @@
|
||||
import argparse
|
||||
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest.mock import call as MockCall
|
||||
|
||||
from ahriman.application.handlers.tree_migrate import TreeMigrate
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
tree_create_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
|
||||
application_mock = mocker.patch("ahriman.application.handlers.tree_migrate.TreeMigrate.tree_move")
|
||||
symlinks_mock = mocker.patch("ahriman.application.handlers.tree_migrate.TreeMigrate.symlinks_fix")
|
||||
_, repository_id = configuration.check_loaded()
|
||||
old_paths = configuration.repository_paths
|
||||
new_paths = RepositoryPaths(old_paths.root, old_paths.repository_id, _force_current_tree=True)
|
||||
|
||||
TreeMigrate.run(args, repository_id, configuration, report=False)
|
||||
tree_create_mock.assert_called_once_with()
|
||||
application_mock.assert_called_once_with(old_paths, new_paths)
|
||||
symlinks_mock.assert_called_once_with(new_paths)
|
||||
|
||||
|
||||
def test_symlinks_fix(repository_paths: RepositoryPaths, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must replace symlinks during migration
|
||||
"""
|
||||
mocker.patch("ahriman.application.handlers.tree_migrate.walk", side_effect=[
|
||||
[
|
||||
repository_paths.archive_for(package_ahriman.base) / "file",
|
||||
repository_paths.archive_for(package_ahriman.base) / "symlink",
|
||||
],
|
||||
[
|
||||
repository_paths.repository / "file",
|
||||
repository_paths.repository / "symlink",
|
||||
],
|
||||
])
|
||||
mocker.patch("pathlib.Path.exists", autospec=True, side_effect=lambda p: p.name == "file")
|
||||
unlink_mock = mocker.patch("pathlib.Path.unlink")
|
||||
symlink_mock = mocker.patch("pathlib.Path.symlink_to")
|
||||
|
||||
TreeMigrate.symlinks_fix(repository_paths)
|
||||
unlink_mock.assert_called_once_with()
|
||||
symlink_mock.assert_called_once_with(
|
||||
Path("..") /
|
||||
".." /
|
||||
".." /
|
||||
repository_paths.archive_for(package_ahriman.base).relative_to(repository_paths.root) /
|
||||
"symlink"
|
||||
)
|
||||
|
||||
|
||||
def test_move_tree(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must move tree
|
||||
"""
|
||||
rename_mock = mocker.patch("pathlib.Path.rename", autospec=True)
|
||||
root = Path("local")
|
||||
from_paths = RepositoryPaths(root, RepositoryId("arch", ""))
|
||||
to_paths = RepositoryPaths(root, RepositoryId("arch", "repo"))
|
||||
|
||||
TreeMigrate.tree_move(from_paths, to_paths)
|
||||
rename_mock.assert_has_calls([
|
||||
MockCall(from_paths.packages, to_paths.packages),
|
||||
MockCall(from_paths.pacman, to_paths.pacman),
|
||||
MockCall(from_paths.repository, to_paths.repository),
|
||||
])
|
||||
@@ -0,0 +1,57 @@
|
||||
import argparse
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.handlers.triggers import Triggers
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.trigger = []
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
application_mock = mocker.patch("ahriman.application.application.Application.on_result")
|
||||
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Triggers.run(args, repository_id, configuration, report=False)
|
||||
application_mock.assert_called_once_with(Result())
|
||||
on_start_mock.assert_called_once_with()
|
||||
|
||||
|
||||
def test_run_trigger(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run triggers specified by command line
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.trigger = ["ahriman.core.report.ReportTrigger"]
|
||||
mocker.patch("ahriman.core.repository.Repository.packages", return_value=[package_ahriman])
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
report_mock = mocker.patch("ahriman.core.report.ReportTrigger.on_result")
|
||||
upload_mock = mocker.patch("ahriman.core.upload.UploadTrigger.on_result")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Triggers.run(args, repository_id, configuration, report=False)
|
||||
report_mock.assert_called_once_with(Result(), [package_ahriman])
|
||||
upload_mock.assert_not_called()
|
||||
@@ -0,0 +1,90 @@
|
||||
import argparse
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.ahriman import _parser
|
||||
from ahriman.application.handlers.unsafe_commands import UnsafeCommands
|
||||
from ahriman.core.configuration import Configuration
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.parser = _parser
|
||||
args.subcommand = []
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
commands_mock = mocker.patch("ahriman.application.handlers.unsafe_commands.UnsafeCommands.get_unsafe_commands",
|
||||
return_value=["command"])
|
||||
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
UnsafeCommands.run(args, repository_id, configuration, report=False)
|
||||
commands_mock.assert_called_once_with(pytest.helpers.anyvar(int))
|
||||
print_mock.assert_called_once_with(verbose=True, log_fn=pytest.helpers.anyvar(int), separator=": ")
|
||||
|
||||
|
||||
def test_run_check(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command and check if command is unsafe
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.subcommand = ["clean"]
|
||||
commands_mock = mocker.patch("ahriman.application.handlers.unsafe_commands.UnsafeCommands.get_unsafe_commands",
|
||||
return_value=["command"])
|
||||
check_mock = mocker.patch("ahriman.application.handlers.unsafe_commands.UnsafeCommands.check_unsafe")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
UnsafeCommands.run(args, repository_id, configuration, report=False)
|
||||
commands_mock.assert_called_once_with(pytest.helpers.anyvar(int))
|
||||
check_mock.assert_called_once_with(["clean"], ["command"], pytest.helpers.anyvar(int))
|
||||
|
||||
|
||||
def test_check_unsafe(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must check if command is unsafe
|
||||
"""
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
UnsafeCommands.check_unsafe(["service-clean"], ["service-clean"], _parser())
|
||||
check_mock.assert_called_once_with(True, False)
|
||||
|
||||
|
||||
def test_check_unsafe_safe(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must check if command is safe
|
||||
"""
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
UnsafeCommands.check_unsafe(["package-status"], ["service-clean"], _parser())
|
||||
check_mock.assert_called_once_with(True, True)
|
||||
|
||||
|
||||
def test_get_unsafe_commands() -> None:
|
||||
"""
|
||||
must return unsafe commands
|
||||
"""
|
||||
parser = _parser()
|
||||
subparser = next(action for action in parser._actions if isinstance(action, argparse._SubParsersAction))
|
||||
commands = UnsafeCommands.get_unsafe_commands(parser)
|
||||
for command in commands:
|
||||
assert subparser.choices[command].get_default("unsafe")
|
||||
|
||||
|
||||
def test_disallow_multi_architecture_run() -> None:
|
||||
"""
|
||||
must not allow multi architecture run
|
||||
"""
|
||||
assert not UnsafeCommands.ALLOW_MULTI_ARCHITECTURE_RUN
|
||||
@@ -0,0 +1,161 @@
|
||||
import argparse
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest.mock import call as MockCall
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.update import Update
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.packagers import Packagers
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.aur = True
|
||||
args.changes = True
|
||||
args.check_files = True
|
||||
args.package = []
|
||||
args.dependencies = True
|
||||
args.dry_run = False
|
||||
args.exit_code = False
|
||||
args.increment = True
|
||||
args.local = True
|
||||
args.manual = True
|
||||
args.refresh = 0
|
||||
args.username = "username"
|
||||
args.vcs = True
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, repository: Repository,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
|
||||
perform_mock = mocker.patch("ahriman.application.handlers.update.Update.perform_action")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Update.run(args, repository_id, configuration, report=False)
|
||||
on_start_mock.assert_called_once_with()
|
||||
perform_mock.assert_called_once_with(pytest.helpers.anyvar(int), args)
|
||||
|
||||
|
||||
def test_perform_action(args: argparse.Namespace, application: Application, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must perform update action
|
||||
"""
|
||||
args = _default_args(args)
|
||||
result = Result()
|
||||
result.add_updated(package_ahriman)
|
||||
application_mock = mocker.patch("ahriman.application.application.Application.update", return_value=result)
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
dependencies_mock = mocker.patch("ahriman.application.application.Application.with_dependencies",
|
||||
return_value=[package_ahriman])
|
||||
updates_mock = mocker.patch("ahriman.application.application.Application.updates", return_value=[package_ahriman])
|
||||
changes_mock = mocker.patch("ahriman.application.application.Application.changes")
|
||||
print_mock = mocker.patch("ahriman.application.application.Application.print_updates")
|
||||
|
||||
Update.perform_action(application, args)
|
||||
application_mock.assert_called_once_with([package_ahriman],
|
||||
Packagers(args.username, {package_ahriman.base: "packager"}),
|
||||
bump_pkgrel=args.increment)
|
||||
updates_mock.assert_called_once_with(
|
||||
args.package, aur=args.aur, local=args.local, manual=args.manual, vcs=args.vcs, check_files=args.check_files)
|
||||
changes_mock.assert_called_once_with([package_ahriman])
|
||||
dependencies_mock.assert_called_once_with([package_ahriman], process_dependencies=args.dependencies)
|
||||
check_mock.assert_called_once_with(False, True)
|
||||
print_mock.assert_called_once_with([package_ahriman], log_fn=pytest.helpers.anyvar(int))
|
||||
|
||||
|
||||
def test_perform_action_empty_exception(args: argparse.Namespace, application: Application,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise ExitCode exception on empty update list
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.exit_code = True
|
||||
args.dry_run = True
|
||||
mocker.patch("ahriman.application.application.Application.updates", return_value=[])
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
|
||||
Update.perform_action(application, args)
|
||||
check_mock.assert_called_once_with(True, [])
|
||||
|
||||
|
||||
def test_perform_action_update_empty_exception(args: argparse.Namespace, application: Application,
|
||||
package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise ExitCode exception on empty build result
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.exit_code = True
|
||||
mocker.patch("ahriman.application.application.Application.update", return_value=Result())
|
||||
mocker.patch("ahriman.application.application.Application.updates", return_value=[package_ahriman])
|
||||
mocker.patch("ahriman.application.application.Application.with_dependencies", return_value=[package_ahriman])
|
||||
mocker.patch("ahriman.application.application.Application.print_updates")
|
||||
mocker.patch("ahriman.application.application.Application.changes")
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
|
||||
Update.perform_action(application, args)
|
||||
check_mock.assert_called_once_with(True, False)
|
||||
|
||||
|
||||
def test_perform_action_dry_run(args: argparse.Namespace, application: Application, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run simplified command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.dry_run = True
|
||||
application_mock = mocker.patch("ahriman.application.application.Application.update")
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
updates_mock = mocker.patch("ahriman.application.application.Application.updates", return_value=[package_ahriman])
|
||||
changes_mock = mocker.patch("ahriman.application.application.Application.changes")
|
||||
|
||||
Update.perform_action(application, args)
|
||||
updates_mock.assert_called_once_with(
|
||||
args.package, aur=args.aur, local=args.local, manual=args.manual, vcs=args.vcs, check_files=args.check_files)
|
||||
application_mock.assert_not_called()
|
||||
changes_mock.assert_called_once_with([package_ahriman])
|
||||
check_mock.assert_called_once_with(False, [package_ahriman])
|
||||
|
||||
|
||||
def test_perform_action_no_changes(args: argparse.Namespace, application: Application, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip changes calculation
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.dry_run = True
|
||||
args.changes = False
|
||||
mocker.patch("ahriman.application.application.Application.update")
|
||||
mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
mocker.patch("ahriman.application.application.Application.updates")
|
||||
changes_mock = mocker.patch("ahriman.application.application.Application.changes")
|
||||
|
||||
Update.perform_action(application, args)
|
||||
changes_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_log_fn(application: Application, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must print package updates
|
||||
"""
|
||||
logger_mock = mocker.patch("logging.Logger.info")
|
||||
Update.log_fn(application, False)("hello")
|
||||
logger_mock.assert_has_calls([MockCall("hello")])
|
||||
@@ -0,0 +1,182 @@
|
||||
import argparse
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest.mock import call as MockCall
|
||||
|
||||
from ahriman.application.handlers.users import Users
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.exceptions import PasswordError
|
||||
from ahriman.models.action import Action
|
||||
from ahriman.models.user import User
|
||||
from ahriman.models.user_access import UserAccess
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.username = "user"
|
||||
args.action = Action.Update
|
||||
args.exit_code = False
|
||||
args.key = "key"
|
||||
args.packager = "packager"
|
||||
args.password = "pa55w0rd"
|
||||
args.role = UserAccess.Reporter
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, database: SQLite, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
user = User(username=args.username, password=args.password, access=args.role,
|
||||
packager_id=args.packager, key=args.key)
|
||||
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
|
||||
mocker.patch("ahriman.models.user.User.hash_password", return_value=user)
|
||||
create_user_mock = mocker.patch("ahriman.application.handlers.users.Users.user_create", return_value=user)
|
||||
update_mock = mocker.patch("ahriman.core.database.SQLite.user_update")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Users.run(args, repository_id, configuration, report=False)
|
||||
create_user_mock.assert_called_once_with(args)
|
||||
update_mock.assert_called_once_with(user)
|
||||
|
||||
|
||||
def test_run_empty_salt(args: argparse.Namespace, configuration: Configuration, database: SQLite,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must process users with empty password salt
|
||||
"""
|
||||
configuration.remove_option("auth", "salt")
|
||||
args = _default_args(args)
|
||||
user = User(username=args.username, password=args.password, access=args.role,
|
||||
packager_id=args.packager, key=args.key)
|
||||
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
|
||||
mocker.patch("ahriman.models.user.User.hash_password", return_value=user)
|
||||
create_user_mock = mocker.patch("ahriman.application.handlers.users.Users.user_create", return_value=user)
|
||||
update_mock = mocker.patch("ahriman.core.database.SQLite.user_update")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Users.run(args, repository_id, configuration, report=False)
|
||||
create_user_mock.assert_called_once_with(args)
|
||||
update_mock.assert_called_once_with(user)
|
||||
|
||||
|
||||
def test_run_empty_salt_without_password(args: argparse.Namespace, configuration: Configuration, database: SQLite,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip salt option in case if password was empty
|
||||
"""
|
||||
configuration.remove_option("auth", "salt")
|
||||
args = _default_args(args)
|
||||
user = User(username=args.username, password="", access=args.role,
|
||||
packager_id=args.packager, key=args.key)
|
||||
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
|
||||
mocker.patch("ahriman.models.user.User.hash_password", return_value=user)
|
||||
create_user_mock = mocker.patch("ahriman.application.handlers.users.Users.user_create", return_value=user)
|
||||
update_mock = mocker.patch("ahriman.core.database.SQLite.user_update")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Users.run(args, repository_id, configuration, report=False)
|
||||
create_user_mock.assert_called_once_with(args)
|
||||
update_mock.assert_called_once_with(user)
|
||||
|
||||
|
||||
def test_run_list(args: argparse.Namespace, configuration: Configuration, database: SQLite, user: User,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must list available users
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.action = Action.List
|
||||
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
list_mock = mocker.patch("ahriman.core.database.SQLite.user_list", return_value=[user])
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Users.run(args, repository_id, configuration, report=False)
|
||||
list_mock.assert_called_once_with("user", args.role)
|
||||
check_mock.assert_called_once_with(False, [user])
|
||||
|
||||
|
||||
def test_run_empty_exception(args: argparse.Namespace, configuration: Configuration, database: SQLite,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise ExitCode exception on empty user list
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.action = Action.List
|
||||
args.exit_code = True
|
||||
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
|
||||
mocker.patch("ahriman.core.database.SQLite.user_list", return_value=[])
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Users.run(args, repository_id, configuration, report=False)
|
||||
check_mock.assert_called_once_with(True, [])
|
||||
|
||||
|
||||
def test_run_remove(args: argparse.Namespace, configuration: Configuration, database: SQLite,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must remove user if remove flag supplied
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.action = Action.Remove
|
||||
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
|
||||
remove_mock = mocker.patch("ahriman.core.database.SQLite.user_remove")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Users.run(args, repository_id, configuration, report=False)
|
||||
remove_mock.assert_called_once_with(args.username)
|
||||
|
||||
|
||||
def test_user_create(args: argparse.Namespace, user: User) -> None:
|
||||
"""
|
||||
must create user
|
||||
"""
|
||||
args = _default_args(args)
|
||||
generated = Users.user_create(args)
|
||||
assert generated.username == user.username
|
||||
assert generated.access == user.access
|
||||
|
||||
|
||||
def test_user_create_getpass(args: argparse.Namespace, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must create user and get password from command line
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.password = None
|
||||
getpass_mock = mocker.patch("getpass.getpass", return_value="password")
|
||||
|
||||
generated = Users.user_create(args)
|
||||
getpass_mock.assert_has_calls([MockCall(), MockCall("Repeat password: ")])
|
||||
assert generated.password == "password"
|
||||
|
||||
|
||||
def test_user_create_getpass_exception(args: argparse.Namespace, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise password error in case if password doesn't match
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.password = None
|
||||
mocker.patch("getpass.getpass", side_effect=lambda *_: User.generate_password(10))
|
||||
|
||||
with pytest.raises(PasswordError):
|
||||
Users.user_create(args)
|
||||
|
||||
|
||||
def test_disallow_multi_architecture_run() -> None:
|
||||
"""
|
||||
must not allow multi architecture run
|
||||
"""
|
||||
assert not Users.ALLOW_MULTI_ARCHITECTURE_RUN
|
||||
@@ -0,0 +1,162 @@
|
||||
import argparse
|
||||
import json
|
||||
import pytest
|
||||
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.handlers.validate import Validate
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.configuration.schema import CONFIGURATION_SCHEMA
|
||||
from ahriman.core.configuration.validator import Validator
|
||||
from ahriman.core.gitremote import RemotePullTrigger, RemotePushTrigger
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
"""
|
||||
default arguments for these test cases
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line arguments fixture
|
||||
|
||||
Returns:
|
||||
argparse.Namespace: generated arguments for these test cases
|
||||
"""
|
||||
args.exit_code = False
|
||||
return args
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch.object(Validator, "errors", {"node": ["error"]})
|
||||
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
application_mock = mocker.patch("ahriman.core.configuration.validator.Validator.validate", return_value=False)
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Validate.run(args, repository_id, configuration, report=False)
|
||||
application_mock.assert_called_once_with(configuration.dump())
|
||||
print_mock.assert_called_once_with(verbose=True, log_fn=pytest.helpers.anyvar(int), separator=": ")
|
||||
|
||||
|
||||
def test_run_skip(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip print if no errors found
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.configuration.validator.Validator.validate", return_value=True)
|
||||
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Validate.run(args, repository_id, configuration, report=False)
|
||||
print_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_run_default(args: argparse.Namespace, configuration: Configuration) -> None:
|
||||
"""
|
||||
must run on default configuration without errors
|
||||
"""
|
||||
args.exit_code = True
|
||||
_, repository_id = configuration.check_loaded()
|
||||
|
||||
default = Configuration.from_path(Configuration.SYSTEM_CONFIGURATION_PATH, repository_id)
|
||||
# copy autogenerated values
|
||||
for section, key in (("build", "build_command"), ("repository", "root")):
|
||||
value = configuration.get(section, key)
|
||||
default.set_option(section, key, value)
|
||||
|
||||
Validate.run(args, repository_id, default, report=False)
|
||||
|
||||
|
||||
def test_run_repo_specific_triggers(args: argparse.Namespace, configuration: Configuration,
|
||||
resource_path_root: Path) -> None:
|
||||
"""
|
||||
must correctly insert repo specific triggers
|
||||
"""
|
||||
args.exit_code = True
|
||||
_, repository_id = configuration.check_loaded()
|
||||
|
||||
# remove unused sections
|
||||
for section in ("archive", "customs3", "github:x86_64", "logs-rotation", "mirrorlist"):
|
||||
configuration.remove_section(section)
|
||||
|
||||
configuration.set_option("report", "target", "test")
|
||||
for section in ("test", "test:i686", "test:another-repo:x86_64"):
|
||||
configuration.set_option(section, "type", "html")
|
||||
configuration.set_option(section, "link_path", "http://link_path")
|
||||
configuration.set_option(section, "path", "path")
|
||||
configuration.set_option(section, "template", "template")
|
||||
configuration.set_option(section, "templates", str(resource_path_root))
|
||||
|
||||
Validate.run(args, repository_id, configuration, report=False)
|
||||
|
||||
|
||||
def test_schema(configuration: Configuration) -> None:
|
||||
"""
|
||||
must generate full schema correctly
|
||||
"""
|
||||
schema = Validate.schema(configuration)
|
||||
|
||||
# defaults
|
||||
assert schema.pop("console")
|
||||
assert schema.pop("email")
|
||||
assert schema.pop("github")
|
||||
assert schema.pop("gitremote")
|
||||
assert schema.pop("html")
|
||||
assert schema.pop("keyring")
|
||||
assert schema.pop("keyring-generator")
|
||||
assert schema.pop("mirrorlist")
|
||||
assert schema.pop("mirrorlist-generator")
|
||||
assert schema.pop("remote-call")
|
||||
assert schema.pop("remote-pull")
|
||||
assert schema.pop("remote-push")
|
||||
assert schema.pop("remote-service")
|
||||
assert schema.pop("report")
|
||||
assert schema.pop("rss")
|
||||
assert schema.pop("rsync")
|
||||
assert schema.pop("s3")
|
||||
assert schema.pop("telegram")
|
||||
assert schema.pop("upload")
|
||||
assert schema.pop("worker")
|
||||
|
||||
assert schema == CONFIGURATION_SCHEMA
|
||||
|
||||
|
||||
def test_schema_invalid_trigger(configuration: Configuration) -> None:
|
||||
"""
|
||||
must skip trigger if it caused exception on load
|
||||
"""
|
||||
configuration.set_option("build", "triggers", "some.invalid.trigger.path.Trigger")
|
||||
configuration.remove_option("build", "triggers_known")
|
||||
assert Validate.schema(configuration) == CONFIGURATION_SCHEMA
|
||||
|
||||
|
||||
def test_schema_erase_required() -> None:
|
||||
"""
|
||||
must remove required field from dictionaries recursively
|
||||
"""
|
||||
# the easiest way is to just dump to string and check
|
||||
assert "required" not in json.dumps(Validate.schema_erase_required(CONFIGURATION_SCHEMA))
|
||||
|
||||
|
||||
def test_schema_merge() -> None:
|
||||
"""
|
||||
must merge schemas correctly
|
||||
"""
|
||||
erased = Validate.schema_erase_required(CONFIGURATION_SCHEMA)
|
||||
assert Validate.schema_merge(erased, CONFIGURATION_SCHEMA) == CONFIGURATION_SCHEMA
|
||||
|
||||
merged = Validate.schema_merge(RemotePullTrigger.CONFIGURATION_SCHEMA, RemotePushTrigger.CONFIGURATION_SCHEMA)
|
||||
for key in RemotePullTrigger.CONFIGURATION_SCHEMA["gitremote"]["schema"]:
|
||||
assert key in merged["gitremote"]["schema"]
|
||||
for key in RemotePushTrigger.CONFIGURATION_SCHEMA["gitremote"]["schema"]:
|
||||
assert key in merged["gitremote"]["schema"]
|
||||
|
||||
|
||||
def test_disallow_multi_architecture_run() -> None:
|
||||
"""
|
||||
must not allow multi architecture run
|
||||
"""
|
||||
assert not Validate.ALLOW_MULTI_ARCHITECTURE_RUN
|
||||
@@ -0,0 +1,50 @@
|
||||
import argparse
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest.mock import call as MockCall
|
||||
|
||||
from ahriman.application.handlers.versions import Versions
|
||||
from ahriman.core.configuration import Configuration
|
||||
|
||||
|
||||
def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
application_mock = mocker.patch("ahriman.application.handlers.versions.Versions.package_dependencies")
|
||||
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||
|
||||
_, repository_id = configuration.check_loaded()
|
||||
Versions.run(args, repository_id, configuration, report=False)
|
||||
application_mock.assert_called_once_with("ahriman")
|
||||
print_mock.assert_has_calls([
|
||||
MockCall(verbose=False, log_fn=pytest.helpers.anyvar(int), separator=" "),
|
||||
MockCall(verbose=False, log_fn=pytest.helpers.anyvar(int), separator=" "),
|
||||
])
|
||||
|
||||
|
||||
def test_package_dependencies() -> None:
|
||||
"""
|
||||
must extract package dependencies
|
||||
"""
|
||||
packages = dict(Versions.package_dependencies("requests"))
|
||||
assert packages
|
||||
assert packages.get("urllib3") is not None
|
||||
|
||||
|
||||
def test_package_dependencies_missing() -> None:
|
||||
"""
|
||||
must extract package dependencies even if some of them are missing
|
||||
"""
|
||||
packages = dict(Versions.package_dependencies("ahriman"))
|
||||
assert packages
|
||||
assert packages.get("pyalpm") is not None
|
||||
assert packages.get("Sphinx") is None
|
||||
|
||||
|
||||
def test_disallow_multi_architecture_run() -> None:
|
||||
"""
|
||||
must not allow multi architecture run
|
||||
"""
|
||||
assert not Versions.ALLOW_MULTI_ARCHITECTURE_RUN
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,19 @@
|
||||
from ahriman.application.help_formatter import _HelpFormatter
|
||||
|
||||
|
||||
def test_whitespace_matcher(formatter: _HelpFormatter) -> None:
|
||||
"""
|
||||
must only match spaces or tabs
|
||||
"""
|
||||
assert formatter._whitespace_matcher.match(" ")
|
||||
assert formatter._whitespace_matcher.match("\t")
|
||||
|
||||
assert formatter._whitespace_matcher.match("\n") is None
|
||||
assert formatter._whitespace_matcher.match("\r") is None
|
||||
|
||||
|
||||
def test_fill_text(formatter: _HelpFormatter) -> None:
|
||||
"""
|
||||
must wrap text keeping new lines
|
||||
"""
|
||||
assert formatter._fill_text("first\n 1 longwordhere", 10, "") == "first\n 1 longwor\ndhere"
|
||||
@@ -0,0 +1,46 @@
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.interactive_shell import InteractiveShell
|
||||
|
||||
|
||||
def test_has_ipython(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must correctly check if IPython is installed
|
||||
"""
|
||||
find_spec_mock = mocker.patch("ahriman.application.interactive_shell.find_spec")
|
||||
assert InteractiveShell.has_ipython()
|
||||
find_spec_mock.assert_called_once_with("IPython.terminal.embed")
|
||||
|
||||
|
||||
def test_has_ipython_module_not_found(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must return False if IPython is not installed
|
||||
"""
|
||||
mocker.patch("ahriman.application.interactive_shell.find_spec", side_effect=ModuleNotFoundError)
|
||||
assert not InteractiveShell.has_ipython()
|
||||
|
||||
|
||||
def test_interact(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must call IPython shell
|
||||
"""
|
||||
mocker.patch("ahriman.application.interactive_shell.InteractiveShell.has_ipython", return_value=True)
|
||||
banner_mock = mocker.patch("IPython.terminal.embed.InteractiveShellEmbed.show_banner")
|
||||
interact_mock = mocker.patch("IPython.terminal.embed.InteractiveShellEmbed.interact")
|
||||
|
||||
shell = InteractiveShell()
|
||||
shell.interact()
|
||||
banner_mock.assert_called_once_with()
|
||||
interact_mock.assert_called_once_with()
|
||||
|
||||
|
||||
def test_interact_no_ipython(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must call builtin shell if no IPython available
|
||||
"""
|
||||
mocker.patch("ahriman.application.interactive_shell.InteractiveShell.has_ipython", return_value=None)
|
||||
interact_mock = mocker.patch("code.InteractiveConsole.interact")
|
||||
|
||||
shell = InteractiveShell()
|
||||
shell.interact()
|
||||
interact_mock.assert_called_once_with(shell)
|
||||
@@ -0,0 +1,296 @@
|
||||
import argparse
|
||||
import fcntl
|
||||
import os
|
||||
import pytest
|
||||
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
from tempfile import NamedTemporaryFile
|
||||
from unittest.mock import MagicMock, call as MockCall
|
||||
|
||||
from ahriman import __version__
|
||||
from ahriman.application.lock import Lock
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.exceptions import DuplicateRunError, UnsafeRunError
|
||||
from ahriman.models.build_status import BuildStatus, BuildStatusEnum
|
||||
from ahriman.models.internal_status import InternalStatus
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
def test_path(args: argparse.Namespace, configuration: Configuration) -> None:
|
||||
"""
|
||||
must create path variable correctly
|
||||
"""
|
||||
_, repository_id = configuration.check_loaded()
|
||||
|
||||
assert Lock(args, repository_id, configuration).path is None
|
||||
|
||||
args.lock = Path("/run/ahriman.pid")
|
||||
assert Lock(args, repository_id, configuration).path == Path("/run/ahriman_x86_64-aur.pid")
|
||||
|
||||
args.lock = Path("ahriman.pid")
|
||||
assert Lock(args, repository_id, configuration).path == Path("/run/ahriman/ahriman_x86_64-aur.pid")
|
||||
|
||||
assert Lock(args, RepositoryId("", ""), configuration).path == Path("/run/ahriman/ahriman.pid")
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
args.lock = Path("/")
|
||||
assert Lock(args, repository_id, configuration).path # special case
|
||||
|
||||
|
||||
def test_perform_lock(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must lock file with fcntl
|
||||
"""
|
||||
flock_mock = mocker.patch("fcntl.flock")
|
||||
assert Lock.perform_lock(1)
|
||||
flock_mock.assert_called_once_with(1, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||
|
||||
|
||||
def test_perform_lock_exception(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must return False on OSError
|
||||
"""
|
||||
mocker.patch("fcntl.flock", side_effect=OSError)
|
||||
assert not Lock.perform_lock(1)
|
||||
|
||||
|
||||
def test_open(lock: Lock, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must open file
|
||||
"""
|
||||
open_mock = mocker.patch("pathlib.Path.open")
|
||||
lock.path = Path("ahriman.pid")
|
||||
|
||||
lock._open()
|
||||
open_mock.assert_called_once_with("a+", encoding="utf8")
|
||||
|
||||
|
||||
def test_open_skip(lock: Lock, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip file opening if path is not set
|
||||
"""
|
||||
open_mock = mocker.patch("pathlib.Path.open")
|
||||
lock._open()
|
||||
open_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_watch(lock: Lock, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must check if lock file exists
|
||||
"""
|
||||
lock._pid_file = MagicMock()
|
||||
lock._pid_file.fileno.return_value = 1
|
||||
wait_mock = mocker.patch("ahriman.models.waiter.Waiter.wait")
|
||||
|
||||
lock._watch()
|
||||
wait_mock.assert_called_once_with(pytest.helpers.anyvar(int), 1)
|
||||
|
||||
|
||||
def test_watch_skip(lock: Lock, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip watch on empty path
|
||||
"""
|
||||
mocker.patch("ahriman.application.lock.Lock.perform_lock", return_value=True)
|
||||
lock._watch()
|
||||
|
||||
|
||||
def test_write(lock: Lock) -> None:
|
||||
"""
|
||||
must write PID to lock file
|
||||
"""
|
||||
with NamedTemporaryFile("a+") as pid_file:
|
||||
lock._pid_file = pid_file
|
||||
lock._write(is_locked=False)
|
||||
|
||||
assert int(lock._pid_file.readline()) == os.getpid()
|
||||
|
||||
|
||||
def test_write_skip(lock: Lock) -> None:
|
||||
"""
|
||||
must skip write to file if no path set
|
||||
"""
|
||||
lock._write(is_locked=False)
|
||||
|
||||
|
||||
def test_write_locked(lock: Lock, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise DuplicateRunError if it cannot lock file
|
||||
"""
|
||||
mocker.patch("ahriman.application.lock.Lock.perform_lock", return_value=False)
|
||||
with pytest.raises(DuplicateRunError):
|
||||
lock._pid_file = MagicMock()
|
||||
lock._write(is_locked=False)
|
||||
|
||||
|
||||
def test_write_locked_before(lock: Lock, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip lock in case if file was locked before
|
||||
"""
|
||||
lock_mock = mocker.patch("ahriman.application.lock.Lock.perform_lock")
|
||||
lock._pid_file = MagicMock()
|
||||
|
||||
lock._write(is_locked=True)
|
||||
lock_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_check_user(lock: Lock, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must check user correctly
|
||||
"""
|
||||
check_user_patch = mocker.patch("ahriman.application.lock.check_user")
|
||||
tree_create = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
|
||||
|
||||
lock.check_user()
|
||||
check_user_patch.assert_called_once_with(lock.paths.root, unsafe=False)
|
||||
tree_create.assert_called_once_with()
|
||||
|
||||
|
||||
def test_check_user_exception(lock: Lock, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise exception if user differs
|
||||
"""
|
||||
mocker.patch("ahriman.application.lock.check_user", side_effect=UnsafeRunError(0, 1))
|
||||
with pytest.raises(UnsafeRunError):
|
||||
lock.check_user()
|
||||
|
||||
|
||||
def test_check_user_unsafe(lock: Lock, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip user check if unsafe flag set
|
||||
"""
|
||||
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
|
||||
lock.unsafe = True
|
||||
lock.check_user()
|
||||
|
||||
|
||||
def test_check_version(lock: Lock, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must check version correctly
|
||||
"""
|
||||
mocker.patch("ahriman.core.status.Client.status_get",
|
||||
return_value=InternalStatus(status=BuildStatus(), version=__version__))
|
||||
logging_mock = mocker.patch("logging.Logger.warning")
|
||||
|
||||
lock.check_version()
|
||||
logging_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_check_version_mismatch(lock: Lock, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must check mismatched version correctly
|
||||
"""
|
||||
mocker.patch("ahriman.core.status.Client.status_get",
|
||||
return_value=InternalStatus(status=BuildStatus(), version="version"))
|
||||
logging_mock = mocker.patch("logging.Logger.warning")
|
||||
|
||||
lock.check_version()
|
||||
logging_mock.assert_called_once() # we do not check logging arguments
|
||||
|
||||
|
||||
def test_clear(lock: Lock) -> None:
|
||||
"""
|
||||
must remove lock file
|
||||
"""
|
||||
lock.path = Path("ahriman-test.pid")
|
||||
lock.path.touch()
|
||||
|
||||
lock.clear()
|
||||
assert not lock.path.is_file()
|
||||
|
||||
|
||||
def test_clear_missing(lock: Lock) -> None:
|
||||
"""
|
||||
must not fail on lock removal if file is missing
|
||||
"""
|
||||
lock.path = Path("ahriman-test.pid")
|
||||
lock.clear()
|
||||
|
||||
|
||||
def test_clear_skip(lock: Lock, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip removal if no file set
|
||||
"""
|
||||
unlink_mock = mocker.patch("pathlib.Path.unlink")
|
||||
lock.clear()
|
||||
unlink_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_clear_close(lock: Lock) -> None:
|
||||
"""
|
||||
must close pid file if opened
|
||||
"""
|
||||
close_mock = lock._pid_file = MagicMock()
|
||||
lock.clear()
|
||||
close_mock.close.assert_called_once_with()
|
||||
|
||||
|
||||
def test_clear_close_exception(lock: Lock) -> None:
|
||||
"""
|
||||
must suppress IO exception on file closure
|
||||
"""
|
||||
close_mock = lock._pid_file = MagicMock()
|
||||
close_mock.close.side_effect = IOError
|
||||
lock.clear()
|
||||
|
||||
|
||||
def test_lock(lock: Lock, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must perform lock correctly
|
||||
"""
|
||||
clear_mock = mocker.patch("ahriman.application.lock.Lock.clear")
|
||||
open_mock = mocker.patch("ahriman.application.lock.Lock._open")
|
||||
watch_mock = mocker.patch("ahriman.application.lock.Lock._watch", return_value=True)
|
||||
write_mock = mocker.patch("ahriman.application.lock.Lock._write")
|
||||
|
||||
lock.lock()
|
||||
clear_mock.assert_not_called()
|
||||
open_mock.assert_called_once_with()
|
||||
watch_mock.assert_called_once_with()
|
||||
write_mock.assert_called_once_with(is_locked=True)
|
||||
|
||||
|
||||
def test_lock_clear(lock: Lock, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must clear lock file before lock if force flag is set
|
||||
"""
|
||||
mocker.patch("ahriman.application.lock.Lock._open")
|
||||
mocker.patch("ahriman.application.lock.Lock._watch")
|
||||
mocker.patch("ahriman.application.lock.Lock._write")
|
||||
clear_mock = mocker.patch("ahriman.application.lock.Lock.clear")
|
||||
lock.force = True
|
||||
|
||||
lock.lock()
|
||||
clear_mock.assert_called_once_with()
|
||||
|
||||
|
||||
def test_enter(lock: Lock, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must process with context manager
|
||||
"""
|
||||
check_user_mock = mocker.patch("ahriman.application.lock.Lock.check_user")
|
||||
check_version_mock = mocker.patch("ahriman.application.lock.Lock.check_version")
|
||||
lock_mock = mocker.patch("ahriman.application.lock.Lock.lock")
|
||||
update_status_mock = mocker.patch("ahriman.core.status.Client.status_update")
|
||||
|
||||
with lock:
|
||||
pass
|
||||
check_user_mock.assert_called_once_with()
|
||||
check_version_mock.assert_called_once_with()
|
||||
lock_mock.assert_called_once_with()
|
||||
update_status_mock.assert_has_calls([MockCall(BuildStatusEnum.Building), MockCall(BuildStatusEnum.Success)])
|
||||
|
||||
|
||||
def test_exit_with_exception(lock: Lock, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must process with context manager in case if exception raised
|
||||
"""
|
||||
mocker.patch("ahriman.application.lock.Lock.check_user")
|
||||
mocker.patch("ahriman.application.lock.Lock.clear")
|
||||
mocker.patch("ahriman.application.lock.Lock.lock")
|
||||
update_status_mock = mocker.patch("ahriman.core.status.Client.status_update")
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
with lock:
|
||||
raise ValueError()
|
||||
update_status_mock.assert_has_calls([MockCall(BuildStatusEnum.Building), MockCall(BuildStatusEnum.Failed)])
|
||||
@@ -0,0 +1,21 @@
|
||||
import pytest
|
||||
|
||||
from ahriman.core.alpm.pacman_database import PacmanDatabase
|
||||
from ahriman.core.alpm.pacman import Pacman
|
||||
from ahriman.core.configuration import Configuration
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def pacman_database(configuration: Configuration, pacman: Pacman) -> PacmanDatabase:
|
||||
"""
|
||||
database sync fixture
|
||||
|
||||
Args:
|
||||
configuration(Configuration): configuration test instance
|
||||
pacman(Pacman): pacman test instance
|
||||
|
||||
Returns:
|
||||
DatabaseSync: database sync test instance
|
||||
"""
|
||||
database = next(iter(pacman.handle.get_syncdbs()))
|
||||
return PacmanDatabase(database, configuration)
|
||||
@@ -0,0 +1,47 @@
|
||||
import pytest
|
||||
|
||||
from ahriman.core.alpm.remote import AUR, Official, OfficialSyncdb, Remote
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def aur() -> AUR:
|
||||
"""
|
||||
aur helper fixture
|
||||
|
||||
Returns:
|
||||
AUR: aur helper instance
|
||||
"""
|
||||
return AUR()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def official() -> Official:
|
||||
"""
|
||||
official repository fixture
|
||||
|
||||
Returns:
|
||||
Official: official repository helper instance
|
||||
"""
|
||||
return Official()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def official_syncdb() -> OfficialSyncdb:
|
||||
"""
|
||||
official repository fixture with database processing
|
||||
|
||||
Returns:
|
||||
OfficialSyncdb: official repository with database processing helper instance
|
||||
"""
|
||||
return OfficialSyncdb()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def remote() -> Remote:
|
||||
"""
|
||||
official repository fixture
|
||||
|
||||
Returns:
|
||||
Remote: official repository helper instance
|
||||
"""
|
||||
return Remote()
|
||||
@@ -0,0 +1,177 @@
|
||||
import json
|
||||
import pytest
|
||||
import requests
|
||||
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest.mock import MagicMock, call as MockCall
|
||||
|
||||
from ahriman.core.alpm.remote import AUR
|
||||
from ahriman.core.exceptions import PackageInfoError, UnknownPackageError
|
||||
from ahriman.models.aur_package import AURPackage
|
||||
|
||||
|
||||
def _get_response(resource_path_root: Path) -> str:
|
||||
"""
|
||||
load response from resource file
|
||||
|
||||
Args:
|
||||
resource_path_root(Path): path to resource root
|
||||
|
||||
Returns:
|
||||
str: response text
|
||||
"""
|
||||
return (resource_path_root / "models" / "package_ahriman_aur").read_text()
|
||||
|
||||
|
||||
def test_parse_response(aur_package_ahriman: AURPackage, resource_path_root: Path) -> None:
|
||||
"""
|
||||
must parse success response
|
||||
"""
|
||||
response = _get_response(resource_path_root)
|
||||
assert AUR.parse_response(json.loads(response)) == [aur_package_ahriman]
|
||||
|
||||
|
||||
def test_parse_response_error(resource_path_root: Path) -> None:
|
||||
"""
|
||||
must raise exception on invalid response
|
||||
"""
|
||||
response = (resource_path_root / "models" / "aur_error").read_text()
|
||||
with pytest.raises(PackageInfoError, match="Incorrect request type specified."):
|
||||
AUR.parse_response(json.loads(response))
|
||||
|
||||
|
||||
def test_parse_response_unknown_error() -> None:
|
||||
"""
|
||||
must raise exception on invalid response with empty error message
|
||||
"""
|
||||
with pytest.raises(PackageInfoError, match="Unknown API error"):
|
||||
AUR.parse_response({"type": "error"})
|
||||
|
||||
|
||||
def test_remote_git_url(aur_package_ahriman: AURPackage) -> None:
|
||||
"""
|
||||
must generate package git url
|
||||
"""
|
||||
git_url = AUR.remote_git_url(aur_package_ahriman.package_base, aur_package_ahriman.repository)
|
||||
assert git_url.endswith(".git")
|
||||
assert git_url.startswith(AUR.DEFAULT_AUR_URL)
|
||||
|
||||
|
||||
def test_remote_web_url(aur_package_ahriman: AURPackage) -> None:
|
||||
"""
|
||||
must generate package web url
|
||||
"""
|
||||
web_url = AUR.remote_web_url(aur_package_ahriman.package_base)
|
||||
assert web_url.startswith(AUR.DEFAULT_AUR_URL)
|
||||
|
||||
|
||||
def test_aur_request(aur: AUR, aur_package_ahriman: AURPackage,
|
||||
mocker: MockerFixture, resource_path_root: Path) -> None:
|
||||
"""
|
||||
must perform request to AUR
|
||||
"""
|
||||
response_mock = MagicMock()
|
||||
response_mock.json.return_value = json.loads(_get_response(resource_path_root))
|
||||
request_mock = mocker.patch("ahriman.core.alpm.remote.AUR.make_request", return_value=response_mock)
|
||||
|
||||
assert aur.aur_request("info", "ahriman") == [aur_package_ahriman]
|
||||
request_mock.assert_called_once_with("GET", "https://aur.archlinux.org/rpc/v5/info/ahriman", params=[])
|
||||
|
||||
|
||||
def test_aur_request_multi_arg(aur: AUR) -> None:
|
||||
"""
|
||||
must raise PackageInfoError if invalid amount of arguments supplied
|
||||
"""
|
||||
with pytest.raises(PackageInfoError):
|
||||
aur.aur_request("search", "ahriman", "is", "cool")
|
||||
|
||||
with pytest.raises(PackageInfoError):
|
||||
aur.aur_request("search")
|
||||
|
||||
|
||||
def test_aur_request_with_kwargs(aur: AUR, aur_package_ahriman: AURPackage,
|
||||
mocker: MockerFixture, resource_path_root: Path) -> None:
|
||||
"""
|
||||
must perform request to AUR with named parameters
|
||||
"""
|
||||
response_mock = MagicMock()
|
||||
response_mock.json.return_value = json.loads(_get_response(resource_path_root))
|
||||
request_mock = mocker.patch("ahriman.core.alpm.remote.AUR.make_request", return_value=response_mock)
|
||||
|
||||
assert aur.aur_request("search", "ahriman", by="name") == [aur_package_ahriman]
|
||||
request_mock.assert_called_once_with("GET", "https://aur.archlinux.org/rpc/v5/search/ahriman",
|
||||
params=[("by", "name")])
|
||||
|
||||
|
||||
def test_aur_request_failed(aur: AUR, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must reraise generic exception
|
||||
"""
|
||||
mocker.patch("requests.Session.request", side_effect=Exception)
|
||||
with pytest.raises(Exception):
|
||||
aur.aur_request("info", "ahriman")
|
||||
|
||||
|
||||
def test_aur_request_failed_http_error(aur: AUR, mocker: MockerFixture) -> None:
|
||||
""" must reraise http exception
|
||||
"""
|
||||
mocker.patch("requests.Session.request", side_effect=requests.HTTPError)
|
||||
with pytest.raises(requests.HTTPError):
|
||||
aur.aur_request("info", "ahriman")
|
||||
|
||||
|
||||
def test_package_info(aur: AUR, aur_package_ahriman: AURPackage, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must make request for info
|
||||
"""
|
||||
request_mock = mocker.patch("ahriman.core.alpm.remote.AUR.aur_request", return_value=[aur_package_ahriman])
|
||||
assert aur.package_info(aur_package_ahriman.name, pacman=None) == aur_package_ahriman
|
||||
request_mock.assert_called_once_with("info", aur_package_ahriman.name)
|
||||
|
||||
|
||||
def test_package_info_not_found(aur: AUR, aur_package_ahriman: AURPackage, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise UnknownPackageError in case if no package was found
|
||||
"""
|
||||
mocker.patch("ahriman.core.alpm.remote.AUR.aur_request", return_value=[])
|
||||
with pytest.raises(UnknownPackageError, match=aur_package_ahriman.name):
|
||||
assert aur.package_info(aur_package_ahriman.name, pacman=None)
|
||||
|
||||
|
||||
def test_package_provided_by(aur: AUR, aur_package_ahriman: AURPackage, aur_package_akonadi: AURPackage,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must search for packages which provide required one
|
||||
"""
|
||||
aur_package_ahriman.provides.append(aur_package_ahriman.name)
|
||||
search_mock = mocker.patch("ahriman.core.alpm.remote.AUR.package_search", return_value=[
|
||||
aur_package_ahriman, aur_package_akonadi
|
||||
])
|
||||
info_mock = mocker.patch("ahriman.core.alpm.remote.AUR.package_info", side_effect=[
|
||||
aur_package_ahriman, aur_package_akonadi
|
||||
])
|
||||
|
||||
assert aur.package_provided_by(aur_package_ahriman.name, pacman=None) == [aur_package_ahriman]
|
||||
search_mock.assert_called_once_with(aur_package_ahriman.name, pacman=None, search_by="provides")
|
||||
info_mock.assert_has_calls([
|
||||
MockCall(aur_package_ahriman.name, pacman=None), MockCall(aur_package_akonadi.name, pacman=None)
|
||||
])
|
||||
|
||||
|
||||
def test_package_search(aur: AUR, aur_package_ahriman: AURPackage, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must make request for search
|
||||
"""
|
||||
request_mock = mocker.patch("ahriman.core.alpm.remote.AUR.aur_request", return_value=[aur_package_ahriman])
|
||||
assert aur.package_search(aur_package_ahriman.name, pacman=None, search_by=None) == [aur_package_ahriman]
|
||||
request_mock.assert_called_once_with("search", aur_package_ahriman.name, by="name-desc")
|
||||
|
||||
|
||||
def test_package_search_provides(aur: AUR, aur_package_ahriman: AURPackage, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must make request for search with custom field
|
||||
"""
|
||||
request_mock = mocker.patch("ahriman.core.alpm.remote.AUR.aur_request")
|
||||
aur.package_search(aur_package_ahriman.name, pacman=None, search_by="provides")
|
||||
request_mock.assert_called_once_with("search", aur_package_ahriman.name, by="provides")
|
||||
@@ -0,0 +1,134 @@
|
||||
import json
|
||||
import pytest
|
||||
import requests
|
||||
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from ahriman.core.alpm.remote import Official
|
||||
from ahriman.core.exceptions import PackageInfoError, UnknownPackageError
|
||||
from ahriman.models.aur_package import AURPackage
|
||||
|
||||
|
||||
def _get_response(resource_path_root: Path) -> str:
|
||||
"""
|
||||
load response from resource file
|
||||
|
||||
Args:
|
||||
resource_path_root(Path): path to resource root
|
||||
|
||||
Returns:
|
||||
str: response text
|
||||
"""
|
||||
return (resource_path_root / "models" / "package_akonadi_aur").read_text()
|
||||
|
||||
|
||||
def test_parse_response(aur_package_akonadi: AURPackage, resource_path_root: Path) -> None:
|
||||
"""
|
||||
must parse success response
|
||||
"""
|
||||
response = _get_response(resource_path_root)
|
||||
assert Official.parse_response(json.loads(response)) == [aur_package_akonadi]
|
||||
|
||||
|
||||
def test_parse_response_unknown_error(resource_path_root: Path) -> None:
|
||||
"""
|
||||
must raise exception on invalid response with empty error message
|
||||
"""
|
||||
response = (resource_path_root / "models" / "official_error").read_text()
|
||||
with pytest.raises(PackageInfoError, match="API validation error"):
|
||||
Official.parse_response(json.loads(response))
|
||||
|
||||
|
||||
def test_remote_git_url(aur_package_akonadi: AURPackage) -> None:
|
||||
"""
|
||||
must generate package git url for core packages
|
||||
"""
|
||||
git_urls = [
|
||||
Official.remote_git_url(aur_package_akonadi.package_base, repository)
|
||||
for repository in ("core", "extra", "Core", "Extra")
|
||||
]
|
||||
assert all(git_url.endswith(f"{aur_package_akonadi.package_base}.git") for git_url in git_urls)
|
||||
assert len(set(git_urls)) == 1
|
||||
|
||||
|
||||
def test_remote_web_url(aur_package_akonadi: AURPackage) -> None:
|
||||
"""
|
||||
must generate package git url
|
||||
"""
|
||||
web_url = Official.remote_web_url(aur_package_akonadi.package_base)
|
||||
assert web_url.startswith(Official.DEFAULT_ARCHLINUX_URL)
|
||||
|
||||
|
||||
def test_arch_request(official: Official, aur_package_akonadi: AURPackage,
|
||||
mocker: MockerFixture, resource_path_root: Path) -> None:
|
||||
"""
|
||||
must perform request to official repositories
|
||||
"""
|
||||
response_mock = MagicMock()
|
||||
response_mock.json.return_value = json.loads(_get_response(resource_path_root))
|
||||
request_mock = mocker.patch("ahriman.core.alpm.remote.Official.make_request", return_value=response_mock)
|
||||
|
||||
assert official.arch_request("akonadi", by="q") == [aur_package_akonadi]
|
||||
request_mock.assert_called_once_with(
|
||||
"GET", "https://archlinux.org/packages/search/json",
|
||||
params=[("repo", repository) for repository in Official.DEFAULT_SEARCH_REPOSITORIES] + [("q", "akonadi")])
|
||||
|
||||
|
||||
def test_arch_request_failed(official: Official, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must reraise generic exception
|
||||
"""
|
||||
mocker.patch("requests.Session.request", side_effect=Exception)
|
||||
with pytest.raises(Exception):
|
||||
official.arch_request("akonadi", by="q")
|
||||
|
||||
|
||||
def test_arch_request_failed_http_error(official: Official, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must reraise http exception
|
||||
"""
|
||||
mocker.patch("requests.Session.request", side_effect=requests.HTTPError)
|
||||
with pytest.raises(requests.HTTPError):
|
||||
official.arch_request("akonadi", by="q")
|
||||
|
||||
|
||||
def test_package_info(official: Official, aur_package_akonadi: AURPackage, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must make request for info
|
||||
"""
|
||||
request_mock = mocker.patch("ahriman.core.alpm.remote.Official.arch_request",
|
||||
return_value=[aur_package_akonadi])
|
||||
assert official.package_info(aur_package_akonadi.name, pacman=None) == aur_package_akonadi
|
||||
request_mock.assert_called_once_with(aur_package_akonadi.name, by="name")
|
||||
|
||||
|
||||
def test_package_info_not_found(official: Official, aur_package_ahriman: AURPackage, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise UnknownPackageError in case if no package was found
|
||||
"""
|
||||
mocker.patch("ahriman.core.alpm.remote.Official.arch_request", return_value=[])
|
||||
with pytest.raises(UnknownPackageError, match=aur_package_ahriman.name):
|
||||
assert official.package_info(aur_package_ahriman.name, pacman=None)
|
||||
|
||||
|
||||
def test_package_search(official: Official, aur_package_akonadi: AURPackage, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must make request for search
|
||||
"""
|
||||
request_mock = mocker.patch("ahriman.core.alpm.remote.Official.arch_request",
|
||||
return_value=[aur_package_akonadi])
|
||||
assert official.package_search(aur_package_akonadi.name, pacman=None, search_by=None) == [
|
||||
aur_package_akonadi,
|
||||
]
|
||||
request_mock.assert_called_once_with(aur_package_akonadi.name, by="q")
|
||||
|
||||
|
||||
def test_package_search_name(official: Official, aur_package_akonadi: AURPackage, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must make request for search with custom field
|
||||
"""
|
||||
request_mock = mocker.patch("ahriman.core.alpm.remote.Official.arch_request")
|
||||
official.package_search(aur_package_akonadi.name, pacman=None, search_by="name")
|
||||
request_mock.assert_called_once_with(aur_package_akonadi.name, by="name")
|
||||
@@ -0,0 +1,57 @@
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.core.alpm.pacman import Pacman
|
||||
from ahriman.core.alpm.remote import OfficialSyncdb
|
||||
from ahriman.core.exceptions import UnknownPackageError
|
||||
from ahriman.models.aur_package import AURPackage
|
||||
|
||||
|
||||
def test_package_info(official_syncdb: OfficialSyncdb, aur_package_akonadi: AURPackage, pacman: Pacman,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must return package info from the database
|
||||
"""
|
||||
mocker.patch("ahriman.models.aur_package.AURPackage.from_pacman", return_value=aur_package_akonadi)
|
||||
get_mock = mocker.patch("ahriman.core.alpm.pacman.Pacman.package", return_value=[aur_package_akonadi])
|
||||
|
||||
assert official_syncdb.package_info(aur_package_akonadi.name, pacman=pacman) == aur_package_akonadi
|
||||
get_mock.assert_called_once_with(aur_package_akonadi.name)
|
||||
|
||||
|
||||
def test_package_info_no_pacman(official_syncdb: OfficialSyncdb, aur_package_akonadi: AURPackage) -> None:
|
||||
"""
|
||||
must raise UnknownPackageError if no pacman set
|
||||
"""
|
||||
with pytest.raises(UnknownPackageError, match=aur_package_akonadi.name):
|
||||
official_syncdb.package_info(aur_package_akonadi.name, pacman=None)
|
||||
|
||||
|
||||
def test_package_info_not_found(official_syncdb: OfficialSyncdb, aur_package_akonadi: AURPackage, pacman: Pacman,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise UnknownPackage exception in case if no package was found
|
||||
"""
|
||||
mocker.patch("ahriman.core.alpm.pacman.Pacman.package", return_value=[])
|
||||
with pytest.raises(UnknownPackageError, match=aur_package_akonadi.name):
|
||||
assert official_syncdb.package_info(aur_package_akonadi.name, pacman=pacman)
|
||||
|
||||
|
||||
def test_package_provided_by(official_syncdb: OfficialSyncdb, aur_package_akonadi: AURPackage, pacman: Pacman,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must search by provides in database
|
||||
"""
|
||||
mocker.patch("ahriman.models.aur_package.AURPackage.from_pacman", return_value=aur_package_akonadi)
|
||||
get_mock = mocker.patch("ahriman.core.alpm.pacman.Pacman.provided_by", return_value=[aur_package_akonadi])
|
||||
|
||||
assert official_syncdb.package_provided_by(aur_package_akonadi.name, pacman=pacman) == [aur_package_akonadi]
|
||||
get_mock.assert_called_once_with(aur_package_akonadi.name)
|
||||
|
||||
|
||||
def test_package_provided_by_no_pacman(official_syncdb: OfficialSyncdb, aur_package_akonadi: AURPackage) -> None:
|
||||
"""
|
||||
must return empty list if no pacman set
|
||||
"""
|
||||
assert official_syncdb.package_provided_by(aur_package_akonadi.name, pacman=None) == []
|
||||
@@ -0,0 +1,148 @@
|
||||
import pytest
|
||||
|
||||
from dataclasses import replace
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest.mock import call as MockCall
|
||||
|
||||
from ahriman.core.alpm.pacman import Pacman
|
||||
from ahriman.core.alpm.remote import Remote
|
||||
from ahriman.core.exceptions import UnknownPackageError
|
||||
from ahriman.models.aur_package import AURPackage
|
||||
|
||||
|
||||
def test_info(aur_package_ahriman: AURPackage, pacman: Pacman, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must call info method
|
||||
"""
|
||||
info_mock = mocker.patch("ahriman.core.alpm.remote.Remote.package_info", return_value=aur_package_ahriman)
|
||||
assert Remote.info(aur_package_ahriman.name, pacman=pacman) == aur_package_ahriman
|
||||
info_mock.assert_called_once_with(aur_package_ahriman.name, pacman=pacman)
|
||||
|
||||
|
||||
def test_info_not_found(aur_package_ahriman: AURPackage, pacman: Pacman, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise UnknownPackageError if no package found and search by provides is disabled
|
||||
"""
|
||||
mocker.patch("ahriman.core.alpm.remote.Remote.package_info",
|
||||
side_effect=UnknownPackageError(aur_package_ahriman.name))
|
||||
with pytest.raises(UnknownPackageError):
|
||||
Remote.info(aur_package_ahriman.name, pacman=pacman)
|
||||
|
||||
|
||||
def test_info_include_provides(aur_package_ahriman: AURPackage, pacman: Pacman, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must perform search through provides list is set
|
||||
"""
|
||||
mocker.patch("ahriman.core.alpm.remote.Remote.package_info",
|
||||
side_effect=UnknownPackageError(aur_package_ahriman.name))
|
||||
provided_mock = mocker.patch("ahriman.core.alpm.remote.Remote.package_provided_by",
|
||||
return_value=[aur_package_ahriman])
|
||||
|
||||
assert Remote.info(aur_package_ahriman.name, pacman=pacman, include_provides=True) == aur_package_ahriman
|
||||
provided_mock.assert_called_once_with(aur_package_ahriman.name, pacman=pacman)
|
||||
|
||||
|
||||
def test_info_include_provides_not_found(aur_package_ahriman: AURPackage, pacman: Pacman,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise UnknownPackageError if no package found and search by provides returns empty list
|
||||
"""
|
||||
mocker.patch("ahriman.core.alpm.remote.Remote.package_info",
|
||||
side_effect=UnknownPackageError(aur_package_ahriman.name))
|
||||
mocker.patch("ahriman.core.alpm.remote.Remote.package_provided_by", return_value=[])
|
||||
|
||||
with pytest.raises(UnknownPackageError):
|
||||
Remote.info("ahriman", pacman=pacman, include_provides=True)
|
||||
|
||||
|
||||
def test_multisearch(aur_package_ahriman: AURPackage, pacman: Pacman, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must search in AUR with multiple words
|
||||
"""
|
||||
terms = ["ahriman", "is", "cool"]
|
||||
search_mock = mocker.patch("ahriman.core.alpm.remote.Remote.package_search", return_value=[aur_package_ahriman])
|
||||
|
||||
assert Remote.multisearch(*terms, pacman=pacman, search_by="name") == [aur_package_ahriman]
|
||||
search_mock.assert_has_calls([
|
||||
MockCall("ahriman", pacman=pacman, search_by="name"),
|
||||
MockCall("cool", pacman=pacman, search_by="name"),
|
||||
])
|
||||
|
||||
|
||||
def test_multisearch_empty(pacman: Pacman, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must return empty list if no long terms supplied
|
||||
"""
|
||||
terms = ["it", "is"]
|
||||
search_mock = mocker.patch("ahriman.core.alpm.remote.Remote.package_search")
|
||||
|
||||
assert Remote.multisearch(*terms, pacman=pacman) == []
|
||||
search_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_multisearch_single(aur_package_ahriman: AURPackage, pacman: Pacman, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must search in AUR with one word
|
||||
"""
|
||||
search_mock = mocker.patch("ahriman.core.alpm.remote.Remote.package_search", return_value=[aur_package_ahriman])
|
||||
assert Remote.multisearch("ahriman", pacman=pacman) == [aur_package_ahriman]
|
||||
search_mock.assert_called_once_with("ahriman", pacman=pacman, search_by=None)
|
||||
|
||||
|
||||
def test_multisearch_remove_duplicates(aur_package_ahriman: AURPackage, pacman: Pacman, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must remove duplicates from search result
|
||||
"""
|
||||
package1 = replace(aur_package_ahriman)
|
||||
package2 = replace(aur_package_ahriman, name="ahriman-triggers")
|
||||
mocker.patch("ahriman.core.alpm.remote.Remote.package_search", return_value=[package1, package2])
|
||||
|
||||
assert Remote.multisearch("ahriman", pacman=pacman) == [package1]
|
||||
|
||||
|
||||
def test_remote_git_url(remote: Remote) -> None:
|
||||
"""
|
||||
must raise NotImplemented for missing remote git url
|
||||
"""
|
||||
with pytest.raises(NotImplementedError):
|
||||
remote.remote_git_url("package", "repositories")
|
||||
|
||||
|
||||
def test_remote_web_url(remote: Remote) -> None:
|
||||
"""
|
||||
must raise NotImplemented for missing remote web url
|
||||
"""
|
||||
with pytest.raises(NotImplementedError):
|
||||
remote.remote_web_url("package")
|
||||
|
||||
|
||||
def test_search(pacman: Pacman, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must call search method
|
||||
"""
|
||||
search_mock = mocker.patch("ahriman.core.alpm.remote.Remote.package_search")
|
||||
Remote.search("ahriman", pacman=pacman, search_by="name")
|
||||
search_mock.assert_called_once_with("ahriman", pacman=pacman, search_by="name")
|
||||
|
||||
|
||||
def test_package_info(remote: Remote, pacman: Pacman) -> None:
|
||||
"""
|
||||
must raise NotImplemented for missing package info method
|
||||
"""
|
||||
with pytest.raises(NotImplementedError):
|
||||
remote.package_info("package", pacman=pacman)
|
||||
|
||||
|
||||
def test_package_provided_by(remote: Remote, pacman: Pacman) -> None:
|
||||
"""
|
||||
must return empty list for provides method
|
||||
"""
|
||||
assert remote.package_provided_by("package", pacman=pacman) == []
|
||||
|
||||
|
||||
def test_package_search(remote: Remote, pacman: Pacman) -> None:
|
||||
"""
|
||||
must raise NotImplemented for missing package search method
|
||||
"""
|
||||
with pytest.raises(NotImplementedError):
|
||||
remote.package_search("package", pacman=pacman, search_by=None)
|
||||
@@ -0,0 +1,292 @@
|
||||
import pyalpm
|
||||
import pytest
|
||||
import tarfile
|
||||
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
from tempfile import TemporaryDirectory
|
||||
from unittest.mock import MagicMock, call as MockCall
|
||||
|
||||
from ahriman.core.alpm.pacman import Pacman
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.pacman_synchronization import PacmanSynchronization
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
|
||||
|
||||
def test_init_with_local_cache(configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must sync repositories at the start if set
|
||||
"""
|
||||
mocker.patch("ahriman.core.alpm.pacman.Pacman.database_copy")
|
||||
sync_mock = mocker.patch("ahriman.core.alpm.pacman.Pacman.database_sync")
|
||||
configuration.set_option("alpm", "use_ahriman_cache", "yes")
|
||||
_, repository_id = configuration.check_loaded()
|
||||
|
||||
# pyalpm.Handle is trying to reach the directory we've asked, thus we need to patch it a bit
|
||||
with TemporaryDirectory(ignore_cleanup_errors=True) as pacman_root:
|
||||
mocker.patch.object(RepositoryPaths, "pacman", Path(pacman_root))
|
||||
# during the creation pyalpm.Handle will create also version file which we would like to remove later
|
||||
pacman = Pacman(repository_id, configuration, refresh_database=PacmanSynchronization.Enabled)
|
||||
assert pacman.handle
|
||||
sync_mock.assert_called_once_with(pytest.helpers.anyvar(int), force=False)
|
||||
|
||||
|
||||
def test_init_with_local_cache_forced(configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must sync repositories at the start if set with force flag
|
||||
"""
|
||||
mocker.patch("ahriman.core.alpm.pacman.Pacman.database_copy")
|
||||
sync_mock = mocker.patch("ahriman.core.alpm.pacman.Pacman.database_sync")
|
||||
configuration.set_option("alpm", "use_ahriman_cache", "yes")
|
||||
_, repository_id = configuration.check_loaded()
|
||||
|
||||
# pyalpm.Handle is trying to reach the directory we've asked, thus we need to patch it a bit
|
||||
with TemporaryDirectory(ignore_cleanup_errors=True) as pacman_root:
|
||||
mocker.patch.object(RepositoryPaths, "pacman", Path(pacman_root))
|
||||
# during the creation pyalpm.Handle will create also version file which we would like to remove later
|
||||
pacman = Pacman(repository_id, configuration, refresh_database=PacmanSynchronization.Force)
|
||||
assert pacman.handle
|
||||
sync_mock.assert_called_once_with(pytest.helpers.anyvar(int), force=True)
|
||||
|
||||
|
||||
def test_database_copy(pacman: Pacman, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must copy database from root
|
||||
"""
|
||||
database = next(db for db in pacman.handle.get_syncdbs() if db.name == "core")
|
||||
path = Path("randomname")
|
||||
dst_path = Path("/var/lib/pacman/sync/core.db")
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||
# root database exists, local database does not
|
||||
mocker.patch("pathlib.Path.is_file", autospec=True, side_effect=lambda p: p.is_relative_to(path))
|
||||
mkdir_mock = mocker.patch("pathlib.Path.mkdir")
|
||||
copy_mock = mocker.patch("shutil.copy")
|
||||
owner_guard_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.preserve_owner")
|
||||
|
||||
pacman.database_copy(pacman.handle, database, path, use_ahriman_cache=True)
|
||||
mkdir_mock.assert_called_once_with(mode=0o755, exist_ok=True)
|
||||
copy_mock.assert_called_once_with(path / "sync" / "core.db", dst_path)
|
||||
owner_guard_mock.assert_called_once_with()
|
||||
|
||||
|
||||
def test_database_copy_skip(pacman: Pacman, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must do not copy database from root if local cache is disabled
|
||||
"""
|
||||
database = next(db for db in pacman.handle.get_syncdbs() if db.name == "core")
|
||||
path = Path("randomname")
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||
# root database exists, local database does not
|
||||
mocker.patch("pathlib.Path.is_file", autospec=True, side_effect=lambda p: p.is_relative_to(path))
|
||||
copy_mock = mocker.patch("shutil.copy")
|
||||
|
||||
pacman.database_copy(pacman.handle, database, path, use_ahriman_cache=False)
|
||||
copy_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_database_copy_no_directory(pacman: Pacman, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must do not copy database if directory does not exist
|
||||
"""
|
||||
database = next(db for db in pacman.handle.get_syncdbs() if db.name == "core")
|
||||
path = Path("randomname")
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||
# root database exists, local database does not
|
||||
mocker.patch("pathlib.Path.is_file", autospec=True, side_effect=lambda p: p.is_relative_to(path))
|
||||
copy_mock = mocker.patch("shutil.copy")
|
||||
|
||||
pacman.database_copy(pacman.handle, database, path, use_ahriman_cache=True)
|
||||
copy_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_database_copy_no_root_file(pacman: Pacman, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must do not copy database if no repository file exists in filesystem
|
||||
"""
|
||||
database = next(db for db in pacman.handle.get_syncdbs() if db.name == "core")
|
||||
path = Path("randomname")
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||
# root database does not exist, local database does not either
|
||||
mocker.patch("pathlib.Path.is_file", return_value=False)
|
||||
copy_mock = mocker.patch("shutil.copy")
|
||||
|
||||
pacman.database_copy(pacman.handle, database, path, use_ahriman_cache=True)
|
||||
copy_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_database_copy_database_exist(pacman: Pacman, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must do not copy database if local cache already exists
|
||||
"""
|
||||
database = next(db for db in pacman.handle.get_syncdbs() if db.name == "core")
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||
# root database exists, local database does either
|
||||
mocker.patch("pathlib.Path.is_file", return_value=True)
|
||||
copy_mock = mocker.patch("shutil.copy")
|
||||
|
||||
pacman.database_copy(pacman.handle, database, Path("root"), use_ahriman_cache=True)
|
||||
copy_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_database_init(pacman: Pacman) -> None:
|
||||
"""
|
||||
must init database with settings
|
||||
"""
|
||||
database = pacman.database_init(pacman.handle, "testing", "x86_64")
|
||||
assert database.servers == ["https://geo.mirror.pkgbuild.com/testing/os/x86_64"]
|
||||
|
||||
|
||||
def test_database_init_local(pacman: Pacman, configuration: Configuration) -> None:
|
||||
"""
|
||||
must set file protocol for local databases
|
||||
"""
|
||||
_, repository_id = configuration.check_loaded()
|
||||
database = pacman.database_init(MagicMock(), repository_id.name, repository_id.architecture)
|
||||
assert database.servers == [f"file://{configuration.repository_paths.repository}"]
|
||||
|
||||
|
||||
def test_database_sync(pacman: Pacman, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must sync databases
|
||||
"""
|
||||
handle_mock = MagicMock()
|
||||
transaction_mock = MagicMock()
|
||||
handle_mock.get_syncdbs.return_value = [1, 2]
|
||||
handle_mock.init_transaction.return_value = transaction_mock
|
||||
|
||||
sync_mock = mocker.patch("ahriman.core.alpm.pacman_database.PacmanDatabase.sync")
|
||||
|
||||
pacman.database_sync(handle_mock, force=False)
|
||||
handle_mock.init_transaction.assert_called_once_with()
|
||||
sync_mock.assert_has_calls([MockCall(force=False), MockCall(force=False)])
|
||||
transaction_mock.release.assert_called_once_with()
|
||||
|
||||
|
||||
def test_database_sync_forced(pacman: Pacman, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must sync databases with force flag
|
||||
"""
|
||||
handle_mock = MagicMock()
|
||||
handle_mock.get_syncdbs.return_value = [1]
|
||||
|
||||
sync_mock = mocker.patch("ahriman.core.alpm.pacman_database.PacmanDatabase.sync")
|
||||
|
||||
pacman.database_sync(handle_mock, force=True)
|
||||
sync_mock.assert_called_once_with(force=True)
|
||||
|
||||
|
||||
def test_files_package(pacman: Pacman, package_ahriman: Package, pyalpm_package_ahriman: pyalpm.Package,
|
||||
mocker: MockerFixture, resource_path_root: Path) -> None:
|
||||
"""
|
||||
must load files only for the specified package
|
||||
"""
|
||||
mocker.patch("ahriman.core.alpm.pacman.Pacman.package", return_value=[pyalpm_package_ahriman])
|
||||
handle_mock = MagicMock()
|
||||
handle_mock.get_syncdbs.return_value = [MagicMock()]
|
||||
pacman.handle = handle_mock
|
||||
|
||||
tarball = resource_path_root / "core" / "arcanisrepo.files.tar.gz"
|
||||
|
||||
with tarfile.open(tarball, "r:gz") as fd:
|
||||
mocker.patch("pathlib.Path.is_file", return_value=True)
|
||||
mocker.patch("ahriman.core.alpm.pacman.tarfile.open", return_value=fd)
|
||||
|
||||
files = pacman.files([package_ahriman.base])
|
||||
assert len(files) == 1
|
||||
assert package_ahriman.base in files
|
||||
|
||||
|
||||
def test_files_skip(pacman: Pacman, pyalpm_package_ahriman: pyalpm.Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must return empty list if no database found
|
||||
"""
|
||||
mocker.patch("ahriman.core.alpm.pacman.Pacman.package", return_value=[pyalpm_package_ahriman])
|
||||
handle_mock = MagicMock()
|
||||
handle_mock.get_syncdbs.return_value = [MagicMock()]
|
||||
pacman.handle = handle_mock
|
||||
|
||||
mocker.patch("pathlib.Path.is_file", return_value=False)
|
||||
|
||||
assert not pacman.files([pyalpm_package_ahriman.name])
|
||||
|
||||
|
||||
def test_files_no_content(pacman: Pacman, pyalpm_package_ahriman: pyalpm.Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip package if no content can be loaded
|
||||
"""
|
||||
mocker.patch("ahriman.core.alpm.pacman.Pacman.package", return_value=[pyalpm_package_ahriman])
|
||||
handle_mock = MagicMock()
|
||||
handle_mock.get_syncdbs.return_value = [MagicMock()]
|
||||
pacman.handle = handle_mock
|
||||
|
||||
tar_mock = MagicMock()
|
||||
tar_mock.extractfile.return_value = None
|
||||
|
||||
open_mock = MagicMock()
|
||||
open_mock.__enter__.return_value = tar_mock
|
||||
|
||||
mocker.patch("pathlib.Path.is_file", return_value=True)
|
||||
mocker.patch("ahriman.core.alpm.pacman.tarfile.open", return_value=open_mock)
|
||||
|
||||
assert not pacman.files([pyalpm_package_ahriman.name])
|
||||
|
||||
|
||||
def test_files_no_entry(pacman: Pacman, pyalpm_package_ahriman: pyalpm.Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip package if it wasn't found in the archive
|
||||
"""
|
||||
mocker.patch("ahriman.core.alpm.pacman.Pacman.package", return_value=[pyalpm_package_ahriman])
|
||||
handle_mock = MagicMock()
|
||||
handle_mock.get_syncdbs.return_value = [MagicMock()]
|
||||
pacman.handle = handle_mock
|
||||
|
||||
tar_mock = MagicMock()
|
||||
tar_mock.extractfile.side_effect = KeyError
|
||||
|
||||
open_mock = MagicMock()
|
||||
open_mock.__enter__.return_value = tar_mock
|
||||
|
||||
mocker.patch("pathlib.Path.is_file", return_value=True)
|
||||
mocker.patch("ahriman.core.alpm.pacman.tarfile.open", return_value=open_mock)
|
||||
|
||||
assert not pacman.files([pyalpm_package_ahriman.name])
|
||||
|
||||
|
||||
def test_package(pacman: Pacman) -> None:
|
||||
"""
|
||||
must retrieve package
|
||||
"""
|
||||
assert list(pacman.package("pacman"))
|
||||
|
||||
|
||||
def test_package_empty(pacman: Pacman) -> None:
|
||||
"""
|
||||
must return empty packages list without exception
|
||||
"""
|
||||
assert not list(pacman.package("some-random-name"))
|
||||
|
||||
|
||||
def test_packages(pacman: Pacman) -> None:
|
||||
"""
|
||||
package list must not be empty
|
||||
"""
|
||||
packages = pacman.packages()
|
||||
assert packages
|
||||
assert "pacman" in packages
|
||||
|
||||
|
||||
def test_packages_with_provides(pacman: Pacman) -> None:
|
||||
"""
|
||||
package list must contain provides packages
|
||||
"""
|
||||
assert "sh" in pacman.packages()
|
||||
assert "mysql" in pacman.packages() # mariadb
|
||||
|
||||
|
||||
def test_package_provided_by(pacman: Pacman) -> None:
|
||||
"""
|
||||
must search through the provides lists
|
||||
"""
|
||||
assert list(pacman.provided_by("sh"))
|
||||
assert list(pacman.provided_by("libacl.so")) # case with exact version
|
||||
@@ -0,0 +1,212 @@
|
||||
import pytest
|
||||
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest.mock import MagicMock, call as MockCall
|
||||
|
||||
from ahriman.core.alpm.pacman_database import PacmanDatabase
|
||||
from ahriman.core.exceptions import PacmanError
|
||||
|
||||
|
||||
def test_copy(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must copy local database file
|
||||
"""
|
||||
copy_mock = mocker.patch("shutil.copy")
|
||||
PacmanDatabase.copy(Path("remote"), Path("local"))
|
||||
copy_mock.assert_called_once_with(Path("remote"), Path("local"))
|
||||
|
||||
|
||||
def test_download(pacman_database: PacmanDatabase, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must download database by remote url
|
||||
"""
|
||||
response_obj = MagicMock()
|
||||
response_obj.headers = {pacman_database.LAST_MODIFIED_HEADER: "Fri, 09 Feb 2024 00:25:55 GMT"}
|
||||
response_obj.iter_content.return_value = ["chunk".encode("utf8")]
|
||||
|
||||
path = Path("local")
|
||||
url = "url"
|
||||
|
||||
file_mock = MagicMock()
|
||||
request_mock = mocker.patch("ahriman.core.alpm.pacman_database.PacmanDatabase.make_request",
|
||||
return_value=response_obj)
|
||||
open_mock = mocker.patch("pathlib.Path.open")
|
||||
open_mock.return_value.__enter__.return_value = file_mock
|
||||
mtime_mock = mocker.patch("os.utime")
|
||||
|
||||
pacman_database.download(url, path)
|
||||
request_mock.assert_called_once_with("GET", url, stream=True)
|
||||
open_mock.assert_called_once_with("wb")
|
||||
file_mock.write.assert_called_once_with("chunk".encode("utf8"))
|
||||
mtime_mock.assert_called_once_with(path, (1707438355.0, 1707438355.0))
|
||||
|
||||
|
||||
def test_download_no_header(pacman_database: PacmanDatabase, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise exception in case if no last modified head found
|
||||
"""
|
||||
response_obj = MagicMock()
|
||||
response_obj.headers = {}
|
||||
mocker.patch("ahriman.core.alpm.pacman_database.PacmanDatabase.make_request", return_value=response_obj)
|
||||
|
||||
with pytest.raises(PacmanError):
|
||||
pacman_database.download("url", Path("local"))
|
||||
|
||||
|
||||
def test_is_outdated(pacman_database: PacmanDatabase, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must correctly check if file is outdated
|
||||
"""
|
||||
response_obj = MagicMock()
|
||||
response_obj.headers = {pacman_database.LAST_MODIFIED_HEADER: "Fri, 09 Feb 2024 00:25:55 GMT"}
|
||||
stat_mock = MagicMock()
|
||||
stat_mock.st_mtime = 1707438354
|
||||
|
||||
path = Path("local")
|
||||
url = "url"
|
||||
|
||||
mocker.patch("pathlib.Path.is_file", return_value=True)
|
||||
mocker.patch("ahriman.core.alpm.pacman_database.PacmanDatabase.make_request", return_value=response_obj)
|
||||
mocker.patch("pathlib.Path.stat", return_value=stat_mock)
|
||||
|
||||
assert pacman_database.is_outdated(url, path)
|
||||
|
||||
stat_mock.st_mtime += 1
|
||||
assert not pacman_database.is_outdated(url, path)
|
||||
|
||||
stat_mock.st_mtime += 1
|
||||
assert not pacman_database.is_outdated(url, path)
|
||||
|
||||
|
||||
def test_is_outdated_not_a_file(pacman_database: PacmanDatabase, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must mark as outdated if no file was found
|
||||
"""
|
||||
mocker.patch("pathlib.Path.is_file", return_value=False)
|
||||
assert pacman_database.is_outdated("url", Path("local"))
|
||||
|
||||
|
||||
def test_is_outdated_no_header(pacman_database: PacmanDatabase, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise exception in case if no last modified head found during timestamp check
|
||||
"""
|
||||
response_obj = MagicMock()
|
||||
response_obj.headers = {}
|
||||
mocker.patch("ahriman.core.alpm.pacman_database.PacmanDatabase.make_request", return_value=response_obj)
|
||||
mocker.patch("pathlib.Path.is_file", return_value=True)
|
||||
|
||||
with pytest.raises(PacmanError):
|
||||
pacman_database.is_outdated("url", Path("local"))
|
||||
|
||||
|
||||
def test_sync(pacman_database: PacmanDatabase, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must sync database
|
||||
"""
|
||||
sync_db_mock = mocker.patch("ahriman.core.alpm.pacman_database.PacmanDatabase.sync_packages")
|
||||
sync_files_mock = mocker.patch("ahriman.core.alpm.pacman_database.PacmanDatabase.sync_files")
|
||||
|
||||
pacman_database.sync(force=True)
|
||||
pacman_database.sync(force=False)
|
||||
sync_db_mock.assert_has_calls([MockCall(force=True), MockCall(force=False)])
|
||||
sync_files_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_sync_with_files(pacman_database: PacmanDatabase, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must sync database and files
|
||||
"""
|
||||
sync_db_mock = mocker.patch("ahriman.core.alpm.pacman_database.PacmanDatabase.sync_packages")
|
||||
sync_files_mock = mocker.patch("ahriman.core.alpm.pacman_database.PacmanDatabase.sync_files")
|
||||
pacman_database.sync_files_database = True
|
||||
|
||||
pacman_database.sync(force=True)
|
||||
pacman_database.sync(force=False)
|
||||
sync_db_mock.assert_has_calls([MockCall(force=True), MockCall(force=False)])
|
||||
sync_files_mock.assert_has_calls([MockCall(force=True), MockCall(force=False)])
|
||||
|
||||
|
||||
def test_sync_exception(pacman_database: PacmanDatabase, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must suppress all exceptions on failure
|
||||
"""
|
||||
mocker.patch("ahriman.core.alpm.pacman_database.PacmanDatabase.sync_packages", side_effect=Exception)
|
||||
pacman_database.sync(force=True)
|
||||
|
||||
|
||||
def test_sync_files(pacman_database: PacmanDatabase, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must sync files database
|
||||
"""
|
||||
outdated_mock = mocker.patch("ahriman.core.alpm.pacman_database.PacmanDatabase.is_outdated", return_value=True)
|
||||
download_mock = mocker.patch("ahriman.core.alpm.pacman_database.PacmanDatabase.download")
|
||||
|
||||
pacman_database.sync_files(force=False)
|
||||
outdated_mock.assert_called_once_with(
|
||||
"https://geo.mirror.pkgbuild.com/core/os/x86_64/core.files.tar.gz", pytest.helpers.anyvar(int))
|
||||
download_mock.assert_called_once_with(
|
||||
"https://geo.mirror.pkgbuild.com/core/os/x86_64/core.files.tar.gz", pytest.helpers.anyvar(int))
|
||||
|
||||
|
||||
def test_sync_files_not_outdated(pacman_database: PacmanDatabase, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip files sync if up-to-date
|
||||
"""
|
||||
mocker.patch("ahriman.core.alpm.pacman_database.PacmanDatabase.is_outdated", return_value=False)
|
||||
download_mock = mocker.patch("ahriman.core.alpm.pacman_database.PacmanDatabase.download")
|
||||
|
||||
pacman_database.sync_files(force=False)
|
||||
download_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_sync_files_force(pacman_database: PacmanDatabase, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must sync up-to-date files if force flag is set
|
||||
"""
|
||||
mocker.patch("ahriman.core.alpm.pacman_database.PacmanDatabase.is_outdated", return_value=False)
|
||||
download_mock = mocker.patch("ahriman.core.alpm.pacman_database.PacmanDatabase.download")
|
||||
|
||||
pacman_database.sync_files(force=True)
|
||||
download_mock.assert_called_once_with(
|
||||
"https://geo.mirror.pkgbuild.com/core/os/x86_64/core.files.tar.gz", pytest.helpers.anyvar(int))
|
||||
|
||||
|
||||
def test_sync_files_local(pacman_database: PacmanDatabase, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must copy local files instead of downloading them
|
||||
"""
|
||||
pacman_database.database.servers = ["file:///var"]
|
||||
copy_mock = mocker.patch("ahriman.core.alpm.pacman_database.PacmanDatabase.copy")
|
||||
|
||||
pacman_database.sync_files(force=False)
|
||||
copy_mock.assert_called_once_with(Path("/var/core.files.tar.gz"), pytest.helpers.anyvar(int))
|
||||
|
||||
|
||||
def test_sync_files_no_servers(pacman_database: PacmanDatabase) -> None:
|
||||
"""
|
||||
must raise PacmanError if no servers are configured
|
||||
"""
|
||||
pacman_database.database.servers = []
|
||||
with pytest.raises(PacmanError):
|
||||
pacman_database.sync_files(force=False)
|
||||
|
||||
|
||||
def test_sync_files_unknown_source(pacman_database: PacmanDatabase) -> None:
|
||||
"""
|
||||
must raise an exception in case if server scheme is unsupported
|
||||
"""
|
||||
pacman_database.database.servers = ["some random string"]
|
||||
with pytest.raises(PacmanError):
|
||||
pacman_database.sync_files(force=False)
|
||||
|
||||
|
||||
def test_sync_packages(pacman_database: PacmanDatabase) -> None:
|
||||
"""
|
||||
must sync packages by using pyalpm method
|
||||
"""
|
||||
pacman_database.database = MagicMock()
|
||||
|
||||
pacman_database.sync_packages(force=True)
|
||||
pacman_database.sync_packages(force=False)
|
||||
pacman_database.database.update.assert_has_calls([MockCall(True), MockCall(False)])
|
||||
@@ -0,0 +1,37 @@
|
||||
import pytest
|
||||
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from ahriman.core.alpm.pacman_handle import PacmanHandle
|
||||
|
||||
|
||||
def test_package_load() -> None:
|
||||
"""
|
||||
must load package from archive path
|
||||
"""
|
||||
local = Path("local")
|
||||
instance = PacmanHandle.ephemeral()
|
||||
handle_mock = instance.handle = MagicMock()
|
||||
|
||||
instance.package_load(local)
|
||||
handle_mock.load_pkg.assert_called_once_with(str(local))
|
||||
|
||||
PacmanHandle._ephemeral = None
|
||||
|
||||
|
||||
def test_getattr() -> None:
|
||||
"""
|
||||
must proxy attribute access to underlying handle
|
||||
"""
|
||||
instance = PacmanHandle.ephemeral()
|
||||
assert instance.dbpath
|
||||
|
||||
|
||||
def test_getattr_not_found() -> None:
|
||||
"""
|
||||
must raise AttributeError for missing handle attributes
|
||||
"""
|
||||
instance = PacmanHandle.ephemeral()
|
||||
with pytest.raises(AttributeError):
|
||||
assert instance.random_attribute
|
||||
@@ -0,0 +1,329 @@
|
||||
import pytest
|
||||
|
||||
from io import StringIO
|
||||
from pathlib import Path
|
||||
|
||||
from ahriman.core.alpm.pkgbuild_parser import PkgbuildParser
|
||||
from ahriman.core.exceptions import PkgbuildParserError
|
||||
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||
|
||||
|
||||
def test_expand_array() -> None:
|
||||
"""
|
||||
must correctly expand array
|
||||
"""
|
||||
assert PkgbuildParser._expand_array(["${pkgbase}{", ",", "-libs", ",", "-fortran}"]) == [
|
||||
"${pkgbase}", "${pkgbase}-libs", "${pkgbase}-fortran"
|
||||
]
|
||||
assert PkgbuildParser._expand_array(["first", "prefix{1", ",", "2", ",", "3}suffix", "last"]) == [
|
||||
"first", "prefix1suffix", "prefix2suffix", "prefix3suffix", "last"
|
||||
]
|
||||
|
||||
|
||||
def test_expand_array_no_comma() -> None:
|
||||
"""
|
||||
must skip array extraction if there is no comma
|
||||
"""
|
||||
assert PkgbuildParser._expand_array(["${pkgbase}{", "-libs", "-fortran}"]) == ["${pkgbase}{", "-libs", "-fortran}"]
|
||||
|
||||
|
||||
def test_expand_array_short() -> None:
|
||||
"""
|
||||
must skip array extraction if it is short
|
||||
"""
|
||||
assert PkgbuildParser._expand_array(["${pkgbase}{", ","]) == ["${pkgbase}{", ","]
|
||||
|
||||
|
||||
def test_expand_array_exception() -> None:
|
||||
"""
|
||||
must raise exception if there is unclosed element
|
||||
"""
|
||||
with pytest.raises(PkgbuildParserError):
|
||||
assert PkgbuildParser._expand_array(["${pkgbase}{", ",", "-libs"])
|
||||
|
||||
|
||||
def test_is_escaped_exception(resource_path_root: Path) -> None:
|
||||
"""
|
||||
must raise PkgbuildParserError if no valid utf symbols found
|
||||
"""
|
||||
utf8 = resource_path_root / "models" / "utf8"
|
||||
with utf8.open(encoding="utf8") as content:
|
||||
content.seek(2)
|
||||
with pytest.raises(PkgbuildParserError):
|
||||
assert not PkgbuildParser(content)._is_escaped()
|
||||
|
||||
|
||||
def test_parse_array() -> None:
|
||||
"""
|
||||
must parse array
|
||||
"""
|
||||
parser = PkgbuildParser(StringIO("var=(first second)"))
|
||||
assert list(parser.parse()) == [PkgbuildPatch("var", ["first", "second"])]
|
||||
|
||||
|
||||
def test_parse_array_comment() -> None:
|
||||
"""
|
||||
must parse array with comments inside
|
||||
"""
|
||||
parser = PkgbuildParser(StringIO("""validpgpkeys=(
|
||||
'F3691687D867B81B51CE07D9BBE43771487328A9' # bpiotrowski@archlinux.org
|
||||
'86CFFCA918CF3AF47147588051E8B148A9999C34' # evangelos@foutrelis.com
|
||||
'13975A70E63C361C73AE69EF6EEB81F8981C74C7' # richard.guenther@gmail.com
|
||||
'D3A93CAD751C2AF4F8C7AD516C35B99309B5FA62' # Jakub Jelinek <jakub@redhat.com>
|
||||
)"""))
|
||||
assert list(parser.parse()) == [PkgbuildPatch("validpgpkeys", [
|
||||
"F3691687D867B81B51CE07D9BBE43771487328A9",
|
||||
"86CFFCA918CF3AF47147588051E8B148A9999C34",
|
||||
"13975A70E63C361C73AE69EF6EEB81F8981C74C7",
|
||||
"D3A93CAD751C2AF4F8C7AD516C35B99309B5FA62",
|
||||
])]
|
||||
|
||||
|
||||
def test_parse_array_escaped() -> None:
|
||||
"""
|
||||
must correctly process quoted brackets
|
||||
"""
|
||||
parser = PkgbuildParser(StringIO("""var=(first "(" second)"""))
|
||||
assert list(parser.parse()) == [PkgbuildPatch("var", ["first", "(", "second"])]
|
||||
|
||||
parser = PkgbuildParser(StringIO("""var=(first ")" second)"""))
|
||||
assert list(parser.parse()) == [PkgbuildPatch("var", ["first", ")", "second"])]
|
||||
|
||||
parser = PkgbuildParser(StringIO("""var=(first ')' second)"""))
|
||||
assert list(parser.parse()) == [PkgbuildPatch("var", ["first", ")", "second"])]
|
||||
|
||||
parser = PkgbuildParser(StringIO("""var=(first \\) second)"""))
|
||||
assert list(parser.parse()) == [PkgbuildPatch("var", ["first", ")", "second"])]
|
||||
|
||||
|
||||
def test_parse_array_exception() -> None:
|
||||
"""
|
||||
must raise exception if there is no closing bracket
|
||||
"""
|
||||
parser = PkgbuildParser(StringIO("var=(first second"))
|
||||
with pytest.raises(PkgbuildParserError):
|
||||
assert list(parser.parse())
|
||||
|
||||
|
||||
def test_parse_function() -> None:
|
||||
"""
|
||||
must parse function
|
||||
"""
|
||||
parser = PkgbuildParser(StringIO("var() { echo hello world } "))
|
||||
assert list(parser.parse()) == [PkgbuildPatch("var()", "{ echo hello world }")]
|
||||
|
||||
|
||||
def test_parse_function_eof() -> None:
|
||||
"""
|
||||
must parse function with "}" at the end of the file
|
||||
"""
|
||||
parser = PkgbuildParser(StringIO("var() { echo hello world }"))
|
||||
assert list(parser.parse()) == [PkgbuildPatch("var()", "{ echo hello world }")]
|
||||
|
||||
|
||||
def test_parse_function_spaces() -> None:
|
||||
"""
|
||||
must parse function with spaces in declaration
|
||||
"""
|
||||
parser = PkgbuildParser(StringIO("var ( ) { echo hello world } "))
|
||||
assert list(parser.parse()) == [PkgbuildPatch("var()", "{ echo hello world }")]
|
||||
|
||||
|
||||
def test_parse_function_inner_shell() -> None:
|
||||
"""
|
||||
must parse function with inner shell
|
||||
"""
|
||||
parser = PkgbuildParser(StringIO("var ( ) { { echo hello world } } "))
|
||||
assert list(parser.parse()) == [PkgbuildPatch("var()", "{ { echo hello world } }")]
|
||||
|
||||
|
||||
def test_parse_function_escaped() -> None:
|
||||
"""
|
||||
must parse function with bracket in quotes
|
||||
"""
|
||||
parser = PkgbuildParser(StringIO("""var ( ) { echo "hello world {" } """))
|
||||
assert list(parser.parse()) == [PkgbuildPatch("var()", """{ echo "hello world {" }""")]
|
||||
|
||||
parser = PkgbuildParser(StringIO("""var ( ) { echo hello world "{" } """))
|
||||
assert list(parser.parse()) == [PkgbuildPatch("var()", """{ echo hello world "{" }""")]
|
||||
|
||||
parser = PkgbuildParser(StringIO("""var ( ) { echo "hello world }" } """))
|
||||
assert list(parser.parse()) == [PkgbuildPatch("var()", """{ echo "hello world }" }""")]
|
||||
|
||||
parser = PkgbuildParser(StringIO("""var ( ) { echo hello world "}" } """))
|
||||
assert list(parser.parse()) == [PkgbuildPatch("var()", """{ echo hello world "}" }""")]
|
||||
|
||||
parser = PkgbuildParser(StringIO("""var ( ) { echo hello world '}' } """))
|
||||
assert list(parser.parse()) == [PkgbuildPatch("var()", """{ echo hello world '}' }""")]
|
||||
|
||||
parser = PkgbuildParser(StringIO("""var ( ) { echo hello world \\} } """))
|
||||
assert list(parser.parse()) == [PkgbuildPatch("var()", """{ echo hello world \\} }""")]
|
||||
|
||||
|
||||
def test_parse_function_exception() -> None:
|
||||
"""
|
||||
must raise exception if no bracket found
|
||||
"""
|
||||
parser = PkgbuildParser(StringIO("var() echo hello world } "))
|
||||
with pytest.raises(PkgbuildParserError):
|
||||
assert list(parser.parse())
|
||||
|
||||
parser = PkgbuildParser(StringIO("var() { echo hello world"))
|
||||
with pytest.raises(PkgbuildParserError):
|
||||
assert list(parser.parse())
|
||||
|
||||
|
||||
def test_parse_token_assignment() -> None:
|
||||
"""
|
||||
must parse simple assignment
|
||||
"""
|
||||
parser = PkgbuildParser(StringIO())
|
||||
assert next(parser._parse_token("var=value")) == PkgbuildPatch("var", "value")
|
||||
assert next(parser._parse_token("var=$value")) == PkgbuildPatch("var", "$value")
|
||||
assert next(parser._parse_token("var=${value}")) == PkgbuildPatch("var", "${value}")
|
||||
assert next(parser._parse_token("var=${value/-/_}")) == PkgbuildPatch("var", "${value/-/_}")
|
||||
|
||||
|
||||
def test_parse_token_comment() -> None:
|
||||
"""
|
||||
must correctly parse comment
|
||||
"""
|
||||
parser = PkgbuildParser(StringIO("""first=1 # comment
|
||||
# comment line
|
||||
second=2
|
||||
#third=3
|
||||
"""))
|
||||
assert list(parser.parse()) == [
|
||||
PkgbuildPatch("first", "1"),
|
||||
PkgbuildPatch("second", "2"),
|
||||
]
|
||||
|
||||
|
||||
def test_read_comment() -> None:
|
||||
"""
|
||||
must read comment correctly
|
||||
"""
|
||||
io = StringIO("# comment\nnew line")
|
||||
io.seek(2)
|
||||
|
||||
PkgbuildParser(io)._read_comment()
|
||||
assert io.tell() == 10
|
||||
|
||||
|
||||
def test_read_comment_skip() -> None:
|
||||
"""
|
||||
must skip reading new line if comment ends with new line
|
||||
"""
|
||||
io = StringIO("#comment\nnew line")
|
||||
io.seek(7)
|
||||
|
||||
PkgbuildParser(io)._read_comment()
|
||||
assert io.tell() == 9
|
||||
|
||||
|
||||
def test_read_last() -> None:
|
||||
"""
|
||||
must read last symbol from current position
|
||||
"""
|
||||
io = StringIO("mock")
|
||||
io.seek(2)
|
||||
assert PkgbuildParser(io)._read_last() == (1, "o")
|
||||
|
||||
|
||||
def test_read_last_starting() -> None:
|
||||
"""
|
||||
must raise exception if it reads from starting position
|
||||
"""
|
||||
with pytest.raises(PkgbuildParserError):
|
||||
assert PkgbuildParser(StringIO("mock"))._read_last()
|
||||
|
||||
|
||||
def test_read_last_from_position() -> None:
|
||||
"""
|
||||
must read last symbol from the specified position
|
||||
"""
|
||||
assert PkgbuildParser(StringIO("mock"))._read_last(2) == (2, "c")
|
||||
|
||||
|
||||
def test_parse(resource_path_root: Path) -> None:
|
||||
"""
|
||||
must parse complex file
|
||||
"""
|
||||
pkgbuild = resource_path_root / "models" / "pkgbuild"
|
||||
with pkgbuild.open(encoding="utf8") as content:
|
||||
parser = PkgbuildParser(content)
|
||||
assert list(parser.parse()) == [
|
||||
PkgbuildPatch("var", "value"),
|
||||
PkgbuildPatch("var", "value"),
|
||||
PkgbuildPatch("var", "value with space"),
|
||||
PkgbuildPatch("var", "value"),
|
||||
PkgbuildPatch("var", "$ref"),
|
||||
PkgbuildPatch("var", "${ref}"),
|
||||
PkgbuildPatch("var", "$ref value"),
|
||||
PkgbuildPatch("var", "${ref}value"),
|
||||
PkgbuildPatch("var", "${ref/-/_}"),
|
||||
PkgbuildPatch("var", "${ref##.*}"),
|
||||
PkgbuildPatch("var", "${ref%%.*}"),
|
||||
PkgbuildPatch("array", ["first", "second", "third", "with space"]),
|
||||
PkgbuildPatch("array", ["single"]),
|
||||
PkgbuildPatch("array", ["$ref"]),
|
||||
PkgbuildPatch("array", ["first", "second", "third"]),
|
||||
PkgbuildPatch("array", ["first", "second", "third"]),
|
||||
PkgbuildPatch("array", ["first", "last"]),
|
||||
PkgbuildPatch("array", ["first", "1suffix", "2suffix", "last"]),
|
||||
PkgbuildPatch("array", ["first", "prefix1", "prefix2", "last"]),
|
||||
PkgbuildPatch("array", ["first", "prefix1suffix", "prefix2suffix", "last"]),
|
||||
PkgbuildPatch("array", ["first", "(", "second"]),
|
||||
PkgbuildPatch("array", ["first", ")", "second"]),
|
||||
PkgbuildPatch("array", ["first", "(", "second"]),
|
||||
PkgbuildPatch("array", ["first", ")", "second"]),
|
||||
PkgbuildPatch("function()", """{ single line }"""),
|
||||
PkgbuildPatch("function()", """{
|
||||
multi
|
||||
line
|
||||
}"""),
|
||||
PkgbuildPatch("function()", """{
|
||||
c
|
||||
multi
|
||||
line
|
||||
}"""),
|
||||
PkgbuildPatch("function()", """{
|
||||
# comment
|
||||
multi
|
||||
line
|
||||
}"""),
|
||||
PkgbuildPatch("function()", """{
|
||||
body
|
||||
}"""),
|
||||
PkgbuildPatch("function()", """{
|
||||
body
|
||||
}"""),
|
||||
PkgbuildPatch("function_with-package-name()", """{ body }"""),
|
||||
PkgbuildPatch("function()", """{
|
||||
first
|
||||
{ inner shell }
|
||||
last
|
||||
}"""),
|
||||
PkgbuildPatch("function()", """{
|
||||
body "{" argument
|
||||
}"""),
|
||||
PkgbuildPatch("function()", """{
|
||||
body "}" argument
|
||||
}"""),
|
||||
PkgbuildPatch("function()", """{
|
||||
body '{' argument
|
||||
}"""),
|
||||
PkgbuildPatch("function()", """{
|
||||
body '}' argument
|
||||
}"""),
|
||||
PkgbuildPatch("function()", """{
|
||||
# we don't care about unclosed quotation in comments
|
||||
body # no, I said we really don't care
|
||||
}"""),
|
||||
PkgbuildPatch("function()", """{
|
||||
mv "$pkgdir"/usr/share/fonts/站酷小薇体 "$pkgdir"/usr/share/fonts/zcool-xiaowei-regular
|
||||
mv "$pkgdir"/usr/share/licenses/"$pkgname"/LICENSE.站酷小薇体 "$pkgdir"/usr/share/licenses/"$pkgname"/LICENSE.zcool-xiaowei-regular
|
||||
}"""),
|
||||
PkgbuildPatch("var", "value"),
|
||||
PkgbuildPatch("array", ["first", "second", "third"]),
|
||||
]
|
||||
@@ -0,0 +1,71 @@
|
||||
import pytest
|
||||
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.core.alpm.repo import Repo
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
|
||||
|
||||
def test_root(repository_paths: RepositoryPaths) -> None:
|
||||
"""
|
||||
must correctly define repository root
|
||||
"""
|
||||
assert Repo(repository_paths.repository_id.name, repository_paths, []).root == repository_paths.repository
|
||||
assert Repo(repository_paths.repository_id.name, repository_paths, [], Path("path")).root == Path("path")
|
||||
|
||||
|
||||
def test_repo_path(repo: Repo) -> None:
|
||||
"""
|
||||
name must be something like archive name
|
||||
"""
|
||||
assert repo.repo_path.name.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.check_output")
|
||||
|
||||
repo.add(Path("path"))
|
||||
check_output_mock.assert_called_once() # it will be checked later
|
||||
assert check_output_mock.call_args[0][0] == "repo-add"
|
||||
assert "--remove" in check_output_mock.call_args[0]
|
||||
|
||||
|
||||
def test_repo_init(repo: Repo, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must call repo-add with empty package list on repo initializing
|
||||
"""
|
||||
check_output_mock = mocker.patch("ahriman.core.alpm.repo.check_output")
|
||||
|
||||
repo.init()
|
||||
check_output_mock.assert_called_once() # it will be checked later
|
||||
assert check_output_mock.call_args[0][0] == "repo-add"
|
||||
|
||||
|
||||
def test_repo_remove(repo: Repo, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must call repo-remove on package removal
|
||||
"""
|
||||
filepath = package_ahriman.packages[package_ahriman.base].filepath
|
||||
mocker.patch("pathlib.Path.glob", return_value=[])
|
||||
check_output_mock = mocker.patch("ahriman.core.alpm.repo.check_output")
|
||||
|
||||
repo.remove(package_ahriman.base, filepath)
|
||||
check_output_mock.assert_called_once() # it will be checked later
|
||||
assert check_output_mock.call_args[0][0] == "repo-remove"
|
||||
assert package_ahriman.base in check_output_mock.call_args[0]
|
||||
|
||||
|
||||
def test_repo_remove_fail_no_file(repo: Repo, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must fail removal on missing file
|
||||
"""
|
||||
mocker.patch("pathlib.Path.glob", return_value=[Path("package.pkg.tar.xz")])
|
||||
mocker.patch("pathlib.Path.unlink", side_effect=FileNotFoundError)
|
||||
|
||||
with pytest.raises(FileNotFoundError):
|
||||
repo.remove("package", Path("package.pkg.tar.xz"))
|
||||
@@ -0,0 +1,43 @@
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
from typing import Any
|
||||
|
||||
from ahriman.core.alpm.pacman import Pacman
|
||||
from ahriman.core.build_tools.package_archive import PackageArchive
|
||||
from ahriman.core.build_tools.sources import Sources
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
from ahriman.models.scan_paths import ScanPaths
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def package_archive_ahriman(package_ahriman: Package, repository_paths: RepositoryPaths, pacman: Pacman,
|
||||
scan_paths: ScanPaths, passwd: Any, mocker: MockerFixture) -> PackageArchive:
|
||||
"""
|
||||
package archive fixture
|
||||
|
||||
Args:
|
||||
package_ahriman(Package): package test instance
|
||||
repository_paths(RepositoryPaths): repository paths test instance
|
||||
pacman(Pacman): pacman test instance
|
||||
scan_paths(ScanPaths): scan paths test instance
|
||||
passwd(Any): passwd structure test instance
|
||||
mocker(MockerFixture): mocker object
|
||||
|
||||
Returns:
|
||||
PackageArchive: package archive test instance
|
||||
"""
|
||||
mocker.patch("ahriman.models.repository_paths.getpwuid", return_value=passwd)
|
||||
return PackageArchive(repository_paths.build_root, package_ahriman, pacman, scan_paths)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sources() -> Sources:
|
||||
"""
|
||||
sources fixture
|
||||
|
||||
Returns:
|
||||
Sources: sources instance
|
||||
"""
|
||||
return Sources()
|
||||
@@ -0,0 +1,231 @@
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest.mock import MagicMock, PropertyMock
|
||||
|
||||
from ahriman.core.build_tools.package_archive import PackageArchive
|
||||
from ahriman.core.exceptions import UnknownPackageError
|
||||
from ahriman.models.filesystem_package import FilesystemPackage
|
||||
|
||||
|
||||
def test_dynamic_needed(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must correctly define list of dynamically linked libraries
|
||||
"""
|
||||
mocker.patch("ahriman.core.build_tools.package_archive.PackageArchive.is_elf", return_value=True)
|
||||
|
||||
linked = PackageArchive.dynamic_needed(Path(".tox") / "tests" / "bin" / "python")
|
||||
assert linked
|
||||
assert next(library for library in linked if library.startswith("libpython"))
|
||||
assert next(library for library in linked if library.startswith("libc"))
|
||||
|
||||
|
||||
def test_dynamic_needed_not_elf(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip checking if not an elf file
|
||||
"""
|
||||
mocker.patch("ahriman.core.build_tools.package_archive.PackageArchive.is_elf", return_value=False)
|
||||
assert not PackageArchive.dynamic_needed(Path(".tox") / "tests" / "bin" / "python")
|
||||
|
||||
|
||||
def test_dynamic_needed_no_section(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip checking if there was no dynamic section found
|
||||
"""
|
||||
mocker.patch("ahriman.core.build_tools.package_archive.PackageArchive.is_elf", return_value=True)
|
||||
mocker.patch("elftools.elf.elffile.ELFFile.iter_sections", return_value=[])
|
||||
assert not PackageArchive.dynamic_needed(Path(".tox") / "tests" / "bin" / "python")
|
||||
|
||||
|
||||
def test_is_elf() -> None:
|
||||
"""
|
||||
must correctly define elf file
|
||||
"""
|
||||
assert not PackageArchive.is_elf(BytesIO())
|
||||
assert not PackageArchive.is_elf(BytesIO(b"random string"))
|
||||
assert PackageArchive.is_elf(BytesIO(b"\x7fELF"))
|
||||
assert PackageArchive.is_elf(BytesIO(b"\x7fELF\nrandom string"))
|
||||
|
||||
|
||||
def test_load_pacman_package(package_archive_ahriman: PackageArchive, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must correctly load filesystem package from pacman
|
||||
"""
|
||||
directory = f"{package_archive_ahriman.package.base}-{package_archive_ahriman.package.version}"
|
||||
path = Path("/") / "var" / "lib" / "pacman" / "local" / directory / "files"
|
||||
package = MagicMock()
|
||||
type(package).depends = PropertyMock(return_value=["depends"])
|
||||
type(package).opt_depends = PropertyMock(return_value=["opt_depends"])
|
||||
info_mock = mocker.patch("ahriman.core.alpm.remote.OfficialSyncdb.info", return_value=package)
|
||||
|
||||
assert package_archive_ahriman._load_pacman_package(path) == FilesystemPackage(
|
||||
package_name=package_archive_ahriman.package.base,
|
||||
depends={"depends"},
|
||||
opt_depends={"opt_depends"},
|
||||
)
|
||||
info_mock.assert_called_once_with(package_archive_ahriman.package.base, pacman=package_archive_ahriman.pacman)
|
||||
|
||||
|
||||
def test_load_pacman_package_exception(package_archive_ahriman: PackageArchive, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must return empty package if no package found
|
||||
"""
|
||||
directory = f"{package_archive_ahriman.package.base}-{package_archive_ahriman.package.version}"
|
||||
path = Path("/") / "var" / "lib" / "pacman" / "local" / directory / "files"
|
||||
mocker.patch("ahriman.core.alpm.remote.OfficialSyncdb.info",
|
||||
side_effect=UnknownPackageError(package_archive_ahriman.package.base))
|
||||
|
||||
assert package_archive_ahriman._load_pacman_package(path) == FilesystemPackage(
|
||||
package_name=package_archive_ahriman.package.base,
|
||||
depends=set(),
|
||||
opt_depends=set(),
|
||||
)
|
||||
|
||||
|
||||
def test_raw_dependencies_packages(package_archive_ahriman: PackageArchive, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must correctly extract raw dependencies list
|
||||
"""
|
||||
packages = {
|
||||
package_archive_ahriman.package.base: FilesystemPackage(
|
||||
package_name=package_archive_ahriman.package.base,
|
||||
depends=set(),
|
||||
opt_depends=set(),
|
||||
directories=[Path("usr") / "dir2"],
|
||||
files=[Path("file1")],
|
||||
),
|
||||
"package1": FilesystemPackage(
|
||||
package_name="package1",
|
||||
depends=set(),
|
||||
opt_depends=set(),
|
||||
directories=[Path("package1") / "dir1", Path("usr") / "dir2"],
|
||||
files=[Path("package1") / "file1", Path("package1") / "file2"],
|
||||
),
|
||||
"package2": FilesystemPackage(
|
||||
package_name="package2",
|
||||
depends=set(),
|
||||
opt_depends=set(),
|
||||
directories=[Path("usr") / "dir2", Path("package2") / "dir3", Path("package2") / "dir4"],
|
||||
files=[Path("package2") / "file4", Path("package2") / "file3"],
|
||||
),
|
||||
}
|
||||
mocker.patch("ahriman.core.build_tools.package_archive.PackageArchive.installed_packages", return_value=packages)
|
||||
mocker.patch("ahriman.core.build_tools.package_archive.PackageArchive.depends_on_paths", return_value=(
|
||||
{"file1", "file3"},
|
||||
{Path("usr") / "dir2", Path("dir3"), Path("package2") / "dir4"},
|
||||
))
|
||||
|
||||
result = package_archive_ahriman._raw_dependencies_packages()
|
||||
assert result == {
|
||||
Path("package1") / "file1": [packages["package1"]],
|
||||
Path("package2") / "file3": [packages["package2"]],
|
||||
Path("package2") / "dir4": [packages["package2"]],
|
||||
Path("usr") / "dir2": [packages["package1"], packages["package2"]],
|
||||
}
|
||||
|
||||
|
||||
def test_refine_dependencies(package_archive_ahriman: PackageArchive, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must correctly refine dependencies list
|
||||
"""
|
||||
base_package = MagicMock()
|
||||
type(base_package).depends = PropertyMock(return_value=["base"])
|
||||
info_mock = mocker.patch("ahriman.core.alpm.remote.OfficialSyncdb.info", return_value=base_package)
|
||||
|
||||
path1 = Path("usr") / "lib" / "python3.12"
|
||||
path2 = path1 / "site-packages"
|
||||
path3 = Path("usr") / "lib" / "path"
|
||||
path4 = Path("usr") / "lib" / "whatever"
|
||||
path5 = Path("usr") / "share" / "applications"
|
||||
path6 = Path("etc")
|
||||
|
||||
package1 = FilesystemPackage(package_name="package1", depends={"package5"}, opt_depends={"package2"})
|
||||
package2 = FilesystemPackage(package_name="package2", depends={"package1"}, opt_depends=set())
|
||||
package3 = FilesystemPackage(package_name="package3", depends=set(), opt_depends={"package1"})
|
||||
package4 = FilesystemPackage(package_name="base", depends=set(), opt_depends=set())
|
||||
package5 = FilesystemPackage(package_name="package5", depends={"package1"}, opt_depends=set())
|
||||
package6 = FilesystemPackage(package_name="package6", depends=set(), opt_depends=set())
|
||||
|
||||
assert package_archive_ahriman._refine_dependencies({
|
||||
path1: [package1, package2, package3, package5, package6],
|
||||
path2: [package1, package2, package3, package5],
|
||||
path3: [package1, package4],
|
||||
path4: [package1],
|
||||
path5: [package1],
|
||||
path6: [package1],
|
||||
}) == {
|
||||
path1: [package6],
|
||||
path2: [package1, package5],
|
||||
path4: [package1],
|
||||
}
|
||||
info_mock.assert_called_once_with("base", pacman=package_archive_ahriman.pacman)
|
||||
|
||||
|
||||
def test_depends_on(package_archive_ahriman: PackageArchive, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must extract packages and files which are dependencies for the package
|
||||
"""
|
||||
raw_mock = mocker.patch("ahriman.core.build_tools.package_archive.PackageArchive._raw_dependencies_packages",
|
||||
return_value="1")
|
||||
refined_mock = mocker.patch(
|
||||
"ahriman.core.build_tools.package_archive.PackageArchive._refine_dependencies", return_value={
|
||||
Path("package1") / "file1": [FilesystemPackage(package_name="package1", depends=set(), opt_depends=set())],
|
||||
Path("package2") / "file3": [FilesystemPackage(package_name="package2", depends=set(), opt_depends=set())],
|
||||
Path("package2") / "dir4": [FilesystemPackage(package_name="package2", depends=set(), opt_depends=set())],
|
||||
Path("usr") / "dir2": [
|
||||
FilesystemPackage(package_name="package1", depends=set(), opt_depends=set()),
|
||||
FilesystemPackage(package_name="package2", depends=set(), opt_depends=set()),
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
result = package_archive_ahriman.depends_on()
|
||||
raw_mock.assert_called_once_with()
|
||||
refined_mock.assert_called_once_with("1")
|
||||
assert result.paths == {
|
||||
"package1/file1": ["package1"],
|
||||
"package2/file3": ["package2"],
|
||||
"package2/dir4": ["package2"],
|
||||
"usr/dir2": ["package1", "package2"]
|
||||
}
|
||||
|
||||
|
||||
def test_depends_on_paths(package_archive_ahriman: PackageArchive, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must correctly extract dependencies
|
||||
"""
|
||||
package_dir = package_archive_ahriman.root / "build" / \
|
||||
package_archive_ahriman.package.base / "pkg" / package_archive_ahriman.package.base
|
||||
dynamic_mock = mocker.patch("ahriman.core.build_tools.package_archive.PackageArchive.dynamic_needed",
|
||||
return_value=["lib"])
|
||||
walk_mock = mocker.patch("ahriman.core.build_tools.package_archive.walk", return_value=[
|
||||
package_dir / "root" / "file",
|
||||
Path("directory"),
|
||||
])
|
||||
mocker.patch("pathlib.Path.is_file", autospec=True, side_effect=lambda path: path != Path("directory"))
|
||||
|
||||
dependencies, roots = package_archive_ahriman.depends_on_paths()
|
||||
assert dependencies == {"lib"}
|
||||
assert roots == {Path("root")}
|
||||
dynamic_mock.assert_called_once_with(package_dir / "root" / "file")
|
||||
walk_mock.assert_called_once_with(package_dir)
|
||||
|
||||
|
||||
def test_installed_packages(package_archive_ahriman: PackageArchive, mocker: MockerFixture,
|
||||
resource_path_root: Path) -> None:
|
||||
"""
|
||||
must load list of installed packages and their files
|
||||
"""
|
||||
walk_mock = mocker.patch("ahriman.core.build_tools.package_archive.walk", return_value=[
|
||||
Path("ahriman-2.13.3-1") / "desc",
|
||||
Path("ahriman-2.13.3-1") / "files",
|
||||
])
|
||||
files = (resource_path_root / "models" / "package_ahriman_files").read_text(encoding="utf8")
|
||||
read_mock = mocker.patch("pathlib.Path.read_text", return_value=files)
|
||||
|
||||
result = package_archive_ahriman.installed_packages()
|
||||
assert result
|
||||
assert Path("usr") in result[package_archive_ahriman.package.base].directories
|
||||
assert Path("usr/bin/ahriman") in result[package_archive_ahriman.package.base].files
|
||||
walk_mock.assert_called_once_with(package_archive_ahriman.root / "var" / "lib" / "pacman" / "local")
|
||||
read_mock.assert_called_once_with(encoding="utf8")
|
||||
@@ -0,0 +1,111 @@
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.core.build_tools.package_version import PackageVersion
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.utils import utcnow
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.pkgbuild import Pkgbuild
|
||||
|
||||
|
||||
def test_actual_version(package_ahriman: Package, configuration: Configuration) -> None:
|
||||
"""
|
||||
must return same actual_version as version is
|
||||
"""
|
||||
assert PackageVersion(package_ahriman).actual_version(configuration) == package_ahriman.version
|
||||
|
||||
|
||||
def test_actual_version_vcs(package_tpacpi_bat_git: Package, configuration: Configuration,
|
||||
mocker: MockerFixture, resource_path_root: Path) -> None:
|
||||
"""
|
||||
must return valid actual_version for VCS package
|
||||
"""
|
||||
pkgbuild = resource_path_root / "models" / "package_tpacpi-bat-git_pkgbuild"
|
||||
mocker.patch("ahriman.models.pkgbuild.Pkgbuild.from_file", return_value=Pkgbuild.from_file(pkgbuild))
|
||||
mocker.patch("pathlib.Path.glob", return_value=[Path("local")])
|
||||
init_mock = mocker.patch("ahriman.core.build_tools.task.Task.init")
|
||||
unlink_mock = mocker.patch("pathlib.Path.unlink")
|
||||
|
||||
assert PackageVersion(package_tpacpi_bat_git).actual_version(configuration) == "3.1.r13.g4959b52-1"
|
||||
init_mock.assert_called_once_with(configuration.repository_paths.cache_for(package_tpacpi_bat_git.base), [], None)
|
||||
unlink_mock.assert_called_once_with()
|
||||
|
||||
|
||||
def test_actual_version_failed(package_tpacpi_bat_git: Package, configuration: Configuration,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must return same version in case if exception occurred
|
||||
"""
|
||||
mocker.patch("ahriman.core.build_tools.task.Task.init", side_effect=Exception)
|
||||
mocker.patch("pathlib.Path.glob", return_value=[Path("local")])
|
||||
unlink_mock = mocker.patch("pathlib.Path.unlink")
|
||||
|
||||
assert PackageVersion(package_tpacpi_bat_git).actual_version(configuration) == package_tpacpi_bat_git.version
|
||||
unlink_mock.assert_called_once_with()
|
||||
|
||||
|
||||
def test_is_newer_than(package_ahriman: Package, package_python_schedule: Package) -> None:
|
||||
"""
|
||||
must correctly check if package is newer than specified timestamp
|
||||
"""
|
||||
# base checks, true/false
|
||||
older = package_ahriman.packages[package_ahriman.base].build_date - 1
|
||||
assert PackageVersion(package_ahriman).is_newer_than(older)
|
||||
|
||||
newer = package_ahriman.packages[package_ahriman.base].build_date + 1
|
||||
assert not PackageVersion(package_ahriman).is_newer_than(newer)
|
||||
|
||||
# list check
|
||||
min_date = min(package.build_date for package in package_python_schedule.packages.values())
|
||||
assert PackageVersion(package_python_schedule).is_newer_than(min_date)
|
||||
|
||||
# null list check
|
||||
package_python_schedule.packages["python-schedule"].build_date = None
|
||||
assert PackageVersion(package_python_schedule).is_newer_than(min_date)
|
||||
|
||||
package_python_schedule.packages["python2-schedule"].build_date = None
|
||||
assert not PackageVersion(package_python_schedule).is_newer_than(min_date)
|
||||
|
||||
|
||||
def test_is_outdated_false(package_ahriman: Package, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must be not outdated for the same package
|
||||
"""
|
||||
actual_version_mock = mocker.patch("ahriman.core.build_tools.package_version.PackageVersion.actual_version",
|
||||
return_value=package_ahriman.version)
|
||||
assert not PackageVersion(package_ahriman).is_outdated(package_ahriman, configuration)
|
||||
actual_version_mock.assert_called_once_with(configuration)
|
||||
|
||||
|
||||
def test_is_outdated_true(package_ahriman: Package, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must be outdated for the new version
|
||||
"""
|
||||
other = Package.from_json(package_ahriman.view())
|
||||
other.version = other.version.replace("-1", "-2")
|
||||
actual_version_mock = mocker.patch("ahriman.core.build_tools.package_version.PackageVersion.actual_version",
|
||||
return_value=other.version)
|
||||
|
||||
assert PackageVersion(package_ahriman).is_outdated(other, configuration)
|
||||
actual_version_mock.assert_called_once_with(configuration)
|
||||
|
||||
|
||||
def test_is_outdated_no_version_calculation(package_ahriman: Package, configuration: Configuration,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must not call actual version if calculation is disabled
|
||||
"""
|
||||
actual_version_mock = mocker.patch("ahriman.core.build_tools.package_version.PackageVersion.actual_version")
|
||||
assert not PackageVersion(package_ahriman).is_outdated(package_ahriman, configuration, calculate_version=False)
|
||||
actual_version_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_is_outdated_fresh_package(package_ahriman: Package, configuration: Configuration,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must not call actual version if package is never than specified time
|
||||
"""
|
||||
configuration.set_option("build", "vcs_allowed_age", str(int(utcnow().timestamp())))
|
||||
actual_version_mock = mocker.patch("ahriman.core.build_tools.package_version.PackageVersion.actual_version")
|
||||
assert not PackageVersion(package_ahriman).is_outdated(package_ahriman, configuration)
|
||||
actual_version_mock.assert_not_called()
|
||||
@@ -0,0 +1,616 @@
|
||||
import pytest
|
||||
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest.mock import call as MockCall
|
||||
|
||||
from ahriman.core.build_tools.sources import Sources
|
||||
from ahriman.core.exceptions import CalledProcessError
|
||||
from ahriman.models.changes import Changes
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.package_source import PackageSource
|
||||
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||
from ahriman.models.remote_source import RemoteSource
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
|
||||
|
||||
def test_changes(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must calculate changes from the last known commit
|
||||
"""
|
||||
fetch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.fetch_until")
|
||||
diff_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.diff", return_value="diff")
|
||||
read_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.read", return_value="pkgbuild")
|
||||
local = Path("local")
|
||||
last_commit_sha = "sha"
|
||||
|
||||
assert Sources.changes(local, last_commit_sha) == Changes(last_commit_sha, "diff", "pkgbuild")
|
||||
fetch_mock.assert_called_once_with(local, commit_sha=last_commit_sha)
|
||||
diff_mock.assert_called_once_with(local, last_commit_sha)
|
||||
read_mock.assert_called_once_with(local, "HEAD", Path("PKGBUILD"))
|
||||
|
||||
|
||||
def test_changes_unknown_commit(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must return changes without diff in case if commit sha wasn't found at the required depth
|
||||
"""
|
||||
mocker.patch("ahriman.core.build_tools.sources.Sources.fetch_until", return_value=None)
|
||||
diff_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.diff")
|
||||
read_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.read", return_value="pkgbuild")
|
||||
|
||||
assert Sources.changes(Path("local"), "sha") == Changes("sha", None, "pkgbuild")
|
||||
diff_mock.assert_not_called()
|
||||
read_mock.assert_called_once_with(Path("local"), "HEAD", Path("PKGBUILD"))
|
||||
|
||||
|
||||
def test_extend_architectures(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must update available architecture list
|
||||
"""
|
||||
mocker.patch("pathlib.Path.is_file", return_value=True)
|
||||
architectures_mock = mocker.patch("ahriman.models.pkgbuild.Pkgbuild.supported_architectures",
|
||||
return_value={"x86_64"})
|
||||
|
||||
assert Sources.extend_architectures(Path("local"), "i686") == [PkgbuildPatch("arch", list({"x86_64", "i686"}))]
|
||||
architectures_mock.assert_called_once_with(Path("local"))
|
||||
|
||||
|
||||
def test_extend_architectures_any(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip architecture patching in case if there is any architecture
|
||||
"""
|
||||
mocker.patch("pathlib.Path.is_file", return_value=True)
|
||||
mocker.patch("ahriman.models.pkgbuild.Pkgbuild.supported_architectures", return_value={"any"})
|
||||
assert Sources.extend_architectures(Path("local"), "i686") == []
|
||||
|
||||
|
||||
def test_fetch_empty(remote_source: RemoteSource, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must do nothing in case if no branches available
|
||||
"""
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||
mocker.patch("ahriman.core.build_tools.sources.Sources.has_remotes", return_value=False)
|
||||
head_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.head", return_value="sha")
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output")
|
||||
|
||||
local = Path("local")
|
||||
assert Sources.fetch(local, remote_source) == "sha"
|
||||
head_mock.assert_called_once_with(local)
|
||||
check_output_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_fetch_existing(sources: Sources, remote_source: RemoteSource, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must fetch new package via fetch command
|
||||
"""
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||
mocker.patch("ahriman.core.build_tools.sources.Sources.has_remotes", return_value=True)
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output")
|
||||
fetch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.fetch_until")
|
||||
move_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.move")
|
||||
head_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.head", return_value="sha")
|
||||
|
||||
local = Path("local")
|
||||
assert sources.fetch(local, remote_source) == "sha"
|
||||
fetch_mock.assert_called_once_with(local, branch=remote_source.branch)
|
||||
check_output_mock.assert_has_calls([
|
||||
MockCall(*sources.git(), "checkout", "--force", remote_source.branch,
|
||||
cwd=local, logger=pytest.helpers.anyvar(int)),
|
||||
MockCall(*sources.git(), "reset", "--quiet", "--hard", f"origin/{remote_source.branch}",
|
||||
cwd=local, logger=pytest.helpers.anyvar(int)),
|
||||
])
|
||||
move_mock.assert_called_once_with(local.resolve(), local)
|
||||
head_mock.assert_called_once_with(local)
|
||||
|
||||
|
||||
def test_fetch_new(sources: Sources, remote_source: RemoteSource, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must fetch new package via clone command
|
||||
"""
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output")
|
||||
move_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.move")
|
||||
head_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.head", return_value="sha")
|
||||
|
||||
local = Path("local")
|
||||
assert sources.fetch(local, remote_source) == "sha"
|
||||
check_output_mock.assert_has_calls([
|
||||
MockCall(*sources.git(), "clone", "--quiet", "--depth", "1", "--branch", remote_source.branch,
|
||||
"--single-branch", remote_source.git_url, str(local),
|
||||
cwd=local.parent, logger=pytest.helpers.anyvar(int)),
|
||||
MockCall(*sources.git(), "checkout", "--force", remote_source.branch,
|
||||
cwd=local, logger=pytest.helpers.anyvar(int)),
|
||||
MockCall(*sources.git(), "reset", "--quiet", "--hard", f"origin/{remote_source.branch}",
|
||||
cwd=local, logger=pytest.helpers.anyvar(int))
|
||||
])
|
||||
move_mock.assert_called_once_with(local.resolve(), local)
|
||||
head_mock.assert_called_once_with(local)
|
||||
|
||||
|
||||
def test_fetch_new_without_remote(sources: Sources, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must fetch nothing in case if no remote set
|
||||
"""
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output")
|
||||
move_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.move")
|
||||
head_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.head", return_value="sha")
|
||||
|
||||
local = Path("local")
|
||||
assert sources.fetch(local, RemoteSource(source=PackageSource.Archive)) == "sha"
|
||||
check_output_mock.assert_has_calls([
|
||||
MockCall(*sources.git(), "checkout", "--force", sources.DEFAULT_BRANCH,
|
||||
cwd=local, logger=pytest.helpers.anyvar(int)),
|
||||
MockCall(*sources.git(), "reset", "--quiet", "--hard", f"origin/{sources.DEFAULT_BRANCH}",
|
||||
cwd=local, logger=pytest.helpers.anyvar(int))
|
||||
])
|
||||
move_mock.assert_called_once_with(local.resolve(), local)
|
||||
head_mock.assert_called_once_with(local)
|
||||
|
||||
|
||||
def test_fetch_relative(remote_source: RemoteSource, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must process move correctly on relative directory
|
||||
"""
|
||||
mocker.patch("ahriman.core.build_tools.sources.check_output")
|
||||
move_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.move")
|
||||
head_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.head", return_value="sha")
|
||||
|
||||
local = Path("local")
|
||||
assert Sources.fetch(local, remote_source) == "sha"
|
||||
move_mock.assert_called_once_with(local.resolve(), local)
|
||||
head_mock.assert_called_once_with(local)
|
||||
|
||||
|
||||
def test_has_remotes(sources: Sources, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must ask for remotes
|
||||
"""
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output", return_value="origin")
|
||||
|
||||
local = Path("local")
|
||||
assert sources.has_remotes(local)
|
||||
check_output_mock.assert_called_once_with(*sources.git(), "remote", cwd=local, logger=pytest.helpers.anyvar(int))
|
||||
|
||||
|
||||
def test_has_remotes_empty(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must ask for remotes and return false in case if no remotes found
|
||||
"""
|
||||
mocker.patch("ahriman.core.build_tools.sources.check_output", return_value="")
|
||||
assert not Sources.has_remotes(Path("local"))
|
||||
|
||||
|
||||
def test_init(sources: Sources, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must create empty repository at the specified path
|
||||
"""
|
||||
mocker.patch("ahriman.models.pkgbuild.Pkgbuild.local_files", return_value=[Path("local")])
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||
add_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.add")
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output")
|
||||
commit_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.commit")
|
||||
|
||||
local = Path("local")
|
||||
sources.init(local)
|
||||
check_output_mock.assert_called_once_with(*sources.git(), "init", "--quiet", "--initial-branch",
|
||||
sources.DEFAULT_BRANCH, cwd=local, logger=pytest.helpers.anyvar(int))
|
||||
add_mock.assert_called_once_with(local, "PKGBUILD", ".SRCINFO", "local")
|
||||
commit_mock.assert_called_once_with(local)
|
||||
|
||||
|
||||
def test_init_skip(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip git init if it was already
|
||||
"""
|
||||
mocker.patch("ahriman.models.pkgbuild.Pkgbuild.local_files", return_value=[Path("local")])
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||
mocker.patch("ahriman.core.build_tools.sources.Sources.add")
|
||||
mocker.patch("ahriman.core.build_tools.sources.Sources.commit")
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output")
|
||||
|
||||
Sources.init(Path("local"))
|
||||
check_output_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_load(package_ahriman: Package, repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must load packages sources correctly
|
||||
"""
|
||||
patch = PkgbuildPatch(None, "patch")
|
||||
path = Path("local")
|
||||
fetch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.fetch", return_value="sha")
|
||||
patch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.patch_apply")
|
||||
architectures_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.extend_architectures", return_value=[])
|
||||
|
||||
assert Sources.load(path, package_ahriman, [patch], repository_paths) == "sha"
|
||||
fetch_mock.assert_called_once_with(path, package_ahriman.remote)
|
||||
patch_mock.assert_called_once_with(path, patch)
|
||||
architectures_mock.assert_called_once_with(path, repository_paths.repository_id.architecture)
|
||||
|
||||
|
||||
def test_load_no_patch(package_ahriman: Package, repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must load packages sources correctly without patches
|
||||
"""
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||
mocker.patch("ahriman.core.build_tools.sources.Sources.fetch", return_value="sha")
|
||||
mocker.patch("ahriman.core.build_tools.sources.Sources.extend_architectures", return_value=[])
|
||||
patch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.patch_apply")
|
||||
|
||||
assert Sources.load(Path("local"), package_ahriman, [], repository_paths) == "sha"
|
||||
patch_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_load_with_cache(package_ahriman: Package, repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must load sources by using local cache
|
||||
"""
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||
copytree_mock = mocker.patch("shutil.copytree")
|
||||
mocker.patch("ahriman.core.build_tools.sources.Sources.fetch", return_value="sha")
|
||||
mocker.patch("ahriman.core.build_tools.sources.Sources.extend_architectures", return_value=[])
|
||||
|
||||
assert Sources.load(Path("local"), package_ahriman, [], repository_paths) == "sha"
|
||||
copytree_mock.assert_called_once() # we do not check full command here, sorry
|
||||
|
||||
|
||||
def test_patch_create(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must create patch set for the package
|
||||
"""
|
||||
add_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.add")
|
||||
diff_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.diff")
|
||||
|
||||
Sources.patch_create(Path("local"), "glob")
|
||||
add_mock.assert_called_once_with(Path("local"), "glob", intent_to_add=True)
|
||||
diff_mock.assert_called_once_with(Path("local"))
|
||||
|
||||
|
||||
def test_patch_create_with_newline(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
created patch must have new line at the end
|
||||
"""
|
||||
mocker.patch("ahriman.core.build_tools.sources.Sources.add")
|
||||
mocker.patch("ahriman.core.build_tools.sources.Sources.diff", return_value="diff")
|
||||
assert Sources.patch_create(Path("local"), "glob").endswith("\n")
|
||||
|
||||
|
||||
def test_push(package_ahriman: Package, sources: Sources, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must correctly push files to remote repository
|
||||
"""
|
||||
add_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.add")
|
||||
commit_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.commit", return_value=True)
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output")
|
||||
|
||||
commit_author = ("commit author", "user@host")
|
||||
local = Path("local")
|
||||
sources.push(local, package_ahriman.remote, "glob", commit_author=commit_author)
|
||||
add_mock.assert_called_once_with(local, "glob")
|
||||
commit_mock.assert_called_once_with(local, commit_author=commit_author)
|
||||
check_output_mock.assert_called_once_with(
|
||||
*sources.git(), "push", "--quiet", package_ahriman.remote.git_url, package_ahriman.remote.branch,
|
||||
cwd=local, logger=pytest.helpers.anyvar(int))
|
||||
|
||||
|
||||
def test_push_skipped(package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip push if no changes were committed
|
||||
"""
|
||||
mocker.patch("ahriman.core.build_tools.sources.Sources.add")
|
||||
mocker.patch("ahriman.core.build_tools.sources.Sources.commit", return_value=False)
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output")
|
||||
|
||||
Sources.push(Path("local"), package_ahriman.remote)
|
||||
check_output_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_add(sources: Sources, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must add files to git
|
||||
"""
|
||||
glob_mock = mocker.patch("pathlib.Path.glob", return_value=[Path("local/1"), Path("local/2")])
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output")
|
||||
|
||||
local = Path("local")
|
||||
sources.add(local, "pattern1", "pattern2")
|
||||
glob_mock.assert_has_calls([MockCall("pattern1"), MockCall("pattern2")])
|
||||
check_output_mock.assert_called_once_with(
|
||||
*sources.git(), "add", "1", "2", "1", "2", cwd=local, logger=sources.logger
|
||||
)
|
||||
|
||||
|
||||
def test_add_intent_to_add(sources: Sources, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must add files to git with --intent-to-add flag
|
||||
"""
|
||||
glob_mock = mocker.patch("pathlib.Path.glob", return_value=[Path("local/1"), Path("local/2")])
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output")
|
||||
|
||||
local = Path("local")
|
||||
sources.add(local, "pattern1", "pattern2", intent_to_add=True)
|
||||
glob_mock.assert_has_calls([MockCall("pattern1"), MockCall("pattern2")])
|
||||
check_output_mock.assert_called_once_with(
|
||||
*sources.git(), "add", "--intent-to-add", "1", "2", "1", "2", cwd=local, logger=sources.logger
|
||||
)
|
||||
|
||||
|
||||
def test_add_skip(sources: Sources, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip addition of files to index if no fields found
|
||||
"""
|
||||
mocker.patch("pathlib.Path.glob", return_value=[])
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output")
|
||||
|
||||
sources.add(Path("local"), "pattern1")
|
||||
check_output_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_commit(sources: Sources, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must commit changes
|
||||
"""
|
||||
mocker.patch("ahriman.core.build_tools.sources.Sources.has_changes", return_value=True)
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output")
|
||||
|
||||
local = Path("local")
|
||||
message = "Commit message"
|
||||
user, email = sources.DEFAULT_COMMIT_AUTHOR
|
||||
assert sources.commit(local, message=message)
|
||||
check_output_mock.assert_called_once_with(
|
||||
*sources.git(), "-c", f"user.email=\"{email}\"", "-c", f"user.name=\"{user}\"",
|
||||
"commit", "--quiet", "--message", message, cwd=local, logger=sources.logger
|
||||
)
|
||||
|
||||
|
||||
def test_commit_no_changes(sources: Sources, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip commit if there are no changes
|
||||
"""
|
||||
mocker.patch("ahriman.core.build_tools.sources.Sources.has_changes", return_value=False)
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output")
|
||||
|
||||
assert not sources.commit(Path("local"))
|
||||
check_output_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_commit_author(sources: Sources, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must commit changes with commit author
|
||||
"""
|
||||
mocker.patch("ahriman.core.build_tools.sources.Sources.has_changes", return_value=True)
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output")
|
||||
|
||||
local = Path("local")
|
||||
message = "Commit message"
|
||||
user, email = author = ("commit author", "user@host")
|
||||
assert sources.commit(Path("local"), message=message, commit_author=author)
|
||||
check_output_mock.assert_called_once_with(
|
||||
*sources.git(), "-c", f"user.email=\"{email}\"", "-c", f"user.name=\"{user}\"",
|
||||
"commit", "--quiet", "--message", message, cwd=local, logger=sources.logger
|
||||
)
|
||||
|
||||
|
||||
def test_commit_autogenerated_message(sources: Sources, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must commit changes with autogenerated commit message
|
||||
"""
|
||||
mocker.patch("ahriman.core.build_tools.sources.Sources.has_changes", return_value=True)
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output")
|
||||
|
||||
local = Path("local")
|
||||
assert sources.commit(Path("local"))
|
||||
user, email = sources.DEFAULT_COMMIT_AUTHOR
|
||||
check_output_mock.assert_called_once_with(
|
||||
*sources.git(), "-c", f"user.email=\"{email}\"", "-c", f"user.name=\"{user}\"",
|
||||
"commit", "--quiet", "--message", pytest.helpers.anyvar(str, strict=True), cwd=local, logger=sources.logger
|
||||
)
|
||||
|
||||
|
||||
def test_diff(sources: Sources, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must calculate diff
|
||||
"""
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output")
|
||||
|
||||
local = Path("local")
|
||||
assert sources.diff(local)
|
||||
check_output_mock.assert_called_once_with(*sources.git(), "diff", cwd=local, logger=sources.logger)
|
||||
|
||||
|
||||
def test_diff_specific(sources: Sources, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must calculate diff from specific ref
|
||||
"""
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output")
|
||||
|
||||
local = Path("local")
|
||||
assert sources.diff(local, "hash")
|
||||
check_output_mock.assert_called_once_with(*sources.git(), "diff", "hash", cwd=local, logger=sources.logger)
|
||||
|
||||
|
||||
def test_fetch_until(sources: Sources, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must fetch until the specified commit
|
||||
"""
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output", side_effect=[
|
||||
"",
|
||||
CalledProcessError(1, ["command"], "error"),
|
||||
"",
|
||||
"",
|
||||
])
|
||||
local = Path("local")
|
||||
last_commit_sha = "sha"
|
||||
|
||||
assert sources.fetch_until(local, branch="master", commit_sha="sha") == last_commit_sha
|
||||
check_output_mock.assert_has_calls([
|
||||
MockCall(*sources.git(), "fetch", "--quiet", "--depth", "1", "origin", "master",
|
||||
cwd=local, logger=sources.logger),
|
||||
MockCall(*sources.git(), "cat-file", "-e", last_commit_sha, cwd=local, logger=sources.logger),
|
||||
MockCall(*sources.git(), "fetch", "--quiet", "--depth", "2", "origin", "master",
|
||||
cwd=local, logger=sources.logger),
|
||||
MockCall(*sources.git(), "cat-file", "-e", last_commit_sha, cwd=local, logger=sources.logger),
|
||||
])
|
||||
|
||||
|
||||
def test_fetch_until_first(sources: Sources, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must fetch first commit only
|
||||
"""
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output")
|
||||
local = Path("local")
|
||||
|
||||
assert sources.fetch_until(local, branch="master") == "HEAD"
|
||||
check_output_mock.assert_has_calls([
|
||||
MockCall(*sources.git(), "fetch", "--quiet", "--depth", "1", "origin", "master",
|
||||
cwd=local, logger=sources.logger),
|
||||
MockCall(*sources.git(), "cat-file", "-e", "HEAD", cwd=local, logger=sources.logger),
|
||||
])
|
||||
|
||||
|
||||
def test_fetch_until_all_branches(sources: Sources, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must fetch all branches
|
||||
"""
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output")
|
||||
local = Path("local")
|
||||
|
||||
assert sources.fetch_until(local) == "HEAD"
|
||||
check_output_mock.assert_has_calls([
|
||||
MockCall(*sources.git(), "fetch", "--quiet", "--depth", "1", cwd=local, logger=sources.logger),
|
||||
MockCall(*sources.git(), "cat-file", "-e", "HEAD", cwd=local, logger=sources.logger),
|
||||
])
|
||||
|
||||
|
||||
def test_fetch_until_not_found(sources: Sources, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must return None in case if no commit found at the required maximal depth
|
||||
"""
|
||||
mocker.patch("ahriman.core.build_tools.sources.check_output", side_effect=[
|
||||
"",
|
||||
CalledProcessError(1, ["command"], "error"),
|
||||
"",
|
||||
CalledProcessError(1, ["command"], "error"),
|
||||
])
|
||||
assert sources.fetch_until(Path("local"), branch="master", commit_sha="sha", max_depth=2) is None
|
||||
|
||||
|
||||
def test_git(sources: Sources) -> None:
|
||||
"""
|
||||
must correctly generate git command
|
||||
"""
|
||||
assert sources.git() == ["git", "-c", "init.defaultBranch=\"master\""]
|
||||
|
||||
|
||||
def test_git_overrides(sources: Sources) -> None:
|
||||
"""
|
||||
must correctly generate git command with additional settings
|
||||
"""
|
||||
assert sources.git({"user.email": "ahriman@localhost"}) == [
|
||||
"git", "-c", "init.defaultBranch=\"master\"", "-c", "user.email=\"ahriman@localhost\""
|
||||
]
|
||||
|
||||
|
||||
def test_has_changes(sources: Sources, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must correctly identify if there are changes
|
||||
"""
|
||||
local = Path("local")
|
||||
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output", return_value="M a.txt")
|
||||
assert sources.has_changes(local)
|
||||
check_output_mock.assert_called_once_with(*sources.git(), "diff", "--cached", "--name-only",
|
||||
cwd=local, logger=sources.logger)
|
||||
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output", return_value="")
|
||||
assert not sources.has_changes(local)
|
||||
check_output_mock.assert_called_once_with(*sources.git(), "diff", "--cached", "--name-only",
|
||||
cwd=local, logger=sources.logger)
|
||||
|
||||
|
||||
def test_head(sources: Sources, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must correctly define HEAD hash
|
||||
"""
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output", return_value="sha")
|
||||
local = Path("local")
|
||||
|
||||
assert sources.head(local) == "sha"
|
||||
check_output_mock.assert_called_once_with(*sources.git(), "rev-parse", "HEAD", cwd=local, logger=sources.logger)
|
||||
|
||||
|
||||
def test_head_specific(sources: Sources, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must correctly define ref hash
|
||||
"""
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output", return_value="sha")
|
||||
local = Path("local")
|
||||
|
||||
assert sources.head(local, "master") == "sha"
|
||||
check_output_mock.assert_called_once_with(*sources.git(), "rev-parse", "master", cwd=local, logger=sources.logger)
|
||||
|
||||
|
||||
def test_move(sources: Sources, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must move content between directories
|
||||
"""
|
||||
mocker.patch("ahriman.core.build_tools.sources.walk", return_value=[Path("/source/path")])
|
||||
move_mock = mocker.patch("shutil.move")
|
||||
|
||||
sources.move(Path("/source"), Path("/destination"))
|
||||
move_mock.assert_called_once_with(Path("/source/path"), Path("/destination/path"))
|
||||
|
||||
|
||||
def test_move_same(sources: Sources, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must not do anything in case if directories are the same
|
||||
"""
|
||||
walk_mock = mocker.patch("ahriman.core.build_tools.sources.walk")
|
||||
sources.move(Path("/same"), Path("/same"))
|
||||
walk_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_patch_apply(sources: Sources, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must apply patches if any
|
||||
"""
|
||||
patch = PkgbuildPatch(None, "patch")
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output")
|
||||
|
||||
local = Path("local")
|
||||
sources.patch_apply(local, patch)
|
||||
check_output_mock.assert_called_once_with(
|
||||
*sources.git(), "apply", "--ignore-space-change", "--ignore-whitespace",
|
||||
cwd=local, input_data=patch.value, logger=sources.logger
|
||||
)
|
||||
|
||||
|
||||
def test_patch_apply_function(sources: Sources, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must apply single-function patches
|
||||
"""
|
||||
patch = PkgbuildPatch("version", "42")
|
||||
local = Path("local")
|
||||
write_mock = mocker.patch("ahriman.models.pkgbuild_patch.PkgbuildPatch.write")
|
||||
|
||||
sources.patch_apply(local, patch)
|
||||
write_mock.assert_called_once_with(local / "PKGBUILD")
|
||||
|
||||
|
||||
def test_read(sources: Sources, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must read file from commit
|
||||
"""
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output", return_value="content")
|
||||
assert sources.read(Path("local"), "sha", Path("PKGBUILD")) == "content"
|
||||
check_output_mock.assert_called_once()
|
||||
|
||||
|
||||
def test_read_failed(sources: Sources, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must return None in case if file cannot be read from commit
|
||||
"""
|
||||
mocker.patch("ahriman.core.build_tools.sources.check_output",
|
||||
side_effect=CalledProcessError(1, ["command"], "error"))
|
||||
assert sources.read(Path("local"), "sha", Path("PKGBUILD")) is None
|
||||
@@ -0,0 +1,168 @@
|
||||
import pytest
|
||||
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.core.build_tools.task import Task
|
||||
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||
|
||||
|
||||
def test_package_archives(task_ahriman: Task, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must correctly return list of new files
|
||||
"""
|
||||
mocker.patch("pathlib.Path.iterdir", return_value=[
|
||||
Path(f"{task_ahriman.package.base}-{task_ahriman.package.version}-any.pkg.tar.xz"),
|
||||
Path(f"{task_ahriman.package.base}-debug-{task_ahriman.package.version}-any.pkg.tar.xz"),
|
||||
Path("source.pkg.tar.xz"),
|
||||
Path("randomfile"),
|
||||
Path("namcap.log"),
|
||||
])
|
||||
assert task_ahriman._package_archives(Path("local"), [Path("source.pkg.tar.xz")]) == [
|
||||
Path(f"{task_ahriman.package.base}-{task_ahriman.package.version}-any.pkg.tar.xz"),
|
||||
Path(f"{task_ahriman.package.base}-debug-{task_ahriman.package.version}-any.pkg.tar.xz"),
|
||||
]
|
||||
|
||||
|
||||
def test_package_archives_no_debug(task_ahriman: Task, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must correctly return list of new files without debug packages
|
||||
"""
|
||||
task_ahriman.include_debug_packages = False
|
||||
mocker.patch("pathlib.Path.iterdir", return_value=[
|
||||
Path(f"{task_ahriman.package.base}-{task_ahriman.package.version}-any.pkg.tar.xz"),
|
||||
Path(f"{task_ahriman.package.base}-debug-{task_ahriman.package.version}-any.pkg.tar.xz"),
|
||||
Path("source.pkg.tar.xz"),
|
||||
Path("randomfile"),
|
||||
Path("namcap.log"),
|
||||
])
|
||||
assert task_ahriman._package_archives(Path("local"), [Path("source.pkg.tar.xz")]) == [
|
||||
Path(f"{task_ahriman.package.base}-{task_ahriman.package.version}-any.pkg.tar.xz"),
|
||||
]
|
||||
|
||||
|
||||
def test_build(task_ahriman: Task, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must build package
|
||||
"""
|
||||
local = Path("local")
|
||||
mocker.patch("pathlib.Path.iterdir", return_value=["file"])
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.task.check_output")
|
||||
archives_mock = mocker.patch("ahriman.core.build_tools.task.Task._package_archives",
|
||||
return_value=[task_ahriman.package.base])
|
||||
|
||||
assert task_ahriman.build(local) == [task_ahriman.package.base]
|
||||
check_output_mock.assert_called_once_with(
|
||||
"extra-x86_64-build",
|
||||
"-r", str(task_ahriman.paths.chroot),
|
||||
"--", "-D", str(task_ahriman.paths.archive),
|
||||
"--", "--skippgpcheck",
|
||||
exception=pytest.helpers.anyvar(int),
|
||||
cwd=local,
|
||||
logger=task_ahriman.logger,
|
||||
user=task_ahriman.uid,
|
||||
environment={},
|
||||
)
|
||||
archives_mock.assert_called_once_with(local, ["file"])
|
||||
|
||||
|
||||
def test_build_environment(task_ahriman: Task, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must build package with environment variables set
|
||||
"""
|
||||
local = Path("local")
|
||||
mocker.patch("pathlib.Path.iterdir", return_value=["file"])
|
||||
mocker.patch("ahriman.core.build_tools.task.Task._package_archives", return_value=[task_ahriman.package.base])
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.task.check_output")
|
||||
|
||||
environment = {"variable": "value"}
|
||||
|
||||
task_ahriman.build(local, **environment, empty=None)
|
||||
check_output_mock.assert_called_once_with(
|
||||
"extra-x86_64-build",
|
||||
"-r", str(task_ahriman.paths.chroot),
|
||||
"--", "-D", str(task_ahriman.paths.archive),
|
||||
"--", "--skippgpcheck",
|
||||
exception=pytest.helpers.anyvar(int),
|
||||
cwd=local,
|
||||
logger=task_ahriman.logger,
|
||||
user=task_ahriman.uid,
|
||||
environment=environment,
|
||||
)
|
||||
|
||||
|
||||
def test_build_dry_run(task_ahriman: Task, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run devtools in dry-run mode
|
||||
"""
|
||||
local = Path("local")
|
||||
mocker.patch("pathlib.Path.iterdir", return_value=["file"])
|
||||
mocker.patch("ahriman.core.build_tools.task.Task._package_archives", return_value=[task_ahriman.package.base])
|
||||
check_output_mock = mocker.patch("ahriman.core.build_tools.task.check_output")
|
||||
|
||||
assert task_ahriman.build(local, dry_run=True) == [task_ahriman.package.base]
|
||||
check_output_mock.assert_called_once_with(
|
||||
"extra-x86_64-build",
|
||||
"-r", str(task_ahriman.paths.chroot),
|
||||
"--", "-D", str(task_ahriman.paths.archive),
|
||||
"--", "--skippgpcheck",
|
||||
"--nobuild",
|
||||
exception=pytest.helpers.anyvar(int),
|
||||
cwd=local,
|
||||
logger=task_ahriman.logger,
|
||||
user=task_ahriman.uid,
|
||||
environment={},
|
||||
)
|
||||
|
||||
|
||||
def test_init(task_ahriman: Task, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must copy tree instead of fetch
|
||||
"""
|
||||
patches = [PkgbuildPatch("hash", "patch")]
|
||||
mocker.patch("ahriman.models.package.Package.from_build", return_value=task_ahriman.package)
|
||||
load_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.load", return_value="sha")
|
||||
|
||||
assert task_ahriman.init(Path("ahriman"), patches, None) == "sha"
|
||||
load_mock.assert_called_once_with(Path("ahriman"), task_ahriman.package, patches, task_ahriman.paths)
|
||||
|
||||
|
||||
def test_init_vcs(task_ahriman: Task, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must copy tree instead of fetch
|
||||
"""
|
||||
task_ahriman.package.base += "-git"
|
||||
mocker.patch("ahriman.models.package.Package.from_build", return_value=task_ahriman.package)
|
||||
load_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.load", return_value="sha")
|
||||
build_mock = mocker.patch("ahriman.core.build_tools.task.Task.build")
|
||||
|
||||
local = Path("ahriman")
|
||||
assert task_ahriman.init(local, [], None) == "sha"
|
||||
load_mock.assert_called_once_with(local, task_ahriman.package, [], task_ahriman.paths)
|
||||
build_mock.assert_called_once_with(local, dry_run=True)
|
||||
|
||||
|
||||
def test_init_bump_pkgrel(task_ahriman: Task, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must bump pkgrel if it is same as provided
|
||||
"""
|
||||
mocker.patch("ahriman.models.package.Package.from_build", return_value=task_ahriman.package)
|
||||
mocker.patch("ahriman.core.build_tools.sources.Sources.load", return_value="sha")
|
||||
write_mock = mocker.patch("ahriman.models.pkgbuild_patch.PkgbuildPatch.write")
|
||||
|
||||
local = Path("ahriman")
|
||||
assert task_ahriman.init(local, [], task_ahriman.package.version) == "sha"
|
||||
write_mock.assert_called_once_with(local / "PKGBUILD")
|
||||
|
||||
|
||||
def test_init_bump_pkgrel_skip(task_ahriman: Task, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must keep pkgrel if version is different from provided
|
||||
"""
|
||||
task_ahriman.package.version = "2.0.0-1"
|
||||
mocker.patch("ahriman.models.package.Package.from_build", return_value=task_ahriman.package)
|
||||
mocker.patch("ahriman.core.build_tools.sources.Sources.load", return_value="sha")
|
||||
write_mock = mocker.patch("ahriman.models.pkgbuild_patch.PkgbuildPatch.write")
|
||||
|
||||
assert task_ahriman.init(Path("ahriman"), [], "1.0.0-1") == "sha"
|
||||
write_mock.assert_not_called()
|
||||
@@ -0,0 +1,19 @@
|
||||
import pytest
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.configuration.schema import CONFIGURATION_SCHEMA
|
||||
from ahriman.core.configuration.validator import Validator
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def validator(configuration: Configuration) -> Validator:
|
||||
"""
|
||||
fixture for validator
|
||||
|
||||
Args:
|
||||
configuration(Configuration): configuration fixture
|
||||
|
||||
Returns:
|
||||
Validator: validator test instance
|
||||
"""
|
||||
return Validator(configuration=configuration, schema=CONFIGURATION_SCHEMA)
|
||||
@@ -0,0 +1,547 @@
|
||||
import configparser
|
||||
import pytest
|
||||
import os
|
||||
|
||||
from io import StringIO
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest.mock import call as MockCall
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.exceptions import InitializeError
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
|
||||
|
||||
def test_architecture(configuration: Configuration) -> None:
|
||||
"""
|
||||
must return valid repository architecture
|
||||
"""
|
||||
assert configuration.architecture == "x86_64"
|
||||
|
||||
|
||||
def test_repository_id(configuration: Configuration, repository_id: RepositoryId) -> None:
|
||||
"""
|
||||
must return repository identifier
|
||||
"""
|
||||
assert configuration.repository_id == repository_id
|
||||
assert configuration.get("repository", "name") == repository_id.name
|
||||
assert configuration.get("repository", "architecture") == repository_id.architecture
|
||||
|
||||
|
||||
def test_repository_id_erase(configuration: Configuration) -> None:
|
||||
"""
|
||||
must remove repository identifier properties if empty identifier supplied
|
||||
"""
|
||||
configuration.repository_id = None
|
||||
assert configuration.get("repository", "name", fallback=None) is None
|
||||
assert configuration.get("repository", "architecture", fallback=None) is None
|
||||
|
||||
configuration.repository_id = RepositoryId("", "")
|
||||
assert configuration.get("repository", "name", fallback=None) is None
|
||||
assert configuration.get("repository", "architecture", fallback=None) is None
|
||||
|
||||
|
||||
def test_repository_id_update(configuration: Configuration, repository_id: RepositoryId) -> None:
|
||||
"""
|
||||
must update repository identifier and related configuration options
|
||||
"""
|
||||
repository_id = RepositoryId("i686", repository_id.name)
|
||||
|
||||
configuration.repository_id = repository_id
|
||||
assert configuration.repository_id == repository_id
|
||||
assert configuration.get("repository", "name") == repository_id.name
|
||||
assert configuration.get("repository", "architecture") == repository_id.architecture
|
||||
|
||||
|
||||
def test_repository_name(configuration: Configuration) -> None:
|
||||
"""
|
||||
must return valid repository name
|
||||
"""
|
||||
assert configuration.repository_name == "aur"
|
||||
|
||||
|
||||
def test_repository_paths(configuration: Configuration, repository_paths: RepositoryPaths) -> None:
|
||||
"""
|
||||
must return repository paths
|
||||
"""
|
||||
assert configuration.repository_paths == repository_paths
|
||||
|
||||
|
||||
def test_from_path(repository_id: RepositoryId, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must load configuration
|
||||
"""
|
||||
mocker.patch("pathlib.Path.is_file", return_value=True)
|
||||
mocker.patch("ahriman.core.configuration.Configuration.get", return_value="ahriman.ini.d")
|
||||
read_mock = mocker.patch("ahriman.core.configuration.Configuration.read")
|
||||
load_includes_mock = mocker.patch("ahriman.core.configuration.Configuration.load_includes")
|
||||
merge_mock = mocker.patch("ahriman.core.configuration.Configuration.merge_sections")
|
||||
environment_mock = mocker.patch("ahriman.core.configuration.Configuration.load_environment")
|
||||
path = Path("path")
|
||||
|
||||
configuration = Configuration.from_path(path, repository_id)
|
||||
assert configuration.path == path
|
||||
read_mock.assert_called_once_with(path)
|
||||
load_includes_mock.assert_called_once_with()
|
||||
merge_mock.assert_called_once_with(repository_id)
|
||||
environment_mock.assert_called_once_with()
|
||||
|
||||
|
||||
def test_from_path_file_missing(repository_id: RepositoryId, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must load configuration based on package files
|
||||
"""
|
||||
mocker.patch("pathlib.Path.is_file", return_value=False)
|
||||
mocker.patch("ahriman.core.configuration.Configuration.load_includes")
|
||||
mocker.patch("ahriman.core.configuration.Configuration.get", return_value="ahriman.ini.d")
|
||||
read_mock = mocker.patch("ahriman.core.configuration.Configuration.read")
|
||||
|
||||
configuration = Configuration.from_path(Path("path"), repository_id)
|
||||
read_mock.assert_called_once_with(configuration.SYSTEM_CONFIGURATION_PATH)
|
||||
|
||||
|
||||
def test_section_name(configuration: Configuration) -> None:
|
||||
"""
|
||||
must return architecture specific group
|
||||
"""
|
||||
assert configuration.section_name("build") == "build"
|
||||
assert configuration.section_name("build", None) == "build"
|
||||
assert configuration.section_name("build", "x86_64") == "build:x86_64"
|
||||
assert configuration.section_name("build", "aur", "x86_64") == "build:aur:x86_64"
|
||||
assert configuration.section_name("build", "aur", None) == "build:aur"
|
||||
assert configuration.section_name("build", None, "x86_64") == "build:x86_64"
|
||||
|
||||
|
||||
def test_check_loaded(configuration: Configuration) -> None:
|
||||
"""
|
||||
must return valid path and architecture
|
||||
"""
|
||||
path, repository_id = configuration.check_loaded()
|
||||
assert path == configuration.path
|
||||
assert repository_id == configuration.repository_id
|
||||
|
||||
|
||||
def test_check_loaded_path(configuration: Configuration) -> None:
|
||||
"""
|
||||
must raise exception if path is none
|
||||
"""
|
||||
configuration.path = None
|
||||
with pytest.raises(InitializeError):
|
||||
configuration.check_loaded()
|
||||
|
||||
|
||||
def test_check_loaded_architecture(configuration: Configuration) -> None:
|
||||
"""
|
||||
must raise exception if architecture is none
|
||||
"""
|
||||
configuration.repository_id = None
|
||||
with pytest.raises(InitializeError):
|
||||
configuration.check_loaded()
|
||||
|
||||
|
||||
def test_copy_from(configuration: Configuration) -> None:
|
||||
"""
|
||||
must copy values from another instance
|
||||
"""
|
||||
instance = Configuration()
|
||||
instance.copy_from(configuration)
|
||||
assert instance.dump() == configuration.dump()
|
||||
|
||||
|
||||
def test_dump(configuration: Configuration) -> None:
|
||||
"""
|
||||
dump must not be empty
|
||||
"""
|
||||
assert configuration.dump()
|
||||
|
||||
|
||||
def test_dump_architecture_specific(configuration: Configuration) -> None:
|
||||
"""
|
||||
dump must contain architecture specific settings
|
||||
"""
|
||||
section = configuration.section_name("build", configuration.architecture)
|
||||
configuration.set_option(section, "archbuild_flags", "hello flag")
|
||||
configuration.merge_sections(configuration.repository_id)
|
||||
|
||||
dump = configuration.dump()
|
||||
assert dump
|
||||
assert "build" in dump
|
||||
assert section not in dump
|
||||
assert dump["build"]["archbuild_flags"] == "hello flag"
|
||||
|
||||
|
||||
def test_getintlist(configuration: Configuration) -> None:
|
||||
"""
|
||||
must extract list of integers
|
||||
"""
|
||||
configuration.set_option("build", "test_int_list", "1 42 3")
|
||||
assert configuration.getintlist("build", "test_int_list") == [1, 42, 3]
|
||||
|
||||
|
||||
def test_getlist(configuration: Configuration) -> None:
|
||||
"""
|
||||
must return list of string correctly
|
||||
"""
|
||||
configuration.set_option("build", "test_list", "a b c")
|
||||
assert configuration.getlist("build", "test_list") == ["a", "b", "c"]
|
||||
|
||||
|
||||
def test_getlist_empty(configuration: Configuration) -> None:
|
||||
"""
|
||||
must return list of string correctly for non-existing option
|
||||
"""
|
||||
assert configuration.getlist("build", "test_list", fallback=[]) == []
|
||||
configuration.set_option("build", "test_list", "")
|
||||
assert configuration.getlist("build", "test_list") == []
|
||||
|
||||
|
||||
def test_getlist_single(configuration: Configuration) -> None:
|
||||
"""
|
||||
must return list of strings for single string
|
||||
"""
|
||||
configuration.set_option("build", "test_list", "a")
|
||||
assert configuration.getlist("build", "test_list") == ["a"]
|
||||
assert configuration.getlist("build", "test_list") == ["a"]
|
||||
|
||||
|
||||
def test_getlist_with_spaces(configuration: Configuration) -> None:
|
||||
"""
|
||||
must return list of string if there is string with spaces in quotes
|
||||
"""
|
||||
configuration.set_option("build", "test_list", """"ahriman is" cool""")
|
||||
assert configuration.getlist("build", "test_list") == ["""ahriman is""", """cool"""]
|
||||
configuration.set_option("build", "test_list", """'ahriman is' cool""")
|
||||
assert configuration.getlist("build", "test_list") == ["""ahriman is""", """cool"""]
|
||||
|
||||
|
||||
def test_getlist_with_quotes(configuration: Configuration) -> None:
|
||||
"""
|
||||
must return list of string if there is string with quote inside quote
|
||||
"""
|
||||
configuration.set_option("build", "test_list", """"ahriman is" c"'"ool""")
|
||||
assert configuration.getlist("build", "test_list") == ["""ahriman is""", """c'ool"""]
|
||||
configuration.set_option("build", "test_list", """'ahriman is' c'"'ool""")
|
||||
assert configuration.getlist("build", "test_list") == ["""ahriman is""", """c"ool"""]
|
||||
|
||||
|
||||
def test_getlist_unmatched_quote(configuration: Configuration) -> None:
|
||||
"""
|
||||
must raise exception on unmatched quote in string value
|
||||
"""
|
||||
configuration.set_option("build", "test_list", """ahri"man is cool""")
|
||||
with pytest.raises(ValueError):
|
||||
configuration.getlist("build", "test_list")
|
||||
configuration.set_option("build", "test_list", """ahri'man is cool""")
|
||||
with pytest.raises(ValueError):
|
||||
configuration.getlist("build", "test_list")
|
||||
|
||||
|
||||
def test_getlist_append() -> None:
|
||||
"""
|
||||
must correctly append list values
|
||||
"""
|
||||
configuration = Configuration()
|
||||
configuration._read(
|
||||
StringIO("""
|
||||
[section]
|
||||
list1[] = value1
|
||||
list1[] = value2
|
||||
|
||||
list2[] = value3
|
||||
list2[] =
|
||||
list2[] = value4
|
||||
list2[] = value5
|
||||
|
||||
list3[] = value6
|
||||
list3 = value7
|
||||
list3[] = value8
|
||||
"""), "io")
|
||||
|
||||
assert configuration.getlist("section", "list1") == ["value1", "value2"]
|
||||
assert configuration.getlist("section", "list2") == ["value4", "value5"]
|
||||
assert configuration.getlist("section", "list3") == ["value7", "value8"]
|
||||
|
||||
|
||||
def test_getpath_absolute_to_absolute(configuration: Configuration) -> None:
|
||||
"""
|
||||
must not change path for absolute path in settings
|
||||
"""
|
||||
path = Path("/a/b/c")
|
||||
configuration.set_option("build", "path", str(path))
|
||||
assert configuration.getpath("build", "path") == path
|
||||
|
||||
|
||||
def test_getpath_absolute_to_relative(configuration: Configuration) -> None:
|
||||
"""
|
||||
must prepend root path to relative path
|
||||
"""
|
||||
path = Path("a")
|
||||
configuration.set_option("build", "path", str(path))
|
||||
result = configuration.getpath("build", "path")
|
||||
assert result.is_absolute()
|
||||
assert result.parent == configuration.path.parent
|
||||
assert result.name == path.name
|
||||
|
||||
|
||||
def test_getpath_with_fallback(configuration: Configuration) -> None:
|
||||
"""
|
||||
must return fallback path
|
||||
"""
|
||||
path = Path("a")
|
||||
assert configuration.getpath("some", "option", fallback=path).name == str(path)
|
||||
assert configuration.getpath("some", "option", fallback=None) is None
|
||||
|
||||
|
||||
def test_getpath_without_fallback(configuration: Configuration) -> None:
|
||||
"""
|
||||
must raise exception without fallback
|
||||
"""
|
||||
with pytest.raises(configparser.NoSectionError):
|
||||
assert configuration.getpath("some", "option")
|
||||
with pytest.raises(configparser.NoOptionError):
|
||||
assert configuration.getpath("build", "option")
|
||||
|
||||
|
||||
def test_getpathlist(configuration: Configuration) -> None:
|
||||
"""
|
||||
must extract path list
|
||||
"""
|
||||
path = Path("/a/b/c")
|
||||
configuration.set_option("build", "path", f"""{path} {path.relative_to("/")}""")
|
||||
|
||||
result = configuration.getpathlist("build", "path")
|
||||
assert all(element.is_absolute() for element in result)
|
||||
assert path in result
|
||||
assert all(element.is_relative_to("/") for element in result)
|
||||
|
||||
|
||||
def test_gettype(configuration: Configuration) -> None:
|
||||
"""
|
||||
must extract type from variable
|
||||
"""
|
||||
section, provider = configuration.gettype("customs3", configuration.repository_id)
|
||||
assert section == "customs3"
|
||||
assert provider == "s3"
|
||||
|
||||
|
||||
def test_gettype_with_fallback(configuration: Configuration) -> None:
|
||||
"""
|
||||
must return same provider name as in fallback
|
||||
"""
|
||||
section, provider = configuration.gettype("rsync", configuration.repository_id, fallback="abracadabra")
|
||||
assert section == "rsync"
|
||||
assert provider == "abracadabra"
|
||||
|
||||
|
||||
def test_gettype_from_section(configuration: Configuration) -> None:
|
||||
"""
|
||||
must extract type from section name
|
||||
"""
|
||||
section, provider = configuration.gettype("rsync", configuration.repository_id)
|
||||
assert section == "rsync"
|
||||
assert provider == "rsync"
|
||||
|
||||
|
||||
def test_gettype_from_section_with_architecture(configuration: Configuration) -> None:
|
||||
"""
|
||||
must extract type from section name with architecture
|
||||
"""
|
||||
section, provider = configuration.gettype("github", configuration.repository_id)
|
||||
assert section == "github:x86_64"
|
||||
assert provider == "github"
|
||||
|
||||
|
||||
def test_gettype_from_section_no_section(configuration: Configuration) -> None:
|
||||
"""
|
||||
must raise NoSectionError during type extraction from section name with architecture
|
||||
"""
|
||||
# technically rsync:x86_64 is valid section
|
||||
# but in current configuration it must be considered as missing section
|
||||
with pytest.raises(configparser.NoSectionError):
|
||||
configuration.gettype("rsync:x86_64", configuration.repository_id)
|
||||
|
||||
|
||||
def test_load_environment(configuration: Configuration) -> None:
|
||||
"""
|
||||
must load environment variables
|
||||
"""
|
||||
os.environ["section:key"] = "value1"
|
||||
os.environ["section:identifier:key"] = "value2"
|
||||
|
||||
configuration.load_environment()
|
||||
assert configuration.get("section", "key") == "value1"
|
||||
assert configuration.get("section:identifier", "key") == "value2"
|
||||
|
||||
|
||||
def test_load_includes(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must load includes
|
||||
"""
|
||||
mocker.patch.object(Configuration, "logging_path", Path("logging"))
|
||||
read_mock = mocker.patch("ahriman.core.configuration.Configuration.read")
|
||||
glob_mock = mocker.patch("pathlib.Path.glob", autospec=True, return_value=[Path("include"), Path("logging")])
|
||||
configuration = Configuration()
|
||||
|
||||
configuration.load_includes(Path("path"))
|
||||
glob_mock.assert_called_once_with(Path("path"), "*.ini")
|
||||
read_mock.assert_called_once_with(Path("include"))
|
||||
assert configuration.includes == [Path("include")]
|
||||
|
||||
|
||||
def test_load_includes_missing() -> None:
|
||||
"""
|
||||
must not fail if not include directory found
|
||||
"""
|
||||
configuration = Configuration()
|
||||
configuration.set_option("settings", "include", "path")
|
||||
configuration.load_includes()
|
||||
|
||||
|
||||
def test_load_includes_no_option() -> None:
|
||||
"""
|
||||
must not fail if no option set
|
||||
"""
|
||||
configuration = Configuration()
|
||||
configuration.set_option("settings", "key", "value")
|
||||
configuration.load_includes()
|
||||
|
||||
|
||||
def test_load_includes_no_section() -> None:
|
||||
"""
|
||||
must not fail if no section set
|
||||
"""
|
||||
configuration = Configuration()
|
||||
configuration.load_includes()
|
||||
|
||||
|
||||
def test_load_includes_default_path(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must load includes from default path
|
||||
"""
|
||||
mocker.patch.object(Configuration, "include", Path("path"))
|
||||
glob_mock = mocker.patch("pathlib.Path.glob", autospec=True, return_value=[])
|
||||
|
||||
Configuration().load_includes()
|
||||
glob_mock.assert_called_once_with(Path("path"), "*.ini")
|
||||
|
||||
|
||||
def test_merge_sections_missing(configuration: Configuration) -> None:
|
||||
"""
|
||||
must merge create section if not exists
|
||||
"""
|
||||
section = configuration.section_name("build", configuration.architecture)
|
||||
configuration.remove_section("build")
|
||||
configuration.set_option(section, "key", "value")
|
||||
|
||||
configuration.merge_sections(configuration.repository_id)
|
||||
assert configuration.get("build", "key") == "value"
|
||||
|
||||
|
||||
def test_merge_sections_priority(configuration: Configuration) -> None:
|
||||
"""
|
||||
must merge sections in valid order
|
||||
"""
|
||||
empty = "build"
|
||||
arch = configuration.section_name(empty, configuration.architecture)
|
||||
repo = configuration.section_name(empty, configuration.repository_name)
|
||||
repo_arch = configuration.section_name(empty, configuration.repository_name, configuration.architecture)
|
||||
|
||||
configuration.set_option(empty, "key1", "key1_value1")
|
||||
configuration.set_option(arch, "key1", "key1_value2")
|
||||
configuration.set_option(repo, "key1", "key1_value3")
|
||||
configuration.set_option(repo_arch, "key1", "key1_value4")
|
||||
|
||||
configuration.set_option(empty, "key2", "key2_value1")
|
||||
configuration.set_option(arch, "key2", "key2_value2")
|
||||
configuration.set_option(repo, "key2", "key2_value3")
|
||||
|
||||
configuration.set_option(empty, "key3", "key3_value1")
|
||||
configuration.set_option(arch, "key3", "key3_value2")
|
||||
|
||||
configuration.set_option(empty, "key4", "key4_value1")
|
||||
|
||||
configuration.merge_sections(configuration.repository_id)
|
||||
assert configuration.get("build", "key1") == "key1_value4"
|
||||
assert configuration.get("build", "key2") == "key2_value3"
|
||||
assert configuration.get("build", "key3") == "key3_value2"
|
||||
assert configuration.get("build", "key4") == "key4_value1"
|
||||
|
||||
|
||||
def test_override_sections(configuration: Configuration, repository_id: RepositoryId) -> None:
|
||||
"""
|
||||
must correctly generate override section names
|
||||
"""
|
||||
assert configuration.override_sections("build", repository_id) == [
|
||||
"build:x86_64",
|
||||
"build:aur",
|
||||
"build:aur:x86_64",
|
||||
]
|
||||
|
||||
|
||||
def test_override_sections_empty(configuration: Configuration) -> None:
|
||||
"""
|
||||
must look up for sections if repository identifier is empty
|
||||
"""
|
||||
configuration.set_option("web:x86_64", "port", "8080")
|
||||
configuration.set_option("web:i686", "port", "8080")
|
||||
assert configuration.override_sections("web", RepositoryId("", "")) == ["web:i686", "web:x86_64"]
|
||||
|
||||
|
||||
def test_reload(configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must reload configuration
|
||||
"""
|
||||
load_mock = mocker.patch("ahriman.core.configuration.Configuration.load")
|
||||
merge_mock = mocker.patch("ahriman.core.configuration.Configuration.merge_sections")
|
||||
environment_mock = mocker.patch("ahriman.core.configuration.Configuration.load_environment")
|
||||
|
||||
configuration.reload()
|
||||
load_mock.assert_called_once_with(configuration.path)
|
||||
merge_mock.assert_called_once_with(configuration.repository_id)
|
||||
environment_mock.assert_called_once_with()
|
||||
|
||||
|
||||
def test_reload_clear(configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must clear current settings before configuration reload
|
||||
"""
|
||||
clear_mock = mocker.patch("ahriman.core.configuration.Configuration.remove_section")
|
||||
sections = configuration.sections()
|
||||
|
||||
configuration.reload()
|
||||
clear_mock.assert_has_calls([MockCall(section) for section in sections])
|
||||
|
||||
|
||||
def test_reload_no_architecture(configuration: Configuration) -> None:
|
||||
"""
|
||||
must raise exception on reload if no architecture set
|
||||
"""
|
||||
configuration.repository_id = None
|
||||
with pytest.raises(InitializeError):
|
||||
configuration.reload()
|
||||
|
||||
|
||||
def test_reload_no_path(configuration: Configuration) -> None:
|
||||
"""
|
||||
must raise exception on reload if no path set
|
||||
"""
|
||||
configuration.path = None
|
||||
with pytest.raises(InitializeError):
|
||||
configuration.reload()
|
||||
|
||||
|
||||
def test_set_option(configuration: Configuration) -> None:
|
||||
"""
|
||||
must set option correctly
|
||||
"""
|
||||
configuration.set_option("settings", "option", "value")
|
||||
assert configuration.get("settings", "option") == "value"
|
||||
|
||||
|
||||
def test_set_option_new_section(configuration: Configuration) -> None:
|
||||
"""
|
||||
must set option correctly even if no section found
|
||||
"""
|
||||
configuration.set_option("section", "option", "value")
|
||||
assert configuration.get("section", "option") == "value"
|
||||
@@ -0,0 +1,54 @@
|
||||
import pytest
|
||||
|
||||
from ahriman.core.configuration.configuration_multi_dict import ConfigurationMultiDict
|
||||
from ahriman.core.exceptions import OptionError
|
||||
|
||||
|
||||
def test_setitem_non_list() -> None:
|
||||
"""
|
||||
must insert not list correctly
|
||||
"""
|
||||
instance = ConfigurationMultiDict()
|
||||
instance["key"] = "value"
|
||||
assert instance["key"] == "value"
|
||||
|
||||
|
||||
def test_setitem_remove() -> None:
|
||||
"""
|
||||
must remove key
|
||||
"""
|
||||
instance = ConfigurationMultiDict()
|
||||
instance["key"] = "value"
|
||||
instance["key"] = [""]
|
||||
|
||||
assert "key" not in instance
|
||||
|
||||
|
||||
def test_setitem_array() -> None:
|
||||
"""
|
||||
must set array correctly
|
||||
"""
|
||||
instance = ConfigurationMultiDict()
|
||||
instance["key[]"] = ["value1"]
|
||||
instance["key[]"] = ["value2"]
|
||||
|
||||
assert instance["key"] == ["value1 value2"]
|
||||
|
||||
|
||||
def test_setitem_array_exception() -> None:
|
||||
"""
|
||||
must raise exception if the current value is not a single value array
|
||||
"""
|
||||
instance = ConfigurationMultiDict()
|
||||
instance["key[]"] = ["value1", "value2"]
|
||||
with pytest.raises(OptionError):
|
||||
instance["key[]"] = ["value3"]
|
||||
|
||||
|
||||
def test_setitem_exception() -> None:
|
||||
"""
|
||||
must raise exception on invalid key
|
||||
"""
|
||||
instance = ConfigurationMultiDict()
|
||||
with pytest.raises(OptionError):
|
||||
instance["prefix[]suffix"] = "value"
|
||||
@@ -0,0 +1,100 @@
|
||||
import os
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.configuration.shell_interpolator import ShellInterpolator
|
||||
|
||||
|
||||
def _parser() -> dict[str, dict[str, str]]:
|
||||
"""
|
||||
parser mock
|
||||
|
||||
Returns:
|
||||
dict[str, dict[str, str]]: options to be used as configparser mock
|
||||
"""
|
||||
return {
|
||||
"section1": {
|
||||
"home": "$HOME",
|
||||
"key1": "value1",
|
||||
"key4": "${home}",
|
||||
},
|
||||
"section2": {
|
||||
"key2": "value2",
|
||||
},
|
||||
"section3": {
|
||||
"key3": "${section1:home}",
|
||||
"key5": "${section1:key4}",
|
||||
},
|
||||
"section4:suffix": {
|
||||
"key6": "value6"
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def test_extract_variables() -> None:
|
||||
"""
|
||||
must extract variables list
|
||||
"""
|
||||
parser = _parser()
|
||||
|
||||
assert dict(ShellInterpolator._extract_variables(parser, "${key1}", parser["section1"])) == {
|
||||
"key1": "value1",
|
||||
}
|
||||
assert not dict(ShellInterpolator._extract_variables(parser, "${key2}", parser["section1"]))
|
||||
|
||||
assert dict(ShellInterpolator._extract_variables(parser, "${section2:key2}", parser["section1"])) == {
|
||||
"section2:key2": "value2",
|
||||
}
|
||||
assert not dict(ShellInterpolator._extract_variables(parser, "${section2:key1}", parser["section1"]))
|
||||
|
||||
assert not dict(ShellInterpolator._extract_variables(parser, "${section4:key1}", parser["section1"]))
|
||||
|
||||
assert dict(ShellInterpolator._extract_variables(parser, "${section4:suffix:key6}", parser["section1"])) == {
|
||||
"section4:suffix:key6": "value6",
|
||||
}
|
||||
|
||||
|
||||
def test_environment() -> None:
|
||||
"""
|
||||
must extend environment variables
|
||||
"""
|
||||
assert "HOME" in ShellInterpolator.environment()
|
||||
assert "prefix" in ShellInterpolator.environment()
|
||||
|
||||
|
||||
def test_before_get() -> None:
|
||||
"""
|
||||
must correctly extract environment variables
|
||||
"""
|
||||
interpolator = ShellInterpolator()
|
||||
assert interpolator.before_get({}, "", "", "value", {}) == "value"
|
||||
assert interpolator.before_get({}, "", "", "$value", {}) == "$value"
|
||||
assert interpolator.before_get({}, "", "", "$HOME", {}) == os.environ["HOME"]
|
||||
|
||||
|
||||
def test_before_get_escaped() -> None:
|
||||
"""
|
||||
must correctly read escaped variables
|
||||
"""
|
||||
interpolator = ShellInterpolator()
|
||||
assert interpolator.before_get({}, "", "", "$$HOME", {}) == "$HOME"
|
||||
|
||||
|
||||
def test_before_get_reference() -> None:
|
||||
"""
|
||||
must correctly extract environment variables after resolving cross-reference
|
||||
"""
|
||||
interpolator = ShellInterpolator()
|
||||
assert interpolator.before_get(_parser(), "", "", "${section1:home}", {}) == os.environ["HOME"]
|
||||
|
||||
|
||||
def test_before_get_reference_recursive(configuration: Configuration) -> None:
|
||||
"""
|
||||
must correctly extract environment variables after resolving cross-reference recursively
|
||||
"""
|
||||
interpolator = ShellInterpolator()
|
||||
for section, items in _parser().items():
|
||||
for option, value in items.items():
|
||||
configuration.set_option(section, option, value)
|
||||
|
||||
assert interpolator.before_get(configuration, "", "", "${section1:home}", {}) == os.environ["HOME"]
|
||||
assert interpolator.before_get(configuration, "", "", "${section3:key5}", {}) == os.environ["HOME"]
|
||||
@@ -0,0 +1,81 @@
|
||||
from ahriman.core.configuration.shell_template import ShellTemplate
|
||||
|
||||
|
||||
def test_shell_template_braceidpattern() -> None:
|
||||
"""
|
||||
must match colons in braces
|
||||
"""
|
||||
assert ShellTemplate("$k:value").get_identifiers() == ["k"]
|
||||
assert ShellTemplate("${k:value}").get_identifiers() == ["k:value"]
|
||||
|
||||
|
||||
def test_remove_back() -> None:
|
||||
"""
|
||||
must remove substring from the back
|
||||
"""
|
||||
assert ShellTemplate("${k%removeme}").shell_substitute({"k": "please removeme"}) == "please "
|
||||
assert ShellTemplate("${k%removeme*}").shell_substitute({"k": "please removeme removeme"}) == "please removeme "
|
||||
assert ShellTemplate("${k%removem?}").shell_substitute({"k": "please removeme removeme"}) == "please removeme "
|
||||
|
||||
assert ShellTemplate("${k%%removeme}").shell_substitute({"k": "please removeme removeme"}) == "please removeme "
|
||||
assert ShellTemplate("${k%%removeme*}").shell_substitute({"k": "please removeme removeme"}) == "please "
|
||||
assert ShellTemplate("${k%%removem?}").shell_substitute({"k": "please removeme removeme"}) == "please removeme "
|
||||
|
||||
assert ShellTemplate("${k%removeme}").shell_substitute({}) == "${k%removeme}"
|
||||
assert ShellTemplate("${k%%removeme}").shell_substitute({}) == "${k%%removeme}"
|
||||
|
||||
assert ShellTemplate("${k%r3m0v3m3}").shell_substitute({"k": "please removeme"}) == "please removeme"
|
||||
assert ShellTemplate("${k%%r3m0v3m3}").shell_substitute({"k": "please removeme"}) == "please removeme"
|
||||
|
||||
|
||||
def test_remove_front() -> None:
|
||||
"""
|
||||
must remove substring from the front
|
||||
"""
|
||||
assert ShellTemplate("${k#removeme}").shell_substitute({"k": "removeme please"}) == " please"
|
||||
assert ShellTemplate("${k#*removeme}").shell_substitute({"k": "removeme removeme please"}) == " removeme please"
|
||||
assert ShellTemplate("${k#removem?}").shell_substitute({"k": "removeme removeme please"}) == " removeme please"
|
||||
|
||||
assert ShellTemplate("${k##removeme}").shell_substitute({"k": "removeme removeme please"}) == " removeme please"
|
||||
assert ShellTemplate("${k##*removeme}").shell_substitute({"k": "removeme removeme please"}) == " please"
|
||||
assert ShellTemplate("${k##removem?}").shell_substitute({"k": "removeme removeme please"}) == " removeme please"
|
||||
|
||||
assert ShellTemplate("${k#removeme}").shell_substitute({}) == "${k#removeme}"
|
||||
assert ShellTemplate("${k##removeme}").shell_substitute({}) == "${k##removeme}"
|
||||
|
||||
assert ShellTemplate("${k#r3m0v3m3}").shell_substitute({"k": "removeme please"}) == "removeme please"
|
||||
assert ShellTemplate("${k##r3m0v3m3}").shell_substitute({"k": "removeme please"}) == "removeme please"
|
||||
|
||||
|
||||
def test_replace() -> None:
|
||||
"""
|
||||
must perform regular replacement
|
||||
"""
|
||||
assert ShellTemplate("${k/in/out}").shell_substitute({"k": "in replace in"}) == "out replace in"
|
||||
assert ShellTemplate("${k/in*/out}").shell_substitute({"k": "in replace in"}) == "out"
|
||||
assert ShellTemplate("${k/*in/out}").shell_substitute({"k": "in replace in replace"}) == "out replace"
|
||||
assert ShellTemplate("${k/i?/out}").shell_substitute({"k": "in replace in"}) == "out replace in"
|
||||
|
||||
assert ShellTemplate("${k//in/out}").shell_substitute({"k": "in replace in"}) == "out replace out"
|
||||
assert ShellTemplate("${k//in*/out}").shell_substitute({"k": "in replace in"}) == "out"
|
||||
assert ShellTemplate("${k//*in/out}").shell_substitute({"k": "in replace in replace"}) == "out replace"
|
||||
assert ShellTemplate("${k//i?/out}").shell_substitute({"k": "in replace in replace"}) == "out replace out replace"
|
||||
|
||||
assert ShellTemplate("${k/in/out}").shell_substitute({}) == "${k/in/out}"
|
||||
assert ShellTemplate("${k//in/out}").shell_substitute({}) == "${k//in/out}"
|
||||
|
||||
|
||||
def test_replace_back() -> None:
|
||||
"""
|
||||
must replace substring from the back
|
||||
"""
|
||||
assert ShellTemplate("${k/%in/out}").shell_substitute({"k": "in replace in"}) == "in replace out"
|
||||
assert ShellTemplate("${k/%in/out}").shell_substitute({"k": "in replace in "}) == "in replace in "
|
||||
|
||||
|
||||
def test_replace_front() -> None:
|
||||
"""
|
||||
must replace substring from the front
|
||||
"""
|
||||
assert ShellTemplate("${k/#in/out}").shell_substitute({"k": "in replace in"}) == "out replace in"
|
||||
assert ShellTemplate("${k/#in/out}").shell_substitute({"k": " in replace in"}) == " in replace in"
|
||||
@@ -0,0 +1,152 @@
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest.mock import MagicMock, call as MockCall
|
||||
|
||||
from ahriman.core.configuration.validator import Validator
|
||||
|
||||
|
||||
def test_types_mapping() -> None:
|
||||
"""
|
||||
must set custom types
|
||||
"""
|
||||
assert "path" in Validator.types_mapping
|
||||
assert Path in Validator.types_mapping["path"].included_types
|
||||
|
||||
|
||||
def test_normalize_coerce_absolute_path(validator: Validator) -> None:
|
||||
"""
|
||||
must convert string value to path by using configuration converters
|
||||
"""
|
||||
convert_mock = MagicMock()
|
||||
validator.configuration.converters["path"] = convert_mock
|
||||
|
||||
validator._normalize_coerce_absolute_path("value")
|
||||
convert_mock.assert_called_once_with("value")
|
||||
|
||||
|
||||
def test_normalize_coerce_boolean(validator: Validator, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must convert string value to boolean by using configuration converters
|
||||
"""
|
||||
convert_mock = mocker.patch("ahriman.core.configuration.Configuration._convert_to_boolean")
|
||||
validator._normalize_coerce_boolean("1")
|
||||
convert_mock.assert_called_once_with("1")
|
||||
|
||||
|
||||
def test_normalize_coerce_float(validator: Validator) -> None:
|
||||
"""
|
||||
must convert string value to float by using configuration converters
|
||||
"""
|
||||
assert validator._normalize_coerce_float("1.5") == 1.5
|
||||
assert validator._normalize_coerce_float("0.0") == 0.0
|
||||
|
||||
|
||||
def test_normalize_coerce_integer(validator: Validator) -> None:
|
||||
"""
|
||||
must convert string value to integer by using configuration converters
|
||||
"""
|
||||
assert validator._normalize_coerce_integer("1") == 1
|
||||
assert validator._normalize_coerce_integer("42") == 42
|
||||
|
||||
|
||||
def test_normalize_coerce_list(validator: Validator) -> None:
|
||||
"""
|
||||
must convert string value to list by using configuration converters
|
||||
"""
|
||||
convert_mock = MagicMock()
|
||||
validator.configuration.converters["list"] = convert_mock
|
||||
|
||||
validator._normalize_coerce_list("value")
|
||||
convert_mock.assert_called_once_with("value")
|
||||
|
||||
|
||||
def test_validate_is_ip_address(validator: Validator, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must validate addresses correctly
|
||||
"""
|
||||
error_mock = mocker.patch("ahriman.core.configuration.validator.Validator._error")
|
||||
|
||||
validator._validate_is_ip_address(["localhost"], "field", "localhost")
|
||||
validator._validate_is_ip_address([], "field", "localhost")
|
||||
|
||||
validator._validate_is_ip_address([], "field", "127.0.0.1")
|
||||
validator._validate_is_ip_address([], "field", "::") # nosec
|
||||
validator._validate_is_ip_address([], "field", "0.0.0.0") # nosec
|
||||
|
||||
validator._validate_is_ip_address([], "field", "random string")
|
||||
|
||||
error_mock.assert_has_calls([
|
||||
MockCall("field", "Value localhost must be valid IP address"),
|
||||
MockCall("field", "Value random string must be valid IP address"),
|
||||
])
|
||||
|
||||
|
||||
def test_validate_is_url(validator: Validator, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must validate url correctly
|
||||
"""
|
||||
error_mock = mocker.patch("ahriman.core.configuration.validator.Validator._error")
|
||||
|
||||
validator._validate_is_url([], "field", "http://example.com")
|
||||
validator._validate_is_url([], "field", "https://example.com")
|
||||
validator._validate_is_url([], "field", "file:///tmp")
|
||||
|
||||
validator._validate_is_url(["http", "https"], "field", "file:///tmp")
|
||||
|
||||
validator._validate_is_url([], "field", "http:///path")
|
||||
|
||||
validator._validate_is_url([], "field", "random string")
|
||||
|
||||
error_mock.assert_has_calls([
|
||||
MockCall("field", "Url file:///tmp scheme must be one of ['http', 'https']"),
|
||||
MockCall("field", "Location must be set for url http:///path of scheme http"),
|
||||
MockCall("field", "Url scheme is not set for random string"),
|
||||
])
|
||||
|
||||
|
||||
def test_validate_path_exists(validator: Validator, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must validate that paths exists
|
||||
"""
|
||||
error_mock = mocker.patch("ahriman.core.configuration.validator.Validator._error")
|
||||
|
||||
mocker.patch("pathlib.Path.exists", return_value=False)
|
||||
validator._validate_path_exists(False, "field", Path("1"))
|
||||
|
||||
mocker.patch("pathlib.Path.exists", return_value=True)
|
||||
validator._validate_path_exists(False, "field", Path("2"))
|
||||
|
||||
mocker.patch("pathlib.Path.exists", return_value=False)
|
||||
validator._validate_path_exists(True, "field", Path("3"))
|
||||
|
||||
mocker.patch("pathlib.Path.exists", return_value=True)
|
||||
validator._validate_path_exists(True, "field", Path("4"))
|
||||
|
||||
error_mock.assert_has_calls([
|
||||
MockCall("field", "Path 2 must not exist"),
|
||||
MockCall("field", "Path 3 must exist"),
|
||||
])
|
||||
|
||||
|
||||
def test_validate_path_type(validator: Validator, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must correctly validate path type
|
||||
"""
|
||||
error_mock = mocker.patch("ahriman.core.configuration.validator.Validator._error")
|
||||
|
||||
mocker.patch("pathlib.Path.is_file", return_value=True)
|
||||
validator._validate_path_type("file", "field", Path("1"))
|
||||
|
||||
mocker.patch("pathlib.Path.is_file", return_value=False)
|
||||
validator._validate_path_type("file", "field", Path("2"))
|
||||
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||
validator._validate_path_type("dir", "field", Path("3"))
|
||||
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||
validator._validate_path_type("dir", "field", Path("4"))
|
||||
|
||||
error_mock.assert_has_calls([
|
||||
MockCall("field", "Path 2 must be type of file"),
|
||||
MockCall("field", "Path 4 must be type of dir"),
|
||||
])
|
||||
@@ -0,0 +1,94 @@
|
||||
import logging
|
||||
import pytest
|
||||
|
||||
from ahriman.core.alpm.repo import Repo
|
||||
from ahriman.core.build_tools.task import Task
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.sign.gpg import GPG
|
||||
from ahriman.core.tree import Leaf
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def leaf_ahriman(package_ahriman: Package) -> Leaf:
|
||||
"""
|
||||
fixture for tree leaf with package
|
||||
|
||||
Args:
|
||||
package_ahriman(Package): package fixture
|
||||
|
||||
Returns:
|
||||
Leaf: tree leaf test instance
|
||||
"""
|
||||
return Leaf(package_ahriman)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def leaf_python_schedule(package_python_schedule: Package) -> Leaf:
|
||||
"""
|
||||
fixture for tree leaf with package
|
||||
|
||||
Args:
|
||||
package_python_schedule(Package): package fixture
|
||||
|
||||
Returns:
|
||||
Leaf: tree leaf test instance
|
||||
"""
|
||||
return Leaf(package_python_schedule)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def log_record() -> logging.LogRecord:
|
||||
"""
|
||||
fixture for log record object
|
||||
|
||||
Returns:
|
||||
logging.LogRecord: log record test instance
|
||||
"""
|
||||
return logging.LogRecord("record", logging.INFO, "path", 42, "log message", args=(), exc_info=None)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def repo(configuration: Configuration, repository_paths: RepositoryPaths) -> Repo:
|
||||
"""
|
||||
fixture for repository wrapper
|
||||
|
||||
Args:
|
||||
configuration(Configuration): configuration fixture
|
||||
repository_paths(RepositoryPaths): repository paths fixture
|
||||
|
||||
Returns:
|
||||
Repo: repository wrapper test instance
|
||||
"""
|
||||
return Repo(configuration.get("repository", "name"), repository_paths, [])
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def gpg(configuration: Configuration) -> GPG:
|
||||
"""
|
||||
fixture for empty GPG
|
||||
|
||||
Args:
|
||||
configuration(Configuration): configuration fixture
|
||||
|
||||
Returns:
|
||||
GPG: GPG test instance
|
||||
"""
|
||||
return GPG(configuration)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def task_ahriman(package_ahriman: Package, configuration: Configuration, repository_paths: RepositoryPaths) -> Task:
|
||||
"""
|
||||
fixture for built task
|
||||
|
||||
Args:
|
||||
package_ahriman(Package): package fixture
|
||||
configuration(Configuration): configuration fixture
|
||||
repository_paths(RepositoryPaths): repository paths fixture
|
||||
|
||||
Returns:
|
||||
Task: built task test instance
|
||||
"""
|
||||
return Task(package_ahriman, configuration, "x86_64", repository_paths)
|
||||
@@ -0,0 +1,15 @@
|
||||
import pytest
|
||||
|
||||
from sqlite3 import Connection
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def connection() -> Connection:
|
||||
"""
|
||||
mock object for sqlite3 connection
|
||||
|
||||
Returns:
|
||||
Connection: sqlite3 connection test instance
|
||||
"""
|
||||
return MagicMock()
|
||||
@@ -0,0 +1,21 @@
|
||||
import pytest
|
||||
|
||||
from sqlite3 import Connection
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database.migrations import Migrations
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def migrations(connection: Connection, configuration: Configuration) -> Migrations:
|
||||
"""
|
||||
fixture for migrations object
|
||||
|
||||
Args:
|
||||
connection(Connection): sqlite connection fixture
|
||||
configuration(Configuration): configuration fixture
|
||||
|
||||
Returns:
|
||||
Migrations: migrations test instance
|
||||
"""
|
||||
return Migrations(connection, configuration)
|
||||
@@ -0,0 +1,120 @@
|
||||
import pytest
|
||||
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
from sqlite3 import Connection
|
||||
from unittest.mock import call as MockCall
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database.migrations.m000_initial import migrate_data, migrate_package_statuses, migrate_patches, \
|
||||
migrate_users_data, steps
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
|
||||
|
||||
def test_migration_initial() -> None:
|
||||
"""
|
||||
migration must not be empty
|
||||
"""
|
||||
assert steps
|
||||
|
||||
|
||||
def test_migrate_data(connection: Connection, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must perform data migration
|
||||
"""
|
||||
packages = mocker.patch("ahriman.core.database.migrations.m000_initial.migrate_package_statuses")
|
||||
patches = mocker.patch("ahriman.core.database.migrations.m000_initial.migrate_patches")
|
||||
users = mocker.patch("ahriman.core.database.migrations.m000_initial.migrate_users_data")
|
||||
|
||||
migrate_data(connection, configuration)
|
||||
packages.assert_called_once_with(connection, configuration.repository_paths)
|
||||
patches.assert_called_once_with(connection, configuration.repository_paths)
|
||||
users.assert_called_once_with(connection, configuration)
|
||||
|
||||
|
||||
def test_migrate_package_statuses(connection: Connection, package_ahriman: Package, repository_paths: RepositoryPaths,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must migrate packages to database
|
||||
"""
|
||||
response = {"packages": [pytest.helpers.get_package_status_extended(package_ahriman)]}
|
||||
|
||||
mocker.patch("pathlib.Path.is_file", return_value=True)
|
||||
mocker.patch("pathlib.Path.open")
|
||||
mocker.patch("json.load", return_value=response)
|
||||
|
||||
migrate_package_statuses(connection, repository_paths)
|
||||
connection.execute.assert_has_calls([
|
||||
MockCall(pytest.helpers.anyvar(str, strict=True), pytest.helpers.anyvar(int)),
|
||||
MockCall(pytest.helpers.anyvar(str, strict=True), pytest.helpers.anyvar(int)),
|
||||
])
|
||||
connection.executemany.assert_has_calls([
|
||||
MockCall(pytest.helpers.anyvar(str, strict=True), pytest.helpers.anyvar(int)),
|
||||
])
|
||||
|
||||
|
||||
def test_migrate_package_statuses_skip(connection: Connection, repository_paths: RepositoryPaths,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip packages migration if no cache file found
|
||||
"""
|
||||
mocker.patch("pathlib.Path.is_file", return_value=False)
|
||||
migrate_package_statuses(connection, repository_paths)
|
||||
|
||||
|
||||
def test_migrate_patches(connection: Connection, repository_paths: RepositoryPaths,
|
||||
package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must perform migration for patches
|
||||
"""
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||
mocker.patch("pathlib.Path.is_file", return_value=True)
|
||||
iterdir_mock = mocker.patch("pathlib.Path.iterdir", return_value=[Path(package_ahriman.base)])
|
||||
read_mock = mocker.patch("pathlib.Path.read_text", return_value="patch")
|
||||
|
||||
migrate_patches(connection, repository_paths)
|
||||
iterdir_mock.assert_called_once_with()
|
||||
read_mock.assert_called_once_with(encoding="utf8")
|
||||
connection.execute.assert_called_once_with(pytest.helpers.anyvar(str, strict=True), pytest.helpers.anyvar(int))
|
||||
|
||||
|
||||
def test_migrate_patches_skip(connection: Connection, repository_paths: RepositoryPaths,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip patches migration in case if no root found
|
||||
"""
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||
iterdir_mock = mocker.patch("pathlib.Path.iterdir")
|
||||
|
||||
migrate_patches(connection, repository_paths)
|
||||
iterdir_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_migrate_patches_no_patch(connection: Connection, repository_paths: RepositoryPaths,
|
||||
package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip package if no match found
|
||||
"""
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||
mocker.patch("pathlib.Path.is_file", return_value=False)
|
||||
iterdir_mock = mocker.patch("pathlib.Path.iterdir", return_value=[Path(package_ahriman.base)])
|
||||
read_mock = mocker.patch("pathlib.Path.read_text")
|
||||
|
||||
migrate_patches(connection, repository_paths)
|
||||
iterdir_mock.assert_called_once_with()
|
||||
read_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_migrate_users_data(connection: Connection, configuration: Configuration) -> None:
|
||||
"""
|
||||
must put users to database
|
||||
"""
|
||||
configuration.set_option("auth:read", "user1", "password1")
|
||||
configuration.set_option("auth:write", "user2", "password2")
|
||||
|
||||
migrate_users_data(connection, configuration)
|
||||
connection.execute.assert_has_calls([
|
||||
MockCall(pytest.helpers.anyvar(str, strict=True), pytest.helpers.anyvar(int)),
|
||||
MockCall(pytest.helpers.anyvar(str, strict=True), pytest.helpers.anyvar(int)),
|
||||
])
|
||||
@@ -0,0 +1,82 @@
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
from sqlite3 import Connection
|
||||
from unittest.mock import call as MockCall
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database.migrations.m001_package_source import migrate_data, migrate_package_remotes, steps
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.package_source import PackageSource
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
|
||||
|
||||
def test_migration_package_source() -> None:
|
||||
"""
|
||||
migration must not be empty
|
||||
"""
|
||||
assert steps
|
||||
|
||||
|
||||
def test_migrate_data(connection: Connection, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must perform data migration
|
||||
"""
|
||||
remotes = mocker.patch("ahriman.core.database.migrations.m001_package_source.migrate_package_remotes")
|
||||
migrate_data(connection, configuration)
|
||||
remotes.assert_called_once_with(connection, configuration.repository_paths)
|
||||
|
||||
|
||||
def test_migrate_package_remotes(package_ahriman: Package, connection: Connection, repository_paths: RepositoryPaths,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must put package remotes to database
|
||||
"""
|
||||
connection.execute.return_value = [{
|
||||
"package_base": package_ahriman.base,
|
||||
"version": package_ahriman.version,
|
||||
"source": PackageSource.AUR,
|
||||
}]
|
||||
mocker.patch("pathlib.Path.exists", return_value=False)
|
||||
|
||||
migrate_package_remotes(connection, repository_paths)
|
||||
connection.execute.assert_has_calls([
|
||||
MockCall(pytest.helpers.anyvar(str, strict=True)),
|
||||
MockCall(pytest.helpers.anyvar(str, strict=True), pytest.helpers.anyvar(int)),
|
||||
])
|
||||
|
||||
|
||||
def test_migrate_package_remotes_has_local(package_ahriman: Package, connection: Connection,
|
||||
repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip processing for packages which have local cache
|
||||
"""
|
||||
connection.execute.return_value = [{
|
||||
"package_base": package_ahriman.base,
|
||||
"version": package_ahriman.version,
|
||||
"source": PackageSource.AUR,
|
||||
}]
|
||||
mocker.patch("pathlib.Path.exists", return_value=True)
|
||||
|
||||
migrate_package_remotes(connection, repository_paths)
|
||||
connection.execute.assert_called_once_with(pytest.helpers.anyvar(str, strict=True))
|
||||
|
||||
|
||||
def test_migrate_package_remotes_vcs(package_ahriman: Package, connection: Connection,
|
||||
repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must process VCS packages with local cache
|
||||
"""
|
||||
connection.execute.return_value = [{
|
||||
"package_base": package_ahriman.base,
|
||||
"version": package_ahriman.version,
|
||||
"source": PackageSource.AUR,
|
||||
}]
|
||||
mocker.patch("pathlib.Path.exists", return_value=True)
|
||||
mocker.patch.object(Package, "is_vcs", True)
|
||||
|
||||
migrate_package_remotes(connection, repository_paths)
|
||||
connection.execute.assert_has_calls([
|
||||
MockCall(pytest.helpers.anyvar(str, strict=True)),
|
||||
MockCall(pytest.helpers.anyvar(str, strict=True), pytest.helpers.anyvar(int)),
|
||||
])
|
||||
@@ -0,0 +1,8 @@
|
||||
from ahriman.core.database.migrations.m002_user_access import steps
|
||||
|
||||
|
||||
def test_migration_user_access() -> None:
|
||||
"""
|
||||
migration must not be empty
|
||||
"""
|
||||
assert steps
|
||||
@@ -0,0 +1,8 @@
|
||||
from ahriman.core.database.migrations.m003_patch_variables import steps
|
||||
|
||||
|
||||
def test_migration_patches() -> None:
|
||||
"""
|
||||
migration must not be empty
|
||||
"""
|
||||
assert steps
|
||||
@@ -0,0 +1,8 @@
|
||||
from ahriman.core.database.migrations.m004_logs import steps
|
||||
|
||||
|
||||
def test_migration_logs() -> None:
|
||||
"""
|
||||
migration must not be empty
|
||||
"""
|
||||
assert steps
|
||||
@@ -0,0 +1,52 @@
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
from sqlite3 import Connection
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database.migrations.m005_make_opt_depends import migrate_data, migrate_package_depends, steps
|
||||
from ahriman.models.package import Package
|
||||
|
||||
|
||||
def test_migration_make_opt_depends() -> None:
|
||||
"""
|
||||
migration must not be empty
|
||||
"""
|
||||
assert steps
|
||||
|
||||
|
||||
def test_migrate_data(connection: Connection, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must perform data migration
|
||||
"""
|
||||
depends_mock = mocker.patch("ahriman.core.database.migrations.m005_make_opt_depends.migrate_package_depends")
|
||||
migrate_data(connection, configuration)
|
||||
depends_mock.assert_called_once_with(connection, configuration)
|
||||
|
||||
|
||||
def test_migrate_package_depends(connection: Connection, configuration: Configuration, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must update make and opt depends list
|
||||
"""
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||
mocker.patch("pathlib.Path.iterdir", return_value=[package_ahriman.packages[package_ahriman.base].filepath])
|
||||
package_mock = mocker.patch("ahriman.models.package.Package.from_archive", return_value=package_ahriman)
|
||||
|
||||
migrate_package_depends(connection, configuration)
|
||||
package_mock.assert_called_once_with(package_ahriman.packages[package_ahriman.base].filepath)
|
||||
connection.executemany.assert_called_once_with(pytest.helpers.anyvar(str, strict=True), [{
|
||||
"make_depends": package_ahriman.packages[package_ahriman.base].make_depends,
|
||||
"opt_depends": package_ahriman.packages[package_ahriman.base].opt_depends,
|
||||
"package": package_ahriman.base,
|
||||
}])
|
||||
|
||||
|
||||
def test_migrate_package_depends_skip(connection: Connection, configuration: Configuration,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip update make and opt depends list if no repository directory found
|
||||
"""
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||
migrate_package_depends(connection, configuration)
|
||||
connection.executemany.assert_not_called()
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
from ahriman.core.database.migrations.m006_packages_architecture_required import steps
|
||||
|
||||
|
||||
def test_migration_logs() -> None:
|
||||
"""
|
||||
migration must not be empty
|
||||
"""
|
||||
assert steps
|
||||
@@ -0,0 +1,51 @@
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
from sqlite3 import Connection
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database.migrations.m007_check_depends import migrate_data, migrate_package_check_depends, steps
|
||||
from ahriman.models.package import Package
|
||||
|
||||
|
||||
def test_migration_check_depends() -> None:
|
||||
"""
|
||||
migration must not be empty
|
||||
"""
|
||||
assert steps
|
||||
|
||||
|
||||
def test_migrate_data(connection: Connection, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must perform data migration
|
||||
"""
|
||||
depends_mock = mocker.patch("ahriman.core.database.migrations.m007_check_depends.migrate_package_check_depends")
|
||||
migrate_data(connection, configuration)
|
||||
depends_mock.assert_called_once_with(connection, configuration)
|
||||
|
||||
|
||||
def test_migrate_package_depends(connection: Connection, configuration: Configuration, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must update check depends list
|
||||
"""
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||
mocker.patch("pathlib.Path.iterdir", return_value=[package_ahriman.packages[package_ahriman.base].filepath])
|
||||
package_mock = mocker.patch("ahriman.models.package.Package.from_archive", return_value=package_ahriman)
|
||||
|
||||
migrate_package_check_depends(connection, configuration)
|
||||
package_mock.assert_called_once_with(package_ahriman.packages[package_ahriman.base].filepath)
|
||||
connection.executemany.assert_called_once_with(pytest.helpers.anyvar(str, strict=True), [{
|
||||
"check_depends": package_ahriman.packages[package_ahriman.base].check_depends,
|
||||
"package": package_ahriman.base,
|
||||
}])
|
||||
|
||||
|
||||
def test_migrate_package_depends_skip(connection: Connection, configuration: Configuration,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip update check depends list if no repository directory found
|
||||
"""
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||
migrate_package_check_depends(connection, configuration)
|
||||
connection.executemany.assert_not_called()
|
||||
@@ -0,0 +1,51 @@
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
from sqlite3 import Connection
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database.migrations.m008_packagers import migrate_data, migrate_package_base_packager, steps
|
||||
from ahriman.models.package import Package
|
||||
|
||||
|
||||
def test_migration_packagers() -> None:
|
||||
"""
|
||||
migration must not be empty
|
||||
"""
|
||||
assert steps
|
||||
|
||||
|
||||
def test_migrate_data(connection: Connection, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must perform data migration
|
||||
"""
|
||||
depends_mock = mocker.patch("ahriman.core.database.migrations.m008_packagers.migrate_package_base_packager")
|
||||
migrate_data(connection, configuration)
|
||||
depends_mock.assert_called_once_with(connection, configuration)
|
||||
|
||||
|
||||
def test_migrate_package_base_packager(connection: Connection, configuration: Configuration, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must update packagers
|
||||
"""
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||
mocker.patch("pathlib.Path.iterdir", return_value=[package_ahriman.packages[package_ahriman.base].filepath])
|
||||
package_mock = mocker.patch("ahriman.models.package.Package.from_archive", return_value=package_ahriman)
|
||||
|
||||
migrate_package_base_packager(connection, configuration)
|
||||
package_mock.assert_called_once_with(package_ahriman.packages[package_ahriman.base].filepath)
|
||||
connection.executemany.assert_called_once_with(pytest.helpers.anyvar(str, strict=True), [{
|
||||
"package_base": package_ahriman.base,
|
||||
"packager": package_ahriman.packager,
|
||||
}])
|
||||
|
||||
|
||||
def test_migrate_package_depends_skip(connection: Connection, configuration: Configuration,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip update packagers if no repository directory found
|
||||
"""
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||
migrate_package_base_packager(connection, configuration)
|
||||
connection.executemany.assert_not_called()
|
||||
@@ -0,0 +1,8 @@
|
||||
from ahriman.core.database.migrations.m009_local_source import steps
|
||||
|
||||
|
||||
def test_migration_local_source() -> None:
|
||||
"""
|
||||
migration must not be empty
|
||||
"""
|
||||
assert steps
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
from ahriman.core.database.migrations.m010_version_based_logs_removal import steps
|
||||
|
||||
|
||||
def test_migration_version_based_logs_removal() -> None:
|
||||
"""
|
||||
migration must not be empty
|
||||
"""
|
||||
assert steps
|
||||
@@ -0,0 +1,39 @@
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
from sqlite3 import Connection
|
||||
from unittest.mock import call as MockCall
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database.migrations.m011_repository_name import migrate_data, migrate_package_repository, steps
|
||||
|
||||
|
||||
def test_migration_repository_name() -> None:
|
||||
"""
|
||||
migration must not be empty
|
||||
"""
|
||||
assert steps
|
||||
|
||||
|
||||
def test_migrate_data(connection: Connection, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must perform data migration
|
||||
"""
|
||||
repository_mock = mocker.patch("ahriman.core.database.migrations.m011_repository_name.migrate_package_repository")
|
||||
migrate_data(connection, configuration)
|
||||
repository_mock.assert_called_once_with(connection, configuration)
|
||||
|
||||
|
||||
def test_migrate_package_repository(connection: Connection, configuration: Configuration) -> None:
|
||||
"""
|
||||
must correctly set repository and architecture
|
||||
"""
|
||||
migrate_package_repository(connection, configuration)
|
||||
|
||||
connection.execute.assert_has_calls([
|
||||
MockCall(pytest.helpers.anyvar(str, strict=True), {"repository": configuration.repository_id.id}),
|
||||
MockCall(pytest.helpers.anyvar(str, strict=True), {"repository": configuration.repository_id.id}),
|
||||
MockCall(pytest.helpers.anyvar(str, strict=True), {"repository": configuration.repository_id.id}),
|
||||
MockCall(pytest.helpers.anyvar(str, strict=True), {"repository": configuration.repository_id.id}),
|
||||
MockCall(pytest.helpers.anyvar(str, strict=True), {"repository": configuration.repository_id.id}),
|
||||
])
|
||||
@@ -0,0 +1,8 @@
|
||||
from ahriman.core.database.migrations.m012_last_commit_sha import steps
|
||||
|
||||
|
||||
def test_migration_last_commit_sha() -> None:
|
||||
"""
|
||||
migration must not be empty
|
||||
"""
|
||||
assert steps
|
||||
@@ -0,0 +1,8 @@
|
||||
from ahriman.core.database.migrations.m013_dependencies import steps
|
||||
|
||||
|
||||
def test_migration_dependencies() -> None:
|
||||
"""
|
||||
migration must not be empty
|
||||
"""
|
||||
assert steps
|
||||
@@ -0,0 +1,8 @@
|
||||
from ahriman.core.database.migrations.m014_auditlog import steps
|
||||
|
||||
|
||||
def test_migration_auditlog() -> None:
|
||||
"""
|
||||
migration must not be empty
|
||||
"""
|
||||
assert steps
|
||||
@@ -0,0 +1,8 @@
|
||||
from ahriman.core.database.migrations.m015_logs_process_id import steps
|
||||
|
||||
|
||||
def test_migration_logs_process_id() -> None:
|
||||
"""
|
||||
migration must not be empty
|
||||
"""
|
||||
assert steps
|
||||
@@ -0,0 +1,77 @@
|
||||
import pytest
|
||||
|
||||
from dataclasses import replace
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
from sqlite3 import Connection
|
||||
from typing import Any
|
||||
from unittest.mock import call as MockCall
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database.migrations.m016_archive import migrate_data, move_packages
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
|
||||
|
||||
def test_migrate_data(connection: Connection, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must perform data migration
|
||||
"""
|
||||
_, repository_id = configuration.check_loaded()
|
||||
repositories = [
|
||||
repository_id,
|
||||
replace(repository_id, architecture="i686"),
|
||||
]
|
||||
mocker.patch("ahriman.core.repository.Explorer.repositories_extract", return_value=repositories)
|
||||
migration_mock = mocker.patch("ahriman.core.database.migrations.m016_archive.move_packages")
|
||||
|
||||
migrate_data(connection, configuration)
|
||||
migration_mock.assert_has_calls([
|
||||
MockCall(replace(configuration.repository_paths, repository_id=repository))
|
||||
for repository in repositories
|
||||
])
|
||||
|
||||
|
||||
def test_move_packages(repository_paths: RepositoryPaths, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must move packages to the archive directory
|
||||
"""
|
||||
|
||||
def is_file(self: Path, *args: Any, **kwargs: Any) -> bool:
|
||||
return "file" in self.name
|
||||
|
||||
mocker.patch("pathlib.Path.iterdir", return_value=[
|
||||
repository_paths.repository / ".hidden-file.pkg.tar.xz",
|
||||
repository_paths.repository / "directory",
|
||||
repository_paths.repository / "file.pkg.tar.xz",
|
||||
repository_paths.repository / "file.pkg.tar.xz.sig",
|
||||
repository_paths.repository / "file2.pkg.tar.xz",
|
||||
repository_paths.repository / "symlink.pkg.tar.xz",
|
||||
])
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||
mocker.patch("pathlib.Path.is_file", autospec=True, side_effect=is_file)
|
||||
mocker.patch("pathlib.Path.exists", return_value=True)
|
||||
archive_mock = mocker.patch("ahriman.models.package.Package.from_archive", return_value=package_ahriman)
|
||||
move_mock = mocker.patch("ahriman.core.database.migrations.m016_archive.atomic_move")
|
||||
symlink_mock = mocker.patch("pathlib.Path.symlink_to")
|
||||
|
||||
move_packages(repository_paths)
|
||||
archive_mock.assert_has_calls([
|
||||
MockCall(repository_paths.repository / filename)
|
||||
for filename in ("file.pkg.tar.xz", "file2.pkg.tar.xz")
|
||||
])
|
||||
move_mock.assert_has_calls([
|
||||
MockCall(repository_paths.repository / filename, repository_paths.archive_for(package_ahriman.base) / filename)
|
||||
for filename in ("file.pkg.tar.xz", "file.pkg.tar.xz.sig", "file2.pkg.tar.xz")
|
||||
])
|
||||
symlink_mock.assert_has_calls([
|
||||
MockCall(
|
||||
Path("..") /
|
||||
".." /
|
||||
".." /
|
||||
repository_paths.archive_for(package_ahriman.base).relative_to(repository_paths.root) /
|
||||
filename
|
||||
)
|
||||
for filename in ("file.pkg.tar.xz", "file.pkg.tar.xz.sig", "file2.pkg.tar.xz")
|
||||
])
|
||||
@@ -0,0 +1,8 @@
|
||||
from ahriman.core.database.migrations.m017_pkgbuild import steps
|
||||
|
||||
|
||||
def test_migration_pkgbuild() -> None:
|
||||
"""
|
||||
migration must not be empty
|
||||
"""
|
||||
assert steps
|
||||
@@ -0,0 +1,8 @@
|
||||
from ahriman.core.database.migrations.m018_package_hold import steps
|
||||
|
||||
|
||||
def test_migration_package_hold() -> None:
|
||||
"""
|
||||
migration must not be empty
|
||||
"""
|
||||
assert steps
|
||||
@@ -0,0 +1,126 @@
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
from sqlite3 import Connection
|
||||
from unittest.mock import MagicMock, call as MockCall
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database.migrations import Migrations
|
||||
from ahriman.models.migration import Migration
|
||||
from ahriman.models.migration_result import MigrationResult
|
||||
|
||||
|
||||
def test_migrate(connection: Connection, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must perform migrations
|
||||
"""
|
||||
run_mock = mocker.patch("ahriman.core.database.migrations.Migrations.run")
|
||||
Migrations.migrate(connection, configuration)
|
||||
run_mock.assert_called_once_with()
|
||||
|
||||
|
||||
def test_apply_migrations(migrations: Migrations, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must apply list of migrations
|
||||
"""
|
||||
cursor = MagicMock()
|
||||
migration = Migration(index=0, name="test", steps=["select 1"], migrate_data=MagicMock())
|
||||
migrations.connection.cursor.return_value = cursor
|
||||
migration_mock = mocker.patch("ahriman.core.database.migrations.Migrations.perform_migration")
|
||||
|
||||
migrations.apply_migrations([migration])
|
||||
cursor.execute.assert_has_calls([
|
||||
MockCall("begin exclusive"),
|
||||
MockCall("commit"),
|
||||
])
|
||||
cursor.close.assert_called_once_with()
|
||||
migration_mock.assert_called_once_with(cursor, migration)
|
||||
|
||||
|
||||
def test_apply_migration_exception(migrations: Migrations, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must roll back and close cursor on exception during migration
|
||||
"""
|
||||
cursor = MagicMock()
|
||||
mocker.patch("logging.Logger.info", side_effect=Exception)
|
||||
migrations.connection.cursor.return_value = cursor
|
||||
|
||||
with pytest.raises(Exception):
|
||||
migrations.apply_migrations([Migration(index=0, name="test", steps=["select 1"], migrate_data=MagicMock())])
|
||||
cursor.execute.assert_has_calls([
|
||||
MockCall("begin exclusive"),
|
||||
MockCall("rollback"),
|
||||
])
|
||||
cursor.close.assert_called_once_with()
|
||||
|
||||
|
||||
def test_apply_migration_sql_exception(migrations: Migrations) -> None:
|
||||
"""
|
||||
must close cursor on general migration error
|
||||
"""
|
||||
cursor = MagicMock()
|
||||
cursor.execute.side_effect = Exception
|
||||
migrations.connection.cursor.return_value = cursor
|
||||
|
||||
with pytest.raises(Exception):
|
||||
migrations.apply_migrations([Migration(index=0, name="test", steps=["select 1"], migrate_data=MagicMock())])
|
||||
cursor.close.assert_called_once_with()
|
||||
|
||||
|
||||
def test_migrations(migrations: Migrations) -> None:
|
||||
"""
|
||||
must retrieve migrations
|
||||
"""
|
||||
assert migrations.migrations()
|
||||
|
||||
|
||||
def test_perform_migration(migrations: Migrations) -> None:
|
||||
"""
|
||||
must perform single migration
|
||||
"""
|
||||
migrate_data_mock = MagicMock()
|
||||
cursor = MagicMock()
|
||||
migration = Migration(index=0, name="test", steps=["select 1"], migrate_data=migrate_data_mock)
|
||||
|
||||
migrations.perform_migration(cursor, migration)
|
||||
cursor.execute.assert_called_once_with("select 1")
|
||||
migrate_data_mock.assert_called_once_with(migrations.connection, migrations.configuration)
|
||||
|
||||
|
||||
def test_run_skip(migrations: Migrations, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must skip migration if version is the same
|
||||
"""
|
||||
mocker.patch.object(MigrationResult, "is_outdated", False)
|
||||
|
||||
migrations.run()
|
||||
migrations.connection.cursor.assert_not_called()
|
||||
|
||||
|
||||
def test_run(migrations: Migrations, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run migration
|
||||
"""
|
||||
migration = Migration(index=0, name="test", steps=["select 1"], migrate_data=MagicMock())
|
||||
mocker.patch("ahriman.core.database.migrations.Migrations.user_version", return_value=0)
|
||||
mocker.patch("ahriman.core.database.migrations.Migrations.migrations", return_value=[migration])
|
||||
validate_mock = mocker.patch("ahriman.models.migration_result.MigrationResult.validate")
|
||||
apply_mock = mocker.patch("ahriman.core.database.migrations.Migrations.apply_migrations")
|
||||
|
||||
migrations.run()
|
||||
apply_mock.assert_called_once_with([migration])
|
||||
validate_mock.assert_called_once_with()
|
||||
migrations.connection.execute.assert_called_once_with("pragma user_version = 1")
|
||||
|
||||
|
||||
def test_user_version(migrations: Migrations) -> None:
|
||||
"""
|
||||
must correctly extract current migration version
|
||||
"""
|
||||
cursor = MagicMock()
|
||||
cursor.fetchone.return_value = {"user_version": 42}
|
||||
migrations.connection.execute.return_value = cursor
|
||||
|
||||
version = migrations.user_version()
|
||||
migrations.connection.execute.assert_called_once_with("pragma user_version")
|
||||
assert version == 42
|
||||
@@ -0,0 +1,98 @@
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.models.user import User
|
||||
from ahriman.models.user_access import UserAccess
|
||||
|
||||
|
||||
def test_user_get_update(database: SQLite, user: User) -> None:
|
||||
"""
|
||||
must retrieve user from the database
|
||||
"""
|
||||
database.user_update(user)
|
||||
assert database.user_get(user.username) == user
|
||||
|
||||
|
||||
def test_user_list(database: SQLite, user: User) -> None:
|
||||
"""
|
||||
must return all users
|
||||
"""
|
||||
database.user_update(user)
|
||||
second = User(username=user.password, password=user.username, access=user.access, packager_id=None, key=None)
|
||||
database.user_update(second)
|
||||
|
||||
users = database.user_list(None, None)
|
||||
assert len(users) == 2
|
||||
assert user in users
|
||||
assert second in users
|
||||
|
||||
|
||||
def test_user_list_filter_by_username(database: SQLite) -> None:
|
||||
"""
|
||||
must return users filtered by its id
|
||||
"""
|
||||
first = User(username="1", password="", access=UserAccess.Read, packager_id=None, key=None)
|
||||
second = User(username="2", password="", access=UserAccess.Full, packager_id=None, key=None)
|
||||
third = User(username="3", password="", access=UserAccess.Read, packager_id=None, key=None)
|
||||
|
||||
database.user_update(first)
|
||||
database.user_update(second)
|
||||
database.user_update(third)
|
||||
|
||||
assert database.user_list("1", None) == [first]
|
||||
assert database.user_list("2", None) == [second]
|
||||
assert database.user_list("3", None) == [third]
|
||||
|
||||
|
||||
def test_user_list_filter_by_access(database: SQLite) -> None:
|
||||
"""
|
||||
must return users filtered by its access
|
||||
"""
|
||||
first = User(username="1", password="", access=UserAccess.Read, packager_id=None, key=None)
|
||||
second = User(username="2", password="", access=UserAccess.Full, packager_id=None, key=None)
|
||||
third = User(username="3", password="", access=UserAccess.Read, packager_id=None, key=None)
|
||||
|
||||
database.user_update(first)
|
||||
database.user_update(second)
|
||||
database.user_update(third)
|
||||
|
||||
users = database.user_list(None, UserAccess.Read)
|
||||
assert len(users) == 2
|
||||
assert first in users
|
||||
assert third in users
|
||||
|
||||
|
||||
def test_user_list_filter_by_username_access(database: SQLite) -> None:
|
||||
"""
|
||||
must return users filtered by its access and username
|
||||
"""
|
||||
first = User(username="1", password="", access=UserAccess.Read, packager_id=None, key=None)
|
||||
second = User(username="2", password="", access=UserAccess.Full, packager_id=None, key=None)
|
||||
third = User(username="3", password="", access=UserAccess.Read, packager_id=None, key=None)
|
||||
|
||||
database.user_update(first)
|
||||
database.user_update(second)
|
||||
database.user_update(third)
|
||||
|
||||
assert database.user_list("1", UserAccess.Read) == [first]
|
||||
assert not database.user_list("1", UserAccess.Full)
|
||||
|
||||
|
||||
def test_user_remove_update(database: SQLite, user: User) -> None:
|
||||
"""
|
||||
must remove user from the database
|
||||
"""
|
||||
database.user_update(user)
|
||||
database.user_remove(user.username)
|
||||
assert database.user_get(user.username) is None
|
||||
|
||||
|
||||
def test_user_update(database: SQLite, user: User) -> None:
|
||||
"""
|
||||
must update user in the database
|
||||
"""
|
||||
database.user_update(user)
|
||||
assert database.user_get(user.username) == user
|
||||
|
||||
new_user = User(username=user.username, password=user.hash_password("salt").password, access=UserAccess.Full,
|
||||
packager_id=None, key="new key")
|
||||
database.user_update(new_user)
|
||||
assert database.user_get(new_user.username) == new_user
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user