diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..86cebba --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.pytest_cache +__pycache__ diff --git a/src/notify-email.py b/src/notify-email.py index ef4ed0f..2c912d3 100755 --- a/src/notify-email.py +++ b/src/notify-email.py @@ -16,8 +16,13 @@ log_local = get_logger('email') -EMAIL_TEMPLATE_FILE = 'templates/base.html' -EMAIL_TEMPLATE = Template('') +EMAIL_TEMPLATE_DEFAULT_FILE = 'templates/default.html' +EMAIL_TEMPLATE_APP_PUB_FILE = 'templates/app-pub.html' + +EMAIL_TEMPLATES = { + 'default': Template('dummy'), + 'app-pub': Template('dummy'), +} NUVLA_API_LOCAL = 'http://api:8200' @@ -41,10 +46,10 @@ def get_nuvla_config(): return resp.json() -def set_smpt_params(): +def set_smtp_params(): global SMTP_HOST, SMTP_USER, SMTP_PASSWORD, SMTP_PORT, SMTP_SSL try: - if 'SMTP_HOST' in os.environ: + if os.environ.get('SMTP_HOST') and len(os.environ.get('SMTP_HOST')) > 0: SMTP_HOST = os.environ['SMTP_HOST'] SMTP_USER = os.environ['SMTP_USER'] SMTP_PASSWORD = os.environ['SMTP_PASSWORD'] @@ -84,35 +89,56 @@ def get_smtp_server(debug_level=0) -> smtplib.SMTP: return server -def html_content(values: dict): - subs_config_link = f'Notification configuration' +def get_email_template(msg_params: dict) -> Template: + if 'TEMPLATE' not in msg_params: + return EMAIL_TEMPLATES['default'] + tmpl_name = msg_params.get('TEMPLATE', 'default') + template = EMAIL_TEMPLATES.get(tmpl_name) + if template is None: + log_local.warning('Failed to find email template: %s', tmpl_name) + template = EMAIL_TEMPLATES['default'] + return template + + +def html_content(msg_params: dict): + r_uri = msg_params.get('RESOURCE_URI') + link_text = msg_params.get('RESOURCE_NAME') or r_uri + component_link = f'{link_text}' - r_uri = values.get('RESOURCE_URI') - r_name = values.get('RESOURCE_NAME') - component_link = f'{r_name or r_uri}' - metric = values.get('METRIC') - condition = values.get('CONDITION') - if values.get('RECOVERY', False): + if msg_params.get('RECOVERY', False): img_alert = IMG_ALERT_OK - title = f"[OK] {values.get('SUBS_NAME')}" + notif_title = f"[OK] {msg_params.get('SUBS_NAME')}" else: img_alert = IMG_ALERT_NOK - title = f"[Alert] {values.get('SUBS_NAME')}" + notif_title = f"[Alert] {msg_params.get('SUBS_NAME')}" + + subs_name = 'Notification configuration' + subs_config_link = f'{subs_name}' + params = { - 'title': title, - 'subs_description': values.get('SUBS_DESCRIPTION'), + 'title': notif_title, + 'subs_description': msg_params.get('SUBS_DESCRIPTION'), 'component_link': component_link, - 'metric': metric, - 'condition': condition.upper(), - 'timestamp': timestamp_convert(values.get('TIMESTAMP')), + 'metric': msg_params.get('METRIC'), + 'timestamp': timestamp_convert(msg_params.get('TIMESTAMP')), 'subs_config_link': subs_config_link, 'header_img': f'{NUVLA_ENDPOINT}/{img_alert}', 'current_year': str(datetime.now().year) } - if values.get('VALUE'): - params['condition'] = f"{values.get('CONDITION')} {values.get('CONDITION_VALUE')}" - params['value'] = values.get('VALUE') - return EMAIL_TEMPLATE.render(**params) + + if 'TRIGGER_RESOURCE_PATH' in msg_params: + resource_path = msg_params.get('TRIGGER_RESOURCE_PATH') + resource_name = msg_params.get('TRIGGER_RESOURCE_NAME') + params['trigger_link'] = \ + f'{resource_name}' + + if msg_params.get('CONDITION'): + params['condition'] = msg_params.get('CONDITION') + if 'VALUE' in msg_params: + params['condition'] = f"{msg_params.get('CONDITION')} {msg_params.get('CONDITION_VALUE')}" + params['value'] = msg_params.get('VALUE') + + return get_email_template(msg_params).render(**params) def send(server: smtplib.SMTP, recipients, subject, html, attempts=SEND_EMAIL_ATTEMPTS): @@ -125,9 +151,9 @@ def send(server: smtplib.SMTP, recipients, subject, html, attempts=SEND_EMAIL_AT if i > 0: log_local.warning(f'Failed sending email: retry {i}') time.sleep(.5) - log_local.warning(f'Reconnecting to SMTP server...') + log_local.warning('Reconnecting to SMTP server...') server = get_smtp_server() - log_local.warning(f'Reconnecting to SMTP server... done.') + log_local.warning('Reconnecting to SMTP server... done.') try: resp = server.sendmail(server.user, recipients, msg.as_string()) if resp: @@ -160,14 +186,24 @@ def worker(workq: multiprocessing.Queue): log_local.info(f'sent: {msg} to {recipients}') except smtplib.SMTPException as ex: log_local.error(f'Failed sending email due to SMTP error: {ex}') - log_local.warning(f'Reconnecting to SMTP server...') + log_local.warning('Reconnecting to SMTP server...') smtp_server = get_smtp_server() - log_local.warning(f'Reconnecting to SMTP server... done.') + log_local.warning('Reconnecting to SMTP server... done.') except Exception as ex: log_local.error(f'Failed sending email: {ex}') +def email_template(template_file=EMAIL_TEMPLATE_DEFAULT_FILE): + return Template(open(template_file).read()) + + +def init_email_templates(default=EMAIL_TEMPLATE_DEFAULT_FILE, + app_pub=EMAIL_TEMPLATE_APP_PUB_FILE): + EMAIL_TEMPLATES['default'] = email_template(default) + EMAIL_TEMPLATES['app-pub'] = email_template(app_pub) + + if __name__ == "__main__": - EMAIL_TEMPLATE = Template(open(EMAIL_TEMPLATE_FILE).read()) - set_smpt_params() + init_email_templates() + set_smtp_params() main(worker, KAFKA_TOPIC, KAFKA_GROUP_ID) diff --git a/src/notify-slack.py b/src/notify-slack.py index d2d0249..048b432 100755 --- a/src/notify-slack.py +++ b/src/notify-slack.py @@ -26,73 +26,93 @@ def now_timestamp(): return datetime.now().timestamp() -def message_content(values: dict): - subs_name = lt.sub('<', gt.sub('>', values.get('SUBS_NAME', ''))) - subs_config_txt = f'<{NUVLA_ENDPOINT}/ui/notifications|{subs_name}>' - - metric = values.get('METRIC') - if values.get('VALUE'): - cond_value = values.get('CONDITION_VALUE') - condition = f"{values.get('CONDITION')}" - criteria = f'_{metric}_ {gt.sub(">", lt.sub("<", condition))} *{cond_value}*' - value = f"*{values.get('VALUE')}*" - else: - condition = values.get('CONDITION', '').upper() - criteria = f'_{metric}_' - value = f'*{condition}*' - - r_uri = values.get('RESOURCE_URI') - r_name = values.get('RESOURCE_NAME') - link_text = r_name or r_uri - component = f'<{NUVLA_ENDPOINT}/ui/{r_uri}|{link_text}>' - - ts = timestamp_convert(values.get('TIMESTAMP')) +def message_content(msg_params: dict): + r_uri = msg_params.get('RESOURCE_URI') + link_text = msg_params.get('RESOURCE_NAME') or r_uri + component_link = f'<{NUVLA_ENDPOINT}/ui/{r_uri}|{link_text}>' - if values.get('RECOVERY', False): + if msg_params.get('RECOVERY', False): color = COLOR_OK - notif_title = "[OK] Notification" + notif_title = f"[OK] {msg_params.get('SUBS_NAME')}" else: color = COLOR_NOK - notif_title = "[Alert] Notification" - - return { - "attachments": [ + notif_title = f"[Alert] {msg_params.get('SUBS_NAME')}" + + subs_config_link = f'<{NUVLA_ENDPOINT}/ui/notifications|Notification configuration>' + + # Order of the fields defines the layout of the message. + + fields = [ + { + 'title': notif_title, + 'value': subs_config_link, + 'short': True + } + ] + + if 'TRIGGER_RESOURCE_PATH' in msg_params: + resource_path = msg_params.get('TRIGGER_RESOURCE_PATH') + resource_name = msg_params.get('TRIGGER_RESOURCE_NAME') + trigger_link = \ + f'<{NUVLA_ENDPOINT}/ui/{resource_path}|{resource_name}>' + fields.append({ + 'title': 'Application was published', + 'value': trigger_link, + 'short': True + }) + + fields.append({ + 'title': 'Affected resource(s)', + 'value': component_link, + 'short': True + }) + + if msg_params.get('CONDITION'): + metric = msg_params.get('METRIC') + if 'VALUE' in msg_params: + cond_value = msg_params.get('CONDITION_VALUE') + condition = f"{msg_params.get('CONDITION')}" + criteria = f'_{metric}_ {gt.sub(">", lt.sub("<", condition))} *{cond_value}*' + value = f"*{msg_params.get('VALUE')}*" + else: + condition = msg_params.get('CONDITION', '').upper() + criteria = f'_{metric}_' + value = f'*{condition}*' + + fields.extend([ + { + 'title': 'Criteria', + 'value': criteria, + 'short': True + }, { - "color": color, - "author_name": "Nuvla", - "author_link": "https://sixsq.com", - "author_icon": "https://sixsq.com/img/logo/logo_sixsq.png", - "fields": [ - { - "title": notif_title, - "value": subs_config_txt, - "short": True - }, - { - "title": "Affected resource", - "value": component, - "short": True - }, - { - "title": "Criteria", - "value": criteria, - "short": True - }, - { - "title": "Value", - "value": value, - "short": True - }, - { - "title": "Event Timestamp", - "value": ts, - "short": True - } - ], - "ts": now_timestamp() - } - ] - } + 'title': 'Value', + 'value': value, + 'short': True + }] + ) + + fields.append( + { + 'title': 'Event Timestamp', + 'value': timestamp_convert(msg_params.get('TIMESTAMP')), + 'short': True + } + ) + + attachments = [{ + 'color': color, + 'author_name': 'Nuvla.io', + 'author_link': 'https://nuvla.io', + 'author_icon': 'https://sixsq.com/assets/img/logo-sixsq.svg', + 'fields': fields, + 'footer': 'https://sixsq.com', + 'footer_icon': 'https://sixsq.com/assets/img/logo-sixsq.svg', + 'ts': now_timestamp() + } + ] + + return {'attachments': attachments} def send_message(dest, message): diff --git a/src/notify_deps.py b/src/notify_deps.py index 98731dc..e6d9802 100644 --- a/src/notify_deps.py +++ b/src/notify_deps.py @@ -51,7 +51,7 @@ def kafka_consumer(topic, bootstrap_servers, group_id, auto_offset_reset='latest def timestamp_convert(ts): return datetime.strptime(ts, '%Y-%m-%dT%H:%M:%SZ'). \ - strftime('%a %d, %Y %H:%M:%S UTC') + strftime('%Y-%m-%d %H:%M:%S UTC') def main(worker, kafka_topic, group_id): diff --git a/src/templates/app-pub.html b/src/templates/app-pub.html new file mode 100644 index 0000000..62c2bf6 --- /dev/null +++ b/src/templates/app-pub.html @@ -0,0 +1,438 @@ + + + + + + {{title}} + + + +{{title}} + + + + + + + + + diff --git a/src/templates/base.html b/src/templates/default.html similarity index 94% rename from src/templates/base.html rename to src/templates/default.html index ddb26b9..c22c032 100644 --- a/src/templates/base.html +++ b/src/templates/default.html @@ -1,5 +1,5 @@ - + @@ -372,18 +372,20 @@

{{title}}

+ {% if condition is defined %} + {% endif %} {% if value is defined %} - + {% endif %} @@ -393,13 +395,15 @@

{{title}}

+ {% if condition is defined %} + {% endif %} {% if value is defined %} - + {% endif %}
- Component + Affected resource(s) Metric

Condition

-

Value

-
+

Value

+
{{metric}} {{condition}} - {{value}} - + {{value}} +
@@ -407,7 +411,7 @@

{{title}}

-

Timestamp {{timestamp}}

+

Event Timestamp {{timestamp}}

diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000..0b84df0 --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1 @@ +*.html \ No newline at end of file diff --git a/tests/email-template-test.py b/tests/email-template-test.py index be66e26..5bf980d 100755 --- a/tests/email-template-test.py +++ b/tests/email-template-test.py @@ -1,13 +1,17 @@ #!/usr/bin/env python3 import json -from jinja2 import Template +import os import notify_email - -notify_email.EMAIL_TEMPLATE = Template(open('../src/templates/base.html').read()) +notify_email.init_email_templates( + default=os.path.join('..', 'src', notify_email.EMAIL_TEMPLATE_DEFAULT_FILE), + app_pub=os.path.join('..', 'src', notify_email.EMAIL_TEMPLATE_APP_PUB_FILE)) tests = [ + 'event-app-pub-app-bq.json', + 'event-app-pub-depl-grp.json', + 'event-app-pub-depl.json', 'metric-no-value-NOK.json', 'metric-no-value-OK.json', 'metric-with-value-NOK.json', diff --git a/tests/event-app-pub-app-bq.json b/tests/event-app-pub-app-bq.json new file mode 100644 index 0000000..b1809ce --- /dev/null +++ b/tests/event-app-pub-app-bq.json @@ -0,0 +1,13 @@ +{ + "TEMPLATE": "app-pub", + "SUBS_ID": "subscription-config/891bdb6c-fb8c-41e6-9023-e317757365ab", + "DESTINATION": "https://hooks.slack.com/services/foo", + "SUBS_NAME": "App Published for App Bouquet", + "SUBS_DESCRIPTION": "Apps Published for App Bouquet", + "TRIGGER_RESOURCE_PATH": "apps/test/trigger-app-name", + "TRIGGER_RESOURCE_NAME": "published app name", + "RESOURCE_URI": "my-app-bqs/new-app-bq", + "RESOURCE_NAME": "Update App Bouquet: affected app name", + "TIMESTAMP": "2023-11-29T13:22:26Z", + "RECOVERY": true +} diff --git a/tests/event-app-pub-depl-grp.json b/tests/event-app-pub-depl-grp.json new file mode 100644 index 0000000..7edef8c --- /dev/null +++ b/tests/event-app-pub-depl-grp.json @@ -0,0 +1,14 @@ +{ + "TEMPLATE": "app-pub", + "SUBS_ID": "subscription-config/891bdb6c-fb8c-41e6-9023-e317757365ab", + "DESTINATION": "https://hooks.slack.com/services/foo", + "SUBS_NAME": "App Published for Deployments", + "SUBS_DESCRIPTION": "App Published for Deployments", + "TRIGGER_RESOURCE_PATH": "apps/test/trigger-app-name", + "TRIGGER_RESOURCE_NAME": "published app name", + "RESOURCE_URI": "deployment-groups/1-2-3-4-5?deployment-groups-detail-tab=apps", + "RESOURCE_NAME": "Update Deployment Group: deployment group name", + "TIMESTAMP": "2023-11-29T13:22:26Z", + "RECOVERY": true +} + diff --git a/tests/event-app-pub-depl.json b/tests/event-app-pub-depl.json new file mode 100644 index 0000000..f9e7727 --- /dev/null +++ b/tests/event-app-pub-depl.json @@ -0,0 +1,13 @@ +{ + "TEMPLATE": "app-pub", + "SUBS_ID": "subscription-config/891bdb6c-fb8c-41e6-9023-e317757365ab", + "DESTINATION": "https://hooks.slack.com/services/foo", + "SUBS_NAME": "App Published for Deployments", + "SUBS_DESCRIPTION": "App Published for Deployments", + "TRIGGER_RESOURCE_PATH": "apps/test/trigger-app-name", + "TRIGGER_RESOURCE_NAME": "published app name", + "RESOURCE_URI": "deployments?select=all&view=table&deployment=module/id='module/1-2-3-4-5' and deployment-set=null", + "RESOURCE_NAME": "Update Deployments", + "TIMESTAMP": "2023-11-29T13:22:26Z", + "RECOVERY": true +} diff --git a/tests/metric-no-value-NOK.json b/tests/metric-no-value-NOK.json index b8236ae..568b4fb 100644 --- a/tests/metric-no-value-NOK.json +++ b/tests/metric-no-value-NOK.json @@ -1,10 +1,10 @@ { "SUBS_ID": "subscription-config/1-2-3-4-5", - "SUBS_NAME": "NB London off-line", - "SUBS_DESCRIPTION": "NB in London off-line", + "SUBS_NAME": "NE London online", + "SUBS_DESCRIPTION": "NE in London online", "RESOURCE_URI": "edge/1c2347d5-9463-47d4-a540-fffa3aad1367", - "RESOURCE_NAME": "NB London", - "METRIC": "NB online", + "RESOURCE_NAME": "NE London", + "METRIC": "NE online", "CONDITION": "no", "RECOVERY": false, "TIMESTAMP": "2021-02-01T10:11:12Z" diff --git a/tests/metric-no-value-OK.json b/tests/metric-no-value-OK.json index 79b2a0f..2731963 100644 --- a/tests/metric-no-value-OK.json +++ b/tests/metric-no-value-OK.json @@ -1,10 +1,10 @@ { "SUBS_ID": "subscription-config/1-2-3-4-5", - "SUBS_NAME": "NB London off-line", - "SUBS_DESCRIPTION": "NB in London off-line", + "SUBS_NAME": "NE London online", + "SUBS_DESCRIPTION": "NE in London online", "RESOURCE_URI": "edge/1c2347d5-9463-47d4-a540-fffa3aad1367", - "RESOURCE_NAME": "NB London", - "METRIC": "NB online", + "RESOURCE_NAME": "NE London", + "METRIC": "NE online", "CONDITION": "yes", "RECOVERY": true, "TIMESTAMP": "2021-02-01T10:11:12Z" diff --git a/tests/metric-with-value-NOK.json b/tests/metric-with-value-NOK.json index 949df54..9aa56e2 100644 --- a/tests/metric-with-value-NOK.json +++ b/tests/metric-with-value-NOK.json @@ -1,9 +1,9 @@ { "SUBS_ID": "subscription-config/1-2-3-4-5", - "SUBS_NAME": "NB Paris CPU load > 75", - "SUBS_DESCRIPTION": "CPU load too high on NB Paris", + "SUBS_NAME": "NE Paris CPU load > 75", + "SUBS_DESCRIPTION": "CPU load too high on NE Paris", "RESOURCE_URI": "edge/1c2347d5-9463-47d4-a540-fffa3aad1367", - "RESOURCE_NAME": "NB Paris", + "RESOURCE_NAME": "NE Paris", "METRIC": "CPU load %", "CONDITION": ">", "CONDITION_VALUE": "75", diff --git a/tests/metric-with-value-OK.json b/tests/metric-with-value-OK.json index 2d40abc..2fb30e6 100644 --- a/tests/metric-with-value-OK.json +++ b/tests/metric-with-value-OK.json @@ -1,9 +1,9 @@ { "SUBS_ID": "subscription-config/1-2-3-4-5", - "SUBS_NAME": "NB Paris CPU load > 75", - "SUBS_DESCRIPTION": "CPU load too high on NB Paris", + "SUBS_NAME": "NE Paris CPU load > 75", + "SUBS_DESCRIPTION": "CPU load too high on NE Paris", "RESOURCE_URI": "edge/1c2347d5-9463-47d4-a540-fffa3aad1367", - "RESOURCE_NAME": "NB Paris", + "RESOURCE_NAME": "NE Paris", "METRIC": "CPU load %", "CONDITION": ">", "CONDITION_VALUE": "75", diff --git a/tests/slack-template-test.py b/tests/slack-template-test.py index c79cd43..505876e 100755 --- a/tests/slack-template-test.py +++ b/tests/slack-template-test.py @@ -1,13 +1,17 @@ #!/usr/bin/env python3 -import sys import json +import sys + import notify_slack # Slack webhook URL dest = sys.argv[1] tests = [ + 'event-app-pub-app-bq.json', + 'event-app-pub-depl-grp.json', + 'event-app-pub-depl.json', 'metric-no-value-NOK.json', 'metric-no-value-OK.json', 'metric-with-value-NOK.json', diff --git a/tests/test_notify_deps.py b/tests/test_notify_deps.py new file mode 100644 index 0000000..0343f30 --- /dev/null +++ b/tests/test_notify_deps.py @@ -0,0 +1,10 @@ +import unittest + +from notify_deps import timestamp_convert + + +class NotifyDeps(unittest.TestCase): + + @staticmethod + def test_now_timestamp(): + assert '2023-10-08 01:02:03 UTC' == timestamp_convert('2023-10-08T01:02:03Z') diff --git a/tests/test_notify_email.py b/tests/test_notify_email.py index fcd4b26..027e568 100644 --- a/tests/test_notify_email.py +++ b/tests/test_notify_email.py @@ -1,6 +1,14 @@ +import os import unittest -from notify_email import get_recipients +import notify_email +from notify_email import get_recipients, html_content, email_template + +notify_email.EMAIL_TEMPLATES['default'] = email_template( + os.path.join('src', notify_email.EMAIL_TEMPLATE_DEFAULT_FILE)) + +notify_email.EMAIL_TEMPLATES['app-pub'] = email_template( + os.path.join('src', notify_email.EMAIL_TEMPLATE_APP_PUB_FILE)) class NotifyEmail(unittest.TestCase): @@ -12,3 +20,63 @@ def test_get_recipients(self): assert [e1] == get_recipients({'DESTINATION': e1}) assert [e1, e2] == get_recipients({'DESTINATION': f'{e1} {e2}'}) assert [e1, e2] == get_recipients({'DESTINATION': f' {e1} {e2} '}) + + def test_html_content(self): + msg = {'TIMESTAMP': '2023-11-09T10:29:31Z'} + html = html_content(msg) + assert 'Condition' not in html + assert 'Value' not in html + + msg = {'CONDITION': 'foo', + 'VALUE': '123', + 'TIMESTAMP': '2023-11-09T10:29:31Z'} + html = html_content(msg) + assert 'Condition' in html + assert 'Value' in html + + def test_AppAppBqPublishedDeploymentGroupUpdateNotification(self): + + affected_dpl_grp = 'affected deployment group name' + msg = { + 'TEMPLATE': 'app-pub', + + 'SUBS_ID': 'subscription-config/891bdb6c-fb8c-41e6-9023-e317757365ab', + 'SUBS_NAME': 'Apps Published for Deployment', + 'SUBS_DESCRIPTION': 'Apps Published for Deployment', + + 'TRIGGER_RESOURCE_PATH': 'apps/test/new-application', + 'TRIGGER_RESOURCE_NAME': 'test', + + 'RESOURCE_URI': 'deployment-groups/8c9cf316-6092-4d98-97e6-bbf030c1a1ce?deployment-groups-detail-tab=apps', + 'RESOURCE_NAME': f'Update Deployment Group: {affected_dpl_grp}', + + 'TIMESTAMP': '2023-11-29T13:22:26Z', + 'RECOVERY': True + } + html = html_content(msg) + open('email-Apps-Published-for-Deployment.html', 'w').write(html) + + def test_AppPublishedAppsBouquetUpdateNotification(self): + + affected_app_name = 'affected app name' + trigger_app_name = 'trigger app name' + msg = { + 'TEMPLATE': 'app-pub', + + 'SUBS_ID': 'subscription-config/891bdb6c-fb8c-41e6-9023-e317757365ab', + 'DESTINATION': 'https://hooks.slack.com/services/foo', + + 'SUBS_NAME': 'Apps Published for App Bouquet', + 'SUBS_DESCRIPTION': 'Apps Published for App Bouquet', + + 'TRIGGER_RESOURCE_PATH': 'apps/test/trigger-app-name', + 'TRIGGER_RESOURCE_NAME': trigger_app_name, + + 'RESOURCE_URI': 'my-app-bqs/new-app-bq', + 'RESOURCE_NAME': f'Update App Bouquet: {affected_app_name}', + + 'TIMESTAMP': '2023-11-29T13:22:26Z', + 'RECOVERY': True + } + html = html_content(msg) + open('email-Apps-Published-for-AppBq.html', 'w').write(html) diff --git a/tests/test_notify_slack.py b/tests/test_notify_slack.py index da3ef97..a9ee83b 100644 --- a/tests/test_notify_slack.py +++ b/tests/test_notify_slack.py @@ -1,9 +1,23 @@ import unittest -from notify_slack import now_timestamp +from notify_slack import now_timestamp, message_content class NotifyEmail(unittest.TestCase): - def test_now_timestamp(self): + @staticmethod + def test_now_timestamp(): assert isinstance(now_timestamp(), float) + + @staticmethod + def test_message_content_condition_optional(): + msg = {'CONDITION': 'foo', + 'TIMESTAMP': '2023-11-09T10:29:31Z'} + fields = message_content(msg)['attachments'][0]['fields'] + assert 2 == len(list(filter( + lambda x: x['title'] in ['Criteria', 'Value'], fields))) + + msg = {'TIMESTAMP': '2023-11-09T10:29:31Z'} + fields = message_content(msg)['attachments'][0]['fields'] + assert 0 == len(list(filter( + lambda x: x['title'] in ['Criteria', 'Value'], fields)))