Add Sentinel configuration reading 50/1050/2
authorRolf Badorek <rolf.badorek@nokia.com>
Tue, 1 Oct 2019 15:33:58 +0000 (18:33 +0300)
committerRolf Badorek <rolf.badorek@nokia.com>
Wed, 2 Oct 2019 14:01:20 +0000 (17:01 +0300)
Added reading Sentinel configuration from environment variables.

Sentinel address is configured via 'DBAAS_SERVICE_HOST' and
'DBAAS_SERVICE_SENTINEL_PORT' environment variables.

Sentinel master name is configured via 'DBAAS_MASTER_NAME' environment
variable.

Sentinel support is now activated.

Using Sentinel is optional. If Sentinel related environment variables
are not set, then static address for Redis server is used as before
(i.e. this change is backward compatible).

Signed-off-by: Rolf Badorek <rolf.badorek@nokia.com>
Change-Id: I34031ac56268673996c6fecb00eeed6e5dda8b9a

18 files changed:
Makefile.am
configure.ac
include/private/configurationreader.hpp
include/private/databaseconfiguration.hpp
include/private/databaseconfigurationimpl.hpp
include/private/hostandport.hpp
include/private/redis/asyncsentineldatabasediscovery.hpp
include/private/tst/databaseconfigurationmock.hpp
src/cli/testconnectivitycommand.cpp
src/configurationreader.cpp
src/databaseconfigurationimpl.cpp
src/hostandport.cpp
src/redis/asyncdatabasediscovery.cpp
src/redis/asyncsentineldatabasediscovery.cpp
tst/asyncsentineldatabasediscovery_test.cpp
tst/configurationreader_test.cpp
tst/databaseconfigurationimpl_test.cpp
tst/hostandport_test.cpp

index acd2cb6..19f2de9 100644 (file)
@@ -85,6 +85,7 @@ libsdl_la_SOURCES += \
     include/private/redis/asyncdatabasediscovery.hpp \
     include/private/redis/asyncredisreply.hpp \
     include/private/redis/asyncredisstorage.hpp \
+    include/private/redis/asyncsentineldatabasediscovery.hpp \
     include/private/redis/contents.hpp \
     include/private/redis/contentsbuilder.hpp \
     include/private/redis/databaseinfo.hpp \
@@ -93,6 +94,7 @@ libsdl_la_SOURCES += \
     src/redis/asyncdatabasediscovery.cpp \
     src/redis/asyncredisreply.cpp \
     src/redis/asyncredisstorage.cpp \
+    src/redis/asyncsentineldatabasediscovery.cpp \
     src/redis/contentsbuilder.cpp
 endif
 if HIREDIS
@@ -117,11 +119,6 @@ libsdl_la_SOURCES += \
     src/redis/hiredisclusterepolladapter.cpp \
     src/redis/hiredisclustersystem.cpp
 endif
-if SENTINEL
-libsdl_la_SOURCES += \
-    include/private/redis/asyncsentineldatabasediscovery.hpp \
-    src/redis/asyncsentineldatabasediscovery.cpp
-endif
 libsdl_la_CPPFLAGS = \
     $(BASE_CPPFLAGS) \
     $(HIREDIS_CFLAGS) \
@@ -350,6 +347,7 @@ testrunner_SOURCES += \
     tst/asynccommanddispatcher_test.cpp \
     tst/asyncdatabasediscovery_test.cpp \
     tst/asyncredisstorage_test.cpp \
+    tst/asyncsentineldatabasediscovery_test.cpp \
     tst/asyncstorageimpl_test.cpp \
     tst/contents_test.cpp \
     tst/contentsbuilder_test.cpp \
@@ -375,10 +373,6 @@ testrunner_SOURCES += \
     tst/hiredisclusterepolladapter_test.cpp \
     tst/hiredisclustersystem_test.cpp
 endif
-if SENTINEL
-testrunner_SOURCES += \
-    tst/asyncsentineldatabasediscovery_test.cpp
-endif
 testrunner_CPPFLAGS = \
     $(BASE_CPPFLAGS) \
     -I$(top_srcdir)/3rdparty/googletest/googlemock/include \
index 6155bde..216705f 100644 (file)
@@ -11,7 +11,7 @@
 
 m4_define([SDL_MAJOR], [1])
 m4_define([SDL_MINOR], [0])
