Fix INF-359 and INF-352 about the alarm event record
[pti/o2.git] / tests / unit / test_alarm.py
1 # Copyright (C) 2021 Wind River Systems, Inc.
2 #
3 #  Licensed under the Apache License, Version 2.0 (the "License");
4 #  you may not use this file except in compliance with the License.
5 #  You may obtain a copy of the License at
6 #
7 #      http://www.apache.org/licenses/LICENSE-2.0
8 #
9 #  Unless required by applicable law or agreed to in writing, software
10 #  distributed under the License is distributed on an "AS IS" BASIS,
11 #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 #  See the License for the specific language governing permissions and
13 #  limitations under the License.
14
15 import uuid
16 import time
17 import json
18 from datetime import datetime
19 from unittest.mock import MagicMock
20 from typing import Callable
21
22 from o2common.service.watcher import worker
23 from o2common.service.unit_of_work import AbstractUnitOfWork
24 from o2common.service.client.base_client import BaseClient
25 from o2common.service.watcher.base import BaseWatcher, WatcherTree
26 from o2common.service import messagebus
27 from o2common.config import config
28
29 from o2ims.domain.resource_type import ResourceTypeEnum
30 from o2ims.domain import alarm_obj
31 from o2ims.domain import commands
32 from o2ims.views import alarm_view
33 from o2ims.service.watcher.alarm_watcher import AlarmWatcher
34
35 from o2app.service import handlers
36 from o2app import bootstrap
37
38
39 def test_new_alarm_event_record():
40     alarm_event_record_id1 = str(uuid.uuid4())
41     alarm_event_record = alarm_obj.AlarmEventRecord(
42         alarm_event_record_id1, '',
43         '', '', '', alarm_obj.PerceivedSeverityEnum.CRITICAL)
44     assert alarm_event_record_id1 is not None and \
45         alarm_event_record.alarmEventRecordId == alarm_event_record_id1
46
47
48 def test_view_alarm_event_records(mock_uow):
49     session, uow = mock_uow
50
51     alarm_event_record_id1 = str(uuid.uuid4())
52     alarm_event_record1 = MagicMock()
53     alarm_event_record1.serialize.return_value = {
54         "alarmEventRecordId": alarm_event_record_id1}
55
56     order_by = MagicMock()
57     order_by.count.return_value = 1
58     order_by.limit.return_value.offset.return_value = [alarm_event_record1]
59     session.return_value.query.return_value.filter.return_value.\
60         order_by.return_value = order_by
61
62     result = alarm_view.alarm_event_records(uow)
63     assert result['count'] == 1
64     ret_list = result['results']
65     assert str(ret_list[0].get("alarmEventRecordId")) == alarm_event_record_id1
66
67
68 def test_view_alarm_event_record_one(mock_uow):
69     session, uow = mock_uow
70
71     alarm_event_record_id1 = str(uuid.uuid4())
72     session.return_value.query.return_value.filter_by.return_value.first.\
73         return_value.serialize.return_value = None
74
75     # Query return None
76     alarm_event_record1 = alarm_view.alarm_event_record_one(
77         alarm_event_record_id1, uow)
78     assert alarm_event_record1 is None
79
80     session.return_value.query.return_value.filter_by.return_value.first.\
81         return_value.serialize.return_value = {
82             "alarmEventRecordId": alarm_event_record_id1}
83
84     alarm_event_record1 = alarm_view.alarm_event_record_one(
85         alarm_event_record_id1, uow)
86     assert str(alarm_event_record1.get(
87         "alarmEventRecordId")) == alarm_event_record_id1
88
89
90 def test_view_alarm_subscriptions(mock_uow):
91     session, uow = mock_uow
92
93     subscription_id1 = str(uuid.uuid4())
94     sub1 = MagicMock()
95     sub1.serialize.return_value = {
96         "alarmSubscriptionId": subscription_id1,
97     }
98
99     order_by = MagicMock()
100     order_by.count.return_value = 1
101     order_by.limit.return_value.offset.return_value = [sub1]
102     session.return_value.query.return_value.filter.return_value.\
103         order_by.return_value = order_by
104
105     result = alarm_view.subscriptions(uow)
106     assert result['count'] == 1
107     ret_list = result['results']
108     assert str(ret_list[0].get("alarmSubscriptionId")) == subscription_id1
109
110
111 def test_view_alarm_subscription_one(mock_uow):
112     session, uow = mock_uow
113
114     subscription_id1 = str(uuid.uuid4())
115     session.return_value.query.return_value.filter_by.return_value.first.\
116         return_value.serialize.return_value = None
117
118     # Query return None
119     subscription_res = alarm_view.subscription_one(
120         subscription_id1, uow)
121     assert subscription_res is None
122
123     session.return_value.query.return_value.filter_by.return_value.first.\
124         return_value.serialize.return_value = {
125             "alarmSubscriptionId": subscription_id1,
126         }
127
128     subscription_res = alarm_view.subscription_one(
129         subscription_id1, uow)
130     assert str(subscription_res.get(
131         "alarmSubscriptionId")) == subscription_id1
132
133
134 def test_flask_get_list(mock_flask_uow):
135     session, app = mock_flask_uow
136     order_by = MagicMock()
137     order_by.count.return_value = 0
138     order_by.limit.return_value.offset.return_value = []
139     session.return_value.query.return_value.filter.return_value.\
140         order_by.return_value = order_by
141     apibase = config.get_o2ims_monitoring_api_base() + '/v1'
142
143     with app.test_client() as client:
144         # Get list and return empty list
145         ##########################
146         resp = client.get(apibase+"/alarms")
147         assert resp.get_data() == b'[]\n'
148
149         resp = client.get(apibase+"/alarmSubscriptions")
150         assert resp.get_data() == b'[]\n'
151
152
153 def test_flask_get_one(mock_flask_uow):
154     session, app = mock_flask_uow
155
156     session.return_value.query.return_value.filter_by.return_value.\
157         first.return_value = None
158     apibase = config.get_o2ims_monitoring_api_base() + '/v1'
159
160     with app.test_client() as client:
161         # Get one and return 404
162         ###########################
163         alarm_id1 = str(uuid.uuid4())
164         resp = client.get(apibase+"/alarms/"+alarm_id1)
165         assert resp.status_code == 404
166
167         sub_id1 = str(uuid.uuid4())
168         resp = client.get(apibase+"/alarmSubscriptions/"+sub_id1)
169         assert resp.status_code == 404
170
171
172 def test_flask_post(mock_flask_uow, mappers):
173     session, app = mock_flask_uow
174     apibase = config.get_o2ims_monitoring_api_base() + '/v1'
175
176     order_by = MagicMock()
177     order_by.count.return_value = 0
178     order_by.limit.return_value.offset.return_value = []
179     session.return_value.query.return_value.filter.return_value.\
180         order_by.return_value = order_by
181
182     with app.test_client() as client:
183         session.return_value.execute.return_value = []
184
185         sub_callback = 'http://subscription/callback/url'
186         resp = client.post(apibase+'/alarmSubscriptions', json={
187             'callback': sub_callback,
188             'consumerSubscriptionId': 'consumerSubId1',
189             'filter': '(eq,resourceTypeId,xxx)'
190         })
191         assert resp.status_code == 201
192         assert 'alarmSubscriptionId' in resp.get_json()
193
194
195 def test_flask_delete(mock_flask_uow):
196     session, app = mock_flask_uow
197     apibase = config.get_o2ims_monitoring_api_base() + '/v1'
198
199     with app.test_client() as client:
200         session.return_value.execute.return_value.first.return_value = {}
201
202         subscription_id1 = str(uuid.uuid4())
203         resp = client.delete(apibase+"/alarmSubscriptions/"+subscription_id1)
204         assert resp.status_code == 200
205
206
207 def test_flask_not_allowed(mock_flask_uow):
208     _, app = mock_flask_uow
209     apibase = config.get_o2ims_monitoring_api_base() + '/v1'
210
211     with app.test_client() as client:
212         # Testing resource type not support method
213         ##########################
214         uri = apibase + "/alarms"
215         resp = client.post(uri)
216         assert resp.status == '405 METHOD NOT ALLOWED'
217         resp = client.put(uri)
218         assert resp.status == '405 METHOD NOT ALLOWED'
219         resp = client.patch(uri)
220         assert resp.status == '405 METHOD NOT ALLOWED'
221         resp = client.delete(uri)
222         assert resp.status == '405 METHOD NOT ALLOWED'
223
224
225 class FakeAlarmClient(BaseClient):
226     def __init__(self):
227         super().__init__()
228         fakeAlarm = alarm_obj.FaultGenericModel(ResourceTypeEnum.OCLOUD)
229         fakeAlarm.id = str(uuid.uuid4())
230         fakeAlarm.name = 'alarm'
231         fakeAlarm.content = json.dumps({})
232         fakeAlarm.createtime = datetime.now()
233         fakeAlarm.updatetime = datetime.now()
234         fakeAlarm.hash = str(hash((fakeAlarm.id, fakeAlarm.updatetime)))
235         self.fakeAlarm = fakeAlarm
236
237     def _get(self, id) -> alarm_obj.FaultGenericModel:
238         return self.fakeAlarm
239
240     def _list(self):
241         return [self.fakeAlarm]
242
243     def _set_stx_client(self):
244         pass
245
246
247 # class FakeStxObjRepo(StxObjectRepository):
248 #     def __init__(self):
249 #         super().__init__()
250 #         self.alarms = []
251
252 #     def _add(self, alarm: alarm_obj.AlarmEventRecord):
253 #         self.alarms.append(alarm)
254
255 #     def _get(self, alarmid) -> alarm_obj.AlarmEventRecord:
256 #         filtered = [a for a in self.alarms if a.id == alarmid]
257 #         return filtered.pop()
258
259 #     def _list(self) -> List[alarm_obj.AlarmEventRecord]:
260 #         return [x for x in self.oclouds]
261
262 #     def _update(self, alarm: alarm_obj.AlarmEventRecord):
263 #         filtered = [a for a in self.alarms if a.id == alarm.id]
264 #         assert len(filtered) == 1
265 #         ocloud1 = filtered.pop()
266 #         ocloud1.update_by(alarm)
267
268
269 class FakeUnitOfWork(AbstractUnitOfWork):
270     def __init__(self, session_factory=None):
271         self.session_factory = session_factory
272
273     def __enter__(self):
274         self.session = self.session_factory
275         # self.stxobjects = FakeStxObjRepo()
276         return super().__enter__()
277
278     def __exit__(self, *args):
279         super().__exit__(*args)
280         # self.session.close()
281
282     def _commit(self):
283         pass
284         # self.session.commit()
285
286     def rollback(self):
287         pass
288         # self.session.rollback()
289
290     def collect_new_events(self):
291         yield
292         # return super().collect_new_events()
293
294
295 def create_alarm_fake_bus(uow):
296     def update_alarm(
297             cmd: commands.UpdateAlarm,
298             uow: AbstractUnitOfWork,
299             publish: Callable):
300         return
301
302     handlers.EVENT_HANDLERS = {}
303     handlers.COMMAND_HANDLERS = {
304         commands.UpdateAlarm: update_alarm,
305     }
306     bus = bootstrap.bootstrap(False, uow)
307     return bus
308
309
310 def test_probe_new_alarm():
311     session = MagicMock()
312     session.return_value.execute.return_value = []
313     fakeuow = FakeUnitOfWork(session)
314     bus = create_alarm_fake_bus(fakeuow)
315     fakeClient = FakeAlarmClient()
316     alarmwatcher = AlarmWatcher(fakeClient, bus)
317     parent = type('obj', (object,), {
318         'data': type('obj', (object,), {
319             'id': 'test_parent_id',
320             'res_pool_id': 'test_res_pool'
321         })})
322     cmds = alarmwatcher.probe(parent)
323     assert cmds is not None
324     assert len(cmds) == 1
325     assert cmds[0].data.name == "alarm"
326     # assert len(fakeuow.stxobjects.oclouds) == 1
327     # assert fakeuow.stxobjects.oclouds[0].name == "stx1"
328
329
330 def test_watchers_worker():
331     testedworker = worker.PollWorker()
332
333     class FakeAlarmWatcher(BaseWatcher):
334         def __init__(self, client: BaseClient,
335                      bus: messagebus) -> None:
336             super().__init__(client, None)
337             self.fakeOcloudWatcherCounter = 0
338             self._client = client
339             self._bus = bus
340
341         def _targetname(self):
342             return "fakealarmwatcher"
343
344         def _probe(self, parent: object = None, tags=None):
345             # import pdb; pdb.set_trace()
346             self.fakeOcloudWatcherCounter += 1
347             # hacking to stop the blocking sched task
348             if self.fakeOcloudWatcherCounter > 2:
349                 testedworker.stop()
350             return []
351
352     # fakeRepo = FakeOcloudRepo()
353     fakeuow = FakeUnitOfWork()
354     bus = create_alarm_fake_bus(fakeuow)
355
356     fakeClient = FakeAlarmClient()
357     fakewatcher = FakeAlarmWatcher(fakeClient, bus)
358
359     root = WatcherTree(fakewatcher)
360
361     testedworker.set_interval(1)
362     testedworker.add_watcher(root)
363     assert fakewatcher.fakeOcloudWatcherCounter == 0
364
365     count1 = fakewatcher.fakeOcloudWatcherCounter
366     testedworker.start()
367     time.sleep(20)
368     assert fakewatcher.fakeOcloudWatcherCounter > count1
369
370     # assumed hacking: probe has stopped the sched task
371     count3 = fakewatcher.fakeOcloudWatcherCounter
372     time.sleep(3)
373     assert fakewatcher.fakeOcloudWatcherCounter == count3