handler: Implement open as a pass-through function

When opening a blob id, handler finds a blobstore with matching
base id and calls its open function, passing down the path and open
flags.

Signed-off-by: Kun Yi <kunyi@google.com>
Change-Id: I6127b3c2b2c4752b5e094db61f12451089ccb20b
diff --git a/binarystore.hpp b/binarystore.hpp
index 068db5a..0fc316b 100644
--- a/binarystore.hpp
+++ b/binarystore.hpp
@@ -25,7 +25,8 @@
     virtual std::string getBaseBlobId() const = 0;
     virtual std::vector<std::string> getBlobIds() const = 0;
     virtual bool canHandleBlob(const std::string& blobId) const = 0;
-    virtual bool openOrCreateBlob(const std::string& blobId) = 0;
+    virtual bool openOrCreateBlob(const std::string& blobId,
+                                  uint16_t flags) = 0;
     virtual std::vector<uint8_t> read(uint32_t offset,
                                       uint32_t requestedSize) = 0;
     virtual bool write(uint32_t offset, const std::vector<uint8_t>& data) = 0;
diff --git a/binarystore_mock.hpp b/binarystore_mock.hpp
index 3ea1201..ada526d 100644
--- a/binarystore_mock.hpp
+++ b/binarystore_mock.hpp
@@ -13,7 +13,7 @@
     MOCK_CONST_METHOD0(getBaseBlobId, std::string());
     MOCK_CONST_METHOD1(canHandleBlob, bool(const std::string&));
     MOCK_CONST_METHOD0(getBlobIds, std::vector<std::string>());
-    MOCK_METHOD1(openOrCreateBlob, bool(const std::string&));
+    MOCK_METHOD2(openOrCreateBlob, bool(const std::string&, uint16_t));
     MOCK_METHOD2(read, std::vector<uint8_t>(uint32_t, uint32_t));
     MOCK_METHOD2(write, bool(uint32_t, const std::vector<uint8_t>&));
     MOCK_METHOD0(commit, bool());
diff --git a/handler.cpp b/handler.cpp
index 4e6e6ea..7bbac6b 100644
--- a/handler.cpp
+++ b/handler.cpp
@@ -5,6 +5,17 @@
 namespace blobs
 {
 
+namespace internal
+{
+
+/* Strip the basename till the last '/' */
+std::string getBaseFromId(const std::string& blobId)
+{
+    return blobId.substr(0, blobId.find_last_of('/') + 1);
+}
+
+} // namespace internal
+
 void BinaryStoreBlobHandler::addNewBinaryStore(
     std::unique_ptr<binstore::BinaryStoreInterface> store)
 {
@@ -61,8 +72,20 @@
         return false;
     }
 
-    // TODO: implement
-    return false;
+    const auto& base = internal::getBaseFromId(path);
+
+    if (stores_.find(base) == stores_.end())
+    {
+        return false;
+    }
+
+    if (!stores_[base]->openOrCreateBlob(path, flags))
+    {
+        return false;
+    }
+
+    sessions_[session] = stores_[base].get();
+    return true;
 }
 
 std::vector<uint8_t> BinaryStoreBlobHandler::read(uint16_t session,
diff --git a/handler.hpp b/handler.hpp
index 61ded36..2a75a57 100644
--- a/handler.hpp
+++ b/handler.hpp
@@ -61,8 +61,8 @@
     std::map<std::string, std::unique_ptr<binstore::BinaryStoreInterface>>
         stores_;
 
-    /* map of sessionId: open binaryStore base, which has a 1:1 relationship. */
-    std::unordered_map<uint16_t, std::string> sessions_;
+    /* map of sessionId: open binaryStore pointer. */
+    std::unordered_map<uint16_t, binstore::BinaryStoreInterface*> sessions_;
 };
 
 } // namespace blobs
