Add a new SDL storage API function 'is_active()' 96/2296/3
authorTimo Tietavainen <timo.tietavainen@nokia.com>
Tue, 21 Jan 2020 19:57:17 +0000 (21:57 +0200)
committerTimo Tietavainen <timo.tietavainen@nokia.com>
Wed, 22 Jan 2020 11:03:25 +0000 (13:03 +0200)
Implement a new SDL storage API function 'is_active()' to check healthiness
of an SDL instance. For now function only validates SDL DB backend (Redis)
connection. This function can be integrated into SDL client (such as A1
Mediator) health checks and runtime initializations.

Signed-off-by: Timo Tietavainen <timo.tietavainen@nokia.com>
Change-Id: I8bf457b9528e39223ea65a20d422d2fab49602bb

docs/release-notes.rst
ricsdl-package/examples/sync.py
ricsdl-package/ricsdl/__init__.py
ricsdl-package/ricsdl/backend/dbbackend_abc.py
ricsdl-package/ricsdl/backend/fake_dict_db.py
ricsdl-package/ricsdl/backend/redis.py
ricsdl-package/ricsdl/syncstorage.py
ricsdl-package/ricsdl/syncstorage_abc.py
ricsdl-package/tests/backend/test_fake_dict_db.py
ricsdl-package/tests/backend/test_redis.py
ricsdl-package/tests/test_syncstorage.py

index 007bf35..257c772 100644 (file)
@@ -33,6 +33,10 @@ This document provides the release notes of the ricsdl library.
 Version history
 ---------------
 
+[2.0.3] - 2020-01-22
+
+* Add a new SDL storage API function `is_active()` to check healthiness of SDL instance.
+
 [2.0.2] - 2020-01-14
 
 * Version bump.
index f01369a..6ea9ef9 100644 (file)
@@ -78,6 +78,11 @@ mysdl = _try_func_return(SyncStorage)
 # database services.
 # mysdl = _try_func_return(lambda: SyncStorage(fake_db_backend='dict'))
 
+# Checks if SDL is operational. Note that it is not necessary to call `is_active()` after each
+# SDL instance creation. Below example is here just to show how to call it spontaneously
+# when SDL healthiness is needed to check.
+is_active = mysdl.is_active()
+assert is_active is True
 
 # Sets a value 'my_value' for a key 'my_key' under given namespace. Note that value
 # type must be bytes and multiple key values can be set in one set function call.
index 726caf6..8d4b484 100644 (file)
@@ -31,7 +31,7 @@ from .exceptions import (
 )
 
 
-__version__ = '2.0.2'
+__version__ = '2.0.3'
 
 
 __all__ = [
index 08f4600..4f31554 100644 (file)
@@ -28,6 +28,11 @@ from abc import ABC, abstractmethod
 class DbBackendAbc(ABC):
     """An abstract Shared Data Layer (SDL) class providing database backend interface."""
 
+    @abstractmethod
+    def is_connected(self):
+        """Test database backend connection."""
+        pass
+
     @abstractmethod
     def close(self):
         """Close database backend connection."""
index 51e6c18..b6c84a2 100644 (file)
@@ -51,6 +51,9 @@ class FakeDictBackend(DbBackendAbc):
             }
         )
 
+    def is_connected(self):
+        return True
+
     def close(self):
         pass
 
index 63972e3..3364497 100644 (file)
@@ -90,6 +90,10 @@ class RedisBackend(DbBackendAbc):
             }
         )
 
+    def is_connected(self):
+        with _map_to_sdl_exception():
+            return self.__redis.ping()
+
     def close(self):
         self.__redis.close()
 
index 41deeba..29adb17 100644 (file)
@@ -25,7 +25,7 @@ from ricsdl.configuration import _Configuration
 from ricsdl.syncstorage_abc import (SyncStorageAbc, SyncLockAbc)
 import ricsdl.backend
 from ricsdl.backend.dbbackend_abc import DbBackendAbc
