Pack notifications to be compatible with SDL golang
[ric-plt/sdlpy.git] / ricsdl-package / tests / test_syncstorage.py
1 # Copyright (c) 2019 AT&T Intellectual Property.
2 # Copyright (c) 2018-2019 Nokia.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 #
17 # This source code is part of the near-RT RIC (RAN Intelligent Controller)
18 # platform project (RICP).
19 #
20
21
22 from unittest.mock import patch, Mock
23 import pytest
24 from ricsdl.syncstorage import SyncStorage
25 from ricsdl.syncstorage import SyncLock
26 from ricsdl.syncstorage import func_arg_checker
27 from ricsdl.exceptions import (SdlTypeError, NotConnected)
28
29 EVENT_SEPARATOR = "___"
30
31 @pytest.fixture()
32 def sync_storage_fixture(request):
33     request.cls.ns = 'some-ns'
34     request.cls.key = 'a'
35     request.cls.keys = {'a', 'b'}
36     request.cls.dm = {'b': b'2', 'a': b'1'}
37     request.cls.old_data = b'1'
38     request.cls.new_data = b'3'
39     request.cls.keyprefix = 'x'
40     request.cls.matchedkeys = ['x1', 'x2', 'x3', 'x4', 'x5']
41     request.cls.group = 'some-group'
42     request.cls.groupmembers = set([b'm1', b'm2'])
43     request.cls.groupmember = b'm1'
44     request.cls.lock_name = 'some-lock-name'
45     request.cls.lock_int_expiration = 10
46     request.cls.lock_float_expiration = 1.1
47     request.cls.channels = {'abs', 'cbn'}
48     request.cls.channels_and_events = {'ch1': 'ev1', 'ch2': ['ev1', 'ev2', 'ev3']}
49     request.cls.ill_event = "illegal" + EVENT_SEPARATOR + "ev"
50
51     with patch('ricsdl.backend.get_backend_instance') as mock_db_backend:
52         storage = SyncStorage()
53         request.cls.mock_db_backend = mock_db_backend.return_value
54     request.cls.storage = storage
55     yield
56
57
58 @pytest.mark.usefixtures('sync_storage_fixture')
59 class TestSyncStorage:
60     def test_is_active_function_success(self):
61         self.mock_db_backend.is_connected.return_value = True
62         ret = self.storage.is_active()
63         self.mock_db_backend.is_connected.assert_called_once()
64         assert ret is True
65
66     def test_is_active_function_can_catch_backend_exception_and_return_false(self):
67         self.mock_db_backend.is_connected.side_effect = NotConnected
68         ret = self.storage.is_active()
69         self.mock_db_backend.is_connected.assert_called_once()
70         assert ret is False
71
72     def test_set_function_success(self):
73         self.storage.set(self.ns, self.dm)
74         self.mock_db_backend.set.assert_called_once_with(self.ns, self.dm)
75
76     def test_set_function_can_raise_exception_for_wrong_argument(self):
77         with pytest.raises(SdlTypeError):
78             self.storage.set(123, {'a': b'v1'})
79         with pytest.raises(SdlTypeError):
80             self.storage.set('ns', [1, 2])
81         with pytest.raises(SdlTypeError):
82             self.storage.set('ns', {0xbad: b'v1'})
83         with pytest.raises(SdlTypeError):
84             self.storage.set('ns', {'a': 0xbad})
85
86     def test_set_if_function_success(self):
87         self.mock_db_backend.set_if.return_value = True
88         ret = self.storage.set_if(self.ns, self.key, self.old_data, self.new_data)
89         self.mock_db_backend.set_if.assert_called_once_with(self.ns, self.key, self.old_data,
90                                                             self.new_data)
91         assert ret is True
92
93     def test_set_if_function_can_return_false_if_same_data_already_exists(self):
94         self.mock_db_backend.set_if.return_value = False
95         ret = self.storage.set_if(self.ns, self.key, self.old_data, self.new_data)
96         self.mock_db_backend.set_if.assert_called_once_with(self.ns, self.key, self.old_data,
97                                                             self.new_data)
98         assert ret is False
99
100     def test_set_if_function_can_raise_exception_for_wrong_argument(self):
101         with pytest.raises(SdlTypeError):
102             self.storage.set_if(0xbad, 'key', b'v1', b'v2')
103         with pytest.raises(SdlTypeError):
104             self.storage.set_if('ns', 0xbad, b'v1', b'v2')
105         with pytest.raises(SdlTypeError):
106             self.storage.set_if('ns', 'key', 0xbad, b'v2')
107         with pytest.raises(SdlTypeError):
108             self.storage.set_if('ns', 'key', b'v1', 0xbad)
109
110     def test_set_if_not_exists_function_success(self):
111         self.mock_db_backend.set_if_not_exists.return_value = True
112         ret = self.storage.set_if_not_exists(self.ns, self.key, self.new_data)
113         self.mock_db_backend.set_if_not_exists.assert_called_once_with(self.ns, self.key,
114                                                                        self.new_data)
115         assert ret is True
116
117     def test_set_if_not_exists_function_can_return_false_if_key_already_exists(self):
118         self.mock_db_backend.set_if_not_exists.return_value = False
119         ret = self.storage.set_if_not_exists(self.ns, self.key, self.new_data)
120         self.mock_db_backend.set_if_not_exists.assert_called_once_with(self.ns, self.key,
121                                                                        self.new_data)
122         assert ret is False
123
124     def test_set_if_not_exists_function_can_raise_exception_for_wrong_argument(self):
125         with pytest.raises(SdlTypeError):
126             self.storage.set_if_not_exists(0xbad, 'key', b'v1')
127         with pytest.raises(SdlTypeError):
128             self.storage.set_if_not_exists('ns', 0xbad, b'v1')
129         with pytest.raises(SdlTypeError):
130             self.storage.set_if_not_exists('ns', 'key', 0xbad)
131
132     def test_get_function_success(self):
133         self.mock_db_backend.get.return_value = self.dm
134         ret = self.storage.get(self.ns, self.keys)
135         self.mock_db_backend.get.assert_called_once()
136         call_args, _ = self.mock_db_backend.get.call_args
137         assert call_args[0] == self.ns
138         assert len(call_args[1]) == len(self.keys)
139         assert all(k in call_args[1] for k in self.keys)
140         assert ret == self.dm
141         # Validate that SDL returns a dictionary with keys in alphabetical order
142         assert sorted(self.dm)[0] == list(ret.keys())[0]
143
144     def test_get_function_can_return_empty_dict_when_no_key_values_exist(self):
145         self.mock_db_backend.get.return_value = dict()
146         ret = self.storage.get(self.ns, self.keys)
147         self.mock_db_backend.get.assert_called_once()
148         call_args, _ = self.mock_db_backend.get.call_args
149         assert call_args[0] == self.ns
150         assert len(call_args[1]) == len(self.keys)
151         assert all(k in call_args[1] for k in self.keys)
152         assert ret == dict()
153
154     def test_get_function_can_raise_exception_for_wrong_argument(self):
155         with pytest.raises(SdlTypeError):
156             self.storage.get(0xbad, self.key)
157         with pytest.raises(SdlTypeError):
158             self.storage.get(self.ns, 0xbad)
159
160     def test_find_keys_function_success(self):
161         self.mock_db_backend.find_keys.return_value = self.matchedkeys
162         ret = self.storage.find_keys(self.ns, self.keyprefix)
163         self.mock_db_backend.find_keys.assert_called_once_with(self.ns, self.keyprefix)
164         assert ret == self.matchedkeys
165
166     def test_find_keys_function_can_return_empty_list_when_no_keys_exist(self):
167         self.mock_db_backend.find_keys.return_value = list()
168         ret = self.storage.find_keys(self.ns, self.keyprefix)
169         self.mock_db_backend.find_keys.assert_called_once_with(self.ns, self.keyprefix)
170         assert ret == list()
171
172     def test_find_keys_function_can_raise_exception_for_wrong_argument(self):
173         with pytest.raises(SdlTypeError):
174             self.storage.find_keys(0xbad, self.keyprefix)
175         with pytest.raises(SdlTypeError):
176             self.storage.find_keys(self.ns, 0xbad)
177
178     def test_find_and_get_function_success(self):
179         self.mock_db_backend.find_and_get.return_value = self.dm
180         ret = self.storage.find_and_get(self.ns, self.keyprefix)
181         self.mock_db_backend.find_and_get.assert_called_once_with(self.ns, self.keyprefix)
182         assert ret == self.dm
183         # Validate that SDL returns a dictionary with keys in alphabetical order
184         assert sorted(self.dm)[0] == list(ret.keys())[0]
185
186     def test_find_and_get_function_can_return_empty_dict_when_no_keys_exist(self):
187         self.mock_db_backend.find_and_get.return_value = dict()
188         ret = self.storage.find_and_get(self.ns, self.keyprefix)
189         self.mock_db_backend.find_and_get.assert_called_once_with(self.ns, self.keyprefix)
190         assert ret == dict()
191
192     def test_find_and_get_function_can_raise_exception_for_wrong_argument(self):
193         with pytest.raises(SdlTypeError):
194             self.storage.find_and_get(0xbad, self.keyprefix)
195         with pytest.raises(SdlTypeError):
196             self.storage.find_and_get(self.ns, 0xbad)
197
198     def test_remove_function_success(self):
199         self.storage.remove(self.ns, self.keys)
200         self.mock_db_backend.remove.assert_called_once()
201         call_args, _ = self.mock_db_backend.remove.call_args
202         assert call_args[0] == self.ns
203         assert isinstance(call_args[1], list)
204         assert len(call_args[1]) == len(self.keys)
205         assert all(k in call_args[1] for k in self.keys)
206
207     def test_remove_function_can_raise_exception_for_wrong_argument(self):
208         with pytest.raises(SdlTypeError):
209             self.storage.remove(0xbad, self.keys)
210         with pytest.raises(SdlTypeError):
211             self.storage.remove(self.ns, 0xbad)
212
213     def test_remove_if_function_success(self):
214         self.mock_db_backend.remove_if.return_value = True
215         ret = self.storage.remove_if(self.ns, self.key, self.new_data)
216         self.mock_db_backend.remove_if.assert_called_once_with(self.ns, self.key, self.new_data)
217         assert ret is True
218
219     def test_remove_if_function_can_return_false_if_data_does_not_match(self):
220         self.mock_db_backend.remove_if.return_value = False
221         ret = self.storage.remove_if(self.ns, self.key, self.old_data)
222         self.mock_db_backend.remove_if.assert_called_once_with(self.ns, self.key, self.old_data)
223         assert ret is False
224
225     def test_remove_if_function_can_raise_exception_for_wrong_argument(self):
226         with pytest.raises(SdlTypeError):
227             self.storage.remove_if(0xbad, self.keys, self.old_data)
228         with pytest.raises(SdlTypeError):
229             self.storage.remove_if(self.ns, 0xbad, self.old_data)
230         with pytest.raises(SdlTypeError):
231             self.storage.remove_if(self.ns, self.keys, 0xbad)
232
233     def test_remove_all_function_success(self):
234         self.mock_db_backend.find_keys.return_value = ['a1']
235         self.storage.remove_all(self.ns)
236         self.mock_db_backend.find_keys.assert_called_once_with(self.ns, '*')
237         self.mock_db_backend.remove.assert_called_once_with(self.ns,
238                                                             self.mock_db_backend.find_keys.return_value)
239
240     def test_remove_all_function_can_raise_exception_for_wrong_argument(self):
241         with pytest.raises(SdlTypeError):
242             self.storage.remove_all(0xbad)
243
244     def test_add_member_function_success(self):
245         self.storage.add_member(self.ns, self.group, self.groupmembers)
246         self.mock_db_backend.add_member.assert_called_once_with(self.ns,
247                                                                 self.group, self.groupmembers)
248
249     def test_add_member_function_can_raise_exception_for_wrong_argument(self):
250         with pytest.raises(SdlTypeError):
251             self.storage.add_member(0xbad, self.group, self.groupmembers)
252         with pytest.raises(SdlTypeError):
253             self.storage.add_member(self.ns, 0xbad, self.groupmembers)
254         with pytest.raises(SdlTypeError):
255             self.storage.add_member(self.ns, self.group, 0xbad)
256
257     def test_remove_member_function_success(self):
258         self.storage.remove_member(self.ns, self.group, self.groupmembers)
259         self.mock_db_backend.remove_member.assert_called_once_with(self.ns, self.group,
260                                                                    self.groupmembers)
261
262     def test_remove_member_function_can_raise_exception_for_wrong_argument(self):
263         with pytest.raises(SdlTypeError):
264             self.storage.remove_member(0xbad, self.group, self.groupmembers)
265         with pytest.raises(SdlTypeError):
266             self.storage.remove_member(self.ns, 0xbad, self.groupmembers)
267         with pytest.raises(SdlTypeError):
268             self.storage.remove_member(self.ns, self.group, 0xbad)
269
270     def test_remove_group_function_success(self):
271         self.storage.remove_group(self.ns, self.group)
272         self.mock_db_backend.remove_group.assert_called_once_with(self.ns, self.group)
273
274     def test_remove_group_function_can_raise_exception_for_wrong_argument(self):
275         with pytest.raises(SdlTypeError):
276             self.storage.remove_group(0xbad, self.group)
277         with pytest.raises(SdlTypeError):
278             self.storage.remove_group(self.ns, 0xbad)
279
280     def test_get_members_function_success(self):
281         self.mock_db_backend.get_members.return_value = self.groupmembers
282         ret = self.storage.get_members(self.ns, self.group)
283         self.mock_db_backend.get_members.assert_called_once_with(self.ns, self.group)
284         assert ret == self.groupmembers
285
286     def test_get_members_function_can_raise_exception_for_wrong_argument(self):
287         with pytest.raises(SdlTypeError):
288             self.storage.get_members(0xbad, self.group)
289         with pytest.raises(SdlTypeError):
290             self.storage.get_members(self.ns, 0xbad)
291
292     def test_is_member_function_success(self):
293         self.mock_db_backend.is_member.return_value = True
294         ret = self.storage.is_member(self.ns, self.group, self.groupmember)
295         self.mock_db_backend.is_member.assert_called_once_with(self.ns, self.group,
296                                                                self.groupmember)
297         assert ret is True
298
299     def test_is_member_function_can_raise_exception_for_wrong_argument(self):
300         with pytest.raises(SdlTypeError):
301             self.storage.is_member(0xbad, self.group, self.groupmember)
302         with pytest.raises(SdlTypeError):
303             self.storage.is_member(self.ns, 0xbad, self.groupmember)
304         with pytest.raises(SdlTypeError):
305             self.storage.is_member(self.ns, self.group, 0xbad)
306
307     def test_group_size_function_success(self):
308         self.mock_db_backend.group_size.return_value = 100
309         ret = self.storage.group_size(self.ns, self.group)
310         self.mock_db_backend.group_size.assert_called_once_with(self.ns, self.group)
311         assert ret == 100
312
313     def test_group_size_function_can_raise_exception_for_wrong_argument(self):
314         with pytest.raises(SdlTypeError):
315             self.storage.group_size(0xbad, self.group)
316         with pytest.raises(SdlTypeError):
317             self.storage.group_size(self.ns, 0xbad)
318
319     def test_set_and_publish_function_success(self):
320         self.storage.set_and_publish(self.ns, self.channels_and_events, self.dm)
321         self.mock_db_backend.set_and_publish.assert_called_once_with(self.ns,
322                                                                      self.channels_and_events,
323                                                                      self.dm)
324
325     def test_set_and_publish_can_raise_exception_for_wrong_argument(self):
326         with pytest.raises(SdlTypeError):
327             self.storage.set_and_publish(123, self.channels_and_events, self.dm)
328         with pytest.raises(SdlTypeError):
329             self.storage.set_and_publish(self.ns, None, self.dm)
330         with pytest.raises(SdlTypeError):
331             self.storage.set_and_publish(self.ns, {0xbad: "ev1"}, self.dm)
332         with pytest.raises(SdlTypeError):
333             self.storage.set_and_publish(self.ns, {"ch1": 0xbad}, self.dm)
334         with pytest.raises(SdlTypeError):
335             self.storage.set_and_publish(self.ns, {"ch1": self.ill_event}, self.dm)
336         with pytest.raises(SdlTypeError):
337             self.storage.set_and_publish(self.ns, {"ch1": ["ev1", 0xbad]}, self.dm)
338         with pytest.raises(SdlTypeError):
339             self.storage.set_and_publish(self.ns, {"ch1": ["ev1", self.ill_event]}, self.dm)
340         with pytest.raises(SdlTypeError):
341             self.storage.set_and_publish(self.ns, self.channels_and_events, [1, 2])
342         with pytest.raises(SdlTypeError):
343             self.storage.set_and_publish(self.ns, self.channels_and_events, {0xbad: b'v1'})
344         with pytest.raises(SdlTypeError):
345             self.storage.set_and_publish(self.ns, self.channels_and_events, {'a': 0xbad})
346
347     def test_set_if_and_publish_success(self):
348         self.mock_db_backend.set_if_and_publish.return_value = True
349         ret = self.storage.set_if_and_publish(self.ns, self.channels_and_events, self.key,
350                                               self.old_data, self.new_data)
351         self.mock_db_backend.set_if_and_publish.assert_called_once_with(
352             self.ns, self.channels_and_events, self.key, self.old_data, self.new_data)
353         assert ret is True
354
355     def test_set_if_and_publish_can_return_false_if_same_data_already_exists(self):
356         self.mock_db_backend.set_if_and_publish.return_value = False
357         ret = self.storage.set_if_and_publish(self.ns, self.channels_and_events, self.key,
358                                               self.old_data, self.new_data)
359         self.mock_db_backend.set_if_and_publish.assert_called_once_with(
360             self.ns, self.channels_and_events, self.key, self.old_data, self.new_data)
361         assert ret is False
362
363     def test_set_if_and_publish_can_raise_exception_for_wrong_argument(self):
364         with pytest.raises(SdlTypeError):
365             self.storage.set_if_and_publish(0xbad, self.channels_and_events, self.key,
366                                             self.old_data, self.new_data)
367         with pytest.raises(SdlTypeError):
368             self.storage.set_if_and_publish(self.ns, None, self.key, self.old_data,
369                                             self.new_data)
370         with pytest.raises(SdlTypeError):
371             self.storage.set_if_and_publish(self.ns, {0xbad: "ev1"}, self.key,
372                                             self.old_data, self.new_data)
373         with pytest.raises(SdlTypeError):
374             self.storage.set_if_and_publish(self.ns, {"ch1": 0xbad}, self.key,
375                                             self.old_data, self.new_data)
376         with pytest.raises(SdlTypeError):
377             self.storage.set_if_and_publish(self.ns, {"ch1": self.ill_event}, self.key,
378                                             self.old_data, self.new_data)
379         with pytest.raises(SdlTypeError):
380             self.storage.set_if_and_publish(self.ns, {"ch1": ["ev1", 0xbad]}, self.key,
381                                             self.old_data, self.new_data)
382         with pytest.raises(SdlTypeError):
383             self.storage.set_if_and_publish(self.ns, {"ch1": ["ev1", self.ill_event]}, self.key,
384                                             self.old_data, self.new_data)
385         with pytest.raises(SdlTypeError):
386             self.storage.set_if_and_publish(self.ns, self.channels_and_events, 0xbad,
387                                             self.old_data, self.new_data)
388         with pytest.raises(SdlTypeError):
389             self.storage.set_if_and_publish(self.ns, self.channels_and_events, self.key,
390                                             0xbad, self.new_data)
391         with pytest.raises(SdlTypeError):
392             self.storage.set_if_and_publish(self.ns, self.channels_and_events, self.key,
393                                             self.old_data, 0xbad)
394
395     def test_set_if_not_exists_and_publish_success(self):
396         self.mock_db_backend.set_if_not_exists_and_publish.return_value = True
397         ret = self.storage.set_if_not_exists_and_publish(self.ns, self.channels_and_events,
398                                                          self.key, self.new_data)
399         self.mock_db_backend.set_if_not_exists_and_publish.assert_called_once_with(
400             self.ns, self.channels_and_events, self.key, self.new_data)
401         assert ret is True
402
403     def test_set_if_not_exists_and_publish_function_can_return_false_if_key_already_exists(self):
404         self.mock_db_backend.set_if_not_exists_and_publish.return_value = False
405         ret = self.storage.set_if_not_exists_and_publish(self.ns, self.channels_and_events,
406                                                          self.key, self.new_data)
407         self.mock_db_backend.set_if_not_exists_and_publish.assert_called_once_with(
408             self.ns, self.channels_and_events, self.key, self.new_data)
409         assert ret is False
410
411     def test_set_if_not_exists_and_publish_can_raise_exception_for_wrong_argument(self):
412         with pytest.raises(SdlTypeError):
413             self.storage.set_if_not_exists_and_publish(0xbad, self.channels_and_events,
414                                                        self.key, self.new_data)
415         with pytest.raises(SdlTypeError):
416             self.storage.set_if_not_exists_and_publish(self.ns, None, self.key,
417                                                        self.new_data)
418         with pytest.raises(SdlTypeError):
419             self.storage.set_if_not_exists_and_publish(self.ns, {0xbad: "ev1"},
420                                                        self.key, self.new_data)
421         with pytest.raises(SdlTypeError):
422             self.storage.set_if_not_exists_and_publish(self.ns, {"ch1": 0xbad},
423                                                        self.key, self.new_data)
424         with pytest.raises(SdlTypeError):
425             self.storage.set_if_not_exists_and_publish(self.ns, {"ch1": self.ill_event},
426                                                        self.key, self.new_data)
427         with pytest.raises(SdlTypeError):
428             self.storage.set_if_not_exists_and_publish(self.ns, {"ch1": ["ev1", 0xbad]},
429                                                        self.key, self.new_data)
430         with pytest.raises(SdlTypeError):
431             self.storage.set_if_not_exists_and_publish(self.ns, {"ch1": ["ev1", self.ill_event]},
432                                                        self.key, self.new_data)
433         with pytest.raises(SdlTypeError):
434             self.storage.set_if_not_exists_and_publish(self.ns, self.channels_and_events,
435                                                        0xbad, b'v1')
436         with pytest.raises(SdlTypeError):
437             self.storage.set_if_not_exists_and_publish(self.ns, self.channels_and_events,
438                                                        self.key, 0xbad)
439
440     def test_remove_and_publish_function_success(self):
441         self.storage.remove_and_publish(self.ns, self.channels_and_events, self.keys)
442         self.mock_db_backend.remove_and_publish.assert_called_once_with(
443             self.ns, self.channels_and_events, list(self.keys))
444
445     def test_remove_and_publish_can_raise_exception_for_wrong_argument(self):
446         with pytest.raises(SdlTypeError):
447             self.storage.remove_and_publish(0xbad, self.channels_and_events, self.keys)
448         with pytest.raises(SdlTypeError):
449             self.storage.remove_and_publish(self.ns, None, self.keys)
450         with pytest.raises(SdlTypeError):
451             self.storage.remove_and_publish(self.ns, {0xbad: "ev1"}, self.keys)
452         with pytest.raises(SdlTypeError):
453             self.storage.remove_and_publish(self.ns, {"ch1": 0xbad}, self.keys)
454         with pytest.raises(SdlTypeError):
455             self.storage.remove_and_publish(self.ns, {"ch1": self.ill_event}, self.keys)
456         with pytest.raises(SdlTypeError):
457             self.storage.remove_and_publish(self.ns, {"ch1": ["ev1", 0xbad]}, self.keys)
458         with pytest.raises(SdlTypeError):
459             self.storage.remove_and_publish(self.ns, {"ch1": ["ev1", self.ill_event]}, self.keys)
460         with pytest.raises(SdlTypeError):
461             self.storage.remove_and_publish(self.ns, self.channels_and_events, 0xbad)
462
463     def test_remove_if_and_publish_success(self):
464         self.mock_db_backend.remove_if_and_publish.return_value = True
465         ret = self.storage.remove_if_and_publish(self.ns, self.channels_and_events, self.key,
466                                                  self.new_data)
467         self.mock_db_backend.remove_if_and_publish.assert_called_once_with(
468             self.ns, self.channels_and_events, self.key, self.new_data)
469         assert ret is True
470
471     def test_remove_if_remove_and_publish_can_return_false_if_data_does_not_match(self):
472         self.mock_db_backend.remove_if_and_publish.return_value = False
473         ret = self.storage.remove_if_and_publish(self.ns, self.channels_and_events, self.key,
474                                                  self.old_data)
475         self.mock_db_backend.remove_if_and_publish.assert_called_once_with(
476             self.ns, self.channels_and_events, self.key, self.old_data)
477         assert ret is False
478
479     def test_remove_if_remove_and_publish_can_raise_exception_for_wrong_argument(self):
480         with pytest.raises(SdlTypeError):
481             self.storage.remove_if_and_publish(0xbad, self.channels_and_events, self.keys,
482                                                self.old_data)
483         with pytest.raises(SdlTypeError):
484             self.storage.remove_if_and_publish(self.ns, None, self.keys, self.old_data)
485         with pytest.raises(SdlTypeError):
486             self.storage.remove_if_and_publish(self.ns, {0xbad: "ev1"}, self.keys,
487                                                self.old_data)
488         with pytest.raises(SdlTypeError):
489             self.storage.remove_if_and_publish(self.ns, {"ch1": 0xbad}, self.keys,
490                                                self.old_data)
491         with pytest.raises(SdlTypeError):
492             self.storage.remove_if_and_publish(self.ns, {"ch1": self.ill_event}, self.keys,
493                                                self.old_data)
494         with pytest.raises(SdlTypeError):
495             self.storage.remove_if_and_publish(self.ns, {"ch1": ["ev1", 0xbad]}, self.keys,
496                                                self.old_data)
497         with pytest.raises(SdlTypeError):
498             self.storage.remove_if_and_publish(self.ns, {"ch1": ["ev1", self.ill_event]}, self.keys,
499                                                self.old_data)
500         with pytest.raises(SdlTypeError):
501             self.storage.remove_if_and_publish(self.ns, self.channels_and_events, 0xbad,
502                                                self.old_data)
503         with pytest.raises(SdlTypeError):
504             self.storage.remove_if_and_publish(self.ns, self.channels_and_events, self.keys, 0xbad)
505
506     def test_remove_all_and_publish_success(self):
507         self.storage.remove_all_and_publish(self.ns, self.channels_and_events)
508         self.mock_db_backend.remove_all_and_publish.assert_called_once_with(
509             self.ns, self.channels_and_events)
510
511     def test_remove_all_and_publish_can_raise_exception_for_wrong_argument(self):
512         with pytest.raises(SdlTypeError):
513             self.storage.remove_all_and_publish(0xbad, self.channels_and_events)
514         with pytest.raises(SdlTypeError):
515             self.storage.remove_all_and_publish(self.ns, None)
516         with pytest.raises(SdlTypeError):
517             self.storage.remove_all_and_publish(self.ns, {0xbad: "ev1"})
518         with pytest.raises(SdlTypeError):
519             self.storage.remove_all_and_publish(self.ns, {"ch1": 0xbad})
520         with pytest.raises(SdlTypeError):
521             self.storage.remove_all_and_publish(self.ns, {"ch1": self.ill_event})
522         with pytest.raises(SdlTypeError):
523             self.storage.remove_all_and_publish(self.ns, {"ch1": ["ev1", 0xbad]})
524         with pytest.raises(SdlTypeError):
525             self.storage.remove_all_and_publish(self.ns, {"ch1": ["ev1", self.ill_event]})
526
527     def test_subscribe_function_success(self):
528         def cb(channel, message):
529             pass
530         self.storage.subscribe_channel(self.ns, cb, self.channels)
531         self.mock_db_backend.subscribe_channel.assert_called_once_with(
532             self.ns, cb, list(self.channels))
533
534     def test_subscribe_can_raise_exception_for_wrong_argument(self):
535         def cb3(channel, message, extra):
536             pass
537         def cb1(channel):
538             pass
539         with pytest.raises(SdlTypeError):
540             self.storage.subscribe_channel(self.ns, cb3, self.channels)
541         with pytest.raises(SdlTypeError):
542             self.storage.subscribe_channel(self.ns, cb1, self.channels)
543
544     def test_unsubscribe_function_success(self):
545         self.storage.unsubscribe_channel(self.ns, self.channels)
546         self.mock_db_backend.unsubscribe_channel.assert_called_once_with(
547             self.ns, list(self.channels))
548
549     def test_start_event_listener_success(self):
550         self.storage.start_event_listener()
551         self.mock_db_backend.start_event_listener.assert_called()
552
553     def test_handle_events_success(self):
554         self.storage.handle_events()
555         self.mock_db_backend.handle_events.assert_called()
556
557     @patch('ricsdl.syncstorage.SyncLock')
558     def test_get_lock_resource_function_success_when_expiration_time_is_integer(self, mock_db_lock):
559         ret = self.storage.get_lock_resource(self.ns, self.lock_name, self.lock_int_expiration)
560         mock_db_lock.assert_called_once_with(self.ns, self.lock_name, self.lock_int_expiration,
561                                              self.storage)
562         assert ret == mock_db_lock.return_value
563
564     @patch('ricsdl.syncstorage.SyncLock')
565     def test_get_lock_resource_function_success_when_expiration_time_is_float_number(self,
566                                                                                      mock_db_lock):
567         ret = self.storage.get_lock_resource(self.ns, self.lock_name, self.lock_float_expiration)
568         mock_db_lock.assert_called_once_with(self.ns, self.lock_name, self.lock_float_expiration,
569                                              self.storage)
570         assert ret == mock_db_lock.return_value
571
572     def test_get_lock_resource_function_can_raise_exception_for_wrong_argument(self):
573         with pytest.raises(SdlTypeError):
574             self.storage.get_lock_resource(0xbad, self.lock_name, self.lock_int_expiration)
575         with pytest.raises(SdlTypeError):
576             self.storage.get_lock_resource(self.ns, 0xbad, self.lock_int_expiration)
577         with pytest.raises(SdlTypeError):
578             self.storage.get_lock_resource(self.ns, self.lock_name, 'bad')
579
580     def test_get_backend_function_success(self):
581         ret = self.storage.get_backend()
582         assert ret == self.mock_db_backend
583
584     def test_storage_object_string_representation(self):
585         str_out = str(self.storage)
586         assert str_out is not None
587
588
589 @pytest.fixture()
590 def lock_fixture(request):
591     request.cls.ns = 'some-ns'
592     request.cls.lockname = 'some-lock-name'
593     request.cls.expiration = 10
594     request.cls.retry_interval = 0.1
595     request.cls.retry_timeout = 1
596
597     with patch('ricsdl.backend.get_backend_lock_instance') as mock_db_backend_lock:
598         lock = SyncLock('test-ns', 'test-lock-name', request.cls.expiration, Mock())
599         request.cls.mock_db_backend_lock = mock_db_backend_lock.return_value
600     request.cls.lock = lock
601     yield
602
603
604 @pytest.mark.usefixtures('lock_fixture')
605 class TestSyncLock:
606     def test_acquire_function_success_when_timeout_and_interval_are_integers(self):
607         self.lock.acquire(self.retry_interval, self.retry_timeout)
608         self.mock_db_backend_lock.acquire.assert_called_once_with(self.retry_interval,
609                                                                   self.retry_timeout)
610
611     def test_acquire_function_success_when_timeout_and_interval_are_float_numbers(self):
612         self.lock.acquire(float(self.retry_interval), float(self.retry_timeout))
613         self.mock_db_backend_lock.acquire.assert_called_once_with(float(self.retry_interval),
614                                                                   float(self.retry_timeout))
615
616     def test_acquire_function_can_raise_exception_for_wrong_argument(self):
617         with pytest.raises(SdlTypeError):
618             self.lock.acquire('bad', self.retry_timeout)
619         with pytest.raises(SdlTypeError):
620             self.lock.acquire(self.retry_interval, 'bad')
621
622     def test_release_function_success(self):
623         self.lock.release()
624         self.mock_db_backend_lock.release.assert_called_once()
625
626     def test_refresh_function_success(self):
627         self.lock.refresh()
628         self.mock_db_backend_lock.refresh.assert_called_once()
629
630     def test_get_validity_time_function_success(self):
631         self.mock_db_backend_lock.get_validity_time.return_value = self.expiration
632         ret = self.lock.get_validity_time()
633         self.mock_db_backend_lock.get_validity_time.assert_called_once()
634         assert ret == self.expiration
635
636     def test_get_validity_time_function_success_when_returned_time_is_float(self):
637         self.mock_db_backend_lock.get_validity_time.return_value = float(self.expiration)
638         ret = self.lock.get_validity_time()
639         self.mock_db_backend_lock.get_validity_time.assert_called_once()
640         assert ret == float(self.expiration)
641
642     def test_lock_object_string_representation(self):
643         str_out = str(self.lock)
644         assert str_out is not None
645
646
647 def test_function_arg_validator():
648     @func_arg_checker(SdlTypeError, 0, a=str, b=(int, float), c=set, d=(dict, type(None)))
649     def _my_func(a='abc', b=1, c={'x', 'y'}, d={'x': b'1'}):
650         pass
651     with pytest.raises(SdlTypeError, match=r"Wrong argument type: 'a'=<class 'NoneType'>. "
652                                            r"Must be: <class 'str'>"):
653         _my_func(None)
654
655     with pytest.raises(SdlTypeError, match=r"Wrong argument type: 'b'=<class 'str'>. "):
656         _my_func('abc', 'wrong type')
657
658     with pytest.raises(SdlTypeError, match=r"Wrong argument type: 'c'=<class 'str'>. "
659                                            r"Must be: <class 'set'>"):
660         _my_func('abc', 1.0, 'wrong type')
661
662     with pytest.raises(SdlTypeError, match=r"Wrong argument type: 'd'=<class 'str'>. "):
663         _my_func('abc', 1.0, {'x', 'y'}, 'wrong type')
664
665
666 def test_function_kwarg_validator():
667     @func_arg_checker(SdlTypeError, 0, a=str, b=(int, float), c=set, d=(dict, type(None)))
668     def _my_func(a='abc', b=1, c={'x', 'y'}, d={'x': b'1'}):
669         pass
670     with pytest.raises(SdlTypeError, match=r"Wrong argument type: 'a'=<class 'NoneType'>. "
671                                            r"Must be: <class 'str'>"):
672         _my_func(a=None)
673
674     with pytest.raises(SdlTypeError, match=r"Wrong argument type: 'b'=<class 'str'>. "):
675         _my_func(b='wrong type')
676
677     with pytest.raises(SdlTypeError, match=r"Wrong argument type: 'c'=<class 'str'>. "
678                                            r"Must be: <class 'set'>"):
679         _my_func(c='wrong type')
680
681     with pytest.raises(SdlTypeError, match=r"Wrong argument type: 'd'=<class 'str'>. "):
682         _my_func(d='wrong type')