1 /*
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
17 #include "BlobCache.h"
18
19 #include <fcntl.h>
20 #include <gtest/gtest.h>
21 #include <stdio.h>
22
23 #include <memory>
24
25 namespace android {
26
27 template <typename T>
28 using sp = std::shared_ptr<T>;
29
30 class BlobCacheTest : public ::testing::Test {
31 protected:
32 enum {
33 OK = 0,
34 BAD_VALUE = -EINVAL,
35 };
36
37 enum {
38 MAX_KEY_SIZE = 6,
39 MAX_VALUE_SIZE = 8,
40 MAX_TOTAL_SIZE = 13,
41 };
42
SetUp()43 virtual void SetUp() { mBC.reset(new BlobCache(MAX_KEY_SIZE, MAX_VALUE_SIZE, MAX_TOTAL_SIZE)); }
44
TearDown()45 virtual void TearDown() { mBC.reset(); }
46
47 std::unique_ptr<BlobCache> mBC;
48 };
49
TEST_F(BlobCacheTest,CacheSingleValueSucceeds)50 TEST_F(BlobCacheTest, CacheSingleValueSucceeds) {
51 unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
52 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
53 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
TEST_F(BlobCacheTest,CacheTwoValuesSucceeds)60 TEST_F(BlobCacheTest, CacheTwoValuesSucceeds) {
61 unsigned char buf[2] = {0xee, 0xee};
62 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("ab", 2, "cd", 2));
63 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("ef", 2, "gh", 2));
64 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
TEST_F(BlobCacheTest,GetOnlyWritesInsideBounds)72 TEST_F(BlobCacheTest, GetOnlyWritesInsideBounds) {
73 unsigned char buf[6] = {0xee, 0xee, 0xee, 0xee, 0xee, 0xee};
74 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
75 ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf + 1, 4));
76 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
TEST_F(BlobCacheTest,GetOnlyWritesIfBufferIsLargeEnough)84 TEST_F(BlobCacheTest, GetOnlyWritesIfBufferIsLargeEnough) {
85 unsigned char buf[3] = {0xee, 0xee, 0xee};
86 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
87 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
TEST_F(BlobCacheTest,GetDoesntAccessNullBuffer)93 TEST_F(BlobCacheTest, GetDoesntAccessNullBuffer) {
94 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
95 ASSERT_EQ(size_t(4), mBC->get("abcd", 4, nullptr, 0));
96 }
97
TEST_F(BlobCacheTest,MultipleSetsCacheLatestValue)98 TEST_F(BlobCacheTest, MultipleSetsCacheLatestValue) {
99 unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
100 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
101 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "ijkl", 4));
102 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
TEST_F(BlobCacheTest,SecondSetKeepsFirstValueIfTooLarge)109 TEST_F(BlobCacheTest, SecondSetKeepsFirstValueIfTooLarge) {
110 unsigned char buf[MAX_VALUE_SIZE + 1] = {0xee, 0xee, 0xee, 0xee};
111 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));
113 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
TEST_F(BlobCacheTest,DoesntCacheIfKeyIsTooBig)120 TEST_F(BlobCacheTest, DoesntCacheIfKeyIsTooBig) {
121 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++) {
124 key[i] = 'a';
125 }
126 ASSERT_EQ(BlobCache::InsertResult::kKeyTooBig, mBC->set(key, MAX_KEY_SIZE + 1, "bbbb", 4));
127 ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE + 1, buf, 4));
128 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
TEST_F(BlobCacheTest,DoesntCacheIfValueIsTooBig)134 TEST_F(BlobCacheTest, DoesntCacheIfValueIsTooBig) {
135 char buf[MAX_VALUE_SIZE + 1];
136 for (int i = 0; i < MAX_VALUE_SIZE + 1; i++) {
137 buf[i] = 'b';
138 }
139 ASSERT_EQ(BlobCache::InsertResult::kValueTooBig, mBC->set("abcd", 4, buf, MAX_VALUE_SIZE + 1));
140 for (int i = 0; i < MAX_VALUE_SIZE + 1; i++) {
141 buf[i] = 0xee;
142 }
143 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++) {
145 SCOPED_TRACE(i);
146 ASSERT_EQ(0xee, buf[i]);
147 }
148 }
149
TEST_F(BlobCacheTest,DoesntCacheIfKeyValuePairIsTooBig)150 TEST_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
166 ASSERT_EQ(BlobCache::InsertResult::kCombinedTooBig,
167 mBC->set(key, MAX_KEY_SIZE, buf, MAX_VALUE_SIZE));
168 ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE, nullptr, 0));
169 }
170
TEST_F(BlobCacheTest,CacheMaxKeySizeSucceeds)171 TEST_F(BlobCacheTest, CacheMaxKeySizeSucceeds) {
172 char key[MAX_KEY_SIZE];
173 unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
174 for (int i = 0; i < MAX_KEY_SIZE; i++) {
175 key[i] = 'a';
176 }
177 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set(key, MAX_KEY_SIZE, "wxyz", 4));
178 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
TEST_F(BlobCacheTest,CacheMaxValueSizeSucceeds)185 TEST_F(BlobCacheTest, CacheMaxValueSizeSucceeds) {
186 char buf[MAX_VALUE_SIZE];
187 for (int i = 0; i < MAX_VALUE_SIZE; i++) {
188 buf[i] = 'b';
189 }
190 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, buf, MAX_VALUE_SIZE));
191 for (int i = 0; i < MAX_VALUE_SIZE; i++) {
192 buf[i] = 0xee;
193 }
194 ASSERT_EQ(size_t(MAX_VALUE_SIZE), mBC->get("abcd", 4, buf, MAX_VALUE_SIZE));
195 for (int i = 0; i < MAX_VALUE_SIZE; i++) {
196 SCOPED_TRACE(i);
197 ASSERT_EQ('b', buf[i]);
198 }
199 }
200
TEST_F(BlobCacheTest,CacheMaxKeyValuePairSizeSucceeds)201 TEST_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
216 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set(key, MAX_KEY_SIZE, buf, bufSize));
217 ASSERT_EQ(size_t(bufSize), mBC->get(key, MAX_KEY_SIZE, nullptr, 0));
218 }
219
220 // Verify that kNotEnoughSpace is returned from BlobCache::set when expected.
221 // Note: This relies on internal knowledge of how BlobCache works.
TEST_F(BlobCacheTest,NotEnoughSpace)222 TEST_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
TEST_F(BlobCacheTest,CacheMinKeyAndValueSizeSucceeds)252 TEST_F(BlobCacheTest, CacheMinKeyAndValueSizeSucceeds) {
253 unsigned char buf[1] = {0xee};
254 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("x", 1, "y", 1));
255 ASSERT_EQ(size_t(1), mBC->get("x", 1, buf, 1));
256 ASSERT_EQ('y', buf[0]);
257 }
258
TEST_F(BlobCacheTest,CacheSizeDoesntExceedTotalLimit)259 TEST_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;
267 if (mBC->get(&k, 1, nullptr, 0) == 1) {
268 numCached++;
269 }
270 }
271 ASSERT_GE(MAX_TOTAL_SIZE / 2, numCached);
272 }
273
TEST_F(BlobCacheTest,ExceedingTotalLimitHalvesCacheSize)274 TEST_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;
279 ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set(&k, 1, "x", 1));
280 }
281 // Insert one more entry, causing a cache overflow.
282 {
283 uint8_t k = maxEntries;
284 ASSERT_EQ(BlobCache::InsertResult::kDidClean, mBC->set(&k, 1, "x", 1));
285 }
286 // Count the number of entries in the cache.
287 int numCached = 0;
288 for (int i = 0; i < maxEntries + 1; i++) {
289 uint8_t k = i;
290 if (mBC->get(&k, 1, nullptr, 0) == 1) {
291 numCached++;
292 }
293 }
294 ASSERT_EQ(maxEntries / 2 + 1, numCached);
295 }
296
TEST_F(BlobCacheTest,InvalidKeySize)297 TEST_F(BlobCacheTest, InvalidKeySize) {
298 ASSERT_EQ(BlobCache::InsertResult::kInvalidKeySize, mBC->set("", 0, "efgh", 4));
299 }
300
TEST_F(BlobCacheTest,InvalidValueSize)301 TEST_F(BlobCacheTest, InvalidValueSize) {
302 ASSERT_EQ(BlobCache::InsertResult::kInvalidValueSize, mBC->set("abcd", 4, "", 0));
303 }
304
305 class BlobCacheFlattenTest : public BlobCacheTest {
306 protected:
SetUp()307 virtual void SetUp() {
308 BlobCacheTest::SetUp();
309 mBC2.reset(new BlobCache(MAX_KEY_SIZE, MAX_VALUE_SIZE, MAX_TOTAL_SIZE));
310 }
311
TearDown()312 virtual void TearDown() {
313 mBC2.reset();
314 BlobCacheTest::TearDown();
315 }
316
roundTrip()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
TEST_F(BlobCacheFlattenTest,FlattenOneValue)328 TEST_F(BlobCacheFlattenTest, FlattenOneValue) {
329 unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
330 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
TEST_F(BlobCacheFlattenTest,FlattenFullCache)339 TEST_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
TEST_F(BlobCacheFlattenTest,FlattenDoesntChangeCache)358 TEST_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
TEST_F(BlobCacheFlattenTest,FlattenCatchesBufferTooSmall)380 TEST_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
TEST_F(BlobCacheFlattenTest,UnflattenCatchesBadMagic)396 TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadMagic) {
397 unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
398 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
TEST_F(BlobCacheFlattenTest,UnflattenCatchesBadBlobCacheVersion)413 TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheVersion) {
414 unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
415 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
TEST_F(BlobCacheFlattenTest,UnflattenCatchesBadBlobCacheDeviceVersion)432 TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheDeviceVersion) {
433 unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
434 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
TEST_F(BlobCacheFlattenTest,UnflattenCatchesBufferTooSmall)451 TEST_F(BlobCacheFlattenTest, UnflattenCatchesBufferTooSmall) {
452 unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
453 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
469 // 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.
TEST_F(BlobCacheFlattenTest,SetAfterFailedUnflatten)472 TEST_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
496 } // namespace android
497