diff --git a/src/ahriman/application/ahriman.py b/src/ahriman/application/ahriman.py
index 1f4b5477..4713fdf8 100644
--- a/src/ahriman/application/ahriman.py
+++ b/src/ahriman/application/ahriman.py
@@ -446,7 +446,7 @@ def _set_patch_list_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
parser = root.add_parser("patch-list", help="list patch sets",
description="list available patches for the package", formatter_class=_formatter)
- parser.add_argument("package", help="package base", nargs="?")
+ parser.add_argument("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("-v", "--variable", help="if set, show only patches for specified PKGBUILD variables",
action="append")
diff --git a/src/ahriman/application/application/application.py b/src/ahriman/application/application/application.py
index 4ec45a61..11f1d758 100644
--- a/src/ahriman/application/application/application.py
+++ b/src/ahriman/application/application/application.py
@@ -161,8 +161,7 @@ class Application(ApplicationPackages, ApplicationRepository):
package = Package.from_aur(package_name, username)
with_dependencies[package.base] = package
- # register package in local database
- self.database.package_base_update(package)
+ # register package in the database
self.repository.reporter.set_unknown(package)
return list(with_dependencies.values())
diff --git a/src/ahriman/application/application/application_packages.py b/src/ahriman/application/application/application_packages.py
index 5ff74826..45e62a89 100644
--- a/src/ahriman/application/application/application_packages.py
+++ b/src/ahriman/application/application/application_packages.py
@@ -65,7 +65,7 @@ class ApplicationPackages(ApplicationProperties):
"""
package = Package.from_aur(source, username)
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:
"""
@@ -139,7 +139,7 @@ class ApplicationPackages(ApplicationProperties):
"""
package = Package.from_official(source, self.repository.pacman, username)
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:
"""
diff --git a/src/ahriman/application/application/application_properties.py b/src/ahriman/application/application/application_properties.py
index 9d5ba208..4b9c5a59 100644
--- a/src/ahriman/application/application/application_properties.py
+++ b/src/ahriman/application/application/application_properties.py
@@ -21,6 +21,7 @@ from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite
from ahriman.core.log import LazyLogging
from ahriman.core.repository import Repository
+from ahriman.core.status import Client
from ahriman.models.pacman_synchronization import PacmanSynchronization
from ahriman.models.repository_id import RepositoryId
@@ -63,3 +64,13 @@ class ApplicationProperties(LazyLogging):
str: repository 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
diff --git a/src/ahriman/application/application/application_repository.py b/src/ahriman/application/application/application_repository.py
index f4547c75..6ac306db 100644
--- a/src/ahriman/application/application/application_repository.py
+++ b/src/ahriman/application/application/application_repository.py
@@ -39,15 +39,13 @@ class ApplicationRepository(ApplicationProperties):
Args:
packages(Iterable[Package]): list of packages to retrieve changes
"""
- last_commit_hashes = self.database.hashes_get()
-
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:
continue # skip check in case if we can't calculate diff
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:
"""
diff --git a/src/ahriman/application/handlers/add.py b/src/ahriman/application/handlers/add.py
index ac185e1c..e567c4aa 100644
--- a/src/ahriman/application/handlers/add.py
+++ b/src/ahriman/application/handlers/add.py
@@ -50,7 +50,8 @@ class Add(Handler):
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 []
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:
return
diff --git a/src/ahriman/application/handlers/change.py b/src/ahriman/application/handlers/change.py
index cac737ea..1764b133 100644
--- a/src/ahriman/application/handlers/change.py
+++ b/src/ahriman/application/handlers/change.py
@@ -56,4 +56,4 @@ class Change(Handler):
ChangesPrinter(changes)(verbose=True, separator="")
Change.check_if_empty(args.exit_code, changes.is_empty)
case Action.Remove:
- client.package_changes_set(args.package, Changes())
+ client.package_changes_update(args.package, Changes())
diff --git a/src/ahriman/application/handlers/patch.py b/src/ahriman/application/handlers/patch.py
index 0f131257..ef58e068 100644
--- a/src/ahriman/application/handlers/patch.py
+++ b/src/ahriman/application/handlers/patch.py
@@ -116,25 +116,28 @@ class Patch(Handler):
package_base(str): package base
patch(PkgbuildPatch): patch descriptor
"""
- application.database.patches_insert(package_base, [patch])
+ application.reporter.package_patches_update(package_base, patch)
@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:
"""
list patches available for the package base
Args:
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
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)
- for base, patch in patches.items():
- PatchPrinter(base, patch)(verbose=True, separator=" = ")
+ PatchPrinter(package_base, patches)(verbose=True, separator=" = ")
@staticmethod
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
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
diff --git a/src/ahriman/application/handlers/rebuild.py b/src/ahriman/application/handlers/rebuild.py
index 5313c5b0..344b18a0 100644
--- a/src/ahriman/application/handlers/rebuild.py
+++ b/src/ahriman/application/handlers/rebuild.py
@@ -76,7 +76,7 @@ class Rebuild(Handler):
if from_database:
return [
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
]
diff --git a/src/ahriman/application/handlers/status_update.py b/src/ahriman/application/handlers/status_update.py
index 3b1637b0..085060fe 100644
--- a/src/ahriman/application/handlers/status_update.py
+++ b/src/ahriman/application/handlers/status_update.py
@@ -51,12 +51,8 @@ class StatusUpdate(Handler):
match args.action:
case Action.Update if args.package:
# update packages statuses
- packages = application.repository.packages()
- for base in args.package:
- 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)
+ for package in args.package:
+ client.package_update(package, args.status)
case Action.Update:
# update service status
client.status_update(args.status)
diff --git a/src/ahriman/application/lock.py b/src/ahriman/application/lock.py
index a0d3610f..58b0cdc3 100644
--- a/src/ahriman/application/lock.py
+++ b/src/ahriman/application/lock.py
@@ -27,7 +27,7 @@ from ahriman import __version__
from ahriman.core.configuration import Configuration
from ahriman.core.exceptions import DuplicateRunError
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.models.build_status import BuildStatusEnum
from ahriman.models.repository_id import RepositoryId
diff --git a/src/ahriman/core/alpm/pacman.py b/src/ahriman/core/alpm/pacman.py
index 66b52269..8f717093 100644
--- a/src/ahriman/core/alpm/pacman.py
+++ b/src/ahriman/core/alpm/pacman.py
@@ -177,7 +177,7 @@ class Pacman(LazyLogging):
PacmanDatabase(database, self.configuration).sync(force=force)
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
@@ -185,11 +185,11 @@ class Pacman(LazyLogging):
packages(Iterable[str] | None, optional): filter by package names (Default value = None)
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 []
- 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()):
package, *_ = str(Path(descriptor.path).parent).rsplit("-", 2)
if packages and package not in packages:
@@ -197,11 +197,11 @@ class Pacman(LazyLogging):
content = tar.extractfile(descriptor)
if content is None:
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
- result: dict[str, set[Path]] = {}
+ result: dict[str, set[str]] = {}
for database in self.handle.get_syncdbs():
database_file = self.repository_paths.pacman / "sync" / f"{database.name}.files.tar.gz"
if not database_file.is_file():
diff --git a/src/ahriman/core/build_tools/task.py b/src/ahriman/core/build_tools/task.py
index ea5f05bf..12bf1aa6 100644
--- a/src/ahriman/core/build_tools/task.py
+++ b/src/ahriman/core/build_tools/task.py
@@ -21,7 +21,6 @@ from pathlib import Path
from ahriman.core.build_tools.sources import Sources
from ahriman.core.configuration import Configuration
-from ahriman.core.database import SQLite
from ahriman.core.exceptions import BuildError
from ahriman.core.log import LazyLogging
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
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
Args:
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
automatically bump pkgrel
Returns:
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:
return last_commit_sha # there is no local package or pkgrel increment is disabled
diff --git a/src/ahriman/core/database/operations/changes_operations.py b/src/ahriman/core/database/operations/changes_operations.py
index 53fe6495..cba29cf3 100644
--- a/src/ahriman/core/database/operations/changes_operations.py
+++ b/src/ahriman/core/database/operations/changes_operations.py
@@ -117,27 +117,3 @@ class ChangesOperations(Operations):
})
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)
diff --git a/src/ahriman/core/database/operations/dependencies_operations.py b/src/ahriman/core/database/operations/dependencies_operations.py
index e5ee99ac..1f2a7780 100644
--- a/src/ahriman/core/database/operations/dependencies_operations.py
+++ b/src/ahriman/core/database/operations/dependencies_operations.py
@@ -17,7 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from pathlib import Path
from sqlite3 import Connection
from ahriman.core.database.operations.operations import Operations
@@ -31,7 +30,7 @@ class DependenciesOperations(Operations):
"""
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
@@ -44,15 +43,9 @@ class DependenciesOperations(Operations):
"""
repository_id = repository_id or self._repository_id
- def run(connection: Connection) -> list[Dependencies]:
- return [
- Dependencies(
- row["package_base"],
- {
- Path(path): packages
- for path, packages in row["dependencies"].items()
- }
- )
+ def run(connection: Connection) -> dict[str, Dependencies]:
+ return {
+ row["package_base"]: Dependencies(row["dependencies"])
for row in connection.execute(
"""
select package_base, dependencies from package_dependencies
@@ -64,15 +57,17 @@ class DependenciesOperations(Operations):
"repository": repository_id.id,
}
)
- ]
+ }
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
Args:
+ package_base(str): package base
dependencies(Dependencies): package dependencies
repository_id(RepositoryId, optional): repository unique identifier override (Default value = None)
"""
@@ -89,12 +84,9 @@ class DependenciesOperations(Operations):
dependencies = :dependencies
""",
{
- "package_base": dependencies.package_base,
+ "package_base": package_base,
"repository": repository_id.id,
- "dependencies": {
- str(path): packages
- for path, packages in dependencies.paths.items()
- }
+ "dependencies": dependencies.paths,
})
return self.with_connection(run, commit=True)
diff --git a/src/ahriman/core/database/operations/operations.py b/src/ahriman/core/database/operations/operations.py
index 09dbee59..b2d0631c 100644
--- a/src/ahriman/core/database/operations/operations.py
+++ b/src/ahriman/core/database/operations/operations.py
@@ -25,6 +25,7 @@ from typing import Any, TypeVar
from ahriman.core.log import LazyLogging
from ahriman.models.repository_id import RepositoryId
+from ahriman.models.repository_paths import RepositoryPaths
T = TypeVar("T")
@@ -38,7 +39,7 @@ class Operations(LazyLogging):
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
@@ -48,6 +49,7 @@ class Operations(LazyLogging):
"""
self.path = path
self._repository_id = repository_id
+ self._repository_paths = repository_paths
@staticmethod
def factory(cursor: sqlite3.Cursor, row: tuple[Any, ...]) -> dict[str, Any]:
diff --git a/src/ahriman/core/database/operations/package_operations.py b/src/ahriman/core/database/operations/package_operations.py
index 812d0009..1aeffda3 100644
--- a/src/ahriman/core/database/operations/package_operations.py
+++ b/src/ahriman/core/database/operations/package_operations.py
@@ -150,34 +150,6 @@ class PackageOperations(Operations):
""",
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
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:
"""
remove package from database
@@ -277,20 +234,18 @@ class PackageOperations(Operations):
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
Args:
package(Package): package properties
- status(BuildStatus): new build status
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)
- self._package_update_insert_status(connection, package.base, status, repository_id)
self._package_update_insert_packages(connection, package, 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)))
- 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:
+ package_base(str): package base name
+ status(BuildStatus): new build status
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
- def run(connection: Connection) -> dict[str, Package]:
- return self._packages_get_select_package_bases(connection, repository_id)
+ def run(connection: Connection) -> None:
+ 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 {
- package_base: package.remote
- for package_base, package in self.with_connection(run).items()
- }
+ return self.with_connection(run, commit=True)
diff --git a/src/ahriman/core/database/sqlite.py b/src/ahriman/core/database/sqlite.py
index 06bcd2bb..e6d26d7e 100644
--- a/src/ahriman/core/database/sqlite.py
+++ b/src/ahriman/core/database/sqlite.py
@@ -66,7 +66,7 @@ class SQLite(
path = cls.database_path(configuration)
_, repository_id = configuration.check_loaded()
- database = cls(path, repository_id)
+ database = cls(path, repository_id, configuration.repository_paths)
database.init(configuration)
return database
@@ -119,3 +119,6 @@ class SQLite(
self.logs_remove(package_base, None)
self.changes_remove(package_base)
self.dependencies_remove(package_base)
+
+ # remove local cache too
+ self._repository_paths.tree_clear(package_base)
diff --git a/src/ahriman/core/gitremote/remote_push.py b/src/ahriman/core/gitremote/remote_push.py
index d51cc913..25ef0fb5 100644
--- a/src/ahriman/core/gitremote/remote_push.py
+++ b/src/ahriman/core/gitremote/remote_push.py
@@ -25,9 +25,9 @@ from tempfile import TemporaryDirectory
from ahriman.core.build_tools.sources import Sources
from ahriman.core.configuration import Configuration
-from ahriman.core.database import SQLite
from ahriman.core.exceptions import GitRemoteError
from ahriman.core.log import LazyLogging
+from ahriman.core.status import Client
from ahriman.models.package import Package
from ahriman.models.package_source import PackageSource
from ahriman.models.remote_source import RemoteSource
@@ -40,20 +40,20 @@ class RemotePush(LazyLogging):
Attributes:
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)
+ 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
Args:
- database(SQLite): database instance
+ reporter(Client): reporter client
configuration(Configuration): configuration instance
section(str): settings section name
"""
- self.database = database
+ self.reporter = reporter
commit_email = configuration.get(section, "commit_email", fallback="ahriman@localhost")
commit_user = configuration.get(section, "commit_user", fallback="ahriman")
@@ -92,7 +92,7 @@ class RemotePush(LazyLogging):
else:
shutil.rmtree(git_file)
# ...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"
patch.write(package_target_dir / filename)
# ...and finally return path to the copied directory
diff --git a/src/ahriman/core/gitremote/remote_push_trigger.py b/src/ahriman/core/gitremote/remote_push_trigger.py
index 44aa9166..3e45e678 100644
--- a/src/ahriman/core/gitremote/remote_push_trigger.py
+++ b/src/ahriman/core/gitremote/remote_push_trigger.py
@@ -19,8 +19,8 @@
#
from ahriman.core import context
from ahriman.core.configuration import Configuration
-from ahriman.core.database import SQLite
from ahriman.core.gitremote.remote_push import RemotePush
+from ahriman.core.status import Client
from ahriman.core.triggers import Trigger
from ahriman.models.package import Package
from ahriman.models.repository_id import RepositoryId
@@ -110,10 +110,10 @@ class RemotePushTrigger(Trigger):
GitRemoteError: if database is not set in context
"""
ctx = context.get()
- database = ctx.get(SQLite)
+ reporter = ctx.get(Client)
for target in self.targets:
section, _ = self.configuration.gettype(
target, self.repository_id, fallback=self.CONFIGURATION_SCHEMA_FALLBACK)
- runner = RemotePush(database, self.configuration, section)
+ runner = RemotePush(reporter, self.configuration, section)
runner.run(result)
diff --git a/src/ahriman/core/log/http_log_handler.py b/src/ahriman/core/log/http_log_handler.py
index f2b0fde3..86c3211d 100644
--- a/src/ahriman/core/log/http_log_handler.py
+++ b/src/ahriman/core/log/http_log_handler.py
@@ -22,6 +22,7 @@ import logging
from typing import Self
from ahriman.core.configuration import Configuration
+from ahriman.core.status import Client
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
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.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
try:
- self.reporter.package_logs(log_record_id, record)
+ self.reporter.package_logs_add(log_record_id, record.created, record.getMessage())
except Exception:
if self.suppress_errors:
return
diff --git a/src/ahriman/core/repository/executor.py b/src/ahriman/core/repository/executor.py
index 43033ab1..1037d107 100644
--- a/src/ahriman/core/repository/executor.py
+++ b/src/ahriman/core/repository/executor.py
@@ -58,7 +58,8 @@ class Executor(PackageInfo, Cleaner):
self.reporter.set_building(package.base)
task = Task(package, self.configuration, self.architecture, self.paths)
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)
for src in built:
dst = self.paths.packages / src.name
@@ -77,10 +78,10 @@ class Executor(PackageInfo, Cleaner):
packager = self.packager(packagers, single.base)
last_commit_sha = build_single(single, Path(dir_name), packager.packager_id)
# 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
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
result.add_updated(single)
except Exception:
@@ -102,9 +103,7 @@ class Executor(PackageInfo, Cleaner):
"""
def remove_base(package_base: str) -> None:
try:
- self.paths.tree_clear(package_base) # remove all internal files
- self.database.package_clear(package_base)
- self.reporter.package_remove(package_base) # we only update status page in case of base removal
+ self.reporter.package_remove(package_base)
except Exception:
self.logger.exception("could not remove base %s", package_base)
diff --git a/src/ahriman/core/repository/package_info.py b/src/ahriman/core/repository/package_info.py
index 56a6fef1..28ba659f 100644
--- a/src/ahriman/core/repository/package_info.py
+++ b/src/ahriman/core/repository/package_info.py
@@ -43,14 +43,14 @@ class PackageInfo(RepositoryProperties):
Returns:
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] = {}
# we are iterating over bases, not single packages
for full_path in packages:
try:
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
current = result.setdefault(local.base, local)
@@ -78,7 +78,8 @@ class PackageInfo(RepositoryProperties):
"""
with TemporaryDirectory(ignore_cleanup_errors=True) as 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
if current_commit_sha != last_commit_sha:
diff --git a/src/ahriman/core/repository/repository.py b/src/ahriman/core/repository/repository.py
index f9c97907..44c76413 100644
--- a/src/ahriman/core/repository/repository.py
+++ b/src/ahriman/core/repository/repository.py
@@ -26,6 +26,7 @@ from ahriman.core.database import SQLite
from ahriman.core.repository.executor import Executor
from ahriman.core.repository.update_handler import UpdateHandler
from ahriman.core.sign.gpg import GPG
+from ahriman.core.status import Client
from ahriman.models.pacman_synchronization import PacmanSynchronization
from ahriman.models.repository_id import RepositoryId
@@ -92,6 +93,7 @@ class Repository(Executor, UpdateHandler):
ctx.set(Configuration, self.configuration)
ctx.set(Pacman, self.pacman)
ctx.set(GPG, self.sign)
+ ctx.set(Client, self.reporter)
ctx.set(type(self), self)
diff --git a/src/ahriman/core/repository/repository_properties.py b/src/ahriman/core/repository/repository_properties.py
index 714b3c6d..67d84666 100644
--- a/src/ahriman/core/repository/repository_properties.py
+++ b/src/ahriman/core/repository/repository_properties.py
@@ -23,7 +23,7 @@ from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite
from ahriman.core.log import LazyLogging
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.models.packagers import Packagers
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.sign = GPG(configuration)
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)
@property
diff --git a/src/ahriman/core/repository/update_handler.py b/src/ahriman/core/repository/update_handler.py
index ca79f8b4..9658cee5 100644
--- a/src/ahriman/core/repository/update_handler.py
+++ b/src/ahriman/core/repository/update_handler.py
@@ -18,7 +18,6 @@
# along with this program. If not, see .
#
from collections.abc import Iterable
-from pathlib import Path
from ahriman.core.build_tools.sources import Sources
from ahriman.core.exceptions import UnknownPackageError
@@ -89,27 +88,25 @@ class UpdateHandler(PackageInfo, Cleaner):
Returns:
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)
- files: dict[Path, set[str]] = {}
+ files: dict[str, set[str]] = {}
for package_name, package_files in database_files.items(): # invert map
for package_file in package_files:
files.setdefault(package_file, set()).add(package_name)
return files
- dependencies = {dependency.package_base: dependency for dependency in self.database.dependencies_get()}
-
result: list[Package] = []
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
- required = dependencies[package.base].paths
- required_packages = {dep for dep_packages in required.values() for dep in dep_packages}
+ required_packages = {dep for dep_packages in dependencies.paths.values() for dep in dep_packages}
filesystem = extract_files(required_packages)
- for path, packages in required.items():
+ for path, packages in dependencies.paths.items():
found = filesystem.get(path, set())
if found.intersection(packages):
continue
diff --git a/src/ahriman/core/status/__init__.py b/src/ahriman/core/status/__init__.py
index 78e01321..daec2653 100644
--- a/src/ahriman/core/status/__init__.py
+++ b/src/ahriman/core/status/__init__.py
@@ -17,3 +17,4 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
+from ahriman.core.status.client import Client
diff --git a/src/ahriman/core/status/client.py b/src/ahriman/core/status/client.py
index 585f2aec..c8a3398e 100644
--- a/src/ahriman/core/status/client.py
+++ b/src/ahriman/core/status/client.py
@@ -17,16 +17,18 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
+# pylint: disable=too-many-public-methods
from __future__ import annotations
-import logging
-
from ahriman.core.configuration import Configuration
+from ahriman.core.database import SQLite
from ahriman.models.build_status import BuildStatus, BuildStatusEnum
from ahriman.models.changes import Changes
+from ahriman.models.dependencies import Dependencies
from ahriman.models.internal_status import InternalStatus
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
@@ -36,22 +38,31 @@ class Client:
"""
@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
Args:
repository_id(RepositoryId): repository unique identifier
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:
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:
- return Client()
+ return make_local_client()
if not configuration.getboolean("status", "enabled", fallback=True): # global switch
- return Client()
+ return make_local_client()
# new-style section
address = configuration.get("status", "address", fallback=None)
@@ -65,16 +76,8 @@ class Client:
if address or legacy_address or (host and port) or socket:
from ahriman.core.status.web_client import WebClient
return WebClient(repository_id, configuration)
- return Client()
- 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
- """
+ return make_local_client()
def package_changes_get(self, package_base: str) -> Changes:
"""
@@ -85,18 +88,52 @@ class Client:
Returns:
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
Args:
package_base(str): package base to update
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]]:
"""
@@ -107,18 +144,94 @@ class Client:
Returns:
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
Args:
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:
"""
@@ -126,16 +239,37 @@ class Client:
Args:
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:
package_base(str): package base to update
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:
"""
@@ -144,7 +278,7 @@ class Client:
Args:
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:
"""
@@ -153,7 +287,7 @@ class Client:
Args:
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:
"""
@@ -162,7 +296,7 @@ class Client:
Args:
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:
"""
@@ -171,16 +305,19 @@ class Client:
Args:
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:
"""
- 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:
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:
"""
diff --git a/src/ahriman/core/status/local_client.py b/src/ahriman/core/status/local_client.py
new file mode 100644
index 00000000..e0900805
--- /dev/null
+++ b/src/ahriman/core/status/local_client.py
@@ -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 .
+#
+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)
diff --git a/src/ahriman/core/status/watcher.py b/src/ahriman/core/status/watcher.py
index 7b36dae8..a3d704ff 100644
--- a/src/ahriman/core/status/watcher.py
+++ b/src/ahriman/core/status/watcher.py
@@ -17,17 +17,19 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
+from collections.abc import Callable
from threading import Lock
+from typing import Any, Self
-from ahriman.core.database import SQLite
from ahriman.core.exceptions import UnknownPackageError
from ahriman.core.log import LazyLogging
+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 Watcher(LazyLogging):
@@ -35,21 +37,18 @@ class Watcher(LazyLogging):
package status watcher
Attributes:
- database(SQLite): database instance
- repository_id(RepositoryId): repository unique identifier
+ client(Client): reporter instance
status(BuildStatus): daemon status
"""
- def __init__(self, repository_id: RepositoryId, database: SQLite) -> None:
+ def __init__(self, client: Client) -> None:
"""
default constructor
Args:
- repository_id(RepositoryId): repository unique identifier
- database(SQLite): database instance
+ client(Client): reporter instance
"""
- self.repository_id = repository_id
- self.database = database
+ self.client = client
self._lock = Lock()
self._known: dict[str, tuple[Package, BuildStatus]] = {}
@@ -76,61 +75,16 @@ class Watcher(LazyLogging):
with self._lock:
self._known = {
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]]:
- """
- extract logs for the package base
+ package_changes_get: Callable[[str], Changes]
- 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)
+ package_changes_update: Callable[[str, Changes], None]
- Returns:
- list[tuple[float, str]]: package logs
- """
- self.package_get(package_base)
- return self.database.logs_get(package_base, limit, offset, self.repository_id)
+ package_dependencies_get: Callable[[str], Dependencies]
- def logs_remove(self, package_base: str, version: str | None) -> 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)
+ package_dependencies_update: Callable[[str, Dependencies], None]
def package_get(self, package_base: str) -> tuple[Package, BuildStatus]:
"""
@@ -151,6 +105,31 @@ class Watcher(LazyLogging):
except KeyError:
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:
"""
remove package base from known list if any
@@ -160,60 +139,33 @@ class Watcher(LazyLogging):
"""
with self._lock:
self._known.pop(package_base, None)
- self.database.package_remove(package_base, self.repository_id)
- self.logs_remove(package_base, None)
+ self.client.package_remove(package_base)
+ 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:
package_base(str): package base to update
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)
- full_status = BuildStatus(status)
+ package, _ = self.package_get(package_base)
with self._lock:
- self._known[package_base] = (package, full_status)
- self.database.package_update(package, full_status, self.repository_id)
+ self._known[package_base] = (package, BuildStatus(status))
+ 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:
- package_base(str): package base
- variable(str | None): patch variable name if any
-
- Returns:
- list[PkgbuildPatch]: list of patches which are stored for the package
+ package(Package): package description
+ status(BuildStatusEnum): new build status
"""
- # patches are package base based, we don't know (and don't differentiate) to which package does them belong
- # so here we skip checking if package exists or not
- variables = [variable] if variable is not None else None
- 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])
+ with self._lock:
+ self._known[package.base] = (package, BuildStatus(status))
+ self.client.package_update(package, status)
def status_update(self, status: BuildStatusEnum) -> None:
"""
@@ -223,3 +175,34 @@ class Watcher(LazyLogging):
status(BuildStatusEnum): new service 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}'")
diff --git a/src/ahriman/core/status/web_client.py b/src/ahriman/core/status/web_client.py
index 45a05a90..24b4ccd3 100644
--- a/src/ahriman/core/status/web_client.py
+++ b/src/ahriman/core/status/web_client.py
@@ -18,18 +18,19 @@
# along with this program. If not, see .
#
import contextlib
-import logging
from urllib.parse import quote_plus as urlencode
from ahriman.core.configuration import Configuration
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.changes import Changes
+from ahriman.models.dependencies import Dependencies
from ahriman.models.internal_status import InternalStatus
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
@@ -92,10 +93,22 @@ class WebClient(Client, SyncAhrimanClient):
package_base(str): package base
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"
+ 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:
"""
get url for the logs api
@@ -110,7 +123,7 @@ class WebClient(Client, SyncAhrimanClient):
def _package_url(self, package_base: str = "") -> str:
"""
- url generator
+ package url generator
Args:
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 ""
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:
"""
get url for the status api
@@ -130,22 +157,6 @@ class WebClient(Client, SyncAhrimanClient):
"""
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:
"""
get package changes
@@ -165,7 +176,7 @@ class WebClient(Client, SyncAhrimanClient):
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
@@ -177,6 +188,37 @@ class WebClient(Client, SyncAhrimanClient):
self.make_request("POST", self._changes_url(package_base),
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]]:
"""
get package status
@@ -199,17 +241,18 @@ class WebClient(Client, SyncAhrimanClient):
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
Args:
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 = {
- "created": record.created,
- "message": record.getMessage(),
+ "created": created,
+ "message": message,
"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),
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:
"""
remove packages from watcher
@@ -229,19 +349,41 @@ class WebClient(Client, SyncAhrimanClient):
with contextlib.suppress(Exception):
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:
package_base(str): package base to update
status(BuildStatusEnum): current package build status
+
+ Raises:
+ NotImplementedError: not implemented method
"""
payload = {"status": status.value}
with contextlib.suppress(Exception):
self.make_request("POST", self._package_url(package_base),
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:
"""
get internal service status
diff --git a/src/ahriman/core/support/package_creator.py b/src/ahriman/core/support/package_creator.py
index d33248ca..18dc06b7 100644
--- a/src/ahriman/core/support/package_creator.py
+++ b/src/ahriman/core/support/package_creator.py
@@ -19,12 +19,13 @@
#
import shutil
+from pathlib import Path
+
from ahriman.core import context
from ahriman.core.build_tools.sources import Sources
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.models.build_status import BuildStatus
from ahriman.models.package import Package
@@ -48,23 +49,39 @@ class PackageCreator:
self.configuration = configuration
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:
"""
create new local package
"""
local_path = self.configuration.repository_paths.cache_for(self.generator.pkgname)
-
- # clear old tree if any
- 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())
+ self.package_create(local_path)
+ self.package_register(local_path)
diff --git a/src/ahriman/models/dependencies.py b/src/ahriman/models/dependencies.py
index fed89841..b823cc1c 100644
--- a/src/ahriman/models/dependencies.py
+++ b/src/ahriman/models/dependencies.py
@@ -17,8 +17,10 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from dataclasses import dataclass, field
-from pathlib import Path
+from dataclasses import dataclass, field, fields
+from typing import Any, Self
+
+from ahriman.core.util import dataclass_view, filter_json
@dataclass(frozen=True)
@@ -27,9 +29,31 @@ class Dependencies:
package paths dependencies
Attributes:
- package_base(str): package base
- paths(dict[Path, list[str]]): map of the paths used by this package to set of packages in which they were found
+ paths(dict[str, list[str]]): map of the paths used by this package to set of packages in which they were found
"""
- package_base: str
- paths: dict[Path, list[str]] = field(default_factory=dict)
+ paths: dict[str, 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)
diff --git a/src/ahriman/models/package_archive.py b/src/ahriman/models/package_archive.py
index dd82cb47..974f95bb 100644
--- a/src/ahriman/models/package_archive.py
+++ b/src/ahriman/models/package_archive.py
@@ -99,7 +99,7 @@ class PackageArchive:
"""
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():
if package in self.package.packages:
continue # skip package itself
@@ -108,9 +108,9 @@ class PackageArchive:
required_by.extend(library for library in files if library.name in dependencies)
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]]:
"""
diff --git a/src/ahriman/models/pkgbuild_patch.py b/src/ahriman/models/pkgbuild_patch.py
index b0ba710b..def9b14e 100644
--- a/src/ahriman/models/pkgbuild_patch.py
+++ b/src/ahriman/models/pkgbuild_patch.py
@@ -19,11 +19,11 @@
#
import shlex
-from dataclasses import dataclass
+from dataclasses import dataclass, fields
from pathlib import Path
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)
@@ -84,6 +84,21 @@ class PkgbuildPatch:
raw_value = next(iter(value_parts), "") # extract 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
def parse(source: str) -> str | list[str]:
"""
diff --git a/src/ahriman/web/schemas/__init__.py b/src/ahriman/web/schemas/__init__.py
index 3b3e4bd6..aac967f8 100644
--- a/src/ahriman/web/schemas/__init__.py
+++ b/src/ahriman/web/schemas/__init__.py
@@ -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.changes_schema import ChangesSchema
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.file_schema import FileSchema
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_schema import PackageSchema
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.patch_name_schema import PatchNameSchema
from ahriman.web.schemas.patch_schema import PatchSchema
diff --git a/src/ahriman/web/schemas/dependencies_schema.py b/src/ahriman/web/schemas/dependencies_schema.py
new file mode 100644
index 00000000..0c8d98ac
--- /dev/null
+++ b/src/ahriman/web/schemas/dependencies_schema.py
@@ -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 .
+#
+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",
+ })
diff --git a/src/ahriman/web/schemas/package_version_schema.py b/src/ahriman/web/schemas/package_version_schema.py
new file mode 100644
index 00000000..8ec967db
--- /dev/null
+++ b/src/ahriman/web/schemas/package_version_schema.py
@@ -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 .
+#
+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__,
+ })
diff --git a/src/ahriman/web/schemas/patch_schema.py b/src/ahriman/web/schemas/patch_schema.py
index aa6cebb5..56032128 100644
--- a/src/ahriman/web/schemas/patch_schema.py
+++ b/src/ahriman/web/schemas/patch_schema.py
@@ -25,8 +25,8 @@ class PatchSchema(Schema):
request and response patch schema
"""
- key = fields.String(required=True, metadata={
- "description": "environment variable name",
+ key = fields.String(metadata={
+ "description": "environment variable name. Required in case if it is not full diff",
})
value = fields.String(metadata={
"description": "environment variable value",
diff --git a/src/ahriman/web/views/base.py b/src/ahriman/web/views/base.py
index 061c9370..6807175a 100644
--- a/src/ahriman/web/views/base.py
+++ b/src/ahriman/web/views/base.py
@@ -25,6 +25,7 @@ from typing import TypeVar
from ahriman.core.auth import Auth
from ahriman.core.configuration import Configuration
from ahriman.core.distributed import WorkersCache
+from ahriman.core.exceptions import UnknownPackageError
from ahriman.core.sign.gpg import GPG
from ahriman.core.spawn import Spawn
from ahriman.core.status.watcher import Watcher
@@ -218,12 +219,13 @@ class BaseView(View, CorsViewMixin):
return RepositoryId(architecture, name)
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
Args:
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:
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:
repository_id = self.repository_id()
try:
- return self.services[repository_id]
+ return self.services[repository_id](package_base)
except KeyError:
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:
"""
diff --git a/src/ahriman/web/views/v1/packages/changes.py b/src/ahriman/web/views/v1/packages/changes.py
index b14eb282..6a7765d7 100644
--- a/src/ahriman/web/views/v1/packages/changes.py
+++ b/src/ahriman/web/views/v1/packages/changes.py
@@ -19,9 +19,8 @@
#
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.user_access import UserAccess
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"]
- try:
- changes = self.service().package_changes_get(package_base)
- except UnknownPackageError:
- raise HTTPNotFound(reason=f"Package {package_base} is unknown")
+ changes = self.service(package_base=package_base).package_changes_get(package_base)
return json_response(changes.view())
@@ -113,7 +109,6 @@ class ChangesView(StatusViewGuard, BaseView):
raise HTTPBadRequest(reason=str(ex))
changes = Changes(last_commit_sha, change)
- repository_id = self.repository_id()
- self.service(repository_id).database.changes_insert(package_base, changes, repository_id)
+ self.service().package_changes_update(package_base, changes)
raise HTTPNoContent
diff --git a/src/ahriman/web/views/v1/packages/dependencies.py b/src/ahriman/web/views/v1/packages/dependencies.py
new file mode 100644
index 00000000..f4fce028
--- /dev/null
+++ b/src/ahriman/web/views/v1/packages/dependencies.py
@@ -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 .
+#
+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
diff --git a/src/ahriman/web/views/v1/packages/logs.py b/src/ahriman/web/views/v1/packages/logs.py
index af527c46..be59685e 100644
--- a/src/ahriman/web/views/v1/packages/logs.py
+++ b/src/ahriman/web/views/v1/packages/logs.py
@@ -25,8 +25,8 @@ from ahriman.core.exceptions import UnknownPackageError
from ahriman.core.util import pretty_datetime
from ahriman.models.log_record_id import LogRecordId
from ahriman.models.user_access import UserAccess
-from ahriman.web.schemas import AuthSchema, ErrorSchema, LogsSchema, PackageNameSchema, RepositoryIdSchema, \
- VersionedLogSchema
+from ahriman.web.schemas import AuthSchema, ErrorSchema, LogsSchema, PackageNameSchema, PackageVersionSchema, \
+ RepositoryIdSchema, VersionedLogSchema
from ahriman.web.views.base import BaseView
from ahriman.web.views.status_view_guard import StatusViewGuard
@@ -60,7 +60,7 @@ class LogsView(StatusViewGuard, BaseView):
)
@aiohttp_apispec.cookies_schema(AuthSchema)
@aiohttp_apispec.match_info_schema(PackageNameSchema)
- @aiohttp_apispec.querystring_schema(RepositoryIdSchema)
+ @aiohttp_apispec.querystring_schema(PackageVersionSchema)
async def delete(self) -> None:
"""
delete package logs
@@ -69,7 +69,8 @@ class LogsView(StatusViewGuard, BaseView):
HTTPNoContent: on success response
"""
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
@@ -103,7 +104,7 @@ class LogsView(StatusViewGuard, BaseView):
try:
_, 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:
raise HTTPNotFound(reason=f"Package {package_base} is unknown")
@@ -149,6 +150,6 @@ class LogsView(StatusViewGuard, BaseView):
except Exception as 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
diff --git a/src/ahriman/web/views/v1/packages/package.py b/src/ahriman/web/views/v1/packages/package.py
index f7993cf5..a2cbddd2 100644
--- a/src/ahriman/web/views/v1/packages/package.py
+++ b/src/ahriman/web/views/v1/packages/package.py
@@ -152,7 +152,10 @@ class PackageView(StatusViewGuard, BaseView):
raise HTTPBadRequest(reason=str(ex))
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:
raise HTTPBadRequest(reason=f"Package {package_base} is unknown, but no package body set")
diff --git a/src/ahriman/web/views/v1/packages/patch.py b/src/ahriman/web/views/v1/packages/patch.py
index bb72fc2e..c0d76018 100644
--- a/src/ahriman/web/views/v1/packages/patch.py
+++ b/src/ahriman/web/views/v1/packages/patch.py
@@ -63,7 +63,8 @@ class PatchView(StatusViewGuard, BaseView):
"""
package_base = self.request.match_info["package"]
variable = self.request.match_info["patch"]
- self.service().patches_remove(package_base, variable)
+
+ self.service().package_patches_remove(package_base, variable)
raise HTTPNoContent
@@ -95,7 +96,7 @@ class PatchView(StatusViewGuard, BaseView):
package_base = self.request.match_info["package"]
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)
if selected is None:
diff --git a/src/ahriman/web/views/v1/packages/patches.py b/src/ahriman/web/views/v1/packages/patches.py
index 54dc3760..8b068ed4 100644
--- a/src/ahriman/web/views/v1/packages/patches.py
+++ b/src/ahriman/web/views/v1/packages/patches.py
@@ -63,7 +63,7 @@ class PatchesView(StatusViewGuard, BaseView):
Response: 200 with package patches on success
"""
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]
return json_response(response)
@@ -96,11 +96,11 @@ class PatchesView(StatusViewGuard, BaseView):
try:
data = await self.request.json()
- key = data["key"]
+ key = data.get("key")
value = data["value"]
except Exception as 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
diff --git a/src/ahriman/web/views/v2/packages/logs.py b/src/ahriman/web/views/v2/packages/logs.py
index 98e56519..049f9c0f 100644
--- a/src/ahriman/web/views/v2/packages/logs.py
+++ b/src/ahriman/web/views/v2/packages/logs.py
@@ -19,9 +19,8 @@
#
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.web.schemas import AuthSchema, ErrorSchema, LogSchema, PackageNameSchema, PaginationSchema
from ahriman.web.views.base import BaseView
@@ -68,10 +67,8 @@ class LogsView(StatusViewGuard, BaseView):
"""
package_base = self.request.match_info["package"]
limit, offset = self.page()
- try:
- logs = self.service().logs_get(package_base, limit, offset)
- except UnknownPackageError:
- raise HTTPNotFound(reason=f"Package {package_base} is unknown")
+
+ logs = self.service(package_base=package_base).package_logs_get(package_base, limit, offset)
response = [
{
diff --git a/src/ahriman/web/web.py b/src/ahriman/web/web.py
index 64b48ae8..c3297a70 100644
--- a/src/ahriman/web/web.py
+++ b/src/ahriman/web/web.py
@@ -30,6 +30,7 @@ from ahriman.core.database import SQLite
from ahriman.core.distributed import WorkersCache
from ahriman.core.exceptions import InitializeError
from ahriman.core.spawn import Spawn
+from ahriman.core.status import Client
from ahriman.core.status.watcher import Watcher
from ahriman.models.repository_id import RepositoryId
from ahriman.web.apispec import setup_apispec
@@ -167,7 +168,8 @@ def setup_server(configuration: Configuration, spawner: Spawn, repositories: lis
watchers: dict[RepositoryId, Watcher] = {}
for repository_id in repositories:
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
# workers cache
application[WorkersKey] = WorkersCache(configuration)
diff --git a/tests/ahriman/application/application/test_application.py b/tests/ahriman/application/application/test_application.py
index 526683b3..a53750f7 100644
--- a/tests/ahriman/application/application/test_application.py
+++ b/tests/ahriman/application/application/test_application.py
@@ -93,8 +93,7 @@ def test_with_dependencies(application: Application, package_ahriman: Package, p
side_effect=lambda *args: packages[args[0].name])
packages_mock = mocker.patch("ahriman.application.application.Application._known_packages",
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.Client.set_unknown")
+ status_client_mock = mocker.patch("ahriman.core.status.Client.set_unknown")
result = application.with_dependencies([package_ahriman], process_dependencies=True)
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)
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([
MockCall(package_python_schedule),
MockCall(packages["python"]),
diff --git a/tests/ahriman/application/application/test_application_packages.py b/tests/ahriman/application/application/test_application_packages.py
index 17d0b541..94210120 100644
--- a/tests/ahriman/application/application/test_application_packages.py
+++ b/tests/ahriman/application/application/test_application_packages.py
@@ -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)
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")
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,
@@ -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)
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")
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,
diff --git a/tests/ahriman/application/application/test_application_properties.py b/tests/ahriman/application/application/test_application_properties.py
index ab64cdcd..cf456457 100644
--- a/tests/ahriman/application/application/test_application_properties.py
+++ b/tests/ahriman/application/application/test_application_properties.py
@@ -1,15 +1,15 @@
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:
"""
must return repository 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
diff --git a/tests/ahriman/application/application/test_application_repository.py b/tests/ahriman/application/application/test_application_repository.py
index cfb68680..3f023f40 100644
--- a/tests/ahriman/application/application/test_application_repository.py
+++ b/tests/ahriman/application/application/test_application_repository.py
@@ -17,14 +17,12 @@ def test_changes(application_repository: ApplicationRepository, package_ahriman:
must generate changes for the packages
"""
changes = Changes("hash", "change")
- hashes_mock = mocker.patch("ahriman.core.database.SQLite.hashes_get", return_value={
- package_ahriman.base: changes.last_commit_sha,
- })
+ hashes_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_get", 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])
- 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)
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
"""
- mocker.patch("ahriman.core.database.SQLite.hashes_get", return_value={})
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])
changes_mock.assert_not_called()
diff --git a/tests/ahriman/application/handlers/test_handler_add.py b/tests/ahriman/application/handlers/test_handler_add.py
index cfb640bc..5f381dd0 100644
--- a/tests/ahriman/application/handlers/test_handler_add.py
+++ b/tests/ahriman/application/handlers/test_handler_add.py
@@ -62,11 +62,11 @@ def test_run_with_patches(args: argparse.Namespace, configuration: Configuration
args.variable = ["KEY=VALUE"]
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
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()
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,
diff --git a/tests/ahriman/application/handlers/test_handler_change.py b/tests/ahriman/application/handlers/test_handler_change.py
index bbe02578..eb8892f4 100644
--- a/tests/ahriman/application/handlers/test_handler_change.py
+++ b/tests/ahriman/application/handlers/test_handler_change.py
@@ -34,7 +34,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
"""
args = _default_args(args)
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"))
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
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.exit_code = True
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")
_, repository_id = configuration.check_loaded()
@@ -70,7 +70,7 @@ def test_run_remove(args: argparse.Namespace, configuration: Configuration, repo
args = _default_args(args)
args.action = Action.Remove
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()
Change.run(args, repository_id, configuration, report=False)
diff --git a/tests/ahriman/application/handlers/test_handler_patch.py b/tests/ahriman/application/handlers/test_handler_patch.py
index c629714c..97be1632 100644
--- a/tests/ahriman/application/handlers/test_handler_patch.py
+++ b/tests/ahriman/application/handlers/test_handler_patch.py
@@ -160,13 +160,28 @@ def test_patch_set_list(application: Application, mocker: MockerFixture) -> None
"""
must list available patches for the command
"""
- get_mock = mocker.patch("ahriman.core.database.SQLite.patches_list",
- return_value={"ahriman": PkgbuildPatch(None, "patch")})
+ get_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_get",
+ return_value=[PkgbuildPatch(None, "patch"), PkgbuildPatch("version", "value")])
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", ["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=" = ")
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
"""
- 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")
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
"""
- 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))
- 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:
"""
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"])
- 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:
diff --git a/tests/ahriman/application/handlers/test_handler_rebuild.py b/tests/ahriman/application/handlers/test_handler_rebuild.py
index 6ba76ae1..002b9365 100644
--- a/tests/ahriman/application/handlers/test_handler_rebuild.py
+++ b/tests/ahriman/application/handlers/test_handler_rebuild.py
@@ -185,7 +185,7 @@ def test_extract_packages_by_status(application: Application, mocker: MockerFixt
("package2", BuildStatus(BuildStatusEnum.Failed)),
])
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:
@@ -194,4 +194,4 @@ def test_extract_packages_from_database(application: Application, mocker: Mocker
"""
packages_mock = mocker.patch("ahriman.core.database.SQLite.packages_get")
Rebuild.extract_packages(application, None, from_database=True)
- packages_mock.assert_called_once_with()
+ packages_mock.assert_called_once_with(application.repository_id)
diff --git a/tests/ahriman/application/handlers/test_handler_status.py b/tests/ahriman/application/handlers/test_handler_status.py
index 44909243..74f53e55 100644
--- a/tests/ahriman/application/handlers/test_handler_status.py
+++ b/tests/ahriman/application/handlers/test_handler_status.py
@@ -37,8 +37,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
"""
args = _default_args(args)
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
- application_mock = mocker.patch("ahriman.core.status.client.Client.status_get")
- packages_mock = mocker.patch("ahriman.core.status.client.Client.package_get",
+ application_mock = mocker.patch("ahriman.core.status.Client.status_get")
+ packages_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_get",
return_value=[(package_ahriman, BuildStatus(BuildStatusEnum.Success)),
(package_python_schedule, BuildStatus(BuildStatusEnum.Failed))])
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.exit_code = True
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.Client.package_get", return_value=[])
+ mocker.patch("ahriman.core.status.Client.status_get")
+ mocker.patch("ahriman.core.status.local_client.LocalClient.package_get", return_value=[])
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
_, repository_id = configuration.check_loaded()
@@ -80,7 +80,7 @@ def test_run_verbose(args: argparse.Namespace, configuration: Configuration, rep
args = _default_args(args)
args.info = True
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))])
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.package = [package_ahriman.base]
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))])
_, 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.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)),
(package_python_schedule, BuildStatus(BuildStatusEnum.Failed))])
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
diff --git a/tests/ahriman/application/handlers/test_handler_status_update.py b/tests/ahriman/application/handlers/test_handler_status_update.py
index 99a67f60..289032e4 100644
--- a/tests/ahriman/application/handlers/test_handler_status_update.py
+++ b/tests/ahriman/application/handlers/test_handler_status_update.py
@@ -34,7 +34,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
"""
args = _default_args(args)
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()
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,
- package_ahriman: Package, mocker: MockerFixture) -> None:
+ mocker: MockerFixture) -> None:
"""
must run command with specified packages
"""
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.Repository.packages", return_value=[package_ahriman])
- add_mock = mocker.patch("ahriman.core.status.client.Client.package_add")
- update_mock = mocker.patch("ahriman.core.status.client.Client.package_update")
+ update_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_update")
_, repository_id = configuration.check_loaded()
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)
@@ -68,7 +65,7 @@ def test_run_remove(args: argparse.Namespace, configuration: Configuration, repo
args.package = [package_ahriman.base]
args.action = Action.Remove
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()
StatusUpdate.run(args, repository_id, configuration, report=False)
diff --git a/tests/ahriman/application/test_lock.py b/tests/ahriman/application/test_lock.py
index 646675f4..1a0b3b03 100644
--- a/tests/ahriman/application/test_lock.py
+++ b/tests/ahriman/application/test_lock.py
@@ -27,7 +27,7 @@ def test_path(args: argparse.Namespace, configuration: Configuration) -> None:
with pytest.raises(ValueError):
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:
@@ -64,7 +64,7 @@ def test_check_version(lock: Lock, mocker: MockerFixture) -> None:
"""
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__))
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
"""
- mocker.patch("ahriman.core.status.client.Client.status_get",
+ mocker.patch("ahriman.core.status.Client.status_get",
return_value=InternalStatus(status=BuildStatus(), version="version"))
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")
clear_mock = mocker.patch("ahriman.application.lock.Lock.clear")
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:
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.clear")
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:
- raise Exception()
+ raise ValueError()
update_status_mock.assert_has_calls([MockCall(BuildStatusEnum.Building), MockCall(BuildStatusEnum.Failed)])
diff --git a/tests/ahriman/conftest.py b/tests/ahriman/conftest.py
index 878b9c12..45f72896 100644
--- a/tests/ahriman/conftest.py
+++ b/tests/ahriman/conftest.py
@@ -13,6 +13,7 @@ from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite
from ahriman.core.repository import Repository
from ahriman.core.spawn import Spawn
+from ahriman.core.status import Client
from ahriman.core.status.watcher import Watcher
from ahriman.models.aur_package import AURPackage
from ahriman.models.build_status import BuildStatus, BuildStatusEnum
@@ -276,6 +277,21 @@ def database(configuration: Configuration) -> SQLite:
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
def package_ahriman(package_description_ahriman: PackageDescription, remote_source: RemoteSource) -> Package:
"""
@@ -559,15 +575,14 @@ def user() -> User:
@pytest.fixture
-def watcher(repository_id: RepositoryId, database: SQLite) -> Watcher:
+def watcher(local_client: Client) -> Watcher:
"""
package status watcher fixture
Args:
- repository_id(RepositoryId): repository identifier fixture
- database(SQLite): database fixture
+ local_client(Client): local status client fixture
Returns:
Watcher: package status watcher test instance
"""
- return Watcher(repository_id, database)
+ return Watcher(local_client)
diff --git a/tests/ahriman/core/alpm/test_pacman.py b/tests/ahriman/core/alpm/test_pacman.py
index d0dce96a..33d9b2b7 100644
--- a/tests/ahriman/core/alpm/test_pacman.py
+++ b/tests/ahriman/core/alpm/test_pacman.py
@@ -128,7 +128,7 @@ def test_database_copy_database_exist(pacman: Pacman, mocker: MockerFixture) ->
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
"""
@@ -184,14 +184,15 @@ def test_files(pacman: Pacman, package_ahriman: Package, mocker: MockerFixture,
pacman.handle = handle_mock
tarball = resource_path_root / "core" / "arcanisrepo.files.tar.gz"
- 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"))
+ with tarfile.open(tarball, "r:gz") as fd:
+ mocker.patch("pathlib.Path.is_file", return_value=True)
+ open_mock = mocker.patch("ahriman.core.alpm.pacman.tarfile.open", return_value=fd)
- files = pacman.files()
- assert len(files) == 2
- assert package_ahriman.base in files
- assert Path("usr/bin/ahriman") in files[package_ahriman.base]
- open_mock.assert_called_once_with(pytest.helpers.anyvar(int), "r:gz")
+ files = pacman.files()
+ assert len(files) == 2
+ assert package_ahriman.base in files
+ assert "usr/bin/ahriman" in files[package_ahriman.base]
+ open_mock.assert_called_once_with(pytest.helpers.anyvar(int), "r:gz")
def test_files_package(pacman: Pacman, package_ahriman: Package, mocker: MockerFixture,
@@ -205,12 +206,13 @@ def test_files_package(pacman: Pacman, package_ahriman: Package, mocker: MockerF
tarball = resource_path_root / "core" / "arcanisrepo.files.tar.gz"
- mocker.patch("pathlib.Path.is_file", return_value=True)
- mocker.patch("ahriman.core.alpm.pacman.tarfile.open", return_value=tarfile.open(tarball, "r:gz"))
+ with tarfile.open(tarball, "r:gz") as fd:
+ mocker.patch("pathlib.Path.is_file", return_value=True)
+ mocker.patch("ahriman.core.alpm.pacman.tarfile.open", return_value=fd)
- files = pacman.files(package_ahriman.base)
- assert len(files) == 1
- assert package_ahriman.base in files
+ files = pacman.files(package_ahriman.base)
+ assert len(files) == 1
+ assert package_ahriman.base in files
def test_files_skip(pacman: Pacman, mocker: MockerFixture) -> None:
diff --git a/tests/ahriman/core/build_tools/test_task.py b/tests/ahriman/core/build_tools/test_task.py
index 893b113d..399baeac 100644
--- a/tests/ahriman/core/build_tools/test_task.py
+++ b/tests/ahriman/core/build_tools/test_task.py
@@ -5,7 +5,7 @@ from pytest_mock import MockerFixture
from unittest.mock import call as MockCall
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:
@@ -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
"""
+ patches = [PkgbuildPatch("hash", "patch")]
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")
- assert task_ahriman.init(Path("ahriman"), database, None) == "sha"
- load_mock.assert_called_once_with(Path("ahriman"), task_ahriman.package, [], task_ahriman.paths)
+ assert task_ahriman.init(Path("ahriman"), patches, None) == "sha"
+ 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
"""
@@ -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")
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")
-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
"""
@@ -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")
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()
diff --git a/tests/ahriman/core/database/operations/test_changes_operations.py b/tests/ahriman/core/database/operations/test_changes_operations.py
index da262a47..a82ed902 100644
--- a/tests/ahriman/core/database/operations/test_changes_operations.py
+++ b/tests/ahriman/core/database/operations/test_changes_operations.py
@@ -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_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"}
diff --git a/tests/ahriman/core/database/operations/test_dependencies_operations.py b/tests/ahriman/core/database/operations/test_dependencies_operations.py
index 5b466f46..25e37605 100644
--- a/tests/ahriman/core/database/operations/test_dependencies_operations.py
+++ b/tests/ahriman/core/database/operations/test_dependencies_operations.py
@@ -1,5 +1,3 @@
-from pathlib import Path
-
from ahriman.core.database import SQLite
from ahriman.models.dependencies import Dependencies
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
"""
- dependencies = Dependencies(package_ahriman.base, {Path("usr/lib/python3.11/site-packages"): ["python"]})
- database.dependencies_insert(dependencies)
- assert database.dependencies_get(package_ahriman.base) == [dependencies]
+ dependencies = Dependencies({"usr/lib/python3.11/site-packages": ["python"]})
+ database.dependencies_insert(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"]})
- database.dependencies_insert(dependencies2, RepositoryId("i686", database._repository_id.name))
- assert database.dependencies_get() == [dependencies]
- assert database.dependencies_get(package_ahriman.base) == [dependencies]
- assert database.dependencies_get(
- package_ahriman.base, RepositoryId("i686", database._repository_id.name)) == [dependencies2]
+ dependencies2 = Dependencies({"usr/lib/python3.11/site-packages": ["python3"]})
+ database.dependencies_insert(
+ package_ahriman.base, dependencies2, RepositoryId(
+ "i686", database._repository_id.name))
+ assert database.dependencies_get() == {package_ahriman.base: dependencies}
+ 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,
@@ -27,23 +28,28 @@ def test_dependencies_insert_remove(database: SQLite, package_ahriman: Package,
"""
must remove dependencies for the package
"""
- dependencies1 = Dependencies(package_ahriman.base, {Path("usr"): ["python"]})
- database.dependencies_insert(dependencies1)
- dependencies2 = Dependencies(package_python_schedule.base, {Path("usr"): ["filesystem"]})
- database.dependencies_insert(dependencies2)
- dependencies3 = Dependencies(package_ahriman.base, {Path("usr"): ["python3"]})
- database.dependencies_insert(dependencies3, RepositoryId("i686", database._repository_id.name))
+ dependencies1 = Dependencies({"usr": ["python"]})
+ database.dependencies_insert(package_ahriman.base, dependencies1)
+ dependencies2 = Dependencies({"usr": ["filesystem"]})
+ database.dependencies_insert(package_python_schedule.base, dependencies2)
+ dependencies3 = Dependencies({"usr": ["python3"]})
+ 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)
- assert database.dependencies_get(package_ahriman.base) == []
- assert database.dependencies_get(package_python_schedule.base) == [dependencies2]
+ assert database.dependencies_get(package_ahriman.base) == {}
+ assert database.dependencies_get(package_python_schedule.base) == {package_python_schedule.base: dependencies2}
# insert null
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_python_schedule.base) == [dependencies2]
+ assert database.dependencies_get(package_ahriman.base, RepositoryId("i686", database._repository_id.name)) == {}
+ assert database.dependencies_get(package_python_schedule.base) == {package_python_schedule.base: dependencies2}
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
"""
- database.dependencies_insert(Dependencies(package_ahriman.base, {Path("usr"): ["python"]}))
- database.dependencies_insert(Dependencies(package_python_schedule.base, {Path("usr"): ["filesystem"]}))
- database.dependencies_insert(Dependencies(package_ahriman.base, {Path("usr"): ["python3"]}),
+ database.dependencies_insert(package_ahriman.base, Dependencies({"usr": ["python"]}))
+ database.dependencies_insert(package_python_schedule.base, Dependencies({"usr": ["filesystem"]}))
+ database.dependencies_insert(package_ahriman.base, Dependencies({"usr": ["python3"]}),
RepositoryId("i686", database._repository_id.name))
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))
diff --git a/tests/ahriman/core/database/operations/test_package_operations.py b/tests/ahriman/core/database/operations/test_package_operations.py
index 424b990c..c87d478e 100644
--- a/tests/ahriman/core/database/operations/test_package_operations.py
+++ b/tests/ahriman/core/database/operations/test_package_operations.py
@@ -5,10 +5,8 @@ from sqlite3 import Connection
from unittest.mock import call as MockCall
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_source import PackageSource
-from ahriman.models.remote_source import RemoteSource
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), [])
-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:
"""
must select all bases
@@ -131,16 +121,12 @@ def test_package_update(database: SQLite, package_ahriman: Package, mocker: Mock
"""
must update package status
"""
- status = BuildStatus()
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")
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_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,
database._repository_id)
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
"""
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)
for db_package, db_status in database.packages_get()
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
"""
- status = BuildStatus()
- database.package_update(package_ahriman, status)
+ database.package_update(package_ahriman)
database.package_remove(package_ahriman.base)
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
"""
- database.package_update(package_ahriman, BuildStatus())
- database.package_update(package_ahriman, BuildStatus(BuildStatusEnum.Failed))
- assert next(db_status.status
- for db_package, db_status in database.packages_get()
- if db_package.base == package_ahriman.base) == BuildStatusEnum.Failed
+ database.package_update(package_ahriman)
+ package_ahriman.version = "1.0.0"
+ database.package_update(package_ahriman)
+ assert next(db_package.version
+ 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)
- assert database.remotes_get()[package_ahriman.base] == package_ahriman.remote
+ status = BuildStatus()
-
-def test_remote_update_update(database: SQLite, package_ahriman: Package) -> None:
- """
- 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
+ database.package_update(package_ahriman, database._repository_id)
+ database.status_update(package_ahriman.base, status, database._repository_id)
+ assert database.packages_get(database._repository_id) == [(package_ahriman, status)]
diff --git a/tests/ahriman/core/database/test_sqlite.py b/tests/ahriman/core/database/test_sqlite.py
index 5afe8354..ef30badf 100644
--- a/tests/ahriman/core/database/test_sqlite.py
+++ b/tests/ahriman/core/database/test_sqlite.py
@@ -44,6 +44,7 @@ def test_package_clear(database: SQLite, mocker: MockerFixture) -> None:
logs_mock = mocker.patch("ahriman.core.database.SQLite.logs_remove")
changes_mock = mocker.patch("ahriman.core.database.SQLite.changes_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")
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)
changes_mock.assert_called_once_with("package")
dependencies_mock.assert_called_once_with("package")
+ tree_clear_mock.assert_called_once_with("package")
diff --git a/tests/ahriman/core/gitremote/test_remote_push.py b/tests/ahriman/core/gitremote/test_remote_push.py
index a0ff93cf..3d8a4007 100644
--- a/tests/ahriman/core/gitremote/test_remote_push.py
+++ b/tests/ahriman/core/gitremote/test_remote_push.py
@@ -5,15 +5,15 @@ from pytest_mock import MockerFixture
from unittest.mock import call as MockCall
from ahriman.core.configuration import Configuration
-from ahriman.core.database import SQLite
from ahriman.core.exceptions import GitRemoteError
from ahriman.core.gitremote.remote_push import RemotePush
+from ahriman.core.status import Client
from ahriman.models.package import Package
from ahriman.models.pkgbuild_patch import PkgbuildPatch
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:
"""
must update single package
@@ -27,9 +27,10 @@ def test_package_update(database: SQLite, configuration: Configuration, package_
rmtree_mock = mocker.patch("shutil.rmtree")
unlink_mock = mocker.patch("pathlib.Path.unlink")
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")
- runner = RemotePush(database, configuration, "gitremote")
+ runner = RemotePush(local_client, configuration, "gitremote")
assert runner.package_update(package_ahriman, local) == package_ahriman.base
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()
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([
MockCall(local / package_ahriman.base / f"ahriman-{package_ahriman.base}.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:
"""
must generate packages update
"""
update_mock = mocker.patch("ahriman.core.gitremote.remote_push.RemotePush.package_update",
return_value=[package_ahriman.base])
- runner = RemotePush(database, configuration, "gitremote")
+ runner = RemotePush(local_client, configuration, "gitremote")
local = Path("local")
assert list(runner.packages_update(result, 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:
"""
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])
fetch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
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)
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
"""
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):
runner.run(result)
diff --git a/tests/ahriman/core/gitremote/test_remote_push_trigger.py b/tests/ahriman/core/gitremote/test_remote_push_trigger.py
index d0458397..7511a256 100644
--- a/tests/ahriman/core/gitremote/test_remote_push_trigger.py
+++ b/tests/ahriman/core/gitremote/test_remote_push_trigger.py
@@ -1,8 +1,8 @@
from pytest_mock import MockerFixture
from ahriman.core.configuration import Configuration
-from ahriman.core.database import SQLite
from ahriman.core.gitremote import RemotePushTrigger
+from ahriman.core.status import Client
from ahriman.models.package import Package
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,
- database: SQLite, mocker: MockerFixture) -> None:
+ local_client: Client, mocker: MockerFixture) -> None:
"""
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")
_, repository_id = configuration.check_loaded()
trigger = RemotePushTrigger(repository_id, configuration)
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)
diff --git a/tests/ahriman/core/log/test_http_log_handler.py b/tests/ahriman/core/log/test_http_log_handler.py
index 14df2bba..40395c30 100644
--- a/tests/ahriman/core/log/test_http_log_handler.py
+++ b/tests/ahriman/core/log/test_http_log_handler.py
@@ -18,7 +18,7 @@ def test_load(configuration: Configuration, mocker: MockerFixture) -> None:
root.removeHandler(current_handler)
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()
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
"""
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()
handler = HttpLogHandler(repository_id, configuration, report=False, suppress_errors=False)
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,
@@ -58,7 +58,7 @@ def test_emit_failed(configuration: Configuration, log_record: logging.LogRecord
must call handle error on exception
"""
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")
_, repository_id = configuration.check_loaded()
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
"""
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")
_, repository_id = configuration.check_loaded()
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
"""
- 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()
handler = HttpLogHandler(repository_id, configuration, report=False, suppress_errors=False)
diff --git a/tests/ahriman/core/log/test_lazy_logging.py b/tests/ahriman/core/log/test_lazy_logging.py
index 81abe4f2..5a05878d 100644
--- a/tests/ahriman/core/log/test_lazy_logging.py
+++ b/tests/ahriman/core/log/test_lazy_logging.py
@@ -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")
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, ""):
- raise Exception()
+ raise ValueError()
reset_mock.assert_called_once_with()
@@ -81,11 +81,3 @@ def test_logger(database: SQLite) -> None:
"""
assert database.logger
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
diff --git a/tests/ahriman/core/repository/test_executor.py b/tests/ahriman/core/repository/test_executor.py
index ec992c08..9025634a 100644
--- a/tests/ahriman/core/repository/test_executor.py
+++ b/tests/ahriman/core/repository/test_executor.py
@@ -17,22 +17,21 @@ def test_process_build(executor: Executor, package_ahriman: Package, passwd: Any
"""
must run build process
"""
- dependencies = Dependencies(package_ahriman.base)
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.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")
move_mock = mocker.patch("shutil.move")
- status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_building")
- commit_sha_mock = mocker.patch("ahriman.core.status.client.Client.package_changes_set")
+ status_client_mock = mocker.patch("ahriman.core.status.Client.set_building")
+ 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",
- return_value=dependencies)
- dependencies_mock = mocker.patch("ahriman.core.database.SQLite.dependencies_insert")
+ return_value=Dependencies())
+ dependencies_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_dependencies_update")
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)
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)
move_mock.assert_called_once_with(Path(package_ahriman.base), executor.paths.packages / package_ahriman.base)
# 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.build_tools.task.Task.build", return_value=[Path(package_ahriman.base)])
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")
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.init")
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])
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
"""
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")
- database_mock = mocker.patch("ahriman.core.database.SQLite.package_clear")
- 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])
# must remove via alpm wrapper
repo_remove_mock.assert_called_once_with(
package_ahriman.base, package_ahriman.packages[package_ahriman.base].filepath)
# 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)
@@ -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],
}
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.database.SQLite.package_clear")
- mocker.patch("ahriman.core.status.client.Client.package_remove")
+ mocker.patch("ahriman.core.status.local_client.LocalClient.package_remove")
repo_remove_mock = mocker.patch("ahriman.core.alpm.repo.Repo.remove")
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])
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])
# 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])
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"])
# 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
"""
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])
@@ -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=[])
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])
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")
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])
- 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")
packager_mock = mocker.patch("ahriman.core.repository.executor.Executor.packager", return_value=user)
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.packages", return_value=[package_python_schedule])
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")
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("ahriman.core.repository.executor.Executor.load_archives", 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()])
status_client_mock.assert_called_once_with(package_ahriman.base)
diff --git a/tests/ahriman/core/repository/test_package_info.py b/tests/ahriman/core/repository/test_package_info.py
index a6a1656b..e228919e 100644
--- a/tests/ahriman/core/repository/test_package_info.py
+++ b/tests/ahriman/core/repository/test_package_info.py
@@ -21,9 +21,9 @@ def test_load_archives(package_ahriman: Package, package_python_schedule: Packag
for package, props in package_python_schedule.packages.items()
] + [package_ahriman]
mocker.patch("ahriman.models.package.Package.from_archive", side_effect=single_packages)
- mocker.patch("ahriman.core.database.SQLite.remotes_get", return_value={
- package_ahriman.base: package_ahriman.base
- })
+ mocker.patch("ahriman.core.status.local_client.LocalClient.package_get", return_value=[
+ (package_ahriman, None),
+ ])
packages = package_info.load_archives([Path("a.pkg.tar.xz"), Path("b.pkg.tar.xz"), Path("c.pkg.tar.xz")])
assert len(packages) == 2
diff --git a/tests/ahriman/core/repository/test_repository.py b/tests/ahriman/core/repository/test_repository.py
index 0983c1fd..b687b20c 100644
--- a/tests/ahriman/core/repository/test_repository.py
+++ b/tests/ahriman/core/repository/test_repository.py
@@ -6,6 +6,7 @@ from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite
from ahriman.core.repository import Repository
from ahriman.core.sign.gpg import GPG
+from ahriman.core.status import Client
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(Pacman, instance.pacman),
MockCall(GPG, instance.sign),
+ MockCall(Client, instance.reporter),
MockCall(Repository, instance),
])
diff --git a/tests/ahriman/core/repository/test_update_handler.py b/tests/ahriman/core/repository/test_update_handler.py
index 567fb2e3..037d6c3f 100644
--- a/tests/ahriman/core/repository/test_update_handler.py
+++ b/tests/ahriman/core/repository/test_update_handler.py
@@ -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",
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)
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.models.package.Package.is_outdated", return_value=True)
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]
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.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)
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.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)
@@ -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",
return_value=[package_ahriman, package_python_schedule])
- dependencies = [
- Dependencies(package_ahriman.base, {Path("usr/lib/python3.11/site-packages"): ["python"]}),
- Dependencies(package_python_schedule.base, {Path("usr/lib/python3.12/site-packages"): ["python"]}),
- ]
- mocker.patch("ahriman.core.database.SQLite.dependencies_get", return_value=dependencies)
+ dependencies = {
+ package_ahriman.base: Dependencies({"usr/lib/python3.11/site-packages": ["python"]}),
+ package_python_schedule.base: Dependencies({"usr/lib/python3.12/site-packages": ["python"]}),
+ }
+ 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",
- 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]
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
"""
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",
- 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"]) == []
@@ -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
"""
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
- dependencies = [
- Dependencies(package_ahriman.base, {Path("usr"): ["filesystem", "python"]}),
- ]
- mocker.patch("ahriman.core.database.SQLite.dependencies_get", return_value=dependencies)
+ dependencies = Dependencies({"usr": ["filesystem", "python"]})
+ mocker.patch("ahriman.core.status.local_client.LocalClient.package_dependencies_get", return_value=dependencies)
mocker.patch("ahriman.core.alpm.pacman.Pacman.files", return_value={
- "filesystem": {Path("usr")},
- "python": {Path("usr")},
+ "filesystem": {"usr"},
+ "python": {"usr"},
})
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)])
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)
- 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)
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.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()
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.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()
status_client_mock.assert_called_once_with(package_ahriman)
diff --git a/tests/ahriman/core/status/conftest.py b/tests/ahriman/core/status/conftest.py
index 6f52d866..f51af705 100644
--- a/tests/ahriman/core/status/conftest.py
+++ b/tests/ahriman/core/status/conftest.py
@@ -1,7 +1,7 @@
import pytest
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
diff --git a/tests/ahriman/core/status/test_client.py b/tests/ahriman/core/status/test_client.py
index 7fcac79b..51b151f3 100644
--- a/tests/ahriman/core/status/test_client.py
+++ b/tests/ahriman/core/status/test_client.py
@@ -1,26 +1,39 @@
import logging
+import pytest
from pytest_mock import MockerFixture
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.models.build_status import BuildStatus, BuildStatusEnum
from ahriman.models.changes import Changes
+from ahriman.models.dependencies import Dependencies
from ahriman.models.internal_status import InternalStatus
from ahriman.models.log_record_id import LogRecordId
from ahriman.models.package import Package
+from ahriman.models.pkgbuild_patch import PkgbuildPatch
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
"""
_, 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
"""
@@ -28,10 +41,10 @@ def test_load_dummy_client_disabled(configuration: Configuration) -> None:
configuration.set_option("web", "port", "8080")
_, 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
"""
@@ -40,19 +53,19 @@ def test_load_dummy_client_disabled_in_configuration(configuration: Configuratio
configuration.set_option("status", "enabled", "no")
_, 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
"""
configuration.set_option("status", "address", "http://localhost:8080")
_, 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
"""
@@ -60,82 +73,144 @@ def test_load_full_client_from_legacy_host(configuration: Configuration) -> None
configuration.set_option("web", "port", "8080")
_, 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
"""
configuration.set_option("web", "address", "http://localhost:8080")
_, 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
"""
configuration.set_option("web", "unix_socket", "/var/lib/ahriman/ahriman-web.sock")
_, repository_id = configuration.check_loaded()
- assert isinstance(Client.load(repository_id, configuration, 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)
+ assert isinstance(Client.load(repository_id, configuration, database, report=True), WebClient)
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:
"""
- must return empty package list
+ must raise not implemented on packages get
"""
- assert client.package_get(package_ahriman.base) == []
- assert client.package_get(None) == []
+ with pytest.raises(NotImplementedError):
+ 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:
"""
- must process remove without errors
+ must raise not implemented on package removal
"""
- client.package_remove(package_ahriman.base)
+ with pytest.raises(NotImplementedError):
+ 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:
"""
- 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:
"""
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)
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
"""
- 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)
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
"""
- 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)
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
"""
- 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)
- 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:
"""
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)
- 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:
diff --git a/tests/ahriman/core/status/test_local_client.py b/tests/ahriman/core/status/test_local_client.py
new file mode 100644
index 00000000..8e3db4f4
--- /dev/null
+++ b/tests/ahriman/core/status/test_local_client.py
@@ -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)
diff --git a/tests/ahriman/core/status/test_watcher.py b/tests/ahriman/core/status/test_watcher.py
index 9962e1dc..34e9c182 100644
--- a/tests/ahriman/core/status/test_watcher.py
+++ b/tests/ahriman/core/status/test_watcher.py
@@ -1,26 +1,33 @@
import pytest
from pytest_mock import MockerFixture
-from unittest.mock import call as MockCall
from ahriman.core.exceptions import UnknownPackageError
from ahriman.core.status.watcher import Watcher
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.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:
"""
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())])
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]
assert package == package_ahriman
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
"""
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.load()
@@ -39,85 +46,6 @@ def test_load_known(watcher: Watcher, package_ahriman: Package, mocker: MockerFi
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:
"""
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)
+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:
"""
must remove package base
"""
- cache_mock = mocker.patch("ahriman.core.database.SQLite.package_remove")
- logs_mock = mocker.patch("ahriman.core.status.watcher.Watcher.logs_remove")
+ cache_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_remove")
+ logs_mock = mocker.patch("ahriman.core.status.watcher.Watcher.package_logs_remove", create=True)
watcher._known = {package_ahriman.base: (package_ahriman, BuildStatus())}
watcher.package_remove(package_ahriman.base)
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)
@@ -154,82 +114,42 @@ def test_package_remove_unknown(watcher: Watcher, package_ahriman: Package, mock
"""
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)
- 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:
- """
- 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:
+def test_package_status_update(watcher: Watcher, package_ahriman: Package, mocker: MockerFixture) -> None:
"""
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.package_update(package_ahriman.base, BuildStatusEnum.Success, None)
- cache_mock.assert_called_once_with(package_ahriman, pytest.helpers.anyvar(int), watcher.repository_id)
+ watcher.package_status_update(package_ahriman.base, BuildStatusEnum.Success)
+ cache_mock.assert_called_once_with(package_ahriman.base, pytest.helpers.anyvar(int))
package, status = watcher._known[package_ahriman.base]
assert package == package_ahriman
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
"""
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())}
- patches_mock = mocker.patch("ahriman.core.database.SQLite.patches_list")
+ cache_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_update")
- watcher.patches_get(package_ahriman.base, None)
- watcher.patches_get(package_ahriman.base, "var")
- patches_mock.assert_has_calls([
- 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])
+ watcher.package_update(package_ahriman, BuildStatusEnum.Unknown)
+ assert watcher.packages
+ cache_mock.assert_called_once_with(package_ahriman, pytest.helpers.anyvar(int))
def test_status_update(watcher: Watcher) -> None:
@@ -238,3 +158,41 @@ def test_status_update(watcher: Watcher) -> None:
"""
watcher.status_update(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
diff --git a/tests/ahriman/core/status/test_web_client.py b/tests/ahriman/core/status/test_web_client.py
index c174d396..3b75fb95 100644
--- a/tests/ahriman/core/status/test_web_client.py
+++ b/tests/ahriman/core/status/test_web_client.py
@@ -9,9 +9,11 @@ from ahriman.core.configuration import Configuration
from ahriman.core.status.web_client import WebClient
from ahriman.models.build_status import BuildStatus, BuildStatusEnum
from ahriman.models.changes import Changes
+from ahriman.models.dependencies import Dependencies
from ahriman.models.internal_status import InternalStatus
from ahriman.models.log_record_id import LogRecordId
from ahriman.models.package import Package
+from ahriman.models.pkgbuild_patch import PkgbuildPatch
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")
+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:
"""
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")
-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:
"""
must get changes
@@ -183,37 +157,37 @@ def test_package_changes_get_failed_http_error_suppress(web_client: WebClient, p
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
"""
changes = Changes("sha")
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),
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
"""
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,
- mocker: MockerFixture) -> None:
+def test_package_changes_update_failed_http_error(web_client: WebClient, package_ahriman: Package,
+ mocker: MockerFixture) -> None:
"""
must suppress HTTP exception happened during changes update
"""
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,
- mocker: MockerFixture) -> None:
+def test_package_changes_update_failed_suppress(web_client: WebClient, package_ahriman: Package,
+ mocker: MockerFixture) -> None:
"""
must suppress any exception happened during changes update and don't log
"""
@@ -221,12 +195,12 @@ def test_package_changes_set_failed_suppress(web_client: WebClient, package_ahri
mocker.patch("requests.Session.request", side_effect=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_changes_set_failed_http_error_suppress(web_client: WebClient, package_ahriman: Package,
- mocker: MockerFixture) -> None:
+def test_package_changes_update_failed_http_error_suppress(web_client: WebClient, package_ahriman: Package,
+ mocker: MockerFixture) -> None:
"""
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())
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()
@@ -291,8 +382,8 @@ 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]
-def test_package_logs(web_client: WebClient, log_record: logging.LogRecord, package_ahriman: Package,
- mocker: MockerFixture) -> None:
+def test_package_logs_add(web_client: WebClient, log_record: logging.LogRecord, package_ahriman: Package,
+ mocker: MockerFixture) -> None:
"""
must process log record
"""
@@ -303,31 +394,314 @@ def test_package_logs(web_client: WebClient, log_record: logging.LogRecord, pack
"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),
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,
- mocker: MockerFixture) -> None:
+def test_package_logs_add_failed(web_client: WebClient, log_record: logging.LogRecord, package_ahriman: Package,
+ mocker: MockerFixture) -> None:
"""
must pass exception during log post
"""
mocker.patch("requests.Session.request", side_effect=Exception())
log_record.package_base = package_ahriman.base
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,
- mocker: MockerFixture) -> None:
+def test_package_logs_add_failed_http_error(web_client: WebClient, log_record: logging.LogRecord,
+ package_ahriman: Package, mocker: MockerFixture) -> None:
"""
must pass exception during log post
"""
mocker.patch("requests.Session.request", side_effect=requests.HTTPError())
log_record.package_base = package_ahriman.base
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:
@@ -358,13 +732,13 @@ def test_package_remove_failed_http_error(web_client: WebClient, package_ahriman
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
"""
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),
params=web_client.repository_id.query(),
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
"""
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_status_update_failed_http_error(web_client: WebClient, package_ahriman: Package,
+ mocker: MockerFixture) -> None:
+ """
+ must suppress HTTP exception happened during update
+ """
+ mocker.patch("requests.Session.request", side_effect=requests.HTTPError())
+ 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 update
+ must suppress HTTP exception happened during addition
"""
mocker.patch("requests.Session.request", side_effect=requests.HTTPError())
- web_client.package_update(package_ahriman.base, BuildStatusEnum.Unknown)
+ 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:
diff --git a/tests/ahriman/core/support/test_package_creator.py b/tests/ahriman/core/support/test_package_creator.py
index acb32316..dc2b88a7 100644
--- a/tests/ahriman/core/support/test_package_creator.py
+++ b/tests/ahriman/core/support/test_package_creator.py
@@ -1,8 +1,7 @@
-import pytest
-
+from pathlib import Path
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.models.package import Package
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
-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(
base=package_creator.generator.pkgname,
version=package_creator.generator.pkgver,
remote=RemoteSource(source=PackageSource.Local),
packages={package_creator.generator.pkgname: PackageDescription()},
)
- local_path = package_creator.configuration.repository_paths.cache_for(package_creator.generator.pkgname)
-
- rmtree_mock = mocker.patch("shutil.rmtree")
- database_mock = mocker.patch("ahriman.core._Context.get", return_value=database)
- init_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.init")
- insert_mock = mocker.patch("ahriman.core.database.SQLite.package_update")
- mkdir_mock = mocker.patch("pathlib.Path.mkdir")
+ client_mock = mocker.patch("ahriman.core._Context.get", return_value=Client())
+ insert_mock = mocker.patch("ahriman.core.status.Client.set_unknown")
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()
- rmtree_mock.assert_called_once_with(local_path, ignore_errors=True)
- mkdir_mock.assert_called_once_with(mode=0o755, parents=True, exist_ok=True)
- write_mock.assert_called_once_with(local_path)
- init_mock.assert_called_once_with(local_path)
-
- package_mock.assert_called_once_with(local_path, "x86_64", None)
- database_mock.assert_called_once_with(SQLite)
- insert_mock.assert_called_once_with(package, pytest.helpers.anyvar(int))
+ create_mock.assert_called_once_with(path)
+ register_mock.assert_called_once_with(path)
diff --git a/tests/ahriman/core/test_util.py b/tests/ahriman/core/test_util.py
index 9686e332..b26303fc 100644
--- a/tests/ahriman/core/test_util.py
+++ b/tests/ahriman/core/test_util.py
@@ -2,7 +2,6 @@ import datetime
import logging
import os
import pytest
-import shlex
from pathlib import Path
from pytest_mock import MockerFixture
diff --git a/tests/ahriman/models/test_dependencies.py b/tests/ahriman/models/test_dependencies.py
index e69de29b..098a8eff 100644
--- a/tests/ahriman/models/test_dependencies.py
+++ b/tests/ahriman/models/test_dependencies.py
@@ -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
diff --git a/tests/ahriman/models/test_package_archive.py b/tests/ahriman/models/test_package_archive.py
index 35c27654..6cab8a0e 100644
--- a/tests/ahriman/models/test_package_archive.py
+++ b/tests/ahriman/models/test_package_archive.py
@@ -65,13 +65,11 @@ def test_depends_on(package_archive_ahriman: PackageArchive, mocker: MockerFixtu
))
result = package_archive_ahriman.depends_on()
- assert result.package_base == package_archive_ahriman.package.base
assert result.paths == {
- Path("package1") / "file1": ["package1"],
- Path("package2") / "file3": ["package2"],
- Path("package2") / "dir4": ["package2"],
- Path("package2") / "file3": ["package2"],
- Path("usr") / "dir2": ["package1", "package2"]
+ "package1/file1": ["package1"],
+ "package2/file3": ["package2"],
+ "package2/dir4": ["package2"],
+ "usr/dir2": ["package1", "package2"]
}
diff --git a/tests/ahriman/models/test_pkgbuild_patch.py b/tests/ahriman/models/test_pkgbuild_patch.py
index e0214d7c..70d95ed3 100644
--- a/tests/ahriman/models/test_pkgbuild_patch.py
+++ b/tests/ahriman/models/test_pkgbuild_patch.py
@@ -51,6 +51,14 @@ def test_from_env() -> None:
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:
"""
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')"""
-def test_view() -> None:
- """
- must correctly serialize to json
- """
- assert PkgbuildPatch("key", "value").view() == {"key": "key", "value": "value"}
-
-
def test_write(mocker: MockerFixture) -> None:
"""
must write serialized value to the file
diff --git a/tests/ahriman/models/test_repository_id.py b/tests/ahriman/models/test_repository_id.py
index 94a9fb23..f18973c0 100644
--- a/tests/ahriman/models/test_repository_id.py
+++ b/tests/ahriman/models/test_repository_id.py
@@ -60,4 +60,4 @@ def test_lt_invalid() -> None:
must raise ValueError if other is not valid repository id
"""
with pytest.raises(ValueError):
- RepositoryId("x86_64", "a") < 42
+ assert RepositoryId("x86_64", "a") < 42
diff --git a/tests/ahriman/web/schemas/test_dependencies_schema.py b/tests/ahriman/web/schemas/test_dependencies_schema.py
new file mode 100644
index 00000000..1982fb6b
--- /dev/null
+++ b/tests/ahriman/web/schemas/test_dependencies_schema.py
@@ -0,0 +1 @@
+# schema testing goes in view class tests
diff --git a/tests/ahriman/web/schemas/test_package_version_schema.py b/tests/ahriman/web/schemas/test_package_version_schema.py
new file mode 100644
index 00000000..1982fb6b
--- /dev/null
+++ b/tests/ahriman/web/schemas/test_package_version_schema.py
@@ -0,0 +1 @@
+# schema testing goes in view class tests
diff --git a/tests/ahriman/web/views/test_view_base.py b/tests/ahriman/web/views/test_view_base.py
index cb74933a..901e095c 100644
--- a/tests/ahriman/web/views/test_view_base.py
+++ b/tests/ahriman/web/views/test_view_base.py
@@ -204,6 +204,15 @@ def test_service_not_found(base: BaseView) -> None:
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:
"""
must return identity of logged-in user
diff --git a/tests/ahriman/web/views/v1/packages/test_view_v1_packages_dependencies.py b/tests/ahriman/web/views/v1/packages/test_view_v1_packages_dependencies.py
new file mode 100644
index 00000000..ffa1e913
--- /dev/null
+++ b/tests/ahriman/web/views/v1/packages/test_view_v1_packages_dependencies.py
@@ -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())
diff --git a/tests/ahriman/web/views/v1/packages/test_view_v1_packages_logs.py b/tests/ahriman/web/views/v1/packages/test_view_v1_packages_logs.py
index 8c220f0d..04c50f58 100644
--- a/tests/ahriman/web/views/v1/packages/test_view_v1_packages_logs.py
+++ b/tests/ahriman/web/views/v1/packages/test_view_v1_packages_logs.py
@@ -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()})
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",
- 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")
assert response.status == 204
diff --git a/tests/ahriman/web/views/v1/packages/test_view_v1_packages_patches.py b/tests/ahriman/web/views/v1/packages/test_view_v1_packages_patches.py
index fee9bc0f..b337e968 100644
--- a/tests/ahriman/web/views/v1/packages/test_view_v1_packages_patches.py
+++ b/tests/ahriman/web/views/v1/packages/test_view_v1_packages_patches.py
@@ -64,6 +64,24 @@ async def test_post(client: TestClient, package_ahriman: Package) -> None:
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:
"""
must raise exception on invalid payload
diff --git a/tests/ahriman/web/views/v1/status/test_view_v1_status_info.py b/tests/ahriman/web/views/v1/status/test_view_v1_status_info.py
index 3e72deaf..ff741482 100644
--- a/tests/ahriman/web/views/v1/status/test_view_v1_status_info.py
+++ b/tests/ahriman/web/views/v1/status/test_view_v1_status_info.py
@@ -30,7 +30,7 @@ async def test_get(client: TestClient, repository_id: RepositoryId) -> None:
"""
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
json = await response.json()
assert not response_schema.validate(json)
diff --git a/tests/ahriman/web/views/v1/status/test_view_v1_status_repositories.py b/tests/ahriman/web/views/v1/status/test_view_v1_status_repositories.py
index cd6f54f8..62ec0628 100644
--- a/tests/ahriman/web/views/v1/status/test_view_v1_status_repositories.py
+++ b/tests/ahriman/web/views/v1/status/test_view_v1_status_repositories.py
@@ -29,7 +29,7 @@ async def test_get(client: TestClient, repository_id: RepositoryId) -> None:
"""
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
json = await response.json()
assert not response_schema.validate(json, many=True)