add configurable exit codes to some commands (#55)

This commit is contained in:
Evgenii Alekseev 2022-04-01 18:30:11 +03:00 committed by GitHub
parent a132b1544a
commit d5503b22ba
22 changed files with 279 additions and 28 deletions

View File

@ -36,6 +36,7 @@ if [ -n "$AHRIMAN_API_USER" ]; then
# python getpass does not read from stdin
# see thread https://mail.python.org/pipermail/python-dev/2008-February/077235.html
# WARNING with debug mode password will be put to stdout
ahriman "${AHRIMAN_DEFAULT_ARGS[@]}" user-list --error-on-empty "$AHRIMAN_API_USER" > /dev/null ||
ahriman "${AHRIMAN_DEFAULT_ARGS[@]}" user-add --as-service --role write --secure "$AHRIMAN_API_USER" -p "$(openssl rand -base64 20)"
fi

View File

@ -112,6 +112,7 @@ def _set_aur_search_parser(root: SubParserAction) -> argparse.ArgumentParser:
description="search for package in AUR using API", formatter_class=_formatter)
parser.add_argument("search", help="search terms, can be specified multiple times, result will match all terms",
nargs="+")
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
parser.add_argument("-i", "--info", help="show additional package information", action="store_true")
parser.add_argument("--sort-by", help="sort field by this field. In case if two packages have the same value of "
"the specified field, they will be always sorted by name",
@ -189,6 +190,7 @@ def _set_package_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
"5) and finally you can add package from AUR.",
formatter_class=_formatter)
parser.add_argument("package", help="package source (base name, path to local files, remote URL)", nargs="+")
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
parser.add_argument("-n", "--now", help="run update function after", action="store_true")
parser.add_argument("-s", "--source", help="explicitly specify the package source for this command",
type=PackageSource, choices=PackageSource, default=PackageSource.Auto)
@ -222,6 +224,7 @@ def _set_package_status_parser(root: SubParserAction) -> argparse.ArgumentParser
formatter_class=_formatter)
parser.add_argument("package", help="filter status by package base", nargs="*")
parser.add_argument("--ahriman", help="get service status itself", action="store_true")
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
parser.add_argument("-i", "--info", help="show additional package information", action="store_true")
parser.add_argument("-s", "--status", help="filter packages by status",
type=BuildStatusEnum, choices=BuildStatusEnum)
@ -293,6 +296,7 @@ def _set_patch_list_parser(root: SubParserAction) -> argparse.ArgumentParser:
parser = root.add_parser("patch-list", help="list patch sets",
description="list available patches for the package", formatter_class=_formatter)
parser.add_argument("package", help="package base", nargs="?")
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
parser.set_defaults(handler=handlers.Patch, action=Action.List, architecture=[""], lock=None, no_report=True)
return parser
@ -320,6 +324,7 @@ def _set_repo_check_parser(root: SubParserAction) -> argparse.ArgumentParser:
description="check for packages updates. Same as update --dry-run --no-manual",
formatter_class=_formatter)
parser.add_argument("package", help="filter check by package base", nargs="*")
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
parser.add_argument("--no-vcs", help="do not check VCS packages", action="store_true")
parser.set_defaults(handler=handlers.Update, dry_run=True, no_aur=False, no_local=False, no_manual=True)
return parser
@ -369,6 +374,7 @@ def _set_repo_rebuild_parser(root: SubParserAction) -> argparse.ArgumentParser:
parser.add_argument("--depends-on", help="only rebuild packages that depend on specified package", action="append")
parser.add_argument("--dry-run", help="just perform check for packages without rebuild process itself",
action="store_true")
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
parser.set_defaults(handler=handlers.Rebuild)
return parser
@ -484,6 +490,7 @@ def _set_repo_update_parser(root: SubParserAction) -> argparse.ArgumentParser:
formatter_class=_formatter)
parser.add_argument("package", help="filter check by package base", nargs="*")
parser.add_argument("--dry-run", help="just perform check for updates, same as check command", action="store_true")
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
parser.add_argument("--no-aur", help="do not check for AUR updates. Implies --no-vcs", action="store_true")
parser.add_argument("--no-local", help="do not check local packages for updates", action="store_true")
parser.add_argument("--no-manual", help="do not include manual updates", action="store_true")
@ -524,6 +531,7 @@ def _set_user_list_parser(root: SubParserAction) -> argparse.ArgumentParser:
description="list users from the user mapping and their roles",
formatter_class=_formatter)
parser.add_argument("username", help="filter users by username", nargs="?")
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
parser.add_argument("-r", "--role", help="filter users by role", type=UserAccess, choices=UserAccess)
parser.set_defaults(handler=handlers.User, action=Action.List, architecture=[""], lock=None, no_report=True, # nosec
password="", quiet=True, unsafe=True)

