Coverage for osm_policy_module/tests/unit/autoscaling/test_autoscaling_service.py: 91%

186 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-05-07 08:03 +0000

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## 

24import asyncio 

25import datetime 

26from unittest import TestCase, mock 

27 

28from osm_policy_module.autoscaling.service import AutoscalingService 

29from osm_policy_module.common.common_db_client import CommonDbClient 

30from osm_policy_module.common.lcm_client import LcmClient 

31from osm_policy_module.common.mon_client import MonClient 

32from osm_policy_module.core.config import Config 

33from 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) 

39class 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