-m4_define([SDL_MICRO], [0])
+m4_define([SDL_MICRO], [1])
 
 # SDL ABI version with libtool
 #
@@ -26,7 +26,7 @@ m4_define([SDL_MICRO], [0])
 # Change the numbers just before release.
 
 m4_define([SDL_CURRENT], [1])
-m4_define([SDL_REVISION], [0])
+m4_define([SDL_REVISION], [1])
 m4_define([SDL_AGE], [0])
 
 AC_INIT([shareddatalayer], [SDL_MAJOR.SDL_MINOR.SDL_MICRO], [], [], [https://gerrit.o-ran-sc.org/r/admin/repos/ric-plt/sdl])
@@ -62,10 +62,6 @@ AC_SUBST(SDL_CONF_DIR)
 AC_DEFINE(HAVE_REDIS, [1], [Have redis])
 AM_CONDITIONAL([REDIS], [test xtrue])
 
-# @TODO Change to true when Redis HA support is activated.
-AC_DEFINE(HAVE_SENTINEL, [0], [Have sentinel])
-AM_CONDITIONAL([SENTINEL], [test "xyes" = "xno"])
-
 PKG_CHECK_MODULES([HIREDIS], [hiredis])
 AC_DEFINE(HAVE_HIREDIS, [1], [Have hiredis])
 AM_CONDITIONAL([HIREDIS], [test xtrue])
index 6c175e7..7cb6f1a 100644 (file)
@@ -19,6 +19,8 @@
 
 #define DB_HOST_ENV_VAR_NAME "DBAAS_SERVICE_HOST"
 #define DB_PORT_ENV_VAR_NAME "DBAAS_SERVICE_PORT"
+#define SENTINEL_PORT_ENV_VAR_NAME "DBAAS_SERVICE_SENTINEL_PORT"
+#define SENTINEL_MASTER_NAME_ENV_VAR_NAME "DBAAS_MASTER_NAME"
 
 #include <iosfwd>
 #include <string>
@@ -61,6 +63,10 @@ namespace shareddatalayer
         std::string dbHostEnvVariableValue;
         const std::string dbPortEnvVariableName;
         std::string dbPortEnvVariableValue;
+        const std::string sentinelPortEnvVariableName;
+        std::string sentinelPortEnvVariableValue;
+        const std::string sentinelMasterNameEnvVariableName;
+        std::string sentinelMasterNameEnvVariableValue;
         boost::optional<boost::property_tree::ptree> jsonDatabaseConfiguration;
         std::string sourceForDatabaseConfiguration;
         std::unordered_map<std::string, std::pair<boost::property_tree::ptree, std::string>> jsonNamespaceConfigurations;
index fd24a11..5bf38a1 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <string>
 #include <vector>
+#include <boost/optional.hpp>
 #include "private/hostandport.hpp"
 
 namespace shareddatalayer
@@ -32,15 +33,20 @@ namespace shareddatalayer
         {
             UNKNOWN = 0,
             REDIS_STANDALONE,
-            REDIS_CLUSTER
+            REDIS_CLUSTER,
+            REDIS_SENTINEL
         };
 
         virtual ~DatabaseConfiguration() = default;
         virtual void checkAndApplyDbType(const std::string& type) = 0;
         virtual void checkAndApplyServerAddress(const std::string& address) = 0;
+        virtual void checkAndApplySentinelAddress(const std::string& address) = 0;
+        virtual void checkAndApplySentinelMasterName(const std::string& name) = 0;
         virtual DatabaseConfiguration::DbType getDbType() const = 0;
         virtual DatabaseConfiguration::Addresses getServerAddresses() const = 0;
         virtual DatabaseConfiguration::Addresses getDefaultServerAddresses() const = 0;
+        virtual boost::optional<HostAndPort> getSentinelAddress() const = 0; // Optional return value, because empty HostAndPort can't be created.
+        virtual std::string getSentinelMasterName() const = 0;
         virtual bool isEmpty() const = 0;
 
         DatabaseConfiguration(DatabaseConfiguration&&) = delete;
index 6349ea3..64b3c21 100644 (file)
@@ -32,17 +32,27 @@ namespace shareddatalayer
 
         void checkAndApplyServerAddress(const std::string& address) override;
 
+        void checkAndApplySentinelAddress(const std::string& address) override;
+
+        void checkAndApplySentinelMasterName(const std::string& name) override;
+
         DatabaseConfiguration::DbType getDbType() const override;
 
         DatabaseConfigurationImpl::Addresses getServerAddresses() const override;
 
         DatabaseConfiguration::Addresses getDefaultServerAddresses() const override;
 
+        boost::optional<HostAndPort> getSentinelAddress() const override;
+
+        std::string getSentinelMasterName() const override;
+
         bool isEmpty() const override;
 
     private:
         DbType dbType;
         Addresses serverAddresses;
+        boost::optional<HostAndPort> sentinelAddress;
+        std::string sentinelMasterName;
     };
 }
 
