Support type triggers (#96)

* implement mirrorlist package generator

* implement keyring package generator

* docs update

* do not skip empty lines

* fill remote source for local packages

* faq update
This commit is contained in:
2023-05-25 16:27:16 +03:00
committed by GitHub
parent 8b2601beaa
commit adb5b58a1d
55 changed files with 2304 additions and 76 deletions

View File

@ -5,25 +5,36 @@ 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:
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
@ -37,21 +48,29 @@ def test_add_aur(application_packages: ApplicationPackages, package_ahriman: Pac
update_remote_mock.assert_called_once_with(package_ahriman)
def test_add_directory(
application_packages: ApplicationPackages,
package_ahriman: Package,
mocker: MockerFixture) -> None:
def test_add_directory(application_packages: ApplicationPackages, package_ahriman: Package,
mocker: MockerFixture) -> None:
"""
must add packages from directory
"""
iterdir_mock = mocker.patch("pathlib.Path.iterdir",
return_value=[package.filepath for package in package_ahriman.packages.values()])
copy_mock = mocker.patch("shutil.copy")
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()
copy_mock.assert_called_once_with(filename, application_packages.repository.paths.packages / filename.name)
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:
@ -59,17 +78,46 @@ def test_add_local(application_packages: ApplicationPackages, package_ahriman: P
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)
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))
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: True if p.is_relative_to(application_packages.repository.paths.cache) else False)
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)
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")
def test_add_remote(application_packages: ApplicationPackages, package_description_ahriman: PackageDescription,
mocker: MockerFixture) -> None:
"""
@ -87,6 +135,15 @@ def test_add_remote(application_packages: ApplicationPackages, package_descripti
response_mock.raise_for_status.assert_called_once_with()
def test_add_remote_missing(application_packages: ApplicationPackages, mocker: MockerFixture) -> None:
"""
must add package from remote source
"""
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:
"""
@ -112,10 +169,8 @@ def test_add_add_archive(application_packages: ApplicationPackages, package_ahri
add_mock.assert_called_once_with(package_ahriman.base)
def test_add_add_aur(
application_packages: ApplicationPackages,
package_ahriman: Package,
mocker: MockerFixture) -> None:
def test_add_add_aur(application_packages: ApplicationPackages, package_ahriman: Package,
mocker: MockerFixture) -> None:
"""
must add package from AUR via add function
"""

View File

@ -62,6 +62,10 @@ def test_schema(configuration: Configuration) -> None:
assert schema.pop("email")
assert schema.pop("github")
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("report")
assert schema.pop("rsync")
assert schema.pop("s3")
@ -76,6 +80,7 @@ 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("x86_64", configuration) == CONFIGURATION_SCHEMA

View File

@ -373,6 +373,42 @@ def test_subparsers_repo_check_option_refresh(parser: argparse.ArgumentParser) -
assert args.refresh == 2
def test_subparsers_repo_create_keyring(parser: argparse.ArgumentParser) -> None:
"""
repo-create-keyring command must imply trigger
"""
args = parser.parse_args(["repo-create-keyring"])
assert args.trigger == ["ahriman.core.support.KeyringTrigger"]
def test_subparsers_repo_create_keyring_architecture(parser: argparse.ArgumentParser) -> None:
"""
repo-create-keyring command must correctly parse architecture list
"""
args = parser.parse_args(["repo-create-keyring"])
assert args.architecture is None
args = parser.parse_args(["-a", "x86_64", "repo-create-keyring"])
assert args.architecture == ["x86_64"]
def test_subparsers_repo_create_mirrorlist(parser: argparse.ArgumentParser) -> None:
"""
repo-create-mirrorlist command must imply trigger
"""
args = parser.parse_args(["repo-create-mirrorlist"])
assert args.trigger == ["ahriman.core.support.MirrorlistTrigger"]
def test_subparsers_repo_create_mirrorlist_architecture(parser: argparse.ArgumentParser) -> None:
"""
repo-create-mirrorlist command must correctly parse architecture list
"""
args = parser.parse_args(["repo-create-mirrorlist"])
assert args.architecture is None
args = parser.parse_args(["-a", "x86_64", "repo-create-mirrorlist"])
assert args.architecture == ["x86_64"]
def test_subparsers_repo_daemon(parser: argparse.ArgumentParser) -> None:
"""
repo-daemon command must imply dry run, exit code and package

View File

@ -135,12 +135,17 @@ def test_init(mocker: MockerFixture) -> None:
"""
must create empty repository at the specified path
"""
mocker.patch("ahriman.models.package.Package.local_files", return_value=[Path("local")])
add_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.add")
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.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("git", "init", "--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, author="ahriman <ahriman@localhost>")
def test_load(package_ahriman: Package, repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:

View File

@ -10,6 +10,13 @@ from ahriman.core.exceptions import InitializeError
from ahriman.models.repository_paths import RepositoryPaths
def test_repository_name(configuration: Configuration) -> None:
"""
must return valid repository name
"""
assert configuration.repository_name == "aur-clone"
def test_repository_paths(configuration: Configuration, repository_paths: RepositoryPaths) -> None:
"""
must return repository paths

View File

@ -73,6 +73,30 @@ def test_validate_is_ip_address(validator: Validator, mocker: MockerFixture) ->
])
def test_validate_path_is_absolute(validator: Validator, mocker: MockerFixture) -> None:
"""
must validate that path is absolute
"""
error_mock = mocker.patch("ahriman.core.configuration.validator.Validator._error")
mocker.patch("pathlib.Path.is_absolute", return_value=False)
validator._validate_path_is_absolute(False, "field", Path("1"))
mocker.patch("pathlib.Path.is_absolute", return_value=True)
validator._validate_path_is_absolute(False, "field", Path("2"))
mocker.patch("pathlib.Path.is_absolute", return_value=False)
validator._validate_path_is_absolute(True, "field", Path("3"))
mocker.patch("pathlib.Path.is_absolute", return_value=True)
validator._validate_path_is_absolute(True, "field", Path("4"))
error_mock.assert_has_calls([
MockCall("field", "Path 2 must be relative"),
MockCall("field", "Path 3 must be absolute"),
])
def test_validate_is_url(validator: Validator, mocker: MockerFixture) -> None:
"""
must validate url correctly
@ -105,12 +129,16 @@ def test_validate_path_exists(validator: Validator, mocker: MockerFixture) -> No
mocker.patch("pathlib.Path.exists", return_value=False)
validator._validate_path_exists(False, "field", Path("1"))
mocker.patch("pathlib.Path.exists", return_value=False)
validator._validate_path_exists(True, "field", Path("2"))
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 exist"),
MockCall("field", "Path 2 must not exist"),
MockCall("field", "Path 3 must exist"),
])

View File

@ -4,6 +4,7 @@ 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
@ -63,6 +64,20 @@ def repo(configuration: Configuration, repository_paths: RepositoryPaths) -> Rep
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:
"""

