diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/Makefile.am | 23 | ||||
-rw-r--r-- | test/entitymap_json_unittest.cpp | 223 | ||||
-rw-r--r-- | test/message/pack.cpp | 71 | ||||
-rw-r--r-- | test/message/payload.cpp | 134 | ||||
-rw-r--r-- | test/message/unpack.cpp | 51 | ||||
-rw-r--r-- | test/session/closesession_unittest.cpp | 114 |
6 files changed, 613 insertions, 3 deletions
diff --git a/test/Makefile.am b/test/Makefile.am index e510230..0faeda7 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -26,6 +26,11 @@ AM_LDFLAGS = $(GTEST_MAIN_LIBS) $(OESDK_TESTCASE_FLAGS) check_PROGRAMS = TESTS = $(check_PROGRAMS) +entitymap_json_unittest_SOURCES = entitymap_json_unittest.cpp +entitymap_json_unittest_LDADD = $(top_builddir)/entity_map_json.o -lgmock + +check_PROGRAMS += entitymap_json_unittest + # Build/add sample_unittest to test suite sample_unittest_CPPFLAGS = -Igtest $(GTEST_CPPFLAGS) $(AM_CPPFLAGS) sample_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(CODE_COVERAGE_CXXFLAGS) \ @@ -67,3 +72,21 @@ message_unittest_SOURCES = \ %reldir%/message/unpack.cpp \ %reldir%/message/pack.cpp check_PROGRAMS += %reldir%/message_unittest + +# Build/add closesession_unittest to test suite +session_unittest_CPPFLAGS = \ + -Igtest \ + $(GTEST_CPPFLAGS) \ + $(AM_CPPFLAGS) +session_unittest_CXXFLAGS = \ + $(PTHREAD_CFLAGS) \ + $(CODE_COVERAGE_CXXFLAGS) \ + $(CODE_COVERAGE_CFLAGS) +session_unittest_LDFLAGS = \ + -lgtest_main \ + -lgtest \ + -pthread \ + $(OESDK_TESTCASE_FLAGS) \ + $(CODE_COVERAGE_LDFLAGS) +session_unittest_SOURCES = %reldir%/session/closesession_unittest.cpp +check_PROGRAMS += %reldir%/session_unittest diff --git a/test/entitymap_json_unittest.cpp b/test/entitymap_json_unittest.cpp new file mode 100644 index 0000000..a380a9e --- /dev/null +++ b/test/entitymap_json_unittest.cpp @@ -0,0 +1,223 @@ +#include "entity_map_json.hpp" + +#include <ipmid/types.hpp> +#include <nlohmann/json.hpp> +#include <utility> + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +namespace ipmi +{ +namespace sensor +{ + +namespace +{ +using ::testing::IsEmpty; + +TEST(ValidateJson, FailWithNonArrayReturnsEmpty) +{ + /* The entity map input json is expected to be an array of objects. */ + auto j = R"( + { + "id" : 1, + "containerEntityId" : 2, + "containerEntityInstance" : 3, + "isList" : false, + "isLinked" : false, + "entities" : [ + {"id" : 1, "instance" : 2}, + {"id" : 1, "instance" : 3}, + {"id" : 1, "instance" : 4}, + {"id" : 1, "instance" : 5} + ] + } + )"_json; + + EXPECT_THAT(buildJsonEntityMap(j), IsEmpty()); +} + +TEST(ValidateJson, FailWithMissingFieldReturnsEmpty) +{ + /* There are many required fields, let's just validate that if one is + * missing, it returns the empty map. + */ + auto j = R"( + [ + { + "id" : 1, + "containerEntityId" : 2, + "containerEntityInstance" : 3, + "isList" : false, + "entities" : [ + {"id" : 1, "instance" : 2}, + {"id" : 1, "instance" : 3}, + {"id" : 1, "instance" : 4}, + {"id" : 1, "instance" : 5} + ] + } + ] + )"_json; + + EXPECT_THAT(buildJsonEntityMap(j), IsEmpty()); +} + +TEST(ValidateJson, AllValidEntryReturnsExpectedMap) +{ + /* Boring test where we provide completely valid information and expect the + * resulting map contains that information. + */ + auto j = R"( + [ + { + "id" : 1, + "containerEntityId" : 2, + "containerEntityInstance" : 3, + "isList" : false, + "isLinked" : false, + "entities" : [ + {"id" : 1, "instance" : 2}, + {"id" : 1, "instance" : 3}, + {"id" : 1, "instance" : 4}, + {"id" : 1, "instance" : 5} + ] + } + ] + )"_json; + + auto map = buildJsonEntityMap(j); + EXPECT_FALSE(map.find(1) == map.end()); + auto entry = map.find(1); + EXPECT_EQ(entry->first, 1); + + /* TODO: someone could write an equality operator for this object. */ + EXPECT_EQ(entry->second.containerEntityId, 2); + EXPECT_EQ(entry->second.containerEntityInstance, 3); + EXPECT_FALSE(entry->second.isList); + EXPECT_FALSE(entry->second.isLinked); + ContainedEntitiesArray expected = { + std::make_pair(1, 2), std::make_pair(1, 3), std::make_pair(1, 4), + std::make_pair(1, 5)}; + EXPECT_EQ(entry->second.containedEntities, expected); +} + +TEST(ValidateJson, EntryHasInsufficientContainerEntryCountReturnsEmpty) +{ + /* The container must have four pairs. (I don't know why, and maybe this + * restriction will change). + */ + auto j = R"( + [ + { + "id" : 1, + "containerEntityId" : 2, + "containerEntityInstance" : 3, + "isList" : false, + "isLinked" : false, + "entities" : [ + {"id" : 1, "instance" : 2}, + {"id" : 1, "instance" : 3}, + {"id" : 1, "instance" : 4} + ] + } + ] + )"_json; + + EXPECT_THAT(buildJsonEntityMap(j), IsEmpty()); +} + +TEST(ValidateJson, ThereAreTwoEntriesOneInvalidReturnsEmpty) +{ + /* If any entry in the file is corrupt, the file is disregarded. */ + auto j = R"( + [ + { + "id" : 1, + "containerEntityId" : 2, + "containerEntityInstance" : 3, + "isList" : false, + "isLinked" : false, + "entities" : [ + {"id" : 1, "instance" : 2}, + {"id" : 1, "instance" : 3}, + {"id" : 1, "instance" : 4}, + {"id" : 1, "instance" : 5} + ] + }, + { + "id" : 2, + "containerEntityId" : 2, + "containerEntityInstance" : 3, + "isList" : false, + "isLinked" : false, + "entities" : [ + {"id" : 1, "instance" : 2}, + {"id" : 1, "instance" : 3}, + {"id" : 1, "instance" : 4} + ] + } + ] + )"_json; + + EXPECT_THAT(buildJsonEntityMap(j), IsEmpty()); +} + +TEST(ValidateJson, ThereAreTwoEntriesBothValidReturnsBoth) +{ + /* The map supports more than one entry, just validate this. */ + auto j = R"( + [ + { + "id" : 1, + "containerEntityId" : 2, + "containerEntityInstance" : 3, + "isList" : false, + "isLinked" : false, + "entities" : [ + {"id" : 1, "instance" : 2}, + {"id" : 1, "instance" : 3}, + {"id" : 1, "instance" : 4}, + {"id" : 1, "instance" : 5} + ] + }, + { + "id" : 2, + "containerEntityId" : 2, + "containerEntityInstance" : 3, + "isList" : false, + "isLinked" : false, + "entities" : [ + {"id" : 1, "instance" : 6}, + {"id" : 1, "instance" : 7}, + {"id" : 1, "instance" : 8}, + {"id" : 1, "instance" : 9} + ] + } + ] + )"_json; + + auto map = buildJsonEntityMap(j); + EXPECT_FALSE(map.find(1) == map.end()); + EXPECT_FALSE(map.find(2) == map.end()); + + auto entry = map.find(1); + EXPECT_EQ(entry->first, 1); + EXPECT_EQ(entry->second.containerEntityId, 2); + EXPECT_EQ(entry->second.containerEntityInstance, 3); + EXPECT_FALSE(entry->second.isList); + EXPECT_FALSE(entry->second.isLinked); + ContainedEntitiesArray expected = { + std::make_pair(1, 2), std::make_pair(1, 3), std::make_pair(1, 4), + std::make_pair(1, 5)}; + EXPECT_EQ(entry->second.containedEntities, expected); + + entry = map.find(2); + expected = {std::make_pair(1, 6), std::make_pair(1, 7), + std::make_pair(1, 8), std::make_pair(1, 9)}; + EXPECT_EQ(entry->second.containedEntities, expected); +} + +} // namespace +} // namespace sensor +} // namespace ipmi diff --git a/test/message/pack.cpp b/test/message/pack.cpp index d0a738a..9e88f2b 100644 --- a/test/message/pack.cpp +++ b/test/message/pack.cpp @@ -235,6 +235,27 @@ TEST(PackBasics, VectorUint8) ASSERT_EQ(p.raw, k); } +TEST(PackBasics, VectorUnaligned) +{ + ipmi::message::Payload p; + EXPECT_EQ(p.pack(true, std::vector<uint8_t>{1}), 1); + EXPECT_EQ(p.raw, std::vector<uint8_t>{0b1}); +} + +TEST(PackBasics, StringView) +{ + ipmi::message::Payload p; + EXPECT_EQ(p.pack(std::string_view{"\x24\x30\x11"}), 0); + EXPECT_EQ(p.raw, std::vector<uint8_t>({0x24, 0x30, 0x11})); +} + +TEST(PackBasics, StringViewUnaligned) +{ + ipmi::message::Payload p; + EXPECT_EQ(p.pack(true, std::string_view{"abc"}), 1); + EXPECT_EQ(p.raw, std::vector<uint8_t>({0b1})); +} + TEST(PackBasics, OptionalEmpty) { // an optional will only pack if the value is present @@ -261,6 +282,56 @@ TEST(PackBasics, OptionalContainsValue) ASSERT_EQ(p.raw, k); } +TEST(PackBasics, Payload) +{ + ipmi::message::Payload p; + EXPECT_EQ(p.pack(true), 0); + EXPECT_EQ(p.pack(ipmi::message::Payload({0x24, 0x30})), 0); + EXPECT_EQ(p.raw, std::vector<uint8_t>({0b1, 0x24, 0x30})); +} + +TEST(PackBasics, PayloadUnaligned) +{ + ipmi::message::Payload p; + EXPECT_EQ(p.pack(true, ipmi::message::Payload({0x24})), 1); + EXPECT_EQ(p.raw, std::vector<uint8_t>({0b1})); +} + +TEST(PackBasics, PayloadOtherUnaligned) +{ + ipmi::message::Payload p, q; + q.appendBits(1, 1); + EXPECT_EQ(p.pack(true), 0); + EXPECT_EQ(p.pack(q), 1); + EXPECT_EQ(p.raw, std::vector<uint8_t>({0b1})); +} + +TEST(PackBasics, PrependPayload) +{ + ipmi::message::Payload p; + EXPECT_EQ(p.pack(true), 0); + EXPECT_EQ(p.prepend(ipmi::message::Payload({0x24, 0x30})), 0); + EXPECT_EQ(p.raw, std::vector<uint8_t>({0x24, 0x30, 0b1})); +} + +TEST(PackBasics, PrependPayloadUnaligned) +{ + ipmi::message::Payload p; + p.appendBits(1, 1); + EXPECT_EQ(p.prepend(ipmi::message::Payload({0x24})), 1); + p.drain(); + EXPECT_EQ(p.raw, std::vector<uint8_t>({0b1})); +} + +TEST(PackBasics, PrependPayloadOtherUnaligned) +{ + ipmi::message::Payload p, q; + q.appendBits(1, 1); + EXPECT_EQ(p.pack(true), 0); + EXPECT_EQ(p.prepend(q), 1); + EXPECT_EQ(p.raw, std::vector<uint8_t>({0b1})); +} + TEST(PackAdvanced, Uints) { // all elements will be processed in order, with each multi-byte diff --git a/test/message/payload.cpp b/test/message/payload.cpp index 9d20ff0..56d8d41 100644 --- a/test/message/payload.cpp +++ b/test/message/payload.cpp @@ -13,8 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#define SD_JOURNAL_SUPPRESS_LOCATION + +#include <systemd/sd-journal.h> + #include <ipmid/api.hpp> #include <ipmid/message.hpp> +#include <stdexcept> #include <gtest/gtest.h> @@ -306,3 +311,132 @@ TEST(PayloadRequest, PartialPayload) uint32_t k2 = 0x02008604; ASSERT_EQ(v2, k2); } + +std::vector<std::string> logs; + +extern "C" { +int sd_journal_send(const char* format, ...) +{ + logs.push_back(format); + return 0; +} + +int sd_journal_send_with_location(const char* file, const char* line, + const char* func, const char* format, ...) +{ + logs.push_back(format); + return 0; +} +} + +class PayloadLogging : public testing::Test +{ + public: + void SetUp() + { + logs.clear(); + } +}; + +TEST_F(PayloadLogging, TrailingOk) +{ + { + ipmi::message::Payload p({1, 2}); + } + EXPECT_EQ(logs.size(), 0); +} + +TEST_F(PayloadLogging, EnforcingUnchecked) +{ + { + ipmi::message::Payload p({1, 2}); + p.trailingOk = false; + } + EXPECT_EQ(logs.size(), 1); +} + +TEST_F(PayloadLogging, EnforcingUncheckedUnpacked) +{ + { + ipmi::message::Payload p({1, 2}); + p.trailingOk = false; + uint8_t out; + p.unpack(out, out); + } + EXPECT_EQ(logs.size(), 1); +} + +TEST_F(PayloadLogging, EnforcingUncheckedError) +{ + { + ipmi::message::Payload p({1, 2}); + p.trailingOk = false; + uint32_t out; + p.unpack(out); + } + EXPECT_EQ(logs.size(), 0); +} + +TEST_F(PayloadLogging, EnforcingChecked) +{ + { + ipmi::message::Payload p({1, 2}); + p.trailingOk = false; + EXPECT_FALSE(p.fullyUnpacked()); + } + EXPECT_EQ(logs.size(), 0); +} + +TEST_F(PayloadLogging, EnforcingCheckedUnpacked) +{ + { + ipmi::message::Payload p({1, 2}); + p.trailingOk = false; + uint8_t out; + p.unpack(out, out); + EXPECT_TRUE(p.fullyUnpacked()); + } + EXPECT_EQ(logs.size(), 0); +} + +TEST_F(PayloadLogging, EnforcingUnpackPayload) +{ + { + ipmi::message::Payload p; + { + ipmi::message::Payload q({1, 2}); + q.trailingOk = false; + q.unpack(p); + } + EXPECT_EQ(logs.size(), 0); + } + EXPECT_EQ(logs.size(), 1); +} + +TEST_F(PayloadLogging, EnforcingMove) +{ + { + ipmi::message::Payload p; + { + ipmi::message::Payload q({1, 2}); + q.trailingOk = false; + p = std::move(q); + } + EXPECT_EQ(logs.size(), 0); + } + EXPECT_EQ(logs.size(), 1); +} + +TEST_F(PayloadLogging, EnforcingException) +{ + try + { + ipmi::message::Payload p({1, 2}); + p.trailingOk = false; + throw std::runtime_error("test"); + } + catch (...) + { + } + EXPECT_EQ(logs.size(), 0); +} diff --git a/test/message/unpack.cpp b/test/message/unpack.cpp index 611a5fe..7d69218 100644 --- a/test/message/unpack.cpp +++ b/test/message/unpack.cpp @@ -660,8 +660,8 @@ TEST(Vectors, VectorUint32NonIntegralBytes) 0x99, 0x77, 0x55, 0x33, 0x78, 0x56, 0x34}; ipmi::message::Payload p(std::forward<std::vector<uint8_t>>(i)); std::vector<uint32_t> v; - // check that the number of bytes matches - ASSERT_NE(p.unpack(v), 0); + // check that the vector unpacks successfully + ASSERT_EQ(p.unpack(v), 0); // check that the payload was not fully unpacked ASSERT_FALSE(p.fullyUnpacked()); // arrays of uint32_t will be unpacked one at a time, so the @@ -686,6 +686,51 @@ TEST(Vectors, VectorUint8) ASSERT_EQ(v, k); } +TEST(Vectors, VectorEmptyOk) +{ + // an empty input vector to show that unpacking elements is okay + std::vector<uint8_t> i{}; + ipmi::message::Payload p(std::forward<std::vector<uint8_t>>(i)); + std::vector<uint32_t> v; + // check that the number of bytes matches + ASSERT_EQ(p.unpack(v), 0); + // check that the payload was fully unpacked + ASSERT_TRUE(p.fullyUnpacked()); + std::vector<uint32_t> k{}; + // check that the unpacked vector is empty as expected + ASSERT_EQ(v, k); +} + +TEST(Vectors, VectorOfTuplesOk) +{ + // a vector of bytes will be unpacked verbatim, low-order element first + std::vector<uint8_t> i = {0x02, 0x00, 0x86, 0x04}; + ipmi::message::Payload p(std::forward<std::vector<uint8_t>>(i)); + std::vector<std::tuple<uint8_t, uint8_t>> v; + // check that the number of bytes matches + ASSERT_EQ(p.unpack(v), 0); + // check that the payload was fully unpacked + ASSERT_TRUE(p.fullyUnpacked()); + std::vector<std::tuple<uint8_t, uint8_t>> k = {{0x02, 0x00}, {0x86, 0x04}}; + // check that the bytes were correctly unpacked (in byte order) + ASSERT_EQ(v, k); +} + +TEST(Vectors, VectorOfTuplesInsufficientBytes) +{ + // a vector of bytes will be unpacked verbatim, low-order element first + std::vector<uint8_t> i = {0x02, 0x00, 0x86, 0x04, 0xb4}; + ipmi::message::Payload p(std::forward<std::vector<uint8_t>>(i)); + std::vector<std::tuple<uint8_t, uint8_t>> v; + // check that the number of bytes matches + ASSERT_EQ(p.unpack(v), 0); + // check that the payload was not fully unpacked + ASSERT_FALSE(p.fullyUnpacked()); + std::vector<std::tuple<uint8_t, uint8_t>> k = {{0x02, 0x00}, {0x86, 0x04}}; + // check that the bytes were correctly unpacked (in byte order) + ASSERT_EQ(v, k); +} + // Cannot test TooManyBytes or InsufficientBytes for vector<uint8_t> // because it will always unpack whatever bytes are remaining // TEST(Vectors, VectorUint8TooManyBytes) {} @@ -716,7 +761,7 @@ TEST(UnpackAdvanced, OptionalInsufficientBytes) ASSERT_EQ(p.unpack(v), 0); // check that the payload was fully unpacked ASSERT_FALSE(p.fullyUnpacked()); - std::optional<std::tuple<uint8_t, uint32_t>> k = {{0, 0}}; + std::optional<std::tuple<uint8_t, uint32_t>> k; // check that the bytes were correctly unpacked (in byte order) ASSERT_EQ(v, k); } diff --git a/test/session/closesession_unittest.cpp b/test/session/closesession_unittest.cpp new file mode 100644 index 0000000..2b184ca --- /dev/null +++ b/test/session/closesession_unittest.cpp @@ -0,0 +1,114 @@ +#include <ipmid/sessionhelper.hpp> + +#include <gtest/gtest.h> + +TEST(parseSessionInputPayloadTest, ValidObjectPath) +{ + uint32_t sessionId = 0; + uint8_t sessionHandle = 0; + std::string objectPath = + "/xyz/openbmc_project/ipmi/session/eth0/12a4567d_8a"; + + EXPECT_TRUE( + parseCloseSessionInputPayload(objectPath, sessionId, sessionHandle)); + EXPECT_EQ(0x12a4567d, sessionId); + EXPECT_EQ(0x8a, sessionHandle); +} + +TEST(parseSessionInputPayloadTest, InvalidObjectPath) +{ + uint32_t sessionId = 0; + uint8_t sessionHandle = 0; + // A valid object path will be like + // "/xyz/openbmc_project/ipmi/session/channel/sessionId_sessionHandle" + // Ex: "/xyz/openbmc_project/ipmi/session/eth0/12a4567d_8a" + // SessionId : 0X12a4567d + // SessionHandle: 0X8a + std::string objectPath = "/xyz/openbmc_project/ipmi/session/eth0/12a4567d"; + + EXPECT_FALSE( + parseCloseSessionInputPayload(objectPath, sessionId, sessionHandle)); +} + +TEST(parseSessionInputPayloadTest, NoObjectPath) +{ + uint32_t sessionId = 0; + uint8_t sessionHandle = 0; + std::string objectPath; + + EXPECT_FALSE( + parseCloseSessionInputPayload(objectPath, sessionId, sessionHandle)); +} + +TEST(isSessionObjectMatchedTest, ValidSessionId) +{ + std::string objectPath = + "/xyz/openbmc_project/ipmi/session/eth0/12a4567d_8a"; + uint32_t sessionId = 0x12a4567d; + uint8_t sessionHandle = 0; + + EXPECT_TRUE(isSessionObjectMatched(objectPath, sessionId, sessionHandle)); +} + +TEST(isSessionObjectMatchedTest, ValidSessionHandle) +{ + std::string objectPath = + "/xyz/openbmc_project/ipmi/session/eth0/12a4567d_8a"; + uint32_t sessionId = 0; + uint8_t sessionHandle = 0x8a; + + EXPECT_TRUE(isSessionObjectMatched(objectPath, sessionId, sessionHandle)); +} + +TEST(isSessionObjectMatchedTest, InvalidSessionId) +{ + std::string objectPath = + "/xyz/openbmc_project/ipmi/session/eth0/12a4567d_8a"; + uint32_t sessionId = 0x1234b67d; + uint8_t sessionHandle = 0; + + EXPECT_FALSE(isSessionObjectMatched(objectPath, sessionId, sessionHandle)); +} + +TEST(isSessionObjectMatchedTest, InvalidSessionHandle) +{ + std::string objectPath = + "/xyz/openbmc_project/ipmi/session/eth0/12a4567d_8a"; + uint32_t sessionId = 0; + uint8_t sessionHandle = 0x9b; + + EXPECT_FALSE(isSessionObjectMatched(objectPath, sessionId, sessionHandle)); +} + +TEST(isSessionObjectMatchedTest, ZeroSessionId_ZeroSessionHandle) +{ + std::string objectPath = + "/xyz/openbmc_project/ipmi/session/eth0/12a4567d_8a"; + uint32_t sessionId = 0; + uint8_t sessionHandle = 0; + + EXPECT_FALSE(isSessionObjectMatched(objectPath, sessionId, sessionHandle)); +} + +TEST(isSessionObjectMatchedTest, InvalidObjectPath) +{ + // A valid object path will be like + // "/xyz/openbmc_project/ipmi/session/channel/sessionId_sessionHandle" + // Ex: "/xyz/openbmc_project/ipmi/session/eth0/12a4567d_8a" + // SessionId : 0X12a4567d + // SessionHandle: 0X8a + std::string objectPath = "/xyz/openbmc_project/ipmi/session/eth0/12a4567d"; + uint32_t sessionId = 0x12a4567d; + uint8_t sessionHandle = 0; + + EXPECT_FALSE(isSessionObjectMatched(objectPath, sessionId, sessionHandle)); +} + +TEST(isSessionObjectMatchedTest, NoObjectPath) +{ + std::string objectPath; + uint32_t sessionId = 0x12a4567d; + uint8_t sessionHandle = 0x8a; + + EXPECT_FALSE(isSessionObjectMatched(objectPath, sessionId, sessionHandle)); +} |