From 19b2bcc8beb757d9e7bd24925db891e3ad4bff86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Victor=20H=2E=20Garc=C3=ADa?= Date: Thu, 4 Jul 2024 16:40:55 -0600 Subject: [PATCH] Add support for sending event attachments --- app/conftest.py | 26 ++++++++++++++++++++++++- app/services/gundi.py | 15 ++++++++++++++ app/services/tests/test_gundi_api.py | 29 +++++++++++++++++++++++++++- requirements-base.in | 4 ++-- 4 files changed, 70 insertions(+), 4 deletions(-) diff --git a/app/conftest.py b/app/conftest.py index d16d171..8f62237 100644 --- a/app/conftest.py +++ b/app/conftest.py @@ -748,12 +748,20 @@ def mock_gundi_client_v2_class(mocker, mock_gundi_client_v2): @pytest.fixture -def mock_gundi_sensors_client_class(mocker, events_created_response, observations_created_response): +def mock_gundi_sensors_client_class( + mocker, + events_created_response, + event_attachment_created_response, + observations_created_response +): mock_gundi_sensors_client_class = mocker.MagicMock() mock_gundi_sensors_client = mocker.MagicMock() mock_gundi_sensors_client.post_events.return_value = async_return( events_created_response ) + mock_gundi_sensors_client.post_event_attachments.return_value = async_return( + event_attachment_created_response + ) mock_gundi_sensors_client.post_observations.return_value = async_return( observations_created_response ) @@ -795,6 +803,22 @@ def events_created_response(): ] +@pytest.fixture +def event_attachment_created_response(): + return [ + { + "object_id": "af8e2946-bad6-4d02-8a26-99dde34bd9fa", + "created_at": "2024-07-04T13:15:26.559894Z", + "updated_at": None + }, + { + "object_id": "gat51h73-dd71-dj88-91uh-jah7162hy6fs", + "created_at": "2024-07-03T13:15:26.559894Z", + "updated_at": None + } + ] + + @pytest.fixture def observations_created_response(): return [ diff --git a/app/services/gundi.py b/app/services/gundi.py index 4769617..531d0ad 100644 --- a/app/services/gundi.py +++ b/app/services/gundi.py @@ -51,6 +51,21 @@ async def send_events_to_gundi(events: List[dict], **kwargs) -> dict: return await sensors_api_client.post_events(data=events) +@stamina.retry(on=httpx.HTTPError, wait_initial=1.0, wait_jitter=5.0, wait_max=32.0) +async def send_event_attachments_to_gundi(event_id: str, attachments: List[bytes], **kwargs) -> dict: + """ + Send Event Attachments to Gundi using the REST API v2 + :param event_id: Created event in which the attachments are going to be linked + :param attachments: A list of attachments (in bytes) + :param kwargs: integration_id: The UUID of the related integration + :return: A dict with the response from the API + """ + integration_id = kwargs.get("integration_id") + assert integration_id, "integration_id is required" + sensors_api_client = await _get_sensors_api_client(integration_id=str(integration_id)) + return await sensors_api_client.post_event_attachments(event_id=event_id, attachments=attachments) + + @stamina.retry(on=httpx.HTTPError, wait_initial=1.0, wait_jitter=5.0, wait_max=32.0) async def send_observations_to_gundi(observations: List[dict], **kwargs) -> dict: """ diff --git a/app/services/tests/test_gundi_api.py b/app/services/tests/test_gundi_api.py index 8e9e165..eae577f 100644 --- a/app/services/tests/test_gundi_api.py +++ b/app/services/tests/test_gundi_api.py @@ -1,5 +1,5 @@ import pytest -from app.services.gundi import send_events_to_gundi, send_observations_to_gundi +from app.services.gundi import send_events_to_gundi, send_observations_to_gundi, send_event_attachments_to_gundi @pytest.mark.asyncio @@ -49,6 +49,33 @@ async def test_send_events_to_gundi( mock_gundi_sensors_client_class.return_value.post_events.assert_called_once_with(data=events) +@pytest.mark.asyncio +async def test_send_event_attachments_to_gundi( + mocker, mock_gundi_client_v2_class, mock_gundi_sensors_client_class, + mock_get_gundi_api_key, integration_v2 +): + mocker.patch("app.services.gundi.GundiClient", mock_gundi_client_v2_class) + mocker.patch("app.services.gundi.GundiDataSenderClient", mock_gundi_sensors_client_class) + mocker.patch("app.services.gundi._get_gundi_api_key", mock_get_gundi_api_key) + attachments = [ + b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x01\x00x\x00x\x00\x00\xff\xdb\x00C\x00\x02\x01\x01\x02', + b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x06\x01\x01\x00x\x00x\x01\x00\xff\xd5\x00C\x00\x98\x01\x01\x56' + ] + response = await send_event_attachments_to_gundi( + event_id="dummy-1234", + attachments=attachments, + integration_id=integration_v2.id + ) + + # Data is sent to gundi using the REST API for now + assert len(response) == 2 + assert mock_gundi_sensors_client_class.called + mock_gundi_sensors_client_class.return_value.post_event_attachments.assert_called_once_with( + event_id="dummy-1234", + attachments=attachments + ) + + @pytest.mark.asyncio async def test_send_observations_to_gundi( mocker, mock_gundi_client_v2_class, mock_gundi_sensors_client_class, diff --git a/requirements-base.in b/requirements-base.in index 649a08a..fd79276 100644 --- a/requirements-base.in +++ b/requirements-base.in @@ -4,8 +4,8 @@ environs~=9.5.0 pydantic~=1.10.15 fastapi~=0.103.2 uvicorn~=0.23.2 -gundi-core~=1.4.1 -gundi-client-v2~=2.3.0 +gundi-core~=1.5.0 +gundi-client-v2~=2.3.1 stamina~=23.2.0 redis~=5.0.1 gcloud-aio-pubsub~=6.0.0