mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-07-23 18:59:56 +00:00
Extended package status page (#76)
* implement log storage at backend * handle process id during removal. During one process we can write logs from different packages in different times (e.g. check and update later) and we would like to store all logs belong to the same process * set package context in main functions * implement logs support in interface * filter out logs posting http logs * add timestamp to log records * hide getting logs under reporter permission List of breaking changes: * `ahriman.core.lazy_logging.LazyLogging` has been renamed to `ahriman.core.log.LazyLogging` * `ahriman.core.configuration.Configuration.from_path` does not have `quiet` attribute now * `ahriman.core.configuration.Configuration` class does not have `load_logging` method now * `ahriman.core.status.client.Client.load` requires `report` argument now
This commit is contained in:
@ -4,6 +4,7 @@ from aiohttp import web
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
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 on_shutdown, on_startup, run_server
|
||||
|
||||
@ -48,8 +49,10 @@ def test_run(application: web.Application, mocker: MockerFixture) -> None:
|
||||
run_application_mock = mocker.patch("aiohttp.web.run_app")
|
||||
|
||||
run_server(application)
|
||||
run_application_mock.assert_called_once_with(application, host="127.0.0.1", port=port,
|
||||
handle_signals=False, access_log=pytest.helpers.anyvar(int))
|
||||
run_application_mock.assert_called_once_with(
|
||||
application, host="127.0.0.1", port=port, handle_signals=False,
|
||||
access_log=pytest.helpers.anyvar(int), access_log_class=FilteredAccessLogger
|
||||
)
|
||||
|
||||
|
||||
def test_run_with_auth(application_with_auth: web.Application, mocker: MockerFixture) -> None:
|
||||
@ -61,8 +64,10 @@ def test_run_with_auth(application_with_auth: web.Application, mocker: MockerFix
|
||||
run_application_mock = mocker.patch("aiohttp.web.run_app")
|
||||
|
||||
run_server(application_with_auth)
|
||||
run_application_mock.assert_called_once_with(application_with_auth, host="127.0.0.1", port=port,
|
||||
handle_signals=False, access_log=pytest.helpers.anyvar(int))
|
||||
run_application_mock.assert_called_once_with(
|
||||
application_with_auth, host="127.0.0.1", port=port, handle_signals=False,
|
||||
access_log=pytest.helpers.anyvar(int), access_log_class=FilteredAccessLogger
|
||||
)
|
||||
|
||||
|
||||
def test_run_with_debug(application_with_debug: web.Application, mocker: MockerFixture) -> None:
|
||||
@ -74,5 +79,7 @@ def test_run_with_debug(application_with_debug: web.Application, mocker: MockerF
|
||||
run_application_mock = mocker.patch("aiohttp.web.run_app")
|
||||
|
||||
run_server(application_with_debug)
|
||||
run_application_mock.assert_called_once_with(application_with_debug, host="127.0.0.1", port=port,
|
||||
handle_signals=False, access_log=pytest.helpers.anyvar(int))
|
||||
run_application_mock.assert_called_once_with(
|
||||
application_with_debug, host="127.0.0.1", port=port, handle_signals=False,
|
||||
access_log=pytest.helpers.anyvar(int), access_log_class=FilteredAccessLogger
|
||||
)
|
||||
|
94
tests/ahriman/web/views/status/test_views_status_logs.py
Normal file
94
tests/ahriman/web/views/status/test_views_status_logs.py
Normal file
@ -0,0 +1,94 @@
|
||||
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.status.logs import LogsView
|
||||
|
||||
|
||||
async def test_get_permission() -> None:
|
||||
"""
|
||||
must return correct permission for the request
|
||||
"""
|
||||
for method in ("GET", "HEAD"):
|
||||
request = pytest.helpers.request("", "", method)
|
||||
assert await LogsView.get_permission(request) == UserAccess.Reporter
|
||||
for method in ("DELETE", "POST"):
|
||||
request = pytest.helpers.request("", "", method)
|
||||
assert await LogsView.get_permission(request) == UserAccess.Full
|
||||
|
||||
|
||||
async def test_delete(client: TestClient, package_ahriman: Package, package_python_schedule: Package) -> None:
|
||||
"""
|
||||
must delete 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_python_schedule.base}",
|
||||
json={"status": BuildStatusEnum.Success.value, "package": package_python_schedule.view()})
|
||||
|
||||
await client.post(f"/api/v1/packages/{package_ahriman.base}/logs",
|
||||
json={"created": 42.0, "message": "message", "process_id": 42})
|
||||
await client.post(f"/api/v1/packages/{package_python_schedule.base}/logs",
|
||||
json={"created": 42.0, "message": "message", "process_id": 42})
|
||||
|
||||
response = await client.delete(f"/api/v1/packages/{package_ahriman.base}/logs")
|
||||
assert response.status == 204
|
||||
|
||||
response = await client.get(f"/api/v1/packages/{package_ahriman.base}/logs")
|
||||
logs = await response.json()
|
||||
assert not logs["logs"]
|
||||
|
||||
response = await client.get(f"/api/v1/packages/{package_python_schedule.base}/logs")
|
||||
logs = await response.json()
|
||||
assert logs["logs"]
|
||||
|
||||
|
||||
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", "process_id": 42})
|
||||
|
||||
response = await client.get(f"/api/v1/packages/{package_ahriman.base}/logs")
|
||||
assert response.status == 200
|
||||
|
||||
logs = await response.json()
|
||||
assert logs["logs"] == "[1970-01-01 00:00:42] message"
|
||||
|
||||
|
||||
async def test_get_not_foud(client: TestClient, package_ahriman: Package) -> None:
|
||||
"""
|
||||
must return not found for missing package
|
||||
"""
|
||||
response = await client.get(f"/api/v1/packages/{package_ahriman.base}/logs")
|
||||
assert response.status == 404
|
||||
|
||||
|
||||
async def test_post(client: TestClient, package_ahriman: Package) -> None:
|
||||
"""
|
||||
must create logs record
|
||||
"""
|
||||
await client.post(f"/api/v1/packages/{package_ahriman.base}",
|
||||
json={"status": BuildStatusEnum.Success.value, "package": package_ahriman.view()})
|
||||
|
||||
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
|
||||
|
||||
response = await client.get(f"/api/v1/packages/{package_ahriman.base}/logs")
|
||||
logs = await response.json()
|
||||
assert logs["logs"] == "[1970-01-01 00:00:42] message"
|
||||
|
||||
|
||||
async def test_post_exception(client: TestClient, package_ahriman: Package) -> None:
|
||||
"""
|
||||
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
|
@ -20,31 +20,6 @@ async def test_get_permission() -> None:
|
||||
assert await PackageView.get_permission(request) == UserAccess.Full
|
||||
|
||||
|
||||
async def test_get(client: TestClient, package_ahriman: Package, package_python_schedule: Package) -> None:
|
||||
"""
|
||||
must return status for specific package
|
||||
"""
|
||||
await client.post(f"/api/v1/packages/{package_ahriman.base}",
|
||||
json={"status": BuildStatusEnum.Success.value, "package": package_ahriman.view()})
|
||||
await client.post(f"/api/v1/packages/{package_python_schedule.base}",
|
||||
json={"status": BuildStatusEnum.Success.value, "package": package_python_schedule.view()})
|
||||
|
||||
response = await client.get(f"/api/v1/packages/{package_ahriman.base}")
|
||||
assert response.ok
|
||||
|
||||
packages = [Package.from_json(item["package"]) for item in await response.json()]
|
||||
assert packages
|
||||
assert {package.base for package in packages} == {package_ahriman.base}
|
||||
|
||||
|
||||
async def test_get_not_found(client: TestClient, package_ahriman: Package) -> None:
|
||||
"""
|
||||
must return Not Found for unknown package
|
||||
"""
|
||||
response = await client.get(f"/api/v1/packages/{package_ahriman.base}")
|
||||
assert response.status == 404
|
||||
|
||||
|
||||
async def test_delete(client: TestClient, package_ahriman: Package, package_python_schedule: Package) -> None:
|
||||
"""
|
||||
must delete single base
|
||||
@ -81,6 +56,31 @@ async def test_delete_unknown(client: TestClient, package_ahriman: Package, pack
|
||||
assert response.ok
|
||||
|
||||
|
||||
async def test_get(client: TestClient, package_ahriman: Package, package_python_schedule: Package) -> None:
|
||||
"""
|
||||
must return status for specific package
|
||||
"""
|
||||
await client.post(f"/api/v1/packages/{package_ahriman.base}",
|
||||
json={"status": BuildStatusEnum.Success.value, "package": package_ahriman.view()})
|
||||
await client.post(f"/api/v1/packages/{package_python_schedule.base}",
|
||||
json={"status": BuildStatusEnum.Success.value, "package": package_python_schedule.view()})
|
||||
|
||||
response = await client.get(f"/api/v1/packages/{package_ahriman.base}")
|
||||
assert response.ok
|
||||
|
||||
packages = [Package.from_json(item["package"]) for item in await response.json()]
|
||||
assert packages
|
||||
assert {package.base for package in packages} == {package_ahriman.base}
|
||||
|
||||
|
||||
async def test_get_not_found(client: TestClient, package_ahriman: Package) -> None:
|
||||
"""
|
||||
must return Not Found for unknown package
|
||||
"""
|
||||
response = await client.get(f"/api/v1/packages/{package_ahriman.base}")
|
||||
assert response.status == 404
|
||||
|
||||
|
||||
async def test_post(client: TestClient, package_ahriman: Package) -> None:
|
||||
"""
|
||||
must update package status
|
||||
|
Reference in New Issue
Block a user