firmware: add handler for static layout

Add static layout handler.

Change-Id: I5c4cfe9782d59d32b16556e1d82b468c119eeb76
Signed-off-by: Patrick Venture <venture@google.com>
diff --git a/Makefile.am b/Makefile.am
index 1b469cc..f990788 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3,7 +3,8 @@
 libfirmwareblobdir = ${libdir}/ipmid-providers
 libfirmwareblob_LTLIBRARIES = libfirmwareblob.la
 libfirmwareblob_la_SOURCES = main.cpp \
-		      firmware_handler.cpp
+		      firmware_handler.cpp \
+		      static_handler.cpp
 libfirmwareblob_la_LDFLAGS = $(PHOSPHOR_LOGGING_LIBS) \
                         -version-info 0:0:0 -shared
 libfirmwareblob_la_CXXFLAGS = $(PHOSPHOR_LOGGING_CFLAGS) \
diff --git a/firmware_handler.cpp b/firmware_handler.cpp
index eccac73..21556e1 100644
--- a/firmware_handler.cpp
+++ b/firmware_handler.cpp
@@ -1,5 +1,7 @@
 #include "firmware_handler.hpp"
 
+#include "image_handler.hpp"
+
 #include <algorithm>
 #include <cstdint>
 #include <memory>
@@ -16,7 +18,7 @@
 
 std::unique_ptr<GenericBlobInterface>
     FirmwareBlobHandler::CreateFirmwareBlobHandler(
-        const std::vector<std::string>& firmwares, std::uint16_t transports)
+        const std::vector<HandlerPack>& firmwares, std::uint16_t transports)
 {
     /* There must be at least one. */
     if (!firmwares.size())
@@ -24,10 +26,14 @@
         return nullptr;
     }
 
-    std::vector<std::string> blobs = firmwares;
+    std::vector<std::string> blobs;
+    for (const auto& item : firmwares)
+    {
+        blobs.push_back(item.blobName);
+    }
     blobs.push_back(hashBlobID);
 
-    return std::make_unique<FirmwareBlobHandler>(blobs, transports);
+    return std::make_unique<FirmwareBlobHandler>(firmwares, blobs, transports);
 }
 
 bool FirmwareBlobHandler::canHandleBlob(const std::string& path)
@@ -168,6 +174,20 @@
          */
         /* 2e) are they opening the /flash/image ? (to start the process) */
         /* 2...) are they opening the /flash/... ? (to start the process) */
+
+        auto h = std::find_if(
+            handlers.begin(), handlers.end(),
+            [&path](const auto& iter) { return (iter.blobName == path); });
+        if (h != handlers.end())
+        {
+            /* Ok, so we found a handler that matched, so call open() */
+            if (h->handler->open(path))
+            {
+                /* open() succeeded. */
+            }
+        }
+
+        /* TODO: Actually handle storing this information. */
     }
 
     return false;
diff --git a/firmware_handler.hpp b/firmware_handler.hpp
index 18b04fc..1a9e8b0 100644
--- a/firmware_handler.hpp
+++ b/firmware_handler.hpp
@@ -1,5 +1,7 @@
 #pragma once
 
+#include "image_handler.hpp"
+
 #include <blobs-ipmid/blobs.hpp>
 #include <cstdint>
 #include <memory>
@@ -29,19 +31,20 @@
      * @param[in] transports - bitmask of transports to support.
      */
     static std::unique_ptr<GenericBlobInterface>