index 567f1ec..c9e25d1 100644 (file)
@@ -20,6 +20,7 @@
 #include <string>
 #include <stdint.h>
 #include <sdl/exception.hpp>
+#include <iosfwd>
 
 namespace shareddatalayer
 {
@@ -77,6 +78,8 @@ namespace shareddatalayer
     public:
         EmptyHost();
     };
+
+    std::ostream& operator << (std::ostream& os, const HostAndPort& hostAndPort);
 }
 
 #endif
index 98d1d23..effc4f9 100644 (file)
@@ -52,10 +52,14 @@ namespace shareddatalayer
             AsyncSentinelDatabaseDiscovery& operator = (const AsyncSentinelDatabaseDiscovery&) = delete;
 
             AsyncSentinelDatabaseDiscovery(std::shared_ptr<Engine> engine,
-                                           std::shared_ptr<Logger> logger);
+                                           std::shared_ptr<Logger> logger,
+                                           const HostAndPort& sentinelAddress,
+                                           const std::string& sentinelMasterName);
 
             AsyncSentinelDatabaseDiscovery(std::shared_ptr<Engine> engine,
                                            std::shared_ptr<Logger> logger,
+                                           const HostAndPort& sentinelAddress,
+                                           const std::string& sentinelMasterName,
                                            const AsyncCommandDispatcherCreator& asyncCommandDispatcherCreator,
                                            std::shared_ptr<redis::ContentsBuilder> contentsBuilder);
 
@@ -71,6 +75,7 @@ namespace shareddatalayer
             std::shared_ptr<Logger> logger;
             StateChangedCb stateChangedCb;
             DatabaseInfo databaseInfo;
+            std::string sentinelMasterName;
             std::shared_ptr<redis::AsyncCommandDispatcher> subscriber;
             std::shared_ptr<redis::AsyncCommandDispatcher> dispatcher;
             std::shared_ptr<redis::ContentsBuilder> contentsBuilder;
index a195c67..0fd56f8 100644 (file)
@@ -28,10 +28,14 @@ namespace shareddatalayer
         public:
             MOCK_METHOD1(checkAndApplyDbType, void(const std::string& type));
             MOCK_METHOD1(checkAndApplyServerAddress, void(const std::string& address));
+            MOCK_METHOD1(checkAndApplySentinelAddress, void(const std::string& address));
+            MOCK_METHOD1(checkAndApplySentinelMasterName, void(const std::string& name));
             MOCK_CONST_METHOD0(getDbType, DatabaseConfiguration::DbType());
             MOCK_CONST_METHOD0(getServerAddresses, DatabaseConfiguration::Addresses());
             MOCK_CONST_METHOD0(getDefaultServerAddresses, DatabaseConfiguration::Addresses());
             MOCK_CONST_METHOD0(isEmpty, bool());
+            MOCK_CONST_METHOD0(getSentinelAddress, boost::optional<HostAndPort>());
+            MOCK_CONST_METHOD0(getSentinelMasterName, std::string());
         };
     }
 }
index 87ac8c0..3c89e1e 100644 (file)
@@ -75,6 +75,14 @@ namespace
         return ports;
     }
 
+    void PrintEnvironmentVariable(std::ostream& out, std::string name)
+    {
+        const auto var(name.c_str());
+        const auto conf(getenv(var));
+        if (conf != nullptr)
+            out << var  << ": " << conf << std::endl;
+    }
+
     void PrintStaticConfiguration(std::ostream& out)
     {
         auto engine(std::make_shared<EngineImpl>());
@@ -93,6 +101,8 @@ namespace
                 out << "Static DB type: redis-cluster" << std::endl;
             else if (staticDbType == DatabaseConfiguration::DbType::REDIS_STANDALONE)
                 out << "Static DB type: redis-standalone" << std::endl;
+            else if (staticDbType == DatabaseConfiguration::DbType::REDIS_SENTINEL)
+                out << "Static DB type: redis-sentinel" << std::endl;
             else
                 out << "Static DB type not defined" << std::endl;
         }
