| 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":\ |
| 55 | {"resource_id": "None"}}' |
| 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() |
| 120 | config.read_environ("aodh") |
| 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 | |
| 127 | auth_token = self._common._authenticate() |
| 128 | endpoint = self._common.get_endpoint("alarming") |
| 129 | |
| 130 | # If authenticated generate and send response message |
| 131 | if (auth_token is not None and endpoint is not None): |
| 132 | url = "{}/v2/alarms/%s".format(endpoint) % alarm_id |
| 133 | |
| 134 | # Get the resource_id of the triggered alarm and the date |
| 135 | result = self._common._perform_request( |
| 136 | url, auth_token, req_type="get") |
| 137 | alarm_details = json.loads(result.text) |
| 138 | gnocchi_rule = alarm_details['gnocchi_resources_threshold_rule'] |
| 139 | resource_id = gnocchi_rule['resource_id'] |
| 140 | a_date = "dd-mm-yyyy 00:00" |
| 141 | |
| 142 | # Process an alarm notification if resource_id is valid |
| 143 | if resource_id is not None: |
| 144 | # Try generate and send response |
| 145 | try: |
| 146 | resp_message = self._response.generate_response( |
| 147 | 'notify_alarm', a_id=alarm_id, |
| 148 | r_id=resource_id, |
| 149 | sev=values['severity'], date=a_date, |
| 150 | state=values['current'], vim_type="OpenStack") |
| 151 | self._producer.notify_alarm( |
| 152 | 'notify_alarm', resp_message, 'alarm_response') |
| 153 | except Exception: |
| 154 | pass |
| 155 | |
| 156 | |
| 157 | class TestNotifier(unittest.TestCase): |
| 158 | """Test the NotifierHandler class for requests from aodh.""" |
| 159 | |
| 160 | def setUp(self): |
| 161 | """Setup tests.""" |
| 162 | super(TestNotifier, self).setUp() |
| 163 | self.handler = NotifierHandler( |
| 164 | "mock_request", "mock_address", "mock_server") |
| 165 | |
| 166 | @mock.patch.object(NotifierHandler, "_set_headers") |
| 167 | def test_do_GET(self, set_head): |
| 168 | """Test do_GET, generates headers for get request.""" |
| 169 | self.handler.do_GET() |
| 170 | |
| 171 | set_head.assert_called_once |
| 172 | |
| 173 | @mock.patch.object(NotifierHandler, "notify_alarm") |
| 174 | @mock.patch.object(NotifierHandler, "_set_headers") |
| 175 | def test_do_POST(self, set_head, notify): |
| 176 | """Test do_POST functionality for a POST request.""" |
| 177 | self.handler.do_POST() |
| 178 | |
| 179 | set_head.assert_called_once |
| 180 | notify.assert_called_with(json.loads(post_data)) |
| 181 | |
| 182 | @mock.patch.object(Common, "get_endpoint") |
| 183 | @mock.patch.object(Common, "_authenticate") |
| 184 | @mock.patch.object(Common, "_perform_request") |
| 185 | def test_notify_alarm_unauth(self, perf_req, auth, endpoint): |
| 186 | """Test notify alarm when not authenticated with keystone.""" |
| 187 | # Response request will not be performed unless there is a valid |
| 188 | # auth_token and endpoint |
| 189 | # Invalid auth_token and endpoint |
| 190 | auth.return_value = None |
| 191 | endpoint.return_value = None |
| 192 | self.handler.notify_alarm(json.loads(post_data)) |
| 193 | |
| 194 | perf_req.assert_not_called |
| 195 | |
| 196 | # Valid endpoint |
| 197 | auth.return_value = None |
| 198 | endpoint.return_value = "my_endpoint" |
| 199 | self.handler.notify_alarm(json.loads(post_data)) |
| 200 | |
| 201 | perf_req.assert_not_called |
| 202 | |
| 203 | # Valid auth_token |
| 204 | auth.return_value = "my_auth_token" |
| 205 | endpoint.return_value = None |
| 206 | self.handler.notify_alarm(json.loads(post_data)) |
| 207 | |
| 208 | perf_req.assert_not_called |
| 209 | |
| 210 | @mock.patch.object(Common, "get_endpoint") |
| 211 | @mock.patch.object(OpenStack_Response, "generate_response") |
| 212 | @mock.patch.object(Common, "_authenticate") |
| 213 | @mock.patch.object(Common, "_perform_request") |
| 214 | def test_notify_alarm_invalid_alarm(self, perf_req, auth, resp, endpoint): |
| 215 | """Test valid authentication, invalid alarm details.""" |
| 216 | # Mock valid auth_token and endpoint |
| 217 | auth.return_value = "my_auth_token" |
| 218 | endpoint.return_value = "my_endpoint" |
| 219 | perf_req.return_value = Response(invalid_get_resp) |
| 220 | |
| 221 | self.handler.notify_alarm(json.loads(post_data)) |
| 222 | |
| 223 | # Response is not generated |
| 224 | resp.assert_not_called |
| 225 | |
| 226 | @mock.patch.object(Common, "get_endpoint") |
| 227 | @mock.patch.object(OpenStack_Response, "generate_response") |
| 228 | @mock.patch.object(Common, "_authenticate") |
| 229 | @mock.patch.object(Common, "_perform_request") |
| 230 | def test_notify_alarm_resp_call(self, perf_req, auth, response, endpoint): |
| 231 | """Test notify_alarm tries to generate a response for SO.""" |
| 232 | # Mock valid auth token and endpoint, valid response from aodh |
| 233 | auth.return_value = "my_auth_token" |
| 234 | endpoint.returm_value = "my_endpoint" |
| 235 | perf_req.return_value = Response(valid_get_resp) |
| 236 | self.handler.notify_alarm(json.loads(post_data)) |
| 237 | |
| 238 | response.assert_called_with('notify_alarm', a_id="my_alarm_id", |
| 239 | r_id="my_resource_id", sev="critical", |
| 240 | date="dd-mm-yyyy 00:00", |
| 241 | state="current_state", |
| 242 | vim_type="OpenStack") |
| 243 | |
| 244 | @mock.patch.object(Common, "get_endpoint") |
| 245 | @mock.patch.object(KafkaProducer, "notify_alarm") |
| 246 | @mock.patch.object(OpenStack_Response, "generate_response") |
| 247 | @mock.patch.object(Common, "_authenticate") |
| 248 | @mock.patch.object(Common, "_perform_request") |
| 249 | def test_notify_alarm_invalid_resp( |
| 250 | self, perf_req, auth, response, notify, endpoint): |
| 251 | """Test the notify_alarm function, sends response to the producer.""" |
| 252 | # Generate return values for valid notify_alarm operation |
| 253 | auth.return_value = "my_auth_token" |
| 254 | endpoint.return_value = "my_endpoint" |
| 255 | perf_req.return_value = Response(valid_get_resp) |
| 256 | response.return_value = invalid_notify_resp |
| 257 | |
| 258 | self.handler.notify_alarm(json.loads(post_data)) |
| 259 | |
| 260 | notify.assert_not_called |
| 261 | |
| 262 | @mock.patch.object(Common, "get_endpoint") |
| 263 | @mock.patch.object(KafkaProducer, "notify_alarm") |
| 264 | @mock.patch.object(OpenStack_Response, "generate_response") |
| 265 | @mock.patch.object(Common, "_authenticate") |
| 266 | @mock.patch.object(Common, "_perform_request") |
| 267 | def test_notify_alarm_valid_resp( |
| 268 | self, perf_req, auth, response, notify, endpoint): |
| 269 | """Test the notify_alarm function, sends response to the producer.""" |
| 270 | # Generate return values for valid notify_alarm operation |
| 271 | auth.return_value = "my_auth_token" |
| 272 | endpoint.return_value = "my_endpoint" |
| 273 | perf_req.return_value = Response(valid_get_resp) |
| 274 | response.return_value = valid_notify_resp |
| 275 | |
| 276 | self.handler.notify_alarm(json.loads(post_data)) |
| 277 | |
| 278 | notify.assert_called_with( |
| 279 | "notify_alarm", valid_notify_resp, "alarm_response") |