summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile.am2
-rw-r--r--tools/test/Makefile.am32
-rw-r--r--tools/test/data_interface_mock.hpp21
-rw-r--r--tools/test/internal_sys_mock.hpp27
-rw-r--r--tools/test/io_mock.hpp21
-rw-r--r--tools/test/tools_bt_unittest.cpp48
-rw-r--r--tools/test/tools_lpc_unittest.cpp37
-rw-r--r--tools/test/tools_updater_unittest.cpp142
-rw-r--r--tools/test/updater_mock.hpp20
9 files changed, 350 insertions, 0 deletions
diff --git a/tools/Makefile.am b/tools/Makefile.am
index f8879b0..c85ffeb 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -16,3 +16,5 @@ libupdater_la_SOURCES = \
pci.cpp \
p2a.cpp \
$(top_srcdir)/internal/sys.cpp
+
+SUBDIRS = . test
diff --git a/tools/test/Makefile.am b/tools/test/Makefile.am
new file mode 100644
index 0000000..26de6c5
--- /dev/null
+++ b/tools/test/Makefile.am
@@ -0,0 +1,32 @@
+@VALGRIND_CHECK_RULES@
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/ \
+ -I$(top_srcdir)/tools/ \
+ $(GTEST_CFLAGS) \
+ $(GMOCK_CFLAGS) \
+ $(CODE_COVERAGE_CPPFLAGS)
+AM_CXXFLAGS = \
+ $(CODE_COVERAGE_CXXFLAGS)
+AM_LDFLAGS = \
+ $(GTEST_LIBS) \
+ $(GMOCK_LIBS) \
+ -lgmock_main \
+ $(OESDK_TESTCASE_FLAGS) \
+ $(CODE_COVERAGE_LIBS)
+
+check_PROGRAMS = \
+ tools_bt_unittest \
+ tools_lpc_unittest \
+ tools_updater_unittest
+
+TESTS = $(check_PROGRAMS)
+
+tools_bt_unittest_SOURCES = tools_bt_unittest.cpp
+tools_bt_unittest_LDADD = $(top_builddir)/tools/libupdater.la
+
+tools_lpc_unittest_SOURCES = tools_lpc_unittest.cpp
+tools_lpc_unittest_LDADD = $(top_builddir)/tools/libupdater.la
+
+tools_updater_unittest_SOURCES = tools_updater_unittest.cpp
+tools_updater_unittest_LDADD = $(top_builddir)/tools/libupdater.la
diff --git a/tools/test/data_interface_mock.hpp b/tools/test/data_interface_mock.hpp
new file mode 100644
index 0000000..3189e5b
--- /dev/null
+++ b/tools/test/data_interface_mock.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "interface.hpp"
+
+#include <gmock/gmock.h>
+
+namespace host_tool
+{
+
+class DataInterfaceMock : public DataInterface
+{
+
+ public:
+ virtual ~DataInterfaceMock() = default;
+
+ MOCK_METHOD2(sendContents, bool(const std::string&, std::uint16_t));
+ MOCK_CONST_METHOD0(supportedType,
+ ipmi_flash::FirmwareBlobHandler::UpdateFlags());
+};
+
+} // namespace host_tool
diff --git a/tools/test/internal_sys_mock.hpp b/tools/test/internal_sys_mock.hpp
new file mode 100644
index 0000000..fc98561
--- /dev/null
+++ b/tools/test/internal_sys_mock.hpp
@@ -0,0 +1,27 @@
+#pragma once
+
+#include "internal/sys.hpp"
+
+#include <unistd.h>
+
+#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/tools/test/io_mock.hpp b/tools/test/io_mock.hpp
new file mode 100644
index 0000000..4d18204
--- /dev/null
+++ b/tools/test/io_mock.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "io.hpp"
+
+#include <gmock/gmock.h>
+
+namespace host_tool
+{
+
+class HostIoInterfaceMock : public HostIoInterface
+{
+ public:
+ ~HostIoInterfaceMock() = default;
+
+ MOCK_METHOD3(read, bool(const std::size_t, const std::size_t, void* const));
+
+ MOCK_METHOD3(write,
+ bool(const std::size_t, const std::size_t, const void* const));
+};
+
+} // namespace host_tool
diff --git a/tools/test/tools_bt_unittest.cpp b/tools/test/tools_bt_unittest.cpp
new file mode 100644
index 0000000..1a364d3
--- /dev/null
+++ b/tools/test/tools_bt_unittest.cpp
@@ -0,0 +1,48 @@
+#include "bt.hpp"
+#include "internal_sys_mock.hpp"
+
+#include <cstring>
+#include <ipmiblob/test/blob_interface_mock.hpp>
+
+#include <gtest/gtest.h>
+
+namespace host_tool
+{
+
+using ::testing::_;
+using ::testing::ContainerEq;
+using ::testing::Eq;
+using ::testing::Invoke;
+using ::testing::NotNull;
+using ::testing::Return;
+
+TEST(BtHandlerTest, verifySendsFileContents)
+{
+ /* In this very basic test, we'll feed the bt handler data from the internal
+ * syscall mock and catch the writes via the blob mock.
+ */
+ internal::InternalSysMock sysMock;
+ ipmiblob::BlobInterfaceMock blobMock;
+
+ BtDataHandler handler(&blobMock, &sysMock);
+ std::string filePath = "/asdf";
+ int fd = 1;
+ std::uint16_t session = 0xbeef;
+ std::vector<std::uint8_t> bytes = {'1', '2', '3', '4'};
+
+ EXPECT_CALL(sysMock, open(Eq(filePath), _)).WillOnce(Return(fd));
+ EXPECT_CALL(sysMock, read(fd, NotNull(), _))
+ .WillOnce(Invoke([&](int fd, void* buf, std::size_t count) {
+ EXPECT_TRUE(count > bytes.size());
+ std::memcpy(buf, bytes.data(), bytes.size());
+ return bytes.size();
+ }))
+ .WillOnce(Return(0));
+ EXPECT_CALL(sysMock, close(fd)).WillOnce(Return(0));
+
+ EXPECT_CALL(blobMock, writeBytes(session, 0, ContainerEq(bytes)));
+
+ EXPECT_TRUE(handler.sendContents(filePath, session));
+}
+
+} // namespace host_tool
diff --git a/tools/test/tools_lpc_unittest.cpp b/tools/test/tools_lpc_unittest.cpp
new file mode 100644
index 0000000..1645ea5
--- /dev/null
+++ b/tools/test/tools_lpc_unittest.cpp
@@ -0,0 +1,37 @@
+#include "internal_sys_mock.hpp"
+#include "io_mock.hpp"
+#include "lpc.hpp"
+
+#include <cstring>
+#include <ipmiblob/test/blob_interface_mock.hpp>
+
+#include <gtest/gtest.h>
+
+namespace host_tool
+{
+
+using ::testing::ContainerEq;
+
+TEST(LpcHandleTest, verifySendsFileContents)
+{
+ internal::InternalSysMock sysMock;
+ ipmiblob::BlobInterfaceMock blobMock;
+ HostIoInterfaceMock ioMock;
+
+ LpcDataHandler handler(&blobMock, &ioMock, &sysMock);
+ std::uint16_t session = 0xbeef;
+ std::string filePath = "/asdf";
+
+ LpcRegion host_lpc_buf;
+ host_lpc_buf.address = 0xfedc1000;
+ host_lpc_buf.length = 0x1000;
+
+ std::vector<std::uint8_t> bytes(sizeof(host_lpc_buf));
+ std::memcpy(bytes.data(), &host_lpc_buf, sizeof(host_lpc_buf));
+
+ EXPECT_CALL(blobMock, writeMeta(session, 0, ContainerEq(bytes)));
+
+ EXPECT_FALSE(handler.sendContents(filePath, session));
+}
+
+} // namespace host_tool
diff --git a/tools/test/tools_updater_unittest.cpp b/tools/test/tools_updater_unittest.cpp
new file mode 100644
index 0000000..cacf2b0
--- /dev/null
+++ b/tools/test/tools_updater_unittest.cpp
@@ -0,0 +1,142 @@
+#include "data_interface_mock.hpp"
+#include "updater.hpp"
+#include "updater_mock.hpp"
+#include "util.hpp"
+
+#include <blobs-ipmid/blobs.hpp>
+#include <ipmiblob/test/blob_interface_mock.hpp>
+#include <string>
+
+#include <gtest/gtest.h>
+
+namespace host_tool
+{
+
+using ::testing::_;
+using ::testing::Eq;
+using ::testing::Return;
+using ::testing::StrEq;
+using ::testing::TypedEq;
+
+TEST(UpdaterTest, CheckAvailableSuccess)
+{
+ /* Call checkAvailable directly() to make sure it works. */
+ DataInterfaceMock handlerMock;
+ ipmiblob::BlobInterfaceMock blobMock;
+
+ ipmiblob::StatResponse statObj;
+ statObj.blob_state = ipmi_flash::FirmwareBlobHandler::UpdateFlags::ipmi |
+ ipmi_flash::FirmwareBlobHandler::UpdateFlags::lpc;
+ statObj.size = 0;
+
+ EXPECT_CALL(blobMock, getBlobList())
+ .WillOnce(
+ Return(std::vector<std::string>({ipmi_flash::staticLayoutBlobId})));
+ EXPECT_CALL(blobMock, getStat(TypedEq<const std::string&>(
+ ipmi_flash::staticLayoutBlobId)))
+ .WillOnce(Return(statObj));
+
+ EXPECT_CALL(handlerMock, supportedType())
+ .WillOnce(Return(ipmi_flash::FirmwareBlobHandler::UpdateFlags::lpc));
+
+ UpdateHandler updater(&blobMock, &handlerMock);
+ EXPECT_TRUE(updater.checkAvailable(ipmi_flash::staticLayoutBlobId));
+}
+
+TEST(UpdaterTest, SendFileSuccess)
+{
+ /* Call sendFile to verify it does what we expect. */
+ DataInterfaceMock handlerMock;
+ ipmiblob::BlobInterfaceMock blobMock;
+
+ std::string firmwareImage = "image.bin";
+
+ std::uint16_t supported =
+ static_cast<std::uint16_t>(
+ ipmi_flash::FirmwareBlobHandler::UpdateFlags::lpc) |
+ static_cast<std::uint16_t>(blobs::OpenFlags::write);
+ std::uint16_t session = 0xbeef;
+
+ EXPECT_CALL(handlerMock, supportedType())
+ .WillOnce(Return(ipmi_flash::FirmwareBlobHandler::UpdateFlags::lpc));
+
+ EXPECT_CALL(
+ blobMock,
+ openBlob(StrEq(ipmi_flash::staticLayoutBlobId.c_str()), supported))
+ .WillOnce(Return(session));
+
+ EXPECT_CALL(handlerMock,
+ sendContents(StrEq(firmwareImage.c_str()), session))
+ .WillOnce(Return(true));
+
+ EXPECT_CALL(blobMock, closeBlob(session)).Times(1);
+
+ UpdateHandler updater(&blobMock, &handlerMock);
+ updater.sendFile(ipmi_flash::staticLayoutBlobId, firmwareImage);
+}
+
+#if 0 /* TODO: fix this up. */
+TEST(UpdaterTest, NormalWalkthroughAllHappy)
+{
+ /* Call updaterMain and have everything respond happily. */
+ DataInterfaceMock handlerMock;
+ ipmiblob::BlobInterfaceMock blobMock;
+
+ UpdateHandlerMock updaterMock;
+
+ std::string firmwareImage = "image.bin";
+ std::string signatureFile = "image.sig";
+
+ std::vector<std::string> blobList = {ipmi_flash::staticLayoutBlobId};
+ ipmiblob::StatResponse statObj;
+ statObj.blob_state = ipmi_flash::FirmwareBlobHandler::UpdateFlags::ipmi |
+ ipmi_flash::FirmwareBlobHandler::UpdateFlags::lpc;
+ statObj.size = 0;
+ std::uint16_t supported =
+ static_cast<std::uint16_t>(
+ ipmi_flash::FirmwareBlobHandler::UpdateFlags::lpc) |
+ static_cast<std::uint16_t>(blobs::OpenFlags::write);
+ std::uint16_t session = 0xbeef;
+
+ EXPECT_CALL(blobMock, getBlobList()).WillOnce(Return(blobList));
+
+ EXPECT_CALL(blobMock, getStat(TypedEq<const std::string&>(ipmi_flash::staticLayoutBlobId)))
+ .WillOnce(Return(statObj));
+
+ EXPECT_CALL(handlerMock, supportedType())
+ .WillOnce(Return(ipmi_flash::FirmwareBlobHandler::UpdateFlags::lpc));
+
+ EXPECT_CALL(blobMock, openBlob(StrEq(ipmi_flash::staticLayoutBlobId.c_str()), Eq(supported)))
+ .WillOnce(Return(session));
+
+ EXPECT_CALL(handlerMock,
+ sendContents(StrEq(firmwareImage.c_str()), Eq(session)))
+ .WillOnce(Return(true));
+
+ EXPECT_CALL(blobMock, openBlob(StrEq(blobs::hashBlobId.c_str()), Eq(supported)))
+ .WillOnce(Return(session));
+
+ EXPECT_CALL(handlerMock,
+ sendContents(StrEq(signatureFile.c_str()), Eq(session)))
+ .WillOnce(Return(true));
+
+ EXPECT_CALL(blobMock,
+ openBlob(StrEq(blobs::verifyBlobId.c_str()), Eq(supported)))
+ .WillOnce(Return(session));
+
+ EXPECT_CALL(blobMock, commit(session, _)).WillOnce(Return());
+
+ ipmiblob::StatResponse verificationResponse;
+ verificationResponse.blob_state = supported | blobs::StateFlags::committing;
+ verificationResponse.size = 0;
+ verificationResponse.metadata.push_back(static_cast<std::uint8_t>(
+ ipmi_flash::FirmwareBlobHandler::ActionStatus::success));
+
+ EXPECT_CALL(blobMock, getStat(TypedEq<std::uint16_t>(session)))
+ .WillOnce(Return(verificationResponse));
+
+ updaterMain(&blobMock, &handlerMock, firmwareImage, signatureFile);
+}
+#endif
+
+} // namespace host_tool
diff --git a/tools/test/updater_mock.hpp b/tools/test/updater_mock.hpp
new file mode 100644
index 0000000..d065219
--- /dev/null
+++ b/tools/test/updater_mock.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "updater.hpp"
+
+#include <string>
+
+#include <gmock/gmock.h>
+
+namespace host_tool
+{
+
+class UpdateHandlerMock : public UpdateHandler
+{
+ public:
+ MOCK_METHOD1(checkAvailable, bool(const std::string&));
+ MOCK_METHOD2(sendFile, void(const std::string&, const std::string&));
+ MOCK_METHOD1(verifyFile, bool(const std::string&));
+};
+
+} // namespace host_tool
OpenPOWER on IntegriCloud