@@ -102,10 +112,10 @@ namespace
             out << "Default Host: " << getHosts(defaultAddresses) << std::endl;
             out << "Default Port: " << getPorts(defaultAddresses) << std::endl;
         }
-        const auto var(DB_HOST_ENV_VAR_NAME);
-        const auto conf(getenv(var));
-        if (conf != nullptr)
-            out << var  << ": " << conf << std::endl;
+        PrintEnvironmentVariable(out, DB_HOST_ENV_VAR_NAME);
+        PrintEnvironmentVariable(out, DB_PORT_ENV_VAR_NAME);
+        PrintEnvironmentVariable(out, SENTINEL_PORT_ENV_VAR_NAME);
+        PrintEnvironmentVariable(out, SENTINEL_MASTER_NAME_ENV_VAR_NAME);
     }
 
     void PrintDatabaseInfo(const DatabaseInfo& databaseInfo, std::ostream& out)
index 85ab627..4b5de3b 100644 (file)
@@ -200,10 +200,14 @@ ConfigurationReader::ConfigurationReader(std::shared_ptr<Logger> logger):
 ConfigurationReader::ConfigurationReader(const Directories& directories,
                                          System& system,
                                          std::shared_ptr<Logger> logger):
-       dbHostEnvVariableName(DB_HOST_ENV_VAR_NAME),
-       dbHostEnvVariableValue({}),
-       dbPortEnvVariableName(DB_PORT_ENV_VAR_NAME),
-       dbPortEnvVariableValue({}),
+    dbHostEnvVariableName(DB_HOST_ENV_VAR_NAME),
+    dbHostEnvVariableValue({}),
+    dbPortEnvVariableName(DB_PORT_ENV_VAR_NAME),
+    dbPortEnvVariableValue({}),
+    sentinelPortEnvVariableName(SENTINEL_PORT_ENV_VAR_NAME),
+    sentinelPortEnvVariableValue({}),
+    sentinelMasterNameEnvVariableName(SENTINEL_MASTER_NAME_ENV_VAR_NAME),
+    sentinelMasterNameEnvVariableValue({}),
     jsonDatabaseConfiguration(boost::none),
     logger(logger)
 {
@@ -215,6 +219,12 @@ ConfigurationReader::ConfigurationReader(const Directories& directories,
         auto envStr = system.getenv(dbPortEnvVariableName.c_str());
         if (envStr)
             dbPortEnvVariableValue = envStr;
+        envStr = system.getenv(sentinelPortEnvVariableName.c_str());
+        if (envStr)
+            sentinelPortEnvVariableValue = envStr;
+        envStr = system.getenv(sentinelMasterNameEnvVariableName.c_str());
+        if (envStr)
+            sentinelMasterNameEnvVariableValue = envStr;
     }
 
     readConfigurationFromDirectories(directories);
@@ -285,12 +295,21 @@ void ConfigurationReader::readDatabaseConfiguration(DatabaseConfiguration& datab
     {
         if (sourceForDatabaseConfiguration == dbHostEnvVariableName)
         {
-            // Currently hard coded to redis-standalone, because RIC dbaas does not support Redis cluster configuration.
-               validateAndSetDbType("redis-standalone", databaseConfiguration, sourceForDatabaseConfiguration);
-               if (dbPortEnvVariableValue.empty())
-                       parseDatabaseServersConfigurationFromString(databaseConfiguration, dbHostEnvVariableValue, sourceForDatabaseConfiguration);
-               else
-                       parseDatabaseServersConfigurationFromString(databaseConfiguration, dbHostEnvVariableValue + ":" + dbPortEnvVariableValue, sourceForDatabaseConfiguration);
+            // NOTE: Redis cluster is not currently configurable via environment variables.
+            if (sentinelPortEnvVariableValue.empty())
+            {
+                validateAndSetDbType("redis-standalone", databaseConfiguration, sourceForDatabaseConfiguration);
+                if (dbPortEnvVariableValue.empty())
+                    parseDatabaseServersConfigurationFromString(databaseConfiguration, dbHostEnvVariableValue, sourceForDatabaseConfiguration);
+                else
+                    parseDatabaseServersConfigurationFromString(databaseConfiguration, dbHostEnvVariableValue + ":" + dbPortEnvVariableValue, sourceForDatabaseConfiguration);
+            }
+            else
+            {
+                validateAndSetDbType("redis-sentinel", databaseConfiguration, sourceForDatabaseConfiguration);
+                databaseConfiguration.checkAndApplySentinelAddress(dbHostEnvVariableValue + ":" + sentinelPortEnvVariableValue);
+                databaseConfiguration.checkAndApplySentinelMasterName(sentinelMasterNameEnvVariableValue);
+            }
         }
         else
             parseDatabaseConfigurationTree(databaseConfiguration, jsonDatabaseConfiguration, sourceForDatabaseConfiguration);
index f1fb2be..909e4e4 100644 (file)
@@ -28,6 +28,7 @@ namespace
     }
 
     const uint16_t DEFAULT_PORT(6379U);
+    const uint16_t DEFAULT_SENTINEL_PORT(26379U);
 }
 
 DatabaseConfigurationImpl::DatabaseConfigurationImpl():
@@ -45,6 +46,8 @@ void DatabaseConfigurationImpl::checkAndApplyDbType(const std::string& type)
         dbType = DatabaseConfiguration::DbType::REDIS_STANDALONE;
     else if (type == "redis-cluster")
         dbType = DatabaseConfiguration::DbType::REDIS_CLUSTER;
+    else if (type == "redis-sentinel")
+        dbType = DatabaseConfiguration::DbType::REDIS_SENTINEL;
     else
         throw DatabaseConfiguration::InvalidDbType(type);
 }
