diff --git a/common/dbconnector.cpp b/common/dbconnector.cpp index dc080d9b2..2f66931af 100644 --- a/common/dbconnector.cpp +++ b/common/dbconnector.cpp @@ -16,17 +16,11 @@ using namespace std; namespace swss { -void SonicDBConfig::initialize(const string &file) +void SonicDBConfig::parseDatabaseConfig(const string &file, + std::unordered_map &inst_entry, + std::unordered_map &db_entry, + std::unordered_map &separator_entry) { - - SWSS_LOG_ENTER(); - - if (m_init) - { - SWSS_LOG_ERROR("SonicDBConfig already initialized"); - throw runtime_error("SonicDBConfig already initialized"); - } - ifstream i(file); if (i.good()) { @@ -40,7 +34,7 @@ void SonicDBConfig::initialize(const string &file) string socket = it.value().at("unix_socket_path"); string hostname = it.value().at("hostname"); int port = it.value().at("port"); - m_inst_info[instName] = {socket, {hostname, port}}; + inst_entry[instName] = {socket, hostname, port}; } for (auto it = j["DATABASES"].begin(); it!= j["DATABASES"].end(); it++) @@ -49,12 +43,12 @@ void SonicDBConfig::initialize(const string &file) string instName = it.value().at("instance"); int dbId = it.value().at("id"); string separator = it.value().at("separator"); - m_db_info[dbName] = {instName, dbId, separator}; + db_entry[dbName] = {instName, dbId, separator}; - m_db_separator.emplace(dbId, separator); + separator_entry.emplace(dbId, separator); } - m_init = true; } + catch (domain_error& e) { SWSS_LOG_ERROR("key doesn't exist in json object, NULL value has no iterator >> %s\n", e.what()); @@ -73,32 +67,174 @@ void SonicDBConfig::initialize(const string &file) } } -string SonicDBConfig::getDbInst(const string &dbName) +void SonicDBConfig::initializeGlobalConfig(const string &file) +{ + std::string local_file, dir_name, ns_name; + std::unordered_map db_entry; + std::unordered_map inst_entry; + std::unordered_map separator_entry; + + SWSS_LOG_ENTER(); + + if (m_global_init) + { + SWSS_LOG_ERROR("SonicDBConfig Global config is already initialized"); + return; + } + + ifstream i(file); + if (i.good()) + { + local_file = dir_name = std::string(); + + // Get the directory name from the file path given as input. + std::string::size_type pos = file.rfind("/"); + if( pos != std::string::npos) + { + dir_name = file.substr(0,pos+1); + } + + try + { + json j; + i >> j; + + for (auto& element : j["INCLUDES"]) + { + local_file.append(dir_name); + local_file.append(element["include"]); + + if(element["namespace"].empty()) + { + // If database_config.json is already initlized via SonicDBConfig::initialize + // skip initializing it here again. + if(m_init) + { + local_file.clear(); + continue; + } + ns_name = EMPTY_NAMESPACE; + } + else + { + ns_name = element["namespace"]; + } + + parseDatabaseConfig(local_file, inst_entry, db_entry, separator_entry); + m_inst_info[ns_name] = inst_entry; + m_db_info[ns_name] = db_entry; + m_db_separator[ns_name] = separator_entry; + + if(element["namespace"].empty()) + { + // Make regular init also done + m_init = true; + } + + inst_entry.clear(); + db_entry.clear(); + separator_entry.clear(); + local_file.clear(); + } + } + + catch (domain_error& e) + { + SWSS_LOG_ERROR("key doesn't exist in json object, NULL value has no iterator >> %s\n", e.what()); + throw runtime_error("key doesn't exist in json object, NULL value has no iterator >> " + string(e.what())); + } + catch (exception &e) + { + SWSS_LOG_ERROR("Sonic database config file syntax error >> %s\n", e.what()); + throw runtime_error("Sonic database config file syntax error >> " + string(e.what())); + } + } + else + { + SWSS_LOG_ERROR("Sonic database config global file doesn't exist at %s\n", file.c_str()); + } + + // Set it as the global config file is already parsed and init done. + m_global_init = true; +} + +void SonicDBConfig::initialize(const string &file) +{ + std::unordered_map db_entry; + std::unordered_map inst_entry; + std::unordered_map separator_entry; + + SWSS_LOG_ENTER(); + + if (m_init) + { + SWSS_LOG_ERROR("SonicDBConfig already initialized"); + throw runtime_error("SonicDBConfig already initialized"); + } + + parseDatabaseConfig(file, inst_entry, db_entry, separator_entry); + m_inst_info[EMPTY_NAMESPACE] = inst_entry; + m_db_info[EMPTY_NAMESPACE] = db_entry; + m_db_separator[EMPTY_NAMESPACE] = separator_entry; + + // Set it as the config file is already parsed and init done. + m_init = true; +} + +void SonicDBConfig::validateNamespace(const string &netns) +{ + SWSS_LOG_ENTER(); + + // With valid namespace input and database_global.json is not loaded, ask user to initializeGlobalConfig first + if(!netns.empty()) + { + // If global initialization is not done, ask user to initialize global DB Config first. + if (!m_global_init) + { + SWSS_LOG_ERROR("Initialize global DB config first using API SonicDBConfig::initializeGlobalConfig \n"); + throw runtime_error("Initialize global DB config using API SonicDBConfig::initializeGlobalConfig"); + } + + // Check if the namespace is valid, check if this is a key in either of this map + unordered_map>::const_iterator entry = m_inst_info.find(netns); + if (entry == m_inst_info.end()) + { + SWSS_LOG_ERROR("Namespace %s is not a valid namespace name in config file\n", netns.c_str()); + throw runtime_error("Namespace " + netns + " is not a valid namespace name in config file"); + } + } +} + +string SonicDBConfig::getDbInst(const string &dbName, const string &netns) { if (!m_init) - initialize(); - return m_db_info.at(dbName).instName; + initialize(DEFAULT_SONIC_DB_CONFIG_FILE); + validateNamespace(netns); + return m_db_info[netns].at(dbName).instName; } -int SonicDBConfig::getDbId(const string &dbName) +int SonicDBConfig::getDbId(const string &dbName, const string &netns) { if (!m_init) - initialize(); - return m_db_info.at(dbName).dbId; + initialize(DEFAULT_SONIC_DB_CONFIG_FILE); + validateNamespace(netns); + return m_db_info[netns].at(dbName).dbId; } -string SonicDBConfig::getSeparator(const string &dbName) +string SonicDBConfig::getSeparator(const string &dbName, const string &netns) { if (!m_init) - initialize(); - return m_db_info.at(dbName).separator; + initialize(DEFAULT_SONIC_DB_CONFIG_FILE); + validateNamespace(netns); + return m_db_info[netns].at(dbName).separator; } -string SonicDBConfig::getSeparator(int dbId) +string SonicDBConfig::getSeparator(int dbId, const string &netns) { if (!m_init) - initialize(); - return m_db_separator.at(dbId); + initialize(DEFAULT_SONIC_DB_CONFIG_FILE); + validateNamespace(netns); + return m_db_separator[netns].at(dbId); } string SonicDBConfig::getSeparator(const DBConnector* db) @@ -109,42 +245,64 @@ string SonicDBConfig::getSeparator(const DBConnector* db) } string dbName = db->getDbName(); + string netns = db->getNamespace(); if (dbName.empty()) { - return getSeparator(db->getDbId()); + return getSeparator(db->getDbId(), netns); } else { - return getSeparator(dbName); + return getSeparator(dbName, netns); } } -string SonicDBConfig::getDbSock(const string &dbName) +string SonicDBConfig::getDbSock(const string &dbName, const string &netns) { if (!m_init) - initialize(); - return m_inst_info.at(getDbInst(dbName)).first; + initialize(DEFAULT_SONIC_DB_CONFIG_FILE); + validateNamespace(netns); + return m_inst_info[netns].at(getDbInst(dbName)).unixSocketPath; } -string SonicDBConfig::getDbHostname(const string &dbName) +string SonicDBConfig::getDbHostname(const string &dbName, const string &netns) { if (!m_init) - initialize(); - return m_inst_info.at(getDbInst(dbName)).second.first; + initialize(DEFAULT_SONIC_DB_CONFIG_FILE); + validateNamespace(netns); + return m_inst_info[netns].at(getDbInst(dbName)).hostname; } -int SonicDBConfig::getDbPort(const string &dbName) +int SonicDBConfig::getDbPort(const string &dbName, const string &netns) { if (!m_init) - initialize(); - return m_inst_info.at(getDbInst(dbName)).second.second; + initialize(DEFAULT_SONIC_DB_CONFIG_FILE); + validateNamespace(netns); + return m_inst_info[netns].at(getDbInst(dbName)).port; +} + +vector SonicDBConfig::getNamespaces() +{ + vector list; + + if (!m_global_init) + initializeGlobalConfig(); + + // This API returns back non-empty namespaces. + for (auto it = m_inst_info.cbegin(); it != m_inst_info.cend(); ++it) { + if(!((it->first).empty())) + list.push_back(it->first); + } + + return list; } constexpr const char *SonicDBConfig::DEFAULT_SONIC_DB_CONFIG_FILE; -unordered_map>> SonicDBConfig::m_inst_info; -unordered_map SonicDBConfig::m_db_info; -unordered_map SonicDBConfig::m_db_separator; +constexpr const char *SonicDBConfig::DEFAULT_SONIC_DB_GLOBAL_CONFIG_FILE; +unordered_map> SonicDBConfig::m_inst_info; +unordered_map> SonicDBConfig::m_db_info; +unordered_map> SonicDBConfig::m_db_separator; bool SonicDBConfig::m_init = false; +bool SonicDBConfig::m_global_init = false; constexpr const char *DBConnector::DEFAULT_UNIXSOCKET; @@ -164,7 +322,8 @@ DBConnector::~DBConnector() DBConnector::DBConnector(int dbId, const string& hostname, int port, unsigned int timeout) : - m_dbId(dbId) + m_dbId(dbId), + m_namespace(EMPTY_NAMESPACE) { struct timeval tv = {0, (suseconds_t)timeout * 1000}; @@ -181,7 +340,8 @@ DBConnector::DBConnector(int dbId, const string& hostname, int port, } DBConnector::DBConnector(int dbId, const string& unixPath, unsigned int timeout) : - m_dbId(dbId) + m_dbId(dbId), + m_namespace(EMPTY_NAMESPACE) { struct timeval tv = {0, (suseconds_t)timeout * 1000}; @@ -192,30 +352,31 @@ DBConnector::DBConnector(int dbId, const string& unixPath, unsigned int timeout) if (m_conn->err) throw system_error(make_error_code(errc::address_not_available), - "Unable to connect to redis (unixs-socket)"); + "Unable to connect to redis (unix-socket)"); select(this); } -DBConnector::DBConnector(const string& dbName, unsigned int timeout, bool isTcpConn) - : m_dbId(SonicDBConfig::getDbId(dbName)) +DBConnector::DBConnector(const string& dbName, unsigned int timeout, bool isTcpConn, const string& netns) + : m_dbId(SonicDBConfig::getDbId(dbName, netns)) , m_dbName(dbName) + , m_namespace(netns) { struct timeval tv = {0, (suseconds_t)timeout * 1000}; if (timeout) { if (isTcpConn) - m_conn = redisConnectWithTimeout(SonicDBConfig::getDbHostname(dbName).c_str(), SonicDBConfig::getDbPort(dbName), tv); + m_conn = redisConnectWithTimeout(SonicDBConfig::getDbHostname(dbName, netns).c_str(), SonicDBConfig::getDbPort(dbName, netns), tv); else - m_conn = redisConnectUnixWithTimeout(SonicDBConfig::getDbSock(dbName).c_str(), tv); + m_conn = redisConnectUnixWithTimeout(SonicDBConfig::getDbSock(dbName, netns).c_str(), tv); } else { if (isTcpConn) - m_conn = redisConnect(SonicDBConfig::getDbHostname(dbName).c_str(), SonicDBConfig::getDbPort(dbName)); + m_conn = redisConnect(SonicDBConfig::getDbHostname(dbName, netns).c_str(), SonicDBConfig::getDbPort(dbName, netns)); else - m_conn = redisConnectUnix(SonicDBConfig::getDbSock(dbName).c_str()); + m_conn = redisConnectUnix(SonicDBConfig::getDbSock(dbName, netns).c_str()); } if (m_conn->err) @@ -225,6 +386,12 @@ DBConnector::DBConnector(const string& dbName, unsigned int timeout, bool isTcpC select(this); } +DBConnector::DBConnector(const string& dbName, unsigned int timeout, bool isTcpConn) + : DBConnector(dbName, timeout, isTcpConn, EMPTY_NAMESPACE) +{ + // Empty contructor +} + redisContext *DBConnector::getContext() const { return m_conn; @@ -240,9 +407,15 @@ string DBConnector::getDbName() const return m_dbName; } +string DBConnector::getNamespace() const +{ + return m_namespace; +} + DBConnector *DBConnector::newConnector(unsigned int timeout) const { DBConnector *ret; + if (getContext()->connection_type == REDIS_CONN_TCP) ret = new DBConnector(getDbId(), getContext()->tcp.host, @@ -252,7 +425,10 @@ DBConnector *DBConnector::newConnector(unsigned int timeout) const ret = new DBConnector(getDbId(), getContext()->unix_sock.path, timeout); + ret->m_dbName = m_dbName; + ret->m_namespace = m_namespace; + return ret; } diff --git a/common/dbconnector.h b/common/dbconnector.h index 62fbbde96..ef397dc79 100644 --- a/common/dbconnector.h +++ b/common/dbconnector.h @@ -7,11 +7,20 @@ #include #include +#define EMPTY_NAMESPACE std::string() namespace swss { class DBConnector; +class RedisInstInfo +{ +public: + std::string unixSocketPath; + std::string hostname; + int port; +}; + class SonicDBInfo { public: @@ -24,25 +33,35 @@ class SonicDBConfig { public: static void initialize(const std::string &file = DEFAULT_SONIC_DB_CONFIG_FILE); - static std::string getDbInst(const std::string &dbName); - static int getDbId(const std::string &dbName); - static std::string getSeparator(const std::string &dbName); - static std::string getSeparator(int dbId); + static void initializeGlobalConfig(const std::string &file = DEFAULT_SONIC_DB_GLOBAL_CONFIG_FILE); + static void validateNamespace(const std::string &netns); + static std::string getDbInst(const std::string &dbName, const std::string &netns = EMPTY_NAMESPACE); + static int getDbId(const std::string &dbName, const std::string &netns = EMPTY_NAMESPACE); + static std::string getSeparator(const std::string &dbName, const std::string &netns = EMPTY_NAMESPACE); + static std::string getSeparator(int dbId, const std::string &netns = EMPTY_NAMESPACE); static std::string getSeparator(const DBConnector* db); - static std::string getDbSock(const std::string &dbName); - static std::string getDbHostname(const std::string &dbName); - static int getDbPort(const std::string &dbName); + static std::string getDbSock(const std::string &dbName, const std::string &netns = EMPTY_NAMESPACE); + static std::string getDbHostname(const std::string &dbName, const std::string &netns = EMPTY_NAMESPACE); + static int getDbPort(const std::string &dbName, const std::string &netns = EMPTY_NAMESPACE); + static std::vector getNamespaces(); static bool isInit() { return m_init; }; + static bool isGlobalInit() { return m_global_init; }; private: static constexpr const char *DEFAULT_SONIC_DB_CONFIG_FILE = "/var/run/redis/sonic-db/database_config.json"; - // { instName, { unix_socket_path, {hostname, port} } } - static std::unordered_map>> m_inst_info; - // { dbName, {instName, dbId} } - static std::unordered_map m_db_info; - // { dbIp, separator } - static std::unordered_map m_db_separator; + static constexpr const char *DEFAULT_SONIC_DB_GLOBAL_CONFIG_FILE = "/var/run/redis/sonic-db/database_global.json"; + // { namespace { instName, { unix_socket_path, hostname, port } } } + static std::unordered_map> m_inst_info; + // { namespace, { dbName, {instName, dbId, separator} } } + static std::unordered_map> m_db_info; + // { namespace, { dbId, separator } } + static std::unordered_map> m_db_separator; static bool m_init; + static bool m_global_init; + static void parseDatabaseConfig(const std::string &file, + std::unordered_map &inst_entry, + std::unordered_map &db_entry, + std::unordered_map &separator_entry); }; class DBConnector @@ -60,12 +79,14 @@ class DBConnector DBConnector(int dbId, const std::string &hostname, int port, unsigned int timeout); DBConnector(int dbId, const std::string &unixPath, unsigned int timeout); DBConnector(const std::string &dbName, unsigned int timeout, bool isTcpConn = false); + DBConnector(const std::string &dbName, unsigned int timeout, bool isTcpConn, const std::string &netns); ~DBConnector(); redisContext *getContext() const; int getDbId() const; std::string getDbName() const; + std::string getNamespace() const; static void select(DBConnector *db); @@ -84,6 +105,7 @@ class DBConnector redisContext *m_conn; int m_dbId; std::string m_dbName; + std::string m_namespace; }; } diff --git a/common/redisselect.cpp b/common/redisselect.cpp index 465428220..4c76f19f8 100644 --- a/common/redisselect.cpp +++ b/common/redisselect.cpp @@ -16,6 +16,15 @@ int RedisSelect::getFd() { return m_subscribe->getContext()->fd; } +int RedisSelect::getDbConnectorId() +{ + return m_subscribe->getDbId(); +} + +std::string RedisSelect::getDbNamespace() +{ + return m_subscribe->getNamespace(); +} uint64_t RedisSelect::readData() { diff --git a/common/redisselect.h b/common/redisselect.h index 97a70b12b..6c291a4dd 100644 --- a/common/redisselect.h +++ b/common/redisselect.h @@ -20,6 +20,8 @@ class RedisSelect : public Selectable bool hasCachedData() override; bool initializedWithData() override; void updateAfterRead() override; + int getDbConnectorId() override; + std::string getDbNamespace() override; /* Create a new redisContext, SELECT DB and SUBSCRIBE */ void subscribe(DBConnector* db, const std::string &channelName); diff --git a/common/selectable.h b/common/selectable.h index 268b933c8..7de56685a 100644 --- a/common/selectable.h +++ b/common/selectable.h @@ -58,6 +58,16 @@ class Selectable return m_priority; } + virtual int getDbConnectorId() + { + return 0; + } + + virtual std::string getDbNamespace() + { + return std::string(); + } + private: friend class Select; diff --git a/tests/Makefile.am b/tests/Makefile.am index a059ac792..9fbf48ead 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -28,6 +28,7 @@ tests_SOURCES = redis_ut.cpp \ warm_restart_ut.cpp \ redis_multi_db_ut.cpp \ logger_ut.cpp \ + redis_multi_ns_ut.cpp \ fdb_flush.cpp \ main.cpp diff --git a/tests/main.cpp b/tests/main.cpp index 89c4bdb29..94aa53da8 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -7,6 +7,11 @@ using namespace swss; string existing_file = "./tests/redis_multi_db_ut_config/database_config.json"; string nonexisting_file = "./tests/redis_multi_db_ut_config/database_config_nonexisting.json"; +string global_existing_file = "./tests/redis_multi_db_ut_config/database_global.json"; + +#define TEST_DB "APPL_DB" +#define TEST_NAMESPACE "asic0" +#define INVALID_NAMESPACE "invalid" class SwsscommonEnvironment : public ::testing::Environment { public: @@ -32,6 +37,39 @@ class SwsscommonEnvironment : public ::testing::Environment { SonicDBConfig::initialize(existing_file); cout<<"INIT: load local db config file, isInit = "< +#include +#include "gtest/gtest.h" +#include "common/dbconnector.h" +#include "common/json.hpp" +#include "common/table.h" +#include + +using namespace std; +using namespace swss; +using json = nlohmann::json; + +extern string global_existing_file; + +TEST(DBConnector, multi_ns_test) +{ + std::string local_file, dir_name, ns_name; + vector namespaces; + vector ns_names; + + // load global config file again, should throw exception with init already done + try + { + cout<<"INIT: loading local config file again"<> g; + + // Get the directory name from the file path given as input. + std::string::size_type pos = global_existing_file.rfind("/"); + dir_name = global_existing_file.substr(0,pos+1); + + for (auto& element : g["INCLUDES"]) + { + local_file.append(dir_name); + local_file.append(element["include"]); + + if(element["namespace"].empty()) + { + ns_name = EMPTY_NAMESPACE; + } + else + { + ns_name = element["namespace"]; + namespaces.push_back(ns_name); + } + + // parse config file + ifstream i(local_file); + + if (i.good()) + { + json j; + i >> j; + unordered_map m_inst_info; + for (auto it = j["INSTANCES"].begin(); it!= j["INSTANCES"].end(); it++) + { + string instName = it.key(); + string socket = it.value().at("unix_socket_path"); + string hostname = it.value().at("hostname"); + int port = it.value().at("port"); + m_inst_info[instName] = {socket, hostname, port}; + } + + for (auto it = j["DATABASES"].begin(); it!= j["DATABASES"].end(); it++) + { + string dbName = it.key(); + string instName = it.value().at("instance"); + int dbId = it.value().at("id"); + cout<<"testing "< values; + + for (int i = 1; i < 4; i++) + { + string field = "field_" + to_string(i); + string value = to_string(i); + values.push_back(make_pair(field, value)); + } + + cout << "- Step 1. SET" << endl; + cout << "Set key [a] field_1:1 field_2:2 field_3:3" << endl; + cout << "Set key [b] field_1:1 field_2:2 field_3:3" << endl; + + t.set(key_1, values); + t.set(key_2, values); + + cout << "- Step 2. GET_TABLE_KEYS" << endl; + vector keys; + t.getKeys(keys); + EXPECT_EQ(keys.size(), (size_t)2); + + for (auto k : keys) + { + cout << "Get key [" << k << "]" << flush; + EXPECT_EQ(k.length(), (size_t)1); + } + + cout << "- Step 3. GET_TABLE_CONTENT" << endl; + vector tuples; + t.getContent(tuples); + + cout << "Get total " << tuples.size() << " number of entries" << endl; + EXPECT_EQ(tuples.size(), (size_t)2); + + for (auto tuple: tuples) + { + cout << "Get key [" << kfvKey(tuple) << "]" << flush; + unsigned int size_v = 3; + EXPECT_EQ(kfvFieldsValues(tuple).size(), size_v); + for (auto fv: kfvFieldsValues(tuple)) + { + string value_1 = "1", value_2 = "2"; + cout << " " << fvField(fv) << ":" << fvValue(fv) << flush; + if (fvField(fv) == "field_1") + { + EXPECT_EQ(fvValue(fv), value_1); + } + if (fvField(fv) == "field_2") + { + EXPECT_EQ(fvValue(fv), value_2); + } + } + cout << endl; + } + + cout << "- Step 4. DEL" << endl; + cout << "Delete key [a]" << endl; + t.del(key_1); + + cout << "- Step 5. GET" << endl; + cout << "Get key [a] and key [b]" << endl; + EXPECT_EQ(t.get(key_1, values), false); + t.get(key_2, values); + + cout << "Get key [b]" << flush; + for (auto fv: values) + { + string value_1 = "1", value_2 = "2"; + cout << " " << fvField(fv) << ":" << fvValue(fv) << flush; + if (fvField(fv) == "field_1") + { + EXPECT_EQ(fvValue(fv), value_1); + } + if (fvField(fv) == "field_2") + { + EXPECT_EQ(fvValue(fv), value_2); + } + } + cout << endl; + + cout << "- Step 6. DEL and GET_TABLE_CONTENT" << endl; + cout << "Delete key [b]" << endl; + t.del(key_2); + t.getContent(tuples); + + EXPECT_EQ(tuples.size(), unsigned(0)); + + cout << "- Step 7. hset and hget" << endl; + string key = "k"; + string field_1 = "f1"; + string value_1_set = "v1"; + string field_2 = "f2"; + string value_2_set = "v2"; + string field_empty = ""; + string value_empty = ""; + t.hset(key, field_1, value_1_set); + t.hset(key, field_2, value_2_set); + t.hset(key, field_empty, value_empty); + + string value_got; + t.hget(key, field_1, value_got); + EXPECT_EQ(value_1_set, value_got); + + t.hget(key, field_2, value_got); + EXPECT_EQ(value_2_set, value_got); + + bool r = t.hget(key, field_empty, value_got); + ASSERT_TRUE(r); + EXPECT_EQ(value_empty, value_got); + + r = t.hget(key, "e", value_got); + ASSERT_FALSE(r); + + cout << "Done." << endl; +} + +TEST(DBConnector, multi_ns_table_test) +{ + TableNetnsTest("TABLE_NS_TEST"); +} diff --git a/tests/redis_ut.cpp b/tests/redis_ut.cpp index 02d133ed8..d7938bfda 100644 --- a/tests/redis_ut.cpp +++ b/tests/redis_ut.cpp @@ -142,17 +142,29 @@ void clearDB() r.checkStatusOK(); } -void TableBasicTest(string tableName) +// Add "useDbId" to test connector objects made with dbId/dbName +void TableBasicTest(string tableName, bool useDbId = false) { - DBConnector db("TEST_DB", 0, true); - int dbId = db.getDbId(); + DBConnector *db; + DBConnector db1("TEST_DB", 0, true); + + int dbId = db1.getDbId(); - // Test we can still use dbId to construct a DBConnector + // Use dbId to construct a DBConnector DBConnector db_dup(dbId, "localhost", 6379, 0); cout << "db_dup separator: " << SonicDBConfig::getSeparator(&db_dup) << endl; - Table t(&db, tableName); + if (useDbId) + { + db = &db_dup; + } + else + { + db = &db1; + } + + Table t(db, tableName); clearDB(); cout << "Starting table manipulations" << endl; @@ -656,19 +668,22 @@ TEST(DBConnector, selectabletimer) TEST(Table, basic) { - TableBasicTest("TABLE_UT_TEST"); + TableBasicTest("TABLE_UT_TEST", true); + TableBasicTest("TABLE_UT_TEST", false); } TEST(Table, separator_in_table_name) { std::string tableName = "TABLE_UT|TEST"; - TableBasicTest(tableName); + TableBasicTest(tableName, true); + TableBasicTest(tableName, false); } TEST(Table, table_separator_test) { - TableBasicTest("TABLE_UT_TEST"); + TableBasicTest("TABLE_UT_TEST", true); + TableBasicTest("TABLE_UT_TEST", false); } TEST(ProducerConsumer, Prefix)