blob: 450c12837b7c6a1e781f7cffbac4ca5e95a24baf [file] [log] [blame]
Mathias Agopianb7f9a242017-03-08 22:29:31 -08001/*
2 ** Copyright 2011, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
Yiwei Zhang8af03062020-08-12 21:28:15 -070017#include "BlobCache.h"
18
Mathias Agopianb7f9a242017-03-08 22:29:31 -080019#include <fcntl.h>
Yiwei Zhang8af03062020-08-12 21:28:15 -070020#include <gtest/gtest.h>
Mathias Agopianb7f9a242017-03-08 22:29:31 -080021#include <stdio.h>
22
23#include <memory>
24
Mathias Agopianb7f9a242017-03-08 22:29:31 -080025namespace android {
26
Yiwei Zhang8af03062020-08-12 21:28:15 -070027template <typename T>
28using sp = std::shared_ptr<T>;
Mathias Agopianb7f9a242017-03-08 22:29:31 -080029
30class BlobCacheTest : public ::testing::Test {
31protected:
Mathias Agopianb7f9a242017-03-08 22:29:31 -080032 enum {
33 OK = 0,
Yiwei Zhang8af03062020-08-12 21:28:15 -070034 BAD_VALUE = -EINVAL,
Mathias Agopianb7f9a242017-03-08 22:29:31 -080035 };
36
37 enum {
38 MAX_KEY_SIZE = 6,
39 MAX_VALUE_SIZE = 8,
40 MAX_TOTAL_SIZE = 13,
41 };
42
Yiwei Zhang8af03062020-08-12 21:28:15 -070043 virtual void SetUp() { mBC.reset(new BlobCache(MAX_KEY_SIZE, MAX_VALUE_SIZE, MAX_TOTAL_SIZE)); }
Mathias Agopianb7f9a242017-03-08 22:29:31 -080044
Yiwei Zhang8af03062020-08-12 21:28:15 -070045 virtual void TearDown() { mBC.reset(); }
Mathias Agopianb7f9a242017-03-08 22:29:31 -080046
47 std::unique_ptr<BlobCache> mBC;
48};
49
50TEST_F(BlobCacheTest, CacheSingleValueSucceeds) {
Yiwei Zhang8af03062020-08-12 21:28:15 -070051 unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
Leon Scroggins III23377962022-05-03 14:53:14 -040052 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
Mathias Agopianb7f9a242017-03-08 22:29:31 -080053 ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
54 ASSERT_EQ('e', buf[0]);
55 ASSERT_EQ('f', buf[1]);
56 ASSERT_EQ('g', buf[2]);
57 ASSERT_EQ('h', buf[3]);
58}
59
60TEST_F(BlobCacheTest, CacheTwoValuesSucceeds) {
Yiwei Zhang8af03062020-08-12 21:28:15 -070061 unsigned char buf[2] = {0xee, 0xee};
Leon Scroggins III23377962022-05-03 14:53:14 -040062 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("ab", 2, "cd", 2));
63 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("ef", 2, "gh", 2));
Mathias Agopianb7f9a242017-03-08 22:29:31 -080064 ASSERT_EQ(size_t(2), mBC->get("ab", 2, buf, 2));
65 ASSERT_EQ('c', buf[0]);
66 ASSERT_EQ('d', buf[1]);
67 ASSERT_EQ(size_t(2), mBC->get("ef", 2, buf, 2));
68 ASSERT_EQ('g', buf[0]);
69 ASSERT_EQ('h', buf[1]);
70}
71
72TEST_F(BlobCacheTest, GetOnlyWritesInsideBounds) {
Yiwei Zhang8af03062020-08-12 21:28:15 -070073 unsigned char buf[6] = {0xee, 0xee, 0xee, 0xee, 0xee, 0xee};
Leon Scroggins III23377962022-05-03 14:53:14 -040074 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
Yiwei Zhang8af03062020-08-12 21:28:15 -070075 ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf + 1, 4));
Mathias Agopianb7f9a242017-03-08 22:29:31 -080076 ASSERT_EQ(0xee, buf[0]);
77 ASSERT_EQ('e', buf[1]);
78 ASSERT_EQ('f', buf[2]);
79 ASSERT_EQ('g', buf[3]);
80 ASSERT_EQ('h', buf[4]);
81 ASSERT_EQ(0xee, buf[5]);
82}
83
84TEST_F(BlobCacheTest, GetOnlyWritesIfBufferIsLargeEnough) {
Yiwei Zhang8af03062020-08-12 21:28:15 -070085 unsigned char buf[3] = {0xee, 0xee, 0xee};
Leon Scroggins III23377962022-05-03 14:53:14 -040086 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
Mathias Agopianb7f9a242017-03-08 22:29:31 -080087 ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 3));
88 ASSERT_EQ(0xee, buf[0]);
89 ASSERT_EQ(0xee, buf[1]);
90 ASSERT_EQ(0xee, buf[2]);
91}
92
93TEST_F(BlobCacheTest, GetDoesntAccessNullBuffer) {
Leon Scroggins III23377962022-05-03 14:53:14 -040094 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
Yi Kong48a6cd22018-07-18 10:07:09 -070095 ASSERT_EQ(size_t(4), mBC->get("abcd", 4, nullptr, 0));
Mathias Agopianb7f9a242017-03-08 22:29:31 -080096}
97
98TEST_F(BlobCacheTest, MultipleSetsCacheLatestValue) {
Yiwei Zhang8af03062020-08-12 21:28:15 -070099 unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
Leon Scroggins III23377962022-05-03 14:53:14 -0400100 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
101 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "ijkl", 4));
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800102 ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
103 ASSERT_EQ('i', buf[0]);
104 ASSERT_EQ('j', buf[1]);
105 ASSERT_EQ('k', buf[2]);
106 ASSERT_EQ('l', buf[3]);
107}
108
109TEST_F(BlobCacheTest, SecondSetKeepsFirstValueIfTooLarge) {
Yiwei Zhang8af03062020-08-12 21:28:15 -0700110 unsigned char buf[MAX_VALUE_SIZE + 1] = {0xee, 0xee, 0xee, 0xee};
Leon Scroggins III23377962022-05-03 14:53:14 -0400111 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
112 ASSERT_EQ(BlobCache::InsertResult::kValueTooBig, mBC->set("abcd", 4, buf, MAX_VALUE_SIZE + 1));
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800113 ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
114 ASSERT_EQ('e', buf[0]);
115 ASSERT_EQ('f', buf[1]);
116 ASSERT_EQ('g', buf[2]);
117 ASSERT_EQ('h', buf[3]);
118}
119
120TEST_F(BlobCacheTest, DoesntCacheIfKeyIsTooBig) {
Yiwei Zhang8af03062020-08-12 21:28:15 -0700121 char key[MAX_KEY_SIZE + 1];
122 unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
123 for (int i = 0; i < MAX_KEY_SIZE + 1; i++) {
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800124 key[i] = 'a';
125 }
Leon Scroggins III23377962022-05-03 14:53:14 -0400126 ASSERT_EQ(BlobCache::InsertResult::kKeyTooBig, mBC->set(key, MAX_KEY_SIZE + 1, "bbbb", 4));
Yiwei Zhang8af03062020-08-12 21:28:15 -0700127 ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE + 1, buf, 4));
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800128 ASSERT_EQ(0xee, buf[0]);
129 ASSERT_EQ(0xee, buf[1]);
130 ASSERT_EQ(0xee, buf[2]);
131 ASSERT_EQ(0xee, buf[3]);
132}
133
134TEST_F(BlobCacheTest, DoesntCacheIfValueIsTooBig) {
Yiwei Zhang8af03062020-08-12 21:28:15 -0700135 char buf[MAX_VALUE_SIZE + 1];
136 for (int i = 0; i < MAX_VALUE_SIZE + 1; i++) {
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800137 buf[i] = 'b';
138 }
Leon Scroggins III23377962022-05-03 14:53:14 -0400139 ASSERT_EQ(BlobCache::InsertResult::kValueTooBig, mBC->set("abcd", 4, buf, MAX_VALUE_SIZE + 1));
Yiwei Zhang8af03062020-08-12 21:28:15 -0700140 for (int i = 0; i < MAX_VALUE_SIZE + 1; i++) {
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800141 buf[i] = 0xee;
142 }
Yiwei Zhang8af03062020-08-12 21:28:15 -0700143 ASSERT_EQ(size_t(0), mBC->get("abcd", 4, buf, MAX_VALUE_SIZE + 1));
144 for (int i = 0; i < MAX_VALUE_SIZE + 1; i++) {
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800145 SCOPED_TRACE(i);
146 ASSERT_EQ(0xee, buf[i]);
147 }
148}
149
150TEST_F(BlobCacheTest, DoesntCacheIfKeyValuePairIsTooBig) {
151 // Check a testing assumptions
152 ASSERT_TRUE(MAX_TOTAL_SIZE < MAX_KEY_SIZE + MAX_VALUE_SIZE);
153 ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE);
154
155 enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE + 1 };
156
157 char key[MAX_KEY_SIZE];
158 char buf[bufSize];
159 for (int i = 0; i < MAX_KEY_SIZE; i++) {
160 key[i] = 'a';
161 }
162 for (int i = 0; i < bufSize; i++) {
163 buf[i] = 'b';
164 }
165
Leon Scroggins III23377962022-05-03 14:53:14 -0400166 ASSERT_EQ(BlobCache::InsertResult::kCombinedTooBig,
167 mBC->set(key, MAX_KEY_SIZE, buf, MAX_VALUE_SIZE));
Yi Kong48a6cd22018-07-18 10:07:09 -0700168 ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE, nullptr, 0));
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800169}
170
171TEST_F(BlobCacheTest, CacheMaxKeySizeSucceeds) {
172 char key[MAX_KEY_SIZE];
Yiwei Zhang8af03062020-08-12 21:28:15 -0700173 unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800174 for (int i = 0; i < MAX_KEY_SIZE; i++) {
175 key[i] = 'a';
176 }
Leon Scroggins III23377962022-05-03 14:53:14 -0400177 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set(key, MAX_KEY_SIZE, "wxyz", 4));
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800178 ASSERT_EQ(size_t(4), mBC->get(key, MAX_KEY_SIZE, buf, 4));
179 ASSERT_EQ('w', buf[0]);
180 ASSERT_EQ('x', buf[1]);
181 ASSERT_EQ('y', buf[2]);
182 ASSERT_EQ('z', buf[3]);
183}
184
185TEST_F(BlobCacheTest, CacheMaxValueSizeSucceeds) {
186 char buf[MAX_VALUE_SIZE];
187 for (int i = 0; i < MAX_VALUE_SIZE; i++) {
188 buf[i] = 'b';
189 }
Leon Scroggins III23377962022-05-03 14:53:14 -0400190 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, buf, MAX_VALUE_SIZE));
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800191 for (int i = 0; i < MAX_VALUE_SIZE; i++) {
192 buf[i] = 0xee;
193 }
Yiwei Zhang8af03062020-08-12 21:28:15 -0700194 ASSERT_EQ(size_t(MAX_VALUE_SIZE), mBC->get("abcd", 4, buf, MAX_VALUE_SIZE));
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800195 for (int i = 0; i < MAX_VALUE_SIZE; i++) {
196 SCOPED_TRACE(i);
197 ASSERT_EQ('b', buf[i]);
198 }
199}
200
201TEST_F(BlobCacheTest, CacheMaxKeyValuePairSizeSucceeds) {
202 // Check a testing assumption
203 ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE);
204
205 enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE };
206
207 char key[MAX_KEY_SIZE];
208 char buf[bufSize];
209 for (int i = 0; i < MAX_KEY_SIZE; i++) {
210 key[i] = 'a';
211 }
212 for (int i = 0; i < bufSize; i++) {
213 buf[i] = 'b';
214 }
215
Leon Scroggins III23377962022-05-03 14:53:14 -0400216 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set(key, MAX_KEY_SIZE, buf, bufSize));
Yi Kong48a6cd22018-07-18 10:07:09 -0700217 ASSERT_EQ(size_t(bufSize), mBC->get(key, MAX_KEY_SIZE, nullptr, 0));
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800218}
219
Leon Scroggins III23377962022-05-03 14:53:14 -0400220// Verify that kNotEnoughSpace is returned from BlobCache::set when expected.
221// Note: This relies on internal knowledge of how BlobCache works.
222TEST_F(BlobCacheTest, NotEnoughSpace) {
223 // Insert a small entry into the cache.
224 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("x", 1, "y", 1));
225
226 // Attempt to put a max size entry into the cache. If the cache were empty,
227 // as in CacheMaxKeyValuePairSizeSucceeds, this would succeed. Based on the
228 // current logic of BlobCache, the small entry is not big enough to allow it
229 // to be cleaned to insert the new entry.
230 ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE);
231
232 enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE };
233
234 char key[MAX_KEY_SIZE];
235 char buf[bufSize];
236 for (int i = 0; i < MAX_KEY_SIZE; i++) {
237 key[i] = 'a';
238 }
239 for (int i = 0; i < bufSize; i++) {
240 buf[i] = 'b';
241 }
242
243 ASSERT_EQ(BlobCache::InsertResult::kNotEnoughSpace, mBC->set(key, MAX_KEY_SIZE, buf, bufSize));
244 ASSERT_EQ(0, mBC->get(key, MAX_KEY_SIZE, nullptr, 0));
245
246 // The original entry remains in the cache.
247 unsigned char buf2[1] = {0xee};
248 ASSERT_EQ(size_t(1), mBC->get("x", 1, buf2, 1));
249 ASSERT_EQ('y', buf2[0]);
250}
251
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800252TEST_F(BlobCacheTest, CacheMinKeyAndValueSizeSucceeds) {
Yiwei Zhang8af03062020-08-12 21:28:15 -0700253 unsigned char buf[1] = {0xee};
Leon Scroggins III23377962022-05-03 14:53:14 -0400254 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("x", 1, "y", 1));
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800255 ASSERT_EQ(size_t(1), mBC->get("x", 1, buf, 1));
256 ASSERT_EQ('y', buf[0]);
257}
258
259TEST_F(BlobCacheTest, CacheSizeDoesntExceedTotalLimit) {
260 for (int i = 0; i < 256; i++) {
261 uint8_t k = i;
262 mBC->set(&k, 1, "x", 1);
263 }
264 int numCached = 0;
265 for (int i = 0; i < 256; i++) {
266 uint8_t k = i;
Yi Kong48a6cd22018-07-18 10:07:09 -0700267 if (mBC->get(&k, 1, nullptr, 0) == 1) {
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800268 numCached++;
269 }
270 }
271 ASSERT_GE(MAX_TOTAL_SIZE / 2, numCached);
272}
273
274TEST_F(BlobCacheTest, ExceedingTotalLimitHalvesCacheSize) {
275 // Fill up the entire cache with 1 char key/value pairs.
276 const int maxEntries = MAX_TOTAL_SIZE / 2;
277 for (int i = 0; i < maxEntries; i++) {
278 uint8_t k = i;
Leon Scroggins III23377962022-05-03 14:53:14 -0400279 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set(&k, 1, "x", 1));
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800280 }
281 // Insert one more entry, causing a cache overflow.
282 {
283 uint8_t k = maxEntries;
Leon Scroggins III23377962022-05-03 14:53:14 -0400284 ASSERT_EQ(BlobCache::InsertResult::kDidClean, mBC->set(&k, 1, "x", 1));
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800285 }
286 // Count the number of entries in the cache.
287 int numCached = 0;
Yiwei Zhang8af03062020-08-12 21:28:15 -0700288 for (int i = 0; i < maxEntries + 1; i++) {
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800289 uint8_t k = i;
Yi Kong48a6cd22018-07-18 10:07:09 -0700290 if (mBC->get(&k, 1, nullptr, 0) == 1) {
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800291 numCached++;
292 }
293 }
Yiwei Zhang8af03062020-08-12 21:28:15 -0700294 ASSERT_EQ(maxEntries / 2 + 1, numCached);
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800295}
296
Leon Scroggins III23377962022-05-03 14:53:14 -0400297TEST_F(BlobCacheTest, InvalidKeySize) {
298 ASSERT_EQ(BlobCache::InsertResult::kInvalidKeySize, mBC->set("", 0, "efgh", 4));
299}
300
301TEST_F(BlobCacheTest, InvalidValueSize) {
302 ASSERT_EQ(BlobCache::InsertResult::kInvalidValueSize, mBC->set("abcd", 4, "", 0));
303}
304
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800305class BlobCacheFlattenTest : public BlobCacheTest {
306protected:
307 virtual void SetUp() {
308 BlobCacheTest::SetUp();
309 mBC2.reset(new BlobCache(MAX_KEY_SIZE, MAX_VALUE_SIZE, MAX_TOTAL_SIZE));
310 }
311
312 virtual void TearDown() {
313 mBC2.reset();
314 BlobCacheTest::TearDown();
315 }
316
317 void roundTrip() {
318 size_t size = mBC->getFlattenedSize();
319 uint8_t* flat = new uint8_t[size];
320 ASSERT_EQ(OK, mBC->flatten(flat, size));
321 ASSERT_EQ(OK, mBC2->unflatten(flat, size));
322 delete[] flat;
323 }
324
325 sp<BlobCache> mBC2;
326};
327
328TEST_F(BlobCacheFlattenTest, FlattenOneValue) {
Yiwei Zhang8af03062020-08-12 21:28:15 -0700329 unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800330 mBC->set("abcd", 4, "efgh", 4);
331 roundTrip();
332 ASSERT_EQ(size_t(4), mBC2->get("abcd", 4, buf, 4));
333 ASSERT_EQ('e', buf[0]);
334 ASSERT_EQ('f', buf[1]);
335 ASSERT_EQ('g', buf[2]);
336 ASSERT_EQ('h', buf[3]);
337}
338
339TEST_F(BlobCacheFlattenTest, FlattenFullCache) {
340 // Fill up the entire cache with 1 char key/value pairs.
341 const int maxEntries = MAX_TOTAL_SIZE / 2;
342 for (int i = 0; i < maxEntries; i++) {
343 uint8_t k = i;
344 mBC->set(&k, 1, &k, 1);
345 }
346
347 roundTrip();
348
349 // Verify the deserialized cache
350 for (int i = 0; i < maxEntries; i++) {
351 uint8_t k = i;
352 uint8_t v = 0xee;
353 ASSERT_EQ(size_t(1), mBC2->get(&k, 1, &v, 1));
354 ASSERT_EQ(k, v);
355 }
356}
357
358TEST_F(BlobCacheFlattenTest, FlattenDoesntChangeCache) {
359 // Fill up the entire cache with 1 char key/value pairs.
360 const int maxEntries = MAX_TOTAL_SIZE / 2;
361 for (int i = 0; i < maxEntries; i++) {
362 uint8_t k = i;
363 mBC->set(&k, 1, &k, 1);
364 }
365
366 size_t size = mBC->getFlattenedSize();
367 uint8_t* flat = new uint8_t[size];
368 ASSERT_EQ(OK, mBC->flatten(flat, size));
369 delete[] flat;
370
371 // Verify the cache that we just serialized
372 for (int i = 0; i < maxEntries; i++) {
373 uint8_t k = i;
374 uint8_t v = 0xee;
375 ASSERT_EQ(size_t(1), mBC->get(&k, 1, &v, 1));
376 ASSERT_EQ(k, v);
377 }
378}
379
380TEST_F(BlobCacheFlattenTest, FlattenCatchesBufferTooSmall) {
381 // Fill up the entire cache with 1 char key/value pairs.
382 const int maxEntries = MAX_TOTAL_SIZE / 2;
383 for (int i = 0; i < maxEntries; i++) {
384 uint8_t k = i;
385 mBC->set(&k, 1, &k, 1);
386 }
387
388 size_t size = mBC->getFlattenedSize() - 1;
389 uint8_t* flat = new uint8_t[size];
390 // ASSERT_EQ(BAD_VALUE, mBC->flatten(flat, size));
391 // TODO: The above fails. I expect this is so because getFlattenedSize()
392 // overstimates the size by using PROPERTY_VALUE_MAX.
393 delete[] flat;
394}
395
396TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadMagic) {
Yiwei Zhang8af03062020-08-12 21:28:15 -0700397 unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800398 mBC->set("abcd", 4, "efgh", 4);
399
400 size_t size = mBC->getFlattenedSize();
401 uint8_t* flat = new uint8_t[size];
402 ASSERT_EQ(OK, mBC->flatten(flat, size));
403 flat[1] = ~flat[1];
404
405 // Bad magic should cause an error.
406 ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size));
407 delete[] flat;
408
409 // The error should cause the unflatten to result in an empty cache
410 ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4));
411}
412
413TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheVersion) {
Yiwei Zhang8af03062020-08-12 21:28:15 -0700414 unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800415 mBC->set("abcd", 4, "efgh", 4);
416
417 size_t size = mBC->getFlattenedSize();
418 uint8_t* flat = new uint8_t[size];
419 ASSERT_EQ(OK, mBC->flatten(flat, size));
420 flat[5] = ~flat[5];
421
422 // Version mismatches shouldn't cause errors, but should not use the
423 // serialized entries
424 ASSERT_EQ(OK, mBC2->unflatten(flat, size));
425 delete[] flat;
426
427 // The version mismatch should cause the unflatten to result in an empty
428 // cache
429 ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4));
430}
431
432TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheDeviceVersion) {
Yiwei Zhang8af03062020-08-12 21:28:15 -0700433 unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800434 mBC->set("abcd", 4, "efgh", 4);
435
436 size_t size = mBC->getFlattenedSize();
437 uint8_t* flat = new uint8_t[size];
438 ASSERT_EQ(OK, mBC->flatten(flat, size));
439 flat[10] = ~flat[10];
440
441 // Version mismatches shouldn't cause errors, but should not use the
442 // serialized entries
443 ASSERT_EQ(OK, mBC2->unflatten(flat, size));
444 delete[] flat;
445
446 // The version mismatch should cause the unflatten to result in an empty
447 // cache
448 ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4));
449}
450
451TEST_F(BlobCacheFlattenTest, UnflattenCatchesBufferTooSmall) {
Yiwei Zhang8af03062020-08-12 21:28:15 -0700452 unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800453 mBC->set("abcd", 4, "efgh", 4);
454
455 size_t size = mBC->getFlattenedSize();
456 uint8_t* flat = new uint8_t[size];
457 ASSERT_EQ(OK, mBC->flatten(flat, size));
458
459 // A buffer truncation shouldt cause an error
460 // ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size-1));
461 // TODO: The above appears to fail because getFlattenedSize() is
462 // conservative.
463 delete[] flat;
464
465 // The error should cause the unflatten to result in an empty cache
466 ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4));
467}
468
Tom Cherry4fcb1c32023-02-17 15:13:59 -0800469// Test for a divide by zero bug (b/239862516). Before the fix, unflatten() would not reset
470// mTotalSize when it encountered an error, which would trigger division by 0 in clean() in the
471// right conditions.
472TEST_F(BlobCacheFlattenTest, SetAfterFailedUnflatten) {
473 // isCleanable() must be true, so mTotalSize must be > mMaxTotalSize / 2 after unflattening
474 // after one entry is lost. To make this the case, MaxTotalSize is 30 and three 10 sized
475 // entries are used. One of those entries is lost, resulting in mTotalSize=20
476 const size_t kMaxKeySize = 10;
477 const size_t kMaxValueSize = 10;
478 const size_t kMaxTotalSize = 30;
479 mBC.reset(new BlobCache(kMaxKeySize, kMaxValueSize, kMaxTotalSize));
480 mBC2.reset(new BlobCache(kMaxKeySize, kMaxValueSize, kMaxTotalSize));
481 mBC->set("aaaaa", 5, "aaaaa", 5);
482 mBC->set("bbbbb", 5, "bbbbb", 5);
483 mBC->set("ccccc", 5, "ccccc", 5);
484
485 size_t size = mBC->getFlattenedSize();
486 uint8_t* flat = new uint8_t[size];
487 ASSERT_EQ(OK, mBC->flatten(flat, size));
488
489 ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size - 10));
490 delete[] flat;
491
492 // This line will trigger clean() which caused a crash.
493 mBC2->set("dddddddddd", 10, "dddddddddd", 10);
494}
495
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800496} // namespace android