View File

@ -132,7 +132,7 @@ class Repository(Properties):
result.extend(unknown_aur(package)) # local package not found
return result
def update(self, updates: Iterable[Package]) -> None:
def update(self, updates: Iterable[Package]) -> Result:
"""
run package updates
:param updates: list of packages to update
@ -144,8 +144,9 @@ class Repository(Properties):
self._finalize(result.merge(update_result))
# process built packages
build_result = Result()
packages = self.repository.packages_built()
process_update(packages, Result())
process_update(packages, build_result)
# process manual packages
tree = Tree.load(updates, self.database)
@ -155,6 +156,8 @@ class Repository(Properties):
packages = self.repository.packages_built()
process_update(packages, build_result)
return build_result
def updates(self, filter_packages: Iterable[str], no_aur: bool, no_local: bool, no_manual: bool, no_vcs: bool,
log_fn: Callable[[str], None]) -> List[Package]:
"""

View File

@ -48,4 +48,5 @@ class Add(Handler):
return
packages = application.updates(args.package, True, True, False, True, application.logger.info)
application.update(packages)
result = application.update(packages)
Add.check_if_empty(args.exit_code, result.is_empty)

View File

@ -119,3 +119,13 @@ class Handler:
:param unsafe: if set no user check will be performed before path creation
"""
raise NotImplementedError
@staticmethod
def check_if_empty(enabled: bool, predicate: bool) -> None:
"""
check condition and flag and raise ExitCode exception in case if it is enabled and condition match
:param enabled: if False no check will be performed
:param predicate: indicates condition on which exception should be thrown
"""
if enabled and predicate:
raise ExitCode()

View File

@ -51,7 +51,7 @@ class Patch(Handler):
application = Application(architecture, configuration, no_report, unsafe)
if args.action == Action.List:
Patch.patch_set_list(application, args.package)
Patch.patch_set_list(application, args.package, args.exit_code)
elif args.action == Action.Remove:
Patch.patch_set_remove(application, args.package)
elif args.action == Action.Update:
@ -71,13 +71,16 @@ class Patch(Handler):
application.database.patches_insert(package.base, patch)
@staticmethod
def patch_set_list(application: Application, package_base: Optional[str]) -> None:
def patch_set_list(application: Application, package_base: Optional[str], exit_code: bool) -> None:
"""
list patches available for the package base
:param application: application instance
:param package_base: package base
:param exit_code: raise ExitCode on empty search result
"""
patches = application.database.patches_list(package_base)
Patch.check_if_empty(exit_code, not patches)
for base, patch in patches.items():
content = base if package_base is None else patch
StringPrinter(content).print(verbose=True)

View File

@ -47,9 +47,12 @@ class Rebuild(Handler):
application = Application(architecture, configuration, no_report, unsafe)
updates = application.repository.packages_depends_on(depends_on)
Rebuild.check_if_empty(args.exit_code, not updates)
if args.dry_run:
for package in updates:
UpdatePrinter(package, package.version).print(verbose=True)
return
application.update(updates)
result = application.update(updates)
Rebuild.check_if_empty(args.exit_code, result.is_empty)

View File

@ -45,6 +45,7 @@ class RemoveUnknown(Handler):
"""
application = Application(architecture, configuration, no_report, unsafe)
unknown_packages = application.unknown()
if args.dry_run:
for package in sorted(unknown_packages):
StringPrinter(package).print(args.info)

View File

@ -37,8 +37,7 @@ class Search(Handler):
"""
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
# later we will have to remove some fields from here (lists)
SORT_FIELDS = {pair.name for pair in fields(AURPackage)}
SORT_FIELDS = {field.name for field in fields(AURPackage) if field.default_factory is not list}
@classmethod
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
@ -52,6 +51,7 @@ class Search(Handler):
:param unsafe: if set no user check will be performed before path creation
"""
packages_list = AUR.multisearch(*args.search)
Search.check_if_empty(args.exit_code, not packages_list)
for package in Search.sort(packages_list, args.sort_by):
AurPrinter(package).print(args.info)

