mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-07-16 15:29:56 +00:00
provide service api endpoints
This commit is contained in:
@ -19,13 +19,17 @@
|
||||
#
|
||||
from aiohttp.web import Application
|
||||
|
||||
from ahriman.web.views.ahriman import AhrimanView
|
||||
from ahriman.web.views.index import IndexView
|
||||
from ahriman.web.views.login import LoginView
|
||||
from ahriman.web.views.logout import LogoutView
|
||||
from ahriman.web.views.package import PackageView
|
||||
from ahriman.web.views.packages import PackagesView
|
||||
from ahriman.web.views.status import StatusView
|
||||
from ahriman.web.views.service.add import AddView
|
||||
from ahriman.web.views.service.remove import RemoveView
|
||||
from ahriman.web.views.service.search import SearchView
|
||||
from ahriman.web.views.service.update import UpdateView
|
||||
from ahriman.web.views.status.ahriman import AhrimanView
|
||||
from ahriman.web.views.status.package import PackageView
|
||||
from ahriman.web.views.status.packages import PackagesView
|
||||
from ahriman.web.views.status.status import StatusView
|
||||
from ahriman.web.views.user.login import LoginView
|
||||
from ahriman.web.views.user.logout import LogoutView
|
||||
|
||||
|
||||
def setup_routes(application: Application) -> None:
|
||||
@ -37,8 +41,13 @@ def setup_routes(application: Application) -> None:
|
||||
GET / get build status page
|
||||
GET /index.html same as above
|
||||
|
||||
POST /user-api/v1/login login to service
|
||||
POST /user-api/v1/logout logout from service
|
||||
POST /service-api/v1/add add new packages to repository
|
||||
|
||||
POST /service-api/v1/remove remove existing package from repository
|
||||
|
||||
GET /service-api/v1/search search for substring in AUR
|
||||
|
||||
POST /service-api/v1/update update existing package in repository
|
||||
|
||||
GET /status-api/v1/ahriman get current service status
|
||||
POST /status-api/v1/ahriman update service status
|
||||
@ -52,13 +61,21 @@ def setup_routes(application: Application) -> None:
|
||||
|
||||
GET /status-api/v1/status get web service status itself
|
||||
|
||||
POST /user-api/v1/login login to service
|
||||
POST /user-api/v1/logout logout from service
|
||||
|
||||
:param application: web application instance
|
||||
"""
|
||||
application.router.add_get("/", IndexView, allow_head=True)
|
||||
application.router.add_get("/index.html", IndexView, allow_head=True)
|
||||
|
||||
application.router.add_post("/user-api/v1/login", LoginView)
|
||||
application.router.add_post("/user-api/v1/logout", LogoutView)
|
||||
application.router.add_post("/service-api/v1/add", AddView)
|
||||
|
||||
application.router.add_post("/service-api/v1/remove", RemoveView)
|
||||
|
||||
application.router.add_get("/service-api/v1/search", SearchView, allow_head=False)
|
||||
|
||||
application.router.add_post("/service-api/v1/update", UpdateView)
|
||||
|
||||
application.router.add_get("/status-api/v1/ahriman", AhrimanView, allow_head=True)
|
||||
application.router.add_post("/status-api/v1/ahriman", AhrimanView)
|
||||
@ -71,3 +88,6 @@ def setup_routes(application: Application) -> None:
|
||||
application.router.add_post("/status-api/v1/packages/{package}", PackageView)
|
||||
|
||||
application.router.add_get("/status-api/v1/status", StatusView, allow_head=True)
|
||||
|
||||
application.router.add_post("/user-api/v1/login", LoginView)
|
||||
application.router.add_post("/user-api/v1/logout", LogoutView)
|
||||
|
@ -18,7 +18,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from aiohttp.web import View
|
||||
from typing import Any, Dict
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from ahriman.core.auth.auth import Auth
|
||||
from ahriman.core.spawn import Spawn
|
||||
@ -54,20 +54,22 @@ class BaseView(View):
|
||||
validator: Auth = self.request.app["validator"]
|
||||
return validator
|
||||
|
||||
async def extract_data(self) -> Dict[str, Any]:
|
||||
async def extract_data(self, list_keys: Optional[List[str]] = None) -> Dict[str, Any]:
|
||||
"""
|
||||
extract json data from either json or form data
|
||||
:param list_keys: optional list of keys which must be forced to list from form data
|
||||
:return: raw json object or form data converted to json
|
||||
"""
|
||||
try:
|
||||
json: Dict[str, Any] = await self.request.json()
|
||||
return json
|
||||
except ValueError:
|
||||
return await self.data_as_json()
|
||||
return await self.data_as_json(list_keys or [])
|
||||
|
||||
async def data_as_json(self) -> Dict[str, Any]:
|
||||
async def data_as_json(self, list_keys: List[str]) -> Dict[str, Any]:
|
||||
"""
|
||||
extract form data and convert it to json object
|
||||
:param list_keys: list of keys which must be forced to list from form data
|
||||
:return: form data converted to json. In case if a key is found multiple times it will be returned as list
|
||||
"""
|
||||
raw = await self.request.post()
|
||||
@ -77,6 +79,8 @@ class BaseView(View):
|
||||
json[key].append(value)
|
||||
elif key in json:
|
||||
json[key] = [json[key], value]
|
||||
elif key in list_keys:
|
||||
json[key] = [value]
|
||||
else:
|
||||
json[key] = value
|
||||
return json
|
||||
|
19
src/ahriman/web/views/service/__init__.py
Normal file
19
src/ahriman/web/views/service/__init__.py
Normal file
@ -0,0 +1,19 @@
|
||||
#
|
||||
# Copyright (c) 2021 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/>.
|
||||
#
|
52
src/ahriman/web/views/service/add.py
Normal file
52
src/ahriman/web/views/service/add.py
Normal file
@ -0,0 +1,52 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from aiohttp.web import HTTPFound, Response, json_response
|
||||
|
||||
from ahriman.web.views.base import BaseView
|
||||
|
||||
|
||||
class AddView(BaseView):
|
||||
"""
|
||||
add package web view
|
||||
"""
|
||||
|
||||
async def post(self) -> Response:
|
||||
"""
|
||||
add new package
|
||||
|
||||
JSON body must be supplied, the following model is used:
|
||||
{
|
||||
"packages": "ahriman", # either list of packages or package name as in AUR
|
||||
"build_now": true # optional flag which runs build
|
||||
}
|
||||
|
||||
:return: redirect to main page on success
|
||||
"""
|
||||
data = await self.extract_data(["packages"])
|
||||
|
||||
try:
|
||||
now = data.get("build_now") or False
|
||||
packages = data["packages"]
|
||||
except Exception as e:
|
||||
return json_response(text=str(e), status=400)
|
||||
|
||||
self.spawner.packages_add(packages, now)
|
||||
|
||||
return HTTPFound("/")
|
50
src/ahriman/web/views/service/remove.py
Normal file
50
src/ahriman/web/views/service/remove.py
Normal file
@ -0,0 +1,50 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from aiohttp.web import HTTPFound, Response, json_response
|
||||
|
||||
from ahriman.web.views.base import BaseView
|
||||
|
||||
|
||||
class RemoveView(BaseView):
|
||||
"""
|
||||
remove package web view
|
||||
"""
|
||||
|
||||
async def post(self) -> Response:
|
||||
"""
|
||||
remove existing packages
|
||||
|
||||
JSON body must be supplied, the following model is used:
|
||||
{
|
||||
"packages": "ahriman", # either list of packages or package name
|
||||
}
|
||||
|
||||
:return: redirect to main page on success
|
||||
"""
|
||||
data = await self.extract_data(["packages"])
|
||||
|
||||
try:
|
||||
packages = data["packages"]
|
||||
except Exception as e:
|
||||
return json_response(text=str(e), status=400)
|
||||
|
||||
self.spawner.packages_remove(packages)
|
||||
|
||||
return HTTPFound("/")
|
48
src/ahriman/web/views/service/search.py
Normal file
48
src/ahriman/web/views/service/search.py
Normal file
@ -0,0 +1,48 @@
|
||||
#
|
||||
# Copyright (c) 2021 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 aur # type: ignore
|
||||
|
||||
from aiohttp.web import Response, json_response
|
||||
from typing import Iterator
|
||||
|
||||
from ahriman.web.views.base import BaseView
|
||||
|
||||
|
||||
class SearchView(BaseView):
|
||||
"""
|
||||
AUR search web view
|
||||
"""
|
||||
|
||||
async def get(self) -> Response:
|
||||
"""
|
||||
search packages in AUR
|
||||
|
||||
search string (non empty) must be supplied as `for` parameter
|
||||
|
||||
:return: 200 with found package bases sorted by name
|
||||
"""
|
||||
search: Iterator[str] = filter(lambda s: len(s) > 3, self.request.query.getall("for", default=[]))
|
||||
search_string = " ".join(search)
|
||||
|
||||
if not search_string:
|
||||
return json_response(text="Search string must not be empty", status=400)
|
||||
packages = aur.search(search_string)
|
||||
|
||||
return json_response(sorted(package.package_base for package in packages))
|
50
src/ahriman/web/views/service/update.py
Normal file
50
src/ahriman/web/views/service/update.py
Normal file
@ -0,0 +1,50 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from aiohttp.web import HTTPFound, Response, json_response
|
||||
|
||||
from ahriman.web.views.base import BaseView
|
||||
|
||||
|
||||
class UpdateView(BaseView):
|
||||
"""
|
||||
update package web view
|
||||
"""
|
||||
|
||||
async def post(self) -> Response:
|
||||
"""
|
||||
update existing packages
|
||||
|
||||
JSON body must be supplied, the following model is used:
|
||||
{
|
||||
"packages": "ahriman", # either list of packages or package name
|
||||
}
|
||||
|
||||
:return: redirect to main page on success
|
||||
"""
|
||||
data = await self.extract_data(["packages"])
|
||||
|
||||
try:
|
||||
packages = data["packages"]
|
||||
except Exception as e:
|
||||
return json_response(text=str(e), status=400)
|
||||
|
||||
self.spawner.packages_update(packages)
|
||||
|
||||
return HTTPFound("/")
|
19
src/ahriman/web/views/status/__init__.py
Normal file
19
src/ahriman/web/views/status/__init__.py
Normal file
@ -0,0 +1,19 @@
|
||||
#
|
||||
# Copyright (c) 2021 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/>.
|
||||
#
|
@ -17,7 +17,7 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from aiohttp.web import HTTPBadRequest, HTTPNoContent, Response, json_response
|
||||
from aiohttp.web import HTTPNoContent, Response, json_response
|
||||
|
||||
from ahriman.models.build_status import BuildStatusEnum
|
||||
from ahriman.web.views.base import BaseView
|
||||
@ -51,7 +51,7 @@ class AhrimanView(BaseView):
|
||||
try:
|
||||
status = BuildStatusEnum(data["status"])
|
||||
except Exception as e:
|
||||
raise HTTPBadRequest(text=str(e))
|
||||
return json_response(text=str(e), status=400)
|
||||
|
||||
self.service.update_self(status)
|
||||
|
@ -17,7 +17,7 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from aiohttp.web import HTTPBadRequest, HTTPNoContent, HTTPNotFound, Response, json_response
|
||||
from aiohttp.web import HTTPNoContent, HTTPNotFound, Response, json_response
|
||||
|
||||
from ahriman.core.exceptions import UnknownPackage
|
||||
from ahriman.models.build_status import BuildStatusEnum
|
||||
@ -80,11 +80,11 @@ class PackageView(BaseView):
|
||||
package = Package.from_json(data["package"]) if "package" in data else None
|
||||
status = BuildStatusEnum(data["status"])
|
||||
except Exception as e:
|
||||
raise HTTPBadRequest(text=str(e))
|
||||
return json_response(text=str(e), status=400)
|
||||
|
||||
try:
|
||||
self.service.update(base, status, package)
|
||||
except UnknownPackage:
|
||||
raise HTTPBadRequest(text=f"Package {base} is unknown, but no package body set")
|
||||
return json_response(text=f"Package {base} is unknown, but no package body set", status=400)
|
||||
|
||||
return HTTPNoContent()
|
19
src/ahriman/web/views/user/__init__.py
Normal file
19
src/ahriman/web/views/user/__init__.py
Normal file
@ -0,0 +1,19 @@
|
||||
#
|
||||
# Copyright (c) 2021 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/>.
|
||||
#
|
@ -1,5 +1,4 @@
|
||||
import argparse
|
||||
import aur
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
@ -8,7 +7,6 @@ from ahriman.application.ahriman import _parser
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.lock import Lock
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.package import Package
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@ -32,31 +30,6 @@ def args() -> argparse.Namespace:
|
||||
return argparse.Namespace(lock=None, force=False, unsafe=False, no_report=True)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def aur_package_ahriman(package_ahriman: Package) -> aur.Package:
|
||||
"""
|
||||
fixture for AUR package
|
||||
:param package_ahriman: package fixture
|
||||
:return: AUR package test instance
|
||||
"""
|
||||
return aur.Package(
|
||||
num_votes=None,
|
||||
description=package_ahriman.packages[package_ahriman.base].description,
|
||||
url_path=package_ahriman.web_url,
|
||||
last_modified=None,
|
||||
name=package_ahriman.base,
|
||||
out_of_date=None,
|
||||
id=None,
|
||||
first_submitted=None,
|
||||
maintainer=None,
|
||||
version=package_ahriman.version,
|
||||
license=package_ahriman.packages[package_ahriman.base].licenses,
|
||||
url=None,
|
||||
package_base=package_ahriman.base,
|
||||
package_base_id=None,
|
||||
category_id=None)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def lock(args: argparse.Namespace, configuration: Configuration) -> Lock:
|
||||
"""
|
||||
|
@ -1,3 +1,4 @@
|
||||
import aur
|
||||
import pytest
|
||||
|
||||
from pathlib import Path
|
||||
@ -46,6 +47,31 @@ def anyvar(cls: Type[T], strict: bool = False) -> T:
|
||||
|
||||
|
||||
# generic fixtures
|
||||
@pytest.fixture
|
||||
def aur_package_ahriman(package_ahriman: Package) -> aur.Package:
|
||||
"""
|
||||
fixture for AUR package
|
||||
:param package_ahriman: package fixture
|
||||
:return: AUR package test instance
|
||||
"""
|
||||
return aur.Package(
|
||||
num_votes=None,
|
||||
description=package_ahriman.packages[package_ahriman.base].description,
|
||||
url_path=package_ahriman.web_url,
|
||||
last_modified=None,
|
||||
name=package_ahriman.base,
|
||||
out_of_date=None,
|
||||
id=None,
|
||||
first_submitted=None,
|
||||
maintainer=None,
|
||||
version=package_ahriman.version,
|
||||
license=package_ahriman.packages[package_ahriman.base].licenses,
|
||||
url=None,
|
||||
package_base=package_ahriman.base,
|
||||
package_base_id=None,
|
||||
category_id=None)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def auth(configuration: Configuration) -> Auth:
|
||||
"""
|
||||
|
35
tests/ahriman/web/views/service/test_views_service_add.py
Normal file
35
tests/ahriman/web/views/service/test_views_service_add.py
Normal file
@ -0,0 +1,35 @@
|
||||
from aiohttp.test_utils import TestClient
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
|
||||
async def test_post(client: TestClient, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must call post request correctly
|
||||
"""
|
||||
add_mock = mocker.patch("ahriman.core.spawn.Spawn.packages_add")
|
||||
response = await client.post("/service-api/v1/add", json={"packages": ["ahriman"]})
|
||||
|
||||
assert response.status == 200
|
||||
add_mock.assert_called_with(["ahriman"], False)
|
||||
|
||||
|
||||
async def test_post_now(client: TestClient, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must call post and run build
|
||||
"""
|
||||
add_mock = mocker.patch("ahriman.core.spawn.Spawn.packages_add")
|
||||
response = await client.post("/service-api/v1/add", json={"packages": ["ahriman"], "build_now": True})
|
||||
|
||||
assert response.status == 200
|
||||
add_mock.assert_called_with(["ahriman"], True)
|
||||
|
||||
|
||||
async def test_post_exception(client: TestClient, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise exception on missing packages payload
|
||||
"""
|
||||
add_mock = mocker.patch("ahriman.core.spawn.Spawn.packages_add")
|
||||
response = await client.post("/service-api/v1/add")
|
||||
|
||||
assert response.status == 400
|
||||
add_mock.assert_not_called()
|
24
tests/ahriman/web/views/service/test_views_service_remove.py
Normal file
24
tests/ahriman/web/views/service/test_views_service_remove.py
Normal file
@ -0,0 +1,24 @@
|
||||
from aiohttp.test_utils import TestClient
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
|
||||
async def test_post(client: TestClient, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must call post request correctly
|
||||
"""
|
||||
add_mock = mocker.patch("ahriman.core.spawn.Spawn.packages_remove")
|
||||
response = await client.post("/service-api/v1/remove", json={"packages": ["ahriman"]})
|
||||
|
||||
assert response.status == 200
|
||||
add_mock.assert_called_with(["ahriman"])
|
||||
|
||||
|
||||
async def test_post_exception(client: TestClient, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise exception on missing packages payload
|
||||
"""
|
||||
add_mock = mocker.patch("ahriman.core.spawn.Spawn.packages_remove")
|
||||
response = await client.post("/service-api/v1/remove")
|
||||
|
||||
assert response.status == 400
|
||||
add_mock.assert_not_called()
|
59
tests/ahriman/web/views/service/test_views_service_search.py
Normal file
59
tests/ahriman/web/views/service/test_views_service_search.py
Normal file
@ -0,0 +1,59 @@
|
||||
import aur
|
||||
|
||||
from aiohttp.test_utils import TestClient
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
|
||||
async def test_get(client: TestClient, aur_package_ahriman: aur.Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must call get request correctly
|
||||
"""
|
||||
mocker.patch("aur.search", return_value=[aur_package_ahriman])
|
||||
response = await client.get("/service-api/v1/search", params={"for": "ahriman"})
|
||||
|
||||
assert response.status == 200
|
||||
assert await response.json() == ["ahriman"]
|
||||
|
||||
|
||||
async def test_get_exception(client: TestClient, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise 400 on empty search string
|
||||
"""
|
||||
search_mock = mocker.patch("aur.search")
|
||||
response = await client.get("/service-api/v1/search")
|
||||
|
||||
assert response.status == 400
|
||||
search_mock.assert_not_called()
|
||||
|
||||
|
||||
async def test_get_join(client: TestClient, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must join search args with space
|
||||
"""
|
||||
search_mock = mocker.patch("aur.search")
|
||||
response = await client.get("/service-api/v1/search", params=[("for", "ahriman"), ("for", "maybe")])
|
||||
|
||||
assert response.status == 200
|
||||
search_mock.assert_called_with("ahriman maybe")
|
||||
|
||||
|
||||
async def test_get_join_filter(client: TestClient, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must filter search parameters with less than 3 symbols
|
||||
"""
|
||||
search_mock = mocker.patch("aur.search")
|
||||
response = await client.get("/service-api/v1/search", params=[("for", "ah"), ("for", "maybe")])
|
||||
|
||||
assert response.status == 200
|
||||
search_mock.assert_called_with("maybe")
|
||||
|
||||
|
||||
async def test_get_join_filter_empty(client: TestClient, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must filter search parameters with less than 3 symbols (empty result)
|
||||
"""
|
||||
search_mock = mocker.patch("aur.search")
|
||||
response = await client.get("/service-api/v1/search", params=[("for", "ah"), ("for", "ma")])
|
||||
|
||||
assert response.status == 400
|
||||
search_mock.assert_not_called()
|
24
tests/ahriman/web/views/service/test_views_service_update.py
Normal file
24
tests/ahriman/web/views/service/test_views_service_update.py
Normal file
@ -0,0 +1,24 @@
|
||||
from aiohttp.test_utils import TestClient
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
|
||||
async def test_post(client: TestClient, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must call post request correctly
|
||||
"""
|
||||
add_mock = mocker.patch("ahriman.core.spawn.Spawn.packages_update")
|
||||
response = await client.post("/service-api/v1/update", json={"packages": ["ahriman"]})
|
||||
|
||||
assert response.status == 200
|
||||
add_mock.assert_called_with(["ahriman"])
|
||||
|
||||
|
||||
async def test_post_exception(client: TestClient, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise exception on missing packages payload
|
||||
"""
|
||||
add_mock = mocker.patch("ahriman.core.spawn.Spawn.packages_update")
|
||||
response = await client.post("/service-api/v1/update")
|
||||
|
||||
assert response.status == 400
|
||||
add_mock.assert_not_called()
|
@ -61,9 +61,6 @@ async def test_data_as_json(base: BaseView) -> None:
|
||||
"""
|
||||
json = {"key1": "value1", "key2": ["value2", "value3"], "key3": ["value4", "value5", "value6"]}
|
||||
|
||||
async def get_json():
|
||||
raise ValueError()
|
||||
|
||||
async def get_data():
|
||||
result = MultiDict()
|
||||
for key, values in json.items():
|
||||
@ -74,5 +71,18 @@ async def test_data_as_json(base: BaseView) -> None:
|
||||
result.add(key, values)
|
||||
return result
|
||||
|
||||
base._request = pytest.helpers.request(base.request.app, "", "", json=get_json, data=get_data)
|
||||
assert await base.data_as_json() == json
|
||||
base._request = pytest.helpers.request(base.request.app, "", "", data=get_data)
|
||||
assert await base.data_as_json([]) == json
|
||||
|
||||
|
||||
async def test_data_as_json_with_list_keys(base: BaseView) -> None:
|
||||
"""
|
||||
must parse multi value form payload with forced list
|
||||
"""
|
||||
json = {"key1": "value1"}
|
||||
|
||||
async def get_data():
|
||||
return json
|
||||
|
||||
base._request = pytest.helpers.request(base.request.app, "", "", data=get_data)
|
||||
assert await base.data_as_json(["key1"]) == {"key1": ["value1"]}
|
Reference in New Issue
Block a user