diff --git a/common/Makefile.am b/common/Makefile.am index a6231cb57..fec265852 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -33,7 +33,6 @@ libswsscommon_la_SOURCES = \ json.cpp \ producertable.cpp \ producerstatetable.cpp \ - redisclient.cpp \ rediscommand.cpp \ redistran.cpp \ redisselect.cpp \ diff --git a/common/dbconnector.cpp b/common/dbconnector.cpp index 2f66931af..a26f7331e 100644 --- a/common/dbconnector.cpp +++ b/common/dbconnector.cpp @@ -461,4 +461,165 @@ string DBConnector::getClientName() } } +int64_t DBConnector::del(const string &key) +{ + RedisCommand sdel; + sdel.format("DEL %s", key.c_str()); + RedisReply r(this, sdel, REDIS_REPLY_INTEGER); + return r.getContext()->integer; +} + +bool DBConnector::exists(const string &key) +{ + RedisCommand rexists; + if (key.find_first_of(" \t") != string::npos) + { + SWSS_LOG_ERROR("EXISTS failed, invalid space or tab in single key: %s", key.c_str()); + throw runtime_error("EXISTS failed, invalid space or tab in single key"); + } + rexists.format("EXISTS %s", key.c_str()); + RedisReply r(this, rexists, REDIS_REPLY_INTEGER); + return (r.getContext()->integer > 0); +} + +int64_t DBConnector::hdel(const string &key, const string &field) +{ + RedisCommand shdel; + shdel.format("HDEL %s %s", key.c_str(), field.c_str()); + RedisReply r(this, shdel, REDIS_REPLY_INTEGER); + return r.getContext()->integer; +} + +int64_t DBConnector::hdel(const std::string &key, const std::vector &fields) +{ + RedisCommand shdel; + shdel.formatHDEL(key, fields); + RedisReply r(this, shdel, REDIS_REPLY_INTEGER); + return r.getContext()->integer; +} + +void DBConnector::hset(const string &key, const string &field, const string &value) +{ + RedisCommand shset; + shset.format("HSET %s %s %s", key.c_str(), field.c_str(), value.c_str()); + RedisReply r(this, shset, REDIS_REPLY_INTEGER); +} + +void DBConnector::set(const string &key, const string &value) +{ + RedisCommand sset; + sset.format("SET %s %s", key.c_str(), value.c_str()); + RedisReply r(this, sset, REDIS_REPLY_STATUS); +} + +unordered_map DBConnector::hgetall(const string &key) +{ + unordered_map map; + hgetall(key, std::inserter(map, map.end())); + return map; +} + +vector DBConnector::keys(const string &key) +{ + RedisCommand skeys; + skeys.format("KEYS %s", key.c_str()); + RedisReply r(this, skeys, REDIS_REPLY_ARRAY); + + auto ctx = r.getContext(); + + vector list; + for (unsigned int i = 0; i < ctx->elements; i++) + list.emplace_back(ctx->element[i]->str); + + return list; +} + +int64_t DBConnector::incr(const string &key) +{ + RedisCommand sincr; + sincr.format("INCR %s", key.c_str()); + RedisReply r(this, sincr, REDIS_REPLY_INTEGER); + return r.getContext()->integer; +} + +int64_t DBConnector::decr(const string &key) +{ + RedisCommand sdecr; + sdecr.format("DECR %s", key.c_str()); + RedisReply r(this, sdecr, REDIS_REPLY_INTEGER); + return r.getContext()->integer; +} + +shared_ptr DBConnector::get(const string &key) +{ + RedisCommand sget; + sget.format("GET %s", key.c_str()); + RedisReply r(this, sget); + auto reply = r.getContext(); + + if (reply->type == REDIS_REPLY_NIL) + { + return shared_ptr(NULL); + } + + if (reply->type == REDIS_REPLY_STRING) + { + shared_ptr ptr(new string(reply->str)); + return ptr; + } + + throw runtime_error("GET failed, memory exception"); +} + +shared_ptr DBConnector::hget(const string &key, const string &field) +{ + RedisCommand shget; + shget.format("HGET %s %s", key.c_str(), field.c_str()); + RedisReply r(this, shget); + auto reply = r.getContext(); + + if (reply->type == REDIS_REPLY_NIL) + { + return shared_ptr(NULL); + } + + if (reply->type == REDIS_REPLY_STRING) + { + shared_ptr ptr(new string(reply->str)); + return ptr; + } + + SWSS_LOG_ERROR("HGET failed, reply-type: %d, %s: %s", reply->type, key.c_str(), field.c_str()); + throw runtime_error("HGET failed, unexpected reply type, memory exception"); +} + +int64_t DBConnector::rpush(const string &list, const string &item) +{ + RedisCommand srpush; + srpush.format("RPUSH %s %s", list.c_str(), item.c_str()); + RedisReply r(this, srpush, REDIS_REPLY_INTEGER); + return r.getContext()->integer; +} + +shared_ptr DBConnector::blpop(const string &list, int timeout) +{ + RedisCommand sblpop; + sblpop.format("BLPOP %s %d", list.c_str(), timeout); + RedisReply r(this, sblpop); + auto reply = r.getContext(); + + if (reply->type == REDIS_REPLY_NIL) + { + return shared_ptr(NULL); + } + + if (reply->type == REDIS_REPLY_STRING) + { + shared_ptr ptr(new string(reply->str)); + return ptr; + } + + throw runtime_error("GET failed, memory exception"); +} + } diff --git a/common/dbconnector.h b/common/dbconnector.h index ef397dc79..6ea56e144 100644 --- a/common/dbconnector.h +++ b/common/dbconnector.h @@ -5,8 +5,11 @@ #include #include #include +#include #include +#include "rediscommand.h" +#include "redisreply.h" #define EMPTY_NAMESPACE std::string() namespace swss { @@ -101,6 +104,40 @@ class DBConnector std::string getClientName(); + int64_t del(const std::string &key); + + bool exists(const std::string &key); + + int64_t hdel(const std::string &key, const std::string &field); + + int64_t hdel(const std::string &key, const std::vector &fields); + + std::unordered_map hgetall(const std::string &key); + + template + void hgetall(const std::string &key, OutputIterator result); + + std::vector keys(const std::string &key); + + void set(const std::string &key, const std::string &value); + + void hset(const std::string &key, const std::string &field, const std::string &value); + + template + void hmset(const std::string &key, InputIterator start, InputIterator stop); + + std::shared_ptr get(const std::string &key); + + std::shared_ptr hget(const std::string &key, const std::string &field); + + int64_t incr(const std::string &key); + + int64_t decr(const std::string &key); + + int64_t rpush(const std::string &list, const std::string &item); + + std::shared_ptr blpop(const std::string &list, int timeout); + private: redisContext *m_conn; int m_dbId; @@ -108,5 +145,29 @@ class DBConnector std::string m_namespace; }; +template +void DBConnector::hgetall(const std::string &key, OutputIterator result) +{ + RedisCommand sincr; + sincr.format("HGETALL %s", key.c_str()); + RedisReply r(this, sincr, REDIS_REPLY_ARRAY); + + auto ctx = r.getContext(); + + for (unsigned int i = 0; i < ctx->elements; i += 2) + { + *result = std::make_pair(ctx->element[i]->str, ctx->element[i+1]->str); + ++result; + } +} + +template +void DBConnector::hmset(const std::string &key, InputIterator start, InputIterator stop) +{ + RedisCommand shmset; + shmset.formatHMSET(key, start, stop); + RedisReply r(this, shmset, REDIS_REPLY_STATUS); +} + } #endif diff --git a/common/logger.cpp b/common/logger.cpp index c7e412532..f25d434cb 100644 --- a/common/logger.cpp +++ b/common/logger.cpp @@ -92,14 +92,13 @@ void Logger::linkToDbWithOutput(const std::string &dbName, const PriorityChangeN // Initialize internal DB with observer logger.m_settingChangeObservers.insert(std::make_pair(dbName, std::make_pair(prioNotify, outputNotify))); DBConnector db("LOGLEVEL_DB", 0); - RedisClient redisClient(&db); - auto keys = redisClient.keys("*"); + auto keys = db.keys("*"); std::string key = dbName + ":" + dbName; std::string prio, output; bool doUpdate = false; - auto prioPtr = redisClient.hget(key, DAEMON_LOGLEVEL); - auto outputPtr = redisClient.hget(key, DAEMON_LOGOUTPUT); + auto prioPtr = db.hget(key, DAEMON_LOGLEVEL); + auto outputPtr = db.hget(key, DAEMON_LOGOUTPUT); if ( prioPtr == nullptr ) { diff --git a/common/loglevel.cpp b/common/loglevel.cpp index 603b41d7c..6ae85af63 100644 --- a/common/loglevel.cpp +++ b/common/loglevel.cpp @@ -108,8 +108,7 @@ int main(int argc, char **argv) } DBConnector db("LOGLEVEL_DB", 0); - RedisClient redisClient(&db); - auto keys = redisClient.keys("*"); + auto keys = db.keys("*"); for (auto& key : keys) { size_t colonPos = key.find(':'); @@ -136,7 +135,7 @@ int main(int argc, char **argv) for (const auto& key : keys) { const auto redis_key = std::string(key).append(":").append(key); - auto level = redisClient.hget(redis_key, DAEMON_LOGLEVEL); + auto level = db.hget(redis_key, DAEMON_LOGLEVEL); if (nullptr == level) { std::cerr << std::left << std::setw(30) << key << "Unknown log level" << std::endl; diff --git a/common/redisclient.cpp b/common/redisclient.cpp deleted file mode 100644 index 13f9cf13a..000000000 --- a/common/redisclient.cpp +++ /dev/null @@ -1,176 +0,0 @@ -#include "redisclient.h" -#include "logger.h" -#include "rediscommand.h" - -using namespace std; - -namespace swss -{ - -RedisClient::RedisClient(swss::DBConnector *db): - m_db(db) -{ -} - -int64_t RedisClient::del(const string &key) -{ - RedisCommand sdel; - sdel.format("DEL %s", key.c_str()); - RedisReply r(m_db, sdel, REDIS_REPLY_INTEGER); - return r.getContext()->integer; -} - -bool RedisClient::exists(const string &key) -{ - RedisCommand rexists; - if (key.find_first_of(" \t") != string::npos) - { - SWSS_LOG_ERROR("EXISTS failed, invalid space or tab in single key: %s", key.c_str()); - throw runtime_error("EXISTS failed, invalid space or tab in single key"); - } - rexists.format("EXISTS %s", key.c_str()); - RedisReply r(m_db, rexists, REDIS_REPLY_INTEGER); - return (r.getContext()->integer > 0); -} - -int64_t RedisClient::hdel(const string &key, const string &field) -{ - RedisCommand shdel; - shdel.format("HDEL %s %s", key.c_str(), field.c_str()); - RedisReply r(m_db, shdel, REDIS_REPLY_INTEGER); - return r.getContext()->integer; -} - -int64_t RedisClient::hdel(const std::string &key, const std::vector &fields) -{ - RedisCommand shdel; - shdel.formatHDEL(key, fields); - RedisReply r(m_db, shdel, REDIS_REPLY_INTEGER); - return r.getContext()->integer; -} - -void RedisClient::hset(const string &key, const string &field, const string &value) -{ - RedisCommand shset; - shset.format("HSET %s %s %s", key.c_str(), field.c_str(), value.c_str()); - RedisReply r(m_db, shset, REDIS_REPLY_INTEGER); -} - -void RedisClient::set(const string &key, const string &value) -{ - RedisCommand sset; - sset.format("SET %s %s", key.c_str(), value.c_str()); - RedisReply r(m_db, sset, REDIS_REPLY_STATUS); -} - -unordered_map RedisClient::hgetall(const string &key) -{ - unordered_map map; - hgetall(key, std::inserter(map, map.end())); - return map; -} - -vector RedisClient::keys(const string &key) -{ - RedisCommand skeys; - skeys.format("KEYS %s", key.c_str()); - RedisReply r(m_db, skeys, REDIS_REPLY_ARRAY); - - auto ctx = r.getContext(); - - vector list; - for (unsigned int i = 0; i < ctx->elements; i++) - list.emplace_back(ctx->element[i]->str); - - return list; -} - -int64_t RedisClient::incr(const string &key) -{ - RedisCommand sincr; - sincr.format("INCR %s", key.c_str()); - RedisReply r(m_db, sincr, REDIS_REPLY_INTEGER); - return r.getContext()->integer; -} - -int64_t RedisClient::decr(const string &key) -{ - RedisCommand sdecr; - sdecr.format("DECR %s", key.c_str()); - RedisReply r(m_db, sdecr, REDIS_REPLY_INTEGER); - return r.getContext()->integer; -} - -shared_ptr RedisClient::get(const string &key) -{ - RedisCommand sget; - sget.format("GET %s", key.c_str()); - RedisReply r(m_db, sget); - auto reply = r.getContext(); - - if (reply->type == REDIS_REPLY_NIL) - { - return shared_ptr(NULL); - } - - if (reply->type == REDIS_REPLY_STRING) - { - shared_ptr ptr(new string(reply->str)); - return ptr; - } - - throw runtime_error("GET failed, memory exception"); -} - -shared_ptr RedisClient::hget(const string &key, const string &field) -{ - RedisCommand shget; - shget.format("HGET %s %s", key.c_str(), field.c_str()); - RedisReply r(m_db, shget); - auto reply = r.getContext(); - - if (reply->type == REDIS_REPLY_NIL) - { - return shared_ptr(NULL); - } - - if (reply->type == REDIS_REPLY_STRING) - { - shared_ptr ptr(new string(reply->str)); - return ptr; - } - - SWSS_LOG_ERROR("HGET failed, reply-type: %d, %s: %s", reply->type, key.c_str(), field.c_str()); - throw runtime_error("HGET failed, unexpected reply type, memory exception"); -} - -int64_t RedisClient::rpush(const string &list, const string &item) -{ - RedisCommand srpush; - srpush.format("RPUSH %s %s", list.c_str(), item.c_str()); - RedisReply r(m_db, srpush, REDIS_REPLY_INTEGER); - return r.getContext()->integer; -} - -shared_ptr RedisClient::blpop(const string &list, int timeout) -{ - RedisCommand sblpop; - sblpop.format("BLPOP %s %d", list.c_str(), timeout); - RedisReply r(m_db, sblpop); - auto reply = r.getContext(); - - if (reply->type == REDIS_REPLY_NIL) - { - return shared_ptr(NULL); - } - - if (reply->type == REDIS_REPLY_STRING) - { - shared_ptr ptr(new string(reply->str)); - return ptr; - } - - throw runtime_error("GET failed, memory exception"); -} - -} diff --git a/common/redisclient.h b/common/redisclient.h index 593884e90..5494f24cc 100644 --- a/common/redisclient.h +++ b/common/redisclient.h @@ -22,77 +22,48 @@ class RedisClient { public: - RedisClient(swss::DBConnector *db); + RedisClient(swss::DBConnector *db) : m_db(db) { } - int64_t del(const std::string &key); + int64_t del(const std::string &key) { return m_db->del(key); } - bool exists(const std::string &key); + bool exists(const std::string &key) { return m_db->exists(key); } - int64_t hdel(const std::string &key, const std::string &field); + int64_t hdel(const std::string &key, const std::string &field) { return m_db->hdel(key, field); } - int64_t hdel(const std::string &key, const std::vector &fields); + int64_t hdel(const std::string &key, const std::vector &fields) { return m_db->hdel(key, fields); } - std::unordered_map hgetall(const std::string &key); + std::unordered_map hgetall(const std::string &key) { return m_db->hgetall(key); } template - void hgetall(const std::string &key, OutputIterator result); + void hgetall(const std::string &key, OutputIterator result) { return m_db->hgetall(key, result); } - std::vector keys(const std::string &key); + std::vector keys(const std::string &key) { return m_db->keys(key); } - std::vector hkeys(const std::string &key); + void set(const std::string &key, const std::string &value) { return m_db->set(key, value); } - void set(const std::string &key, const std::string &value); - - void hset(const std::string &key, const std::string &field, const std::string &value); - - void mset(const std::unordered_map &map); + void hset(const std::string &key, const std::string &field, const std::string &value) { return m_db->hset(key, field, value); } template - void hmset(const std::string &key, InputIterator start, InputIterator stop); - - std::shared_ptr get(const std::string &key); + void hmset(const std::string &key, InputIterator start, InputIterator stop) { return m_db->hmset(key, start, stop); } - std::shared_ptr hget(const std::string &key, const std::string &field); + std::shared_ptr get(const std::string &key) { return m_db->get(key); } - std::vector> mget(const std::vector &keys); + std::shared_ptr hget(const std::string &key, const std::string &field) { return m_db->hget(key, field); } - std::vector> hmget(const std::string &key, const std::vector &fields); + int64_t incr(const std::string &key) { return m_db->incr(key); } - int64_t incr(const std::string &key); + int64_t decr(const std::string &key) { return m_db->decr(key); } - int64_t decr(const std::string &key); + int64_t rpush(const std::string &list, const std::string &item) { return m_db->rpush(list, item); } - int64_t rpush(const std::string &list, const std::string &item); - - std::shared_ptr blpop(const std::string &list, int timeout); + std::shared_ptr blpop(const std::string &list, int timeout) { return m_db->blpop(list, timeout); } private: swss::DBConnector *m_db; }; -template -void RedisClient::hgetall(const std::string &key, OutputIterator result) -{ - RedisCommand sincr; - sincr.format("HGETALL %s", key.c_str()); - RedisReply r(m_db, sincr, REDIS_REPLY_ARRAY); - - auto ctx = r.getContext(); - - for (unsigned int i = 0; i < ctx->elements; i += 2) - { - *result = std::make_pair(ctx->element[i]->str, ctx->element[i+1]->str); - ++result; - } -} - -template -void RedisClient::hmset(const std::string &key, InputIterator start, InputIterator stop) -{ - RedisCommand shmset; - shmset.formatHMSET(key, start, stop); - RedisReply r(m_db, shmset, REDIS_REPLY_STATUS); -} +// TODO: mark above class: __attribute__ ((__deprecated__)); +// After remove all the caller code } diff --git a/common/rediscommand.h b/common/rediscommand.h index 568217323..e5f2840ed 100644 --- a/common/rediscommand.h +++ b/common/rediscommand.h @@ -2,6 +2,7 @@ #include #include #include +#include namespace swss { diff --git a/common/redisreply.cpp b/common/redisreply.cpp index 59f9ad3c9..422a550d9 100644 --- a/common/redisreply.cpp +++ b/common/redisreply.cpp @@ -7,6 +7,7 @@ #include "common/logger.h" #include "common/redisreply.h" +#include "common/dbconnector.h" #include "common/rediscommand.h" using namespace std; diff --git a/common/redisreply.h b/common/redisreply.h index 30cec1f78..71cb06728 100644 --- a/common/redisreply.h +++ b/common/redisreply.h @@ -3,11 +3,12 @@ #include #include -#include "dbconnector.h" #include "rediscommand.h" namespace swss { +class DBConnector; + class RedisReply { public: diff --git a/tests/fdb_flush.cpp b/tests/fdb_flush.cpp new file mode 100644 index 000000000..cab2225ab --- /dev/null +++ b/tests/fdb_flush.cpp @@ -0,0 +1,223 @@ +#include "gtest/gtest.h" + +#include "common/dbconnector.h" +#include "common/producertable.h" +#include "common/consumertable.h" +#include "common/redisapi.h" +#include "common/redisclient.h" + +#include +#include +#include +#include +#include + +using namespace std; +using namespace swss; + +static std::string tableName = "ASIC_STATE"; + +static void clear() +{ + DBConnector db("TEST_DB", 0, true); + + RedisReply r(&db, "FLUSHALL", REDIS_REPLY_STATUS); + + r.checkStatusOK(); +} + +static void insert( + uint64_t switchId, + uint64_t bvId, + uint64_t portId, + unsigned char mac, + bool isStatic) +{ + DBConnector db("TEST_DB", 0, true); + + ProducerTable producer(&db, tableName); + ConsumerTable consumer(&db, tableName); + + std::vector values; + + char buffer[4000]; + + sprintf(buffer, "SAI_OBJECT_TYPE_FDB_ENTRY:{\"bvid\":\"oid:0x%" PRIx64 "\",\"mac\":\"00:00:00:00:00:%02X\",\"switch_id\":\"oid:0x%" PRIx64 "\"}", bvId, mac, switchId); + + std::string key = buffer; + + char port[1000]; + + sprintf(port, "oid:0x%" PRIx64, portId); + + values.emplace_back("SAI_FDB_ENTRY_ATTR_PACKET_ACTION", "SAI_PACKET_ACTION_FORWARD"); + values.emplace_back("SAI_FDB_ENTRY_ATTR_TYPE", (isStatic ? "SAI_FDB_ENTRY_TYPE_STATIC" : "SAI_FDB_ENTRY_TYPE_DYNAMIC")); + values.emplace_back("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", port); + + producer.set(key, values, "set"); + + std::string op; + std::vector fvs; + + consumer.pop(key, op, fvs); +} + +static size_t count() +{ + DBConnector db("TEST_DB", 0, true); + + auto keys = db.keys("ASIC_STATE:*"); + + return keys.size(); +} + +void print() +{ + DBConnector db("TEST_DB", 0, true); + + auto keys = db.keys("ASIC_STATE:*"); + + for (auto&k : keys) + { + printf("K %s\n", k.c_str()); + + auto hash = db.hgetall(k); + + for (auto&h: hash) + { + printf(" * %s = %s\n", h.first.c_str(), h.second.c_str()); + } + } +} + +static std::string sOid( + uint64_t oid) +{ + char buffer[100]; + + sprintf(buffer, "oid:0x%" PRIx64, oid); + + return buffer; +} + +static void populate() +{ + clear(); + + insert(0x21000000000000, 0x26000000000001, 0x3a000000000001, 1, true); + insert(0x21000000000000, 0x26000000000002, 0x3a000000000002, 2, false); + + insert(0x121000000000001, 0x126000000000003, 0x13a000000000003, 3, true); + insert(0x121000000000001, 0x126000000000004, 0x13a000000000004, 4, false); +} + +static void exec( + uint64_t switchId, + uint64_t bvId, + uint64_t portId, + std::string type) +{ + DBConnector db("TEST_DB", 0, true); + + populate(); + + auto fdbFlushLuaScript = swss::readTextFile("./common/fdb_flush.v2.lua"); + + auto sha = swss::loadRedisScript(&db, fdbFlushLuaScript); + + swss::RedisCommand command; + + command.format( + "EVALSHA %s 4 %s %s %s %s", + sha.c_str(), + sOid(switchId).c_str(), // 0x0 == any + sOid(bvId).c_str(), // 0x0 == any + sOid(portId).c_str(), // 0x0 == any + type.c_str()); //(0 ? "SAI_FDB_ENTRY_TYPE_STATIC" : "SAI_FDB_ENTRY_TYPE_DYNAMIC")); // empty == any + + swss::RedisReply r(&db, command); +} + +static void mac(unsigned char m, bool is) +{ + DBConnector db("TEST_DB", 0, true); + + char buffer[100]; + + sprintf(buffer, "*SAI_OBJECT_TYPE_FDB_ENTRY:*\"mac\":\"00:00:00:00:00:%02X\"*", m); + + auto keys = db.keys(buffer); + + if (is) + { + EXPECT_EQ(keys.size(), 1); + return; + } + + EXPECT_EQ(keys.size(), 0); +} + +TEST(Fdb, flush) +{ + DBConnector db("TEST_DB", 0, true); + + exec(0,0,0, ""); + + EXPECT_EQ(count(), 0); + + exec(0x21000000000000,0,0, ""); + + mac(1,0); + mac(2,0); + mac(3,1); + mac(4,1); + + exec(0x21000000000000,0x26000000000001,0, ""); + + mac(1,0); + mac(2,1); + mac(3,1); + mac(4,1); + + exec(0x21000000000000,0,0x3a000000000001, ""); + + mac(1,0); + mac(2,1); + mac(3,1); + mac(4,1); + + exec(0x21000000000000,0,0, "SAI_FDB_ENTRY_TYPE_STATIC"); + + mac(1,0); + mac(2,1); + mac(3,1); + mac(4,1); + + exec(0x21000000000000,0x26000000000001,0x3a000000000001, "SAI_FDB_ENTRY_TYPE_STATIC"); + + mac(1,0); + mac(2,1); + mac(3,1); + mac(4,1); + + exec(0x121000000000001,0,0, ""); + + mac(1,1); + mac(2,1); + mac(3,0); + mac(4,0); + + exec(0,0,0, "SAI_FDB_ENTRY_TYPE_STATIC"); + + mac(1,0); + mac(2,1); + mac(3,0); + mac(4,1); + + exec(0,0,0, "SAI_FDB_ENTRY_TYPE_DYNAMIC"); + + mac(1,1); + mac(2,0); + mac(3,1); + mac(4,0); +} diff --git a/tests/logger_ut.cpp b/tests/logger_ut.cpp new file mode 100644 index 000000000..65203e4e1 --- /dev/null +++ b/tests/logger_ut.cpp @@ -0,0 +1,72 @@ +#include "common/dbconnector.h" +#include "common/redisclient.h" +#include "common/producerstatetable.h" +#include "common/consumerstatetable.h" +#include "common/select.h" +#include "common/schema.h" +#include "gtest/gtest.h" +#include + +using namespace std; +using namespace swss; + +void setLoglevel(DBConnector& db, const string& key, const string& loglevel) +{ + ProducerStateTable table(&db, key); + FieldValueTuple fv(DAEMON_LOGLEVEL, loglevel); + std::vectorfieldValues = { fv }; + table.set(key, fieldValues); +} + +void clearLoglevelDB() +{ + DBConnector db("LOGLEVEL_DB", 0); + RedisReply r(&db, "FLUSHALL", REDIS_REPLY_STATUS); + r.checkStatusOK(); +} + +void prioNotify(const string &component, const string &prioStr) +{ + Logger::priorityStringMap.at(prioStr); +} + +void checkLoglevel(DBConnector& db, const string& key, const string& loglevel) +{ + string redis_key = key + ":" + key; + auto level = db.hget(redis_key, DAEMON_LOGLEVEL); + EXPECT_FALSE(level == nullptr); + if (level != nullptr) + { + EXPECT_EQ(*level, loglevel); + } +} + +TEST(LOGGER, loglevel) +{ + DBConnector db("LOGLEVEL_DB", 0); + clearLoglevelDB(); + + string key1 = "table1", key2 = "table2", key3 = "table3"; + + cout << "Setting log level for table1." << endl; + Logger::linkToDbNative(key1); + + sleep(1); + + cout << "Checking log level for table1." << endl; + checkLoglevel(db, key1, "NOTICE"); + + cout << "Setting log level for tables." << endl; + Logger::linkToDb(key2, prioNotify, "NOTICE"); + Logger::linkToDb(key3, prioNotify, "INFO"); + setLoglevel(db, key1, "DEBUG"); + + sleep(1); + + cout << "Checking log levels." << endl; + checkLoglevel(db, key1, "DEBUG"); + checkLoglevel(db, key2, "NOTICE"); + checkLoglevel(db, key3, "INFO"); + + cout << "Done." << endl; +} diff --git a/tests/redis_state_ut.cpp b/tests/redis_state_ut.cpp index 4cc86b1e6..5ec353870 100644 --- a/tests/redis_state_ut.cpp +++ b/tests/redis_state_ut.cpp @@ -104,7 +104,6 @@ static void consumerWorker(int index) { string tableName = "UT_REDIS_THREAD_" + to_string(index); DBConnector db(TEST_DB, 0, true); - RedisClient redisClient(&db); ConsumerStateTable c(&db, tableName); Select cs; Selectable *selectcs; @@ -124,13 +123,13 @@ static void consumerWorker(int index) for (auto fv : kfvFieldsValues(kco)) { - string val = *redisClient.hget(tableName + ":" + kfvKey(kco), fvField(fv)); + string val = *db.hget(tableName + ":" + kfvKey(kco), fvField(fv)); EXPECT_EQ(val, fvValue(fv)); } } else if (kfvOp(kco) == "DEL") { numberOfKeyDeleted++; - auto keys = redisClient.keys(tableName + ":" + kfvKey(kco)); + auto keys = db.keys(tableName + ":" + kfvKey(kco)); EXPECT_EQ(0UL, keys.size()); } diff --git a/tests/redis_ut.cpp b/tests/redis_ut.cpp index 0b727f8d8..cdc444732 100644 --- a/tests/redis_ut.cpp +++ b/tests/redis_ut.cpp @@ -315,8 +315,6 @@ TEST(DBConnector, RedisClient) { DBConnector db("TEST_DB", 0, true); - RedisClient redic(&db); - clearDB(); cout << "Starting table manipulations" << endl; @@ -335,11 +333,11 @@ TEST(DBConnector, RedisClient) 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; - redic.hmset(key_1, values.begin(), values.end()); - redic.hmset(key_2, values.begin(), values.end()); + db.hmset(key_1, values.begin(), values.end()); + db.hmset(key_2, values.begin(), values.end()); cout << "- Step 2. GET_TABLE_KEYS" << endl; - auto keys = redic.keys("*"); + auto keys = db.keys("*"); EXPECT_EQ(keys.size(), (size_t)2); for (auto k : keys) @@ -353,7 +351,7 @@ TEST(DBConnector, RedisClient) for (auto k : keys) { cout << "Get key [" << k << "]" << flush; - auto fvs = redic.hgetall(k); + auto fvs = db.hgetall(k); unsigned int size_v = 3; EXPECT_EQ(fvs.size(), size_v); for (auto fv: fvs) @@ -374,10 +372,10 @@ TEST(DBConnector, RedisClient) cout << "- Step 4. HDEL single field" << endl; cout << "Delete field_2 under key [a]" << endl; - int64_t rval = redic.hdel(key_1, "field_2"); + int64_t rval = db.hdel(key_1, "field_2"); EXPECT_EQ(rval, 1); - auto fvs = redic.hgetall(key_1); + auto fvs = db.hgetall(key_1); EXPECT_EQ(fvs.size(), 2); for (auto fv: fvs) { @@ -398,13 +396,13 @@ TEST(DBConnector, RedisClient) cout << "- Step 5. DEL" << endl; cout << "Delete key [a]" << endl; - redic.del(key_1); + db.del(key_1); cout << "- Step 6. GET" << endl; cout << "Get key [a] and key [b]" << endl; - fvs = redic.hgetall(key_1); + fvs = db.hgetall(key_1); EXPECT_TRUE(fvs.empty()); - fvs = redic.hgetall(key_2); + fvs = db.hgetall(key_2); cout << "Get key [b]" << flush; for (auto fv: fvs) @@ -424,10 +422,10 @@ TEST(DBConnector, RedisClient) cout << "- Step 7. HDEL multiple fields" << endl; cout << "Delete field_2, field_3 under key [b]" << endl; - rval = redic.hdel(key_2, vector({"field_2", "field_3"})); + rval = db.hdel(key_2, vector({"field_2", "field_3"})); EXPECT_EQ(rval, 2); - fvs = redic.hgetall(key_2); + fvs = db.hgetall(key_2); EXPECT_EQ(fvs.size(), 1); for (auto fv: fvs) { @@ -445,8 +443,8 @@ TEST(DBConnector, RedisClient) cout << "- Step 8. DEL and GET_TABLE_CONTENT" << endl; cout << "Delete key [b]" << endl; - redic.del(key_2); - fvs = redic.hgetall(key_2); + db.del(key_2); + fvs = db.hgetall(key_2); EXPECT_TRUE(fvs.empty());