blob: f7c8a8e1853bf3850543def4bacc51ee97719662 [file] [log] [blame]
Maksym Sloykoeb274112021-10-27 23:48:32 +00001#include "binarystore.hpp"
2#include "binarystore_interface.hpp"
3#include "sys_file.hpp"
4
5#include <google/protobuf/text_format.h>
6
7#include <iostream>
8#include <ipmid/handler.hpp>
9#include <iterator>
10#include <memory>
11#include <sstream>
Willy Tu67391d52021-12-07 19:53:49 -080012#include <vector>
Maksym Sloykoeb274112021-10-27 23:48:32 +000013
14#include <gmock/gmock.h>
15
16const std::string blobData = "jW7jiID}kD&gm&Azi:^]JT]'Ov4"
17 "Y.Oey]mw}yak9Wf3[S`+$!g]@[0}gikis^";
18const std::string inputProto = "blob_base_id: \"/blob/my-test\""
19 "blobs: [{ "
20 " blob_id: \"/blob/my-test/0\""
21 " data:\"" +
22 blobData +
23 "\""
24 "}, { "
25 " blob_id: \"/blob/my-test/1\""
26 " data:\"" +
27 blobData +
28 "\""
29 "}, { "
30 " blob_id: \"/blob/my-test/2\""
31 " data:\"" +
32 blobData +
33 "\""
34 "}, {"
35 " blob_id: \"/blob/my-test/3\""
36 " data:\"" +
37 blobData +
38 "\""
39 "}] "
40 "max_size_bytes: 64";
Willy Tu67391d52021-12-07 19:53:49 -080041const std::string smallInputProto = "blob_base_id: \"/s/test\""
42 "blobs: [{ "
43 " blob_id: \"/s/test/0\""
44 "}] "
45 "max_size_bytes: 64";
Maksym Sloykoeb274112021-10-27 23:48:32 +000046
47class SysFileBuf : public binstore::SysFile
48{
49 public:
Willy Tufdebaa32022-02-08 16:34:20 -080050 explicit SysFileBuf(std::string* storage) : data_{storage}
Maksym Sloykoeb274112021-10-27 23:48:32 +000051 {
52 }
53
54 size_t readToBuf(size_t pos, size_t count, char* buf) const override
55 {
56 std::cout << "Read " << count << " bytes at " << pos << std::endl;
57 return data_->copy(buf, count, pos);
58 }
59
60 std::string readAsStr(size_t pos, size_t count) const override
61 {
62 std::cout << "Read as str " << count << " bytes at " << pos
63 << std::endl;
64 return data_->substr(pos, count);
65 }
66
67 std::string readRemainingAsStr(size_t pos) const override
68 {
69 return data_->substr(pos);
70 }
71
72 void writeStr(const std::string& data, size_t pos) override
73 {
74 data_->replace(pos, data.size(), data);
75 }
76
77 std::string* data_;
78};
79
80using binstore::binaryblobproto::BinaryBlobBase;
81using google::protobuf::TextFormat;
82
83using testing::ElementsAreArray;
84using testing::UnorderedElementsAre;
85
86class BinaryStoreTest : public testing::Test
87{
88 public:
89 std::unique_ptr<SysFileBuf> createBlobStorage(const std::string& textProto)
90 {
91 BinaryBlobBase storeProto;
92 TextFormat::ParseFromString(textProto, &storeProto);
93
94 std::stringstream storage;
95 std::string data;
96 storeProto.SerializeToString(&data);
97
98 const uint64_t dataSize = data.size();
99 storage.write(reinterpret_cast<const char*>(&dataSize),
100 sizeof(dataSize));
101 storage << data;
102
103 blobDataStorage = storage.str();
104 return std::make_unique<SysFileBuf>(&blobDataStorage);
105 }
106
107 std::string blobDataStorage;
108};
109
110TEST_F(BinaryStoreTest, SimpleLoad)
111{
112 auto testDataFile = createBlobStorage(inputProto);
113 auto initialData = blobDataStorage;
114 auto store = binstore::BinaryStore::createFromConfig(
115 "/blob/my-test", std::move(testDataFile));
116 EXPECT_THAT(store->getBlobIds(),
117 UnorderedElementsAre("/blob/my-test", "/blob/my-test/0",
118 "/blob/my-test/1", "/blob/my-test/2",
119 "/blob/my-test/3"));
120 EXPECT_EQ(initialData, blobDataStorage);
121}
122
123TEST_F(BinaryStoreTest, TestCreateFromFile)
124{
125 auto testDataFile = createBlobStorage(inputProto);
126 auto initialData = blobDataStorage;
127 auto store =
128 binstore::BinaryStore::createFromFile(std::move(testDataFile), true);
129 ASSERT_TRUE(store);
130 EXPECT_EQ("/blob/my-test", store->getBaseBlobId());
131 EXPECT_THAT(store->getBlobIds(),
132 UnorderedElementsAre("/blob/my-test", "/blob/my-test/0",
133 "/blob/my-test/1", "/blob/my-test/2",
134 "/blob/my-test/3"));
135 // Check that the storage has not changed
136 EXPECT_EQ(initialData, blobDataStorage);
137}
138
139TEST_F(BinaryStoreTest, TestReadBlob)
140{
141 auto testDataFile = createBlobStorage(inputProto);
142 auto store =
143 binstore::BinaryStore::createFromFile(std::move(testDataFile), true);
144 ASSERT_TRUE(store);
145
146 const auto blobStoredData = store->readBlob("/blob/my-test/1");
147 EXPECT_FALSE(blobStoredData.empty());
148
149 decltype(blobStoredData) origData(blobData.begin(), blobData.end());
150
151 EXPECT_THAT(blobStoredData, ElementsAreArray(origData));
152}
153
154TEST_F(BinaryStoreTest, TestReadBlobError)
155{
156 auto testDataFile = createBlobStorage(inputProto);
157 auto store =
158 binstore::BinaryStore::createFromFile(std::move(testDataFile), true);
159 ASSERT_TRUE(store);
160
161 EXPECT_THROW(store->readBlob("/nonexistent/1"), ipmi::HandlerCompletion);
162}
163
164TEST_F(BinaryStoreTest, TestOpenReadOnlyBlob)
165{
166 auto testDataFile = createBlobStorage(inputProto);
167 auto store =
168 binstore::BinaryStore::createFromFile(std::move(testDataFile), true);
169 ASSERT_TRUE(store);
170
171 EXPECT_TRUE(
172 store->openOrCreateBlob("/blob/my-test/2", blobs::OpenFlags::read));
173 EXPECT_FALSE(store->openOrCreateBlob(
174 "/blob/my-test/2", blobs::OpenFlags::read & blobs::OpenFlags::write));
175}
Willy Tu67391d52021-12-07 19:53:49 -0800176
177TEST_F(BinaryStoreTest, TestWriteExceedMaxSize)
178{
179 std::vector<uint8_t> writeData(10, 0);
180 auto testDataFile = createBlobStorage(smallInputProto);
181 auto store = binstore::BinaryStore::createFromConfig(
182 "/s/test", std::move(testDataFile), 48);
183 ASSERT_TRUE(store);
184
185 EXPECT_TRUE(store->openOrCreateBlob(
186 "/s/test/0", blobs::OpenFlags::write | blobs::OpenFlags::read));
187 // Current size 24(blob_ + max_size) + 8(size var) = 32
188 EXPECT_TRUE(store->write(
189 0, writeData)); // 44 = 32(existing) + 10 (data) + 2 (blob_id '/0')
190 EXPECT_FALSE(
191 store->write(10, writeData)); // 54 = 44 (existing) + 10 (new data)
192 EXPECT_FALSE(
193 store->write(5, writeData)); // 49 = 44 (existing) + 5 (new data)
194 EXPECT_TRUE(
195 store->write(4, writeData)); // 48 = 44 (existing) + 4 (new data)
196}
197
198TEST_F(BinaryStoreTest, TestCreateFromConfigExceedMaxSize)
199{
200 auto testDataFile = createBlobStorage(inputProto);
201 auto store = binstore::BinaryStore::createFromConfig(
202 "/blob/my-test", std::move(testDataFile), 1);
203 ASSERT_TRUE(store);
204 EXPECT_FALSE(store->commit());
205}
206
207TEST_F(BinaryStoreTest, TestCreateFromFileExceedMaxSize)
208{
209 auto testDataFile = createBlobStorage(inputProto);
210 auto store = binstore::BinaryStore::createFromFile(std::move(testDataFile),
211 false, 1);
212
213 // Reading from File is expected to call loadSerializedData and fail at the
214 // commit()
215 EXPECT_FALSE(store);
216}