@@ -73,3 +76,23 @@ DatabaseConfiguration::Addresses DatabaseConfigurationImpl::getDefaultServerAddr
 {
     return { HostAndPort(getDefaultHost(), htons(DEFAULT_PORT)) };
 }
+
+void DatabaseConfigurationImpl::checkAndApplySentinelAddress(const std::string& address)
+{
+    sentinelAddress = HostAndPort(address, htons(DEFAULT_SENTINEL_PORT));
+}
+
+boost::optional<HostAndPort> DatabaseConfigurationImpl::getSentinelAddress() const
+{
+    return sentinelAddress;
+}
+
+void DatabaseConfigurationImpl::checkAndApplySentinelMasterName(const std::string& name)
+{
+    sentinelMasterName = name;
+}
+
+std::string DatabaseConfigurationImpl::getSentinelMasterName() const
+{
+    return sentinelMasterName;
+}
index de045ed..ed711c8 100644 (file)
@@ -20,6 +20,7 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <boost/lexical_cast.hpp>
+#include <ostream>
 
 using namespace shareddatalayer;
 
@@ -156,3 +157,9 @@ bool HostAndPort::operator<(const HostAndPort& hp) const
     else
         return this->getHost() < hp.getHost();
 }
+
+std::ostream& shareddatalayer::operator << (std::ostream& os, const HostAndPort& hostAndPort)
+{
+    os << hostAndPort.getHost() << ":" << hostAndPort.getPort();
+    return os;
+}
index 63f2f12..66a440d 100644 (file)
    limitations under the License.
 */
 
-#include "private/redis/asyncdatabasediscovery.hpp"
-#include "private/databaseconfiguration.hpp"
-#include "private/logger.hpp"
 #include <cstdlib>
 #include "config.h"
+#include "private/abort.hpp"
+#include "private/databaseconfiguration.hpp"
+#include "private/logger.hpp"
+#include "private/redis/asyncdatabasediscovery.hpp"
 #if HAVE_HIREDIS
 #include "private/redis/asynchiredisdatabasediscovery.hpp"
 #endif
-#if HAVE_SENTINEL
 #include "private/redis/asyncsentineldatabasediscovery.hpp"
-#endif
-#include "private/abort.hpp"
 
 using namespace shareddatalayer::redis;
 
