Added LICENSE file to root folder
[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', a_id=alarm_id,
119 r_id=resource_id,
120 sev=values['severity'], date=a_date,
121 state=values['current'], vim_type="OpenStack")
122 self._producer.publish_alarm_response(
123 'notify_alarm', resp_message)
124 except Exception:
125 pass
126
127
128 def get_free_port():
129 """Function to get a free port to run the test webserver on."""
130 s = socket.socket(socket.AF_INET, type=socket.SOCK_STREAM)
131 s.bind(('localhost', 0))
132 address, port = s.getsockname()
133 s.close()
134 return port
135
136
137 # Create the webserver, port and run it on its own thread
138 mock_server_port = get_free_port()
139 mock_server = HTTPServer(('localhost', mock_server_port), MockNotifierHandler)
140 mock_server_thread = Thread(target=mock_server.serve_forever)
141 mock_server_thread.setDaemon(True)
142 mock_server_thread.start()
143
144
145 def test_do_get():
146 """Integration test for get request on notifier webserver."""
147 url = 'http://localhost:{port}/users'.format(port=mock_server_port)
148
149 # Send a request to the mock API server and store the response.
150 response = requests.get(url)
151
152 # Confirm that the request-response cycle completed successfully.
153 assert response.ok
154
155
156 class AlarmNotificationTest(unittest.TestCase):
157 @mock.patch.object(KafkaProducer, "publish_alarm_response")
158 @mock.patch.object(OpenStack_Response, "generate_response")
159 @mock.patch.object(Common, "perform_request")
160 @mock.patch.object(Common, "get_endpoint")
161 @mock.patch.object(Common, "get_auth_token")
162 def test_post_notify_alarm(self, auth, endpoint, perf_req, resp, notify):
163 """Integration test for notify_alarm."""
164 url = 'http://localhost:{port}/users'.format(port=mock_server_port)
165 payload = {"severity": "critical",
166 "alarm_name": "my_alarm",
167 "current": "current_state",
168 "alarm_id": "my_alarm_id",
169 "reason": "Threshold has been broken",
170 "reason_data": {"count": 1,
171 "most_recent": "null",
172 "type": "threshold",
173 "disposition": "unknown"},
174 "previous": "previous_state"}
175
176 # Mock authenticate and request response for testing
177 auth.return_value = "my_auth_token"
178 endpoint.return_value = "my_endpoint"
179 perf_req.return_value = MockResponse(valid_get_resp)
180
181 # Generate a post request for testing
182 response = requests.post(url, json.dumps(payload))
183 self.assertEqual(response.status_code, 200)
184 # A response message is generated with the following details
185 resp.assert_called_with(
186 "notify_alarm", a_id="my_alarm_id", r_id="my_resource_id",
187 sev="critical", date='dd-mm-yyyy 00:00', state="current_state",
188 vim_type="OpenStack")
189
190 # Response message is sent back to the SO via MON's producer
191 notify.assert_called_with("notify_alarm", mock.ANY)