diff --git a/test/Makefile.am b/test/Makefile.am
index b80b6d2..5b3fe6c 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -10,6 +10,7 @@
 
 # Run all 'check' test programs
 check_PROGRAMS = \
+	handler_open_unittest \
 	handler_unittest
 TESTS = $(check_PROGRAMS)
 
@@ -17,3 +18,8 @@
 handler_unittest_LDADD = $(PHOSPHOR_LOGGING_LIBS) \
 	$(top_builddir)/handler.o
 handler_unittest_CXXFLAGS = $(PHOSPHOR_LOGGING_CFLAGS)
+
+handler_open_unittest_SOURCES = handler_open_unittest.cpp
+handler_open_unittest_LDADD = $(PHOSPHOR_LOGGING_LIBS) \
+	$(top_builddir)/handler.o
+handler_open_unittest_CXXFLAGS = $(PHOSPHOR_LOGGING_CFLAGS)
diff --git a/test/handler_open_unittest.cpp b/test/handler_open_unittest.cpp
new file mode 100644
index 0000000..1d69f24
--- /dev/null
+++ b/test/handler_open_unittest.cpp
@@ -0,0 +1,53 @@
+#include "handler_unittest.hpp"
+
+using ::testing::_;
+using ::testing::Return;
+using ::testing::StartsWith;
+
+using namespace std::string_literals;
+using namespace binstore;
+
+namespace blobs
+{
+
+TEST_F(BinaryStoreBlobHandlerOpenTest, FailWhenCannotHandleId)
+{
+    uint16_t flags = OpenFlags::read, sessionId = 0;
+    EXPECT_FALSE(handler.open(sessionId, flags, "/invalid/blob"s));
+}
+
+TEST_F(BinaryStoreBlobHandlerOpenTest, FailWhenStoreOpenReturnsFailure)
+{
+    auto testBaseId = "/test/"s;
+    auto testBlobId = "/test/blob0"s;
+    uint16_t flags = OpenFlags::read, sessionId = 0;
+    auto bstore = std::make_unique<MockBinaryStore>();
+
+    EXPECT_CALL(*bstore, getBaseBlobId()).WillRepeatedly(Return(testBaseId));
+    EXPECT_CALL(*bstore, canHandleBlob(StartsWith(testBaseId)))
+        .WillRepeatedly(Return(true));
+    EXPECT_CALL(*bstore, openOrCreateBlob(_, flags)).WillOnce(Return(false));
+
+    handler.addNewBinaryStore(std::move(bstore));
+
+    EXPECT_FALSE(handler.open(sessionId, flags, testBlobId));
+}
+
+TEST_F(BinaryStoreBlobHandlerOpenTest, SucceedWhenStoreOpenReturnsTrue)
+{
+    auto testBaseId = "/test/"s;
+    auto testBlobId = "/test/blob0"s;
+    uint16_t flags = OpenFlags::read, sessionId = 0;
+    auto bstore = std::make_unique<MockBinaryStore>();
+
+    EXPECT_CALL(*bstore, getBaseBlobId()).WillRepeatedly(Return(testBaseId));
+    EXPECT_CALL(*bstore, canHandleBlob(StartsWith(testBaseId)))
+        .WillRepeatedly(Return(true));
+    EXPECT_CALL(*bstore, openOrCreateBlob(_, flags)).WillOnce(Return(true));
+
+    handler.addNewBinaryStore(std::move(bstore));
+
+    EXPECT_TRUE(handler.open(sessionId, flags, testBlobId));
+}
+
+} // namespace blobs
diff --git a/test/handler_unittest.hpp b/test/handler_unittest.hpp
index f6390fc..7f5df42 100644
--- a/test/handler_unittest.hpp
+++ b/test/handler_unittest.hpp
@@ -15,4 +15,8 @@
     BinaryStoreBlobHandler handler;
 };
 
+class BinaryStoreBlobHandlerOpenTest : public BinaryStoreBlobHandlerTest
+{
+};
+
 } // namespace blobs