update tests

This commit is contained in:
Evgenii Alekseev 2023-08-29 04:48:41 +03:00
parent 32b00de42c
commit 812bf07803
90 changed files with 1172 additions and 581 deletions

View File

@ -36,9 +36,9 @@ systemd-machine-id-setup
# initial setup command as root
[[ -z $MINIMAL_INSTALL ]] && WEB_ARGS=("--web-port" "8080")
ahriman -a x86_64 service-setup --packager "ahriman bot <ahriman@example.com>" --repository "github" "${WEB_ARGS[@]}"
ahriman -a x86_64 -r "github" service-setup --packager "ahriman bot <ahriman@example.com>" "${WEB_ARGS[@]}"
# validate configuration
ahriman -a x86_64 service-config-validate --exit-code
ahriman -a x86_64 -r "github" service-config-validate --exit-code
# enable services
systemctl enable ahriman-web@x86_64
systemctl enable ahriman@x86_64.timer
@ -48,9 +48,9 @@ if [[ -z $MINIMAL_INSTALL ]]; then
WEB_PID=$!
fi
# add the first package
sudo -u ahriman -- ahriman package-add --now yay
sudo -u ahriman -- ahriman package-add --now ahriman
# check if package was actually installed
test -n "$(find "/var/lib/ahriman/repository/x86_64" -name "yay*pkg*")"
test -n "$(find "/var/lib/ahriman/repository/github/x86_64" -name "ahriman*pkg*")"
# run package check
sudo -u ahriman -- ahriman repo-update
# stop web service lol

View File

@ -25,7 +25,7 @@ from multiprocessing import Pool
from ahriman.application.lock import Lock
from ahriman.core.configuration import Configuration
from ahriman.core.exceptions import ExitCode, MissingArchitectureError, MultipleArchitecturesError
from ahriman.core.log.log_loader import LogLoader
from ahriman.core.log import Log
from ahriman.models.repository_id import RepositoryId
from ahriman.models.repository_paths import RepositoryPaths
@ -65,8 +65,8 @@ class Handler:
try:
configuration = Configuration.from_path(args.configuration, repository_id)
log_handler = LogLoader.handler(args.log_handler)
LogLoader.load(configuration, log_handler, quiet=args.quiet, report=args.report)
log_handler = Log.handler(args.log_handler)
Log.load(configuration, log_handler, quiet=args.quiet, report=args.report)
with Lock(args, repository_id, configuration):
cls.run(args, repository_id, configuration, report=args.report)
@ -116,7 +116,7 @@ class Handler:
args(argparse.Namespace): command line args
Returns:
tuple[str | None, str]: list of repository names and architectures for which tree is created
list[RepositoryId]: list of repository names and architectures for which tree is created
Raises:
MissingArchitectureError: if no architecture set and automatic detection is not allowed or failed

View File

@ -66,8 +66,8 @@ class Setup(Handler):
Setup.configuration_create_makepkg(args.packager, args.makeflags_jobs, application.repository.paths)
Setup.executable_create(application.repository.paths, repository_id)
repository_server = f"file://{application.repository.paths.repository}" if args.server is None else args.server
Setup.configuration_create_devtools(repository_id, args.from_configuration, args.mirror, args.multilib,
repository_server)
Setup.configuration_create_devtools(
repository_id, args.from_configuration, args.mirror, args.multilib, repository_server)
Setup.configuration_create_sudo(application.repository.paths, repository_id)
application.repository.repo.init()

View File

@ -77,8 +77,7 @@ class Web(Handler):
"""
# read architecture from the same argument list
yield from ["--architecture", repository_id.architecture]
if repository_id.name is not None:
yield from ["--repository", repository_id.name]
yield from ["--repository", repository_id.name]
# read configuration path from current settings
if (configuration_path := configuration.path) is not None:
yield from ["--configuration", str(configuration_path)]

View File

@ -70,7 +70,7 @@ class Lock(LazyLogging):
repository_id(RepositoryId): repository unique identifier
configuration(Configuration): configuration instance
"""
lock_suffix = f"{repository_id.name}_{repository_id.architecture}" if repository_id.name is not None else repository_id.architecture
lock_suffix = f"{repository_id.name}_{repository_id.architecture}"
self.path: Path | None = \
args.lock.with_stem(f"{args.lock.stem}_{lock_suffix}") if args.lock is not None else None

View File

@ -89,6 +89,17 @@ class Configuration(configparser.RawConfigParser):
self.path: Path | None = None
self.includes: list[Path] = []
@property
def architecture(self) -> str:
"""
repository architecture for backward compatibility
Returns:
str: repository architecture
"""
_, repository_id = self.check_loaded()
return repository_id.architecture
@property
def include(self) -> Path:
"""
@ -163,23 +174,23 @@ class Configuration(configparser.RawConfigParser):
# the valid order is global < per architecture < per repository < per repository and architecture
return [
Configuration.section_name(section, repository_id.architecture), # architecture specific override
Configuration.section_name(section, repository_id.name),
Configuration.section_name(section, repository_id.name, repository_id.architecture),
Configuration.section_name(section, repository_id.name), # override with repository name
Configuration.section_name(section, repository_id.name, repository_id.architecture), # both
]
@staticmethod
def section_name(section: str, *suffixes: str) -> str:
def section_name(section: str, *suffixes: str | None) -> str:
"""
generate section name for sections which depends on context
Args:
section(str): section name
*suffixes(str): session suffix, e.g. repository architecture
*suffixes(str | None): session suffix, e.g. repository architecture
Returns:
str: correct section name for repository specific section
"""
for suffix in suffixes:
for suffix in filter(bool, suffixes):
section = f"{section}:{suffix}"
return section

View File

@ -80,7 +80,7 @@ def migrate_package_remotes(connection: Connection, paths: RepositoryPaths) -> N
version=row["version"],
remote=RemoteSource.from_json(row),
packages={},
packager=row["packager"] or None,
packager=row.get("packager") or None,
) for row in connection.execute("""select * from package_bases""")
}

View File

@ -51,6 +51,9 @@ steps = [
alter table build_queue add column repository text not null default ''
""",
"""
alter table build_queue add column architecture text not null default ''
""",
"""
alter table build_queue rename to build_queue_
""",
"""
@ -58,7 +61,8 @@ steps = [
package_base text not null,
properties json not null,
repository text not null,
primary key (package_base, repository)
architecture text not null,
unique (package_base, architecture, repository)
)
""",
"""
@ -72,6 +76,9 @@ steps = [
alter table package_bases add column repository text not null default ''
""",
"""
alter table package_bases add column architecture text not null default ''
""",
"""
alter table package_bases rename to package_bases_
""",
"""
@ -85,7 +92,8 @@ steps = [
source text,
packager text,
repository text not null,
primary key (package_base, repository)
architecture text not null,
unique (package_base, architecture, repository)
)
""",
"""
@ -99,6 +107,9 @@ steps = [
alter table package_statuses add column repository text not null default ''
""",
"""
alter table package_statuses add column architecture text not null default ''
""",
"""
alter table package_statuses rename to package_statuses_
""",
"""
@ -107,7 +118,8 @@ steps = [
status text not null,
last_updated integer,
repository text not null,
primary key (package_base, repository)
architecture text not null,
unique (package_base, architecture, repository)
)
""",
"""
@ -142,7 +154,7 @@ steps = [
opt_depends json,
check_depends json,
repository text not null,
primary key (package, architecture, repository)
unique (package, architecture, repository)
)
""",
"""
@ -151,39 +163,14 @@ steps = [
"""
drop table packages_
""",
# patches
"""
alter table patches add column repository text not null default ''
""",
"""
drop index patches_package_base_variable
""",
"""
alter table patches rename to patches_
""",
"""
create table patches (
package_base text not null,
variable text,
patch blob not null,
repository text not null
)
""",
"""
create unique index patches_package_base_variable_repository
on patches (package_base, coalesce(variable, ''), repository)
""",
"""
insert into patches select * from patches_
""",
"""
drop table patches_
""",
# logs
"""
alter table logs add column repository text not null default ''
""",
"""
alter table logs add column architecture text not null default ''
""",
"""
drop index logs_package_base_version
""",
"""
@ -195,14 +182,16 @@ steps = [
created real not null,
record text,
version text not null,
repository text not null
repository text not null,
architecture text not null
)
""",
"""
insert into logs select * from logs_
""",
"""
create index logs_package_base_version on logs (package_base, version)
create index logs_package_base_version_architecture_repository
on logs (package_base, version, architecture, repository)
""",
"""
drop table logs_
@ -231,15 +220,13 @@ def migrate_package_repository(connection: Connection, configuration: Configurat
"""
_, repository_id = configuration.check_loaded()
connection.execute("""update build_queue set repository = :repository""",
{"repository": repository_id.name, })
connection.execute("""update package_bases set repository = :repository""",
{"repository": repository_id.name, })
connection.execute("""update package_statuses set repository = :repository""",
{"repository": repository_id.name, })
connection.execute("""update build_queue set repository = :repository, architecture = :architecture""",
{"repository": repository_id.name, "architecture": repository_id.architecture})
connection.execute("""update package_bases set repository = :repository, architecture = :architecture""",
{"repository": repository_id.name, "architecture": repository_id.architecture})
connection.execute("""update package_statuses set repository = :repository, architecture = :architecture""",
{"repository": repository_id.name, "architecture": repository_id.architecture})
connection.execute("""update packages set repository = :repository""",
{"repository": repository_id.name, })
connection.execute("""update patches set repository = :repository""",
{"repository": repository_id.name, })
connection.execute("""update logs set repository = :repository""",
{"repository": repository_id.name, })
{"repository": repository_id.name})
connection.execute("""update logs set repository = :repository, architecture = :architecture""",
{"repository": repository_id.name, "architecture": repository_id.architecture})

View File

@ -39,9 +39,14 @@ class BuildOperations(Operations):
connection.execute(
"""
delete from build_queue
where (:package_base is null or package_base = :package_base) and repository = :repository
where (:package_base is null or package_base = :package_base)
and repository = :repository and architecture = :architecture
""",
{"package_base": package_base, "repository": self.repository_id.name})
{
"package_base": package_base,
"repository": self.repository_id.name,
"architecture": self.repository_id.architecture,
})
return self.with_connection(run, commit=True)
@ -56,8 +61,11 @@ class BuildOperations(Operations):
return [
Package.from_json(row["properties"])
for row in connection.execute(
"""select properties from build_queue where repository = :repository""",
{"repository": self.repository_id.name}
"""
select properties from build_queue
where repository = :repository and architecture = :architecture
""",
{"repository": self.repository_id.name, "architecture": self.repository_id.architecture}
)
]
@ -74,12 +82,17 @@ class BuildOperations(Operations):
connection.execute(
"""
insert into build_queue
(package_base, properties, repository)
(package_base, properties, repository, architecture)
values
(:package_base, :properties, :repository)
on conflict (package_base, repository) do update set
(:package_base, :properties, :repository, :architecture)
on conflict (package_base, architecture, repository) do update set
properties = :properties
""",
{"package_base": package.base, "properties": package.view(), "repository": self.repository_id.name})
{
"package_base": package.base,
"properties": package.view(),
"repository": self.repository_id.name,
"architecture": self.repository_id.architecture,
})
return self.with_connection(run, commit=True)

View File

@ -46,10 +46,16 @@ class LogsOperations(Operations):
for row in connection.execute(
"""
select created, record from logs
where package_base = :package_base and repository = :repository
where package_base = :package_base and repository = :repository and architecture = :architecture
order by created limit :limit offset :offset
""",
{"package_base": package_base, "repository": self.repository_id.name, "limit": limit, "offset": offset})
{
"package_base": package_base,
"repository": self.repository_id.name,
"architecture": self.repository_id.architecture,
"limit": limit,
"offset": offset,
})
]
return self.with_connection(run)
@ -67,9 +73,9 @@ class LogsOperations(Operations):
connection.execute(
"""
insert into logs
(package_base, version, created, record, repository)
(package_base, version, created, record, repository, architecture)
values
(:package_base, :version, :created, :record, :repository)
(:package_base, :version, :created, :record, :repository, :architecture)
""",
{
"package_base": log_record_id.package_base,
@ -77,6 +83,7 @@ class LogsOperations(Operations):
"created": created,
"record": record,
"repository": self.repository_id.name,
"architecture": self.repository_id.architecture,
}
)
@ -95,10 +102,15 @@ class LogsOperations(Operations):
connection.execute(
"""
delete from logs
where package_base = :package_base and repository = :repository
where package_base = :package_base and repository = :repository and architecture = :architecture
and (:version is null or version <> :version)
""",
{"package_base": package_base, "version": version, "repository": self.repository_id.name}
{
"package_base": package_base,
"version": version,
"repository": self.repository_id.name,
"architecture": self.repository_id.architecture,
}
)
return self.with_connection(run, commit=True)

View File

@ -43,14 +43,23 @@ class PackageOperations(Operations):
connection.execute(
"""
delete from package_statuses
where package_base = :package_base and repository = :repository
where package_base = :package_base and repository = :repository and architecture = :architecture
""",
{"package_base": package_base, "repository": self.repository_id.name})
{
"package_base": package_base,
"repository": self.repository_id.name,
"architecture": self.repository_id.architecture,
})
connection.execute(
"""
delete from package_bases
where package_base = :package_base and repository = :repository""",
{"package_base": package_base, "repository": self.repository_id.name})
where package_base = :package_base and repository = :repository and architecture = :architecture
""",
{
"package_base": package_base,
"repository": self.repository_id.name,
"architecture": self.repository_id.architecture,
})
def _package_remove_packages(self, connection: Connection, package_base: str,
current_packages: Iterable[str]) -> None:
@ -66,15 +75,19 @@ class PackageOperations(Operations):
package
for package in connection.execute(
"""
select package, repository from packages
where package_base = :package_base and repository = :repository""",
{"package_base": package_base, "repository": self.repository_id.name})
select package, repository, architecture from packages
where package_base = :package_base and repository = :repository and architecture = :architecture""",
{
"package_base": package_base,
"repository": self.repository_id.name,
"architecture": self.repository_id.architecture,
})
if package["package"] not in current_packages
]
connection.executemany(
"""
delete from packages
where package = :package and repository = :repository
where package = :package and repository = :repository and architecture = :architecture
""",
packages)
@ -89,10 +102,12 @@ class PackageOperations(Operations):
connection.execute(
"""
insert into package_bases
(package_base, version, source, branch, git_url, path, web_url, packager, repository)
(package_base, version, source, branch, git_url, path, web_url, packager,
repository, architecture)
values
(:package_base, :version, :source, :branch, :git_url, :path, :web_url, :packager, :repository)
on conflict (package_base, repository) do update set
(:package_base, :version, :source, :branch, :git_url, :path, :web_url, :packager,
:repository, :architecture)
on conflict (package_base, architecture, repository) do update set
version = :version, branch = :branch, git_url = :git_url, path = :path, web_url = :web_url,
source = :source, packager = :packager
""",
@ -106,6 +121,7 @@ class PackageOperations(Operations):
"source": package.remote.source.value,
"packager": package.packager,
"repository": self.repository_id.name,
"architecture": self.repository_id.architecture,
}
)
@ -161,10 +177,10 @@ class PackageOperations(Operations):
connection.execute(
"""
insert into package_statuses
(package_base, status, last_updated, repository)
(package_base, status, last_updated, repository, architecture)
values
(:package_base, :status, :last_updated, :repository)
on conflict (package_base, repository) do update set
(:package_base, :status, :last_updated, :repository, :architecture)
on conflict (package_base, architecture, repository) do update set
status = :status, last_updated = :last_updated
""",
{
@ -172,6 +188,7 @@ class PackageOperations(Operations):
"status": status.status.value,
"last_updated": status.timestamp,
"repository": self.repository_id.name,
"architecture": self.repository_id.architecture,
})
def _packages_get_select_package_bases(self, connection: Connection) -> dict[str, Package]:
@ -192,8 +209,8 @@ class PackageOperations(Operations):
packages={},
packager=row["packager"] or None,
) for row in connection.execute(
"""select * from package_bases where repository = :repository""",
{"repository": self.repository_id.name}
"""select * from package_bases where repository = :repository and architecture = :architecture""",
{"repository": self.repository_id.name, "architecture": self.repository_id.architecture}
)
}
@ -209,8 +226,9 @@ class PackageOperations(Operations):
dict[str, Package]: map of the package base to its descriptor including individual packages
"""
for row in connection.execute(
"""select * from packages where repository = :repository""",
{"repository": self.repository_id.name}):
"""select * from packages where repository = :repository and architecture = :architecture""",
{"repository": self.repository_id.name, "architecture": self.repository_id.architecture}
):
if row["package_base"] not in packages:
continue # normally must never happen though
packages[row["package_base"]].packages[row["package"]] = PackageDescription.from_json(row)
@ -229,8 +247,8 @@ class PackageOperations(Operations):
return {
row["package_base"]: BuildStatus.from_json({"status": row["status"], "timestamp": row["last_updated"]})
for row in connection.execute(
"""select * from package_statuses where repository = :repository""",
{"repository": self.repository_id.name}
"""select * from package_statuses where repository = :repository and architecture = :architecture""",
{"repository": self.repository_id.name, "architecture": self.repository_id.architecture}
)
}

View File

