summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormanojkiraneda <manojkiran.eda@gmail.com>2019-12-13 14:40:41 +0300
committerManojKiran Eda <manojkiran.eda@gmail.com>2020-06-09 06:34:14 +0300
commit4eaf2ee36116b4d2be4269df106d37d7d437a711 (patch)
treeae35ad99e1826a439c20e090e956ca7da5309ca1
parentd6d59a65c334f0040177ffb3ab87f9b512a72cad (diff)
downloadbmcweb-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.txt18
-rw-r--r--include/ibm/locks.hpp60
-rw-r--r--redfish-core/ut/lock_test.cpp356
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