Skip to content

Commit

Permalink
feat: add method to download events from Event Controller (#140)
Browse files Browse the repository at this point in the history
* feat: add method to download events from Event Controller

* pylint/caplog

---------

Co-authored-by: Konstantin <konstantin.klein+github@hochfrequenz.de>
  • Loading branch information
hf-kklein and Konstantin authored Jan 20, 2025
1 parent 87dfd80 commit e08187c
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 0 deletions.
20 changes: 20 additions & 0 deletions src/bssclient/client/bssclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from bssclient.client.oauth import _OAuthHttpClient, token_is_valid
from bssclient.models.aufgabe import AufgabeStats
from bssclient.models.ermittlungsauftrag import Ermittlungsauftrag, _ListOfErmittlungsauftraege
from bssclient.models.events import EventHeader, EventHeaders

_logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -156,6 +157,25 @@ async def get_all_ermittlungsauftraege(self, package_size: int = 100) -> list[Er
_logger.info("Downloaded %i Ermittlungsautraege", len(result))
return result

async def get_events(self, model_type: DomainModelType, model_id: uuid.UUID) -> list[EventHeader]:
"""reads event headers from bss API"""
session = await self._get_session()
request_url = self._config.server_url / "api" / "Event" / model_type / str(model_id)
request_uuid = uuid.uuid4()
_logger.debug("[%s] requesting %s", str(request_uuid), request_url)
async with session.get(request_url) as response:
_logger.debug("[%s] response status: %s", str(request_uuid), response.status)
response_body = await response.json()
result = EventHeaders.model_validate(response_body)
if not result.is_continuous:
_logger.warning(
"The events for %s-%s are NOT continuous. There might be a problem with the deserialization",
model_type,
model_id,
)
_logger.debug("Read %i events from Aggregate %s-%s", len(result.root), model_type, model_id)
return result.root

async def replay_event(self, model_type: DomainModelType, model_id: uuid.UUID, event_number: int) -> bool:
"""calls the re-apply endpoint"""
session = await self._get_session()
Expand Down
34 changes: 34 additions & 0 deletions src/bssclient/models/events.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""
models for the event controller
"""

from itertools import pairwise
from uuid import UUID

from pydantic import BaseModel, RootModel


class EventHeader(BaseModel):
"""
model returned by /api/Event/prozess/<id goes here>
"""

number: int
name: str
id: UUID


class EventHeaders(RootModel[list[EventHeader]]):
"""wrapper around a list of EventHeaders"""

@property
def is_continuous(self) -> bool:
"""
returns true iff all event numbers are continuous.
a gap like: 1,2,3,5 indicates that there is a problem with the event at position 4
"""
number_pairs = pairwise(sorted((x.number for x in self.root)))
return all(abs(x - y) == 1 for x, y in number_pairs)


__all__ = ["EventHeader", "EventHeaders"]
77 changes: 77 additions & 0 deletions unittests/example_data/prozess-events.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
[
{
"number": 0,
"name": "ProzessErzeugt-1.0.0",
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
},
{
"number": 1,
"name": "FooXMLEmpfangen-1.0.0",
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
},
{
"number": 2,
"name": "MappingDurchführen-1.0.0",
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
},
{
"number": 4,
"name": "MeLoIdentifizieren-1.0.0",
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
},
{
"number": 5,
"name": "FooAntwortSenden-1.0.0",
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
},
{
"number": 8,
"name": "MesslokationGeaendert-1.0.0",
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
},
{
"number": 9,
"name": "EigentuemerIdentifizieren-1.0.0",
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
},
{
"number": 10,
"name": "EigentuemerIdentifizieren-1.0.0",
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
},
{
"number": 12,
"name": "GeschaeftspartnerIdentifiziert-1.0.0",
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
},
{
"number": 13,
"name": "ProzessWartenBeendet-1.0.0",
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
},
{
"number": 14,
"name": "VertraegeAnBarSenden-1.0.0",
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
},
{
"number": 15,
"name": "VertraegeAnBarGesendet-1.0.0",
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
},
{
"number": 16,
"name": "VertragVonBarBestaetigtEvent-1.0.0",
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
},
{
"number": 17,
"name": "MarktdatenAnBarSenden-1.0.0",
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
},
{
"number": 18,
"name": "ProzessStatusGeändert-1.0.0",
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
}
]
21 changes: 21 additions & 0 deletions unittests/test_bss_client.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import json
import uuid
from pathlib import Path

import pytest
from aioresponses import aioresponses
from yarl import URL

from bssclient.client.bssclient import BasicAuthBssClient
from bssclient.client.config import BasicAuthBssConfig, OAuthBssConfig
from bssclient.models.events import EventHeader


@pytest.mark.parametrize(
Expand All @@ -27,3 +33,18 @@ def test_get_tld(actual_url: URL, expected_tld: URL):
def test_oauth_config():
with pytest.raises(ValueError):
OAuthBssConfig(server_url=URL("https://bss.example.com"), bearer_token="something-which-is-definittly no token")


async def test_get_events(bss_client_with_basic_auth, caplog) -> None:
client, bss_config = bss_client_with_basic_auth
random_guid = uuid.uuid4()
client.get_events("Prozess", random_guid)
stats_json_file = Path(__file__).parent / "example_data" / "prozess-events.json"
with open(stats_json_file, "r", encoding="utf-8") as infile:
response_body = json.load(infile)
with aioresponses() as mocked_bss:
mocked_get_url = f"{bss_config.server_url}api/Event/Prozess/{random_guid}"
mocked_bss.get(mocked_get_url, status=200, payload=response_body)
actual = await client.get_events("Prozess", random_guid)
assert all(isinstance(x, EventHeader) for x in actual)
assert any(m for m in caplog.messages if "There might be a problem with the deserialization" in m)

0 comments on commit e08187c

Please # to comment.