diff options
author | Nan Zhou <nanzhoumails@gmail.com> | 2022-09-10 21:11:41 +0300 |
---|---|---|
committer | Nan Zhou <nanzhoumails@gmail.com> | 2022-09-22 02:44:37 +0300 |
commit | c33a039b56fc5789ae71289adaca1e572a48d318 (patch) | |
tree | 8b936ca291537cebebf6bf505e565bff9635f511 /test/include | |
parent | 6ab9ad5492b9203c7dd8fb3e8c59d37bbc455cde (diff) | |
download | bmcweb-c33a039b56fc5789ae71289adaca1e572a48d318.tar.xz |
treewide: reorganize unit tests
Like other C++ projects, unit tests normally are in a separate repo and
respect the folder structure of the file under test.
This commit deleted all "ut" folder and move tests to a "test" folder.
The test folder also has similar structure as the main folder.
This commit also made neccessary include changes to make codes compile.
Unused tests are untouched.
Tested: unit test passed.
Reference:
[1] https://github.com/grpc/grpc/tree/master/test
[2] https://github.com/boostorg/core/tree/414dfb466878af427d33b36e6ccf84d21c0e081b/test
[3] Many other OpenBMC repos: https://github.com/openbmc/entity-manager/tree/master/test
[4] https://stackoverflow.com/questions/2360734/whats-a-good-directory-structure-for-larger-c-projects-using-makefile
Signed-off-by: Nan Zhou <nanzhoumails@gmail.com>
Change-Id: I4521c7ef5fa03c47cca5c146d322bbb51365ee96
Diffstat (limited to 'test/include')
-rw-r--r-- | test/include/dbus_utility_test.cpp | 48 | ||||
-rw-r--r-- | test/include/google/google_service_root_test.cpp | 39 | ||||
-rw-r--r-- | test/include/http_utility_test.cpp | 82 | ||||
-rw-r--r-- | test/include/human_sort_test.cpp | 58 | ||||
-rw-r--r-- | test/include/ibm/configfile_test.cpp | 56 | ||||
-rw-r--r-- | test/include/ibm/lock_test.cpp | 366 | ||||
-rw-r--r-- | test/include/multipart_test.cpp | 256 | ||||
-rw-r--r-- | test/include/openbmc_dbus_rest_test.cpp | 76 |
8 files changed, 981 insertions, 0 deletions
diff --git a/test/include/dbus_utility_test.cpp b/test/include/dbus_utility_test.cpp new file mode 100644 index 0000000000..71978d01ba --- /dev/null +++ b/test/include/dbus_utility_test.cpp @@ -0,0 +1,48 @@ +#include "dbus_utility.hpp" + +#include <string> + +#include <gtest/gtest.h> // IWYU pragma: keep + +// IWYU pragma: no_include <gtest/gtest-message.h> +// IWYU pragma: no_include <gtest/gtest-test-part.h> +// IWYU pragma: no_include "gtest/gtest_pred_impl.h" + +namespace dbus::utility +{ +namespace +{ + +TEST(GetNthStringFromPath, ParsingSucceedsAndReturnsNthArg) +{ + std::string path("/0th/1st/2nd/3rd"); + std::string result; + EXPECT_TRUE(getNthStringFromPath(path, 0, result)); + EXPECT_EQ(result, "0th"); + EXPECT_TRUE(getNthStringFromPath(path, 1, result)); + EXPECT_EQ(result, "1st"); + EXPECT_TRUE(getNthStringFromPath(path, 2, result)); + EXPECT_EQ(result, "2nd"); + EXPECT_TRUE(getNthStringFromPath(path, 3, result)); + EXPECT_EQ(result, "3rd"); + EXPECT_FALSE(getNthStringFromPath(path, 4, result)); + + path = "////0th///1st//\2nd///3rd?/"; + EXPECT_TRUE(getNthStringFromPath(path, 0, result)); + EXPECT_EQ(result, "0th"); + EXPECT_TRUE(getNthStringFromPath(path, 1, result)); + EXPECT_EQ(result, "1st"); + EXPECT_TRUE(getNthStringFromPath(path, 2, result)); + EXPECT_EQ(result, "\2nd"); + EXPECT_TRUE(getNthStringFromPath(path, 3, result)); + EXPECT_EQ(result, "3rd?"); +} + +TEST(GetNthStringFromPath, InvalidIndexReturnsFalse) +{ + std::string path("////0th///1st//\2nd///3rd?/"); + std::string result; + EXPECT_FALSE(getNthStringFromPath(path, -1, result)); +} +} // namespace +} // namespace dbus::utility
\ No newline at end of file diff --git a/test/include/google/google_service_root_test.cpp b/test/include/google/google_service_root_test.cpp new file mode 100644 index 0000000000..32d4e526fb --- /dev/null +++ b/test/include/google/google_service_root_test.cpp @@ -0,0 +1,39 @@ +#include "async_resp.hpp" +#include "google/google_service_root.hpp" +#include "http_request.hpp" +#include "nlohmann/json.hpp" + +#include <gtest/gtest.h> + +namespace crow::google_api +{ +namespace +{ + +void validateServiceRootGet(crow::Response& res) +{ + nlohmann::json& json = res.jsonValue; + EXPECT_EQ(json["@odata.id"], "/google/v1"); + EXPECT_EQ(json["@odata.type"], + "#GoogleServiceRoot.v1_0_0.GoogleServiceRoot"); + EXPECT_EQ(json["@odata.id"], "/google/v1"); + EXPECT_EQ(json["Id"], "Google Rest RootService"); + EXPECT_EQ(json["Name"], "Google Service Root"); + EXPECT_EQ(json["Version"], "1.0.0"); + EXPECT_EQ(json["RootOfTrustCollection"]["@odata.id"], + "/google/v1/RootOfTrustCollection"); +} + +TEST(HandleGoogleV1Get, OnSuccess) +{ + std::error_code ec; + auto asyncResp = std::make_shared<bmcweb::AsyncResp>(); + + asyncResp->res.setCompleteRequestHandler(validateServiceRootGet); + + crow::Request dummyRequest{{boost::beast::http::verb::get, "", 11}, ec}; + handleGoogleV1Get(dummyRequest, asyncResp); +} + +} // namespace +} // namespace crow::google_api
\ No newline at end of file diff --git a/test/include/http_utility_test.cpp b/test/include/http_utility_test.cpp new file mode 100644 index 0000000000..d1df6d1087 --- /dev/null +++ b/test/include/http_utility_test.cpp @@ -0,0 +1,82 @@ +#include "http_utility.hpp" + +#include <gtest/gtest.h> // IWYU pragma: keep + +// IWYU pragma: no_include <gtest/gtest-message.h> +// IWYU pragma: no_include <gtest/gtest-test-part.h> +// IWYU pragma: no_include "gtest/gtest_pred_impl.h" + +namespace http_helpers +{ +namespace +{ + +TEST(isContentTypeAllowed, PositiveTest) +{ + EXPECT_TRUE(isContentTypeAllowed("*/*, application/octet-stream", + ContentType::OctetStream)); + EXPECT_TRUE(isContentTypeAllowed("application/octet-stream", + ContentType::OctetStream)); + EXPECT_TRUE(isContentTypeAllowed("text/html", ContentType::HTML)); + EXPECT_TRUE(isContentTypeAllowed("application/json", ContentType::JSON)); + EXPECT_TRUE(isContentTypeAllowed("application/cbor", ContentType::CBOR)); + EXPECT_TRUE( + isContentTypeAllowed("application/json, text/html", ContentType::HTML)); +} + +TEST(isContentTypeAllowed, NegativeTest) +{ + EXPECT_FALSE( + isContentTypeAllowed("application/octet-stream", ContentType::HTML)); + EXPECT_FALSE(isContentTypeAllowed("application/html", ContentType::JSON)); + EXPECT_FALSE(isContentTypeAllowed("application/json", ContentType::CBOR)); + EXPECT_FALSE(isContentTypeAllowed("application/cbor", ContentType::HTML)); + EXPECT_FALSE(isContentTypeAllowed("application/json, text/html", + ContentType::OctetStream)); +} + +TEST(isContentTypeAllowed, ContainsAnyMimeTypeReturnsTrue) +{ + EXPECT_TRUE( + isContentTypeAllowed("text/html, */*", ContentType::OctetStream)); +} + +TEST(isContentTypeAllowed, ContainsQFactorWeightingReturnsTrue) +{ + EXPECT_TRUE( + isContentTypeAllowed("text/html, */*;q=0.8", ContentType::OctetStream)); +} + +TEST(getPreferedContentType, PositiveTest) +{ + std::array<ContentType, 1> contentType{ContentType::HTML}; + EXPECT_EQ( + getPreferedContentType("text/html, application/json", contentType), + ContentType::HTML); + + std::array<ContentType, 2> htmlJson{ContentType::HTML, ContentType::JSON}; + EXPECT_EQ(getPreferedContentType("text/html, application/json", htmlJson), + ContentType::HTML); + + std::array<ContentType, 2> jsonHtml{ContentType::JSON, ContentType::HTML}; + EXPECT_EQ(getPreferedContentType("text/html, application/json", jsonHtml), + ContentType::HTML); + + std::array<ContentType, 2> cborJson{ContentType::CBOR, ContentType::JSON}; + EXPECT_EQ( + getPreferedContentType("application/cbor, application::json", cborJson), + ContentType::CBOR); + + EXPECT_EQ(getPreferedContentType("application/json", cborJson), + ContentType::JSON); +} + +TEST(getPreferedContentType, NegativeTest) +{ + std::array<ContentType, 1> contentType{ContentType::CBOR}; + EXPECT_EQ( + getPreferedContentType("text/html, application/json", contentType), + ContentType::NoMatch); +} +} // namespace +} // namespace http_helpers diff --git a/test/include/human_sort_test.cpp b/test/include/human_sort_test.cpp new file mode 100644 index 0000000000..be21a198b0 --- /dev/null +++ b/test/include/human_sort_test.cpp @@ -0,0 +1,58 @@ +#include "human_sort.hpp" + +#include <set> +#include <string> + +#include <gmock/gmock.h> // IWYU pragma: keep +#include <gtest/gtest.h> // IWYU pragma: keep + +// IWYU pragma: no_include <gtest/gtest-message.h> +// IWYU pragma: no_include <gtest/gtest-test-part.h> +// IWYU pragma: no_include "gtest/gtest_pred_impl.h" +// IWYU pragma: no_include <gmock/gmock-matchers.h> + +namespace +{ + +using ::testing::ElementsAreArray; + +TEST(AlphaNum, NumberTests) +{ + // testcases for the algorithm + EXPECT_EQ(alphanumComp("", ""), 0); + EXPECT_LT(alphanumComp("", "a"), 0); + EXPECT_GT(alphanumComp("a", ""), 0); + EXPECT_EQ(alphanumComp("a", "a"), 0); + EXPECT_LT(alphanumComp("", "9"), 0); + EXPECT_GT(alphanumComp("9", ""), 0); + EXPECT_EQ(alphanumComp("1", "1"), 0); + EXPECT_LT(alphanumComp("1", "2"), 0); + EXPECT_GT(alphanumComp("3", "2"), 0); + EXPECT_EQ(alphanumComp("a1", "a1"), 0); + EXPECT_LT(alphanumComp("a1", "a2"), 0); + EXPECT_GT(alphanumComp("a2", "a1"), 0); + EXPECT_LT(alphanumComp("a1a2", "a1a3"), 0); + EXPECT_GT(alphanumComp("a1a2", "a1a0"), 0); + EXPECT_GT(alphanumComp("134", "122"), 0); + EXPECT_EQ(alphanumComp("12a3", "12a3"), 0); + EXPECT_GT(alphanumComp("12a1", "12a0"), 0); + EXPECT_LT(alphanumComp("12a1", "12a2"), 0); + EXPECT_LT(alphanumComp("a", "aa"), 0); + EXPECT_GT(alphanumComp("aaa", "aa"), 0); + EXPECT_EQ(alphanumComp("Alpha 2", "Alpha 2"), 0); + EXPECT_LT(alphanumComp("Alpha 2", "Alpha 2A"), 0); + EXPECT_GT(alphanumComp("Alpha 2 B", "Alpha 2"), 0); + + std::string str("Alpha 2"); + EXPECT_EQ(alphanumComp(str, "Alpha 2"), 0); + EXPECT_LT(alphanumComp(str, "Alpha 2A"), 0); + EXPECT_GT(alphanumComp("Alpha 2 B", str), 0); +} + +TEST(AlphaNum, LessTest) +{ + std::set<std::string, AlphanumLess<std::string>> sorted{"Alpha 10", + "Alpha 2"}; + EXPECT_THAT(sorted, ElementsAreArray({"Alpha 2", "Alpha 10"})); +} +} // namespace
\ No newline at end of file diff --git a/test/include/ibm/configfile_test.cpp b/test/include/ibm/configfile_test.cpp new file mode 100644 index 0000000000..1d95a79066 --- /dev/null +++ b/test/include/ibm/configfile_test.cpp @@ -0,0 +1,56 @@ +#include "http_response.hpp" +#include "ibm/management_console_rest.hpp" + +#include <string> + +#include <gtest/gtest.h> // IWYU pragma: keep + +// IWYU pragma: no_include <gtest/gtest-message.h> +// IWYU pragma: no_include <gtest/gtest-test-part.h> +// IWYU pragma: no_include "gtest/gtest_pred_impl.h" + +namespace crow +{ +namespace ibm_mc +{ + +TEST(IsValidConfigFileName, FileNameValidCharReturnsTrue) +{ + crow::Response res; + + EXPECT_TRUE(isValidConfigFileName("GoodConfigFile", res)); +} +TEST(IsValidConfigFileName, FileNameInvalidCharReturnsFalse) +{ + crow::Response res; + + EXPECT_FALSE(isValidConfigFileName("Bad@file", res)); +} +TEST(IsValidConfigFileName, FileNameInvalidPathReturnsFalse) +{ + crow::Response res; + + EXPECT_FALSE(isValidConfigFileName("/../../../../../etc/badpath", res)); + EXPECT_FALSE(isValidConfigFileName("/../../etc/badpath", res)); + EXPECT_FALSE(isValidConfigFileName("/mydir/configFile", res)); +} + +TEST(IsValidConfigFileName, EmptyFileNameReturnsFalse) +{ + crow::Response res; + EXPECT_FALSE(isValidConfigFileName("", res)); +} + +TEST(IsValidConfigFileName, SlashFileNameReturnsFalse) +{ + crow::Response res; + EXPECT_FALSE(isValidConfigFileName("/", res)); +} +TEST(IsValidConfigFileName, FileNameMoreThan20CharReturnsFalse) +{ + crow::Response res; + EXPECT_FALSE(isValidConfigFileName("BadfileBadfileBadfile", res)); +} + +} // namespace ibm_mc +} // namespace crow diff --git a/test/include/ibm/lock_test.cpp b/test/include/ibm/lock_test.cpp new file mode 100644 index 0000000000..33c5354f64 --- /dev/null +++ b/test/include/ibm/lock_test.cpp @@ -0,0 +1,366 @@ +#include "ibm/locks.hpp" + +#include <cstdint> +#include <memory> +#include <string> +#include <tuple> +#include <utility> +#include <variant> +#include <vector> + +#include <gmock/gmock.h> // IWYU pragma: keep +#include <gtest/gtest.h> // IWYU pragma: keep + +// IWYU pragma: no_include <gtest/gtest-message.h> +// IWYU pragma: no_include <gtest/gtest-test-part.h> +// IWYU pragma: no_include "gtest/gtest_pred_impl.h" + +namespace crow::ibm_mc_lock +{ +namespace +{ + +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>; +using ::testing::IsEmpty; + +class LockTest : public ::testing::Test +{ + protected: + LockRequests request; + LockRequests request1, request2; + LockRequest record; + + public: + LockTest() : + // 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}}}}, + record{ + "xxxxx", "hmc-id", "Read", 234, {{"DontLock", 2}, {"DontLock", 4}}} + {} + + ~LockTest() override = default; + + LockTest(const LockTest&) = delete; + LockTest(LockTest&&) = delete; + LockTest& operator=(const LockTest&) = delete; + LockTest& operator=(const LockTest&&) = delete; +}; + +class MockLock : public crow::ibm_mc_lock::Lock +{ + public: + bool isValidLockRequest(const LockRequest& record1) override + { + bool status = Lock::isValidLockRequest(record1); + return status; + } + bool isConflictRequest(const LockRequests& request) override + { + bool status = Lock::isConflictRequest(request); + return status; + } + Rc isConflictWithTable(const 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; + } + friend class LockTest; +}; + +TEST_F(LockTest, ValidationGoodTestCase) +{ + MockLock lockManager; + const LockRequest& t = record; + EXPECT_TRUE(lockManager.isValidLockRequest(t)); +} + +TEST_F(LockTest, ValidationBadTestWithLocktype) +{ + MockLock lockManager; + // Corrupt the lock type + std::get<2>(record) = "rwrite"; + const LockRequest& t = record; + EXPECT_FALSE(lockManager.isValidLockRequest(t)); +} + +TEST_F(LockTest, ValidationBadTestWithlockFlags) +{ + MockLock lockManager; + // Corrupt the lockflag + std::get<4>(record)[0].first = "lock"; + const LockRequest& t = record; + EXPECT_FALSE(lockManager.isValidLockRequest(t)); +} + +TEST_F(LockTest, ValidationBadTestWithSegmentlength) +{ + MockLock lockManager; + // Corrupt the Segment length + std::get<4>(record)[0].second = 7; + const LockRequest& t = record; + EXPECT_FALSE(lockManager.isValidLockRequest(t)); +} + +TEST_F(LockTest, MultiRequestWithoutConflict) +{ + MockLock lockManager; + const LockRequests& t = request; + EXPECT_FALSE(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; + EXPECT_TRUE(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; + EXPECT_FALSE(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; + EXPECT_TRUE(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 + EXPECT_FALSE(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 + EXPECT_FALSE(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 + EXPECT_FALSE(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 + EXPECT_TRUE(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 + EXPECT_FALSE(rc2.first); +} + +TEST_F(LockTest, TestGenerateTransactionIDFunction) +{ + MockLock lockManager; + uint32_t transactionId1 = lockManager.generateTransactionId(); + uint32_t transactionId2 = lockManager.generateTransactionId(); + EXPECT_EQ(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; + EXPECT_TRUE(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 = {10}; + const std::vector<uint32_t>& p = tids; + EXPECT_FALSE(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); + EXPECT_TRUE(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 = "random"; + std::pair<SType, SType> ids = std::make_pair(hmcid, sessionid); + auto rc = lockManager.isItMyLock(p, ids); + EXPECT_FALSE(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); + EXPECT_THAT(result, IsEmpty()); +} + +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); + EXPECT_EQ(result.size(), 1); +} + +} // namespace +} // namespace crow::ibm_mc_lock diff --git a/test/include/multipart_test.cpp b/test/include/multipart_test.cpp new file mode 100644 index 0000000000..7ad7d98f89 --- /dev/null +++ b/test/include/multipart_test.cpp @@ -0,0 +1,256 @@ +#include "http/http_request.hpp" +#include "multipart_parser.hpp" + +#include <boost/beast/http/fields.hpp> +#include <boost/beast/http/message.hpp> +#include <boost/beast/http/string_body.hpp> + +#include <memory> +#include <string_view> +#include <system_error> +#include <vector> + +#include <gtest/gtest.h> // IWYU pragma: keep + +// IWYU pragma: no_include <gtest/gtest-message.h> +// IWYU pragma: no_include <gtest/gtest-test-part.h> +// IWYU pragma: no_include "gtest/gtest_pred_impl.h" +// IWYU pragma: no_include <boost/beast/http/impl/fields.hpp> +// IWYU pragma: no_include <boost/intrusive/detail/list_iterator.hpp> +// IWYU pragma: no_include <boost/intrusive/detail/tree_iterator.hpp> + +namespace +{ +using ::testing::Test; + +class MultipartTest : public Test +{ + public: + boost::beast::http::request<boost::beast::http::string_body> req{}; + MultipartParser parser; + std::error_code ec; +}; + +TEST_F(MultipartTest, TestGoodMultipartParser) +{ + req.set("Content-Type", + "multipart/form-data; " + "boundary=---------------------------d74496d66958873e"); + + req.body() = "-----------------------------d74496d66958873e\r\n" + "Content-Disposition: form-data; name=\"Test1\"\r\n\r\n" + "111111111111111111111111112222222222222222222222222222222\r\n" + "-----------------------------d74496d66958873e\r\n" + "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n" + "{\r\n-----------------------------d74496d66958873e123456\r\n" + "-----------------------------d74496d66958873e\r\n" + "Content-Disposition: form-data; name=\"Test3\"\r\n\r\n" + "{\r\n--------d74496d6695887}\r\n" + "-----------------------------d74496d66958873e--\r\n"; + + crow::Request reqIn(req, ec); + ParserError rc = parser.parse(reqIn); + ASSERT_EQ(rc, ParserError::PARSER_SUCCESS); + + EXPECT_EQ(parser.boundary, + "\r\n-----------------------------d74496d66958873e"); + EXPECT_EQ(parser.mime_fields.size(), 3); + + EXPECT_EQ(parser.mime_fields[0].fields.at("Content-Disposition"), + "form-data; name=\"Test1\""); + EXPECT_EQ(parser.mime_fields[0].content, + "111111111111111111111111112222222222222222222222222222222"); + + EXPECT_EQ(parser.mime_fields[1].fields.at("Content-Disposition"), + "form-data; name=\"Test2\""); + EXPECT_EQ(parser.mime_fields[1].content, + "{\r\n-----------------------------d74496d66958873e123456"); + EXPECT_EQ(parser.mime_fields[2].fields.at("Content-Disposition"), + "form-data; name=\"Test3\""); + EXPECT_EQ(parser.mime_fields[2].content, "{\r\n--------d74496d6695887}"); +} + +TEST_F(MultipartTest, TestBadMultipartParser1) +{ + req.set("Content-Type", + "multipart/form-data; " + "boundary=---------------------------d74496d66958873e"); + + req.body() = "-----------------------------d74496d66958873e\r\n" + "Content-Disposition: form-data; name=\"Test1\"\r\n\r\n" + "1234567890\r\n" + "-----------------------------d74496d66958873e\r-\r\n"; + + crow::Request reqIn(req, ec); + ParserError rc = parser.parse(reqIn); + ASSERT_EQ(rc, ParserError::PARSER_SUCCESS); + + EXPECT_EQ(parser.boundary, + "\r\n-----------------------------d74496d66958873e"); + EXPECT_EQ(parser.mime_fields.size(), 1); +} + +TEST_F(MultipartTest, TestBadMultipartParser2) +{ + req.set("Content-Type", + "multipart/form-data; " + "boundary=---------------------------d74496d66958873e"); + + req.body() = "-----------------------------d74496d66958873e\r\n" + "Content-Disposition: form-data; name=\"Test1\"\r\n\r\n" + "abcd\r\n" + "-----------------------------d74496d66958873e-\r\n"; + + crow::Request reqIn(req, ec); + ParserError rc = parser.parse(reqIn); + ASSERT_EQ(rc, ParserError::PARSER_SUCCESS); + + EXPECT_EQ(parser.boundary, + "\r\n-----------------------------d74496d66958873e"); + EXPECT_EQ(parser.mime_fields.size(), 1); +} + +TEST_F(MultipartTest, TestErrorBoundaryFormat) +{ + req.set("Content-Type", + "multipart/form-data; " + "boundary+=-----------------------------d74496d66958873e"); + + req.body() = "-----------------------------d74496d66958873e\r\n" + "Content-Disposition: form-data; name=\"Test1\"\r\n\r\n" + "{\"Key1\": 11223333333333333333333333333333333333333333}\r\n" + "-----------------------------d74496d66958873e\r\n" + "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n" + "123456\r\n" + "-----------------------------d74496d66958873e--\r\n"; + + crow::Request reqIn(req, ec); + EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_BOUNDARY_FORMAT); +} + +TEST_F(MultipartTest, TestErrorBoundaryCR) +{ + req.set("Content-Type", + "multipart/form-data; " + "boundary=---------------------------d74496d66958873e"); + + req.body() = "-----------------------------d74496d66958873e" + "Content-Disposition: form-data; name=\"Test1\"\r\n\r" + "{\"Key1\": 112233}\r\n" + "-----------------------------d74496d66958873e\r\n" + "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n" + "123456\r\n" + "-----------------------------d74496d66958873e--\r\n"; + + crow::Request reqIn(req, ec); + EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_BOUNDARY_CR); +} + +TEST_F(MultipartTest, TestErrorBoundaryLF) +{ + req.set("Content-Type", + "multipart/form-data; " + "boundary=---------------------------d74496d66958873e"); + + req.body() = "-----------------------------d74496d66958873e\r" + "Content-Disposition: form-data; name=\"Test1\"\r\n\r\n" + "{\"Key1\": 112233}\r\n" + "-----------------------------d74496d66958873e\r\n" + "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n" + "123456\r\n" + "-----------------------------d74496d66958873e--\r\n"; + + crow::Request reqIn(req, ec); + EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_BOUNDARY_LF); +} + +TEST_F(MultipartTest, TestErrorBoundaryData) +{ + req.set("Content-Type", + "multipart/form-data; " + "boundary=---------------------------d7449sd6d66958873e"); + + req.body() = "-----------------------------d74496d66958873e\r\n" + "Content-Disposition: form-data; name=\"Test1\"\r\n\r\n" + "{\"Key1\": 112233}\r\n" + "-----------------------------d74496d66958873e\r\n" + "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n" + "123456\r\n" + "-----------------------------d74496d66958873e--\r\n"; + + crow::Request reqIn(req, ec); + EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_BOUNDARY_DATA); +} + +TEST_F(MultipartTest, TestErrorEmptyHeader) +{ + req.set("Content-Type", + "multipart/form-data; " + "boundary=---------------------------d74496d66958873e"); + + req.body() = "-----------------------------d74496d66958873e\r\n" + ": form-data; name=\"Test1\"\r\n" + "{\"Key1\": 112233}\r\n" + "-----------------------------d74496d66958873e\r\n" + "Content-Disposition: form-data; name=\"Test2\"\r\n" + "123456\r\n" + "-----------------------------d74496d66958873e--\r\n"; + + crow::Request reqIn(req, ec); + EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_EMPTY_HEADER); +} + +TEST_F(MultipartTest, TestErrorHeaderName) +{ + req.set("Content-Type", + "multipart/form-data; " + "boundary=---------------------------d74496d66958873e"); + + req.body() = "-----------------------------d74496d66958873e\r\n" + "Content-!!Disposition: form-data; name=\"Test1\"\r\n" + "{\"Key1\": 112233}\r\n" + "-----------------------------d74496d66958873e\r\n" + "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n" + "123456\r\n" + "-----------------------------d74496d66958873e--\r\n"; + + crow::Request reqIn(req, ec); + EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_HEADER_NAME); +} + +TEST_F(MultipartTest, TestErrorHeaderValue) +{ + req.set("Content-Type", + "multipart/form-data; " + "boundary=---------------------------d74496d66958873e"); + + req.body() = "-----------------------------d74496d66958873e\r\n" + "Content-Disposition: form-data; name=\"Test1\"\r" + "{\"Key1\": 112233}\r\n" + "-----------------------------d74496d66958873e\r\n" + "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n" + "123456\r\n" + "-----------------------------d74496d66958873e--\r\n"; + + crow::Request reqIn(req, ec); + EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_HEADER_VALUE); +} + +TEST_F(MultipartTest, TestErrorHeaderEnding) +{ + req.set("Content-Type", + "multipart/form-data; " + "boundary=---------------------------d74496d66958873e"); + + req.body() = "-----------------------------d74496d66958873e\r\n" + "Content-Disposition: form-data; name=\"Test1\"\r\n\r" + "{\"Key1\": 112233}\r\n" + "-----------------------------d74496d66958873e\r\n" + "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n" + "123456\r\n" + "-----------------------------d74496d66958873e--\r\n"; + + crow::Request reqIn(req, ec); + EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_HEADER_ENDING); +} +} // namespace
\ No newline at end of file diff --git a/test/include/openbmc_dbus_rest_test.cpp b/test/include/openbmc_dbus_rest_test.cpp new file mode 100644 index 0000000000..b01e92a505 --- /dev/null +++ b/test/include/openbmc_dbus_rest_test.cpp @@ -0,0 +1,76 @@ +#include "openbmc_dbus_rest.hpp" + +#include <gmock/gmock.h> // IWYU pragma: keep +#include <gtest/gtest.h> // IWYU pragma: keep + +// IWYU pragma: no_include <gtest/gtest-message.h> +// IWYU pragma: no_include <gtest/gtest-test-part.h> +// IWYU pragma: no_include "gtest/gtest_pred_impl.h" +// IWYU pragma: no_include <gmock/gmock-matchers.h> + +namespace crow::openbmc_mapper +{ +namespace +{ + +using ::testing::ElementsAre; +// Also see redfish-core/ut/configfile_test.cpp +TEST(OpenbmcDbusRestTest, ValidFilenameGood) +{ + EXPECT_TRUE(validateFilename("GoodConfigFile")); + EXPECT_TRUE(validateFilename("_Underlines_")); + EXPECT_TRUE(validateFilename("8675309")); + EXPECT_TRUE(validateFilename("-Dashes-")); + EXPECT_TRUE(validateFilename("With Spaces")); + EXPECT_TRUE(validateFilename("One.Dot")); + EXPECT_TRUE(validateFilename("trailingdot.")); + EXPECT_TRUE(validateFilename("-_ o _-")); + EXPECT_TRUE(validateFilename(" ")); + EXPECT_TRUE(validateFilename(" .")); +} + +// There is no length test yet because validateFilename() does not care yet +TEST(OpenbmcDbusRestTest, ValidFilenameBad) +{ + EXPECT_FALSE(validateFilename("")); + EXPECT_FALSE(validateFilename("Bad@file")); + EXPECT_FALSE(validateFilename("/../../../../../etc/badpath")); + EXPECT_FALSE(validateFilename("/../../etc/badpath")); + EXPECT_FALSE(validateFilename("/mydir/configFile")); + EXPECT_FALSE(validateFilename("/")); + EXPECT_FALSE(validateFilename(".leadingdot")); + EXPECT_FALSE(validateFilename("Two..Dots")); + EXPECT_FALSE(validateFilename("../../../../../../etc/shadow")); + EXPECT_FALSE(validateFilename(".")); +} + +TEST(OpenBmcDbusTest, TestArgSplit) +{ + // test the basic types + EXPECT_THAT(dbusArgSplit("x"), ElementsAre("x")); + EXPECT_THAT(dbusArgSplit("y"), ElementsAre("y")); + EXPECT_THAT(dbusArgSplit("b"), ElementsAre("b")); + EXPECT_THAT(dbusArgSplit("n"), ElementsAre("n")); + EXPECT_THAT(dbusArgSplit("q"), ElementsAre("q")); + EXPECT_THAT(dbusArgSplit("i"), ElementsAre("i")); + EXPECT_THAT(dbusArgSplit("u"), ElementsAre("u")); + EXPECT_THAT(dbusArgSplit("x"), ElementsAre("x")); + EXPECT_THAT(dbusArgSplit("t"), ElementsAre("t")); + EXPECT_THAT(dbusArgSplit("d"), ElementsAre("d")); + EXPECT_THAT(dbusArgSplit("h"), ElementsAre("h")); + // test arrays + EXPECT_THAT(dbusArgSplit("ai"), ElementsAre("ai")); + EXPECT_THAT(dbusArgSplit("ax"), ElementsAre("ax")); + // test tuples + EXPECT_THAT(dbusArgSplit("(sss)"), ElementsAre("(sss)")); + EXPECT_THAT(dbusArgSplit("(sss)b"), ElementsAre("(sss)", "b")); + EXPECT_THAT(dbusArgSplit("b(sss)"), ElementsAre("b", "(sss)")); + + // Test nested types + EXPECT_THAT(dbusArgSplit("a{si}b"), ElementsAre("a{si}", "b")); + EXPECT_THAT(dbusArgSplit("a(sss)b"), ElementsAre("a(sss)", "b")); + EXPECT_THAT(dbusArgSplit("aa{si}b"), ElementsAre("aa{si}", "b")); + EXPECT_THAT(dbusArgSplit("i{si}b"), ElementsAre("i", "{si}", "b")); +} +} // namespace +} // namespace crow::openbmc_mapper |