SIENTIAPDE-1163

refactor: update MongoDB notification IDs for error handling in activities; add tests for error scenarios in MongoDB and TemporalManager activities to ensure proper notification sending on failures
This commit is contained in:
vitor-aignosi
2025-07-16 15:18:49 -03:00
parent b67d23da1f
commit d60062af74
5 changed files with 164 additions and 165 deletions

View File

@@ -281,6 +281,35 @@ async def test_update_pipelines_timestamps_success(datetime_mock, mongo_db):
)
@mark.asyncio
@patch("orchestrator.activities.mongo_db.datetime")
async def test_update_pipelines_timestamps_failure(datetime_mock, mongo_db):
input_data = {
"updated_pipelines": [
{"schedule_name": "test1", "namespace": "test1", "success": True},
{"schedule_name": "test2", "namespace": "test2", "success": True}
],
**metadata
}
mongo_db.database["pipelines"].update_many.side_effect = Exception("Error")
try:
await mongo_db.update_pipelines_timestamps(input_data)
except Exception as e:
assert str(e) == "Error"
mongo_db.send_notification.assert_called_once_with(
metadata=metadata['metadata'],
notification_id="MONGODB_UPDATE_PIPELINES_ERROR",
message="Failed to update pipelines timestamps: Error",
block="update_pipelines_timestamps",
level=NotificationLevel.ERROR,
attachment_content=ANY
)
else:
assert False, "Expected an exception to be raised"
@mark.asyncio
@patch("orchestrator.activities.mongo_db.datetime")
async def test_create_pipelines_timestamps_success(datetime_mock, mongo_db):
@@ -300,6 +329,33 @@ async def test_create_pipelines_timestamps_success(datetime_mock, mongo_db):
)
@mark.asyncio
@patch("orchestrator.activities.mongo_db.datetime")
async def test_create_pipelines_timestamps_failure(datetime_mock, mongo_db):
input_data = {"created_pipelines": [
{"schedule_name": "test1", "namespace": "test1", "success": True},
{"schedule_name": "test2", "namespace": "test2", "success": True}
],
**metadata
}
mongo_db.database["pipelines"].insert_many.side_effect = Exception("Error")
try:
await mongo_db.create_pipelines_timestamps(input_data)
except Exception as e:
assert str(e) == "Error"
mongo_db.send_notification.assert_called_once_with(
metadata=metadata['metadata'],
notification_id="MONGODB_CREATE_PIPELINES_ERROR",
message="Failed to create pipelines timestamps: Error",
block="create_pipelines_timestamps",
level=NotificationLevel.ERROR,
attachment_content=ANY
)
else:
assert False, "Expected an exception to be raised"
@mark.asyncio
@patch("orchestrator.activities.mongo_db.datetime")
async def test_delete_pipelines_timestamps_success(datetime_mock, mongo_db):
@@ -315,3 +371,30 @@ async def test_delete_pipelines_timestamps_success(datetime_mock, mongo_db):
{"schedule_name": "test2", "namespace": "test2"}
]}
)
@mark.asyncio
@patch("orchestrator.activities.mongo_db.datetime")
async def test_delete_pipelines_timestamps_failure(datetime_mock, mongo_db):
input_data = {"deleted_pipelines": [
{"schedule_name": "test1", "namespace": "test1", "success": True},
{"schedule_name": "test2", "namespace": "test2", "success": True}
],
**metadata
}
mongo_db.database["pipelines"].delete_many.side_effect = Exception("Error")
try:
await mongo_db.delete_pipelines_timestamps(input_data)
except Exception as e:
assert str(e) == "Error"
mongo_db.send_notification.assert_called_once_with(
metadata=metadata['metadata'],
notification_id="MONGODB_DELETE_PIPELINES_ERROR",
message="Failed to delete pipelines timestamps: Error",
block="delete_pipelines_timestamps",
level=NotificationLevel.ERROR,
attachment_content=ANY
)
else:
assert False, "Expected an exception to be raised"

View File

