test: cleanup by moving tool tests into subfolder

Signed-off-by: Patrick Venture <venture@google.com>
Change-Id: I15b3514d095d9fc770a1b0fe125eb48d96ada2c8
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 @@
 	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