handler: Implement read/write/close/delete

Implement read/write/close/delete as pass-through functions.

Signed-off-by: Kun Yi <kunyi@google.com>
Change-Id: I56b935b03b8048a70a168d00061c043795b90f5e
diff --git a/binarystore.hpp b/binarystore.hpp
index 0fc316b..11ca241 100644
--- a/binarystore.hpp
+++ b/binarystore.hpp
@@ -27,6 +27,7 @@
     virtual bool canHandleBlob(const std::string& blobId) const = 0;
     virtual bool openOrCreateBlob(const std::string& blobId,
                                   uint16_t flags) = 0;
+    virtual bool deleteBlob(const std::string& blobId) = 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 ada526d..7792e74 100644
--- a/binarystore_mock.hpp
+++ b/binarystore_mock.hpp
@@ -14,6 +14,7 @@
     MOCK_CONST_METHOD1(canHandleBlob, bool(const std::string&));
     MOCK_CONST_METHOD0(getBlobIds, std::vector<std::string>());
     MOCK_METHOD2(openOrCreateBlob, bool(const std::string&, uint16_t));
+    MOCK_METHOD1(deleteBlob, bool(const std::string&));
     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 7bbac6b..ae21ab1 100644
--- a/handler.cpp
+++ b/handler.cpp
@@ -46,8 +46,13 @@
 
 bool BinaryStoreBlobHandler::deleteBlob(const std::string& path)
 {
-    // TODO: implement
-    return false;
+    auto it = stores_.find(internal::getBaseFromId(path));
+    if (it == stores_.end())
+    {
+        return false;
+    }
+
+    return it->second->deleteBlob(path);
 }
 
 bool BinaryStoreBlobHandler::stat(const std::string& path,
@@ -92,16 +97,25 @@
                                                   uint32_t offset,
                                                   uint32_t requestedSize)
 {
-    // TODO: implement
-    std::vector<uint8_t> result;
-    return result;
+    auto it = sessions_.find(session);
+    if (it == sessions_.end())
+    {
+        return std::vector<uint8_t>();
+    }
+
+    return it->second->read(offset, requestedSize);
 }
 
 bool BinaryStoreBlobHandler::write(uint16_t session, uint32_t offset,
                                    const std::vector<uint8_t>& data)
 {
-    // TODO: implement
-    return false;
+    auto it = sessions_.find(session);
+    if (it == sessions_.end())
+    {
+        return false;
+    }
+
+    return it->second->write(offset, data);
 }
 
 bool BinaryStoreBlobHandler::writeMeta(uint16_t session, uint32_t offset,
@@ -120,8 +134,19 @@
 
 bool BinaryStoreBlobHandler::close(uint16_t session)
 {
-    // TODO: implement
-    return false;
+    auto it = sessions_.find(session);
+    if (it == sessions_.end())
+    {
+        return false;
+    }
+
+    if (!it->second->close())
+    {
+        return false;
+    }
+
+    sessions_.erase(session);
+    return true;
 }
 
 bool BinaryStoreBlobHandler::stat(uint16_t session, struct BlobMeta* meta)
diff --git a/test/Makefile.am b/test/Makefile.am
index 5b3fe6c..5ce51f2 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -11,6 +11,7 @@
 # Run all 'check' test programs
 check_PROGRAMS = \
 	handler_open_unittest \
+	handler_readwrite_unittest \
 	handler_unittest
 TESTS = $(check_PROGRAMS)
 
@@ -23,3 +24,8 @@
 handler_open_unittest_LDADD = $(PHOSPHOR_LOGGING_LIBS) \
 	$(top_builddir)/handler.o
 handler_open_unittest_CXXFLAGS = $(PHOSPHOR_LOGGING_CFLAGS)
+
+handler_readwrite_unittest_SOURCES = handler_readwrite_unittest.cpp
+handler_readwrite_unittest_LDADD = $(PHOSPHOR_LOGGING_LIBS) \
+	$(top_builddir)/handler.o
+handler_readwrite_unittest_CXXFLAGS = $(PHOSPHOR_LOGGING_CFLAGS)
diff --git a/test/handler_open_unittest.cpp b/test/handler_open_unittest.cpp
index 1d69f24..83053ad 100644
--- a/test/handler_open_unittest.cpp
+++ b/test/handler_open_unittest.cpp
@@ -50,4 +50,68 @@
     EXPECT_TRUE(handler.open(sessionId, flags, testBlobId));
 }
 
