mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-06-28 06:41:43 +00:00
feat: pagination support for logs request
This commit is contained in:
@ -13,8 +13,8 @@ def test_logs_insert_remove_process(database: SQLite, package_ahriman: Package,
|
||||
database.logs_insert(LogRecordId(package_python_schedule.base, "1"), 42.0, "message 3")
|
||||
|
||||
database.logs_remove(package_ahriman.base, "1")
|
||||
assert database.logs_get(package_ahriman.base) == "[1970-01-01 00:00:42] message 1"
|
||||
assert database.logs_get(package_python_schedule.base) == "[1970-01-01 00:00:42] message 3"
|
||||
assert database.logs_get(package_ahriman.base) == [(42.0, "message 1")]
|
||||
assert database.logs_get(package_python_schedule.base) == [(42.0, "message 3")]
|
||||
|
||||
|
||||
def test_logs_insert_remove_full(database: SQLite, package_ahriman: Package, package_python_schedule: Package) -> None:
|
||||
@ -27,7 +27,7 @@ def test_logs_insert_remove_full(database: SQLite, package_ahriman: Package, pac
|
||||
|
||||
database.logs_remove(package_ahriman.base, None)
|
||||
assert not database.logs_get(package_ahriman.base)
|
||||
assert database.logs_get(package_python_schedule.base) == "[1970-01-01 00:00:42] message 3"
|
||||
assert database.logs_get(package_python_schedule.base) == [(42.0, "message 3")]
|
||||
|
||||
|
||||
def test_logs_insert_get(database: SQLite, package_ahriman: Package) -> None:
|
||||
@ -36,4 +36,13 @@ def test_logs_insert_get(database: SQLite, package_ahriman: Package) -> None:
|
||||
"""
|
||||
database.logs_insert(LogRecordId(package_ahriman.base, "1"), 43.0, "message 2")
|
||||
database.logs_insert(LogRecordId(package_ahriman.base, "1"), 42.0, "message 1")
|
||||
assert database.logs_get(package_ahriman.base) == "[1970-01-01 00:00:42] message 1\n[1970-01-01 00:00:43] message 2"
|
||||
assert database.logs_get(package_ahriman.base) == [(42.0, "message 1"), (43.0, "message 2")]
|
||||
|
||||
|
||||
def test_logs_insert_get_pagination(database: SQLite, package_ahriman: Package) -> None:
|
||||
"""
|
||||
must insert and get package logs with pagination
|
||||
"""
|
||||
database.logs_insert(LogRecordId(package_ahriman.base, "1"), 42.0, "message 1")
|
||||
database.logs_insert(LogRecordId(package_ahriman.base, "1"), 43.0, "message 2")
|
||||
assert database.logs_get(package_ahriman.base, 1, 1) == [(43.0, "message 2")]
|
||||
|
@ -55,8 +55,8 @@ def test_logs_get(watcher: Watcher, package_ahriman: Package, mocker: MockerFixt
|
||||
must return package logs
|
||||
"""
|
||||
logs_mock = mocker.patch("ahriman.core.database.SQLite.logs_get")
|
||||
watcher.logs_get(package_ahriman.base)
|
||||
logs_mock.assert_called_once_with(package_ahriman.base)
|
||||
watcher.logs_get(package_ahriman.base, 1, 2)
|
||||
logs_mock.assert_called_once_with(package_ahriman.base, 1, 2)
|
||||
|
||||
|
||||
def test_logs_remove(watcher: Watcher, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
|
27
tests/ahriman/test_tests.py
Normal file
27
tests/ahriman/test_tests.py
Normal file
@ -0,0 +1,27 @@
|
||||
from pathlib import Path
|
||||
|
||||
from ahriman.core.util import walk
|
||||
|
||||
|
||||
def test_test_coverage() -> None:
|
||||
"""
|
||||
must have test files for each source file
|
||||
"""
|
||||
root = Path()
|
||||
for source_file in filter(lambda fn: fn.suffix == ".py" and fn.name != "__init__.py", walk(root / "src")):
|
||||
# some workaround for well known files
|
||||
if source_file.parts[2:4] == ("application", "handlers") and source_file.name != "handler.py":
|
||||
filename = f"test_handler_{source_file.name}"
|
||||
elif source_file.parts[2:4] == ("web", "views"):
|
||||
if (api := source_file.parts[4]) == "api":
|
||||
filename = f"test_view_{api}_{source_file.name}"
|
||||
elif (version := source_file.parts[4]) in ("v1", "v2"):
|
||||
api = source_file.parts[5]
|
||||
filename = f"test_view_{version}_{api}_{source_file.name}"
|
||||
else:
|
||||
filename = f"test_view_{source_file.name}"
|
||||
else:
|
||||
filename = f"test_{source_file.name}"
|
||||
|
||||
test_file = Path("tests", *source_file.parts[1:-1], filename)
|
||||
assert test_file.is_file(), test_file
|
1
tests/ahriman/web/schemas/test_pagination_schema.py
Normal file
1
tests/ahriman/web/schemas/test_pagination_schema.py
Normal file
@ -0,0 +1 @@
|
||||
# schema testing goes in view class tests
|
@ -5,7 +5,7 @@ from pytest_mock import MockerFixture
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.views.service.add import AddView
|
||||
from ahriman.web.views.v1 import AddView
|
||||
|
||||
|
||||
async def test_get_permission() -> None:
|
@ -4,7 +4,7 @@ from aiohttp.test_utils import TestClient
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.views.service.pgp import PGPView
|
||||
from ahriman.web.views.v1 import PGPView
|
||||
|
||||
|
||||
async def test_get_permission() -> None:
|
@ -4,7 +4,7 @@ from aiohttp.test_utils import TestClient
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.views.service.process import ProcessView
|
||||
from ahriman.web.views.v1 import ProcessView
|
||||
|
||||
|
||||
async def test_get_permission() -> None:
|
@ -5,7 +5,7 @@ from pytest_mock import MockerFixture
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.views.service.rebuild import RebuildView
|
||||
from ahriman.web.views.v1 import RebuildView
|
||||
|
||||
|
||||
async def test_get_permission() -> None:
|
@ -4,7 +4,7 @@ from aiohttp.test_utils import TestClient
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.views.service.remove import RemoveView
|
||||
from ahriman.web.views.v1 import RemoveView
|
||||
|
||||
|
||||
async def test_get_permission() -> None:
|
@ -5,7 +5,7 @@ from pytest_mock import MockerFixture
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.views.service.request import RequestView
|
||||
from ahriman.web.views.v1 import RequestView
|
||||
|
||||
|
||||
async def test_get_permission() -> None:
|
@ -5,7 +5,7 @@ from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.models.aur_package import AURPackage
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.views.service.search import SearchView
|
||||
from ahriman.web.views.v1 import SearchView
|
||||
|
||||
|
||||
async def test_get_permission() -> None:
|
@ -5,7 +5,7 @@ from pytest_mock import MockerFixture
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.views.service.update import UpdateView
|
||||
from ahriman.web.views.v1 import UpdateView
|
||||
|
||||
|
||||
async def test_get_permission() -> None:
|
@ -10,7 +10,7 @@ from unittest.mock import AsyncMock, MagicMock, call as MockCall
|
||||
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.views.service.upload import UploadView
|
||||
from ahriman.web.views.v1 import UploadView
|
||||
|
||||
|
||||
async def test_get_permission() -> None:
|
||||
@ -30,7 +30,7 @@ async def test_save_file(mocker: MockerFixture) -> None:
|
||||
part_mock.filename = "filename"
|
||||
part_mock.read_chunk = AsyncMock(side_effect=[b"content", None])
|
||||
|
||||
tempfile_mock = mocker.patch("ahriman.web.views.service.upload.NamedTemporaryFile")
|
||||
tempfile_mock = mocker.patch("ahriman.web.views.v1.service.upload.NamedTemporaryFile")
|
||||
file_mock = MagicMock()
|
||||
tempfile_mock.return_value.__enter__.return_value = file_mock
|
||||
|
||||
@ -84,7 +84,7 @@ async def test_post(client: TestClient, repository_paths: RepositoryPaths, mocke
|
||||
must process file upload via http
|
||||
"""
|
||||
local = Path("local")
|
||||
save_mock = mocker.patch("ahriman.web.views.service.upload.UploadView.save_file",
|
||||
save_mock = mocker.patch("ahriman.web.views.v1.UploadView.save_file",
|
||||
side_effect=AsyncMock(return_value=("filename", local / ".filename")))
|
||||
rename_mock = mocker.patch("pathlib.Path.rename")
|
||||
# no content validation here because it has invalid schema
|
||||
@ -103,7 +103,7 @@ async def test_post_with_sig(client: TestClient, repository_paths: RepositoryPat
|
||||
must process file upload with signature via http
|
||||
"""
|
||||
local = Path("local")
|
||||
save_mock = mocker.patch("ahriman.web.views.service.upload.UploadView.save_file",
|
||||
save_mock = mocker.patch("ahriman.web.views.v1.UploadView.save_file",
|
||||
side_effect=AsyncMock(side_effect=[
|
||||
("filename", local / ".filename"),
|
||||
("filename.sig", local / ".filename.sig"),
|
@ -5,7 +5,7 @@ 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.views.status.logs import LogsView
|
||||
from ahriman.web.views.v1 import LogsView
|
||||
|
||||
|
||||
async def test_get_permission() -> None:
|
@ -5,7 +5,7 @@ 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.views.status.package import PackageView
|
||||
from ahriman.web.views.v1 import PackageView
|
||||
|
||||
|
||||
async def test_get_permission() -> None:
|
@ -6,7 +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.views.status.packages import PackagesView
|
||||
from ahriman.web.views.v1 import PackagesView
|
||||
|
||||
|
||||
async def test_get_permission() -> None:
|
@ -8,7 +8,7 @@ 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.views.status.status import StatusView
|
||||
from ahriman.web.views.v1 import StatusView
|
||||
|
||||
|
||||
async def test_get_permission() -> None:
|
@ -5,7 +5,7 @@ from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.models.user import User
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.views.user.login import LoginView
|
||||
from ahriman.web.views.v1 import LoginView
|
||||
|
||||
|
||||
async def test_get_permission() -> None:
|
@ -5,7 +5,7 @@ from aiohttp.web import HTTPUnauthorized
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.views.user.logout import LogoutView
|
||||
from ahriman.web.views.v1 import LogoutView
|
||||
|
||||
|
||||
async def test_get_permission() -> None:
|
@ -0,0 +1,93 @@
|
||||
import pytest
|
||||
|
||||
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.views.v2 import LogsView
|
||||
|
||||
|
||||
async def test_get_permission() -> None:
|
||||
"""
|
||||
must return correct permission for the request
|
||||
"""
|
||||
for method in ("GET",):
|
||||
request = pytest.helpers.request("", "", method)
|
||||
assert await LogsView.get_permission(request) == UserAccess.Reporter
|
||||
|
||||
|
||||
async def test_get(client: TestClient, package_ahriman: Package) -> None:
|
||||
"""
|
||||
must get logs for package
|
||||
"""
|
||||
await client.post(f"/api/v1/packages/{package_ahriman.base}",
|
||||
json={"status": BuildStatusEnum.Success.value, "package": package_ahriman.view()})
|
||||
await client.post(f"/api/v1/packages/{package_ahriman.base}/logs",
|
||||
json={"created": 42.0, "message": "message 1", "version": "42"})
|
||||
await client.post(f"/api/v1/packages/{package_ahriman.base}/logs",
|
||||
json={"created": 43.0, "message": "message 2", "version": "42"})
|
||||
request_schema = pytest.helpers.schema_request(LogsView.get, location="querystring")
|
||||
response_schema = pytest.helpers.schema_response(LogsView.get)
|
||||
|
||||
payload = {}
|
||||
assert not request_schema.validate(payload)
|
||||
response = await client.get(f"/api/v2/packages/{package_ahriman.base}/logs", params=payload)
|
||||
assert response.status == 200
|
||||
|
||||
logs = await response.json()
|
||||
assert not response_schema.validate(logs)
|
||||
assert logs["logs"] == [[42.0, "message 1"], [43.0, "message 2"]]
|
||||
|
||||
|
||||
async def test_get_with_pagination(client: TestClient, package_ahriman: Package) -> None:
|
||||
"""
|
||||
must get logs with pagination
|
||||
"""
|
||||
await client.post(f"/api/v1/packages/{package_ahriman.base}",
|
||||
json={"status": BuildStatusEnum.Success.value, "package": package_ahriman.view()})
|
||||
await client.post(f"/api/v1/packages/{package_ahriman.base}/logs",
|
||||
json={"created": 42.0, "message": "message 1", "version": "42"})
|
||||
await client.post(f"/api/v1/packages/{package_ahriman.base}/logs",
|
||||
json={"created": 43.0, "message": "message 2", "version": "42"})
|
||||
request_schema = pytest.helpers.schema_request(LogsView.get, location="querystring")
|
||||
response_schema = pytest.helpers.schema_response(LogsView.get)
|
||||
|
||||
payload = {"limit": 1, "offset": 1}
|
||||
assert not request_schema.validate(payload)
|
||||
response = await client.get(f"/api/v2/packages/{package_ahriman.base}/logs", params=payload)
|
||||
assert response.status == 200
|
||||
|
||||
logs = await response.json()
|
||||
assert not response_schema.validate(logs)
|
||||
assert logs["logs"] == [[43.0, "message 2"]]
|
||||
|
||||
|
||||
async def test_get_not_found(client: TestClient, package_ahriman: Package) -> None:
|
||||
"""
|
||||
must return not found for missing package
|
||||
"""
|
||||
response_schema = pytest.helpers.schema_response(LogsView.get, code=404)
|
||||
|
||||
response = await client.get(f"/api/v2/packages/{package_ahriman.base}/logs")
|
||||
assert response.status == 404
|
||||
assert not response_schema.validate(await response.json())
|
||||
|
||||
|
||||
async def test_get_bad_request(client: TestClient, package_ahriman: Package) -> None:
|
||||
"""
|
||||
must return bad request for invalid query parameters
|
||||
"""
|
||||
await client.post(f"/api/v1/packages/{package_ahriman.base}",
|
||||
json={"status": BuildStatusEnum.Success.value, "package": package_ahriman.view()})
|
||||
await client.post(f"/api/v1/packages/{package_ahriman.base}/logs",
|
||||
json={"created": 42.0, "message": "message", "version": "42"})
|
||||
response_schema = pytest.helpers.schema_response(LogsView.get, code=400)
|
||||
|
||||
response = await client.get(f"/api/v2/packages/{package_ahriman.base}/logs", params={"limit": "limit"})
|
||||
assert response.status == 400
|
||||
assert not response_schema.validate(await response.json())
|
||||
|
||||
response = await client.get(f"/api/v2/packages/{package_ahriman.base}/logs", params={"offset": "offset"})
|
||||
assert response.status == 400
|
||||
assert not response_schema.validate(await response.json())
|
Reference in New Issue
Block a user