@@ -1,6 +1,7 @@
from unittest.mock import MagicMock, patch, call
from unittest.mock import MagicMock, patch, call, ANY
from pytest import mark, fixture
from orchestrator.activities.slot_manager import SlotManager
from sientia_do.notifications.models import NotificationLevel
metadata = {
"metadata": {
@@ -28,6 +29,7 @@ def slot_manager(_redis_mock):
slot_manager.redis_client = MagicMock()
slot_manager.logger = MagicMock()
slot_manager.notification_handler = MagicMock()
slot_manager.send_notification = MagicMock()
return slot_manager
@@ -82,6 +84,32 @@ async def test_load_opc_slots_no_decode(slot_manager):
}
@mark.asyncio
async def test_load_opc_slots_error(slot_manager):
slot_manager.redis_client.keys.return_value = [
"slot:opc_tags:1", "slot:opc_tags:2", "slot:opc_tags:3"]
slot_manager.get = MagicMock(
side_effect=Exception("Test exception")
)
try:
await slot_manager.load_opc_slots(metadata)
except Exception as e:
assert str(e) == "Test exception"
slot_manager.send_notification.assert_called_once_with(
metadata=metadata['metadata'],
notification_id="REDIS_GET_ERROR",
message="Failed to load OPC slots: Test exception",
block="load_opc_slots",
level=NotificationLevel.ERROR,
attachment_content=ANY
)
else:
assert False, "Expected an exception to be raised"
@mark.asyncio
async def test_load_active_ingestors(slot_manager):
slot_manager.redis_client.keys.return_value = [
@@ -93,6 +121,30 @@ async def test_load_active_ingestors(slot_manager):
"heartbeat:ingestor:2", "heartbeat:ingestor:3"]
@mark.asyncio
async def test_load_active_ingestors_error(slot_manager):
slot_manager.redis_client.keys.return_value = [
"heartbeat:ingestor:1", "heartbeat:ingestor:2", "heartbeat:ingestor:3"]
slot_manager.redis_client.keys.side_effect = Exception("Test exception")
try:
await slot_manager.load_active_ingestors(metadata)
except Exception as e:
assert str(e) == "Test exception"
slot_manager.send_notification.assert_called_once_with(
metadata=metadata['metadata'],
notification_id="REDIS_GET_ERROR",
message="Failed to load active ingestors: Test exception",
block="load_active_ingestors",
level=NotificationLevel.ERROR,
attachment_content=ANY
)
else:
assert False, "Expected an exception to be raised"
@mark.asyncio
async def test_update_slots(slot_manager):
slot_manager.set = MagicMock(

View File

@@ -1,9 +1,7 @@
from unittest.mock import MagicMock, patch, AsyncMock, call, ANY
from datetime import timedelta
import base64
import json
from sientia_do.notifications.models import NotificationLevel
from pytest import fixture, mark
import pytest_asyncio
from orchestrator.activities.temporal_manager import TemporalManager
from orchestrator.utils.converters import parse_frequency
@@ -30,6 +28,7 @@ def temporal_manager(connect_mock):
temporal_manager.temporal_clients['scouter'] = MagicMock()
temporal_manager.temporal_clients['laborious'] = MagicMock()
temporal_manager.send_notification = MagicMock()
return temporal_manager
@@ -71,80 +70,6 @@ async def async_iter():
)
@mark.asyncio
@patch("orchestrator.activities.temporal_manager.MessageToDict",
return_value={"data": base64.b64encode(json.dumps({"test": "test"}).encode('utf-8'))})
async def test_load_schedule(_mock_message_to_dict, temporal_manager):
# Create async iterator mock
handle = MagicMock(
describe=AsyncMock(
return_value=MagicMock(
schedule=MagicMock(
action=MagicMock(
args=[
MagicMock(
data=base64.b64encode(json.dumps(
{"test": "test"}).encode('utf-8'))
)
]
)
)
)
)
)
temporal_manager.temporal_clients['scouter'].list_schedules = AsyncMock(
return_value=async_iter()
)
temporal_manager.temporal_clients['laborious'].list_schedules = AsyncMock(
return_value=async_iter()
)
temporal_manager.temporal_clients['scouter'].get_schedule_handle = MagicMock(
return_value=handle
)
temporal_manager.temporal_clients['laborious'].get_schedule_handle = MagicMock(
return_value=handle
)
describe_mock = MagicMock(
intervals=[
MagicMock(
every=MagicMock(
seconds=60
)
)
]
)
temporal_manager.temporal_clients['scouter'].get_schedule_handle.return_value.describe \
.return_value.schedule.spec = describe_mock
temporal_manager.temporal_clients['laborious'].get_schedule_handle.return_value.describe \
.return_value.schedule.spec = describe_mock
response = await temporal_manager.load_schedule(metadata)
temporal_manager.temporal_clients['scouter'].list_schedules.assert_awaited_once(
)
temporal_manager.temporal_clients['laborious'].list_schedules.assert_awaited_once(
)
assert response == {
"scouter": {
"test-schedule-id": {
"frequency": 60,
"data": {"test": "test"}
}
},
"laborious": {
"test-schedule-id": {
"frequency": 60,
"data": {"test": "test"}
}
}
}
@mark.asyncio
async def test_normalize_schedules(temporal_manager):
input_data = {
@@ -182,6 +107,29 @@ async def test_normalize_schedules(temporal_manager):
)
@mark.asyncio
async def test_normalize_schedules_error(temporal_manager):
temporal_manager.temporal_clients['scouter'].list_schedules = AsyncMock(
side_effect=Exception("Test exception")
)
try:
await temporal_manager.normalize_schedules(metadata)
except Exception as e:
assert str(e) == "Test exception"
temporal_manager.send_notification.assert_called_once_with(
metadata=metadata['metadata'],
notification_id="TEMPORAL_NORMALIZE_SCHEDULES_ERROR",
message="Failed to normalize schedules: Test exception",
block="normalize_schedules",
level=NotificationLevel.ERROR,
attachment_content=ANY
)
else:
assert False, "Expected an exception to be raised"
@mark.asyncio
@patch("orchestrator.activities.temporal_manager.parse_frequency",
side_effect=parse_frequency)