-        CreateFirmwareBlobHandler(const std::vector<std::string>& firmwares,
+        CreateFirmwareBlobHandler(const std::vector<HandlerPack>& firmwares,
                                   std::uint16_t transports);
 
     /**
      * Create a FirmwareBlobHandler.
      *
-     * @param[in] blobs - list of blobs_ids to support.
+     * @param[in] blobs - list of blobs_ids to support and their image handlers.
      * @param[in] transports - bitmask of transports to support.
      */
-    FirmwareBlobHandler(const std::vector<std::string>& blobs,
+    FirmwareBlobHandler(const std::vector<HandlerPack>& firmwares,
+                        const std::vector<std::string>& blobs,
                         std::uint16_t transports) :
-        blobIDs(blobs),
-        transports(transports)
+        handlers(firmwares),
+        blobIDs(blobs), transports(transports)
     {
     }
     ~FirmwareBlobHandler() = default;
@@ -72,6 +75,9 @@
     static const std::string activeHashBlobID;
 
   private:
+    /** List of handlers by type. */
+    std::vector<HandlerPack> handlers;
+
     /** Active list of blobIDs. */
     std::vector<std::string> blobIDs;
 
diff --git a/image_handler.hpp b/image_handler.hpp
index e4589f5..f09e7a2 100644
--- a/image_handler.hpp
+++ b/image_handler.hpp
@@ -1,5 +1,9 @@
 #pragma once
 
+#include <functional>
+#include <memory>
+#include <string>
+
 namespace blobs
 {
 
@@ -14,9 +18,16 @@
     /**
      * open the firmware update mechanism.
      *
+     * @param[in] path - the path passed to the handler (the blob_id).
      * @return bool - returns true on success.
      */
-    virtual bool open() = 0;
+    virtual bool open(const std::string& path) = 0;
+};
+
+struct HandlerPack
+{
+    std::string blobName;
+    ImageHandlerInterface* handler;
 };
 
 } // namespace blobs
diff --git a/main.cpp b/main.cpp
index f6d63da..1934c6f 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,6 +1,8 @@
 #include "config.h"
 
 #include "firmware_handler.hpp"
+#include "image_handler.hpp"
+#include "static_handler.hpp"
 
 #include <blobs-ipmid/manager.hpp>
 #include <cstdint>
@@ -11,14 +13,19 @@
 {
 using namespace phosphor::logging;
 
-std::vector<std::string> supportedFirmware = {
+namespace
+{
+StaticLayoutHandler staticLayoutHandler;
+
+std::vector<HandlerPack> supportedFirmware = {
 #ifdef ENABLE_STATIC_LAYOUT
-    "/flash/image",
+    {"/flash/image", &staticLayoutHandler},
 #endif
 };
 
 std::uint16_t supportedTransports =
     static_cast<std::uint16_t>(FirmwareUpdateFlags::bt);
+} // namespace
 
 void setupFirmwareHandler() __attribute__((constructor));
 
diff --git a/static_handler.cpp b/static_handler.cpp
new file mode 100644
index 0000000..1d7e8e9
--- /dev/null
+++ b/static_handler.cpp
@@ -0,0 +1,15 @@
+#include "static_handler.hpp"
+
+#include <memory>
+#include <string>
+
+namespace blobs
+{
+
+bool StaticLayoutHandler::open(const std::string& path)
+{
+    this->path = path;
+    return false;
+}
+
+} // namespace blobs
diff --git a/static_handler.hpp b/static_handler.hpp
new file mode 100644
index 0000000..d1cca08
--- /dev/null
+++ b/static_handler.hpp
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "image_handler.hpp"
+
+#include <memory>
+#include <string>
+
+namespace blobs
+{
+
+class StaticLayoutHandler : public ImageHandlerInterface
+{
+  public:
+    /**
+     * Create a StaticLayoutHandler.
+     */
+    StaticLayoutHandler() = default;
+
+    bool open(const std::string& path) override;
+
+  private:
+    std::string path;
+};
+
+} // namespace blobs
diff --git a/test/firmware_canhandle_unittest.cpp b/test/firmware_canhandle_unittest.cpp
index 2350828..b82ab6a 100644
--- a/test/firmware_canhandle_unittest.cpp
+++ b/test/firmware_canhandle_unittest.cpp
@@ -1,4 +1,5 @@
 #include "firmware_handler.hpp"
+#include "image_mock.hpp"
 
 #include <memory>
 #include <vector>
@@ -9,7 +10,6 @@
 {
 TEST(FirmwareHandlerCanHandleTest, VerifyItemsInListAreOk)
 {
-
     struct ListItem
     {
         std::string name;
@@ -19,8 +19,15 @@
     std::vector<ListItem> items = {
         {"asdf", true}, {"nope", false}, {"123123", false}, {"bcdf", true}};
 
+    ImageHandlerMock imageMock;
+
+    std::vector<HandlerPack> blobs = {
+        {"asdf", &imageMock},
+        {"bcdf", &imageMock},
+    };
+
     auto handler = FirmwareBlobHandler::CreateFirmwareBlobHandler(
-        {"asdf", "bcdf"}, static_cast<uint16_t>(FirmwareUpdateFlags::bt));
+        blobs, static_cast<uint16_t>(FirmwareUpdateFlags::bt));
 
     for (const auto& item : items)
     {
diff --git a/test/firmware_handler_unittest.cpp b/test/firmware_handler_unittest.cpp
index 8ef74c1..16395df 100644
--- a/test/firmware_handler_unittest.cpp
+++ b/test/firmware_handler_unittest.cpp
@@ -1,7 +1,9 @@
 #include "firmware_handler.hpp"
+#include "image_mock.hpp"
 
 #include <algorithm>
 #include <memory>
+#include <vector>
 
 #include <gtest/gtest.h>
 
@@ -15,7 +17,13 @@
 }
 TEST(FirmwareHandlerTest, CreateEmptyListVerifyHasHash)
 {
-    auto handler = FirmwareBlobHandler::CreateFirmwareBlobHandler({"asdf"}, 0);
+    ImageHandlerMock imageMock;
+
+    std::vector<HandlerPack> blobs = {
+        {"asdf", &imageMock},
+    };
+
+    auto handler = FirmwareBlobHandler::CreateFirmwareBlobHandler(blobs, 0);
     auto result = handler->getBlobIds();
     EXPECT_EQ(2, result.size());
     EXPECT_EQ(2, std::count(result.begin(), result.end(), "asdf") +
diff --git a/test/firmware_stat_unittest.cpp b/test/firmware_stat_unittest.cpp
index b872b16..7d0961b 100644
--- a/test/firmware_stat_unittest.cpp
+++ b/test/firmware_stat_unittest.cpp
@@ -1,6 +1,8 @@
 #include "firmware_handler.hpp"
+#include "image_mock.hpp"
 
 #include <memory>
+#include <vector>
 
 #include <gtest/gtest.h>
 
@@ -15,8 +17,14 @@
      * the input for this function.
      */
 
+    ImageHandlerMock imageMock;
+
+    std::vector<HandlerPack> blobs = {
+        {"asdf", &imageMock},
+    };
+
     auto handler = FirmwareBlobHandler::CreateFirmwareBlobHandler(
-        {"asdf"}, static_cast<uint16_t>(FirmwareUpdateFlags::bt));
+        blobs, static_cast<uint16_t>(FirmwareUpdateFlags::bt));
     struct BlobMeta meta;
     EXPECT_TRUE(handler->stat("asdf", &meta));
     EXPECT_EQ(static_cast<uint16_t>(FirmwareUpdateFlags::bt), meta.blobState);
diff --git a/test/image_mock.hpp b/test/image_mock.hpp
new file mode 100644
index 0000000..4e615b1
--- /dev/null
+++ b/test/image_mock.hpp
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "image_handler.hpp"
+
+#include <gmock/gmock.h>
+
+namespace blobs
+{
+
+class ImageHandlerMock : public ImageHandlerInterface
+{
+  public:
+    virtual ~ImageHandlerMock() = default;
+
+    MOCK_METHOD1(open, bool(const std::string&));
+};
+
+} // namespace blobs