From: Rolf Badorek Date: Tue, 1 Oct 2019 15:33:58 +0000 (+0300) Subject: Add Sentinel configuration reading X-Git-Tag: 1.2.1~23 X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=commitdiff_plain;h=2dcf940b7a815456af601cdc6fd8ebbc57bda161;p=ric-plt%2Fsdl.git Add Sentinel configuration reading 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 Change-Id: I34031ac56268673996c6fecb00eeed6e5dda8b9a --- diff --git a/Makefile.am b/Makefile.am index acd2cb6..19f2de9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 \ diff --git a/configure.ac b/configure.ac index 6155bde..216705f 100644 --- a/configure.ac +++ b/configure.ac @@ -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]) diff --git a/include/private/configurationreader.hpp b/include/private/configurationreader.hpp index 6c175e7..7cb6f1a 100644 --- a/include/private/configurationreader.hpp +++ b/include/private/configurationreader.hpp @@ -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 #include @@ -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 jsonDatabaseConfiguration; std::string sourceForDatabaseConfiguration; std::unordered_map> jsonNamespaceConfigurations; diff --git a/include/private/databaseconfiguration.hpp b/include/private/databaseconfiguration.hpp index fd24a11..5bf38a1 100644 --- a/include/private/databaseconfiguration.hpp +++ b/include/private/databaseconfiguration.hpp @@ -19,6 +19,7 @@ #include #include +#include #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 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; diff --git a/include/private/databaseconfigurationimpl.hpp b/include/private/databaseconfigurationimpl.hpp index 6349ea3..64b3c21 100644 --- a/include/private/databaseconfigurationimpl.hpp +++ b/include/private/databaseconfigurationimpl.hpp @@ -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 getSentinelAddress() const override; + + std::string getSentinelMasterName() const override; + bool isEmpty() const override; private: DbType dbType; Addresses serverAddresses; + boost::optional sentinelAddress; + std::string sentinelMasterName; }; } diff --git a/include/private/hostandport.hpp b/include/private/hostandport.hpp index 567f1ec..c9e25d1 100644 --- a/include/private/hostandport.hpp +++ b/include/private/hostandport.hpp @@ -20,6 +20,7 @@ #include #include #include +#include namespace shareddatalayer { @@ -77,6 +78,8 @@ namespace shareddatalayer public: EmptyHost(); }; + + std::ostream& operator << (std::ostream& os, const HostAndPort& hostAndPort); } #endif diff --git a/include/private/redis/asyncsentineldatabasediscovery.hpp b/include/private/redis/asyncsentineldatabasediscovery.hpp index 98d1d23..effc4f9 100644 --- a/include/private/redis/asyncsentineldatabasediscovery.hpp +++ b/include/private/redis/asyncsentineldatabasediscovery.hpp @@ -52,10 +52,14 @@ namespace shareddatalayer AsyncSentinelDatabaseDiscovery& operator = (const AsyncSentinelDatabaseDiscovery&) = delete; AsyncSentinelDatabaseDiscovery(std::shared_ptr engine, - std::shared_ptr logger); + std::shared_ptr logger, + const HostAndPort& sentinelAddress, + const std::string& sentinelMasterName); AsyncSentinelDatabaseDiscovery(std::shared_ptr engine, std::shared_ptr logger, + const HostAndPort& sentinelAddress, + const std::string& sentinelMasterName, const AsyncCommandDispatcherCreator& asyncCommandDispatcherCreator, std::shared_ptr contentsBuilder); @@ -71,6 +75,7 @@ namespace shareddatalayer std::shared_ptr logger; StateChangedCb stateChangedCb; DatabaseInfo databaseInfo; + std::string sentinelMasterName; std::shared_ptr subscriber; std::shared_ptr dispatcher; std::shared_ptr contentsBuilder; diff --git a/include/private/tst/databaseconfigurationmock.hpp b/include/private/tst/databaseconfigurationmock.hpp index a195c67..0fd56f8 100644 --- a/include/private/tst/databaseconfigurationmock.hpp +++ b/include/private/tst/databaseconfigurationmock.hpp @@ -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()); + MOCK_CONST_METHOD0(getSentinelMasterName, std::string()); }; } } diff --git a/src/cli/testconnectivitycommand.cpp b/src/cli/testconnectivitycommand.cpp index 87ac8c0..3c89e1e 100644 --- a/src/cli/testconnectivitycommand.cpp +++ b/src/cli/testconnectivitycommand.cpp @@ -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()); @@ -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) diff --git a/src/configurationreader.cpp b/src/configurationreader.cpp index 85ab627..4b5de3b 100644 --- a/src/configurationreader.cpp +++ b/src/configurationreader.cpp @@ -200,10 +200,14 @@ ConfigurationReader::ConfigurationReader(std::shared_ptr logger): ConfigurationReader::ConfigurationReader(const Directories& directories, System& system, std::shared_ptr 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); diff --git a/src/databaseconfigurationimpl.cpp b/src/databaseconfigurationimpl.cpp index f1fb2be..909e4e4 100644 --- a/src/databaseconfigurationimpl.cpp +++ b/src/databaseconfigurationimpl.cpp @@ -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 DatabaseConfigurationImpl::getSentinelAddress() const +{ + return sentinelAddress; +} + +void DatabaseConfigurationImpl::checkAndApplySentinelMasterName(const std::string& name) +{ + sentinelMasterName = name; +} + +std::string DatabaseConfigurationImpl::getSentinelMasterName() const +{ + return sentinelMasterName; +} diff --git a/src/hostandport.cpp b/src/hostandport.cpp index de045ed..ed711c8 100644 --- a/src/hostandport.cpp +++ b/src/hostandport.cpp @@ -20,6 +20,7 @@ #include #include #include +#include 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; +} diff --git a/src/redis/asyncdatabasediscovery.cpp b/src/redis/asyncdatabasediscovery.cpp index 63f2f12..66a440d 100644 --- a/src/redis/asyncdatabasediscovery.cpp +++ b/src/redis/asyncdatabasediscovery.cpp @@ -14,18 +14,16 @@ limitations under the License. */ -#include "private/redis/asyncdatabasediscovery.hpp" -#include "private/databaseconfiguration.hpp" -#include "private/logger.hpp" #include #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::create(std::shar else { #if HAVE_HIREDIS -#if HAVE_SENTINEL - static_cast(ns); - return std::make_shared(engine, - logger); -#else - return std::make_shared(engine, - ns, - DatabaseInfo::Type::SINGLE, - staticAddresses, - logger); -#endif + if (staticDbType == DatabaseConfiguration::DbType::REDIS_SENTINEL) + { + static_cast(ns); + auto sentinelAddress(staticDatabaseConfiguration.getSentinelAddress()); + if (sentinelAddress) + return std::make_shared(engine, + logger, + *sentinelAddress, + staticDatabaseConfiguration.getSentinelMasterName()); + else + SHAREDDATALAYER_ABORT("Sentinel address not configured."); + } + else + { + return std::make_shared(engine, + ns, + DatabaseInfo::Type::SINGLE, + staticAddresses, + logger); + } #else static_cast(logger); SHAREDDATALAYER_ABORT("No Hiredis"); diff --git a/src/redis/asyncsentineldatabasediscovery.cpp b/src/redis/asyncsentineldatabasediscovery.cpp index be51c5e..7c06f15 100644 --- a/src/redis/asyncsentineldatabasediscovery.cpp +++ b/src/redis/asyncsentineldatabasediscovery.cpp @@ -56,9 +56,13 @@ namespace } AsyncSentinelDatabaseDiscovery::AsyncSentinelDatabaseDiscovery(std::shared_ptr engine, - std::shared_ptr logger): + std::shared_ptr logger, + const HostAndPort& sentinelAddress, + const std::string& sentinelMasterName): AsyncSentinelDatabaseDiscovery(engine, logger, + sentinelAddress, + sentinelMasterName, ::asyncCommandDispatcherCreator, std::make_shared(AsyncStorage::SEPARATOR)) { @@ -66,15 +70,17 @@ AsyncSentinelDatabaseDiscovery::AsyncSentinelDatabaseDiscovery(std::shared_ptr engine, std::shared_ptr logger, + const HostAndPort& sentinelAddress, + const std::string& sentinelMasterName, const AsyncCommandDispatcherCreator& asyncCommandDispatcherCreator, std::shared_ptr 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, diff --git a/tst/asyncsentineldatabasediscovery_test.cpp b/tst/asyncsentineldatabasediscovery_test.cpp index ab48284..f6c43fa 100644 --- a/tst/asyncsentineldatabasediscovery_test.cpp +++ b/tst/asyncsentineldatabasediscovery_test.cpp @@ -364,6 +364,8 @@ namespace new AsyncSentinelDatabaseDiscovery( engineMock, logger, + HostAndPort(someHost, somePort), + "mymaster", std::bind(&AsyncSentinelDatabaseDiscoveryBaseTest::asyncCommandDispatcherCreator, this), contentsBuilderMock)); diff --git a/tst/configurationreader_test.cpp b/tst/configurationreader_test.cpp index 8120052..980c470 100644 --- a/tst/configurationreader_test.cpp +++ b/tst/configurationreader_test.cpp @@ -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); +} diff --git a/tst/databaseconfigurationimpl_test.cpp b/tst/databaseconfigurationimpl_test.cpp index d29e663..7a34b0f 100644 --- a/tst/databaseconfigurationimpl_test.cpp +++ b/tst/databaseconfigurationimpl_test.cpp @@ -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()); +} diff --git a/tst/hostandport_test.cpp b/tst/hostandport_test.cpp index 7b9f97b..8f0c2d2 100644 --- a/tst/hostandport_test.cpp +++ b/tst/hostandport_test.cpp @@ -17,6 +17,7 @@ #include #include #include "private/hostandport.hpp" +#include 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()); +}