View File

@ -60,6 +60,8 @@ class Status(Handler):
else:
packages = client.get(None)
Status.check_if_empty(args.exit_code, not packages)
comparator: Callable[[Tuple[Package, BuildStatus]], str] = lambda item: item[0].base
filter_fn: Callable[[Tuple[Package, BuildStatus]], bool] =\
lambda item: args.status is None or item[1].status == args.status

View File

@ -45,10 +45,12 @@ class Update(Handler):
application = Application(architecture, configuration, no_report, unsafe)
packages = application.updates(args.package, args.no_aur, args.no_local, args.no_manual, args.no_vcs,
Update.log_fn(application, args.dry_run))
Update.check_if_empty(args.exit_code, not packages)
if args.dry_run:
return
application.update(packages)
result = application.update(packages)
Update.check_if_empty(args.exit_code, result.is_empty)
@staticmethod
def log_fn(application: Application, dry_run: bool) -> Callable[[str], None]:

View File

@ -60,8 +60,10 @@ class User(Handler):
User.configuration_create(auth_configuration, user, salt, args.as_service, args.secure)
database.user_update(user.hash_password(salt))
elif args.action == Action.List:
for found_user in database.user_list(args.username, args.access):
UserPrinter(found_user).print(verbose=True)
users = database.user_list(args.username, args.role)
User.check_if_empty(args.exit_code, not users)
for user in users:
UserPrinter(user).print(verbose=True)
elif args.action == Action.Remove:
database.user_remove(args.username)

View File

@ -48,6 +48,13 @@ class Result:
"""
return list(self._failed.values())
@property
def is_empty(self) -> bool:
"""
:return: True in case if success list is empty and False otherwise
"""
return not bool(self._success)
@property
def success(self) -> List[Package]:
"""

View File

