From: Petri Ovaska Date: Thu, 15 Apr 2021 08:08:13 +0000 (+0300) Subject: Multiple DBAAS Redis Sentinel groups X-Git-Tag: 1.2.1~2 X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=commitdiff_plain;h=ece67088ea6c4f67b9d0db74477a9d5c614d7763;p=ric-plt%2Fsdl.git Multiple DBAAS Redis Sentinel groups Added support to have one or more Redis Sentinel DB groups. The DB groups can be used to spread out SDL DB operations to different DB instances. The new DBAAS_CLUSTER_ADDR_LIST environment variable is used for Sentinel DB service addresses configuration. The selection of DB instance is done based on the calculation of crc32 value from the namespace string and return modulo hash value of number of addresses in the list. Issue-ID: RIC-699 Change-Id: I8bb3a78680cedfba4a39f06f7e2f8cdd60d26949 Signed-off-by: Petri Ovaska --- diff --git a/configure.ac b/configure.ac index 349e84a..5ad03f7 100644 --- a/configure.ac +++ b/configure.ac @@ -10,8 +10,8 @@ # Change the numbers just before release. m4_define([SDL_MAJOR], [1]) -m4_define([SDL_MINOR], [1]) -m4_define([SDL_MICRO], [3]) +m4_define([SDL_MINOR], [2]) +m4_define([SDL_MICRO], [0]) # SDL ABI version with libtool # @@ -28,8 +28,8 @@ m4_define([SDL_MICRO], [3]) # Change the numbers just before release. m4_define([SDL_CURRENT], [2]) -m4_define([SDL_REVISION], [7]) -m4_define([SDL_AGE], [1]) +m4_define([SDL_REVISION], [8]) +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]) AC_CONFIG_HEADERS([include/config.h]) diff --git a/debian/changelog.in b/debian/changelog.in index 9963428..0291e29 100644 --- a/debian/changelog.in +++ b/debian/changelog.in @@ -1,3 +1,10 @@ +sdl (1.2.0-1) UNRELEASED; urgency=low + + * Multiple DBAAS Redis Sentinel groups + * New namespace (--ns) option in sdltool test-get-set -command + + -- Petri Ovaska Wed May 26 17:27:08 2021 +0300 + sdl (1.1.3-1) UNRELEASED; urgency=low * Rename rpm and Debian makefile targets to rpm-pkg and deb-pkg. diff --git a/docs/release-notes.rst b/docs/release-notes.rst index cc07534..ca53e2b 100644 --- a/docs/release-notes.rst +++ b/docs/release-notes.rst @@ -29,6 +29,11 @@ This document provides the release notes of the sdl library. Version history --------------- +[1.2.0] - 2021-05-26 + +* Multiple DBAAS Redis Sentinel groups +* New namespace (--ns) option in sdltool test-get-set -command + [1.1.3] - 2020-05-16 * Rename rpm and Debian makefile targets to rpm-pkg and deb-pkg. diff --git a/docs/user-guide.rst b/docs/user-guide.rst index a601b15..9b5d6a8 100644 --- a/docs/user-guide.rst +++ b/docs/user-guide.rst @@ -238,6 +238,7 @@ configure database backend: * DBAAS_SERVICE_PORT * DBAAS_SERVICE_SENTINEL_PORT * DBAAS_MASTER_NAME +* DBAAS_CLUSTER_ADDR_LIST After DBaaS service is installed, environment variables are exposed to application containers. SDL library will automatically use these environment @@ -419,9 +420,11 @@ storage: * Standalone (single DB node without redundancy) * Redundant (DB node pair working in master/slave redundancy model) -SDL does not currently have any intelligent logic (e.g. dynamic scaling) on -which storage node each namespace data is stored. This area might be developed -further in the future. +SDL supports also Redis sentinel based DB cluster where deployment has one or +more DBAAS Redis sentinel group. Different DBAAS Redis sentinel groups +can be used to distribute SDL DB operations to different SDL DB instances. When +more than one DBAAS Redis sentinel group exits the selection of SDL DB instance +is based on the namespace string hash calculation. SDL does not prevent backend data storage to be deployed in the same node with the SDL client. Such deployments are, however, typically used only in diff --git a/include/private/asyncstorageimpl.hpp b/include/private/asyncstorageimpl.hpp index 34548f0..5999833 100644 --- a/include/private/asyncstorageimpl.hpp +++ b/include/private/asyncstorageimpl.hpp @@ -30,6 +30,7 @@ #include "private/logger.hpp" #include "private/namespaceconfigurationsimpl.hpp" #include "private/redis/asyncdatabasediscovery.hpp" +#include "private/redis/asyncredisstorage.hpp" namespace shareddatalayer { @@ -39,7 +40,9 @@ namespace shareddatalayer { public: using AsyncDatabaseDiscoveryCreator = std::function(std::shared_ptr engine, + const std::string& ns, const DatabaseConfiguration& databaseConfiguration, + const boost::optional& addressIndex, std::shared_ptr logger)>; AsyncStorageImpl(const AsyncStorageImpl&) = delete; @@ -94,8 +97,13 @@ namespace shareddatalayer std::shared_ptr logger; AsyncDatabaseDiscoveryCreator asyncDatabaseDiscoveryCreator; - AsyncStorage& getRedisHandler(); + std::vector> asyncStorages; + + AsyncStorage& getRedisHandler(const std::string& ns); AsyncStorage& getDummyHandler(); + + void setAsyncRedisStorageHandlers(const std::string& ns); + AsyncStorage& getAsyncRedisStorageHandler(const std::string& ns); }; } diff --git a/include/private/configurationreader.hpp b/include/private/configurationreader.hpp index dd151c6..9454ba8 100644 --- a/include/private/configurationreader.hpp +++ b/include/private/configurationreader.hpp @@ -26,6 +26,7 @@ #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" +#define DB_CLUSTER_ADDR_LIST_ENV_VAR_NAME "DBAAS_CLUSTER_ADDR_LIST" #include #include @@ -72,6 +73,8 @@ namespace shareddatalayer std::string sentinelPortEnvVariableValue; const std::string sentinelMasterNameEnvVariableName; std::string sentinelMasterNameEnvVariableValue; + const std::string dbClusterAddrListEnvVariableName; + std::string dbClusterAddrListEnvVariableValue; boost::optional jsonDatabaseConfiguration; std::string sourceForDatabaseConfiguration; std::unordered_map> jsonNamespaceConfigurations; diff --git a/include/private/databaseconfiguration.hpp b/include/private/databaseconfiguration.hpp index 7f4e7bd..56274cb 100644 --- a/include/private/databaseconfiguration.hpp +++ b/include/private/databaseconfiguration.hpp @@ -39,7 +39,8 @@ namespace shareddatalayer UNKNOWN = 0, REDIS_STANDALONE, REDIS_CLUSTER, - REDIS_SENTINEL + REDIS_SENTINEL, + SDL_CLUSTER }; virtual ~DatabaseConfiguration() = default; @@ -51,6 +52,7 @@ namespace shareddatalayer 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 boost::optional getSentinelAddress(const boost::optional& addressIndex) const = 0; virtual std::string getSentinelMasterName() const = 0; virtual bool isEmpty() const = 0; diff --git a/include/private/databaseconfigurationimpl.hpp b/include/private/databaseconfigurationimpl.hpp index 8ae4f9a..c499d5a 100644 --- a/include/private/databaseconfigurationimpl.hpp +++ b/include/private/databaseconfigurationimpl.hpp @@ -49,6 +49,8 @@ namespace shareddatalayer boost::optional getSentinelAddress() const override; + boost::optional getSentinelAddress(const boost::optional& addressIndex) const override; + std::string getSentinelMasterName() const override; bool isEmpty() const override; diff --git a/include/private/redis/asyncdatabasediscovery.hpp b/include/private/redis/asyncdatabasediscovery.hpp index 37a45d4..813d658 100644 --- a/include/private/redis/asyncdatabasediscovery.hpp +++ b/include/private/redis/asyncdatabasediscovery.hpp @@ -71,6 +71,7 @@ namespace shareddatalayer static std::shared_ptr create(std::shared_ptr engine, const boost::optional& ns, const DatabaseConfiguration& staticDatabaseConfiguration, + const boost::optional& addressIndex, std::shared_ptr logger); protected: diff --git a/include/private/tst/databaseconfigurationmock.hpp b/include/private/tst/databaseconfigurationmock.hpp index 502e6a6..e4fe0af 100644 --- a/include/private/tst/databaseconfigurationmock.hpp +++ b/include/private/tst/databaseconfigurationmock.hpp @@ -40,6 +40,7 @@ namespace shareddatalayer MOCK_CONST_METHOD0(getDefaultServerAddresses, DatabaseConfiguration::Addresses()); MOCK_CONST_METHOD0(isEmpty, bool()); MOCK_CONST_METHOD0(getSentinelAddress, boost::optional()); + MOCK_CONST_METHOD1(getSentinelAddress, boost::optional(const boost::optional& addressIndex)); MOCK_CONST_METHOD0(getSentinelMasterName, std::string()); }; } diff --git a/rpm/sdl.spec.in b/rpm/sdl.spec.in index f7973ec..ed49ad7 100755 --- a/rpm/sdl.spec.in +++ b/rpm/sdl.spec.in @@ -1,5 +1,5 @@ Name: sdl -Version: 1.1.3 +Version: 1.2.0 Release: 1%{?dist} Summary: C++ API library for Shared Data Layer clients @@ -50,6 +50,10 @@ rm -f %{buildroot}%{_libdir}/lib*.*a %{_includedir}/sdl %changelog +* Wed May 26 2021 Petri Ovaska - 1.2.0-1 +- Multiple DBAAS Redis Sentinel groups +- New namespace (--ns) option in sdltool test-get-set -command + * Sat May 16 2020 Timo Tietavainen - 1.1.3-1 - Rename rpm and Debian makefile targets to rpm-pkg and deb-pkg. - Update CI Dockerfile to utilize rpm-pkg and deb-pkg makefile targets. diff --git a/src/asyncstorageimpl.cpp b/src/asyncstorageimpl.cpp index 31ac713..d9478c2 100644 --- a/src/asyncstorageimpl.cpp +++ b/src/asyncstorageimpl.cpp @@ -31,20 +31,38 @@ #include "private/redis/asyncredisstorage.hpp" #endif +#include +#include + using namespace shareddatalayer; using namespace shareddatalayer::redis; namespace { std::shared_ptr asyncDatabaseDiscoveryCreator(std::shared_ptr engine, + const std::string& ns, const DatabaseConfiguration& databaseConfiguration, + const boost::optional& addressIndex, std::shared_ptr logger) { return AsyncDatabaseDiscovery::create(engine, - boost::none, + ns, databaseConfiguration, + addressIndex, logger); } + + std::uint32_t crc32(const std::string& s) + { + boost::crc_32_type result; + result.process_bytes(s.data(), s.size()); + return result.checksum(); + } + + std::uint32_t getClusterHashIndex(const std::string& s, const size_t count) + { + return crc32(s)%count; + } } AsyncStorageImpl::AsyncStorageImpl(std::shared_ptr engine, @@ -78,19 +96,40 @@ AsyncStorageImpl::AsyncStorageImpl(std::shared_ptr engine, { } -AsyncStorage& AsyncStorageImpl::getRedisHandler() +void AsyncStorageImpl::setAsyncRedisStorageHandlers(const std::string& ns) +{ + for (std::size_t i = 0; i < databaseConfiguration->getServerAddresses().size(); i++) + { + auto redisHandler = std::make_shared(engine, + asyncDatabaseDiscoveryCreator( + engine, + ns, + std::ref(*databaseConfiguration), + i, + logger), + publisherId, + namespaceConfigurations, + logger); + asyncStorages.push_back(redisHandler); + } +} + +AsyncStorage& AsyncStorageImpl::getAsyncRedisStorageHandler(const std::string& ns) +{ + std::size_t handlerIndex{0}; + if (DatabaseConfiguration::DbType::SDL_CLUSTER == databaseConfiguration->getDbType()) + handlerIndex = getClusterHashIndex(ns, databaseConfiguration->getServerAddresses().size()); + return *asyncStorages.at(handlerIndex); +} + +AsyncStorage& AsyncStorageImpl::getRedisHandler(const std::string& ns) { #if HAVE_REDIS - static AsyncRedisStorage redisHandler{engine, - asyncDatabaseDiscoveryCreator( - engine, - std::ref(*databaseConfiguration), - logger), - publisherId, - namespaceConfigurations, - logger}; - - return redisHandler; + auto serverAddresses(databaseConfiguration->getServerAddresses()); + if (asyncStorages.empty()) + setAsyncRedisStorageHandlers(ns); + + return getAsyncRedisStorageHandler(ns); #else logger->error() << "Redis operations cannot be performed, Redis not enabled"; SHAREDDATALAYER_ABORT("Invalid configuration."); @@ -106,7 +145,7 @@ AsyncStorage& AsyncStorageImpl::getDummyHandler() AsyncStorage& AsyncStorageImpl::getOperationHandler(const std::string& ns) { if (namespaceConfigurations->isDbBackendUseEnabled(ns)) - return getRedisHandler(); + return getRedisHandler(ns); return getDummyHandler(); } diff --git a/src/configurationreader.cpp b/src/configurationreader.cpp index cc5e33e..18945b6 100644 --- a/src/configurationreader.cpp +++ b/src/configurationreader.cpp @@ -213,6 +213,8 @@ ConfigurationReader::ConfigurationReader(const Directories& directories, sentinelPortEnvVariableValue({}), sentinelMasterNameEnvVariableName(SENTINEL_MASTER_NAME_ENV_VAR_NAME), sentinelMasterNameEnvVariableValue({}), + dbClusterAddrListEnvVariableName(DB_CLUSTER_ADDR_LIST_ENV_VAR_NAME), + dbClusterAddrListEnvVariableValue({}), jsonDatabaseConfiguration(boost::none), logger(logger) { @@ -230,6 +232,9 @@ ConfigurationReader::ConfigurationReader(const Directories& directories, envStr = system.getenv(sentinelMasterNameEnvVariableName.c_str()); if (envStr) sentinelMasterNameEnvVariableValue = envStr; + envStr = system.getenv(dbClusterAddrListEnvVariableName.c_str()); + if (envStr) + dbClusterAddrListEnvVariableValue = envStr; } readConfigurationFromDirectories(directories); @@ -311,7 +316,14 @@ void ConfigurationReader::readDatabaseConfiguration(DatabaseConfiguration& datab } else { - validateAndSetDbType("redis-sentinel", databaseConfiguration, sourceForDatabaseConfiguration); + if (dbClusterAddrListEnvVariableValue.empty()) + validateAndSetDbType("redis-sentinel", databaseConfiguration, sourceForDatabaseConfiguration); + else { + validateAndSetDbType("sdl-cluster", databaseConfiguration, sourceForDatabaseConfiguration); + parseDatabaseServersConfigurationFromString(databaseConfiguration, + dbClusterAddrListEnvVariableValue, + dbClusterAddrListEnvVariableName); + } databaseConfiguration.checkAndApplySentinelAddress(dbHostEnvVariableValue + ":" + sentinelPortEnvVariableValue); databaseConfiguration.checkAndApplySentinelMasterName(sentinelMasterNameEnvVariableValue); } diff --git a/src/databaseconfiguration.cpp b/src/databaseconfiguration.cpp index a33f5bc..41dfb09 100644 --- a/src/databaseconfiguration.cpp +++ b/src/databaseconfiguration.cpp @@ -30,7 +30,7 @@ namespace { std::ostringstream os; os << "invalid database type: '" << type << "'. "; - os << "Allowed types are: 'redis-standalone' or 'redis-cluster'"; + os << "Allowed types are: 'redis-standalone', 'redis-cluster', 'redis-sentinel' or 'sdl-cluster'"; return os.str(); } } diff --git a/src/databaseconfigurationimpl.cpp b/src/databaseconfigurationimpl.cpp index a8f64e6..211c537 100644 --- a/src/databaseconfigurationimpl.cpp +++ b/src/databaseconfigurationimpl.cpp @@ -21,6 +21,7 @@ #include "private/databaseconfigurationimpl.hpp" #include +#include using namespace shareddatalayer; @@ -53,6 +54,8 @@ void DatabaseConfigurationImpl::checkAndApplyDbType(const std::string& type) dbType = DatabaseConfiguration::DbType::REDIS_CLUSTER; else if (type == "redis-sentinel") dbType = DatabaseConfiguration::DbType::REDIS_SENTINEL; + else if (type == "sdl-cluster") + dbType = DatabaseConfiguration::DbType::SDL_CLUSTER; else throw DatabaseConfiguration::InvalidDbType(type); } @@ -92,6 +95,14 @@ boost::optional DatabaseConfigurationImpl::getSentinelAddress() con return sentinelAddress; } +boost::optional DatabaseConfigurationImpl::getSentinelAddress(const boost::optional& addressIndex) const +{ + if (addressIndex) + return { HostAndPort(serverAddresses.at(*addressIndex).getHost(), sentinelAddress->getPort()) }; + + return getSentinelAddress(); +} + void DatabaseConfigurationImpl::checkAndApplySentinelMasterName(const std::string& name) { sentinelMasterName = name; diff --git a/src/redis/asyncdatabasediscovery.cpp b/src/redis/asyncdatabasediscovery.cpp index 28bbf79..8723def 100644 --- a/src/redis/asyncdatabasediscovery.cpp +++ b/src/redis/asyncdatabasediscovery.cpp @@ -35,6 +35,7 @@ using namespace shareddatalayer::redis; std::shared_ptr AsyncDatabaseDiscovery::create(std::shared_ptr engine, const boost::optional& ns, const DatabaseConfiguration& staticDatabaseConfiguration, + const boost::optional& addressIndex, std::shared_ptr logger) { auto staticAddresses(staticDatabaseConfiguration.getServerAddresses()); @@ -57,10 +58,10 @@ std::shared_ptr AsyncDatabaseDiscovery::create(std::shar else { #if HAVE_HIREDIS - if (staticDbType == DatabaseConfiguration::DbType::REDIS_SENTINEL) + if (staticDbType == DatabaseConfiguration::DbType::REDIS_SENTINEL || + staticDbType == DatabaseConfiguration::DbType::SDL_CLUSTER) { - static_cast(ns); - auto sentinelAddress(staticDatabaseConfiguration.getSentinelAddress()); + auto sentinelAddress(staticDatabaseConfiguration.getSentinelAddress(addressIndex)); if (sentinelAddress) return std::make_shared(engine, logger, diff --git a/tst/asyncstorage_test.cpp b/tst/asyncstorage_test.cpp index 5e0fe16..3ee1d5f 100644 --- a/tst/asyncstorage_test.cpp +++ b/tst/asyncstorage_test.cpp @@ -53,3 +53,9 @@ TEST(AsyncStorageTest, CanThrowWhenDisallowedSeparatorCharacterIsUsedInNamespace const std::string notValidNamespace(std::string("someNamespace") + AsyncStorage::SEPARATOR); EXPECT_THROW(validateNamespace(notValidNamespace), InvalidNamespace); } + +TEST(AsyncStorageTest, AsyncStorageCreateInstanceHasCorrectType) +{ + auto asyncStorageInstance(shareddatalayer::AsyncStorage::create()); + EXPECT_EQ(typeid(std::unique_ptr), typeid(asyncStorageInstance)); +} diff --git a/tst/asyncstorageimpl_test.cpp b/tst/asyncstorageimpl_test.cpp index 84955f5..8fd2147 100644 --- a/tst/asyncstorageimpl_test.cpp +++ b/tst/asyncstorageimpl_test.cpp @@ -71,12 +71,16 @@ namespace this, std::placeholders::_1, std::placeholders::_2, - std::placeholders::_3))); + std::placeholders::_3, + std::placeholders::_4, + std::placeholders::_5))); } std::shared_ptr asyncDatabaseDiscoveryCreator(std::shared_ptr, - const DatabaseConfiguration&, - std::shared_ptr) + const std::string&, + const DatabaseConfiguration&, + const boost::optional&, + std::shared_ptr) { return discoveryMock; } @@ -140,3 +144,11 @@ TEST_F(AsyncStorageImplTest, CorrectHandlerIsUsedBasedOnConfiguration) AsyncStorage& returnedHandler2 = asyncStorageImpl->getOperationHandler(ns); EXPECT_EQ(typeid(AsyncDummyStorage&), typeid(returnedHandler2)); } + +TEST_F(AsyncStorageImplTest, CorrectSdlClusterHandlerIsUsedBasedOnConfiguration) +{ + expectNamespaceConfigurationIsDbBackendUseEnabled_returnTrue(); + dummyDatabaseConfiguration->checkAndApplyDbType("sdl-cluster"); + AsyncStorage& returnedHandler = asyncStorageImpl->getOperationHandler(ns); + EXPECT_EQ(typeid(AsyncRedisStorage&), typeid(returnedHandler)); +} diff --git a/tst/configurationreader_test.cpp b/tst/configurationreader_test.cpp index b1ed9f1..4e730f0 100644 --- a/tst/configurationreader_test.cpp +++ b/tst/configurationreader_test.cpp @@ -740,6 +740,7 @@ public: std::string dbPortEnvVariableValue; std::string sentinelPortEnvVariableValue; std::string sentinelMasterNameEnvVariableValue; + std::string dbClusterAddrListEnvVariableValue; std::istringstream is{R"JSON( { "database": @@ -774,8 +775,11 @@ public: try { EXPECT_CALL(systemMock, getenv(_)) - .Times(4) + .Times(5) .WillOnce(Return(dbHostEnvVariableValue.c_str())) + .WillOnce(Return(nullptr)) + .WillOnce(Return(nullptr)) + .WillOnce(Return(nullptr)) .WillOnce(Return(nullptr)); initializeReaderWithoutDirectories(); configurationReader->readDatabaseConfiguration(databaseConfigurationMock); @@ -798,6 +802,7 @@ TEST_F(ConfigurationReaderEnvironmentVariableTest, EnvironmentConfigurationCanOv expectGetEnvironmentString(dbPortEnvVariableValue.c_str()); expectGetEnvironmentString(nullptr); //SENTINEL_PORT_ENV_VAR_NAME expectGetEnvironmentString(nullptr); //SENTINEL_MASTER_NAME_ENV_VAR_NAME + expectGetEnvironmentString(nullptr); //DB_CLUSTER_ENV_VAR_NAME expectDbTypeConfigurationCheckAndApply("redis-standalone"); expectDBServerAddressConfigurationCheckAndApply("unknownAddress.local:12345"); @@ -814,6 +819,7 @@ TEST_F(ConfigurationReaderEnvironmentVariableTest, EnvironmentConfigurationWitho expectGetEnvironmentString(nullptr); //DB_PORT_ENV_VAR_NAME expectGetEnvironmentString(nullptr); //SENTINEL_PORT_ENV_VAR_NAME expectGetEnvironmentString(nullptr); //SENTINEL_MASTER_NAME_ENV_VAR_NAME + expectGetEnvironmentString(nullptr); //DB_CLUSTER_ENV_VAR_NAME expectDbTypeConfigurationCheckAndApply("redis-standalone"); expectDBServerAddressConfigurationCheckAndApply("server.local"); @@ -841,6 +847,7 @@ TEST_F(ConfigurationReaderEnvironmentVariableTest, EnvironmentConfigurationAccep expectGetEnvironmentString(nullptr); //DB_PORT_ENV_VAR_NAME expectGetEnvironmentString(nullptr); //SENTINEL_PORT_ENV_VAR_NAME expectGetEnvironmentString(nullptr); //SENTINEL_MASTER_NAME_ENV_VAR_NAME + expectGetEnvironmentString(nullptr); //DB_CLUSTER_ENV_VAR_NAME expectDbTypeConfigurationCheckAndApply("redis-standalone"); expectDBServerAddressConfigurationCheckAndApply("[2001::123]:12345"); @@ -859,6 +866,7 @@ TEST_F(ConfigurationReaderEnvironmentVariableTest, EnvironmentConfigurationWithS expectGetEnvironmentString(sentinelPortEnvVariableValue.c_str()); sentinelMasterNameEnvVariableValue = "mymaster"; expectGetEnvironmentString(sentinelMasterNameEnvVariableValue.c_str()); + expectGetEnvironmentString(nullptr); //DB_CLUSTER_ENV_VAR_NAME expectDbTypeConfigurationCheckAndApply("redis-sentinel"); expectSentinelAddressConfigurationCheckAndApply("sentinelAddress.local:2222"); @@ -866,3 +874,27 @@ TEST_F(ConfigurationReaderEnvironmentVariableTest, EnvironmentConfigurationWithS initializeReaderWithoutDirectories(); configurationReader->readDatabaseConfiguration(databaseConfigurationMock); } + +TEST_F(ConfigurationReaderEnvironmentVariableTest, EnvironmentConfigurationWithSentinelAndClusterConfiguration) +{ + InSequence dummy; + dbHostEnvVariableValue = "address-0.local"; + expectGetEnvironmentString(dbHostEnvVariableValue.c_str()); + dbPortEnvVariableValue = "1111"; + expectGetEnvironmentString(dbPortEnvVariableValue.c_str()); + sentinelPortEnvVariableValue = "2222"; + expectGetEnvironmentString(sentinelPortEnvVariableValue.c_str()); + sentinelMasterNameEnvVariableValue = "mymaster"; + expectGetEnvironmentString(sentinelMasterNameEnvVariableValue.c_str()); + dbClusterAddrListEnvVariableValue = "address-0.local,address-1.local,address-2.local"; + expectGetEnvironmentString(dbClusterAddrListEnvVariableValue.c_str()); + + expectDbTypeConfigurationCheckAndApply("sdl-cluster"); + expectDBServerAddressConfigurationCheckAndApply("address-0.local"); + expectDBServerAddressConfigurationCheckAndApply("address-1.local"); + expectDBServerAddressConfigurationCheckAndApply("address-2.local"); + expectSentinelAddressConfigurationCheckAndApply("address-0.local:2222"); + expectSentinelMasterNameConfigurationCheckAndApply(sentinelMasterNameEnvVariableValue); + initializeReaderWithoutDirectories(); + configurationReader->readDatabaseConfiguration(databaseConfigurationMock); +} diff --git a/tst/databaseconfiguration_test.cpp b/tst/databaseconfiguration_test.cpp index 331deb7..9fc1a50 100644 --- a/tst/databaseconfiguration_test.cpp +++ b/tst/databaseconfiguration_test.cpp @@ -52,7 +52,7 @@ TEST(DatabaseConfigurationTest, CanThrowAndCatchInvalidDbType) } catch (const std::exception& e) { - EXPECT_STREQ("invalid database type: 'someBadDbType'. Allowed types are: 'redis-standalone' or 'redis-cluster'", e.what()); + EXPECT_STREQ("invalid database type: 'someBadDbType'. Allowed types are: 'redis-standalone', 'redis-cluster', 'redis-sentinel' or 'sdl-cluster'", e.what()); } } diff --git a/tst/databaseconfigurationimpl_test.cpp b/tst/databaseconfigurationimpl_test.cpp index 3b3083b..5a5356c 100644 --- a/tst/databaseconfigurationimpl_test.cpp +++ b/tst/databaseconfigurationimpl_test.cpp @@ -83,6 +83,13 @@ TEST_F(DatabaseConfigurationImplTest, CanApplyRedisSentinelDbTypeStringAndReturn EXPECT_EQ(DatabaseConfiguration::DbType::REDIS_SENTINEL, retDbType); } +TEST_F(DatabaseConfigurationImplTest, CanApplySdlClusterDbTypeStringAndReturnType) +{ + databaseConfigurationImpl->checkAndApplyDbType("sdl-cluster"); + const auto retDbType(databaseConfigurationImpl->getDbType()); + EXPECT_EQ(DatabaseConfiguration::DbType::SDL_CLUSTER, retDbType); +} + TEST_F(DatabaseConfigurationImplTest, CanApplyNewAddressesOneByOneAndReturnAllAddresses) { databaseConfigurationImpl->checkAndApplyServerAddress("dummydatabaseaddress.local"); @@ -118,14 +125,14 @@ TEST_F(DatabaseConfigurationImplTest, IsEmptyReturnsCorrectInformation) TEST_F(DatabaseConfigurationImplTest, DefaultSentinelAddressIsNone) { - EXPECT_EQ(boost::none, databaseConfigurationImpl->getSentinelAddress()); + EXPECT_EQ(boost::none, databaseConfigurationImpl->getSentinelAddress(boost::none)); } TEST_F(DatabaseConfigurationImplTest, CanApplyAndReturnSentinelAddress) { databaseConfigurationImpl->checkAndApplySentinelAddress("dummydatabaseaddress.local:1234"); - auto address = databaseConfigurationImpl->getSentinelAddress(); - EXPECT_NE(boost::none, databaseConfigurationImpl->getSentinelAddress()); + auto address = databaseConfigurationImpl->getSentinelAddress(boost::none); + EXPECT_NE(boost::none, databaseConfigurationImpl->getSentinelAddress(boost::none)); EXPECT_EQ("dummydatabaseaddress.local", address->getHost()); EXPECT_EQ(1234, ntohs(address->getPort())); } @@ -140,3 +147,32 @@ TEST_F(DatabaseConfigurationImplTest, CanApplyAndReturnSentinelMasterName) databaseConfigurationImpl->checkAndApplySentinelMasterName("mymaster"); EXPECT_EQ("mymaster", databaseConfigurationImpl->getSentinelMasterName()); } + +TEST_F(DatabaseConfigurationImplTest, CanReturnSDLClusterAddress) +{ + databaseConfigurationImpl->checkAndApplyDbType("sdl-cluster"); + databaseConfigurationImpl->checkAndApplyServerAddress("cluster-0.local"); + databaseConfigurationImpl->checkAndApplyServerAddress("cluster-1.local"); + databaseConfigurationImpl->checkAndApplyServerAddress("cluster-2.local"); + databaseConfigurationImpl->checkAndApplySentinelAddress("cluster-0.local:54321"); + auto address0 = databaseConfigurationImpl->getSentinelAddress(0); + auto address1 = databaseConfigurationImpl->getSentinelAddress(1); + auto address2 = databaseConfigurationImpl->getSentinelAddress(2); + EXPECT_NE(boost::none, databaseConfigurationImpl->getSentinelAddress(0)); + EXPECT_NE(boost::none, databaseConfigurationImpl->getSentinelAddress(1)); + EXPECT_NE(boost::none, databaseConfigurationImpl->getSentinelAddress(2)); + EXPECT_EQ("cluster-0.local", address0->getHost()); + EXPECT_EQ("cluster-1.local", address1->getHost()); + EXPECT_EQ("cluster-2.local", address2->getHost()); + EXPECT_EQ(54321, ntohs(address0->getPort())); +} + +TEST_F(DatabaseConfigurationImplTest, CanReturnDefaultPortForSDLClusterAddress) +{ + databaseConfigurationImpl->checkAndApplyServerAddress("cluster-0.local"); + databaseConfigurationImpl->checkAndApplySentinelAddress("cluster-0.local"); + auto address0 = databaseConfigurationImpl->getSentinelAddress(0); + EXPECT_NE(boost::none, databaseConfigurationImpl->getSentinelAddress(0)); + EXPECT_EQ("cluster-0.local", address0->getHost()); + EXPECT_EQ(26379, ntohs(address0->getPort())); +} diff --git a/tst/syncstorage_test.cpp b/tst/syncstorage_test.cpp index fdc4253..9467ef9 100644 --- a/tst/syncstorage_test.cpp +++ b/tst/syncstorage_test.cpp @@ -42,3 +42,9 @@ TEST(SyncStorageTest, IsAbstract) { EXPECT_TRUE(std::is_abstract::value); } + +TEST(SyncStorageTest, SyncStorageCreateInstanceHasCorrectType) +{ + auto syncStorageInstance(shareddatalayer::SyncStorage::create()); + EXPECT_EQ(typeid(std::unique_ptr), typeid(syncStorageInstance)); +}