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
diff --git a/redfish-core/ut/lock_test.cpp b/redfish-core/ut/lock_test.cpp
new file mode 100644
index 0000000..0ecd8a9
--- /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