fdc-shared-kernel 0.0.89__tar.gz → 0.0.91__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/PKG-INFO +1 -1
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/fdc_shared_kernel.egg-info/PKG-INFO +1 -1
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/fdc_shared_kernel.egg-info/SOURCES.txt +5 -1
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/fdc_shared_kernel.egg-info/top_level.txt +1 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/pyproject.toml +1 -1
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/event_executor/event_executor.py +2 -3
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/messaging/aws_databus.py +2 -1
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/messaging/utils/aws_utility.py +116 -3
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/messaging/utils/event_messages.py +1 -0
- fdc_shared_kernel-0.0.91/tests/__init__.py +3 -0
- fdc_shared_kernel-0.0.91/tests/messaging/__init__.py +3 -0
- fdc_shared_kernel-0.0.91/tests/messaging/utils/__init__.py +3 -0
- fdc_shared_kernel-0.0.91/tests/messaging/utils/test_aws_utility.py +247 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/README.md +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/README_pypi.md +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/fdc_shared_kernel.egg-info/dependency_links.txt +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/fdc_shared_kernel.egg-info/requires.txt +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/requirements.txt +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/setup.cfg +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/async_task_executor/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/async_task_executor/async_task_executor.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/auth/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/auth/jwt_helper.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/auth/token_handler.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/auth/workbook_permission_handler.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/config/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/database/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/datatype_mappings/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/datatype_mappings/connectors_to_system/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/datatype_mappings/connectors_to_system/csv.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/datatype_mappings/connectors_to_system/db2.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/datatype_mappings/connectors_to_system/jira.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/datatype_mappings/connectors_to_system/mssql.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/datatype_mappings/connectors_to_system/mysql.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/datatype_mappings/connectors_to_system/oracle.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/datatype_mappings/connectors_to_system/postgres.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/datatype_mappings/connectors_to_system/redshift.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/datatype_mappings/connectors_to_system/salesforce.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/datatype_mappings/system_to_warehouse/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/datatype_mappings/system_to_warehouse/postgres.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/datatype_mappings/system_to_warehouse/redshift.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/enums/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/enums/async_task_executor.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/enums/status_tracker.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/event_executor/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/event_executor/utils.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/exceptions/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/exceptions/configuration_exceptions.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/exceptions/custom_exceptions.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/exceptions/data_validation_exceptions.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/exceptions/http_exceptions.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/exceptions/infrastructure_exceptions.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/exceptions/operational_exceptions.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/exceptions/security_exceptions.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/http/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/http/httpx_http_client.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/http/request_http_client.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/interfaces/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/interfaces/databus.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/interfaces/http.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/interfaces/keyvault.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/logger/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/messaging/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/messaging/http_databus.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/messaging/nats_databus.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/messaging/nats_publisher.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/messaging/nats_test.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/metrics/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/metrics/status_tracker.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/models/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/registries/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/registries/service_event_registry.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/security/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/security/key_vault/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/security/key_vault/aws_secret_manager.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/security/key_vault/azure_keyvault.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/status_tracker/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/status_tracker/status_tracker.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/tests/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/tests/config/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/tests/config/test_config.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/tests/logger/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/tests/logger/test_logger.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/tests/messaging/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/tests/messaging/test_aws_databus.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/tests/messaging/test_event_executor.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/tests/messaging/test_nats_interface.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/tests/utils/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/tests/utils/test_data_validators.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/tests/utils/test_date_format_utils.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/tests/utils/test_string_utils.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/utils/__init__.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/utils/data_validators_utils.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/utils/date_format_utils.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/utils/string_utils.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/utils/template_renderer.py +0 -0
- {fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/utils/thread_local_util.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fdc_shared_kernel
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.91
|
|
4
4
|
Summary: Shared library for microservice
|
|
5
5
|
Author-email: Shikhil S <shikhil.s@dbizsolution.com>, Ahammed Akdham N <ahammedakdham.n@dbizsolution.com>
|
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fdc_shared_kernel
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.91
|
|
4
4
|
Summary: Shared library for microservice
|
|
5
5
|
Author-email: Shikhil S <shikhil.s@dbizsolution.com>, Ahammed Akdham N <ahammedakdham.n@dbizsolution.com>
|
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/fdc_shared_kernel.egg-info/SOURCES.txt
RENAMED
|
@@ -89,4 +89,8 @@ shared_kernel/utils/data_validators_utils.py
|
|
|
89
89
|
shared_kernel/utils/date_format_utils.py
|
|
90
90
|
shared_kernel/utils/string_utils.py
|
|
91
91
|
shared_kernel/utils/template_renderer.py
|
|
92
|
-
shared_kernel/utils/thread_local_util.py
|
|
92
|
+
shared_kernel/utils/thread_local_util.py
|
|
93
|
+
tests/__init__.py
|
|
94
|
+
tests/messaging/__init__.py
|
|
95
|
+
tests/messaging/utils/__init__.py
|
|
96
|
+
tests/messaging/utils/test_aws_utility.py
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/event_executor/event_executor.py
RENAMED
|
@@ -206,7 +206,7 @@ class EventExecutor:
|
|
|
206
206
|
else:
|
|
207
207
|
self._stats[event_name].failed_events += 1
|
|
208
208
|
|
|
209
|
-
def _callback_wrapper(self, callback: Callable[[Any], None],
|
|
209
|
+
def _callback_wrapper(self, callback: Callable[[Any], None], event_msg: AWSEventMessage) -> None:
|
|
210
210
|
"""
|
|
211
211
|
Wrapper around message processing to handle cleanup and status updates.
|
|
212
212
|
"""
|
|
@@ -214,8 +214,7 @@ class EventExecutor:
|
|
|
214
214
|
event_name = None
|
|
215
215
|
|
|
216
216
|
try:
|
|
217
|
-
logger.info(f"Initiating callback for message: {
|
|
218
|
-
event_msg = AWSEventMessage(message)
|
|
217
|
+
logger.info(f"Initiating callback for message: {event_msg}")
|
|
219
218
|
event_name = event_msg.event_name
|
|
220
219
|
|
|
221
220
|
# Set thread-local context
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/messaging/aws_databus.py
RENAMED
|
@@ -120,7 +120,8 @@ class AWSDataBus(DataBus):
|
|
|
120
120
|
def get_async_message(self, event_name):
|
|
121
121
|
queue = self.event_queue_mapper[event_name]
|
|
122
122
|
# get_message_from_queue should be blocking
|
|
123
|
-
message = self.aws_utility.
|
|
123
|
+
message = self.aws_utility.recieve_event(queue)
|
|
124
|
+
# message = self.aws_utility.get_message_from_queue(queue)
|
|
124
125
|
return message
|
|
125
126
|
|
|
126
127
|
def delete_message(self, message: AWSEventMessage):
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/messaging/utils/aws_utility.py
RENAMED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import json
|
|
2
2
|
from typing import Dict, Optional, Union
|
|
3
|
+
import uuid
|
|
3
4
|
|
|
4
5
|
import boto3
|
|
5
6
|
from botocore.exceptions import ClientError
|
|
6
7
|
|
|
7
8
|
from shared_kernel.config import Config
|
|
8
9
|
from shared_kernel.logger import Logger
|
|
9
|
-
from shared_kernel.messaging.utils.event_messages import PublishEventMessage
|
|
10
|
+
from shared_kernel.messaging.utils.event_messages import AWSEventMessage, PublishEventMessage
|
|
10
11
|
|
|
11
12
|
app_config = Config()
|
|
12
13
|
logger = Logger(app_config.get("APP_NAME"))
|
|
@@ -29,11 +30,13 @@ class AWSMessagingUtility:
|
|
|
29
30
|
def __init__(self):
|
|
30
31
|
self.event_bridge = boto3.client("events")
|
|
31
32
|
self.sqs = boto3.client("sqs")
|
|
33
|
+
self.s3 = boto3.client("s3")
|
|
32
34
|
self.event_bus_name = app_config.get("EVENT_BUS_NAME")
|
|
33
35
|
self.service_name = app_config.get("APP_NAME")
|
|
34
36
|
self.account_id = app_config.get("ACCOUNT_ID")
|
|
35
37
|
self.region = app_config.get("AWS_REGION")
|
|
36
38
|
self.queue_visiblity_timeout = app_config.get("QUEUE_VISIBLITY_TIMEOUT")
|
|
39
|
+
self.s3_bucket = app_config.get("AWS_EVENT_PAYLOAD_BUCKET")
|
|
37
40
|
|
|
38
41
|
def create_queue(self, event_name: str) -> AWSQueue:
|
|
39
42
|
"""
|
|
@@ -216,6 +219,49 @@ class AWSMessagingUtility:
|
|
|
216
219
|
f"Message deleted from queue with receipt handle '{receipt_handle}'."
|
|
217
220
|
)
|
|
218
221
|
|
|
222
|
+
def _check_payload_size(self, json_payload: str) -> bool:
|
|
223
|
+
"""
|
|
224
|
+
Check if the payload size exceeds 256 KB.
|
|
225
|
+
|
|
226
|
+
Args:
|
|
227
|
+
json_payload (str): The JSON payload to check
|
|
228
|
+
|
|
229
|
+
Returns:
|
|
230
|
+
bool: True if payload size exceeds 256 KB, False otherwise
|
|
231
|
+
"""
|
|
232
|
+
return len(json_payload.encode('utf-8')) > 262144 # 256 KB in bytes
|
|
233
|
+
|
|
234
|
+
def _upload_payload_to_s3(self, json_payload: str) -> str:
|
|
235
|
+
"""
|
|
236
|
+
Upload large payload to S3 and return the S3 path.
|
|
237
|
+
|
|
238
|
+
Args:
|
|
239
|
+
json_payload (str): The JSON payload to upload
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
str: The S3 path where the payload is stored
|
|
243
|
+
"""
|
|
244
|
+
try:
|
|
245
|
+
# Generate a unique filename using UUID
|
|
246
|
+
file_name = f"event_payload/{str(uuid.uuid4())}.txt"
|
|
247
|
+
|
|
248
|
+
# Upload to S3
|
|
249
|
+
self.s3.put_object(
|
|
250
|
+
Bucket=self.s3_bucket,
|
|
251
|
+
Key=file_name,
|
|
252
|
+
Body=json_payload,
|
|
253
|
+
ContentType='application/json'
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
# Return the S3 path
|
|
257
|
+
s3_path = f"s3://{self.s3_bucket}/{file_name}"
|
|
258
|
+
logger.info(f"Uploaded large payload to S3: {s3_path}")
|
|
259
|
+
return s3_path
|
|
260
|
+
|
|
261
|
+
except Exception as e:
|
|
262
|
+
logger.error(f"Failed to upload payload to S3: {e}")
|
|
263
|
+
raise
|
|
264
|
+
|
|
219
265
|
def publish_event(self, event_name: str, event_payload: dict) -> Union[bool, Optional[dict]]:
|
|
220
266
|
"""
|
|
221
267
|
Publish an event to EventBridge.
|
|
@@ -227,12 +273,26 @@ class AWSMessagingUtility:
|
|
|
227
273
|
"""
|
|
228
274
|
try:
|
|
229
275
|
publish_message = PublishEventMessage(event_payload)
|
|
276
|
+
json_payload = publish_message.to_json()
|
|
277
|
+
|
|
278
|
+
# Check if payload size exceeds 256 KB
|
|
279
|
+
if self._check_payload_size(json_payload):
|
|
280
|
+
# Upload to S3 and get the path
|
|
281
|
+
s3_path = self._upload_payload_to_s3(json_payload)
|
|
282
|
+
|
|
283
|
+
# Replace the payload with the S3 path and remove event_payload
|
|
284
|
+
event_payload['event_payload_path'] = s3_path
|
|
285
|
+
del event_payload['event_payload']
|
|
286
|
+
publish_message = PublishEventMessage(event_payload)
|
|
287
|
+
json_payload = publish_message.to_json()
|
|
288
|
+
logger.warning(f"Event payload size exceeded 256 KB limit. Using S3 path: {s3_path}")
|
|
289
|
+
|
|
230
290
|
response: dict = self.event_bridge.put_events(
|
|
231
291
|
Entries=[
|
|
232
292
|
{
|
|
233
293
|
"Source": self.service_name,
|
|
234
294
|
"DetailType": event_name,
|
|
235
|
-
"Detail":
|
|
295
|
+
"Detail": json_payload,
|
|
236
296
|
"EventBusName": self.event_bus_name,
|
|
237
297
|
}
|
|
238
298
|
]
|
|
@@ -256,7 +316,60 @@ class AWSMessagingUtility:
|
|
|
256
316
|
except Exception as e:
|
|
257
317
|
logger.error(f"Failed to publish event: {e}")
|
|
258
318
|
return False, None
|
|
259
|
-
|
|
319
|
+
|
|
320
|
+
def _get_payload_from_s3(self, s3_path: str) -> str:
|
|
321
|
+
"""
|
|
322
|
+
Retrieve and decode payload from S3 bucket.
|
|
323
|
+
|
|
324
|
+
Args:
|
|
325
|
+
s3_path (str): The S3 path where the payload is stored
|
|
326
|
+
|
|
327
|
+
Returns:
|
|
328
|
+
str: The decoded payload content
|
|
329
|
+
|
|
330
|
+
Raises:
|
|
331
|
+
ClientError: If there's an error accessing the S3 bucket
|
|
332
|
+
ValueError: If the S3 path is invalid
|
|
333
|
+
"""
|
|
334
|
+
try:
|
|
335
|
+
# Extract bucket and key from s3:// path
|
|
336
|
+
if not s3_path.startswith('s3://'):
|
|
337
|
+
raise ValueError(f"Invalid S3 path format: {s3_path}")
|
|
338
|
+
|
|
339
|
+
path_parts = s3_path.replace('s3://', '').split('/', 1)
|
|
340
|
+
if len(path_parts) != 2:
|
|
341
|
+
raise ValueError(f"Invalid S3 path format: {s3_path}")
|
|
342
|
+
|
|
343
|
+
bucket, key = path_parts
|
|
344
|
+
|
|
345
|
+
s3_object = self.s3.get_object(Bucket=bucket, Key=key)
|
|
346
|
+
return s3_object["Body"].read().decode("utf-8")
|
|
347
|
+
|
|
348
|
+
except ClientError as e:
|
|
349
|
+
logger.error(f"Failed to retrieve payload from S3: {e}")
|
|
350
|
+
raise
|
|
351
|
+
except Exception as e:
|
|
352
|
+
logger.error(f"Unexpected error while retrieving payload from S3: {e}")
|
|
353
|
+
raise
|
|
354
|
+
|
|
355
|
+
def recieve_event(self, queue):
|
|
356
|
+
"""
|
|
357
|
+
Receive and process an event from the queue, handling both direct payloads and S3-stored payloads.
|
|
358
|
+
|
|
359
|
+
Args:
|
|
360
|
+
queue (AWSQueue): The queue to receive the message from
|
|
361
|
+
|
|
362
|
+
Returns:
|
|
363
|
+
AWSEventMessage: The processed event message
|
|
364
|
+
"""
|
|
365
|
+
deserialized_message = self.get_message_from_queue(queue)
|
|
366
|
+
event_msg = AWSEventMessage(deserialized_message)
|
|
367
|
+
|
|
368
|
+
if event_msg.event_payload_path:
|
|
369
|
+
event_msg.event_payload = json.loads(self._get_payload_from_s3(event_msg.event_payload_path))["event_payload"]
|
|
370
|
+
|
|
371
|
+
return event_msg
|
|
372
|
+
|
|
260
373
|
def get_queue_url_arn(self, event_name: str) -> dict:
|
|
261
374
|
queue_name = f"{self.service_name}-{event_name}"
|
|
262
375
|
queue_arn = f"arn:aws:sqs:{self.region}:{self.account_id}:{queue_name}"
|
|
@@ -158,6 +158,7 @@ class EventMessage:
|
|
|
158
158
|
# event payload will contain entity_id, connector_id and other info
|
|
159
159
|
# needed for specific events
|
|
160
160
|
self.event_payload: dict = raw_message.get("event_payload", {})
|
|
161
|
+
self.event_payload_path = raw_message.get("event_payload_path", False)
|
|
161
162
|
|
|
162
163
|
# initialize EventMeta object
|
|
163
164
|
self.event_meta = EventMeta(raw_message.get("event_meta", {}))
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import pytest
|
|
3
|
+
from unittest.mock import patch, MagicMock
|
|
4
|
+
from moto.sqs import mock_sqs
|
|
5
|
+
from moto.events import mock_events
|
|
6
|
+
from moto.s3 import mock_s3
|
|
7
|
+
import boto3
|
|
8
|
+
|
|
9
|
+
from shared_kernel.messaging.utils.aws_utility import AWSMessagingUtility, AWSQueue
|
|
10
|
+
from shared_kernel.messaging.utils.event_messages import AWSEventMessage, PublishEventMessage
|
|
11
|
+
|
|
12
|
+
@pytest.fixture
|
|
13
|
+
def aws_utility():
|
|
14
|
+
mock_config = MagicMock()
|
|
15
|
+
mock_config.get.side_effect = lambda key: {
|
|
16
|
+
"APP_NAME": "test-app",
|
|
17
|
+
"EVENT_BUS_NAME": "test-bus",
|
|
18
|
+
"ACCOUNT_ID": "123456789012",
|
|
19
|
+
"AWS_REGION": "us-east-1",
|
|
20
|
+
"QUEUE_VISIBLITY_TIMEOUT": "30",
|
|
21
|
+
"AWS_EVENT_PAYLOAD_BUCKET": "test-bucket"
|
|
22
|
+
}[key]
|
|
23
|
+
|
|
24
|
+
with patch('shared_kernel.messaging.utils.aws_utility.app_config', mock_config):
|
|
25
|
+
utility = AWSMessagingUtility()
|
|
26
|
+
return utility
|
|
27
|
+
|
|
28
|
+
@pytest.fixture
|
|
29
|
+
def sample_event_payload():
|
|
30
|
+
return {
|
|
31
|
+
"event_name": "test-event",
|
|
32
|
+
"event_id": "test-event-id",
|
|
33
|
+
"event_payload": {"key": "value"},
|
|
34
|
+
"event_meta": {
|
|
35
|
+
"trace_id": "test-trace-id",
|
|
36
|
+
"span_id": "test-span-id",
|
|
37
|
+
"timestamp": "2024-04-17T13:54:14.479Z"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@pytest.fixture
|
|
42
|
+
def setup_s3(aws_utility):
|
|
43
|
+
with mock_s3():
|
|
44
|
+
s3 = boto3.client('s3', region_name='us-east-1')
|
|
45
|
+
s3.create_bucket(Bucket='test-bucket')
|
|
46
|
+
yield s3
|
|
47
|
+
|
|
48
|
+
@pytest.fixture
|
|
49
|
+
def setup_sqs(aws_utility):
|
|
50
|
+
with mock_sqs():
|
|
51
|
+
sqs = boto3.client('sqs', region_name='us-east-1')
|
|
52
|
+
yield sqs
|
|
53
|
+
|
|
54
|
+
@pytest.fixture
|
|
55
|
+
def setup_events(aws_utility):
|
|
56
|
+
with mock_events():
|
|
57
|
+
events = boto3.client('events', region_name='us-east-1')
|
|
58
|
+
events.create_event_bus(Name='test-bus')
|
|
59
|
+
yield events
|
|
60
|
+
|
|
61
|
+
class TestAWSQueue:
|
|
62
|
+
def test_aws_queue_initialization(self):
|
|
63
|
+
queue = AWSQueue("test-arn", "test-url", "test-event")
|
|
64
|
+
assert queue.arn == "test-arn"
|
|
65
|
+
assert queue.url == "test-url"
|
|
66
|
+
assert queue.event_name == "test-event"
|
|
67
|
+
|
|
68
|
+
def test_aws_queue_is_valid(self):
|
|
69
|
+
valid_queue = AWSQueue("test-arn", "test-url", "test-event")
|
|
70
|
+
assert valid_queue.is_valid()
|
|
71
|
+
|
|
72
|
+
invalid_queue = AWSQueue(None, "test-url", "test-event")
|
|
73
|
+
assert not invalid_queue.is_valid()
|
|
74
|
+
|
|
75
|
+
invalid_queue = AWSQueue("test-arn", None, "test-event")
|
|
76
|
+
assert not invalid_queue.is_valid()
|
|
77
|
+
|
|
78
|
+
class TestQueueOperations:
|
|
79
|
+
def test_create_queue(self, aws_utility, setup_sqs):
|
|
80
|
+
queue = aws_utility.create_queue("test-event")
|
|
81
|
+
assert isinstance(queue, AWSQueue)
|
|
82
|
+
assert queue.event_name == "test-event"
|
|
83
|
+
assert "test-app-test-event" in queue.url
|
|
84
|
+
|
|
85
|
+
def test_get_queue(self, aws_utility, setup_sqs):
|
|
86
|
+
# First create a queue
|
|
87
|
+
created_queue = aws_utility.create_queue("test-event")
|
|
88
|
+
# Then get it
|
|
89
|
+
queue = aws_utility.get_queue("test-event")
|
|
90
|
+
assert queue.url == created_queue.url
|
|
91
|
+
assert queue.arn == created_queue.arn
|
|
92
|
+
|
|
93
|
+
def test_check_if_queue_exist(self, aws_utility, setup_sqs):
|
|
94
|
+
# Queue doesn't exist initially
|
|
95
|
+
assert aws_utility.check_if_queue_exist("test-event") is False
|
|
96
|
+
|
|
97
|
+
# Create queue
|
|
98
|
+
aws_utility.create_queue("test-event")
|
|
99
|
+
assert aws_utility.check_if_queue_exist("test-event") is True
|
|
100
|
+
|
|
101
|
+
def test_check_and_update_queue_config(self, aws_utility, setup_sqs):
|
|
102
|
+
queue = aws_utility.create_queue("test-event")
|
|
103
|
+
aws_utility.check_and_update_queue_config(queue)
|
|
104
|
+
# No assertion needed as we're just ensuring no exceptions are raised
|
|
105
|
+
|
|
106
|
+
class TestEventBridgeOperations:
|
|
107
|
+
def test_add_event_bridge_rule(self, aws_utility, setup_sqs, setup_events):
|
|
108
|
+
queue = aws_utility.create_queue("test-event")
|
|
109
|
+
aws_utility.add_event_bridge_rule(queue)
|
|
110
|
+
# Verify rule was created by checking if we can get it
|
|
111
|
+
rules = aws_utility.event_bridge.list_rules(EventBusName='test-bus', NamePrefix="test-event_rule")
|
|
112
|
+
assert len(rules['Rules']) == 1
|
|
113
|
+
rule = rules['Rules'][0]
|
|
114
|
+
assert rule['Name'] == "test-event_rule"
|
|
115
|
+
assert rule['State'] == "ENABLED"
|
|
116
|
+
|
|
117
|
+
def test_publish_event_success(self, aws_utility, setup_events, sample_event_payload):
|
|
118
|
+
success, result = aws_utility.publish_event("test-event", sample_event_payload)
|
|
119
|
+
assert success is True
|
|
120
|
+
assert result is not None
|
|
121
|
+
|
|
122
|
+
def test_publish_event_failure(self, aws_utility):
|
|
123
|
+
with patch('boto3.client') as mock_client:
|
|
124
|
+
mock_client.return_value.put_events.return_value = {
|
|
125
|
+
"FailedEntryCount": 1,
|
|
126
|
+
"Entries": [{"ErrorMessage": "Test error"}]
|
|
127
|
+
}
|
|
128
|
+
success, result = aws_utility.publish_event("test-event", {})
|
|
129
|
+
assert success is False
|
|
130
|
+
assert result is None
|
|
131
|
+
|
|
132
|
+
class TestS3Operations:
|
|
133
|
+
def test_check_payload_size(self, aws_utility):
|
|
134
|
+
small_payload = json.dumps({"key": "value"})
|
|
135
|
+
large_payload = json.dumps({"key": "x" * 300000}) # > 256KB
|
|
136
|
+
|
|
137
|
+
assert aws_utility._check_payload_size(small_payload) is False
|
|
138
|
+
assert aws_utility._check_payload_size(large_payload) is True
|
|
139
|
+
|
|
140
|
+
def test_upload_payload_to_s3(self, aws_utility, setup_s3):
|
|
141
|
+
payload = json.dumps({"key": "value"})
|
|
142
|
+
s3_path = aws_utility._upload_payload_to_s3(payload)
|
|
143
|
+
|
|
144
|
+
assert s3_path.startswith("s3://")
|
|
145
|
+
assert aws_utility.s3_bucket in s3_path
|
|
146
|
+
|
|
147
|
+
def test_get_payload_from_s3(self, aws_utility, setup_s3):
|
|
148
|
+
# First upload a payload
|
|
149
|
+
original_payload = json.dumps({"key": "value"})
|
|
150
|
+
s3_path = aws_utility._upload_payload_to_s3(original_payload)
|
|
151
|
+
|
|
152
|
+
# Then retrieve it
|
|
153
|
+
retrieved_payload = aws_utility._get_payload_from_s3(s3_path)
|
|
154
|
+
assert retrieved_payload == original_payload
|
|
155
|
+
|
|
156
|
+
def test_get_payload_from_s3_invalid_path(self, aws_utility):
|
|
157
|
+
with pytest.raises(ValueError):
|
|
158
|
+
aws_utility._get_payload_from_s3("invalid-path")
|
|
159
|
+
|
|
160
|
+
class TestMessageOperations:
|
|
161
|
+
def test_get_message_from_queue(self, aws_utility, setup_sqs):
|
|
162
|
+
queue = aws_utility.create_queue("test-event")
|
|
163
|
+
# Send a message to the queue
|
|
164
|
+
aws_utility.sqs.send_message(
|
|
165
|
+
QueueUrl=queue.url,
|
|
166
|
+
MessageBody=json.dumps({"test": "message"})
|
|
167
|
+
)
|
|
168
|
+
message = aws_utility.get_message_from_queue(queue)
|
|
169
|
+
assert message is not None
|
|
170
|
+
assert "test" in json.loads(message["Body"])
|
|
171
|
+
|
|
172
|
+
def test_delete_message_from_queue(self, aws_utility, setup_sqs):
|
|
173
|
+
queue = aws_utility.create_queue("test-event")
|
|
174
|
+
# Send and receive a message
|
|
175
|
+
aws_utility.sqs.send_message(
|
|
176
|
+
QueueUrl=queue.url,
|
|
177
|
+
MessageBody=json.dumps({"test": "message"})
|
|
178
|
+
)
|
|
179
|
+
message = aws_utility.get_message_from_queue(queue)
|
|
180
|
+
# Delete the message
|
|
181
|
+
aws_utility.delete_message_from_queue(queue, message["ReceiptHandle"])
|
|
182
|
+
# Try to receive messages again, should be empty
|
|
183
|
+
response = aws_utility.sqs.receive_message(QueueUrl=queue.url)
|
|
184
|
+
assert "Messages" not in response
|
|
185
|
+
|
|
186
|
+
def test_recieve_event_with_direct_payload(self, aws_utility, setup_sqs):
|
|
187
|
+
queue = aws_utility.create_queue("test-event")
|
|
188
|
+
# Send a message with the correct event structure
|
|
189
|
+
aws_utility.sqs.send_message(
|
|
190
|
+
QueueUrl=queue.url,
|
|
191
|
+
MessageBody=json.dumps({
|
|
192
|
+
"detail": {
|
|
193
|
+
"event_name": "test-event",
|
|
194
|
+
"event_payload": "test",
|
|
195
|
+
"metadata": {
|
|
196
|
+
"trace_id": "test-trace-id",
|
|
197
|
+
"timestamp": "2024-04-17T13:54:14.479Z"
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
})
|
|
201
|
+
)
|
|
202
|
+
event_msg = aws_utility.recieve_event(queue)
|
|
203
|
+
assert event_msg is not None
|
|
204
|
+
assert event_msg.event_name == "test-event"
|
|
205
|
+
assert event_msg.event_payload == "test"
|
|
206
|
+
|
|
207
|
+
def test_recieve_event_with_s3_payload(self, aws_utility, setup_sqs, setup_s3):
|
|
208
|
+
queue = aws_utility.create_queue("test-event")
|
|
209
|
+
# Upload payload to S3 with proper JSON format
|
|
210
|
+
payload = json.dumps({"event_payload": "test payload"})
|
|
211
|
+
s3_path = aws_utility._upload_payload_to_s3(payload)
|
|
212
|
+
# Send a message with S3 path
|
|
213
|
+
aws_utility.sqs.send_message(
|
|
214
|
+
QueueUrl=queue.url,
|
|
215
|
+
MessageBody=json.dumps({
|
|
216
|
+
"detail": {
|
|
217
|
+
"event_name": "test-event",
|
|
218
|
+
"event_payload_path": s3_path,
|
|
219
|
+
"event_meta": {
|
|
220
|
+
"trace_id": "test-trace-id",
|
|
221
|
+
"span_id": "test-span-id",
|
|
222
|
+
"timestamp": "2024-04-17T13:54:14.479Z"
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
})
|
|
226
|
+
)
|
|
227
|
+
event_msg = aws_utility.recieve_event(queue)
|
|
228
|
+
assert event_msg.event_payload == "test payload"
|
|
229
|
+
|
|
230
|
+
def test_update_visibility_timeout(self, aws_utility, setup_sqs):
|
|
231
|
+
queue = aws_utility.create_queue("test-event")
|
|
232
|
+
# Send and receive a message
|
|
233
|
+
aws_utility.sqs.send_message(
|
|
234
|
+
QueueUrl=queue.url,
|
|
235
|
+
MessageBody=json.dumps({"test": "message"})
|
|
236
|
+
)
|
|
237
|
+
message = aws_utility.get_message_from_queue(queue)
|
|
238
|
+
# Update visibility timeout
|
|
239
|
+
aws_utility.update_visibility_timeout(queue.url, message["ReceiptHandle"], 30)
|
|
240
|
+
# No assertion needed as we're just ensuring no exceptions are raised
|
|
241
|
+
|
|
242
|
+
def test_get_queue_url_arn(self, aws_utility):
|
|
243
|
+
result = aws_utility.get_queue_url_arn("test-event")
|
|
244
|
+
assert "queue_arn" in result
|
|
245
|
+
assert "queue_url" in result
|
|
246
|
+
assert "test-event" in result["queue_arn"]
|
|
247
|
+
assert "test-event" in result["queue_url"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/fdc_shared_kernel.egg-info/requires.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/async_task_executor/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/datatype_mappings/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/enums/async_task_executor.py
RENAMED
|
File without changes
|
|
File without changes
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/event_executor/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/exceptions/custom_exceptions.py
RENAMED
|
File without changes
|
|
File without changes
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/exceptions/http_exceptions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/http/httpx_http_client.py
RENAMED
|
File without changes
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/http/request_http_client.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/messaging/http_databus.py
RENAMED
|
File without changes
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/messaging/nats_databus.py
RENAMED
|
File without changes
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/messaging/nats_publisher.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/metrics/status_tracker.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/security/key_vault/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/status_tracker/__init__.py
RENAMED
|
File without changes
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/status_tracker/status_tracker.py
RENAMED
|
File without changes
|
|
File without changes
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/tests/config/__init__.py
RENAMED
|
File without changes
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/tests/config/test_config.py
RENAMED
|
File without changes
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/tests/logger/__init__.py
RENAMED
|
File without changes
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/tests/logger/test_logger.py
RENAMED
|
File without changes
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/tests/messaging/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/tests/utils/test_string_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/utils/data_validators_utils.py
RENAMED
|
File without changes
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/utils/date_format_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/utils/template_renderer.py
RENAMED
|
File without changes
|
{fdc_shared_kernel-0.0.89 → fdc_shared_kernel-0.0.91}/shared_kernel/utils/thread_local_util.py
RENAMED
|
File without changes
|