Refactors code in OpenStack plugin
[osm/MON.git] / osm_mon / test / OpenStack / integration / test_notify_alarm.py
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
25 from __future__ import unicode_literals
26 import json
27 import logging
28 import socket
29 import unittest
30 from threading import Thread
31
32 import mock
33 import requests
34 from six.moves.BaseHTTPServer import BaseHTTPRequestHandler
35 from six.moves.BaseHTTPServer import HTTPServer
36
37 from osm_mon.core.message_bus.producer import KafkaProducer
38 from osm_mon.core.settings import Config
39 from osm_mon.plugins.OpenStack.Aodh.alarming import Alarming
40 from osm_mon.plugins.OpenStack.common import Common
41 from osm_mon.plugins.OpenStack.response import OpenStack_Response
42
43 log = logging.getLogger(__name__)
44
45 # Create an instance of the common openstack class, producer and consumer
46 openstack_auth = Common()
47
48 # Mock a valid get_response for alarm details
49 valid_get_resp = '{"gnocchi_resources_threshold_rule":\
50 {"resource_id": "my_resource_id"}}'
51
52
53 class MockResponse(object):
54 """Mock a response class for generating responses."""
55
56 def __init__(self, text):
57 """Initialise a mock response with a text attribute."""
58 self.text = text
59
60
61 class MockNotifierHandler(BaseHTTPRequestHandler):
62 """Mock the NotifierHandler class for testing purposes."""
63
64 def _set_headers(self):
65 """Set the headers for a request."""
66 self.send_response(200)
67 self.send_header('Content-type', 'text/html')
68 self.end_headers()
69
70 def do_GET(self):
71 """Mock functionality for GET request."""
72 # self.send_response(requests.codes.ok)
73 self._set_headers()
74 pass
75
76 def do_POST(self):
77 """Mock functionality for a POST request."""
78 self._set_headers()
79 content_length = int(self.headers['Content-Length'])
80 post_data = self.rfile.read(content_length)
81 try:
82 post_data = post_data.decode()
83 except AttributeError:
84 pass
85 self.notify_alarm(json.loads(post_data))
86
87 def notify_alarm(self, values):
88 """Mock the notify_alarm functionality to generate a valid response."""
89 config = Config.instance()
90 config.read_environ()
91 self._alarming = Alarming()
92 self._common = Common()
93 self._response = OpenStack_Response()
94 self._producer = KafkaProducer('alarm_response')
95 alarm_id = values['alarm_id']
96
97 auth_token = Common.get_auth_token('test_id')
98 endpoint = Common.get_endpoint('alarming', 'test_id')
99
100 # If authenticated generate and send response message
101 if auth_token is not None and endpoint is not None:
102 url = "{}/v2/alarms/%s".format(endpoint) % alarm_id
103
104 # Get the resource_id of the triggered alarm and the date
105 result = Common.perform_request(
106 url, auth_token, req_type="get")
107 alarm_details = json.loads(result.text)
108 gnocchi_rule = alarm_details['gnocchi_resources_threshold_rule']
109 resource_id = gnocchi_rule['resource_id']
110 # Mock a date for testing purposes
111 a_date = "dd-mm-yyyy 00:00"
112
113 # Process an alarm notification if resource_id is valid
114 if resource_id is not None:
115 # Try generate and send response
116 try:
117 resp_message = self._response.generate_response(
118 'notify_alarm',
119 alarm_id=alarm_id,
120 resource_id=resource_id,
121 sev=values['severity'], date=a_date,
122 state=values['current'], vim_type="OpenStack")
123 self._producer.publish_alarm_response(
124 'notify_alarm', resp_message)
125 except Exception:
126 pass
127
128
129 def get_free_port():
130 """Function to get a free port to run the test webserver on."""
131 s = socket.socket(socket.AF_INET, type=socket.SOCK_STREAM)
132 s.bind(('localhost', 0))
133 address, port = s.getsockname()
134 s.close()
135 return port
136
137
138 # Create the webserver, port and run it on its own thread
139 mock_server_port = get_free_port()
140 mock_server = HTTPServer(('localhost', mock_server_port), MockNotifierHandler)
141 mock_server_thread = Thread(target=mock_server.serve_forever)
142 mock_server_thread.setDaemon(True)
143 mock_server_thread.start()
144
145
146 def test_do_get():
147 """Integration test for get request on notifier webserver."""
148 url = 'http://localhost:{port}/users'.format(port=mock_server_port)
149
150 # Send a request to the mock API server and store the response.
151 response = requests.get(url)
152
153 # Confirm that the request-response cycle completed successfully.
154 assert response.ok
155
156
157 class AlarmNotificationTest(unittest.TestCase):
158 @mock.patch.object(KafkaProducer, "publish_alarm_response")
159 @mock.patch.object(OpenStack_Response, "generate_response")
160 @mock.patch.object(Common, "perform_request")
161 @mock.patch.object(Common, "get_endpoint")
162 @mock.patch.object(Common, "get_auth_token")
163 def test_post_notify_alarm(self, auth, endpoint, perf_req, resp, notify):
164 """Integration test for notify_alarm."""
165 url = 'http://localhost:{port}/users'.format(port=mock_server_port)
166 payload = {"severity": "critical",
167 "alarm_name": "my_alarm",
168 "current": "current_state",
169 "alarm_id": "my_alarm_id",
170 "reason": "Threshold has been broken",
171 "reason_data": {"count": 1,
172 "most_recent": "null",
173 "type": "threshold",
174 "disposition": "unknown"},
175 "previous": "previous_state"}
176
177 # Mock authenticate and request response for testing
178 auth.return_value = "my_auth_token"
179 endpoint.return_value = "my_endpoint"
180 perf_req.return_value = MockResponse(valid_get_resp)
181
182 # Generate a post request for testing
183 response = requests.post(url, json.dumps(payload))
184 self.assertEqual(response.status_code, 200)
185 # A response message is generated with the following details
186 resp.assert_called_with(
187 "notify_alarm", alarm_id="my_alarm_id", resource_id="my_resource_id",
188 sev="critical", date='dd-mm-yyyy 00:00', state="current_state",
189 vim_type="OpenStack")
190
191 # Response message is sent back to the SO via MON's producer
192 notify.assert_called_with("notify_alarm", mock.ANY)