feat: add patch controls to web, review web, enrich info tab (#115)

* add ability to specify one-time patch on package addition

* support vars in interface
This commit is contained in:
2023-10-29 23:41:20 +02:00
committed by GitHub
parent 54bd016c17
commit 8f047f9a96
54 changed files with 1327 additions and 276 deletions

View File

@ -9,6 +9,7 @@ from ahriman.core.repository import Repository
from ahriman.models.package import Package
from ahriman.models.package_source import PackageSource
from ahriman.models.packagers import Packagers
from ahriman.models.pkgbuild_patch import PkgbuildPatch
from ahriman.models.result import Result
@ -22,7 +23,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
Returns:
argparse.Namespace: generated arguments for these test cases
"""
args.package = []
args.package = ["ahriman"]
args.exit_code = False
args.increment = True
args.now = False
@ -30,6 +31,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
args.source = PackageSource.Auto
args.dependencies = True
args.username = "username"
args.variable = None
return args
@ -51,6 +53,22 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
on_start_mock.assert_called_once_with()
def test_run_with_patches(args: argparse.Namespace, configuration: Configuration, repository: Repository,
mocker: MockerFixture) -> None:
"""
must run command and insert temporary patches
"""
args = _default_args(args)
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")
_, 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")])
def test_run_with_updates(args: argparse.Namespace, configuration: Configuration, repository: Repository,
package_ahriman: Package, mocker: MockerFixture) -> None:
"""

View File

@ -180,7 +180,7 @@ def test_patch_set_create(application: Application, package_ahriman: Package, mo
"""
create_mock = mocker.patch("ahriman.core.database.SQLite.patches_insert")
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:

View File

@ -254,6 +254,22 @@ def test_subparsers_package_add_option_refresh(parser: argparse.ArgumentParser)
assert args.refresh == 2
def test_subparsers_package_add_option_variable_empty(parser: argparse.ArgumentParser) -> None:
"""
package-add command must accept empty variable list as None
"""
args = parser.parse_args(["package-add", "ahriman"])
assert args.variable is None
def test_subparsers_package_add_option_variable_multiple(parser: argparse.ArgumentParser) -> None:
"""
repo-rebuild command must accept multiple depends-on
"""
args = parser.parse_args(["package-add", "ahriman", "-v", "var1", "-v", "var2"])
assert args.variable == ["var1", "var2"]
def test_subparsers_package_remove_option_architecture(parser: argparse.ArgumentParser) -> None:
"""
package-remove command must correctly parse architecture list

View File

@ -20,6 +20,7 @@ def test_init(task_ahriman: Task, database: SQLite, mocker: MockerFixture) -> No
"""
mocker.patch("ahriman.models.package.Package.from_build", return_value=task_ahriman.package)
load_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.load")
task_ahriman.init(Path("ahriman"), database, None)
load_mock.assert_called_once_with(Path("ahriman"), task_ahriman.package, [], task_ahriman.paths)

View File

@ -8,7 +8,7 @@ from ahriman.core.configuration import Configuration
from ahriman.core.database.migrations.m011_repository_name import migrate_data, migrate_package_repository, steps
def test_migration_check_depends() -> None:
def test_migration_repository_name() -> None:
"""
migration must not be empty
"""

View File

@ -7,9 +7,9 @@ def test_patches_get_insert(database: SQLite, package_ahriman: Package, package_
"""
must insert patch to database
"""
database.patches_insert(package_ahriman.base, PkgbuildPatch(None, "patch_1"))
database.patches_insert(package_ahriman.base, PkgbuildPatch("key", "patch_3"))
database.patches_insert(package_python_schedule.base, PkgbuildPatch(None, "patch_2"))
database.patches_insert(package_ahriman.base, [PkgbuildPatch(None, "patch_1")])
database.patches_insert(package_ahriman.base, [PkgbuildPatch("key", "patch_3")])
database.patches_insert(package_python_schedule.base, [PkgbuildPatch(None, "patch_2")])
assert database.patches_get(package_ahriman.base) == [
PkgbuildPatch(None, "patch_1"), PkgbuildPatch("key", "patch_3")
]
@ -19,9 +19,9 @@ def test_patches_list(database: SQLite, package_ahriman: Package, package_python
"""
must list all patches
"""
database.patches_insert(package_ahriman.base, PkgbuildPatch(None, "patch1"))
database.patches_insert(package_ahriman.base, PkgbuildPatch("key", "patch3"))
database.patches_insert(package_python_schedule.base, PkgbuildPatch(None, "patch2"))
database.patches_insert(package_ahriman.base, [PkgbuildPatch(None, "patch1")])
database.patches_insert(package_ahriman.base, [PkgbuildPatch("key", "patch3")])
database.patches_insert(package_python_schedule.base, [PkgbuildPatch(None, "patch2")])
assert database.patches_list(None, None) == {
package_ahriman.base: [PkgbuildPatch(None, "patch1"), PkgbuildPatch("key", "patch3")],
package_python_schedule.base: [PkgbuildPatch(None, "patch2")],
@ -32,8 +32,8 @@ def test_patches_list_filter(database: SQLite, package_ahriman: Package, package
"""
must list all patches filtered by package name (same as get)
"""
database.patches_insert(package_ahriman.base, PkgbuildPatch(None, "patch1"))
database.patches_insert(package_python_schedule.base, PkgbuildPatch(None, "patch2"))
database.patches_insert(package_ahriman.base, [PkgbuildPatch(None, "patch1")])
database.patches_insert(package_python_schedule.base, [PkgbuildPatch(None, "patch2")])
assert database.patches_list(package_ahriman.base, None) == {package_ahriman.base: [PkgbuildPatch(None, "patch1")]}
assert database.patches_list(package_python_schedule.base, None) == {
@ -46,9 +46,9 @@ def test_patches_list_filter_by_variable(database: SQLite, package_ahriman: Pack
"""
must list all patches filtered by package name (same as get)
"""
database.patches_insert(package_ahriman.base, PkgbuildPatch(None, "patch1"))
database.patches_insert(package_ahriman.base, PkgbuildPatch("key", "patch2"))
database.patches_insert(package_python_schedule.base, PkgbuildPatch(None, "patch3"))
database.patches_insert(package_ahriman.base, [PkgbuildPatch(None, "patch1")])
database.patches_insert(package_ahriman.base, [PkgbuildPatch("key", "patch2")])
database.patches_insert(package_python_schedule.base, [PkgbuildPatch(None, "patch3")])
assert database.patches_list(None, None) == {
package_ahriman.base: [PkgbuildPatch(None, "patch1"), PkgbuildPatch("key", "patch2")],
@ -63,8 +63,8 @@ def test_patches_insert_remove(database: SQLite, package_ahriman: Package, packa
"""
must remove patch from database
"""
database.patches_insert(package_ahriman.base, PkgbuildPatch(None, "patch1"))
database.patches_insert(package_python_schedule.base, PkgbuildPatch(None, "patch2"))
database.patches_insert(package_ahriman.base, [PkgbuildPatch(None, "patch1")])
database.patches_insert(package_python_schedule.base, [PkgbuildPatch(None, "patch2")])
database.patches_remove(package_ahriman.base, None)
assert database.patches_get(package_ahriman.base) == []
@ -76,9 +76,9 @@ def test_patches_insert_remove_by_variable(database: SQLite, package_ahriman: Pa
"""
must remove patch from database by variable
"""
database.patches_insert(package_ahriman.base, PkgbuildPatch(None, "patch1"))
database.patches_insert(package_ahriman.base, PkgbuildPatch("key", "patch3"))
database.patches_insert(package_python_schedule.base, PkgbuildPatch(None, "patch2"))
database.patches_insert(package_ahriman.base, [PkgbuildPatch(None, "patch1")])
database.patches_insert(package_ahriman.base, [PkgbuildPatch("key", "patch3")])
database.patches_insert(package_python_schedule.base, [PkgbuildPatch(None, "patch2")])
database.patches_remove(package_ahriman.base, ["key"])
assert database.patches_get(package_ahriman.base) == [PkgbuildPatch(None, "patch1")]
@ -89,8 +89,14 @@ def test_patches_insert_insert(database: SQLite, package_ahriman: Package) -> No
"""
must update patch in database
"""
database.patches_insert(package_ahriman.base, PkgbuildPatch(None, "patch1"))
database.patches_insert(package_ahriman.base, [PkgbuildPatch(None, "patch1")])
assert database.patches_get(package_ahriman.base) == [PkgbuildPatch(None, "patch1")]
database.patches_insert(package_ahriman.base, PkgbuildPatch(None, "patch2"))
database.patches_insert(package_ahriman.base, [PkgbuildPatch(None, "patch2")])
assert database.patches_get(package_ahriman.base) == [PkgbuildPatch(None, "patch2")]
database.patches_insert(package_ahriman.base, [PkgbuildPatch(None, "patch3"), PkgbuildPatch("key", "patch4")])
assert database.patches_get(package_ahriman.base) == [
PkgbuildPatch(None, "patch3"),
PkgbuildPatch("key", "patch4"),
]

View File

@ -1,12 +1,14 @@
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.log_record_id import LogRecordId
from ahriman.models.package import Package
from ahriman.models.pkgbuild_patch import PkgbuildPatch
def test_load(watcher: Watcher, package_ahriman: Package, mocker: MockerFixture) -> None:
@ -163,6 +165,42 @@ def test_package_update_unknown(watcher: Watcher, package_ahriman: Package) -> N
watcher.package_update(package_ahriman.base, BuildStatusEnum.Unknown, None)
def test_patches_get(watcher: Watcher, package_ahriman: Package, mocker: MockerFixture) -> None:
"""
must return patches for the package
"""
patches_mock = mocker.patch("ahriman.core.database.SQLite.patches_list")
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])
def test_status_update(watcher: Watcher) -> None:
"""
must update service status

View File

@ -4,6 +4,7 @@ from pytest_mock import MockerFixture
from unittest.mock import MagicMock
from ahriman.core.spawn import Spawn
from ahriman.models.pkgbuild_patch import PkgbuildPatch
from ahriman.models.process_status import ProcessStatus
from ahriman.models.repository_id import RepositoryId
@ -56,11 +57,12 @@ def test_spawn_process(spawner: Spawn, repository_id: RepositoryId, mocker: Mock
"""
start_mock = mocker.patch("multiprocessing.Process.start")
assert spawner._spawn_process(repository_id, "add", "ahriman", now="", maybe="?", none=None)
assert spawner._spawn_process(repository_id, "command", "argument",
empty="", string="v", list=["a", "b"], empty_list=[], none=None)
start_mock.assert_called_once_with()
spawner.args_parser.parse_args.assert_called_once_with(
spawner.command_arguments + [
"add", "ahriman", "--now", "--maybe", "?"
"command", "argument", "--empty", "--string", "v", "--list", "a", "--list", "b",
]
)
@ -99,7 +101,7 @@ def test_packages_add(spawner: Spawn, repository_id: RepositoryId, mocker: Mocke
must call package addition
"""
spawn_mock = mocker.patch("ahriman.core.spawn.Spawn._spawn_process")
assert spawner.packages_add(repository_id, ["ahriman", "linux"], None, now=False)
assert spawner.packages_add(repository_id, ["ahriman", "linux"], None, patches=[], now=False)
spawn_mock.assert_called_once_with(repository_id, "package-add", "ahriman", "linux", username=None)
@ -108,7 +110,7 @@ def test_packages_add_with_build(spawner: Spawn, repository_id: RepositoryId, mo
must call package addition with update
"""
spawn_mock = mocker.patch("ahriman.core.spawn.Spawn._spawn_process")
assert spawner.packages_add(repository_id, ["ahriman", "linux"], None, now=True)
assert spawner.packages_add(repository_id, ["ahriman", "linux"], None, patches=[], now=True)
spawn_mock.assert_called_once_with(repository_id, "package-add", "ahriman", "linux", username=None, now="")
@ -117,10 +119,21 @@ def test_packages_add_with_username(spawner: Spawn, repository_id: RepositoryId,
must call package addition with username
"""
spawn_mock = mocker.patch("ahriman.core.spawn.Spawn._spawn_process")
assert spawner.packages_add(repository_id, ["ahriman", "linux"], "username", now=False)
assert spawner.packages_add(repository_id, ["ahriman", "linux"], "username", patches=[], now=False)
spawn_mock.assert_called_once_with(repository_id, "package-add", "ahriman", "linux", username="username")
def test_packages_add_with_patches(spawner: Spawn, repository_id: RepositoryId, mocker: MockerFixture) -> None:
"""
must call package addition with patches
"""
patches = [PkgbuildPatch("key", "value"), PkgbuildPatch("key", "value")]
spawn_mock = mocker.patch("ahriman.core.spawn.Spawn._spawn_process")
assert spawner.packages_add(repository_id, ["ahriman", "linux"], None, patches=patches, now=False)
spawn_mock.assert_called_once_with(repository_id, "package-add", "ahriman", "linux", username=None,
variable=[patch.serialize() for patch in patches])
def test_packages_rebuild(spawner: Spawn, repository_id: RepositoryId, mocker: MockerFixture) -> None:
"""
must call package rebuild

View File

@ -2,6 +2,7 @@ import datetime
import logging
import os
import pytest
import shlex
from pathlib import Path
from pytest_mock import MockerFixture
@ -11,7 +12,7 @@ from unittest.mock import call as MockCall
from ahriman.core.exceptions import BuildError, CalledProcessError, OptionError, UnsafeRunError
from ahriman.core.util import check_output, check_user, dataclass_view, enum_values, extract_user, filter_json, \
full_version, minmax, package_like, parse_version, partition, pretty_datetime, pretty_size, safe_filename, \
srcinfo_property, srcinfo_property_list, trim_package, utcnow, walk
srcinfo_property, srcinfo_property_list, trim_package, unquote, utcnow, walk
from ahriman.models.package import Package
from ahriman.models.package_source import PackageSource
from ahriman.models.repository_paths import RepositoryPaths
@ -443,6 +444,26 @@ def test_trim_package() -> None:
assert trim_package("package: a description") == "package"
def test_unquote() -> None:
"""
must remove quotation marks
"""
for source in (
"abc",
"ab'c",
"ab\"c",
):
assert unquote(shlex.quote(source)) == source
def test_unquote_error() -> None:
"""
must raise value error on invalid quotation
"""
with pytest.raises(ValueError):
unquote("ab'c")
def test_utcnow() -> None:
"""
must generate correct timestamp

View File

@ -34,9 +34,18 @@ def test_quote() -> None:
"""
must quote strings if unsafe flag is not set
"""
assert PkgbuildPatch("key", "value").quote("value") == """value"""
assert PkgbuildPatch("key", "va'lue").quote("va'lue") == """'va'"'"'lue'"""
assert PkgbuildPatch("key", "va'lue", unsafe=True).quote("va'lue") == """va'lue"""
assert PkgbuildPatch.quote("value") == """value"""
assert PkgbuildPatch.quote("va'lue") == """'va'"'"'lue'"""
def test_from_env() -> None:
"""
must construct patch from environment variable
"""
assert PkgbuildPatch.from_env("KEY=VALUE") == PkgbuildPatch("KEY", "VALUE")
assert PkgbuildPatch.from_env("KEY=VA=LUE") == PkgbuildPatch("KEY", "VA=LUE")
assert PkgbuildPatch.from_env("KEY=") == PkgbuildPatch("KEY", "")
assert PkgbuildPatch.from_env("KEY") == PkgbuildPatch("KEY", "")
def test_serialize() -> None:
@ -46,7 +55,19 @@ def test_serialize() -> None:
assert PkgbuildPatch("key", "value").serialize() == "key=value"
assert PkgbuildPatch("key", "42").serialize() == "key=42"
assert PkgbuildPatch("key", "4'2").serialize() == """key='4'"'"'2'"""
assert PkgbuildPatch("key", "4'2", unsafe=True).serialize() == "key=4'2"
def test_from_env_serialize() -> None:
"""
must serialize and parse back
"""
for patch in (
PkgbuildPatch("key", "value"),
PkgbuildPatch("key", "4'2"),
PkgbuildPatch("arch", ["i686", "x86_64"]),
PkgbuildPatch("key", ["val'ue", "val\"ue2"]),
):
assert PkgbuildPatch.from_env(patch.serialize()) == patch
def test_serialize_plain_diff() -> None:
@ -60,7 +81,7 @@ def test_serialize_function() -> None:
"""
must correctly serialize function values
"""
assert PkgbuildPatch("key()", "{ value }", unsafe=True).serialize() == "key() { value }"
assert PkgbuildPatch("key()", "{ value }").serialize() == "key() { value }"
def test_serialize_list() -> None:
@ -69,7 +90,13 @@ def test_serialize_list() -> None:
"""
assert PkgbuildPatch("arch", ["i686", "x86_64"]).serialize() == """arch=(i686 x86_64)"""
assert PkgbuildPatch("key", ["val'ue", "val\"ue2"]).serialize() == """key=('val'"'"'ue' 'val"ue2')"""
assert PkgbuildPatch("key", ["val'ue", "val\"ue2"], unsafe=True).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:

View File

@ -17,7 +17,7 @@ def test_id() -> None:
"""
must correctly generate id
"""
assert RepositoryId("", "").id == "-"
assert RepositoryId("", "").id == ""
assert RepositoryId("arch", "repo").id == "arch-repo"

View File

@ -0,0 +1 @@
# schema testing goes in view class tests

View File

@ -0,0 +1 @@
# schema testing goes in view class tests

View File

@ -0,0 +1 @@
# schema testing goes in view class tests

View File

@ -0,0 +1 @@
# schema testing goes in view class tests

View File

@ -4,6 +4,7 @@ from aiohttp.test_utils import TestClient
from pytest_mock import MockerFixture
from unittest.mock import AsyncMock
from ahriman.models.pkgbuild_patch import PkgbuildPatch
from ahriman.models.repository_id import RepositoryId
from ahriman.models.user_access import UserAccess
from ahriman.web.views.v1.service.add import AddView
@ -40,13 +41,42 @@ async def test_post(client: TestClient, repository_id: RepositoryId, mocker: Moc
assert not request_schema.validate(payload)
response = await client.post("/api/v1/service/add", json=payload)
assert response.ok
add_mock.assert_called_once_with(repository_id, ["ahriman"], "username", now=True)
add_mock.assert_called_once_with(repository_id, ["ahriman"], "username", patches=[], now=True)
json = await response.json()
assert json["process_id"] == "abc"
assert not response_schema.validate(json)
async def test_post_patches(client: TestClient, repository_id: RepositoryId, mocker: MockerFixture) -> None:
"""
must call post request with patches correctly
"""
add_mock = mocker.patch("ahriman.core.spawn.Spawn.packages_add", return_value="abc")
user_mock = AsyncMock()
user_mock.return_value = "username"
mocker.patch("ahriman.web.views.base.BaseView.username", side_effect=user_mock)
request_schema = pytest.helpers.schema_request(AddView.post)
payload = {
"packages": ["ahriman"],
"patches": [
{
"key": "k",
"value": "v",
},
{
"key": "k2",
},
]
}
assert not request_schema.validate(payload)
response = await client.post("/api/v1/service/add", json=payload)
assert response.ok
add_mock.assert_called_once_with(repository_id, ["ahriman"], "username",
patches=[PkgbuildPatch("k", "v"), PkgbuildPatch("k2", "")], now=True)
async def test_post_empty(client: TestClient, mocker: MockerFixture) -> None:
"""
must call raise 400 on empty request

View File

@ -4,6 +4,7 @@ from aiohttp.test_utils import TestClient
from pytest_mock import MockerFixture
from unittest.mock import AsyncMock
from ahriman.models.pkgbuild_patch import PkgbuildPatch
from ahriman.models.repository_id import RepositoryId
from ahriman.models.user_access import UserAccess
from ahriman.web.views.v1.service.request import RequestView
@ -40,13 +41,42 @@ async def test_post(client: TestClient, repository_id: RepositoryId, mocker: Moc
assert not request_schema.validate(payload)
response = await client.post("/api/v1/service/request", json=payload)
assert response.ok
add_mock.assert_called_once_with(repository_id, ["ahriman"], "username", now=False)
add_mock.assert_called_once_with(repository_id, ["ahriman"], "username", patches=[], now=False)
json = await response.json()
assert json["process_id"] == "abc"
assert not response_schema.validate(json)
async def test_post_patches(client: TestClient, repository_id: RepositoryId, mocker: MockerFixture) -> None:
"""
must call post request with patches correctly
"""
add_mock = mocker.patch("ahriman.core.spawn.Spawn.packages_add", return_value="abc")
user_mock = AsyncMock()
user_mock.return_value = "username"
mocker.patch("ahriman.web.views.base.BaseView.username", side_effect=user_mock)
request_schema = pytest.helpers.schema_request(RequestView.post)
payload = {
"packages": ["ahriman"],
"patches": [
{
"key": "k",
"value": "v",
},
{
"key": "k2",
},
]
}
assert not request_schema.validate(payload)
response = await client.post("/api/v1/service/request", json=payload)
assert response.ok
add_mock.assert_called_once_with(repository_id, ["ahriman"], "username",
patches=[PkgbuildPatch("k", "v"), PkgbuildPatch("k2", "")], now=False)
async def test_post_exception(client: TestClient, mocker: MockerFixture) -> None:
"""
must raise exception on missing packages payload

View File

@ -0,0 +1,81 @@
import pytest
from aiohttp.test_utils import TestClient
from ahriman.models.build_status import BuildStatusEnum
from ahriman.models.package import Package
from ahriman.models.pkgbuild_patch import PkgbuildPatch
from ahriman.models.user_access import UserAccess
from ahriman.web.views.v1.status.patch import PatchView
async def test_get_permission() -> None:
"""
must return correct permission for the request
"""
for method in ("GET",):
request = pytest.helpers.request("", "", method)
assert await PatchView.get_permission(request) == UserAccess.Reporter
for method in ("DELETE",):
request = pytest.helpers.request("", "", method)
assert await PatchView.get_permission(request) == UserAccess.Full
def test_routes() -> None:
"""
must return correct routes
"""
assert PatchView.ROUTES == ["/api/v1/packages/{package}/patches/{patch}"]
async def test_delete(client: TestClient, package_ahriman: Package, package_python_schedule: Package) -> None:
"""
must delete patch for 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_python_schedule.base}",
json={"status": BuildStatusEnum.Success.value, "package": package_python_schedule.view()})
patch_key = "k"
await client.post(f"/api/v1/packages/{package_ahriman.base}/patches", json={"key": patch_key, "value": "v"})
await client.post(f"/api/v1/packages/{package_python_schedule.base}/patches",
json={"key": patch_key, "value": "v2"})
response = await client.delete(f"/api/v1/packages/{package_ahriman.base}/patches/{patch_key}")
assert response.status == 204
response = await client.get(f"/api/v1/packages/{package_ahriman.base}/patches")
assert not await response.json()
response = await client.get(f"/api/v1/packages/{package_python_schedule.base}/patches")
assert await response.json()
async def test_get(client: TestClient, package_ahriman: Package) -> None:
"""
must get patch for package
"""
patch = PkgbuildPatch("k", "v")
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}/patches", json=patch.view())
response_schema = pytest.helpers.schema_response(PatchView.get)
response = await client.get(f"/api/v1/packages/{package_ahriman.base}/patches/{patch.key}")
assert response.status == 200
patches = await response.json()
assert not response_schema.validate(patches)
assert patches == patch.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(PatchView.get, code=404)
response = await client.get(f"/api/v1/packages/{package_ahriman.base}/patches/random")
assert response.status == 404
assert not response_schema.validate(await response.json())

View File

@ -0,0 +1,75 @@
import pytest
from aiohttp.test_utils import TestClient
from ahriman.models.build_status import BuildStatusEnum
from ahriman.models.package import Package
from ahriman.models.pkgbuild_patch import PkgbuildPatch
from ahriman.models.user_access import UserAccess
from ahriman.web.views.v1.status.patches import PatchesView
async def test_get_permission() -> None:
"""
must return correct permission for the request
"""
for method in ("GET",):
request = pytest.helpers.request("", "", method)
assert await PatchesView.get_permission(request) == UserAccess.Reporter
for method in ("POST",):
request = pytest.helpers.request("", "", method)
assert await PatchesView.get_permission(request) == UserAccess.Full
def test_routes() -> None:
"""
must return correct routes
"""
assert PatchesView.ROUTES == ["/api/v1/packages/{package}/patches"]
async def test_get(client: TestClient, package_ahriman: Package) -> None:
"""
must get patch for package
"""
patch = PkgbuildPatch("k", "v")
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}/patches", json=patch.view())
response_schema = pytest.helpers.schema_response(PatchesView.get)
response = await client.get(f"/api/v1/packages/{package_ahriman.base}/patches")
assert response.status == 200
patches = await response.json()
assert not response_schema.validate(patches)
assert patches == [patch.view()]
async def test_post(client: TestClient, package_ahriman: Package) -> None:
"""
must create patch
"""
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 = {"key": "k", "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
"""
response_schema = pytest.helpers.schema_response(PatchesView.post, code=400)
response = await client.post(f"/api/v1/packages/{package_ahriman.base}/patches", json={})
assert response.status == 400
assert not response_schema.validate(await response.json())

View File

@ -44,7 +44,16 @@ async def test_get(client: TestClient, package_ahriman: Package) -> None:
logs = await response.json()
assert not response_schema.validate(logs)
assert logs["logs"] == [[42.0, "message 1"], [43.0, "message 2"]]
assert logs == [
{
"created": 42.0,
"message": "message 1",
},
{
"created": 43.0,
"message": "message 2",
},
]
async def test_get_with_pagination(client: TestClient, package_ahriman: Package) -> None:
@ -67,18 +76,7 @@ async def test_get_with_pagination(client: TestClient, package_ahriman: Package)
logs = await response.json()
assert not response_schema.validate(logs)
assert logs["logs"] == [[43.0, "message 2"]]
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(LogsView.get, code=404)
response = await client.get(f"/api/v2/packages/{package_ahriman.base}/logs")
assert response.status == 404
assert not response_schema.validate(await response.json())
assert logs == [{"created": 43.0, "message": "message 2"}]
async def test_get_bad_request(client: TestClient, package_ahriman: Package) -> None: