implement session stat command

Implement the session stat command.

Change-Id: I1ff715dd32d963722182db84b475bc9adbfcc7ea
Signed-off-by: Patrick Venture <venture@google.com>
diff --git a/src/ipmiblob/blob_handler.cpp b/src/ipmiblob/blob_handler.cpp
index 74ecd02..0d31b3f 100644
--- a/src/ipmiblob/blob_handler.cpp
+++ b/src/ipmiblob/blob_handler.cpp
@@ -242,6 +242,37 @@
     return meta;
 }
 
+StatResponse BlobHandler::getStat(std::uint16_t session)
+{
+    StatResponse meta;
+    std::vector<std::uint8_t> resp;
+    std::vector<std::uint8_t> request;
+    auto addrSession = reinterpret_cast<const std::uint8_t*>(&session);
+    std::copy(addrSession, addrSession + sizeof(session),
+              std::back_inserter(request));
+
+    try
+    {
+        resp = sendIpmiPayload(BlobOEMCommands::bmcBlobSessionStat, request);
+    }
+    catch (const BlobException& b)
+    {
+        throw;
+    }
+
+    std::memcpy(&meta.blob_state, &resp[0], sizeof(meta.blob_state));
+    std::memcpy(&meta.size, &resp[sizeof(meta.blob_state)], sizeof(meta.size));
+    int offset = sizeof(meta.blob_state) + sizeof(meta.size);
+    std::uint8_t len = resp[offset];
+    if (len > 0)
+    {
+        std::copy(&resp[offset + 1], &resp[resp.size()],
+                  std::back_inserter(meta.metadata));
+    }
+
+    return meta;
+}
+
 std::uint16_t BlobHandler::openBlob(const std::string& id,
                                     std::uint16_t handlerFlags)
 {
diff --git a/src/ipmiblob/blob_handler.hpp b/src/ipmiblob/blob_handler.hpp
index 22ad5f5..a663b63 100644
--- a/src/ipmiblob/blob_handler.hpp
+++ b/src/ipmiblob/blob_handler.hpp
@@ -63,6 +63,11 @@
     /**
      * @throws BlobException.
      */
+    StatResponse getStat(std::uint16_t session) override;
+
+    /**
+     * @throws BlobException.
+     */
     std::uint16_t openBlob(const std::string& id,
                            std::uint16_t handlerFlags) override;
 
diff --git a/src/ipmiblob/blob_interface.hpp b/src/ipmiblob/blob_interface.hpp
index 5d311ee..ece5c34 100644
--- a/src/ipmiblob/blob_interface.hpp
+++ b/src/ipmiblob/blob_interface.hpp
@@ -57,6 +57,14 @@
     virtual StatResponse getStat(const std::string& id) = 0;
 
     /**
+     * Get the stat() on the blob session.
+     *
+     * @param[in] session - the blob session
+     * @return metadata structure
+     */
+    virtual StatResponse getStat(std::uint16_t session) = 0;
+
+    /**
      * Attempt to open the file using the specific data interface flag.
      *
      * @param[in] blob - the blob_id to open.
diff --git a/src/ipmiblob/test/blob_interface_mock.hpp b/src/ipmiblob/test/blob_interface_mock.hpp
index 97f37df..0faa6fe 100644
--- a/src/ipmiblob/test/blob_interface_mock.hpp
+++ b/src/ipmiblob/test/blob_interface_mock.hpp
@@ -15,6 +15,7 @@
                                   const std::vector<std::uint8_t>&));
     MOCK_METHOD0(getBlobList, std::vector<std::string>());
     MOCK_METHOD1(getStat, StatResponse(const std::string&));
+    MOCK_METHOD1(getStat, StatResponse(std::uint16_t));
     MOCK_METHOD2(openBlob, std::uint16_t(const std::string&, std::uint16_t));
     MOCK_METHOD1(closeBlob, void(std::uint16_t));
     MOCK_METHOD3(readBytes,
diff --git a/test/tools_blob_unittest.cpp b/test/tools_blob_unittest.cpp
index e958630..74614a7 100644
--- a/test/tools_blob_unittest.cpp
+++ b/test/tools_blob_unittest.cpp
@@ -188,6 +188,36 @@
     EXPECT_EQ(metadata, meta.metadata);
 }
 
+TEST_F(BlobHandlerTest, getSessionStatNoMetadata)
+{
+    /* The get session stat succeeds. */
+    IpmiInterfaceMock ipmiMock;
+    BlobHandler blob(&ipmiMock);
+
+    std::vector<std::uint8_t> request = {
+        0xcf, 0xc2, 0x00, BlobHandler::BlobOEMCommands::bmcBlobSessionStat,
+        0x00, 0x00, 0x01, 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 = {0x01, 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(0x0001);
+    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. */