Skip to content

Commit e08187c

Browse files
hf-kkleinKonstantin
and
Konstantin
authored
feat: add method to download events from Event Controller (#140)
* feat: add method to download events from Event Controller * pylint/caplog --------- Co-authored-by: Konstantin <[email protected]>
1 parent 87dfd80 commit e08187c

File tree

4 files changed

+152
-0
lines changed

4 files changed

+152
-0
lines changed

src/bssclient/client/bssclient.py

+20
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from bssclient.client.oauth import _OAuthHttpClient, token_is_valid
1515
from bssclient.models.aufgabe import AufgabeStats
1616
from bssclient.models.ermittlungsauftrag import Ermittlungsauftrag, _ListOfErmittlungsauftraege
17+
from bssclient.models.events import EventHeader, EventHeaders
1718

1819
_logger = logging.getLogger(__name__)
1920

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

160+
async def get_events(self, model_type: DomainModelType, model_id: uuid.UUID) -> list[EventHeader]:
161+
"""reads event headers from bss API"""
162+
session = await self._get_session()
163+
request_url = self._config.server_url / "api" / "Event" / model_type / str(model_id)
164+
request_uuid = uuid.uuid4()
165+
_logger.debug("[%s] requesting %s", str(request_uuid), request_url)
166+
async with session.get(request_url) as response:
167+
_logger.debug("[%s] response status: %s", str(request_uuid), response.status)
168+
response_body = await response.json()
169+
result = EventHeaders.model_validate(response_body)
170+
if not result.is_continuous:
171+
_logger.warning(
172+
"The events for %s-%s are NOT continuous. There might be a problem with the deserialization",
173+
model_type,
174+
model_id,
175+
)
176+
_logger.debug("Read %i events from Aggregate %s-%s", len(result.root), model_type, model_id)
177+
return result.root
178+
159179
async def replay_event(self, model_type: DomainModelType, model_id: uuid.UUID, event_number: int) -> bool:
160180
"""calls the re-apply endpoint"""
161181
session = await self._get_session()

src/bssclient/models/events.py

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
"""
2+
models for the event controller
3+
"""
4+
5+
from itertools import pairwise
6+
from uuid import UUID
7+
8+
from pydantic import BaseModel, RootModel
9+
10+
11+
class EventHeader(BaseModel):
12+
"""
13+
model returned by /api/Event/prozess/<id goes here>
14+
"""
15+
16+
number: int
17+
name: str
18+
id: UUID
19+
20+
21+
class EventHeaders(RootModel[list[EventHeader]]):
22+
"""wrapper around a list of EventHeaders"""
23+
24+
@property
25+
def is_continuous(self) -> bool:
26+
"""
27+
returns true iff all event numbers are continuous.
28+
a gap like: 1,2,3,5 indicates that there is a problem with the event at position 4
29+
"""
30+
number_pairs = pairwise(sorted((x.number for x in self.root)))
31+
return all(abs(x - y) == 1 for x, y in number_pairs)
32+
33+
34+
__all__ = ["EventHeader", "EventHeaders"]
+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
[
2+
{
3+
"number": 0,
4+
"name": "ProzessErzeugt-1.0.0",
5+
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
6+
},
7+
{
8+
"number": 1,
9+
"name": "FooXMLEmpfangen-1.0.0",
10+
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
11+
},
12+
{
13+
"number": 2,
14+
"name": "MappingDurchführen-1.0.0",
15+
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
16+
},
17+
{
18+
"number": 4,
19+
"name": "MeLoIdentifizieren-1.0.0",
20+
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
21+
},
22+
{
23+
"number": 5,
24+
"name": "FooAntwortSenden-1.0.0",
25+
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
26+
},
27+
{
28+
"number": 8,
29+
"name": "MesslokationGeaendert-1.0.0",
30+
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
31+
},
32+
{
33+
"number": 9,
34+
"name": "EigentuemerIdentifizieren-1.0.0",
35+
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
36+
},
37+
{
38+
"number": 10,
39+
"name": "EigentuemerIdentifizieren-1.0.0",
40+
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
41+
},
42+
{
43+
"number": 12,
44+
"name": "GeschaeftspartnerIdentifiziert-1.0.0",
45+
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
46+
},
47+
{
48+
"number": 13,
49+
"name": "ProzessWartenBeendet-1.0.0",
50+
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
51+
},
52+
{
53+
"number": 14,
54+
"name": "VertraegeAnBarSenden-1.0.0",
55+
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
56+
},
57+
{
58+
"number": 15,
59+
"name": "VertraegeAnBarGesendet-1.0.0",
60+
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
61+
},
62+
{
63+
"number": 16,
64+
"name": "VertragVonBarBestaetigtEvent-1.0.0",
65+
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
66+
},
67+
{
68+
"number": 17,
69+
"name": "MarktdatenAnBarSenden-1.0.0",
70+
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
71+
},
72+
{
73+
"number": 18,
74+
"name": "ProzessStatusGeändert-1.0.0",
75+
"id": "d7e40c6e-c7ae-4ef5-b821-aa55fe085909"
76+
}
77+
]

unittests/test_bss_client.py

+21
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1+
import json
2+
import uuid
3+
from pathlib import Path
4+
15
import pytest
6+
from aioresponses import aioresponses
27
from yarl import URL
38

49
from bssclient.client.bssclient import BasicAuthBssClient
510
from bssclient.client.config import BasicAuthBssConfig, OAuthBssConfig
11+
from bssclient.models.events import EventHeader
612

713

814
@pytest.mark.parametrize(
@@ -27,3 +33,18 @@ def test_get_tld(actual_url: URL, expected_tld: URL):
2733
def test_oauth_config():
2834
with pytest.raises(ValueError):
2935
OAuthBssConfig(server_url=URL("https://bss.example.com"), bearer_token="something-which-is-definittly no token")
36+
37+
38+
async def test_get_events(bss_client_with_basic_auth, caplog) -> None:
39+
client, bss_config = bss_client_with_basic_auth
40+
random_guid = uuid.uuid4()
41+
client.get_events("Prozess", random_guid)
42+
stats_json_file = Path(__file__).parent / "example_data" / "prozess-events.json"
43+
with open(stats_json_file, "r", encoding="utf-8") as infile:
44+
response_body = json.load(infile)
45+
with aioresponses() as mocked_bss:
46+
mocked_get_url = f"{bss_config.server_url}api/Event/Prozess/{random_guid}"
47+
mocked_bss.get(mocked_get_url, status=200, payload=response_body)
48+
actual = await client.get_events("Prozess", random_guid)
49+
assert all(isinstance(x, EventHeader) for x in actual)
50+
assert any(m for m in caplog.messages if "There might be a problem with the deserialization" in m)

0 commit comments

Comments
 (0)