@@ -54,17 +52,26 @@ std::shared_ptr<AsyncDatabaseDiscovery> AsyncDatabaseDiscovery::create(std::shar
     else
     {
 #if HAVE_HIREDIS
-#if HAVE_SENTINEL
-        static_cast<void>(ns);
-        return std::make_shared<AsyncSentinelDatabaseDiscovery>(engine,
-                                                                logger);
-#else
-        return std::make_shared<AsyncHiredisDatabaseDiscovery>(engine,
-                                                               ns,
-                                                               DatabaseInfo::Type::SINGLE,
-                                                               staticAddresses,
-                                                               logger);
-#endif
+        if (staticDbType == DatabaseConfiguration::DbType::REDIS_SENTINEL)
+        {
+            static_cast<void>(ns);
+            auto sentinelAddress(staticDatabaseConfiguration.getSentinelAddress());
+            if (sentinelAddress)
+                return std::make_shared<AsyncSentinelDatabaseDiscovery>(engine,
+                                                                        logger,
+                                                                        *sentinelAddress,
+                                                                        staticDatabaseConfiguration.getSentinelMasterName());
+            else
+                SHAREDDATALAYER_ABORT("Sentinel address not configured.");
+        }
+        else
+        {
+            return std::make_shared<AsyncHiredisDatabaseDiscovery>(engine,
+                                                                   ns,
+                                                                   DatabaseInfo::Type::SINGLE,
+                                                                   staticAddresses,
+                                                                   logger);
+        }
 #else
         static_cast<void>(logger);
         SHAREDDATALAYER_ABORT("No Hiredis");
index be51c5e..7c06f15 100644 (file)
@@ -56,9 +56,13 @@ namespace
 }
 
 AsyncSentinelDatabaseDiscovery::AsyncSentinelDatabaseDiscovery(std::shared_ptr<Engine> engine,
-                                                               std::shared_ptr<Logger> logger):
+                                                               std::shared_ptr<Logger> logger,
+                                                               const HostAndPort& sentinelAddress,
+                                                               const std::string& sentinelMasterName):
         AsyncSentinelDatabaseDiscovery(engine,
                                        logger,
+                                       sentinelAddress,
+                                       sentinelMasterName,
                                        ::asyncCommandDispatcherCreator,
                                        std::make_shared<redis::ContentsBuilder>(AsyncStorage::SEPARATOR))
 {
@@ -66,15 +70,17 @@ AsyncSentinelDatabaseDiscovery::AsyncSentinelDatabaseDiscovery(std::shared_ptr<E
 
 AsyncSentinelDatabaseDiscovery::AsyncSentinelDatabaseDiscovery(std::shared_ptr<Engine> engine,
                                                                std::shared_ptr<Logger> logger,
+                                                               const HostAndPort& sentinelAddress,
+                                                               const std::string& sentinelMasterName,
                                                                const AsyncCommandDispatcherCreator& asyncCommandDispatcherCreator,
                                                                std::shared_ptr<redis::ContentsBuilder> contentsBuilder):
         engine(engine),
         logger(logger),
-        // @TODO Make configurable.
-        databaseInfo(DatabaseInfo({DatabaseConfiguration::Addresses({HostAndPort("dbaas-ha", htons(26379U))}),
+        databaseInfo(DatabaseInfo({DatabaseConfiguration::Addresses({sentinelAddress}),
                      DatabaseInfo::Type::SINGLE,
                      boost::none,
                      DatabaseInfo::Discovery::SENTINEL})),
+        sentinelMasterName(sentinelMasterName),
         contentsBuilder(contentsBuilder),
         subscribeRetryTimer(*engine),
         subscribeRetryTimerDuration(std::chrono::seconds(1)),
@@ -181,7 +187,7 @@ void AsyncSentinelDatabaseDiscovery::sendMasterInquiry()
                                         std::placeholders::_1,
                                         std::placeholders::_2),
                               "dummyNamespace", // Not meaningful for Sentinel
-                              contentsBuilder->build("SENTINEL", "get-master-addr-by-name", "mymaster")); //@TODO Make master name configurable
+                              contentsBuilder->build("SENTINEL", "get-master-addr-by-name", sentinelMasterName));
 }
 
 void AsyncSentinelDatabaseDiscovery::masterInquiryAck(const std::error_code& error,
index ab48284..f6c43fa 100644 (file)
@@ -364,6 +364,8 @@ namespace
                     new AsyncSentinelDatabaseDiscovery(
                             engineMock,
                             logger,
+                            HostAndPort(someHost, somePort),
+                            "mymaster",
                             std::bind(&AsyncSentinelDatabaseDiscoveryBaseTest::asyncCommandDispatcherCreator,
                                       this),
                             contentsBuilderMock));
index 8120052..980c470 100644 (file)
@@ -62,6 +62,16 @@ namespace
             EXPECT_CALL(databaseConfigurationMock, checkAndApplyServerAddress(address));
         }
 
