tools: implement lpc support

Tested: Verified this works for a Nuvoton BMC.

EXTRA_OECONF_append_xxx = " \
  --enable-static-layout \
  --enable-lpc-bridge \
  --enable-nuvoton-lpc \
  --enable-reboot-update \
  MAPPED_ADDRESS=0xc0008000 \
  "

/tmp/phosphor_ipmi_flash_tool \
 --command update \
 --interface ipmilpc \
 --image image-bmc \
 --sig image-bmc.sig \
 --type static \
 --address 0xfedc1000 \
 --length 0x1000
Sending over the firmware image.
trying to open blob
sending writeMeta
caught exception
EFBIG returned!
sending writeMeta
writemeta sent
Sending over the hash file.
trying to open blob
sending writeMeta
caught exception
EFBIG returned!
sending writeMeta
writemeta sent
Opening the verification file
Committing to /flash/verify to trigger service
Calling stat on /flash/verify session to check status
other
success
Returned success
succeeded
Opening the update file
Committing to /flash/update to trigger service
Calling stat on /flash/update session to check status
running
Opening the cleanup blob
Exception received: blob exception received: Received IPMI_CC: 255

Signed-off-by: Patrick Venture <venture@google.com>
Change-Id: If866303e95e9b6a19dc8b20a99bb89fd66f95eeb
diff --git a/tools/test/tools_lpc_unittest.cpp b/tools/test/tools_lpc_unittest.cpp
index ef8e93e..84a81eb 100644
--- a/tools/test/tools_lpc_unittest.cpp
+++ b/tools/test/tools_lpc_unittest.cpp
@@ -10,7 +10,13 @@
 namespace host_tool
 {
 
+using ::testing::_;
 using ::testing::ContainerEq;
+using ::testing::Gt;
+using ::testing::Invoke;
+using ::testing::NotNull;
+using ::testing::Return;
+using ::testing::StrEq;
 
 TEST(LpcHandleTest, verifySendsFileContents)
 {
@@ -18,20 +24,46 @@
     ipmiblob::BlobInterfaceMock blobMock;
     HostIoInterfaceMock ioMock;
 
-    LpcDataHandler handler(&blobMock, &ioMock, 0xfedc1000, 0x1000, &sysMock);
+    const std::uint32_t address = 0xfedc1000;
+    const std::uint32_t length = 0x1000;
+
+    LpcDataHandler handler(&blobMock, &ioMock, address, length, &sysMock);
     std::uint16_t session = 0xbeef;
     std::string filePath = "/asdf";
+    int fileDescriptor = 5;
 
     LpcRegion host_lpc_buf;
-    host_lpc_buf.address = 0xfedc1000;
-    host_lpc_buf.length = 0x1000;
+    host_lpc_buf.address = address;
+    host_lpc_buf.length = length;
 
     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));
+    std::vector<std::uint8_t> data = {0x01, 0x02, 0x03};
+
+    EXPECT_CALL(sysMock, open(StrEq(filePath.c_str()), _))
+        .WillOnce(Return(fileDescriptor));
+    EXPECT_CALL(sysMock, read(_, NotNull(), Gt(data.size())))
+        .WillOnce(Invoke([&data](int, void* buf, std::size_t) {
+            std::memcpy(buf, data.data(), data.size());
+            return data.size();
+        }))
+        .WillOnce(Return(0));
+
+    EXPECT_CALL(ioMock, write(_, data.size(), _))
+        .WillOnce(Invoke([&data](const std::size_t, const std::size_t length,
+                                 const void* const source) {
+            EXPECT_THAT(std::memcmp(source, data.data(), data.size()), 0);
+            return true;
+        }));
+
+    EXPECT_CALL(blobMock, writeBytes(session, 0, _));
+
+    EXPECT_CALL(sysMock, close(fileDescriptor)).WillOnce(Return(0));
+
+    EXPECT_TRUE(handler.sendContents(filePath, session));
 }
 
 } // namespace host_tool