| Helena McGough | 94f93f7 | 2017-11-23 17:29:54 +0000 | [diff] [blame] | 1 | # Copyright 2017 Intel Research and Development Ireland Limited |
| 2 | # ************************************************************* |
| 3 | |
| 4 | # This file is part of OSM Monitoring module |
| 5 | # All Rights Reserved to Intel Corporation |
| 6 | |
| 7 | # Licensed under the Apache License, Version 2.0 (the "License"); you may |
| 8 | # not use this file except in compliance with the License. You may obtain |
| 9 | # a copy of the License at |
| 10 | |
| 11 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 12 | |
| 13 | # Unless required by applicable law or agreed to in writing, software |
| 14 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| 15 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| 16 | # License for the specific language governing permissions and limitations |
| 17 | # under the License. |
| 18 | |
| 19 | # For those usages not covered by the Apache License, Version 2.0 please |
| 20 | # contact: helena.mcgough@intel.com or adrian.hoban@intel.com |
| 21 | ## |
| 22 | """Tests for all common OpenStack methods.""" |
| 23 | |
| 24 | import json |
| 25 | |
| 26 | import unittest |
| 27 | |
| 28 | from BaseHTTPServer import BaseHTTPRequestHandler |
| 29 | |
| Helena McGough | 94f93f7 | 2017-11-23 17:29:54 +0000 | [diff] [blame] | 30 | import mock |
| 31 | |
| Helena McGough | effeb7c | 2017-11-23 15:54:08 +0000 | [diff] [blame] | 32 | from osm_mon.core.message_bus.producer import KafkaProducer |
| Helena McGough | 94f93f7 | 2017-11-23 17:29:54 +0000 | [diff] [blame] | 33 | |
| Helena McGough | effeb7c | 2017-11-23 15:54:08 +0000 | [diff] [blame] | 34 | from osm_mon.plugins.OpenStack.Aodh.alarming import Alarming |
| 35 | from osm_mon.plugins.OpenStack.common import Common |
| 36 | from osm_mon.plugins.OpenStack.response import OpenStack_Response |
| 37 | from osm_mon.plugins.OpenStack.settings import Config |
| Helena McGough | 94f93f7 | 2017-11-23 17:29:54 +0000 | [diff] [blame] | 38 | |
| 39 | # Mock data from post request |
| 40 | post_data = json.dumps({"severity": "critical", |
| 41 | "alarm_name": "my_alarm", |
| 42 | "current": "current_state", |
| 43 | "alarm_id": "my_alarm_id", |
| 44 | "reason": "Threshold has been broken", |
| 45 | "reason_data": {"count": 1, |
| 46 | "most_recent": "null", |
| 47 | "type": "threshold", |
| 48 | "disposition": "unknown"}, |
| 49 | "previous": "previous_state"}) |
| 50 | |
| 51 | valid_get_resp = '{"gnocchi_resources_threshold_rule":\ |
| 52 | {"resource_id": "my_resource_id"}}' |
| 53 | |
| 54 | invalid_get_resp = '{"gnocchi_resources_threshold_rule":\ |
| Benjamin Diaz | 181cce8 | 2018-03-28 21:12:11 -0300 | [diff] [blame] | 55 | {"resource_id": null}}' |
| Helena McGough | 94f93f7 | 2017-11-23 17:29:54 +0000 | [diff] [blame] | 56 | |
| 57 | valid_notify_resp = '{"notify_details": {"status": "current_state",\ |
| 58 | "severity": "critical",\ |
| 59 | "resource_uuid": "my_resource_id",\ |
| 60 | "alarm_uuid": "my_alarm_id",\ |
| 61 | "vim_type": "OpenStack",\ |
| 62 | "start_date": "dd-mm-yyyy 00:00"},\ |
| 63 | "schema_version": "1.0",\ |
| 64 | "schema_type": "notify_alarm"}' |
| 65 | |
| 66 | invalid_notify_resp = '{"notify_details": {"invalid":"mock_details"}' |
| 67 | |
| 68 | |
| 69 | class Response(object): |
| 70 | """Mock a response class for generating responses.""" |
| 71 | |
| 72 | def __init__(self, text): |
| 73 | """Initialise a mock response with a text attribute.""" |
| 74 | self.text = text |
| 75 | |
| 76 | |
| 77 | class NotifierHandler(BaseHTTPRequestHandler): |
| 78 | """Mock the NotifierHandler class for testing purposes.""" |
| 79 | |
| 80 | def __init__(self, request, client_address, server): |
| 81 | """Initilase mock NotifierHandler.""" |
| 82 | self.request = request |
| 83 | self.client_address = client_address |
| 84 | self.server = server |
| 85 | self.setup() |
| 86 | try: |
| 87 | self.handle() |
| 88 | finally: |
| 89 | self.finish() |
| 90 | |
| 91 | def setup(self): |
| 92 | """Mock setup function.""" |
| 93 | pass |
| 94 | |
| 95 | def handle(self): |
| 96 | """Mock handle function.""" |
| 97 | pass |
| 98 | |
| 99 | def finish(self): |
| 100 | """Mock finish function.""" |
| 101 | pass |
| 102 | |
| 103 | def _set_headers(self): |
| 104 | """Mock getting the request headers.""" |
| 105 | pass |
| 106 | |
| 107 | def do_GET(self): |
| 108 | """Mock functionality for GET request.""" |
| 109 | self._set_headers() |
| 110 | pass |
| 111 | |
| 112 | def do_POST(self): |
| 113 | """Mock functionality for a POST request.""" |
| 114 | self._set_headers() |
| 115 | self.notify_alarm(json.loads(post_data)) |
| 116 | |
| 117 | def notify_alarm(self, values): |
| 118 | """Mock the notify_alarm functionality to generate a valid response.""" |
| 119 | config = Config.instance() |
| Benjamin Diaz | 181cce8 | 2018-03-28 21:12:11 -0300 | [diff] [blame] | 120 | config.read_environ() |
| Helena McGough | 94f93f7 | 2017-11-23 17:29:54 +0000 | [diff] [blame] | 121 | self._alarming = Alarming() |
| 122 | self._common = Common() |
| 123 | self._response = OpenStack_Response() |
| 124 | self._producer = KafkaProducer('alarm_response') |
| 125 | alarm_id = values['alarm_id'] |
| 126 | |
| Benjamin Diaz | 181cce8 | 2018-03-28 21:12:11 -0300 | [diff] [blame] | 127 | vim_uuid = 'test_id' |
| 128 | |
| 129 | auth_token = Common.get_auth_token(vim_uuid) |
| 130 | endpoint = Common.get_endpoint("alarming", vim_uuid) |
| Helena McGough | 94f93f7 | 2017-11-23 17:29:54 +0000 | [diff] [blame] | 131 | |
| 132 | # If authenticated generate and send response message |
| Benjamin Diaz | 181cce8 | 2018-03-28 21:12:11 -0300 | [diff] [blame] | 133 | if auth_token is not None and endpoint is not None: |
| Helena McGough | 94f93f7 | 2017-11-23 17:29:54 +0000 | [diff] [blame] | 134 | url = "{}/v2/alarms/%s".format(endpoint) % alarm_id |
| 135 | |
| 136 | # Get the resource_id of the triggered alarm and the date |
| Benjamin Diaz | 181cce8 | 2018-03-28 21:12:11 -0300 | [diff] [blame] | 137 | result = Common.perform_request( |
| Helena McGough | 94f93f7 | 2017-11-23 17:29:54 +0000 | [diff] [blame] | 138 | url, auth_token, req_type="get") |
| 139 | alarm_details = json.loads(result.text) |
| 140 | gnocchi_rule = alarm_details['gnocchi_resources_threshold_rule'] |
| 141 | resource_id = gnocchi_rule['resource_id'] |
| 142 | a_date = "dd-mm-yyyy 00:00" |
| 143 | |
| 144 | # Process an alarm notification if resource_id is valid |
| 145 | if resource_id is not None: |
| 146 | # Try generate and send response |
| 147 | try: |
| 148 | resp_message = self._response.generate_response( |
| 149 | 'notify_alarm', a_id=alarm_id, |
| 150 | r_id=resource_id, |
| 151 | sev=values['severity'], date=a_date, |
| 152 | state=values['current'], vim_type="OpenStack") |
| 153 | self._producer.notify_alarm( |
| 154 | 'notify_alarm', resp_message, 'alarm_response') |
| 155 | except Exception: |
| 156 | pass |
| 157 | |
| 158 | |
| 159 | class TestNotifier(unittest.TestCase): |
| 160 | """Test the NotifierHandler class for requests from aodh.""" |
| 161 | |
| 162 | def setUp(self): |
| 163 | """Setup tests.""" |
| 164 | super(TestNotifier, self).setUp() |
| 165 | self.handler = NotifierHandler( |
| 166 | "mock_request", "mock_address", "mock_server") |
| 167 | |
| 168 | @mock.patch.object(NotifierHandler, "_set_headers") |
| 169 | def test_do_GET(self, set_head): |
| 170 | """Test do_GET, generates headers for get request.""" |
| 171 | self.handler.do_GET() |
| 172 | |
| Benjamin Diaz | 181cce8 | 2018-03-28 21:12:11 -0300 | [diff] [blame] | 173 | set_head.assert_called_once() |
| Helena McGough | 94f93f7 | 2017-11-23 17:29:54 +0000 | [diff] [blame] | 174 | |
| 175 | @mock.patch.object(NotifierHandler, "notify_alarm") |
| 176 | @mock.patch.object(NotifierHandler, "_set_headers") |
| 177 | def test_do_POST(self, set_head, notify): |
| 178 | """Test do_POST functionality for a POST request.""" |
| 179 | self.handler.do_POST() |
| 180 | |
| Benjamin Diaz | 181cce8 | 2018-03-28 21:12:11 -0300 | [diff] [blame] | 181 | set_head.assert_called_once() |
| Helena McGough | 94f93f7 | 2017-11-23 17:29:54 +0000 | [diff] [blame] | 182 | notify.assert_called_with(json.loads(post_data)) |
| 183 | |
| 184 | @mock.patch.object(Common, "get_endpoint") |
| Benjamin Diaz | 181cce8 | 2018-03-28 21:12:11 -0300 | [diff] [blame] | 185 | @mock.patch.object(Common, "get_auth_token") |
| 186 | @mock.patch.object(Common, "perform_request") |
| Helena McGough | 94f93f7 | 2017-11-23 17:29:54 +0000 | [diff] [blame] | 187 | def test_notify_alarm_unauth(self, perf_req, auth, endpoint): |
| 188 | """Test notify alarm when not authenticated with keystone.""" |
| 189 | # Response request will not be performed unless there is a valid |
| 190 | # auth_token and endpoint |
| 191 | # Invalid auth_token and endpoint |
| 192 | auth.return_value = None |
| 193 | endpoint.return_value = None |
| 194 | self.handler.notify_alarm(json.loads(post_data)) |
| 195 | |
| Benjamin Diaz | 181cce8 | 2018-03-28 21:12:11 -0300 | [diff] [blame] | 196 | perf_req.assert_not_called() |
| Helena McGough | 94f93f7 | 2017-11-23 17:29:54 +0000 | [diff] [blame] | 197 | |
| 198 | # Valid endpoint |
| 199 | auth.return_value = None |
| 200 | endpoint.return_value = "my_endpoint" |
| 201 | self.handler.notify_alarm(json.loads(post_data)) |
| 202 | |
| Benjamin Diaz | 181cce8 | 2018-03-28 21:12:11 -0300 | [diff] [blame] | 203 | perf_req.assert_not_called() |
| Helena McGough | 94f93f7 | 2017-11-23 17:29:54 +0000 | [diff] [blame] | 204 | |
| 205 | # Valid auth_token |
| 206 | auth.return_value = "my_auth_token" |
| 207 | endpoint.return_value = None |
| 208 | self.handler.notify_alarm(json.loads(post_data)) |
| 209 | |
| Benjamin Diaz | 181cce8 | 2018-03-28 21:12:11 -0300 | [diff] [blame] | 210 | perf_req.assert_not_called() |
| Helena McGough | 94f93f7 | 2017-11-23 17:29:54 +0000 | [diff] [blame] | 211 | |
| 212 | @mock.patch.object(Common, "get_endpoint") |
| 213 | @mock.patch.object(OpenStack_Response, "generate_response") |
| Benjamin Diaz | 181cce8 | 2018-03-28 21:12:11 -0300 | [diff] [blame] | 214 | @mock.patch.object(Common, "get_auth_token") |
| 215 | @mock.patch.object(Common, "perform_request") |
| Helena McGough | 94f93f7 | 2017-11-23 17:29:54 +0000 | [diff] [blame] | 216 | def test_notify_alarm_invalid_alarm(self, perf_req, auth, resp, endpoint): |
| 217 | """Test valid authentication, invalid alarm details.""" |
| 218 | # Mock valid auth_token and endpoint |
| 219 | auth.return_value = "my_auth_token" |
| 220 | endpoint.return_value = "my_endpoint" |
| 221 | perf_req.return_value = Response(invalid_get_resp) |
| 222 | |
| 223 | self.handler.notify_alarm(json.loads(post_data)) |
| 224 | |
| 225 | # Response is not generated |
| Benjamin Diaz | 181cce8 | 2018-03-28 21:12:11 -0300 | [diff] [blame] | 226 | resp.assert_not_called() |
| Helena McGough | 94f93f7 | 2017-11-23 17:29:54 +0000 | [diff] [blame] | 227 | |
| Benjamin Diaz | 181cce8 | 2018-03-28 21:12:11 -0300 | [diff] [blame] | 228 | @mock.patch.object(KafkaProducer, "notify_alarm") |
| Helena McGough | 94f93f7 | 2017-11-23 17:29:54 +0000 | [diff] [blame] | 229 | @mock.patch.object(Common, "get_endpoint") |
| 230 | @mock.patch.object(OpenStack_Response, "generate_response") |
| Benjamin Diaz | 181cce8 | 2018-03-28 21:12:11 -0300 | [diff] [blame] | 231 | @mock.patch.object(Common, "get_auth_token") |
| 232 | @mock.patch.object(Common, "perform_request") |
| 233 | def test_notify_alarm_resp_call(self, perf_req, auth, response, endpoint, notify): |
| Helena McGough | 94f93f7 | 2017-11-23 17:29:54 +0000 | [diff] [blame] | 234 | """Test notify_alarm tries to generate a response for SO.""" |
| 235 | # Mock valid auth token and endpoint, valid response from aodh |
| 236 | auth.return_value = "my_auth_token" |
| 237 | endpoint.returm_value = "my_endpoint" |
| 238 | perf_req.return_value = Response(valid_get_resp) |
| 239 | self.handler.notify_alarm(json.loads(post_data)) |
| 240 | |
| Benjamin Diaz | 181cce8 | 2018-03-28 21:12:11 -0300 | [diff] [blame] | 241 | notify.assert_called() |
| Helena McGough | 94f93f7 | 2017-11-23 17:29:54 +0000 | [diff] [blame] | 242 | response.assert_called_with('notify_alarm', a_id="my_alarm_id", |
| 243 | r_id="my_resource_id", sev="critical", |
| 244 | date="dd-mm-yyyy 00:00", |
| 245 | state="current_state", |
| 246 | vim_type="OpenStack") |
| 247 | |
| 248 | @mock.patch.object(Common, "get_endpoint") |
| 249 | @mock.patch.object(KafkaProducer, "notify_alarm") |
| 250 | @mock.patch.object(OpenStack_Response, "generate_response") |
| Benjamin Diaz | 181cce8 | 2018-03-28 21:12:11 -0300 | [diff] [blame] | 251 | @mock.patch.object(Common, "get_auth_token") |
| 252 | @mock.patch.object(Common, "perform_request") |
| 253 | @unittest.skip("Schema validation not implemented yet.") |
| Helena McGough | 94f93f7 | 2017-11-23 17:29:54 +0000 | [diff] [blame] | 254 | def test_notify_alarm_invalid_resp( |
| 255 | self, perf_req, auth, response, notify, endpoint): |
| 256 | """Test the notify_alarm function, sends response to the producer.""" |
| 257 | # Generate return values for valid notify_alarm operation |
| 258 | auth.return_value = "my_auth_token" |
| 259 | endpoint.return_value = "my_endpoint" |
| 260 | perf_req.return_value = Response(valid_get_resp) |
| 261 | response.return_value = invalid_notify_resp |
| 262 | |
| 263 | self.handler.notify_alarm(json.loads(post_data)) |
| 264 | |
| Benjamin Diaz | 181cce8 | 2018-03-28 21:12:11 -0300 | [diff] [blame] | 265 | notify.assert_not_called() |
| Helena McGough | 94f93f7 | 2017-11-23 17:29:54 +0000 | [diff] [blame] | 266 | |
| 267 | @mock.patch.object(Common, "get_endpoint") |
| 268 | @mock.patch.object(KafkaProducer, "notify_alarm") |
| 269 | @mock.patch.object(OpenStack_Response, "generate_response") |
| Benjamin Diaz | 181cce8 | 2018-03-28 21:12:11 -0300 | [diff] [blame] | 270 | @mock.patch.object(Common, "get_auth_token") |
| 271 | @mock.patch.object(Common, "perform_request") |
| Helena McGough | 94f93f7 | 2017-11-23 17:29:54 +0000 | [diff] [blame] | 272 | def test_notify_alarm_valid_resp( |
| 273 | self, perf_req, auth, response, notify, endpoint): |
| 274 | """Test the notify_alarm function, sends response to the producer.""" |
| 275 | # Generate return values for valid notify_alarm operation |
| 276 | auth.return_value = "my_auth_token" |
| 277 | endpoint.return_value = "my_endpoint" |
| 278 | perf_req.return_value = Response(valid_get_resp) |
| 279 | response.return_value = valid_notify_resp |
| 280 | |
| 281 | self.handler.notify_alarm(json.loads(post_data)) |
| 282 | |
| 283 | notify.assert_called_with( |
| 284 | "notify_alarm", valid_notify_resp, "alarm_response") |