+        void expectSentinelAddressConfigurationCheckAndApply(const std::string& address)
+        {
+            EXPECT_CALL(databaseConfigurationMock, checkAndApplySentinelAddress(address));
+        }
+
+        void expectSentinelMasterNameConfigurationCheckAndApply(const std::string& address)
+        {
+            EXPECT_CALL(databaseConfigurationMock, checkAndApplySentinelMasterName(address));
+        }
+
         void expectDatabaseConfigurationIsEmpty_returnFalse()
         {
             EXPECT_CALL(databaseConfigurationMock, isEmpty()).
@@ -723,6 +733,8 @@ class ConfigurationReaderEnvironmentVariableTest: public ConfigurationReaderBase
 public:
     std::string dbHostEnvVariableValue;
     std::string dbPortEnvVariableValue;
+    std::string sentinelPortEnvVariableValue;
+    std::string sentinelMasterNameEnvVariableValue;
     std::istringstream is{R"JSON(
         {
             "database":
@@ -757,7 +769,7 @@ public:
             try
             {
                 EXPECT_CALL(systemMock, getenv(_))
-                                   .Times(2)
+                    .Times(4)
                     .WillOnce(Return(dbHostEnvVariableValue.c_str()))
                     .WillOnce(Return(nullptr));
                 initializeReaderWithoutDirectories();
@@ -779,6 +791,8 @@ TEST_F(ConfigurationReaderEnvironmentVariableTest, EnvironmentConfigurationCanOv
     expectGetEnvironmentString(dbHostEnvVariableValue.c_str());
     dbPortEnvVariableValue = "12345";
     expectGetEnvironmentString(dbPortEnvVariableValue.c_str());
+    expectGetEnvironmentString(nullptr); //SENTINEL_PORT_ENV_VAR_NAME
+    expectGetEnvironmentString(nullptr); //SENTINEL_MASTER_NAME_ENV_VAR_NAME
 
     expectDbTypeConfigurationCheckAndApply("redis-standalone");
     expectDBServerAddressConfigurationCheckAndApply("unknownAddress.local:12345");
@@ -792,7 +806,9 @@ TEST_F(ConfigurationReaderEnvironmentVariableTest, EnvironmentConfigurationWitho
     InSequence dummy;
     dbHostEnvVariableValue = "server.local";
     expectGetEnvironmentString(dbHostEnvVariableValue.c_str());
-    expectGetEnvironmentString(nullptr);
+    expectGetEnvironmentString(nullptr); //DB_PORT_ENV_VAR_NAME
+    expectGetEnvironmentString(nullptr); //SENTINEL_PORT_ENV_VAR_NAME
+    expectGetEnvironmentString(nullptr); //SENTINEL_MASTER_NAME_ENV_VAR_NAME
 
     expectDbTypeConfigurationCheckAndApply("redis-standalone");
     expectDBServerAddressConfigurationCheckAndApply("server.local");
@@ -817,10 +833,31 @@ TEST_F(ConfigurationReaderEnvironmentVariableTest, EnvironmentConfigurationAccep
     InSequence dummy;
     dbHostEnvVariableValue = "[2001::123]:12345";
     expectGetEnvironmentString(dbHostEnvVariableValue.c_str());
-    expectGetEnvironmentString(nullptr);
+    expectGetEnvironmentString(nullptr); //DB_PORT_ENV_VAR_NAME
+    expectGetEnvironmentString(nullptr); //SENTINEL_PORT_ENV_VAR_NAME
+    expectGetEnvironmentString(nullptr); //SENTINEL_MASTER_NAME_ENV_VAR_NAME
 
     expectDbTypeConfigurationCheckAndApply("redis-standalone");
     expectDBServerAddressConfigurationCheckAndApply("[2001::123]:12345");
     initializeReaderWithoutDirectories();
     configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
 }
+
+TEST_F(ConfigurationReaderEnvironmentVariableTest, EnvironmentConfigurationWithSentinel)
+{
+    InSequence dummy;
+    dbHostEnvVariableValue = "sentinelAddress.local";
+    expectGetEnvironmentString(dbHostEnvVariableValue.c_str());
+    dbPortEnvVariableValue = "1111";
+    expectGetEnvironmentString(dbPortEnvVariableValue.c_str());
+    sentinelPortEnvVariableValue = "2222";
+    expectGetEnvironmentString(sentinelPortEnvVariableValue.c_str());
+    sentinelMasterNameEnvVariableValue = "mymaster";
+    expectGetEnvironmentString(sentinelMasterNameEnvVariableValue.c_str());
+
+    expectDbTypeConfigurationCheckAndApply("redis-sentinel");
+    expectSentinelAddressConfigurationCheckAndApply("sentinelAddress.local:2222");
+    expectSentinelMasterNameConfigurationCheckAndApply(sentinelMasterNameEnvVariableValue);
+    initializeReaderWithoutDirectories();
+    configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
+}
index d29e663..7a34b0f 100644 (file)
@@ -71,6 +71,13 @@ TEST_F(DatabaseConfigurationImplTest, CanApplyRedisClusterDbTypeStringAndReturnT
     EXPECT_EQ(DatabaseConfiguration::DbType::REDIS_CLUSTER, retDbType);
 }
 
+TEST_F(DatabaseConfigurationImplTest, CanApplyRedisSentinelDbTypeStringAndReturnType)
+{
+    databaseConfigurationImpl->checkAndApplyDbType("redis-sentinel");
+    const auto retDbType(databaseConfigurationImpl->getDbType());
+    EXPECT_EQ(DatabaseConfiguration::DbType::REDIS_SENTINEL, retDbType);
+}
+
 TEST_F(DatabaseConfigurationImplTest, CanApplyNewAddressesOneByOneAndReturnAllAddresses)
 {
     databaseConfigurationImpl->checkAndApplyServerAddress("dummydatabaseaddress.local");
@@ -103,3 +110,28 @@ TEST_F(DatabaseConfigurationImplTest, IsEmptyReturnsCorrectInformation)
     databaseConfigurationImpl->checkAndApplyServerAddress("[2001::123]:12345");
     EXPECT_FALSE(databaseConfigurationImpl->isEmpty());
 }
+
+TEST_F(DatabaseConfigurationImplTest, DefaultSentinelAddressIsNone)
+{
+    EXPECT_EQ(boost::none, databaseConfigurationImpl->getSentinelAddress());
+}
+
+TEST_F(DatabaseConfigurationImplTest, CanApplyAndReturnSentinelAddress)
+{
+    databaseConfigurationImpl->checkAndApplySentinelAddress("dummydatabaseaddress.local:1234");
+    auto address = databaseConfigurationImpl->getSentinelAddress();
+    EXPECT_NE(boost::none, databaseConfigurationImpl->getSentinelAddress());
+    EXPECT_EQ("dummydatabaseaddress.local", address->getHost());
+    EXPECT_EQ(1234, ntohs(address->getPort()));
+}
+
+TEST_F(DatabaseConfigurationImplTest, DefaultSentinelMasterNameIsEmpty)
+{
+    EXPECT_EQ("", databaseConfigurationImpl->getSentinelMasterName());
+}
+
+TEST_F(DatabaseConfigurationImplTest, CanApplyAndReturnSentinelMasterName)
+{
+    databaseConfigurationImpl->checkAndApplySentinelMasterName("mymaster");
+    EXPECT_EQ("mymaster", databaseConfigurationImpl->getSentinelMasterName());
+}
index 7b9f97b..8f0c2d2 100644 (file)
@@ -17,6 +17,7 @@
 #include <arpa/inet.h>
 #include <gtest/gtest.h>
 #include "private/hostandport.hpp"
+#include <sstream>
 
 using namespace shareddatalayer;
 using namespace testing;
@@ -135,3 +136,12 @@ TEST(HostAndPortTest, EmptyHostThrows)
 {
     EXPECT_THROW(HostAndPort(":1234", htons(100)), HostAndPort::EmptyHost);
 }
+
+TEST(HostAndPortTest, CanOutput)
+{
+    std::string expectedOutput("somehost.somesubdomain.somedomain:1234");
+    std::stringstream ss;
+    HostAndPort hostAndPort("somehost.somesubdomain.somedomain", 1234);
+    ss << hostAndPort;
+    EXPECT_EQ(expectedOutput, ss.str());
+}