-from ricsdl.exceptions import SdlTypeError
+from ricsdl.exceptions import (SdlException, SdlTypeError)
 
 
 def func_arg_checker(exception, start_arg_idx, **types):
@@ -132,6 +132,12 @@ class SyncStorage(SyncStorageAbc):
             }
         )
 
+    def is_active(self):
+        try:
+            return self.__dbbackend.is_connected()
+        except SdlException:
+            return False
+
     def close(self):
         self.__dbbackend.close()
 
index 9ccd99d..c5b15b3 100644 (file)
@@ -170,6 +170,24 @@ class SyncStorageAbc(ABC):
     A concrete implementation subclass 'SyncStorage' derives from this abstract class.
     """
 
+    @abstractmethod
+    def is_active(self):
+        """
+        Verify SDL storage healthiness.
+
+        Verify SDL connection to the backend data storage.
+
+        Args:
+            None
+
+        Returns:
+            bool: True if SDL is operational, false otherwise.
+
+        Raises:
+            None
+        """
+        pass
+
     @abstractmethod
     def close(self):
         """
index 45b0f0f..3b072e5 100644 (file)
@@ -57,6 +57,10 @@ def fake_dict_backend_fixture(request):
 
 @pytest.mark.usefixtures('fake_dict_backend_fixture')
 class TestFakeDictBackend:
+    def test_is_connected_function_success(self):
+        ret = self.db.is_connected()
+        assert ret is True
+
     def test_set_function_success(self):
         self.db.set(self.ns, self.dm)
         self.db.set(self.ns, self.dm2)
index 61b56ff..4f46205 100644 (file)
@@ -72,6 +72,23 @@ def redis_backend_fixture(request):
 
 @pytest.mark.usefixtures('redis_backend_fixture')
 class TestRedisBackend:
+    def test_is_connected_function_success(self):
+        self.mock_redis.ping.return_value = True
+        ret = self.db.is_connected()
+        self.mock_redis.ping.assert_called_once()
+        assert ret is True
+
+    def test_is_connected_function_returns_false_if_ping_fails(self):
+        self.mock_redis.ping.return_value = False
+        ret = self.db.is_connected()
+        self.mock_redis.ping.assert_called_once()
+        assert ret is False
+
+    def test_is_connected_function_can_map_redis_exception_to_sdl_exception(self):
+        self.mock_redis.ping.side_effect = redis_exceptions.ResponseError('redis error!')
+        with pytest.raises(ricsdl.exceptions.RejectedByBackend):
+            self.db.is_connected()
+
     def test_set_function_success(self):
         self.db.set(self.ns, self.dm)
         self.mock_redis.mset.assert_called_once_with(self.dm_redis)
index 00d3ed8..29fd5d4 100644 (file)
@@ -24,7 +24,7 @@ import pytest
 from ricsdl.syncstorage import SyncStorage
 from ricsdl.syncstorage import SyncLock
 from ricsdl.syncstorage import func_arg_checker
-from ricsdl.exceptions import SdlTypeError
+from ricsdl.exceptions import (SdlTypeError, NotConnected)
 
 
 @pytest.fixture()
@@ -53,6 +53,18 @@ def sync_storage_fixture(request):
 
 @pytest.mark.usefixtures('sync_storage_fixture')
 class TestSyncStorage:
+    def test_is_active_function_success(self):
+        self.mock_db_backend.is_connected.return_value = True
+        ret = self.storage.is_active()
+        self.mock_db_backend.is_connected.assert_called_once()
+        assert ret is True
+
+    def test_is_active_function_can_catch_backend_exception_and_return_false(self):
+        self.mock_db_backend.is_connected.side_effect = NotConnected
+        ret = self.storage.is_active()
+        self.mock_db_backend.is_connected.assert_called_once()
+        assert ret is False
+
     def test_set_function_success(self):
         self.storage.set(self.ns, self.dm)
         self.mock_db_backend.set.assert_called_once_with(self.ns, self.dm)