+TEST_F(BinaryStoreBlobHandlerOpenTest, CloseFailForInvalidSession)
+{
+    uint16_t invalidSessionId = 1;
+    EXPECT_FALSE(handler.close(invalidSessionId));
+}
+
+TEST_F(BinaryStoreBlobHandlerOpenTest, CloseFailWhenStoreCloseFails)
+{
+    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));
+    EXPECT_CALL(*bstore, close()).WillOnce(Return(false));
+
+    handler.addNewBinaryStore(std::move(bstore));
+
+    EXPECT_TRUE(handler.open(sessionId, flags, testBlobId));
+    EXPECT_FALSE(handler.close(sessionId));
+}
+
+TEST_F(BinaryStoreBlobHandlerOpenTest, CloseSucceedWhenStoreCloseSucceeds)
+{
+    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));
+    EXPECT_CALL(*bstore, close()).WillOnce(Return(true));
+
+    handler.addNewBinaryStore(std::move(bstore));
+
+    EXPECT_TRUE(handler.open(sessionId, flags, testBlobId));
+    EXPECT_TRUE(handler.close(sessionId));
+}
+
+TEST_F(BinaryStoreBlobHandlerOpenTest, ClosedSessionCannotBeReclosed)
+{
+    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));
+    EXPECT_CALL(*bstore, close()).WillRepeatedly(Return(true));
+
+    handler.addNewBinaryStore(std::move(bstore));
+
+    EXPECT_TRUE(handler.open(sessionId, flags, testBlobId));
+    EXPECT_TRUE(handler.close(sessionId));
+    EXPECT_FALSE(handler.close(sessionId));
+}
+
 } // namespace blobs
diff --git a/test/handler_readwrite_unittest.cpp b/test/handler_readwrite_unittest.cpp
new file mode 100644
index 0000000..b335596
--- /dev/null
+++ b/test/handler_readwrite_unittest.cpp
@@ -0,0 +1,54 @@
+#include "handler_unittest.hpp"
+
+using ::testing::_;
+using ::testing::Return;
+using ::testing::StartsWith;
+
+using namespace std::string_literals;
+using namespace binstore;
+
+namespace blobs
+{
+
+class BinaryStoreBlobHandlerReadWriteTest : public BinaryStoreBlobHandlerTest
+{
+  protected:
+    static inline std::string rwTestBaseId = "/test/"s;
+    static inline std::string rwTestBlobId = "/test/blob0"s;
+    static inline std::vector<uint8_t> rwTestData = {0, 1, 2, 3, 4,
+                                                     5, 6, 7, 8, 9};
+    static inline uint16_t rwTestSessionId = 0;
+    static inline uint32_t rwTestOffset = 0;
+};
+
+TEST_F(BinaryStoreBlobHandlerReadWriteTest, ReadWriteReturnsWhatStoreReturns)
+{
+    auto testBaseId = "/test/"s;
+    auto testBlobId = "/test/blob0"s;
+    uint16_t flags = OpenFlags::read;
+    const std::vector<uint8_t> emptyData;
+    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));
+    EXPECT_CALL(*bstore, read(rwTestOffset, _))
+        .WillOnce(Return(emptyData))
+        .WillOnce(Return(rwTestData));
+
+    EXPECT_CALL(*bstore, write(rwTestOffset, emptyData))
+        .WillOnce(Return(false));
+    EXPECT_CALL(*bstore, write(rwTestOffset, rwTestData))
+        .WillOnce(Return(true));
+
+    handler.addNewBinaryStore(std::move(bstore));
+
+    EXPECT_TRUE(handler.open(rwTestSessionId, flags, testBlobId));
+    EXPECT_EQ(emptyData, handler.read(rwTestSessionId, rwTestOffset, 1));
+    EXPECT_EQ(rwTestData, handler.read(rwTestSessionId, rwTestOffset, 1));
+    EXPECT_FALSE(handler.write(rwTestSessionId, rwTestOffset, emptyData));
+    EXPECT_TRUE(handler.write(rwTestSessionId, rwTestOffset, rwTestData));
+}
+
+} // namespace blobs
diff --git a/test/handler_unittest.cpp b/test/handler_unittest.cpp
index d96fc41..d51818e 100644
--- a/test/handler_unittest.cpp
+++ b/test/handler_unittest.cpp
@@ -103,4 +103,27 @@
     EXPECT_EQ(expectedIdList, handler.getBlobIds());
 }
 
+TEST_F(BinaryStoreBlobHandlerBasicTest, DeleteReturnsWhatStoreReturns)
+{
+    auto bstore = std::make_unique<MockBinaryStore>();
+
+    EXPECT_CALL(*bstore, getBaseBlobId())
+        .WillRepeatedly(Return(basicTestBaseId));
+    EXPECT_CALL(*bstore, canHandleBlob(StrNe(basicTestBlobId)))
+        .WillRepeatedly(Return(false));
+    EXPECT_CALL(*bstore, canHandleBlob(StrEq(basicTestBlobId)))
+        .WillRepeatedly(Return(true));
+    EXPECT_CALL(*bstore, deleteBlob(StrEq(basicTestBlobId)))
+        .WillOnce(Return(false))
+        .WillOnce(Return(true));
+    handler.addNewBinaryStore(std::move(bstore));
+
+    // Verify canHandleBlob return true for a blob id that it can handle
+    EXPECT_FALSE(handler.canHandleBlob(basicTestInvalidBlobId));
+    EXPECT_TRUE(handler.canHandleBlob(basicTestBlobId));
+    EXPECT_FALSE(handler.deleteBlob(basicTestInvalidBlobId));
+    EXPECT_FALSE(handler.deleteBlob(basicTestBlobId));
+    EXPECT_TRUE(handler.deleteBlob(basicTestBlobId));
+}
+
 } // namespace blobs