blob: 8103d6f6990718baf8b45565ad1afb84de5ff32a [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 Tu7f107802023-11-06 23:05:25 -080012#include <stdplus/print.hpp>
Willy Tu67391d52021-12-07 19:53:49 -080013#include <vector>
Maksym Sloykoeb274112021-10-27 23:48:32 +000014
15#include <gmock/gmock.h>
16
17const std::string blobData = "jW7jiID}kD&gm&Azi:^]JT]'Ov4"
18 "Y.Oey]mw}yak9Wf3[S`+$!g]@[0}gikis^";
19const std::string inputProto = "blob_base_id: \"/blob/my-test\""
20 "blobs: [{ "
21 " blob_id: \"/blob/my-test/0\""
22 " data:\"" +
23 blobData +
24 "\""
25 "}, { "
26 " blob_id: \"/blob/my-test/1\""
27 " data:\"" +
28 blobData +
29 "\""
30 "}, { "
31 " blob_id: \"/blob/my-test/2\""
32 " data:\"" +
33 blobData +
34 "\""
35 "}, {"
36 " blob_id: \"/blob/my-test/3\""
37 " data:\"" +
38 blobData +
39 "\""
William A. Kennington III145b57f2024-02-01 19:17:03 -080040 "}]";
Willy Tu67391d52021-12-07 19:53:49 -080041const std::string smallInputProto = "blob_base_id: \"/s/test\""
42 "blobs: [{ "
43 " blob_id: \"/s/test/0\""
William A. Kennington III145b57f2024-02-01 19:17:03 -080044 "}]";
Maksym Sloykoeb274112021-10-27 23:48:32 +000045
46class SysFileBuf : public binstore::SysFile
47{
48 public:
Willy Tufdebaa32022-02-08 16:34:20 -080049 explicit SysFileBuf(std::string* storage) : data_{storage}
Maksym Sloykoeb274112021-10-27 23:48:32 +000050 {
51 }
52
53 size_t readToBuf(size_t pos, size_t count, char* buf) const override
54 {
Willy Tuca170bb2023-11-06 00:26:43 -080055 stdplus::print(stderr, "Read {} bytes at {}\n", count, pos);
Maksym Sloykoeb274112021-10-27 23:48:32 +000056 return data_->copy(buf, count, pos);
57 }
58
59 std::string readAsStr(size_t pos, size_t count) const override
60 {
Willy Tuca170bb2023-11-06 00:26:43 -080061 stdplus::print(stderr, "Read as str {} bytes at {}\n", count, pos);
Maksym Sloykoeb274112021-10-27 23:48:32 +000062 return data_->substr(pos, count);
63 }
64
65 std::string readRemainingAsStr(size_t pos) const override
66 {
67 return data_->substr(pos);
68 }
69
70 void writeStr(const std::string& data, size_t pos) override
71 {
72 data_->replace(pos, data.size(), data);
73 }
74
75 std::string* data_;
76};
77
78using binstore::binaryblobproto::BinaryBlobBase;
79using google::protobuf::TextFormat;
80
81using testing::ElementsAreArray;
82using testing::UnorderedElementsAre;
83
84class BinaryStoreTest : public testing::Test
85{
86 public:
87 std::unique_ptr<SysFileBuf> createBlobStorage(const std::string& textProto)
88 {
89 BinaryBlobBase storeProto;
90 TextFormat::ParseFromString(textProto, &storeProto);
91
92 std::stringstream storage;
93 std::string data;
94 storeProto.SerializeToString(&data);
95
96 const uint64_t dataSize = data.size();
97 storage.write(reinterpret_cast<const char*>(&dataSize),
98 sizeof(dataSize));
99 storage << data;
100
101 blobDataStorage = storage.str();
102 return std::make_unique<SysFileBuf>(&blobDataStorage);
103 }
104
105 std::string blobDataStorage;
106};
107
108TEST_F(BinaryStoreTest, SimpleLoad)
109{
110 auto testDataFile = createBlobStorage(inputProto);
111 auto initialData = blobDataStorage;
112 auto store = binstore::BinaryStore::createFromConfig(
113 "/blob/my-test", std::move(testDataFile));
114 EXPECT_THAT(store->getBlobIds(),
115 UnorderedElementsAre("/blob/my-test", "/blob/my-test/0",
116 "/blob/my-test/1", "/blob/my-test/2",
117 "/blob/my-test/3"));
118 EXPECT_EQ(initialData, blobDataStorage);
119}
120
Willy Tu7f107802023-11-06 23:05:25 -0800121TEST_F(BinaryStoreTest, SimpleLoadWithAlias)
122{
123 auto testDataFile = createBlobStorage(inputProto);
124 auto initialData = blobDataStorage;
125 auto store = binstore::BinaryStore::createFromConfig(
126 "/blob/my-test-2", std::move(testDataFile), std::nullopt,
127 "/blob/my-test");
128 EXPECT_THAT(store->getBlobIds(),
129 UnorderedElementsAre("/blob/my-test-2", "/blob/my-test-2/0",
130 "/blob/my-test-2/1", "/blob/my-test-2/2",
131 "/blob/my-test-2/3"));
132 EXPECT_NE(initialData, blobDataStorage);
133}
134
Maksym Sloykoeb274112021-10-27 23:48:32 +0000135TEST_F(BinaryStoreTest, TestCreateFromFile)
136{
137 auto testDataFile = createBlobStorage(inputProto);
138 auto initialData = blobDataStorage;
139 auto store =
140 binstore::BinaryStore::createFromFile(std::move(testDataFile), true);
141 ASSERT_TRUE(store);
142 EXPECT_EQ("/blob/my-test", store->getBaseBlobId());
143 EXPECT_THAT(store->getBlobIds(),
144 UnorderedElementsAre("/blob/my-test", "/blob/my-test/0",
145 "/blob/my-test/1", "/blob/my-test/2",
146 "/blob/my-test/3"));
147 // Check that the storage has not changed
148 EXPECT_EQ(initialData, blobDataStorage);
149}
150
Willy Tu7f107802023-11-06 23:05:25 -0800151TEST_F(BinaryStoreTest, TestSetBaseBlobId)
152{
153 auto testDataFile = createBlobStorage(inputProto);
154 auto initialData = blobDataStorage;
155 auto store = binstore::BinaryStore::createFromConfig(
156 "/blob/my-test", std::move(testDataFile), std::nullopt);
157 ASSERT_TRUE(store);
158 EXPECT_EQ("/blob/my-test", store->getBaseBlobId());
159 EXPECT_TRUE(store->setBaseBlobId("/blob/my-test-1"));
160 EXPECT_EQ("/blob/my-test-1", store->getBaseBlobId());
161 EXPECT_THAT(store->getBlobIds(),
162 UnorderedElementsAre("/blob/my-test-1", "/blob/my-test-1/0",
163 "/blob/my-test-1/1", "/blob/my-test-1/2",
164 "/blob/my-test-1/3"));
165 // Check that the storage has changed
166 EXPECT_NE(initialData, blobDataStorage);
167}
168
Maksym Sloykoeb274112021-10-27 23:48:32 +0000169TEST_F(BinaryStoreTest, TestReadBlob)
170{
171 auto testDataFile = createBlobStorage(inputProto);
172 auto store =
173 binstore::BinaryStore::createFromFile(std::move(testDataFile), true);
174 ASSERT_TRUE(store);
175
176 const auto blobStoredData = store->readBlob("/blob/my-test/1");
177 EXPECT_FALSE(blobStoredData.empty());
178
179 decltype(blobStoredData) origData(blobData.begin(), blobData.end());
180
181 EXPECT_THAT(blobStoredData, ElementsAreArray(origData));
182}
183
184TEST_F(BinaryStoreTest, TestReadBlobError)
185{
186 auto testDataFile = createBlobStorage(inputProto);
187 auto store =
188 binstore::BinaryStore::createFromFile(std::move(testDataFile), true);
189 ASSERT_TRUE(store);
190
191 EXPECT_THROW(store->readBlob("/nonexistent/1"), ipmi::HandlerCompletion);
192}
193
194TEST_F(BinaryStoreTest, TestOpenReadOnlyBlob)
195{
196 auto testDataFile = createBlobStorage(inputProto);
197 auto store =
198 binstore::BinaryStore::createFromFile(std::move(testDataFile), true);
199 ASSERT_TRUE(store);
200
201 EXPECT_TRUE(
202 store->openOrCreateBlob("/blob/my-test/2", blobs::OpenFlags::read));
203 EXPECT_FALSE(store->openOrCreateBlob(
204 "/blob/my-test/2", blobs::OpenFlags::read & blobs::OpenFlags::write));
205}
Willy Tu67391d52021-12-07 19:53:49 -0800206
207TEST_F(BinaryStoreTest, TestWriteExceedMaxSize)
208{
209 std::vector<uint8_t> writeData(10, 0);
210 auto testDataFile = createBlobStorage(smallInputProto);
211 auto store = binstore::BinaryStore::createFromConfig(
212 "/s/test", std::move(testDataFile), 48);
213 ASSERT_TRUE(store);
214
215 EXPECT_TRUE(store->openOrCreateBlob(
216 "/s/test/0", blobs::OpenFlags::write | blobs::OpenFlags::read));
William A. Kennington III145b57f2024-02-01 19:17:03 -0800217 // Current size 22(blob_) + 8(size var) = 30
Willy Tu67391d52021-12-07 19:53:49 -0800218 EXPECT_TRUE(store->write(
William A. Kennington III145b57f2024-02-01 19:17:03 -0800219 0, writeData)); // 42 = 30(existing) + 10 (data) + 2 (blob_id '/0')
Willy Tu67391d52021-12-07 19:53:49 -0800220 EXPECT_FALSE(
William A. Kennington III145b57f2024-02-01 19:17:03 -0800221 store->write(10, writeData)); // 52 = 42 (existing) + 10 (new data)
Willy Tu67391d52021-12-07 19:53:49 -0800222 EXPECT_FALSE(
William A. Kennington III145b57f2024-02-01 19:17:03 -0800223 store->write(7, writeData)); // 49 = 42 (existing) + 7 (new data)
Willy Tu67391d52021-12-07 19:53:49 -0800224 EXPECT_TRUE(
William A. Kennington III145b57f2024-02-01 19:17:03 -0800225 store->write(6, writeData)); // 48 = 42 (existing) + 6 (new data)
Willy Tu67391d52021-12-07 19:53:49 -0800226}
227
228TEST_F(BinaryStoreTest, TestCreateFromConfigExceedMaxSize)
229{
230 auto testDataFile = createBlobStorage(inputProto);
231 auto store = binstore::BinaryStore::createFromConfig(
232 "/blob/my-test", std::move(testDataFile), 1);
233 ASSERT_TRUE(store);
234 EXPECT_FALSE(store->commit());
235}
236
237TEST_F(BinaryStoreTest, TestCreateFromFileExceedMaxSize)
238{
239 auto testDataFile = createBlobStorage(inputProto);
240 auto store = binstore::BinaryStore::createFromFile(std::move(testDataFile),
241 false, 1);
242
243 // Reading from File is expected to call loadSerializedData and fail at the
244 // commit()
245 EXPECT_FALSE(store);
246}