diff --git a/.github/workflows/setup.sh b/.github/workflows/setup.sh index 792566a5..d4627858 100755 --- a/.github/workflows/setup.sh +++ b/.github/workflows/setup.sh @@ -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 " --repository "github" "${WEB_ARGS[@]}" +ahriman -a x86_64 -r "github" service-setup --packager "ahriman bot " "${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 diff --git a/src/ahriman/application/handlers/handler.py b/src/ahriman/application/handlers/handler.py index a74a6d15..f670f3a3 100644 --- a/src/ahriman/application/handlers/handler.py +++ b/src/ahriman/application/handlers/handler.py @@ -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 diff --git a/src/ahriman/application/handlers/setup.py b/src/ahriman/application/handlers/setup.py index 8700c4ee..06f27a82 100644 --- a/src/ahriman/application/handlers/setup.py +++ b/src/ahriman/application/handlers/setup.py @@ -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() diff --git a/src/ahriman/application/handlers/web.py b/src/ahriman/application/handlers/web.py index 50baf7b0..7d24bc8c 100644 --- a/src/ahriman/application/handlers/web.py +++ b/src/ahriman/application/handlers/web.py @@ -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)] diff --git a/src/ahriman/application/lock.py b/src/ahriman/application/lock.py index f9203089..084ef4ef 100644 --- a/src/ahriman/application/lock.py +++ b/src/ahriman/application/lock.py @@ -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 diff --git a/src/ahriman/core/configuration/configuration.py b/src/ahriman/core/configuration/configuration.py index 562fed4c..4089cb5b 100644 --- a/src/ahriman/core/configuration/configuration.py +++ b/src/ahriman/core/configuration/configuration.py @@ -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 diff --git a/src/ahriman/core/database/migrations/m001_package_source.py b/src/ahriman/core/database/migrations/m001_package_source.py index 6719a198..193a5cc6 100644 --- a/src/ahriman/core/database/migrations/m001_package_source.py +++ b/src/ahriman/core/database/migrations/m001_package_source.py @@ -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""") } diff --git a/src/ahriman/core/database/migrations/m011_repository_name.py b/src/ahriman/core/database/migrations/m011_repository_name.py index 1e929017..fdc12b7d 100644 --- a/src/ahriman/core/database/migrations/m011_repository_name.py +++ b/src/ahriman/core/database/migrations/m011_repository_name.py @@ -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}) diff --git a/src/ahriman/core/database/operations/build_operations.py b/src/ahriman/core/database/operations/build_operations.py index cfbab902..0012d16d 100644 --- a/src/ahriman/core/database/operations/build_operations.py +++ b/src/ahriman/core/database/operations/build_operations.py @@ -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) diff --git a/src/ahriman/core/database/operations/logs_operations.py b/src/ahriman/core/database/operations/logs_operations.py index 5cd29878..18d8b411 100644 --- a/src/ahriman/core/database/operations/logs_operations.py +++ b/src/ahriman/core/database/operations/logs_operations.py @@ -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) diff --git a/src/ahriman/core/database/operations/package_operations.py b/src/ahriman/core/database/operations/package_operations.py index 4278e1bc..f77e8eca 100644 --- a/src/ahriman/core/database/operations/package_operations.py +++ b/src/ahriman/core/database/operations/package_operations.py @@ -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} ) } diff --git a/src/ahriman/core/database/operations/patch_operations.py b/src/ahriman/core/database/operations/patch_operations.py index 064ad6ce..98cbbfc4 100644 --- a/src/ahriman/core/database/operations/patch_operations.py +++ b/src/ahriman/core/database/operations/patch_operations.py @@ -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) diff --git a/src/ahriman/core/log/__init__.py b/src/ahriman/core/log/__init__.py index c0ba3e7d..97b65d75 100644 --- a/src/ahriman/core/log/__init__.py +++ b/src/ahriman/core/log/__init__.py @@ -18,3 +18,4 @@ # along with this program. If not, see . # from ahriman.core.log.lazy_logging import LazyLogging +from ahriman.core.log.log import Log diff --git a/src/ahriman/core/log/log_loader.py b/src/ahriman/core/log/log.py similarity index 95% rename from src/ahriman/core/log/log_loader.py rename to src/ahriman/core/log/log.py index 57189d44..3f155b1e 100644 --- a/src/ahriman/core/log/log_loader.py +++ b/src/ahriman/core/log/log.py @@ -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) diff --git a/src/ahriman/core/upload/s3.py b/src/ahriman/core/upload/s3.py index c2e3e5e3..922cde8f 100644 --- a/src/ahriman/core/upload/s3.py +++ b/src/ahriman/core/upload/s3.py @@ -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 diff --git a/src/ahriman/models/repository_id.py b/src/ahriman/models/repository_id.py index 67ca8478..1d1c4bd1 100644 --- a/src/ahriman/models/repository_id.py +++ b/src/ahriman/models/repository_id.py @@ -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) diff --git a/src/ahriman/models/repository_paths.py b/src/ahriman/models/repository_paths.py index 8295905c..bef12ba4 100644 --- a/src/ahriman/models/repository_paths.py +++ b/src/ahriman/models/repository_paths.py @@ -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]: diff --git a/tests/ahriman/application/application/test_application_properties.py b/tests/ahriman/application/application/test_application_properties.py index 803c8a16..ab64cdcd 100644 --- a/tests/ahriman/application/application/test_application_properties.py +++ b/tests/ahriman/application/application/test_application_properties.py @@ -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 diff --git a/tests/ahriman/application/handlers/test_handler.py b/tests/ahriman/application/handlers/test_handler.py index 645cb738..9b16ce9d 100644 --- a/tests/ahriman/application/handlers/test_handler.py +++ b/tests/ahriman/application/handlers/test_handler.py @@ -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: diff --git a/tests/ahriman/application/handlers/test_handler_add.py b/tests/ahriman/application/handlers/test_handler_add.py index b9939bbb..8cd5177e 100644 --- a/tests/ahriman/application/handlers/test_handler_add.py +++ b/tests/ahriman/application/handlers/test_handler_add.py @@ -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) diff --git a/tests/ahriman/application/handlers/test_handler_backup.py b/tests/ahriman/application/handlers/test_handler_backup.py index 3679dcd7..b7683459 100644 --- a/tests/ahriman/application/handlers/test_handler_backup.py +++ b/tests/ahriman/application/handlers/test_handler_backup.py @@ -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")) diff --git a/tests/ahriman/application/handlers/test_handler_clean.py b/tests/ahriman/application/handlers/test_handler_clean.py index 35fa0252..196c4138 100644 --- a/tests/ahriman/application/handlers/test_handler_clean.py +++ b/tests/ahriman/application/handlers/test_handler_clean.py @@ -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() diff --git a/tests/ahriman/application/handlers/test_handler_daemon.py b/tests/ahriman/application/handlers/test_handler_daemon.py index 698c3758..4018e3a1 100644 --- a/tests/ahriman/application/handlers/test_handler_daemon.py +++ b/tests/ahriman/application/handlers/test_handler_daemon.py @@ -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() diff --git a/tests/ahriman/application/handlers/test_handler_dump.py b/tests/ahriman/application/handlers/test_handler_dump.py index 2f5ebc37..aeb6ac47 100644 --- a/tests/ahriman/application/handlers/test_handler_dump.py +++ b/tests/ahriman/application/handlers/test_handler_dump.py @@ -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() diff --git a/tests/ahriman/application/handlers/test_handler_help.py b/tests/ahriman/application/handlers/test_handler_help.py index db986c0f..13f91434 100644 --- a/tests/ahriman/application/handlers/test_handler_help.py +++ b/tests/ahriman/application/handlers/test_handler_help.py @@ -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"]) diff --git a/tests/ahriman/application/handlers/test_handler_key_import.py b/tests/ahriman/application/handlers/test_handler_key_import.py index 33d2f0fb..bb202e9b 100644 --- a/tests/ahriman/application/handlers/test_handler_key_import.py +++ b/tests/ahriman/application/handlers/test_handler_key_import.py @@ -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) diff --git a/tests/ahriman/application/handlers/test_handler_patch.py b/tests/ahriman/application/handlers/test_handler_patch.py index 0c504ff8..97dbb3cd 100644 --- a/tests/ahriman/application/handlers/test_handler_patch.py +++ b/tests/ahriman/application/handlers/test_handler_patch.py @@ -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") diff --git a/tests/ahriman/application/handlers/test_handler_rebuild.py b/tests/ahriman/application/handlers/test_handler_rebuild.py index 1fd3604a..26584218 100644 --- a/tests/ahriman/application/handlers/test_handler_rebuild.py +++ b/tests/ahriman/application/handlers/test_handler_rebuild.py @@ -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)]) diff --git a/tests/ahriman/application/handlers/test_handler_remove.py b/tests/ahriman/application/handlers/test_handler_remove.py index 77b6acb4..fba69bed 100644 --- a/tests/ahriman/application/handlers/test_handler_remove.py +++ b/tests/ahriman/application/handlers/test_handler_remove.py @@ -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() diff --git a/tests/ahriman/application/handlers/test_handler_remove_unknown.py b/tests/ahriman/application/handlers/test_handler_remove_unknown.py index 00adf667..d0f25819 100644 --- a/tests/ahriman/application/handlers/test_handler_remove_unknown.py +++ b/tests/ahriman/application/handlers/test_handler_remove_unknown.py @@ -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) diff --git a/tests/ahriman/application/handlers/test_handler_restore.py b/tests/ahriman/application/handlers/test_handler_restore.py index 243fa0fa..e2a6dad6 100644 --- a/tests/ahriman/application/handlers/test_handler_restore.py +++ b/tests/ahriman/application/handlers/test_handler_restore.py @@ -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) diff --git a/tests/ahriman/application/handlers/test_handler_search.py b/tests/ahriman/application/handlers/test_handler_search.py index 8d7f6131..8e57f43f 100644 --- a/tests/ahriman/application/handlers/test_handler_search.py +++ b/tests/ahriman/application/handlers/test_handler_search.py @@ -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__() diff --git a/tests/ahriman/application/handlers/test_handler_service_updates.py b/tests/ahriman/application/handlers/test_handler_service_updates.py index f09f6caf..d652e7f6 100644 --- a/tests/ahriman/application/handlers/test_handler_service_updates.py +++ b/tests/ahriman/application/handlers/test_handler_service_updates.py @@ -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() diff --git a/tests/ahriman/application/handlers/test_handler_setup.py b/tests/ahriman/application/handlers/test_handler_setup.py index cec5bc03..e550a047 100644 --- a/tests/ahriman/application/handlers/test_handler_setup.py +++ b/tests/ahriman/application/handlers/test_handler_setup.py @@ -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 " - 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) diff --git a/tests/ahriman/application/handlers/test_handler_shell.py b/tests/ahriman/application/handlers/test_handler_shell.py index 5a6e32c6..80799524 100644 --- a/tests/ahriman/application/handlers/test_handler_shell.py +++ b/tests/ahriman/application/handlers/test_handler_shell.py @@ -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) diff --git a/tests/ahriman/application/handlers/test_handler_sign.py b/tests/ahriman/application/handlers/test_handler_sign.py index c40d3492..9e1fa579 100644 --- a/tests/ahriman/application/handlers/test_handler_sign.py +++ b/tests/ahriman/application/handlers/test_handler_sign.py @@ -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([]) diff --git a/tests/ahriman/application/handlers/test_handler_status.py b/tests/ahriman/application/handlers/test_handler_status.py index 4c2bf40e..a4e41086 100644 --- a/tests/ahriman/application/handlers/test_handler_status.py +++ b/tests/ahriman/application/handlers/test_handler_status.py @@ -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: diff --git a/tests/ahriman/application/handlers/test_handler_status_update.py b/tests/ahriman/application/handlers/test_handler_status_update.py index 5e307115..ad051579 100644 --- a/tests/ahriman/application/handlers/test_handler_status_update.py +++ b/tests/ahriman/application/handlers/test_handler_status_update.py @@ -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: diff --git a/tests/ahriman/application/handlers/test_handler_structure.py b/tests/ahriman/application/handlers/test_handler_structure.py index 49c66a16..441d89cb 100644 --- a/tests/ahriman/application/handlers/test_handler_structure.py +++ b/tests/ahriman/application/handlers/test_handler_structure.py @@ -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([ diff --git a/tests/ahriman/application/handlers/test_handler_triggers.py b/tests/ahriman/application/handlers/test_handler_triggers.py index d433d1e5..fcc4220d 100644 --- a/tests/ahriman/application/handlers/test_handler_triggers.py +++ b/tests/ahriman/application/handlers/test_handler_triggers.py @@ -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() diff --git a/tests/ahriman/application/handlers/test_handler_unsafe_commands.py b/tests/ahriman/application/handlers/test_handler_unsafe_commands.py index 238133ba..f377631d 100644 --- a/tests/ahriman/application/handlers/test_handler_unsafe_commands.py +++ b/tests/ahriman/application/handlers/test_handler_unsafe_commands.py @@ -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)) diff --git a/tests/ahriman/application/handlers/test_handler_update.py b/tests/ahriman/application/handlers/test_handler_update.py index e41761d5..40f61fdf 100644 --- a/tests/ahriman/application/handlers/test_handler_update.py +++ b/tests/ahriman/application/handlers/test_handler_update.py @@ -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)) diff --git a/tests/ahriman/application/handlers/test_handler_users.py b/tests/ahriman/application/handlers/test_handler_users.py index 2c050c0c..a5128048 100644 --- a/tests/ahriman/application/handlers/test_handler_users.py +++ b/tests/ahriman/application/handlers/test_handler_users.py @@ -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) diff --git a/tests/ahriman/application/handlers/test_handler_validate.py b/tests/ahriman/application/handlers/test_handler_validate.py index 05a95de6..2a81e259 100644 --- a/tests/ahriman/application/handlers/test_handler_validate.py +++ b/tests/ahriman/application/handlers/test_handler_validate.py @@ -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: diff --git a/tests/ahriman/application/handlers/test_handler_versions.py b/tests/ahriman/application/handlers/test_handler_versions.py index 47cf725e..4f4964e9 100644 --- a/tests/ahriman/application/handlers/test_handler_versions.py +++ b/tests/ahriman/application/handlers/test_handler_versions.py @@ -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=" ")]) diff --git a/tests/ahriman/application/handlers/test_handler_web.py b/tests/ahriman/application/handlers/test_handler_web.py index 59ace2d1..ae2649e4 100644 --- a/tests/ahriman/application/handlers/test_handler_web.py +++ b/tests/ahriman/application/handlers/test_handler_web.py @@ -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", diff --git a/tests/ahriman/application/test_ahriman.py b/tests/ahriman/application/test_ahriman.py index d3aa0868..8f749ba2 100644 --- a/tests/ahriman/application/test_ahriman.py +++ b/tests/ahriman/application/test_ahriman.py @@ -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 ", - "--repository", "aur-clone"]) + args = parser.parse_args(["-a", "x86_64", "service-setup", "--packager", "John Doe "]) 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 ", - "--repository", "aur-clone"]) + args = parser.parse_args(["-a", "x86_64", "service-setup", "--packager", "John Doe "]) assert isinstance(args.from_configuration, Path) args = parser.parse_args(["-a", "x86_64", "service-setup", "--packager", "John Doe ", - "--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 ", - "--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 diff --git a/tests/ahriman/application/test_lock.py b/tests/ahriman/application/test_lock.py index 088f6b5c..23851685 100644 --- a/tests/ahriman/application/test_lock.py +++ b/tests/ahriman/application/test_lock.py @@ -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: diff --git a/tests/ahriman/core/alpm/test_pacman.py b/tests/ahriman/core/alpm/test_pacman.py index 63644055..ff4bd5ee 100644 --- a/tests/ahriman/core/alpm/test_pacman.py +++ b/tests/ahriman/core/alpm/test_pacman.py @@ -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: diff --git a/tests/ahriman/core/build_tools/test_sources.py b/tests/ahriman/core/build_tools/test_sources.py index 5499788a..509ee2d5 100644 --- a/tests/ahriman/core/build_tools/test_sources.py +++ b/tests/ahriman/core/build_tools/test_sources.py @@ -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: diff --git a/tests/ahriman/core/configuration/test_configuration.py b/tests/ahriman/core/configuration/test_configuration.py index 9aa1d249..db635f46 100644 --- a/tests/ahriman/core/configuration/test_configuration.py +++ b/tests/ahriman/core/configuration/test_configuration.py @@ -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() diff --git a/tests/ahriman/core/database/migrations/test_m001_package_source.py b/tests/ahriman/core/database/migrations/test_m001_package_source.py index 61cca58d..67d79e85 100644 --- a/tests/ahriman/core/database/migrations/test_m001_package_source.py +++ b/tests/ahriman/core/database/migrations/test_m001_package_source.py @@ -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)), + ]) diff --git a/tests/ahriman/core/database/migrations/test_m011_repository_name.py b/tests/ahriman/core/database/migrations/test_m011_repository_name.py new file mode 100644 index 00000000..b69d30ae --- /dev/null +++ b/tests/ahriman/core/database/migrations/test_m011_repository_name.py @@ -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}), + ]) diff --git a/tests/ahriman/core/database/operations/test_build_operations.py b/tests/ahriman/core/database/operations/test_build_operations.py index 3e43e93d..e155d379 100644 --- a/tests/ahriman/core/database/operations/test_build_operations.py +++ b/tests/ahriman/core/database/operations/test_build_operations.py @@ -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] diff --git a/tests/ahriman/core/database/operations/test_logs_operations.py b/tests/ahriman/core/database/operations/test_logs_operations.py index c4802be7..6a7c5f2c 100644 --- a/tests/ahriman/core/database/operations/test_logs_operations.py +++ b/tests/ahriman/core/database/operations/test_logs_operations.py @@ -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")] diff --git a/tests/ahriman/core/database/operations/test_package_operations.py b/tests/ahriman/core/database/operations/test_package_operations.py index 7ad2cee7..ae02c720 100644 --- a/tests/ahriman/core/database/operations/test_package_operations.py +++ b/tests/ahriman/core/database/operations/test_package_operations.py @@ -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), []) diff --git a/tests/ahriman/core/gitremote/test_remote_pull.py b/tests/ahriman/core/gitremote/test_remote_pull.py index 8382c70f..219336ab 100644 --- a/tests/ahriman/core/gitremote/test_remote_pull.py +++ b/tests/ahriman/core/gitremote/test_remote_pull.py @@ -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() diff --git a/tests/ahriman/core/gitremote/test_remote_pull_trigger.py b/tests/ahriman/core/gitremote/test_remote_pull_trigger.py index f3c39f02..7e743429 100644 --- a/tests/ahriman/core/gitremote/test_remote_pull_trigger.py +++ b/tests/ahriman/core/gitremote/test_remote_pull_trigger.py @@ -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() diff --git a/tests/ahriman/core/gitremote/test_remote_push_trigger.py b/tests/ahriman/core/gitremote/test_remote_push_trigger.py index 15acef38..bfe35173 100644 --- a/tests/ahriman/core/gitremote/test_remote_push_trigger.py +++ b/tests/ahriman/core/gitremote/test_remote_push_trigger.py @@ -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)) diff --git a/tests/ahriman/core/http/test_sync_http_client.py b/tests/ahriman/core/http/test_sync_http_client.py index 9154102a..b5565905 100644 --- a/tests/ahriman/core/http/test_sync_http_client.py +++ b/tests/ahriman/core/http/test_sync_http_client.py @@ -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 diff --git a/tests/ahriman/core/log/test_log_loader.py b/tests/ahriman/core/log/test_log.py similarity index 72% rename from tests/ahriman/core/log/test_log_loader.py rename to tests/ahriman/core/log/test_log.py index 4e12eb26..b6652481 100644 --- a/tests/ahriman/core/log/test_log_loader.py +++ b/tests/ahriman/core/log/test_log.py @@ -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) diff --git a/tests/ahriman/core/report/conftest.py b/tests/ahriman/core/report/conftest.py index 0a6ffb37..8dcc79dd 100644 --- a/tests/ahriman/core/report/conftest.py +++ b/tests/ahriman/core/report/conftest.py @@ -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") diff --git a/tests/ahriman/core/report/test_console.py b/tests/ahriman/core/report/test_console.py index 55429e74..24edb6bb 100644 --- a/tests/ahriman/core/report/test_console.py +++ b/tests/ahriman/core/report/test_console.py @@ -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)]) diff --git a/tests/ahriman/core/report/test_email.py b/tests/ahriman/core/report/test_email.py index f215702d..b835df7f 100644 --- a/tests/ahriman/core/report/test_email.py +++ b/tests/ahriman/core/report/test_email.py @@ -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), {}) diff --git a/tests/ahriman/core/report/test_html.py b/tests/ahriman/core/report/test_html.py index fa790b6c..71690118 100644 --- a/tests/ahriman/core/report/test_html.py +++ b/tests/ahriman/core/report/test_html.py @@ -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") diff --git a/tests/ahriman/core/report/test_jinja_template.py b/tests/ahriman/core/report/test_jinja_template.py index 93deccbf..dd735d77 100644 --- a/tests/ahriman/core/report/test_jinja_template.py +++ b/tests/ahriman/core/report/test_jinja_template.py @@ -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) diff --git a/tests/ahriman/core/report/test_report.py b/tests/ahriman/core/report/test_report.py index c47f97a3..7c92317d 100644 --- a/tests/ahriman/core/report/test_report.py +++ b/tests/ahriman/core/report/test_report.py @@ -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) diff --git a/tests/ahriman/core/report/test_report_trigger.py b/tests/ahriman/core/report/test_report_trigger.py index 4e1377ba..9e79edc9 100644 --- a/tests/ahriman/core/report/test_report_trigger.py +++ b/tests/ahriman/core/report/test_report_trigger.py @@ -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(), []) diff --git a/tests/ahriman/core/report/test_telegram.py b/tests/ahriman/core/report/test_telegram.py index dc86641b..047824fe 100644 --- a/tests/ahriman/core/report/test_telegram.py +++ b/tests/ahriman/core/report/test_telegram.py @@ -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() diff --git a/tests/ahriman/core/repository/test_repository.py b/tests/ahriman/core/repository/test_repository.py index 413d2aca..0422e780 100644 --- a/tests/ahriman/core/repository/test_repository.py +++ b/tests/ahriman/core/repository/test_repository.py @@ -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), diff --git a/tests/ahriman/core/repository/test_repository_properties.py b/tests/ahriman/core/repository/test_repository_properties.py index 694e8467..2f6e6bf3 100644 --- a/tests/ahriman/core/repository/test_repository_properties.py +++ b/tests/ahriman/core/repository/test_repository_properties.py @@ -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 diff --git a/tests/ahriman/core/status/test_watcher.py b/tests/ahriman/core/status/test_watcher.py index 2fb618c8..0444268b 100644 --- a/tests/ahriman/core/status/test_watcher.py +++ b/tests/ahriman/core/status/test_watcher.py @@ -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: diff --git a/tests/ahriman/core/support/conftest.py b/tests/ahriman/core/support/conftest.py index 6e85fca9..905b9053 100644 --- a/tests/ahriman/core/support/conftest.py +++ b/tests/ahriman/core/support/conftest.py @@ -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 diff --git a/tests/ahriman/core/support/pkgbuild/conftest.py b/tests/ahriman/core/support/pkgbuild/conftest.py index 2851d5a2..e9f1c177 100644 --- a/tests/ahriman/core/support/pkgbuild/conftest.py +++ b/tests/ahriman/core/support/pkgbuild/conftest.py @@ -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 diff --git a/tests/ahriman/core/support/pkgbuild/test_keyring_generator.py b/tests/ahriman/core/support/pkgbuild/test_keyring_generator.py index 44ba059c..fdb0adf0 100644 --- a/tests/ahriman/core/support/pkgbuild/test_keyring_generator.py +++ b/tests/ahriman/core/support/pkgbuild/test_keyring_generator.py @@ -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: diff --git a/tests/ahriman/core/support/pkgbuild/test_mirrorlist_generator.py b/tests/ahriman/core/support/pkgbuild/test_mirrorlist_generator.py index 6e5c3553..e1691e6f 100644 --- a/tests/ahriman/core/support/pkgbuild/test_mirrorlist_generator.py +++ b/tests/ahriman/core/support/pkgbuild/test_mirrorlist_generator.py @@ -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: diff --git a/tests/ahriman/core/support/test_keyring_trigger.py b/tests/ahriman/core/support/test_keyring_trigger.py index cf171ef1..bcc2fbfa 100644 --- a/tests/ahriman/core/support/test_keyring_trigger.py +++ b/tests/ahriman/core/support/test_keyring_trigger.py @@ -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() diff --git a/tests/ahriman/core/support/test_mirrorlist_trigger.py b/tests/ahriman/core/support/test_mirrorlist_trigger.py index e5e79013..7f34faaa 100644 --- a/tests/ahriman/core/support/test_mirrorlist_trigger.py +++ b/tests/ahriman/core/support/test_mirrorlist_trigger.py @@ -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() diff --git a/tests/ahriman/core/support/test_package_creator.py b/tests/ahriman/core/support/test_package_creator.py index 6a472e94..61ae71d5 100644 --- a/tests/ahriman/core/support/test_package_creator.py +++ b/tests/ahriman/core/support/test_package_creator.py @@ -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) diff --git a/tests/ahriman/core/test_spawn.py b/tests/ahriman/core/test_spawn.py index 1608966d..dd137a09 100644 --- a/tests/ahriman/core/test_spawn.py +++ b/tests/ahriman/core/test_spawn.py @@ -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" diff --git a/tests/ahriman/core/triggers/test_trigger.py b/tests/ahriman/core/triggers/test_trigger.py index 2a5e832f..57a0ef05 100644 --- a/tests/ahriman/core/triggers/test_trigger.py +++ b/tests/ahriman/core/triggers/test_trigger.py @@ -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: diff --git a/tests/ahriman/core/triggers/test_trigger_loader.py b/tests/ahriman/core/triggers/test_trigger_loader.py index 187a8451..0ea672fd 100644 --- a/tests/ahriman/core/triggers/test_trigger_loader.py +++ b/tests/ahriman/core/triggers/test_trigger_loader.py @@ -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() diff --git a/tests/ahriman/core/upload/conftest.py b/tests/ahriman/core/upload/conftest.py index 380fac6e..4b051825 100644 --- a/tests/ahriman/core/upload/conftest.py +++ b/tests/ahriman/core/upload/conftest.py @@ -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 diff --git a/tests/ahriman/core/upload/test_github.py b/tests/ahriman/core/upload/test_github.py index 57bb12e6..e050b973 100644 --- a/tests/ahriman/core/upload/test_github.py +++ b/tests/ahriman/core/upload/test_github.py @@ -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() diff --git a/tests/ahriman/core/upload/test_s3.py b/tests/ahriman/core/upload/test_s3.py index 979a1fce..7715fb29 100644 --- a/tests/ahriman/core/upload/test_s3.py +++ b/tests/ahriman/core/upload/test_s3.py @@ -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 diff --git a/tests/ahriman/core/upload/test_upload.py b/tests/ahriman/core/upload/test_upload.py index 3f996a52..b01666c8 100644 --- a/tests/ahriman/core/upload/test_upload.py +++ b/tests/ahriman/core/upload/test_upload.py @@ -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"), []) diff --git a/tests/ahriman/core/upload/test_upload_trigger.py b/tests/ahriman/core/upload/test_upload_trigger.py index 06c45400..f49bc02c 100644 --- a/tests/ahriman/core/upload/test_upload_trigger.py +++ b/tests/ahriman/core/upload/test_upload_trigger.py @@ -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, []) diff --git a/tests/ahriman/models/test_repository_id.py b/tests/ahriman/models/test_repository_id.py new file mode 100644 index 00000000..dfb14d6f --- /dev/null +++ b/tests/ahriman/models/test_repository_id.py @@ -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 diff --git a/tests/ahriman/models/test_repository_paths.py b/tests/ahriman/models/test_repository_paths.py index a4d849f2..bcfac33b 100644 --- a/tests/ahriman/models/test_repository_paths.py +++ b/tests/ahriman/models/test_repository_paths.py @@ -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", diff --git a/tests/ahriman/web/conftest.py b/tests/ahriman/web/conftest.py index cc53c7b9..2480a451 100644 --- a/tests/ahriman/web/conftest.py +++ b/tests/ahriman/web/conftest.py @@ -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