mirror of
https://github.com/arcan1s/ahriman.git
synced 2026-07-23 19:01:14 +00:00
this project is actively using optional imports, which leads to duplicate handling here and there. This commit implements logic in special method to reduce complexity and simplify tests paths
572 lines
15 KiB
Python
572 lines
15 KiB
Python
#
|
|
# Copyright (c) 2021-2025 ahriman team.
|
|
#
|
|
# This file is part of ahriman
|
|
# (see https://github.com/arcan1s/ahriman).
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
import argparse
|
|
import datetime
|
|
import pytest
|
|
|
|
from dataclasses import replace
|
|
from pathlib import Path
|
|
from pytest_mock import MockerFixture
|
|
from sqlite3 import Cursor
|
|
from typing import Any, TypeVar
|
|
from unittest.mock import MagicMock
|
|
|
|
from ahriman.application.ahriman import _parser
|
|
from ahriman.core.alpm.remote import AUR
|
|
from ahriman.core.configuration import Configuration
|
|
from ahriman.core.database import SQLite
|
|
from ahriman.core.database.migrations import Migrations
|
|
from ahriman.core.log.log_loader import LogLoader
|
|
from ahriman.core.repository import Repository
|
|
from ahriman.core.repository.package_info import PackageInfo
|
|
from ahriman.core.sign.gpg import GPG
|
|
from ahriman.core.spawn import Spawn
|
|
from ahriman.core.status import Client
|
|
from ahriman.core.status.event_bus import EventBus
|
|
from ahriman.core.status.watcher import Watcher
|
|
from ahriman.models.aur_package import AURPackage
|
|
from ahriman.models.build_status import BuildStatus, BuildStatusEnum
|
|
from ahriman.models.migration import Migration
|
|
from ahriman.models.package import Package
|
|
from ahriman.models.package_description import PackageDescription
|
|
from ahriman.models.package_source import PackageSource
|
|
from ahriman.models.remote_source import RemoteSource
|
|
from ahriman.models.repository_id import RepositoryId
|
|
from ahriman.models.repository_paths import RepositoryPaths
|
|
from ahriman.models.result import Result
|
|
from ahriman.models.user import User
|
|
from ahriman.models.user_access import UserAccess
|
|
|
|
|
|
T = TypeVar("T")
|
|
|
|
|
|
# helpers
|
|
# https://stackoverflow.com/a/21611963
|
|
def anyvar(cls: type[T], strict: bool = False) -> T:
|
|
"""
|
|
any value helper for mocker calls check
|
|
|
|
Args:
|
|
cls(type[T]): type of the variable to check
|
|
strict(bool, optional): if True then check type of supplied argument (Default value = False)
|
|
|
|
Returns:
|
|
T: any wrapper
|
|
"""
|
|
class AnyVar(cls):
|
|
"""
|
|
any value wrapper
|
|
"""
|
|
|
|
def __eq__(self, other: Any) -> bool:
|
|
"""
|
|
compare object to other
|
|
|
|
Args:
|
|
other(Any): other object to compare
|
|
|
|
Returns:
|
|
bool: True in case if objects are equal
|
|
"""
|
|
return not strict or isinstance(other, cls)
|
|
|
|
return AnyVar()
|
|
|
|
|
|
def get_package_status(package: Package) -> dict[str, Any]:
|
|
"""
|
|
helper to extract package status from package
|
|
|
|
Args:
|
|
package(Package): package object
|
|
|
|
Returns:
|
|
dict[str, Any]: simplified package status map (with only status and view)
|
|
"""
|
|
return {"status": BuildStatusEnum.Unknown.value, "package": package.view()}
|
|
|
|
|
|
def get_package_status_extended(package: Package) -> dict[str, Any]:
|
|
"""
|
|
helper to extract package status from package
|
|
|
|
Args:
|
|
package(Package): package object
|
|
|
|
Returns:
|
|
dict[str, Any]: full package status map (with timestamped build status and view)
|
|
"""
|
|
return {"status": BuildStatus().view(), "package": package.view()}
|
|
|
|
|
|
@pytest.hookimpl(trylast=True)
|
|
def pytest_configure() -> None:
|
|
"""
|
|
register helpers after pytest-helpers-namespace has initialized
|
|
"""
|
|
for helper in (anyvar, get_package_status, get_package_status_extended):
|
|
pytest.helpers.register(helper)
|
|
|
|
|
|
# generic fixtures
|
|
@pytest.fixture(autouse=True)
|
|
def _register_log_context() -> None:
|
|
"""
|
|
register log context variables and factory
|
|
"""
|
|
LogLoader.register_context()
|
|
|
|
|
|
@pytest.fixture
|
|
def args() -> argparse.Namespace:
|
|
"""
|
|
fixture for command line arguments
|
|
|
|
Returns:
|
|
argparse.Namespace: command line arguments test instance
|
|
"""
|
|
return argparse.Namespace(architecture=None, lock=None, force=False, unsafe=False, report=False,
|
|
repository=None, repository_id=None, wait_timeout=-1)
|
|
|
|
|
|
@pytest.fixture
|
|
def aur_package_ahriman() -> AURPackage:
|
|
"""
|
|
fixture for AUR package
|
|
|
|
Returns:
|
|
AURPackage: AUR package test instance
|
|
"""
|
|
return AURPackage(
|
|
id=1197565,
|
|
name="ahriman",
|
|
package_base_id=165427,
|
|
package_base="ahriman",
|
|
version="2.6.0-1",
|
|
description="ArcH linux ReposItory MANager",
|
|
num_votes=0,
|
|
popularity=0,
|
|
first_submitted=datetime.datetime.fromtimestamp(1618008285, datetime.UTC),
|
|
last_modified=datetime.datetime.fromtimestamp(1673826351, datetime.UTC),
|
|
url_path="/cgit/aur.git/snapshot/ahriman.tar.gz",
|
|
url="https://github.com/arcan1s/ahriman",
|
|
out_of_date=None,
|
|
maintainer="arcanis",
|
|
submitter="arcanis",
|
|
depends=[
|
|
"devtools",
|
|
"git",
|
|
"pyalpm",
|
|
"python-cerberus",
|
|
"python-inflection",
|
|
"python-passlib",
|
|
"python-requests",
|
|
"python-setuptools",
|
|
"python-srcinfo",
|
|
],
|
|
make_depends=[
|
|
"python-build",
|
|
"python-installer",
|
|
"python-wheel",
|
|
],
|
|
opt_depends=[
|
|
"breezy",
|
|
"darcs",
|
|
"mercurial",
|
|
"python-aioauth-client",
|
|
"python-aiohttp",
|
|
"python-aiohttp-debugtoolbar",
|
|
"python-aiohttp-jinja2",
|
|
"python-aiohttp-security",
|
|
"python-aiohttp-session",
|
|
"python-boto3",
|
|
"python-cryptography",
|
|
"python-requests-unixsocket",
|
|
"python-jinja",
|
|
"rsync",
|
|
"subversion",
|
|
],
|
|
check_depends=[
|
|
"python-pytest",
|
|
],
|
|
conflicts=[],
|
|
provides=[],
|
|
license=["GPL3"],
|
|
keywords=[],
|
|
groups=[],
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def configuration(repository_id: RepositoryId, tmp_path: Path, resource_path_root: Path) -> Configuration:
|
|
"""
|
|
configuration fixture
|
|
|
|
Args:
|
|
repository_id(RepositoryId): repository identifier fixture
|
|
tmp_path(Path): temporary path used by the fixture as root
|
|
resource_path_root(Path): resource path root directory
|
|
|
|
Returns:
|
|
Configuration: configuration test instance
|
|
"""
|
|
path = resource_path_root / "core" / "ahriman.ini"
|
|
|
|
instance = Configuration.from_path(path, repository_id)
|
|
instance.set_option("repository", "root", str(tmp_path))
|
|
instance.set_option("settings", "database", str(tmp_path / "ahriman.db"))
|
|
|
|
return instance
|
|
|
|
|
|
@pytest.fixture
|
|
def database(configuration: Configuration, mocker: MockerFixture) -> SQLite:
|
|
"""
|
|
database fixture
|
|
|
|
Args:
|
|
configuration(Configuration): configuration fixture
|
|
mocker(MockerFixture): mocker object
|
|
|
|
Returns:
|
|
SQLite: database test instance
|
|
"""
|
|
original_method = Migrations.perform_migration
|
|
|
|
def perform_migration(self: Migrations, cursor: Cursor, migration: Migration) -> None:
|
|
original_method(self, cursor, replace(migration, migrate_data=lambda *args: None))
|
|
|
|
mocker.patch.object(Migrations, "perform_migration", autospec=True, side_effect=perform_migration)
|
|
return SQLite.load(configuration)
|
|
|
|
|
|
@pytest.fixture
|
|
def gpg(configuration: Configuration) -> GPG:
|
|
"""
|
|
fixture for empty GPG
|
|
|
|
Args:
|
|
configuration(Configuration): configuration fixture
|
|
|
|
Returns:
|
|
GPG: GPG test instance
|
|
"""
|
|
return GPG(configuration)
|
|
|
|
|
|
@pytest.fixture
|
|
def local_client(database: SQLite, configuration: Configuration) -> Client:
|
|
"""
|
|
local status client
|
|
|
|
Args:
|
|
database(SQLite): database fixture
|
|
configuration(Configuration): configuration 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:
|
|
"""
|
|
package fixture
|
|
|
|
Args:
|
|
package_description_ahriman(PackageDescription): description fixture
|
|
remote_source(RemoteSource): remote source fixture
|
|
|
|
Returns:
|
|
Package: package test instance
|
|
"""
|
|
packages = {"ahriman": package_description_ahriman}
|
|
return Package(
|
|
base="ahriman",
|
|
version="2.6.0-1",
|
|
remote=remote_source,
|
|
packages=packages,
|
|
packager="packager")
|
|
|
|
|
|
@pytest.fixture
|
|
def package_python_schedule(
|
|
package_description_python_schedule: PackageDescription,
|
|
package_description_python2_schedule: PackageDescription) -> Package:
|
|
"""
|
|
multi package fixture
|
|
|
|
Args:
|
|
package_description_python_schedule(PackageDescription): description fixture
|
|
package_description_python2_schedule(PackageDescription): description fixture
|
|
|
|
Returns:
|
|
Package: multi package test instance
|
|
"""
|
|
packages = {
|
|
"python-schedule": package_description_python_schedule,
|
|
"python2-schedule": package_description_python2_schedule
|
|
}
|
|
return Package(
|
|
base="python-schedule",
|
|
version="1.0.0-2",
|
|
remote=RemoteSource(
|
|
source=PackageSource.AUR,
|
|
git_url=AUR.remote_git_url("python-schedule", "aur"),
|
|
web_url=AUR.remote_web_url("python-schedule"),
|
|
path=".",
|
|
branch="master",
|
|
),
|
|
packages=packages)
|
|
|
|
|
|
@pytest.fixture
|
|
def package_description_ahriman() -> PackageDescription:
|
|
"""
|
|
package description fixture
|
|
|
|
Returns:
|
|
PackageDescription: package description test instance
|
|
"""
|
|
return PackageDescription(
|
|
architecture="x86_64",
|
|
archive_size=4200,
|
|
build_date=42,
|
|
depends=[
|
|
"devtools",
|
|
"git",
|
|
"pyalpm",
|
|
"python-cerberus",
|
|
"python-inflection",
|
|
"python-passlib",
|
|
"python-requests",
|
|
"python-setuptools",
|
|
"python-srcinfo",
|
|
],
|
|
make_depends=[
|
|
"python-build",
|
|
"python-installer",
|
|
"python-wheel",
|
|
],
|
|
opt_depends=[
|
|
"breezy",
|
|
"darcs",
|
|
"mercurial",
|
|
"python-aioauth-client",
|
|
"python-aiohttp",
|
|
"python-aiohttp-debugtoolbar",
|
|
"python-aiohttp-jinja2",
|
|
"python-aiohttp-security",
|
|
"python-aiohttp-session",
|
|
"python-boto3",
|
|
"python-cryptography",
|
|
"python-requests-unixsocket",
|
|
"python-jinja",
|
|
"rsync",
|
|
"subversion",
|
|
],
|
|
check_depends=[
|
|
"python-pytest",
|
|
],
|
|
description="ArcH linux ReposItory MANager",
|
|
filename="ahriman-2.6.0-1-any.pkg.tar.zst",
|
|
groups=[],
|
|
installed_size=4200000,
|
|
licenses=["GPL3"],
|
|
url="https://github.com/arcan1s/ahriman",
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def package_description_python_schedule() -> PackageDescription:
|
|
"""
|
|
package description fixture
|
|
|
|
Returns:
|
|
PackageDescription: package description test instance
|
|
"""
|
|
return PackageDescription(
|
|
architecture="x86_64",
|
|
archive_size=4201,
|
|
build_date=421,
|
|
depends=["python"],
|
|
description="Python job scheduling for humans.",
|
|
filename="python-schedule-1.0.0-2-any.pkg.tar.zst",
|
|
groups=[],
|
|
installed_size=4200001,
|
|
licenses=["MIT"],
|
|
url="https://github.com/dbader/schedule",
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def package_description_python2_schedule() -> PackageDescription:
|
|
"""
|
|
package description fixture
|
|
|
|
Returns:
|
|
PackageDescription: package description test instance
|
|
"""
|
|
return PackageDescription(
|
|
architecture="x86_64",
|
|
archive_size=4202,
|
|
build_date=422,
|
|
depends=["python2"],
|
|
description="Python job scheduling for humans.",
|
|
filename="python2-schedule-1.0.0-2-any.pkg.tar.zst",
|
|
groups=[],
|
|
installed_size=4200002,
|
|
licenses=["MIT"],
|
|
url="https://github.com/dbader/schedule",
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def parser() -> argparse.ArgumentParser:
|
|
"""
|
|
fixture for command line arguments parser
|
|
|
|
Returns:
|
|
argparse.ArgumentParser: command line arguments parser instance
|
|
"""
|
|
return _parser()
|
|
|
|
|
|
@pytest.fixture
|
|
def remote_source() -> RemoteSource:
|
|
"""
|
|
remote source fixture
|
|
|
|
Returns:
|
|
RemoteSource: remote source test instance
|
|
"""
|
|
return RemoteSource(
|
|
source=PackageSource.AUR,
|
|
git_url=AUR.remote_git_url("ahriman", "aur"),
|
|
web_url=AUR.remote_web_url("ahriman"),
|
|
path=".",
|
|
branch="master",
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def repository(configuration: Configuration, database: SQLite, mocker: MockerFixture) -> Repository:
|
|
"""
|
|
fixture for repository
|
|
|
|
Args:
|
|
configuration(Configuration): configuration fixture
|
|
database(SQLite): database fixture
|
|
mocker(MockerFixture): mocker object
|
|
|
|
Returns:
|
|
Repository: repository test instance
|
|
"""
|
|
mocker.patch("ahriman.core.repository.Repository._set_context")
|
|
_, repository_id = configuration.check_loaded()
|
|
return Repository.load(repository_id, configuration, database, report=False)
|
|
|
|
|
|
@pytest.fixture
|
|
def repository_id() -> RepositoryId:
|
|
"""
|
|
fixture for repository identifier
|
|
|
|
Returns:
|
|
RepositoryId: repository identifier test instance
|
|
"""
|
|
return RepositoryId("x86_64", "aur")
|
|
|
|
|
|
@pytest.fixture
|
|
def repository_paths(configuration: Configuration) -> RepositoryPaths:
|
|
"""
|
|
repository paths fixture
|
|
|
|
Args:
|
|
configuration(Configuration): configuration fixture
|
|
|
|
Returns:
|
|
RepositoryPaths: repository paths test instance
|
|
"""
|
|
return configuration.repository_paths
|
|
|
|
|
|
@pytest.fixture
|
|
def result(package_ahriman: Package) -> Result:
|
|
"""
|
|
result fixture
|
|
|
|
Args:
|
|
package_ahriman(Package): package fixture
|
|
|
|
Returns:
|
|
Result: result test instance
|
|
"""
|
|
result = Result()
|
|
result.add_updated(package_ahriman)
|
|
return result
|
|
|
|
|
|
@pytest.fixture
|
|
def spawner(configuration: Configuration) -> Spawn:
|
|
"""
|
|
spawner fixture
|
|
|
|
Args:
|
|
configuration(Configuration): configuration fixture
|
|
|
|
Returns:
|
|
Spawn: spawner fixture
|
|
"""
|
|
return Spawn(MagicMock(), [
|
|
"--configuration", str(configuration.path),
|
|
])
|
|
|
|
|
|
@pytest.fixture
|
|
def user() -> User:
|
|
"""
|
|
fixture for user descriptor
|
|
|
|
Returns:
|
|
User: user descriptor instance
|
|
"""
|
|
return User(username="user", password="pa55w0rd", access=UserAccess.Reporter, packager_id="packager", key="key")
|
|
|
|
|
|
@pytest.fixture
|
|
def watcher(local_client: Client) -> Watcher:
|
|
"""
|
|
package status watcher fixture
|
|
|
|
Args:
|
|
local_client(Client): local status client fixture
|
|
|
|
Returns:
|
|
Watcher: package status watcher test instance
|
|
"""
|
|
package_info = PackageInfo()
|
|
event_bus = EventBus(0)
|
|
return Watcher(local_client, package_info, event_bus)
|