@ -136,3 +136,14 @@ def test_run(args: argparse.Namespace, configuration: Configuration) -> None:
"""
with pytest.raises(NotImplementedError):
Handler.run(args, "x86_64", configuration, True, True)
def test_check_if_empty() -> None:
"""
must raise exception in case if predicate is True and enabled
"""
Handler.check_if_empty(False, False)
Handler.check_if_empty(True, False)
Handler.check_if_empty(False, True)
with pytest.raises(ExitCode):
Handler.check_if_empty(True, True)

View File

@ -7,6 +7,7 @@ from ahriman.application.handlers import Add
from ahriman.core.configuration import Configuration
from ahriman.models.package import Package
from ahriman.models.package_source import PackageSource
from ahriman.models.result import Result
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
@ -16,6 +17,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
:return: generated arguments for these test cases
"""
args.package = []
args.exit_code = False
args.now = False
args.source = PackageSource.Auto
args.without_dependencies = False
@ -41,11 +43,32 @@ def test_run_with_updates(args: argparse.Namespace, configuration: Configuration
"""
args = _default_args(args)
args.now = True
result = Result()
result.add_success(package_ahriman)
mocker.patch("ahriman.application.application.Application.add")
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
application_mock = mocker.patch("ahriman.application.application.Application.update")
application_mock = mocker.patch("ahriman.application.application.Application.update", return_value=result)
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_if_empty")
updates_mock = mocker.patch("ahriman.application.application.Application.updates", return_value=[package_ahriman])
Add.run(args, "x86_64", configuration, True, False)
updates_mock.assert_called_once_with(args.package, True, True, False, True, pytest.helpers.anyvar(int))
application_mock.assert_called_once_with([package_ahriman])
check_mock.assert_called_once_with(False, False)
def test_run_empty_exception(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
"""
must raise ExitCode exception on empty result
"""
args = _default_args(args)
args.now = True
args.exit_code = True
mocker.patch("ahriman.application.application.Application.add")
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
mocker.patch("ahriman.application.application.Application.update", return_value=Result())
mocker.patch("ahriman.application.application.Application.updates")
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_if_empty")
Add.run(args, "x86_64", configuration, True, False)
check_mock.assert_called_once_with(True, True)

View File

@ -1,7 +1,6 @@
import argparse
import pytest
from pathlib import Path
from pytest_mock import MockerFixture
from ahriman.application.application import Application
@ -18,6 +17,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
:return: generated arguments for these test cases
"""
args.package = "ahriman"
args.exit_code = False
args.remove = False
args.track = ["*.diff", "*.patch"]
return args
@ -46,7 +46,7 @@ def test_run_list(args: argparse.Namespace, configuration: Configuration, mocker
application_mock = mocker.patch("ahriman.application.handlers.patch.Patch.patch_set_list")
Patch.run(args, "x86_64", configuration, True, False)
application_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.package)
application_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.package, False)
def test_run_remove(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
@ -66,25 +66,25 @@ def test_patch_set_list(application: Application, mocker: MockerFixture) -> None
"""
must list available patches for the command
"""
mocker.patch("pathlib.Path.is_dir", return_value=True)
get_mock = mocker.patch("ahriman.core.database.sqlite.SQLite.patches_list", return_value={"ahriman": "patch"})
print_mock = mocker.patch("ahriman.core.formatters.printer.Printer.print")
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_if_empty")
Patch.patch_set_list(application, "ahriman")
Patch.patch_set_list(application, "ahriman", False)
get_mock.assert_called_once_with("ahriman")
print_mock.assert_called_once_with(verbose=True)
check_mock.assert_called_once_with(False, False)
def test_patch_set_list_no_patches(application: Application, mocker: MockerFixture) -> None:
def test_patch_set_list_empty_exception(application: Application, mocker: MockerFixture) -> None:
"""
must not fail if no patches directory found
must raise ExitCode exception on empty patch list
"""
mocker.patch("pathlib.Path.is_dir", return_value=False)
mocker.patch("ahriman.core.database.sqlite.SQLite.patches_get", return_value=None)
print_mock = mocker.patch("ahriman.core.formatters.printer.Printer.print")
mocker.patch("ahriman.core.database.sqlite.SQLite.patches_list", return_value={})
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_if_empty")
Patch.patch_set_list(application, "ahriman")
print_mock.assert_not_called()
Patch.patch_set_list(application, "ahriman", True)
check_mock.assert_called_once_with(True, True)
def test_patch_set_create(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None:

View File

@ -1,10 +1,13 @@
import argparse
import pytest
from pytest_mock import MockerFixture
from unittest import mock
from ahriman.application.handlers import Rebuild
from ahriman.core.configuration import Configuration
from ahriman.models.package import Package
from ahriman.models.result import Result
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
@ -15,6 +18,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
"""
args.depends_on = []
args.dry_run = False
args.exit_code = False
return args
@ -24,14 +28,18 @@ def test_run(args: argparse.Namespace, package_ahriman: Package,
must run command
"""
args = _default_args(args)
result = Result()
result.add_success(package_ahriman)
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
application_packages_mock = mocker.patch("ahriman.core.repository.repository.Repository.packages_depends_on",
return_value=[package_ahriman])
application_mock = mocker.patch("ahriman.application.application.Application.update")
application_mock = mocker.patch("ahriman.application.application.Application.update", return_value=result)
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_if_empty")
Rebuild.run(args, "x86_64", configuration, True, False)
application_packages_mock.assert_called_once_with(None)
application_mock.assert_called_once_with([package_ahriman])
check_mock.assert_has_calls([mock.call(False, False), mock.call(False, False)])
def test_run_dry_run(args: argparse.Namespace, configuration: Configuration,
@ -44,9 +52,11 @@ def test_run_dry_run(args: argparse.Namespace, configuration: Configuration,
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
mocker.patch("ahriman.core.repository.repository.Repository.packages_depends_on", return_value=[package_ahriman])
application_mock = mocker.patch("ahriman.application.application.Application.update")
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_if_empty")
Rebuild.run(args, "x86_64", configuration, True, False)
application_mock.assert_not_called()
check_mock.assert_called_once_with(False, False)
def test_run_filter(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
@ -74,3 +84,35 @@ def test_run_without_filter(args: argparse.Namespace, configuration: Configurati
Rebuild.run(args, "x86_64", configuration, True, False)
application_packages_mock.assert_called_once_with(None)
def test_run_update_empty_exception(args: argparse.Namespace, configuration: Configuration,
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.models.repository_paths.RepositoryPaths.tree_create")
mocker.patch("ahriman.core.repository.repository.Repository.packages_depends_on", return_value=[])
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_if_empty")
Rebuild.run(args, "x86_64", configuration, True, False)
check_mock.assert_called_once_with(True, True)
def test_run_build_empty_exception(args: argparse.Namespace, configuration: Configuration,
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.models.repository_paths.RepositoryPaths.tree_create")
mocker.patch("ahriman.core.repository.repository.Repository.packages_depends_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_if_empty")
Rebuild.run(args, "x86_64", configuration, True, False)
check_mock.assert_has_calls([mock.call(True, False), mock.call(True, True)])

View File

@ -17,6 +17,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
:return: generated arguments for these test cases
"""
args.search = ["ahriman"]
args.exit_code = False
args.info = False
args.sort_by = "name"
return args
@ -29,13 +30,29 @@ def test_run(args: argparse.Namespace, configuration: Configuration, aur_package
"""
args = _default_args(args)
search_mock = mocker.patch("ahriman.core.alpm.aur.AUR.multisearch", return_value=[aur_package_ahriman])
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_if_empty")
print_mock = mocker.patch("ahriman.core.formatters.printer.Printer.print")
Search.run(args, "x86_64", configuration, True, False)
search_mock.assert_called_once_with("ahriman")
check_mock.assert_called_once_with(False, False)
print_mock.assert_called_once_with(False)
def test_run_empty_exception(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
"""
must run command
"""
args = _default_args(args)
args.exit_code = True
mocker.patch("ahriman.core.alpm.aur.AUR.multisearch", return_value=[])
mocker.patch("ahriman.core.formatters.printer.Printer.print")
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_if_empty")
Search.run(args, "x86_64", configuration, True, False)
check_mock.assert_called_once_with(True, True)
def test_run_sort(args: argparse.Namespace, configuration: Configuration, aur_package_ahriman: AURPackage,
mocker: MockerFixture) -> None:
"""
@ -95,5 +112,5 @@ def test_sort_fields() -> None:
"""
must store valid field list which are allowed to be used for sorting
"""
expected = {pair.name for pair in dataclasses.fields(AURPackage)}
expected = {field.name for field in dataclasses.fields(AURPackage)}
assert all(field in expected for field in Search.SORT_FIELDS)

View File

@ -16,6 +16,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
:return: generated arguments for these test cases
"""
args.ahriman = True
args.exit_code = False
args.info = False
args.package = []
args.status = None
@ -33,14 +34,31 @@ def test_run(args: argparse.Namespace, configuration: Configuration, package_ahr
packages_mock = mocker.patch("ahriman.core.status.client.Client.get",
return_value=[(package_ahriman, BuildStatus(BuildStatusEnum.Success)),
(package_python_schedule, BuildStatus(BuildStatusEnum.Failed))])
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_if_empty")
print_mock = mocker.patch("ahriman.core.formatters.printer.Printer.print")
Status.run(args, "x86_64", configuration, True, False)
application_mock.assert_called_once_with()
packages_mock.assert_called_once_with(None)
check_mock.assert_called_once_with(False, False)
print_mock.assert_has_calls([mock.call(False) for _ in range(3)])
def test_run_empty_exception(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
"""
must raise ExitCode exception on empty status result
"""
args = _default_args(args)
args.exit_code = True
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
mocker.patch("ahriman.core.status.client.Client.get_self")
mocker.patch("ahriman.core.status.client.Client.get", return_value=[])
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_if_empty")
Status.run(args, "x86_64", configuration, True, False)
check_mock.assert_called_once_with(True, True)
def test_run_verbose(args: argparse.Namespace, configuration: Configuration, package_ahriman: Package,
mocker: MockerFixture) -> None:
"""

View File

@ -2,11 +2,13 @@ import argparse
import pytest
from pytest_mock import MockerFixture
from unittest import mock
from ahriman.application.application import Application
from ahriman.application.handlers import Update
from ahriman.core.configuration import Configuration
from ahriman.models.package import Package
from ahriman.models.result import Result
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
@ -17,6 +19,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
"""
args.package = []
args.dry_run = False
args.exit_code = False
args.no_aur = False
args.no_local = False
args.no_manual = False
@ -30,14 +33,49 @@ def test_run(args: argparse.Namespace, package_ahriman: Package,
must run command
"""
args = _default_args(args)
result = Result()
result.add_success(package_ahriman)
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
application_mock = mocker.patch("ahriman.application.application.Application.update")
application_mock = mocker.patch("ahriman.application.application.Application.update", return_value=result)
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_if_empty")
updates_mock = mocker.patch("ahriman.application.application.Application.updates", return_value=[package_ahriman])
Update.run(args, "x86_64", configuration, True, False)
application_mock.assert_called_once_with([package_ahriman])
updates_mock.assert_called_once_with(args.package, args.no_aur, args.no_local, args.no_manual, args.no_vcs,
pytest.helpers.anyvar(int))
check_mock.assert_has_calls([mock.call(False, False), mock.call(False, False)])
def test_run_empty_exception(args: argparse.Namespace, configuration: Configuration, 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.models.repository_paths.RepositoryPaths.tree_create")
mocker.patch("ahriman.application.application.Application.updates", return_value=[])
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_if_empty")
Update.run(args, "x86_64", configuration, True, False)
check_mock.assert_called_once_with(True, True)
def test_run_update_empty_exception(args: argparse.Namespace, package_ahriman: Package,
configuration: Configuration, mocker: MockerFixture) -> None:
"""
must raise ExitCode exception on empty build result
"""
args = _default_args(args)
args.exit_code = True
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
mocker.patch("ahriman.application.application.Application.update", return_value=Result())
mocker.patch("ahriman.application.application.Application.updates", return_value=[package_ahriman])
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_if_empty")
Update.run(args, "x86_64", configuration, True, False)
check_mock.assert_has_calls([mock.call(True, False), mock.call(True, True)])
def test_run_dry_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
@ -47,11 +85,15 @@ def test_run_dry_run(args: argparse.Namespace, configuration: Configuration, moc
args = _default_args(args)
args.dry_run = True
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
application_mock = mocker.patch("ahriman.application.application.Application.update")
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_if_empty")
updates_mock = mocker.patch("ahriman.application.application.Application.updates")
Update.run(args, "x86_64", configuration, True, False)
updates_mock.assert_called_once_with(args.package, args.no_aur, args.no_local, args.no_manual, args.no_vcs,
pytest.helpers.anyvar(int))
application_mock.assert_not_called()
check_mock.assert_called_once_with(False, pytest.helpers.anyvar(int))
def test_log_fn(application: Application, mocker: MockerFixture) -> None:

View File

@ -22,6 +22,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
args.username = "user"
args.action = Action.Update
args.as_service = False
args.exit_code = False
args.password = "pa55w0rd"
args.role = UserAccess.Read
args.secure = False
@ -58,12 +59,29 @@ def test_run_list(args: argparse.Namespace, configuration: Configuration, databa
"""
args = _default_args(args)
args.action = Action.List
args.access = None
mocker.patch("ahriman.core.database.sqlite.SQLite.load", return_value=database)
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_if_empty")
list_mock = mocker.patch("ahriman.core.database.sqlite.SQLite.user_list", return_value=[user])
User.run(args, "x86_64", configuration, True, False)
list_mock.assert_called_once_with("user", None)
list_mock.assert_called_once_with("user", args.role)
check_mock.assert_called_once_with(False, False)
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.SQLite.load", return_value=database)
mocker.patch("ahriman.core.database.sqlite.SQLite.user_list", return_value=[])
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_if_empty")
User.run(args, "x86_64", configuration, True, False)
check_mock.assert_called_once_with(True, True)
def test_run_remove(args: argparse.Namespace, configuration: Configuration, database: SQLite,

View File

@ -5,6 +5,43 @@ from ahriman.models.package import Package
from ahriman.models.result import Result
def test_is_empty() -> None:
"""
must return is empty for empty builds
"""
result = Result()
assert result.is_empty
def test_non_empty_success(package_ahriman: Package) -> None:
"""
must be non-empty if there is success build
"""
result = Result()
result.add_success(package_ahriman)
assert not result.is_empty
def test_is_empty_failed(package_ahriman: Package) -> None:
"""
must be empty if there is only failed build
"""
result = Result()
result.add_failed(package_ahriman)
assert result.is_empty
def test_non_empty_full(package_ahriman: Package) -> None:
"""
must be non-empty if there are both failed and success builds
"""
result = Result()
result.add_failed(package_ahriman)
result.add_success(package_ahriman)
assert not result.is_empty
def test_add_failed(package_ahriman: Package) -> None:
"""
must add package to failed list