mirror of
				https://github.com/arcan1s/ahriman.git
				synced 2025-10-30 13:23:43 +00:00 
			
		
		
		
	feat: implement local reporter mode (#126)
* implement local reporter mode * simplify watcher class * review changes * do not update unknown status * allow empty key patches via api * fix some pylint warnings in tests
This commit is contained in:
		| @ -446,7 +446,7 @@ def _set_patch_list_parser(root: SubParserAction) -> argparse.ArgumentParser: | |||||||
|     """ |     """ | ||||||
|     parser = root.add_parser("patch-list", help="list patch sets", |     parser = root.add_parser("patch-list", help="list patch sets", | ||||||
|                              description="list available patches for the package", formatter_class=_formatter) |                              description="list available patches for the package", formatter_class=_formatter) | ||||||
|     parser.add_argument("package", help="package base", nargs="?") |     parser.add_argument("package", help="package base") | ||||||
|     parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true") |     parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true") | ||||||
|     parser.add_argument("-v", "--variable", help="if set, show only patches for specified PKGBUILD variables", |     parser.add_argument("-v", "--variable", help="if set, show only patches for specified PKGBUILD variables", | ||||||
|                         action="append") |                         action="append") | ||||||
|  | |||||||
| @ -161,8 +161,7 @@ class Application(ApplicationPackages, ApplicationRepository): | |||||||
|                     package = Package.from_aur(package_name, username) |                     package = Package.from_aur(package_name, username) | ||||||
|                 with_dependencies[package.base] = package |                 with_dependencies[package.base] = package | ||||||
|  |  | ||||||
|                 # register package in local database |                 # register package in the database | ||||||
|                 self.database.package_base_update(package) |  | ||||||
|                 self.repository.reporter.set_unknown(package) |                 self.repository.reporter.set_unknown(package) | ||||||
|  |  | ||||||
|         return list(with_dependencies.values()) |         return list(with_dependencies.values()) | ||||||
|  | |||||||
| @ -65,7 +65,7 @@ class ApplicationPackages(ApplicationProperties): | |||||||
|         """ |         """ | ||||||
|         package = Package.from_aur(source, username) |         package = Package.from_aur(source, username) | ||||||
|         self.database.build_queue_insert(package) |         self.database.build_queue_insert(package) | ||||||
|         self.database.package_base_update(package) |         self.reporter.set_unknown(package) | ||||||
|  |  | ||||||
|     def _add_directory(self, source: str, *_: Any) -> None: |     def _add_directory(self, source: str, *_: Any) -> None: | ||||||
|         """ |         """ | ||||||
| @ -139,7 +139,7 @@ class ApplicationPackages(ApplicationProperties): | |||||||
|         """ |         """ | ||||||
|         package = Package.from_official(source, self.repository.pacman, username) |         package = Package.from_official(source, self.repository.pacman, username) | ||||||
|         self.database.build_queue_insert(package) |         self.database.build_queue_insert(package) | ||||||
|         self.database.package_base_update(package) |         self.reporter.set_unknown(package) | ||||||
|  |  | ||||||
|     def add(self, names: Iterable[str], source: PackageSource, username: str | None = None) -> None: |     def add(self, names: Iterable[str], source: PackageSource, username: str | None = None) -> None: | ||||||
|         """ |         """ | ||||||
|  | |||||||
| @ -21,6 +21,7 @@ from ahriman.core.configuration import Configuration | |||||||
| from ahriman.core.database import SQLite | from ahriman.core.database import SQLite | ||||||
| from ahriman.core.log import LazyLogging | from ahriman.core.log import LazyLogging | ||||||
| from ahriman.core.repository import Repository | from ahriman.core.repository import Repository | ||||||
|  | from ahriman.core.status import Client | ||||||
| from ahriman.models.pacman_synchronization import PacmanSynchronization | from ahriman.models.pacman_synchronization import PacmanSynchronization | ||||||
| from ahriman.models.repository_id import RepositoryId | from ahriman.models.repository_id import RepositoryId | ||||||
|  |  | ||||||
| @ -63,3 +64,13 @@ class ApplicationProperties(LazyLogging): | |||||||
|             str: repository architecture |             str: repository architecture | ||||||
|         """ |         """ | ||||||
|         return self.repository_id.architecture |         return self.repository_id.architecture | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def reporter(self) -> Client: | ||||||
|  |         """ | ||||||
|  |         instance of the web/database client | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             Client: repository reposter | ||||||
|  |         """ | ||||||
|  |         return self.repository.reporter | ||||||
|  | |||||||
| @ -39,15 +39,13 @@ class ApplicationRepository(ApplicationProperties): | |||||||
|         Args: |         Args: | ||||||
|             packages(Iterable[Package]): list of packages to retrieve changes |             packages(Iterable[Package]): list of packages to retrieve changes | ||||||
|         """ |         """ | ||||||
|         last_commit_hashes = self.database.hashes_get() |  | ||||||
|  |  | ||||||
|         for package in packages: |         for package in packages: | ||||||
|             last_commit_sha = last_commit_hashes.get(package.base) |             last_commit_sha = self.reporter.package_changes_get(package.base).last_commit_sha | ||||||
|             if last_commit_sha is None: |             if last_commit_sha is None: | ||||||
|                 continue  # skip check in case if we can't calculate diff |                 continue  # skip check in case if we can't calculate diff | ||||||
|  |  | ||||||
|             changes = self.repository.package_changes(package, last_commit_sha) |             changes = self.repository.package_changes(package, last_commit_sha) | ||||||
|             self.repository.reporter.package_changes_set(package.base, changes) |             self.repository.reporter.package_changes_update(package.base, changes) | ||||||
|  |  | ||||||
|     def clean(self, *, cache: bool, chroot: bool, manual: bool, packages: bool, pacman: bool) -> None: |     def clean(self, *, cache: bool, chroot: bool, manual: bool, packages: bool, pacman: bool) -> None: | ||||||
|         """ |         """ | ||||||
|  | |||||||
| @ -50,7 +50,8 @@ class Add(Handler): | |||||||
|         application.add(args.package, args.source, args.username) |         application.add(args.package, args.source, args.username) | ||||||
|         patches = [PkgbuildPatch.from_env(patch) for patch in args.variable] if args.variable is not None else [] |         patches = [PkgbuildPatch.from_env(patch) for patch in args.variable] if args.variable is not None else [] | ||||||
|         for package in args.package:  # for each requested package insert patch |         for package in args.package:  # for each requested package insert patch | ||||||
|             application.database.patches_insert(package, patches) |             for patch in patches: | ||||||
|  |                 application.reporter.package_patches_update(package, patch) | ||||||
|  |  | ||||||
|         if not args.now: |         if not args.now: | ||||||
|             return |             return | ||||||
|  | |||||||
| @ -56,4 +56,4 @@ class Change(Handler): | |||||||
|                 ChangesPrinter(changes)(verbose=True, separator="") |                 ChangesPrinter(changes)(verbose=True, separator="") | ||||||
|                 Change.check_if_empty(args.exit_code, changes.is_empty) |                 Change.check_if_empty(args.exit_code, changes.is_empty) | ||||||
|             case Action.Remove: |             case Action.Remove: | ||||||
|                 client.package_changes_set(args.package, Changes()) |                 client.package_changes_update(args.package, Changes()) | ||||||
|  | |||||||
| @ -116,25 +116,28 @@ class Patch(Handler): | |||||||
|             package_base(str): package base |             package_base(str): package base | ||||||
|             patch(PkgbuildPatch): patch descriptor |             patch(PkgbuildPatch): patch descriptor | ||||||
|         """ |         """ | ||||||
|         application.database.patches_insert(package_base, [patch]) |         application.reporter.package_patches_update(package_base, patch) | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def patch_set_list(application: Application, package_base: str | None, variables: list[str] | None, |     def patch_set_list(application: Application, package_base: str, variables: list[str] | None, | ||||||
|                        exit_code: bool) -> None: |                        exit_code: bool) -> None: | ||||||
|         """ |         """ | ||||||
|         list patches available for the package base |         list patches available for the package base | ||||||
|  |  | ||||||
|         Args: |         Args: | ||||||
|             application(Application): application instance |             application(Application): application instance | ||||||
|             package_base(str | None): package base |             package_base(str): package base | ||||||
|             variables(list[str] | None): extract patches only for specified PKGBUILD variables |             variables(list[str] | None): extract patches only for specified PKGBUILD variables | ||||||
|             exit_code(bool): exit with error on empty search result |             exit_code(bool): exit with error on empty search result | ||||||
|         """ |         """ | ||||||
|         patches = application.database.patches_list(package_base, variables) |         patches = [ | ||||||
|  |             patch | ||||||
|  |             for patch in application.reporter.package_patches_get(package_base, None) | ||||||
|  |             if variables is None or patch.key in variables | ||||||
|  |         ] | ||||||
|         Patch.check_if_empty(exit_code, not patches) |         Patch.check_if_empty(exit_code, not patches) | ||||||
|  |  | ||||||
|         for base, patch in patches.items(): |         PatchPrinter(package_base, patches)(verbose=True, separator=" = ") | ||||||
|             PatchPrinter(base, patch)(verbose=True, separator=" = ") |  | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def patch_set_remove(application: Application, package_base: str, variables: list[str] | None) -> None: |     def patch_set_remove(application: Application, package_base: str, variables: list[str] | None) -> None: | ||||||
| @ -146,4 +149,8 @@ class Patch(Handler): | |||||||
|             package_base(str): package base |             package_base(str): package base | ||||||
|             variables(list[str] | None): remove patches only for specified PKGBUILD variables |             variables(list[str] | None): remove patches only for specified PKGBUILD variables | ||||||
|         """ |         """ | ||||||
|         application.database.patches_remove(package_base, variables) |         if variables is not None: | ||||||
|  |             for variable in variables:  # iterate over single variable | ||||||
|  |                 application.reporter.package_patches_remove(package_base, variable) | ||||||
|  |         else: | ||||||
|  |             application.reporter.package_patches_remove(package_base, None)  # just pass as is | ||||||
|  | |||||||
| @ -76,7 +76,7 @@ class Rebuild(Handler): | |||||||
|         if from_database: |         if from_database: | ||||||
|             return [ |             return [ | ||||||
|                 package |                 package | ||||||
|                 for (package, last_status) in application.database.packages_get() |                 for (package, last_status) in application.reporter.package_get(None) | ||||||
|                 if status is None or last_status.status == status |                 if status is None or last_status.status == status | ||||||
|             ] |             ] | ||||||
|  |  | ||||||
|  | |||||||
| @ -51,12 +51,8 @@ class StatusUpdate(Handler): | |||||||
|         match args.action: |         match args.action: | ||||||
|             case Action.Update if args.package: |             case Action.Update if args.package: | ||||||
|                 # update packages statuses |                 # update packages statuses | ||||||
|                 packages = application.repository.packages() |                 for package in args.package: | ||||||
|                 for base in args.package: |                     client.package_update(package, args.status) | ||||||
|                     if (local := next((package for package in packages if package.base == base), None)) is not None: |  | ||||||
|                         client.package_add(local, args.status) |  | ||||||
|                     else: |  | ||||||
|                         client.package_update(base, args.status) |  | ||||||
|             case Action.Update: |             case Action.Update: | ||||||
|                 # update service status |                 # update service status | ||||||
|                 client.status_update(args.status) |                 client.status_update(args.status) | ||||||
|  | |||||||
| @ -27,7 +27,7 @@ from ahriman import __version__ | |||||||
| from ahriman.core.configuration import Configuration | from ahriman.core.configuration import Configuration | ||||||
| from ahriman.core.exceptions import DuplicateRunError | from ahriman.core.exceptions import DuplicateRunError | ||||||
| from ahriman.core.log import LazyLogging | from ahriman.core.log import LazyLogging | ||||||
| from ahriman.core.status.client import Client | from ahriman.core.status import Client | ||||||
| from ahriman.core.util import check_user | from ahriman.core.util import check_user | ||||||
| from ahriman.models.build_status import BuildStatusEnum | from ahriman.models.build_status import BuildStatusEnum | ||||||
| from ahriman.models.repository_id import RepositoryId | from ahriman.models.repository_id import RepositoryId | ||||||
|  | |||||||
| @ -177,7 +177,7 @@ class Pacman(LazyLogging): | |||||||
|             PacmanDatabase(database, self.configuration).sync(force=force) |             PacmanDatabase(database, self.configuration).sync(force=force) | ||||||
|         transaction.release() |         transaction.release() | ||||||
|  |  | ||||||
|     def files(self, packages: Iterable[str] | None = None) -> dict[str, set[Path]]: |     def files(self, packages: Iterable[str] | None = None) -> dict[str, set[str]]: | ||||||
|         """ |         """ | ||||||
|         extract list of known packages from the databases |         extract list of known packages from the databases | ||||||
|  |  | ||||||
| @ -185,11 +185,11 @@ class Pacman(LazyLogging): | |||||||
|             packages(Iterable[str] | None, optional): filter by package names (Default value = None) |             packages(Iterable[str] | None, optional): filter by package names (Default value = None) | ||||||
|  |  | ||||||
|         Returns: |         Returns: | ||||||
|             dict[str, set[Path]]: map of package name to its list of files |             dict[str, set[str]]: map of package name to its list of files | ||||||
|         """ |         """ | ||||||
|         packages = packages or [] |         packages = packages or [] | ||||||
|  |  | ||||||
|         def extract(tar: tarfile.TarFile) -> Generator[tuple[str, set[Path]], None, None]: |         def extract(tar: tarfile.TarFile) -> Generator[tuple[str, set[str]], None, None]: | ||||||
|             for descriptor in filter(lambda info: info.path.endswith("/files"), tar.getmembers()): |             for descriptor in filter(lambda info: info.path.endswith("/files"), tar.getmembers()): | ||||||
|                 package, *_ = str(Path(descriptor.path).parent).rsplit("-", 2) |                 package, *_ = str(Path(descriptor.path).parent).rsplit("-", 2) | ||||||
|                 if packages and package not in packages: |                 if packages and package not in packages: | ||||||
| @ -197,11 +197,11 @@ class Pacman(LazyLogging): | |||||||
|                 content = tar.extractfile(descriptor) |                 content = tar.extractfile(descriptor) | ||||||
|                 if content is None: |                 if content is None: | ||||||
|                     continue |                     continue | ||||||
|                 files = {Path(filename.decode("utf8").rstrip()) for filename in content.readlines()} |                 files = {filename.decode("utf8").rstrip() for filename in content.readlines()} | ||||||
|  |  | ||||||
|                 yield package, files |                 yield package, files | ||||||
|  |  | ||||||
|         result: dict[str, set[Path]] = {} |         result: dict[str, set[str]] = {} | ||||||
|         for database in self.handle.get_syncdbs(): |         for database in self.handle.get_syncdbs(): | ||||||
|             database_file = self.repository_paths.pacman / "sync" / f"{database.name}.files.tar.gz" |             database_file = self.repository_paths.pacman / "sync" / f"{database.name}.files.tar.gz" | ||||||
|             if not database_file.is_file(): |             if not database_file.is_file(): | ||||||
|  | |||||||
| @ -21,7 +21,6 @@ from pathlib import Path | |||||||
|  |  | ||||||
| from ahriman.core.build_tools.sources import Sources | from ahriman.core.build_tools.sources import Sources | ||||||
| from ahriman.core.configuration import Configuration | from ahriman.core.configuration import Configuration | ||||||
| from ahriman.core.database import SQLite |  | ||||||
| from ahriman.core.exceptions import BuildError | from ahriman.core.exceptions import BuildError | ||||||
| from ahriman.core.log import LazyLogging | from ahriman.core.log import LazyLogging | ||||||
| from ahriman.core.util import check_output | from ahriman.core.util import check_output | ||||||
| @ -116,20 +115,20 @@ class Task(LazyLogging): | |||||||
|         # e.g. in some cases packagelist command produces debug packages which were not actually built |         # e.g. in some cases packagelist command produces debug packages which were not actually built | ||||||
|         return list(filter(lambda path: path.is_file(), map(Path, packages))) |         return list(filter(lambda path: path.is_file(), map(Path, packages))) | ||||||
|  |  | ||||||
|     def init(self, sources_dir: Path, database: SQLite, local_version: str | None) -> str | None: |     def init(self, sources_dir: Path, patches: list[PkgbuildPatch], local_version: str | None) -> str | None: | ||||||
|         """ |         """ | ||||||
|         fetch package from git |         fetch package from git | ||||||
|  |  | ||||||
|         Args: |         Args: | ||||||
|             sources_dir(Path): local path to fetch |             sources_dir(Path): local path to fetch | ||||||
|             database(SQLite): database instance |             patches(list[PkgbuildPatch]): list of patches for the package | ||||||
|             local_version(str | None): local version of the package. If set and equal to current version, it will |             local_version(str | None): local version of the package. If set and equal to current version, it will | ||||||
|                 automatically bump pkgrel |                 automatically bump pkgrel | ||||||
|  |  | ||||||
|         Returns: |         Returns: | ||||||
|             str | None: current commit sha if available |             str | None: current commit sha if available | ||||||
|         """ |         """ | ||||||
|         last_commit_sha = Sources.load(sources_dir, self.package, database.patches_get(self.package.base), self.paths) |         last_commit_sha = Sources.load(sources_dir, self.package, patches, self.paths) | ||||||
|         if local_version is None: |         if local_version is None: | ||||||
|             return last_commit_sha  # there is no local package or pkgrel increment is disabled |             return last_commit_sha  # there is no local package or pkgrel increment is disabled | ||||||
|  |  | ||||||
|  | |||||||
| @ -117,27 +117,3 @@ class ChangesOperations(Operations): | |||||||
|                 }) |                 }) | ||||||
|  |  | ||||||
|         return self.with_connection(run, commit=True) |         return self.with_connection(run, commit=True) | ||||||
|  |  | ||||||
|     def hashes_get(self, repository_id: RepositoryId | None = None) -> dict[str, str]: |  | ||||||
|         """ |  | ||||||
|         extract last commit hashes if available |  | ||||||
|  |  | ||||||
|         Args: |  | ||||||
|             repository_id(RepositoryId, optional): repository unique identifier override (Default value = None) |  | ||||||
|  |  | ||||||
|         Returns: |  | ||||||
|             dict[str, str]: map of package base to its last commit hash |  | ||||||
|         """ |  | ||||||
|  |  | ||||||
|         repository_id = repository_id or self._repository_id |  | ||||||
|  |  | ||||||
|         def run(connection: Connection) -> dict[str, str]: |  | ||||||
|             return { |  | ||||||
|                 row["package_base"]: row["last_commit_sha"] |  | ||||||
|                 for row in connection.execute( |  | ||||||
|                     """select package_base, last_commit_sha from package_changes where repository = :repository""", |  | ||||||
|                     {"repository": repository_id.id} |  | ||||||
|                 ) |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|         return self.with_connection(run) |  | ||||||
|  | |||||||
| @ -17,7 +17,6 @@ | |||||||
| # You should have received a copy of the GNU General Public License | # You should have received a copy of the GNU General Public License | ||||||
| # along with this program. If not, see <http://www.gnu.org/licenses/>. | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
| # | # | ||||||
| from pathlib import Path |  | ||||||
| from sqlite3 import Connection | from sqlite3 import Connection | ||||||
|  |  | ||||||
| from ahriman.core.database.operations.operations import Operations | from ahriman.core.database.operations.operations import Operations | ||||||
| @ -31,7 +30,7 @@ class DependenciesOperations(Operations): | |||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     def dependencies_get(self, package_base: str | None = None, |     def dependencies_get(self, package_base: str | None = None, | ||||||
|                          repository_id: RepositoryId | None = None) -> list[Dependencies]: |                          repository_id: RepositoryId | None = None) -> dict[str, Dependencies]: | ||||||
|         """ |         """ | ||||||
|         get dependencies for the specific package base if available |         get dependencies for the specific package base if available | ||||||
|  |  | ||||||
| @ -44,15 +43,9 @@ class DependenciesOperations(Operations): | |||||||
|         """ |         """ | ||||||
|         repository_id = repository_id or self._repository_id |         repository_id = repository_id or self._repository_id | ||||||
|  |  | ||||||
|         def run(connection: Connection) -> list[Dependencies]: |         def run(connection: Connection) -> dict[str, Dependencies]: | ||||||
|             return [ |             return { | ||||||
|                 Dependencies( |                 row["package_base"]: Dependencies(row["dependencies"]) | ||||||
|                     row["package_base"], |  | ||||||
|                     { |  | ||||||
|                         Path(path): packages |  | ||||||
|                         for path, packages in row["dependencies"].items() |  | ||||||
|                     } |  | ||||||
|                 ) |  | ||||||
|                 for row in connection.execute( |                 for row in connection.execute( | ||||||
|                     """ |                     """ | ||||||
|                         select package_base, dependencies from package_dependencies |                         select package_base, dependencies from package_dependencies | ||||||
| @ -64,15 +57,17 @@ class DependenciesOperations(Operations): | |||||||
|                         "repository": repository_id.id, |                         "repository": repository_id.id, | ||||||
|                     } |                     } | ||||||
|                 ) |                 ) | ||||||
|             ] |             } | ||||||
|  |  | ||||||
|         return self.with_connection(run) |         return self.with_connection(run) | ||||||
|  |  | ||||||
|     def dependencies_insert(self, dependencies: Dependencies, repository_id: RepositoryId | None = None) -> None: |     def dependencies_insert(self, package_base: str, dependencies: Dependencies, | ||||||
|  |                             repository_id: RepositoryId | None = None) -> None: | ||||||
|         """ |         """ | ||||||
|         insert package dependencies |         insert package dependencies | ||||||
|  |  | ||||||
|         Args: |         Args: | ||||||
|  |             package_base(str): package base | ||||||
|             dependencies(Dependencies): package dependencies |             dependencies(Dependencies): package dependencies | ||||||
|             repository_id(RepositoryId, optional): repository unique identifier override (Default value = None) |             repository_id(RepositoryId, optional): repository unique identifier override (Default value = None) | ||||||
|         """ |         """ | ||||||
| @ -89,12 +84,9 @@ class DependenciesOperations(Operations): | |||||||
|                 dependencies = :dependencies |                 dependencies = :dependencies | ||||||
|                 """, |                 """, | ||||||
|                 { |                 { | ||||||
|                     "package_base": dependencies.package_base, |                     "package_base": package_base, | ||||||
|                     "repository": repository_id.id, |                     "repository": repository_id.id, | ||||||
|                     "dependencies": { |                     "dependencies": dependencies.paths, | ||||||
|                         str(path): packages |  | ||||||
|                         for path, packages in dependencies.paths.items() |  | ||||||
|                     } |  | ||||||
|                 }) |                 }) | ||||||
|  |  | ||||||
|         return self.with_connection(run, commit=True) |         return self.with_connection(run, commit=True) | ||||||
|  | |||||||
| @ -25,6 +25,7 @@ from typing import Any, TypeVar | |||||||
|  |  | ||||||
| from ahriman.core.log import LazyLogging | from ahriman.core.log import LazyLogging | ||||||
| from ahriman.models.repository_id import RepositoryId | from ahriman.models.repository_id import RepositoryId | ||||||
|  | from ahriman.models.repository_paths import RepositoryPaths | ||||||
|  |  | ||||||
|  |  | ||||||
| T = TypeVar("T") | T = TypeVar("T") | ||||||
| @ -38,7 +39,7 @@ class Operations(LazyLogging): | |||||||
|         path(Path): path to the database file |         path(Path): path to the database file | ||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     def __init__(self, path: Path, repository_id: RepositoryId) -> None: |     def __init__(self, path: Path, repository_id: RepositoryId, repository_paths: RepositoryPaths) -> None: | ||||||
|         """ |         """ | ||||||
|         default constructor |         default constructor | ||||||
|  |  | ||||||
| @ -48,6 +49,7 @@ class Operations(LazyLogging): | |||||||
|         """ |         """ | ||||||
|         self.path = path |         self.path = path | ||||||
|         self._repository_id = repository_id |         self._repository_id = repository_id | ||||||
|  |         self._repository_paths = repository_paths | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def factory(cursor: sqlite3.Cursor, row: tuple[Any, ...]) -> dict[str, Any]: |     def factory(cursor: sqlite3.Cursor, row: tuple[Any, ...]) -> dict[str, Any]: | ||||||
|  | |||||||
| @ -150,34 +150,6 @@ class PackageOperations(Operations): | |||||||
|             """, |             """, | ||||||
|             package_list) |             package_list) | ||||||
|  |  | ||||||
|     @staticmethod |  | ||||||
|     def _package_update_insert_status(connection: Connection, package_base: str, status: BuildStatus, |  | ||||||
|                                       repository_id: RepositoryId) -> None: |  | ||||||
|         """ |  | ||||||
|         insert base package status into table |  | ||||||
|  |  | ||||||
|         Args: |  | ||||||
|             connection(Connection): database connection |  | ||||||
|             package_base(str): package base name |  | ||||||
|             status(BuildStatus): new build status |  | ||||||
|             repository_id(RepositoryId): repository unique identifier |  | ||||||
|         """ |  | ||||||
|         connection.execute( |  | ||||||
|             """ |  | ||||||
|             insert into package_statuses |  | ||||||
|             (package_base, status, last_updated, repository) |  | ||||||
|             values |  | ||||||
|             (:package_base, :status, :last_updated, :repository) |  | ||||||
|             on conflict (package_base, repository) do update set |  | ||||||
|             status = :status, last_updated = :last_updated |  | ||||||
|             """, |  | ||||||
|             { |  | ||||||
|                 "package_base": package_base, |  | ||||||
|                 "status": status.status.value, |  | ||||||
|                 "last_updated": status.timestamp, |  | ||||||
|                 "repository": repository_id.id, |  | ||||||
|             }) |  | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def _packages_get_select_package_bases(connection: Connection, repository_id: RepositoryId) -> dict[str, Package]: |     def _packages_get_select_package_bases(connection: Connection, repository_id: RepositoryId) -> dict[str, Package]: | ||||||
|         """ |         """ | ||||||
| @ -246,21 +218,6 @@ class PackageOperations(Operations): | |||||||
|             ) |             ) | ||||||
|         } |         } | ||||||
|  |  | ||||||
|     def package_base_update(self, package: Package, repository_id: RepositoryId | None = None) -> None: |  | ||||||
|         """ |  | ||||||
|         update package base only |  | ||||||
|  |  | ||||||
|         Args: |  | ||||||
|             package(Package): package properties |  | ||||||
|             repository_id(RepositoryId, optional): repository unique identifier override (Default value = None) |  | ||||||
|         """ |  | ||||||
|         repository_id = repository_id or self._repository_id |  | ||||||
|  |  | ||||||
|         def run(connection: Connection) -> None: |  | ||||||
|             self._package_update_insert_base(connection, package, repository_id) |  | ||||||
|  |  | ||||||
|         return self.with_connection(run, commit=True) |  | ||||||
|  |  | ||||||
|     def package_remove(self, package_base: str, repository_id: RepositoryId | None = None) -> None: |     def package_remove(self, package_base: str, repository_id: RepositoryId | None = None) -> None: | ||||||
|         """ |         """ | ||||||
|         remove package from database |         remove package from database | ||||||
| @ -277,20 +234,18 @@ class PackageOperations(Operations): | |||||||
|  |  | ||||||
|         return self.with_connection(run, commit=True) |         return self.with_connection(run, commit=True) | ||||||
|  |  | ||||||
|     def package_update(self, package: Package, status: BuildStatus, repository_id: RepositoryId | None = None) -> None: |     def package_update(self, package: Package, repository_id: RepositoryId | None = None) -> None: | ||||||
|         """ |         """ | ||||||
|         update package status |         update package status | ||||||
|  |  | ||||||
|         Args: |         Args: | ||||||
|             package(Package): package properties |             package(Package): package properties | ||||||
|             status(BuildStatus): new build status |  | ||||||
|             repository_id(RepositoryId, optional): repository unique identifier override (Default value = None) |             repository_id(RepositoryId, optional): repository unique identifier override (Default value = None) | ||||||
|         """ |         """ | ||||||
|         repository_id = repository_id or self._repository_id |         repository_id = repository_id or self._repository_id | ||||||
|  |  | ||||||
|         def run(connection: Connection) -> None: |         def run(connection: Connection) -> None: | ||||||
|             self._package_update_insert_base(connection, package, repository_id) |             self._package_update_insert_base(connection, package, repository_id) | ||||||
|             self._package_update_insert_status(connection, package.base, status, repository_id) |  | ||||||
|             self._package_update_insert_packages(connection, package, repository_id) |             self._package_update_insert_packages(connection, package, repository_id) | ||||||
|             self._package_remove_packages(connection, package.base, package.packages.keys(), repository_id) |             self._package_remove_packages(connection, package.base, package.packages.keys(), repository_id) | ||||||
|  |  | ||||||
| @ -317,22 +272,32 @@ class PackageOperations(Operations): | |||||||
|  |  | ||||||
|         return self.with_connection(lambda connection: list(run(connection))) |         return self.with_connection(lambda connection: list(run(connection))) | ||||||
|  |  | ||||||
|     def remotes_get(self, repository_id: RepositoryId | None = None) -> dict[str, RemoteSource]: |     def status_update(self, package_base: str, status: BuildStatus, repository_id: RepositoryId | None = None) -> None: | ||||||
|         """ |         """ | ||||||
|         get packages remotes based on current settings |         insert base package status into table | ||||||
|  |  | ||||||
|         Args: |         Args: | ||||||
|  |             package_base(str): package base name | ||||||
|  |             status(BuildStatus): new build status | ||||||
|             repository_id(RepositoryId, optional): repository unique identifier override (Default value = None) |             repository_id(RepositoryId, optional): repository unique identifier override (Default value = None) | ||||||
|  |  | ||||||
|         Returns: |  | ||||||
|             dict[str, RemoteSource]: map of package base to its remote sources |  | ||||||
|         """ |         """ | ||||||
|         repository_id = repository_id or self._repository_id |         repository_id = repository_id or self._repository_id | ||||||
|  |  | ||||||
|         def run(connection: Connection) -> dict[str, Package]: |         def run(connection: Connection) -> None: | ||||||
|             return self._packages_get_select_package_bases(connection, repository_id) |             connection.execute( | ||||||
|  |                 """ | ||||||
|  |                 insert into package_statuses | ||||||
|  |                 (package_base, status, last_updated, repository) | ||||||
|  |                 values | ||||||
|  |                 (:package_base, :status, :last_updated, :repository) | ||||||
|  |                 on conflict (package_base, repository) do update set | ||||||
|  |                 status = :status, last_updated = :last_updated | ||||||
|  |                 """, | ||||||
|  |                 { | ||||||
|  |                     "package_base": package_base, | ||||||
|  |                     "status": status.status.value, | ||||||
|  |                     "last_updated": status.timestamp, | ||||||
|  |                     "repository": repository_id.id, | ||||||
|  |                 }) | ||||||
|  |  | ||||||
|         return { |         return self.with_connection(run, commit=True) | ||||||
|             package_base: package.remote |  | ||||||
|             for package_base, package in self.with_connection(run).items() |  | ||||||
|         } |  | ||||||
|  | |||||||
| @ -66,7 +66,7 @@ class SQLite( | |||||||
|         path = cls.database_path(configuration) |         path = cls.database_path(configuration) | ||||||
|         _, repository_id = configuration.check_loaded() |         _, repository_id = configuration.check_loaded() | ||||||
|  |  | ||||||
|         database = cls(path, repository_id) |         database = cls(path, repository_id, configuration.repository_paths) | ||||||
|         database.init(configuration) |         database.init(configuration) | ||||||
|  |  | ||||||
|         return database |         return database | ||||||
| @ -119,3 +119,6 @@ class SQLite( | |||||||
|         self.logs_remove(package_base, None) |         self.logs_remove(package_base, None) | ||||||
|         self.changes_remove(package_base) |         self.changes_remove(package_base) | ||||||
|         self.dependencies_remove(package_base) |         self.dependencies_remove(package_base) | ||||||
|  |  | ||||||
|  |         # remove local cache too | ||||||
|  |         self._repository_paths.tree_clear(package_base) | ||||||
|  | |||||||
| @ -25,9 +25,9 @@ from tempfile import TemporaryDirectory | |||||||
|  |  | ||||||
| from ahriman.core.build_tools.sources import Sources | from ahriman.core.build_tools.sources import Sources | ||||||
| from ahriman.core.configuration import Configuration | from ahriman.core.configuration import Configuration | ||||||
| from ahriman.core.database import SQLite |  | ||||||
| from ahriman.core.exceptions import GitRemoteError | from ahriman.core.exceptions import GitRemoteError | ||||||
| from ahriman.core.log import LazyLogging | from ahriman.core.log import LazyLogging | ||||||
|  | from ahriman.core.status import Client | ||||||
| from ahriman.models.package import Package | from ahriman.models.package import Package | ||||||
| from ahriman.models.package_source import PackageSource | from ahriman.models.package_source import PackageSource | ||||||
| from ahriman.models.remote_source import RemoteSource | from ahriman.models.remote_source import RemoteSource | ||||||
| @ -40,20 +40,20 @@ class RemotePush(LazyLogging): | |||||||
|  |  | ||||||
|     Attributes: |     Attributes: | ||||||
|         commit_author(tuple[str, str] | None): optional commit author in form of git config |         commit_author(tuple[str, str] | None): optional commit author in form of git config | ||||||
|         database(SQLite): database instance |  | ||||||
|         remote_source(RemoteSource): repository remote source (remote pull url and branch) |         remote_source(RemoteSource): repository remote source (remote pull url and branch) | ||||||
|  |         reporter(Client): reporter client used for additional information retrieval | ||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     def __init__(self, database: SQLite, configuration: Configuration, section: str) -> None: |     def __init__(self, reporter: Client, configuration: Configuration, section: str) -> None: | ||||||
|         """ |         """ | ||||||
|         default constructor |         default constructor | ||||||
|  |  | ||||||
|         Args: |         Args: | ||||||
|             database(SQLite): database instance |             reporter(Client): reporter client | ||||||
|             configuration(Configuration): configuration instance |             configuration(Configuration): configuration instance | ||||||
|             section(str): settings section name |             section(str): settings section name | ||||||
|         """ |         """ | ||||||
|         self.database = database |         self.reporter = reporter | ||||||
|  |  | ||||||
|         commit_email = configuration.get(section, "commit_email", fallback="ahriman@localhost") |         commit_email = configuration.get(section, "commit_email", fallback="ahriman@localhost") | ||||||
|         commit_user = configuration.get(section, "commit_user", fallback="ahriman") |         commit_user = configuration.get(section, "commit_user", fallback="ahriman") | ||||||
| @ -92,7 +92,7 @@ class RemotePush(LazyLogging): | |||||||
|             else: |             else: | ||||||
|                 shutil.rmtree(git_file) |                 shutil.rmtree(git_file) | ||||||
|         # ...copy all patches... |         # ...copy all patches... | ||||||
|         for patch in self.database.patches_get(package.base): |         for patch in self.reporter.package_patches_get(package.base, None): | ||||||
|             filename = f"ahriman-{package.base}.patch" if patch.key is None else f"ahriman-{patch.key}.patch" |             filename = f"ahriman-{package.base}.patch" if patch.key is None else f"ahriman-{patch.key}.patch" | ||||||
|             patch.write(package_target_dir / filename) |             patch.write(package_target_dir / filename) | ||||||
|         # ...and finally return path to the copied directory |         # ...and finally return path to the copied directory | ||||||
|  | |||||||
| @ -19,8 +19,8 @@ | |||||||
| # | # | ||||||
| from ahriman.core import context | from ahriman.core import context | ||||||
| from ahriman.core.configuration import Configuration | from ahriman.core.configuration import Configuration | ||||||
| from ahriman.core.database import SQLite |  | ||||||
| from ahriman.core.gitremote.remote_push import RemotePush | from ahriman.core.gitremote.remote_push import RemotePush | ||||||
|  | from ahriman.core.status import Client | ||||||
| from ahriman.core.triggers import Trigger | from ahriman.core.triggers import Trigger | ||||||
| from ahriman.models.package import Package | from ahriman.models.package import Package | ||||||
| from ahriman.models.repository_id import RepositoryId | from ahriman.models.repository_id import RepositoryId | ||||||
| @ -110,10 +110,10 @@ class RemotePushTrigger(Trigger): | |||||||
|             GitRemoteError: if database is not set in context |             GitRemoteError: if database is not set in context | ||||||
|         """ |         """ | ||||||
|         ctx = context.get() |         ctx = context.get() | ||||||
|         database = ctx.get(SQLite) |         reporter = ctx.get(Client) | ||||||
|  |  | ||||||
|         for target in self.targets: |         for target in self.targets: | ||||||
|             section, _ = self.configuration.gettype( |             section, _ = self.configuration.gettype( | ||||||
|                 target, self.repository_id, fallback=self.CONFIGURATION_SCHEMA_FALLBACK) |                 target, self.repository_id, fallback=self.CONFIGURATION_SCHEMA_FALLBACK) | ||||||
|             runner = RemotePush(database, self.configuration, section) |             runner = RemotePush(reporter, self.configuration, section) | ||||||
|             runner.run(result) |             runner.run(result) | ||||||
|  | |||||||
| @ -22,6 +22,7 @@ import logging | |||||||
| from typing import Self | from typing import Self | ||||||
|  |  | ||||||
| from ahriman.core.configuration import Configuration | from ahriman.core.configuration import Configuration | ||||||
|  | from ahriman.core.status import Client | ||||||
| from ahriman.models.repository_id import RepositoryId | from ahriman.models.repository_id import RepositoryId | ||||||
|  |  | ||||||
|  |  | ||||||
| @ -49,8 +50,6 @@ class HttpLogHandler(logging.Handler): | |||||||
|         # we don't really care about those parameters because they will be handled by the reporter |         # we don't really care about those parameters because they will be handled by the reporter | ||||||
|         logging.Handler.__init__(self) |         logging.Handler.__init__(self) | ||||||
|  |  | ||||||
|         # client has to be imported here because of circular imports |  | ||||||
|         from ahriman.core.status.client import Client |  | ||||||
|         self.reporter = Client.load(repository_id, configuration, report=report) |         self.reporter = Client.load(repository_id, configuration, report=report) | ||||||
|         self.suppress_errors = suppress_errors |         self.suppress_errors = suppress_errors | ||||||
|  |  | ||||||
| @ -92,7 +91,7 @@ class HttpLogHandler(logging.Handler): | |||||||
|             return  # in case if no package base supplied we need just skip log message |             return  # in case if no package base supplied we need just skip log message | ||||||
|  |  | ||||||
|         try: |         try: | ||||||
|             self.reporter.package_logs(log_record_id, record) |             self.reporter.package_logs_add(log_record_id, record.created, record.getMessage()) | ||||||
|         except Exception: |         except Exception: | ||||||
|             if self.suppress_errors: |             if self.suppress_errors: | ||||||
|                 return |                 return | ||||||
|  | |||||||
| @ -58,7 +58,8 @@ class Executor(PackageInfo, Cleaner): | |||||||
|             self.reporter.set_building(package.base) |             self.reporter.set_building(package.base) | ||||||
|             task = Task(package, self.configuration, self.architecture, self.paths) |             task = Task(package, self.configuration, self.architecture, self.paths) | ||||||
|             local_version = local_versions.get(package.base) if bump_pkgrel else None |             local_version = local_versions.get(package.base) if bump_pkgrel else None | ||||||
|             commit_sha = task.init(local_path, self.database, local_version) |             patches = self.reporter.package_patches_get(package.base, None) | ||||||
|  |             commit_sha = task.init(local_path, patches, local_version) | ||||||
|             built = task.build(local_path, PACKAGER=packager_id) |             built = task.build(local_path, PACKAGER=packager_id) | ||||||
|             for src in built: |             for src in built: | ||||||
|                 dst = self.paths.packages / src.name |                 dst = self.paths.packages / src.name | ||||||
| @ -77,10 +78,10 @@ class Executor(PackageInfo, Cleaner): | |||||||
|                     packager = self.packager(packagers, single.base) |                     packager = self.packager(packagers, single.base) | ||||||
|                     last_commit_sha = build_single(single, Path(dir_name), packager.packager_id) |                     last_commit_sha = build_single(single, Path(dir_name), packager.packager_id) | ||||||
|                     # clear changes and update commit hash |                     # clear changes and update commit hash | ||||||
|                     self.reporter.package_changes_set(single.base, Changes(last_commit_sha)) |                     self.reporter.package_changes_update(single.base, Changes(last_commit_sha)) | ||||||
|                     # update dependencies list |                     # update dependencies list | ||||||
|                     dependencies = PackageArchive(self.paths.build_directory, single).depends_on() |                     dependencies = PackageArchive(self.paths.build_directory, single).depends_on() | ||||||
|                     self.database.dependencies_insert(dependencies) |                     self.reporter.package_dependencies_update(single.base, dependencies) | ||||||
|                     # update result set |                     # update result set | ||||||
|                     result.add_updated(single) |                     result.add_updated(single) | ||||||
|                 except Exception: |                 except Exception: | ||||||
| @ -102,9 +103,7 @@ class Executor(PackageInfo, Cleaner): | |||||||
|         """ |         """ | ||||||
|         def remove_base(package_base: str) -> None: |         def remove_base(package_base: str) -> None: | ||||||
|             try: |             try: | ||||||
|                 self.paths.tree_clear(package_base)  # remove all internal files |                 self.reporter.package_remove(package_base) | ||||||
|                 self.database.package_clear(package_base) |  | ||||||
|                 self.reporter.package_remove(package_base)  # we only update status page in case of base removal |  | ||||||
|             except Exception: |             except Exception: | ||||||
|                 self.logger.exception("could not remove base %s", package_base) |                 self.logger.exception("could not remove base %s", package_base) | ||||||
|  |  | ||||||
|  | |||||||
| @ -43,14 +43,14 @@ class PackageInfo(RepositoryProperties): | |||||||
|         Returns: |         Returns: | ||||||
|             list[Package]: list of read packages |             list[Package]: list of read packages | ||||||
|         """ |         """ | ||||||
|         sources = self.database.remotes_get() |         sources = {package.base: package.remote for package, _, in self.reporter.package_get(None)} | ||||||
|  |  | ||||||
|         result: dict[str, Package] = {} |         result: dict[str, Package] = {} | ||||||
|         # we are iterating over bases, not single packages |         # we are iterating over bases, not single packages | ||||||
|         for full_path in packages: |         for full_path in packages: | ||||||
|             try: |             try: | ||||||
|                 local = Package.from_archive(full_path, self.pacman) |                 local = Package.from_archive(full_path, self.pacman) | ||||||
|                 if (source := sources.get(local.base)) is not None: |                 if (source := sources.get(local.base)) is not None:  # update source with remote | ||||||
|                     local.remote = source |                     local.remote = source | ||||||
|  |  | ||||||
|                 current = result.setdefault(local.base, local) |                 current = result.setdefault(local.base, local) | ||||||
| @ -78,7 +78,8 @@ class PackageInfo(RepositoryProperties): | |||||||
|         """ |         """ | ||||||
|         with TemporaryDirectory(ignore_cleanup_errors=True) as dir_name: |         with TemporaryDirectory(ignore_cleanup_errors=True) as dir_name: | ||||||
|             dir_path = Path(dir_name) |             dir_path = Path(dir_name) | ||||||
|             current_commit_sha = Sources.load(dir_path, package, self.database.patches_get(package.base), self.paths) |             patches = self.reporter.package_patches_get(package.base, None) | ||||||
|  |             current_commit_sha = Sources.load(dir_path, package, patches, self.paths) | ||||||
|  |  | ||||||
|             changes: str | None = None |             changes: str | None = None | ||||||
|             if current_commit_sha != last_commit_sha: |             if current_commit_sha != last_commit_sha: | ||||||
|  | |||||||
| @ -26,6 +26,7 @@ from ahriman.core.database import SQLite | |||||||
| from ahriman.core.repository.executor import Executor | from ahriman.core.repository.executor import Executor | ||||||
| from ahriman.core.repository.update_handler import UpdateHandler | from ahriman.core.repository.update_handler import UpdateHandler | ||||||
| from ahriman.core.sign.gpg import GPG | from ahriman.core.sign.gpg import GPG | ||||||
|  | from ahriman.core.status import Client | ||||||
| from ahriman.models.pacman_synchronization import PacmanSynchronization | from ahriman.models.pacman_synchronization import PacmanSynchronization | ||||||
| from ahriman.models.repository_id import RepositoryId | from ahriman.models.repository_id import RepositoryId | ||||||
|  |  | ||||||
| @ -92,6 +93,7 @@ class Repository(Executor, UpdateHandler): | |||||||
|         ctx.set(Configuration, self.configuration) |         ctx.set(Configuration, self.configuration) | ||||||
|         ctx.set(Pacman, self.pacman) |         ctx.set(Pacman, self.pacman) | ||||||
|         ctx.set(GPG, self.sign) |         ctx.set(GPG, self.sign) | ||||||
|  |         ctx.set(Client, self.reporter) | ||||||
|  |  | ||||||
|         ctx.set(type(self), self) |         ctx.set(type(self), self) | ||||||
|  |  | ||||||
|  | |||||||
| @ -23,7 +23,7 @@ from ahriman.core.configuration import Configuration | |||||||
| from ahriman.core.database import SQLite | from ahriman.core.database import SQLite | ||||||
| from ahriman.core.log import LazyLogging | from ahriman.core.log import LazyLogging | ||||||
| from ahriman.core.sign.gpg import GPG | from ahriman.core.sign.gpg import GPG | ||||||
| from ahriman.core.status.client import Client | from ahriman.core.status import Client | ||||||
| from ahriman.core.triggers import TriggerLoader | from ahriman.core.triggers import TriggerLoader | ||||||
| from ahriman.models.packagers import Packagers | from ahriman.models.packagers import Packagers | ||||||
| from ahriman.models.pacman_synchronization import PacmanSynchronization | from ahriman.models.pacman_synchronization import PacmanSynchronization | ||||||
| @ -75,7 +75,7 @@ class RepositoryProperties(LazyLogging): | |||||||
|         self.pacman = Pacman(repository_id, configuration, refresh_database=refresh_pacman_database) |         self.pacman = Pacman(repository_id, configuration, refresh_database=refresh_pacman_database) | ||||||
|         self.sign = GPG(configuration) |         self.sign = GPG(configuration) | ||||||
|         self.repo = Repo(self.name, self.paths, self.sign.repository_sign_args) |         self.repo = Repo(self.name, self.paths, self.sign.repository_sign_args) | ||||||
|         self.reporter = Client.load(repository_id, configuration, report=report) |         self.reporter = Client.load(repository_id, configuration, database, report=report) | ||||||
|         self.triggers = TriggerLoader.load(repository_id, configuration) |         self.triggers = TriggerLoader.load(repository_id, configuration) | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|  | |||||||
| @ -18,7 +18,6 @@ | |||||||
| # along with this program. If not, see <http://www.gnu.org/licenses/>. | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
| # | # | ||||||
| from collections.abc import Iterable | from collections.abc import Iterable | ||||||
| from pathlib import Path |  | ||||||
|  |  | ||||||
| from ahriman.core.build_tools.sources import Sources | from ahriman.core.build_tools.sources import Sources | ||||||
| from ahriman.core.exceptions import UnknownPackageError | from ahriman.core.exceptions import UnknownPackageError | ||||||
| @ -89,27 +88,25 @@ class UpdateHandler(PackageInfo, Cleaner): | |||||||
|         Returns: |         Returns: | ||||||
|             list[Package]: list of packages for which there is breaking linking |             list[Package]: list of packages for which there is breaking linking | ||||||
|         """ |         """ | ||||||
|         def extract_files(lookup_packages: Iterable[str]) -> dict[Path, set[str]]: |         def extract_files(lookup_packages: Iterable[str]) -> dict[str, set[str]]: | ||||||
|             database_files = self.pacman.files(lookup_packages) |             database_files = self.pacman.files(lookup_packages) | ||||||
|             files: dict[Path, set[str]] = {} |             files: dict[str, set[str]] = {} | ||||||
|             for package_name, package_files in database_files.items():  # invert map |             for package_name, package_files in database_files.items():  # invert map | ||||||
|                 for package_file in package_files: |                 for package_file in package_files: | ||||||
|                     files.setdefault(package_file, set()).add(package_name) |                     files.setdefault(package_file, set()).add(package_name) | ||||||
|  |  | ||||||
|             return files |             return files | ||||||
|  |  | ||||||
|         dependencies = {dependency.package_base: dependency for dependency in self.database.dependencies_get()} |  | ||||||
|  |  | ||||||
|         result: list[Package] = [] |         result: list[Package] = [] | ||||||
|         for package in self.packages(filter_packages): |         for package in self.packages(filter_packages): | ||||||
|             if package.base not in dependencies: |             dependencies = self.reporter.package_dependencies_get(package.base) | ||||||
|  |             if not dependencies.paths: | ||||||
|                 continue  # skip check if no package dependencies found |                 continue  # skip check if no package dependencies found | ||||||
|  |  | ||||||
|             required = dependencies[package.base].paths |             required_packages = {dep for dep_packages in dependencies.paths.values() for dep in dep_packages} | ||||||
|             required_packages = {dep for dep_packages in required.values() for dep in dep_packages} |  | ||||||
|             filesystem = extract_files(required_packages) |             filesystem = extract_files(required_packages) | ||||||
|  |  | ||||||
|             for path, packages in required.items(): |             for path, packages in dependencies.paths.items(): | ||||||
|                 found = filesystem.get(path, set()) |                 found = filesystem.get(path, set()) | ||||||
|                 if found.intersection(packages): |                 if found.intersection(packages): | ||||||
|                     continue |                     continue | ||||||
|  | |||||||
| @ -17,3 +17,4 @@ | |||||||
| # You should have received a copy of the GNU General Public License | # You should have received a copy of the GNU General Public License | ||||||
| # along with this program. If not, see <http://www.gnu.org/licenses/>. | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
| # | # | ||||||
|  | from ahriman.core.status.client import Client | ||||||
|  | |||||||
| @ -17,16 +17,18 @@ | |||||||
| # You should have received a copy of the GNU General Public License | # You should have received a copy of the GNU General Public License | ||||||
| # along with this program. If not, see <http://www.gnu.org/licenses/>. | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
| # | # | ||||||
|  | # pylint: disable=too-many-public-methods | ||||||
| from __future__ import annotations | from __future__ import annotations | ||||||
|  |  | ||||||
| import logging |  | ||||||
|  |  | ||||||
| from ahriman.core.configuration import Configuration | from ahriman.core.configuration import Configuration | ||||||
|  | from ahriman.core.database import SQLite | ||||||
| from ahriman.models.build_status import BuildStatus, BuildStatusEnum | from ahriman.models.build_status import BuildStatus, BuildStatusEnum | ||||||
| from ahriman.models.changes import Changes | from ahriman.models.changes import Changes | ||||||
|  | from ahriman.models.dependencies import Dependencies | ||||||
| from ahriman.models.internal_status import InternalStatus | from ahriman.models.internal_status import InternalStatus | ||||||
| from ahriman.models.log_record_id import LogRecordId | from ahriman.models.log_record_id import LogRecordId | ||||||
| from ahriman.models.package import Package | from ahriman.models.package import Package | ||||||
|  | from ahriman.models.pkgbuild_patch import PkgbuildPatch | ||||||
| from ahriman.models.repository_id import RepositoryId | from ahriman.models.repository_id import RepositoryId | ||||||
|  |  | ||||||
|  |  | ||||||
| @ -36,22 +38,31 @@ class Client: | |||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def load(repository_id: RepositoryId, configuration: Configuration, *, report: bool) -> Client: |     def load(repository_id: RepositoryId, configuration: Configuration, database: SQLite | None = None, *, | ||||||
|  |              report: bool = True) -> Client: | ||||||
|         """ |         """ | ||||||
|         load client from settings |         load client from settings | ||||||
|  |  | ||||||
|         Args: |         Args: | ||||||
|             repository_id(RepositoryId): repository unique identifier |             repository_id(RepositoryId): repository unique identifier | ||||||
|             configuration(Configuration): configuration instance |             configuration(Configuration): configuration instance | ||||||
|             report(bool): force enable or disable reporting |             database(SQLite | None, optional): database instance (Default value = None) | ||||||
|  |             report(bool, optional): force enable or disable reporting (Default value = True) | ||||||
|  |  | ||||||
|         Returns: |         Returns: | ||||||
|             Client: client according to current settings |             Client: client according to current settings | ||||||
|         """ |         """ | ||||||
|  |         def make_local_client() -> Client: | ||||||
|  |             if database is None: | ||||||
|  |                 return Client() | ||||||
|  |  | ||||||
|  |             from ahriman.core.status.local_client import LocalClient | ||||||
|  |             return LocalClient(repository_id, database) | ||||||
|  |  | ||||||
|         if not report: |         if not report: | ||||||
|             return Client() |             return make_local_client() | ||||||
|         if not configuration.getboolean("status", "enabled", fallback=True):  # global switch |         if not configuration.getboolean("status", "enabled", fallback=True):  # global switch | ||||||
|             return Client() |             return make_local_client() | ||||||
|  |  | ||||||
|         # new-style section |         # new-style section | ||||||
|         address = configuration.get("status", "address", fallback=None) |         address = configuration.get("status", "address", fallback=None) | ||||||
| @ -65,16 +76,8 @@ class Client: | |||||||
|         if address or legacy_address or (host and port) or socket: |         if address or legacy_address or (host and port) or socket: | ||||||
|             from ahriman.core.status.web_client import WebClient |             from ahriman.core.status.web_client import WebClient | ||||||
|             return WebClient(repository_id, configuration) |             return WebClient(repository_id, configuration) | ||||||
|         return Client() |  | ||||||
|  |  | ||||||
|     def package_add(self, package: Package, status: BuildStatusEnum) -> None: |         return make_local_client() | ||||||
|         """ |  | ||||||
|         add new package with status |  | ||||||
|  |  | ||||||
|         Args: |  | ||||||
|             package(Package): package properties |  | ||||||
|             status(BuildStatusEnum): current package build status |  | ||||||
|         """ |  | ||||||
|  |  | ||||||
|     def package_changes_get(self, package_base: str) -> Changes: |     def package_changes_get(self, package_base: str) -> Changes: | ||||||
|         """ |         """ | ||||||
| @ -85,18 +88,52 @@ class Client: | |||||||
|  |  | ||||||
|         Returns: |         Returns: | ||||||
|             Changes: package changes if available and empty object otherwise |             Changes: package changes if available and empty object otherwise | ||||||
|         """ |  | ||||||
|         del package_base |  | ||||||
|         return Changes() |  | ||||||
|  |  | ||||||
|     def package_changes_set(self, package_base: str, changes: Changes) -> None: |         Raises: | ||||||
|  |             NotImplementedError: not implemented method | ||||||
|  |         """ | ||||||
|  |         raise NotImplementedError | ||||||
|  |  | ||||||
|  |     def package_changes_update(self, package_base: str, changes: Changes) -> None: | ||||||
|         """ |         """ | ||||||
|         update package changes |         update package changes | ||||||
|  |  | ||||||
|         Args: |         Args: | ||||||
|             package_base(str): package base to update |             package_base(str): package base to update | ||||||
|             changes(Changes): changes descriptor |             changes(Changes): changes descriptor | ||||||
|  |  | ||||||
|  |         Raises: | ||||||
|  |             NotImplementedError: not implemented method | ||||||
|         """ |         """ | ||||||
|  |         raise NotImplementedError | ||||||
|  |  | ||||||
|  |     def package_dependencies_get(self, package_base: str) -> Dependencies: | ||||||
|  |         """ | ||||||
|  |         get package dependencies | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base to retrieve | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             list[Dependencies]: package implicit dependencies if available | ||||||
|  |  | ||||||
|  |         Raises: | ||||||
|  |             NotImplementedError: not implemented method | ||||||
|  |         """ | ||||||
|  |         raise NotImplementedError | ||||||
|  |  | ||||||
|  |     def package_dependencies_update(self, package_base: str, dependencies: Dependencies) -> None: | ||||||
|  |         """ | ||||||
|  |         update package dependencies | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base to update | ||||||
|  |             dependencies(Dependencies): dependencies descriptor | ||||||
|  |  | ||||||
|  |         Raises: | ||||||
|  |             NotImplementedError: not implemented method | ||||||
|  |         """ | ||||||
|  |         raise NotImplementedError | ||||||
|  |  | ||||||
|     def package_get(self, package_base: str | None) -> list[tuple[Package, BuildStatus]]: |     def package_get(self, package_base: str | None) -> list[tuple[Package, BuildStatus]]: | ||||||
|         """ |         """ | ||||||
| @ -107,18 +144,94 @@ class Client: | |||||||
|  |  | ||||||
|         Returns: |         Returns: | ||||||
|             list[tuple[Package, BuildStatus]]: list of current package description and status if it has been found |             list[tuple[Package, BuildStatus]]: list of current package description and status if it has been found | ||||||
|         """ |  | ||||||
|         del package_base |  | ||||||
|         return [] |  | ||||||
|  |  | ||||||
|     def package_logs(self, log_record_id: LogRecordId, record: logging.LogRecord) -> None: |         Raises: | ||||||
|  |             NotImplementedError: not implemented method | ||||||
|  |         """ | ||||||
|  |         raise NotImplementedError | ||||||
|  |  | ||||||
|  |     def package_logs_add(self, log_record_id: LogRecordId, created: float, message: str) -> None: | ||||||
|         """ |         """ | ||||||
|         post log record |         post log record | ||||||
|  |  | ||||||
|         Args: |         Args: | ||||||
|             log_record_id(LogRecordId): log record id |             log_record_id(LogRecordId): log record id | ||||||
|             record(logging.LogRecord): log record to post to api |             created(float): log created timestamp | ||||||
|  |             message(str): log message | ||||||
|         """ |         """ | ||||||
|  |         # this method does not raise NotImplementedError because it is actively used as dummy client for http log | ||||||
|  |  | ||||||
|  |     def package_logs_get(self, package_base: str, limit: int = -1, offset: int = 0) -> list[tuple[float, str]]: | ||||||
|  |         """ | ||||||
|  |         get package logs | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base | ||||||
|  |             limit(int, optional): limit records to the specified count, -1 means unlimited (Default value = -1) | ||||||
|  |             offset(int, optional): records offset (Default value = 0) | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             list[tuple[float, str]]: package logs | ||||||
|  |  | ||||||
|  |         Raises: | ||||||
|  |             NotImplementedError: not implemented method | ||||||
|  |         """ | ||||||
|  |         raise NotImplementedError | ||||||
|  |  | ||||||
|  |     def package_logs_remove(self, package_base: str, version: str | None) -> None: | ||||||
|  |         """ | ||||||
|  |         remove package logs | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base | ||||||
|  |             version(str | None): package version to remove logs. If None set, all logs will be removed | ||||||
|  |  | ||||||
|  |         Raises: | ||||||
|  |             NotImplementedError: not implemented method | ||||||
|  |         """ | ||||||
|  |         raise NotImplementedError | ||||||
|  |  | ||||||
|  |     def package_patches_get(self, package_base: str, variable: str | None) -> list[PkgbuildPatch]: | ||||||
|  |         """ | ||||||
|  |         get package patches | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base to retrieve | ||||||
|  |             variable(str | None): optional filter by patch variable | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             list[PkgbuildPatch]: list of patches for the specified package | ||||||
|  |  | ||||||
|  |         Raises: | ||||||
|  |             NotImplementedError: not implemented method | ||||||
|  |         """ | ||||||
|  |         raise NotImplementedError | ||||||
|  |  | ||||||
|  |     def package_patches_remove(self, package_base: str, variable: str | None) -> None: | ||||||
|  |         """ | ||||||
|  |         remove package patch | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base to update | ||||||
|  |             variable(str | None): patch name. If None set, all patches will be removed | ||||||
|  |  | ||||||
|  |         Raises: | ||||||
|  |             NotImplementedError: not implemented method | ||||||
|  |         """ | ||||||
|  |         raise NotImplementedError | ||||||
|  |  | ||||||
|  |     def package_patches_update(self, package_base: str, patch: PkgbuildPatch) -> None: | ||||||
|  |         """ | ||||||
|  |         create or update package patch | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base to update | ||||||
|  |             patch(PkgbuildPatch): package patch | ||||||
|  |  | ||||||
|  |         Raises: | ||||||
|  |             NotImplementedError: not implemented method | ||||||
|  |         """ | ||||||
|  |         raise NotImplementedError | ||||||
|  |  | ||||||
|     def package_remove(self, package_base: str) -> None: |     def package_remove(self, package_base: str) -> None: | ||||||
|         """ |         """ | ||||||
| @ -126,16 +239,37 @@ class Client: | |||||||
|  |  | ||||||
|         Args: |         Args: | ||||||
|             package_base(str): package base to remove |             package_base(str): package base to remove | ||||||
|         """ |  | ||||||
|  |  | ||||||
|     def package_update(self, package_base: str, status: BuildStatusEnum) -> None: |         Raises: | ||||||
|  |             NotImplementedError: not implemented method | ||||||
|         """ |         """ | ||||||
|         update package build status. Unlike :func:`package_add()` it does not update package properties |         raise NotImplementedError | ||||||
|  |  | ||||||
|  |     def package_status_update(self, package_base: str, status: BuildStatusEnum) -> None: | ||||||
|  |         """ | ||||||
|  |         update package build status. Unlike :func:`package_update()` it does not update package properties | ||||||
|  |  | ||||||
|         Args: |         Args: | ||||||
|             package_base(str): package base to update |             package_base(str): package base to update | ||||||
|             status(BuildStatusEnum): current package build status |             status(BuildStatusEnum): current package build status | ||||||
|  |  | ||||||
|  |         Raises: | ||||||
|  |             NotImplementedError: not implemented method | ||||||
|         """ |         """ | ||||||
|  |         raise NotImplementedError | ||||||
|  |  | ||||||
|  |     def package_update(self, package: Package, status: BuildStatusEnum) -> None: | ||||||
|  |         """ | ||||||
|  |         add new package or update existing one with status | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package(Package): package properties | ||||||
|  |             status(BuildStatusEnum): current package build status | ||||||
|  |  | ||||||
|  |         Raises: | ||||||
|  |             NotImplementedError: not implemented method | ||||||
|  |         """ | ||||||
|  |         raise NotImplementedError | ||||||
|  |  | ||||||
|     def set_building(self, package_base: str) -> None: |     def set_building(self, package_base: str) -> None: | ||||||
|         """ |         """ | ||||||
| @ -144,7 +278,7 @@ class Client: | |||||||
|         Args: |         Args: | ||||||
|             package_base(str): package base to update |             package_base(str): package base to update | ||||||
|         """ |         """ | ||||||
|         return self.package_update(package_base, BuildStatusEnum.Building) |         self.package_status_update(package_base, BuildStatusEnum.Building) | ||||||
|  |  | ||||||
|     def set_failed(self, package_base: str) -> None: |     def set_failed(self, package_base: str) -> None: | ||||||
|         """ |         """ | ||||||
| @ -153,7 +287,7 @@ class Client: | |||||||
|         Args: |         Args: | ||||||
|             package_base(str): package base to update |             package_base(str): package base to update | ||||||
|         """ |         """ | ||||||
|         return self.package_update(package_base, BuildStatusEnum.Failed) |         self.package_status_update(package_base, BuildStatusEnum.Failed) | ||||||
|  |  | ||||||
|     def set_pending(self, package_base: str) -> None: |     def set_pending(self, package_base: str) -> None: | ||||||
|         """ |         """ | ||||||
| @ -162,7 +296,7 @@ class Client: | |||||||
|         Args: |         Args: | ||||||
|             package_base(str): package base to update |             package_base(str): package base to update | ||||||
|         """ |         """ | ||||||
|         return self.package_update(package_base, BuildStatusEnum.Pending) |         self.package_status_update(package_base, BuildStatusEnum.Pending) | ||||||
|  |  | ||||||
|     def set_success(self, package: Package) -> None: |     def set_success(self, package: Package) -> None: | ||||||
|         """ |         """ | ||||||
| @ -171,16 +305,19 @@ class Client: | |||||||
|         Args: |         Args: | ||||||
|             package(Package): current package properties |             package(Package): current package properties | ||||||
|         """ |         """ | ||||||
|         return self.package_add(package, BuildStatusEnum.Success) |         self.package_update(package, BuildStatusEnum.Success) | ||||||
|  |  | ||||||
|     def set_unknown(self, package: Package) -> None: |     def set_unknown(self, package: Package) -> None: | ||||||
|         """ |         """ | ||||||
|         set package status to unknown |         set package status to unknown. Unlike other methods, this method also checks if package is known, | ||||||
|  |         and - in case if it is - it silently skips updatd | ||||||
|  |  | ||||||
|         Args: |         Args: | ||||||
|             package(Package): current package properties |             package(Package): current package properties | ||||||
|         """ |         """ | ||||||
|         return self.package_add(package, BuildStatusEnum.Unknown) |         if self.package_get(package.base): | ||||||
|  |             return  # skip update in case if package is already known | ||||||
|  |         self.package_update(package, BuildStatusEnum.Unknown) | ||||||
|  |  | ||||||
|     def status_get(self) -> InternalStatus: |     def status_get(self) -> InternalStatus: | ||||||
|         """ |         """ | ||||||
|  | |||||||
							
								
								
									
										214
									
								
								src/ahriman/core/status/local_client.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										214
									
								
								src/ahriman/core/status/local_client.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,214 @@ | |||||||
|  | # | ||||||
|  | # Copyright (c) 2021-2024 ahriman team. | ||||||
|  | # | ||||||
|  | # This file is part of ahriman | ||||||
|  | # (see https://github.com/arcan1s/ahriman). | ||||||
|  | # | ||||||
|  | # This program is free software: you can redistribute it and/or modify | ||||||
|  | # it under the terms of the GNU General Public License as published by | ||||||
|  | # the Free Software Foundation, either version 3 of the License, or | ||||||
|  | # (at your option) any later version. | ||||||
|  | # | ||||||
|  | # This program is distributed in the hope that it will be useful, | ||||||
|  | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  | # GNU General Public License for more details. | ||||||
|  | # | ||||||
|  | # You should have received a copy of the GNU General Public License | ||||||
|  | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  | # | ||||||
|  | from ahriman.core.database import SQLite | ||||||
|  | from ahriman.core.status import Client | ||||||
|  | from ahriman.models.build_status import BuildStatus, BuildStatusEnum | ||||||
|  | from ahriman.models.changes import Changes | ||||||
|  | from ahriman.models.dependencies import Dependencies | ||||||
|  | from ahriman.models.log_record_id import LogRecordId | ||||||
|  | from ahriman.models.package import Package | ||||||
|  | from ahriman.models.pkgbuild_patch import PkgbuildPatch | ||||||
|  | from ahriman.models.repository_id import RepositoryId | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class LocalClient(Client): | ||||||
|  |     """ | ||||||
|  |     local database handler | ||||||
|  |  | ||||||
|  |     Attributes: | ||||||
|  |         database(SQLite): database instance | ||||||
|  |         repository_id(RepositoryId): repository unique identifier | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     def __init__(self, repository_id: RepositoryId, database: SQLite) -> None: | ||||||
|  |         """ | ||||||
|  |         default constructor | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             repository_id(RepositoryId): repository unique identifier | ||||||
|  |             database(SQLite): database instance: | ||||||
|  |         """ | ||||||
|  |         self.database = database | ||||||
|  |         self.repository_id = repository_id | ||||||
|  |  | ||||||
|  |     def package_changes_get(self, package_base: str) -> Changes: | ||||||
|  |         """ | ||||||
|  |         get package changes | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base to retrieve | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             Changes: package changes if available and empty object otherwise | ||||||
|  |         """ | ||||||
|  |         return self.database.changes_get(package_base, self.repository_id) | ||||||
|  |  | ||||||
|  |     def package_changes_update(self, package_base: str, changes: Changes) -> None: | ||||||
|  |         """ | ||||||
|  |         update package changes | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base to update | ||||||
|  |             changes(Changes): changes descriptor | ||||||
|  |         """ | ||||||
|  |         self.database.changes_insert(package_base, changes, self.repository_id) | ||||||
|  |  | ||||||
|  |     def package_dependencies_get(self, package_base: str) -> Dependencies: | ||||||
|  |         """ | ||||||
|  |         get package dependencies | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base to retrieve | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             list[Dependencies]: package implicit dependencies if available | ||||||
|  |         """ | ||||||
|  |         return self.database.dependencies_get(package_base, self.repository_id).get(package_base, Dependencies()) | ||||||
|  |  | ||||||
|  |     def package_dependencies_update(self, package_base: str, dependencies: Dependencies) -> None: | ||||||
|  |         """ | ||||||
|  |         update package dependencies | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base to update | ||||||
|  |             dependencies(Dependencies): dependencies descriptor | ||||||
|  |         """ | ||||||
|  |         self.database.dependencies_insert(package_base, dependencies, self.repository_id) | ||||||
|  |  | ||||||
|  |     def package_get(self, package_base: str | None) -> list[tuple[Package, BuildStatus]]: | ||||||
|  |         """ | ||||||
|  |         get package status | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str | None): package base to get | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             list[tuple[Package, BuildStatus]]: list of current package description and status if it has been found | ||||||
|  |         """ | ||||||
|  |         packages = self.database.packages_get(self.repository_id) | ||||||
|  |         if package_base is None: | ||||||
|  |             return packages | ||||||
|  |         return [(package, status) for package, status in packages if package.base == package_base] | ||||||
|  |  | ||||||
|  |     def package_logs_add(self, log_record_id: LogRecordId, created: float, message: str) -> None: | ||||||
|  |         """ | ||||||
|  |         post log record | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             log_record_id(LogRecordId): log record id | ||||||
|  |             created(float): log created timestamp | ||||||
|  |             message(str): log message | ||||||
|  |         """ | ||||||
|  |         self.database.logs_insert(log_record_id, created, message, self.repository_id) | ||||||
|  |  | ||||||
|  |     def package_logs_get(self, package_base: str, limit: int = -1, offset: int = 0) -> list[tuple[float, str]]: | ||||||
|  |         """ | ||||||
|  |         get package logs | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base | ||||||
|  |             limit(int, optional): limit records to the specified count, -1 means unlimited (Default value = -1) | ||||||
|  |             offset(int, optional): records offset (Default value = 0) | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             list[tuple[float, str]]: package logs | ||||||
|  |         """ | ||||||
|  |         return self.database.logs_get(package_base, limit, offset, self.repository_id) | ||||||
|  |  | ||||||
|  |     def package_logs_remove(self, package_base: str, version: str | None) -> None: | ||||||
|  |         """ | ||||||
|  |         remove package logs | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base | ||||||
|  |             version(str | None): package version to remove logs. If None set, all logs will be removed | ||||||
|  |         """ | ||||||
|  |         self.database.logs_remove(package_base, version, self.repository_id) | ||||||
|  |  | ||||||
|  |     def package_patches_get(self, package_base: str, variable: str | None) -> list[PkgbuildPatch]: | ||||||
|  |         """ | ||||||
|  |         get package patches | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base to retrieve | ||||||
|  |             variable(str | None): optional filter by patch variable | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             list[PkgbuildPatch]: list of patches for the specified package | ||||||
|  |         """ | ||||||
|  |         variables = [variable] if variable is not None else None | ||||||
|  |         return self.database.patches_list(package_base, variables).get(package_base, []) | ||||||
|  |  | ||||||
|  |     def package_patches_remove(self, package_base: str, variable: str | None) -> None: | ||||||
|  |         """ | ||||||
|  |         remove package patch | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base to update | ||||||
|  |             variable(str | None): patch name. If None set, all patches will be removed | ||||||
|  |         """ | ||||||
|  |         variables = [variable] if variable is not None else None | ||||||
|  |         self.database.patches_remove(package_base, variables) | ||||||
|  |  | ||||||
|  |     def package_patches_update(self, package_base: str, patch: PkgbuildPatch) -> None: | ||||||
|  |         """ | ||||||
|  |         create or update package patch | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base to update | ||||||
|  |             patch(PkgbuildPatch): package patch | ||||||
|  |         """ | ||||||
|  |         self.database.patches_insert(package_base, [patch]) | ||||||
|  |  | ||||||
|  |     def package_remove(self, package_base: str) -> None: | ||||||
|  |         """ | ||||||
|  |         remove packages from watcher | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base to remove | ||||||
|  |         """ | ||||||
|  |         self.database.package_clear(package_base) | ||||||
|  |  | ||||||
|  |     def package_status_update(self, package_base: str, status: BuildStatusEnum) -> None: | ||||||
|  |         """ | ||||||
|  |         update package build status. Unlike :func:`package_update()` it does not update package properties | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base to update | ||||||
|  |             status(BuildStatusEnum): current package build status | ||||||
|  |  | ||||||
|  |         Raises: | ||||||
|  |             NotImplementedError: not implemented method | ||||||
|  |         """ | ||||||
|  |         self.database.status_update(package_base, BuildStatus(status), self.repository_id) | ||||||
|  |  | ||||||
|  |     def package_update(self, package: Package, status: BuildStatusEnum) -> None: | ||||||
|  |         """ | ||||||
|  |         add new package or update existing one with status | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package(Package): package properties | ||||||
|  |             status(BuildStatusEnum): current package build status | ||||||
|  |  | ||||||
|  |         Raises: | ||||||
|  |             NotImplementedError: not implemented method | ||||||
|  |         """ | ||||||
|  |         self.database.package_update(package, self.repository_id) | ||||||
|  |         self.database.status_update(package.base, BuildStatus(status), self.repository_id) | ||||||
| @ -17,17 +17,19 @@ | |||||||
| # You should have received a copy of the GNU General Public License | # You should have received a copy of the GNU General Public License | ||||||
| # along with this program. If not, see <http://www.gnu.org/licenses/>. | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
| # | # | ||||||
|  | from collections.abc import Callable | ||||||
| from threading import Lock | from threading import Lock | ||||||
|  | from typing import Any, Self | ||||||
|  |  | ||||||
| from ahriman.core.database import SQLite |  | ||||||
| from ahriman.core.exceptions import UnknownPackageError | from ahriman.core.exceptions import UnknownPackageError | ||||||
| from ahriman.core.log import LazyLogging | from ahriman.core.log import LazyLogging | ||||||
|  | from ahriman.core.status import Client | ||||||
| from ahriman.models.build_status import BuildStatus, BuildStatusEnum | from ahriman.models.build_status import BuildStatus, BuildStatusEnum | ||||||
| from ahriman.models.changes import Changes | from ahriman.models.changes import Changes | ||||||
|  | from ahriman.models.dependencies import Dependencies | ||||||
| from ahriman.models.log_record_id import LogRecordId | from ahriman.models.log_record_id import LogRecordId | ||||||
| from ahriman.models.package import Package | from ahriman.models.package import Package | ||||||
| from ahriman.models.pkgbuild_patch import PkgbuildPatch | from ahriman.models.pkgbuild_patch import PkgbuildPatch | ||||||
| from ahriman.models.repository_id import RepositoryId |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class Watcher(LazyLogging): | class Watcher(LazyLogging): | ||||||
| @ -35,21 +37,18 @@ class Watcher(LazyLogging): | |||||||
|     package status watcher |     package status watcher | ||||||
|  |  | ||||||
|     Attributes: |     Attributes: | ||||||
|         database(SQLite): database instance |         client(Client): reporter instance | ||||||
|         repository_id(RepositoryId): repository unique identifier |  | ||||||
|         status(BuildStatus): daemon status |         status(BuildStatus): daemon status | ||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     def __init__(self, repository_id: RepositoryId, database: SQLite) -> None: |     def __init__(self, client: Client) -> None: | ||||||
|         """ |         """ | ||||||
|         default constructor |         default constructor | ||||||
|  |  | ||||||
|         Args: |         Args: | ||||||
|             repository_id(RepositoryId): repository unique identifier |             client(Client): reporter instance | ||||||
|             database(SQLite): database instance |  | ||||||
|         """ |         """ | ||||||
|         self.repository_id = repository_id |         self.client = client | ||||||
|         self.database = database |  | ||||||
|  |  | ||||||
|         self._lock = Lock() |         self._lock = Lock() | ||||||
|         self._known: dict[str, tuple[Package, BuildStatus]] = {} |         self._known: dict[str, tuple[Package, BuildStatus]] = {} | ||||||
| @ -76,61 +75,16 @@ class Watcher(LazyLogging): | |||||||
|         with self._lock: |         with self._lock: | ||||||
|             self._known = { |             self._known = { | ||||||
|                 package.base: (package, status) |                 package.base: (package, status) | ||||||
|                 for package, status in self.database.packages_get(self.repository_id) |                 for package, status in self.client.package_get(None) | ||||||
|             } |             } | ||||||
|  |  | ||||||
|     def logs_get(self, package_base: str, limit: int = -1, offset: int = 0) -> list[tuple[float, str]]: |     package_changes_get: Callable[[str], Changes] | ||||||
|         """ |  | ||||||
|         extract logs for the package base |  | ||||||
|  |  | ||||||
|         Args: |     package_changes_update: Callable[[str, Changes], None] | ||||||
|             package_base(str): package base |  | ||||||
|             limit(int, optional): limit records to the specified count, -1 means unlimited (Default value = -1) |  | ||||||
|             offset(int, optional): records offset (Default value = 0) |  | ||||||
|  |  | ||||||
|         Returns: |     package_dependencies_get: Callable[[str], Dependencies] | ||||||
|             list[tuple[float, str]]: package logs |  | ||||||
|         """ |  | ||||||
|         self.package_get(package_base) |  | ||||||
|         return self.database.logs_get(package_base, limit, offset, self.repository_id) |  | ||||||
|  |  | ||||||
|     def logs_remove(self, package_base: str, version: str | None) -> None: |     package_dependencies_update: Callable[[str, Dependencies], None] | ||||||
|         """ |  | ||||||
|         remove package related logs |  | ||||||
|  |  | ||||||
|         Args: |  | ||||||
|             package_base(str): package base |  | ||||||
|             version(str): package versio |  | ||||||
|         """ |  | ||||||
|         self.database.logs_remove(package_base, version, self.repository_id) |  | ||||||
|  |  | ||||||
|     def logs_update(self, log_record_id: LogRecordId, created: float, record: str) -> None: |  | ||||||
|         """ |  | ||||||
|         make new log record into database |  | ||||||
|  |  | ||||||
|         Args: |  | ||||||
|             log_record_id(LogRecordId): log record id |  | ||||||
|             created(float): log created timestamp |  | ||||||
|             record(str): log record |  | ||||||
|         """ |  | ||||||
|         if self._last_log_record_id != log_record_id: |  | ||||||
|             # there is new log record, so we remove old ones |  | ||||||
|             self.logs_remove(log_record_id.package_base, log_record_id.version) |  | ||||||
|         self._last_log_record_id = log_record_id |  | ||||||
|         self.database.logs_insert(log_record_id, created, record, self.repository_id) |  | ||||||
|  |  | ||||||
|     def package_changes_get(self, package_base: str) -> Changes: |  | ||||||
|         """ |  | ||||||
|         retrieve package changes |  | ||||||
|  |  | ||||||
|         Args: |  | ||||||
|             package_base(str): package base |  | ||||||
|  |  | ||||||
|         Returns: |  | ||||||
|             Changes: package changes if available |  | ||||||
|         """ |  | ||||||
|         self.package_get(package_base) |  | ||||||
|         return self.database.changes_get(package_base, self.repository_id) |  | ||||||
|  |  | ||||||
|     def package_get(self, package_base: str) -> tuple[Package, BuildStatus]: |     def package_get(self, package_base: str) -> tuple[Package, BuildStatus]: | ||||||
|         """ |         """ | ||||||
| @ -151,6 +105,31 @@ class Watcher(LazyLogging): | |||||||
|         except KeyError: |         except KeyError: | ||||||
|             raise UnknownPackageError(package_base) from None |             raise UnknownPackageError(package_base) from None | ||||||
|  |  | ||||||
|  |     def package_logs_add(self, log_record_id: LogRecordId, created: float, message: str) -> None: | ||||||
|  |         """ | ||||||
|  |         make new log record into database | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             log_record_id(LogRecordId): log record id | ||||||
|  |             created(float): log created timestamp | ||||||
|  |             message(str): log message | ||||||
|  |         """ | ||||||
|  |         if self._last_log_record_id != log_record_id: | ||||||
|  |             # there is new log record, so we remove old ones | ||||||
|  |             self.package_logs_remove(log_record_id.package_base, log_record_id.version) | ||||||
|  |         self._last_log_record_id = log_record_id | ||||||
|  |         self.client.package_logs_add(log_record_id, created, message) | ||||||
|  |  | ||||||
|  |     package_logs_get: Callable[[str, int, int], list[tuple[float, str]]] | ||||||
|  |  | ||||||
|  |     package_logs_remove: Callable[[str, str | None], None] | ||||||
|  |  | ||||||
|  |     package_patches_get: Callable[[str, str | None], list[PkgbuildPatch]] | ||||||
|  |  | ||||||
|  |     package_patches_remove: Callable[[str, str], None] | ||||||
|  |  | ||||||
|  |     package_patches_update: Callable[[str, PkgbuildPatch], None] | ||||||
|  |  | ||||||
|     def package_remove(self, package_base: str) -> None: |     def package_remove(self, package_base: str) -> None: | ||||||
|         """ |         """ | ||||||
|         remove package base from known list if any |         remove package base from known list if any | ||||||
| @ -160,60 +139,33 @@ class Watcher(LazyLogging): | |||||||
|         """ |         """ | ||||||
|         with self._lock: |         with self._lock: | ||||||
|             self._known.pop(package_base, None) |             self._known.pop(package_base, None) | ||||||
|         self.database.package_remove(package_base, self.repository_id) |         self.client.package_remove(package_base) | ||||||
|         self.logs_remove(package_base, None) |         self.package_logs_remove(package_base, None) | ||||||
|  |  | ||||||
|     def package_update(self, package_base: str, status: BuildStatusEnum, package: Package | None) -> None: |     def package_status_update(self, package_base: str, status: BuildStatusEnum) -> None: | ||||||
|         """ |         """ | ||||||
|         update package status and description |         update package status | ||||||
|  |  | ||||||
|         Args: |         Args: | ||||||
|             package_base(str): package base to update |             package_base(str): package base to update | ||||||
|             status(BuildStatusEnum): new build status |             status(BuildStatusEnum): new build status | ||||||
|             package(Package | None): optional package description. In case if not set current properties will be used |  | ||||||
|         """ |         """ | ||||||
|         if package is None: |  | ||||||
|         package, _ = self.package_get(package_base) |         package, _ = self.package_get(package_base) | ||||||
|         full_status = BuildStatus(status) |  | ||||||
|         with self._lock: |         with self._lock: | ||||||
|             self._known[package_base] = (package, full_status) |             self._known[package_base] = (package, BuildStatus(status)) | ||||||
|         self.database.package_update(package, full_status, self.repository_id) |         self.client.package_status_update(package_base, status) | ||||||
|  |  | ||||||
|     def patches_get(self, package_base: str, variable: str | None) -> list[PkgbuildPatch]: |     def package_update(self, package: Package, status: BuildStatusEnum) -> None: | ||||||
|         """ |         """ | ||||||
|         get patches for the package |         update package | ||||||
|  |  | ||||||
|         Args: |         Args: | ||||||
|             package_base(str): package base |             package(Package): package description | ||||||
|             variable(str | None): patch variable name if any |             status(BuildStatusEnum): new build status | ||||||
|  |  | ||||||
|         Returns: |  | ||||||
|             list[PkgbuildPatch]: list of patches which are stored for the package |  | ||||||
|         """ |         """ | ||||||
|         # patches are package base based, we don't know (and don't differentiate) to which package does them belong |         with self._lock: | ||||||
|         # so here we skip checking if package exists or not |             self._known[package.base] = (package, BuildStatus(status)) | ||||||
|         variables = [variable] if variable is not None else None |         self.client.package_update(package, status) | ||||||
|         return self.database.patches_list(package_base, variables).get(package_base, []) |  | ||||||
|  |  | ||||||
|     def patches_remove(self, package_base: str, variable: str) -> None: |  | ||||||
|         """ |  | ||||||
|         remove package patch |  | ||||||
|  |  | ||||||
|         Args: |  | ||||||
|             package_base(str): package base |  | ||||||
|             variable(str): patch variable name |  | ||||||
|         """ |  | ||||||
|         self.database.patches_remove(package_base, [variable]) |  | ||||||
|  |  | ||||||
|     def patches_update(self, package_base: str, patch: PkgbuildPatch) -> None: |  | ||||||
|         """ |  | ||||||
|         update package patch |  | ||||||
|  |  | ||||||
|         Args: |  | ||||||
|             package_base(str): package base |  | ||||||
|             patch(PkgbuildPatch): package patch |  | ||||||
|         """ |  | ||||||
|         self.database.patches_insert(package_base, [patch]) |  | ||||||
|  |  | ||||||
|     def status_update(self, status: BuildStatusEnum) -> None: |     def status_update(self, status: BuildStatusEnum) -> None: | ||||||
|         """ |         """ | ||||||
| @ -223,3 +175,34 @@ class Watcher(LazyLogging): | |||||||
|             status(BuildStatusEnum): new service status |             status(BuildStatusEnum): new service status | ||||||
|         """ |         """ | ||||||
|         self.status = BuildStatus(status) |         self.status = BuildStatus(status) | ||||||
|  |  | ||||||
|  |     def __call__(self, package_base: str | None) -> Self: | ||||||
|  |         """ | ||||||
|  |         extract client for future calls | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str | None): package base to validate that package exists if applicable | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             Self: instance of self to pass calls to the client | ||||||
|  |         """ | ||||||
|  |         if package_base is not None: | ||||||
|  |             _ = self.package_get(package_base) | ||||||
|  |         return self | ||||||
|  |  | ||||||
|  |     def __getattr__(self, item: str) -> Any: | ||||||
|  |         """ | ||||||
|  |         proxy methods for reporter client | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             item(str): property name: | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             Any: attribute by its name | ||||||
|  |  | ||||||
|  |         Raises: | ||||||
|  |             AttributeError: in case if no such attribute found | ||||||
|  |         """ | ||||||
|  |         if (method := getattr(self.client, item, None)) is not None: | ||||||
|  |             return method | ||||||
|  |         raise AttributeError(f"'{self.__class__.__qualname__}' object has no attribute '{item}'") | ||||||
|  | |||||||
| @ -18,18 +18,19 @@ | |||||||
| # along with this program. If not, see <http://www.gnu.org/licenses/>. | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
| # | # | ||||||
| import contextlib | import contextlib | ||||||
| import logging |  | ||||||
|  |  | ||||||
| from urllib.parse import quote_plus as urlencode | from urllib.parse import quote_plus as urlencode | ||||||
|  |  | ||||||
| from ahriman.core.configuration import Configuration | from ahriman.core.configuration import Configuration | ||||||
| from ahriman.core.http import SyncAhrimanClient | from ahriman.core.http import SyncAhrimanClient | ||||||
| from ahriman.core.status.client import Client | from ahriman.core.status import Client | ||||||
| from ahriman.models.build_status import BuildStatus, BuildStatusEnum | from ahriman.models.build_status import BuildStatus, BuildStatusEnum | ||||||
| from ahriman.models.changes import Changes | from ahriman.models.changes import Changes | ||||||
|  | from ahriman.models.dependencies import Dependencies | ||||||
| from ahriman.models.internal_status import InternalStatus | from ahriman.models.internal_status import InternalStatus | ||||||
| from ahriman.models.log_record_id import LogRecordId | from ahriman.models.log_record_id import LogRecordId | ||||||
| from ahriman.models.package import Package | from ahriman.models.package import Package | ||||||
|  | from ahriman.models.pkgbuild_patch import PkgbuildPatch | ||||||
| from ahriman.models.repository_id import RepositoryId | from ahriman.models.repository_id import RepositoryId | ||||||
|  |  | ||||||
|  |  | ||||||
| @ -92,10 +93,22 @@ class WebClient(Client, SyncAhrimanClient): | |||||||
|             package_base(str): package base |             package_base(str): package base | ||||||
|  |  | ||||||
|         Returns: |         Returns: | ||||||
|             str: full url for web service for logs |             str: full url for web service for changes | ||||||
|         """ |         """ | ||||||
|         return f"{self.address}/api/v1/packages/{urlencode(package_base)}/changes" |         return f"{self.address}/api/v1/packages/{urlencode(package_base)}/changes" | ||||||
|  |  | ||||||
|  |     def _dependencies_url(self, package_base: str) -> str: | ||||||
|  |         """ | ||||||
|  |         get url for the dependencies api | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             str: full url for web service for dependencies | ||||||
|  |         """ | ||||||
|  |         return f"{self.address}/api/v1/packages/{urlencode(package_base)}/dependencies" | ||||||
|  |  | ||||||
|     def _logs_url(self, package_base: str) -> str: |     def _logs_url(self, package_base: str) -> str: | ||||||
|         """ |         """ | ||||||
|         get url for the logs api |         get url for the logs api | ||||||
| @ -110,7 +123,7 @@ class WebClient(Client, SyncAhrimanClient): | |||||||
|  |  | ||||||
|     def _package_url(self, package_base: str = "") -> str: |     def _package_url(self, package_base: str = "") -> str: | ||||||
|         """ |         """ | ||||||
|         url generator |         package url generator | ||||||
|  |  | ||||||
|         Args: |         Args: | ||||||
|             package_base(str, optional): package base to generate url (Default value = "") |             package_base(str, optional): package base to generate url (Default value = "") | ||||||
| @ -121,6 +134,20 @@ class WebClient(Client, SyncAhrimanClient): | |||||||
|         suffix = f"/{urlencode(package_base)}" if package_base else "" |         suffix = f"/{urlencode(package_base)}" if package_base else "" | ||||||
|         return f"{self.address}/api/v1/packages{suffix}" |         return f"{self.address}/api/v1/packages{suffix}" | ||||||
|  |  | ||||||
|  |     def _patches_url(self, package_base: str, variable: str = "") -> str: | ||||||
|  |         """ | ||||||
|  |         patches url generator | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base | ||||||
|  |             variable(str, optional): patch variable name to generate url (Default value = "") | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             str: full url of web service for the package patch | ||||||
|  |         """ | ||||||
|  |         suffix = f"/{urlencode(variable)}" if variable else "" | ||||||
|  |         return f"{self.address}/api/v1/packages/{urlencode(package_base)}/patches{suffix}" | ||||||
|  |  | ||||||
|     def _status_url(self) -> str: |     def _status_url(self) -> str: | ||||||
|         """ |         """ | ||||||
|         get url for the status api |         get url for the status api | ||||||
| @ -130,22 +157,6 @@ class WebClient(Client, SyncAhrimanClient): | |||||||
|         """ |         """ | ||||||
|         return f"{self.address}/api/v1/status" |         return f"{self.address}/api/v1/status" | ||||||
|  |  | ||||||
|     def package_add(self, package: Package, status: BuildStatusEnum) -> None: |  | ||||||
|         """ |  | ||||||
|         add new package with status |  | ||||||
|  |  | ||||||
|         Args: |  | ||||||
|             package(Package): package properties |  | ||||||
|             status(BuildStatusEnum): current package build status |  | ||||||
|         """ |  | ||||||
|         payload = { |  | ||||||
|             "status": status.value, |  | ||||||
|             "package": package.view() |  | ||||||
|         } |  | ||||||
|         with contextlib.suppress(Exception): |  | ||||||
|             self.make_request("POST", self._package_url(package.base), |  | ||||||
|                               params=self.repository_id.query(), json=payload) |  | ||||||
|  |  | ||||||
|     def package_changes_get(self, package_base: str) -> Changes: |     def package_changes_get(self, package_base: str) -> Changes: | ||||||
|         """ |         """ | ||||||
|         get package changes |         get package changes | ||||||
| @ -165,7 +176,7 @@ class WebClient(Client, SyncAhrimanClient): | |||||||
|  |  | ||||||
|         return Changes() |         return Changes() | ||||||
|  |  | ||||||
|     def package_changes_set(self, package_base: str, changes: Changes) -> None: |     def package_changes_update(self, package_base: str, changes: Changes) -> None: | ||||||
|         """ |         """ | ||||||
|         update package changes |         update package changes | ||||||
|  |  | ||||||
| @ -177,6 +188,37 @@ class WebClient(Client, SyncAhrimanClient): | |||||||
|             self.make_request("POST", self._changes_url(package_base), |             self.make_request("POST", self._changes_url(package_base), | ||||||
|                               params=self.repository_id.query(), json=changes.view()) |                               params=self.repository_id.query(), json=changes.view()) | ||||||
|  |  | ||||||
|  |     def package_dependencies_get(self, package_base: str) -> Dependencies: | ||||||
|  |         """ | ||||||
|  |         get package dependencies | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base to retrieve | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             list[Dependencies]: package implicit dependencies if available | ||||||
|  |         """ | ||||||
|  |         with contextlib.suppress(Exception): | ||||||
|  |             response = self.make_request("GET", self._dependencies_url(package_base), | ||||||
|  |                                          params=self.repository_id.query()) | ||||||
|  |             response_json = response.json() | ||||||
|  |  | ||||||
|  |             return Dependencies.from_json(response_json) | ||||||
|  |  | ||||||
|  |         return Dependencies() | ||||||
|  |  | ||||||
|  |     def package_dependencies_update(self, package_base: str, dependencies: Dependencies) -> None: | ||||||
|  |         """ | ||||||
|  |         update package dependencies | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base to update | ||||||
|  |             dependencies(Dependencies): dependencies descriptor | ||||||
|  |         """ | ||||||
|  |         with contextlib.suppress(Exception): | ||||||
|  |             self.make_request("POST", self._dependencies_url(package_base), | ||||||
|  |                               params=self.repository_id.query(), json=dependencies.view()) | ||||||
|  |  | ||||||
|     def package_get(self, package_base: str | None) -> list[tuple[Package, BuildStatus]]: |     def package_get(self, package_base: str | None) -> list[tuple[Package, BuildStatus]]: | ||||||
|         """ |         """ | ||||||
|         get package status |         get package status | ||||||
| @ -199,17 +241,18 @@ class WebClient(Client, SyncAhrimanClient): | |||||||
|  |  | ||||||
|         return [] |         return [] | ||||||
|  |  | ||||||
|     def package_logs(self, log_record_id: LogRecordId, record: logging.LogRecord) -> None: |     def package_logs_add(self, log_record_id: LogRecordId, created: float, message: str) -> None: | ||||||
|         """ |         """ | ||||||
|         post log record |         post log record | ||||||
|  |  | ||||||
|         Args: |         Args: | ||||||
|             log_record_id(LogRecordId): log record id |             log_record_id(LogRecordId): log record id | ||||||
|             record(logging.LogRecord): log record to post to api |             created(float): log created timestamp | ||||||
|  |             message(str): log message | ||||||
|         """ |         """ | ||||||
|         payload = { |         payload = { | ||||||
|             "created": record.created, |             "created": created, | ||||||
|             "message": record.getMessage(), |             "message": message, | ||||||
|             "version": log_record_id.version, |             "version": log_record_id.version, | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @ -219,6 +262,83 @@ class WebClient(Client, SyncAhrimanClient): | |||||||
|         self.make_request("POST", self._logs_url(log_record_id.package_base), |         self.make_request("POST", self._logs_url(log_record_id.package_base), | ||||||
|                           params=self.repository_id.query(), json=payload, suppress_errors=True) |                           params=self.repository_id.query(), json=payload, suppress_errors=True) | ||||||
|  |  | ||||||
|  |     def package_logs_get(self, package_base: str, limit: int = -1, offset: int = 0) -> list[tuple[float, str]]: | ||||||
|  |         """ | ||||||
|  |         get package logs | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base | ||||||
|  |             limit(int, optional): limit records to the specified count, -1 means unlimited (Default value = -1) | ||||||
|  |             offset(int, optional): records offset (Default value = 0) | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             list[tuple[float, str]]: package logs | ||||||
|  |         """ | ||||||
|  |         with contextlib.suppress(Exception): | ||||||
|  |             query = self.repository_id.query() + [("limit", str(limit)), ("offset", str(offset))] | ||||||
|  |             response = self.make_request("GET", self._logs_url(package_base), params=query) | ||||||
|  |             response_json = response.json() | ||||||
|  |  | ||||||
|  |             return [(record["created"], record["message"]) for record in response_json] | ||||||
|  |  | ||||||
|  |         return [] | ||||||
|  |  | ||||||
|  |     def package_logs_remove(self, package_base: str, version: str | None) -> None: | ||||||
|  |         """ | ||||||
|  |         remove package logs | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base | ||||||
|  |             version(str | None): package version to remove logs. If None set, all logs will be removed | ||||||
|  |         """ | ||||||
|  |         with contextlib.suppress(Exception): | ||||||
|  |             query = self.repository_id.query() | ||||||
|  |             if version is not None: | ||||||
|  |                 query += [("version", version)] | ||||||
|  |             self.make_request("DELETE", self._logs_url(package_base), params=query) | ||||||
|  |  | ||||||
|  |     def package_patches_get(self, package_base: str, variable: str | None) -> list[PkgbuildPatch]: | ||||||
|  |         """ | ||||||
|  |         get package patches | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base to retrieve | ||||||
|  |             variable(str | None): optional filter by patch variable | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             list[PkgbuildPatch]: list of patches for the specified package | ||||||
|  |         """ | ||||||
|  |         with contextlib.suppress(Exception): | ||||||
|  |             response = self.make_request("GET", self._patches_url(package_base, variable or "")) | ||||||
|  |             response_json = response.json() | ||||||
|  |  | ||||||
|  |             patches = response_json if variable is None else [response_json] | ||||||
|  |             return [PkgbuildPatch.from_json(patch) for patch in patches] | ||||||
|  |  | ||||||
|  |         return [] | ||||||
|  |  | ||||||
|  |     def package_patches_remove(self, package_base: str, variable: str | None) -> None: | ||||||
|  |         """ | ||||||
|  |         remove package patch | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base to update | ||||||
|  |             variable(str | None): patch name. If None set, all patches will be removed | ||||||
|  |         """ | ||||||
|  |         with contextlib.suppress(Exception): | ||||||
|  |             self.make_request("DELETE", self._patches_url(package_base, variable or "")) | ||||||
|  |  | ||||||
|  |     def package_patches_update(self, package_base: str, patch: PkgbuildPatch) -> None: | ||||||
|  |         """ | ||||||
|  |         create or update package patch | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package_base(str): package base to update | ||||||
|  |             patch(PkgbuildPatch): package patch | ||||||
|  |         """ | ||||||
|  |         with contextlib.suppress(Exception): | ||||||
|  |             self.make_request("POST", self._patches_url(package_base), json=patch.view()) | ||||||
|  |  | ||||||
|     def package_remove(self, package_base: str) -> None: |     def package_remove(self, package_base: str) -> None: | ||||||
|         """ |         """ | ||||||
|         remove packages from watcher |         remove packages from watcher | ||||||
| @ -229,19 +349,41 @@ class WebClient(Client, SyncAhrimanClient): | |||||||
|         with contextlib.suppress(Exception): |         with contextlib.suppress(Exception): | ||||||
|             self.make_request("DELETE", self._package_url(package_base), params=self.repository_id.query()) |             self.make_request("DELETE", self._package_url(package_base), params=self.repository_id.query()) | ||||||
|  |  | ||||||
|     def package_update(self, package_base: str, status: BuildStatusEnum) -> None: |     def package_status_update(self, package_base: str, status: BuildStatusEnum) -> None: | ||||||
|         """ |         """ | ||||||
|         update package build status. Unlike :func:`package_add()` it does not update package properties |         update package build status. Unlike :func:`package_update()` it does not update package properties | ||||||
|  |  | ||||||
|         Args: |         Args: | ||||||
|             package_base(str): package base to update |             package_base(str): package base to update | ||||||
|             status(BuildStatusEnum): current package build status |             status(BuildStatusEnum): current package build status | ||||||
|  |  | ||||||
|  |         Raises: | ||||||
|  |             NotImplementedError: not implemented method | ||||||
|         """ |         """ | ||||||
|         payload = {"status": status.value} |         payload = {"status": status.value} | ||||||
|         with contextlib.suppress(Exception): |         with contextlib.suppress(Exception): | ||||||
|             self.make_request("POST", self._package_url(package_base), |             self.make_request("POST", self._package_url(package_base), | ||||||
|                               params=self.repository_id.query(), json=payload) |                               params=self.repository_id.query(), json=payload) | ||||||
|  |  | ||||||
|  |     def package_update(self, package: Package, status: BuildStatusEnum) -> None: | ||||||
|  |         """ | ||||||
|  |         add new package or update existing one with status | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             package(Package): package properties | ||||||
|  |             status(BuildStatusEnum): current package build status | ||||||
|  |  | ||||||
|  |         Raises: | ||||||
|  |             NotImplementedError: not implemented method | ||||||
|  |         """ | ||||||
|  |         payload = { | ||||||
|  |             "status": status.value, | ||||||
|  |             "package": package.view(), | ||||||
|  |         } | ||||||
|  |         with contextlib.suppress(Exception): | ||||||
|  |             self.make_request("POST", self._package_url(package.base), | ||||||
|  |                               params=self.repository_id.query(), json=payload) | ||||||
|  |  | ||||||
|     def status_get(self) -> InternalStatus: |     def status_get(self) -> InternalStatus: | ||||||
|         """ |         """ | ||||||
|         get internal service status |         get internal service status | ||||||
|  | |||||||
| @ -19,12 +19,13 @@ | |||||||
| # | # | ||||||
| import shutil | import shutil | ||||||
|  |  | ||||||
|  | from pathlib import Path | ||||||
|  |  | ||||||
| from ahriman.core import context | from ahriman.core import context | ||||||
| from ahriman.core.build_tools.sources import Sources | from ahriman.core.build_tools.sources import Sources | ||||||
| from ahriman.core.configuration import Configuration | from ahriman.core.configuration import Configuration | ||||||
| from ahriman.core.database import SQLite | from ahriman.core.status import Client | ||||||
| from ahriman.core.support.pkgbuild.pkgbuild_generator import PkgbuildGenerator | from ahriman.core.support.pkgbuild.pkgbuild_generator import PkgbuildGenerator | ||||||
| from ahriman.models.build_status import BuildStatus |  | ||||||
| from ahriman.models.package import Package | from ahriman.models.package import Package | ||||||
|  |  | ||||||
|  |  | ||||||
| @ -48,23 +49,39 @@ class PackageCreator: | |||||||
|         self.configuration = configuration |         self.configuration = configuration | ||||||
|         self.generator = generator |         self.generator = generator | ||||||
|  |  | ||||||
|  |     def package_create(self, path: Path) -> None: | ||||||
|  |         """ | ||||||
|  |         create package files | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             path(Path): path to directory with package files | ||||||
|  |         """ | ||||||
|  |         # clear old tree if any | ||||||
|  |         shutil.rmtree(path, ignore_errors=True) | ||||||
|  |  | ||||||
|  |         # create local tree | ||||||
|  |         path.mkdir(mode=0o755, parents=True, exist_ok=True) | ||||||
|  |         self.generator.write_pkgbuild(path) | ||||||
|  |         Sources.init(path) | ||||||
|  |  | ||||||
|  |     def package_register(self, path: Path) -> None: | ||||||
|  |         """ | ||||||
|  |         register package in build worker | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             path(Path): path to directory with package files | ||||||
|  |         """ | ||||||
|  |         ctx = context.get() | ||||||
|  |         reporter = ctx.get(Client) | ||||||
|  |         _, repository_id = self.configuration.check_loaded() | ||||||
|  |         package = Package.from_build(path, repository_id.architecture, None) | ||||||
|  |  | ||||||
|  |         reporter.set_unknown(package) | ||||||
|  |  | ||||||
|     def run(self) -> None: |     def run(self) -> None: | ||||||
|         """ |         """ | ||||||
|         create new local package |         create new local package | ||||||
|         """ |         """ | ||||||
|         local_path = self.configuration.repository_paths.cache_for(self.generator.pkgname) |         local_path = self.configuration.repository_paths.cache_for(self.generator.pkgname) | ||||||
|  |         self.package_create(local_path) | ||||||
|         # clear old tree if any |         self.package_register(local_path) | ||||||
|         shutil.rmtree(local_path, ignore_errors=True) |  | ||||||
|  |  | ||||||
|         # create local tree |  | ||||||
|         local_path.mkdir(mode=0o755, parents=True, exist_ok=True) |  | ||||||
|         self.generator.write_pkgbuild(local_path) |  | ||||||
|         Sources.init(local_path) |  | ||||||
|  |  | ||||||
|         # register package |  | ||||||
|         ctx = context.get() |  | ||||||
|         database = ctx.get(SQLite) |  | ||||||
|         _, repository_id = self.configuration.check_loaded() |  | ||||||
|         package = Package.from_build(local_path, repository_id.architecture, None) |  | ||||||
|         database.package_update(package, BuildStatus()) |  | ||||||
|  | |||||||
| @ -17,8 +17,10 @@ | |||||||
| # You should have received a copy of the GNU General Public License | # You should have received a copy of the GNU General Public License | ||||||
| # along with this program. If not, see <http://www.gnu.org/licenses/>. | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
| # | # | ||||||
| from dataclasses import dataclass, field | from dataclasses import dataclass, field, fields | ||||||
| from pathlib import Path | from typing import Any, Self | ||||||
|  |  | ||||||
|  | from ahriman.core.util import dataclass_view, filter_json | ||||||
|  |  | ||||||
|  |  | ||||||
| @dataclass(frozen=True) | @dataclass(frozen=True) | ||||||
| @ -27,9 +29,31 @@ class Dependencies: | |||||||
|     package paths dependencies |     package paths dependencies | ||||||
|  |  | ||||||
|     Attributes: |     Attributes: | ||||||
|         package_base(str): package base |         paths(dict[str, list[str]]): map of the paths used by this package to set of packages in which they were found | ||||||
|         paths(dict[Path, list[str]]): map of the paths used by this package to set of packages in which they were found |  | ||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     package_base: str |     paths: dict[str, list[str]] = field(default_factory=dict) | ||||||
|     paths: dict[Path, list[str]] = field(default_factory=dict) |  | ||||||
|  |     @classmethod | ||||||
|  |     def from_json(cls, dump: dict[str, Any]) -> Self: | ||||||
|  |         """ | ||||||
|  |         construct dependencies from the json dump | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             dump(dict[str, Any]): json dump body | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             Self: dependencies object | ||||||
|  |         """ | ||||||
|  |         # filter to only known fields | ||||||
|  |         known_fields = [pair.name for pair in fields(cls)] | ||||||
|  |         return cls(**filter_json(dump, known_fields)) | ||||||
|  |  | ||||||
|  |     def view(self) -> dict[str, Any]: | ||||||
|  |         """ | ||||||
|  |         generate json dependencies view | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             dict[str, Any]: json-friendly dictionary | ||||||
|  |         """ | ||||||
|  |         return dataclass_view(self) | ||||||
|  | |||||||
| @ -99,7 +99,7 @@ class PackageArchive: | |||||||
|         """ |         """ | ||||||
|         dependencies, roots = self.depends_on_paths() |         dependencies, roots = self.depends_on_paths() | ||||||
|  |  | ||||||
|         result: dict[Path, list[str]] = {} |         result: dict[str, list[str]] = {} | ||||||
|         for package, (directories, files) in self.installed_packages().items(): |         for package, (directories, files) in self.installed_packages().items(): | ||||||
|             if package in self.package.packages: |             if package in self.package.packages: | ||||||
|                 continue  # skip package itself |                 continue  # skip package itself | ||||||
| @ -108,9 +108,9 @@ class PackageArchive: | |||||||
|             required_by.extend(library for library in files if library.name in dependencies) |             required_by.extend(library for library in files if library.name in dependencies) | ||||||
|  |  | ||||||
|             for path in required_by: |             for path in required_by: | ||||||
|                 result.setdefault(path, []).append(package) |                 result.setdefault(str(path), []).append(package) | ||||||
|  |  | ||||||
|         return Dependencies(self.package.base, result) |         return Dependencies(result) | ||||||
|  |  | ||||||
|     def depends_on_paths(self) -> tuple[set[str], set[Path]]: |     def depends_on_paths(self) -> tuple[set[str], set[Path]]: | ||||||
|         """ |         """ | ||||||
|  | |||||||
| @ -19,11 +19,11 @@ | |||||||
| # | # | ||||||
| import shlex | import shlex | ||||||
|  |  | ||||||
| from dataclasses import dataclass | from dataclasses import dataclass, fields | ||||||
| from pathlib import Path | from pathlib import Path | ||||||
| from typing import Any, Generator, Self | from typing import Any, Generator, Self | ||||||
|  |  | ||||||
| from ahriman.core.util import dataclass_view | from ahriman.core.util import dataclass_view, filter_json | ||||||
|  |  | ||||||
|  |  | ||||||
| @dataclass(frozen=True) | @dataclass(frozen=True) | ||||||
| @ -84,6 +84,21 @@ class PkgbuildPatch: | |||||||
|         raw_value = next(iter(value_parts), "")  # extract raw value |         raw_value = next(iter(value_parts), "")  # extract raw value | ||||||
|         return cls(key, cls.parse(raw_value)) |         return cls(key, cls.parse(raw_value)) | ||||||
|  |  | ||||||
|  |     @classmethod | ||||||
|  |     def from_json(cls, dump: dict[str, Any]) -> Self: | ||||||
|  |         """ | ||||||
|  |         construct patch descriptor from the json dump | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             dump(dict[str, Any]): json dump body | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             Self: patch object | ||||||
|  |         """ | ||||||
|  |         # filter to only known fields | ||||||
|  |         known_fields = [pair.name for pair in fields(cls)] | ||||||
|  |         return cls(**filter_json(dump, known_fields)) | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def parse(source: str) -> str | list[str]: |     def parse(source: str) -> str | list[str]: | ||||||
|         """ |         """ | ||||||
|  | |||||||
| @ -22,6 +22,7 @@ from ahriman.web.schemas.auth_schema import AuthSchema | |||||||
| from ahriman.web.schemas.build_options_schema import BuildOptionsSchema | from ahriman.web.schemas.build_options_schema import BuildOptionsSchema | ||||||
| from ahriman.web.schemas.changes_schema import ChangesSchema | from ahriman.web.schemas.changes_schema import ChangesSchema | ||||||
| from ahriman.web.schemas.counters_schema import CountersSchema | from ahriman.web.schemas.counters_schema import CountersSchema | ||||||
|  | from ahriman.web.schemas.dependencies_schema import DependenciesSchema | ||||||
| from ahriman.web.schemas.error_schema import ErrorSchema | from ahriman.web.schemas.error_schema import ErrorSchema | ||||||
| from ahriman.web.schemas.file_schema import FileSchema | from ahriman.web.schemas.file_schema import FileSchema | ||||||
| from ahriman.web.schemas.info_schema import InfoSchema | from ahriman.web.schemas.info_schema import InfoSchema | ||||||
| @ -36,6 +37,7 @@ from ahriman.web.schemas.package_patch_schema import PackagePatchSchema | |||||||
| from ahriman.web.schemas.package_properties_schema import PackagePropertiesSchema | from ahriman.web.schemas.package_properties_schema import PackagePropertiesSchema | ||||||
| from ahriman.web.schemas.package_schema import PackageSchema | from ahriman.web.schemas.package_schema import PackageSchema | ||||||
| from ahriman.web.schemas.package_status_schema import PackageStatusSchema, PackageStatusSimplifiedSchema | from ahriman.web.schemas.package_status_schema import PackageStatusSchema, PackageStatusSimplifiedSchema | ||||||
|  | from ahriman.web.schemas.package_version_schema import PackageVersionSchema | ||||||
| from ahriman.web.schemas.pagination_schema import PaginationSchema | from ahriman.web.schemas.pagination_schema import PaginationSchema | ||||||
| from ahriman.web.schemas.patch_name_schema import PatchNameSchema | from ahriman.web.schemas.patch_name_schema import PatchNameSchema | ||||||
| from ahriman.web.schemas.patch_schema import PatchSchema | from ahriman.web.schemas.patch_schema import PatchSchema | ||||||
|  | |||||||
							
								
								
									
										31
									
								
								src/ahriman/web/schemas/dependencies_schema.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/ahriman/web/schemas/dependencies_schema.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | |||||||
|  | # | ||||||
|  | # Copyright (c) 2021-2024 ahriman team. | ||||||
|  | # | ||||||
|  | # This file is part of ahriman | ||||||
|  | # (see https://github.com/arcan1s/ahriman). | ||||||
|  | # | ||||||
|  | # This program is free software: you can redistribute it and/or modify | ||||||
|  | # it under the terms of the GNU General Public License as published by | ||||||
|  | # the Free Software Foundation, either version 3 of the License, or | ||||||
|  | # (at your option) any later version. | ||||||
|  | # | ||||||
|  | # This program is distributed in the hope that it will be useful, | ||||||
|  | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  | # GNU General Public License for more details. | ||||||
|  | # | ||||||
|  | # You should have received a copy of the GNU General Public License | ||||||
|  | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  | # | ||||||
|  | from marshmallow import Schema, fields | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class DependenciesSchema(Schema): | ||||||
|  |     """ | ||||||
|  |     request/response package dependencies schema | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     paths = fields.Dict( | ||||||
|  |         keys=fields.String(), values=fields.List(fields.String()), required=True, metadata={ | ||||||
|  |             "description": "Map of filesystem paths to packages which contain this path", | ||||||
|  |         }) | ||||||
							
								
								
									
										34
									
								
								src/ahriman/web/schemas/package_version_schema.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/ahriman/web/schemas/package_version_schema.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | |||||||
|  | # | ||||||
|  | # Copyright (c) 2021-2024 ahriman team. | ||||||
|  | # | ||||||
|  | # This file is part of ahriman | ||||||
|  | # (see https://github.com/arcan1s/ahriman). | ||||||
|  | # | ||||||
|  | # This program is free software: you can redistribute it and/or modify | ||||||
|  | # it under the terms of the GNU General Public License as published by | ||||||
|  | # the Free Software Foundation, either version 3 of the License, or | ||||||
|  | # (at your option) any later version. | ||||||
|  | # | ||||||
|  | # This program is distributed in the hope that it will be useful, | ||||||
|  | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  | # GNU General Public License for more details. | ||||||
|  | # | ||||||
|  | # You should have received a copy of the GNU General Public License | ||||||
|  | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  | # | ||||||
|  | from marshmallow import fields | ||||||
|  |  | ||||||
|  | from ahriman import __version__ | ||||||
|  | from ahriman.web.schemas.repository_id_schema import RepositoryIdSchema | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class PackageVersionSchema(RepositoryIdSchema): | ||||||
|  |     """ | ||||||
|  |     request package name schema | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     version = fields.String(metadata={ | ||||||
|  |         "description": "Package version", | ||||||
|  |         "example": __version__, | ||||||
|  |     }) | ||||||
| @ -25,8 +25,8 @@ class PatchSchema(Schema): | |||||||
|     request and response patch schema |     request and response patch schema | ||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     key = fields.String(required=True, metadata={ |     key = fields.String(metadata={ | ||||||
|         "description": "environment variable name", |         "description": "environment variable name. Required in case if it is not full diff", | ||||||
|     }) |     }) | ||||||
|     value = fields.String(metadata={ |     value = fields.String(metadata={ | ||||||
|         "description": "environment variable value", |         "description": "environment variable value", | ||||||
|  | |||||||
| @ -25,6 +25,7 @@ from typing import TypeVar | |||||||
| from ahriman.core.auth import Auth | from ahriman.core.auth import Auth | ||||||
| from ahriman.core.configuration import Configuration | from ahriman.core.configuration import Configuration | ||||||
| from ahriman.core.distributed import WorkersCache | from ahriman.core.distributed import WorkersCache | ||||||
|  | from ahriman.core.exceptions import UnknownPackageError | ||||||
| from ahriman.core.sign.gpg import GPG | from ahriman.core.sign.gpg import GPG | ||||||
| from ahriman.core.spawn import Spawn | from ahriman.core.spawn import Spawn | ||||||
| from ahriman.core.status.watcher import Watcher | from ahriman.core.status.watcher import Watcher | ||||||
| @ -218,12 +219,13 @@ class BaseView(View, CorsViewMixin): | |||||||
|             return RepositoryId(architecture, name) |             return RepositoryId(architecture, name) | ||||||
|         return next(iter(sorted(self.services.keys()))) |         return next(iter(sorted(self.services.keys()))) | ||||||
|  |  | ||||||
|     def service(self, repository_id: RepositoryId | None = None) -> Watcher: |     def service(self, repository_id: RepositoryId | None = None, package_base: str | None = None) -> Watcher: | ||||||
|         """ |         """ | ||||||
|         get status watcher instance |         get status watcher instance | ||||||
|  |  | ||||||
|         Args: |         Args: | ||||||
|             repository_id(RepositoryId | None, optional): repository unique identifier (Default value = None) |             repository_id(RepositoryId | None, optional): repository unique identifier (Default value = None) | ||||||
|  |             package_base(str | None, optional): package base to validate if exists (Default value = None) | ||||||
|  |  | ||||||
|         Returns: |         Returns: | ||||||
|             Watcher: build status watcher instance. If no repository provided, it will return the first one |             Watcher: build status watcher instance. If no repository provided, it will return the first one | ||||||
| @ -234,9 +236,11 @@ class BaseView(View, CorsViewMixin): | |||||||
|         if repository_id is None: |         if repository_id is None: | ||||||
|             repository_id = self.repository_id() |             repository_id = self.repository_id() | ||||||
|         try: |         try: | ||||||
|             return self.services[repository_id] |             return self.services[repository_id](package_base) | ||||||
|         except KeyError: |         except KeyError: | ||||||
|             raise HTTPNotFound(reason=f"Repository {repository_id.id} is unknown") |             raise HTTPNotFound(reason=f"Repository {repository_id.id} is unknown") | ||||||
|  |         except UnknownPackageError: | ||||||
|  |             raise HTTPNotFound(reason=f"Package {package_base} is unknown") | ||||||
|  |  | ||||||
|     async def username(self) -> str | None: |     async def username(self) -> str | None: | ||||||
|         """ |         """ | ||||||
|  | |||||||
| @ -19,9 +19,8 @@ | |||||||
| # | # | ||||||
| import aiohttp_apispec  # type: ignore[import-untyped] | import aiohttp_apispec  # type: ignore[import-untyped] | ||||||
|  |  | ||||||
| from aiohttp.web import HTTPBadRequest, HTTPNoContent, HTTPNotFound, Response, json_response | from aiohttp.web import HTTPBadRequest, HTTPNoContent, Response, json_response | ||||||
|  |  | ||||||
| from ahriman.core.exceptions import UnknownPackageError |  | ||||||
| from ahriman.models.changes import Changes | from ahriman.models.changes import Changes | ||||||
| from ahriman.models.user_access import UserAccess | from ahriman.models.user_access import UserAccess | ||||||
| from ahriman.web.schemas import AuthSchema, ChangesSchema, ErrorSchema, PackageNameSchema, RepositoryIdSchema | from ahriman.web.schemas import AuthSchema, ChangesSchema, ErrorSchema, PackageNameSchema, RepositoryIdSchema | ||||||
| @ -70,10 +69,7 @@ class ChangesView(StatusViewGuard, BaseView): | |||||||
|         """ |         """ | ||||||
|         package_base = self.request.match_info["package"] |         package_base = self.request.match_info["package"] | ||||||
|  |  | ||||||
|         try: |         changes = self.service(package_base=package_base).package_changes_get(package_base) | ||||||
|             changes = self.service().package_changes_get(package_base) |  | ||||||
|         except UnknownPackageError: |  | ||||||
|             raise HTTPNotFound(reason=f"Package {package_base} is unknown") |  | ||||||
|  |  | ||||||
|         return json_response(changes.view()) |         return json_response(changes.view()) | ||||||
|  |  | ||||||
| @ -113,7 +109,6 @@ class ChangesView(StatusViewGuard, BaseView): | |||||||
|             raise HTTPBadRequest(reason=str(ex)) |             raise HTTPBadRequest(reason=str(ex)) | ||||||
|  |  | ||||||
|         changes = Changes(last_commit_sha, change) |         changes = Changes(last_commit_sha, change) | ||||||
|         repository_id = self.repository_id() |         self.service().package_changes_update(package_base, changes) | ||||||
|         self.service(repository_id).database.changes_insert(package_base, changes, repository_id) |  | ||||||
|  |  | ||||||
|         raise HTTPNoContent |         raise HTTPNoContent | ||||||
|  | |||||||
							
								
								
									
										113
									
								
								src/ahriman/web/views/v1/packages/dependencies.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								src/ahriman/web/views/v1/packages/dependencies.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,113 @@ | |||||||
|  | # | ||||||
|  | # Copyright (c) 2021-2024 ahriman team. | ||||||
|  | # | ||||||
|  | # This file is part of ahriman | ||||||
|  | # (see https://github.com/arcan1s/ahriman). | ||||||
|  | # | ||||||
|  | # This program is free software: you can redistribute it and/or modify | ||||||
|  | # it under the terms of the GNU General Public License as published by | ||||||
|  | # the Free Software Foundation, either version 3 of the License, or | ||||||
|  | # (at your option) any later version. | ||||||
|  | # | ||||||
|  | # This program is distributed in the hope that it will be useful, | ||||||
|  | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  | # GNU General Public License for more details. | ||||||
|  | # | ||||||
|  | # You should have received a copy of the GNU General Public License | ||||||
|  | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  | # | ||||||
|  | import aiohttp_apispec  # type: ignore[import-untyped] | ||||||
|  |  | ||||||
|  | from aiohttp.web import HTTPBadRequest, HTTPNoContent, Response, json_response | ||||||
|  |  | ||||||
|  | from ahriman.models.dependencies import Dependencies | ||||||
|  | from ahriman.models.user_access import UserAccess | ||||||
|  | from ahriman.web.schemas import AuthSchema, DependenciesSchema, ErrorSchema, PackageNameSchema, RepositoryIdSchema | ||||||
|  | from ahriman.web.views.base import BaseView | ||||||
|  | from ahriman.web.views.status_view_guard import StatusViewGuard | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class DependenciesView(StatusViewGuard, BaseView): | ||||||
|  |     """ | ||||||
|  |     package dependencies web view | ||||||
|  |  | ||||||
|  |     Attributes: | ||||||
|  |         GET_PERMISSION(UserAccess): (class attribute) get permissions of self | ||||||
|  |         POST_PERMISSION(UserAccess): (class attribute) post permissions of self | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     GET_PERMISSION = UserAccess.Reporter | ||||||
|  |     POST_PERMISSION = UserAccess.Full | ||||||
|  |     ROUTES = ["/api/v1/packages/{package}/dependencies"] | ||||||
|  |  | ||||||
|  |     @aiohttp_apispec.docs( | ||||||
|  |         tags=["Build"], | ||||||
|  |         summary="Get package dependencies", | ||||||
|  |         description="Retrieve package implicit dependencies", | ||||||
|  |         responses={ | ||||||
|  |             200: {"description": "Success response", "schema": DependenciesSchema}, | ||||||
|  |             401: {"description": "Authorization required", "schema": ErrorSchema}, | ||||||
|  |             403: {"description": "Access is forbidden", "schema": ErrorSchema}, | ||||||
|  |             404: {"description": "Package base and/or repository are unknown", "schema": ErrorSchema}, | ||||||
|  |             500: {"description": "Internal server error", "schema": ErrorSchema}, | ||||||
|  |         }, | ||||||
|  |         security=[{"token": [GET_PERMISSION]}], | ||||||
|  |     ) | ||||||
|  |     @aiohttp_apispec.cookies_schema(AuthSchema) | ||||||
|  |     @aiohttp_apispec.match_info_schema(PackageNameSchema) | ||||||
|  |     @aiohttp_apispec.querystring_schema(RepositoryIdSchema) | ||||||
|  |     async def get(self) -> Response: | ||||||
|  |         """ | ||||||
|  |         get package dependencies | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             Response: 200 with package implicit dependencies on success | ||||||
|  |  | ||||||
|  |         Raises: | ||||||
|  |             HTTPNotFound: if package base is unknown | ||||||
|  |         """ | ||||||
|  |         package_base = self.request.match_info["package"] | ||||||
|  |  | ||||||
|  |         dependencies = self.service(package_base=package_base).package_dependencies_get(package_base) | ||||||
|  |  | ||||||
|  |         return json_response(dependencies.view()) | ||||||
|  |  | ||||||
|  |     @aiohttp_apispec.docs( | ||||||
|  |         tags=["Build"], | ||||||
|  |         summary="Update package dependencies", | ||||||
|  |         description="Set package implicit dependencies", | ||||||
|  |         responses={ | ||||||
|  |             204: {"description": "Success response"}, | ||||||
|  |             400: {"description": "Bad data is supplied", "schema": ErrorSchema}, | ||||||
|  |             401: {"description": "Authorization required", "schema": ErrorSchema}, | ||||||
|  |             403: {"description": "Access is forbidden", "schema": ErrorSchema}, | ||||||
|  |             404: {"description": "Repository is unknown", "schema": ErrorSchema}, | ||||||
|  |             500: {"description": "Internal server error", "schema": ErrorSchema}, | ||||||
|  |         }, | ||||||
|  |         security=[{"token": [POST_PERMISSION]}], | ||||||
|  |     ) | ||||||
|  |     @aiohttp_apispec.cookies_schema(AuthSchema) | ||||||
|  |     @aiohttp_apispec.match_info_schema(PackageNameSchema) | ||||||
|  |     @aiohttp_apispec.querystring_schema(RepositoryIdSchema) | ||||||
|  |     @aiohttp_apispec.json_schema(DependenciesSchema) | ||||||
|  |     async def post(self) -> None: | ||||||
|  |         """ | ||||||
|  |         insert new package dependencies | ||||||
|  |  | ||||||
|  |         Raises: | ||||||
|  |             HTTPBadRequest: if bad data is supplied | ||||||
|  |             HTTPNoContent: in case of success response | ||||||
|  |         """ | ||||||
|  |         package_base = self.request.match_info["package"] | ||||||
|  |  | ||||||
|  |         try: | ||||||
|  |             data = await self.request.json() | ||||||
|  |             data["package_base"] = package_base  # read from path instead of object | ||||||
|  |             dependencies = Dependencies.from_json(data) | ||||||
|  |         except Exception as ex: | ||||||
|  |             raise HTTPBadRequest(reason=str(ex)) | ||||||
|  |  | ||||||
|  |         self.service(package_base=package_base).package_dependencies_update(package_base, dependencies) | ||||||
|  |  | ||||||
|  |         raise HTTPNoContent | ||||||
| @ -25,8 +25,8 @@ from ahriman.core.exceptions import UnknownPackageError | |||||||
| from ahriman.core.util import pretty_datetime | from ahriman.core.util import pretty_datetime | ||||||
| from ahriman.models.log_record_id import LogRecordId | from ahriman.models.log_record_id import LogRecordId | ||||||
| from ahriman.models.user_access import UserAccess | from ahriman.models.user_access import UserAccess | ||||||
| from ahriman.web.schemas import AuthSchema, ErrorSchema, LogsSchema, PackageNameSchema, RepositoryIdSchema, \ | from ahriman.web.schemas import AuthSchema, ErrorSchema, LogsSchema, PackageNameSchema, PackageVersionSchema, \ | ||||||
|     VersionedLogSchema |     RepositoryIdSchema, VersionedLogSchema | ||||||
| from ahriman.web.views.base import BaseView | from ahriman.web.views.base import BaseView | ||||||
| from ahriman.web.views.status_view_guard import StatusViewGuard | from ahriman.web.views.status_view_guard import StatusViewGuard | ||||||
|  |  | ||||||
| @ -60,7 +60,7 @@ class LogsView(StatusViewGuard, BaseView): | |||||||
|     ) |     ) | ||||||
|     @aiohttp_apispec.cookies_schema(AuthSchema) |     @aiohttp_apispec.cookies_schema(AuthSchema) | ||||||
|     @aiohttp_apispec.match_info_schema(PackageNameSchema) |     @aiohttp_apispec.match_info_schema(PackageNameSchema) | ||||||
|     @aiohttp_apispec.querystring_schema(RepositoryIdSchema) |     @aiohttp_apispec.querystring_schema(PackageVersionSchema) | ||||||
|     async def delete(self) -> None: |     async def delete(self) -> None: | ||||||
|         """ |         """ | ||||||
|         delete package logs |         delete package logs | ||||||
| @ -69,7 +69,8 @@ class LogsView(StatusViewGuard, BaseView): | |||||||
|             HTTPNoContent: on success response |             HTTPNoContent: on success response | ||||||
|         """ |         """ | ||||||
|         package_base = self.request.match_info["package"] |         package_base = self.request.match_info["package"] | ||||||
|         self.service().logs_remove(package_base, None) |         version = self.request.query.get("version") | ||||||
|  |         self.service().package_logs_remove(package_base, version) | ||||||
|  |  | ||||||
|         raise HTTPNoContent |         raise HTTPNoContent | ||||||
|  |  | ||||||
| @ -103,7 +104,7 @@ class LogsView(StatusViewGuard, BaseView): | |||||||
|  |  | ||||||
|         try: |         try: | ||||||
|             _, status = self.service().package_get(package_base) |             _, status = self.service().package_get(package_base) | ||||||
|             logs = self.service().logs_get(package_base) |             logs = self.service(package_base=package_base).package_logs_get(package_base, -1, 0) | ||||||
|         except UnknownPackageError: |         except UnknownPackageError: | ||||||
|             raise HTTPNotFound(reason=f"Package {package_base} is unknown") |             raise HTTPNotFound(reason=f"Package {package_base} is unknown") | ||||||
|  |  | ||||||
| @ -149,6 +150,6 @@ class LogsView(StatusViewGuard, BaseView): | |||||||
|         except Exception as ex: |         except Exception as ex: | ||||||
|             raise HTTPBadRequest(reason=str(ex)) |             raise HTTPBadRequest(reason=str(ex)) | ||||||
|  |  | ||||||
|         self.service().logs_update(LogRecordId(package_base, version), created, record) |         self.service().package_logs_add(LogRecordId(package_base, version), created, record) | ||||||
|  |  | ||||||
|         raise HTTPNoContent |         raise HTTPNoContent | ||||||
|  | |||||||
| @ -152,7 +152,10 @@ class PackageView(StatusViewGuard, BaseView): | |||||||
|             raise HTTPBadRequest(reason=str(ex)) |             raise HTTPBadRequest(reason=str(ex)) | ||||||
|  |  | ||||||
|         try: |         try: | ||||||
|             self.service().package_update(package_base, status, package) |             if package is None: | ||||||
|  |                 self.service().package_status_update(package_base, status) | ||||||
|  |             else: | ||||||
|  |                 self.service().package_update(package, status) | ||||||
|         except UnknownPackageError: |         except UnknownPackageError: | ||||||
|             raise HTTPBadRequest(reason=f"Package {package_base} is unknown, but no package body set") |             raise HTTPBadRequest(reason=f"Package {package_base} is unknown, but no package body set") | ||||||
|  |  | ||||||
|  | |||||||
| @ -63,7 +63,8 @@ class PatchView(StatusViewGuard, BaseView): | |||||||
|         """ |         """ | ||||||
|         package_base = self.request.match_info["package"] |         package_base = self.request.match_info["package"] | ||||||
|         variable = self.request.match_info["patch"] |         variable = self.request.match_info["patch"] | ||||||
|         self.service().patches_remove(package_base, variable) |  | ||||||
|  |         self.service().package_patches_remove(package_base, variable) | ||||||
|  |  | ||||||
|         raise HTTPNoContent |         raise HTTPNoContent | ||||||
|  |  | ||||||
| @ -95,7 +96,7 @@ class PatchView(StatusViewGuard, BaseView): | |||||||
|         package_base = self.request.match_info["package"] |         package_base = self.request.match_info["package"] | ||||||
|         variable = self.request.match_info["patch"] |         variable = self.request.match_info["patch"] | ||||||
|  |  | ||||||
|         patches = self.service().patches_get(package_base, variable) |         patches = self.service().package_patches_get(package_base, variable) | ||||||
|  |  | ||||||
|         selected = next((patch for patch in patches if patch.key == variable), None) |         selected = next((patch for patch in patches if patch.key == variable), None) | ||||||
|         if selected is None: |         if selected is None: | ||||||
|  | |||||||
| @ -63,7 +63,7 @@ class PatchesView(StatusViewGuard, BaseView): | |||||||
|             Response: 200 with package patches on success |             Response: 200 with package patches on success | ||||||
|         """ |         """ | ||||||
|         package_base = self.request.match_info["package"] |         package_base = self.request.match_info["package"] | ||||||
|         patches = self.service().patches_get(package_base, None) |         patches = self.service().package_patches_get(package_base, None) | ||||||
|  |  | ||||||
|         response = [patch.view() for patch in patches] |         response = [patch.view() for patch in patches] | ||||||
|         return json_response(response) |         return json_response(response) | ||||||
| @ -96,11 +96,11 @@ class PatchesView(StatusViewGuard, BaseView): | |||||||
|  |  | ||||||
|         try: |         try: | ||||||
|             data = await self.request.json() |             data = await self.request.json() | ||||||
|             key = data["key"] |             key = data.get("key") | ||||||
|             value = data["value"] |             value = data["value"] | ||||||
|         except Exception as ex: |         except Exception as ex: | ||||||
|             raise HTTPBadRequest(reason=str(ex)) |             raise HTTPBadRequest(reason=str(ex)) | ||||||
|  |  | ||||||
|         self.service().patches_update(package_base, PkgbuildPatch(key, value)) |         self.service().package_patches_update(package_base, PkgbuildPatch(key, value)) | ||||||
|  |  | ||||||
|         raise HTTPNoContent |         raise HTTPNoContent | ||||||
|  | |||||||
| @ -19,9 +19,8 @@ | |||||||
| # | # | ||||||
| import aiohttp_apispec  # type: ignore[import-untyped] | import aiohttp_apispec  # type: ignore[import-untyped] | ||||||
|  |  | ||||||
| from aiohttp.web import HTTPNotFound, Response, json_response | from aiohttp.web import Response, json_response | ||||||
|  |  | ||||||
| from ahriman.core.exceptions import UnknownPackageError |  | ||||||
| from ahriman.models.user_access import UserAccess | from ahriman.models.user_access import UserAccess | ||||||
| from ahriman.web.schemas import AuthSchema, ErrorSchema, LogSchema, PackageNameSchema, PaginationSchema | from ahriman.web.schemas import AuthSchema, ErrorSchema, LogSchema, PackageNameSchema, PaginationSchema | ||||||
| from ahriman.web.views.base import BaseView | from ahriman.web.views.base import BaseView | ||||||
| @ -68,10 +67,8 @@ class LogsView(StatusViewGuard, BaseView): | |||||||
|         """ |         """ | ||||||
|         package_base = self.request.match_info["package"] |         package_base = self.request.match_info["package"] | ||||||
|         limit, offset = self.page() |         limit, offset = self.page() | ||||||
|         try: |  | ||||||
|             logs = self.service().logs_get(package_base, limit, offset) |         logs = self.service(package_base=package_base).package_logs_get(package_base, limit, offset) | ||||||
|         except UnknownPackageError: |  | ||||||
|             raise HTTPNotFound(reason=f"Package {package_base} is unknown") |  | ||||||
|  |  | ||||||
|         response = [ |         response = [ | ||||||
|             { |             { | ||||||
|  | |||||||
| @ -30,6 +30,7 @@ from ahriman.core.database import SQLite | |||||||
| from ahriman.core.distributed import WorkersCache | from ahriman.core.distributed import WorkersCache | ||||||
| from ahriman.core.exceptions import InitializeError | from ahriman.core.exceptions import InitializeError | ||||||
| from ahriman.core.spawn import Spawn | from ahriman.core.spawn import Spawn | ||||||
|  | from ahriman.core.status import Client | ||||||
| from ahriman.core.status.watcher import Watcher | from ahriman.core.status.watcher import Watcher | ||||||
| from ahriman.models.repository_id import RepositoryId | from ahriman.models.repository_id import RepositoryId | ||||||
| from ahriman.web.apispec import setup_apispec | from ahriman.web.apispec import setup_apispec | ||||||
| @ -167,7 +168,8 @@ def setup_server(configuration: Configuration, spawner: Spawn, repositories: lis | |||||||
|     watchers: dict[RepositoryId, Watcher] = {} |     watchers: dict[RepositoryId, Watcher] = {} | ||||||
|     for repository_id in repositories: |     for repository_id in repositories: | ||||||
|         application.logger.info("load repository %s", repository_id) |         application.logger.info("load repository %s", repository_id) | ||||||
|         watchers[repository_id] = Watcher(repository_id, database) |         client = Client.load(repository_id, configuration, database, report=False)  # explicitly load local client | ||||||
|  |         watchers[repository_id] = Watcher(client) | ||||||
|     application[WatcherKey] = watchers |     application[WatcherKey] = watchers | ||||||
|     # workers cache |     # workers cache | ||||||
|     application[WorkersKey] = WorkersCache(configuration) |     application[WorkersKey] = WorkersCache(configuration) | ||||||
|  | |||||||
| @ -93,8 +93,7 @@ def test_with_dependencies(application: Application, package_ahriman: Package, p | |||||||
|                                       side_effect=lambda *args: packages[args[0].name]) |                                       side_effect=lambda *args: packages[args[0].name]) | ||||||
|     packages_mock = mocker.patch("ahriman.application.application.Application._known_packages", |     packages_mock = mocker.patch("ahriman.application.application.Application._known_packages", | ||||||
|                                  return_value={"devtools", "python-build", "python-pytest"}) |                                  return_value={"devtools", "python-build", "python-pytest"}) | ||||||
|     update_remote_mock = mocker.patch("ahriman.core.database.SQLite.package_base_update") |     status_client_mock = mocker.patch("ahriman.core.status.Client.set_unknown") | ||||||
|     status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_unknown") |  | ||||||
|  |  | ||||||
|     result = application.with_dependencies([package_ahriman], process_dependencies=True) |     result = application.with_dependencies([package_ahriman], process_dependencies=True) | ||||||
|     assert {package.base: package for package in result} == packages |     assert {package.base: package for package in result} == packages | ||||||
| @ -107,11 +106,6 @@ def test_with_dependencies(application: Application, package_ahriman: Package, p | |||||||
|     ], any_order=True) |     ], any_order=True) | ||||||
|     packages_mock.assert_called_once_with() |     packages_mock.assert_called_once_with() | ||||||
|  |  | ||||||
|     update_remote_mock.assert_has_calls([ |  | ||||||
|         MockCall(package_python_schedule), |  | ||||||
|         MockCall(packages["python"]), |  | ||||||
|         MockCall(packages["python-installer"]), |  | ||||||
|     ], any_order=True) |  | ||||||
|     status_client_mock.assert_has_calls([ |     status_client_mock.assert_has_calls([ | ||||||
|         MockCall(package_python_schedule), |         MockCall(package_python_schedule), | ||||||
|         MockCall(packages["python"]), |         MockCall(packages["python"]), | ||||||
|  | |||||||
| @ -41,11 +41,11 @@ def test_add_aur(application_packages: ApplicationPackages, package_ahriman: Pac | |||||||
|     """ |     """ | ||||||
|     mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman) |     mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman) | ||||||
|     build_queue_mock = mocker.patch("ahriman.core.database.SQLite.build_queue_insert") |     build_queue_mock = mocker.patch("ahriman.core.database.SQLite.build_queue_insert") | ||||||
|     update_remote_mock = mocker.patch("ahriman.core.database.SQLite.package_base_update") |     status_client_mock = mocker.patch("ahriman.core.status.Client.set_unknown") | ||||||
|  |  | ||||||
|     application_packages._add_aur(package_ahriman.base, "packager") |     application_packages._add_aur(package_ahriman.base, "packager") | ||||||
|     build_queue_mock.assert_called_once_with(package_ahriman) |     build_queue_mock.assert_called_once_with(package_ahriman) | ||||||
|     update_remote_mock.assert_called_once_with(package_ahriman) |     status_client_mock.assert_called_once_with(package_ahriman) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_add_directory(application_packages: ApplicationPackages, package_ahriman: Package, | def test_add_directory(application_packages: ApplicationPackages, package_ahriman: Package, | ||||||
| @ -153,11 +153,11 @@ def test_add_repository(application_packages: ApplicationPackages, package_ahrim | |||||||
|     """ |     """ | ||||||
|     mocker.patch("ahriman.models.package.Package.from_official", return_value=package_ahriman) |     mocker.patch("ahriman.models.package.Package.from_official", return_value=package_ahriman) | ||||||
|     build_queue_mock = mocker.patch("ahriman.core.database.SQLite.build_queue_insert") |     build_queue_mock = mocker.patch("ahriman.core.database.SQLite.build_queue_insert") | ||||||
|     update_remote_mock = mocker.patch("ahriman.core.database.SQLite.package_base_update") |     status_client_mock = mocker.patch("ahriman.core.status.Client.set_unknown") | ||||||
|  |  | ||||||
|     application_packages._add_repository(package_ahriman.base, "packager") |     application_packages._add_repository(package_ahriman.base, "packager") | ||||||
|     build_queue_mock.assert_called_once_with(package_ahriman) |     build_queue_mock.assert_called_once_with(package_ahriman) | ||||||
|     update_remote_mock.assert_called_once_with(package_ahriman) |     status_client_mock.assert_called_once_with(package_ahriman) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_add_add_archive(application_packages: ApplicationPackages, package_ahriman: Package, | def test_add_add_archive(application_packages: ApplicationPackages, package_ahriman: Package, | ||||||
|  | |||||||
| @ -1,15 +1,15 @@ | |||||||
| from ahriman.application.application.application_properties import ApplicationProperties | from ahriman.application.application.application_properties import ApplicationProperties | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_create_tree(application_properties: ApplicationProperties) -> None: |  | ||||||
|     """ |  | ||||||
|     must have repository attribute |  | ||||||
|     """ |  | ||||||
|     assert application_properties.repository |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_architecture(application_properties: ApplicationProperties) -> None: | def test_architecture(application_properties: ApplicationProperties) -> None: | ||||||
|     """ |     """ | ||||||
|     must return repository architecture |     must return repository architecture | ||||||
|     """ |     """ | ||||||
|     assert application_properties.architecture == application_properties.repository_id.architecture |     assert application_properties.architecture == application_properties.repository_id.architecture | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_reporter(application_properties: ApplicationProperties) -> None: | ||||||
|  |     """ | ||||||
|  |     must have reporter attribute | ||||||
|  |     """ | ||||||
|  |     assert application_properties.reporter | ||||||
|  | |||||||
| @ -17,14 +17,12 @@ def test_changes(application_repository: ApplicationRepository, package_ahriman: | |||||||
|     must generate changes for the packages |     must generate changes for the packages | ||||||
|     """ |     """ | ||||||
|     changes = Changes("hash", "change") |     changes = Changes("hash", "change") | ||||||
|     hashes_mock = mocker.patch("ahriman.core.database.SQLite.hashes_get", return_value={ |     hashes_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_get", return_value=changes) | ||||||
|         package_ahriman.base: changes.last_commit_sha, |  | ||||||
|     }) |  | ||||||
|     changes_mock = mocker.patch("ahriman.core.repository.Repository.package_changes", return_value=changes) |     changes_mock = mocker.patch("ahriman.core.repository.Repository.package_changes", return_value=changes) | ||||||
|     report_mock = mocker.patch("ahriman.core.status.client.Client.package_changes_set") |     report_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_update") | ||||||
|  |  | ||||||
|     application_repository.changes([package_ahriman]) |     application_repository.changes([package_ahriman]) | ||||||
|     hashes_mock.assert_called_once_with() |     hashes_mock.assert_called_once_with(package_ahriman.base) | ||||||
|     changes_mock.assert_called_once_with(package_ahriman, changes.last_commit_sha) |     changes_mock.assert_called_once_with(package_ahriman, changes.last_commit_sha) | ||||||
|     report_mock.assert_called_once_with(package_ahriman.base, changes) |     report_mock.assert_called_once_with(package_ahriman.base, changes) | ||||||
|  |  | ||||||
| @ -34,9 +32,8 @@ def test_changes_skip(application_repository: ApplicationRepository, package_ahr | |||||||
|     """ |     """ | ||||||
|     must skip change generation if no last commit sha has been found |     must skip change generation if no last commit sha has been found | ||||||
|     """ |     """ | ||||||
|     mocker.patch("ahriman.core.database.SQLite.hashes_get", return_value={}) |  | ||||||
|     changes_mock = mocker.patch("ahriman.core.repository.Repository.package_changes") |     changes_mock = mocker.patch("ahriman.core.repository.Repository.package_changes") | ||||||
|     report_mock = mocker.patch("ahriman.core.status.client.Client.package_changes_set") |     report_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_update") | ||||||
|  |  | ||||||
|     application_repository.changes([package_ahriman]) |     application_repository.changes([package_ahriman]) | ||||||
|     changes_mock.assert_not_called() |     changes_mock.assert_not_called() | ||||||
|  | |||||||
| @ -62,11 +62,11 @@ def test_run_with_patches(args: argparse.Namespace, configuration: Configuration | |||||||
|     args.variable = ["KEY=VALUE"] |     args.variable = ["KEY=VALUE"] | ||||||
|     mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) |     mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) | ||||||
|     mocker.patch("ahriman.application.application.Application.add") |     mocker.patch("ahriman.application.application.Application.add") | ||||||
|     application_mock = mocker.patch("ahriman.core.database.SQLite.patches_insert") |     application_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_update") | ||||||
|  |  | ||||||
|     _, repository_id = configuration.check_loaded() |     _, repository_id = configuration.check_loaded() | ||||||
|     Add.run(args, repository_id, configuration, report=False) |     Add.run(args, repository_id, configuration, report=False) | ||||||
|     application_mock.assert_called_once_with(args.package[0], [PkgbuildPatch("KEY", "VALUE")]) |     application_mock.assert_called_once_with(args.package[0], PkgbuildPatch("KEY", "VALUE")) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_run_with_updates(args: argparse.Namespace, configuration: Configuration, repository: Repository, | def test_run_with_updates(args: argparse.Namespace, configuration: Configuration, repository: Repository, | ||||||
|  | |||||||
| @ -34,7 +34,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository: | |||||||
|     """ |     """ | ||||||
|     args = _default_args(args) |     args = _default_args(args) | ||||||
|     mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) |     mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) | ||||||
|     application_mock = mocker.patch("ahriman.core.status.client.Client.package_changes_get", |     application_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_get", | ||||||
|                                     return_value=Changes("sha", "change")) |                                     return_value=Changes("sha", "change")) | ||||||
|     check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") |     check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") | ||||||
|     print_mock = mocker.patch("ahriman.core.formatters.Printer.print") |     print_mock = mocker.patch("ahriman.core.formatters.Printer.print") | ||||||
| @ -54,7 +54,7 @@ def test_run_empty_exception(args: argparse.Namespace, configuration: Configurat | |||||||
|     args = _default_args(args) |     args = _default_args(args) | ||||||
|     args.exit_code = True |     args.exit_code = True | ||||||
|     mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) |     mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) | ||||||
|     mocker.patch("ahriman.core.status.client.Client.package_changes_get", return_value=Changes()) |     mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_get", return_value=Changes()) | ||||||
|     check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") |     check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") | ||||||
|  |  | ||||||
|     _, repository_id = configuration.check_loaded() |     _, repository_id = configuration.check_loaded() | ||||||
| @ -70,7 +70,7 @@ def test_run_remove(args: argparse.Namespace, configuration: Configuration, repo | |||||||
|     args = _default_args(args) |     args = _default_args(args) | ||||||
|     args.action = Action.Remove |     args.action = Action.Remove | ||||||
|     mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) |     mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) | ||||||
|     update_mock = mocker.patch("ahriman.core.status.client.Client.package_changes_set") |     update_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_update") | ||||||
|  |  | ||||||
|     _, repository_id = configuration.check_loaded() |     _, repository_id = configuration.check_loaded() | ||||||
|     Change.run(args, repository_id, configuration, report=False) |     Change.run(args, repository_id, configuration, report=False) | ||||||
|  | |||||||
| @ -160,13 +160,28 @@ def test_patch_set_list(application: Application, mocker: MockerFixture) -> None | |||||||
|     """ |     """ | ||||||
|     must list available patches for the command |     must list available patches for the command | ||||||
|     """ |     """ | ||||||
|     get_mock = mocker.patch("ahriman.core.database.SQLite.patches_list", |     get_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_get", | ||||||
|                             return_value={"ahriman": PkgbuildPatch(None, "patch")}) |                             return_value=[PkgbuildPatch(None, "patch"), PkgbuildPatch("version", "value")]) | ||||||
|     print_mock = mocker.patch("ahriman.core.formatters.Printer.print") |     print_mock = mocker.patch("ahriman.core.formatters.Printer.print") | ||||||
|     check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") |     check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") | ||||||
|  |  | ||||||
|     Patch.patch_set_list(application, "ahriman", ["version"], False) |     Patch.patch_set_list(application, "ahriman", ["version"], False) | ||||||
|     get_mock.assert_called_once_with("ahriman", ["version"]) |     get_mock.assert_called_once_with("ahriman", None) | ||||||
|  |     print_mock.assert_called_once_with(verbose=True, log_fn=pytest.helpers.anyvar(int), separator=" = ") | ||||||
|  |     check_mock.assert_called_once_with(False, False) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_patch_set_list_all(application: Application, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must list all available patches for the command | ||||||
|  |     """ | ||||||
|  |     get_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_get", | ||||||
|  |                             return_value=[PkgbuildPatch(None, "patch")]) | ||||||
|  |     print_mock = mocker.patch("ahriman.core.formatters.Printer.print") | ||||||
|  |     check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") | ||||||
|  |  | ||||||
|  |     Patch.patch_set_list(application, "ahriman", None, False) | ||||||
|  |     get_mock.assert_called_once_with("ahriman", None) | ||||||
|     print_mock.assert_called_once_with(verbose=True, log_fn=pytest.helpers.anyvar(int), separator=" = ") |     print_mock.assert_called_once_with(verbose=True, log_fn=pytest.helpers.anyvar(int), separator=" = ") | ||||||
|     check_mock.assert_called_once_with(False, False) |     check_mock.assert_called_once_with(False, False) | ||||||
|  |  | ||||||
| @ -175,7 +190,7 @@ def test_patch_set_list_empty_exception(application: Application, mocker: Mocker | |||||||
|     """ |     """ | ||||||
|     must raise ExitCode exception on empty patch list |     must raise ExitCode exception on empty patch list | ||||||
|     """ |     """ | ||||||
|     mocker.patch("ahriman.core.database.SQLite.patches_list", return_value={}) |     mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_get", return_value={}) | ||||||
|     check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") |     check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") | ||||||
|  |  | ||||||
|     Patch.patch_set_list(application, "ahriman", [], True) |     Patch.patch_set_list(application, "ahriman", [], True) | ||||||
| @ -186,18 +201,27 @@ def test_patch_set_create(application: Application, package_ahriman: Package, mo | |||||||
|     """ |     """ | ||||||
|     must create patch set for the package |     must create patch set for the package | ||||||
|     """ |     """ | ||||||
|     create_mock = mocker.patch("ahriman.core.database.SQLite.patches_insert") |     create_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_update") | ||||||
|     Patch.patch_set_create(application, package_ahriman.base, PkgbuildPatch("version", package_ahriman.version)) |     Patch.patch_set_create(application, package_ahriman.base, PkgbuildPatch("version", package_ahriman.version)) | ||||||
|     create_mock.assert_called_once_with(package_ahriman.base, [PkgbuildPatch("version", package_ahriman.version)]) |     create_mock.assert_called_once_with(package_ahriman.base, PkgbuildPatch("version", package_ahriman.version)) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_patch_set_remove(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None: | def test_patch_set_remove(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must remove patch set for the package |     must remove patch set for the package | ||||||
|     """ |     """ | ||||||
|     remove_mock = mocker.patch("ahriman.core.database.SQLite.patches_remove") |     remove_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_remove") | ||||||
|     Patch.patch_set_remove(application, package_ahriman.base, ["version"]) |     Patch.patch_set_remove(application, package_ahriman.base, ["version"]) | ||||||
|     remove_mock.assert_called_once_with(package_ahriman.base, ["version"]) |     remove_mock.assert_called_once_with(package_ahriman.base, "version") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_patch_set_remove_all(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must remove all patches for the package | ||||||
|  |     """ | ||||||
|  |     remove_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_remove") | ||||||
|  |     Patch.patch_set_remove(application, package_ahriman.base, None) | ||||||
|  |     remove_mock.assert_called_once_with(package_ahriman.base, None) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_disallow_multi_architecture_run() -> None: | def test_disallow_multi_architecture_run() -> None: | ||||||
|  | |||||||
| @ -185,7 +185,7 @@ def test_extract_packages_by_status(application: Application, mocker: MockerFixt | |||||||
|         ("package2", BuildStatus(BuildStatusEnum.Failed)), |         ("package2", BuildStatus(BuildStatusEnum.Failed)), | ||||||
|     ]) |     ]) | ||||||
|     assert Rebuild.extract_packages(application, BuildStatusEnum.Failed, from_database=True) == ["package2"] |     assert Rebuild.extract_packages(application, BuildStatusEnum.Failed, from_database=True) == ["package2"] | ||||||
|     packages_mock.assert_called_once_with() |     packages_mock.assert_called_once_with(application.repository_id) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_extract_packages_from_database(application: Application, mocker: MockerFixture) -> None: | def test_extract_packages_from_database(application: Application, mocker: MockerFixture) -> None: | ||||||
| @ -194,4 +194,4 @@ def test_extract_packages_from_database(application: Application, mocker: Mocker | |||||||
|     """ |     """ | ||||||
|     packages_mock = mocker.patch("ahriman.core.database.SQLite.packages_get") |     packages_mock = mocker.patch("ahriman.core.database.SQLite.packages_get") | ||||||
|     Rebuild.extract_packages(application, None, from_database=True) |     Rebuild.extract_packages(application, None, from_database=True) | ||||||
|     packages_mock.assert_called_once_with() |     packages_mock.assert_called_once_with(application.repository_id) | ||||||
|  | |||||||
| @ -37,8 +37,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository: | |||||||
|     """ |     """ | ||||||
|     args = _default_args(args) |     args = _default_args(args) | ||||||
|     mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) |     mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) | ||||||
|     application_mock = mocker.patch("ahriman.core.status.client.Client.status_get") |     application_mock = mocker.patch("ahriman.core.status.Client.status_get") | ||||||
|     packages_mock = mocker.patch("ahriman.core.status.client.Client.package_get", |     packages_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_get", | ||||||
|                                  return_value=[(package_ahriman, BuildStatus(BuildStatusEnum.Success)), |                                  return_value=[(package_ahriman, BuildStatus(BuildStatusEnum.Success)), | ||||||
|                                                (package_python_schedule, BuildStatus(BuildStatusEnum.Failed))]) |                                                (package_python_schedule, BuildStatus(BuildStatusEnum.Failed))]) | ||||||
|     check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") |     check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") | ||||||
| @ -63,8 +63,8 @@ def test_run_empty_exception(args: argparse.Namespace, configuration: Configurat | |||||||
|     args = _default_args(args) |     args = _default_args(args) | ||||||
|     args.exit_code = True |     args.exit_code = True | ||||||
|     mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) |     mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) | ||||||
|     mocker.patch("ahriman.core.status.client.Client.status_get") |     mocker.patch("ahriman.core.status.Client.status_get") | ||||||
|     mocker.patch("ahriman.core.status.client.Client.package_get", return_value=[]) |     mocker.patch("ahriman.core.status.local_client.LocalClient.package_get", return_value=[]) | ||||||
|     check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") |     check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") | ||||||
|  |  | ||||||
|     _, repository_id = configuration.check_loaded() |     _, repository_id = configuration.check_loaded() | ||||||
| @ -80,7 +80,7 @@ def test_run_verbose(args: argparse.Namespace, configuration: Configuration, rep | |||||||
|     args = _default_args(args) |     args = _default_args(args) | ||||||
|     args.info = True |     args.info = True | ||||||
|     mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) |     mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) | ||||||
|     mocker.patch("ahriman.core.status.client.Client.package_get", |     mocker.patch("ahriman.core.status.local_client.LocalClient.package_get", | ||||||
|                  return_value=[(package_ahriman, BuildStatus(BuildStatusEnum.Success))]) |                  return_value=[(package_ahriman, BuildStatus(BuildStatusEnum.Success))]) | ||||||
|     print_mock = mocker.patch("ahriman.core.formatters.Printer.print") |     print_mock = mocker.patch("ahriman.core.formatters.Printer.print") | ||||||
|  |  | ||||||
| @ -100,7 +100,7 @@ def test_run_with_package_filter(args: argparse.Namespace, configuration: Config | |||||||
|     args = _default_args(args) |     args = _default_args(args) | ||||||
|     args.package = [package_ahriman.base] |     args.package = [package_ahriman.base] | ||||||
|     mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) |     mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) | ||||||
|     packages_mock = mocker.patch("ahriman.core.status.client.Client.package_get", |     packages_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_get", | ||||||
|                                  return_value=[(package_ahriman, BuildStatus(BuildStatusEnum.Success))]) |                                  return_value=[(package_ahriman, BuildStatus(BuildStatusEnum.Success))]) | ||||||
|  |  | ||||||
|     _, repository_id = configuration.check_loaded() |     _, repository_id = configuration.check_loaded() | ||||||
| @ -115,7 +115,7 @@ def test_run_by_status(args: argparse.Namespace, configuration: Configuration, r | |||||||
|     """ |     """ | ||||||
|     args = _default_args(args) |     args = _default_args(args) | ||||||
|     args.status = BuildStatusEnum.Failed |     args.status = BuildStatusEnum.Failed | ||||||
|     mocker.patch("ahriman.core.status.client.Client.package_get", |     mocker.patch("ahriman.core.status.local_client.LocalClient.package_get", | ||||||
|                  return_value=[(package_ahriman, BuildStatus(BuildStatusEnum.Success)), |                  return_value=[(package_ahriman, BuildStatus(BuildStatusEnum.Success)), | ||||||
|                                (package_python_schedule, BuildStatus(BuildStatusEnum.Failed))]) |                                (package_python_schedule, BuildStatus(BuildStatusEnum.Failed))]) | ||||||
|     mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) |     mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) | ||||||
|  | |||||||
| @ -34,7 +34,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository: | |||||||
|     """ |     """ | ||||||
|     args = _default_args(args) |     args = _default_args(args) | ||||||
|     mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) |     mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) | ||||||
|     update_self_mock = mocker.patch("ahriman.core.status.client.Client.status_update") |     update_self_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.status_update") | ||||||
|  |  | ||||||
|     _, repository_id = configuration.check_loaded() |     _, repository_id = configuration.check_loaded() | ||||||
|     StatusUpdate.run(args, repository_id, configuration, report=False) |     StatusUpdate.run(args, repository_id, configuration, report=False) | ||||||
| @ -42,20 +42,17 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository: | |||||||
|  |  | ||||||
|  |  | ||||||
| def test_run_packages(args: argparse.Namespace, configuration: Configuration, repository: Repository, | def test_run_packages(args: argparse.Namespace, configuration: Configuration, repository: Repository, | ||||||
|                       package_ahriman: Package, mocker: MockerFixture) -> None: |                       mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must run command with specified packages |     must run command with specified packages | ||||||
|     """ |     """ | ||||||
|     args = _default_args(args) |     args = _default_args(args) | ||||||
|     args.package = [package_ahriman.base, "package"] |     args.package = ["package"] | ||||||
|     mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) |     mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) | ||||||
|     mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[package_ahriman]) |     update_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_update") | ||||||
|     add_mock = mocker.patch("ahriman.core.status.client.Client.package_add") |  | ||||||
|     update_mock = mocker.patch("ahriman.core.status.client.Client.package_update") |  | ||||||
|  |  | ||||||
|     _, repository_id = configuration.check_loaded() |     _, repository_id = configuration.check_loaded() | ||||||
|     StatusUpdate.run(args, repository_id, configuration, report=False) |     StatusUpdate.run(args, repository_id, configuration, report=False) | ||||||
|     add_mock.assert_called_once_with(package_ahriman, args.status) |  | ||||||
|     update_mock.assert_called_once_with("package", args.status) |     update_mock.assert_called_once_with("package", args.status) | ||||||
|  |  | ||||||
|  |  | ||||||
| @ -68,7 +65,7 @@ def test_run_remove(args: argparse.Namespace, configuration: Configuration, repo | |||||||
|     args.package = [package_ahriman.base] |     args.package = [package_ahriman.base] | ||||||
|     args.action = Action.Remove |     args.action = Action.Remove | ||||||
|     mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) |     mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) | ||||||
|     update_mock = mocker.patch("ahriman.core.status.client.Client.package_remove") |     update_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_remove") | ||||||
|  |  | ||||||
|     _, repository_id = configuration.check_loaded() |     _, repository_id = configuration.check_loaded() | ||||||
|     StatusUpdate.run(args, repository_id, configuration, report=False) |     StatusUpdate.run(args, repository_id, configuration, report=False) | ||||||
|  | |||||||
| @ -27,7 +27,7 @@ def test_path(args: argparse.Namespace, configuration: Configuration) -> None: | |||||||
|  |  | ||||||
|     with pytest.raises(ValueError): |     with pytest.raises(ValueError): | ||||||
|         args.lock = Path("/") |         args.lock = Path("/") | ||||||
|         Lock(args, repository_id, configuration).path  # special case |         assert Lock(args, repository_id, configuration).path  # special case | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_check_user(lock: Lock, mocker: MockerFixture) -> None: | def test_check_user(lock: Lock, mocker: MockerFixture) -> None: | ||||||
| @ -64,7 +64,7 @@ def test_check_version(lock: Lock, mocker: MockerFixture) -> None: | |||||||
|     """ |     """ | ||||||
|     must check version correctly |     must check version correctly | ||||||
|     """ |     """ | ||||||
|     mocker.patch("ahriman.core.status.client.Client.status_get", |     mocker.patch("ahriman.core.status.Client.status_get", | ||||||
|                  return_value=InternalStatus(status=BuildStatus(), version=__version__)) |                  return_value=InternalStatus(status=BuildStatus(), version=__version__)) | ||||||
|     logging_mock = mocker.patch("logging.Logger.warning") |     logging_mock = mocker.patch("logging.Logger.warning") | ||||||
|  |  | ||||||
| @ -76,7 +76,7 @@ def test_check_version_mismatch(lock: Lock, mocker: MockerFixture) -> None: | |||||||
|     """ |     """ | ||||||
|     must check mismatched version correctly |     must check mismatched version correctly | ||||||
|     """ |     """ | ||||||
|     mocker.patch("ahriman.core.status.client.Client.status_get", |     mocker.patch("ahriman.core.status.Client.status_get", | ||||||
|                  return_value=InternalStatus(status=BuildStatus(), version="version")) |                  return_value=InternalStatus(status=BuildStatus(), version="version")) | ||||||
|     logging_mock = mocker.patch("logging.Logger.warning") |     logging_mock = mocker.patch("logging.Logger.warning") | ||||||
|  |  | ||||||
| @ -184,7 +184,7 @@ def test_enter(lock: Lock, mocker: MockerFixture) -> None: | |||||||
|     watch_mock = mocker.patch("ahriman.application.lock.Lock.watch") |     watch_mock = mocker.patch("ahriman.application.lock.Lock.watch") | ||||||
|     clear_mock = mocker.patch("ahriman.application.lock.Lock.clear") |     clear_mock = mocker.patch("ahriman.application.lock.Lock.clear") | ||||||
|     create_mock = mocker.patch("ahriman.application.lock.Lock.create") |     create_mock = mocker.patch("ahriman.application.lock.Lock.create") | ||||||
|     update_status_mock = mocker.patch("ahriman.core.status.client.Client.status_update") |     update_status_mock = mocker.patch("ahriman.core.status.Client.status_update") | ||||||
|  |  | ||||||
|     with lock: |     with lock: | ||||||
|         pass |         pass | ||||||
| @ -203,9 +203,9 @@ def test_exit_with_exception(lock: Lock, mocker: MockerFixture) -> None: | |||||||
|     mocker.patch("ahriman.application.lock.Lock.check_user") |     mocker.patch("ahriman.application.lock.Lock.check_user") | ||||||
|     mocker.patch("ahriman.application.lock.Lock.clear") |     mocker.patch("ahriman.application.lock.Lock.clear") | ||||||
|     mocker.patch("ahriman.application.lock.Lock.create") |     mocker.patch("ahriman.application.lock.Lock.create") | ||||||
|     update_status_mock = mocker.patch("ahriman.core.status.client.Client.status_update") |     update_status_mock = mocker.patch("ahriman.core.status.Client.status_update") | ||||||
|  |  | ||||||
|     with pytest.raises(Exception): |     with pytest.raises(ValueError): | ||||||
|         with lock: |         with lock: | ||||||
|             raise Exception() |             raise ValueError() | ||||||
|     update_status_mock.assert_has_calls([MockCall(BuildStatusEnum.Building), MockCall(BuildStatusEnum.Failed)]) |     update_status_mock.assert_has_calls([MockCall(BuildStatusEnum.Building), MockCall(BuildStatusEnum.Failed)]) | ||||||
|  | |||||||
| @ -13,6 +13,7 @@ from ahriman.core.configuration import Configuration | |||||||
| from ahriman.core.database import SQLite | from ahriman.core.database import SQLite | ||||||
| from ahriman.core.repository import Repository | from ahriman.core.repository import Repository | ||||||
| from ahriman.core.spawn import Spawn | from ahriman.core.spawn import Spawn | ||||||
|  | from ahriman.core.status import Client | ||||||
| from ahriman.core.status.watcher import Watcher | from ahriman.core.status.watcher import Watcher | ||||||
| from ahriman.models.aur_package import AURPackage | from ahriman.models.aur_package import AURPackage | ||||||
| from ahriman.models.build_status import BuildStatus, BuildStatusEnum | from ahriman.models.build_status import BuildStatus, BuildStatusEnum | ||||||
| @ -276,6 +277,21 @@ def database(configuration: Configuration) -> SQLite: | |||||||
|     database.path.unlink() |     database.path.unlink() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.fixture | ||||||
|  | def local_client(database: SQLite, configuration: Configuration) -> Client: | ||||||
|  |     """ | ||||||
|  |     local status client | ||||||
|  |  | ||||||
|  |     Args: | ||||||
|  |         database(SQLite): database fixture | ||||||
|  |  | ||||||
|  |     Returns: | ||||||
|  |         Client: local status client test instance | ||||||
|  |     """ | ||||||
|  |     _, repository_id = configuration.check_loaded() | ||||||
|  |     return Client.load(repository_id, configuration, database, report=False) | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.fixture | @pytest.fixture | ||||||
| def package_ahriman(package_description_ahriman: PackageDescription, remote_source: RemoteSource) -> Package: | def package_ahriman(package_description_ahriman: PackageDescription, remote_source: RemoteSource) -> Package: | ||||||
|     """ |     """ | ||||||
| @ -559,15 +575,14 @@ def user() -> User: | |||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.fixture | @pytest.fixture | ||||||
| def watcher(repository_id: RepositoryId, database: SQLite) -> Watcher: | def watcher(local_client: Client) -> Watcher: | ||||||
|     """ |     """ | ||||||
|     package status watcher fixture |     package status watcher fixture | ||||||
|  |  | ||||||
|     Args: |     Args: | ||||||
|         repository_id(RepositoryId): repository identifier fixture |         local_client(Client): local status client fixture | ||||||
|         database(SQLite): database fixture |  | ||||||
|  |  | ||||||
|     Returns: |     Returns: | ||||||
|         Watcher: package status watcher test instance |         Watcher: package status watcher test instance | ||||||
|     """ |     """ | ||||||
|     return Watcher(repository_id, database) |     return Watcher(local_client) | ||||||
|  | |||||||
| @ -128,7 +128,7 @@ def test_database_copy_database_exist(pacman: Pacman, mocker: MockerFixture) -> | |||||||
|     copy_mock.assert_not_called() |     copy_mock.assert_not_called() | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_database_init(pacman: Pacman, configuration: Configuration) -> None: | def test_database_init(pacman: Pacman) -> None: | ||||||
|     """ |     """ | ||||||
|     must init database with settings |     must init database with settings | ||||||
|     """ |     """ | ||||||
| @ -184,13 +184,14 @@ def test_files(pacman: Pacman, package_ahriman: Package, mocker: MockerFixture, | |||||||
|     pacman.handle = handle_mock |     pacman.handle = handle_mock | ||||||
|     tarball = resource_path_root / "core" / "arcanisrepo.files.tar.gz" |     tarball = resource_path_root / "core" / "arcanisrepo.files.tar.gz" | ||||||
|  |  | ||||||
|  |     with tarfile.open(tarball, "r:gz") as fd: | ||||||
|         mocker.patch("pathlib.Path.is_file", return_value=True) |         mocker.patch("pathlib.Path.is_file", return_value=True) | ||||||
|     open_mock = mocker.patch("ahriman.core.alpm.pacman.tarfile.open", return_value=tarfile.open(tarball, "r:gz")) |         open_mock = mocker.patch("ahriman.core.alpm.pacman.tarfile.open", return_value=fd) | ||||||
|  |  | ||||||
|         files = pacman.files() |         files = pacman.files() | ||||||
|         assert len(files) == 2 |         assert len(files) == 2 | ||||||
|         assert package_ahriman.base in files |         assert package_ahriman.base in files | ||||||
|     assert Path("usr/bin/ahriman") in files[package_ahriman.base] |         assert "usr/bin/ahriman" in files[package_ahriman.base] | ||||||
|         open_mock.assert_called_once_with(pytest.helpers.anyvar(int), "r:gz") |         open_mock.assert_called_once_with(pytest.helpers.anyvar(int), "r:gz") | ||||||
|  |  | ||||||
|  |  | ||||||
| @ -205,8 +206,9 @@ def test_files_package(pacman: Pacman, package_ahriman: Package, mocker: MockerF | |||||||
|  |  | ||||||
|     tarball = resource_path_root / "core" / "arcanisrepo.files.tar.gz" |     tarball = resource_path_root / "core" / "arcanisrepo.files.tar.gz" | ||||||
|  |  | ||||||
|  |     with tarfile.open(tarball, "r:gz") as fd: | ||||||
|         mocker.patch("pathlib.Path.is_file", return_value=True) |         mocker.patch("pathlib.Path.is_file", return_value=True) | ||||||
|     mocker.patch("ahriman.core.alpm.pacman.tarfile.open", return_value=tarfile.open(tarball, "r:gz")) |         mocker.patch("ahriman.core.alpm.pacman.tarfile.open", return_value=fd) | ||||||
|  |  | ||||||
|         files = pacman.files(package_ahriman.base) |         files = pacman.files(package_ahriman.base) | ||||||
|         assert len(files) == 1 |         assert len(files) == 1 | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ from pytest_mock import MockerFixture | |||||||
| from unittest.mock import call as MockCall | from unittest.mock import call as MockCall | ||||||
|  |  | ||||||
| from ahriman.core.build_tools.task import Task | from ahriman.core.build_tools.task import Task | ||||||
| from ahriman.core.database import SQLite | from ahriman.models.pkgbuild_patch import PkgbuildPatch | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_build(task_ahriman: Task, mocker: MockerFixture) -> None: | def test_build(task_ahriman: Task, mocker: MockerFixture) -> None: | ||||||
| @ -91,18 +91,19 @@ def test_build_no_debug(task_ahriman: Task, mocker: MockerFixture) -> None: | |||||||
|     ]) |     ]) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_init(task_ahriman: Task, database: SQLite, mocker: MockerFixture) -> None: | def test_init(task_ahriman: Task, mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must copy tree instead of fetch |     must copy tree instead of fetch | ||||||
|     """ |     """ | ||||||
|  |     patches = [PkgbuildPatch("hash", "patch")] | ||||||
|     mocker.patch("ahriman.models.package.Package.from_build", return_value=task_ahriman.package) |     mocker.patch("ahriman.models.package.Package.from_build", return_value=task_ahriman.package) | ||||||
|     load_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.load", return_value="sha") |     load_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.load", return_value="sha") | ||||||
|  |  | ||||||
|     assert task_ahriman.init(Path("ahriman"), database, None) == "sha" |     assert task_ahriman.init(Path("ahriman"), patches, None) == "sha" | ||||||
|     load_mock.assert_called_once_with(Path("ahriman"), task_ahriman.package, [], task_ahriman.paths) |     load_mock.assert_called_once_with(Path("ahriman"), task_ahriman.package, patches, task_ahriman.paths) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_init_bump_pkgrel(task_ahriman: Task, database: SQLite, mocker: MockerFixture) -> None: | def test_init_bump_pkgrel(task_ahriman: Task, mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must bump pkgrel if it is same as provided |     must bump pkgrel if it is same as provided | ||||||
|     """ |     """ | ||||||
| @ -111,11 +112,11 @@ def test_init_bump_pkgrel(task_ahriman: Task, database: SQLite, mocker: MockerFi | |||||||
|     write_mock = mocker.patch("ahriman.models.pkgbuild_patch.PkgbuildPatch.write") |     write_mock = mocker.patch("ahriman.models.pkgbuild_patch.PkgbuildPatch.write") | ||||||
|  |  | ||||||
|     local = Path("ahriman") |     local = Path("ahriman") | ||||||
|     assert task_ahriman.init(local, database, task_ahriman.package.version) == "sha" |     assert task_ahriman.init(local, [], task_ahriman.package.version) == "sha" | ||||||
|     write_mock.assert_called_once_with(local / "PKGBUILD") |     write_mock.assert_called_once_with(local / "PKGBUILD") | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_init_bump_pkgrel_skip(task_ahriman: Task, database: SQLite, mocker: MockerFixture) -> None: | def test_init_bump_pkgrel_skip(task_ahriman: Task, mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must keep pkgrel if version is different from provided |     must keep pkgrel if version is different from provided | ||||||
|     """ |     """ | ||||||
| @ -123,5 +124,5 @@ def test_init_bump_pkgrel_skip(task_ahriman: Task, database: SQLite, mocker: Moc | |||||||
|     mocker.patch("ahriman.core.build_tools.sources.Sources.load", return_value="sha") |     mocker.patch("ahriman.core.build_tools.sources.Sources.load", return_value="sha") | ||||||
|     write_mock = mocker.patch("ahriman.models.pkgbuild_patch.PkgbuildPatch.write") |     write_mock = mocker.patch("ahriman.models.pkgbuild_patch.PkgbuildPatch.write") | ||||||
|  |  | ||||||
|     assert task_ahriman.init(Path("ahriman"), database, f"2:{task_ahriman.package.version}") == "sha" |     assert task_ahriman.init(Path("ahriman"), [], f"2:{task_ahriman.package.version}") == "sha" | ||||||
|     write_mock.assert_not_called() |     write_mock.assert_not_called() | ||||||
|  | |||||||
| @ -53,13 +53,3 @@ def test_changes_insert_remove_full(database: SQLite, package_ahriman: Package, | |||||||
|     assert database.changes_get(package_python_schedule.base).changes is None |     assert database.changes_get(package_python_schedule.base).changes is None | ||||||
|     assert database.changes_get( |     assert database.changes_get( | ||||||
|         package_ahriman.base, RepositoryId("i686", database._repository_id.name)).changes == "change2" |         package_ahriman.base, RepositoryId("i686", database._repository_id.name)).changes == "change2" | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_hashes_get(database: SQLite, package_ahriman: Package, package_python_schedule: Package) -> None: |  | ||||||
|     """ |  | ||||||
|     must return non-empty hashes for packages |  | ||||||
|     """ |  | ||||||
|     database.changes_insert(package_ahriman.base, Changes("sha1", "change1")) |  | ||||||
|     database.changes_insert(package_python_schedule.base, Changes()) |  | ||||||
|  |  | ||||||
|     assert database.hashes_get() == {package_ahriman.base: "sha1"} |  | ||||||
|  | |||||||
| @ -1,5 +1,3 @@ | |||||||
| from pathlib import Path |  | ||||||
|  |  | ||||||
| from ahriman.core.database import SQLite | from ahriman.core.database import SQLite | ||||||
| from ahriman.models.dependencies import Dependencies | from ahriman.models.dependencies import Dependencies | ||||||
| from ahriman.models.package import Package | from ahriman.models.package import Package | ||||||
| @ -10,16 +8,19 @@ def test_dependencies_insert_get(database: SQLite, package_ahriman: Package) -> | |||||||
|     """ |     """ | ||||||
|     must insert and get dependencies |     must insert and get dependencies | ||||||
|     """ |     """ | ||||||
|     dependencies = Dependencies(package_ahriman.base, {Path("usr/lib/python3.11/site-packages"): ["python"]}) |     dependencies = Dependencies({"usr/lib/python3.11/site-packages": ["python"]}) | ||||||
|     database.dependencies_insert(dependencies) |     database.dependencies_insert(package_ahriman.base, dependencies) | ||||||
|     assert database.dependencies_get(package_ahriman.base) == [dependencies] |     assert database.dependencies_get(package_ahriman.base) == {package_ahriman.base: dependencies} | ||||||
|  |  | ||||||
|     dependencies2 = Dependencies(package_ahriman.base, {Path("usr/lib/python3.11/site-packages"): ["python3"]}) |     dependencies2 = Dependencies({"usr/lib/python3.11/site-packages": ["python3"]}) | ||||||
|     database.dependencies_insert(dependencies2, RepositoryId("i686", database._repository_id.name)) |     database.dependencies_insert( | ||||||
|     assert database.dependencies_get() == [dependencies] |         package_ahriman.base, dependencies2, RepositoryId( | ||||||
|     assert database.dependencies_get(package_ahriman.base) == [dependencies] |             "i686", database._repository_id.name)) | ||||||
|     assert database.dependencies_get( |     assert database.dependencies_get() == {package_ahriman.base: dependencies} | ||||||
|         package_ahriman.base, RepositoryId("i686", database._repository_id.name)) == [dependencies2] |     assert database.dependencies_get(package_ahriman.base) == {package_ahriman.base: dependencies} | ||||||
|  |     assert database.dependencies_get(package_ahriman.base, RepositoryId("i686", database._repository_id.name)) == { | ||||||
|  |         package_ahriman.base: dependencies2 | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_dependencies_insert_remove(database: SQLite, package_ahriman: Package, | def test_dependencies_insert_remove(database: SQLite, package_ahriman: Package, | ||||||
| @ -27,23 +28,28 @@ def test_dependencies_insert_remove(database: SQLite, package_ahriman: Package, | |||||||
|     """ |     """ | ||||||
|     must remove dependencies for the package |     must remove dependencies for the package | ||||||
|     """ |     """ | ||||||
|     dependencies1 = Dependencies(package_ahriman.base, {Path("usr"): ["python"]}) |     dependencies1 = Dependencies({"usr": ["python"]}) | ||||||
|     database.dependencies_insert(dependencies1) |     database.dependencies_insert(package_ahriman.base, dependencies1) | ||||||
|     dependencies2 = Dependencies(package_python_schedule.base, {Path("usr"): ["filesystem"]}) |     dependencies2 = Dependencies({"usr": ["filesystem"]}) | ||||||
|     database.dependencies_insert(dependencies2) |     database.dependencies_insert(package_python_schedule.base, dependencies2) | ||||||
|     dependencies3 = Dependencies(package_ahriman.base, {Path("usr"): ["python3"]}) |     dependencies3 = Dependencies({"usr": ["python3"]}) | ||||||
|     database.dependencies_insert(dependencies3, RepositoryId("i686", database._repository_id.name)) |     database.dependencies_insert( | ||||||
|  |         package_ahriman.base, dependencies3, RepositoryId( | ||||||
|  |             "i686", database._repository_id.name)) | ||||||
|  |  | ||||||
|     assert database.dependencies_get() == [dependencies1, dependencies2] |     assert database.dependencies_get() == { | ||||||
|  |         package_ahriman.base: dependencies1, | ||||||
|  |         package_python_schedule.base: dependencies2, | ||||||
|  |     } | ||||||
|  |  | ||||||
|     database.dependencies_remove(package_ahriman.base) |     database.dependencies_remove(package_ahriman.base) | ||||||
|     assert database.dependencies_get(package_ahriman.base) == [] |     assert database.dependencies_get(package_ahriman.base) == {} | ||||||
|     assert database.dependencies_get(package_python_schedule.base) == [dependencies2] |     assert database.dependencies_get(package_python_schedule.base) == {package_python_schedule.base: dependencies2} | ||||||
|  |  | ||||||
|     # insert null |     # insert null | ||||||
|     database.dependencies_remove(package_ahriman.base, RepositoryId("i686", database._repository_id.name)) |     database.dependencies_remove(package_ahriman.base, RepositoryId("i686", database._repository_id.name)) | ||||||
|     assert database.dependencies_get(package_ahriman.base, RepositoryId("i686", database._repository_id.name)) == [] |     assert database.dependencies_get(package_ahriman.base, RepositoryId("i686", database._repository_id.name)) == {} | ||||||
|     assert database.dependencies_get(package_python_schedule.base) == [dependencies2] |     assert database.dependencies_get(package_python_schedule.base) == {package_python_schedule.base: dependencies2} | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_dependencies_insert_remove_full(database: SQLite, package_ahriman: Package, | def test_dependencies_insert_remove_full(database: SQLite, package_ahriman: Package, | ||||||
| @ -51,11 +57,11 @@ def test_dependencies_insert_remove_full(database: SQLite, package_ahriman: Pack | |||||||
|     """ |     """ | ||||||
|     must remove all dependencies for the repository |     must remove all dependencies for the repository | ||||||
|     """ |     """ | ||||||
|     database.dependencies_insert(Dependencies(package_ahriman.base, {Path("usr"): ["python"]})) |     database.dependencies_insert(package_ahriman.base, Dependencies({"usr": ["python"]})) | ||||||
|     database.dependencies_insert(Dependencies(package_python_schedule.base, {Path("usr"): ["filesystem"]})) |     database.dependencies_insert(package_python_schedule.base, Dependencies({"usr": ["filesystem"]})) | ||||||
|     database.dependencies_insert(Dependencies(package_ahriman.base, {Path("usr"): ["python3"]}), |     database.dependencies_insert(package_ahriman.base, Dependencies({"usr": ["python3"]}), | ||||||
|                                  RepositoryId("i686", database._repository_id.name)) |                                  RepositoryId("i686", database._repository_id.name)) | ||||||
|  |  | ||||||
|     database.dependencies_remove(None) |     database.dependencies_remove(None) | ||||||
|     assert database.dependencies_get() == [] |     assert database.dependencies_get() == {} | ||||||
|     assert database.dependencies_get(package_ahriman.base, RepositoryId("i686", database._repository_id.name)) |     assert database.dependencies_get(package_ahriman.base, RepositoryId("i686", database._repository_id.name)) | ||||||
|  | |||||||
| @ -5,10 +5,8 @@ from sqlite3 import Connection | |||||||
| from unittest.mock import call as MockCall | from unittest.mock import call as MockCall | ||||||
|  |  | ||||||
| from ahriman.core.database import SQLite | from ahriman.core.database import SQLite | ||||||
| from ahriman.models.build_status import BuildStatus, BuildStatusEnum | from ahriman.models.build_status import BuildStatus | ||||||
| from ahriman.models.package import Package | from ahriman.models.package import Package | ||||||
| from ahriman.models.package_source import PackageSource |  | ||||||
| from ahriman.models.remote_source import RemoteSource |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_remove_package_base(database: SQLite, connection: Connection) -> None: | def test_package_remove_package_base(database: SQLite, connection: Connection) -> None: | ||||||
| @ -66,14 +64,6 @@ def test_package_update_insert_packages_no_arch(database: SQLite, connection: Co | |||||||
|     connection.executemany(pytest.helpers.anyvar(str, strict=True), []) |     connection.executemany(pytest.helpers.anyvar(str, strict=True), []) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_update_insert_status(database: SQLite, connection: Connection, package_ahriman: Package) -> None: |  | ||||||
|     """ |  | ||||||
|     must insert single package status |  | ||||||
|     """ |  | ||||||
|     database._package_update_insert_status(connection, package_ahriman.base, BuildStatus(), database._repository_id) |  | ||||||
|     connection.execute(pytest.helpers.anyvar(str, strict=True), pytest.helpers.anyvar(int)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_packages_get_select_package_bases(database: SQLite, connection: Connection) -> None: | def test_packages_get_select_package_bases(database: SQLite, connection: Connection) -> None: | ||||||
|     """ |     """ | ||||||
|     must select all bases |     must select all bases | ||||||
| @ -131,16 +121,12 @@ def test_package_update(database: SQLite, package_ahriman: Package, mocker: Mock | |||||||
|     """ |     """ | ||||||
|     must update package status |     must update package status | ||||||
|     """ |     """ | ||||||
|     status = BuildStatus() |  | ||||||
|     insert_base_mock = mocker.patch("ahriman.core.database.SQLite._package_update_insert_base") |     insert_base_mock = mocker.patch("ahriman.core.database.SQLite._package_update_insert_base") | ||||||
|     insert_status_mock = mocker.patch("ahriman.core.database.SQLite._package_update_insert_status") |  | ||||||
|     insert_packages_mock = mocker.patch("ahriman.core.database.SQLite._package_update_insert_packages") |     insert_packages_mock = mocker.patch("ahriman.core.database.SQLite._package_update_insert_packages") | ||||||
|     remove_packages_mock = mocker.patch("ahriman.core.database.SQLite._package_remove_packages") |     remove_packages_mock = mocker.patch("ahriman.core.database.SQLite._package_remove_packages") | ||||||
|  |  | ||||||
|     database.package_update(package_ahriman, status) |     database.package_update(package_ahriman) | ||||||
|     insert_base_mock.assert_called_once_with(pytest.helpers.anyvar(int), package_ahriman, database._repository_id) |     insert_base_mock.assert_called_once_with(pytest.helpers.anyvar(int), package_ahriman, database._repository_id) | ||||||
|     insert_status_mock.assert_called_once_with(pytest.helpers.anyvar(int), package_ahriman.base, status, |  | ||||||
|                                                database._repository_id) |  | ||||||
|     insert_packages_mock.assert_called_once_with(pytest.helpers.anyvar(int), package_ahriman, |     insert_packages_mock.assert_called_once_with(pytest.helpers.anyvar(int), package_ahriman, | ||||||
|                                                  database._repository_id) |                                                  database._repository_id) | ||||||
|     remove_packages_mock.assert_called_once_with(pytest.helpers.anyvar(int), package_ahriman.base, |     remove_packages_mock.assert_called_once_with(pytest.helpers.anyvar(int), package_ahriman.base, | ||||||
| @ -168,7 +154,8 @@ def test_package_update_get(database: SQLite, package_ahriman: Package) -> None: | |||||||
|     must insert and retrieve package |     must insert and retrieve package | ||||||
|     """ |     """ | ||||||
|     status = BuildStatus() |     status = BuildStatus() | ||||||
|     database.package_update(package_ahriman, status) |     database.package_update(package_ahriman) | ||||||
|  |     database.status_update(package_ahriman.base, status) | ||||||
|     assert next((db_package, db_status) |     assert next((db_package, db_status) | ||||||
|                 for db_package, db_status in database.packages_get() |                 for db_package, db_status in database.packages_get() | ||||||
|                 if db_package.base == package_ahriman.base) == (package_ahriman, status) |                 if db_package.base == package_ahriman.base) == (package_ahriman, status) | ||||||
| @ -178,8 +165,7 @@ def test_package_update_remove_get(database: SQLite, package_ahriman: Package) - | |||||||
|     """ |     """ | ||||||
|     must insert, remove and retrieve package |     must insert, remove and retrieve package | ||||||
|     """ |     """ | ||||||
|     status = BuildStatus() |     database.package_update(package_ahriman) | ||||||
|     database.package_update(package_ahriman, status) |  | ||||||
|     database.package_remove(package_ahriman.base) |     database.package_remove(package_ahriman.base) | ||||||
|     assert not database.packages_get() |     assert not database.packages_get() | ||||||
|  |  | ||||||
| @ -188,28 +174,20 @@ def test_package_update_update(database: SQLite, package_ahriman: Package) -> No | |||||||
|     """ |     """ | ||||||
|     must perform update for existing package |     must perform update for existing package | ||||||
|     """ |     """ | ||||||
|     database.package_update(package_ahriman, BuildStatus()) |     database.package_update(package_ahriman) | ||||||
|     database.package_update(package_ahriman, BuildStatus(BuildStatusEnum.Failed)) |     package_ahriman.version = "1.0.0" | ||||||
|     assert next(db_status.status |     database.package_update(package_ahriman) | ||||||
|                 for db_package, db_status in database.packages_get() |     assert next(db_package.version | ||||||
|                 if db_package.base == package_ahriman.base) == BuildStatusEnum.Failed |                 for db_package, _ in database.packages_get() | ||||||
|  |                 if db_package.base == package_ahriman.base) == package_ahriman.version | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_remote_update_get(database: SQLite, package_ahriman: Package) -> None: | def test_status_update(database: SQLite, package_ahriman: Package) -> None: | ||||||
|     """ |     """ | ||||||
|     must insert and retrieve package remote |     must insert single package status | ||||||
|     """ |     """ | ||||||
|     database.package_base_update(package_ahriman) |     status = BuildStatus() | ||||||
|     assert database.remotes_get()[package_ahriman.base] == package_ahriman.remote |  | ||||||
|  |  | ||||||
|  |     database.package_update(package_ahriman, database._repository_id) | ||||||
| def test_remote_update_update(database: SQLite, package_ahriman: Package) -> None: |     database.status_update(package_ahriman.base, status, database._repository_id) | ||||||
|     """ |     assert database.packages_get(database._repository_id) == [(package_ahriman, status)] | ||||||
|     must perform package remote update for existing package |  | ||||||
|     """ |  | ||||||
|     database.package_base_update(package_ahriman) |  | ||||||
|     remote_source = RemoteSource(source=PackageSource.Repository) |  | ||||||
|     package_ahriman.remote = remote_source |  | ||||||
|  |  | ||||||
|     database.package_base_update(package_ahriman) |  | ||||||
|     assert database.remotes_get()[package_ahriman.base] == remote_source |  | ||||||
|  | |||||||
| @ -44,6 +44,7 @@ def test_package_clear(database: SQLite, mocker: MockerFixture) -> None: | |||||||
|     logs_mock = mocker.patch("ahriman.core.database.SQLite.logs_remove") |     logs_mock = mocker.patch("ahriman.core.database.SQLite.logs_remove") | ||||||
|     changes_mock = mocker.patch("ahriman.core.database.SQLite.changes_remove") |     changes_mock = mocker.patch("ahriman.core.database.SQLite.changes_remove") | ||||||
|     dependencies_mock = mocker.patch("ahriman.core.database.SQLite.dependencies_remove") |     dependencies_mock = mocker.patch("ahriman.core.database.SQLite.dependencies_remove") | ||||||
|  |     tree_clear_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_clear") | ||||||
|  |  | ||||||
|     database.package_clear("package") |     database.package_clear("package") | ||||||
|     build_queue_mock.assert_called_once_with("package") |     build_queue_mock.assert_called_once_with("package") | ||||||
| @ -51,3 +52,4 @@ def test_package_clear(database: SQLite, mocker: MockerFixture) -> None: | |||||||
|     logs_mock.assert_called_once_with("package", None) |     logs_mock.assert_called_once_with("package", None) | ||||||
|     changes_mock.assert_called_once_with("package") |     changes_mock.assert_called_once_with("package") | ||||||
|     dependencies_mock.assert_called_once_with("package") |     dependencies_mock.assert_called_once_with("package") | ||||||
|  |     tree_clear_mock.assert_called_once_with("package") | ||||||
|  | |||||||
| @ -5,15 +5,15 @@ from pytest_mock import MockerFixture | |||||||
| from unittest.mock import call as MockCall | from unittest.mock import call as MockCall | ||||||
|  |  | ||||||
| from ahriman.core.configuration import Configuration | from ahriman.core.configuration import Configuration | ||||||
| from ahriman.core.database import SQLite |  | ||||||
| from ahriman.core.exceptions import GitRemoteError | from ahriman.core.exceptions import GitRemoteError | ||||||
| from ahriman.core.gitremote.remote_push import RemotePush | from ahriman.core.gitremote.remote_push import RemotePush | ||||||
|  | from ahriman.core.status import Client | ||||||
| from ahriman.models.package import Package | from ahriman.models.package import Package | ||||||
| from ahriman.models.pkgbuild_patch import PkgbuildPatch | from ahriman.models.pkgbuild_patch import PkgbuildPatch | ||||||
| from ahriman.models.result import Result | from ahriman.models.result import Result | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_update(database: SQLite, configuration: Configuration, package_ahriman: Package, | def test_package_update(local_client: Client, configuration: Configuration, package_ahriman: Package, | ||||||
|                         mocker: MockerFixture) -> None: |                         mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must update single package |     must update single package | ||||||
| @ -27,9 +27,10 @@ def test_package_update(database: SQLite, configuration: Configuration, package_ | |||||||
|     rmtree_mock = mocker.patch("shutil.rmtree") |     rmtree_mock = mocker.patch("shutil.rmtree") | ||||||
|     unlink_mock = mocker.patch("pathlib.Path.unlink") |     unlink_mock = mocker.patch("pathlib.Path.unlink") | ||||||
|     fetch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.fetch") |     fetch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.fetch") | ||||||
|     patches_mock = mocker.patch("ahriman.core.database.SQLite.patches_get", return_value=[patch1, patch2]) |     patches_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_get", | ||||||
|  |                                 return_value=[patch1, patch2]) | ||||||
|     patches_write_mock = mocker.patch("ahriman.models.pkgbuild_patch.PkgbuildPatch.write") |     patches_write_mock = mocker.patch("ahriman.models.pkgbuild_patch.PkgbuildPatch.write") | ||||||
|     runner = RemotePush(database, configuration, "gitremote") |     runner = RemotePush(local_client, configuration, "gitremote") | ||||||
|  |  | ||||||
|     assert runner.package_update(package_ahriman, local) == package_ahriman.base |     assert runner.package_update(package_ahriman, local) == package_ahriman.base | ||||||
|     glob_mock.assert_called_once_with(".git*") |     glob_mock.assert_called_once_with(".git*") | ||||||
| @ -39,28 +40,28 @@ def test_package_update(database: SQLite, configuration: Configuration, package_ | |||||||
|     ]) |     ]) | ||||||
|     unlink_mock.assert_called_once_with() |     unlink_mock.assert_called_once_with() | ||||||
|     fetch_mock.assert_called_once_with(pytest.helpers.anyvar(int), package_ahriman.remote) |     fetch_mock.assert_called_once_with(pytest.helpers.anyvar(int), package_ahriman.remote) | ||||||
|     patches_mock.assert_called_once_with(package_ahriman.base) |     patches_mock.assert_called_once_with(package_ahriman.base, None) | ||||||
|     patches_write_mock.assert_has_calls([ |     patches_write_mock.assert_has_calls([ | ||||||
|         MockCall(local / package_ahriman.base / f"ahriman-{package_ahriman.base}.patch"), |         MockCall(local / package_ahriman.base / f"ahriman-{package_ahriman.base}.patch"), | ||||||
|         MockCall(local / package_ahriman.base / f"ahriman-{patch2.key}.patch"), |         MockCall(local / package_ahriman.base / f"ahriman-{patch2.key}.patch"), | ||||||
|     ]) |     ]) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_packages_update(database: SQLite, configuration: Configuration, result: Result, package_ahriman: Package, | def test_packages_update(local_client: Client, configuration: Configuration, result: Result, package_ahriman: Package, | ||||||
|                          mocker: MockerFixture) -> None: |                          mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must generate packages update |     must generate packages update | ||||||
|     """ |     """ | ||||||
|     update_mock = mocker.patch("ahriman.core.gitremote.remote_push.RemotePush.package_update", |     update_mock = mocker.patch("ahriman.core.gitremote.remote_push.RemotePush.package_update", | ||||||
|                                return_value=[package_ahriman.base]) |                                return_value=[package_ahriman.base]) | ||||||
|     runner = RemotePush(database, configuration, "gitremote") |     runner = RemotePush(local_client, configuration, "gitremote") | ||||||
|  |  | ||||||
|     local = Path("local") |     local = Path("local") | ||||||
|     assert list(runner.packages_update(result, local)) |     assert list(runner.packages_update(result, local)) | ||||||
|     update_mock.assert_called_once_with(package_ahriman, local) |     update_mock.assert_called_once_with(package_ahriman, local) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_run(database: SQLite, configuration: Configuration, result: Result, package_ahriman: Package, | def test_run(local_client: Client, configuration: Configuration, result: Result, package_ahriman: Package, | ||||||
|              mocker: MockerFixture) -> None: |              mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must push changes on result |     must push changes on result | ||||||
| @ -68,7 +69,7 @@ def test_run(database: SQLite, configuration: Configuration, result: Result, pac | |||||||
|     mocker.patch("ahriman.core.gitremote.remote_push.RemotePush.packages_update", return_value=[package_ahriman.base]) |     mocker.patch("ahriman.core.gitremote.remote_push.RemotePush.packages_update", return_value=[package_ahriman.base]) | ||||||
|     fetch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.fetch") |     fetch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.fetch") | ||||||
|     push_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.push") |     push_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.push") | ||||||
|     runner = RemotePush(database, configuration, "gitremote") |     runner = RemotePush(local_client, configuration, "gitremote") | ||||||
|  |  | ||||||
|     runner.run(result) |     runner.run(result) | ||||||
|     fetch_mock.assert_called_once_with(pytest.helpers.anyvar(int), runner.remote_source) |     fetch_mock.assert_called_once_with(pytest.helpers.anyvar(int), runner.remote_source) | ||||||
| @ -77,12 +78,12 @@ def test_run(database: SQLite, configuration: Configuration, result: Result, pac | |||||||
|     ) |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_run_failed(database: SQLite, configuration: Configuration, result: Result, mocker: MockerFixture) -> None: | def test_run_failed(local_client: Client, configuration: Configuration, result: Result, mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must reraise exception on error occurred |     must reraise exception on error occurred | ||||||
|     """ |     """ | ||||||
|     mocker.patch("ahriman.core.build_tools.sources.Sources.fetch", side_effect=Exception()) |     mocker.patch("ahriman.core.build_tools.sources.Sources.fetch", side_effect=Exception()) | ||||||
|     runner = RemotePush(database, configuration, "gitremote") |     runner = RemotePush(local_client, configuration, "gitremote") | ||||||
|  |  | ||||||
|     with pytest.raises(GitRemoteError): |     with pytest.raises(GitRemoteError): | ||||||
|         runner.run(result) |         runner.run(result) | ||||||
|  | |||||||
| @ -1,8 +1,8 @@ | |||||||
| from pytest_mock import MockerFixture | from pytest_mock import MockerFixture | ||||||
|  |  | ||||||
| from ahriman.core.configuration import Configuration | from ahriman.core.configuration import Configuration | ||||||
| from ahriman.core.database import SQLite |  | ||||||
| from ahriman.core.gitremote import RemotePushTrigger | from ahriman.core.gitremote import RemotePushTrigger | ||||||
|  | from ahriman.core.status import Client | ||||||
| from ahriman.models.package import Package | from ahriman.models.package import Package | ||||||
| from ahriman.models.result import Result | from ahriman.models.result import Result | ||||||
|  |  | ||||||
| @ -19,15 +19,15 @@ def test_configuration_sections(configuration: Configuration) -> None: | |||||||
|  |  | ||||||
|  |  | ||||||
| def test_on_result(configuration: Configuration, result: Result, package_ahriman: Package, | def test_on_result(configuration: Configuration, result: Result, package_ahriman: Package, | ||||||
|                    database: SQLite, mocker: MockerFixture) -> None: |                    local_client: Client, mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must push changes on result |     must push changes on result | ||||||
|     """ |     """ | ||||||
|     database_mock = mocker.patch("ahriman.core._Context.get", return_value=database) |     database_mock = mocker.patch("ahriman.core._Context.get", return_value=local_client) | ||||||
|     run_mock = mocker.patch("ahriman.core.gitremote.remote_push.RemotePush.run") |     run_mock = mocker.patch("ahriman.core.gitremote.remote_push.RemotePush.run") | ||||||
|     _, repository_id = configuration.check_loaded() |     _, repository_id = configuration.check_loaded() | ||||||
|     trigger = RemotePushTrigger(repository_id, configuration) |     trigger = RemotePushTrigger(repository_id, configuration) | ||||||
|  |  | ||||||
|     trigger.on_result(result, [package_ahriman]) |     trigger.on_result(result, [package_ahriman]) | ||||||
|     database_mock.assert_called_once_with(SQLite) |     database_mock.assert_called_once_with(Client) | ||||||
|     run_mock.assert_called_once_with(result) |     run_mock.assert_called_once_with(result) | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ def test_load(configuration: Configuration, mocker: MockerFixture) -> None: | |||||||
|     root.removeHandler(current_handler) |     root.removeHandler(current_handler) | ||||||
|  |  | ||||||
|     add_mock = mocker.patch("logging.Logger.addHandler") |     add_mock = mocker.patch("logging.Logger.addHandler") | ||||||
|     load_mock = mocker.patch("ahriman.core.status.client.Client.load") |     load_mock = mocker.patch("ahriman.core.status.Client.load") | ||||||
|  |  | ||||||
|     _, repository_id = configuration.check_loaded() |     _, repository_id = configuration.check_loaded() | ||||||
|     handler = HttpLogHandler.load(repository_id, configuration, report=False) |     handler = HttpLogHandler.load(repository_id, configuration, report=False) | ||||||
| @ -43,13 +43,13 @@ def test_emit(configuration: Configuration, log_record: logging.LogRecord, packa | |||||||
|     must emit log record to reporter |     must emit log record to reporter | ||||||
|     """ |     """ | ||||||
|     log_record_id = log_record.package_id = LogRecordId(package_ahriman.base, package_ahriman.version) |     log_record_id = log_record.package_id = LogRecordId(package_ahriman.base, package_ahriman.version) | ||||||
|     log_mock = mocker.patch("ahriman.core.status.client.Client.package_logs") |     log_mock = mocker.patch("ahriman.core.status.Client.package_logs_add") | ||||||
|  |  | ||||||
|     _, repository_id = configuration.check_loaded() |     _, repository_id = configuration.check_loaded() | ||||||
|     handler = HttpLogHandler(repository_id, configuration, report=False, suppress_errors=False) |     handler = HttpLogHandler(repository_id, configuration, report=False, suppress_errors=False) | ||||||
|  |  | ||||||
|     handler.emit(log_record) |     handler.emit(log_record) | ||||||
|     log_mock.assert_called_once_with(log_record_id, log_record) |     log_mock.assert_called_once_with(log_record_id, log_record.created, log_record.getMessage()) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_emit_failed(configuration: Configuration, log_record: logging.LogRecord, package_ahriman: Package, | def test_emit_failed(configuration: Configuration, log_record: logging.LogRecord, package_ahriman: Package, | ||||||
| @ -58,7 +58,7 @@ def test_emit_failed(configuration: Configuration, log_record: logging.LogRecord | |||||||
|     must call handle error on exception |     must call handle error on exception | ||||||
|     """ |     """ | ||||||
|     log_record.package_id = LogRecordId(package_ahriman.base, package_ahriman.version) |     log_record.package_id = LogRecordId(package_ahriman.base, package_ahriman.version) | ||||||
|     mocker.patch("ahriman.core.status.client.Client.package_logs", side_effect=Exception()) |     mocker.patch("ahriman.core.status.Client.package_logs_add", side_effect=Exception()) | ||||||
|     handle_error_mock = mocker.patch("logging.Handler.handleError") |     handle_error_mock = mocker.patch("logging.Handler.handleError") | ||||||
|     _, repository_id = configuration.check_loaded() |     _, repository_id = configuration.check_loaded() | ||||||
|     handler = HttpLogHandler(repository_id, configuration, report=False, suppress_errors=False) |     handler = HttpLogHandler(repository_id, configuration, report=False, suppress_errors=False) | ||||||
| @ -73,7 +73,7 @@ def test_emit_suppress_failed(configuration: Configuration, log_record: logging. | |||||||
|     must not call handle error on exception if suppress flag is set |     must not call handle error on exception if suppress flag is set | ||||||
|     """ |     """ | ||||||
|     log_record.package_id = LogRecordId(package_ahriman.base, package_ahriman.version) |     log_record.package_id = LogRecordId(package_ahriman.base, package_ahriman.version) | ||||||
|     mocker.patch("ahriman.core.status.client.Client.package_logs", side_effect=Exception()) |     mocker.patch("ahriman.core.status.Client.package_logs_add", side_effect=Exception()) | ||||||
|     handle_error_mock = mocker.patch("logging.Handler.handleError") |     handle_error_mock = mocker.patch("logging.Handler.handleError") | ||||||
|     _, repository_id = configuration.check_loaded() |     _, repository_id = configuration.check_loaded() | ||||||
|     handler = HttpLogHandler(repository_id, configuration, report=False, suppress_errors=True) |     handler = HttpLogHandler(repository_id, configuration, report=False, suppress_errors=True) | ||||||
| @ -86,7 +86,7 @@ def test_emit_skip(configuration: Configuration, log_record: logging.LogRecord, | |||||||
|     """ |     """ | ||||||
|     must skip log record posting if no package base set |     must skip log record posting if no package base set | ||||||
|     """ |     """ | ||||||
|     log_mock = mocker.patch("ahriman.core.status.client.Client.package_logs") |     log_mock = mocker.patch("ahriman.core.status.Client.package_logs_add") | ||||||
|  |  | ||||||
|     _, repository_id = configuration.check_loaded() |     _, repository_id = configuration.check_loaded() | ||||||
|     handler = HttpLogHandler(repository_id, configuration, report=False, suppress_errors=False) |     handler = HttpLogHandler(repository_id, configuration, report=False, suppress_errors=False) | ||||||
|  | |||||||
| @ -68,9 +68,9 @@ def test_in_package_context_failed(database: SQLite, package_ahriman: Package, m | |||||||
|     mocker.patch("ahriman.core.log.LazyLogging._package_logger_set") |     mocker.patch("ahriman.core.log.LazyLogging._package_logger_set") | ||||||
|     reset_mock = mocker.patch("ahriman.core.log.LazyLogging._package_logger_reset") |     reset_mock = mocker.patch("ahriman.core.log.LazyLogging._package_logger_reset") | ||||||
|  |  | ||||||
|     with pytest.raises(Exception): |     with pytest.raises(ValueError): | ||||||
|         with database.in_package_context(package_ahriman.base, ""): |         with database.in_package_context(package_ahriman.base, ""): | ||||||
|             raise Exception() |             raise ValueError() | ||||||
|  |  | ||||||
|     reset_mock.assert_called_once_with() |     reset_mock.assert_called_once_with() | ||||||
|  |  | ||||||
| @ -81,11 +81,3 @@ def test_logger(database: SQLite) -> None: | |||||||
|     """ |     """ | ||||||
|     assert database.logger |     assert database.logger | ||||||
|     assert database.logger.name == "ahriman.core.database.sqlite.SQLite" |     assert database.logger.name == "ahriman.core.database.sqlite.SQLite" | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_logger_attribute_error(database: SQLite) -> None: |  | ||||||
|     """ |  | ||||||
|     must raise AttributeError in case if no attribute found |  | ||||||
|     """ |  | ||||||
|     with pytest.raises(AttributeError): |  | ||||||
|         database.loggerrrr |  | ||||||
|  | |||||||
| @ -17,22 +17,21 @@ def test_process_build(executor: Executor, package_ahriman: Package, passwd: Any | |||||||
|     """ |     """ | ||||||
|     must run build process |     must run build process | ||||||
|     """ |     """ | ||||||
|     dependencies = Dependencies(package_ahriman.base) |  | ||||||
|     mocker.patch("ahriman.models.repository_paths.getpwuid", return_value=passwd) |     mocker.patch("ahriman.models.repository_paths.getpwuid", return_value=passwd) | ||||||
|     mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_ahriman]) |     mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_ahriman]) | ||||||
|     mocker.patch("ahriman.core.build_tools.task.Task.build", return_value=[Path(package_ahriman.base)]) |     mocker.patch("ahriman.core.build_tools.task.Task.build", return_value=[Path(package_ahriman.base)]) | ||||||
|     init_mock = mocker.patch("ahriman.core.build_tools.task.Task.init", return_value="sha") |     init_mock = mocker.patch("ahriman.core.build_tools.task.Task.init", return_value="sha") | ||||||
|     move_mock = mocker.patch("shutil.move") |     move_mock = mocker.patch("shutil.move") | ||||||
|     status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_building") |     status_client_mock = mocker.patch("ahriman.core.status.Client.set_building") | ||||||
|     commit_sha_mock = mocker.patch("ahriman.core.status.client.Client.package_changes_set") |     commit_sha_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_update") | ||||||
|     depends_on_mock = mocker.patch("ahriman.models.package_archive.PackageArchive.depends_on", |     depends_on_mock = mocker.patch("ahriman.models.package_archive.PackageArchive.depends_on", | ||||||
|                                    return_value=dependencies) |                                    return_value=Dependencies()) | ||||||
|     dependencies_mock = mocker.patch("ahriman.core.database.SQLite.dependencies_insert") |     dependencies_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_dependencies_update") | ||||||
|  |  | ||||||
|     executor.process_build([package_ahriman], Packagers("packager"), bump_pkgrel=False) |     executor.process_build([package_ahriman], Packagers("packager"), bump_pkgrel=False) | ||||||
|     init_mock.assert_called_once_with(pytest.helpers.anyvar(int), pytest.helpers.anyvar(int), None) |     init_mock.assert_called_once_with(pytest.helpers.anyvar(int), pytest.helpers.anyvar(int), None) | ||||||
|     depends_on_mock.assert_called_once_with() |     depends_on_mock.assert_called_once_with() | ||||||
|     dependencies_mock.assert_called_once_with(dependencies) |     dependencies_mock.assert_called_once_with(package_ahriman.base, Dependencies()) | ||||||
|     # must move files (once) |     # must move files (once) | ||||||
|     move_mock.assert_called_once_with(Path(package_ahriman.base), executor.paths.packages / package_ahriman.base) |     move_mock.assert_called_once_with(Path(package_ahriman.base), executor.paths.packages / package_ahriman.base) | ||||||
|     # must update status |     # must update status | ||||||
| @ -47,8 +46,6 @@ def test_process_build_bump_pkgrel(executor: Executor, package_ahriman: Package, | |||||||
|     mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_ahriman]) |     mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_ahriman]) | ||||||
|     mocker.patch("ahriman.core.build_tools.task.Task.build", return_value=[Path(package_ahriman.base)]) |     mocker.patch("ahriman.core.build_tools.task.Task.build", return_value=[Path(package_ahriman.base)]) | ||||||
|     mocker.patch("shutil.move") |     mocker.patch("shutil.move") | ||||||
|     mocker.patch("ahriman.core.status.client.Client.set_building") |  | ||||||
|     mocker.patch("ahriman.core.status.client.Client.package_changes_set") |  | ||||||
|     init_mock = mocker.patch("ahriman.core.build_tools.task.Task.init") |     init_mock = mocker.patch("ahriman.core.build_tools.task.Task.init") | ||||||
|  |  | ||||||
|     executor.process_build([package_ahriman], Packagers("packager"), bump_pkgrel=True) |     executor.process_build([package_ahriman], Packagers("packager"), bump_pkgrel=True) | ||||||
| @ -66,7 +63,7 @@ def test_process_build_failure(executor: Executor, package_ahriman: Package, moc | |||||||
|     mocker.patch("ahriman.core.build_tools.task.Task.build", return_value=[Path(package_ahriman.base)]) |     mocker.patch("ahriman.core.build_tools.task.Task.build", return_value=[Path(package_ahriman.base)]) | ||||||
|     mocker.patch("ahriman.core.build_tools.task.Task.init") |     mocker.patch("ahriman.core.build_tools.task.Task.init") | ||||||
|     mocker.patch("shutil.move", side_effect=Exception()) |     mocker.patch("shutil.move", side_effect=Exception()) | ||||||
|     status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_failed") |     status_client_mock = mocker.patch("ahriman.core.status.Client.set_failed") | ||||||
|  |  | ||||||
|     executor.process_build([package_ahriman]) |     executor.process_build([package_ahriman]) | ||||||
|     status_client_mock.assert_called_once_with(package_ahriman.base) |     status_client_mock.assert_called_once_with(package_ahriman.base) | ||||||
| @ -77,18 +74,14 @@ def test_process_remove_base(executor: Executor, package_ahriman: Package, mocke | |||||||
|     must run remove process for whole base |     must run remove process for whole base | ||||||
|     """ |     """ | ||||||
|     mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_ahriman]) |     mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_ahriman]) | ||||||
|     tree_clear_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_clear") |  | ||||||
|     repo_remove_mock = mocker.patch("ahriman.core.alpm.repo.Repo.remove") |     repo_remove_mock = mocker.patch("ahriman.core.alpm.repo.Repo.remove") | ||||||
|     database_mock = mocker.patch("ahriman.core.database.SQLite.package_clear") |     status_client_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_remove") | ||||||
|     status_client_mock = mocker.patch("ahriman.core.status.client.Client.package_remove") |  | ||||||
|  |  | ||||||
|     executor.process_remove([package_ahriman.base]) |     executor.process_remove([package_ahriman.base]) | ||||||
|     # must remove via alpm wrapper |     # must remove via alpm wrapper | ||||||
|     repo_remove_mock.assert_called_once_with( |     repo_remove_mock.assert_called_once_with( | ||||||
|         package_ahriman.base, package_ahriman.packages[package_ahriman.base].filepath) |         package_ahriman.base, package_ahriman.packages[package_ahriman.base].filepath) | ||||||
|     # must update status and remove package files |     # must update status and remove package files | ||||||
|     tree_clear_mock.assert_called_once_with(package_ahriman.base) |  | ||||||
|     database_mock.assert_called_once_with(package_ahriman.base) |  | ||||||
|     status_client_mock.assert_called_once_with(package_ahriman.base) |     status_client_mock.assert_called_once_with(package_ahriman.base) | ||||||
|  |  | ||||||
|  |  | ||||||
| @ -101,9 +94,7 @@ def test_process_remove_with_debug(executor: Executor, package_ahriman: Package, | |||||||
|         f"{package_ahriman.base}-debug": package_ahriman.packages[package_ahriman.base], |         f"{package_ahriman.base}-debug": package_ahriman.packages[package_ahriman.base], | ||||||
|     } |     } | ||||||
|     mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_ahriman]) |     mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_ahriman]) | ||||||
|     mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_clear") |     mocker.patch("ahriman.core.status.local_client.LocalClient.package_remove") | ||||||
|     mocker.patch("ahriman.core.database.SQLite.package_clear") |  | ||||||
|     mocker.patch("ahriman.core.status.client.Client.package_remove") |  | ||||||
|     repo_remove_mock = mocker.patch("ahriman.core.alpm.repo.Repo.remove") |     repo_remove_mock = mocker.patch("ahriman.core.alpm.repo.Repo.remove") | ||||||
|  |  | ||||||
|     executor.process_remove([package_ahriman.base]) |     executor.process_remove([package_ahriman.base]) | ||||||
| @ -121,7 +112,7 @@ def test_process_remove_base_multiple(executor: Executor, package_python_schedul | |||||||
|     """ |     """ | ||||||
|     mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_python_schedule]) |     mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_python_schedule]) | ||||||
|     repo_remove_mock = mocker.patch("ahriman.core.alpm.repo.Repo.remove") |     repo_remove_mock = mocker.patch("ahriman.core.alpm.repo.Repo.remove") | ||||||
|     status_client_mock = mocker.patch("ahriman.core.status.client.Client.package_remove") |     status_client_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_remove") | ||||||
|  |  | ||||||
|     executor.process_remove([package_python_schedule.base]) |     executor.process_remove([package_python_schedule.base]) | ||||||
|     # must remove via alpm wrapper |     # must remove via alpm wrapper | ||||||
| @ -140,7 +131,7 @@ def test_process_remove_base_single(executor: Executor, package_python_schedule: | |||||||
|     """ |     """ | ||||||
|     mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_python_schedule]) |     mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_python_schedule]) | ||||||
|     repo_remove_mock = mocker.patch("ahriman.core.alpm.repo.Repo.remove") |     repo_remove_mock = mocker.patch("ahriman.core.alpm.repo.Repo.remove") | ||||||
|     status_client_mock = mocker.patch("ahriman.core.status.client.Client.package_remove") |     status_client_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_remove") | ||||||
|  |  | ||||||
|     executor.process_remove(["python2-schedule"]) |     executor.process_remove(["python2-schedule"]) | ||||||
|     # must remove via alpm wrapper |     # must remove via alpm wrapper | ||||||
| @ -155,7 +146,7 @@ def test_process_remove_failed(executor: Executor, package_ahriman: Package, moc | |||||||
|     must suppress tree clear errors during package base removal |     must suppress tree clear errors during package base removal | ||||||
|     """ |     """ | ||||||
|     mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_ahriman]) |     mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_ahriman]) | ||||||
|     mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_clear", side_effect=Exception()) |     mocker.patch("ahriman.core.status.local_client.LocalClient.package_remove", side_effect=Exception()) | ||||||
|     executor.process_remove([package_ahriman.base]) |     executor.process_remove([package_ahriman.base]) | ||||||
|  |  | ||||||
|  |  | ||||||
| @ -186,7 +177,7 @@ def test_process_remove_unknown(executor: Executor, package_ahriman: Package, mo | |||||||
|     """ |     """ | ||||||
|     mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[]) |     mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[]) | ||||||
|     repo_remove_mock = mocker.patch("ahriman.core.alpm.repo.Repo.remove") |     repo_remove_mock = mocker.patch("ahriman.core.alpm.repo.Repo.remove") | ||||||
|     status_client_mock = mocker.patch("ahriman.core.status.client.Client.package_remove") |     status_client_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_remove") | ||||||
|  |  | ||||||
|     executor.process_remove([package_ahriman.base]) |     executor.process_remove([package_ahriman.base]) | ||||||
|     repo_remove_mock.assert_not_called() |     repo_remove_mock.assert_not_called() | ||||||
| @ -202,7 +193,7 @@ def test_process_update(executor: Executor, package_ahriman: Package, user: User | |||||||
|     move_mock = mocker.patch("shutil.move") |     move_mock = mocker.patch("shutil.move") | ||||||
|     repo_add_mock = mocker.patch("ahriman.core.alpm.repo.Repo.add") |     repo_add_mock = mocker.patch("ahriman.core.alpm.repo.Repo.add") | ||||||
|     sign_package_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process_sign_package", side_effect=lambda fn, _: [fn]) |     sign_package_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process_sign_package", side_effect=lambda fn, _: [fn]) | ||||||
|     status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_success") |     status_client_mock = mocker.patch("ahriman.core.status.Client.set_success") | ||||||
|     remove_mock = mocker.patch("ahriman.core.repository.executor.Executor.process_remove") |     remove_mock = mocker.patch("ahriman.core.repository.executor.Executor.process_remove") | ||||||
|     packager_mock = mocker.patch("ahriman.core.repository.executor.Executor.packager", return_value=user) |     packager_mock = mocker.patch("ahriman.core.repository.executor.Executor.packager", return_value=user) | ||||||
|     filepath = next(package.filepath for package in package_ahriman.packages.values()) |     filepath = next(package.filepath for package in package_ahriman.packages.values()) | ||||||
| @ -234,7 +225,7 @@ def test_process_update_group(executor: Executor, package_python_schedule: Packa | |||||||
|     mocker.patch("ahriman.core.repository.executor.Executor.load_archives", return_value=[package_python_schedule]) |     mocker.patch("ahriman.core.repository.executor.Executor.load_archives", return_value=[package_python_schedule]) | ||||||
|     mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_python_schedule]) |     mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_python_schedule]) | ||||||
|     repo_add_mock = mocker.patch("ahriman.core.alpm.repo.Repo.add") |     repo_add_mock = mocker.patch("ahriman.core.alpm.repo.Repo.add") | ||||||
|     status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_success") |     status_client_mock = mocker.patch("ahriman.core.status.Client.set_success") | ||||||
|     remove_mock = mocker.patch("ahriman.core.repository.executor.Executor.process_remove") |     remove_mock = mocker.patch("ahriman.core.repository.executor.Executor.process_remove") | ||||||
|  |  | ||||||
|     executor.process_update([package.filepath for package in package_python_schedule.packages.values()]) |     executor.process_update([package.filepath for package in package_python_schedule.packages.values()]) | ||||||
| @ -284,7 +275,7 @@ def test_process_update_failed(executor: Executor, package_ahriman: Package, moc | |||||||
|     mocker.patch("shutil.move", side_effect=Exception()) |     mocker.patch("shutil.move", side_effect=Exception()) | ||||||
|     mocker.patch("ahriman.core.repository.executor.Executor.load_archives", return_value=[package_ahriman]) |     mocker.patch("ahriman.core.repository.executor.Executor.load_archives", return_value=[package_ahriman]) | ||||||
|     mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_ahriman]) |     mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_ahriman]) | ||||||
|     status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_failed") |     status_client_mock = mocker.patch("ahriman.core.status.Client.set_failed") | ||||||
|  |  | ||||||
|     executor.process_update([package.filepath for package in package_ahriman.packages.values()]) |     executor.process_update([package.filepath for package in package_ahriman.packages.values()]) | ||||||
|     status_client_mock.assert_called_once_with(package_ahriman.base) |     status_client_mock.assert_called_once_with(package_ahriman.base) | ||||||
|  | |||||||
| @ -21,9 +21,9 @@ def test_load_archives(package_ahriman: Package, package_python_schedule: Packag | |||||||
|         for package, props in package_python_schedule.packages.items() |         for package, props in package_python_schedule.packages.items() | ||||||
|     ] + [package_ahriman] |     ] + [package_ahriman] | ||||||
|     mocker.patch("ahriman.models.package.Package.from_archive", side_effect=single_packages) |     mocker.patch("ahriman.models.package.Package.from_archive", side_effect=single_packages) | ||||||
|     mocker.patch("ahriman.core.database.SQLite.remotes_get", return_value={ |     mocker.patch("ahriman.core.status.local_client.LocalClient.package_get", return_value=[ | ||||||
|         package_ahriman.base: package_ahriman.base |         (package_ahriman, None), | ||||||
|     }) |     ]) | ||||||
|  |  | ||||||
|     packages = package_info.load_archives([Path("a.pkg.tar.xz"), Path("b.pkg.tar.xz"), Path("c.pkg.tar.xz")]) |     packages = package_info.load_archives([Path("a.pkg.tar.xz"), Path("b.pkg.tar.xz"), Path("c.pkg.tar.xz")]) | ||||||
|     assert len(packages) == 2 |     assert len(packages) == 2 | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ from ahriman.core.configuration import Configuration | |||||||
| from ahriman.core.database import SQLite | from ahriman.core.database import SQLite | ||||||
| from ahriman.core.repository import Repository | from ahriman.core.repository import Repository | ||||||
| from ahriman.core.sign.gpg import GPG | from ahriman.core.sign.gpg import GPG | ||||||
|  | from ahriman.core.status import Client | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_load(configuration: Configuration, database: SQLite, mocker: MockerFixture) -> None: | def test_load(configuration: Configuration, database: SQLite, mocker: MockerFixture) -> None: | ||||||
| @ -32,5 +33,6 @@ def test_set_context(configuration: Configuration, database: SQLite, mocker: Moc | |||||||
|         MockCall(Configuration, instance.configuration), |         MockCall(Configuration, instance.configuration), | ||||||
|         MockCall(Pacman, instance.pacman), |         MockCall(Pacman, instance.pacman), | ||||||
|         MockCall(GPG, instance.sign), |         MockCall(GPG, instance.sign), | ||||||
|  |         MockCall(Client, instance.reporter), | ||||||
|         MockCall(Repository, instance), |         MockCall(Repository, instance), | ||||||
|     ]) |     ]) | ||||||
|  | |||||||
| @ -20,7 +20,7 @@ def test_updates_aur(update_handler: UpdateHandler, package_ahriman: Package, | |||||||
|     packages_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", |     packages_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", | ||||||
|                                  return_value=[package_ahriman]) |                                  return_value=[package_ahriman]) | ||||||
|     mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman) |     mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman) | ||||||
|     status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_pending") |     status_client_mock = mocker.patch("ahriman.core.status.Client.set_pending") | ||||||
|     package_is_outdated_mock = mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True) |     package_is_outdated_mock = mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True) | ||||||
|  |  | ||||||
|     assert update_handler.updates_aur([], vcs=True) == [package_ahriman] |     assert update_handler.updates_aur([], vcs=True) == [package_ahriman] | ||||||
| @ -41,7 +41,7 @@ def test_updates_aur_official(update_handler: UpdateHandler, package_ahriman: Pa | |||||||
|     mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman]) |     mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman]) | ||||||
|     mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True) |     mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True) | ||||||
|     mocker.patch("ahriman.models.package.Package.from_official", return_value=package_ahriman) |     mocker.patch("ahriman.models.package.Package.from_official", return_value=package_ahriman) | ||||||
|     status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_pending") |     status_client_mock = mocker.patch("ahriman.core.status.Client.set_pending") | ||||||
|  |  | ||||||
|     assert update_handler.updates_aur([], vcs=True) == [package_ahriman] |     assert update_handler.updates_aur([], vcs=True) == [package_ahriman] | ||||||
|     status_client_mock.assert_called_once_with(package_ahriman.base) |     status_client_mock.assert_called_once_with(package_ahriman.base) | ||||||
| @ -54,7 +54,7 @@ def test_updates_aur_failed(update_handler: UpdateHandler, package_ahriman: Pack | |||||||
|     """ |     """ | ||||||
|     mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman]) |     mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman]) | ||||||
|     mocker.patch("ahriman.models.package.Package.from_aur", side_effect=Exception()) |     mocker.patch("ahriman.models.package.Package.from_aur", side_effect=Exception()) | ||||||
|     status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_failed") |     status_client_mock = mocker.patch("ahriman.core.status.Client.set_failed") | ||||||
|  |  | ||||||
|     update_handler.updates_aur([], vcs=True) |     update_handler.updates_aur([], vcs=True) | ||||||
|     status_client_mock.assert_called_once_with(package_ahriman.base) |     status_client_mock.assert_called_once_with(package_ahriman.base) | ||||||
| @ -141,7 +141,7 @@ def test_updates_aur_load_by_package_failed(update_handler: UpdateHandler, packa | |||||||
|     """ |     """ | ||||||
|     mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman]) |     mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman]) | ||||||
|     mocker.patch("ahriman.models.package.Package.from_aur", side_effect=UnknownPackageError(package_ahriman.base)) |     mocker.patch("ahriman.models.package.Package.from_aur", side_effect=UnknownPackageError(package_ahriman.base)) | ||||||
|     mocker.patch("ahriman.core.status.client.Client.set_failed") |     mocker.patch("ahriman.core.status.Client.set_failed") | ||||||
|  |  | ||||||
|     update_handler.updates_aur([], vcs=True) |     update_handler.updates_aur([], vcs=True) | ||||||
|  |  | ||||||
| @ -153,13 +153,14 @@ def test_updates_dependencies(update_handler: UpdateHandler, package_ahriman: Pa | |||||||
|     """ |     """ | ||||||
|     packages_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", |     packages_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", | ||||||
|                                  return_value=[package_ahriman, package_python_schedule]) |                                  return_value=[package_ahriman, package_python_schedule]) | ||||||
|     dependencies = [ |     dependencies = { | ||||||
|         Dependencies(package_ahriman.base, {Path("usr/lib/python3.11/site-packages"): ["python"]}), |         package_ahriman.base: Dependencies({"usr/lib/python3.11/site-packages": ["python"]}), | ||||||
|         Dependencies(package_python_schedule.base, {Path("usr/lib/python3.12/site-packages"): ["python"]}), |         package_python_schedule.base: Dependencies({"usr/lib/python3.12/site-packages": ["python"]}), | ||||||
|     ] |     } | ||||||
|     mocker.patch("ahriman.core.database.SQLite.dependencies_get", return_value=dependencies) |     mocker.patch("ahriman.core.status.local_client.LocalClient.package_dependencies_get", | ||||||
|  |                  side_effect=lambda base: dependencies[base]) | ||||||
|     mocker.patch("ahriman.core.alpm.pacman.Pacman.files", |     mocker.patch("ahriman.core.alpm.pacman.Pacman.files", | ||||||
|                  return_value={"python": {Path("usr/lib/python3.12/site-packages")}}) |                  return_value={"python": {"usr/lib/python3.12/site-packages"}}) | ||||||
|  |  | ||||||
|     assert update_handler.updates_dependencies(["filter"]) == [package_ahriman] |     assert update_handler.updates_dependencies(["filter"]) == [package_ahriman] | ||||||
|     packages_mock.assert_called_once_with(["filter"]) |     packages_mock.assert_called_once_with(["filter"]) | ||||||
| @ -171,9 +172,10 @@ def test_updates_dependencies_skip_unknown(update_handler: UpdateHandler, packag | |||||||
|     must skip unknown package dependencies |     must skip unknown package dependencies | ||||||
|     """ |     """ | ||||||
|     mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman]) |     mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman]) | ||||||
|     mocker.patch("ahriman.core.database.SQLite.dependencies_get", return_value=[]) |     mocker.patch("ahriman.core.status.local_client.LocalClient.package_dependencies_get", | ||||||
|  |                  return_value=Dependencies()) | ||||||
|     mocker.patch("ahriman.core.alpm.pacman.Pacman.files", |     mocker.patch("ahriman.core.alpm.pacman.Pacman.files", | ||||||
|                  return_value={"python": {Path("usr/lib/python3.12/site-packages")}}) |                  return_value={"python": {"usr/lib/python3.12/site-packages"}}) | ||||||
|  |  | ||||||
|     assert update_handler.updates_dependencies(["filter"]) == [] |     assert update_handler.updates_dependencies(["filter"]) == [] | ||||||
|  |  | ||||||
| @ -184,13 +186,11 @@ def test_updates_dependencies_partial(update_handler: UpdateHandler, package_ahr | |||||||
|     must skip broken dependencies update if at least one package provides file |     must skip broken dependencies update if at least one package provides file | ||||||
|     """ |     """ | ||||||
|     mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman]) |     mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman]) | ||||||
|     dependencies = [ |     dependencies = Dependencies({"usr": ["filesystem", "python"]}) | ||||||
|         Dependencies(package_ahriman.base, {Path("usr"): ["filesystem", "python"]}), |     mocker.patch("ahriman.core.status.local_client.LocalClient.package_dependencies_get", return_value=dependencies) | ||||||
|     ] |  | ||||||
|     mocker.patch("ahriman.core.database.SQLite.dependencies_get", return_value=dependencies) |  | ||||||
|     mocker.patch("ahriman.core.alpm.pacman.Pacman.files", return_value={ |     mocker.patch("ahriman.core.alpm.pacman.Pacman.files", return_value={ | ||||||
|         "filesystem": {Path("usr")}, |         "filesystem": {"usr"}, | ||||||
|         "python": {Path("usr")}, |         "python": {"usr"}, | ||||||
|     }) |     }) | ||||||
|  |  | ||||||
|     assert update_handler.updates_dependencies(["filter"]) == [] |     assert update_handler.updates_dependencies(["filter"]) == [] | ||||||
| @ -204,7 +204,7 @@ def test_updates_local(update_handler: UpdateHandler, package_ahriman: Package, | |||||||
|     mocker.patch("pathlib.Path.iterdir", return_value=[Path(package_ahriman.base)]) |     mocker.patch("pathlib.Path.iterdir", return_value=[Path(package_ahriman.base)]) | ||||||
|     fetch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.fetch") |     fetch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.fetch") | ||||||
|     package_load_mock = mocker.patch("ahriman.models.package.Package.from_build", return_value=package_ahriman) |     package_load_mock = mocker.patch("ahriman.models.package.Package.from_build", return_value=package_ahriman) | ||||||
|     status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_pending") |     status_client_mock = mocker.patch("ahriman.core.status.Client.set_pending") | ||||||
|     package_is_outdated_mock = mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True) |     package_is_outdated_mock = mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True) | ||||||
|  |  | ||||||
|     assert update_handler.updates_local(vcs=True) == [package_ahriman] |     assert update_handler.updates_local(vcs=True) == [package_ahriman] | ||||||
| @ -280,7 +280,7 @@ def test_updates_manual_status_known(update_handler: UpdateHandler, package_ahri | |||||||
|     """ |     """ | ||||||
|     mocker.patch("ahriman.core.database.SQLite.build_queue_get", return_value=[package_ahriman]) |     mocker.patch("ahriman.core.database.SQLite.build_queue_get", return_value=[package_ahriman]) | ||||||
|     mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman]) |     mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman]) | ||||||
|     status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_pending") |     status_client_mock = mocker.patch("ahriman.core.status.Client.set_pending") | ||||||
|  |  | ||||||
|     update_handler.updates_manual() |     update_handler.updates_manual() | ||||||
|     status_client_mock.assert_called_once_with(package_ahriman.base) |     status_client_mock.assert_called_once_with(package_ahriman.base) | ||||||
| @ -293,7 +293,7 @@ def test_updates_manual_status_unknown(update_handler: UpdateHandler, package_ah | |||||||
|     """ |     """ | ||||||
|     mocker.patch("ahriman.core.database.SQLite.build_queue_get", return_value=[package_ahriman]) |     mocker.patch("ahriman.core.database.SQLite.build_queue_get", return_value=[package_ahriman]) | ||||||
|     mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[]) |     mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[]) | ||||||
|     status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_unknown") |     status_client_mock = mocker.patch("ahriman.core.status.Client.set_unknown") | ||||||
|  |  | ||||||
|     update_handler.updates_manual() |     update_handler.updates_manual() | ||||||
|     status_client_mock.assert_called_once_with(package_ahriman) |     status_client_mock.assert_called_once_with(package_ahriman) | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| import pytest | import pytest | ||||||
|  |  | ||||||
| from ahriman.core.configuration import Configuration | from ahriman.core.configuration import Configuration | ||||||
| from ahriman.core.status.client import Client | from ahriman.core.status import Client | ||||||
| from ahriman.core.status.web_client import WebClient | from ahriman.core.status.web_client import WebClient | ||||||
|  |  | ||||||
|  |  | ||||||
|  | |||||||
| @ -1,26 +1,39 @@ | |||||||
| import logging | import logging | ||||||
|  | import pytest | ||||||
|  |  | ||||||
| from pytest_mock import MockerFixture | from pytest_mock import MockerFixture | ||||||
|  |  | ||||||
| from ahriman.core.configuration import Configuration | from ahriman.core.configuration import Configuration | ||||||
| from ahriman.core.status.client import Client | from ahriman.core.database import SQLite | ||||||
|  | from ahriman.core.status import Client | ||||||
|  | from ahriman.core.status.local_client import LocalClient | ||||||
| from ahriman.core.status.web_client import WebClient | from ahriman.core.status.web_client import WebClient | ||||||
| from ahriman.models.build_status import BuildStatus, BuildStatusEnum | from ahriman.models.build_status import BuildStatus, BuildStatusEnum | ||||||
| from ahriman.models.changes import Changes | from ahriman.models.changes import Changes | ||||||
|  | from ahriman.models.dependencies import Dependencies | ||||||
| from ahriman.models.internal_status import InternalStatus | from ahriman.models.internal_status import InternalStatus | ||||||
| from ahriman.models.log_record_id import LogRecordId | from ahriman.models.log_record_id import LogRecordId | ||||||
| from ahriman.models.package import Package | from ahriman.models.package import Package | ||||||
|  | from ahriman.models.pkgbuild_patch import PkgbuildPatch | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_load_dummy_client(configuration: Configuration) -> None: | def test_load_dummy_client(configuration: Configuration) -> None: | ||||||
|  |     """ | ||||||
|  |     must load dummy client if no settings and database set | ||||||
|  |     """ | ||||||
|  |     _, repository_id = configuration.check_loaded() | ||||||
|  |     assert isinstance(Client.load(repository_id, configuration, report=True), Client) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_load_local_client(configuration: Configuration, database: SQLite) -> None: | ||||||
|     """ |     """ | ||||||
|     must load dummy client if no settings set |     must load dummy client if no settings set | ||||||
|     """ |     """ | ||||||
|     _, repository_id = configuration.check_loaded() |     _, repository_id = configuration.check_loaded() | ||||||
|     assert not isinstance(Client.load(repository_id, configuration, report=True), WebClient) |     assert isinstance(Client.load(repository_id, configuration, database, report=True), LocalClient) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_load_dummy_client_disabled(configuration: Configuration) -> None: | def test_load_local_client_disabled(configuration: Configuration, database: SQLite) -> None: | ||||||
|     """ |     """ | ||||||
|     must load dummy client if report is set to False |     must load dummy client if report is set to False | ||||||
|     """ |     """ | ||||||
| @ -28,10 +41,10 @@ def test_load_dummy_client_disabled(configuration: Configuration) -> None: | |||||||
|     configuration.set_option("web", "port", "8080") |     configuration.set_option("web", "port", "8080") | ||||||
|  |  | ||||||
|     _, repository_id = configuration.check_loaded() |     _, repository_id = configuration.check_loaded() | ||||||
|     assert not isinstance(Client.load(repository_id, configuration, report=False), WebClient) |     assert isinstance(Client.load(repository_id, configuration, database, report=False), LocalClient) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_load_dummy_client_disabled_in_configuration(configuration: Configuration) -> None: | def test_load_local_client_disabled_in_configuration(configuration: Configuration, database: SQLite) -> None: | ||||||
|     """ |     """ | ||||||
|     must load dummy client if disabled in configuration |     must load dummy client if disabled in configuration | ||||||
|     """ |     """ | ||||||
| @ -40,19 +53,19 @@ def test_load_dummy_client_disabled_in_configuration(configuration: Configuratio | |||||||
|     configuration.set_option("status", "enabled", "no") |     configuration.set_option("status", "enabled", "no") | ||||||
|  |  | ||||||
|     _, repository_id = configuration.check_loaded() |     _, repository_id = configuration.check_loaded() | ||||||
|     assert not isinstance(Client.load(repository_id, configuration, report=True), WebClient) |     assert isinstance(Client.load(repository_id, configuration, database, report=True), LocalClient) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_load_full_client_from_address(configuration: Configuration) -> None: | def test_load_web_client_from_address(configuration: Configuration, database: SQLite) -> None: | ||||||
|     """ |     """ | ||||||
|     must load full client by using address |     must load full client by using address | ||||||
|     """ |     """ | ||||||
|     configuration.set_option("status", "address", "http://localhost:8080") |     configuration.set_option("status", "address", "http://localhost:8080") | ||||||
|     _, repository_id = configuration.check_loaded() |     _, repository_id = configuration.check_loaded() | ||||||
|     assert isinstance(Client.load(repository_id, configuration, report=True), WebClient) |     assert isinstance(Client.load(repository_id, configuration, database, report=True), WebClient) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_load_full_client_from_legacy_host(configuration: Configuration) -> None: | def test_load_web_client_from_legacy_host(configuration: Configuration, database: SQLite) -> None: | ||||||
|     """ |     """ | ||||||
|     must load full client if host and port settings set |     must load full client if host and port settings set | ||||||
|     """ |     """ | ||||||
| @ -60,82 +73,144 @@ def test_load_full_client_from_legacy_host(configuration: Configuration) -> None | |||||||
|     configuration.set_option("web", "port", "8080") |     configuration.set_option("web", "port", "8080") | ||||||
|  |  | ||||||
|     _, repository_id = configuration.check_loaded() |     _, repository_id = configuration.check_loaded() | ||||||
|     assert isinstance(Client.load(repository_id, configuration, report=True), WebClient) |     assert isinstance(Client.load(repository_id, configuration, database, report=True), WebClient) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_load_full_client_from_legacy_address(configuration: Configuration) -> None: | def test_load_web_client_from_legacy_address(configuration: Configuration, database: SQLite) -> None: | ||||||
|     """ |     """ | ||||||
|     must load full client by using legacy address |     must load full client by using legacy address | ||||||
|     """ |     """ | ||||||
|     configuration.set_option("web", "address", "http://localhost:8080") |     configuration.set_option("web", "address", "http://localhost:8080") | ||||||
|     _, repository_id = configuration.check_loaded() |     _, repository_id = configuration.check_loaded() | ||||||
|     assert isinstance(Client.load(repository_id, configuration, report=True), WebClient) |     assert isinstance(Client.load(repository_id, configuration, database, report=True), WebClient) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_load_full_client_from_legacy_unix_socket(configuration: Configuration) -> None: | def test_load_web_client_from_legacy_unix_socket(configuration: Configuration, database: SQLite) -> None: | ||||||
|     """ |     """ | ||||||
|     must load full client by using unix socket |     must load full client by using unix socket | ||||||
|     """ |     """ | ||||||
|     configuration.set_option("web", "unix_socket", "/var/lib/ahriman/ahriman-web.sock") |     configuration.set_option("web", "unix_socket", "/var/lib/ahriman/ahriman-web.sock") | ||||||
|     _, repository_id = configuration.check_loaded() |     _, repository_id = configuration.check_loaded() | ||||||
|     assert isinstance(Client.load(repository_id, configuration, report=True), WebClient) |     assert isinstance(Client.load(repository_id, configuration, database, report=True), WebClient) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_add(client: Client, package_ahriman: Package) -> None: |  | ||||||
|     """ |  | ||||||
|     must process package addition without errors |  | ||||||
|     """ |  | ||||||
|     client.package_add(package_ahriman, BuildStatusEnum.Unknown) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_changes_get(client: Client, package_ahriman: Package) -> None: | def test_package_changes_get(client: Client, package_ahriman: Package) -> None: | ||||||
|     """ |     """ | ||||||
|     must return null changes |     must raise not implemented on package changes request | ||||||
|     """ |     """ | ||||||
|     assert client.package_changes_get(package_ahriman.base) == Changes() |     with pytest.raises(NotImplementedError): | ||||||
|  |         client.package_changes_get(package_ahriman.base) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_changes_set(client: Client, package_ahriman: Package) -> None: | def test_package_changes_update(client: Client, package_ahriman: Package) -> None: | ||||||
|     """ |     """ | ||||||
|     must process changes update without errors |     must raise not implemented on changes update | ||||||
|     """ |     """ | ||||||
|     client.package_changes_set(package_ahriman.base, Changes()) |     with pytest.raises(NotImplementedError): | ||||||
|  |         client.package_changes_update(package_ahriman.base, Changes()) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_dependencies_get(client: Client, package_ahriman: Package) -> None: | ||||||
|  |     """ | ||||||
|  |     must raise not implemented on package dependencies request | ||||||
|  |     """ | ||||||
|  |     with pytest.raises(NotImplementedError): | ||||||
|  |         client.package_dependencies_get(package_ahriman.base) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_dependencies_update(client: Client, package_ahriman: Package) -> None: | ||||||
|  |     """ | ||||||
|  |     must raise not implemented on dependencies update | ||||||
|  |     """ | ||||||
|  |     with pytest.raises(NotImplementedError): | ||||||
|  |         client.package_dependencies_update(package_ahriman.base, Dependencies()) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_get(client: Client, package_ahriman: Package) -> None: | def test_package_get(client: Client, package_ahriman: Package) -> None: | ||||||
|     """ |     """ | ||||||
|     must return empty package list |     must raise not implemented on packages get | ||||||
|     """ |     """ | ||||||
|     assert client.package_get(package_ahriman.base) == [] |     with pytest.raises(NotImplementedError): | ||||||
|     assert client.package_get(None) == [] |         assert client.package_get(package_ahriman.base) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_logs(client: Client, package_ahriman: Package, log_record: logging.LogRecord) -> None: | def test_package_logs_add(client: Client, package_ahriman: Package, log_record: logging.LogRecord) -> None: | ||||||
|     """ |     """ | ||||||
|     must process log record without errors |     must process log record addition without exception | ||||||
|     """ |     """ | ||||||
|     client.package_logs(LogRecordId(package_ahriman.base, package_ahriman.version), log_record) |     log_record_id = LogRecordId(package_ahriman.base, package_ahriman.version) | ||||||
|  |     client.package_logs_add(log_record_id, log_record.created, log_record.getMessage()) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_logs_get(client: Client, package_ahriman: Package) -> None: | ||||||
|  |     """ | ||||||
|  |     must raise not implemented on logs retrieval | ||||||
|  |     """ | ||||||
|  |     with pytest.raises(NotImplementedError): | ||||||
|  |         client.package_logs_get(package_ahriman.base) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_logs_remove(client: Client, package_ahriman: Package) -> None: | ||||||
|  |     """ | ||||||
|  |     must raise not implemented on logs removal | ||||||
|  |     """ | ||||||
|  |     with pytest.raises(NotImplementedError): | ||||||
|  |         client.package_logs_remove(package_ahriman.base, package_ahriman.version) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_patches_get(client: Client, package_ahriman: Package) -> None: | ||||||
|  |     """ | ||||||
|  |     must raise not implemented on patches retrieval | ||||||
|  |     """ | ||||||
|  |     with pytest.raises(NotImplementedError): | ||||||
|  |         client.package_patches_get(package_ahriman.base, None) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_patches_remove(client: Client, package_ahriman: Package) -> None: | ||||||
|  |     """ | ||||||
|  |     must raise not implemented on patches removal | ||||||
|  |     """ | ||||||
|  |     with pytest.raises(NotImplementedError): | ||||||
|  |         client.package_patches_remove(package_ahriman.base, None) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_patches_update(client: Client, package_ahriman: Package) -> None: | ||||||
|  |     """ | ||||||
|  |     must raise not implemented on patches addition | ||||||
|  |     """ | ||||||
|  |     with pytest.raises(NotImplementedError): | ||||||
|  |         client.package_patches_update(package_ahriman.base, PkgbuildPatch(None, "")) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_remove(client: Client, package_ahriman: Package) -> None: | def test_package_remove(client: Client, package_ahriman: Package) -> None: | ||||||
|     """ |     """ | ||||||
|     must process remove without errors |     must raise not implemented on package removal | ||||||
|     """ |     """ | ||||||
|  |     with pytest.raises(NotImplementedError): | ||||||
|         client.package_remove(package_ahriman.base) |         client.package_remove(package_ahriman.base) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_status_update(client: Client, package_ahriman: Package) -> None: | ||||||
|  |     """ | ||||||
|  |     must raise not implemented on package update | ||||||
|  |     """ | ||||||
|  |     with pytest.raises(NotImplementedError): | ||||||
|  |         client.package_status_update(package_ahriman.base, BuildStatusEnum.Unknown) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_update(client: Client, package_ahriman: Package) -> None: | def test_package_update(client: Client, package_ahriman: Package) -> None: | ||||||
|     """ |     """ | ||||||
|     must update package status without errors |     must raise not implemented on package addition | ||||||
|     """ |     """ | ||||||
|     client.package_update(package_ahriman.base, BuildStatusEnum.Unknown) |     with pytest.raises(NotImplementedError): | ||||||
|  |         client.package_update(package_ahriman, BuildStatusEnum.Unknown) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_set_building(client: Client, package_ahriman: Package, mocker: MockerFixture) -> None: | def test_set_building(client: Client, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must set building status to the package |     must set building status to the package | ||||||
|     """ |     """ | ||||||
|     update_mock = mocker.patch("ahriman.core.status.client.Client.package_update") |     update_mock = mocker.patch("ahriman.core.status.Client.package_status_update") | ||||||
|     client.set_building(package_ahriman.base) |     client.set_building(package_ahriman.base) | ||||||
|  |  | ||||||
|     update_mock.assert_called_once_with(package_ahriman.base, BuildStatusEnum.Building) |     update_mock.assert_called_once_with(package_ahriman.base, BuildStatusEnum.Building) | ||||||
| @ -145,7 +220,7 @@ def test_set_failed(client: Client, package_ahriman: Package, mocker: MockerFixt | |||||||
|     """ |     """ | ||||||
|     must set failed status to the package |     must set failed status to the package | ||||||
|     """ |     """ | ||||||
|     update_mock = mocker.patch("ahriman.core.status.client.Client.package_update") |     update_mock = mocker.patch("ahriman.core.status.Client.package_status_update") | ||||||
|     client.set_failed(package_ahriman.base) |     client.set_failed(package_ahriman.base) | ||||||
|  |  | ||||||
|     update_mock.assert_called_once_with(package_ahriman.base, BuildStatusEnum.Failed) |     update_mock.assert_called_once_with(package_ahriman.base, BuildStatusEnum.Failed) | ||||||
| @ -155,7 +230,7 @@ def test_set_pending(client: Client, package_ahriman: Package, mocker: MockerFix | |||||||
|     """ |     """ | ||||||
|     must set building status to the package |     must set building status to the package | ||||||
|     """ |     """ | ||||||
|     update_mock = mocker.patch("ahriman.core.status.client.Client.package_update") |     update_mock = mocker.patch("ahriman.core.status.Client.package_status_update") | ||||||
|     client.set_pending(package_ahriman.base) |     client.set_pending(package_ahriman.base) | ||||||
|  |  | ||||||
|     update_mock.assert_called_once_with(package_ahriman.base, BuildStatusEnum.Pending) |     update_mock.assert_called_once_with(package_ahriman.base, BuildStatusEnum.Pending) | ||||||
| @ -165,20 +240,32 @@ def test_set_success(client: Client, package_ahriman: Package, mocker: MockerFix | |||||||
|     """ |     """ | ||||||
|     must set success status to the package |     must set success status to the package | ||||||
|     """ |     """ | ||||||
|     add_mock = mocker.patch("ahriman.core.status.client.Client.package_add") |     update_mock = mocker.patch("ahriman.core.status.Client.package_update") | ||||||
|     client.set_success(package_ahriman) |     client.set_success(package_ahriman) | ||||||
|  |  | ||||||
|     add_mock.assert_called_once_with(package_ahriman, BuildStatusEnum.Success) |     update_mock.assert_called_once_with(package_ahriman, BuildStatusEnum.Success) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_set_unknown(client: Client, package_ahriman: Package, mocker: MockerFixture) -> None: | def test_set_unknown(client: Client, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must add new package with unknown status |     must add new package with unknown status | ||||||
|     """ |     """ | ||||||
|     add_mock = mocker.patch("ahriman.core.status.client.Client.package_add") |     mocker.patch("ahriman.core.status.Client.package_get", return_value=[]) | ||||||
|  |     update_mock = mocker.patch("ahriman.core.status.Client.package_update") | ||||||
|     client.set_unknown(package_ahriman) |     client.set_unknown(package_ahriman) | ||||||
|  |  | ||||||
|     add_mock.assert_called_once_with(package_ahriman, BuildStatusEnum.Unknown) |     update_mock.assert_called_once_with(package_ahriman, BuildStatusEnum.Unknown) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_set_unknown_skip(client: Client, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must skip unknown status update in case if pacakge is already known | ||||||
|  |     """ | ||||||
|  |     mocker.patch("ahriman.core.status.Client.package_get", return_value=[(package_ahriman, None)]) | ||||||
|  |     update_mock = mocker.patch("ahriman.core.status.Client.package_update") | ||||||
|  |     client.set_unknown(package_ahriman) | ||||||
|  |  | ||||||
|  |     update_mock.assert_not_called() | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_status_get(client: Client) -> None: | def test_status_get(client: Client) -> None: | ||||||
|  | |||||||
							
								
								
									
										182
									
								
								tests/ahriman/core/status/test_local_client.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								tests/ahriman/core/status/test_local_client.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,182 @@ | |||||||
|  | import logging | ||||||
|  | import pytest | ||||||
|  |  | ||||||
|  | from pytest_mock import MockerFixture | ||||||
|  |  | ||||||
|  | from ahriman.core.status.local_client import LocalClient | ||||||
|  | from ahriman.models.build_status import BuildStatus, BuildStatusEnum | ||||||
|  | from ahriman.models.changes import Changes | ||||||
|  | from ahriman.models.dependencies import Dependencies | ||||||
|  | from ahriman.models.log_record_id import LogRecordId | ||||||
|  | from ahriman.models.package import Package | ||||||
|  | from ahriman.models.pkgbuild_patch import PkgbuildPatch | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_changes_get(local_client: LocalClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must retrieve package changes | ||||||
|  |     """ | ||||||
|  |     changes_mock = mocker.patch("ahriman.core.database.SQLite.changes_get") | ||||||
|  |     local_client.package_changes_get(package_ahriman.base) | ||||||
|  |     changes_mock.assert_called_once_with(package_ahriman.base, local_client.repository_id) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_changes_update(local_client: LocalClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must update package changes | ||||||
|  |     """ | ||||||
|  |     changes_mock = mocker.patch("ahriman.core.database.SQLite.changes_insert") | ||||||
|  |     changes = Changes() | ||||||
|  |  | ||||||
|  |     local_client.package_changes_update(package_ahriman.base, changes) | ||||||
|  |     changes_mock.assert_called_once_with(package_ahriman.base, changes, local_client.repository_id) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_dependencies_get(local_client: LocalClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must retrieve package dependencies | ||||||
|  |     """ | ||||||
|  |     dependencies_mock = mocker.patch("ahriman.core.database.SQLite.dependencies_get") | ||||||
|  |     local_client.package_dependencies_get(package_ahriman.base) | ||||||
|  |     dependencies_mock.assert_called_once_with(package_ahriman.base, local_client.repository_id) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_dependencies_update( | ||||||
|  |         local_client: LocalClient, | ||||||
|  |         package_ahriman: Package, | ||||||
|  |         mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must update package dependencies | ||||||
|  |     """ | ||||||
|  |     dependencies_mock = mocker.patch("ahriman.core.database.SQLite.dependencies_insert") | ||||||
|  |     local_client.package_dependencies_update(package_ahriman.base, Dependencies()) | ||||||
|  |     dependencies_mock.assert_called_once_with(package_ahriman.base, Dependencies(), local_client.repository_id) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_get(local_client: LocalClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must retrieve packages | ||||||
|  |     """ | ||||||
|  |     result = [(package_ahriman, BuildStatus())] | ||||||
|  |     package_mock = mocker.patch("ahriman.core.database.SQLite.packages_get", return_value=result) | ||||||
|  |     assert local_client.package_get(None) == result | ||||||
|  |     package_mock.assert_called_once_with(local_client.repository_id) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_get_package(local_client: LocalClient, package_ahriman: Package, package_python_schedule: Package, | ||||||
|  |                              mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must retrieve specific package | ||||||
|  |     """ | ||||||
|  |     result = [(package_ahriman, BuildStatus()), (package_python_schedule, BuildStatus())] | ||||||
|  |     package_mock = mocker.patch("ahriman.core.database.SQLite.packages_get", return_value=result) | ||||||
|  |     assert local_client.package_get(package_ahriman.base) == [result[0]] | ||||||
|  |     package_mock.assert_called_once_with(local_client.repository_id) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_logs_add(local_client: LocalClient, package_ahriman: Package, log_record: logging.LogRecord, | ||||||
|  |                           mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must add package logs | ||||||
|  |     """ | ||||||
|  |     logs_mock = mocker.patch("ahriman.core.database.SQLite.logs_insert") | ||||||
|  |     log_record_id = LogRecordId(package_ahriman.base, package_ahriman.version) | ||||||
|  |  | ||||||
|  |     local_client.package_logs_add(log_record_id, log_record.created, log_record.getMessage()) | ||||||
|  |     logs_mock.assert_called_once_with(log_record_id, log_record.created, log_record.getMessage(), | ||||||
|  |                                       local_client.repository_id) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_logs_get(local_client: LocalClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must retrieve package logs | ||||||
|  |     """ | ||||||
|  |     logs_mock = mocker.patch("ahriman.core.database.SQLite.logs_get") | ||||||
|  |     local_client.package_logs_get(package_ahriman.base, 1, 2) | ||||||
|  |     logs_mock.assert_called_once_with(package_ahriman.base, 1, 2, local_client.repository_id) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_logs_remove(local_client: LocalClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must remove package logs | ||||||
|  |     """ | ||||||
|  |     logs_mock = mocker.patch("ahriman.core.database.SQLite.logs_remove") | ||||||
|  |     local_client.package_logs_remove(package_ahriman.base, package_ahriman.version) | ||||||
|  |     logs_mock.assert_called_once_with(package_ahriman.base, package_ahriman.version, local_client.repository_id) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_patches_get(local_client: LocalClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must retrieve package patches | ||||||
|  |     """ | ||||||
|  |     patches_mock = mocker.patch("ahriman.core.database.SQLite.patches_list") | ||||||
|  |     local_client.package_patches_get(package_ahriman.base, None) | ||||||
|  |     patches_mock.assert_called_once_with(package_ahriman.base, None) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_patches_get_key(local_client: LocalClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must retrieve package patches for specific patch name | ||||||
|  |     """ | ||||||
|  |     patches_mock = mocker.patch("ahriman.core.database.SQLite.patches_list") | ||||||
|  |     local_client.package_patches_get(package_ahriman.base, "key") | ||||||
|  |     patches_mock.assert_called_once_with(package_ahriman.base, ["key"]) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_patches_remove(local_client: LocalClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must remove package patches | ||||||
|  |     """ | ||||||
|  |     patches_mock = mocker.patch("ahriman.core.database.SQLite.patches_remove") | ||||||
|  |     local_client.package_patches_remove(package_ahriman.base, None) | ||||||
|  |     patches_mock.assert_called_once_with(package_ahriman.base, None) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_patches_remove_key(local_client: LocalClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must remove package specific package patch | ||||||
|  |     """ | ||||||
|  |     patches_mock = mocker.patch("ahriman.core.database.SQLite.patches_remove") | ||||||
|  |     local_client.package_patches_remove(package_ahriman.base, "key") | ||||||
|  |     patches_mock.assert_called_once_with(package_ahriman.base, ["key"]) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_patches_update(local_client: LocalClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must add package patches | ||||||
|  |     """ | ||||||
|  |     patches_mock = mocker.patch("ahriman.core.database.SQLite.patches_insert") | ||||||
|  |     patch = PkgbuildPatch("key", "value") | ||||||
|  |  | ||||||
|  |     local_client.package_patches_update(package_ahriman.base, patch) | ||||||
|  |     patches_mock.assert_called_once_with(package_ahriman.base, [patch]) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_remove(local_client: LocalClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must remove package | ||||||
|  |     """ | ||||||
|  |     package_mock = mocker.patch("ahriman.core.database.SQLite.package_clear") | ||||||
|  |     local_client.package_remove(package_ahriman.base) | ||||||
|  |     package_mock.assert_called_once_with(package_ahriman.base) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_status_update(local_client: LocalClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must update package status | ||||||
|  |     """ | ||||||
|  |     status_mock = mocker.patch("ahriman.core.database.SQLite.status_update") | ||||||
|  |     local_client.package_status_update(package_ahriman.base, BuildStatusEnum.Success) | ||||||
|  |     status_mock.assert_called_once_with(package_ahriman.base, pytest.helpers.anyvar(int), local_client.repository_id) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_update(local_client: LocalClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must process package addition | ||||||
|  |     """ | ||||||
|  |     package_mock = mocker.patch("ahriman.core.database.SQLite.package_update") | ||||||
|  |     status_mock = mocker.patch("ahriman.core.database.SQLite.status_update") | ||||||
|  |  | ||||||
|  |     local_client.package_update(package_ahriman, BuildStatusEnum.Success) | ||||||
|  |     package_mock.assert_called_once_with(package_ahriman, local_client.repository_id) | ||||||
|  |     status_mock.assert_called_once_with(package_ahriman.base, pytest.helpers.anyvar(int), local_client.repository_id) | ||||||
| @ -1,26 +1,33 @@ | |||||||
| import pytest | import pytest | ||||||
|  |  | ||||||
| from pytest_mock import MockerFixture | from pytest_mock import MockerFixture | ||||||
| from unittest.mock import call as MockCall |  | ||||||
|  |  | ||||||
| from ahriman.core.exceptions import UnknownPackageError | from ahriman.core.exceptions import UnknownPackageError | ||||||
| from ahriman.core.status.watcher import Watcher | from ahriman.core.status.watcher import Watcher | ||||||
| from ahriman.models.build_status import BuildStatus, BuildStatusEnum | from ahriman.models.build_status import BuildStatus, BuildStatusEnum | ||||||
| from ahriman.models.changes import Changes |  | ||||||
| from ahriman.models.log_record_id import LogRecordId | from ahriman.models.log_record_id import LogRecordId | ||||||
| from ahriman.models.package import Package | from ahriman.models.package import Package | ||||||
| from ahriman.models.pkgbuild_patch import PkgbuildPatch |  | ||||||
|  |  | ||||||
|  | def test_packages(watcher: Watcher, package_ahriman: Package) -> None: | ||||||
|  |     """ | ||||||
|  |     must return list of available packages | ||||||
|  |     """ | ||||||
|  |     assert not watcher.packages | ||||||
|  |  | ||||||
|  |     watcher._known = {package_ahriman.base: (package_ahriman, BuildStatus())} | ||||||
|  |     assert watcher.packages | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_load(watcher: Watcher, package_ahriman: Package, mocker: MockerFixture) -> None: | def test_load(watcher: Watcher, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must correctly load packages |     must correctly load packages | ||||||
|     """ |     """ | ||||||
|     cache_mock = mocker.patch("ahriman.core.database.SQLite.packages_get", |     cache_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_get", | ||||||
|                               return_value=[(package_ahriman, BuildStatus())]) |                               return_value=[(package_ahriman, BuildStatus())]) | ||||||
|  |  | ||||||
|     watcher.load() |     watcher.load() | ||||||
|     cache_mock.assert_called_once_with(watcher.repository_id) |     cache_mock.assert_called_once_with(None) | ||||||
|     package, status = watcher._known[package_ahriman.base] |     package, status = watcher._known[package_ahriman.base] | ||||||
|     assert package == package_ahriman |     assert package == package_ahriman | ||||||
|     assert status.status == BuildStatusEnum.Unknown |     assert status.status == BuildStatusEnum.Unknown | ||||||
| @ -31,7 +38,7 @@ def test_load_known(watcher: Watcher, package_ahriman: Package, mocker: MockerFi | |||||||
|     must correctly load packages with known statuses |     must correctly load packages with known statuses | ||||||
|     """ |     """ | ||||||
|     status = BuildStatus(BuildStatusEnum.Success) |     status = BuildStatus(BuildStatusEnum.Success) | ||||||
|     mocker.patch("ahriman.core.database.SQLite.packages_get", return_value=[(package_ahriman, status)]) |     mocker.patch("ahriman.core.status.local_client.LocalClient.package_get", return_value=[(package_ahriman, status)]) | ||||||
|     watcher._known = {package_ahriman.base: (package_ahriman, status)} |     watcher._known = {package_ahriman.base: (package_ahriman, status)} | ||||||
|  |  | ||||||
|     watcher.load() |     watcher.load() | ||||||
| @ -39,85 +46,6 @@ def test_load_known(watcher: Watcher, package_ahriman: Package, mocker: MockerFi | |||||||
|     assert status.status == BuildStatusEnum.Success |     assert status.status == BuildStatusEnum.Success | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_logs_get(watcher: Watcher, package_ahriman: Package, mocker: MockerFixture) -> None: |  | ||||||
|     """ |  | ||||||
|     must return package logs |  | ||||||
|     """ |  | ||||||
|     watcher._known = {package_ahriman.base: (package_ahriman, BuildStatus())} |  | ||||||
|     logs_mock = mocker.patch("ahriman.core.database.SQLite.logs_get") |  | ||||||
|  |  | ||||||
|     watcher.logs_get(package_ahriman.base, 1, 2) |  | ||||||
|     logs_mock.assert_called_once_with(package_ahriman.base, 1, 2, watcher.repository_id) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_logs_get_failed(watcher: Watcher, package_ahriman: Package) -> None: |  | ||||||
|     """ |  | ||||||
|     must raise UnknownPackageError on logs in case of unknown package |  | ||||||
|     """ |  | ||||||
|     with pytest.raises(UnknownPackageError): |  | ||||||
|         watcher.logs_get(package_ahriman.base) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_logs_remove(watcher: Watcher, package_ahriman: Package, mocker: MockerFixture) -> None: |  | ||||||
|     """ |  | ||||||
|     must remove package logs |  | ||||||
|     """ |  | ||||||
|     logs_mock = mocker.patch("ahriman.core.database.SQLite.logs_remove") |  | ||||||
|     watcher.logs_remove(package_ahriman.base, "42") |  | ||||||
|     logs_mock.assert_called_once_with(package_ahriman.base, "42", watcher.repository_id) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_logs_update_new(watcher: Watcher, package_ahriman: Package, mocker: MockerFixture) -> None: |  | ||||||
|     """ |  | ||||||
|     must create package logs record for new package |  | ||||||
|     """ |  | ||||||
|     delete_mock = mocker.patch("ahriman.core.status.watcher.Watcher.logs_remove") |  | ||||||
|     insert_mock = mocker.patch("ahriman.core.database.SQLite.logs_insert") |  | ||||||
|  |  | ||||||
|     log_record_id = LogRecordId(package_ahriman.base, watcher._last_log_record_id.version) |  | ||||||
|     assert watcher._last_log_record_id != log_record_id |  | ||||||
|  |  | ||||||
|     watcher.logs_update(log_record_id, 42.01, "log record") |  | ||||||
|     delete_mock.assert_called_once_with(package_ahriman.base, log_record_id.version) |  | ||||||
|     insert_mock.assert_called_once_with(log_record_id, 42.01, "log record", watcher.repository_id) |  | ||||||
|  |  | ||||||
|     assert watcher._last_log_record_id == log_record_id |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_logs_update_update(watcher: Watcher, package_ahriman: Package, mocker: MockerFixture) -> None: |  | ||||||
|     """ |  | ||||||
|     must create package logs record for current package |  | ||||||
|     """ |  | ||||||
|     delete_mock = mocker.patch("ahriman.core.status.watcher.Watcher.logs_remove") |  | ||||||
|     insert_mock = mocker.patch("ahriman.core.database.SQLite.logs_insert") |  | ||||||
|  |  | ||||||
|     log_record_id = LogRecordId(package_ahriman.base, watcher._last_log_record_id.version) |  | ||||||
|     watcher._last_log_record_id = log_record_id |  | ||||||
|  |  | ||||||
|     watcher.logs_update(log_record_id, 42.01, "log record") |  | ||||||
|     delete_mock.assert_not_called() |  | ||||||
|     insert_mock.assert_called_once_with(log_record_id, 42.01, "log record", watcher.repository_id) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_changes_get(watcher: Watcher, package_ahriman: Package, mocker: MockerFixture) -> None: |  | ||||||
|     """ |  | ||||||
|     must return package changes |  | ||||||
|     """ |  | ||||||
|     get_mock = mocker.patch("ahriman.core.database.SQLite.changes_get", return_value=Changes("sha")) |  | ||||||
|     watcher._known = {package_ahriman.base: (package_ahriman, BuildStatus())} |  | ||||||
|  |  | ||||||
|     assert watcher.package_changes_get(package_ahriman.base) == Changes("sha") |  | ||||||
|     get_mock.assert_called_once_with(package_ahriman.base, watcher.repository_id) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_changes_get_failed(watcher: Watcher, package_ahriman: Package) -> None: |  | ||||||
|     """ |  | ||||||
|     must raise UnknownPackageError on changes in case of unknown package |  | ||||||
|     """ |  | ||||||
|     with pytest.raises(UnknownPackageError): |  | ||||||
|         watcher.package_changes_get(package_ahriman.base) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_get(watcher: Watcher, package_ahriman: Package) -> None: | def test_package_get(watcher: Watcher, package_ahriman: Package) -> None: | ||||||
|     """ |     """ | ||||||
|     must return package status |     must return package status | ||||||
| @ -136,17 +64,49 @@ def test_package_get_failed(watcher: Watcher, package_ahriman: Package) -> None: | |||||||
|         watcher.package_get(package_ahriman.base) |         watcher.package_get(package_ahriman.base) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_logs_add_new(watcher: Watcher, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must create package logs record for new package | ||||||
|  |     """ | ||||||
|  |     delete_mock = mocker.patch("ahriman.core.status.watcher.Watcher.package_logs_remove", create=True) | ||||||
|  |     insert_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_logs_add") | ||||||
|  |  | ||||||
|  |     log_record_id = LogRecordId(package_ahriman.base, watcher._last_log_record_id.version) | ||||||
|  |     assert watcher._last_log_record_id != log_record_id | ||||||
|  |  | ||||||
|  |     watcher.package_logs_add(log_record_id, 42.01, "log record") | ||||||
|  |     delete_mock.assert_called_once_with(package_ahriman.base, log_record_id.version) | ||||||
|  |     insert_mock.assert_called_once_with(log_record_id, 42.01, "log record") | ||||||
|  |  | ||||||
|  |     assert watcher._last_log_record_id == log_record_id | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_logs_add_update(watcher: Watcher, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must create package logs record for current package | ||||||
|  |     """ | ||||||
|  |     delete_mock = mocker.patch("ahriman.core.status.watcher.Watcher.package_logs_remove", create=True) | ||||||
|  |     insert_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_logs_add") | ||||||
|  |  | ||||||
|  |     log_record_id = LogRecordId(package_ahriman.base, watcher._last_log_record_id.version) | ||||||
|  |     watcher._last_log_record_id = log_record_id | ||||||
|  |  | ||||||
|  |     watcher.package_logs_add(log_record_id, 42.01, "log record") | ||||||
|  |     delete_mock.assert_not_called() | ||||||
|  |     insert_mock.assert_called_once_with(log_record_id, 42.01, "log record") | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_remove(watcher: Watcher, package_ahriman: Package, mocker: MockerFixture) -> None: | def test_package_remove(watcher: Watcher, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must remove package base |     must remove package base | ||||||
|     """ |     """ | ||||||
|     cache_mock = mocker.patch("ahriman.core.database.SQLite.package_remove") |     cache_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_remove") | ||||||
|     logs_mock = mocker.patch("ahriman.core.status.watcher.Watcher.logs_remove") |     logs_mock = mocker.patch("ahriman.core.status.watcher.Watcher.package_logs_remove", create=True) | ||||||
|     watcher._known = {package_ahriman.base: (package_ahriman, BuildStatus())} |     watcher._known = {package_ahriman.base: (package_ahriman, BuildStatus())} | ||||||
|  |  | ||||||
|     watcher.package_remove(package_ahriman.base) |     watcher.package_remove(package_ahriman.base) | ||||||
|     assert not watcher._known |     assert not watcher._known | ||||||
|     cache_mock.assert_called_once_with(package_ahriman.base, watcher.repository_id) |     cache_mock.assert_called_once_with(package_ahriman.base) | ||||||
|     logs_mock.assert_called_once_with(package_ahriman.base, None) |     logs_mock.assert_called_once_with(package_ahriman.base, None) | ||||||
|  |  | ||||||
|  |  | ||||||
| @ -154,82 +114,42 @@ def test_package_remove_unknown(watcher: Watcher, package_ahriman: Package, mock | |||||||
|     """ |     """ | ||||||
|     must not fail on unknown base removal |     must not fail on unknown base removal | ||||||
|     """ |     """ | ||||||
|     cache_mock = mocker.patch("ahriman.core.database.SQLite.package_remove") |     cache_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_remove") | ||||||
|  |  | ||||||
|     watcher.package_remove(package_ahriman.base) |     watcher.package_remove(package_ahriman.base) | ||||||
|     cache_mock.assert_called_once_with(package_ahriman.base, watcher.repository_id) |     cache_mock.assert_called_once_with(package_ahriman.base) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_update(watcher: Watcher, package_ahriman: Package, mocker: MockerFixture) -> None: | def test_package_status_update(watcher: Watcher, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|     """ |  | ||||||
|     must update package status |  | ||||||
|     """ |  | ||||||
|     cache_mock = mocker.patch("ahriman.core.database.SQLite.package_update") |  | ||||||
|  |  | ||||||
|     watcher.package_update(package_ahriman.base, BuildStatusEnum.Unknown, package_ahriman) |  | ||||||
|     cache_mock.assert_called_once_with(package_ahriman, pytest.helpers.anyvar(int), watcher.repository_id) |  | ||||||
|     package, status = watcher._known[package_ahriman.base] |  | ||||||
|     assert package == package_ahriman |  | ||||||
|     assert status.status == BuildStatusEnum.Unknown |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_update_ping(watcher: Watcher, package_ahriman: Package, mocker: MockerFixture) -> None: |  | ||||||
|     """ |     """ | ||||||
|     must update package status only for known package |     must update package status only for known package | ||||||
|     """ |     """ | ||||||
|     cache_mock = mocker.patch("ahriman.core.database.SQLite.package_update") |     cache_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_status_update") | ||||||
|     watcher._known = {package_ahriman.base: (package_ahriman, BuildStatus())} |     watcher._known = {package_ahriman.base: (package_ahriman, BuildStatus())} | ||||||
|  |  | ||||||
|     watcher.package_update(package_ahriman.base, BuildStatusEnum.Success, None) |     watcher.package_status_update(package_ahriman.base, BuildStatusEnum.Success) | ||||||
|     cache_mock.assert_called_once_with(package_ahriman, pytest.helpers.anyvar(int), watcher.repository_id) |     cache_mock.assert_called_once_with(package_ahriman.base, pytest.helpers.anyvar(int)) | ||||||
|     package, status = watcher._known[package_ahriman.base] |     package, status = watcher._known[package_ahriman.base] | ||||||
|     assert package == package_ahriman |     assert package == package_ahriman | ||||||
|     assert status.status == BuildStatusEnum.Success |     assert status.status == BuildStatusEnum.Success | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_update_unknown(watcher: Watcher, package_ahriman: Package) -> None: | def test_package_status_update_unknown(watcher: Watcher, package_ahriman: Package) -> None: | ||||||
|     """ |     """ | ||||||
|     must fail on unknown package status update only |     must fail on unknown package status update only | ||||||
|     """ |     """ | ||||||
|     with pytest.raises(UnknownPackageError): |     with pytest.raises(UnknownPackageError): | ||||||
|         watcher.package_update(package_ahriman.base, BuildStatusEnum.Unknown, None) |         watcher.package_status_update(package_ahriman.base, BuildStatusEnum.Unknown) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_patches_get(watcher: Watcher, package_ahriman: Package, mocker: MockerFixture) -> None: | def test_package_update(watcher: Watcher, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must return patches for the package |     must add package to cache | ||||||
|     """ |     """ | ||||||
|     watcher._known = {package_ahriman.base: (package_ahriman, BuildStatus())} |     cache_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_update") | ||||||
|     patches_mock = mocker.patch("ahriman.core.database.SQLite.patches_list") |  | ||||||
|  |  | ||||||
|     watcher.patches_get(package_ahriman.base, None) |     watcher.package_update(package_ahriman, BuildStatusEnum.Unknown) | ||||||
|     watcher.patches_get(package_ahriman.base, "var") |     assert watcher.packages | ||||||
|     patches_mock.assert_has_calls([ |     cache_mock.assert_called_once_with(package_ahriman, pytest.helpers.anyvar(int)) | ||||||
|         MockCall(package_ahriman.base, None), |  | ||||||
|         MockCall().get(package_ahriman.base, []), |  | ||||||
|         MockCall(package_ahriman.base, ["var"]), |  | ||||||
|         MockCall().get(package_ahriman.base, []), |  | ||||||
|     ]) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_patches_remove(watcher: Watcher, package_ahriman: Package, mocker: MockerFixture) -> None: |  | ||||||
|     """ |  | ||||||
|     must remove patches for the package |  | ||||||
|     """ |  | ||||||
|     patches_mock = mocker.patch("ahriman.core.database.SQLite.patches_remove") |  | ||||||
|     watcher.patches_remove(package_ahriman.base, "var") |  | ||||||
|     patches_mock.assert_called_once_with(package_ahriman.base, ["var"]) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_patches_update(watcher: Watcher, package_ahriman: Package, mocker: MockerFixture) -> None: |  | ||||||
|     """ |  | ||||||
|     must update patches for the package |  | ||||||
|     """ |  | ||||||
|     patch = PkgbuildPatch("key", "value") |  | ||||||
|     patches_mock = mocker.patch("ahriman.core.database.SQLite.patches_insert") |  | ||||||
|  |  | ||||||
|     watcher.patches_update(package_ahriman.base, patch) |  | ||||||
|     patches_mock.assert_called_once_with(package_ahriman.base, [patch]) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_status_update(watcher: Watcher) -> None: | def test_status_update(watcher: Watcher) -> None: | ||||||
| @ -238,3 +158,41 @@ def test_status_update(watcher: Watcher) -> None: | |||||||
|     """ |     """ | ||||||
|     watcher.status_update(BuildStatusEnum.Success) |     watcher.status_update(BuildStatusEnum.Success) | ||||||
|     assert watcher.status.status == BuildStatusEnum.Success |     assert watcher.status.status == BuildStatusEnum.Success | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_call(watcher: Watcher, package_ahriman: Package) -> None: | ||||||
|  |     """ | ||||||
|  |     must return self instance if package exists | ||||||
|  |     """ | ||||||
|  |     watcher._known = {package_ahriman.base: (package_ahriman, BuildStatus())} | ||||||
|  |     assert watcher(package_ahriman.base) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_call_skip(watcher: Watcher) -> None: | ||||||
|  |     """ | ||||||
|  |     must return self instance if no package base set | ||||||
|  |     """ | ||||||
|  |     assert watcher(None) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_call_failed(watcher: Watcher, package_ahriman: Package) -> None: | ||||||
|  |     """ | ||||||
|  |     must raise UnknownPackage | ||||||
|  |     """ | ||||||
|  |     with pytest.raises(UnknownPackageError): | ||||||
|  |         assert watcher(package_ahriman.base) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_getattr(watcher: Watcher) -> None: | ||||||
|  |     """ | ||||||
|  |     must return client method call | ||||||
|  |     """ | ||||||
|  |     assert watcher.package_logs_remove | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_getattr_unknown_method(watcher: Watcher) -> None: | ||||||
|  |     """ | ||||||
|  |     must raise AttributeError in case if no reporter attribute found | ||||||
|  |     """ | ||||||
|  |     with pytest.raises(AttributeError): | ||||||
|  |         assert watcher.random_method | ||||||
|  | |||||||
| @ -9,9 +9,11 @@ from ahriman.core.configuration import Configuration | |||||||
| from ahriman.core.status.web_client import WebClient | from ahriman.core.status.web_client import WebClient | ||||||
| from ahriman.models.build_status import BuildStatus, BuildStatusEnum | from ahriman.models.build_status import BuildStatus, BuildStatusEnum | ||||||
| from ahriman.models.changes import Changes | from ahriman.models.changes import Changes | ||||||
|  | from ahriman.models.dependencies import Dependencies | ||||||
| from ahriman.models.internal_status import InternalStatus | from ahriman.models.internal_status import InternalStatus | ||||||
| from ahriman.models.log_record_id import LogRecordId | from ahriman.models.log_record_id import LogRecordId | ||||||
| from ahriman.models.package import Package | from ahriman.models.package import Package | ||||||
|  | from ahriman.models.pkgbuild_patch import PkgbuildPatch | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_parse_address(configuration: Configuration) -> None: | def test_parse_address(configuration: Configuration) -> None: | ||||||
| @ -41,6 +43,31 @@ def test_changes_url(web_client: WebClient, package_ahriman: Package) -> None: | |||||||
|     assert web_client._changes_url("some/package%name").endswith("/api/v1/packages/some%2Fpackage%25name/changes") |     assert web_client._changes_url("some/package%name").endswith("/api/v1/packages/some%2Fpackage%25name/changes") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_dependencies_url(web_client: WebClient, package_ahriman: Package) -> None: | ||||||
|  |     """ | ||||||
|  |     must generate changes url correctly | ||||||
|  |     """ | ||||||
|  |     assert web_client._dependencies_url(package_ahriman.base).startswith(web_client.address) | ||||||
|  |     assert web_client._dependencies_url(package_ahriman.base).endswith( | ||||||
|  |         f"/api/v1/packages/{package_ahriman.base}/dependencies") | ||||||
|  |     assert web_client._dependencies_url("some/package%name").endswith( | ||||||
|  |         "/api/v1/packages/some%2Fpackage%25name/dependencies") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test__patches_url(web_client: WebClient, package_ahriman: Package) -> None: | ||||||
|  |     """ | ||||||
|  |     must generate changes url correctly | ||||||
|  |     """ | ||||||
|  |     assert web_client._patches_url(package_ahriman.base).startswith(web_client.address) | ||||||
|  |     assert web_client._patches_url(package_ahriman.base).endswith(f"/api/v1/packages/{package_ahriman.base}/patches") | ||||||
|  |     assert web_client._patches_url("some/package%name").endswith("/api/v1/packages/some%2Fpackage%25name/patches") | ||||||
|  |  | ||||||
|  |     assert web_client._patches_url(package_ahriman.base, "var").endswith( | ||||||
|  |         f"/api/v1/packages/{package_ahriman.base}/patches/var") | ||||||
|  |     assert web_client._patches_url(package_ahriman.base, "some/variable%name").endswith( | ||||||
|  |         f"/api/v1/packages/{package_ahriman.base}/patches/some%2Fvariable%25name") | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_logs_url(web_client: WebClient, package_ahriman: Package) -> None: | def test_logs_url(web_client: WebClient, package_ahriman: Package) -> None: | ||||||
|     """ |     """ | ||||||
|     must generate logs url correctly |     must generate logs url correctly | ||||||
| @ -70,59 +97,6 @@ def test_status_url(web_client: WebClient) -> None: | |||||||
|     assert web_client._status_url().endswith("/api/v1/status") |     assert web_client._status_url().endswith("/api/v1/status") | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_add(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: |  | ||||||
|     """ |  | ||||||
|     must process package addition |  | ||||||
|     """ |  | ||||||
|     requests_mock = mocker.patch("ahriman.core.status.web_client.WebClient.make_request") |  | ||||||
|     payload = pytest.helpers.get_package_status(package_ahriman) |  | ||||||
|  |  | ||||||
|     web_client.package_add(package_ahriman, BuildStatusEnum.Unknown) |  | ||||||
|     requests_mock.assert_called_once_with("POST", pytest.helpers.anyvar(str, True), |  | ||||||
|                                           params=web_client.repository_id.query(), json=payload) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_add_failed(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: |  | ||||||
|     """ |  | ||||||
|     must suppress any exception happened during addition |  | ||||||
|     """ |  | ||||||
|     mocker.patch("requests.Session.request", side_effect=Exception()) |  | ||||||
|     web_client.package_add(package_ahriman, BuildStatusEnum.Unknown) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_add_failed_http_error(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: |  | ||||||
|     """ |  | ||||||
|     must suppress HTTP exception happened during addition |  | ||||||
|     """ |  | ||||||
|     mocker.patch("requests.Session.request", side_effect=requests.HTTPError()) |  | ||||||
|     web_client.package_add(package_ahriman, BuildStatusEnum.Unknown) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_add_failed_suppress(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: |  | ||||||
|     """ |  | ||||||
|     must suppress any exception happened during addition and don't log |  | ||||||
|     """ |  | ||||||
|     web_client.suppress_errors = True |  | ||||||
|     mocker.patch("requests.Session.request", side_effect=Exception()) |  | ||||||
|     logging_mock = mocker.patch("logging.exception") |  | ||||||
|  |  | ||||||
|     web_client.package_add(package_ahriman, BuildStatusEnum.Unknown) |  | ||||||
|     logging_mock.assert_not_called() |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_add_failed_http_error_suppress(web_client: WebClient, package_ahriman: Package, |  | ||||||
|                                                 mocker: MockerFixture) -> None: |  | ||||||
|     """ |  | ||||||
|     must suppress HTTP exception happened during addition and don't log |  | ||||||
|     """ |  | ||||||
|     web_client.suppress_errors = True |  | ||||||
|     mocker.patch("requests.Session.request", side_effect=requests.HTTPError()) |  | ||||||
|     logging_mock = mocker.patch("logging.exception") |  | ||||||
|  |  | ||||||
|     web_client.package_add(package_ahriman, BuildStatusEnum.Unknown) |  | ||||||
|     logging_mock.assert_not_called() |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_changes_get(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | def test_package_changes_get(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must get changes |     must get changes | ||||||
| @ -183,36 +157,36 @@ def test_package_changes_get_failed_http_error_suppress(web_client: WebClient, p | |||||||
|     logging_mock.assert_not_called() |     logging_mock.assert_not_called() | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_changes_set(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | def test_package_changes_update(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must set changes |     must set changes | ||||||
|     """ |     """ | ||||||
|     changes = Changes("sha") |     changes = Changes("sha") | ||||||
|     requests_mock = mocker.patch("ahriman.core.status.web_client.WebClient.make_request") |     requests_mock = mocker.patch("ahriman.core.status.web_client.WebClient.make_request") | ||||||
|  |  | ||||||
|     web_client.package_changes_set(package_ahriman.base, changes) |     web_client.package_changes_update(package_ahriman.base, changes) | ||||||
|     requests_mock.assert_called_once_with("POST", pytest.helpers.anyvar(str, True), |     requests_mock.assert_called_once_with("POST", pytest.helpers.anyvar(str, True), | ||||||
|                                           params=web_client.repository_id.query(), json=changes.view()) |                                           params=web_client.repository_id.query(), json=changes.view()) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_changes_set_failed(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | def test_package_changes_update_failed(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must suppress any exception happened during changes update |     must suppress any exception happened during changes update | ||||||
|     """ |     """ | ||||||
|     mocker.patch("requests.Session.request", side_effect=Exception()) |     mocker.patch("requests.Session.request", side_effect=Exception()) | ||||||
|     web_client.package_changes_set(package_ahriman.base, Changes()) |     web_client.package_changes_update(package_ahriman.base, Changes()) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_changes_set_failed_http_error(web_client: WebClient, package_ahriman: Package, | def test_package_changes_update_failed_http_error(web_client: WebClient, package_ahriman: Package, | ||||||
|                                                   mocker: MockerFixture) -> None: |                                                   mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must suppress HTTP exception happened during changes update |     must suppress HTTP exception happened during changes update | ||||||
|     """ |     """ | ||||||
|     mocker.patch("requests.Session.request", side_effect=requests.HTTPError()) |     mocker.patch("requests.Session.request", side_effect=requests.HTTPError()) | ||||||
|     web_client.package_changes_set(package_ahriman.base, Changes()) |     web_client.package_changes_update(package_ahriman.base, Changes()) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_changes_set_failed_suppress(web_client: WebClient, package_ahriman: Package, | def test_package_changes_update_failed_suppress(web_client: WebClient, package_ahriman: Package, | ||||||
|                                                 mocker: MockerFixture) -> None: |                                                 mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must suppress any exception happened during changes update and don't log |     must suppress any exception happened during changes update and don't log | ||||||
| @ -221,11 +195,11 @@ def test_package_changes_set_failed_suppress(web_client: WebClient, package_ahri | |||||||
|     mocker.patch("requests.Session.request", side_effect=Exception()) |     mocker.patch("requests.Session.request", side_effect=Exception()) | ||||||
|     logging_mock = mocker.patch("logging.exception") |     logging_mock = mocker.patch("logging.exception") | ||||||
|  |  | ||||||
|     web_client.package_changes_set(package_ahriman.base, Changes()) |     web_client.package_changes_update(package_ahriman.base, Changes()) | ||||||
|     logging_mock.assert_not_called() |     logging_mock.assert_not_called() | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_changes_set_failed_http_error_suppress(web_client: WebClient, package_ahriman: Package, | def test_package_changes_update_failed_http_error_suppress(web_client: WebClient, package_ahriman: Package, | ||||||
|                                                            mocker: MockerFixture) -> None: |                                                            mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must suppress HTTP exception happened during changes update and don't log |     must suppress HTTP exception happened during changes update and don't log | ||||||
| @ -234,7 +208,124 @@ def test_package_changes_set_failed_http_error_suppress(web_client: WebClient, p | |||||||
|     mocker.patch("requests.Session.request", side_effect=requests.HTTPError()) |     mocker.patch("requests.Session.request", side_effect=requests.HTTPError()) | ||||||
|     logging_mock = mocker.patch("logging.exception") |     logging_mock = mocker.patch("logging.exception") | ||||||
|  |  | ||||||
|     web_client.package_changes_set(package_ahriman.base, Changes()) |     web_client.package_changes_update(package_ahriman.base, Changes()) | ||||||
|  |     logging_mock.assert_not_called() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_dependencies_get(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must get dependencies | ||||||
|  |     """ | ||||||
|  |     dependencies = Dependencies({"path": ["package"]}) | ||||||
|  |     response_obj = requests.Response() | ||||||
|  |     response_obj._content = json.dumps(dependencies.view()).encode("utf8") | ||||||
|  |     response_obj.status_code = 200 | ||||||
|  |  | ||||||
|  |     requests_mock = mocker.patch("ahriman.core.status.web_client.WebClient.make_request", return_value=response_obj) | ||||||
|  |  | ||||||
|  |     result = web_client.package_dependencies_get(package_ahriman.base) | ||||||
|  |     requests_mock.assert_called_once_with("GET", pytest.helpers.anyvar(str, True), | ||||||
|  |                                           params=web_client.repository_id.query()) | ||||||
|  |     assert result == dependencies | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_dependencies_get_failed(web_client: WebClient, package_ahriman: Package, | ||||||
|  |                                          mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress any exception happened during dependencies fetch | ||||||
|  |     """ | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=Exception()) | ||||||
|  |     web_client.package_dependencies_get(package_ahriman.base) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_dependencies_get_failed_http_error(web_client: WebClient, package_ahriman: Package, | ||||||
|  |                                                     mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress HTTP exception happened during dependencies fetch | ||||||
|  |     """ | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=requests.HTTPError()) | ||||||
|  |     web_client.package_dependencies_get(package_ahriman.base) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_dependencies_get_failed_suppress(web_client: WebClient, package_ahriman: Package, | ||||||
|  |                                                   mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress any exception happened during dependencies fetch and don't log | ||||||
|  |     """ | ||||||
|  |     web_client.suppress_errors = True | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=Exception()) | ||||||
|  |     logging_mock = mocker.patch("logging.exception") | ||||||
|  |  | ||||||
|  |     web_client.package_dependencies_get(package_ahriman.base) | ||||||
|  |     logging_mock.assert_not_called() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_dependencies_get_failed_http_error_suppress(web_client: WebClient, package_ahriman: Package, | ||||||
|  |                                                              mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress HTTP exception happened during dependencies fetch and don't log | ||||||
|  |     """ | ||||||
|  |     web_client.suppress_errors = True | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=requests.HTTPError()) | ||||||
|  |     logging_mock = mocker.patch("logging.exception") | ||||||
|  |  | ||||||
|  |     web_client.package_dependencies_get(package_ahriman.base) | ||||||
|  |     logging_mock.assert_not_called() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_dependencies_update(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must set dependencies | ||||||
|  |     """ | ||||||
|  |     dependencies = Dependencies({"path": ["package"]}) | ||||||
|  |     requests_mock = mocker.patch("ahriman.core.status.web_client.WebClient.make_request") | ||||||
|  |  | ||||||
|  |     web_client.package_dependencies_update(package_ahriman.base, dependencies) | ||||||
|  |     requests_mock.assert_called_once_with("POST", pytest.helpers.anyvar(str, True), | ||||||
|  |                                           params=web_client.repository_id.query(), json=dependencies.view()) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_dependencies_update_failed(web_client: WebClient, package_ahriman: Package, | ||||||
|  |                                             mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress any exception happened during dependencies update | ||||||
|  |     """ | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=Exception()) | ||||||
|  |     web_client.package_dependencies_update(package_ahriman.base, Dependencies()) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_dependencies_update_failed_http_error(web_client: WebClient, package_ahriman: Package, | ||||||
|  |                                                        mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress HTTP exception happened during dependencies update | ||||||
|  |     """ | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=requests.HTTPError()) | ||||||
|  |     web_client.package_dependencies_update(package_ahriman.base, Dependencies()) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_dependencies_update_failed_suppress(web_client: WebClient, package_ahriman: Package, | ||||||
|  |                                                      mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress any exception happened during dependencies update and don't log | ||||||
|  |     """ | ||||||
|  |     web_client.suppress_errors = True | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=Exception()) | ||||||
|  |     logging_mock = mocker.patch("logging.exception") | ||||||
|  |  | ||||||
|  |     web_client.package_dependencies_update(package_ahriman.base, Dependencies()) | ||||||
|  |     logging_mock.assert_not_called() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_dependencies_update_failed_http_error_suppress(web_client: WebClient, package_ahriman: Package, | ||||||
|  |                                                                 mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress HTTP exception happened during dependencies update and don't log | ||||||
|  |     """ | ||||||
|  |     web_client.suppress_errors = True | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=requests.HTTPError()) | ||||||
|  |     logging_mock = mocker.patch("logging.exception") | ||||||
|  |  | ||||||
|  |     web_client.package_dependencies_update(package_ahriman.base, Dependencies()) | ||||||
|     logging_mock.assert_not_called() |     logging_mock.assert_not_called() | ||||||
|  |  | ||||||
|  |  | ||||||
| @ -291,7 +382,7 @@ def test_package_get_single(web_client: WebClient, package_ahriman: Package, moc | |||||||
|     assert (package_ahriman, BuildStatusEnum.Unknown) in [(package, status.status) for package, status in result] |     assert (package_ahriman, BuildStatusEnum.Unknown) in [(package, status.status) for package, status in result] | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_logs(web_client: WebClient, log_record: logging.LogRecord, package_ahriman: Package, | def test_package_logs_add(web_client: WebClient, log_record: logging.LogRecord, package_ahriman: Package, | ||||||
|                           mocker: MockerFixture) -> None: |                           mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must process log record |     must process log record | ||||||
| @ -303,12 +394,13 @@ def test_package_logs(web_client: WebClient, log_record: logging.LogRecord, pack | |||||||
|         "version": package_ahriman.version, |         "version": package_ahriman.version, | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     web_client.package_logs(LogRecordId(package_ahriman.base, package_ahriman.version), log_record) |     web_client.package_logs_add(LogRecordId(package_ahriman.base, package_ahriman.version), | ||||||
|  |                                 log_record.created, log_record.getMessage()) | ||||||
|     requests_mock.assert_called_once_with("POST", pytest.helpers.anyvar(str, True), |     requests_mock.assert_called_once_with("POST", pytest.helpers.anyvar(str, True), | ||||||
|                                           params=web_client.repository_id.query(), json=payload, suppress_errors=True) |                                           params=web_client.repository_id.query(), json=payload, suppress_errors=True) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_logs_failed(web_client: WebClient, log_record: logging.LogRecord, package_ahriman: Package, | def test_package_logs_add_failed(web_client: WebClient, log_record: logging.LogRecord, package_ahriman: Package, | ||||||
|                                  mocker: MockerFixture) -> None: |                                  mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must pass exception during log post |     must pass exception during log post | ||||||
| @ -316,18 +408,300 @@ def test_package_logs_failed(web_client: WebClient, log_record: logging.LogRecor | |||||||
|     mocker.patch("requests.Session.request", side_effect=Exception()) |     mocker.patch("requests.Session.request", side_effect=Exception()) | ||||||
|     log_record.package_base = package_ahriman.base |     log_record.package_base = package_ahriman.base | ||||||
|     with pytest.raises(Exception): |     with pytest.raises(Exception): | ||||||
|         web_client.package_logs(LogRecordId(package_ahriman.base, package_ahriman.version), log_record) |         web_client.package_logs_add(LogRecordId(package_ahriman.base, package_ahriman.version), | ||||||
|  |                                     log_record.created, log_record.getMessage()) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_logs_failed_http_error(web_client: WebClient, log_record: logging.LogRecord, package_ahriman: Package, | def test_package_logs_add_failed_http_error(web_client: WebClient, log_record: logging.LogRecord, | ||||||
|                                         mocker: MockerFixture) -> None: |                                             package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must pass exception during log post |     must pass exception during log post | ||||||
|     """ |     """ | ||||||
|     mocker.patch("requests.Session.request", side_effect=requests.HTTPError()) |     mocker.patch("requests.Session.request", side_effect=requests.HTTPError()) | ||||||
|     log_record.package_base = package_ahriman.base |     log_record.package_base = package_ahriman.base | ||||||
|     with pytest.raises(Exception): |     with pytest.raises(Exception): | ||||||
|         web_client.package_logs(LogRecordId(package_ahriman.base, package_ahriman.version), log_record) |         web_client.package_logs_add(LogRecordId(package_ahriman.base, package_ahriman.version), | ||||||
|  |                                     log_record.created, log_record.getMessage()) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_logs_get(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must get logs | ||||||
|  |     """ | ||||||
|  |     message = {"created": 42.0, "message": "log"} | ||||||
|  |     response_obj = requests.Response() | ||||||
|  |     response_obj._content = json.dumps([message]).encode("utf8") | ||||||
|  |     response_obj.status_code = 200 | ||||||
|  |  | ||||||
|  |     requests_mock = mocker.patch("ahriman.core.status.web_client.WebClient.make_request", return_value=response_obj) | ||||||
|  |  | ||||||
|  |     result = web_client.package_logs_get(package_ahriman.base, 1, 2) | ||||||
|  |     requests_mock.assert_called_once_with("GET", pytest.helpers.anyvar(str, True), | ||||||
|  |                                           params=web_client.repository_id.query() + [("limit", "1"), ("offset", "2")]) | ||||||
|  |     assert result == [(message["created"], message["message"])] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_logs_get_failed(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress any exception happened during logs fetch | ||||||
|  |     """ | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=Exception()) | ||||||
|  |     web_client.package_logs_get(package_ahriman.base) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_logs_get_failed_http_error(web_client: WebClient, package_ahriman: Package, | ||||||
|  |                                             mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress HTTP exception happened during logs fetch | ||||||
|  |     """ | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=requests.HTTPError()) | ||||||
|  |     web_client.package_logs_get(package_ahriman.base) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_logs_get_failed_suppress(web_client: WebClient, package_ahriman: Package, | ||||||
|  |                                           mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress any exception happened during logs fetch and don't log | ||||||
|  |     """ | ||||||
|  |     web_client.suppress_errors = True | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=Exception()) | ||||||
|  |     logging_mock = mocker.patch("logging.exception") | ||||||
|  |  | ||||||
|  |     web_client.package_logs_get(package_ahriman.base) | ||||||
|  |     logging_mock.assert_not_called() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_logs_get_failed_http_error_suppress(web_client: WebClient, package_ahriman: Package, | ||||||
|  |                                                      mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress HTTP exception happened during logs fetch and don't log | ||||||
|  |     """ | ||||||
|  |     web_client.suppress_errors = True | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=requests.HTTPError()) | ||||||
|  |     logging_mock = mocker.patch("logging.exception") | ||||||
|  |  | ||||||
|  |     web_client.package_logs_get(package_ahriman.base) | ||||||
|  |     logging_mock.assert_not_called() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_logs_remove(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must remove logs | ||||||
|  |     """ | ||||||
|  |     requests_mock = mocker.patch("ahriman.core.status.web_client.WebClient.make_request") | ||||||
|  |  | ||||||
|  |     web_client.package_logs_remove(package_ahriman.base, "42") | ||||||
|  |     requests_mock.assert_called_once_with("DELETE", pytest.helpers.anyvar(str, True), | ||||||
|  |                                           params=web_client.repository_id.query() + [("version", "42")]) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_logs_remove_failed(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress any exception happened during logs removal | ||||||
|  |     """ | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=Exception()) | ||||||
|  |     web_client.package_logs_remove(package_ahriman.base, "42") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_logs_remove_failed_http_error(web_client: WebClient, package_ahriman: Package, | ||||||
|  |                                                mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress HTTP exception happened during logs removal | ||||||
|  |     """ | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=requests.HTTPError()) | ||||||
|  |     web_client.package_logs_remove(package_ahriman.base, "42") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_logs_remove_failed_suppress(web_client: WebClient, package_ahriman: Package, | ||||||
|  |                                              mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress any exception happened during logs removal and don't log | ||||||
|  |     """ | ||||||
|  |     web_client.suppress_errors = True | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=Exception()) | ||||||
|  |     logging_mock = mocker.patch("logging.exception") | ||||||
|  |  | ||||||
|  |     web_client.package_logs_remove(package_ahriman.base, "42") | ||||||
|  |     logging_mock.assert_not_called() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_logs_remove_failed_http_error_suppress(web_client: WebClient, package_ahriman: Package, | ||||||
|  |                                                         mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress HTTP exception happened during logs removal and don't log | ||||||
|  |     """ | ||||||
|  |     web_client.suppress_errors = True | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=requests.HTTPError()) | ||||||
|  |     logging_mock = mocker.patch("logging.exception") | ||||||
|  |  | ||||||
|  |     web_client.package_logs_remove(package_ahriman.base, "42") | ||||||
|  |     logging_mock.assert_not_called() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_patches_get(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must get patches | ||||||
|  |     """ | ||||||
|  |     patch = PkgbuildPatch("key", "value") | ||||||
|  |     response_obj = requests.Response() | ||||||
|  |     response_obj._content = json.dumps(patch.view()).encode("utf8") | ||||||
|  |     response_obj.status_code = 200 | ||||||
|  |  | ||||||
|  |     requests_mock = mocker.patch("ahriman.core.status.web_client.WebClient.make_request", return_value=response_obj) | ||||||
|  |  | ||||||
|  |     result = web_client.package_patches_get(package_ahriman.base, "key") | ||||||
|  |     requests_mock.assert_called_once_with("GET", pytest.helpers.anyvar(str, True)) | ||||||
|  |     assert result == [patch] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_patches_get_failed(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress any exception happened during patches fetch | ||||||
|  |     """ | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=Exception()) | ||||||
|  |     web_client.package_patches_get(package_ahriman.base, None) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_patches_get_failed_http_error(web_client: WebClient, package_ahriman: Package, | ||||||
|  |                                                mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress HTTP exception happened during dependencies fetch | ||||||
|  |     """ | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=requests.HTTPError()) | ||||||
|  |     web_client.package_patches_get(package_ahriman.base, None) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_patches_get_failed_suppress(web_client: WebClient, package_ahriman: Package, | ||||||
|  |                                              mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress any exception happened during patches fetch and don't log | ||||||
|  |     """ | ||||||
|  |     web_client.suppress_errors = True | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=Exception()) | ||||||
|  |     logging_mock = mocker.patch("logging.exception") | ||||||
|  |  | ||||||
|  |     web_client.package_patches_get(package_ahriman.base, None) | ||||||
|  |     logging_mock.assert_not_called() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_patches_get_failed_http_error_suppress(web_client: WebClient, package_ahriman: Package, | ||||||
|  |                                                         mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress HTTP exception happened during patches fetch and don't log | ||||||
|  |     """ | ||||||
|  |     web_client.suppress_errors = True | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=requests.HTTPError()) | ||||||
|  |     logging_mock = mocker.patch("logging.exception") | ||||||
|  |  | ||||||
|  |     web_client.package_patches_get(package_ahriman.base, None) | ||||||
|  |     logging_mock.assert_not_called() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_patches_update(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must set patches | ||||||
|  |     """ | ||||||
|  |     patch = PkgbuildPatch("key", "value") | ||||||
|  |     requests_mock = mocker.patch("ahriman.core.status.web_client.WebClient.make_request") | ||||||
|  |  | ||||||
|  |     web_client.package_patches_update(package_ahriman.base, patch) | ||||||
|  |     requests_mock.assert_called_once_with("POST", pytest.helpers.anyvar(str, True), json=patch.view()) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_patches_update_failed(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress any exception happened during patches update | ||||||
|  |     """ | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=Exception()) | ||||||
|  |     web_client.package_patches_update(package_ahriman.base, PkgbuildPatch("key", "value")) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_patches_update_failed_http_error(web_client: WebClient, package_ahriman: Package, | ||||||
|  |                                                   mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress HTTP exception happened during patches update | ||||||
|  |     """ | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=requests.HTTPError()) | ||||||
|  |     web_client.package_patches_update(package_ahriman.base, PkgbuildPatch("key", "value")) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_patches_update_failed_suppress(web_client: WebClient, package_ahriman: Package, | ||||||
|  |                                                 mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress any exception happened during patches update and don't log | ||||||
|  |     """ | ||||||
|  |     web_client.suppress_errors = True | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=Exception()) | ||||||
|  |     logging_mock = mocker.patch("logging.exception") | ||||||
|  |  | ||||||
|  |     web_client.package_patches_update(package_ahriman.base, PkgbuildPatch("key", "value")) | ||||||
|  |     logging_mock.assert_not_called() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_patches_update_failed_http_error_suppress(web_client: WebClient, package_ahriman: Package, | ||||||
|  |                                                            mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress HTTP exception happened during patches update and don't log | ||||||
|  |     """ | ||||||
|  |     web_client.suppress_errors = True | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=requests.HTTPError()) | ||||||
|  |     logging_mock = mocker.patch("logging.exception") | ||||||
|  |  | ||||||
|  |     web_client.package_patches_update(package_ahriman.base, PkgbuildPatch("key", "value")) | ||||||
|  |     logging_mock.assert_not_called() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_patches_remove(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must remove patches | ||||||
|  |     """ | ||||||
|  |     requests_mock = mocker.patch("ahriman.core.status.web_client.WebClient.make_request") | ||||||
|  |  | ||||||
|  |     web_client.package_patches_remove(package_ahriman.base, "key") | ||||||
|  |     requests_mock.assert_called_once_with("DELETE", pytest.helpers.anyvar(str, True)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_patches_remove_failed(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress any exception happened during patches removal | ||||||
|  |     """ | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=Exception()) | ||||||
|  |     web_client.package_patches_remove(package_ahriman.base, None) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_patches_remove_failed_http_error(web_client: WebClient, package_ahriman: Package, | ||||||
|  |                                                   mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress HTTP exception happened during patches removal | ||||||
|  |     """ | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=requests.HTTPError()) | ||||||
|  |     web_client.package_patches_remove(package_ahriman.base, None) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_patches_remove_failed_suppress(web_client: WebClient, package_ahriman: Package, | ||||||
|  |                                                 mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress any exception happened during patches removal and don't log | ||||||
|  |     """ | ||||||
|  |     web_client.suppress_errors = True | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=Exception()) | ||||||
|  |     logging_mock = mocker.patch("logging.exception") | ||||||
|  |  | ||||||
|  |     web_client.package_patches_remove(package_ahriman.base, None) | ||||||
|  |     logging_mock.assert_not_called() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_patches_remove_failed_http_error_suppress(web_client: WebClient, package_ahriman: Package, | ||||||
|  |                                                            mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress HTTP exception happened during patches removal and don't log | ||||||
|  |     """ | ||||||
|  |     web_client.suppress_errors = True | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=requests.HTTPError()) | ||||||
|  |     logging_mock = mocker.patch("logging.exception") | ||||||
|  |  | ||||||
|  |     web_client.package_patches_remove(package_ahriman.base, None) | ||||||
|  |     logging_mock.assert_not_called() | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_remove(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | def test_package_remove(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
| @ -358,13 +732,13 @@ def test_package_remove_failed_http_error(web_client: WebClient, package_ahriman | |||||||
|     web_client.package_remove(package_ahriman.base) |     web_client.package_remove(package_ahriman.base) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_update(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | def test_package_status_update(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must process package update |     must process package update | ||||||
|     """ |     """ | ||||||
|     requests_mock = mocker.patch("ahriman.core.status.web_client.WebClient.make_request") |     requests_mock = mocker.patch("ahriman.core.status.web_client.WebClient.make_request") | ||||||
|  |  | ||||||
|     web_client.package_update(package_ahriman.base, BuildStatusEnum.Unknown) |     web_client.package_status_update(package_ahriman.base, BuildStatusEnum.Unknown) | ||||||
|     requests_mock.assert_called_once_with("POST", pytest.helpers.anyvar(str, True), |     requests_mock.assert_called_once_with("POST", pytest.helpers.anyvar(str, True), | ||||||
|                                           params=web_client.repository_id.query(), |                                           params=web_client.repository_id.query(), | ||||||
|                                           json={ |                                           json={ | ||||||
| @ -372,21 +746,75 @@ def test_package_update(web_client: WebClient, package_ahriman: Package, mocker: | |||||||
|     }) |     }) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_update_failed(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | def test_package_status_update_failed(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must suppress any exception happened during update |     must suppress any exception happened during update | ||||||
|     """ |     """ | ||||||
|     mocker.patch("requests.Session.request", side_effect=Exception()) |     mocker.patch("requests.Session.request", side_effect=Exception()) | ||||||
|     web_client.package_update(package_ahriman.base, BuildStatusEnum.Unknown) |     web_client.package_status_update(package_ahriman.base, BuildStatusEnum.Unknown) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_package_update_failed_http_error(web_client: WebClient, package_ahriman: Package, | def test_package_status_update_failed_http_error(web_client: WebClient, package_ahriman: Package, | ||||||
|                                                  mocker: MockerFixture) -> None: |                                                  mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must suppress HTTP exception happened during update |     must suppress HTTP exception happened during update | ||||||
|     """ |     """ | ||||||
|     mocker.patch("requests.Session.request", side_effect=requests.HTTPError()) |     mocker.patch("requests.Session.request", side_effect=requests.HTTPError()) | ||||||
|     web_client.package_update(package_ahriman.base, BuildStatusEnum.Unknown) |     web_client.package_status_update(package_ahriman.base, BuildStatusEnum.Unknown) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_update(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must process package addition | ||||||
|  |     """ | ||||||
|  |     requests_mock = mocker.patch("ahriman.core.status.web_client.WebClient.make_request") | ||||||
|  |     payload = pytest.helpers.get_package_status(package_ahriman) | ||||||
|  |  | ||||||
|  |     web_client.package_update(package_ahriman, BuildStatusEnum.Unknown) | ||||||
|  |     requests_mock.assert_called_once_with("POST", pytest.helpers.anyvar(str, True), | ||||||
|  |                                           params=web_client.repository_id.query(), json=payload) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_update_failed(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress any exception happened during addition | ||||||
|  |     """ | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=Exception()) | ||||||
|  |     web_client.package_update(package_ahriman, BuildStatusEnum.Unknown) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_update_failed_http_error(web_client: WebClient, package_ahriman: Package, | ||||||
|  |                                           mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress HTTP exception happened during addition | ||||||
|  |     """ | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=requests.HTTPError()) | ||||||
|  |     web_client.package_update(package_ahriman, BuildStatusEnum.Unknown) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_update_failed_suppress(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress any exception happened during addition and don't log | ||||||
|  |     """ | ||||||
|  |     web_client.suppress_errors = True | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=Exception()) | ||||||
|  |     logging_mock = mocker.patch("logging.exception") | ||||||
|  |  | ||||||
|  |     web_client.package_update(package_ahriman, BuildStatusEnum.Unknown) | ||||||
|  |     logging_mock.assert_not_called() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_update_failed_http_error_suppress(web_client: WebClient, package_ahriman: Package, | ||||||
|  |                                                    mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must suppress HTTP exception happened during addition and don't log | ||||||
|  |     """ | ||||||
|  |     web_client.suppress_errors = True | ||||||
|  |     mocker.patch("requests.Session.request", side_effect=requests.HTTPError()) | ||||||
|  |     logging_mock = mocker.patch("logging.exception") | ||||||
|  |  | ||||||
|  |     web_client.package_update(package_ahriman, BuildStatusEnum.Unknown) | ||||||
|  |     logging_mock.assert_not_called() | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_status_get(web_client: WebClient, mocker: MockerFixture) -> None: | def test_status_get(web_client: WebClient, mocker: MockerFixture) -> None: | ||||||
|  | |||||||
| @ -1,8 +1,7 @@ | |||||||
| import pytest | from pathlib import Path | ||||||
|  |  | ||||||
| from pytest_mock import MockerFixture | from pytest_mock import MockerFixture | ||||||
|  |  | ||||||
| from ahriman.core.database import SQLite | from ahriman.core.status import Client | ||||||
| from ahriman.core.support.package_creator import PackageCreator | from ahriman.core.support.package_creator import PackageCreator | ||||||
| from ahriman.models.package import Package | from ahriman.models.package import Package | ||||||
| from ahriman.models.package_description import PackageDescription | from ahriman.models.package_description import PackageDescription | ||||||
| @ -10,32 +9,52 @@ from ahriman.models.package_source import PackageSource | |||||||
| from ahriman.models.remote_source import RemoteSource | from ahriman.models.remote_source import RemoteSource | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_run(package_creator: PackageCreator, database: SQLite, mocker: MockerFixture) -> None: | def test_package_create(package_creator: PackageCreator, mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must correctly process package creation |     must create package | ||||||
|     """ |     """ | ||||||
|  |     path = Path("local") | ||||||
|  |     rmtree_mock = mocker.patch("shutil.rmtree") | ||||||
|  |     mkdir_mock = mocker.patch("pathlib.Path.mkdir") | ||||||
|  |     write_mock = mocker.patch("ahriman.core.support.pkgbuild.pkgbuild_generator.PkgbuildGenerator.write_pkgbuild") | ||||||
|  |     init_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.init") | ||||||
|  |  | ||||||
|  |     package_creator.package_create(path) | ||||||
|  |     rmtree_mock.assert_called_once_with(path, ignore_errors=True) | ||||||
|  |     mkdir_mock.assert_called_once_with(mode=0o755, parents=True, exist_ok=True) | ||||||
|  |     write_mock.assert_called_once_with(path) | ||||||
|  |     init_mock.assert_called_once_with(path) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_package_register(package_creator: PackageCreator, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must register package | ||||||
|  |     """ | ||||||
|  |     path = Path("local") | ||||||
|     package = Package( |     package = Package( | ||||||
|         base=package_creator.generator.pkgname, |         base=package_creator.generator.pkgname, | ||||||
|         version=package_creator.generator.pkgver, |         version=package_creator.generator.pkgver, | ||||||
|         remote=RemoteSource(source=PackageSource.Local), |         remote=RemoteSource(source=PackageSource.Local), | ||||||
|         packages={package_creator.generator.pkgname: PackageDescription()}, |         packages={package_creator.generator.pkgname: PackageDescription()}, | ||||||
|     ) |     ) | ||||||
|     local_path = package_creator.configuration.repository_paths.cache_for(package_creator.generator.pkgname) |     client_mock = mocker.patch("ahriman.core._Context.get", return_value=Client()) | ||||||
|  |     insert_mock = mocker.patch("ahriman.core.status.Client.set_unknown") | ||||||
|     rmtree_mock = mocker.patch("shutil.rmtree") |  | ||||||
|     database_mock = mocker.patch("ahriman.core._Context.get", return_value=database) |  | ||||||
|     init_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.init") |  | ||||||
|     insert_mock = mocker.patch("ahriman.core.database.SQLite.package_update") |  | ||||||
|     mkdir_mock = mocker.patch("pathlib.Path.mkdir") |  | ||||||
|     package_mock = mocker.patch("ahriman.models.package.Package.from_build", return_value=package) |     package_mock = mocker.patch("ahriman.models.package.Package.from_build", return_value=package) | ||||||
|     write_mock = mocker.patch("ahriman.core.support.pkgbuild.pkgbuild_generator.PkgbuildGenerator.write_pkgbuild") |  | ||||||
|  |     package_creator.package_register(path) | ||||||
|  |     package_mock.assert_called_once_with(path, "x86_64", None) | ||||||
|  |     client_mock.assert_called_once_with(Client) | ||||||
|  |     insert_mock.assert_called_once_with(package) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_run(package_creator: PackageCreator, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must correctly process package creation | ||||||
|  |     """ | ||||||
|  |     path = package_creator.configuration.repository_paths.cache_for(package_creator.generator.pkgname) | ||||||
|  |     create_mock = mocker.patch("ahriman.core.support.package_creator.PackageCreator.package_create") | ||||||
|  |     register_mock = mocker.patch("ahriman.core.support.package_creator.PackageCreator.package_register") | ||||||
|  |  | ||||||
|     package_creator.run() |     package_creator.run() | ||||||
|     rmtree_mock.assert_called_once_with(local_path, ignore_errors=True) |     create_mock.assert_called_once_with(path) | ||||||
|     mkdir_mock.assert_called_once_with(mode=0o755, parents=True, exist_ok=True) |     register_mock.assert_called_once_with(path) | ||||||
|     write_mock.assert_called_once_with(local_path) |  | ||||||
|     init_mock.assert_called_once_with(local_path) |  | ||||||
|  |  | ||||||
|     package_mock.assert_called_once_with(local_path, "x86_64", None) |  | ||||||
|     database_mock.assert_called_once_with(SQLite) |  | ||||||
|     insert_mock.assert_called_once_with(package, pytest.helpers.anyvar(int)) |  | ||||||
|  | |||||||
| @ -2,7 +2,6 @@ import datetime | |||||||
| import logging | import logging | ||||||
| import os | import os | ||||||
| import pytest | import pytest | ||||||
| import shlex |  | ||||||
|  |  | ||||||
| from pathlib import Path | from pathlib import Path | ||||||
| from pytest_mock import MockerFixture | from pytest_mock import MockerFixture | ||||||
|  | |||||||
| @ -0,0 +1,9 @@ | |||||||
|  | from ahriman.models.dependencies import Dependencies | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_from_json_view() -> None: | ||||||
|  |     """ | ||||||
|  |     must construct and serialize dependencies to json | ||||||
|  |     """ | ||||||
|  |     dependencies = Dependencies({"/usr/bin/python3": ["python"]}) | ||||||
|  |     assert Dependencies.from_json(dependencies.view()) == dependencies | ||||||
|  | |||||||
| @ -65,13 +65,11 @@ def test_depends_on(package_archive_ahriman: PackageArchive, mocker: MockerFixtu | |||||||
|     )) |     )) | ||||||
|  |  | ||||||
|     result = package_archive_ahriman.depends_on() |     result = package_archive_ahriman.depends_on() | ||||||
|     assert result.package_base == package_archive_ahriman.package.base |  | ||||||
|     assert result.paths == { |     assert result.paths == { | ||||||
|         Path("package1") / "file1": ["package1"], |         "package1/file1": ["package1"], | ||||||
|         Path("package2") / "file3": ["package2"], |         "package2/file3": ["package2"], | ||||||
|         Path("package2") / "dir4": ["package2"], |         "package2/dir4": ["package2"], | ||||||
|         Path("package2") / "file3": ["package2"], |         "usr/dir2": ["package1", "package2"] | ||||||
|         Path("usr") / "dir2": ["package1", "package2"] |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | |||||||
| @ -51,6 +51,14 @@ def test_from_env() -> None: | |||||||
|     assert PkgbuildPatch.from_env("KEY") == PkgbuildPatch("KEY", "") |     assert PkgbuildPatch.from_env("KEY") == PkgbuildPatch("KEY", "") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_from_json_view() -> None: | ||||||
|  |     """ | ||||||
|  |     must correctly serialize to json | ||||||
|  |     """ | ||||||
|  |     patch = PkgbuildPatch("key", "value") | ||||||
|  |     assert PkgbuildPatch.from_json(patch.view()) == patch | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_parse() -> None: | def test_parse() -> None: | ||||||
|     """ |     """ | ||||||
|     must parse string correctly |     must parse string correctly | ||||||
| @ -124,13 +132,6 @@ def test_serialize_list() -> None: | |||||||
|     assert PkgbuildPatch("key", ["val'ue", "val\"ue2"]).serialize() == """key=('val'"'"'ue' 'val"ue2')""" |     assert PkgbuildPatch("key", ["val'ue", "val\"ue2"]).serialize() == """key=('val'"'"'ue' 'val"ue2')""" | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_view() -> None: |  | ||||||
|     """ |  | ||||||
|     must correctly serialize to json |  | ||||||
|     """ |  | ||||||
|     assert PkgbuildPatch("key", "value").view() == {"key": "key", "value": "value"} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_write(mocker: MockerFixture) -> None: | def test_write(mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must write serialized value to the file |     must write serialized value to the file | ||||||
|  | |||||||
| @ -60,4 +60,4 @@ def test_lt_invalid() -> None: | |||||||
|     must raise ValueError if other is not valid repository id |     must raise ValueError if other is not valid repository id | ||||||
|     """ |     """ | ||||||
|     with pytest.raises(ValueError): |     with pytest.raises(ValueError): | ||||||
|         RepositoryId("x86_64", "a") < 42 |         assert RepositoryId("x86_64", "a") < 42 | ||||||
|  | |||||||
							
								
								
									
										1
									
								
								tests/ahriman/web/schemas/test_dependencies_schema.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/ahriman/web/schemas/test_dependencies_schema.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | # schema testing goes in view class tests | ||||||
							
								
								
									
										1
									
								
								tests/ahriman/web/schemas/test_package_version_schema.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/ahriman/web/schemas/test_package_version_schema.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | # schema testing goes in view class tests | ||||||
| @ -204,6 +204,15 @@ def test_service_not_found(base: BaseView) -> None: | |||||||
|         base.service(RepositoryId("", "")) |         base.service(RepositoryId("", "")) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_service_package(base: BaseView, repository_id: RepositoryId, mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must validate that package exists | ||||||
|  |     """ | ||||||
|  |     mocker.patch("ahriman.web.views.base.BaseView.repository_id", return_value=repository_id) | ||||||
|  |     with pytest.raises(HTTPNotFound): | ||||||
|  |         base.service(package_base="base") | ||||||
|  |  | ||||||
|  |  | ||||||
| async def test_username(base: BaseView, mocker: MockerFixture) -> None: | async def test_username(base: BaseView, mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must return identity of logged-in user |     must return identity of logged-in user | ||||||
|  | |||||||
| @ -0,0 +1,97 @@ | |||||||
|  | import pytest | ||||||
|  |  | ||||||
|  | from aiohttp.test_utils import TestClient | ||||||
|  |  | ||||||
|  | from ahriman.models.build_status import BuildStatusEnum | ||||||
|  | from ahriman.models.dependencies import Dependencies | ||||||
|  | from ahriman.models.package import Package | ||||||
|  | from ahriman.models.user_access import UserAccess | ||||||
|  | from ahriman.web.views.v1.packages.dependencies import DependenciesView | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def test_get_permission() -> None: | ||||||
|  |     """ | ||||||
|  |     must return correct permission for the request | ||||||
|  |     """ | ||||||
|  |     for method in ("GET",): | ||||||
|  |         request = pytest.helpers.request("", "", method) | ||||||
|  |         assert await DependenciesView.get_permission(request) == UserAccess.Reporter | ||||||
|  |     for method in ("POST",): | ||||||
|  |         request = pytest.helpers.request("", "", method) | ||||||
|  |         assert await DependenciesView.get_permission(request) == UserAccess.Full | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_routes() -> None: | ||||||
|  |     """ | ||||||
|  |     must return correct routes | ||||||
|  |     """ | ||||||
|  |     assert DependenciesView.ROUTES == ["/api/v1/packages/{package}/dependencies"] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def test_get(client: TestClient, package_ahriman: Package) -> None: | ||||||
|  |     """ | ||||||
|  |     must get dependencies for package | ||||||
|  |     """ | ||||||
|  |     dependency = Dependencies({"path": ["package"]}) | ||||||
|  |     await client.post(f"/api/v1/packages/{package_ahriman.base}", | ||||||
|  |                       json={"status": BuildStatusEnum.Success.value, "package": package_ahriman.view()}) | ||||||
|  |     await client.post(f"/api/v1/packages/{package_ahriman.base}/dependencies", json=dependency.view()) | ||||||
|  |     response_schema = pytest.helpers.schema_response(DependenciesView.get) | ||||||
|  |  | ||||||
|  |     response = await client.get(f"/api/v1/packages/{package_ahriman.base}/dependencies") | ||||||
|  |     assert response.status == 200 | ||||||
|  |  | ||||||
|  |     dependencies = await response.json() | ||||||
|  |     assert not response_schema.validate(dependencies) | ||||||
|  |     assert dependencies == dependency.view() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def test_get_not_found(client: TestClient, package_ahriman: Package) -> None: | ||||||
|  |     """ | ||||||
|  |     must return not found for missing package | ||||||
|  |     """ | ||||||
|  |     response_schema = pytest.helpers.schema_response(DependenciesView.get, code=404) | ||||||
|  |  | ||||||
|  |     response = await client.get(f"/api/v1/packages/{package_ahriman.base}/dependencies") | ||||||
|  |     assert response.status == 404 | ||||||
|  |     assert not response_schema.validate(await response.json()) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def test_post(client: TestClient, package_ahriman: Package) -> None: | ||||||
|  |     """ | ||||||
|  |     must create dependencies | ||||||
|  |     """ | ||||||
|  |     await client.post(f"/api/v1/packages/{package_ahriman.base}", | ||||||
|  |                       json={"status": BuildStatusEnum.Success.value, "package": package_ahriman.view()}) | ||||||
|  |     request_schema = pytest.helpers.schema_request(DependenciesView.post) | ||||||
|  |  | ||||||
|  |     payload = {"paths": {"path": ["package"]}} | ||||||
|  |     assert not request_schema.validate(payload) | ||||||
|  |     response = await client.post(f"/api/v1/packages/{package_ahriman.base}/dependencies", json=payload) | ||||||
|  |     assert response.status == 204 | ||||||
|  |  | ||||||
|  |     response = await client.get(f"/api/v1/packages/{package_ahriman.base}/dependencies") | ||||||
|  |     dependencies = await response.json() | ||||||
|  |     assert dependencies == payload | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def test_post_exception(client: TestClient, package_ahriman: Package) -> None: | ||||||
|  |     """ | ||||||
|  |     must raise exception on invalid payload | ||||||
|  |     """ | ||||||
|  |     response_schema = pytest.helpers.schema_response(DependenciesView.post, code=400) | ||||||
|  |  | ||||||
|  |     response = await client.post(f"/api/v1/packages/{package_ahriman.base}/dependencies", json=[]) | ||||||
|  |     assert response.status == 400 | ||||||
|  |     assert not response_schema.validate(await response.json()) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def test_post_not_found(client: TestClient, package_ahriman: Package) -> None: | ||||||
|  |     """ | ||||||
|  |     must raise exception on unknown package | ||||||
|  |     """ | ||||||
|  |     response_schema = pytest.helpers.schema_response(DependenciesView.post, code=404) | ||||||
|  |  | ||||||
|  |     response = await client.post(f"/api/v1/packages/{package_ahriman.base}/dependencies", json={}) | ||||||
|  |     assert response.status == 404 | ||||||
|  |     assert not response_schema.validate(await response.json()) | ||||||
| @ -37,9 +37,21 @@ async def test_delete(client: TestClient, package_ahriman: Package, package_pyth | |||||||
|                       json={"status": BuildStatusEnum.Success.value, "package": package_python_schedule.view()}) |                       json={"status": BuildStatusEnum.Success.value, "package": package_python_schedule.view()}) | ||||||
|  |  | ||||||
|     await client.post(f"/api/v1/packages/{package_ahriman.base}/logs", |     await client.post(f"/api/v1/packages/{package_ahriman.base}/logs", | ||||||
|                       json={"created": 42.0, "message": "message", "version": "42"}) |                       json={"created": 42.0, "message": "message 1", "version": "42"}) | ||||||
|     await client.post(f"/api/v1/packages/{package_python_schedule.base}/logs", |     await client.post(f"/api/v1/packages/{package_python_schedule.base}/logs", | ||||||
|                       json={"created": 42.0, "message": "message", "version": "42"}) |                       json={"created": 42.0, "message": "message 2", "version": "42"}) | ||||||
|  |     request_schema = pytest.helpers.schema_request(LogsView.delete, location="querystring") | ||||||
|  |  | ||||||
|  |     payload = {} | ||||||
|  |     assert not request_schema.validate(payload) | ||||||
|  |     payload = {"version": "42"} | ||||||
|  |  | ||||||
|  |     response = await client.delete(f"/api/v1/packages/{package_ahriman.base}/logs", params=payload) | ||||||
|  |     assert response.status == 204 | ||||||
|  |  | ||||||
|  |     response = await client.get(f"/api/v1/packages/{package_ahriman.base}/logs") | ||||||
|  |     logs = await response.json() | ||||||
|  |     assert logs["logs"] | ||||||
|  |  | ||||||
|     response = await client.delete(f"/api/v1/packages/{package_ahriman.base}/logs") |     response = await client.delete(f"/api/v1/packages/{package_ahriman.base}/logs") | ||||||
|     assert response.status == 204 |     assert response.status == 204 | ||||||
|  | |||||||
| @ -64,6 +64,24 @@ async def test_post(client: TestClient, package_ahriman: Package) -> None: | |||||||
|     assert patches == [payload] |     assert patches == [payload] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def test_post_full_diff(client: TestClient, package_ahriman: Package) -> None: | ||||||
|  |     """ | ||||||
|  |     must create patch from full diff | ||||||
|  |     """ | ||||||
|  |     await client.post(f"/api/v1/packages/{package_ahriman.base}", | ||||||
|  |                       json={"status": BuildStatusEnum.Success.value, "package": package_ahriman.view()}) | ||||||
|  |     request_schema = pytest.helpers.schema_request(PatchesView.post) | ||||||
|  |  | ||||||
|  |     payload = {"value": "v"} | ||||||
|  |     assert not request_schema.validate(payload) | ||||||
|  |     response = await client.post(f"/api/v1/packages/{package_ahriman.base}/patches", json=payload) | ||||||
|  |     assert response.status == 204 | ||||||
|  |  | ||||||
|  |     response = await client.get(f"/api/v1/packages/{package_ahriman.base}/patches") | ||||||
|  |     patches = await response.json() | ||||||
|  |     assert patches == [payload] | ||||||
|  |  | ||||||
|  |  | ||||||
| async def test_post_exception(client: TestClient, package_ahriman: Package) -> None: | async def test_post_exception(client: TestClient, package_ahriman: Package) -> None: | ||||||
|     """ |     """ | ||||||
|     must raise exception on invalid payload |     must raise exception on invalid payload | ||||||
|  | |||||||
| @ -30,7 +30,7 @@ async def test_get(client: TestClient, repository_id: RepositoryId) -> None: | |||||||
|     """ |     """ | ||||||
|     response_schema = pytest.helpers.schema_response(InfoView.get) |     response_schema = pytest.helpers.schema_response(InfoView.get) | ||||||
|  |  | ||||||
|     response = await client.get(f"/api/v1/info") |     response = await client.get("/api/v1/info") | ||||||
|     assert response.ok |     assert response.ok | ||||||
|     json = await response.json() |     json = await response.json() | ||||||
|     assert not response_schema.validate(json) |     assert not response_schema.validate(json) | ||||||
|  | |||||||
| @ -29,7 +29,7 @@ async def test_get(client: TestClient, repository_id: RepositoryId) -> None: | |||||||
|     """ |     """ | ||||||
|     response_schema = pytest.helpers.schema_response(RepositoriesView.get) |     response_schema = pytest.helpers.schema_response(RepositoriesView.get) | ||||||
|  |  | ||||||
|     response = await client.get(f"/api/v1/repositories") |     response = await client.get("/api/v1/repositories") | ||||||
|     assert response.ok |     assert response.ok | ||||||
|     json = await response.json() |     json = await response.json() | ||||||
|     assert not response_schema.validate(json, many=True) |     assert not response_schema.validate(json, many=True) | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user