diff options
author | manojkiraneda <manojkiran.eda@gmail.com> | 2019-12-13 14:40:41 +0300 |
---|---|---|
committer | ManojKiran Eda <manojkiran.eda@gmail.com> | 2020-06-09 06:34:14 +0300 |
commit | 4eaf2ee36116b4d2be4269df106d37d7d437a711 (patch) | |
tree | ae35ad99e1826a439c20e090e956ca7da5309ca1 | |
parent | d6d59a65c334f0040177ffb3ab87f9b512a72cad (diff) | |
download | bmcweb-4eaf2ee36116b4d2be4269df106d37d7d437a711.tar.xz |
Add unit test for the lock management
- The idea behind this commit is to enable the unit test
for the lock management algorithm, and below are the unit
test cases that are written:
Testedby:
[----------] 20 tests from locktest
[ RUN ] locktest.ValidationGoodTestCase
[ OK ] locktest.ValidationGoodTestCase (3 ms)
[ RUN ] locktest.ValidationBadTestWithLocktype
[ OK ] locktest.ValidationBadTestWithLocktype (1 ms)
[ RUN ] locktest.ValidationBadTestWithlockFlags
[ OK ] locktest.ValidationBadTestWithlockFlags (0 ms)
[ RUN ] locktest.ValidationBadTestWithSegmentlength
[ OK ] locktest.ValidationBadTestWithSegmentlength (1 ms)
[ RUN ] locktest.MultiRequestWithoutConflict
[ OK ] locktest.MultiRequestWithoutConflict (3 ms)
[ RUN ] locktest.MultiRequestWithConflictduetoSameSegmentLength
[ OK ] locktest.MultiRequestWithConflictduetoSameSegmentLength (2 ms)
[ RUN ] locktest.MultiRequestWithoutConflictduetoDifferentSegmentData
[ OK ] locktest.MultiRequestWithoutConflictduetoDifferentSegmentData (1 ms)
[ RUN ] locktest.MultiRequestWithConflictduetoSameSegmentData
[ OK ] locktest.MultiRequestWithConflictduetoSameSegmentData (2 ms)
[ RUN ] locktest.MultiRequestWithoutConflictduetoDifferentSegmentLength
[ OK ] locktest.MultiRequestWithoutConflictduetoDifferentSegmentLength (1 ms)
[ RUN ] locktest.MultiRequestWithoutConflictduetoReadLocktype
[ OK ] locktest.MultiRequestWithoutConflictduetoReadLocktype (1 ms)
[ RUN ] locktest.MultiRequestWithoutConflictduetoReadLocktypeAndLockall
[ OK ] locktest.MultiRequestWithoutConflictduetoReadLocktypeAndLockall (2 ms)
[ RUN ] locktest.RequestConflictedWithLockTableEntries
[ OK ] locktest.RequestConflictedWithLockTableEntries (6 ms)
[ RUN ] locktest.RequestNotConflictedWithLockTableEntries
[ OK ] locktest.RequestNotConflictedWithLockTableEntries (3 ms)
[ RUN ] locktest.TestGenerateTransactionIDFunction
[ OK ] locktest.TestGenerateTransactionIDFunction (1 ms)
[ RUN ] locktest.ValidateTransactionIDsGoodTestCase
[ OK ] locktest.ValidateTransactionIDsGoodTestCase (3 ms)
[ RUN ] locktest.ValidateTransactionIDsBadTestCase
[ OK ] locktest.ValidateTransactionIDsBadTestCase (2 ms)
[ RUN ] locktest.ValidateisItMyLockGoodTestCase
[ OK ] locktest.ValidateisItMyLockGoodTestCase (2 ms)
[ RUN ] locktest.ValidateisItMyLockBadTestCase
[ OK ] locktest.ValidateisItMyLockBadTestCase (2 ms)
[ RUN ] locktest.ValidateSessionIDForGetlocklistBadTestCase
[ OK ] locktest.ValidateSessionIDForGetlocklistBadTestCase (3 ms)
[ RUN ] locktest.ValidateSessionIDForGetlocklistGoodTestCase
[ OK ] locktest.ValidateSessionIDForGetlocklistGoodTestCase (3 ms)
[----------] 20 tests from locktest (82 ms total)
Signed-off-by: manojkiraneda <manojkiran.eda@gmail.com>
Change-Id: Id274ee356adfa7ba03da02d83b609d37c8c99f8d
-rw-r--r-- | CMakeLists.txt | 18 | ||||
-rw-r--r-- | include/ibm/locks.hpp | 60 | ||||
-rw-r--r-- | redfish-core/ut/lock_test.cpp | 356 |
3 files changed, 400 insertions, 34 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 9511cfdb5c..ba52fad51b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -288,6 +288,12 @@ if (NOT ${YOCTO_DEPENDENCIES}) link_directories (${CMAKE_BINARY_DIR}/sdbusplus-src/build) endif () +# Its an Out of tree build,enabling ibm management console for +# unit-test purpose. +if (NOT ${YOCTO_DEPENDENCIES}) + add_definitions(-DBMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE) +endif(NOT ${YOCTO_DEPENDENCIES}) + # Openssl find_package (OpenSSL REQUIRED) include_directories (SYSTEM ${OPENSSL_INCLUDE_DIR}) @@ -341,14 +347,10 @@ set (SRC_FILES redfish-core/src/error_messages.cpp file (COPY src/test_resources DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) # Unit Tests -if (${BMCWEB_BUILD_UT}) - set (UT_FILES src/crow_test.cpp src/gtest_main.cpp - src/token_authorization_middleware_test.cpp - src/security_headers_middleware_test.cpp src/webassets_test.cpp - src/crow_getroutes_test.cpp src/ast_jpeg_decoder_test.cpp - src/kvm_websocket_test.cpp src/msan_test.cpp - src/ast_video_puller_test.cpp src/openbmc_jtag_rest_test.cpp +if (NOT ${YOCTO_DEPENDENCIES}) + set (UT_FILES src/gtest_main.cpp src/msan_test.cpp redfish-core/ut/privileges_test.cpp + redfish-core/ut/lock_test.cpp ${CMAKE_BINARY_DIR}/include/bmcweb/blns.hpp) # big list of naughty # strings add_custom_command (OUTPUT ${CMAKE_BINARY_DIR}/include/bmcweb/blns.hpp @@ -378,7 +380,7 @@ if (${BMCWEB_BUILD_UT}) target_link_libraries (webtest -lstdc++fs) add_test (webtest webtest "--gtest_output=xml:webtest.xml") -endif (${BMCWEB_BUILD_UT}) +endif (NOT ${YOCTO_DEPENDENCIES}) install (DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/static/ DESTINATION share/www) diff --git a/include/ibm/locks.hpp b/include/ibm/locks.hpp index 79079c485e..3c4f8ec46a 100644 --- a/include/ibm/locks.hpp +++ b/include/ibm/locks.hpp @@ -1,5 +1,7 @@ #pragma once +#include <logging.h> + #include <boost/algorithm/string.hpp> #include <boost/container/flat_map.hpp> #include <boost/endian/conversion.hpp> @@ -43,6 +45,21 @@ class Lock boost::container::flat_map<uint32_t, LockRequests> lockTable; /* + * This API implements the logic to persist the locks that are contained in + * the lock table into a json file. + */ + void saveLocks(); + + /* + * This API implements the logic to load the locks that are present in the + * json file into the lock table. + */ + void loadLocks(); + + bool createPersistentLockFilePath(); + + protected: + /* * This function implements the logic for validating an incoming * lock request/requests. * @@ -50,7 +67,7 @@ class Lock * Returns : False (if not a Valid lock request) */ - bool isValidLockRequest(const LockRequest); + virtual bool isValidLockRequest(const LockRequest); /* * This function implements the logic of checking if the incoming @@ -60,7 +77,7 @@ class Lock * Returns : False (if not conflicting) */ - bool isConflictRequest(const LockRequests); + virtual bool isConflictRequest(const LockRequests); /* * Implements the core algorithm to find the conflicting * lock requests. @@ -71,7 +88,7 @@ class Lock * Returns : True (if conflicting) * Returns : False (if not conflicting) */ - bool isConflictRecord(const LockRequest, const LockRequest); + virtual bool isConflictRecord(const LockRequest, const LockRequest); /* * This function implements the logic of checking the conflicting @@ -80,7 +97,7 @@ class Lock * */ - Rc isConflictWithTable(const LockRequests); + virtual Rc isConflictWithTable(const LockRequests); /* * This function implements the logic of checking the ownership of the * lock from the releaselock request. @@ -89,14 +106,15 @@ class Lock * Returns : False (if the request HMC or Session does not own the lock(s)) */ - RcRelaseLock isItMyLock(const ListOfTransactionIds &, const SessionFlags &); + virtual RcRelaseLock isItMyLock(const ListOfTransactionIds &, + const SessionFlags &); /* * This function validates the the list of transactionID's and returns false * if the transaction ID is not valid & not present in the lock table */ - bool validateRids(const ListOfTransactionIds &); + virtual bool validateRids(const ListOfTransactionIds &); /* * This function releases the locks that are already obtained by the @@ -105,17 +123,11 @@ class Lock void releaseLock(const ListOfTransactionIds &); - /* - * This API implements the logic to persist the locks that are contained in - * the lock table into a json file. - */ - void saveLocks(); - - /* - * This API implements the logic to load the locks that are present in the - * json file into the lock table. - */ - void loadLocks(); + Lock() + { + loadLocks(); + transactionId = lockTable.empty() ? 0 : prev(lockTable.end())->first; + } /* * This function implements the algorithm for checking the respective @@ -129,9 +141,7 @@ class Lock * number for every successful transaction. This number will be used by * the Management Console for debug. */ - uint32_t generateTransactionId(); - - bool createPersistentLockFilePath(); + virtual uint32_t generateTransactionId(); public: /* @@ -171,17 +181,15 @@ class Lock void releaseLock(const std::string &); - Lock() - { - loadLocks(); - transactionId = lockTable.empty() ? 0 : prev(lockTable.end())->first; - } - static Lock &getInstance() { static Lock lockObject; return lockObject; } + + virtual ~Lock() + { + } }; inline bool Lock::createPersistentLockFilePath() diff --git a/redfish-core/ut/lock_test.cpp b/redfish-core/ut/lock_test.cpp new file mode 100644 index 0000000000..0ecd8a9248 --- /dev/null +++ b/redfish-core/ut/lock_test.cpp @@ -0,0 +1,356 @@ +#include "ibm/locks.hpp" +#include "nlohmann/json.hpp" + +#include <string> +#include <utils/json_utils.hpp> + +#include "gmock/gmock.h" + +namespace crow +{ +namespace ibm_mc_lock +{ +using SType = std::string; +using LockRequest = std::tuple<SType, SType, SType, uint64_t, SegmentFlags>; +using LockRequests = std::vector<LockRequest>; +using Rc = + std::pair<bool, std::variant<uint32_t, std::pair<uint32_t, LockRequest>>>; +using RcRelaseLock = std::pair<bool, std::pair<uint32_t, LockRequest>>; +using RcGetLockList = + std::variant<std::string, std::vector<std::pair<uint32_t, LockRequests>>>; +using ListOfTransactionIds = std::vector<uint32_t>; +using RcAcquireLock = std::pair<bool, std::variant<Rc, std::pair<bool, int>>>; +using RcReleaseLockApi = std::pair<bool, std::variant<bool, RcRelaseLock>>; +using SessionFlags = std::pair<SType, SType>; +using ListOfSessionIds = std::vector<std::string>; + +class LockTest : public ::testing::Test +{ + protected: + LockRequests request; + LockRequests request1, request2; + LockRequest record; + + public: + LockTest() + { + record = { + "xxxxx", "hmc-id", "Read", 234, {{"DontLock", 2}, {"DontLock", 4}}}; + // lockrequest with multiple lockrequests + request = {{"xxxxx", + "hmc-id", + "Read", + 234, + {{"DontLock", 2}, {"DontLock", 4}}}, + {"xxxxx", + "hmc-id", + "Read", + 234, + {{"DontLock", 2}, {"DontLock", 4}}}}; + request1 = {{"xxxxx", + "hmc-id", + "Read", + 234, + {{"DontLock", 2}, {"DontLock", 4}}}}; + request2 = {{"xxxxx", + "hmc-id", + "Write", + 234, + {{"LockAll", 2}, {"DontLock", 4}}}}; + } + ~LockTest() + { + } +}; + +class MockLock : public crow::ibm_mc_lock::Lock +{ + public: + bool isValidLockRequest(LockRequest record1) override + { + bool status = Lock::isValidLockRequest(record1); + return status; + } + bool isConflictRequest(LockRequests request) override + { + bool status = Lock::isConflictRequest(request); + return status; + } + Rc isConflictWithTable(LockRequests request) override + { + auto conflict = Lock::isConflictWithTable(request); + return conflict; + } + uint32_t generateTransactionId() override + { + uint32_t tid = Lock::generateTransactionId(); + return tid; + } + + bool validateRids(const ListOfTransactionIds& tids) override + { + bool status = Lock::validateRids(tids); + return status; + } + RcRelaseLock isItMyLock(const ListOfTransactionIds& tids, + const SessionFlags& ids) override + { + auto status = Lock::isItMyLock(tids, ids); + return status; + } + RcGetLockList getList(std::vector<std::string>& listSessionid) + { + auto status = Lock::getLockList(listSessionid); + return status; + } + friend class LockTest; +}; + +TEST_F(LockTest, ValidationGoodTestCase) +{ + MockLock lockManager; + const LockRequest& t = record; + ASSERT_EQ(1, lockManager.isValidLockRequest(t)); +} + +TEST_F(LockTest, ValidationBadTestWithLocktype) +{ + MockLock lockManager; + // Corrupt the lock type + std::get<2>(record) = "rwrite"; + const LockRequest& t = record; + ASSERT_EQ(0, lockManager.isValidLockRequest(t)); +} + +TEST_F(LockTest, ValidationBadTestWithlockFlags) +{ + MockLock lockManager; + // Corrupt the lockflag + std::get<4>(record)[0].first = "lock"; + const LockRequest& t = record; + ASSERT_EQ(0, lockManager.isValidLockRequest(t)); +} + +TEST_F(LockTest, ValidationBadTestWithSegmentlength) +{ + MockLock lockManager; + // Corrupt the Segment length + std::get<4>(record)[0].second = 7; + const LockRequest& t = record; + ASSERT_EQ(0, lockManager.isValidLockRequest(t)); +} + +TEST_F(LockTest, MultiRequestWithoutConflict) +{ + MockLock lockManager; + const LockRequests& t = request; + ASSERT_EQ(0, lockManager.isConflictRequest(t)); +} + +TEST_F(LockTest, MultiRequestWithConflictduetoSameSegmentLength) +{ + MockLock lockManager; + // Corrupt the locktype + std::get<2>(request[0]) = "Write"; + // Match the segment lengths to points them to lock similar kind of + // resource + std::get<4>(request[0])[0].first = "LockAll"; + const LockRequests& t = request; + ASSERT_EQ(1, lockManager.isConflictRequest(t)); +} + +TEST_F(LockTest, MultiRequestWithoutConflictduetoDifferentSegmentData) +{ + MockLock lockManager; + // Corrupt the locktype + std::get<2>(request[0]) = "Write"; + // Match the segment lengths to points them to lock similar kind of + // resource + std::get<4>(request[0])[0].first = "DontLock"; + std::get<4>(request[0])[1].first = "LockAll"; + + // Change the resource id(2nd byte) of first record, so the locks are + // different so no conflict + std::get<3>(request[0]) = 216179379183550464; // HEX 03 00 06 00 00 00 00 00 + std::get<3>(request[1]) = 288236973221478400; // HEX 04 00 06 00 00 00 00 00 + const LockRequests& t = request; + ASSERT_EQ(0, lockManager.isConflictRequest(t)); +} + +TEST_F(LockTest, MultiRequestWithConflictduetoSameSegmentData) +{ + MockLock lockManager; + // Corrupt the locktype + std::get<2>(request[0]) = "Write"; + // Match the segment lengths to points them to lock similar kind of + // resource + std::get<4>(request[0])[0].first = "DontLock"; + std::get<4>(request[0])[1].first = "LockAll"; + // Dont Change the resource id(1st & 2nd byte) at all, so that the conflict + // occurs from the second segment which is trying to lock all the resources. + std::get<3>(request[0]) = 216173882346831872; // 03 00 01 00 2B 00 00 00 + std::get<3>(request[1]) = 216173882346831872; // 03 00 01 00 2B 00 00 00 + const LockRequests& t = request; + ASSERT_EQ(1, lockManager.isConflictRequest(t)); +} + +TEST_F(LockTest, MultiRequestWithoutConflictduetoDifferentSegmentLength) +{ + MockLock lockManager; + // Corrupt the locktype + std::get<2>(request[0]) = "Write"; + // Match the segment lengths to points them to lock similar kind of + // resource + std::get<4>(request[0])[0].first = "LockSame"; + // Change the segment length , so that the requests are trying to lock + // two different kind of resources + std::get<4>(request[0])[0].second = 3; + const LockRequests& t = request; + // Return No Conflict + ASSERT_EQ(0, lockManager.isConflictRequest(t)); +} + +TEST_F(LockTest, MultiRequestWithoutConflictduetoReadLocktype) +{ + MockLock lockManager; + // Match the segment lengths to points them to lock similar kind of + // resource + std::get<4>(request[0])[0].first = "LockAll"; + const LockRequests& t = request; + // Return No Conflict + ASSERT_EQ(0, lockManager.isConflictRequest(t)); +} + +TEST_F(LockTest, MultiRequestWithoutConflictduetoReadLocktypeAndLockall) +{ + MockLock lockManager; + // Match the segment lengths to points them to lock similar kind of + // resource + std::get<4>(request[0])[0].first = "LockAll"; + std::get<4>(request[0])[1].first = "LockAll"; + const LockRequests& t = request; + // Return No Conflict + ASSERT_EQ(0, lockManager.isConflictRequest(t)); +} + +TEST_F(LockTest, RequestConflictedWithLockTableEntries) +{ + MockLock lockManager; + const LockRequests& t = request1; + auto rc1 = lockManager.isConflictWithTable(t); + // Corrupt the lock type + std::get<2>(request[0]) = "Write"; + // Corrupt the lockflag + std::get<4>(request[0])[1].first = "LockAll"; + const LockRequests& p = request; + auto rc2 = lockManager.isConflictWithTable(p); + // Return a Conflict + ASSERT_EQ(1, rc2.first); +} + +TEST_F(LockTest, RequestNotConflictedWithLockTableEntries) +{ + MockLock lockManager; + const LockRequests& t = request1; + // Insert the request1 into the lock table + auto rc1 = lockManager.isConflictWithTable(t); + // Corrupt the lock type + std::get<2>(request[0]) = "Read"; + // Corrupt the lockflag + std::get<4>(request[0])[1].first = "LockAll"; + const LockRequests& p = request; + auto rc2 = lockManager.isConflictWithTable(p); + // Return No Conflict + ASSERT_EQ(0, rc2.first); +} + +TEST_F(LockTest, TestGenerateTransactionIDFunction) +{ + MockLock lockManager; + uint32_t transactionid1 = lockManager.generateTransactionId(); + uint32_t transactionid2 = lockManager.generateTransactionId(); + EXPECT_TRUE(transactionid2 == ++transactionid1); +} + +TEST_F(LockTest, ValidateTransactionIDsGoodTestCase) +{ + MockLock lockManager; + const LockRequests& t = request1; + // Insert the request1 into the lock table + auto rc1 = lockManager.isConflictWithTable(t); + std::vector<uint32_t> tids = {1}; + const std::vector<uint32_t>& p = tids; + ASSERT_EQ(1, lockManager.validateRids(p)); +} + +TEST_F(LockTest, ValidateTransactionIDsBadTestCase) +{ + MockLock lockManager; + // Insert the request1 into the lock table + const LockRequests& t = request1; + auto rc1 = lockManager.isConflictWithTable(t); + std::vector<uint32_t> tids = {3}; + const std::vector<uint32_t>& p = tids; + ASSERT_EQ(0, lockManager.validateRids(p)); +} + +TEST_F(LockTest, ValidateisItMyLockGoodTestCase) +{ + MockLock lockManager; + // Insert the request1 into the lock table + const LockRequests& t = request1; + auto rc1 = lockManager.isConflictWithTable(t); + std::vector<uint32_t> tids = {1}; + const std::vector<uint32_t>& p = tids; + std::string hmcid = "hmc-id"; + std::string sessionid = "xxxxx"; + std::pair<SType, SType> ids = std::make_pair(hmcid, sessionid); + auto rc = lockManager.isItMyLock(p, ids); + ASSERT_EQ(1, rc.first); +} + +TEST_F(LockTest, ValidateisItMyLockBadTestCase) +{ + MockLock lockManager; + + // Corrupt the client identifier + std::get<1>(request1[0]) = "randomid"; + // Insert the request1 into the lock table + const LockRequests& t = request1; + auto rc1 = lockManager.isConflictWithTable(t); + std::vector<uint32_t> tids = {1}; + const std::vector<uint32_t>& p = tids; + std::string hmcid = "hmc-id"; + std::string sessionid = "xxxxx"; + std::pair<SType, SType> ids = std::make_pair(hmcid, sessionid); + auto rc = lockManager.isItMyLock(p, ids); + ASSERT_EQ(0, rc.first); +} + +TEST_F(LockTest, ValidateSessionIDForGetlocklistBadTestCase) +{ + MockLock lockManager; + // Insert the request1 into the lock table + const LockRequests& t = request1; + auto rc1 = lockManager.isConflictWithTable(t); + std::vector<std::string> sessionid = {"random"}; + auto status = lockManager.getLockList(sessionid); + auto result = + std::get<std::vector<std::pair<uint32_t, LockRequests>>>(status); + ASSERT_EQ(0, result.size()); +} + +TEST_F(LockTest, ValidateSessionIDForGetlocklistGoodTestCase) +{ + MockLock lockManager; + // Insert the request1 into the lock table + const LockRequests& t = request1; + auto rc1 = lockManager.isConflictWithTable(t); + std::vector<std::string> sessionid = {"xxxxx"}; + auto status = lockManager.getLockList(sessionid); + auto result = + std::get<std::vector<std::pair<uint32_t, LockRequests>>>(status); + ASSERT_EQ(1, result.size()); +} +} // namespace ibm_mc_lock +} // namespace crow |