Notification Engine for Monasca
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_alarm_processor.py 7.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. # (C) Copyright 2014-2016 Hewlett Packard Enterprise Development LP
  2. # Copyright 2017 Fujitsu LIMITED
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
  13. # implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. """Tests the AlarmProcessor"""
  17. import collections
  18. import json
  19. import mock
  20. import time
  21. from monasca_notification import notification as m_notification
  22. from monasca_notification.processors import alarm_processor
  23. from tests import base
  24. alarm_tuple = collections.namedtuple('alarm_tuple', ['offset', 'message'])
  25. message_tuple = collections.namedtuple('message_tuple', ['value'])
  26. class TestAlarmProcessor(base.BaseTestCase):
  27. def setUp(self):
  28. super(TestAlarmProcessor, self).setUp()
  29. self.trap = []
  30. def _create_raw_alarm(self, partition, offset, message):
  31. """Create a raw alarm, with the given message dictionary.
  32. """
  33. json_msg = json.dumps({'alarm-transitioned': message})
  34. msg_tuple = message_tuple(json_msg)
  35. return [partition, alarm_tuple(offset, msg_tuple)]
  36. @mock.patch('pymysql.connect')
  37. @mock.patch('monasca_notification.processors.alarm_processor.log')
  38. def _run_alarm_processor(self, alarm, sql_response, mock_log, mock_mysql):
  39. """Runs a mocked alarm processor reading from queue while running, returns (queue_message, log_message)
  40. """
  41. # Since the log runs in another thread I can mock it directly, instead change the methods to put to a queue
  42. mock_log.warn = self.trap.append
  43. mock_log.error = self.trap.append
  44. mock_log.exception = self.trap.append
  45. # Setup the sql response
  46. if sql_response is not None:
  47. mock_mysql.return_value = mock_mysql
  48. mock_mysql.cursor.return_value = mock_mysql
  49. mock_mysql.__iter__.return_value = sql_response
  50. self.conf_override(group='mysql', ssl=None,
  51. host='localhost', port='3306',
  52. user='mysql_user', db='dbname',
  53. passwd='mysql_passwd')
  54. self.conf_override(group='statsd', host='localhost',
  55. port=8125)
  56. processor = alarm_processor.AlarmProcessor()
  57. return processor.to_notification(alarm)
  58. def test_invalid_alarm(self):
  59. """Invalid Alarms, should log and error and push to the finished queue."""
  60. alarm = self._create_raw_alarm(0, 1, {'invalid': 'invalid_alarm'})
  61. notifications, partition, offset = self._run_alarm_processor(alarm, None)
  62. self.assertEqual(notifications, [])
  63. self.assertEqual(partition, 0)
  64. self.assertEqual(offset, 1)
  65. invalid_msg = ('Invalid Alarm format skipping partition 0, offset 1\n'
  66. 'ErrorAlarm data missing field actionsEnabled')
  67. self.assertIn(invalid_msg, self.trap)
  68. def test_old_timestamp(self):
  69. """Should cause the alarm_ttl to fire log a warning and push to finished queue."""
  70. timestamp = 1375346830042
  71. alarm_dict = {"tenantId": "0", "alarmDefinitionId": "0", "alarmId": "1", "alarmName": "test Alarm",
  72. "oldState": "OK", "newState": "ALARM", "stateChangeReason": "I am alarming!",
  73. "timestamp": timestamp, "actionsEnabled": 1, "metrics": "cpu_util",
  74. "severity": "LOW", "link": "http://some-place.com", "lifecycleState": "OPEN"}
  75. alarm = self._create_raw_alarm(0, 2, alarm_dict)
  76. expected_datetime = time.ctime(timestamp / 1000)
  77. notifications, partition, offset = self._run_alarm_processor(alarm, None)
  78. self.assertEqual(notifications, [])
  79. self.assertEqual(partition, 0)
  80. self.assertEqual(offset, 2)
  81. old_msg = ('Received alarm older than the ttl, skipping. '
  82. 'Alarm from {datetime}'.format(datetime=expected_datetime))
  83. self.assertIn(old_msg, self.trap)
  84. def test_no_notifications(self):
  85. """Test an alarm with no defined notifications
  86. """
  87. alarm_dict = {"tenantId": "0", "alarmDefinitionId": "0", "alarmId": "1", "alarmName": "test Alarm",
  88. "oldState": "OK", "newState": "ALARM", "stateChangeReason": "I am alarming!",
  89. "timestamp": time.time() * 1000, "actionsEnabled": 1, "metrics": "cpu_util",
  90. "severity": "LOW", "link": "http://some-place.com", "lifecycleState": "OPEN"}
  91. alarm = self._create_raw_alarm(0, 3, alarm_dict)
  92. notifications, partition, offset = self._run_alarm_processor(alarm, None)
  93. self.assertEqual(notifications, [])
  94. self.assertEqual(partition, 0)
  95. self.assertEqual(offset, 3)
  96. def test_valid_notification(self):
  97. """Test a valid notification, being put onto the notification_queue
  98. """
  99. alarm_dict = {"tenantId": "0", "alarmDefinitionId": "0", "alarmId": "1", "alarmName": "test Alarm",
  100. "oldState": "OK", "newState": "ALARM", "stateChangeReason": "I am alarming!",
  101. "timestamp": time.time() * 1000, "actionsEnabled": 1, "metrics": "cpu_util",
  102. "severity": "LOW", "link": "http://some-place.com", "lifecycleState": "OPEN"}
  103. alarm = self._create_raw_alarm(0, 4, alarm_dict)
  104. sql_response = [[1, 'EMAIL', 'test notification', 'me@here.com', 0]]
  105. notifications, partition, offset = self._run_alarm_processor(alarm, sql_response)
  106. test_notification = m_notification.Notification(1, 'email', 'test notification',
  107. 'me@here.com', 0, 0, alarm_dict)
  108. self.assertEqual(notifications, [test_notification])
  109. self.assertEqual(partition, 0)
  110. self.assertEqual(offset, 4)
  111. def test_two_valid_notifications(self):
  112. alarm_dict = {"tenantId": "0", "alarmDefinitionId": "0", "alarmId": "1", "alarmName": "test Alarm",
  113. "oldState": "OK", "newState": "ALARM", "stateChangeReason": "I am alarming!",
  114. "timestamp": time.time() * 1000, "actionsEnabled": 1, "metrics": "cpu_util",
  115. "severity": "LOW", "link": "http://some-place.com", "lifecycleState": "OPEN"}
  116. alarm = self._create_raw_alarm(0, 5, alarm_dict)
  117. sql_response = [[1, 'EMAIL', 'test notification', 'me@here.com', 0],
  118. [2, 'EMAIL', 'test notification2', 'me@here.com', 0]]
  119. notifications, partition, offset = self._run_alarm_processor(alarm, sql_response)
  120. test_notification = m_notification.Notification(1, 'email', 'test notification',
  121. 'me@here.com', 0, 0, alarm_dict)
  122. test_notification2 = m_notification.Notification(2, 'email', 'test notification2',
  123. 'me@here.com', 0, 0, alarm_dict)
  124. self.assertEqual(notifications, [test_notification, test_notification2])
  125. self.assertEqual(partition, 0)
  126. self.assertEqual(offset, 5)