diff --git a/tests/mock_tests/Makefile.am b/tests/mock_tests/Makefile.am index 54fb4003a2eb..553cd18bfed6 100644 --- a/tests/mock_tests/Makefile.am +++ b/tests/mock_tests/Makefile.am @@ -31,6 +31,7 @@ tests_SOURCES = aclorch_ut.cpp \ copporch_ut.cpp \ saispy_ut.cpp \ consumer_ut.cpp \ + sfloworh_ut.cpp \ ut_saihelper.cpp \ mock_orchagent_main.cpp \ mock_dbconnector.cpp \ diff --git a/tests/mock_tests/mock_orchagent_main.h b/tests/mock_tests/mock_orchagent_main.h index 57df931cb54b..f41c5b29a588 100644 --- a/tests/mock_tests/mock_orchagent_main.h +++ b/tests/mock_tests/mock_orchagent_main.h @@ -82,3 +82,4 @@ extern sai_queue_api_t *sai_queue_api; extern sai_udf_api_t* sai_udf_api; extern sai_mpls_api_t* sai_mpls_api; extern sai_counter_api_t* sai_counter_api; +extern sai_samplepacket_api_t *sai_samplepacket_api; diff --git a/tests/mock_tests/portal.h b/tests/mock_tests/portal.h index 94b20512110e..8f0c4ab2dbe6 100644 --- a/tests/mock_tests/portal.h +++ b/tests/mock_tests/portal.h @@ -6,6 +6,7 @@ #include "aclorch.h" #include "crmorch.h" #include "copporch.h" +#include "sfloworch.h" #include "directory.h" #undef protected @@ -82,6 +83,24 @@ struct Portal } }; + struct SflowOrchInternal + { + static bool getSflowStatusEnable(SflowOrch &obj) + { + return obj.m_sflowStatus; + } + + static SflowRateSampleMap getSflowSampleMap(SflowOrch &obj) + { + return obj.m_sflowRateSampleMap; + } + + static SflowPortInfoMap getSflowPortInfoMap(SflowOrch &obj) + { + return obj.m_sflowPortInfoMap; + } + }; + struct DirectoryInternal { template diff --git a/tests/mock_tests/sfloworh_ut.cpp b/tests/mock_tests/sfloworh_ut.cpp new file mode 100644 index 000000000000..d3d4d0defa9b --- /dev/null +++ b/tests/mock_tests/sfloworh_ut.cpp @@ -0,0 +1,372 @@ +#include +#include +#include +#include +#include + +#include "ut_helper.h" +#include "mock_orchagent_main.h" + +using namespace swss; + +namespace sflow_test +{ + class MockSflowOrch final + { + public: + MockSflowOrch() + { + this->appDb = std::make_shared("APPL_DB", 0); + std::vector sflow_tables = { + APP_SFLOW_TABLE_NAME, + APP_SFLOW_SESSION_TABLE_NAME, + APP_SFLOW_SAMPLE_RATE_TABLE_NAME + }; + sflowOrch = std::make_shared(this->appDb.get(), sflow_tables); + } + ~MockSflowOrch() = default; + + void doSflowTableTask(const std::deque &entries) + { + // ConsumerStateTable is used for APP DB + auto consumer = std::unique_ptr(new Consumer( + new ConsumerStateTable(this->appDb.get(), APP_SFLOW_TABLE_NAME, 1, 1), + this->sflowOrch.get(), APP_SFLOW_TABLE_NAME + )); + + consumer->addToSync(entries); + static_cast(this->sflowOrch.get())->doTask(*consumer); + } + + void doSflowSessionTableTask(const std::deque &entries) + { + // ConsumerStateTable is used for APP DB + auto consumer = std::unique_ptr(new Consumer( + new ConsumerStateTable(this->appDb.get(), APP_SFLOW_SESSION_TABLE_NAME, 1, 1), + this->sflowOrch.get(), APP_SFLOW_SESSION_TABLE_NAME + )); + + consumer->addToSync(entries); + static_cast(this->sflowOrch.get())->doTask(*consumer); + } + + void doSflowSampleTableTask(const std::deque &entries) + { + // ConsumerStateTable is used for APP DB + auto consumer = std::unique_ptr(new Consumer( + new ConsumerStateTable(this->appDb.get(), APP_SFLOW_SAMPLE_RATE_TABLE_NAME, 1, 1), + this->sflowOrch.get(), APP_SFLOW_SAMPLE_RATE_TABLE_NAME + )); + + consumer->addToSync(entries); + static_cast(this->sflowOrch.get())->doTask(*consumer); + } + + SflowOrch& get() + { + return *sflowOrch; + } + + private: + std::shared_ptr sflowOrch; + std::shared_ptr appDb; + }; + + class SflowOrchTest : public ::testing::Test + { + public: + SflowOrchTest() + { + this->initDb(); + } + virtual ~SflowOrchTest() = default; + + void SetUp() override + { + this->initSaiApi(); + this->initSwitch(); + this->initOrch(); + this->initPorts(); + } + + void TearDown() override + { + this->deinitOrch(); + this->deinitSwitch(); + this->deinitSaiApi(); + } + + private: + void initSaiApi() + { + std::map profileMap = { + { "SAI_VS_SWITCH_TYPE", "SAI_VS_SWITCH_TYPE_BCM56850" }, + { "KV_DEVICE_MAC_ADDRESS", "20:03:04:05:06:00" } + }; + auto status = ut_helper::initSaiApi(profileMap); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + } + + void deinitSaiApi() + { + auto status = ut_helper::uninitSaiApi(); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + } + + void initSwitch() + { + sai_status_t status; + sai_attribute_t attr; + + // Create switch + attr.id = SAI_SWITCH_ATTR_INIT_SWITCH; + attr.value.booldata = true; + + status = sai_switch_api->create_switch(&gSwitchId, 1, &attr); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + // Get switch source MAC address + attr.id = SAI_SWITCH_ATTR_SRC_MAC_ADDRESS; + + status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + gMacAddress = attr.value.mac; + + // Get switch default virtual router ID + attr.id = SAI_SWITCH_ATTR_DEFAULT_VIRTUAL_ROUTER_ID; + + status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + gVirtualRouterId = attr.value.oid; + } + + void deinitSwitch() + { + // Remove switch + auto status = sai_switch_api->remove_switch(gSwitchId); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + gSwitchId = SAI_NULL_OBJECT_ID; + gVirtualRouterId = SAI_NULL_OBJECT_ID; + } + + void initOrch() + { + // + // SwitchOrch + // + + TableConnector switchCapTableStateDb(this->stateDb.get(), "SWITCH_CAPABILITY"); + TableConnector asicSensorsTableCfgDb(this->configDb.get(), CFG_ASIC_SENSORS_TABLE_NAME); + TableConnector switchTableAppDb(this->appDb.get(), APP_SWITCH_TABLE_NAME); + + std::vector switchTableList = { + asicSensorsTableCfgDb, + switchTableAppDb + }; + + gSwitchOrch = new SwitchOrch(this->appDb.get(), switchTableList, switchCapTableStateDb); + gDirectory.set(gSwitchOrch); + resourcesList.push_back(gSwitchOrch); + + // + // PortsOrch + // + + const int portsorchBasePri = 40; + + std::vector portTableList = { + { APP_PORT_TABLE_NAME, portsorchBasePri + 5 }, + { APP_VLAN_TABLE_NAME, portsorchBasePri + 2 }, + { APP_VLAN_MEMBER_TABLE_NAME, portsorchBasePri }, + { APP_LAG_TABLE_NAME, portsorchBasePri + 4 }, + { APP_LAG_MEMBER_TABLE_NAME, portsorchBasePri } + }; + + gPortsOrch = new PortsOrch(this->appDb.get(), this->stateDb.get(), portTableList, this->chassisAppDb.get()); + gDirectory.set(gPortsOrch); + resourcesList.push_back(gPortsOrch); + + // + // QosOrch + // + + std::vector qosTableList = { + CFG_TC_TO_QUEUE_MAP_TABLE_NAME, + CFG_SCHEDULER_TABLE_NAME, + CFG_DSCP_TO_TC_MAP_TABLE_NAME, + CFG_MPLS_TC_TO_TC_MAP_TABLE_NAME, + CFG_DOT1P_TO_TC_MAP_TABLE_NAME, + CFG_QUEUE_TABLE_NAME, + CFG_PORT_QOS_MAP_TABLE_NAME, + CFG_WRED_PROFILE_TABLE_NAME, + CFG_TC_TO_PRIORITY_GROUP_MAP_TABLE_NAME, + CFG_PFC_PRIORITY_TO_PRIORITY_GROUP_MAP_TABLE_NAME, + CFG_PFC_PRIORITY_TO_QUEUE_MAP_TABLE_NAME, + CFG_DSCP_TO_FC_MAP_TABLE_NAME, + CFG_EXP_TO_FC_MAP_TABLE_NAME + }; + gQosOrch = new QosOrch(this->configDb.get(), qosTableList); + gDirectory.set(gQosOrch); + resourcesList.push_back(gQosOrch); + + // + // BufferOrch + // + + std::vector bufferTableList = { + APP_BUFFER_POOL_TABLE_NAME, + APP_BUFFER_PROFILE_TABLE_NAME, + APP_BUFFER_QUEUE_TABLE_NAME, + APP_BUFFER_PG_TABLE_NAME, + APP_BUFFER_PORT_INGRESS_PROFILE_LIST_NAME, + APP_BUFFER_PORT_EGRESS_PROFILE_LIST_NAME + }; + gBufferOrch = new BufferOrch(this->appDb.get(), this->configDb.get(), this->stateDb.get(), bufferTableList); + gDirectory.set(gBufferOrch); + resourcesList.push_back(gBufferOrch); + + // + // FlexCounterOrch + // + + std::vector flexCounterTableList = { + CFG_FLEX_COUNTER_TABLE_NAME + }; + + auto flexCounterOrch = new FlexCounterOrch(this->configDb.get(), flexCounterTableList); + gDirectory.set(flexCounterOrch); + resourcesList.push_back(flexCounterOrch); + } + + void deinitOrch() + { + std::reverse(this->resourcesList.begin(), this->resourcesList.end()); + for (auto &it : this->resourcesList) + { + delete it; + } + + gSwitchOrch = nullptr; + gPortsOrch = nullptr; + gQosOrch = nullptr; + gBufferOrch = nullptr; + + Portal::DirectoryInternal::clear(gDirectory); + EXPECT_TRUE(Portal::DirectoryInternal::empty(gDirectory)); + } + + void initPorts() + { + auto portTable = Table(this->appDb.get(), APP_PORT_TABLE_NAME); + + // Get SAI default ports to populate DB + auto ports = ut_helper::getInitialSaiPorts(); + + // Populate port table with SAI ports + for (const auto &cit : ports) + { + portTable.set(cit.first, cit.second); + } + + // Set PortConfigDone + portTable.set("PortConfigDone", { { "count", to_string(ports.size()) } }); + gPortsOrch->addExistingData(&portTable); + static_cast(gPortsOrch)->doTask(); + + // Set PortInitDone + portTable.set("PortInitDone", { { "lanes", "0" } }); + gPortsOrch->addExistingData(&portTable); + static_cast(gPortsOrch)->doTask(); + } + + void initDb() + { + this->appDb = std::make_shared("APPL_DB", 0); + this->configDb = std::make_shared("CONFIG_DB", 0); + this->stateDb = std::make_shared("STATE_DB", 0); + this->chassisAppDb = std::make_shared("CHASSIS_APP_DB", 0); + } + + std::shared_ptr appDb; + std::shared_ptr configDb; + std::shared_ptr stateDb; + std::shared_ptr chassisAppDb; + + std::vector resourcesList; + }; + + /* Test enabling/disabling SFLOW */ + TEST_F(SflowOrchTest, SflowEnableDisable) + { + MockSflowOrch mock_orch; + { + auto table1 = deque( + { + { + "global", + SET_COMMAND, + { + {"admin_state", "down"} + } + } + }); + mock_orch.doSflowTableTask(table1); + + ASSERT_FALSE(Portal::SflowOrchInternal::getSflowStatusEnable(mock_orch.get())); + } + { + auto table2 = deque( + { + { + "global", + SET_COMMAND, + { + {"admin_state", "up"} + } + } + }); + mock_orch.doSflowTableTask(table2); + + ASSERT_TRUE(Portal::SflowOrchInternal::getSflowStatusEnable(mock_orch.get())); + } + } + + /* Test create/delete SFLOW */ + TEST_F(SflowOrchTest, SflowCreateDelete) + { + MockSflowOrch mock_orch; + { + auto table3 = deque( + { + { + "global", + SET_COMMAND, + { + {"admin_state", "up"}, + } + } + }); + mock_orch.doSflowTableTask(table3); + ASSERT_TRUE(Portal::SflowOrchInternal::getSflowStatusEnable(mock_orch.get())); + } + { + auto table4 = deque( + { + { + "global", + DEL_COMMAND, + { + {"admin_state", "up"}, + } + } + }); + mock_orch.doSflowTableTask(table4); + ASSERT_FALSE(Portal::SflowOrchInternal::getSflowStatusEnable(mock_orch.get())); + } + } +} + + diff --git a/tests/mock_tests/ut_saihelper.cpp b/tests/mock_tests/ut_saihelper.cpp index 80a2d6ee38b5..40594cc32cdf 100644 --- a/tests/mock_tests/ut_saihelper.cpp +++ b/tests/mock_tests/ut_saihelper.cpp @@ -66,6 +66,7 @@ namespace ut_helper sai_api_query(SAI_API_SWITCH, (void **)&sai_switch_api); sai_api_query(SAI_API_BRIDGE, (void **)&sai_bridge_api); sai_api_query(SAI_API_VIRTUAL_ROUTER, (void **)&sai_virtual_router_api); + sai_api_query(SAI_API_SAMPLEPACKET, (void **)&sai_samplepacket_api); sai_api_query(SAI_API_PORT, (void **)&sai_port_api); sai_api_query(SAI_API_LAG, (void **)&sai_lag_api); sai_api_query(SAI_API_VLAN, (void **)&sai_vlan_api);