View File

@ -16,4 +16,4 @@ def test_generate(configuration: Configuration, package_ahriman: Package, mocker
report = HTML("x86_64", configuration, "html")
report.generate([package_ahriman], Result())
write_mock.assert_called_once_with(pytest.helpers.anyvar(int))
write_mock.assert_called_once_with(pytest.helpers.anyvar(int), encoding="utf8")

View File

@ -1,23 +1,8 @@
import pytest
from ahriman.core.configuration import Configuration
from ahriman.core.sign.gpg import GPG
@pytest.fixture
def gpg(configuration: Configuration) -> GPG:
"""
fixture for empty GPG
Args:
configuration(Configuration): configuration fixture
Returns:
GPG: GPG test instance
"""
return GPG("x86_64", configuration)
@pytest.fixture
def gpg_with_key(gpg: GPG) -> GPG:
"""

View File

@ -97,6 +97,33 @@ def test_key_download_failure(gpg: GPG, mocker: MockerFixture) -> None:
gpg.key_download("keyserver.ubuntu.com", "0xE989490C")
def test_key_export(gpg: GPG, mocker: MockerFixture) -> None:
"""
must export gpg key correctly
"""
check_output_mock = mocker.patch("ahriman.core.sign.gpg.GPG._check_output", return_value="key")
assert gpg.key_export("k") == "key"
check_output_mock.assert_called_once_with("gpg", "--armor", "--no-emit-version", "--export", "k",
logger=pytest.helpers.anyvar(int))
def test_key_fingerprint(gpg: GPG, mocker: MockerFixture) -> None:
"""
must extract fingerprint
"""
check_output_mock = mocker.patch(
"ahriman.core.sign.gpg.GPG._check_output",
return_value="""tru::1:1576103830:0:3:1:5
fpr:::::::::C6EBB9222C3C8078631A0DE4BD2AC8C5E989490C:
sub:-:4096:1:7E3A4240CE3C45C2:1615121387::::::e::::::23:
fpr:::::::::43A663569A07EE1E4ECC55CC7E3A4240CE3C45C2:""")
key = "0xCE3C45C2"
assert gpg.key_fingerprint(key) == "C6EBB9222C3C8078631A0DE4BD2AC8C5E989490C"
check_output_mock.assert_called_once_with("gpg", "--with-colons", "--fingerprint", key,
logger=pytest.helpers.anyvar(int))
def test_key_import(gpg: GPG, mocker: MockerFixture) -> None:
"""
must import PGP key from the server
@ -108,6 +135,21 @@ def test_key_import(gpg: GPG, mocker: MockerFixture) -> None:
check_output_mock.assert_called_once_with("gpg", "--import", input_data="key", logger=pytest.helpers.anyvar(int))
def test_keys(gpg: GPG) -> None:
"""
must extract keys
"""
assert gpg.keys() == []
gpg.default_key = "key"
assert gpg.keys() == [gpg.default_key]
gpg.configuration.set_option("sign", "key_a", "key1")
gpg.configuration.set_option("sign", "key_b", "key1")
gpg.configuration.set_option("sign", "key_c", "key2")
assert gpg.keys() == ["key", "key1", "key2"]
def test_process(gpg_with_key: GPG, mocker: MockerFixture) -> None:
"""
must call process method correctly

View File

@ -0,0 +1,34 @@
import pytest
from ahriman.core.configuration import Configuration
from ahriman.core.support.package_creator import PackageCreator
from ahriman.core.support.pkgbuild.mirrorlist_generator import MirrorlistGenerator
@pytest.fixture
def mirrorlist_generator(configuration: Configuration) -> MirrorlistGenerator:
"""
fixture for mirrorlist pkgbuild generator
Args:
configuration(Configuration): configuration fixture
Returns:
MirrorlistGenerator: mirrorlist pkgbuild generator test instance
"""
return MirrorlistGenerator(configuration, "mirrorlist")
@pytest.fixture
def package_creator(configuration: Configuration, mirrorlist_generator: MirrorlistGenerator) -> PackageCreator:
"""
package creator fixture
Args:
configuration(Configuration): configuration fixture
mirrorlist_generator(MirrorlistGenerator):
Returns:
PackageCreator: package creator test instance
"""
return PackageCreator(configuration, mirrorlist_generator)

View File

@ -0,0 +1,32 @@
import pytest
from ahriman.core.configuration import Configuration
from ahriman.core.sign.gpg import GPG
from ahriman.core.support.pkgbuild.keyring_generator import KeyringGenerator
from ahriman.core.support.pkgbuild.pkgbuild_generator import PkgbuildGenerator
@pytest.fixture
def keyring_generator(gpg: GPG, configuration: Configuration) -> KeyringGenerator:
"""
fixture for keyring pkgbuild generator
Args:
gpg(GPG): empty GPG fixture
configuration(Configuration): configuration fixture
Returns:
KeyringGenerator: keyring generator test instance
"""
return KeyringGenerator(gpg, configuration, "keyring")
@pytest.fixture
def pkgbuild_generator() -> PkgbuildGenerator:
"""
fixture for dummy pkgbuild generator
Returns:
PkgbuildGenerator: pkgbuild generator test instance
"""
return PkgbuildGenerator()

View File

@ -0,0 +1,185 @@
import pytest
from pathlib import Path
from pytest_mock import MockerFixture
from unittest.mock import MagicMock, call as MockCall
from ahriman.core.configuration import Configuration
from ahriman.core.exceptions import PkgbuildGeneratorError
from ahriman.core.sign.gpg import GPG
from ahriman.core.support.pkgbuild.keyring_generator import KeyringGenerator
def test_init_packagers(gpg: GPG, configuration: Configuration, mocker: MockerFixture) -> None:
"""
must extract packagers keys
"""
mocker.patch("ahriman.core.sign.gpg.GPG.keys", return_value=["key"])
assert KeyringGenerator(gpg, configuration, "keyring").packagers == ["key"]
configuration.set_option("keyring", "packagers", "key1")
assert KeyringGenerator(gpg, configuration, "keyring").packagers == ["key1"]
def test_init_revoked(gpg: GPG, configuration: Configuration) -> None:
"""
must extract revoked keys
"""
assert KeyringGenerator(gpg, configuration, "keyring").revoked == []
configuration.set_option("keyring", "revoked", "key1")
assert KeyringGenerator(gpg, configuration, "keyring").revoked == ["key1"]
def test_init_trusted(gpg: GPG, configuration: Configuration) -> None:
"""
must extract trusted keys
"""
assert KeyringGenerator(gpg, configuration, "keyring").trusted == []
gpg.default_key = "key"
assert KeyringGenerator(gpg, configuration, "keyring").trusted == ["key"]
configuration.set_option("keyring", "trusted", "key1")
assert KeyringGenerator(gpg, configuration, "keyring").trusted == ["key1"]
def test_license(gpg: GPG, configuration: Configuration) -> None:
"""
must generate correct licenses list
"""
assert KeyringGenerator(gpg, configuration, "keyring").license == ["Unlicense"]
configuration.set_option("keyring", "license", "GPL MPL")
assert KeyringGenerator(gpg, configuration, "keyring").license == ["GPL", "MPL"]
def test_pkgdesc(gpg: GPG, configuration: Configuration) -> None:
"""
must generate correct pkgdesc property
"""
assert KeyringGenerator(gpg, configuration, "keyring").pkgdesc == "aur-clone PGP keyring"
configuration.set_option("keyring", "description", "description")
assert KeyringGenerator(gpg, configuration, "keyring").pkgdesc == "description"
def test_pkgname(gpg: GPG, configuration: Configuration) -> None:
"""
must generate correct pkgname property
"""
assert KeyringGenerator(gpg, configuration, "keyring").pkgname == "aur-clone-keyring"
configuration.set_option("keyring", "package", "keyring")
assert KeyringGenerator(gpg, configuration, "keyring").pkgname == "keyring"
def test_url(gpg: GPG, configuration: Configuration) -> None:
"""
must generate correct url property
"""
assert KeyringGenerator(gpg, configuration, "keyring").url == ""
configuration.set_option("keyring", "homepage", "homepage")
assert KeyringGenerator(gpg, configuration, "keyring").url == "homepage"
def test_generate_gpg(keyring_generator: KeyringGenerator, mocker: MockerFixture) -> None:
"""
must correctly generate file with all PGP keys
"""
file_mock = MagicMock()
export_mock = mocker.patch("ahriman.core.sign.gpg.GPG.key_export", side_effect=lambda key: key)
open_mock = mocker.patch("pathlib.Path.open")
open_mock.return_value.__enter__.return_value = file_mock
keyring_generator.packagers = ["key"]
keyring_generator.revoked = ["revoked"]
keyring_generator.trusted = ["trusted", "key"]
keyring_generator._generate_gpg(Path("local"))
open_mock.assert_called_once_with("w")
export_mock.assert_has_calls([MockCall("key"), MockCall("revoked"), MockCall("trusted")])
file_mock.write.assert_has_calls([
MockCall("key"), MockCall("\n"),
MockCall("revoked"), MockCall("\n"),
MockCall("trusted"), MockCall("\n"),
])
def test_generate_revoked(keyring_generator: KeyringGenerator, mocker: MockerFixture) -> None:
"""
must correctly generate file with revoked keys
"""
file_mock = MagicMock()
fingerprint_mock = mocker.patch("ahriman.core.sign.gpg.GPG.key_fingerprint", side_effect=lambda key: key)
open_mock = mocker.patch("pathlib.Path.open")
open_mock.return_value.__enter__.return_value = file_mock
keyring_generator.revoked = ["revoked"]
keyring_generator._generate_revoked(Path("local"))
open_mock.assert_called_once_with("w")
fingerprint_mock.assert_called_once_with("revoked")
file_mock.write.assert_has_calls([MockCall("revoked"), MockCall("\n")])
def test_generate_trusted(keyring_generator: KeyringGenerator, mocker: MockerFixture) -> None:
"""
must correctly generate file with trusted keys
"""
file_mock = MagicMock()
fingerprint_mock = mocker.patch("ahriman.core.sign.gpg.GPG.key_fingerprint", side_effect=lambda key: key)
open_mock = mocker.patch("pathlib.Path.open")
open_mock.return_value.__enter__.return_value = file_mock
keyring_generator.trusted = ["trusted", "trusted"]
keyring_generator._generate_trusted(Path("local"))
open_mock.assert_called_once_with("w")
fingerprint_mock.assert_called_once_with("trusted")
file_mock.write.assert_has_calls([MockCall("trusted"), MockCall(":4:\n")])
def test_generate_trusted_empty(keyring_generator: KeyringGenerator) -> None:
"""
must raise PkgbuildGeneratorError if no trusted keys set
"""
with pytest.raises(PkgbuildGeneratorError):
keyring_generator._generate_trusted(Path("local"))
def test_install(keyring_generator: KeyringGenerator) -> None:
"""
must return install functions
"""
assert keyring_generator.install() == """post_upgrade() {
if usr/bin/pacman-key -l >/dev/null 2>&1; then
usr/bin/pacman-key --populate aur-clone
usr/bin/pacman-key --updatedb
fi
}
post_install() {
if [ -x usr/bin/pacman-key ]; then
post_upgrade
fi
}"""
def test_package(keyring_generator: KeyringGenerator) -> None:
"""
must generate package function correctly
"""
assert keyring_generator.package() == """{
install -Dm644 "$srcdir/aur-clone.gpg" "$pkgdir/usr/share/pacman/keyrings/aur-clone.gpg"
install -Dm644 "$srcdir/aur-clone-revoked" "$pkgdir/usr/share/pacman/keyrings/aur-clone-revoked"
install -Dm644 "$srcdir/aur-clone-trusted" "$pkgdir/usr/share/pacman/keyrings/aur-clone-trusted"
}"""
def test_sources(keyring_generator: KeyringGenerator) -> None:
"""
must return valid sources files list
"""
assert keyring_generator.sources().get("aur-clone.gpg")
assert keyring_generator.sources().get("aur-clone-revoked")
assert keyring_generator.sources().get("aur-clone-trusted")

View File

@ -0,0 +1,90 @@
from pathlib import Path
from pytest_mock import MockerFixture
from ahriman.core.configuration import Configuration
from ahriman.core.support.pkgbuild.mirrorlist_generator import MirrorlistGenerator
def test_init_path(configuration: Configuration) -> None:
"""
must set relative path to mirrorlist
"""
assert MirrorlistGenerator(configuration, "mirrorlist").path == Path("etc") / "pacman.d" / "aur-clone-mirrorlist"
configuration.set_option("mirrorlist", "path", "/etc")
assert MirrorlistGenerator(configuration, "mirrorlist").path == Path("etc")
def test_license(configuration: Configuration) -> None:
"""
must generate correct licenses list
"""
assert MirrorlistGenerator(configuration, "mirrorlist").license == ["Unlicense"]
configuration.set_option("mirrorlist", "license", "GPL MPL")
assert MirrorlistGenerator(configuration, "mirrorlist").license == ["GPL", "MPL"]
def test_pkgdesc(configuration: Configuration) -> None:
"""
must generate correct pkgdesc property
"""
assert MirrorlistGenerator(configuration, "mirrorlist").pkgdesc == "aur-clone mirror list for use by pacman"
configuration.set_option("mirrorlist", "description", "description")
assert MirrorlistGenerator(configuration, "mirrorlist").pkgdesc == "description"
def test_pkgname(configuration: Configuration) -> None:
"""
must generate correct pkgname property
"""
assert MirrorlistGenerator(configuration, "mirrorlist").pkgname == "aur-clone-mirrorlist"
configuration.set_option("mirrorlist", "package", "mirrorlist")
assert MirrorlistGenerator(configuration, "mirrorlist").pkgname == "mirrorlist"
def test_url(configuration: Configuration) -> None:
"""
must generate correct url property
"""
assert MirrorlistGenerator(configuration, "mirrorlist").url == ""
configuration.set_option("mirrorlist", "homepage", "homepage")
assert MirrorlistGenerator(configuration, "mirrorlist").url == "homepage"
def test_generate_mirrorlist(mirrorlist_generator: MirrorlistGenerator, mocker: MockerFixture) -> None:
"""
must correctly generate mirrorlist file
"""
write_mock = mocker.patch("pathlib.Path.write_text")
mirrorlist_generator._generate_mirrorlist(Path("local"))
write_mock.assert_called_once_with("Server = http://localhost\n", encoding="utf8")
def test_package(mirrorlist_generator: MirrorlistGenerator) -> None:
"""
must generate package function correctly
"""
assert mirrorlist_generator.package() == """{
install -Dm644 "$srcdir/mirrorlist" "$pkgdir/etc/pacman.d/aur-clone-mirrorlist"
}"""
def test_patches(mirrorlist_generator: MirrorlistGenerator) -> None:
"""
must generate additional patch list
"""
patches = {patch.key: patch for patch in mirrorlist_generator.patches()}
assert "backup" in patches
assert patches["backup"].value == [str(mirrorlist_generator.path)]
def test_sources(mirrorlist_generator: MirrorlistGenerator) -> None:
"""
must return valid sources files list
"""
assert mirrorlist_generator.sources().get("mirrorlist")

View File

@ -0,0 +1,141 @@
import datetime
import pytest
from pathlib import Path
from pytest_mock import MockerFixture
from unittest.mock import MagicMock, call as MockCall
from ahriman.core.support.pkgbuild.pkgbuild_generator import PkgbuildGenerator
from ahriman.core.util import utcnow
from ahriman.models.pkgbuild_patch import PkgbuildPatch
def test_license(pkgbuild_generator: PkgbuildGenerator) -> None:
"""
must return empty license list
"""
assert pkgbuild_generator.license == []
def test_pkgdesc(pkgbuild_generator: PkgbuildGenerator) -> None:
"""
must raise NotImplementedError on missing pkgdesc property
"""
with pytest.raises(NotImplementedError):
assert pkgbuild_generator.pkgdesc
def test_pkgname(pkgbuild_generator: PkgbuildGenerator) -> None:
"""
must raise NotImplementedError on missing pkgname property
"""
with pytest.raises(NotImplementedError):
assert pkgbuild_generator.pkgname
def test_pkgver(pkgbuild_generator: PkgbuildGenerator, mocker: MockerFixture) -> None:
"""
must implement default version as current date
"""
mocker.patch("ahriman.core.support.pkgbuild.pkgbuild_generator.utcnow", return_value=datetime.datetime(2002, 3, 11))
assert pkgbuild_generator.pkgver == utcnow().strftime("20020311")
def test_url(pkgbuild_generator: PkgbuildGenerator) -> None:
"""
must return empty url
"""
assert pkgbuild_generator.url == ""
def test_install(pkgbuild_generator: PkgbuildGenerator) -> None:
"""
must return empty install function
"""
assert pkgbuild_generator.install() is None
def test_package(pkgbuild_generator: PkgbuildGenerator) -> None:
"""
must raise NotImplementedError on missing package function
"""
with pytest.raises(NotImplementedError):
pkgbuild_generator.package()
def test_patches(pkgbuild_generator: PkgbuildGenerator) -> None:
"""
must return empty patches list
"""
assert pkgbuild_generator.patches() == []
def test_sources(pkgbuild_generator: PkgbuildGenerator) -> None:
"""
must return empty sources list
"""
assert pkgbuild_generator.sources() == {}
def test_write_install(pkgbuild_generator: PkgbuildGenerator, mocker: MockerFixture) -> None:
"""
must write install file
"""
mocker.patch.object(PkgbuildGenerator, "pkgname", "package")
mocker.patch("ahriman.core.support.pkgbuild.pkgbuild_generator.PkgbuildGenerator.install", return_value="content")
write_mock = mocker.patch("pathlib.Path.write_text")
assert pkgbuild_generator.write_install(Path("local")) == [PkgbuildPatch("install", "package.install")]
write_mock.assert_called_once_with("content")
def test_write_install_empty(pkgbuild_generator: PkgbuildGenerator) -> None:
"""
must return empty patch list for missing install function
"""
assert pkgbuild_generator.write_install(Path("local")) == []
def test_write_pkgbuild(pkgbuild_generator: PkgbuildGenerator, mocker: MockerFixture) -> None:
"""
must write PKGBUILD content to file
"""
path = Path("local")
for prop in ("pkgdesc", "pkgname"):
mocker.patch.object(PkgbuildGenerator, prop, "")
mocker.patch("ahriman.core.support.pkgbuild.pkgbuild_generator.PkgbuildGenerator.package", return_value="{}")
patches_mock = mocker.patch("ahriman.core.support.pkgbuild.pkgbuild_generator.PkgbuildGenerator.patches",
return_value=[PkgbuildPatch("property", "value")])
install_mock = mocker.patch("ahriman.core.support.pkgbuild.pkgbuild_generator.PkgbuildGenerator.write_install",
return_value=[PkgbuildPatch("install", "pkgname.install")])
sources_mock = mocker.patch("ahriman.core.support.pkgbuild.pkgbuild_generator.PkgbuildGenerator.write_sources",
return_value=[PkgbuildPatch("source", []), PkgbuildPatch("sha512sums", [])])
write_mock = mocker.patch("ahriman.models.pkgbuild_patch.PkgbuildPatch.write")
pkgbuild_generator.write_pkgbuild(path)
patches_mock.assert_called_once_with()
install_mock.assert_called_once_with(path)
sources_mock.assert_called_once_with(path)
write_mock.assert_has_calls([MockCall(path / "PKGBUILD")] * 12)
def test_write_sources(pkgbuild_generator: PkgbuildGenerator, mocker: MockerFixture) -> None:
"""
must write sources files
"""
path = Path("local")
generator_mock = MagicMock()
sources_mock = mocker.patch("ahriman.core.support.pkgbuild.pkgbuild_generator.PkgbuildGenerator.sources",
return_value={"source": generator_mock})
open_mock = mocker.patch("pathlib.Path.open")
hash_mock = MagicMock()
hash_mock.hexdigest.return_value = "hash"
mocker.patch("hashlib.sha512", return_value=hash_mock)
assert pkgbuild_generator.write_sources(path) == [
PkgbuildPatch("source", ["source"]),
PkgbuildPatch("sha512sums", ["hash"]),
]
generator_mock.assert_called_once_with(path / "source")
sources_mock.assert_called_once_with()
open_mock.assert_called_once_with("rb")

View File

@ -0,0 +1,30 @@
from pytest_mock import MockerFixture
from ahriman.core.configuration import Configuration
from ahriman.core.sign.gpg import GPG
from ahriman.core.support import KeyringTrigger
from ahriman.models.context_key import ContextKey
def test_configuration_sections(configuration: Configuration) -> None:
"""
must correctly parse target list
"""
configuration.set_option("keyring", "target", "a b c")
assert KeyringTrigger.configuration_sections(configuration) == ["a", "b", "c"]
configuration.remove_option("keyring", "target")
assert KeyringTrigger.configuration_sections(configuration) == []
def test_on_start(configuration: Configuration, mocker: MockerFixture) -> None:
"""
must run report for specified targets
"""
gpg_mock = mocker.patch("ahriman.core._Context.get")
run_mock = mocker.patch("ahriman.core.support.package_creator.PackageCreator.run")
trigger = KeyringTrigger("x86_64", configuration)
trigger.on_start()
gpg_mock.assert_called_once_with(ContextKey("sign", GPG))
run_mock.assert_called_once_with()

View File

@ -0,0 +1,26 @@
from pytest_mock import MockerFixture
from ahriman.core.configuration import Configuration
from ahriman.core.support import MirrorlistTrigger
def test_configuration_sections(configuration: Configuration) -> None:
"""
must correctly parse target list
"""
configuration.set_option("mirrorlist", "target", "a b c")
assert MirrorlistTrigger.configuration_sections(configuration) == ["a", "b", "c"]
configuration.remove_option("mirrorlist", "target")
assert MirrorlistTrigger.configuration_sections(configuration) == []
def test_on_start(configuration: Configuration, mocker: MockerFixture) -> None:
"""
must run report for specified targets
"""
run_mock = mocker.patch("ahriman.core.support.package_creator.PackageCreator.run")
trigger = MirrorlistTrigger("x86_64", configuration)
trigger.on_start()
run_mock.assert_called_once_with()

View File

@ -0,0 +1,40 @@
import pytest
from pytest_mock import MockerFixture
from ahriman.core.database import SQLite
from ahriman.core.support.package_creator import PackageCreator
from ahriman.models.context_key import ContextKey
from ahriman.models.package import Package
from ahriman.models.package_description import PackageDescription
def test_run(package_creator: PackageCreator, database: SQLite, mocker: MockerFixture) -> None:
"""
must correctly process package creation
"""
package = Package(
base=package_creator.generator.pkgname,
version=package_creator.generator.pkgver,
remote=None,
packages={package_creator.generator.pkgname: PackageDescription()},
)
local_path = package_creator.configuration.repository_paths.cache_for(package_creator.generator.pkgname)
rmtree_mock = mocker.patch("shutil.rmtree")
database_mock = mocker.patch("ahriman.core._Context.get", return_value=database)
init_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.init")
insert_mock = mocker.patch("ahriman.core.database.SQLite.package_update")
mkdir_mock = mocker.patch("pathlib.Path.mkdir")
package_mock = mocker.patch("ahriman.models.package.Package.from_build", return_value=package)
write_mock = mocker.patch("ahriman.core.support.pkgbuild.pkgbuild_generator.PkgbuildGenerator.write_pkgbuild")
package_creator.run()
rmtree_mock.assert_called_once_with(local_path, ignore_errors=True)
mkdir_mock.assert_called_once_with(mode=0o755, parents=True, exist_ok=True)
write_mock.assert_called_once_with(local_path)
init_mock.assert_called_once_with(local_path)
package_mock.assert_called_once_with(local_path, "x86_64")
database_mock.assert_called_once_with(ContextKey("database", SQLite))
insert_mock.assert_called_once_with(package, pytest.helpers.anyvar(int))

View File

@ -12,7 +12,8 @@ from unittest.mock import MagicMock
from ahriman.core.exceptions import BuildError, OptionError, UnsafeRunError
from ahriman.core.util import check_output, check_user, enum_values, exception_response_text, filter_json, \
full_version, package_like, partition, pretty_datetime, pretty_size, safe_filename, trim_package, utcnow, walk
full_version, package_like, partition, pretty_datetime, pretty_size, safe_filename, srcinfo_property, \
srcinfo_property_list, trim_package, utcnow, walk
from ahriman.models.package import Package
from ahriman.models.package_source import PackageSource
from ahriman.models.repository_paths import RepositoryPaths
@ -81,12 +82,12 @@ def test_check_output_with_user(passwd: Any, mocker: MockerFixture) -> None:
"""
must run command as specified user and set its homedir
"""
assert check_output("python", "-c", "import os; print(os.getenv('HOME'))") != passwd.pw_dir
assert check_output("python", "-c", """import os; print(os.getenv("HOME"))""") != passwd.pw_dir
getpwuid_mock = mocker.patch("ahriman.core.util.getpwuid", return_value=passwd)
user = os.getuid()
assert check_output("python", "-c", "import os; print(os.getenv('HOME'))", user=user) == passwd.pw_dir
assert check_output("python", "-c", """import os; print(os.getenv("HOME"))""", user=user) == passwd.pw_dir
getpwuid_mock.assert_called_once_with(user)
@ -331,6 +332,31 @@ def test_safe_filename() -> None:
assert safe_filename("tolua++-1.0.93-4-x86_64.pkg.tar.zst") == "tolua---1.0.93-4-x86_64.pkg.tar.zst"
def test_srcinfo_property() -> None:
"""
must correctly extract properties
"""
assert srcinfo_property("key", {"key": "root"}, {"key": "overrides"}, default="default") == "overrides"
assert srcinfo_property("key", {"key": "root"}, {}, default="default") == "root"
assert srcinfo_property("key", {}, {"key": "overrides"}, default="default") == "overrides"
assert srcinfo_property("key", {}, {}, default="default") == "default"
assert srcinfo_property("key", {}, {}) is None
def test_srcinfo_property_list() -> None:
"""
must correctly extract property list
"""
assert srcinfo_property_list("key", {"key": ["root"]}, {"key": ["overrides"]}) == ["overrides"]
assert srcinfo_property_list("key", {"key": ["root"]}, {"key_x86_64": ["overrides"]}, architecture="x86_64") == [
"root", "overrides"
]
assert srcinfo_property_list("key", {"key": ["root"], "key_x86_64": ["overrides"]}, {}, architecture="x86_64") == [
"root", "overrides"
]
assert srcinfo_property_list("key", {"key_x86_64": ["overrides"]}, {}, architecture="x86_64") == ["overrides"]
def test_trim_package() -> None:
"""
must trim package version

View File

@ -11,6 +11,17 @@ from ahriman.models.package import Package
from ahriman.models.result import Result
def test_known_triggers(configuration: Configuration) -> None:
"""
must return used triggers
"""
configuration.set_option("build", "triggers_known", "a b c")
assert TriggerLoader.known_triggers(configuration) == ["a", "b", "c"]
configuration.remove_option("build", "triggers_known")
assert TriggerLoader.known_triggers(configuration) == []
def test_selected_triggers(configuration: Configuration) -> None:
"""
must return used triggers

View File

@ -2,6 +2,7 @@ import pytest
from pathlib import Path
from pytest_mock import MockerFixture
from srcinfo.parse import parse_srcinfo
from unittest.mock import MagicMock
from ahriman.core.alpm.pacman import Pacman
@ -165,7 +166,7 @@ def test_from_build(package_ahriman: Package, mocker: MockerFixture, resource_pa
package = Package.from_build(Path("path"), "x86_64")
assert package_ahriman.packages.keys() == package.packages.keys()
package_ahriman.packages = package.packages # we are not going to test PackageDescription here
package_ahriman.remote = None
package_ahriman.remote = package.remote
assert package_ahriman == package
@ -269,6 +270,70 @@ def test_from_official(package_ahriman: Package, aur_package_ahriman: AURPackage
assert package_ahriman.packages.keys() == package.packages.keys()
def test_local_files(mocker: MockerFixture, resource_path_root: Path) -> None:
"""
must extract local file sources
"""
srcinfo = (resource_path_root / "models" / "package_yay_srcinfo").read_text()
parsed_srcinfo, _ = parse_srcinfo(srcinfo)
parsed_srcinfo["source"] = ["local-file.tar.gz"]
mocker.patch("ahriman.models.package.parse_srcinfo", return_value=(parsed_srcinfo, []))
mocker.patch("ahriman.models.package.Package._check_output", return_value=srcinfo)
mocker.patch("ahriman.models.package.Package.supported_architectures", return_value=["any"])
assert list(Package.local_files(Path("path"))) == [Path("local-file.tar.gz")]
def test_local_files_empty(mocker: MockerFixture, resource_path_root: Path) -> None:
"""
must extract empty local files list when there is no local files
"""
srcinfo = (resource_path_root / "models" / "package_yay_srcinfo").read_text()
mocker.patch("ahriman.models.package.Package._check_output", return_value=srcinfo)
mocker.patch("ahriman.models.package.Package.supported_architectures", return_value=["any"])
assert list(Package.local_files(Path("path"))) == []
def test_local_files_error(mocker: MockerFixture, resource_path_root: Path) -> None:
"""
must raise exception on package parsing for local sources
"""
mocker.patch("ahriman.models.package.Package._check_output", return_value="")
mocker.patch("ahriman.models.package.parse_srcinfo", return_value=({"packages": {}}, ["an error"]))
with pytest.raises(PackageInfoError):
list(Package.local_files(Path("path")))
def test_local_files_schema(mocker: MockerFixture, resource_path_root: Path) -> None:
"""
must skip local file source when file schema is used
"""
srcinfo = (resource_path_root / "models" / "package_yay_srcinfo").read_text()
parsed_srcinfo, _ = parse_srcinfo(srcinfo)
parsed_srcinfo["source"] = ["file:///local-file.tar.gz"]
mocker.patch("ahriman.models.package.parse_srcinfo", return_value=(parsed_srcinfo, []))
mocker.patch("ahriman.models.package.Package._check_output", return_value="")
mocker.patch("ahriman.models.package.Package.supported_architectures", return_value=["any"])
assert list(Package.local_files(Path("path"))) == []
def test_local_files_with_install(mocker: MockerFixture, resource_path_root: Path) -> None:
"""
must extract local file sources with install file
"""
srcinfo = (resource_path_root / "models" / "package_yay_srcinfo").read_text()
parsed_srcinfo, _ = parse_srcinfo(srcinfo)
parsed_srcinfo["install"] = "install"
mocker.patch("ahriman.models.package.parse_srcinfo", return_value=(parsed_srcinfo, []))
mocker.patch("ahriman.models.package.Package._check_output", return_value="")
mocker.patch("ahriman.models.package.Package.supported_architectures", return_value=["any"])
assert list(Package.local_files(Path("path"))) == [Path("install")]
def test_supported_architectures(mocker: MockerFixture, resource_path_root: Path) -> None:
"""
must generate list of available architectures

View File

@ -25,6 +25,7 @@ ignore_packages =
makechrootpkg_flags =
makepkg_flags = --skippgpcheck
triggers = ahriman.core.report.ReportTrigger ahriman.core.upload.UploadTrigger
triggers_known = ahriman.core.support.KeyringTrigger ahriman.core.support.MirrorlistTrigger
[repository]
name = aur-clone
@ -33,6 +34,13 @@ root = ../../../
[sign]
target =
[keyring]
target = keyring
[mirrorlist]
target = mirrorlist
servers = http://localhost
[remote-push]
target = gitremote