Merge "Move pom for sonar analyses into ricsdl-package"
[ric-plt/sdlpy.git] / ricsdl-package / tests / backend / test_redis.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 redis import exceptions as redis_exceptions
25 import ricsdl.backend
26 from ricsdl.backend.redis import (RedisBackendLock, _map_to_sdl_exception)
27 from ricsdl.configuration import _Configuration
28 from ricsdl.configuration import DbBackendType
29 import ricsdl.exceptions
30
31
32 @pytest.fixture()
33 def redis_backend_fixture(request):
34     request.cls.ns = 'some-ns'
35     request.cls.dl_redis = [b'1', b'2']
36     request.cls.dm = {'a': b'1', 'b': b'2'}
37     request.cls.dm_redis = {'{some-ns},a': b'1', '{some-ns},b': b'2'}
38     request.cls.key = 'a'
39     request.cls.key_redis = '{some-ns},a'
40     request.cls.keys = ['a', 'b']
41     request.cls.keys_redis = ['{some-ns},a', '{some-ns},b']
42     request.cls.data = b'123'
43     request.cls.old_data = b'1'
44     request.cls.new_data = b'3'
45     request.cls.keypattern = r'[Aa]bc-\[1\].?-*'
46     request.cls.keypattern_redis = r'{some-ns},[Aa]bc-\[1\].?-*'
47     request.cls.matchedkeys = ['Abc-[1].0-def', 'abc-[1].1-ghi']
48     request.cls.matchedkeys_redis = [b'{some-ns},Abc-[1].0-def',
49                                      b'{some-ns},abc-[1].1-ghi']
50     request.cls.matcheddata_redis = [b'10', b'11']
51     request.cls.matchedkeydata = {'Abc-[1].0-def': b'10',
52                                   'abc-[1].1-ghi': b'11'}
53     request.cls.group = 'some-group'
54     request.cls.group_redis = '{some-ns},some-group'
55     request.cls.groupmembers = set([b'm1', b'm2'])
56     request.cls.groupmember = b'm1'
57
58     request.cls.configuration = Mock()
59     mock_conf_params = _Configuration.Params(db_host=None,
60                                              db_port=None,
61                                              db_sentinel_port=None,
62                                              db_sentinel_master_name=None,
63                                              db_type=DbBackendType.REDIS)
64     request.cls.configuration.get_params.return_value = mock_conf_params
65     with patch('ricsdl.backend.redis.Redis') as mock_redis:
66         db = ricsdl.backend.get_backend_instance(request.cls.configuration)
67         request.cls.mock_redis = mock_redis.return_value
68     request.cls.db = db
69
70     yield
71
72
73 @pytest.mark.usefixtures('redis_backend_fixture')
74 class TestRedisBackend:
75     def test_is_connected_function_success(self):
76         self.mock_redis.ping.return_value = True
77         ret = self.db.is_connected()
78         self.mock_redis.ping.assert_called_once()
79         assert ret is True
80
81     def test_is_connected_function_returns_false_if_ping_fails(self):
82         self.mock_redis.ping.return_value = False
83         ret = self.db.is_connected()
84         self.mock_redis.ping.assert_called_once()
85         assert ret is False
86
87     def test_is_connected_function_can_map_redis_exception_to_sdl_exception(self):
88         self.mock_redis.ping.side_effect = redis_exceptions.ResponseError('redis error!')
89         with pytest.raises(ricsdl.exceptions.RejectedByBackend):
90             self.db.is_connected()
91
92     def test_set_function_success(self):
93         self.db.set(self.ns, self.dm)
94         self.mock_redis.mset.assert_called_once_with(self.dm_redis)
95
96     def test_set_function_can_map_redis_exception_to_sdl_exception(self):
97         self.mock_redis.mset.side_effect = redis_exceptions.ResponseError('redis error!')
98         with pytest.raises(ricsdl.exceptions.RejectedByBackend):
99             self.db.set(self.ns, self.dm)
100
101     def test_set_if_function_success(self):
102         self.mock_redis.execute_command.return_value = True
103         ret = self.db.set_if(self.ns, self.key, self.old_data, self.new_data)
104         self.mock_redis.execute_command.assert_called_once_with('SETIE', self.key_redis,
105                                                                 self.new_data, self.old_data)
106         assert ret is True
107
108     def test_set_if_function_returns_false_if_existing_key_value_not_expected(self):
109         self.mock_redis.execute_command.return_value = False
110         ret = self.db.set_if(self.ns, self.key, self.old_data, self.new_data)
111         self.mock_redis.execute_command.assert_called_once_with('SETIE', self.key_redis,
112                                                                 self.new_data, self.old_data)
113         assert ret is False
114
115     def test_set_if_function_can_map_redis_exception_to_sdl_exception(self):
116         self.mock_redis.execute_command.side_effect = redis_exceptions.ResponseError('redis error!')
117         with pytest.raises(ricsdl.exceptions.RejectedByBackend):
118             self.db.set_if(self.ns, self.key, self.old_data, self.new_data)
119
120     def test_set_if_not_exists_function_success(self):
121         self.mock_redis.setnx.return_value = True
122         ret = self.db.set_if_not_exists(self.ns, self.key, self.new_data)
123         self.mock_redis.setnx.assert_called_once_with(self.key_redis, self.new_data)
124         assert ret is True
125
126     def test_set_if_not_exists_function_returns_false_if_key_already_exists(self):
127         self.mock_redis.setnx.return_value = False
128         ret = self.db.set_if_not_exists(self.ns, self.key, self.new_data)
129         self.mock_redis.setnx.assert_called_once_with(self.key_redis, self.new_data)
130         assert ret is False
131
132     def test_set_if_not_exists_function_can_map_redis_exception_to_sdl_exception(self):
133         self.mock_redis.setnx.side_effect = redis_exceptions.ResponseError('redis error!')
134         with pytest.raises(ricsdl.exceptions.RejectedByBackend):
135             self.db.set_if_not_exists(self.ns, self.key, self.new_data)
136
137     def test_get_function_success(self):
138         self.mock_redis.mget.return_value = self.dl_redis
139         ret = self.db.get(self.ns, self.keys)
140         self.mock_redis.mget.assert_called_once_with(self.keys_redis)
141         assert ret == self.dm
142
143     def test_get_function_returns_empty_dict_when_no_key_values_exist(self):
144         self.mock_redis.mget.return_value = [None, None]
145         ret = self.db.get(self.ns, self.keys)
146         self.mock_redis.mget.assert_called_once_with(self.keys_redis)
147         assert ret == dict()
148
149     def test_get_function_returns_dict_only_with_found_key_values_when_some_keys_exist(self):
150         self.mock_redis.mget.return_value = [self.data, None]
151         ret = self.db.get(self.ns, self.keys)
152         self.mock_redis.mget.assert_called_once_with(self.keys_redis)
153         assert ret == {self.key: self.data}
154
155     def test_get_function_can_map_redis_exception_to_sdl_exception(self):
156         self.mock_redis.mget.side_effect = redis_exceptions.ResponseError('redis error!')
157         with pytest.raises(ricsdl.exceptions.RejectedByBackend):
158             self.db.get(self.ns, self.keys)
159
160     def test_find_keys_function_success(self):
161         self.mock_redis.keys.return_value = self.matchedkeys_redis
162         ret = self.db.find_keys(self.ns, self.keypattern)
163         self.mock_redis.keys.assert_called_once_with(self.keypattern_redis)
164         assert ret == self.matchedkeys
165
166     def test_find_keys_function_returns_empty_list_when_no_matching_keys_found(self):
167         self.mock_redis.keys.return_value = []
168         ret = self.db.find_keys(self.ns, self.keypattern)
169         self.mock_redis.keys.assert_called_once_with(self.keypattern_redis)
170         assert ret == []
171
172     def test_find_keys_function_can_map_redis_exception_to_sdl_exception(self):
173         self.mock_redis.keys.side_effect = redis_exceptions.ResponseError('redis error!')
174         with pytest.raises(ricsdl.exceptions.RejectedByBackend):
175             self.db.find_keys(self.ns, self.keypattern)
176
177     def test_find_keys_function_can_raise_exception_when_redis_key_convert_to_string_fails(self):
178         # Redis returns an illegal key, which conversion to string fails
179         corrupt_redis_key = b'\x81'
180         self.mock_redis.keys.return_value = [corrupt_redis_key]
181         with pytest.raises(ricsdl.exceptions.RejectedByBackend) as excinfo:
182             self.db.find_keys(self.ns, self.keypattern)
183         assert f"Namespace {self.ns} key:{corrupt_redis_key} "
184         "has no namespace prefix" in str(excinfo.value)
185
186     def test_find_keys_function_can_raise_exception_when_redis_key_is_without_prefix(self):
187         # Redis returns an illegal key, which doesn't have comma separated namespace prefix
188         corrupt_redis_key = 'some-corrupt-key'
189         self.mock_redis.keys.return_value = [f'{corrupt_redis_key}'.encode()]
190         with pytest.raises(ricsdl.exceptions.RejectedByBackend) as excinfo:
191             self.db.find_keys(self.ns, self.keypattern)
192         assert f"Namespace {self.ns} key:{corrupt_redis_key} "
193         "has no namespace prefix" in str(excinfo.value)
194
195     def test_find_and_get_function_success(self):
196         self.mock_redis.keys.return_value = self.matchedkeys_redis
197         self.mock_redis.mget.return_value = self.matcheddata_redis
198         ret = self.db.find_and_get(self.ns, self.keypattern)
199         self.mock_redis.keys.assert_called_once_with(self.keypattern_redis)
200         self.mock_redis.mget.assert_called_once_with([i.decode() for i in self.matchedkeys_redis])
201         assert ret == self.matchedkeydata
202
203     def test_find_and_get_function_returns_empty_dict_when_no_matching_keys_exist(self):
204         self.mock_redis.keys.return_value = list()
205         ret = self.db.find_and_get(self.ns, self.keypattern)
206         self.mock_redis.keys.assert_called_once_with(self.keypattern_redis)
207         assert not self.mock_redis.mget.called
208         assert ret == dict()
209
210     def test_find_and_get_function_can_map_redis_exception_to_sdl_exception(self):
211         self.mock_redis.keys.side_effect = redis_exceptions.ResponseError('redis error!')
212         with pytest.raises(ricsdl.exceptions.RejectedByBackend):
213             self.db.find_and_get(self.ns, self.keypattern)
214
215     def test_find_and_get_function_can_raise_exception_when_redis_key_convert_to_string_fails(self):
216         # Redis returns an illegal key, which conversion to string fails
217         corrupt_redis_key = b'\x81'
218         self.mock_redis.keys.return_value = [corrupt_redis_key]
219         with pytest.raises(ricsdl.exceptions.RejectedByBackend) as excinfo:
220             self.db.find_and_get(self.ns, self.keypattern)
221         assert f"Namespace {self.ns} key:{corrupt_redis_key} "
222         "has no namespace prefix" in str(excinfo.value)
223
224     def test_find_and_get_function_can_raise_exception_when_redis_key_is_without_prefix(self):
225         # Redis returns an illegal key, which doesn't have comma separated namespace prefix
226         corrupt_redis_key = 'some-corrupt-key'
227         self.mock_redis.keys.return_value = [f'{corrupt_redis_key}'.encode()]
228         with pytest.raises(ricsdl.exceptions.RejectedByBackend) as excinfo:
229             self.db.find_and_get(self.ns, self.keypattern)
230         assert f"Namespace {self.ns} key:{corrupt_redis_key} "
231         "has no namespace prefix" in str(excinfo.value)
232
233     def test_remove_function_success(self):
234         self.db.remove(self.ns, self.keys)
235         self.mock_redis.delete.assert_called_once_with(*self.keys_redis)
236
237     def test_remove_function_can_map_redis_exception_to_sdl_exception(self):
238         self.mock_redis.delete.side_effect = redis_exceptions.ResponseError('redis error!')
239         with pytest.raises(ricsdl.exceptions.RejectedByBackend):
240             self.db.remove(self.ns, self.keys)
241
242     def test_remove_if_function_success(self):
243         self.mock_redis.execute_command.return_value = True
244         ret = self.db.remove_if(self.ns, self.key, self.new_data)
245         self.mock_redis.execute_command.assert_called_once_with('DELIE', self.key_redis,
246                                                                 self.new_data)
247         assert ret is True
248
249     def test_remove_if_function_returns_false_if_data_does_not_match(self):
250         self.mock_redis.execute_command.return_value = False
251         ret = self.db.remove_if(self.ns, self.key, self.new_data)
252         self.mock_redis.execute_command.assert_called_once_with('DELIE', self.key_redis,
253                                                                 self.new_data)
254         assert ret is False
255
256     def test_remove_if_function_can_map_redis_exception_to_sdl_exception(self):
257         self.mock_redis.execute_command.side_effect = redis_exceptions.ResponseError('redis error!')
258         with pytest.raises(ricsdl.exceptions.RejectedByBackend):
259             self.db.remove_if(self.ns, self.key, self.new_data)
260
261     def test_add_member_function_success(self):
262         self.db.add_member(self.ns, self.group, self.groupmembers)
263         self.mock_redis.sadd.assert_called_once_with(self.group_redis, *self.groupmembers)
264
265     def test_add_member_function_can_map_redis_exception_to_sdl_exception(self):
266         self.mock_redis.sadd.side_effect = redis_exceptions.ResponseError('redis error!')
267         with pytest.raises(ricsdl.exceptions.RejectedByBackend):
268             self.db.add_member(self.ns, self.group, self.groupmembers)
269
270     def test_remove_member_function_success(self):
271         self.db.remove_member(self.ns, self.group, self.groupmembers)
272         self.mock_redis.srem.assert_called_once_with(self.group_redis, *self.groupmembers)
273
274     def test_remove_member_function_can_map_redis_exception_to_sdl_exception(self):
275         self.mock_redis.srem.side_effect = redis_exceptions.ResponseError('redis error!')
276         with pytest.raises(ricsdl.exceptions.RejectedByBackend):
277             self.db.remove_member(self.ns, self.group, self.groupmembers)
278
279     def test_remove_group_function_success(self):
280         self.db.remove_group(self.ns, self.group)
281         self.mock_redis.delete.assert_called_once_with(self.group_redis)
282
283     def test_remove_group_function_can_map_redis_exception_to_sdl_exception(self):
284         self.mock_redis.delete.side_effect = redis_exceptions.ResponseError('redis error!')
285         with pytest.raises(ricsdl.exceptions.RejectedByBackend):
286             self.db.remove_group(self.ns, self.group)
287
288     def test_get_members_function_success(self):
289         self.mock_redis.smembers.return_value = self.groupmembers
290         ret = self.db.get_members(self.ns, self.group)
291         self.mock_redis.smembers.assert_called_once_with(self.group_redis)
292         assert ret is self.groupmembers
293
294     def test_get_members_function_can_map_redis_exception_to_sdl_exception(self):
295         self.mock_redis.smembers.side_effect = redis_exceptions.ResponseError('redis error!')
296         with pytest.raises(ricsdl.exceptions.RejectedByBackend):
297             self.db.get_members(self.ns, self.group)
298
299     def test_is_member_function_success(self):
300         self.mock_redis.sismember.return_value = True
301         ret = self.db.is_member(self.ns, self.group, self.groupmember)
302         self.mock_redis.sismember.assert_called_once_with(self.group_redis, self.groupmember)
303         assert ret is True
304
305     def test_is_member_function_can_map_redis_exception_to_sdl_exception(self):
306         self.mock_redis.sismember.side_effect = redis_exceptions.ResponseError('redis error!')
307         with pytest.raises(ricsdl.exceptions.RejectedByBackend):
308             self.db.is_member(self.ns, self.group, self.groupmember)
309
310     def test_group_size_function_success(self):
311         self.mock_redis.scard.return_value = 100
312         ret = self.db.group_size(self.ns, self.group)
313         self.mock_redis.scard.assert_called_once_with(self.group_redis)
314         assert ret == 100
315
316     def test_group_size_function_can_map_redis_exception_to_sdl_exception(self):
317         self.mock_redis.scard.side_effect = redis_exceptions.ResponseError('Some redis error!')
318         with pytest.raises(ricsdl.exceptions.RejectedByBackend):
319             self.db.group_size(self.ns, self.group)
320
321     def test_get_redis_connection_function_success(self):
322         ret = self.db.get_redis_connection()
323         assert ret is self.mock_redis
324
325     def test_redis_backend_object_string_representation(self):
326         str_out = str(self.db)
327         assert str_out is not None
328
329
330 class MockRedisLock:
331     def __init__(self, redis, name, timeout=None, sleep=0.1,
332                  blocking=True, blocking_timeout=None, thread_local=True):
333         self.redis = redis
334         self.name = name
335         self.timeout = timeout
336         self.sleep = sleep
337         self.blocking = blocking
338         self.blocking_timeout = blocking_timeout
339         self.thread_local = bool(thread_local)
340
341
342 @pytest.fixture(scope="module")
343 def mock_redis_lock():
344     def _mock_redis_lock(name, timeout=None, sleep=0.1,
345                          blocking=True, blocking_timeout=None, thread_local=True):
346         return MockRedisLock(name, timeout, sleep, blocking, blocking_timeout, thread_local)
347     return _mock_redis_lock
348
349
350 @pytest.fixture()
351 def redis_backend_lock_fixture(request, mock_redis_lock):
352     request.cls.ns = 'some-ns'
353     request.cls.lockname = 'some-lock-name'
354     request.cls.lockname_redis = '{some-ns},some-lock-name'
355     request.cls.expiration = 10
356     request.cls.retry_interval = 0.1
357     request.cls.retry_timeout = 1
358
359     request.cls.mock_lua_get_validity_time = Mock()
360     request.cls.mock_lua_get_validity_time.return_value = 2000
361
362     request.cls.mock_redis = Mock()
363     request.cls.mock_redis.register_script = Mock()
364     request.cls.mock_redis.register_script.return_value = request.cls.mock_lua_get_validity_time
365
366     mocked_dbbackend = Mock()
367     mocked_dbbackend.get_redis_connection.return_value = request.cls.mock_redis
368
369     request.cls.configuration = Mock()
370     mock_conf_params = _Configuration.Params(db_host=None,
371                                              db_port=None,
372                                              db_sentinel_port=None,
373                                              db_sentinel_master_name=None,
374                                              db_type=DbBackendType.REDIS)
375     request.cls.configuration.get_params.return_value = mock_conf_params
376
377     with patch('ricsdl.backend.redis.Lock') as mock_redis_lock:
378         lock = ricsdl.backend.get_backend_lock_instance(request.cls.configuration,
379                                                         request.cls.ns, request.cls.lockname,
380                                                         request.cls.expiration, mocked_dbbackend)
381         request.cls.mock_redis_lock = mock_redis_lock.return_value
382         request.cls.lock = lock
383     yield
384     RedisBackendLock.lua_get_validity_time = None
385
386
387 @pytest.mark.usefixtures('redis_backend_lock_fixture')
388 class TestRedisBackendLock:
389     def test_acquire_function_success(self):
390         self.mock_redis_lock.acquire.return_value = True
391         ret = self.lock.acquire(self.retry_interval, self.retry_timeout)
392         self.mock_redis_lock.acquire.assert_called_once_with(blocking_timeout=self.retry_timeout)
393         assert ret is True
394
395     def test_acquire_function_returns_false_if_lock_is_not_acquired(self):
396         self.mock_redis_lock.acquire.return_value = False
397         ret = self.lock.acquire(self.retry_interval, self.retry_timeout)
398         self.mock_redis_lock.acquire.assert_called_once_with(blocking_timeout=self.retry_timeout)
399         assert ret is False
400
401     def test_acquire_function_can_map_redis_exception_to_sdl_exception(self):
402         self.mock_redis_lock.acquire.side_effect = redis_exceptions.LockError('redis lock error!')
403         with pytest.raises(ricsdl.exceptions.BackendError):
404             self.lock.acquire(self.retry_interval, self.retry_timeout)
405
406     def test_release_function_success(self):
407         self.lock.release()
408         self.mock_redis_lock.release.assert_called_once()
409
410     def test_release_function_can_map_redis_exception_to_sdl_exception(self):
411         self.mock_redis_lock.release.side_effect = redis_exceptions.LockError('redis lock error!')
412         with pytest.raises(ricsdl.exceptions.BackendError):
413             self.lock.release()
414
415     def test_refresh_function_success(self):
416         self.lock.refresh()
417         self.mock_redis_lock.reacquire.assert_called_once()
418
419     def test_refresh_function_can_map_redis_exception_to_sdl_exception(self):
420         self.mock_redis_lock.reacquire.side_effect = redis_exceptions.LockError('redis lock error!')
421         with pytest.raises(ricsdl.exceptions.BackendError):
422             self.lock.refresh()
423
424     def test_get_validity_time_function_success(self):
425         self.mock_redis_lock.name = self.lockname_redis
426         self.mock_redis_lock.local.token = 123
427
428         ret = self.lock.get_validity_time()
429         self.mock_lua_get_validity_time.assert_called_once_with(
430             keys=[self.lockname_redis], args=[123], client=self.mock_redis)
431         assert ret == 2
432
433     def test_get_validity_time_function_second_fraction_success(self):
434         self.mock_redis_lock.name = self.lockname_redis
435         self.mock_redis_lock.local.token = 123
436         self.mock_lua_get_validity_time.return_value = 234
437
438         ret = self.lock.get_validity_time()
439         self.mock_lua_get_validity_time.assert_called_once_with(
440             keys=[self.lockname_redis], args=[123], client=self.mock_redis)
441         assert ret == 0.234
442
443     def test_get_validity_time_function_can_raise_exception_if_lock_is_unlocked(self):
444         self.mock_redis_lock.name = self.lockname_redis
445         self.mock_redis_lock.local.token = None
446
447         with pytest.raises(ricsdl.exceptions.RejectedByBackend) as excinfo:
448             self.lock.get_validity_time()
449         assert f"Cannot get validity time of an unlocked lock {self.lockname}" in str(excinfo.value)
450
451     def test_get_validity_time_function_can_raise_exception_if_lua_script_fails(self):
452         self.mock_redis_lock.name = self.lockname_redis
453         self.mock_redis_lock.local.token = 123
454         self.mock_lua_get_validity_time.return_value = -10
455
456         with pytest.raises(ricsdl.exceptions.RejectedByBackend) as excinfo:
457             self.lock.get_validity_time()
458         assert f"Getting validity time of a lock {self.lockname} failed with error code: -10" in str(excinfo.value)
459
460     def test_redis_backend_lock_object_string_representation(self):
461         expected_lock_info = {'lock DB type': 'Redis',
462                               'lock namespace': 'some-ns',
463                               'lock name': 'some-lock-name',
464                               'lock status': 'locked'}
465         assert str(self.lock) == str(expected_lock_info)
466
467     def test_redis_backend_lock_object_string_representation_can_catch_redis_exception(self):
468         self.mock_redis_lock.owned.side_effect = redis_exceptions.LockError('redis lock error!')
469         expected_lock_info = {'lock DB type': 'Redis',
470                               'lock namespace': 'some-ns',
471                               'lock name': 'some-lock-name',
472                               'lock status': 'Error: redis lock error!'}
473         assert str(self.lock) == str(expected_lock_info)
474
475
476 def test_redis_response_error_exception_is_mapped_to_rejected_by_backend_sdl_exception():
477     with pytest.raises(ricsdl.exceptions.RejectedByBackend) as excinfo:
478         with _map_to_sdl_exception():
479             raise redis_exceptions.ResponseError('Some redis error!')
480     assert "SDL backend rejected the request: Some redis error!" in str(excinfo.value)
481
482
483 def test_redis_connection_error_exception_is_mapped_to_not_connected_sdl_exception():
484     with pytest.raises(ricsdl.exceptions.NotConnected) as excinfo:
485         with _map_to_sdl_exception():
486             raise redis_exceptions.ConnectionError('Some redis error!')
487     assert "SDL not connected to backend: Some redis error!" in str(excinfo.value)
488
489
490 def test_rest_redis_exceptions_are_mapped_to_backend_error_sdl_exception():
491     with pytest.raises(ricsdl.exceptions.BackendError) as excinfo:
492         with _map_to_sdl_exception():
493             raise redis_exceptions.RedisError('Some redis error!')
494     assert "SDL backend failed to process the request: Some redis error!" in str(excinfo.value)
495
496
497 def test_system_error_exceptions_are_not_mapped_to_any_sdl_exception():
498     with pytest.raises(SystemExit):
499         with _map_to_sdl_exception():
500             raise SystemExit('Fatal error')