@ -54,19 +54,13 @@ class PatchOperations(Operations):
connection.execute(
"""
insert into patches
(package_base, variable, patch, repository)
(package_base, variable, patch)
values
(:package_base, :variable, :patch, :repository)
on conflict (package_base, coalesce(variable, ''), repository) do update set
(:package_base, :variable, :patch)
on conflict (package_base, coalesce(variable, '')) do update set
patch = :patch
""",
{
"package_base": package_base,
"variable": patch.key,
"patch": patch.value,
"repository": self.repository_id.name,
}
)
{"package_base": package_base, "variable": patch.key, "patch": patch.value})
return self.with_connection(run, commit=True)
@ -85,10 +79,8 @@ class PatchOperations(Operations):
return [
(row["package_base"], PkgbuildPatch(row["variable"], row["patch"]))
for row in connection.execute(
"""
select * from patches
where (:package_base is null or package_base = :package_base) and repository = :repository""",
{"package_base": package_base, "repository": self.repository_id.name})
"""select * from patches where :package_base is null or package_base = :package_base""",
{"package_base": package_base})
]
# we could use itertools & operator but why?
@ -109,23 +101,13 @@ class PatchOperations(Operations):
"""
def run_many(connection: Connection) -> None:
connection.executemany(
"""
delete from patches
where package_base = :package_base and variable = :variable and repository = :repository
""",
[
{
"package_base": package_base,
"variable": variable,
"repository": self.repository_id.name,
} for variable in variables
]
)
"""delete from patches where package_base = :package_base and variable = :variable""",
[{"package_base": package_base, "variable": variable} for variable in variables])
def run(connection: Connection) -> None:
connection.execute(
"""delete from patches where package_base = :package_base and repository = :repository""",
{"package_base": package_base, "repository": self.repository_id.name})
"""delete from patches where package_base = :package_base""",
{"package_base": package_base})
if variables:
return self.with_connection(run_many, commit=True)

View File

@ -18,3 +18,4 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from ahriman.core.log.lazy_logging import LazyLogging
from ahriman.core.log.log import Log

View File

@ -27,7 +27,7 @@ from ahriman.core.log.http_log_handler import HttpLogHandler
from ahriman.models.log_handler import LogHandler
class LogLoader:
class Log:
"""
simple static method class which setups application loggers
@ -63,7 +63,7 @@ class LogLoader:
del JournalHandler
return LogHandler.Journald # journald import was found
except ImportError:
if LogLoader.DEFAULT_SYSLOG_DEVICE.exists():
if Log.DEFAULT_SYSLOG_DEVICE.exists():
return LogHandler.Syslog
return LogHandler.Console
@ -94,7 +94,7 @@ class LogLoader:
fileConfig(log_configuration, disable_existing_loggers=True)
logging.debug("using %s logger", default_handler)
except Exception:
logging.basicConfig(filename=None, format=LogLoader.DEFAULT_LOG_FORMAT, level=LogLoader.DEFAULT_LOG_LEVEL)
logging.basicConfig(filename=None, format=Log.DEFAULT_LOG_FORMAT, level=Log.DEFAULT_LOG_LEVEL)
logging.exception("could not load logging from configuration, fallback to stderr")
HttpLogHandler.load(configuration, report=report)

View File

@ -132,7 +132,7 @@ class S3(Upload):
continue
local_path = path / local_file
remote_path = self.remote_root / local_file
remote_path = self.remote_root / local_file.name
(mime, _) = mimetypes.guess_type(local_path)
extra_args = {"ContentType": mime} if mime is not None else None

View File

@ -62,4 +62,4 @@ class RepositoryId:
if not isinstance(other, RepositoryId):
raise ValueError(f"'<' not supported between instances of '{type(self)}' and '{type(other)}'")
return self.name <= other.name and self.architecture < other.architecture
return (self.name, self.architecture) < (other.name, other.architecture)

View File

@ -26,12 +26,11 @@ from functools import cached_property
from pathlib import Path
from ahriman.core.exceptions import PathError
from ahriman.core.log import LazyLogging
from ahriman.models.repository_id import RepositoryId
@dataclass(frozen=True)
class RepositoryPaths(LazyLogging):
class RepositoryPaths:
"""
repository paths holder. For the most operations with paths you want to use this object
@ -57,6 +56,16 @@ class RepositoryPaths(LazyLogging):
root: Path
repository_id: RepositoryId
@property
def _repository_root(self) -> Path:
"""
repository root which can be used for invalid (not fully loaded instances)
Returns:
Path: root path to repositories
"""
return self.root / "repository"
@cached_property
def _suffix(self) -> Path:
"""
@ -66,8 +75,7 @@ class RepositoryPaths(LazyLogging):
Path: relative path which contains only architecture segment in case if legacy tree is used and repository
name and architecture otherwise
"""
if (self.root / "repository" / self.repository_id.architecture).is_dir():
self.logger.warning("legacy single repository tree has been found")
if (self._repository_root / self.repository_id.architecture).is_dir():
return Path(self.repository_id.architecture)
return Path(self.repository_id.name) / self.repository_id.architecture
@ -120,7 +128,7 @@ class RepositoryPaths(LazyLogging):
Returns:
Path: full path to the repository directory
"""
return self.root / "repository" / self._suffix
return self._repository_root / self._suffix
@property
def root_owner(self) -> tuple[int, int]:
@ -148,13 +156,15 @@ class RepositoryPaths(LazyLogging):
for architecture in filter(lambda path: path.is_dir(), repository_path.iterdir()):
yield RepositoryId(architecture.name, repository_name)
def walk_with_name(paths: RepositoryPaths) -> Generator[RepositoryId, None, None]:
for repository in filter(lambda path: path.is_dir(), paths.repository.iterdir()):
def walk_root(paths: RepositoryPaths) -> Generator[RepositoryId, None, None]:
# pylint: disable=protected-access
for repository in filter(lambda path: path.is_dir(), paths._repository_root.iterdir()):
print(repository)
yield from walk(repository, repository.name)
instance = cls(root, RepositoryId("", ""))
instance = cls(root, RepositoryId("", root.name)) # suppress initialization error
# try to get list per repository first and then fallback to old schema if nothing found
return set(walk_with_name(instance)) or set(walk(instance.repository, name))
return set(walk_root(instance)) or set(walk(instance._repository_root, name))
@staticmethod
def owner(path: Path) -> tuple[int, int]:

View File

