Feature 10986: Autoheal switch and Autoscale switch
[osm/POL.git] / osm_policy_module / tests / unit / autoscaling / test_autoscaling_service.py
1 # -*- coding: utf-8 -*-
2
3 # Copyright 2018 Whitestack, LLC
4 # *************************************************************
5
6 # This file is part of OSM Monitoring module
7 # All Rights Reserved to Whitestack, LLC
8
9 # Licensed under the Apache License, Version 2.0 (the "License"); you may
10 # not use this file except in compliance with the License. You may obtain
11 # a copy of the License at
12
13 # http://www.apache.org/licenses/LICENSE-2.0
14
15 # Unless required by applicable law or agreed to in writing, software
16 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
18 # License for the specific language governing permissions and limitations
19 # under the License.
20
21 # For those usages not covered by the Apache License, Version 2.0 please
22 # contact: bdiaz@whitestack.com or glavado@whitestack.com
23 ##
24 import asyncio
25 import datetime
26 from unittest import TestCase, mock
27
28 from osm_policy_module.autoscaling.service import AutoscalingService
29 from osm_policy_module.common.common_db_client import CommonDbClient
30 from osm_policy_module.common.lcm_client import LcmClient
31 from osm_policy_module.common.mon_client import MonClient
32 from osm_policy_module.core.config import Config
33 from osm_policy_module.core.database import ScalingAlarmRepository
34
35
36 @mock.patch.object(LcmClient, "__init__", lambda *args, **kwargs: None)
37 @mock.patch.object(MonClient, "__init__", lambda *args, **kwargs: None)
38 @mock.patch.object(CommonDbClient, "__init__", lambda *args, **kwargs: None)
39 class TestAutoscalingService(TestCase):
40 def setUp(self):
41 self.config = Config()
42
43 @mock.patch.object(ScalingAlarmRepository, "get")
44 @mock.patch("osm_policy_module.core.database.db")
45 def test_update_alarm_status(self, database, get_alarm):
46 mock_alarm = mock.Mock()
47 mock_alarm.last_status = "insufficient_data"
48 get_alarm.return_value = mock_alarm
49
50 service = AutoscalingService(self.config)
51 asyncio.run(service.update_alarm_status("test_uuid", "alarm"))
52 self.assertEqual(mock_alarm.last_status, "alarm")
53 mock_alarm.save.assert_called_with()
54
55 service = AutoscalingService(self.config)
56 asyncio.run(service.update_alarm_status("test_uuid", "ok"))
57 self.assertEqual(mock_alarm.last_status, "ok")
58 mock_alarm.save.assert_called_with()
59
60 service = AutoscalingService(self.config)
61 asyncio.run(service.update_alarm_status("test_uuid", "insufficient_data"))
62 self.assertEqual(mock_alarm.last_status, "insufficient_data")
63 mock_alarm.save.assert_called_with()
64
65 @mock.patch.object(ScalingAlarmRepository, "list")
66 @mock.patch.object(ScalingAlarmRepository, "get")
67 @mock.patch("osm_policy_module.core.database.db")
68 def test_evaluate_policy_not_enabled(self, database, get_alarm, list_alarms):
69 mock_alarm = mock.Mock()
70 mock_alarm.scaling_criteria.scaling_policy.enabled = False
71 get_alarm.return_value = mock_alarm
72
73 service = AutoscalingService(self.config)
74 asyncio.run(service.evaluate_policy("test_uuid"))
75 list_alarms.assert_not_called()
76
77 @mock.patch.object(ScalingAlarmRepository, "list")
78 @mock.patch.object(ScalingAlarmRepository, "get")
79 @mock.patch.object(LcmClient, "scale")
80 @mock.patch("osm_policy_module.core.database.db")
81 def test_evaluate_policy_scale_in_and_equal(
82 self, database, scale, get_alarm, list_alarms
83 ):
84 """
85 Tests scale in with AND operation, both alarms triggered
86 """
87 future = asyncio.Future(loop=asyncio.new_event_loop())
88 future.set_result("mock")
89 scale.return_value = future
90
91 mock_alarm = self._build_mock_alarm(
92 action="scale_in", last_status="alarm", enabled=True, scale_in_op="AND"
93 )
94 get_alarm.return_value = mock_alarm
95
96 mock_alarm_2 = self._build_mock_alarm(
97 action="scale_in", last_status="alarm", enabled=True, scale_in_op="AND"
98 )
99
100 list_alarms.return_value = [mock_alarm, mock_alarm_2]
101
102 service = AutoscalingService(self.config)
103 if self.config.get("autoscale", "enabled") == "True":
104 asyncio.run(service.evaluate_policy("test_uuid"))
105 scale.assert_called_with("test_nsr_id", "test_group", "1", "scale_in")
106
107 @mock.patch.object(ScalingAlarmRepository, "list")
108 @mock.patch.object(ScalingAlarmRepository, "get")
109 @mock.patch.object(LcmClient, "scale")
110 @mock.patch("osm_policy_module.core.database.db")
111 def test_evaluate_policy_scale_in_and_diff(
112 self, database, scale, get_alarm, list_alarms
113 ):
114 """
115 Tests scale in with AND operation, only one alarm triggered.
116 """
117 future = asyncio.Future(loop=asyncio.new_event_loop())
118 future.set_result("mock")
119 scale.return_value = future
120
121 mock_alarm = self._build_mock_alarm(
122 action="scale_in", last_status="alarm", enabled=True, scale_in_op="AND"
123 )
124 get_alarm.return_value = mock_alarm
125
126 mock_alarm_2 = self._build_mock_alarm(
127 action="scale_in", last_status="ok", enabled=True, scale_in_op="OR"
128 )
129
130 list_alarms.return_value = [mock_alarm, mock_alarm_2]
131
132 service = AutoscalingService(self.config)
133 if self.config.get("autoscale", "enabled") == "True":
134 asyncio.run(service.evaluate_policy("test_uuid"))
135 scale.assert_not_called()
136
137 @mock.patch.object(ScalingAlarmRepository, "list")
138 @mock.patch.object(ScalingAlarmRepository, "get")
139 @mock.patch.object(LcmClient, "scale")
140 @mock.patch("osm_policy_module.core.database.db")
141 def test_evaluate_policy_scale_in_or_equal(
142 self, database, scale, get_alarm, list_alarms
143 ):
144 """
145 Tests scale in with OR operation, both alarms triggered
146 """
147 future = asyncio.Future(loop=asyncio.new_event_loop())
148 future.set_result("mock")
149 scale.return_value = future
150
151 mock_alarm = self._build_mock_alarm(
152 action="scale_in", last_status="alarm", enabled=True, scale_in_op="OR"
153 )
154 get_alarm.return_value = mock_alarm
155
156 mock_alarm_2 = self._build_mock_alarm(
157 action="scale_in", last_status="alarm", enabled=True, scale_in_op="OR"
158 )
159
160 list_alarms.return_value = [mock_alarm, mock_alarm_2]
161
162 service = AutoscalingService(self.config)
163 if self.config.get("autoscale", "enabled") == "True":
164 asyncio.run(service.evaluate_policy("test_uuid"))
165 scale.assert_called_with("test_nsr_id", "test_group", "1", "scale_in")
166
167 @mock.patch.object(ScalingAlarmRepository, "list")
168 @mock.patch.object(ScalingAlarmRepository, "get")
169 @mock.patch.object(LcmClient, "scale")
170 @mock.patch("osm_policy_module.core.database.db")
171 def test_evaluate_policy_scale_in_or_diff(
172 self, database, scale, get_alarm, list_alarms
173 ):
174 """
175 Tests scale in with OR operation, only one alarm triggered
176 """
177 future = asyncio.Future(loop=asyncio.new_event_loop())
178 future.set_result("mock")
179 scale.return_value = future
180
181 mock_alarm = self._build_mock_alarm(
182 action="scale_in", last_status="alarm", enabled=True, scale_in_op="OR"
183 )
184 get_alarm.return_value = mock_alarm
185
186 mock_alarm_2 = self._build_mock_alarm(
187 action="scale_in", last_status="ok", enabled=True, scale_in_op="OR"
188 )
189
190 list_alarms.return_value = [mock_alarm, mock_alarm_2]
191
192 service = AutoscalingService(self.config)
193 if self.config.get("autoscale", "enabled") == "True":
194 asyncio.run(service.evaluate_policy("test_uuid"))
195 scale.assert_called_with("test_nsr_id", "test_group", "1", "scale_in")
196
197 @mock.patch.object(ScalingAlarmRepository, "list")
198 @mock.patch.object(ScalingAlarmRepository, "get")
199 @mock.patch.object(LcmClient, "scale")
200 @mock.patch("osm_policy_module.core.database.db")
201 def test_evaluate_policy_scale_out_and_equal(
202 self, database, scale, get_alarm, list_alarms
203 ):
204 """
205 Tests scale out with AND operation, both alarms triggered
206 """
207 future = asyncio.Future(loop=asyncio.new_event_loop())
208 future.set_result("mock")
209 scale.return_value = future
210
211 mock_alarm = self._build_mock_alarm(
212 action="scale_out", last_status="alarm", enabled=True, scale_out_op="AND"
213 )
214 get_alarm.return_value = mock_alarm
215
216 mock_alarm_2 = self._build_mock_alarm(
217 action="scale_out", last_status="alarm", enabled=True, scale_out_op="AND"
218 )
219
220 list_alarms.return_value = [mock_alarm, mock_alarm_2]
221
222 service = AutoscalingService(self.config)
223 if self.config.get("autoscale", "enabled") == "True":
224 asyncio.run(service.evaluate_policy("test_uuid"))
225 scale.assert_called_with("test_nsr_id", "test_group", "1", "scale_out")
226
227 @mock.patch.object(ScalingAlarmRepository, "list")
228 @mock.patch.object(ScalingAlarmRepository, "get")
229 @mock.patch.object(LcmClient, "scale")
230 @mock.patch("osm_policy_module.core.database.db")
231 def test_evaluate_policy_scale_out_and_diff(
232 self, database, scale, get_alarm, list_alarms
233 ):
234 """
235 Tests scale out with AND operation, only one alarm triggered.
236 """
237 future = asyncio.Future(loop=asyncio.new_event_loop())
238 future.set_result("mock")
239 scale.return_value = future
240
241 mock_alarm = self._build_mock_alarm(
242 action="scale_out", last_status="alarm", enabled=True, scale_out_op="AND"
243 )
244 get_alarm.return_value = mock_alarm
245
246 mock_alarm_2 = self._build_mock_alarm(
247 action="scale_out", last_status="ok", enabled=True, scale_out_op="OR"
248 )
249
250 list_alarms.return_value = [mock_alarm, mock_alarm_2]
251
252 service = AutoscalingService(self.config)
253 if self.config.get("autoscale", "enabled") == "True":
254 asyncio.run(service.evaluate_policy("test_uuid"))
255 scale.assert_not_called()
256
257 @mock.patch.object(ScalingAlarmRepository, "list")
258 @mock.patch.object(ScalingAlarmRepository, "get")
259 @mock.patch.object(LcmClient, "scale")
260 @mock.patch("osm_policy_module.core.database.db")
261 def test_evaluate_policy_scale_out_or_equal(
262 self, database, scale, get_alarm, list_alarms
263 ):
264 """
265 Tests scale out with OR operation, both alarms triggered
266 """
267 future = asyncio.Future(loop=asyncio.new_event_loop())
268 future.set_result("mock")
269 scale.return_value = future
270
271 mock_alarm = self._build_mock_alarm(
272 action="scale_out", last_status="alarm", enabled=True, scale_out_op="OR"
273 )
274 get_alarm.return_value = mock_alarm
275
276 mock_alarm_2 = self._build_mock_alarm(
277 action="scale_out", last_status="alarm", enabled=True, scale_out_op="OR"
278 )
279
280 list_alarms.return_value = [mock_alarm, mock_alarm_2]
281
282 service = AutoscalingService(self.config)
283 asyncio.run(service.evaluate_policy("test_uuid"))
284 if self.config.get("autoscale", "enabled") == "True":
285 asyncio.run(service.evaluate_policy("test_uuid"))
286 scale.assert_called_with("test_nsr_id", "test_group", "1", "scale_out")
287
288 @mock.patch.object(ScalingAlarmRepository, "list")
289 @mock.patch.object(ScalingAlarmRepository, "get")
290 @mock.patch.object(LcmClient, "scale")
291 @mock.patch("osm_policy_module.core.database.db")
292 def test_evaluate_policy_scale_out_or_diff(
293 self, database, scale, get_alarm, list_alarms
294 ):
295 """
296 Tests scale out with OR operation, only one alarm triggered
297 """
298 future = asyncio.Future(loop=asyncio.new_event_loop())
299 future.set_result("mock")
300 scale.return_value = future
301
302 mock_alarm = self._build_mock_alarm(
303 action="scale_out", last_status="alarm", enabled=True, scale_out_op="OR"
304 )
305 get_alarm.return_value = mock_alarm
306
307 mock_alarm_2 = self._build_mock_alarm(
308 action="scale_out", last_status="ok", enabled=True, scale_out_op="OR"
309 )
310
311 list_alarms.return_value = [mock_alarm, mock_alarm_2]
312
313 service = AutoscalingService(self.config)
314 asyncio.run(service.evaluate_policy("test_uuid"))
315 if self.config.get("autoscale", "enabled") == "True":
316 asyncio.run(service.evaluate_policy("test_uuid"))
317 scale.assert_called_with("test_nsr_id", "test_group", "1", "scale_out")
318
319 def _build_mock_alarm(
320 self,
321 action="scale_in",
322 last_status="alarm",
323 last_scale=datetime.datetime.min,
324 cooldown_time=10,
325 enabled=True,
326 scale_in_op="AND",
327 scale_out_op="AND",
328 ):
329 mock_alarm = mock.Mock()
330 mock_alarm.action = action
331 mock_alarm.last_status = last_status
332 mock_alarm.vnf_member_index = "1"
333 mock_alarm.scaling_criteria.scaling_policy.last_scale = last_scale
334 mock_alarm.scaling_criteria.scaling_policy.cooldown_time = cooldown_time
335 mock_alarm.scaling_criteria.scaling_policy.enabled = enabled
336 mock_alarm.scaling_criteria.scaling_policy.scale_in_operation = scale_in_op
337 mock_alarm.scaling_criteria.scaling_policy.scale_out_operation = scale_out_op
338 mock_alarm.scaling_criteria.scaling_policy.scaling_group.nsr_id = "test_nsr_id"
339 mock_alarm.scaling_criteria.scaling_policy.scaling_group.name = "test_group"
340 return mock_alarm