mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-06-28 06:41:43 +00:00
use api generated docs instead of comments (#92)
This commit is contained in:
@ -12,7 +12,7 @@ from unittest.mock import MagicMock
|
||||
|
||||
from ahriman.core.exceptions import BuildError, OptionError, UnsafeRunError
|
||||
from ahriman.core.util import check_output, check_user, enum_values, exception_response_text, filter_json, \
|
||||
full_version, package_like, pretty_datetime, pretty_size, safe_filename, trim_package, utcnow, walk
|
||||
full_version, package_like, partition, pretty_datetime, pretty_size, safe_filename, trim_package, utcnow, walk
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.package_source import PackageSource
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
@ -228,6 +228,15 @@ def test_package_like_sig(package_ahriman: Package) -> None:
|
||||
assert not package_like(sig_file)
|
||||
|
||||
|
||||
def test_partition() -> None:
|
||||
"""
|
||||
must partition list based on predicate
|
||||
"""
|
||||
even, odd = partition([1, 4, 2, 1, 3, 4], lambda i: i % 2 == 0)
|
||||
assert even == [4, 2, 4]
|
||||
assert odd == [1, 1, 3]
|
||||
|
||||
|
||||
def test_pretty_datetime() -> None:
|
||||
"""
|
||||
must generate string from timestamp value
|
||||
@ -371,6 +380,7 @@ def test_walk(resource_path_root: Path) -> None:
|
||||
resource_path_root / "web" / "templates" / "static" / "favicon.ico",
|
||||
resource_path_root / "web" / "templates" / "utils" / "bootstrap-scripts.jinja2",
|
||||
resource_path_root / "web" / "templates" / "utils" / "style.jinja2",
|
||||
resource_path_root / "web" / "templates" / "api.jinja2",
|
||||
resource_path_root / "web" / "templates" / "build-status.jinja2",
|
||||
resource_path_root / "web" / "templates" / "email-index.jinja2",
|
||||
resource_path_root / "web" / "templates" / "error.jinja2",
|
||||
|
@ -1,7 +1,7 @@
|
||||
import pytest
|
||||
|
||||
from asyncio import BaseEventLoop
|
||||
from aiohttp import web
|
||||
from aiohttp.web import Application, Resource, UrlMappingMatchInfo
|
||||
from aiohttp.test_utils import TestClient
|
||||
from pytest_mock import MockerFixture
|
||||
from typing import Any, Dict, Optional
|
||||
@ -19,29 +19,35 @@ from ahriman.web.web import setup_service
|
||||
|
||||
|
||||
@pytest.helpers.register
|
||||
def request(app: web.Application, path: str, method: str, json: Any = None, data: Any = None,
|
||||
extra: Optional[Dict[str, Any]] = None) -> MagicMock:
|
||||
def request(application: Application, path: str, method: str, json: Any = None, data: Any = None,
|
||||
extra: Optional[Dict[str, Any]] = None, resource: Optional[Resource] = None) -> MagicMock:
|
||||
"""
|
||||
request generator helper
|
||||
|
||||
Args:
|
||||
app(web.Application): application fixture
|
||||
application(Application): application fixture
|
||||
path(str): path for the request
|
||||
method(str): method for the request
|
||||
json(Any, optional): json payload of the request (Default value = None)
|
||||
data(Any, optional): form data payload of the request (Default value = None)
|
||||
extra(Optional[Dict[str, Any]], optional): extra info which will be injected for ``get_extra_info`` command
|
||||
resource(Optional[Resource], optional): optional web resource for the request (Default value = None)
|
||||
|
||||
Returns:
|
||||
MagicMock: dummy request mock
|
||||
"""
|
||||
request_mock = MagicMock()
|
||||
request_mock.app = app
|
||||
request_mock.app = application
|
||||
request_mock.path = path
|
||||
request_mock.method = method
|
||||
request_mock.json = json
|
||||
request_mock.post = data
|
||||
|
||||
if resource is not None:
|
||||
route_mock = MagicMock()
|
||||
route_mock.resource = resource
|
||||
request_mock.match_info = UrlMappingMatchInfo({}, route_mock)
|
||||
|
||||
extra = extra or {}
|
||||
request_mock.get_extra_info.side_effect = lambda key: extra.get(key)
|
||||
|
||||
@ -50,7 +56,7 @@ def request(app: web.Application, path: str, method: str, json: Any = None, data
|
||||
|
||||
@pytest.fixture
|
||||
def application(configuration: Configuration, spawner: Spawn, database: SQLite, repository: Repository,
|
||||
mocker: MockerFixture) -> web.Application:
|
||||
mocker: MockerFixture) -> Application:
|
||||
"""
|
||||
application fixture
|
||||
|
||||
@ -62,17 +68,19 @@ def application(configuration: Configuration, spawner: Spawn, database: SQLite,
|
||||
mocker(MockerFixture): mocker object
|
||||
|
||||
Returns:
|
||||
web.Application: application test instance
|
||||
Application: application test instance
|
||||
"""
|
||||
configuration.set_option("web", "port", "8080")
|
||||
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
mocker.patch("aiohttp_apispec.setup_aiohttp_apispec")
|
||||
mocker.patch.object(ahriman.core.auth.helpers, "_has_aiohttp_security", False)
|
||||
return setup_service("x86_64", configuration, spawner)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def application_with_auth(configuration: Configuration, user: User, spawner: Spawn, database: SQLite,
|
||||
repository: Repository, mocker: MockerFixture) -> web.Application:
|
||||
repository: Repository, mocker: MockerFixture) -> Application:
|
||||
"""
|
||||
application fixture with auth enabled
|
||||
|
||||
@ -85,11 +93,13 @@ def application_with_auth(configuration: Configuration, user: User, spawner: Spa
|
||||
mocker(MockerFixture): mocker object
|
||||
|
||||
Returns:
|
||||
web.Application: application test instance
|
||||
Application: application test instance
|
||||
"""
|
||||
configuration.set_option("auth", "target", "configuration")
|
||||
configuration.set_option("web", "port", "8080")
|
||||
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
mocker.patch("aiohttp_apispec.setup_aiohttp_apispec")
|
||||
mocker.patch.object(ahriman.core.auth.helpers, "_has_aiohttp_security", True)
|
||||
application = setup_service("x86_64", configuration, spawner)
|
||||
|
||||
@ -101,7 +111,7 @@ def application_with_auth(configuration: Configuration, user: User, spawner: Spa
|
||||
|
||||
@pytest.fixture
|
||||
def application_with_debug(configuration: Configuration, user: User, spawner: Spawn, database: SQLite,
|
||||
repository: Repository, mocker: MockerFixture) -> web.Application:
|
||||
repository: Repository, mocker: MockerFixture) -> Application:
|
||||
"""
|
||||
application fixture with debug enabled
|
||||
|
||||
@ -114,23 +124,25 @@ def application_with_debug(configuration: Configuration, user: User, spawner: Sp
|
||||
mocker(MockerFixture): mocker object
|
||||
|
||||
Returns:
|
||||
web.Application: application test instance
|
||||
Application: application test instance
|
||||
"""
|
||||
configuration.set_option("web", "debug", "yes")
|
||||
configuration.set_option("web", "port", "8080")
|
||||
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
mocker.patch("aiohttp_apispec.setup_aiohttp_apispec")
|
||||
mocker.patch.object(ahriman.core.auth.helpers, "_has_aiohttp_security", False)
|
||||
return setup_service("x86_64", configuration, spawner)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def client(application: web.Application, event_loop: BaseEventLoop,
|
||||
def client(application: Application, event_loop: BaseEventLoop,
|
||||
aiohttp_client: Any, mocker: MockerFixture) -> TestClient:
|
||||
"""
|
||||
web client fixture
|
||||
|
||||
Args:
|
||||
application(web.Application): application fixture
|
||||
application(Application): application fixture
|
||||
event_loop(BaseEventLoop): context event loop
|
||||
aiohttp_client(Any): aiohttp client fixture
|
||||
mocker(MockerFixture): mocker object
|
||||
@ -143,13 +155,13 @@ def client(application: web.Application, event_loop: BaseEventLoop,
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def client_with_auth(application_with_auth: web.Application, event_loop: BaseEventLoop,
|
||||
def client_with_auth(application_with_auth: Application, event_loop: BaseEventLoop,
|
||||
aiohttp_client: Any, mocker: MockerFixture) -> TestClient:
|
||||
"""
|
||||
web client fixture with full authorization functions
|
||||
|
||||
Args:
|
||||
application_with_auth(web.Application): application fixture
|
||||
application_with_auth(Application): application fixture
|
||||
event_loop(BaseEventLoop): context event loop
|
||||
aiohttp_client(Any): aiohttp client fixture
|
||||
mocker(MockerFixture): mocker object
|
||||
@ -162,13 +174,13 @@ def client_with_auth(application_with_auth: web.Application, event_loop: BaseEve
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def client_with_oauth_auth(application_with_auth: web.Application, event_loop: BaseEventLoop,
|
||||
def client_with_oauth_auth(application_with_auth: Application, event_loop: BaseEventLoop,
|
||||
aiohttp_client: Any, mocker: MockerFixture) -> TestClient:
|
||||
"""
|
||||
web client fixture with full authorization functions
|
||||
|
||||
Args:
|
||||
application_with_auth(web.Application): application fixture
|
||||
application_with_auth(Application): application fixture
|
||||
event_loop(BaseEventLoop): context event loop
|
||||
aiohttp_client(Any): aiohttp client fixture
|
||||
mocker(MockerFixture): mocker object
|
||||
|
@ -4,11 +4,11 @@ from ahriman.core.auth import Auth
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.models.user import User
|
||||
from ahriman.web.middlewares.auth_handler import AuthorizationPolicy
|
||||
from ahriman.web.middlewares.auth_handler import _AuthorizationPolicy
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def authorization_policy(configuration: Configuration, database: SQLite, user: User) -> AuthorizationPolicy:
|
||||
def authorization_policy(configuration: Configuration, database: SQLite, user: User) -> _AuthorizationPolicy:
|
||||
"""
|
||||
fixture for authorization policy
|
||||
|
||||
@ -22,5 +22,5 @@ def authorization_policy(configuration: Configuration, database: SQLite, user: U
|
||||
"""
|
||||
configuration.set_option("auth", "target", "configuration")
|
||||
validator = Auth.load(configuration, database)
|
||||
policy = AuthorizationPolicy(validator)
|
||||
policy = _AuthorizationPolicy(validator)
|
||||
return policy
|
||||
|
@ -1,8 +1,8 @@
|
||||
import pytest
|
||||
import socket
|
||||
|
||||
from aiohttp import web
|
||||
from aiohttp.test_utils import TestClient
|
||||
from aiohttp.web import Application
|
||||
from cryptography import fernet
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest.mock import AsyncMock, call as MockCall
|
||||
@ -11,10 +11,10 @@ from ahriman.core.auth import Auth
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.user import User
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.middlewares.auth_handler import AuthorizationPolicy, auth_handler, cookie_secret_key, setup_auth
|
||||
from ahriman.web.middlewares.auth_handler import _AuthorizationPolicy, _auth_handler, _cookie_secret_key, setup_auth
|
||||
|
||||
|
||||
async def test_authorized_userid(authorization_policy: AuthorizationPolicy, user: User, mocker: MockerFixture) -> None:
|
||||
async def test_authorized_userid(authorization_policy: _AuthorizationPolicy, user: User, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must return authorized user id
|
||||
"""
|
||||
@ -22,7 +22,7 @@ async def test_authorized_userid(authorization_policy: AuthorizationPolicy, user
|
||||
assert await authorization_policy.authorized_userid(user.username) == user.username
|
||||
|
||||
|
||||
async def test_authorized_userid_unknown(authorization_policy: AuthorizationPolicy, user: User) -> None:
|
||||
async def test_authorized_userid_unknown(authorization_policy: _AuthorizationPolicy, user: User) -> None:
|
||||
"""
|
||||
must not allow unknown user id for authorization
|
||||
"""
|
||||
@ -30,7 +30,7 @@ async def test_authorized_userid_unknown(authorization_policy: AuthorizationPoli
|
||||
assert await authorization_policy.authorized_userid("somerandomname") is None
|
||||
|
||||
|
||||
async def test_permits(authorization_policy: AuthorizationPolicy, user: User) -> None:
|
||||
async def test_permits(authorization_policy: _AuthorizationPolicy, user: User) -> None:
|
||||
"""
|
||||
must call validator check
|
||||
"""
|
||||
@ -56,7 +56,7 @@ async def test_auth_handler_unix_socket(client_with_auth: TestClient, mocker: Mo
|
||||
request_handler.get_permission.return_value = UserAccess.Full
|
||||
check_permission_mock = mocker.patch("aiohttp_security.check_permission")
|
||||
|
||||
handler = auth_handler(allow_read_only=False)
|
||||
handler = _auth_handler(allow_read_only=False)
|
||||
await handler(aiohttp_request, request_handler)
|
||||
check_permission_mock.assert_not_called()
|
||||
|
||||
@ -70,7 +70,7 @@ async def test_auth_handler_api(mocker: MockerFixture) -> None:
|
||||
request_handler.get_permission.return_value = UserAccess.Read
|
||||
check_permission_mock = mocker.patch("aiohttp_security.check_permission")
|
||||
|
||||
handler = auth_handler(allow_read_only=False)
|
||||
handler = _auth_handler(allow_read_only=False)
|
||||
await handler(aiohttp_request, request_handler)
|
||||
check_permission_mock.assert_called_once_with(aiohttp_request, UserAccess.Read, aiohttp_request.path)
|
||||
|
||||
@ -102,7 +102,7 @@ async def test_auth_handler_allow_read_only(mocker: MockerFixture) -> None:
|
||||
request_handler.get_permission.return_value = UserAccess.Read
|
||||
check_permission_mock = mocker.patch("aiohttp_security.check_permission")
|
||||
|
||||
handler = auth_handler(allow_read_only=True)
|
||||
handler = _auth_handler(allow_read_only=True)
|
||||
await handler(aiohttp_request, request_handler)
|
||||
check_permission_mock.assert_not_called()
|
||||
|
||||
@ -116,7 +116,7 @@ async def test_auth_handler_api_no_method(mocker: MockerFixture) -> None:
|
||||
request_handler.get_permission = None
|
||||
check_permission_mock = mocker.patch("aiohttp_security.check_permission")
|
||||
|
||||
handler = auth_handler(allow_read_only=False)
|
||||
handler = _auth_handler(allow_read_only=False)
|
||||
await handler(aiohttp_request, request_handler)
|
||||
check_permission_mock.assert_called_once_with(aiohttp_request, UserAccess.Full, aiohttp_request.path)
|
||||
|
||||
@ -130,7 +130,7 @@ async def test_auth_handler_api_post(mocker: MockerFixture) -> None:
|
||||
request_handler.get_permission.return_value = UserAccess.Full
|
||||
check_permission_mock = mocker.patch("aiohttp_security.check_permission")
|
||||
|
||||
handler = auth_handler(allow_read_only=False)
|
||||
handler = _auth_handler(allow_read_only=False)
|
||||
await handler(aiohttp_request, request_handler)
|
||||
check_permission_mock.assert_called_once_with(aiohttp_request, UserAccess.Full, aiohttp_request.path)
|
||||
|
||||
@ -145,7 +145,7 @@ async def test_auth_handler_read(mocker: MockerFixture) -> None:
|
||||
request_handler.get_permission.return_value = UserAccess.Read
|
||||
check_permission_mock = mocker.patch("aiohttp_security.check_permission")
|
||||
|
||||
handler = auth_handler(allow_read_only=False)
|
||||
handler = _auth_handler(allow_read_only=False)
|
||||
await handler(aiohttp_request, request_handler)
|
||||
check_permission_mock.assert_called_once_with(aiohttp_request, UserAccess.Read, aiohttp_request.path)
|
||||
|
||||
@ -160,7 +160,7 @@ async def test_auth_handler_write(mocker: MockerFixture) -> None:
|
||||
request_handler.get_permission.return_value = UserAccess.Full
|
||||
check_permission_mock = mocker.patch("aiohttp_security.check_permission")
|
||||
|
||||
handler = auth_handler(allow_read_only=False)
|
||||
handler = _auth_handler(allow_read_only=False)
|
||||
await handler(aiohttp_request, request_handler)
|
||||
check_permission_mock.assert_called_once_with(aiohttp_request, UserAccess.Full, aiohttp_request.path)
|
||||
|
||||
@ -169,7 +169,7 @@ def test_cookie_secret_key(configuration: Configuration) -> None:
|
||||
"""
|
||||
must generate fernet key
|
||||
"""
|
||||
secret_key = cookie_secret_key(configuration)
|
||||
secret_key = _cookie_secret_key(configuration)
|
||||
assert isinstance(secret_key, fernet.Fernet)
|
||||
|
||||
|
||||
@ -178,10 +178,10 @@ def test_cookie_secret_key_cached(configuration: Configuration) -> None:
|
||||
must use cookie key as set by configuration
|
||||
"""
|
||||
configuration.set_option("auth", "cookie_secret_key", fernet.Fernet.generate_key().decode("utf8"))
|
||||
assert cookie_secret_key(configuration) is not None
|
||||
assert _cookie_secret_key(configuration) is not None
|
||||
|
||||
|
||||
def test_setup_auth(application_with_auth: web.Application, configuration: Configuration, auth: Auth,
|
||||
def test_setup_auth(application_with_auth: Application, configuration: Configuration, auth: Auth,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must set up authorization
|
||||
|
@ -2,12 +2,12 @@ import json
|
||||
import logging
|
||||
import pytest
|
||||
|
||||
from aiohttp.web import HTTPBadRequest, HTTPInternalServerError, HTTPNoContent, HTTPUnauthorized
|
||||
from aiohttp.web import HTTPBadRequest, HTTPInternalServerError, HTTPMethodNotAllowed, HTTPNoContent, HTTPUnauthorized
|
||||
from pytest_mock import MockerFixture
|
||||
from typing import Any
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
from ahriman.web.middlewares.exception_handler import exception_handler, is_templated_unauthorized
|
||||
from ahriman.web.middlewares.exception_handler import _is_templated_unauthorized, exception_handler
|
||||
|
||||
|
||||
def _extract_body(response: Any) -> Any:
|
||||
@ -31,27 +31,27 @@ def test_is_templated_unauthorized() -> None:
|
||||
|
||||
response_mock.path = "/api/v1/login"
|
||||
response_mock.headers.getall.return_value = ["*/*"]
|
||||
assert is_templated_unauthorized(response_mock)
|
||||
assert _is_templated_unauthorized(response_mock)
|
||||
|
||||
response_mock.path = "/api/v1/login"
|
||||
response_mock.headers.getall.return_value = ["application/json"]
|
||||
assert not is_templated_unauthorized(response_mock)
|
||||
assert not _is_templated_unauthorized(response_mock)
|
||||
|
||||
response_mock.path = "/api/v1/logout"
|
||||
response_mock.headers.getall.return_value = ["*/*"]
|
||||
assert is_templated_unauthorized(response_mock)
|
||||
assert _is_templated_unauthorized(response_mock)
|
||||
|
||||
response_mock.path = "/api/v1/logout"
|
||||
response_mock.headers.getall.return_value = ["application/json"]
|
||||
assert not is_templated_unauthorized(response_mock)
|
||||
assert not _is_templated_unauthorized(response_mock)
|
||||
|
||||
response_mock.path = "/api/v1/status"
|
||||
response_mock.headers.getall.return_value = ["*/*"]
|
||||
assert not is_templated_unauthorized(response_mock)
|
||||
assert not _is_templated_unauthorized(response_mock)
|
||||
|
||||
response_mock.path = "/api/v1/status"
|
||||
response_mock.headers.getall.return_value = ["application/json"]
|
||||
assert not is_templated_unauthorized(response_mock)
|
||||
assert not _is_templated_unauthorized(response_mock)
|
||||
|
||||
|
||||
async def test_exception_handler(mocker: MockerFixture) -> None:
|
||||
@ -87,7 +87,7 @@ async def test_exception_handler_unauthorized(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
request = pytest.helpers.request("", "", "")
|
||||
request_handler = AsyncMock(side_effect=HTTPUnauthorized())
|
||||
mocker.patch("ahriman.web.middlewares.exception_handler.is_templated_unauthorized", return_value=False)
|
||||
mocker.patch("ahriman.web.middlewares.exception_handler._is_templated_unauthorized", return_value=False)
|
||||
render_mock = mocker.patch("aiohttp_jinja2.render_template")
|
||||
|
||||
handler = exception_handler(logging.getLogger())
|
||||
@ -102,7 +102,7 @@ async def test_exception_handler_unauthorized_templated(mocker: MockerFixture) -
|
||||
"""
|
||||
request = pytest.helpers.request("", "", "")
|
||||
request_handler = AsyncMock(side_effect=HTTPUnauthorized())
|
||||
mocker.patch("ahriman.web.middlewares.exception_handler.is_templated_unauthorized", return_value=True)
|
||||
mocker.patch("ahriman.web.middlewares.exception_handler._is_templated_unauthorized", return_value=True)
|
||||
render_mock = mocker.patch("aiohttp_jinja2.render_template")
|
||||
|
||||
handler = exception_handler(logging.getLogger())
|
||||
@ -111,6 +111,44 @@ async def test_exception_handler_unauthorized_templated(mocker: MockerFixture) -
|
||||
render_mock.assert_called_once_with("error.jinja2", request, context, status=HTTPUnauthorized.status_code)
|
||||
|
||||
|
||||
async def test_exception_handler_options() -> None:
|
||||
"""
|
||||
must handle OPTIONS request
|
||||
"""
|
||||
request = pytest.helpers.request("", "", "OPTIONS")
|
||||
request_handler = AsyncMock(side_effect=HTTPMethodNotAllowed("OPTIONS", ["GET"]))
|
||||
|
||||
handler = exception_handler(logging.getLogger())
|
||||
with pytest.raises(HTTPNoContent) as response:
|
||||
await handler(request, request_handler)
|
||||
assert response.headers["Allow"] == "GET"
|
||||
|
||||
|
||||
async def test_exception_handler_head() -> None:
|
||||
"""
|
||||
must handle missing HEAD requests
|
||||
"""
|
||||
request = pytest.helpers.request("", "", "HEAD")
|
||||
request_handler = AsyncMock(side_effect=HTTPMethodNotAllowed("HEAD", ["HEAD,GET"]))
|
||||
|
||||
handler = exception_handler(logging.getLogger())
|
||||
with pytest.raises(HTTPMethodNotAllowed) as response:
|
||||
await handler(request, request_handler)
|
||||
assert response.headers["Allow"] == "GET"
|
||||
|
||||
|
||||
async def test_exception_handler_method_not_allowed() -> None:
|
||||
"""
|
||||
must handle not allowed methodss
|
||||
"""
|
||||
request = pytest.helpers.request("", "", "POST")
|
||||
request_handler = AsyncMock(side_effect=HTTPMethodNotAllowed("POST", ["GET"]))
|
||||
|
||||
handler = exception_handler(logging.getLogger())
|
||||
with pytest.raises(HTTPMethodNotAllowed):
|
||||
await handler(request, request_handler)
|
||||
|
||||
|
||||
async def test_exception_handler_client_error(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must handle client exception
|
||||
|
1
tests/ahriman/web/schemas/test_aur_package_schema.py
Normal file
1
tests/ahriman/web/schemas/test_aur_package_schema.py
Normal file
@ -0,0 +1 @@
|
||||
# schema testing goes in view class tests
|
9
tests/ahriman/web/schemas/test_auth_schema.py
Normal file
9
tests/ahriman/web/schemas/test_auth_schema.py
Normal file
@ -0,0 +1,9 @@
|
||||
from ahriman.web.schemas.auth_schema import AuthSchema
|
||||
|
||||
|
||||
def test_schema() -> None:
|
||||
"""
|
||||
must return valid schema
|
||||
"""
|
||||
schema = AuthSchema()
|
||||
assert not schema.validate({"API_SESSION": "key"})
|
1
tests/ahriman/web/schemas/test_counters_schema.py
Normal file
1
tests/ahriman/web/schemas/test_counters_schema.py
Normal file
@ -0,0 +1 @@
|
||||
# schema testing goes in view class tests
|
1
tests/ahriman/web/schemas/test_error_schema.py
Normal file
1
tests/ahriman/web/schemas/test_error_schema.py
Normal file
@ -0,0 +1 @@
|
||||
# schema testing goes in view class tests
|
1
tests/ahriman/web/schemas/test_internal_status_schema.py
Normal file
1
tests/ahriman/web/schemas/test_internal_status_schema.py
Normal file
@ -0,0 +1 @@
|
||||
# schema testing goes in view class tests
|
1
tests/ahriman/web/schemas/test_log_schema.py
Normal file
1
tests/ahriman/web/schemas/test_log_schema.py
Normal file
@ -0,0 +1 @@
|
||||
# schema testing goes in view class tests
|
1
tests/ahriman/web/schemas/test_login_schema.py
Normal file
1
tests/ahriman/web/schemas/test_login_schema.py
Normal file
@ -0,0 +1 @@
|
||||
# schema testing goes in view class tests
|
1
tests/ahriman/web/schemas/test_logs_schema.py
Normal file
1
tests/ahriman/web/schemas/test_logs_schema.py
Normal file
@ -0,0 +1 @@
|
||||
# schema testing goes in view class tests
|
1
tests/ahriman/web/schemas/test_oauth2_schema.py
Normal file
1
tests/ahriman/web/schemas/test_oauth2_schema.py
Normal file
@ -0,0 +1 @@
|
||||
# schema testing goes in view class tests
|
10
tests/ahriman/web/schemas/test_package_name_schema.py
Normal file
10
tests/ahriman/web/schemas/test_package_name_schema.py
Normal file
@ -0,0 +1,10 @@
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.web.schemas.package_name_schema import PackageNameSchema
|
||||
|
||||
|
||||
def test_schema(package_ahriman: Package) -> None:
|
||||
"""
|
||||
must return valid schema
|
||||
"""
|
||||
schema = PackageNameSchema()
|
||||
assert not schema.validate({"package": package_ahriman.base})
|
1
tests/ahriman/web/schemas/test_package_names_schema.py
Normal file
1
tests/ahriman/web/schemas/test_package_names_schema.py
Normal file
@ -0,0 +1 @@
|
||||
# schema testing goes in view class tests
|
@ -0,0 +1 @@
|
||||
# schema testing goes in view class tests
|
1
tests/ahriman/web/schemas/test_package_schema.py
Normal file
1
tests/ahriman/web/schemas/test_package_schema.py
Normal file
@ -0,0 +1 @@
|
||||
# schema testing goes in view class tests
|
1
tests/ahriman/web/schemas/test_package_status_schema.py
Normal file
1
tests/ahriman/web/schemas/test_package_status_schema.py
Normal file
@ -0,0 +1 @@
|
||||
# schema testing goes in view class tests
|
1
tests/ahriman/web/schemas/test_pgp_key_id_schema.py
Normal file
1
tests/ahriman/web/schemas/test_pgp_key_id_schema.py
Normal file
@ -0,0 +1 @@
|
||||
# schema testing goes in view class tests
|
1
tests/ahriman/web/schemas/test_pgp_key_schema.py
Normal file
1
tests/ahriman/web/schemas/test_pgp_key_schema.py
Normal file
@ -0,0 +1 @@
|
||||
# schema testing goes in view class tests
|
1
tests/ahriman/web/schemas/test_remote_schema.py
Normal file
1
tests/ahriman/web/schemas/test_remote_schema.py
Normal file
@ -0,0 +1 @@
|
||||
# schema testing goes in view class tests
|
1
tests/ahriman/web/schemas/test_search_schema.py
Normal file
1
tests/ahriman/web/schemas/test_search_schema.py
Normal file
@ -0,0 +1 @@
|
||||
# schema testing goes in view class tests
|
1
tests/ahriman/web/schemas/test_status_schema.py
Normal file
1
tests/ahriman/web/schemas/test_status_schema.py
Normal file
@ -0,0 +1 @@
|
||||
# schema testing goes in view class tests
|
57
tests/ahriman/web/test_apispec.py
Normal file
57
tests/ahriman/web/test_apispec.py
Normal file
@ -0,0 +1,57 @@
|
||||
import pytest
|
||||
|
||||
from aiohttp.web import Application
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman import version
|
||||
from ahriman.web.apispec import _info, _security, _servers, setup_apispec
|
||||
|
||||
|
||||
def test_info() -> None:
|
||||
"""
|
||||
must generate info object for swagger
|
||||
"""
|
||||
info = _info()
|
||||
assert info["title"] == "ahriman"
|
||||
assert info["version"] == version.__version__
|
||||
|
||||
|
||||
def test_security() -> None:
|
||||
"""
|
||||
must generate security definitions for swagger
|
||||
"""
|
||||
token = next(iter(_security()))["token"]
|
||||
assert token == {"type": "apiKey", "name": "API_SESSION", "in": "cookie"}
|
||||
|
||||
|
||||
def test_servers(application: Application) -> None:
|
||||
"""
|
||||
must generate servers definitions
|
||||
"""
|
||||
servers = _servers(application)
|
||||
assert servers == [{"url": "http://127.0.0.1:8080"}]
|
||||
|
||||
|
||||
def test_servers_address(application: Application) -> None:
|
||||
"""
|
||||
must generate servers definitions with address
|
||||
"""
|
||||
application["configuration"].set_option("web", "address", "https://example.com")
|
||||
servers = _servers(application)
|
||||
assert servers == [{"url": "https://example.com"}]
|
||||
|
||||
|
||||
def test_setup_apispec(application: Application, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must set api specification
|
||||
"""
|
||||
apispec_mock = mocker.patch("aiohttp_apispec.setup_aiohttp_apispec")
|
||||
setup_apispec(application)
|
||||
apispec_mock.assert_called_once_with(
|
||||
application,
|
||||
url="/api-docs/swagger.json",
|
||||
openapi_version="3.0.2",
|
||||
info=pytest.helpers.anyvar(int),
|
||||
servers=pytest.helpers.anyvar(int),
|
||||
security=pytest.helpers.anyvar(int),
|
||||
)
|
20
tests/ahriman/web/test_cors.py
Normal file
20
tests/ahriman/web/test_cors.py
Normal file
@ -0,0 +1,20 @@
|
||||
import aiohttp_cors
|
||||
import pytest
|
||||
|
||||
from aiohttp.web import Application
|
||||
|
||||
|
||||
def test_setup_cors(application: Application) -> None:
|
||||
"""
|
||||
must setup CORS
|
||||
"""
|
||||
cors: aiohttp_cors.CorsConfig = application[aiohttp_cors.APP_CONFIG_KEY]
|
||||
# let's test here that it is enabled for all requests
|
||||
for route in application.router.routes():
|
||||
# we don't want to deal with match info here though
|
||||
try:
|
||||
url = route.url_for()
|
||||
except (KeyError, TypeError):
|
||||
continue
|
||||
request = pytest.helpers.request(application, url, route.method, resource=route.resource)
|
||||
assert cors._cors_impl._router_adapter.is_cors_enabled_on_request(request)
|
@ -1,10 +1,10 @@
|
||||
from aiohttp import web
|
||||
from aiohttp.web import Application
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.web.routes import setup_routes
|
||||
|
||||
|
||||
def test_setup_routes(application: web.Application, configuration: Configuration) -> None:
|
||||
def test_setup_routes(application: Application, configuration: Configuration) -> None:
|
||||
"""
|
||||
must generate non-empty list of routes
|
||||
"""
|
||||
|
@ -1,17 +1,17 @@
|
||||
import pytest
|
||||
import socket
|
||||
|
||||
from aiohttp import web
|
||||
from aiohttp.web import Application
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest.mock import call as MockCall
|
||||
|
||||
from ahriman.core.exceptions import InitializeError
|
||||
from ahriman.core.log.filtered_access_logger import FilteredAccessLogger
|
||||
from ahriman.core.status.watcher import Watcher
|
||||
from ahriman.web.web import create_socket, on_shutdown, on_startup, run_server
|
||||
from ahriman.web.web import _create_socket, _on_shutdown, _on_startup, run_server
|
||||
|
||||
|
||||
async def test_create_socket(application: web.Application, mocker: MockerFixture) -> None:
|
||||
async def test_create_socket(application: Application, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must create socket
|
||||
"""
|
||||
@ -23,7 +23,7 @@ async def test_create_socket(application: web.Application, mocker: MockerFixture
|
||||
chmod_mock = mocker.patch("pathlib.Path.chmod")
|
||||
unlink_mock = mocker.patch("pathlib.Path.unlink")
|
||||
|
||||
sock = create_socket(application["configuration"], application)
|
||||
sock = _create_socket(application["configuration"], application)
|
||||
assert sock.family == socket.AF_UNIX
|
||||
assert sock.type == socket.SOCK_STREAM
|
||||
bind_mock.assert_called_once_with(str(path))
|
||||
@ -35,14 +35,14 @@ async def test_create_socket(application: web.Application, mocker: MockerFixture
|
||||
unlink_mock.assert_has_calls([MockCall(missing_ok=True), MockCall(missing_ok=True)])
|
||||
|
||||
|
||||
def test_create_socket_empty(application: web.Application) -> None:
|
||||
def test_create_socket_empty(application: Application) -> None:
|
||||
"""
|
||||
must skip socket creation if not set by configuration
|
||||
"""
|
||||
assert create_socket(application["configuration"], application) is None
|
||||
assert _create_socket(application["configuration"], application) is None
|
||||
|
||||
|
||||
def test_create_socket_safe(application: web.Application, mocker: MockerFixture) -> None:
|
||||
def test_create_socket_safe(application: Application, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must create socket with default permission set
|
||||
"""
|
||||
@ -54,32 +54,32 @@ def test_create_socket_safe(application: web.Application, mocker: MockerFixture)
|
||||
mocker.patch("pathlib.Path.unlink")
|
||||
chmod_mock = mocker.patch("pathlib.Path.chmod")
|
||||
|
||||
sock = create_socket(application["configuration"], application)
|
||||
sock = _create_socket(application["configuration"], application)
|
||||
assert sock is not None
|
||||
chmod_mock.assert_not_called()
|
||||
|
||||
|
||||
async def test_on_shutdown(application: web.Application, mocker: MockerFixture) -> None:
|
||||
async def test_on_shutdown(application: Application, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must write information to log
|
||||
"""
|
||||
logging_mock = mocker.patch("logging.Logger.warning")
|
||||
await on_shutdown(application)
|
||||
await _on_shutdown(application)
|
||||
logging_mock.assert_called_once_with(pytest.helpers.anyvar(str, True))
|
||||
|
||||
|
||||
async def test_on_startup(application: web.Application, watcher: Watcher, mocker: MockerFixture) -> None:
|
||||
async def test_on_startup(application: Application, watcher: Watcher, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must call load method
|
||||
"""
|
||||
mocker.patch("aiohttp.web.Application.__getitem__", return_value=watcher)
|
||||
load_mock = mocker.patch("ahriman.core.status.watcher.Watcher.load")
|
||||
|
||||
await on_startup(application)
|
||||
await _on_startup(application)
|
||||
load_mock.assert_called_once_with()
|
||||
|
||||
|
||||
async def test_on_startup_exception(application: web.Application, watcher: Watcher, mocker: MockerFixture) -> None:
|
||||
async def test_on_startup_exception(application: Application, watcher: Watcher, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must throw exception on load error
|
||||
"""
|
||||
@ -87,16 +87,16 @@ async def test_on_startup_exception(application: web.Application, watcher: Watch
|
||||
mocker.patch("ahriman.core.status.watcher.Watcher.load", side_effect=Exception())
|
||||
|
||||
with pytest.raises(InitializeError):
|
||||
await on_startup(application)
|
||||
await _on_startup(application)
|
||||
|
||||
|
||||
def test_run(application: web.Application, mocker: MockerFixture) -> None:
|
||||
def test_run(application: Application, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run application
|
||||
"""
|
||||
port = 8080
|
||||
application["configuration"].set_option("web", "port", str(port))
|
||||
run_application_mock = mocker.patch("aiohttp.web.run_app")
|
||||
run_application_mock = mocker.patch("ahriman.web.web.run_app")
|
||||
|
||||
run_server(application)
|
||||
run_application_mock.assert_called_once_with(
|
||||
@ -105,13 +105,13 @@ def test_run(application: web.Application, mocker: MockerFixture) -> None:
|
||||
)
|
||||
|
||||
|
||||
def test_run_with_auth(application_with_auth: web.Application, mocker: MockerFixture) -> None:
|
||||
def test_run_with_auth(application_with_auth: Application, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run application with enabled authorization
|
||||
"""
|
||||
port = 8080
|
||||
application_with_auth["configuration"].set_option("web", "port", str(port))
|
||||
run_application_mock = mocker.patch("aiohttp.web.run_app")
|
||||
run_application_mock = mocker.patch("ahriman.web.web.run_app")
|
||||
|
||||
run_server(application_with_auth)
|
||||
run_application_mock.assert_called_once_with(
|
||||
@ -120,13 +120,13 @@ def test_run_with_auth(application_with_auth: web.Application, mocker: MockerFix
|
||||
)
|
||||
|
||||
|
||||
def test_run_with_debug(application_with_debug: web.Application, mocker: MockerFixture) -> None:
|
||||
def test_run_with_debug(application_with_debug: Application, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run application with enabled debug panel
|
||||
"""
|
||||
port = 8080
|
||||
application_with_debug["configuration"].set_option("web", "port", str(port))
|
||||
run_application_mock = mocker.patch("aiohttp.web.run_app")
|
||||
run_application_mock = mocker.patch("ahriman.web.web.run_app")
|
||||
|
||||
run_server(application_with_debug)
|
||||
run_application_mock.assert_called_once_with(
|
||||
@ -135,14 +135,14 @@ def test_run_with_debug(application_with_debug: web.Application, mocker: MockerF
|
||||
)
|
||||
|
||||
|
||||
def test_run_with_socket(application: web.Application, mocker: MockerFixture) -> None:
|
||||
def test_run_with_socket(application: Application, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run application
|
||||
"""
|
||||
port = 8080
|
||||
application["configuration"].set_option("web", "port", str(port))
|
||||
socket_mock = mocker.patch("ahriman.web.web.create_socket", return_value=42)
|
||||
run_application_mock = mocker.patch("aiohttp.web.run_app")
|
||||
socket_mock = mocker.patch("ahriman.web.web._create_socket", return_value=42)
|
||||
run_application_mock = mocker.patch("ahriman.web.web.run_app")
|
||||
|
||||
run_server(application)
|
||||
socket_mock.assert_called_once_with(application["configuration"], application)
|
||||
|
24
tests/ahriman/web/views/api/test_views_api_docs.py
Normal file
24
tests/ahriman/web/views/api/test_views_api_docs.py
Normal file
@ -0,0 +1,24 @@
|
||||
import pytest
|
||||
|
||||
from aiohttp.test_utils import TestClient
|
||||
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.views.api.docs import DocsView
|
||||
|
||||
|
||||
async def test_get_permission() -> None:
|
||||
"""
|
||||
must return correct permission for the request
|
||||
"""
|
||||
for method in ("GET",):
|
||||
request = pytest.helpers.request("", "", method)
|
||||
assert await DocsView.get_permission(request) == UserAccess.Unauthorized
|
||||
|
||||
|
||||
async def test_get(client: TestClient) -> None:
|
||||
"""
|
||||
must generate api-docs correctly
|
||||
"""
|
||||
response = await client.get("/api-docs")
|
||||
assert response.ok
|
||||
assert await response.text()
|
91
tests/ahriman/web/views/api/test_views_api_swagger.py
Normal file
91
tests/ahriman/web/views/api/test_views_api_swagger.py
Normal file
@ -0,0 +1,91 @@
|
||||
import pytest
|
||||
|
||||
from aiohttp.test_utils import TestClient
|
||||
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.views.api.swagger import SwaggerView
|
||||
|
||||
|
||||
def _client(client: TestClient) -> TestClient:
|
||||
"""
|
||||
generate test client with docs
|
||||
|
||||
Args:
|
||||
client(TestClient): test client fixture
|
||||
|
||||
Returns:
|
||||
TestClient: test client fixture with additional properties
|
||||
"""
|
||||
client.app["swagger_dict"] = {
|
||||
"paths": {
|
||||
"/api/v1/logout": {
|
||||
"get": {
|
||||
"parameters": [
|
||||
{
|
||||
"in": "cookie",
|
||||
"name": "API_SESSION",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
"head": {},
|
||||
"post": {
|
||||
"parameters": [
|
||||
{
|
||||
"in": "cookie",
|
||||
"name": "API_SESSION",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
{
|
||||
"in": "body",
|
||||
"name": "schema",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"components": {},
|
||||
"security": [
|
||||
{
|
||||
"token": {
|
||||
"type": "apiKey",
|
||||
"name": "API_SESSION",
|
||||
"in": "cookie",
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
return client
|
||||
|
||||
|
||||
async def test_get_permission() -> None:
|
||||
"""
|
||||
must return correct permission for the request
|
||||
"""
|
||||
for method in ("GET",):
|
||||
request = pytest.helpers.request("", "", method)
|
||||
assert await SwaggerView.get_permission(request) == UserAccess.Unauthorized
|
||||
|
||||
|
||||
async def test_get(client: TestClient) -> None:
|
||||
"""
|
||||
must generate api-docs correctly
|
||||
"""
|
||||
client = _client(client)
|
||||
response = await client.get("/api-docs/swagger.json")
|
||||
assert response.ok
|
||||
|
||||
json = await response.json()
|
||||
assert "securitySchemes" in json["components"]
|
||||
assert not any(parameter["in"] == "body" for parameter in json["paths"]["/api/v1/logout"]["post"]["parameters"])
|
||||
assert "requestBody" in json["paths"]["/api/v1/logout"]["post"]
|
||||
assert "requestBody" not in json["paths"]["/api/v1/logout"]["get"]
|
||||
assert "requestBody" not in json["paths"]["/api/v1/logout"]["head"]
|
@ -1,17 +1,17 @@
|
||||
import pytest
|
||||
|
||||
from aiohttp import web
|
||||
from aiohttp.web import Application
|
||||
|
||||
from ahriman.web.views.base import BaseView
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def base(application: web.Application) -> BaseView:
|
||||
def base(application: Application) -> BaseView:
|
||||
"""
|
||||
base view fixture
|
||||
|
||||
Args:
|
||||
application(web.Application): application fixture
|
||||
application(Application): application fixture
|
||||
|
||||
Returns:
|
||||
BaseView: generated base view fixture
|
||||
|
@ -4,6 +4,8 @@ from aiohttp.test_utils import TestClient
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.schemas.error_schema import ErrorSchema
|
||||
from ahriman.web.schemas.package_names_schema import PackageNamesSchema
|
||||
from ahriman.web.views.service.add import AddView
|
||||
|
||||
|
||||
@ -21,8 +23,11 @@ async def test_post(client: TestClient, mocker: MockerFixture) -> None:
|
||||
must call post request correctly
|
||||
"""
|
||||
add_mock = mocker.patch("ahriman.core.spawn.Spawn.packages_add")
|
||||
request_schema = PackageNamesSchema()
|
||||
|
||||
response = await client.post("/api/v1/service/add", json={"packages": ["ahriman"]})
|
||||
payload = {"packages": ["ahriman"]}
|
||||
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(["ahriman"], now=True)
|
||||
|
||||
@ -32,15 +37,19 @@ async def test_post_empty(client: TestClient, mocker: MockerFixture) -> None:
|
||||
must call raise 400 on empty request
|
||||
"""
|
||||
add_mock = mocker.patch("ahriman.core.spawn.Spawn.packages_add")
|
||||
response_schema = ErrorSchema()
|
||||
|
||||
response = await client.post("/api/v1/service/add", json={"packages": [""]})
|
||||
assert response.status == 400
|
||||
assert not response_schema.validate(await response.json())
|
||||
add_mock.assert_not_called()
|
||||
|
||||
response = await client.post("/api/v1/service/add", json={"packages": []})
|
||||
assert response.status == 400
|
||||
assert not response_schema.validate(await response.json())
|
||||
add_mock.assert_not_called()
|
||||
|
||||
response = await client.post("/api/v1/service/add", json={})
|
||||
assert response.status == 400
|
||||
assert not response_schema.validate(await response.json())
|
||||
add_mock.assert_not_called()
|
||||
|
@ -4,6 +4,9 @@ from aiohttp.test_utils import TestClient
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.schemas.error_schema import ErrorSchema
|
||||
from ahriman.web.schemas.pgp_key_id_schema import PGPKeyIdSchema
|
||||
from ahriman.web.schemas.pgp_key_schema import PGPKeySchema
|
||||
from ahriman.web.views.service.pgp import PGPView
|
||||
|
||||
|
||||
@ -11,7 +14,7 @@ async def test_get_permission() -> None:
|
||||
"""
|
||||
must return correct permission for the request
|
||||
"""
|
||||
for method in ("GET", "HEAD"):
|
||||
for method in ("GET",):
|
||||
request = pytest.helpers.request("", "", method)
|
||||
assert await PGPView.get_permission(request) == UserAccess.Reporter
|
||||
for method in ("POST",):
|
||||
@ -24,10 +27,15 @@ async def test_get(client: TestClient, mocker: MockerFixture) -> None:
|
||||
must retrieve key from the keyserver
|
||||
"""
|
||||
import_mock = mocker.patch("ahriman.core.sign.gpg.GPG.key_download", return_value="imported")
|
||||
request_schema = PGPKeyIdSchema()
|
||||
response_schema = PGPKeySchema()
|
||||
|
||||
response = await client.get("/api/v1/service/pgp", params={"key": "0xdeadbeaf", "server": "keyserver.ubuntu.com"})
|
||||
payload = {"key": "0xdeadbeaf", "server": "keyserver.ubuntu.com"}
|
||||
assert not request_schema.validate(payload)
|
||||
response = await client.get("/api/v1/service/pgp", params=payload)
|
||||
assert response.ok
|
||||
import_mock.assert_called_once_with("keyserver.ubuntu.com", "0xdeadbeaf")
|
||||
assert not response_schema.validate(await response.json())
|
||||
assert await response.json() == {"key": "imported"}
|
||||
|
||||
|
||||
@ -36,9 +44,11 @@ async def test_get_empty(client: TestClient, mocker: MockerFixture) -> None:
|
||||
must raise 400 on missing parameters
|
||||
"""
|
||||
import_mock = mocker.patch("ahriman.core.sign.gpg.GPG.key_download")
|
||||
response_schema = ErrorSchema()
|
||||
|
||||
response = await client.get("/api/v1/service/pgp")
|
||||
assert response.status == 400
|
||||
assert not response_schema.validate(await response.json())
|
||||
import_mock.assert_not_called()
|
||||
|
||||
|
||||
@ -47,9 +57,11 @@ async def test_get_process_exception(client: TestClient, mocker: MockerFixture)
|
||||
must raise 404 on invalid PGP server response
|
||||
"""
|
||||
import_mock = mocker.patch("ahriman.core.sign.gpg.GPG.key_download", side_effect=Exception())
|
||||
response_schema = ErrorSchema()
|
||||
|
||||
response = await client.get("/api/v1/service/pgp", params={"key": "0xdeadbeaf", "server": "keyserver.ubuntu.com"})
|
||||
assert response.status == 404
|
||||
assert not response_schema.validate(await response.json())
|
||||
import_mock.assert_called_once_with("keyserver.ubuntu.com", "0xdeadbeaf")
|
||||
|
||||
|
||||
@ -58,8 +70,11 @@ async def test_post(client: TestClient, mocker: MockerFixture) -> None:
|
||||
must call post request correctly
|
||||
"""
|
||||
import_mock = mocker.patch("ahriman.core.spawn.Spawn.key_import")
|
||||
request_schema = PGPKeyIdSchema()
|
||||
|
||||
response = await client.post("/api/v1/service/pgp", json={"key": "0xdeadbeaf", "server": "keyserver.ubuntu.com"})
|
||||
payload = {"key": "0xdeadbeaf", "server": "keyserver.ubuntu.com"}
|
||||
assert not request_schema.validate(payload)
|
||||
response = await client.post("/api/v1/service/pgp", json=payload)
|
||||
assert response.ok
|
||||
import_mock.assert_called_once_with("0xdeadbeaf", "keyserver.ubuntu.com")
|
||||
|
||||
@ -69,7 +84,9 @@ async def test_post_exception(client: TestClient, mocker: MockerFixture) -> None
|
||||
must raise exception on missing key payload
|
||||
"""
|
||||
import_mock = mocker.patch("ahriman.core.spawn.Spawn.key_import")
|
||||
response_schema = ErrorSchema()
|
||||
|
||||
response = await client.post("/api/v1/service/pgp")
|
||||
assert response.status == 400
|
||||
assert not response_schema.validate(await response.json())
|
||||
import_mock.assert_not_called()
|
||||
|
@ -4,6 +4,8 @@ from aiohttp.test_utils import TestClient
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.schemas.error_schema import ErrorSchema
|
||||
from ahriman.web.schemas.package_names_schema import PackageNamesSchema
|
||||
from ahriman.web.views.service.rebuild import RebuildView
|
||||
|
||||
|
||||
@ -21,8 +23,11 @@ async def test_post(client: TestClient, mocker: MockerFixture) -> None:
|
||||
must call post request correctly
|
||||
"""
|
||||
rebuild_mock = mocker.patch("ahriman.core.spawn.Spawn.packages_rebuild")
|
||||
request_schema = PackageNamesSchema()
|
||||
|
||||
response = await client.post("/api/v1/service/rebuild", json={"packages": ["python", "ahriman"]})
|
||||
payload = {"packages": ["python", "ahriman"]}
|
||||
assert not request_schema.validate(payload)
|
||||
response = await client.post("/api/v1/service/rebuild", json=payload)
|
||||
assert response.ok
|
||||
rebuild_mock.assert_called_once_with("python")
|
||||
|
||||
@ -32,7 +37,9 @@ async def test_post_exception(client: TestClient, mocker: MockerFixture) -> None
|
||||
must raise exception on missing packages payload
|
||||
"""
|
||||
rebuild_mock = mocker.patch("ahriman.core.spawn.Spawn.packages_rebuild")
|
||||
response_schema = ErrorSchema()
|
||||
|
||||
response = await client.post("/api/v1/service/rebuild")
|
||||
assert response.status == 400
|
||||
assert not response_schema.validate(await response.json())
|
||||
rebuild_mock.assert_not_called()
|
||||
|
@ -4,6 +4,8 @@ from aiohttp.test_utils import TestClient
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.schemas.error_schema import ErrorSchema
|
||||
from ahriman.web.schemas.package_names_schema import PackageNamesSchema
|
||||
from ahriman.web.views.service.remove import RemoveView
|
||||
|
||||
|
||||
@ -21,8 +23,11 @@ async def test_post(client: TestClient, mocker: MockerFixture) -> None:
|
||||
must call post request correctly
|
||||
"""
|
||||
remove_mock = mocker.patch("ahriman.core.spawn.Spawn.packages_remove")
|
||||
request_schema = PackageNamesSchema()
|
||||
|
||||
response = await client.post("/api/v1/service/remove", json={"packages": ["ahriman"]})
|
||||
payload = {"packages": ["ahriman"]}
|
||||
assert not request_schema.validate(payload)
|
||||
response = await client.post("/api/v1/service/remove", json=payload)
|
||||
assert response.ok
|
||||
remove_mock.assert_called_once_with(["ahriman"])
|
||||
|
||||
@ -32,7 +37,9 @@ async def test_post_exception(client: TestClient, mocker: MockerFixture) -> None
|
||||
must raise exception on missing packages payload
|
||||
"""
|
||||
remove_mock = mocker.patch("ahriman.core.spawn.Spawn.packages_remove")
|
||||
response_schema = ErrorSchema()
|
||||
|
||||
response = await client.post("/api/v1/service/remove")
|
||||
assert response.status == 400
|
||||
assert not response_schema.validate(await response.json())
|
||||
remove_mock.assert_not_called()
|
||||
|
@ -4,6 +4,8 @@ from aiohttp.test_utils import TestClient
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.schemas.error_schema import ErrorSchema
|
||||
from ahriman.web.schemas.package_names_schema import PackageNamesSchema
|
||||
from ahriman.web.views.service.request import RequestView
|
||||
|
||||
|
||||
@ -21,8 +23,11 @@ async def test_post(client: TestClient, mocker: MockerFixture) -> None:
|
||||
must call post request correctly
|
||||
"""
|
||||
add_mock = mocker.patch("ahriman.core.spawn.Spawn.packages_add")
|
||||
request_schema = PackageNamesSchema()
|
||||
|
||||
response = await client.post("/api/v1/service/request", json={"packages": ["ahriman"]})
|
||||
payload = {"packages": ["ahriman"]}
|
||||
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(["ahriman"], now=False)
|
||||
|
||||
@ -32,7 +37,9 @@ 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_schema = ErrorSchema()
|
||||
|
||||
response = await client.post("/api/v1/service/request")
|
||||
assert response.status == 400
|
||||
assert not response_schema.validate(await response.json())
|
||||
add_mock.assert_not_called()
|
||||
|
@ -5,6 +5,9 @@ from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.models.aur_package import AURPackage
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.schemas.aur_package_schema import AURPackageSchema
|
||||
from ahriman.web.schemas.error_schema import ErrorSchema
|
||||
from ahriman.web.schemas.search_schema import SearchSchema
|
||||
from ahriman.web.views.service.search import SearchView
|
||||
|
||||
|
||||
@ -12,7 +15,7 @@ async def test_get_permission() -> None:
|
||||
"""
|
||||
must return correct permission for the request
|
||||
"""
|
||||
for method in ("GET", "HEAD"):
|
||||
for method in ("GET",):
|
||||
request = pytest.helpers.request("", "", method)
|
||||
assert await SearchView.get_permission(request) == UserAccess.Reporter
|
||||
|
||||
@ -22,11 +25,16 @@ async def test_get(client: TestClient, aur_package_ahriman: AURPackage, mocker:
|
||||
must call get request correctly
|
||||
"""
|
||||
mocker.patch("ahriman.core.alpm.remote.AUR.multisearch", return_value=[aur_package_ahriman])
|
||||
request_schema = SearchSchema()
|
||||
response_schema = AURPackageSchema()
|
||||
|
||||
response = await client.get("/api/v1/service/search", params={"for": "ahriman"})
|
||||
payload = {"for": ["ahriman"]}
|
||||
assert not request_schema.validate(payload)
|
||||
response = await client.get("/api/v1/service/search", params=payload)
|
||||
assert response.ok
|
||||
assert await response.json() == [{"package": aur_package_ahriman.package_base,
|
||||
"description": aur_package_ahriman.description}]
|
||||
assert not response_schema.validate(await response.json(), many=True)
|
||||
|
||||
|
||||
async def test_get_exception(client: TestClient, mocker: MockerFixture) -> None:
|
||||
@ -34,9 +42,11 @@ async def test_get_exception(client: TestClient, mocker: MockerFixture) -> None:
|
||||
must raise 400 on empty search string
|
||||
"""
|
||||
search_mock = mocker.patch("ahriman.core.alpm.remote.AUR.multisearch")
|
||||
response_schema = ErrorSchema()
|
||||
|
||||
response = await client.get("/api/v1/service/search")
|
||||
assert response.status == 400
|
||||
assert not response_schema.validate(await response.json())
|
||||
search_mock.assert_not_called()
|
||||
|
||||
|
||||
@ -45,8 +55,11 @@ async def test_get_empty(client: TestClient, mocker: MockerFixture) -> None:
|
||||
must raise 404 on empty search result
|
||||
"""
|
||||
mocker.patch("ahriman.core.alpm.remote.AUR.multisearch", return_value=[])
|
||||
response = await client.get("/api/v1/service/search", params={"for": "ahriman"})
|
||||
response_schema = ErrorSchema()
|
||||
|
||||
response = await client.get("/api/v1/service/search", params={"for": ["ahriman"]})
|
||||
assert response.status == 404
|
||||
assert not response_schema.validate(await response.json())
|
||||
|
||||
|
||||
async def test_get_join(client: TestClient, mocker: MockerFixture) -> None:
|
||||
@ -54,7 +67,10 @@ async def test_get_join(client: TestClient, mocker: MockerFixture) -> None:
|
||||
must join search args with space
|
||||
"""
|
||||
search_mock = mocker.patch("ahriman.core.alpm.remote.AUR.multisearch")
|
||||
request_schema = SearchSchema()
|
||||
|
||||
response = await client.get("/api/v1/service/search", params=[("for", "ahriman"), ("for", "maybe")])
|
||||
payload = {"for": ["ahriman", "maybe"]}
|
||||
assert not request_schema.validate(payload)
|
||||
response = await client.get("/api/v1/service/search", params=payload)
|
||||
assert response.ok
|
||||
search_mock.assert_called_once_with("ahriman", "maybe", pacman=pytest.helpers.anyvar(int))
|
||||
|
@ -5,6 +5,9 @@ from aiohttp.test_utils import TestClient
|
||||
from ahriman.models.build_status import BuildStatusEnum
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.schemas.error_schema import ErrorSchema
|
||||
from ahriman.web.schemas.log_schema import LogSchema
|
||||
from ahriman.web.schemas.logs_schema import LogsSchema
|
||||
from ahriman.web.views.status.logs import LogsView
|
||||
|
||||
|
||||
@ -12,7 +15,7 @@ async def test_get_permission() -> None:
|
||||
"""
|
||||
must return correct permission for the request
|
||||
"""
|
||||
for method in ("GET", "HEAD"):
|
||||
for method in ("GET",):
|
||||
request = pytest.helpers.request("", "", method)
|
||||
assert await LogsView.get_permission(request) == UserAccess.Reporter
|
||||
for method in ("DELETE", "POST"):
|
||||
@ -54,11 +57,13 @@ async def test_get(client: TestClient, package_ahriman: Package) -> None:
|
||||
json={"status": BuildStatusEnum.Success.value, "package": package_ahriman.view()})
|
||||
await client.post(f"/api/v1/packages/{package_ahriman.base}/logs",
|
||||
json={"created": 42.0, "message": "message", "process_id": 42})
|
||||
response_schema = LogsSchema()
|
||||
|
||||
response = await client.get(f"/api/v1/packages/{package_ahriman.base}/logs")
|
||||
assert response.status == 200
|
||||
|
||||
logs = await response.json()
|
||||
assert not response_schema.validate(logs)
|
||||
assert logs["logs"] == "[1970-01-01 00:00:42] message"
|
||||
|
||||
|
||||
@ -66,8 +71,11 @@ async def test_get_not_found(client: TestClient, package_ahriman: Package) -> No
|
||||
"""
|
||||
must return not found for missing package
|
||||
"""
|
||||
response_schema = ErrorSchema()
|
||||
|
||||
response = await client.get(f"/api/v1/packages/{package_ahriman.base}/logs")
|
||||
assert response.status == 404
|
||||
assert not response_schema.validate(await response.json())
|
||||
|
||||
|
||||
async def test_post(client: TestClient, package_ahriman: Package) -> None:
|
||||
@ -76,10 +84,12 @@ async def test_post(client: TestClient, package_ahriman: Package) -> None:
|
||||
"""
|
||||
await client.post(f"/api/v1/packages/{package_ahriman.base}",
|
||||
json={"status": BuildStatusEnum.Success.value, "package": package_ahriman.view()})
|
||||
request_schema = LogSchema()
|
||||
|
||||
post_response = await client.post(f"/api/v1/packages/{package_ahriman.base}/logs",
|
||||
json={"created": 42.0, "message": "message", "process_id": 42})
|
||||
assert post_response.status == 204
|
||||
payload = {"created": 42.0, "message": "message", "process_id": 42}
|
||||
assert not request_schema.validate(payload)
|
||||
response = await client.post(f"/api/v1/packages/{package_ahriman.base}/logs", json=payload)
|
||||
assert response.status == 204
|
||||
|
||||
response = await client.get(f"/api/v1/packages/{package_ahriman.base}/logs")
|
||||
logs = await response.json()
|
||||
@ -90,5 +100,8 @@ async def test_post_exception(client: TestClient, package_ahriman: Package) -> N
|
||||
"""
|
||||
must raise exception on invalid payload
|
||||
"""
|
||||
post_response = await client.post(f"/api/v1/packages/{package_ahriman.base}/logs", json={})
|
||||
assert post_response.status == 400
|
||||
response_schema = ErrorSchema()
|
||||
|
||||
response = await client.post(f"/api/v1/packages/{package_ahriman.base}/logs", json={})
|
||||
assert response.status == 400
|
||||
assert not response_schema.validate(await response.json())
|
||||
|
@ -5,6 +5,8 @@ from aiohttp.test_utils import TestClient
|
||||
from ahriman.models.build_status import BuildStatus, BuildStatusEnum
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.schemas.error_schema import ErrorSchema
|
||||
from ahriman.web.schemas.package_status_schema import PackageStatusSchema, PackageStatusSimplifiedSchema
|
||||
from ahriman.web.views.status.package import PackageView
|
||||
|
||||
|
||||
@ -12,7 +14,7 @@ async def test_get_permission() -> None:
|
||||
"""
|
||||
must return correct permission for the request
|
||||
"""
|
||||
for method in ("GET", "HEAD"):
|
||||
for method in ("GET",):
|
||||
request = pytest.helpers.request("", "", method)
|
||||
assert await PackageView.get_permission(request) == UserAccess.Read
|
||||
for method in ("DELETE", "POST"):
|
||||
@ -64,11 +66,14 @@ async def test_get(client: TestClient, package_ahriman: Package, package_python_
|
||||
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()})
|
||||
response_schema = PackageStatusSchema()
|
||||
|
||||
response = await client.get(f"/api/v1/packages/{package_ahriman.base}")
|
||||
assert response.ok
|
||||
json = await response.json()
|
||||
assert not response_schema.validate(json, many=True)
|
||||
|
||||
packages = [Package.from_json(item["package"]) for item in await response.json()]
|
||||
packages = [Package.from_json(item["package"]) for item in json]
|
||||
assert packages
|
||||
assert {package.base for package in packages} == {package_ahriman.base}
|
||||
|
||||
@ -77,18 +82,23 @@ async def test_get_not_found(client: TestClient, package_ahriman: Package) -> No
|
||||
"""
|
||||
must return Not Found for unknown package
|
||||
"""
|
||||
response_schema = ErrorSchema()
|
||||
|
||||
response = await client.get(f"/api/v1/packages/{package_ahriman.base}")
|
||||
assert response.status == 404
|
||||
assert not response_schema.validate(await response.json())
|
||||
|
||||
|
||||
async def test_post(client: TestClient, package_ahriman: Package) -> None:
|
||||
"""
|
||||
must update package status
|
||||
"""
|
||||
post_response = await client.post(
|
||||
f"/api/v1/packages/{package_ahriman.base}",
|
||||
json={"status": BuildStatusEnum.Success.value, "package": package_ahriman.view()})
|
||||
assert post_response.status == 204
|
||||
request_schema = PackageStatusSimplifiedSchema()
|
||||
|
||||
payload = {"status": BuildStatusEnum.Success.value, "package": package_ahriman.view()}
|
||||
assert not request_schema.validate(payload)
|
||||
response = await client.post(f"/api/v1/packages/{package_ahriman.base}", json=payload)
|
||||
assert response.status == 204
|
||||
|
||||
response = await client.get(f"/api/v1/packages/{package_ahriman.base}")
|
||||
assert response.ok
|
||||
@ -98,22 +108,28 @@ async def test_post_exception(client: TestClient, package_ahriman: Package) -> N
|
||||
"""
|
||||
must raise exception on invalid payload
|
||||
"""
|
||||
post_response = await client.post(f"/api/v1/packages/{package_ahriman.base}", json={})
|
||||
assert post_response.status == 400
|
||||
response_schema = ErrorSchema()
|
||||
|
||||
response = await client.post(f"/api/v1/packages/{package_ahriman.base}", json={})
|
||||
assert response.status == 400
|
||||
assert not response_schema.validate(await response.json())
|
||||
|
||||
|
||||
async def test_post_light(client: TestClient, package_ahriman: Package) -> None:
|
||||
"""
|
||||
must update package status only
|
||||
"""
|
||||
post_response = await client.post(
|
||||
f"/api/v1/packages/{package_ahriman.base}",
|
||||
json={"status": BuildStatusEnum.Unknown.value, "package": package_ahriman.view()})
|
||||
assert post_response.status == 204
|
||||
request_schema = PackageStatusSimplifiedSchema()
|
||||
|
||||
post_response = await client.post(
|
||||
f"/api/v1/packages/{package_ahriman.base}", json={"status": BuildStatusEnum.Success.value})
|
||||
assert post_response.status == 204
|
||||
payload = {"status": BuildStatusEnum.Unknown.value, "package": package_ahriman.view()}
|
||||
assert not request_schema.validate(payload)
|
||||
response = await client.post(f"/api/v1/packages/{package_ahriman.base}", json=payload)
|
||||
assert response.status == 204
|
||||
|
||||
payload = {"status": BuildStatusEnum.Success.value}
|
||||
assert not request_schema.validate(payload)
|
||||
response = await client.post(f"/api/v1/packages/{package_ahriman.base}", json=payload)
|
||||
assert response.status == 204
|
||||
|
||||
response = await client.get(f"/api/v1/packages/{package_ahriman.base}")
|
||||
assert response.ok
|
||||
@ -128,6 +144,11 @@ async def test_post_not_found(client: TestClient, package_ahriman: Package) -> N
|
||||
"""
|
||||
must raise exception on status update for unknown package
|
||||
"""
|
||||
post_response = await client.post(
|
||||
f"/api/v1/packages/{package_ahriman.base}", json={"status": BuildStatusEnum.Success.value})
|
||||
assert post_response.status == 400
|
||||
request_schema = PackageStatusSimplifiedSchema()
|
||||
response_schema = ErrorSchema()
|
||||
|
||||
payload = {"status": BuildStatusEnum.Success.value}
|
||||
assert not request_schema.validate(payload)
|
||||
response = await client.post(f"/api/v1/packages/{package_ahriman.base}", json=payload)
|
||||
assert response.status == 400
|
||||
assert not response_schema.validate(await response.json())
|
||||
|
@ -6,6 +6,7 @@ from pytest_mock import MockerFixture
|
||||
from ahriman.models.build_status import BuildStatusEnum
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.schemas.package_status_schema import PackageStatusSchema
|
||||
from ahriman.web.views.status.packages import PackagesView
|
||||
|
||||
|
||||
@ -13,7 +14,7 @@ async def test_get_permission() -> None:
|
||||
"""
|
||||
must return correct permission for the request
|
||||
"""
|
||||
for method in ("GET", "HEAD"):
|
||||
for method in ("GET",):
|
||||
request = pytest.helpers.request("", "", method)
|
||||
assert await PackagesView.get_permission(request) == UserAccess.Read
|
||||
for method in ("POST",):
|
||||
@ -29,11 +30,14 @@ async def test_get(client: TestClient, package_ahriman: Package, package_python_
|
||||
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()})
|
||||
response_schema = PackageStatusSchema()
|
||||
|
||||
response = await client.get("/api/v1/packages")
|
||||
assert response.ok
|
||||
json = await response.json()
|
||||
assert not response_schema.validate(json, many=True)
|
||||
|
||||
packages = [Package.from_json(item["package"]) for item in await response.json()]
|
||||
packages = [Package.from_json(item["package"]) for item in json]
|
||||
assert packages
|
||||
assert {package.base for package in packages} == {package_ahriman.base, package_python_schedule.base}
|
||||
|
||||
@ -43,6 +47,7 @@ async def test_post(client: TestClient, mocker: MockerFixture) -> None:
|
||||
must be able to reload packages
|
||||
"""
|
||||
load_mock = mocker.patch("ahriman.core.status.watcher.Watcher.load")
|
||||
|
||||
response = await client.post("/api/v1/packages")
|
||||
assert response.status == 204
|
||||
load_mock.assert_called_once_with()
|
||||
|
@ -9,6 +9,9 @@ from ahriman.models.build_status import BuildStatusEnum
|
||||
from ahriman.models.internal_status import InternalStatus
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.schemas.error_schema import ErrorSchema
|
||||
from ahriman.web.schemas.internal_status_schema import InternalStatusSchema
|
||||
from ahriman.web.schemas.status_schema import StatusSchema
|
||||
from ahriman.web.views.status.status import StatusView
|
||||
|
||||
|
||||
@ -16,7 +19,7 @@ async def test_get_permission() -> None:
|
||||
"""
|
||||
must return correct permission for the request
|
||||
"""
|
||||
for method in ("GET", "HEAD"):
|
||||
for method in ("GET",):
|
||||
request = pytest.helpers.request("", "", method)
|
||||
assert await StatusView.get_permission(request) == UserAccess.Read
|
||||
for method in ("POST",):
|
||||
@ -30,11 +33,13 @@ async def test_get(client: TestClient, package_ahriman: Package) -> None:
|
||||
"""
|
||||
await client.post(f"/api/v1/packages/{package_ahriman.base}",
|
||||
json={"status": BuildStatusEnum.Success.value, "package": package_ahriman.view()})
|
||||
response_schema = InternalStatusSchema()
|
||||
|
||||
response = await client.get("/api/v1/status")
|
||||
assert response.ok
|
||||
|
||||
json = await response.json()
|
||||
assert not response_schema.validate(json)
|
||||
|
||||
assert json["version"] == version.__version__
|
||||
assert json["packages"]
|
||||
assert json["packages"]["total"] == 1
|
||||
@ -44,7 +49,10 @@ async def test_post(client: TestClient) -> None:
|
||||
"""
|
||||
must update service status correctly
|
||||
"""
|
||||
request_schema = StatusSchema()
|
||||
|
||||
payload = {"status": BuildStatusEnum.Success.value}
|
||||
assert not request_schema.validate(payload)
|
||||
post_response = await client.post("/api/v1/status", json=payload)
|
||||
assert post_response.status == 204
|
||||
|
||||
@ -59,8 +67,11 @@ async def test_post_exception(client: TestClient) -> None:
|
||||
"""
|
||||
must raise exception on invalid payload
|
||||
"""
|
||||
post_response = await client.post("/api/v1/status", json={})
|
||||
assert post_response.status == 400
|
||||
response_schema = ErrorSchema()
|
||||
|
||||
response = await client.post("/api/v1/status", json={})
|
||||
assert response.status == 400
|
||||
assert not response_schema.validate(await response.json())
|
||||
|
||||
|
||||
async def test_post_exception_inside(client: TestClient, mocker: MockerFixture) -> None:
|
||||
@ -69,6 +80,8 @@ async def test_post_exception_inside(client: TestClient, mocker: MockerFixture)
|
||||
"""
|
||||
payload = {"status": BuildStatusEnum.Success.value}
|
||||
mocker.patch("ahriman.core.status.watcher.Watcher.update_self", side_effect=Exception())
|
||||
response_schema = ErrorSchema()
|
||||
|
||||
post_response = await client.post("/api/v1/status", json=payload)
|
||||
assert post_response.status == 500
|
||||
response = await client.post("/api/v1/status", json=payload)
|
||||
assert response.status == 500
|
||||
assert not response_schema.validate(await response.json())
|
||||
|
@ -1,7 +1,9 @@
|
||||
import pytest
|
||||
|
||||
from multidict import MultiDict
|
||||
from aiohttp.test_utils import TestClient
|
||||
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.views.base import BaseView
|
||||
|
||||
|
||||
@ -37,11 +39,17 @@ async def test_get_permission(base: BaseView) -> None:
|
||||
"""
|
||||
must search for permission attribute in class
|
||||
"""
|
||||
for method in ("DELETE", "GET", "POST"):
|
||||
setattr(BaseView, f"{method.upper()}_PERMISSION", "permission")
|
||||
|
||||
for method in ("DELETE", "GET", "HEAD", "POST"):
|
||||
request = pytest.helpers.request(base.request.app, "", method)
|
||||
setattr(BaseView, f"{method.upper()}_PERMISSION", "permission")
|
||||
assert await base.get_permission(request) == "permission"
|
||||
|
||||
for method in ("OPTIONS",):
|
||||
request = pytest.helpers.request(base.request.app, "", method)
|
||||
assert await base.get_permission(request) == UserAccess.Unauthorized
|
||||
|
||||
|
||||
def test_get_non_empty() -> None:
|
||||
"""
|
||||
@ -61,35 +69,6 @@ def test_get_non_empty() -> None:
|
||||
BaseView.get_non_empty(lambda k: [], "key")
|
||||
|
||||
|
||||
async def test_extract_data_json(base: BaseView) -> None:
|
||||
"""
|
||||
must parse and return json
|
||||
"""
|
||||
json = {"key1": "value1", "key2": "value2"}
|
||||
|
||||
async def get_json():
|
||||
return json
|
||||
|
||||
base._request = pytest.helpers.request(base.request.app, "", "", json=get_json)
|
||||
assert await base.extract_data() == json
|
||||
|
||||
|
||||
async def test_extract_data_post(base: BaseView) -> None:
|
||||
"""
|
||||
must parse and return form data
|
||||
"""
|
||||
json = {"key1": "value1", "key2": "value2"}
|
||||
|
||||
async def get_json():
|
||||
raise ValueError()
|
||||
|
||||
async def get_data():
|
||||
return json
|
||||
|
||||
base._request = pytest.helpers.request(base.request.app, "", "", json=get_json, data=get_data)
|
||||
assert await base.extract_data() == json
|
||||
|
||||
|
||||
async def test_data_as_json(base: BaseView) -> None:
|
||||
"""
|
||||
must parse multi value form payload
|
||||
@ -121,3 +100,49 @@ async def test_data_as_json_with_list_keys(base: BaseView) -> None:
|
||||
|
||||
base._request = pytest.helpers.request(base.request.app, "", "", data=get_data)
|
||||
assert await base.data_as_json(["key1"]) == {"key1": ["value1"]}
|
||||
|
||||
|
||||
async def test_extract_data_json(base: BaseView) -> None:
|
||||
"""
|
||||
must parse and return json
|
||||
"""
|
||||
json = {"key1": "value1", "key2": "value2"}
|
||||
|
||||
async def get_json():
|
||||
return json
|
||||
|
||||
base._request = pytest.helpers.request(base.request.app, "", "", json=get_json)
|
||||
assert await base.extract_data() == json
|
||||
|
||||
|
||||
async def test_extract_data_post(base: BaseView) -> None:
|
||||
"""
|
||||
must parse and return form data
|
||||
"""
|
||||
json = {"key1": "value1", "key2": "value2"}
|
||||
|
||||
async def get_json():
|
||||
raise ValueError()
|
||||
|
||||
async def get_data():
|
||||
return json
|
||||
|
||||
base._request = pytest.helpers.request(base.request.app, "", "", json=get_json, data=get_data)
|
||||
assert await base.extract_data() == json
|
||||
|
||||
|
||||
async def test_head(client: TestClient) -> None:
|
||||
"""
|
||||
must implement head as get method
|
||||
"""
|
||||
response = await client.head("/")
|
||||
assert response.ok
|
||||
assert await response.text() == ""
|
||||
|
||||
|
||||
async def test_head_not_allowed(client: TestClient) -> None:
|
||||
"""
|
||||
must raise MethodNotAllowed in case if no get method was implemented
|
||||
"""
|
||||
response = await client.head("/api/v1/service/add")
|
||||
assert response.status == 405
|
||||
|
@ -10,7 +10,7 @@ async def test_get_permission() -> None:
|
||||
"""
|
||||
must return correct permission for the request
|
||||
"""
|
||||
for method in ("GET", "HEAD"):
|
||||
for method in ("GET",):
|
||||
request = pytest.helpers.request("", "", method)
|
||||
assert await IndexView.get_permission(request) == UserAccess.Unauthorized
|
||||
|
||||
|
@ -5,6 +5,9 @@ from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.models.user import User
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.schemas.error_schema import ErrorSchema
|
||||
from ahriman.web.schemas.login_schema import LoginSchema
|
||||
from ahriman.web.schemas.oauth2_schema import OAuth2Schema
|
||||
from ahriman.web.views.user.login import LoginView
|
||||
|
||||
|
||||
@ -21,8 +24,8 @@ async def test_get_default_validator(client_with_auth: TestClient) -> None:
|
||||
"""
|
||||
must return 405 in case if no OAuth enabled
|
||||
"""
|
||||
get_response = await client_with_auth.get("/api/v1/login")
|
||||
assert get_response.status == 405
|
||||
response = await client_with_auth.get("/api/v1/login")
|
||||
assert response.status == 405
|
||||
|
||||
|
||||
async def test_get_redirect_to_oauth(client_with_oauth_auth: TestClient) -> None:
|
||||
@ -31,9 +34,12 @@ async def test_get_redirect_to_oauth(client_with_oauth_auth: TestClient) -> None
|
||||
"""
|
||||
oauth = client_with_oauth_auth.app["validator"]
|
||||
oauth.get_oauth_url.return_value = "https://httpbin.org"
|
||||
request_schema = OAuth2Schema()
|
||||
|
||||
get_response = await client_with_oauth_auth.get("/api/v1/login")
|
||||
assert get_response.ok
|
||||
payload = {}
|
||||
assert not request_schema.validate(payload)
|
||||
response = await client_with_oauth_auth.get("/api/v1/login", params=payload)
|
||||
assert response.ok
|
||||
oauth.get_oauth_url.assert_called_once_with()
|
||||
|
||||
|
||||
@ -43,9 +49,12 @@ async def test_get_redirect_to_oauth_empty_code(client_with_oauth_auth: TestClie
|
||||
"""
|
||||
oauth = client_with_oauth_auth.app["validator"]
|
||||
oauth.get_oauth_url.return_value = "https://httpbin.org"
|
||||
request_schema = OAuth2Schema()
|
||||
|
||||
get_response = await client_with_oauth_auth.get("/api/v1/login", params={"code": ""})
|
||||
assert get_response.ok
|
||||
payload = {"code": ""}
|
||||
assert not request_schema.validate(payload)
|
||||
response = await client_with_oauth_auth.get("/api/v1/login", params=payload)
|
||||
assert response.ok
|
||||
oauth.get_oauth_url.assert_called_once_with()
|
||||
|
||||
|
||||
@ -59,10 +68,13 @@ async def test_get(client_with_oauth_auth: TestClient, mocker: MockerFixture) ->
|
||||
oauth.enabled = False # lol
|
||||
oauth.max_age = 60
|
||||
remember_mock = mocker.patch("aiohttp_security.remember")
|
||||
request_schema = OAuth2Schema()
|
||||
|
||||
get_response = await client_with_oauth_auth.get("/api/v1/login", params={"code": "code"})
|
||||
payload = {"code": "code"}
|
||||
assert not request_schema.validate(payload)
|
||||
response = await client_with_oauth_auth.get("/api/v1/login", params=payload)
|
||||
|
||||
assert get_response.ok
|
||||
assert response.ok
|
||||
oauth.get_oauth_username.assert_called_once_with("code")
|
||||
oauth.known_username.assert_called_once_with("user")
|
||||
remember_mock.assert_called_once_with(
|
||||
@ -77,10 +89,13 @@ async def test_get_unauthorized(client_with_oauth_auth: TestClient, mocker: Mock
|
||||
oauth.known_username.return_value = False
|
||||
oauth.max_age = 60
|
||||
remember_mock = mocker.patch("aiohttp_security.remember")
|
||||
response_schema = ErrorSchema()
|
||||
|
||||
get_response = await client_with_oauth_auth.get("/api/v1/login", params={"code": "code"})
|
||||
response = await client_with_oauth_auth.get(
|
||||
"/api/v1/login", params={"code": "code"}, headers={"accept": "application/json"})
|
||||
|
||||
assert get_response.status == 401
|
||||
assert response.status == 401
|
||||
assert not response_schema.validate(await response.json())
|
||||
remember_mock.assert_not_called()
|
||||
|
||||
|
||||
@ -90,12 +105,15 @@ async def test_post(client_with_auth: TestClient, user: User, mocker: MockerFixt
|
||||
"""
|
||||
payload = {"username": user.username, "password": user.password}
|
||||
remember_mock = mocker.patch("aiohttp_security.remember")
|
||||
request_schema = LoginSchema()
|
||||
|
||||
post_response = await client_with_auth.post("/api/v1/login", json=payload)
|
||||
assert post_response.ok
|
||||
assert not request_schema.validate(payload)
|
||||
|
||||
post_response = await client_with_auth.post("/api/v1/login", data=payload)
|
||||
assert post_response.ok
|
||||
response = await client_with_auth.post("/api/v1/login", json=payload)
|
||||
assert response.ok
|
||||
|
||||
response = await client_with_auth.post("/api/v1/login", data=payload)
|
||||
assert response.ok
|
||||
|
||||
remember_mock.assert_called()
|
||||
|
||||
@ -104,18 +122,24 @@ async def test_post_skip(client: TestClient, user: User) -> None:
|
||||
"""
|
||||
must process if no auth configured
|
||||
"""
|
||||
request_schema = LoginSchema()
|
||||
|
||||
payload = {"username": user.username, "password": user.password}
|
||||
post_response = await client.post("/api/v1/login", json=payload)
|
||||
assert post_response.ok
|
||||
assert not request_schema.validate(payload)
|
||||
response = await client.post("/api/v1/login", json=payload)
|
||||
assert response.ok
|
||||
|
||||
|
||||
async def test_post_unauthorized(client_with_auth: TestClient, user: User, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must return unauthorized on invalid auth
|
||||
"""
|
||||
response_schema = ErrorSchema()
|
||||
|
||||
payload = {"username": user.username, "password": ""}
|
||||
remember_mock = mocker.patch("aiohttp_security.remember")
|
||||
|
||||
post_response = await client_with_auth.post("/api/v1/login", json=payload)
|
||||
assert post_response.status == 401
|
||||
response = await client_with_auth.post("/api/v1/login", json=payload, headers={"accept": "application/json"})
|
||||
assert response.status == 401
|
||||
assert not response_schema.validate(await response.json())
|
||||
remember_mock.assert_not_called()
|
||||
|
@ -5,6 +5,7 @@ from aiohttp.web import HTTPUnauthorized
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.schemas.error_schema import ErrorSchema
|
||||
from ahriman.web.views.user.logout import LogoutView
|
||||
|
||||
|
||||
@ -24,8 +25,8 @@ async def test_post(client_with_auth: TestClient, mocker: MockerFixture) -> None
|
||||
mocker.patch("aiohttp_security.check_authorized")
|
||||
forget_mock = mocker.patch("aiohttp_security.forget")
|
||||
|
||||
post_response = await client_with_auth.post("/api/v1/logout")
|
||||
assert post_response.ok
|
||||
response = await client_with_auth.post("/api/v1/logout")
|
||||
assert response.ok
|
||||
forget_mock.assert_called_once_with(pytest.helpers.anyvar(int), pytest.helpers.anyvar(int))
|
||||
|
||||
|
||||
@ -35,9 +36,11 @@ async def test_post_unauthorized(client_with_auth: TestClient, mocker: MockerFix
|
||||
"""
|
||||
mocker.patch("aiohttp_security.check_authorized", side_effect=HTTPUnauthorized())
|
||||
forget_mock = mocker.patch("aiohttp_security.forget")
|
||||
response_schema = ErrorSchema()
|
||||
|
||||
post_response = await client_with_auth.post("/api/v1/logout")
|
||||
assert post_response.status == 401
|
||||
response = await client_with_auth.post("/api/v1/logout", headers={"accept": "application/json"})
|
||||
assert response.status == 401
|
||||
assert not response_schema.validate(await response.json())
|
||||
forget_mock.assert_not_called()
|
||||
|
||||
|
||||
@ -45,5 +48,5 @@ async def test_post_disabled(client: TestClient) -> None:
|
||||
"""
|
||||
must raise exception if auth is disabled
|
||||
"""
|
||||
post_response = await client.post("/api/v1/logout")
|
||||
assert post_response.ok
|
||||
response = await client.post("/api/v1/logout")
|
||||
assert response.ok
|
||||
|
Reference in New Issue
Block a user