binarystore: Enable maxBinarySize Feature

Fail on write() and commit() if the result will exceed the max size.

Enabled by adding the max_binary_size to the proto buffer. The new one
takes priority and will replace existing one even if it already exists.

The `max_binary_size` is the size of the total data including the size
header. It is calculated with
```
blob_.SerializeAsString().size() +
  sizeof(boost::endian::little_uint64_t)
```

Change-Id: I28a4c7a25fa066c11510b51cdfce27df4e09d3b5
Signed-off-by: Willy Tu <wltu@google.com>
diff --git a/test/binarystore_unittest.cpp b/test/binarystore_unittest.cpp
index f0e8048..2a00696 100644
--- a/test/binarystore_unittest.cpp
+++ b/test/binarystore_unittest.cpp
@@ -9,6 +9,7 @@
 #include <iterator>
 #include <memory>
 #include <sstream>
+#include <vector>
 
 #include <gmock/gmock.h>
 
@@ -37,6 +38,11 @@
                                "\""
                                "}] "
                                "max_size_bytes: 64";
+const std::string smallInputProto = "blob_base_id: \"/s/test\""
+                                    "blobs: [{ "
+                                    "    blob_id: \"/s/test/0\""
+                                    "}] "
+                                    "max_size_bytes: 64";
 
 class SysFileBuf : public binstore::SysFile
 {
@@ -167,3 +173,44 @@
     EXPECT_FALSE(store->openOrCreateBlob(
         "/blob/my-test/2", blobs::OpenFlags::read & blobs::OpenFlags::write));
 }
+
+TEST_F(BinaryStoreTest, TestWriteExceedMaxSize)
+{
+    std::vector<uint8_t> writeData(10, 0);
+    auto testDataFile = createBlobStorage(smallInputProto);
+    auto store = binstore::BinaryStore::createFromConfig(
+        "/s/test", std::move(testDataFile), 48);
+    ASSERT_TRUE(store);
+
+    EXPECT_TRUE(store->openOrCreateBlob(
+        "/s/test/0", blobs::OpenFlags::write | blobs::OpenFlags::read));
+    // Current size 24(blob_ + max_size) + 8(size var) = 32
+    EXPECT_TRUE(store->write(
+        0, writeData)); // 44 =  32(existing) + 10 (data) + 2 (blob_id '/0')
+    EXPECT_FALSE(
+        store->write(10, writeData)); // 54 = 44 (existing) + 10 (new data)
+    EXPECT_FALSE(
+        store->write(5, writeData)); // 49 = 44 (existing) + 5 (new data)
+    EXPECT_TRUE(
+        store->write(4, writeData)); // 48 = 44 (existing) + 4 (new data)
+}
+
+TEST_F(BinaryStoreTest, TestCreateFromConfigExceedMaxSize)
+{
+    auto testDataFile = createBlobStorage(inputProto);
+    auto store = binstore::BinaryStore::createFromConfig(
+        "/blob/my-test", std::move(testDataFile), 1);
+    ASSERT_TRUE(store);
+    EXPECT_FALSE(store->commit());
+}
+
+TEST_F(BinaryStoreTest, TestCreateFromFileExceedMaxSize)
+{
+    auto testDataFile = createBlobStorage(inputProto);
+    auto store = binstore::BinaryStore::createFromFile(std::move(testDataFile),
+                                                       false, 1);
+
+    // Reading from File is expected to call loadSerializedData and fail at the
+    // commit()
+    EXPECT_FALSE(store);
+}