diff options
author | Patrick Venture <venture@google.com> | 2019-03-05 14:01:00 -0800 |
---|---|---|
committer | Patrick Venture <venture@google.com> | 2019-03-06 07:51:32 -0800 |
commit | 123b5c0910e000cf9b00a37146aae99a835f3063 (patch) | |
tree | e1aacf85711d9c5f7e8ad87a1c8e671e09f61db8 /test | |
parent | 85e320906546f3e5a0dfe1ab54a826517dae2a0d (diff) | |
download | ipmi-blob-tool-123b5c0910e000cf9b00a37146aae99a835f3063.tar.gz ipmi-blob-tool-123b5c0910e000cf9b00a37146aae99a835f3063.zip |
initial commit
Add initial code from phosphor-ipmi-flash/tools that was not specific to
firmware update over ipmi-blobs.
Change-Id: I360537a7392347fe989397a699f6a712bc36e62c
Signed-off-by: Patrick Venture <venture@google.com>
Diffstat (limited to 'test')
-rw-r--r-- | test/Makefile.am | 25 | ||||
-rw-r--r-- | test/crc_mock.hpp | 23 | ||||
-rw-r--r-- | test/internal_sys_mock.hpp | 27 | ||||
-rw-r--r-- | test/tools_blob_unittest.cpp | 289 | ||||
-rw-r--r-- | test/tools_ipmi_error_unittest.cpp | 28 | ||||
-rw-r--r-- | test/tools_ipmi_unittest.cpp | 22 |
6 files changed, 414 insertions, 0 deletions
diff --git a/test/Makefile.am b/test/Makefile.am new file mode 100644 index 0000000..05d9b1d --- /dev/null +++ b/test/Makefile.am @@ -0,0 +1,25 @@ +@VALGRIND_CHECK_RULES@ +@CODE_COVERAGE_RULES@ + +gtest_cppflags = $(AM_CPPFLAGS) $(GTEST_CFLAGS) $(GMOCK_CFLAGS) +gtest_ldadd = $(GTEST_LIBS) $(GMOCK_LIBS) -lgmock_main + +check_PROGRAMS = +TESTS = $(check_PROGRAMS) + +check_PROGRAMS += tools_blob_unittest +tools_blob_unittest_SOURCES = tools_blob_unittest.cpp +tools_blob_unittest_CPPFLAGS = $(gtest_cppflags) +tools_blob_unittest_LDADD = $(gtest_ldadd) +tools_blob_unittest_LDADD += $(top_builddir)/src/ipmiblob/blob_handler.o + +check_PROGRAMS += tools_ipmi_unittest +tools_ipmi_unittest_SOURCES = tools_ipmi_unittest.cpp +tools_ipmi_unittest_CPPFLAGS = $(gtest_cppflags) +tools_ipmi_unittest_LDADD = $(gtest_ldadd) +tools_ipmi_unittest_LDADD += $(top_builddir)/src/ipmiblob/ipmi_handler.o + +check_PROGRAMS += tools_ipmi_error_unittest +tools_ipmi_error_unittest_SOURCES = tools_ipmi_error_unittest.cpp +tools_ipmi_error_unittest_CPPFLAGS = $(gtest_cppflags) +tools_ipmi_error_unittest_LDADD = $(gtest_ldadd) diff --git a/test/crc_mock.hpp b/test/crc_mock.hpp new file mode 100644 index 0000000..293ec24 --- /dev/null +++ b/test/crc_mock.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include <cstdint> +#include <vector> + +#include <gmock/gmock.h> + +class CrcInterface +{ + public: + virtual ~CrcInterface() = default; + + virtual std::uint16_t + generateCrc(const std::vector<std::uint8_t>& data) const = 0; +}; + +class CrcMock : public CrcInterface +{ + public: + virtual ~CrcMock() = default; + MOCK_CONST_METHOD1(generateCrc, + std::uint16_t(const std::vector<std::uint8_t>&)); +}; diff --git a/test/internal_sys_mock.hpp b/test/internal_sys_mock.hpp new file mode 100644 index 0000000..b4ba4b1 --- /dev/null +++ b/test/internal_sys_mock.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include <unistd.h> + +#include <ipmiblob/internal/sys.hpp> + +#include <gmock/gmock.h> + +namespace internal +{ + +class InternalSysMock : public Sys +{ + public: + virtual ~InternalSysMock() = default; + + MOCK_CONST_METHOD2(open, int(const char*, int)); + MOCK_CONST_METHOD3(read, int(int, void*, std::size_t)); + MOCK_CONST_METHOD1(close, int(int)); + MOCK_CONST_METHOD6(mmap, void*(void*, std::size_t, int, int, int, off_t)); + MOCK_CONST_METHOD2(munmap, int(void*, std::size_t)); + MOCK_CONST_METHOD0(getpagesize, int()); + MOCK_CONST_METHOD3(ioctl, int(int, unsigned long, void*)); + MOCK_CONST_METHOD3(poll, int(struct pollfd*, nfds_t, int)); +}; + +} // namespace internal diff --git a/test/tools_blob_unittest.cpp b/test/tools_blob_unittest.cpp new file mode 100644 index 0000000..f7f58c4 --- /dev/null +++ b/test/tools_blob_unittest.cpp @@ -0,0 +1,289 @@ +#include "crc_mock.hpp" + +#include <ipmiblob/blob_handler.hpp> +#include <ipmiblob/test/ipmi_interface_mock.hpp> + +#include <gtest/gtest.h> + +namespace host_tool +{ +CrcInterface* crcIntf = nullptr; + +std::uint16_t generateCrc(const std::vector<std::uint8_t>& data) +{ + return (crcIntf) ? crcIntf->generateCrc(data) : 0x00; +} + +using ::testing::Eq; +using ::testing::Return; + +class BlobHandlerTest : public ::testing::Test +{ + protected: + void SetUp() override + { + crcIntf = &crcMock; + } + + CrcMock crcMock; +}; + +TEST_F(BlobHandlerTest, getCountIpmiHappy) +{ + /* Verify returns the value specified by the IPMI response. */ + IpmiInterfaceMock ipmiMock; + BlobHandler blob(&ipmiMock); + std::vector<std::uint8_t> request = { + 0xcf, 0xc2, 0x00, BlobHandler::BlobOEMCommands::bmcBlobGetCount}; + + /* return 1 blob count. */ + std::vector<std::uint8_t> resp = {0xcf, 0xc2, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00}; + + std::vector<std::uint8_t> bytes = {0x01, 0x00, 0x00, 0x00}; + EXPECT_CALL(crcMock, generateCrc(Eq(bytes))).WillOnce(Return(0x00)); + + EXPECT_CALL(ipmiMock, sendPacket(Eq(request))).WillOnce(Return(resp)); + EXPECT_EQ(1, blob.getBlobCount()); +} + +TEST_F(BlobHandlerTest, enumerateBlobIpmiHappy) +{ + /* Verify returns the name specified by the IPMI response. */ + IpmiInterfaceMock ipmiMock; + BlobHandler blob(&ipmiMock); + std::vector<std::uint8_t> request = { + 0xcf, 0xc2, 0x00, BlobHandler::BlobOEMCommands::bmcBlobEnumerate, + 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00}; + + /* return value. */ + std::vector<std::uint8_t> resp = {0xcf, 0xc2, 0x00, 0x00, 0x00, + 'a', 'b', 'c', 'd', 0x00}; + + std::vector<std::uint8_t> bytes = {'a', 'b', 'c', 'd', 0x00}; + std::vector<std::uint8_t> reqCrc = {0x01, 0x00, 0x00, 0x00}; + EXPECT_CALL(crcMock, generateCrc(Eq(reqCrc))).WillOnce(Return(0x00)); + EXPECT_CALL(crcMock, generateCrc(Eq(bytes))).WillOnce(Return(0x00)); + + EXPECT_CALL(ipmiMock, sendPacket(Eq(request))).WillOnce(Return(resp)); + EXPECT_STREQ("abcd", blob.enumerateBlob(1).c_str()); +} + +TEST_F(BlobHandlerTest, enumerateBlobIpmiNoBytes) +{ + /* Simulate a case where the IPMI command returns no data. */ + IpmiInterfaceMock ipmiMock; + BlobHandler blob(&ipmiMock); + std::vector<std::uint8_t> request = { + 0xcf, 0xc2, 0x00, BlobHandler::BlobOEMCommands::bmcBlobEnumerate, + 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00}; + + /* return value. */ + std::vector<std::uint8_t> resp = {}; + + std::vector<std::uint8_t> reqCrc = {0x01, 0x00, 0x00, 0x00}; + EXPECT_CALL(crcMock, generateCrc(Eq(reqCrc))).WillOnce(Return(0x00)); + + EXPECT_CALL(ipmiMock, sendPacket(Eq(request))).WillOnce(Return(resp)); + EXPECT_STREQ("", blob.enumerateBlob(1).c_str()); +} + +TEST_F(BlobHandlerTest, getBlobListIpmiHappy) +{ + /* Verify returns the list built via the above two commands. */ + IpmiInterfaceMock ipmiMock; + BlobHandler blob(&ipmiMock); + + std::vector<std::uint8_t> request1 = { + 0xcf, 0xc2, 0x00, BlobHandler::BlobOEMCommands::bmcBlobGetCount}; + + /* return 1 blob count. */ + std::vector<std::uint8_t> resp1 = {0xcf, 0xc2, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00}; + + std::vector<std::uint8_t> bytes1 = {0x01, 0x00, 0x00, 0x00}; + EXPECT_CALL(crcMock, generateCrc(Eq(bytes1))).WillOnce(Return(0x00)); + + EXPECT_CALL(ipmiMock, sendPacket(Eq(request1))).WillOnce(Return(resp1)); + + std::vector<std::uint8_t> request2 = { + 0xcf, 0xc2, 0x00, BlobHandler::BlobOEMCommands::bmcBlobEnumerate, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00}; + + /* return value. */ + std::vector<std::uint8_t> resp2 = {0xcf, 0xc2, 0x00, 0x00, 0x00, + 'a', 'b', 'c', 'd', 0x00}; + + std::vector<std::uint8_t> reqCrc = {0x00, 0x00, 0x00, 0x00}; + std::vector<std::uint8_t> bytes2 = {'a', 'b', 'c', 'd', 0x00}; + EXPECT_CALL(crcMock, generateCrc(Eq(reqCrc))).WillOnce(Return(0x00)); + EXPECT_CALL(crcMock, generateCrc(Eq(bytes2))).WillOnce(Return(0x00)); + + EXPECT_CALL(ipmiMock, sendPacket(Eq(request2))).WillOnce(Return(resp2)); + + /* A std::string is not nul-terminated by default. */ + std::vector<std::string> expectedList = {std::string{"abcd"}}; + + EXPECT_EQ(expectedList, blob.getBlobList()); +} + +TEST_F(BlobHandlerTest, getStatWithMetadata) +{ + /* Stat received metadata. */ + IpmiInterfaceMock ipmiMock; + BlobHandler blob(&ipmiMock); + std::vector<std::uint8_t> request = { + 0xcf, 0xc2, 0x00, BlobHandler::BlobOEMCommands::bmcBlobStat, + 0x00, 0x00, 'a', 'b', + 'c', 'd', 0x00}; + + /* return blob_state: 0xffff, size: 0x00, metadata 0x3445 */ + std::vector<std::uint8_t> resp = {0xcf, 0xc2, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x34, 0x45}; + + std::vector<std::uint8_t> reqCrc = {'a', 'b', 'c', 'd', 0x00}; + std::vector<std::uint8_t> respCrc = {0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x34, 0x45}; + EXPECT_CALL(crcMock, generateCrc(Eq(reqCrc))).WillOnce(Return(0x00)); + EXPECT_CALL(crcMock, generateCrc(Eq(respCrc))).WillOnce(Return(0x00)); + + EXPECT_CALL(ipmiMock, sendPacket(Eq(request))).WillOnce(Return(resp)); + + auto meta = blob.getStat("abcd"); + EXPECT_EQ(meta.blob_state, 0xffff); + EXPECT_EQ(meta.size, 0x00); + std::vector<std::uint8_t> metadata = {0x34, 0x45}; + EXPECT_EQ(metadata, meta.metadata); +} + +TEST_F(BlobHandlerTest, getStatNoMetadata) +{ + /* Stat received no metadata. */ + IpmiInterfaceMock ipmiMock; + BlobHandler blob(&ipmiMock); + std::vector<std::uint8_t> request = { + 0xcf, 0xc2, 0x00, BlobHandler::BlobOEMCommands::bmcBlobStat, + 0x00, 0x00, 'a', 'b', + 'c', 'd', 0x00}; + + /* return blob_state: 0xffff, size: 0x00, metadata 0x3445 */ + std::vector<std::uint8_t> resp = {0xcf, 0xc2, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00}; + + std::vector<std::uint8_t> reqCrc = {'a', 'b', 'c', 'd', 0x00}; + std::vector<std::uint8_t> respCrc = {0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00}; + + EXPECT_CALL(crcMock, generateCrc(Eq(reqCrc))).WillOnce(Return(0x00)); + EXPECT_CALL(crcMock, generateCrc(Eq(respCrc))).WillOnce(Return(0x00)); + + EXPECT_CALL(ipmiMock, sendPacket(Eq(request))).WillOnce(Return(resp)); + + auto meta = blob.getStat("abcd"); + EXPECT_EQ(meta.blob_state, 0xffff); + EXPECT_EQ(meta.size, 0x00); + std::vector<std::uint8_t> metadata = {}; + EXPECT_EQ(metadata, meta.metadata); +} + +TEST_F(BlobHandlerTest, openBlobSucceeds) +{ + /* The open blob succeeds. */ + IpmiInterfaceMock ipmiMock; + BlobHandler blob(&ipmiMock); + + std::vector<std::uint8_t> request = { + 0xcf, 0xc2, 0x00, BlobHandler::BlobOEMCommands::bmcBlobOpen, + 0x00, 0x00, 0x02, 0x04, + 'a', 'b', 'c', 'd', + 0x00}; + + std::vector<std::uint8_t> resp = {0xcf, 0xc2, 0x00, 0x00, 0x00, 0xfe, 0xed}; + + std::vector<std::uint8_t> reqCrc = {0x02, 0x04, 'a', 'b', 'c', 'd', 0x00}; + std::vector<std::uint8_t> respCrc = {0xfe, 0xed}; + EXPECT_CALL(crcMock, generateCrc(Eq(reqCrc))).WillOnce(Return(0x00)); + EXPECT_CALL(crcMock, generateCrc(Eq(respCrc))).WillOnce(Return(0x00)); + + EXPECT_CALL(ipmiMock, sendPacket(Eq(request))).WillOnce(Return(resp)); + + const int writeBit = (1 << 1); + const int lpcBit = (1 << 10); + + auto session = blob.openBlob("abcd", writeBit | lpcBit); + EXPECT_EQ(0xedfe, session); +} + +TEST_F(BlobHandlerTest, closeBlobSucceeds) +{ + /* The close succeeds. */ + IpmiInterfaceMock ipmiMock; + BlobHandler blob(&ipmiMock); + + std::vector<std::uint8_t> request = { + 0xcf, 0xc2, 0x00, BlobHandler::BlobOEMCommands::bmcBlobClose, + 0x00, 0x00, 0x01, 0x00}; + std::vector<std::uint8_t> resp = {0xcf, 0xc2, 0x00}; + std::vector<std::uint8_t> reqCrc = {0x01, 0x00}; + EXPECT_CALL(crcMock, generateCrc(Eq(reqCrc))).WillOnce(Return(0x00)); + + EXPECT_CALL(ipmiMock, sendPacket(Eq(request))).WillOnce(Return(resp)); + + blob.closeBlob(0x0001); +} + +TEST_F(BlobHandlerTest, writeBytesSucceeds) +{ + /* The write bytes succeeds. */ + IpmiInterfaceMock ipmiMock; + BlobHandler blob(&ipmiMock); + + std::vector<std::uint8_t> request = { + 0xcf, 0xc2, 0x00, BlobHandler::BlobOEMCommands::bmcBlobWrite, + 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, + 'a', 'b', 'c', 'd'}; + + std::vector<std::uint8_t> bytes = {'a', 'b', 'c', 'd'}; + std::vector<std::uint8_t> resp = {0xcf, 0xc2, 0x00}; + std::vector<std::uint8_t> reqCrc = {0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 'a', 'b', 'c', 'd'}; + EXPECT_CALL(crcMock, generateCrc(Eq(reqCrc))).WillOnce(Return(0x00)); + + EXPECT_CALL(ipmiMock, sendPacket(Eq(request))).WillOnce(Return(resp)); + + blob.writeBytes(0x0001, 0, bytes); +} + +TEST_F(BlobHandlerTest, readBytesSucceeds) +{ + /* The reading of bytes succeeds. */ + + IpmiInterfaceMock ipmiMock; + BlobHandler blob(&ipmiMock); + + std::vector<std::uint8_t> request = { + 0xcf, 0xc2, 0x00, BlobHandler::BlobOEMCommands::bmcBlobRead, + 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00}; + + std::vector<std::uint8_t> expectedBytes = {'a', 'b', 'c', 'd'}; + std::vector<std::uint8_t> resp = {0xcf, 0xc2, 0x00, 0x00, 0x00, + 'a', 'b', 'c', 'd'}; + std::vector<std::uint8_t> reqCrc = {0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00}; + std::vector<std::uint8_t> respCrc = {'a', 'b', 'c', 'd'}; + + EXPECT_CALL(crcMock, generateCrc(Eq(reqCrc))).WillOnce(Return(0x00)); + EXPECT_CALL(crcMock, generateCrc(Eq(respCrc))).WillOnce(Return(0x00)); + + EXPECT_CALL(ipmiMock, sendPacket(Eq(request))).WillOnce(Return(resp)); + + EXPECT_EQ(blob.readBytes(0x0001, 0, 4), expectedBytes); +} + +} // namespace host_tool diff --git a/test/tools_ipmi_error_unittest.cpp b/test/tools_ipmi_error_unittest.cpp new file mode 100644 index 0000000..05048e2 --- /dev/null +++ b/test/tools_ipmi_error_unittest.cpp @@ -0,0 +1,28 @@ +#include <ipmiblob/ipmi_errors.hpp> + +#include <gtest/gtest.h> + +namespace host_tool +{ + +TEST(IpmiExceptionTest, VerifyTimedOutIsString) +{ + /* Verify that throwing the exception with the cc code for timed out gets + * converted to the human readable string. + */ + bool verified = false; + + try + { + throw IpmiException(0xc3); + } + catch (const IpmiException& i) + { + EXPECT_STREQ("Received IPMI_CC: timeout", i.what()); + verified = true; + } + + EXPECT_TRUE(verified); +} + +} // namespace host_tool diff --git a/test/tools_ipmi_unittest.cpp b/test/tools_ipmi_unittest.cpp new file mode 100644 index 0000000..9516d46 --- /dev/null +++ b/test/tools_ipmi_unittest.cpp @@ -0,0 +1,22 @@ +#include "internal_sys_mock.hpp" + +#include <ipmiblob/ipmi_errors.hpp> +#include <ipmiblob/ipmi_handler.hpp> + +namespace host_tool +{ + +using ::testing::_; +using ::testing::Return; + +TEST(IpmiHandlerTest, OpenAllFails) +{ + /* Open against all device files fail. */ + internal::InternalSysMock sysMock; + IpmiHandler ipmi(&sysMock); + + EXPECT_CALL(sysMock, open(_, _)).WillRepeatedly(Return(-1)); + EXPECT_THROW(ipmi.open(), IpmiException); +} + +} // namespace host_tool |