SIENTIAPDE-1172
feat: enhance email notifications and orchestrator activities for reports - Updated email HTML structure to clearly present errors, warnings, and info notifications. - Introduced a new method in the Formatters class to filter notification reports based on group configurations. - Enhanced the Reports workflow to integrate the new filtering functionality and manage notification packages effectively. - Adjusted SlotManager to store timestamps with mail type specificity for better tracking. - Improved test coverage for the new filtering functionality in the Formatters class.
This commit is contained in:
246
email.html
246
email.html
@@ -15,11 +15,251 @@
|
|||||||
<body>
|
<body>
|
||||||
<h1>SIENTIA™ Alerts</h1>
|
<h1>SIENTIA™ Alerts</h1>
|
||||||
|
|
||||||
<h3></h3>
|
<h3>Errors detected:</h3>
|
||||||
|
|
||||||
<h3></h3>
|
<h4>Model: <span>ipsum et</span></h4>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Notification ID</th>
|
||||||
|
<th>Schedule</th>
|
||||||
|
<th>Block</th>
|
||||||
|
<th>Timestamp</th>
|
||||||
|
<th>Message</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
<h3></h3>
|
<tr>
|
||||||
|
<td>TAG_node34:tag_8_LISTENNING_STOPPED</td>
|
||||||
|
<td>adipiscing_eiusmod_do</td>
|
||||||
|
<td>dolor_labore_consectetur_ipsum</td>
|
||||||
|
<td>2025-07-29 14:39:52.952316+00:00</td>
|
||||||
|
<td>sed elit dolore incididunt incididunt aliqua</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h4>Model: <span>incididunt et do</span></h4>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Notification ID</th>
|
||||||
|
<th>Schedule</th>
|
||||||
|
<th>Block</th>
|
||||||
|
<th>Timestamp</th>
|
||||||
|
<th>Message</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>OPC_LISTENNING_STOPPED__server_5</td>
|
||||||
|
<td>eiusmod_adipiscing_dolore_ipsum_incididunt_incididunt</td>
|
||||||
|
<td>aliqua_dolore</td>
|
||||||
|
<td>2025-07-29 14:39:52.952579+00:00</td>
|
||||||
|
<td>dolor elit do ipsum consectetur amet ut do amet et</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h4>Model: <span>magna adipiscing aliqua</span></h4>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Notification ID</th>
|
||||||
|
<th>Schedule</th>
|
||||||
|
<th>Block</th>
|
||||||
|
<th>Timestamp</th>
|
||||||
|
<th>Message</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>REPORT_PARTITION_MANAGER</td>
|
||||||
|
<td>do_dolore_ut_amet</td>
|
||||||
|
<td>et_eiusmod</td>
|
||||||
|
<td>2025-07-29 14:39:52.952688+00:00</td>
|
||||||
|
<td>incididunt lorem eiusmod do et ipsum et ut</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h3>Warnings detected:</h3>
|
||||||
|
|
||||||
|
<h4>Model: <span>adipiscing magna lorem</span></h4>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Notification ID</th>
|
||||||
|
<th>Schedule</th>
|
||||||
|
<th>Block</th>
|
||||||
|
<th>Timestamp</th>
|
||||||
|
<th>Message</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>REPORT_PARTITION_MANAGER</td>
|
||||||
|
<td>ipsum_et_incididunt_do</td>
|
||||||
|
<td>ut_sed_incididunt</td>
|
||||||
|
<td>2025-07-29 14:39:52.952121+00:00</td>
|
||||||
|
<td>aliqua tempor aliqua sit ipsum amet elit ipsum</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h4>Model: <span>sed amet adipiscing incididunt</span></h4>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Notification ID</th>
|
||||||
|
<th>Schedule</th>
|
||||||
|
<th>Block</th>
|
||||||
|
<th>Timestamp</th>
|
||||||
|
<th>Message</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>ALIQUA_SIT_INCIDIDUNT_EIUSMOD</td>
|
||||||
|
<td>consectetur_dolore_sit_sed_sed</td>
|
||||||
|
<td>dolore_ipsum</td>
|
||||||
|
<td>2025-07-29 14:39:52.952259+00:00</td>
|
||||||
|
<td>do aliqua ut incididunt consectetur consectetur sed et labore</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h4>Model: <span>ipsum ipsum amet tempor</span></h4>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Notification ID</th>
|
||||||
|
<th>Schedule</th>
|
||||||
|
<th>Block</th>
|
||||||
|
<th>Timestamp</th>
|
||||||
|
<th>Message</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>OPC_LISTENNING_STOPPED__server_6</td>
|
||||||
|
<td>sit_labore_sed_dolor_et_elit</td>
|
||||||
|
<td>dolor_do_magna_et</td>
|
||||||
|
<td>2025-07-29 14:39:52.952376+00:00</td>
|
||||||
|
<td>magna consectetur do et dolor aliqua</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h4>Model: <span>sed ut</span></h4>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Notification ID</th>
|
||||||
|
<th>Schedule</th>
|
||||||
|
<th>Block</th>
|
||||||
|
<th>Timestamp</th>
|
||||||
|
<th>Message</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>REPORT_PARTITION_MANAGER</td>
|
||||||
|
<td>elit_et_ipsum_dolore</td>
|
||||||
|
<td>sed_ipsum</td>
|
||||||
|
<td>2025-07-29 14:39:52.952426+00:00</td>
|
||||||
|
<td>elit dolor dolore dolor eiusmod</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h4>Model: <span>eiusmod labore</span></h4>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Notification ID</th>
|
||||||
|
<th>Schedule</th>
|
||||||
|
<th>Block</th>
|
||||||
|
<th>Timestamp</th>
|
||||||
|
<th>Message</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>OPC_CONNECTION_RETRY__server_3</td>
|
||||||
|
<td>dolor_ut_dolor_sit_adipiscing_incididunt</td>
|
||||||
|
<td>sit_tempor_dolore</td>
|
||||||
|
<td>2025-07-29 14:39:52.952483+00:00</td>
|
||||||
|
<td>ipsum consectetur magna elit dolore</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h4>Model: <span>do dolor tempor amet</span></h4>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Notification ID</th>
|
||||||
|
<th>Schedule</th>
|
||||||
|
<th>Block</th>
|
||||||
|
<th>Timestamp</th>
|
||||||
|
<th>Message</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>REPORT_PARTITION_MANAGER</td>
|
||||||
|
<td>sed_sit_do_tempor_ut</td>
|
||||||
|
<td>eiusmod_adipiscing</td>
|
||||||
|
<td>2025-07-29 14:39:52.952637+00:00</td>
|
||||||
|
<td>incididunt do do adipiscing dolore ut ut elit sit labore</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h3>Infos detected:</h3>
|
||||||
|
|
||||||
|
<h4>Model: <span>sed consectetur ut</span></h4>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Notification ID</th>
|
||||||
|
<th>Schedule</th>
|
||||||
|
<th>Block</th>
|
||||||
|
<th>Timestamp</th>
|
||||||
|
<th>Message</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>TEMPOR_DO_DOLOR_TEMPOR_DOLOR</td>
|
||||||
|
<td>elit_tempor_dolore_consectetur_dolore_adipiscing</td>
|
||||||
|
<td>magna_labore_lorem</td>
|
||||||
|
<td>2025-07-29 14:39:52.952199+00:00</td>
|
||||||
|
<td>et et adipiscing lorem magna eiusmod labore do</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -532,6 +532,41 @@ class Formatters(BaseActivity):
|
|||||||
'mail_type': mail_type
|
'mail_type': mail_type
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
|
if group_name not in data[key]['groups']:
|
||||||
data[key]['groups'].append(group_name)
|
data[key]['groups'].append(group_name)
|
||||||
|
|
||||||
return DataFrame(list(data.values())).to_dict()
|
return DataFrame(list(data.values())).to_dict()
|
||||||
|
|
||||||
|
@activity.defn(name="filter_notification_reports")
|
||||||
|
async def filter_notification_reports(self, input_data: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
"""
|
||||||
|
Filter notification reports.
|
||||||
|
"""
|
||||||
|
metadata = input_data['metadata']
|
||||||
|
notification_package = input_data['notification_package']
|
||||||
|
sending_configs = input_data['sending_configs']
|
||||||
|
|
||||||
|
self.info("Filtering notification reports...", metadata=metadata)
|
||||||
|
|
||||||
|
receiver_groups = {}
|
||||||
|
|
||||||
|
for receiver_group in sending_configs:
|
||||||
|
group_name = receiver_group['group_name']
|
||||||
|
receiver_groups[group_name] = {
|
||||||
|
**receiver_group,
|
||||||
|
"notifications": []
|
||||||
|
}
|
||||||
|
receiver_groups[group_name]['notifications'] = []
|
||||||
|
|
||||||
|
ignore_list = receiver_group.get('ignore', [])
|
||||||
|
|
||||||
|
for notification in notification_package:
|
||||||
|
alert_type = "reports"
|
||||||
|
notification_id = notification['notification_id']
|
||||||
|
|
||||||
|
# Check if this group must be notified
|
||||||
|
if alert_type in receiver_group['contents'] and notification_id not in ignore_list:
|
||||||
|
receiver_groups[group_name]["notifications"].append(
|
||||||
|
notification)
|
||||||
|
|
||||||
|
return receiver_groups
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ class SlotManager(Redis):
|
|||||||
Gets the last data timestamp from redis.
|
Gets the last data timestamp from redis.
|
||||||
"""
|
"""
|
||||||
metadata = input_data['metadata']
|
metadata = input_data['metadata']
|
||||||
key = "notification_last_timestamp"
|
key = f"notification_last_timestamp:{input_data['mail_type']}"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
data_hold = self.get(key)
|
data_hold = self.get(key)
|
||||||
@@ -235,7 +235,7 @@ class SlotManager(Redis):
|
|||||||
Puts the last data timestamp into redis.
|
Puts the last data timestamp into redis.
|
||||||
"""
|
"""
|
||||||
metadata = input_data['metadata']
|
metadata = input_data['metadata']
|
||||||
key = "notification_last_timestamp"
|
key = f"notification_last_timestamp:{input_data['mail_type']}"
|
||||||
|
|
||||||
data = DataFrame(input_data['data'])
|
data = DataFrame(input_data['data'])
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ with workflow.unsafe.imports_passed_through():
|
|||||||
import sys
|
import sys
|
||||||
import asyncio
|
import asyncio
|
||||||
from orchestrator.workflows.alerts import Alerts
|
from orchestrator.workflows.alerts import Alerts
|
||||||
|
from orchestrator.workflows.reports import Reports
|
||||||
from orchestrator.workflows.subworkflows.load_notification_package import LoadNotificationPackage
|
from orchestrator.workflows.subworkflows.load_notification_package import LoadNotificationPackage
|
||||||
from orchestrator.workflows.subworkflows.process_notifications import ProcessNotifications
|
from orchestrator.workflows.subworkflows.process_notifications import ProcessNotifications
|
||||||
from orchestrator.workflows.orchestrator import Orchestrator
|
from orchestrator.workflows.orchestrator import Orchestrator
|
||||||
@@ -121,6 +122,27 @@ async def main():
|
|||||||
# Store notification cache
|
# Store notification cache
|
||||||
activities.store_notification_cache
|
activities.store_notification_cache
|
||||||
]
|
]
|
||||||
|
),
|
||||||
|
Worker(
|
||||||
|
temporal_client,
|
||||||
|
task_queue='reports-queue',
|
||||||
|
workflows=[Reports, LoadNotificationPackage, ProcessNotifications],
|
||||||
|
activities=[
|
||||||
|
# Load notifications
|
||||||
|
activities.get_last_data_timestamp,
|
||||||
|
activities.find_documents_in_mongodb,
|
||||||
|
activities.load_latest_data,
|
||||||
|
activities.put_last_data_timestamp,
|
||||||
|
|
||||||
|
# Format and filter notifications
|
||||||
|
activities.filter_notification_reports,
|
||||||
|
|
||||||
|
# Send email and export data to postgres
|
||||||
|
activities.build_email_html,
|
||||||
|
activities.send_email,
|
||||||
|
activities.format_log_report,
|
||||||
|
activities.export_data_to_postgres
|
||||||
|
]
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ class Alerts:
|
|||||||
mail_type = "Alerts"
|
mail_type = "Alerts"
|
||||||
|
|
||||||
input_data['metadata'] = metadata
|
input_data['metadata'] = metadata
|
||||||
|
input_data['mail_type'] = mail_type
|
||||||
|
|
||||||
input_data['base_data_filter'] = {
|
input_data['base_data_filter'] = {
|
||||||
'level': 'ERROR'
|
'level': 'ERROR'
|
||||||
|
|||||||
@@ -3,17 +3,76 @@ from temporalio import workflow
|
|||||||
with workflow.unsafe.imports_passed_through():
|
with workflow.unsafe.imports_passed_through():
|
||||||
from orchestrator.activities.activities import Activities
|
from orchestrator.activities.activities import Activities
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
from datetime import timedelta
|
||||||
|
from sientia_do.temporal.utils.policies import retry_policy
|
||||||
|
|
||||||
|
|
||||||
@workflow.defn(name="reports")
|
@workflow.defn(name="reports")
|
||||||
class Reports:
|
class Reports:
|
||||||
@workflow.run
|
@workflow.run
|
||||||
async def run(self, input_data: dict[str, Any]):
|
async def run(self, input_data: dict[str, Any]):
|
||||||
|
"""
|
||||||
|
Workflow to send reports to the users
|
||||||
|
|
||||||
|
Args:
|
||||||
|
input_data (dict[str, Any]): Input data. It contains the following keys:
|
||||||
|
- schedule_name: str - Name of the schedule
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
None
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
Exception: If the workflow fails
|
||||||
|
"""
|
||||||
|
metadata = {
|
||||||
|
'metadata': {
|
||||||
|
'schedule_name': input_data['schedule_name'],
|
||||||
|
'workflow_name': 'reports',
|
||||||
|
'model_name': '-',
|
||||||
|
'model_id': '-'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mail_type = "Reports"
|
||||||
|
|
||||||
|
input_data['metadata'] = metadata
|
||||||
|
input_data['mail_type'] = mail_type
|
||||||
|
|
||||||
|
input_data['base_data_filter'] = {}
|
||||||
|
|
||||||
# Call subworkflow "load_notification_package" passing the static filters
|
# Call subworkflow "load_notification_package" passing the static filters
|
||||||
# (timestamp > last timestamp)
|
# (timestamp > last timestamp)
|
||||||
|
|
||||||
# Filter notification package by groups custom configs
|
package = await workflow.execute_child_workflow(
|
||||||
|
'load_notification_package',
|
||||||
|
input_data
|
||||||
|
)
|
||||||
|
|
||||||
|
if not package['notification_package'] or not package['sending_configs']:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Filter notification package by groups custom configs, levels and
|
||||||
|
# timestamp cached
|
||||||
|
|
||||||
|
receiver_groups = await workflow.execute_local_activity_method(
|
||||||
|
Activities.filter_notification_reports,
|
||||||
|
{
|
||||||
|
**metadata,
|
||||||
|
'notification_package': package['notification_package'],
|
||||||
|
'sending_configs': package['sending_configs']
|
||||||
|
},
|
||||||
|
schedule_to_close_timeout=timedelta(seconds=60),
|
||||||
|
retry_policy=retry_policy
|
||||||
|
)
|
||||||
|
|
||||||
# Call subworkflow "process_notifications" passing the notification package
|
# Call subworkflow "process_notifications" passing the notification package
|
||||||
|
await workflow.execute_child_workflow(
|
||||||
pass
|
'process_notifications',
|
||||||
|
{
|
||||||
|
'metadata': metadata,
|
||||||
|
'mail_type': mail_type,
|
||||||
|
'notification_package': receiver_groups,
|
||||||
|
'schema': 'sientia_data',
|
||||||
|
'table_name': 'log_report'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ class LoadNotificationPackage:
|
|||||||
- last_timestamp (str): The last timestamp of the notification package.
|
- last_timestamp (str): The last timestamp of the notification package.
|
||||||
- notification_package (list[dict]): The notification package.
|
- notification_package (list[dict]): The notification package.
|
||||||
- sending_configs (list[dict]): The sending configs.
|
- sending_configs (list[dict]): The sending configs.
|
||||||
|
- mail_type (str): The mail type.
|
||||||
"""
|
"""
|
||||||
metadata = input_data['metadata']
|
metadata = input_data['metadata']
|
||||||
|
|
||||||
@@ -30,6 +31,7 @@ class LoadNotificationPackage:
|
|||||||
Activities.get_last_data_timestamp,
|
Activities.get_last_data_timestamp,
|
||||||
{
|
{
|
||||||
**metadata,
|
**metadata,
|
||||||
|
'mail_type': input_data['mail_type']
|
||||||
},
|
},
|
||||||
start_to_close_timeout=timedelta(seconds=60),
|
start_to_close_timeout=timedelta(seconds=60),
|
||||||
retry_policy=retry_policy
|
retry_policy=retry_policy
|
||||||
@@ -82,7 +84,8 @@ class LoadNotificationPackage:
|
|||||||
Activities.put_last_data_timestamp,
|
Activities.put_last_data_timestamp,
|
||||||
{
|
{
|
||||||
**metadata,
|
**metadata,
|
||||||
'data': notification_package
|
'data': notification_package,
|
||||||
|
'mail_type': input_data['mail_type']
|
||||||
},
|
},
|
||||||
start_to_close_timeout=timedelta(seconds=60),
|
start_to_close_timeout=timedelta(seconds=60),
|
||||||
retry_policy=retry_policy
|
retry_policy=retry_policy
|
||||||
|
|||||||
@@ -765,3 +765,61 @@ async def test_format_log_report(formatters):
|
|||||||
)
|
)
|
||||||
|
|
||||||
assert DataFrame(result).equals(expected_result)
|
assert DataFrame(result).equals(expected_result)
|
||||||
|
|
||||||
|
|
||||||
|
@mark.asyncio
|
||||||
|
async def test_filter_notification_reports(formatters):
|
||||||
|
|
||||||
|
input_data = {
|
||||||
|
**metadata,
|
||||||
|
'notification_package': [
|
||||||
|
{
|
||||||
|
'trigger': 'test_trigger_1',
|
||||||
|
'notification_id': 'test_notification_id_1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'trigger': 'test_trigger_2',
|
||||||
|
'notification_id': 'test_notification_id_2'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'trigger': 'test_trigger_3',
|
||||||
|
'notification_id': 'test_notification_id_3'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'sending_configs': [
|
||||||
|
{
|
||||||
|
'group_name': 'test_group_1',
|
||||||
|
'contents': ['reports'],
|
||||||
|
'ignore': ['test_notification_id_1']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'group_name': 'test_group_2',
|
||||||
|
'contents': ['core_alerts']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
response = await formatters.filter_notification_reports(input_data)
|
||||||
|
|
||||||
|
assert response == {
|
||||||
|
'test_group_1': {
|
||||||
|
'group_name': 'test_group_1',
|
||||||
|
'contents': ['reports'],
|
||||||
|
'ignore': ['test_notification_id_1'],
|
||||||
|
'notifications': [
|
||||||
|
{
|
||||||
|
'trigger': 'test_trigger_2',
|
||||||
|
'notification_id': 'test_notification_id_2'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'trigger': 'test_trigger_3',
|
||||||
|
'notification_id': 'test_notification_id_3'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'test_group_2': {
|
||||||
|
'group_name': 'test_group_2',
|
||||||
|
'contents': ['core_alerts'],
|
||||||
|
'notifications': []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
99
tests/orchestrator/workflows/test_reports.py
Normal file
99
tests/orchestrator/workflows/test_reports.py
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
from unittest.mock import AsyncMock, patch, ANY, call
|
||||||
|
from pytest import fixture, mark
|
||||||
|
from orchestrator.workflows.reports import Reports
|
||||||
|
from orchestrator.activities.activities import Activities
|
||||||
|
|
||||||
|
|
||||||
|
@fixture
|
||||||
|
def reports():
|
||||||
|
return Reports()
|
||||||
|
|
||||||
|
|
||||||
|
metadata = {
|
||||||
|
'metadata': {
|
||||||
|
'schedule_name': 'test-schedule-name',
|
||||||
|
'workflow_name': 'reports',
|
||||||
|
'model_name': '-',
|
||||||
|
'model_id': '-',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@mark.asyncio
|
||||||
|
@patch("orchestrator.workflows.reports.workflow", new_callable=AsyncMock)
|
||||||
|
async def test_run_full_flow(workflow_mock, reports):
|
||||||
|
input_data = {
|
||||||
|
'schedule_name': 'test-schedule-name',
|
||||||
|
'notification_ttl': 300,
|
||||||
|
'sent_ttl': 600
|
||||||
|
}
|
||||||
|
|
||||||
|
await reports.run(input_data)
|
||||||
|
|
||||||
|
workflow_mock.execute_child_workflow.assert_has_calls([
|
||||||
|
call(
|
||||||
|
'load_notification_package',
|
||||||
|
{
|
||||||
|
**input_data,
|
||||||
|
'metadata': metadata,
|
||||||
|
'base_data_filter': {}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
])
|
||||||
|
|
||||||
|
workflow_mock.execute_child_workflow.assert_has_calls([
|
||||||
|
call(
|
||||||
|
'process_notifications',
|
||||||
|
{
|
||||||
|
'metadata': metadata,
|
||||||
|
'mail_type': 'Reports',
|
||||||
|
'notification_package': workflow_mock.execute_local_activity_method.return_value,
|
||||||
|
'schema': 'sientia_data',
|
||||||
|
'table_name': 'log_report'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
])
|
||||||
|
|
||||||
|
workflow_mock.execute_local_activity_method.assert_has_calls([
|
||||||
|
call(
|
||||||
|
Activities.filter_notification_reports,
|
||||||
|
{
|
||||||
|
**metadata,
|
||||||
|
'notification_package': workflow_mock.execute_child_workflow.return_value['notification_package'],
|
||||||
|
'sending_configs': workflow_mock.execute_child_workflow.return_value['sending_configs']
|
||||||
|
},
|
||||||
|
schedule_to_close_timeout=ANY,
|
||||||
|
retry_policy=ANY
|
||||||
|
)
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
@mark.asyncio
|
||||||
|
@patch("orchestrator.workflows.reports.workflow", new_callable=AsyncMock)
|
||||||
|
async def test_run_no_data(workflow_mock, reports):
|
||||||
|
workflow_mock.execute_child_workflow.return_value = {
|
||||||
|
'last_timestamp': '2023-01-01 12:00:00.000000',
|
||||||
|
'notification_package': [],
|
||||||
|
'sending_configs': []
|
||||||
|
}
|
||||||
|
|
||||||
|
input_data = {
|
||||||
|
'schedule_name': 'test-schedule-name',
|
||||||
|
'notification_ttl': 300,
|
||||||
|
'sent_ttl': 600
|
||||||
|
}
|
||||||
|
|
||||||
|
await reports.run(input_data)
|
||||||
|
|
||||||
|
workflow_mock.execute_child_workflow.assert_has_calls([
|
||||||
|
call(
|
||||||
|
'load_notification_package',
|
||||||
|
{
|
||||||
|
**input_data,
|
||||||
|
'metadata': metadata,
|
||||||
|
'base_data_filter': {}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
])
|
||||||
|
|
||||||
|
workflow_mock.execute_local_activity_method.assert_not_called()
|
||||||
Reference in New Issue
Block a user