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 <petri.ovaska@nokia.com>
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 @@
# 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 <petri.ovaska@nokia.com> 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 @@
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 @@
* 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 @@
* 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 @@
{
public:
using AsyncDatabaseDiscoveryCreator = std::function<std::shared_ptr<redis::AsyncDatabaseDiscovery>(std::shared_ptr<Engine> engine,
+ const std::string& ns,
const DatabaseConfiguration& databaseConfiguration,
+ const boost::optional<std::size_t>& addressIndex,
std::shared_ptr<Logger> logger)>;
AsyncStorageImpl(const AsyncStorageImpl&) = delete;
@@ -94,8 +97,13 @@
std::shared_ptr<Logger> logger;
AsyncDatabaseDiscoveryCreator asyncDatabaseDiscoveryCreator;
- AsyncStorage& getRedisHandler();
+ std::vector<std::shared_ptr<AsyncRedisStorage>> 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 <iosfwd>
#include <string>
@@ -72,6 +73,8 @@
std::string sentinelPortEnvVariableValue;
const std::string sentinelMasterNameEnvVariableName;
std::string sentinelMasterNameEnvVariableValue;
+ const std::string dbClusterAddrListEnvVariableName;
+ std::string dbClusterAddrListEnvVariableValue;
boost::optional<boost::property_tree::ptree> jsonDatabaseConfiguration;
std::string sourceForDatabaseConfiguration;
std::unordered_map<std::string, std::pair<boost::property_tree::ptree, std::string>> 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 @@
UNKNOWN = 0,
REDIS_STANDALONE,
REDIS_CLUSTER,
- REDIS_SENTINEL
+ REDIS_SENTINEL,
+ SDL_CLUSTER
};
virtual ~DatabaseConfiguration() = default;
@@ -51,6 +52,7 @@
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 boost::optional<HostAndPort> getSentinelAddress(const boost::optional<std::size_t>& 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 @@
boost::optional<HostAndPort> getSentinelAddress() const override;
+ boost::optional<HostAndPort> getSentinelAddress(const boost::optional<std::size_t>& 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 @@
static std::shared_ptr<AsyncDatabaseDiscovery> create(std::shared_ptr<Engine> engine,
const boost::optional<Namespace>& ns,
const DatabaseConfiguration& staticDatabaseConfiguration,
+ const boost::optional<std::size_t>& addressIndex,
std::shared_ptr<Logger> 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 @@
MOCK_CONST_METHOD0(getDefaultServerAddresses, DatabaseConfiguration::Addresses());
MOCK_CONST_METHOD0(isEmpty, bool());
MOCK_CONST_METHOD0(getSentinelAddress, boost::optional<HostAndPort>());
+ MOCK_CONST_METHOD1(getSentinelAddress, boost::optional<HostAndPort>(const boost::optional<std::size_t>& 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 @@
%{_includedir}/sdl
%changelog
+* Wed May 26 2021 Petri Ovaska <petri.ovaska@nokia.com> - 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 <timo.tietavainen@nokia.com> - 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 <boost/optional/optional_io.hpp>
+#include <boost/crc.hpp>
+
using namespace shareddatalayer;
using namespace shareddatalayer::redis;
namespace
{
std::shared_ptr<AsyncDatabaseDiscovery> asyncDatabaseDiscoveryCreator(std::shared_ptr<Engine> engine,
+ const std::string& ns,
const DatabaseConfiguration& databaseConfiguration,
+ const boost::optional<std::size_t>& addressIndex,
std::shared_ptr<Logger> 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> engine,
@@ -78,19 +96,40 @@
{
}
-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<AsyncRedisStorage>(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};
+ auto serverAddresses(databaseConfiguration->getServerAddresses());
+ if (asyncStorages.empty())
+ setAsyncRedisStorageHandlers(ns);
- return redisHandler;
+ return getAsyncRedisStorageHandler(ns);
#else
logger->error() << "Redis operations cannot be performed, Redis not enabled";
SHAREDDATALAYER_ABORT("Invalid configuration.");
@@ -106,7 +145,7 @@
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 @@
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 @@
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 @@
}
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 @@
{
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 <arpa/inet.h>
+#include <boost/crc.hpp>
using namespace shareddatalayer;
@@ -53,6 +54,8 @@
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 @@
return sentinelAddress;
}
+boost::optional<HostAndPort> DatabaseConfigurationImpl::getSentinelAddress(const boost::optional<std::size_t>& 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 @@
std::shared_ptr<AsyncDatabaseDiscovery> AsyncDatabaseDiscovery::create(std::shared_ptr<Engine> engine,
const boost::optional<Namespace>& ns,
const DatabaseConfiguration& staticDatabaseConfiguration,
+ const boost::optional<std::size_t>& addressIndex,
std::shared_ptr<Logger> logger)
{
auto staticAddresses(staticDatabaseConfiguration.getServerAddresses());
@@ -57,10 +58,10 @@
else
{
#if HAVE_HIREDIS
- if (staticDbType == DatabaseConfiguration::DbType::REDIS_SENTINEL)
+ if (staticDbType == DatabaseConfiguration::DbType::REDIS_SENTINEL ||
+ staticDbType == DatabaseConfiguration::DbType::SDL_CLUSTER)
{
- static_cast<void>(ns);
- auto sentinelAddress(staticDatabaseConfiguration.getSentinelAddress());
+ auto sentinelAddress(staticDatabaseConfiguration.getSentinelAddress(addressIndex));
if (sentinelAddress)
return std::make_shared<AsyncSentinelDatabaseDiscovery>(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 @@
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<AsyncStorage>), 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 @@
this,
std::placeholders::_1,
std::placeholders::_2,
- std::placeholders::_3)));
+ std::placeholders::_3,
+ std::placeholders::_4,
+ std::placeholders::_5)));
}
std::shared_ptr<redis::AsyncDatabaseDiscovery> asyncDatabaseDiscoveryCreator(std::shared_ptr<Engine>,
- const DatabaseConfiguration&,
- std::shared_ptr<Logger>)
+ const std::string&,
+ const DatabaseConfiguration&,
+ const boost::optional<std::size_t>&,
+ std::shared_ptr<Logger>)
{
return discoveryMock;
}
@@ -140,3 +144,11 @@
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 @@
std::string dbPortEnvVariableValue;
std::string sentinelPortEnvVariableValue;
std::string sentinelMasterNameEnvVariableValue;
+ std::string dbClusterAddrListEnvVariableValue;
std::istringstream is{R"JSON(
{
"database":
@@ -774,8 +775,11 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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, 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 @@
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 @@
{
EXPECT_TRUE(std::is_abstract<SyncStorage>::value);
}
+
+TEST(SyncStorageTest, SyncStorageCreateInstanceHasCorrectType)
+{
+ auto syncStorageInstance(shareddatalayer::SyncStorage::create());
+ EXPECT_EQ(typeid(std::unique_ptr<SyncStorage>), typeid(syncStorageInstance));
+}