@ -6,3 +6,10 @@ def test_create_tree(application_properties: ApplicationProperties) -> None:
must have repository attribute
"""
assert application_properties.repository
def test_architecture(application_properties: ApplicationProperties) -> None:
"""
must return repository architecture
"""
assert application_properties.architecture == application_properties.repository_id.architecture

View File

@ -8,48 +8,7 @@ from ahriman.application.handlers import Handler
from ahriman.core.configuration import Configuration
from ahriman.core.exceptions import ExitCode, MissingArchitectureError, MultipleArchitecturesError
from ahriman.models.log_handler import LogHandler
def test_architectures_extract(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
"""
must generate list of available architectures
"""
args.configuration = configuration.path
known_architectures_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_architectures")
Handler.architectures_extract(args)
known_architectures_mock.assert_called_once_with(configuration.getpath("repository", "root"))
def test_architectures_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.models.repository_paths.RepositoryPaths.known_architectures", return_value=set())
with pytest.raises(MissingArchitectureError):
Handler.architectures_extract(args)
def test_architectures_extract_exception(args: argparse.Namespace, mocker: MockerFixture) -> None:
"""
must raise exception on missing architectures
"""
args.command = "config"
mocker.patch.object(Handler, "ALLOW_AUTO_ARCHITECTURE_RUN", False)
with pytest.raises(MissingArchitectureError):
Handler.architectures_extract(args)
def test_architectures_extract_specified(args: argparse.Namespace) -> None:
"""
must return architecture list if it has been specified
"""
architectures = args.architecture = ["i686", "x86_64"]
assert Handler.architectures_extract(args) == sorted(set(architectures))
from ahriman.models.repository_id import RepositoryId
def test_call(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
@ -67,15 +26,16 @@ def test_call(args: argparse.Namespace, configuration: Configuration, mocker: Mo
enter_mock = mocker.patch("ahriman.application.lock.Lock.__enter__")
exit_mock = mocker.patch("ahriman.application.lock.Lock.__exit__")
assert Handler.call(args, "x86_64")
configuration_mock.assert_called_once_with(args.configuration, "x86_64")
_, 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(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, mocker: MockerFixture) -> None:
def test_call_exception(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
"""
must process exception
"""
@ -84,11 +44,12 @@ def test_call_exception(args: argparse.Namespace, mocker: MockerFixture) -> None
mocker.patch("ahriman.core.configuration.Configuration.from_path", side_effect=Exception())
logging_mock = mocker.patch("logging.Logger.exception")
assert not Handler.call(args, "x86_64")
_, 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, mocker: MockerFixture) -> None:
def test_call_exit_code(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
"""
must process exitcode exception
"""
@ -97,7 +58,8 @@ def test_call_exit_code(args: argparse.Namespace, mocker: MockerFixture) -> None
mocker.patch("ahriman.core.configuration.Configuration.from_path", side_effect=ExitCode())
logging_mock = mocker.patch("logging.Logger.exception")
assert not Handler.call(args, "x86_64")
_, repository_id = configuration.check_loaded()
assert not Handler.call(args, repository_id)
logging_mock.assert_not_called()
@ -105,33 +67,39 @@ def test_execute(args: argparse.Namespace, mocker: MockerFixture) -> None:
"""
must run execution in multiple processes
"""
args.architecture = ["i686", "x86_64"]
ids = [
RepositoryId("i686", "aur-clone"),
RepositoryId("x86_64", "aur-clone"),
]
mocker.patch("ahriman.application.handlers.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, architecture) for architecture in args.architecture])
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.architecture = ["i686", "x86_64"]
args.command = "web"
mocker.patch("ahriman.application.handlers.Handler.repositories_extract", return_value=[
RepositoryId("i686", "aur-clone"),
RepositoryId("x86_64", "aur-clone"),
])
mocker.patch.object(Handler, "ALLOW_MULTI_ARCHITECTURE_RUN", False)
with pytest.raises(MultipleArchitecturesError):
Handler.execute(args)
def test_execute_single(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
def test_execute_single(args: argparse.Namespace, mocker: MockerFixture) -> None:
"""
must run execution in current process if only one architecture supplied
"""
args.architecture = ["x86_64"]
args.configuration = Path("")
args.quiet = False
mocker.patch("ahriman.core.configuration.Configuration.from_path", return_value=configuration)
mocker.patch("ahriman.application.handlers.Handler.repositories_extract", return_value=[
RepositoryId("x86_64", "aur-clone"),
])
starmap_mock = mocker.patch("multiprocessing.pool.Pool.starmap")
Handler.execute(args)
@ -142,8 +110,73 @@ 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, "x86_64", configuration, report=True)
Handler.run(args, repository_id, configuration, report=True)
def test_repositories_extract(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
"""
must generate list of available architectures
"""
args.configuration = configuration.path
_, repository_id = configuration.check_loaded()
known_architectures_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_architectures")
Handler.repositories_extract(args)
known_architectures_mock.assert_called_once_with(configuration.getpath("repository", "root"), repository_id.name)
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.models.repository_paths.RepositoryPaths.known_architectures", return_value=set())
with pytest.raises(MissingArchitectureError):
Handler.repositories_extract(args)
def test_repositories_extract_exception(args: argparse.Namespace, mocker: MockerFixture) -> None:
"""
must raise exception on missing architectures
"""
args.command = "config"
mocker.patch.object(Handler, "ALLOW_AUTO_ARCHITECTURE_RUN", False)
with pytest.raises(MissingArchitectureError):
Handler.repositories_extract(args)
def test_repositories_extract_specified(args: argparse.Namespace, configuration: Configuration) -> None:
"""
must return architecture list if it has been specified
"""
args.configuration = configuration.path
args.architecture = ["i686", "x86_64"]
args.repository = []
_, repository_id = configuration.check_loaded()
ids = [RepositoryId(architecture, repository_id.name) for architecture in args.architecture]
assert Handler.repositories_extract(args) == sorted(set(ids))
def test_repositories_extract_specified_with_repository(args: argparse.Namespace, configuration: Configuration) -> None:
"""
must return architecture list if it has been specified together with repositories
"""
args.configuration = configuration.path
args.architecture = ["i686", "x86_64"]
args.repository = ["repo1", "repo2"]
ids = [
RepositoryId(architecture, name)
for architecture in args.architecture
for name in args.repository
]
assert Handler.repositories_extract(args) == sorted(set(ids))
def test_check_if_empty() -> None:

View File

@ -44,7 +44,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
dependencies_mock = mocker.patch("ahriman.application.application.Application.with_dependencies")
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
Add.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Add.run(args, repository_id, configuration, report=False)
application_mock.assert_called_once_with(args.package, args.source, args.username)
dependencies_mock.assert_not_called()
on_start_mock.assert_called_once_with()
@ -68,7 +69,8 @@ def test_run_with_updates(args: argparse.Namespace, configuration: Configuration
return_value=[package_ahriman])
print_mock = mocker.patch("ahriman.application.application.Application.print_updates")
Add.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Add.run(args, repository_id, configuration, report=False)
updates_mock.assert_called_once_with(args.package, aur=False, local=False, manual=True, vcs=False)
application_mock.assert_called_once_with([package_ahriman],
Packagers(args.username, {package_ahriman.base: "packager"}),
@ -94,5 +96,6 @@ def test_run_empty_exception(args: argparse.Namespace, configuration: Configurat
mocker.patch("ahriman.application.application.Application.print_updates")
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
Add.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Add.run(args, repository_id, configuration, report=False)
check_mock.assert_called_once_with(True, True)

View File

@ -33,7 +33,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
add_mock = tarfile.__enter__.return_value = MagicMock()
mocker.patch("tarfile.TarFile.__new__", return_value=tarfile)
Backup.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Backup.run(args, repository_id, configuration, report=False)
add_mock.add.assert_called_once_with(Path("path"))

View File

@ -35,6 +35,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
application_mock = mocker.patch("ahriman.application.application.Application.clean")
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
Clean.run(args, "x86_64", configuration, report=False)
_, 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()

View File

@ -33,7 +33,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
start_mock = mocker.patch("threading.Timer.start")
join_mock = mocker.patch("threading.Timer.join")
Daemon.run(args, "x86_64", configuration, report=True)
run_mock.assert_called_once_with(args, "x86_64", configuration, report=True)
_, 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)
start_mock.assert_called_once_with()
join_mock.assert_called_once_with()

View File

@ -29,7 +29,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
application_mock = mocker.patch("ahriman.core.configuration.Configuration.dump",
return_value=configuration.dump())
Dump.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Dump.run(args, repository_id, configuration, report=False)
application_mock.assert_called_once_with()
print_mock.assert_called()

View File

@ -29,7 +29,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
args = _default_args(args)
parse_mock = mocker.patch("argparse.ArgumentParser.parse_args")
Help.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Help.run(args, repository_id, configuration, report=False)
parse_mock.assert_called_once_with(["--help"])
@ -41,7 +42,8 @@ def test_run_command(args: argparse.Namespace, configuration: Configuration, moc
args.command = "aur-search"
parse_mock = mocker.patch("argparse.ArgumentParser.parse_args")
Help.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Help.run(args, repository_id, configuration, report=False)
parse_mock.assert_called_once_with(["aur-search", "--help"])

View File

@ -31,7 +31,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
application_mock = mocker.patch("ahriman.core.sign.gpg.GPG.key_import")
KeyImport.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
KeyImport.run(args, repository_id, configuration, report=False)
application_mock.assert_called_once_with(args.key_server, args.key)

View File

@ -44,8 +44,9 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
return_value=(args.package, PkgbuildPatch(None, "patch")))
application_mock = mocker.patch("ahriman.application.handlers.Patch.patch_set_create")
Patch.run(args, "x86_64", configuration, report=False)
patch_mock.assert_called_once_with(args.package, "x86_64", args.track)
_, 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"))
@ -63,7 +64,8 @@ def test_run_function(args: argparse.Namespace, configuration: Configuration, re
patch_mock = mocker.patch("ahriman.application.handlers.Patch.patch_create_from_function", return_value=patch)
application_mock = mocker.patch("ahriman.application.handlers.Patch.patch_set_create")
Patch.run(args, "x86_64", configuration, report=False)
_, 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)
@ -79,7 +81,8 @@ def test_run_list(args: argparse.Namespace, configuration: Configuration, reposi
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
application_mock = mocker.patch("ahriman.application.handlers.Patch.patch_set_list")
Patch.run(args, "x86_64", configuration, report=False)
_, 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)
@ -94,11 +97,12 @@ def test_run_remove(args: argparse.Namespace, configuration: Configuration, repo
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
application_mock = mocker.patch("ahriman.application.handlers.Patch.patch_set_remove")
Patch.run(args, "x86_64", configuration, report=False)
_, 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, mocker: MockerFixture) -> None:
def test_patch_create_from_diff(package_ahriman: Package, configuration: Configuration, mocker: MockerFixture) -> None:
"""
must create patch from directory tree diff
"""
@ -108,8 +112,9 @@ def test_patch_create_from_diff(package_ahriman: Package, mocker: MockerFixture)
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)
assert Patch.patch_create_from_diff(path, "x86_64", ["*.diff"]) == (package_ahriman.base, patch)
package_mock.assert_called_once_with(path, "x86_64", None)
_, 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")

View File

@ -49,7 +49,8 @@ def test_run(args: argparse.Namespace, package_ahriman: Package, configuration:
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
Rebuild.run(args, "x86_64", configuration, report=False)
_, 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], args.username, bump_pkgrel=args.increment)
@ -70,7 +71,8 @@ def test_run_extract_packages(args: argparse.Namespace, configuration: Configura
mocker.patch("ahriman.application.application.Application.print_updates")
extract_mock = mocker.patch("ahriman.application.handlers.Rebuild.extract_packages", return_value=[])
Rebuild.run(args, "x86_64", configuration, report=False)
_, 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)
@ -87,7 +89,8 @@ def test_run_dry_run(args: argparse.Namespace, configuration: Configuration, rep
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
print_mock = mocker.patch("ahriman.application.application.Application.print_updates")
Rebuild.run(args, "x86_64", configuration, report=False)
_, 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, False)
print_mock.assert_called_once_with([package_ahriman], log_fn=pytest.helpers.anyvar(int))
@ -105,7 +108,8 @@ def test_run_filter(args: argparse.Namespace, configuration: Configuration, repo
mocker.patch("ahriman.application.handlers.Rebuild.extract_packages", return_value=[])
application_packages_mock = mocker.patch("ahriman.core.repository.repository.Repository.packages_depend_on")
Rebuild.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Rebuild.run(args, repository_id, configuration, report=False)
application_packages_mock.assert_called_once_with([], ["python-aur"])
@ -120,7 +124,8 @@ def test_run_without_filter(args: argparse.Namespace, configuration: Configurati
mocker.patch("ahriman.application.handlers.Rebuild.extract_packages", return_value=[])
application_packages_mock = mocker.patch("ahriman.core.repository.repository.Repository.packages_depend_on")
Rebuild.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Rebuild.run(args, repository_id, configuration, report=False)
application_packages_mock.assert_called_once_with([], None)
@ -138,7 +143,8 @@ def test_run_update_empty_exception(args: argparse.Namespace, configuration: Con
mocker.patch("ahriman.application.application.Application.print_updates")
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
Rebuild.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Rebuild.run(args, repository_id, configuration, report=False)
check_mock.assert_called_once_with(True, True)
@ -155,7 +161,8 @@ def test_run_build_empty_exception(args: argparse.Namespace, configuration: Conf
mocker.patch("ahriman.application.application.Application.update", return_value=Result())
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
Rebuild.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Rebuild.run(args, repository_id, configuration, report=False)
check_mock.assert_has_calls([MockCall(True, False), MockCall(True, True)])

View File

@ -31,6 +31,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
application_mock = mocker.patch("ahriman.application.application.Application.remove")
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
Remove.run(args, "x86_64", configuration, report=False)
_, 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()

View File

@ -34,7 +34,8 @@ def test_run(args: argparse.Namespace, package_ahriman: Package, configuration:
remove_mock = mocker.patch("ahriman.application.application.Application.remove")
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
RemoveUnknown.run(args, "x86_64", configuration, report=False)
_, 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()
@ -53,7 +54,8 @@ def test_run_dry_run(args: argparse.Namespace, configuration: Configuration, rep
remove_mock = mocker.patch("ahriman.application.application.Application.remove")
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
RemoveUnknown.run(args, "x86_64", configuration, report=False)
_, 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)

View File

@ -32,7 +32,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
extract_mock = tarfile.__enter__.return_value = MagicMock()
mocker.patch("tarfile.TarFile.__new__", return_value=tarfile)
Restore.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Restore.run(args, repository_id, configuration, report=False)
extract_mock.extractall.assert_called_once_with(path=args.output)

View File

@ -42,7 +42,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
Search.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Search.run(args, repository_id, configuration, report=False)
aur_search_mock.assert_called_once_with("ahriman", pacman=pytest.helpers.anyvar(int))
official_search_mock.assert_called_once_with("ahriman", pacman=pytest.helpers.anyvar(int))
check_mock.assert_called_once_with(False, False)
@ -62,7 +63,8 @@ def test_run_empty_exception(args: argparse.Namespace, configuration: Configurat
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
Search.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Search.run(args, repository_id, configuration, report=False)
check_mock.assert_called_once_with(True, True)
@ -77,7 +79,8 @@ def test_run_sort(args: argparse.Namespace, configuration: Configuration, reposi
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
sort_mock = mocker.patch("ahriman.application.handlers.Search.sort")
Search.run(args, "x86_64", configuration, report=False)
_, 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__()
@ -96,7 +99,8 @@ def test_run_sort_by(args: argparse.Namespace, configuration: Configuration, rep
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
sort_mock = mocker.patch("ahriman.application.handlers.Search.sort")
Search.run(args, "x86_64", configuration, report=False)
_, 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__()

View File

@ -35,7 +35,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
application_mock = mocker.patch("ahriman.core.formatters.Printer.print")
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
ServiceUpdates.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
ServiceUpdates.run(args, repository_id, configuration, report=False)
package_mock.assert_called_once_with(package_ahriman.base, repository.pacman, None)
application_mock.assert_called_once_with(verbose=True, separator=" -> ")
check_mock.assert_called_once_with(args.exit_code, True)
@ -53,6 +54,7 @@ def test_run_skip(args: argparse.Namespace, configuration: Configuration, reposi
application_mock = mocker.patch("ahriman.core.formatters.Printer.print")
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
ServiceUpdates.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
ServiceUpdates.run(args, repository_id, configuration, report=False)
application_mock.assert_not_called()
check_mock.assert_not_called()

View File

@ -9,6 +9,7 @@ from unittest.mock import call as MockCall
from ahriman.application.handlers import Setup
from ahriman.core.configuration import Configuration
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
@ -24,14 +25,12 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
argparse.Namespace: generated arguments for these test cases
"""
args.build_as_user = "ahriman"
args.build_command = "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 = "John Doe <john@doe.com>"
args.repository = "aur-clone"
args.server = None
args.sign_key = "key"
args.sign_target = [SignSettings.Packages]
@ -54,14 +53,14 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
executable_mock = mocker.patch("ahriman.application.handlers.Setup.executable_create")
init_mock = mocker.patch("ahriman.core.alpm.repo.Repo.init")
Setup.run(args, "x86_64", configuration, report=False)
ahriman_configuration_mock.assert_called_once_with(args, "x86_64", args.repository, configuration)
_, repository_id = configuration.check_loaded()
Setup.run(args, repository_id, configuration, report=False)
ahriman_configuration_mock.assert_called_once_with(args, repository_id, configuration)
devtools_configuration_mock.assert_called_once_with(
args.build_command, "x86_64", args.from_configuration, args.mirror, args.multilib, args.repository,
f"file://{repository_paths.repository}")
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, args.build_command, "x86_64")
executable_mock.assert_called_once_with(repository_paths, args.build_command, "x86_64")
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()
@ -80,21 +79,20 @@ def test_run_with_server(args: argparse.Namespace, configuration: Configuration,
mocker.patch("ahriman.core.alpm.repo.Repo.init")
devtools_configuration_mock = mocker.patch("ahriman.application.handlers.Setup.configuration_create_devtools")
Setup.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Setup.run(args, repository_id, configuration, report=False)
devtools_configuration_mock.assert_called_once_with(
args.build_command, "x86_64", args.from_configuration, args.mirror, args.multilib, args.repository,
"server")
repository_id, args.from_configuration, args.mirror, args.multilib, "server")
def test_build_command(args: argparse.Namespace) -> None:
def test_build_command(repository_id: RepositoryId) -> None:
"""
must generate correct build command name
"""
args = _default_args(args)
path = Path("local")
build_command = Setup.build_command(path, args.build_command, "x86_64")
assert build_command.name == f"{args.build_command}-x86_64-build"
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
@ -107,19 +105,26 @@ def test_configuration_create_ahriman(args: argparse.Namespace, configuration: C
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")
command = Setup.build_command(repository_paths.root, args.build_command, "x86_64")
_, repository_id = configuration.check_loaded()
command = Setup.build_command(repository_paths.root, repository_id)
Setup.configuration_create_ahriman(args, "x86_64", args.repository, configuration)
Setup.configuration_create_ahriman(args, repository_id, configuration)
set_option_mock.assert_has_calls([
MockCall(Configuration.section_name("build", "x86_64"), "build_command", str(command)),
MockCall("repository", "name", args.repository),
MockCall(Configuration.section_name("build", "x86_64"), "makechrootpkg_flags", f"-U {args.build_as_user}"),
MockCall(Configuration.section_name("alpm", "x86_64"), "mirror", args.mirror),
MockCall(Configuration.section_name("sign", "x86_64"), "target",
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", "x86_64"), "key", args.sign_key),
MockCall(Configuration.section_name("web", "x86_64"), "port", str(args.web_port)),
MockCall(Configuration.section_name("web", "x86_64"), "unix_socket", str(args.web_unix_socket)),
MockCall(Configuration.section_name("sign", repository_id.name, repository_id.architecture), "key",
args.sign_key),
MockCall(Configuration.section_name("web", repository_id.name, repository_id.architecture), "port",
str(args.web_port)),
MockCall(Configuration.section_name("web", repository_id.name, repository_id.architecture), "unix_socket",
str(args.web_unix_socket)),
MockCall("auth", "salt", pytest.helpers.anyvar(str, strict=True)),
])
write_mock.assert_called_once_with(pytest.helpers.anyvar(int))
@ -136,13 +141,16 @@ def test_configuration_create_ahriman_no_multilib(args: argparse.Namespace, conf
mocker.patch("ahriman.core.configuration.Configuration.write")
set_option_mock = mocker.patch("ahriman.core.configuration.Configuration.set_option")
Setup.configuration_create_ahriman(args, "x86_64", args.repository, configuration)
_, repository_id = configuration.check_loaded()
Setup.configuration_create_ahriman(args, repository_id, configuration)
set_option_mock.assert_has_calls([
MockCall(Configuration.section_name("alpm", "x86_64"), "mirror", args.mirror),
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, mocker: MockerFixture) -> None:
def test_configuration_create_devtools(args: argparse.Namespace, configuration: Configuration,
mocker: MockerFixture) -> None:
"""
must create configuration for the devtools
"""
@ -152,13 +160,14 @@ def test_configuration_create_devtools(args: argparse.Namespace, mocker: MockerF
add_section_mock = mocker.patch("ahriman.core.configuration.Configuration.add_section")
write_mock = mocker.patch("ahriman.core.configuration.Configuration.write")
Setup.configuration_create_devtools(args.build_command, "x86_64", args.from_configuration,
None, args.multilib, args.repository, "server")
add_section_mock.assert_has_calls([MockCall("multilib"), MockCall(args.repository)])
_, 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, mocker: MockerFixture) -> None:
def test_configuration_create_devtools_mirror(args: argparse.Namespace, configuration: Configuration,
mocker: MockerFixture) -> None:
"""
must create configuration for the devtools with mirror set explicitly
"""
@ -176,14 +185,15 @@ def test_configuration_create_devtools_mirror(args: argparse.Namespace, mocker:
remove_option_mock = mocker.patch("ahriman.core.configuration.Configuration.remove_option")
set_option_mock = mocker.patch("ahriman.core.configuration.Configuration.set_option")
Setup.configuration_create_devtools(args.build_command, "x86_64", args.from_configuration,
args.mirror, False, args.repository, "server")
_, 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, mocker: MockerFixture) -> None:
def test_configuration_create_devtools_no_multilib(args: argparse.Namespace, configuration: Configuration,
mocker: MockerFixture) -> None:
"""
must create configuration for the devtools without multilib
"""
@ -192,8 +202,8 @@ def test_configuration_create_devtools_no_multilib(args: argparse.Namespace, moc
mocker.patch("ahriman.core.configuration.Configuration.set")
write_mock = mocker.patch("ahriman.core.configuration.Configuration.write")
Setup.configuration_create_devtools(args.build_command, "x86_64", args.from_configuration,
None, False, args.repository, "server")
_, 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))
@ -211,31 +221,32 @@ def test_configuration_create_makepkg(args: argparse.Namespace, repository_paths
Path("home") / ".makepkg.conf", pytest.helpers.anyvar(str, True), encoding="utf8")
def test_configuration_create_sudo(args: argparse.Namespace, repository_paths: RepositoryPaths,
def test_configuration_create_sudo(configuration: Configuration, repository_paths: RepositoryPaths,
mocker: MockerFixture) -> None:
"""
must create sudo configuration
"""
args = _default_args(args)
chmod_text_mock = mocker.patch("pathlib.Path.chmod")
write_text_mock = mocker.patch("pathlib.Path.write_text")
Setup.configuration_create_sudo(repository_paths, args.build_command, "x86_64")
_, 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(args: argparse.Namespace, repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
def test_executable_create(configuration: Configuration, repository_paths: RepositoryPaths,
mocker: MockerFixture) -> None:
"""
must create executable
"""
args = _default_args(args)
chown_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.chown")
symlink_mock = mocker.patch("pathlib.Path.symlink_to")
unlink_mock = mocker.patch("pathlib.Path.unlink")
Setup.executable_create(repository_paths, args.build_command, "x86_64")
chown_mock.assert_called_once_with(Setup.build_command(repository_paths.root, args.build_command, "x86_64"))
_, repository_id = configuration.check_loaded()
Setup.executable_create(repository_paths, repository_id)
chown_mock.assert_called_once_with(Setup.build_command(repository_paths.root, repository_id))
symlink_mock.assert_called_once_with(Setup.ARCHBUILD_COMMAND_PATH)
unlink_mock.assert_called_once_with(missing_ok=True)

View File

@ -32,7 +32,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
application_mock = mocker.patch("code.interact")
Shell.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Shell.run(args, repository_id, configuration, report=False)
application_mock.assert_called_once_with(local=pytest.helpers.anyvar(int))
@ -46,7 +47,8 @@ def test_run_eval(args: argparse.Namespace, configuration: Configuration, reposi
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
application_mock = mocker.patch("code.InteractiveConsole.runcode")
Shell.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Shell.run(args, repository_id, configuration, report=False)
application_mock.assert_called_once_with(args.code)
@ -62,7 +64,8 @@ def test_run_verbose(args: argparse.Namespace, configuration: Configuration, rep
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
application_mock = mocker.patch("code.interact")
Shell.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Shell.run(args, repository_id, configuration, report=False)
application_mock.assert_called_once_with(local=pytest.helpers.anyvar(int))
read_mock.assert_called_once_with(encoding="utf8")
print_mock.assert_called_once_with(verbose=False)

View File

@ -30,5 +30,6 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
application_mock = mocker.patch("ahriman.application.application.Application.sign")
Sign.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Sign.run(args, repository_id, configuration, report=False)
application_mock.assert_called_once_with([])

View File

@ -43,7 +43,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
Status.run(args, "x86_64", configuration, report=False)
_, 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, False)
@ -62,7 +63,8 @@ def test_run_empty_exception(args: argparse.Namespace, configuration: Configurat
mocker.patch("ahriman.core.status.client.Client.package_get", return_value=[])
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
Status.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Status.run(args, repository_id, configuration, report=False)
check_mock.assert_called_once_with(True, True)
@ -78,7 +80,8 @@ def test_run_verbose(args: argparse.Namespace, configuration: Configuration, rep
return_value=[(package_ahriman, BuildStatus(BuildStatusEnum.Success))])
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
Status.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Status.run(args, repository_id, configuration, report=False)
print_mock.assert_has_calls([MockCall(verbose=True) for _ in range(2)])
@ -93,7 +96,8 @@ def test_run_with_package_filter(args: argparse.Namespace, configuration: Config
packages_mock = mocker.patch("ahriman.core.status.client.Client.package_get",
return_value=[(package_ahriman, BuildStatus(BuildStatusEnum.Success))])
Status.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Status.run(args, repository_id, configuration, report=False)
packages_mock.assert_called_once_with(package_ahriman.base)
@ -110,7 +114,8 @@ def test_run_by_status(args: argparse.Namespace, configuration: Configuration, r
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
Status.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Status.run(args, repository_id, configuration, report=False)
print_mock.assert_has_calls([MockCall(verbose=False) for _ in range(2)])
@ -123,8 +128,9 @@ def test_imply_with_report(args: argparse.Namespace, configuration: Configuratio
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
load_mock = mocker.patch("ahriman.core.repository.Repository.load")
Status.run(args, "x86_64", configuration, report=False)
load_mock.assert_called_once_with("x86_64", configuration, database, report=True, refresh_pacman_database=0)
_, 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_auto_architecture_run() -> None:

View File

@ -36,7 +36,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
update_self_mock = mocker.patch("ahriman.core.status.client.Client.status_update")
StatusUpdate.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
StatusUpdate.run(args, repository_id, configuration, report=False)
update_self_mock.assert_called_once_with(args.status)
@ -50,7 +51,8 @@ def test_run_packages(args: argparse.Namespace, configuration: Configuration, re
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
update_mock = mocker.patch("ahriman.core.status.client.Client.package_update")
StatusUpdate.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
StatusUpdate.run(args, repository_id, configuration, report=False)
update_mock.assert_called_once_with(package_ahriman.base, args.status)
@ -65,7 +67,8 @@ def test_run_remove(args: argparse.Namespace, configuration: Configuration, repo
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
update_mock = mocker.patch("ahriman.core.status.client.Client.package_remove")
StatusUpdate.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
StatusUpdate.run(args, repository_id, configuration, report=False)
update_mock.assert_called_once_with(package_ahriman.base)
@ -78,8 +81,9 @@ def test_imply_with_report(args: argparse.Namespace, configuration: Configuratio
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
load_mock = mocker.patch("ahriman.core.repository.Repository.load")
StatusUpdate.run(args, "x86_64", configuration, report=False)
load_mock.assert_called_once_with("x86_64", configuration, database, report=True, refresh_pacman_database=0)
_, 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_auto_architecture_run() -> None:

View File

@ -35,7 +35,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
application_mock = mocker.patch("ahriman.core.tree.Tree.resolve", return_value=[[package_ahriman]])
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
Structure.run(args, "x86_64", configuration, report=False)
_, 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([

View File

@ -33,7 +33,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
application_mock = mocker.patch("ahriman.application.application.Application.on_result")
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
Triggers.run(args, "x86_64", configuration, report=False)
_, 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()
@ -50,6 +51,7 @@ def test_run_trigger(args: argparse.Namespace, configuration: Configuration, rep
report_mock = mocker.patch("ahriman.core.report.ReportTrigger.on_result")
upload_mock = mocker.patch("ahriman.core.upload.UploadTrigger.on_result")
Triggers.run(args, "x86_64", configuration, report=False)
_, 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()

View File

@ -32,7 +32,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
return_value=["command"])
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
UnsafeCommands.run(args, "x86_64", configuration, report=False)
_, 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)
@ -47,7 +48,8 @@ def test_run_check(args: argparse.Namespace, configuration: Configuration, mocke
return_value=["command"])
check_mock = mocker.patch("ahriman.application.handlers.UnsafeCommands.check_unsafe")
UnsafeCommands.run(args, "x86_64", configuration, report=False)
_, 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))

View File

@ -54,7 +54,8 @@ def test_run(args: argparse.Namespace, package_ahriman: Package, configuration:
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
print_mock = mocker.patch("ahriman.application.application.Application.print_updates")
Update.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Update.run(args, repository_id, configuration, report=False)
application_mock.assert_called_once_with([package_ahriman],
Packagers(args.username, {package_ahriman.base: "packager"}),
bump_pkgrel=args.increment)
@ -77,7 +78,8 @@ def test_run_empty_exception(args: argparse.Namespace, configuration: Configurat
mocker.patch("ahriman.application.application.Application.updates", return_value=[])
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
Update.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Update.run(args, repository_id, configuration, report=False)
check_mock.assert_called_once_with(True, True)
@ -95,7 +97,8 @@ def test_run_update_empty_exception(args: argparse.Namespace, package_ahriman: P
mocker.patch("ahriman.application.application.Application.print_updates")
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
Update.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Update.run(args, repository_id, configuration, report=False)
check_mock.assert_has_calls([MockCall(True, False), MockCall(True, True)])
@ -111,7 +114,8 @@ def test_run_dry_run(args: argparse.Namespace, configuration: Configuration, rep
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
updates_mock = mocker.patch("ahriman.application.application.Application.updates")
Update.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Update.run(args, repository_id, configuration, report=False)
updates_mock.assert_called_once_with(args.package, aur=args.aur, local=args.local, manual=args.manual, vcs=args.vcs)
application_mock.assert_not_called()
check_mock.assert_called_once_with(False, pytest.helpers.anyvar(int))

View File

@ -47,7 +47,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, database: S
create_user_mock = mocker.patch("ahriman.application.handlers.Users.user_create", return_value=user)
update_mock = mocker.patch("ahriman.core.database.SQLite.user_update")
Users.run(args, "x86_64", configuration, report=False)
_, 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)
@ -64,7 +65,8 @@ def test_run_empty_salt(args: argparse.Namespace, configuration: Configuration,
create_user_mock = mocker.patch("ahriman.application.handlers.Users.user_create", return_value=user)
update_mock = mocker.patch("ahriman.core.database.SQLite.user_update")
Users.run(args, "x86_64", configuration, report=False)
_, 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)
@ -83,7 +85,8 @@ def test_run_empty_salt_without_password(args: argparse.Namespace, configuration
create_user_mock = mocker.patch("ahriman.application.handlers.Users.user_create", return_value=user)
update_mock = mocker.patch("ahriman.core.database.SQLite.user_update")
Users.run(args, "x86_64", configuration, report=False)
_, 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)
@ -99,7 +102,8 @@ def test_run_list(args: argparse.Namespace, configuration: Configuration, databa
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
list_mock = mocker.patch("ahriman.core.database.SQLite.user_list", return_value=[user])
Users.run(args, "x86_64", configuration, report=False)
_, 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, False)
@ -116,7 +120,8 @@ def test_run_empty_exception(args: argparse.Namespace, configuration: Configurat
mocker.patch("ahriman.core.database.SQLite.user_list", return_value=[])
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
Users.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Users.run(args, repository_id, configuration, report=False)
check_mock.assert_called_once_with(True, True)
@ -130,7 +135,8 @@ def test_run_remove(args: argparse.Namespace, configuration: Configuration, data
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
remove_mock = mocker.patch("ahriman.core.database.SQLite.user_remove")
Users.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Users.run(args, repository_id, configuration, report=False)
remove_mock.assert_called_once_with(args.username)

View File

@ -33,8 +33,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
application_mock = mocker.patch("ahriman.core.configuration.validator.Validator.validate", return_value=False)
Validate.run(args, "x86_64", configuration, report=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)
@ -47,7 +47,8 @@ def test_run_skip(args: argparse.Namespace, configuration: Configuration, mocker
mocker.patch("ahriman.core.configuration.validator.Validator.validate", return_value=True)
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
Validate.run(args, "x86_64", configuration, report=False)
_, repository_id = configuration.check_loaded()
Validate.run(args, repository_id, configuration, report=False)
print_mock.assert_not_called()
@ -55,7 +56,8 @@ def test_schema(configuration: Configuration) -> None:
"""
must generate full schema correctly
"""
schema = Validate.schema("x86_64", configuration)
_, repository_id = configuration.check_loaded()
schema = Validate.schema(repository_id, configuration)
# defaults
assert schema.pop("console")
@ -86,7 +88,9 @@ def test_schema_invalid_trigger(configuration: Configuration) -> None:
"""
configuration.set_option("build", "triggers", "some.invalid.trigger.path.Trigger")
configuration.remove_option("build", "triggers_known")
assert Validate.schema("x86_64", configuration) == CONFIGURATION_SCHEMA
_, repository_id = configuration.check_loaded()
assert Validate.schema(repository_id, configuration) == CONFIGURATION_SCHEMA
def test_schema_erase_required() -> None:

View File

@ -14,7 +14,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
application_mock = mocker.patch("ahriman.application.handlers.Versions.package_dependencies")
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
Versions.run(args, "x86_64", configuration, report=False)
_, 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, separator=" "), MockCall(verbose=False, separator=" ")])

View File

@ -41,8 +41,9 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
stop_mock = mocker.patch("ahriman.core.spawn.Spawn.stop")
join_mock = mocker.patch("ahriman.core.spawn.Spawn.join")
Web.run(args, "x86_64", configuration, report=False)
setup_mock.assert_called_once_with("x86_64", configuration, pytest.helpers.anyvar(int))
_, repository_id = configuration.check_loaded()
Web.run(args, repository_id, configuration, report=False)
setup_mock.assert_called_once_with(repository_id, configuration, pytest.helpers.anyvar(int))
run_mock.assert_called_once_with(pytest.helpers.anyvar(int))
start_mock.assert_called_once_with()
stop_mock.assert_called_once_with()
@ -53,33 +54,35 @@ def test_extract_arguments(args: argparse.Namespace, configuration: Configuratio
"""
must extract correct args
"""
_, repository_id = configuration.check_loaded()
expected = [
"--architecture", "x86_64",
"--architecture", repository_id.architecture,
"--repository", repository_id.name,
"--configuration", str(configuration.path),
]
probe = _default_args(args)
assert list(Web.extract_arguments(probe, "x86_64", configuration)) == expected
assert list(Web.extract_arguments(probe, repository_id, configuration)) == expected
probe.force = True
expected.extend(["--force"])
assert list(Web.extract_arguments(probe, "x86_64", configuration)) == expected
assert list(Web.extract_arguments(probe, repository_id, configuration)) == expected
probe.log_handler = LogHandler.Console
expected.extend(["--log-handler", probe.log_handler.value])
assert list(Web.extract_arguments(probe, "x86_64", configuration)) == expected
assert list(Web.extract_arguments(probe, repository_id, configuration)) == expected
probe.quiet = True
expected.extend(["--quiet"])
assert list(Web.extract_arguments(probe, "x86_64", configuration)) == expected
assert list(Web.extract_arguments(probe, repository_id, configuration)) == expected
probe.unsafe = True
expected.extend(["--unsafe"])
assert list(Web.extract_arguments(probe, "x86_64", configuration)) == expected
assert list(Web.extract_arguments(probe, repository_id, configuration)) == expected
configuration.set_option("web", "wait_timeout", "60")
expected.extend(["--wait-timeout", "60"])
assert list(Web.extract_arguments(probe, "x86_64", configuration)) == expected
assert list(Web.extract_arguments(probe, repository_id, configuration)) == expected
def test_extract_arguments_full(parser: argparse.ArgumentParser, configuration: Configuration):
@ -101,8 +104,10 @@ def test_extract_arguments_full(parser: argparse.ArgumentParser, configuration:
value = action.type(value)
setattr(args, action.dest, value)
assert list(Web.extract_arguments(args, "x86_64", configuration)) == [
"--architecture", "x86_64",
_, repository_id = configuration.check_loaded()
assert list(Web.extract_arguments(args, repository_id, configuration)) == [
"--architecture", repository_id.architecture,
"--repository", repository_id.name,
"--configuration", str(configuration.path),
"--force",
"--log-handler", "console",

View File

@ -6,6 +6,7 @@ from pytest_mock import MockerFixture
from ahriman.application import ahriman
from ahriman.application.handlers import Handler
from ahriman.core.configuration import Configuration
from ahriman.models.action import Action
from ahriman.models.build_status import BuildStatusEnum
from ahriman.models.log_handler import LogHandler
@ -66,6 +67,14 @@ def test_multiple_architectures(parser: argparse.ArgumentParser) -> None:
assert args.architecture == ["x86_64", "i686"]
def test_multiple_repositories(parser: argparse.ArgumentParser) -> None:
"""
must accept multiple architectures
"""
args = parser.parse_args(["-r", "repo1", "-r", "repo2", "service-config"])
assert args.repository == ["repo1", "repo2"]
def test_subparsers_aur_search(parser: argparse.ArgumentParser) -> None:
"""
aur-search command must imply architecture list, lock, report, quiet and unsafe
@ -708,8 +717,7 @@ def test_subparsers_service_setup(parser: argparse.ArgumentParser) -> None:
"""
service-setup command must imply lock, report, quiet and unsafe
"""
args = parser.parse_args(["-a", "x86_64", "service-setup", "--packager", "John Doe <john@doe.com>",
"--repository", "aur-clone"])
args = parser.parse_args(["-a", "x86_64", "service-setup", "--packager", "John Doe <john@doe.com>"])
assert args.architecture == ["x86_64"]
assert args.lock is None
assert not args.report
@ -721,11 +729,10 @@ def test_subparsers_service_setup_option_from_configuration(parser: argparse.Arg
"""
service-setup command must convert from-configuration option to path instance
"""
args = parser.parse_args(["-a", "x86_64", "service-setup", "--packager", "John Doe <john@doe.com>",
"--repository", "aur-clone"])
args = parser.parse_args(["-a", "x86_64", "service-setup", "--packager", "John Doe <john@doe.com>"])
assert isinstance(args.from_configuration, Path)
args = parser.parse_args(["-a", "x86_64", "service-setup", "--packager", "John Doe <john@doe.com>",
"--repository", "aur-clone", "--from-configuration", "path"])
"--from-configuration", "path"])
assert isinstance(args.from_configuration, Path)
@ -734,7 +741,7 @@ def test_subparsers_service_setup_option_sign_target(parser: argparse.ArgumentPa
service-setup command must convert sign-target option to SignSettings instance
"""
args = parser.parse_args(["-a", "x86_64", "service-setup", "--packager", "John Doe <john@doe.com>",
"--repository", "aur-clone", "--sign-target", "packages"])
"--sign-target", "packages"])
assert args.sign_target
assert all(isinstance(target, SignSettings) for target in args.sign_target)
@ -837,11 +844,15 @@ def test_subparsers_web(parser: argparse.ArgumentParser) -> None:
assert args.parser is not None and args.parser()
def test_run(args: argparse.Namespace, mocker: MockerFixture) -> None:
def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
"""
application must be run
"""
args.architecture = "x86_64"
path, repository_id = configuration.check_loaded()
args.architecture = repository_id.architecture
args.repository = repository_id.name
args.configuration = path
args.command = ""
args.handler = Handler

View File

@ -18,14 +18,16 @@ def test_path(args: argparse.Namespace, configuration: Configuration) -> None:
"""
must create path variable correctly
"""
assert Lock(args, "x86_64", configuration).path is None
_, repository_id = configuration.check_loaded()
assert Lock(args, repository_id, configuration).path is None
args.lock = Path("/run/ahriman.lock")
assert Lock(args, "x86_64", configuration).path == Path("/run/ahriman_x86_64.lock")
assert Lock(args, repository_id, configuration).path == Path("/run/ahriman_aur-clone_x86_64.lock")
with pytest.raises(ValueError):
args.lock = Path("/")
Lock(args, "x86_64", configuration).path # special case
Lock(args, repository_id, configuration).path # special case
def test_check_version(lock: Lock, mocker: MockerFixture) -> None:

View File

@ -19,12 +19,13 @@ def test_init_with_local_cache(configuration: Configuration, mocker: MockerFixtu
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("x86_64", configuration, refresh_database=PacmanSynchronization.Enabled)
pacman = Pacman(repository_id, configuration, refresh_database=PacmanSynchronization.Enabled)
assert pacman.handle
sync_mock.assert_called_once_with(pytest.helpers.anyvar(int), force=False)
@ -36,12 +37,13 @@ def test_init_with_local_cache_forced(configuration: Configuration, mocker: Mock
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("x86_64", configuration, refresh_database=PacmanSynchronization.Force)
pacman = Pacman(repository_id, configuration, refresh_database=PacmanSynchronization.Force)
assert pacman.handle
sync_mock.assert_called_once_with(pytest.helpers.anyvar(int), force=True)
@ -128,8 +130,8 @@ def test_database_init(pacman: Pacman, configuration: Configuration) -> None:
must init database with settings
"""
mirror = configuration.get("alpm", "mirror")
database = pacman.database_init(pacman.handle, "test", mirror, "x86_64")
assert len(database.servers) == 1
database = pacman.database_init(pacman.handle, "testing", mirror, "x86_64")
assert database.servers == ["https://geo.mirror.pkgbuild.com/testing/os/x86_64"]
def test_database_sync(pacman: Pacman) -> None:

View File

@ -177,7 +177,7 @@ def test_load(package_ahriman: Package, repository_paths: RepositoryPaths, mocke
Sources.load(path, package_ahriman, [patch], repository_paths)
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.architecture)
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:

View File

@ -7,9 +7,17 @@ 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_name(configuration: Configuration) -> None:
"""
must return valid repository name
@ -24,7 +32,7 @@ def test_repository_paths(configuration: Configuration, repository_paths: Reposi
assert configuration.repository_paths == repository_paths
def test_from_path(mocker: MockerFixture) -> None:
def test_from_path(repository_id: RepositoryId, mocker: MockerFixture) -> None:
"""
must load configuration
"""
@ -33,13 +41,13 @@ def test_from_path(mocker: MockerFixture) -> None:
load_includes_mock = mocker.patch("ahriman.core.configuration.Configuration.load_includes")
path = Path("path")
configuration = Configuration.from_path(path, "x86_64")
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()
def test_from_path_file_missing(mocker: MockerFixture) -> None:
def test_from_path_file_missing(repository_id: RepositoryId, mocker: MockerFixture) -> None:
"""
must load configuration based on package files
"""
@ -47,17 +55,40 @@ def test_from_path_file_missing(mocker: MockerFixture) -> None:
mocker.patch("ahriman.core.configuration.Configuration.load_includes")
read_mock = mocker.patch("ahriman.core.configuration.Configuration.read")
configuration = Configuration.from_path(Path("path"), "x86_64")
configuration = Configuration.from_path(Path("path"), repository_id)
read_mock.assert_called_once_with(configuration.SYSTEM_CONFIGURATION_PATH)
def test_override_sections(repository_id: RepositoryId) -> None:
"""
must correctly generate override section names
"""
assert Configuration.override_sections("build", repository_id) == [
"build:x86_64",
"build:aur-clone",
"build:aur-clone:x86_64",
]
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-clone", "x86_64") == "build:aur-clone:x86_64"
assert configuration.section_name("build", "aur-clone", None) == "build:aur-clone"
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, architecture = configuration.check_loaded()
path, repository_id = configuration.check_loaded()
assert path == configuration.path
assert architecture == configuration.architecture
assert repository_id == configuration.repository_id
def test_check_loaded_path(configuration: Configuration) -> None:
@ -73,7 +104,7 @@ def test_check_loaded_architecture(configuration: Configuration) -> None:
"""
must raise exception if architecture is none
"""
configuration.architecture = None
configuration.repository_id = None
with pytest.raises(InitializeError):
configuration.check_loaded()
@ -89,9 +120,9 @@ def test_dump_architecture_specific(configuration: Configuration) -> None:
"""
dump must contain architecture specific settings
"""
section = configuration.section_name("build", "x86_64")
section = configuration.section_name("build", configuration.architecture)
configuration.set_option(section, "archbuild_flags", "hello flag")
configuration.merge_sections("x86_64")
configuration.merge_sections(configuration.repository_id)
dump = configuration.dump()
assert dump
@ -100,13 +131,6 @@ def test_dump_architecture_specific(configuration: Configuration) -> None:
assert dump["build"]["archbuild_flags"] == "hello flag"
def test_section_name(configuration: Configuration) -> None:
"""
must return architecture specific group
"""
assert configuration.section_name("build", "x86_64") == "build:x86_64"
def test_getlist(configuration: Configuration) -> None:
"""
must return list of string correctly
@ -209,7 +233,7 @@ def test_gettype(configuration: Configuration) -> None:
"""
must extract type from variable
"""
section, provider = configuration.gettype("customs3", "x86_64")
section, provider = configuration.gettype("customs3", configuration.repository_id)
assert section == "customs3"
assert provider == "s3"
@ -218,7 +242,7 @@ def test_gettype_with_fallback(configuration: Configuration) -> None:
"""
must return same provider name as in fallback
"""
section, provider = configuration.gettype("rsync", "x86_64", fallback="abracadabra")
section, provider = configuration.gettype("rsync", configuration.repository_id, fallback="abracadabra")
assert section == "rsync"
assert provider == "abracadabra"
@ -227,7 +251,7 @@ def test_gettype_from_section(configuration: Configuration) -> None:
"""
must extract type from section name
"""
section, provider = configuration.gettype("rsync", "x86_64")
section, provider = configuration.gettype("rsync", configuration.repository_id)
assert section == "rsync"
assert provider == "rsync"
@ -236,7 +260,7 @@ def test_gettype_from_section_with_architecture(configuration: Configuration) ->
"""
must extract type from section name with architecture
"""
section, provider = configuration.gettype("github", "x86_64")
section, provider = configuration.gettype("github", configuration.repository_id)
assert section == "github:x86_64"
assert provider == "github"
@ -248,7 +272,7 @@ def test_gettype_from_section_no_section(configuration: Configuration) -> None:
# 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", "x86_64")
configuration.gettype("rsync:x86_64", configuration.repository_id)
def test_load_includes_missing(configuration: Configuration) -> None:
@ -279,14 +303,44 @@ def test_merge_sections_missing(configuration: Configuration) -> None:
"""
must merge create section if not exists
"""
section = configuration.section_name("build", "x86_64")
section = configuration.section_name("build", configuration.architecture)
configuration.remove_section("build")
configuration.set_option(section, "key", "value")
configuration.merge_sections("x86_64")
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_reload(configuration: Configuration, mocker: MockerFixture) -> None:
"""
must reload configuration
@ -296,7 +350,7 @@ def test_reload(configuration: Configuration, mocker: MockerFixture) -> None:
configuration.reload()
load_mock.assert_called_once_with(configuration.path)
merge_mock.assert_called_once_with(configuration.architecture)
merge_mock.assert_called_once_with(configuration.repository_id)
def test_reload_clear(configuration: Configuration, mocker: MockerFixture) -> None:
@ -314,7 +368,7 @@ def test_reload_no_architecture(configuration: Configuration) -> None:
"""
must raise exception on reload if no architecture set
"""
configuration.architecture = None
configuration.repository_id = None
with pytest.raises(InitializeError):
configuration.reload()

View File

@ -2,10 +2,12 @@ import pytest
from sqlite3 import Connection
from pytest_mock import MockerFixture
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
@ -30,13 +32,18 @@ def test_migrate_package_remotes(package_ahriman: Package, connection: Connectio
"""
must put package remotes to database
"""
mocker.patch(
"ahriman.core.database.operations.PackageOperations._packages_get_select_package_bases",
return_value={package_ahriman.base: package_ahriman})
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_called_once_with(pytest.helpers.anyvar(str, strict=True), pytest.helpers.anyvar(int))
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,
@ -44,13 +51,15 @@ def test_migrate_package_remotes_has_local(package_ahriman: Package, connection:
"""
must skip processing for packages which have local cache
"""
mocker.patch(
"ahriman.core.database.operations.PackageOperations._packages_get_select_package_bases",
return_value={package_ahriman.base: package_ahriman})
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_not_called()
connection.execute.assert_called_once_with(pytest.helpers.anyvar(str, strict=True))
def test_migrate_package_remotes_vcs(package_ahriman: Package, connection: Connection,
@ -58,11 +67,16 @@ def test_migrate_package_remotes_vcs(package_ahriman: Package, connection: Conne
"""
must process VCS packages with local cache
"""
mocker.patch(
"ahriman.core.database.operations.PackageOperations._packages_get_select_package_bases",
return_value={package_ahriman.base: package_ahriman})
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_called_once_with(pytest.helpers.anyvar(str, strict=True), pytest.helpers.anyvar(int))
connection.execute.assert_has_calls([
MockCall(pytest.helpers.anyvar(str, strict=True)),
MockCall(pytest.helpers.anyvar(str, strict=True), pytest.helpers.anyvar(int)),
])

View File

@ -0,0 +1,43 @@
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_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
"""
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_name, "architecture": configuration.architecture}),
MockCall(pytest.helpers.anyvar(str, strict=True),
{"repository": configuration.repository_name, "architecture": configuration.architecture}),
MockCall(pytest.helpers.anyvar(str, strict=True),
{"repository": configuration.repository_name, "architecture": configuration.architecture}),
MockCall(pytest.helpers.anyvar(str, strict=True), {"repository": configuration.repository_name}),
MockCall(pytest.helpers.anyvar(str, strict=True),
{"repository": configuration.repository_name, "architecture": configuration.architecture}),
])

View File

@ -1,5 +1,6 @@
from ahriman.core.database import SQLite
from ahriman.models.package import Package
from ahriman.models.repository_id import RepositoryId
def test_build_queue_insert_clear(database: SQLite, package_ahriman: Package, package_python_schedule: Package) -> None:
@ -13,6 +14,19 @@ def test_build_queue_insert_clear(database: SQLite, package_ahriman: Package, pa
assert not database.build_queue_get()
def test_build_queue_insert_clear_multi(database: SQLite, package_ahriman: Package) -> None:
"""
must clear all packages from queue for specific repository
"""
database.build_queue_insert(package_ahriman)
database.repository_id = RepositoryId("i686", database.repository_id.name)
database.build_queue_insert(package_ahriman)
database.build_queue_clear(None)
database.repository_id = RepositoryId("x86_64", database.repository_id.name)
assert database.build_queue_get() == [package_ahriman]
def test_build_queue_insert_clear_specific(database: SQLite, package_ahriman: Package,
package_python_schedule: Package) -> None:
"""
@ -43,3 +57,30 @@ def test_build_queue_insert(database: SQLite, package_ahriman: Package) -> None:
package_ahriman.version = "42"
database.build_queue_insert(package_ahriman)
assert database.build_queue_get() == [package_ahriman]
def test_build_queue_insert_multi(database: SQLite, package_ahriman: Package) -> None:
"""
must update build queue in the database for multiple architectures and repositories
"""
package_ahriman.version = "1"
database.build_queue_insert(package_ahriman)
assert database.build_queue_get() == [package_ahriman]
package_ahriman.version = "2"
database.repository_id = RepositoryId("i686", database.repository_id.name)
database.build_queue_insert(package_ahriman)
assert database.build_queue_get() == [package_ahriman]
package_ahriman.version = "1"
database.repository_id = RepositoryId("x86_64", database.repository_id.name)
assert database.build_queue_get() == [package_ahriman]
package_ahriman.version = "3"
database.repository_id = RepositoryId(database.repository_id.architecture, "repo")
database.build_queue_insert(package_ahriman)
assert database.build_queue_get() == [package_ahriman]
package_ahriman.version = "1"
database.repository_id = RepositoryId(database.repository_id.architecture, "aur-clone")
assert database.build_queue_get() == [package_ahriman]

View File

@ -1,12 +1,13 @@
from ahriman.core.database import SQLite
from ahriman.models.log_record_id import LogRecordId
from ahriman.models.package import Package
from ahriman.models.repository_id import RepositoryId
def test_logs_insert_remove_process(database: SQLite, package_ahriman: Package,
def test_logs_insert_remove_version(database: SQLite, package_ahriman: Package,
package_python_schedule: Package) -> None:
"""
must clear process specific package logs
must clear version specific package logs
"""
database.logs_insert(LogRecordId(package_ahriman.base, "1"), 42.0, "message 1")
database.logs_insert(LogRecordId(package_ahriman.base, "2"), 43.0, "message 2")
@ -17,6 +18,20 @@ def test_logs_insert_remove_process(database: SQLite, package_ahriman: Package,
assert database.logs_get(package_python_schedule.base) == [(42.0, "message 3")]
def test_logs_insert_remove_multi(database: SQLite, package_ahriman: Package) -> None:
"""
must clear logs for specified repository
"""
database.logs_insert(LogRecordId(package_ahriman.base, "1"), 42.0, "message 1")
database.repository_id = RepositoryId("i686", database.repository_id.name)
database.logs_insert(LogRecordId(package_ahriman.base, "1"), 43.0, "message 2")
database.logs_remove(package_ahriman.base, None)
assert not database.logs_get(package_ahriman.base)
database.repository_id = RepositoryId("x86_64", database.repository_id.name)
assert database.logs_get(package_ahriman.base) == "[1970-01-01 00:00:42] message 1"
def test_logs_insert_remove_full(database: SQLite, package_ahriman: Package, package_python_schedule: Package) -> None:
"""
must clear full package logs
@ -46,3 +61,16 @@ def test_logs_insert_get_pagination(database: SQLite, package_ahriman: Package)
database.logs_insert(LogRecordId(package_ahriman.base, "1"), 42.0, "message 1")
database.logs_insert(LogRecordId(package_ahriman.base, "1"), 43.0, "message 2")
assert database.logs_get(package_ahriman.base, 1, 1) == [(43.0, "message 2")]
def test_logs_insert_get_multi(database: SQLite, package_ahriman: Package) -> None:
"""
must insert and get package logs for multiple repositories
"""
database.logs_insert(LogRecordId(package_ahriman.base, "1"), 42.0, "message 1")
database.repository_id = RepositoryId("i686", database.repository_id.name)
database.logs_insert(LogRecordId(package_ahriman.base, "1"), 43.0, "message 2")
assert database.logs_get(package_ahriman.base) == [(43.0, "message 2")]
database.repository_id = RepositoryId("x86_64", database.repository_id.name)
assert database.logs_get(package_ahriman.base) == [(42.0, "message 1")]

View File

@ -16,9 +16,14 @@ def test_package_remove_package_base(database: SQLite, connection: Connection) -
must remove package base
"""
database._package_remove_package_base(connection, "package")
args = {
"package_base": "package",
"repository": database.repository_id.name,
"architecture": database.repository_id.architecture,
}
connection.execute.assert_has_calls([
MockCall(pytest.helpers.anyvar(str, strict=True), {"package_base": "package"}),
MockCall(pytest.helpers.anyvar(str, strict=True), {"package_base": "package"}),
MockCall(pytest.helpers.anyvar(str, strict=True), args),
MockCall(pytest.helpers.anyvar(str, strict=True), args),
])
@ -28,7 +33,11 @@ def test_package_remove_packages(database: SQLite, connection: Connection, packa
"""
database._package_remove_packages(connection, package_ahriman.base, package_ahriman.packages.keys())
connection.execute.assert_called_once_with(
pytest.helpers.anyvar(str, strict=True), {"package_base": package_ahriman.base})
pytest.helpers.anyvar(str, strict=True), {
"package_base": package_ahriman.base,
"repository": database.repository_id.name,
"architecture": database.repository_id.architecture,
})
connection.executemany.assert_called_once_with(pytest.helpers.anyvar(str, strict=True), [])

View File

@ -16,7 +16,8 @@ def test_repo_clone(configuration: Configuration, mocker: MockerFixture) -> None
"""
fetch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
copy_mock = mocker.patch("ahriman.core.gitremote.remote_pull.RemotePull.repo_copy")
runner = RemotePull(configuration, "x86_64", "gitremote")
_, repository_id = configuration.check_loaded()
runner = RemotePull(repository_id, configuration, "gitremote")
runner.repo_clone()
fetch_mock.assert_called_once_with(pytest.helpers.anyvar(int), runner.remote_source)
@ -32,7 +33,8 @@ def test_package_copy(configuration: Configuration, package_ahriman: Package, mo
ignore_patterns_mock = mocker.patch("shutil.ignore_patterns", return_value=patterns)
copytree_mock = mocker.patch("shutil.copytree")
init_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.init")
runner = RemotePull(configuration, "x86_64", "gitremote")
_, repository_id = configuration.check_loaded()
runner = RemotePull(repository_id, configuration, "gitremote")
local = Path("local")
runner.package_copy(local / "PKGBUILD")
@ -57,7 +59,8 @@ def test_repo_copy(configuration: Configuration, mocker: MockerFixture) -> None:
local / "package3" / ".SRCINFO",
])
copy_mock = mocker.patch("ahriman.core.gitremote.remote_pull.RemotePull.package_copy")
runner = RemotePull(configuration, "x86_64", "gitremote")
_, repository_id = configuration.check_loaded()
runner = RemotePull(repository_id, configuration, "gitremote")
runner.repo_copy(local)
copy_mock.assert_has_calls([
@ -71,7 +74,8 @@ def test_run(configuration: Configuration, mocker: MockerFixture) -> None:
must clone repo on run
"""
clone_mock = mocker.patch("ahriman.core.gitremote.remote_pull.RemotePull.repo_clone")
runner = RemotePull(configuration, "x86_64", "gitremote")
_, repository_id = configuration.check_loaded()
runner = RemotePull(repository_id, configuration, "gitremote")
runner.run()
clone_mock.assert_called_once_with()
@ -82,7 +86,8 @@ def test_run_failed(configuration: Configuration, mocker: MockerFixture) -> None
must reraise exception on error occurred
"""
mocker.patch("ahriman.core.gitremote.remote_pull.RemotePull.repo_clone", side_effect=Exception())
runner = RemotePull(configuration, "x86_64", "gitremote")
_, repository_id = configuration.check_loaded()
runner = RemotePull(repository_id, configuration, "gitremote")
with pytest.raises(GitRemoteError):
runner.run()

View File

@ -20,7 +20,8 @@ def test_on_start(configuration: Configuration, mocker: MockerFixture) -> None:
must clone repo on start
"""
run_mock = mocker.patch("ahriman.core.gitremote.remote_pull.RemotePull.run")
trigger = RemotePullTrigger("x86_64", configuration)
_, repository_id = configuration.check_loaded()
trigger = RemotePullTrigger(repository_id, configuration)
trigger.on_start()
run_mock.assert_called_once_with()

View File

@ -26,7 +26,8 @@ def test_on_result(configuration: Configuration, result: Result, package_ahriman
"""
database_mock = mocker.patch("ahriman.core._Context.get", return_value=database)
run_mock = mocker.patch("ahriman.core.gitremote.remote_push.RemotePush.run")
trigger = RemotePushTrigger("x86_64", configuration)
_, repository_id = configuration.check_loaded()
trigger = RemotePushTrigger(repository_id, configuration)
trigger.on_result(result, [package_ahriman])
database_mock.assert_called_once_with(ContextKey("database", SQLite))

View File

@ -22,7 +22,7 @@ def test_init_auth(configuration: Configuration) -> None:
configuration.set_option("web", "username", "username")
configuration.set_option("web", "password", "password")
assert SyncHttpClient("web", configuration).auth == ("username", "password")
assert SyncHttpClient(configuration, "web").auth == ("username", "password")
assert SyncHttpClient(configuration=configuration).auth is None

View File

@ -7,7 +7,7 @@ from pytest_mock import MockerFixture
from systemd.journal import JournalHandler
from ahriman.core.configuration import Configuration
from ahriman.core.log.log_loader import LogLoader
from ahriman.core.log import Log
from ahriman.models.log_handler import LogHandler
@ -15,14 +15,14 @@ def test_handler() -> None:
"""
must extract journald handler if available
"""
assert LogLoader.handler(None) == LogHandler.Journald
assert Log.handler(None) == LogHandler.Journald
def test_handler_selected() -> None:
"""
must return selected log handler
"""
assert LogLoader.handler(LogHandler.Console) == LogHandler.Console
assert Log.handler(LogHandler.Console) == LogHandler.Console
def test_handler_syslog(mocker: MockerFixture) -> None:
@ -31,7 +31,7 @@ def test_handler_syslog(mocker: MockerFixture) -> None:
"""
mocker.patch("pathlib.Path.exists", return_value=True)
mocker.patch.dict(sys.modules, {"systemd.journal": None})
assert LogLoader.handler(None) == LogHandler.Syslog
assert Log.handler(None) == LogHandler.Syslog
def test_handler_console(mocker: MockerFixture) -> None:
@ -40,17 +40,17 @@ def test_handler_console(mocker: MockerFixture) -> None:
"""
mocker.patch("pathlib.Path.exists", return_value=False)
mocker.patch.dict(sys.modules, {"systemd.journal": None})
assert LogLoader.handler(None) == LogHandler.Console
assert Log.handler(None) == LogHandler.Console
def test_load(configuration: Configuration, mocker: MockerFixture) -> None:
"""
must load logging
"""
logging_mock = mocker.patch("ahriman.core.log.log_loader.fileConfig", side_effect=fileConfig)
logging_mock = mocker.patch("ahriman.core.log.log.fileConfig", side_effect=fileConfig)
http_log_mock = mocker.patch("ahriman.core.log.http_log_handler.HttpLogHandler.load")
LogLoader.load(configuration, LogHandler.Journald, quiet=False, report=False)
Log.load(configuration, LogHandler.Journald, quiet=False, report=False)
logging_mock.assert_called_once_with(pytest.helpers.anyvar(int), disable_existing_loggers=True)
http_log_mock.assert_called_once_with(configuration, report=False)
assert all(isinstance(handler, JournalHandler) for handler in logging.getLogger().handlers)
@ -60,8 +60,8 @@ def test_load_fallback(configuration: Configuration, mocker: MockerFixture) -> N
"""
must fall back to stderr without errors
"""
mocker.patch("ahriman.core.log.log_loader.fileConfig", side_effect=PermissionError())
LogLoader.load(configuration, LogHandler.Journald, quiet=False, report=False)
mocker.patch("ahriman.core.log.log.fileConfig", side_effect=PermissionError())
Log.load(configuration, LogHandler.Journald, quiet=False, report=False)
def test_load_quiet(configuration: Configuration, mocker: MockerFixture) -> None:
@ -69,5 +69,5 @@ def test_load_quiet(configuration: Configuration, mocker: MockerFixture) -> None
must disable logging in case if quiet flag set
"""
disable_mock = mocker.patch("logging.disable")
LogLoader.load(configuration, LogHandler.Journald, quiet=True, report=False)
Log.load(configuration, LogHandler.Journald, quiet=True, report=False)
disable_mock.assert_called_once_with(logging.WARNING)

View File

@ -1,7 +1,24 @@
import pytest
from ahriman.core.configuration import Configuration
from ahriman.core.report.email import Email
from ahriman.core.report.remote_call import RemoteCall
from ahriman.core.report.telegram import Telegram
@pytest.fixture
def email(configuration: Configuration) -> Email:
"""
fixture for email trigger
Args:
configuration(Configuration): configuration fixture
Returns:
RemoteCall: email trigger test instance
"""
_, repository_id = configuration.check_loaded()
return Email(repository_id, configuration, "email")
@pytest.fixture
@ -19,3 +36,18 @@ def remote_call(configuration: Configuration) -> RemoteCall:
configuration.set_option("web", "port", "8080")
_, repository_id = configuration.check_loaded()
return RemoteCall(repository_id, configuration, "remote-call")
@pytest.fixture
def telegram(configuration: Configuration) -> Telegram:
"""
fixture for telegram trigger
Args:
configuration(Configuration): configuration fixture
Returns:
RemoteCall: telegram trigger test instance
"""
_, repository_id = configuration.check_loaded()
return Telegram(repository_id, configuration, "telegram")

View File

@ -14,7 +14,8 @@ def test_generate(configuration: Configuration, result: Result, package_python_s
"""
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
result.add_failed(package_python_schedule)
report = Console("x86_64", configuration, "console")
_, repository_id = configuration.check_loaded()
report = Console(repository_id, configuration, "console")
report.generate([], result)
print_mock.assert_has_calls([MockCall(verbose=True), MockCall(verbose=True)])

View File

@ -8,17 +8,16 @@ from ahriman.models.package import Package
from ahriman.models.result import Result
def test_send(configuration: Configuration, mocker: MockerFixture) -> None:
def test_send(email: Email, mocker: MockerFixture) -> None:
"""
must send an email with attachment
"""
smtp_mock = mocker.patch("smtplib.SMTP")
report = Email("x86_64", configuration, "email")
report._send("a text", {"attachment.html": "an attachment"})
email._send("a text", {"attachment.html": "an attachment"})
smtp_mock.return_value.starttls.assert_not_called()
smtp_mock.return_value.login.assert_not_called()
smtp_mock.return_value.sendmail.assert_called_once_with(report.sender, report.receivers, pytest.helpers.anyvar(int))
smtp_mock.return_value.sendmail.assert_called_once_with(email.sender, email.receivers, pytest.helpers.anyvar(int))
smtp_mock.return_value.quit.assert_called_once_with()
@ -29,10 +28,11 @@ def test_send_auth(configuration: Configuration, mocker: MockerFixture) -> None:
configuration.set_option("email", "user", "username")
configuration.set_option("email", "password", "password")
smtp_mock = mocker.patch("smtplib.SMTP")
_, repository_id = configuration.check_loaded()
report = Email("x86_64", configuration, "email")
report._send("a text", {"attachment.html": "an attachment"})
smtp_mock.return_value.login.assert_called_once_with(report.user, report.password)
email = Email(repository_id, configuration, "email")
email._send("a text", {"attachment.html": "an attachment"})
smtp_mock.return_value.login.assert_called_once_with(email.user, email.password)
def test_send_auth_no_password(configuration: Configuration, mocker: MockerFixture) -> None:
@ -41,9 +41,10 @@ def test_send_auth_no_password(configuration: Configuration, mocker: MockerFixtu
"""
configuration.set_option("email", "user", "username")
smtp_mock = mocker.patch("smtplib.SMTP")
_, repository_id = configuration.check_loaded()
report = Email("x86_64", configuration, "email")
report._send("a text", {"attachment.html": "an attachment"})
email = Email(repository_id, configuration, "email")
email._send("a text", {"attachment.html": "an attachment"})
smtp_mock.return_value.login.assert_not_called()
@ -53,9 +54,10 @@ def test_send_auth_no_user(configuration: Configuration, mocker: MockerFixture)
"""
configuration.set_option("email", "password", "password")
smtp_mock = mocker.patch("smtplib.SMTP")
_, repository_id = configuration.check_loaded()
report = Email("x86_64", configuration, "email")
report._send("a text", {"attachment.html": "an attachment"})
email = Email(repository_id, configuration, "email")
email._send("a text", {"attachment.html": "an attachment"})
smtp_mock.return_value.login.assert_not_called()
@ -65,12 +67,13 @@ def test_send_ssl_tls(configuration: Configuration, mocker: MockerFixture) -> No
"""
configuration.set_option("email", "ssl", "ssl")
smtp_mock = mocker.patch("smtplib.SMTP_SSL")
_, repository_id = configuration.check_loaded()
report = Email("x86_64", configuration, "email")
report._send("a text", {"attachment.html": "an attachment"})
email = Email(repository_id, configuration, "email")
email._send("a text", {"attachment.html": "an attachment"})
smtp_mock.return_value.starttls.assert_not_called()
smtp_mock.return_value.login.assert_not_called()
smtp_mock.return_value.sendmail.assert_called_once_with(report.sender, report.receivers, pytest.helpers.anyvar(int))
smtp_mock.return_value.sendmail.assert_called_once_with(email.sender, email.receivers, pytest.helpers.anyvar(int))
smtp_mock.return_value.quit.assert_called_once_with()
@ -80,48 +83,40 @@ def test_send_starttls(configuration: Configuration, mocker: MockerFixture) -> N
"""
configuration.set_option("email", "ssl", "starttls")
smtp_mock = mocker.patch("smtplib.SMTP")
_, repository_id = configuration.check_loaded()
report = Email("x86_64", configuration, "email")
report._send("a text", {"attachment.html": "an attachment"})
email = Email(repository_id, configuration, "email")
email._send("a text", {"attachment.html": "an attachment"})
smtp_mock.return_value.starttls.assert_called_once_with()
def test_generate(configuration: Configuration, package_ahriman: Package, mocker: MockerFixture) -> None:
def test_generate(email: Email, package_ahriman: Package, mocker: MockerFixture) -> None:
"""
must generate report
"""
send_mock = mocker.patch("ahriman.core.report.email.Email._send")
report = Email("x86_64", configuration, "email")
report.generate([package_ahriman], Result())
email.generate([package_ahriman], Result())
send_mock.assert_called_once_with(pytest.helpers.anyvar(int), {})
def test_generate_with_built(configuration: Configuration, package_ahriman: Package, result: Result,
mocker: MockerFixture) -> None:
def test_generate_with_built(email: Email, package_ahriman: Package, result: Result, mocker: MockerFixture) -> None:
"""
must generate report with built packages
"""
send_mock = mocker.patch("ahriman.core.report.email.Email._send")
report = Email("x86_64", configuration, "email")
report.generate([package_ahriman], result)
email.generate([package_ahriman], result)
send_mock.assert_called_once_with(pytest.helpers.anyvar(int), {})
def test_generate_with_built_and_full_path(
configuration: Configuration,
package_ahriman: Package,
result: Result,
mocker: MockerFixture) -> None:
def test_generate_with_built_and_full_path(email: Email, package_ahriman: Package, result: Result,
mocker: MockerFixture) -> None:
"""
must generate report with built packages and full packages lists
"""
send_mock = mocker.patch("ahriman.core.report.email.Email._send")
report = Email("x86_64", configuration, "email")
report.full_template_path = report.template_path
report.generate([package_ahriman], result)
email.full_template_path = email.template_path
email.generate([package_ahriman], result)
send_mock.assert_called_once_with(pytest.helpers.anyvar(int), pytest.helpers.anyvar(int))
@ -131,9 +126,10 @@ def test_generate_no_empty(configuration: Configuration, package_ahriman: Packag
"""
configuration.set_option("email", "no_empty_report", "yes")
send_mock = mocker.patch("ahriman.core.report.email.Email._send")
_, repository_id = configuration.check_loaded()
report = Email("x86_64", configuration, "email")
report.generate([package_ahriman], Result())
email = Email(repository_id, configuration, "email")
email.generate([package_ahriman], Result())
send_mock.assert_not_called()
@ -144,7 +140,8 @@ def test_generate_no_empty_with_built(configuration: Configuration, package_ahri
"""
configuration.set_option("email", "no_empty_report", "yes")
send_mock = mocker.patch("ahriman.core.report.email.Email._send")
_, repository_id = configuration.check_loaded()
report = Email("x86_64", configuration, "email")
report.generate([package_ahriman], result)
email = Email(repository_id, configuration, "email")
email.generate([package_ahriman], result)
send_mock.assert_called_once_with(pytest.helpers.anyvar(int), {})

View File

@ -13,7 +13,8 @@ def test_generate(configuration: Configuration, package_ahriman: Package, mocker
must generate report
"""
write_mock = mocker.patch("pathlib.Path.write_text")
_, repository_id = configuration.check_loaded()
report = HTML("x86_64", configuration, "html")
report = HTML(repository_id, configuration, "html")
report.generate([package_ahriman], Result())
write_mock.assert_called_once_with(pytest.helpers.anyvar(int), encoding="utf8")

View File

@ -9,5 +9,6 @@ def test_generate(configuration: Configuration, package_ahriman: Package) -> Non
must generate html report
"""
path = configuration.getpath("html", "template_path")
report = JinjaTemplate("html", configuration)
_, repository_id = configuration.check_loaded()
report = JinjaTemplate(repository_id, configuration, "html")
assert report.make_html(Result(success=[package_ahriman]), path)

View File

@ -14,8 +14,10 @@ def test_report_failure(configuration: Configuration, mocker: MockerFixture) ->
must raise ReportFailed on errors
"""
mocker.patch("ahriman.core.report.html.HTML.generate", side_effect=Exception())
_, repository_id = configuration.check_loaded()
with pytest.raises(ReportError):
Report.load("x86_64", configuration, "html").run(Result(), [])
Report.load(repository_id, configuration, "html").run(Result(), [])
def test_report_dummy(configuration: Configuration, result: Result, mocker: MockerFixture) -> None:
@ -24,8 +26,9 @@ def test_report_dummy(configuration: Configuration, result: Result, mocker: Mock
"""
mocker.patch("ahriman.models.report_settings.ReportSettings.from_option", return_value=ReportSettings.Disabled)
report_mock = mocker.patch("ahriman.core.report.report.Report.generate")
_, repository_id = configuration.check_loaded()
Report.load("x86_64", configuration, "disabled").run(result, [])
Report.load(repository_id, configuration, "disabled").run(result, [])
report_mock.assert_called_once_with([], result)
@ -34,7 +37,9 @@ def test_report_console(configuration: Configuration, result: Result, mocker: Mo
must generate console report
"""
report_mock = mocker.patch("ahriman.core.report.console.Console.generate")
Report.load("x86_64", configuration, "console").run(result, [])
_, repository_id = configuration.check_loaded()
Report.load(repository_id, configuration, "console").run(result, [])
report_mock.assert_called_once_with([], result)
@ -43,7 +48,9 @@ def test_report_email(configuration: Configuration, result: Result, mocker: Mock
must generate email report
"""
report_mock = mocker.patch("ahriman.core.report.email.Email.generate")
Report.load("x86_64", configuration, "email").run(result, [])
_, repository_id = configuration.check_loaded()
Report.load(repository_id, configuration, "email").run(result, [])
report_mock.assert_called_once_with([], result)
@ -52,7 +59,9 @@ def test_report_html(configuration: Configuration, result: Result, mocker: Mocke
must generate html report
"""
report_mock = mocker.patch("ahriman.core.report.html.HTML.generate")
Report.load("x86_64", configuration, "html").run(result, [])
_, repository_id = configuration.check_loaded()
Report.load(repository_id, configuration, "html").run(result, [])
report_mock.assert_called_once_with([], result)
@ -63,8 +72,9 @@ def test_report_remote_call(configuration: Configuration, result: Result, mocker
configuration.set_option("web", "host", "localhost")
configuration.set_option("web", "port", "8080")
report_mock = mocker.patch("ahriman.core.report.remote_call.RemoteCall.generate")
_, repository_id = configuration.check_loaded()
Report.load("x86_64", configuration, "remote-call").run(result, [])
Report.load(repository_id, configuration, "remote-call").run(result, [])
report_mock.assert_called_once_with([], result)
@ -73,5 +83,7 @@ def test_report_telegram(configuration: Configuration, result: Result, mocker: M
must generate telegram report
"""
report_mock = mocker.patch("ahriman.core.report.telegram.Telegram.generate")
Report.load("x86_64", configuration, "telegram").run(result, [])
_, repository_id = configuration.check_loaded()
Report.load(repository_id, configuration, "telegram").run(result, [])
report_mock.assert_called_once_with([], result)

View File

@ -22,7 +22,8 @@ def test_on_result(configuration: Configuration, mocker: MockerFixture) -> None:
"""
configuration.set_option("report", "target", "email")
run_mock = mocker.patch("ahriman.core.report.report.Report.run")
_, repository_id = configuration.check_loaded()
trigger = ReportTrigger("x86_64", configuration)
trigger = ReportTrigger(repository_id, configuration)
trigger.on_result(Result(), [])
run_mock.assert_called_once_with(Result(), [])

View File

@ -10,67 +10,58 @@ from ahriman.models.package import Package
from ahriman.models.result import Result
def test_send(configuration: Configuration, mocker: MockerFixture) -> None:
def test_send(telegram: Telegram, mocker: MockerFixture) -> None:
"""
must send a message
"""
request_mock = mocker.patch("ahriman.core.report.telegram.Telegram.make_request")
report = Telegram("x86_64", configuration, "telegram")
report._send("a text")
telegram._send("a text")
request_mock.assert_called_once_with(
"POST",
pytest.helpers.anyvar(str, strict=True),
data={"chat_id": pytest.helpers.anyvar(str, strict=True), "text": "a text", "parse_mode": "HTML"})
def test_send_failed(configuration: Configuration, mocker: MockerFixture) -> None:
def test_send_failed(telegram: Telegram, mocker: MockerFixture) -> None:
"""
must reraise generic exception
"""
mocker.patch("requests.Session.request", side_effect=Exception())
report = Telegram("x86_64", configuration, "telegram")
with pytest.raises(Exception):
report._send("a text")
telegram._send("a text")
def test_send_failed_http_error(configuration: Configuration, mocker: MockerFixture) -> None:
def test_send_failed_http_error(telegram: Telegram, mocker: MockerFixture) -> None:
"""
must reraise http exception
"""
mocker.patch("requests.Session.request", side_effect=requests.HTTPError())
report = Telegram("x86_64", configuration, "telegram")
with pytest.raises(requests.HTTPError):
report._send("a text")
telegram._send("a text")
def test_generate(configuration: Configuration, package_ahriman: Package, result: Result,
def test_generate(telegram: Telegram, package_ahriman: Package, result: Result,
mocker: MockerFixture) -> None:
"""
must generate report
"""
send_mock = mocker.patch("ahriman.core.report.telegram.Telegram._send")
report = Telegram("x86_64", configuration, "telegram")
report.generate([package_ahriman], result)
telegram.generate([package_ahriman], result)
send_mock.assert_called_once_with(pytest.helpers.anyvar(int))
def test_generate_big_text_without_spaces(configuration: Configuration, package_ahriman: Package, result: Result,
def test_generate_big_text_without_spaces(telegram: Telegram, package_ahriman: Package, result: Result,
mocker: MockerFixture) -> None:
"""
must raise ValueError in case if there are no new lines in text
"""
mocker.patch("ahriman.core.report.jinja_template.JinjaTemplate.make_html", return_value="ab" * 4096)
report = Telegram("x86_64", configuration, "telegram")
with pytest.raises(ValueError):
report.generate([package_ahriman], result)
telegram.generate([package_ahriman], result)
def test_generate_big_text(configuration: Configuration, package_ahriman: Package, result: Result,
def test_generate_big_text(telegram: Telegram, package_ahriman: Package, result: Result,
mocker: MockerFixture) -> None:
"""
must generate report with big text
@ -78,14 +69,13 @@ def test_generate_big_text(configuration: Configuration, package_ahriman: Packag
mocker.patch("ahriman.core.report.jinja_template.JinjaTemplate.make_html", return_value="a\n" * 4096)
send_mock = mocker.patch("ahriman.core.report.telegram.Telegram._send")
report = Telegram("x86_64", configuration, "telegram")
report.generate([package_ahriman], result)
telegram.generate([package_ahriman], result)
send_mock.assert_has_calls([
MockCall(pytest.helpers.anyvar(str, strict=True)), MockCall(pytest.helpers.anyvar(str, strict=True))
])
def test_generate_very_big_text(configuration: Configuration, package_ahriman: Package, result: Result,
def test_generate_very_big_text(telegram: Telegram, package_ahriman: Package, result: Result,
mocker: MockerFixture) -> None:
"""
must generate report with very big text
@ -93,8 +83,7 @@ def test_generate_very_big_text(configuration: Configuration, package_ahriman: P
mocker.patch("ahriman.core.report.jinja_template.JinjaTemplate.make_html", return_value="ab\n" * 4096)
send_mock = mocker.patch("ahriman.core.report.telegram.Telegram._send")
report = Telegram("x86_64", configuration, "telegram")
report.generate([package_ahriman], result)
telegram.generate([package_ahriman], result)
send_mock.assert_has_calls([
MockCall(pytest.helpers.anyvar(str, strict=True)),
MockCall(pytest.helpers.anyvar(str, strict=True)),
@ -102,12 +91,10 @@ def test_generate_very_big_text(configuration: Configuration, package_ahriman: P
])
def test_generate_no_empty(configuration: Configuration, package_ahriman: Package, mocker: MockerFixture) -> None:
def test_generate_no_empty(telegram: Telegram, package_ahriman: Package, mocker: MockerFixture) -> None:
"""
must generate report
"""
send_mock = mocker.patch("ahriman.core.report.telegram.Telegram._send")
report = Telegram("x86_64", configuration, "telegram")
report.generate([package_ahriman], Result())
telegram.generate([package_ahriman], Result())
send_mock.assert_not_called()

View File

@ -20,7 +20,9 @@ def test_load(configuration: Configuration, database: SQLite, mocker: MockerFixt
must correctly load instance
"""
context_mock = mocker.patch("ahriman.core.repository.Repository._set_context")
Repository.load("x86_64", configuration, database, report=False)
_, repository_id = configuration.check_loaded()
Repository.load(repository_id, configuration, database, report=False)
context_mock.assert_called_once_with()
@ -29,8 +31,9 @@ def test_set_context(configuration: Configuration, database: SQLite, mocker: Moc
must set context variables
"""
set_mock = mocker.patch("ahriman.core._Context.set")
_, repository_id = configuration.check_loaded()
instance = Repository.load("x86_64", configuration, database, report=False)
instance = Repository.load(repository_id, configuration, database, report=False)
set_mock.assert_has_calls([
MockCall(ContextKey("database", SQLite), instance.database),
MockCall(ContextKey("configuration", Configuration), instance.configuration),

View File

@ -6,6 +6,20 @@ from ahriman.models.user import User
from ahriman.models.user_access import UserAccess
def test_architecture(repository: RepositoryProperties) -> None:
"""
must provide repository architecture for backward compatibility
"""
assert repository.architecture == repository.repository_id.architecture
def test_name(repository: RepositoryProperties) -> None:
"""
must provide repository name for backward compatibility
"""
assert repository.name == repository.repository_id.name
def test_packager(repository: RepositoryProperties, mocker: MockerFixture) -> None:
"""
must extract packager

View File

@ -17,9 +17,10 @@ def test_force_no_report(configuration: Configuration, database: SQLite, mocker:
"""
configuration.set_option("web", "port", "8080")
load_mock = mocker.patch("ahriman.core.repository.Repository.load")
_, repository_id = configuration.check_loaded()
Watcher("x86_64", configuration, database)
load_mock.assert_called_once_with("x86_64", configuration, database, report=False)
Watcher(repository_id, configuration, database)
load_mock.assert_called_once_with(repository_id, configuration, database, report=False)
def test_load(watcher: Watcher, package_ahriman: Package, mocker: MockerFixture) -> None:

View File

@ -16,7 +16,8 @@ def mirrorlist_generator(configuration: Configuration) -> MirrorlistGenerator:
Returns:
MirrorlistGenerator: mirrorlist pkgbuild generator test instance
"""
return MirrorlistGenerator(configuration, "mirrorlist")
_, repository_id = configuration.check_loaded()
return MirrorlistGenerator(repository_id, configuration, "mirrorlist")
@pytest.fixture

View File

@ -20,7 +20,8 @@ def keyring_generator(database: SQLite, gpg: GPG, configuration: Configuration)
Returns:
KeyringGenerator: keyring generator test instance
"""
return KeyringGenerator(database, gpg, configuration, "keyring")
_, repository_id = configuration.check_loaded()
return KeyringGenerator(database, gpg, repository_id, configuration, "keyring")
@pytest.fixture

View File

@ -18,74 +18,87 @@ def test_init_packagers(database: SQLite, gpg: GPG, configuration: Configuration
must extract packagers keys
"""
mocker.patch("ahriman.core.database.SQLite.user_list", return_value=[user])
_, repository_id = configuration.check_loaded()
assert KeyringGenerator(database, gpg, configuration, "keyring").packagers == ["key"]
assert KeyringGenerator(database, gpg, repository_id, configuration, "keyring").packagers == ["key"]
configuration.set_option("keyring", "packagers", "key1")
assert KeyringGenerator(database, gpg, configuration, "keyring").packagers == ["key1"]
assert KeyringGenerator(database, gpg, repository_id, configuration, "keyring").packagers == ["key1"]
def test_init_revoked(database: SQLite, gpg: GPG, configuration: Configuration) -> None:
"""
must extract revoked keys
"""
assert KeyringGenerator(database, gpg, configuration, "keyring").revoked == []
_, repository_id = configuration.check_loaded()
assert KeyringGenerator(database, gpg, repository_id, configuration, "keyring").revoked == []
configuration.set_option("keyring", "revoked", "key1")
assert KeyringGenerator(database, gpg, configuration, "keyring").revoked == ["key1"]
assert KeyringGenerator(database, gpg, repository_id, configuration, "keyring").revoked == ["key1"]
def test_init_trusted(database: SQLite, gpg: GPG, configuration: Configuration) -> None:
"""
must extract trusted keys
"""
assert KeyringGenerator(database, gpg, configuration, "keyring").trusted == []
_, repository_id = configuration.check_loaded()
assert KeyringGenerator(database, gpg, repository_id, configuration, "keyring").trusted == []
gpg.default_key = "key"
assert KeyringGenerator(database, gpg, configuration, "keyring").trusted == ["key"]
assert KeyringGenerator(database, gpg, repository_id, configuration, "keyring").trusted == ["key"]
configuration.set_option("keyring", "trusted", "key1")
assert KeyringGenerator(database, gpg, configuration, "keyring").trusted == ["key1"]
assert KeyringGenerator(database, gpg, repository_id, configuration, "keyring").trusted == ["key1"]
def test_license(database: SQLite, gpg: GPG, configuration: Configuration) -> None:
"""
must generate correct licenses list
"""
assert KeyringGenerator(database, gpg, configuration, "keyring").license == ["Unlicense"]
_, repository_id = configuration.check_loaded()
assert KeyringGenerator(database, gpg, repository_id, configuration, "keyring").license == ["Unlicense"]
configuration.set_option("keyring", "license", "GPL MPL")
assert KeyringGenerator(database, gpg, configuration, "keyring").license == ["GPL", "MPL"]
assert KeyringGenerator(database, gpg, repository_id, configuration, "keyring").license == ["GPL", "MPL"]
def test_pkgdesc(database: SQLite, gpg: GPG, configuration: Configuration) -> None:
"""
must generate correct pkgdesc property
"""
assert KeyringGenerator(database, gpg, configuration, "keyring").pkgdesc == "aur-clone PGP keyring"
_, repository_id = configuration.check_loaded()
assert KeyringGenerator(database, gpg, repository_id, configuration, "keyring").pkgdesc == "aur-clone PGP keyring"
configuration.set_option("keyring", "description", "description")
assert KeyringGenerator(database, gpg, configuration, "keyring").pkgdesc == "description"
assert KeyringGenerator(database, gpg, repository_id, configuration, "keyring").pkgdesc == "description"
def test_pkgname(database: SQLite, gpg: GPG, configuration: Configuration) -> None:
"""
must generate correct pkgname property
"""
assert KeyringGenerator(database, gpg, configuration, "keyring").pkgname == "aur-clone-keyring"
_, repository_id = configuration.check_loaded()
assert KeyringGenerator(database, gpg, repository_id, configuration, "keyring").pkgname == "aur-clone-keyring"
configuration.set_option("keyring", "package", "keyring")
assert KeyringGenerator(database, gpg, configuration, "keyring").pkgname == "keyring"
assert KeyringGenerator(database, gpg, repository_id, configuration, "keyring").pkgname == "keyring"
def test_url(database: SQLite, gpg: GPG, configuration: Configuration) -> None:
"""
must generate correct url property
"""
assert KeyringGenerator(database, gpg, configuration, "keyring").url == ""
_, repository_id = configuration.check_loaded()
assert KeyringGenerator(database, gpg, repository_id, configuration, "keyring").url == ""
configuration.set_option("keyring", "homepage", "homepage")
assert KeyringGenerator(database, gpg, configuration, "keyring").url == "homepage"
assert KeyringGenerator(database, gpg, repository_id, configuration, "keyring").url == "homepage"
def test_generate_gpg(keyring_generator: KeyringGenerator, mocker: MockerFixture) -> None:

View File

@ -9,50 +9,62 @@ 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"
_, repository_id = configuration.check_loaded()
assert MirrorlistGenerator(repository_id, configuration, "mirrorlist").path == \
Path("etc") / "pacman.d" / "aur-clone-mirrorlist"
configuration.set_option("mirrorlist", "path", "/etc")
assert MirrorlistGenerator(configuration, "mirrorlist").path == Path("etc")
assert MirrorlistGenerator(repository_id, configuration, "mirrorlist").path == Path("etc")
def test_license(configuration: Configuration) -> None:
"""
must generate correct licenses list
"""
assert MirrorlistGenerator(configuration, "mirrorlist").license == ["Unlicense"]
_, repository_id = configuration.check_loaded()
assert MirrorlistGenerator(repository_id, configuration, "mirrorlist").license == ["Unlicense"]
configuration.set_option("mirrorlist", "license", "GPL MPL")
assert MirrorlistGenerator(configuration, "mirrorlist").license == ["GPL", "MPL"]
assert MirrorlistGenerator(repository_id, 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"
_, repository_id = configuration.check_loaded()
assert MirrorlistGenerator(repository_id, configuration, "mirrorlist").pkgdesc == \
"aur-clone mirror list for use by pacman"
configuration.set_option("mirrorlist", "description", "description")
assert MirrorlistGenerator(configuration, "mirrorlist").pkgdesc == "description"
assert MirrorlistGenerator(repository_id, configuration, "mirrorlist").pkgdesc == "description"
def test_pkgname(configuration: Configuration) -> None:
"""
must generate correct pkgname property
"""
assert MirrorlistGenerator(configuration, "mirrorlist").pkgname == "aur-clone-mirrorlist"
_, repository_id = configuration.check_loaded()
assert MirrorlistGenerator(repository_id, configuration, "mirrorlist").pkgname == "aur-clone-mirrorlist"
configuration.set_option("mirrorlist", "package", "mirrorlist")
assert MirrorlistGenerator(configuration, "mirrorlist").pkgname == "mirrorlist"
assert MirrorlistGenerator(repository_id, configuration, "mirrorlist").pkgname == "mirrorlist"
def test_url(configuration: Configuration) -> None:
"""
must generate correct url property
"""
assert MirrorlistGenerator(configuration, "mirrorlist").url == ""
_, repository_id = configuration.check_loaded()
assert MirrorlistGenerator(repository_id, configuration, "mirrorlist").url == ""
configuration.set_option("mirrorlist", "homepage", "homepage")
assert MirrorlistGenerator(configuration, "mirrorlist").url == "homepage"
assert MirrorlistGenerator(repository_id, configuration, "mirrorlist").url == "homepage"
def test_generate_mirrorlist(mirrorlist_generator: MirrorlistGenerator, mocker: MockerFixture) -> None:

View File

@ -25,8 +25,9 @@ def test_on_start(configuration: Configuration, mocker: MockerFixture) -> None:
"""
context_mock = mocker.patch("ahriman.core._Context.get")
run_mock = mocker.patch("ahriman.core.support.package_creator.PackageCreator.run")
_, repository_id = configuration.check_loaded()
trigger = KeyringTrigger("x86_64", configuration)
trigger = KeyringTrigger(repository_id, configuration)
trigger.on_start()
context_mock.assert_has_calls([MockCall(ContextKey("sign", GPG)), MockCall(ContextKey("database", SQLite))])
run_mock.assert_called_once_with()

View File

@ -20,7 +20,8 @@ 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")
_, repository_id = configuration.check_loaded()
trigger = MirrorlistTrigger("x86_64", configuration)
trigger = MirrorlistTrigger(repository_id, configuration)
trigger.on_start()
run_mock.assert_called_once_with()

View File

@ -7,6 +7,8 @@ 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
from ahriman.models.package_source import PackageSource
from ahriman.models.remote_source import RemoteSource
def test_run(package_creator: PackageCreator, database: SQLite, mocker: MockerFixture) -> None:
@ -16,7 +18,7 @@ def test_run(package_creator: PackageCreator, database: SQLite, mocker: MockerFi
package = Package(
base=package_creator.generator.pkgname,
version=package_creator.generator.pkgver,
remote=None,
remote=RemoteSource(source=PackageSource.Local),
packages={package_creator.generator.pkgname: PackageDescription()},
)
local_path = package_creator.configuration.repository_paths.cache_for(package_creator.generator.pkgname)

View File

@ -20,9 +20,9 @@ def test_process(spawner: Spawn) -> None:
callback = MagicMock()
callback.return_value = True
spawner.process(callback, args, spawner.architecture, "id", spawner.queue)
spawner.process(callback, args, spawner.repository_id, "id", spawner.queue)
callback.assert_called_once_with(args, spawner.architecture)
callback.assert_called_once_with(args, spawner.repository_id)
(uuid, status, time) = spawner.queue.get()
assert uuid == "id"
assert status
@ -37,7 +37,7 @@ def test_process_error(spawner: Spawn) -> None:
callback = MagicMock()
callback.return_value = False
spawner.process(callback, MagicMock(), spawner.architecture, "id", spawner.queue)
spawner.process(callback, MagicMock(), spawner.repository_id, "id", spawner.queue)
(uuid, status, time) = spawner.queue.get()
assert uuid == "id"

View File

@ -6,15 +6,23 @@ from ahriman.core.triggers import Trigger
from ahriman.models.result import Result
def test_architecture(trigger: Trigger) -> None:
"""
must return repository architecture for backward compatibility
"""
assert trigger.architecture == trigger.repository_id.architecture
def test_configuration_schema(configuration: Configuration) -> None:
"""
must return used configuration schema
"""
section = "console"
configuration.set_option("report", "target", section)
_, repository_id = configuration.check_loaded()
expected = {section: ReportTrigger.CONFIGURATION_SCHEMA[section]}
assert ReportTrigger.configuration_schema("x86_64", configuration) == expected
assert ReportTrigger.configuration_schema(repository_id, configuration) == expected
def test_configuration_schema_no_section(configuration: Configuration) -> None:
@ -23,7 +31,9 @@ def test_configuration_schema_no_section(configuration: Configuration) -> None:
"""
section = "abracadabra"
configuration.set_option("report", "target", section)
assert ReportTrigger.configuration_schema("x86_64", configuration) == {}
_, repository_id = configuration.check_loaded()
assert ReportTrigger.configuration_schema(repository_id, configuration) == {}
def test_configuration_schema_no_schema(configuration: Configuration) -> None:
@ -33,15 +43,17 @@ def test_configuration_schema_no_schema(configuration: Configuration) -> None:
section = "abracadabra"
configuration.set_option("report", "target", section)
configuration.set_option(section, "key", "value")
_, repository_id = configuration.check_loaded()
assert ReportTrigger.configuration_schema("x86_64", configuration) == {}
assert ReportTrigger.configuration_schema(repository_id, configuration) == {}
def test_configuration_schema_empty() -> None:
def test_configuration_schema_empty(configuration: Configuration) -> None:
"""
must return default schema if no configuration set
"""
assert ReportTrigger.configuration_schema("x86_64", None) == ReportTrigger.CONFIGURATION_SCHEMA
_, repository_id = configuration.check_loaded()
assert ReportTrigger.configuration_schema(repository_id, None) == ReportTrigger.CONFIGURATION_SCHEMA
def test_configuration_schema_variables(configuration: Configuration) -> None:

View File

@ -48,8 +48,10 @@ def test_load_trigger_package_error_on_creation(trigger_loader: TriggerLoader, c
must raise InvalidException on trigger initialization if any exception is thrown
"""
mocker.patch("ahriman.core.triggers.trigger.Trigger.__init__", side_effect=Exception())
_, repository_id = configuration.check_loaded()
with pytest.raises(ExtensionError):
trigger_loader.load_trigger("ahriman.core.report.ReportTrigger", "x86_64", configuration)
trigger_loader.load_trigger("ahriman.core.report.ReportTrigger", repository_id, configuration)
def test_load_trigger_class_package(trigger_loader: TriggerLoader) -> None:
@ -155,8 +157,9 @@ def test_on_stop_with_on_start(configuration: Configuration, mocker: MockerFixtu
mocker.patch("ahriman.core.upload.UploadTrigger.on_start")
mocker.patch("ahriman.core.report.ReportTrigger.on_start")
on_stop_mock = mocker.patch("ahriman.core.triggers.trigger_loader.TriggerLoader.on_stop")
_, repository_id = configuration.check_loaded()
trigger_loader = TriggerLoader.load("x86_64", configuration)
trigger_loader = TriggerLoader.load(repository_id, configuration)
trigger_loader.on_start()
del trigger_loader
on_stop_mock.assert_called_once_with()
@ -167,8 +170,9 @@ def test_on_stop_without_on_start(configuration: Configuration, mocker: MockerFi
must call not on_stop on exit if on_start wasn't called
"""
on_stop_mock = mocker.patch("ahriman.core.triggers.trigger_loader.TriggerLoader.on_stop")
_, repository_id = configuration.check_loaded()
trigger_loader = TriggerLoader.load("x86_64", configuration)
trigger_loader = TriggerLoader.load(repository_id, configuration)
del trigger_loader
on_stop_mock.assert_not_called()

View File

@ -95,19 +95,20 @@ def s3(configuration: Configuration) -> S3:
@pytest.fixture
def s3_remote_objects() -> list[MagicMock]:
def s3_remote_objects(configuration: Configuration) -> list[MagicMock]:
"""
fixture for boto3 like S3 objects
Returns:
list[MagicMock]: boto3 like S3 objects test instance
"""
_, repository_id = configuration.check_loaded()
delete_mock = MagicMock()
result = []
for item in ["a", "b", "c"]:
s3_object = MagicMock()
s3_object.key = f"x86_64/{item}"
s3_object.key = f"{repository_id.name}/{repository_id.architecture}/{item}"
s3_object.e_tag = f"\"{item}\""
s3_object.delete = delete_mock

View File

@ -6,14 +6,30 @@ from pytest_mock import MockerFixture
from typing import Any
from unittest.mock import call as MockCall
from ahriman.core.configuration import Configuration
from ahriman.core.upload.github import GitHub
def test_github_release_tag(configuration: Configuration) -> None:
"""
must correctly define GitHub release tag
"""
_, repository_id = configuration.check_loaded()
instance = GitHub(repository_id, configuration, "github:x86_64")
assert instance.github_release_tag == instance.github_release_tag_name == repository_id.architecture
configuration.set_option("github:x86_64", "use_full_release_name", "yes")
instance = GitHub(repository_id, configuration, "github:x86_64")
assert instance.github_release_tag == f"{repository_id.name}-{repository_id.architecture}"
assert instance.github_release_tag_name == f"{repository_id.name} {repository_id.architecture}"
def test_asset_remove(github: GitHub, github_release: dict[str, Any], mocker: MockerFixture) -> None:
"""
must remove asset from the release
"""
request_mock = mocker.patch("ahriman.core.upload.github.Github.make_request")
request_mock = mocker.patch("ahriman.core.upload.github.GitHub.make_request")
github.asset_remove(github_release, "asset_name")
request_mock.assert_called_once_with("DELETE", "asset_url")
@ -22,7 +38,7 @@ def test_asset_remove_unknown(github: GitHub, github_release: dict[str, Any], mo
"""
must not fail if no asset found
"""
request_mock = mocker.patch("ahriman.core.upload.github.Github.make_request")
request_mock = mocker.patch("ahriman.core.upload.github.GitHub.make_request")
github.asset_remove(github_release, "unknown_asset_name")
request_mock.assert_not_called()
@ -32,8 +48,8 @@ def test_asset_upload(github: GitHub, github_release: dict[str, Any], mocker: Mo
must upload asset to the repository
"""
mocker.patch("pathlib.Path.open")
request_mock = mocker.patch("ahriman.core.upload.github.Github.make_request")
remove_mock = mocker.patch("ahriman.core.upload.github.Github.asset_remove")
request_mock = mocker.patch("ahriman.core.upload.github.GitHub.make_request")
remove_mock = mocker.patch("ahriman.core.upload.github.GitHub.asset_remove")
github.asset_upload(github_release, Path("/root/new.tar.xz"))
request_mock.assert_called_once_with("POST", "upload_url", params=[("name", "new.tar.xz")],
@ -47,8 +63,8 @@ def test_asset_upload_with_removal(github: GitHub, github_release: dict[str, Any
must remove existing file before upload
"""
mocker.patch("pathlib.Path.open")
mocker.patch("ahriman.core.upload.github.Github.make_request")
remove_mock = mocker.patch("ahriman.core.upload.github.Github.asset_remove")
mocker.patch("ahriman.core.upload.github.GitHub.make_request")
remove_mock = mocker.patch("ahriman.core.upload.github.GitHub.asset_remove")
github.asset_upload(github_release, Path("asset_name"))
github.asset_upload(github_release, Path("/root/asset_name"))
@ -63,9 +79,9 @@ def test_asset_upload_empty_mimetype(github: GitHub, github_release: dict[str, A
must upload asset to the repository with empty mime type if the library cannot guess it
"""
mocker.patch("pathlib.Path.open")
mocker.patch("ahriman.core.upload.github.Github.asset_remove")
mocker.patch("ahriman.core.upload.github.GitHub.asset_remove")
mocker.patch("mimetypes.guess_type", return_value=(None, None))
request_mock = mocker.patch("ahriman.core.upload.github.Github.make_request")
request_mock = mocker.patch("ahriman.core.upload.github.GitHub.make_request")
github.asset_upload(github_release, Path("/root/new.tar.xz"))
request_mock.assert_called_once_with("POST", "upload_url", params=[("name", "new.tar.xz")],
@ -86,7 +102,7 @@ def test_files_remove(github: GitHub, github_release: dict[str, Any], mocker: Mo
"""
must remove files from the remote
"""
remove_mock = mocker.patch("ahriman.core.upload.github.Github.asset_remove")
remove_mock = mocker.patch("ahriman.core.upload.github.GitHub.asset_remove")
github.files_remove(github_release, {Path("a"): "a"}, {"a": "a", "b": "b"})
remove_mock.assert_called_once_with(github_release, "b")
@ -95,7 +111,7 @@ def test_files_remove_empty(github: GitHub, github_release: dict[str, Any], mock
"""
must remove nothing if nothing changed
"""
remove_mock = mocker.patch("ahriman.core.upload.github.Github.asset_remove")
remove_mock = mocker.patch("ahriman.core.upload.github.GitHub.asset_remove")
github.files_remove(github_release, {Path("a"): "a"}, {"a": "a"})
remove_mock.assert_not_called()
@ -104,7 +120,7 @@ def test_files_upload(github: GitHub, github_release: dict[str, Any], mocker: Mo
"""
must upload files to the remote
"""
upload_mock = mocker.patch("ahriman.core.upload.github.Github.asset_upload")
upload_mock = mocker.patch("ahriman.core.upload.github.GitHub.asset_upload")
github.files_upload(github_release, {Path("a"): "a", Path("b"): "c", Path("c"): "c"}, {"a": "a", "b": "b"})
upload_mock.assert_has_calls([
MockCall(github_release, Path("b")),
@ -116,7 +132,7 @@ def test_files_upload_empty(github: GitHub, github_release: dict[str, Any], mock
"""
must upload nothing if nothing changed
"""
upload_mock = mocker.patch("ahriman.core.upload.github.Github.asset_upload")
upload_mock = mocker.patch("ahriman.core.upload.github.GitHub.asset_upload")
github.files_upload(github_release, {Path("a"): "a"}, {"a": "a"})
upload_mock.assert_not_called()
@ -125,17 +141,18 @@ def test_release_create(github: GitHub, mocker: MockerFixture) -> None:
"""
must create release
"""
request_mock = mocker.patch("ahriman.core.upload.github.Github.make_request")
request_mock = mocker.patch("ahriman.core.upload.github.GitHub.make_request")
github.release_create()
request_mock.assert_called_once_with("POST", pytest.helpers.anyvar(str, True),
json={"tag_name": github.architecture, "name": github.architecture})
request_mock.assert_called_once_with(
"POST", pytest.helpers.anyvar(str, True),
json={"tag_name": github.github_release_tag, "name": github.github_release_tag_name})
def test_release_get(github: GitHub, mocker: MockerFixture) -> None:
"""
must get release
"""
request_mock = mocker.patch("ahriman.core.upload.github.Github.make_request")
request_mock = mocker.patch("ahriman.core.upload.github.GitHub.make_request")
github.release_get()
request_mock.assert_called_once_with("GET", pytest.helpers.anyvar(str, True))
@ -146,7 +163,7 @@ def test_release_get_empty(github: GitHub, mocker: MockerFixture) -> None:
"""
response = requests.Response()
response.status_code = 404
mocker.patch("ahriman.core.upload.github.Github.make_request",
mocker.patch("ahriman.core.upload.github.GitHub.make_request",
side_effect=requests.HTTPError(response=response))
assert github.release_get() is None
@ -155,7 +172,7 @@ def test_release_get_exception(github: GitHub, mocker: MockerFixture) -> None:
"""
must re-raise non HTTPError exception
"""
mocker.patch("ahriman.core.upload.github.Github.make_request", side_effect=Exception())
mocker.patch("ahriman.core.upload.github.GitHub.make_request", side_effect=Exception())
with pytest.raises(Exception):
github.release_get()
@ -165,7 +182,7 @@ def test_release_get_exception_http_error(github: GitHub, mocker: MockerFixture)
must re-raise HTTPError exception with code differs from 404
"""
exception = requests.HTTPError(response=requests.Response())
mocker.patch("ahriman.core.upload.github.Github.make_request", side_effect=exception)
mocker.patch("ahriman.core.upload.github.GitHub.make_request", side_effect=exception)
with pytest.raises(requests.HTTPError):
github.release_get()
@ -174,7 +191,7 @@ def test_release_update(github: GitHub, github_release: dict[str, Any], mocker:
"""
must update release
"""
request_mock = mocker.patch("ahriman.core.upload.github.Github.make_request")
request_mock = mocker.patch("ahriman.core.upload.github.GitHub.make_request")
github.release_update(github_release, "body")
request_mock.assert_called_once_with("POST", "release_url", json={"body": "body"})
@ -183,12 +200,12 @@ def test_release_sync(github: GitHub, mocker: MockerFixture) -> None:
"""
must run sync command
"""
release_get_mock = mocker.patch("ahriman.core.upload.github.Github.release_get", return_value={})
get_hashes_mock = mocker.patch("ahriman.core.upload.github.Github.get_hashes", return_value={})
get_local_files_mock = mocker.patch("ahriman.core.upload.github.Github.get_local_files", return_value={})
files_upload_mock = mocker.patch("ahriman.core.upload.github.Github.files_upload")
files_remove_mock = mocker.patch("ahriman.core.upload.github.Github.files_remove")
release_update_mock = mocker.patch("ahriman.core.upload.github.Github.release_update")
release_get_mock = mocker.patch("ahriman.core.upload.github.GitHub.release_get", return_value={})
get_hashes_mock = mocker.patch("ahriman.core.upload.github.GitHub.get_hashes", return_value={})
get_local_files_mock = mocker.patch("ahriman.core.upload.github.GitHub.get_local_files", return_value={})
files_upload_mock = mocker.patch("ahriman.core.upload.github.GitHub.files_upload")
files_remove_mock = mocker.patch("ahriman.core.upload.github.GitHub.files_remove")
release_update_mock = mocker.patch("ahriman.core.upload.github.GitHub.release_update")
github.sync(Path("local"), [])
release_get_mock.assert_called_once_with()
@ -203,13 +220,13 @@ def test_release_sync_create_release(github: GitHub, mocker: MockerFixture) -> N
"""
must create release in case if it does not exist
"""
mocker.patch("ahriman.core.upload.github.Github.release_get", return_value=None)
mocker.patch("ahriman.core.upload.github.Github.get_hashes")
mocker.patch("ahriman.core.upload.github.Github.get_local_files")
mocker.patch("ahriman.core.upload.github.Github.files_upload")
mocker.patch("ahriman.core.upload.github.Github.files_remove")
mocker.patch("ahriman.core.upload.github.Github.release_update")
release_create_mock = mocker.patch("ahriman.core.upload.github.Github.release_create")
mocker.patch("ahriman.core.upload.github.GitHub.release_get", return_value=None)
mocker.patch("ahriman.core.upload.github.GitHub.get_hashes")
mocker.patch("ahriman.core.upload.github.GitHub.get_local_files")
mocker.patch("ahriman.core.upload.github.GitHub.files_upload")
mocker.patch("ahriman.core.upload.github.GitHub.files_remove")
mocker.patch("ahriman.core.upload.github.GitHub.release_update")
release_create_mock = mocker.patch("ahriman.core.upload.github.GitHub.release_create")
github.sync(Path("local"), [])
release_create_mock.assert_called_once_with()

View File

@ -38,12 +38,12 @@ def test_files_remove(s3_remote_objects: list[Any]) -> None:
must remove remote objects
"""
local_files = {
Path(item.key): item.e_tag for item in s3_remote_objects if item.key != "x86_64/a"
Path(item.key): item.e_tag for item in s3_remote_objects if item.key != "aur-clone/x86_64/a"
}
remote_objects = {Path(item.key): item for item in s3_remote_objects}
S3.files_remove(local_files, remote_objects)
remote_objects[Path("x86_64/a")].delete.assert_called_once_with()
remote_objects[Path("aur-clone/x86_64/a")].delete.assert_called_once_with()
def test_files_upload(s3: S3, s3_remote_objects: list[Any], mocker: MockerFixture) -> None:
@ -55,9 +55,10 @@ def test_files_upload(s3: S3, s3_remote_objects: list[Any], mocker: MockerFixtur
root = Path("path")
local_files = {
Path(item.key.replace("a", "d")): item.e_tag.replace("b", "d").replace("\"", "")
Path(item.key[:-1] + item.key[-1].replace("a", "d")): item.e_tag.replace("b", "d").replace("\"", "")
for item in s3_remote_objects
}
print(local_files)
remote_objects = {Path(item.key): item for item in s3_remote_objects}
mocker.patch("mimetypes.guess_type", side_effect=mimetype)
@ -67,12 +68,12 @@ def test_files_upload(s3: S3, s3_remote_objects: list[Any], mocker: MockerFixtur
upload_mock.upload_file.assert_has_calls(
[
MockCall(
Filename=str(root / s3.architecture / "b"),
Key=f"{s3.architecture}/{s3.architecture}/b",
Filename=str(root / s3.remote_root / "b"),
Key=f"{s3.remote_root}/b",
ExtraArgs={"ContentType": "text/html"}),
MockCall(
Filename=str(root / s3.architecture / "d"),
Key=f"{s3.architecture}/{s3.architecture}/d",
Filename=str(root / s3.remote_root / "d"),
Key=f"{s3.remote_root}/d",
ExtraArgs=None),
],
any_order=True)
@ -91,7 +92,7 @@ def test_get_remote_objects(s3: S3, s3_remote_objects: list[Any]) -> None:
"""
must generate list of remote objects by calling boto3 function
"""
expected = {Path(item.key).relative_to(s3.architecture): item for item in s3_remote_objects}
expected = {Path(item.key).relative_to(s3.remote_root): item for item in s3_remote_objects}
s3.bucket = MagicMock()
s3.bucket.objects.filter.return_value = s3_remote_objects

View File

@ -14,8 +14,10 @@ def test_upload_failure(configuration: Configuration, mocker: MockerFixture) ->
must raise SyncFailed on errors
"""
mocker.patch("ahriman.core.upload.rsync.Rsync.sync", side_effect=Exception())
_, repository_id = configuration.check_loaded()
with pytest.raises(SynchronizationError):
Upload.load("x86_64", configuration, "rsync").run(Path("path"), [])
Upload.load(repository_id, configuration, "rsync").run(Path("path"), [])
def test_report_dummy(configuration: Configuration, mocker: MockerFixture) -> None:
@ -24,7 +26,9 @@ def test_report_dummy(configuration: Configuration, mocker: MockerFixture) -> No
"""
mocker.patch("ahriman.models.upload_settings.UploadSettings.from_option", return_value=UploadSettings.Disabled)
upload_mock = mocker.patch("ahriman.core.upload.upload.Upload.sync")
Upload.load("x86_64", configuration, "disabled").run(Path("path"), [])
_, repository_id = configuration.check_loaded()
Upload.load(repository_id, configuration, "disabled").run(Path("path"), [])
upload_mock.assert_called_once_with(Path("path"), [])
@ -33,7 +37,9 @@ def test_upload_rsync(configuration: Configuration, mocker: MockerFixture) -> No
must upload via rsync
"""
upload_mock = mocker.patch("ahriman.core.upload.rsync.Rsync.sync")
Upload.load("x86_64", configuration, "rsync").run(Path("path"), [])
_, repository_id = configuration.check_loaded()
Upload.load(repository_id, configuration, "rsync").run(Path("path"), [])
upload_mock.assert_called_once_with(Path("path"), [])
@ -42,7 +48,9 @@ def test_upload_s3(configuration: Configuration, mocker: MockerFixture) -> None:
must upload via s3
"""
upload_mock = mocker.patch("ahriman.core.upload.s3.S3.sync")
Upload.load("x86_64", configuration, "customs3").run(Path("path"), [])
_, repository_id = configuration.check_loaded()
Upload.load(repository_id, configuration, "customs3").run(Path("path"), [])
upload_mock.assert_called_once_with(Path("path"), [])
@ -50,8 +58,10 @@ def test_upload_github(configuration: Configuration, mocker: MockerFixture) -> N
"""
must upload via github
"""
upload_mock = mocker.patch("ahriman.core.upload.github.Github.sync")
Upload.load("x86_64", configuration, "github").run(Path("path"), [])
upload_mock = mocker.patch("ahriman.core.upload.github.GitHub.sync")
_, repository_id = configuration.check_loaded()
Upload.load(repository_id, configuration, "github").run(Path("path"), [])
upload_mock.assert_called_once_with(Path("path"), [])
@ -62,6 +72,7 @@ def test_upload_ahriman(configuration: Configuration, mocker: MockerFixture) ->
upload_mock = mocker.patch("ahriman.core.upload.remote_service.RemoteService.sync")
configuration.set_option("web", "host", "localhost")
configuration.set_option("web", "port", "8080")
_, repository_id = configuration.check_loaded()
Upload.load("x86_64", configuration, "remote-service").run(Path("path"), [])
Upload.load(repository_id, configuration, "remote-service").run(Path("path"), [])
upload_mock.assert_called_once_with(Path("path"), [])

View File

@ -22,7 +22,8 @@ def test_on_result(configuration: Configuration, mocker: MockerFixture) -> None:
"""
configuration.set_option("upload", "target", "rsync")
run_mock = mocker.patch("ahriman.core.upload.upload.Upload.run")
_, repository_id = configuration.check_loaded()
trigger = UploadTrigger("x86_64", configuration)
trigger = UploadTrigger(repository_id, configuration)
trigger.on_result(Result(), [])
run_mock.assert_called_once_with(configuration.repository_paths.repository, [])

View File

@ -0,0 +1,33 @@
import pytest
from ahriman.core.exceptions import InitializeError
from ahriman.models.repository_id import RepositoryId
def test_post_init() -> None:
"""
must raise InitializeError if name is empty
"""
RepositoryId("x86_64", "aur-clone")
with pytest.raises(InitializeError):
RepositoryId("x86_64", "")
def test_lt() -> None:
"""
must correctly compare instances
"""
assert RepositoryId("x86_64", "a") < RepositoryId("x86_64", "b")
assert RepositoryId("x86_64", "b") > RepositoryId("x86_64", "a")
assert RepositoryId("i686", "a") < RepositoryId("x86_64", "a")
assert RepositoryId("x86_64", "a") > RepositoryId("i686", "a")
def test_lt_invalid() -> None:
"""
must raise ValueError if other is not valid repository id
"""
with pytest.raises(ValueError):
RepositoryId("x86_64", "a") < 42

View File

@ -7,6 +7,7 @@ from unittest.mock import MagicMock, call as MockCall
from ahriman.core.exceptions import PathError
from ahriman.models.package import Package
from ahriman.models.repository_id import RepositoryId
from ahriman.models.repository_paths import RepositoryPaths
@ -26,6 +27,18 @@ def _get_owner(root: Path, same: bool) -> Callable[[Path], tuple[int, int]]:
return lambda path: root_owner if path == root else non_root_owner
def test_suffix(repository_id: RepositoryId, mocker: MockerFixture) -> None:
"""
must correctly define suffix
"""
is_dir_mock = mocker.patch("pathlib.Path.is_dir", autospec=True, return_value=True)
assert RepositoryPaths(Path("root"), repository_id)._suffix == Path(repository_id.architecture)
is_dir_mock.assert_called_once_with(Path("root") / "repository" / repository_id.architecture)
mocker.patch("pathlib.Path.is_dir", return_value=False)
assert RepositoryPaths(Path("root"), repository_id)._suffix == Path(repository_id.name) / repository_id.architecture
def test_root_owner(repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
"""
must correctly define root directory owner
@ -36,11 +49,63 @@ def test_root_owner(repository_paths: RepositoryPaths, mocker: MockerFixture) ->
def test_known_architectures(repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
"""
must list available directory paths
must list available directory paths /repository/repo/arch
"""
iterdir_mock = mocker.patch("pathlib.Path.iterdir")
repository_paths.known_architectures(repository_paths.root)
iterdir_mock.assert_called_once_with()
def iterdir(root: Path) -> list[Path]:
if root == repository_paths._repository_root:
return [Path("repo1"), Path("repo2")]
if root == Path("repo1"):
return [Path("i686"), Path("x86_64")]
return [Path("x86_64")]
is_dir_mock = mocker.patch("pathlib.Path.is_dir", autospec=True, return_value=True)
iterdir_mock = mocker.patch("pathlib.Path.iterdir", autospec=True, side_effect=iterdir)
assert repository_paths.known_architectures(repository_paths.root, "") == {
RepositoryId("i686", "repo1"),
RepositoryId("x86_64", "repo1"),
RepositoryId("x86_64", "repo2"),
}
iterdir_mock.assert_has_calls([
MockCall(repository_paths._repository_root),
MockCall(Path("repo1")),
MockCall(Path("repo2")),
])
is_dir_mock.assert_has_calls([
MockCall(Path("repo1")),
MockCall(Path("i686")),
MockCall(Path("x86_64")),
MockCall(Path("repo2")),
MockCall(Path("x86_64")),
])
def test_known_architectures_legacy(repository_id: RepositoryId, repository_paths: RepositoryPaths,
mocker: MockerFixture) -> None:
"""
must correctly define legacy tree /repository/arch
"""
def iterdir(root: Path) -> list[Path]:
if root == repository_paths._repository_root:
return [Path("i686"), Path("x86_64")]
return []
is_dir_mock = mocker.patch("pathlib.Path.is_dir", autospec=True, return_value=True)
iterdir_mock = mocker.patch("pathlib.Path.iterdir", autospec=True, side_effect=iterdir)
assert repository_paths.known_architectures(repository_paths.root, repository_id.name) == {
RepositoryId("i686", repository_id.name),
RepositoryId("x86_64", repository_id.name),
}
iterdir_mock.assert_has_calls([
MockCall(repository_paths._repository_root),
MockCall(Path("i686")),
MockCall(Path("x86_64")),
])
is_dir_mock.assert_has_calls([
MockCall(Path("i686")),
MockCall(Path("x86_64")),
])
def test_owner(repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
@ -140,10 +205,10 @@ def test_tree_create(repository_paths: RepositoryPaths, mocker: MockerFixture) -
for prop in dir(repository_paths)
if not prop.startswith("_")
and not prop.endswith("_for")
and prop not in ("architecture",
"chown",
and prop not in ("chown",
"known_architectures",
"owner",
"repository_id",
"root",
"root_owner",
"tree_clear",

View File

@ -16,7 +16,6 @@ from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite
from ahriman.core.repository import Repository
from ahriman.core.spawn import Spawn
from ahriman.models.repository_id import RepositoryId
from ahriman.models.user import User
from ahriman.web.web import setup_service