blob: 7202123eb69fe3d81816540fdcd3304f8ac2d561 [file] [log] [blame]
Jamie Gennis1a209932011-04-28 16:19:45 -07001/*
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
Jamie Gennis7451bb42011-05-12 17:39:03 -070017#include <fcntl.h>
18#include <stdio.h>
19
Jamie Gennis1a209932011-04-28 16:19:45 -070020#include <gtest/gtest.h>
21
22#include <utils/BlobCache.h>
Jamie Gennis7451bb42011-05-12 17:39:03 -070023#include <utils/Errors.h>
Jamie Gennis1a209932011-04-28 16:19:45 -070024
25namespace android {
26
27class BlobCacheTest : public ::testing::Test {
28protected:
29 enum {
30 MAX_KEY_SIZE = 6,
31 MAX_VALUE_SIZE = 8,
32 MAX_TOTAL_SIZE = 13,
33 };
34
35 virtual void SetUp() {
36 mBC = new BlobCache(MAX_KEY_SIZE, MAX_VALUE_SIZE, MAX_TOTAL_SIZE);
37 }
38
39 virtual void TearDown() {
40 mBC.clear();
41 }
42
43 sp<BlobCache> mBC;
44};
45
46TEST_F(BlobCacheTest, CacheSingleValueSucceeds) {
47 char buf[4] = { 0xee, 0xee, 0xee, 0xee };
48 mBC->set("abcd", 4, "efgh", 4);
49 ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
50 ASSERT_EQ('e', buf[0]);
51 ASSERT_EQ('f', buf[1]);
52 ASSERT_EQ('g', buf[2]);
53 ASSERT_EQ('h', buf[3]);
54}
55
56TEST_F(BlobCacheTest, CacheTwoValuesSucceeds) {
57 char buf[2] = { 0xee, 0xee };
58 mBC->set("ab", 2, "cd", 2);
59 mBC->set("ef", 2, "gh", 2);
60 ASSERT_EQ(size_t(2), mBC->get("ab", 2, buf, 2));
61 ASSERT_EQ('c', buf[0]);
62 ASSERT_EQ('d', buf[1]);
63 ASSERT_EQ(size_t(2), mBC->get("ef", 2, buf, 2));
64 ASSERT_EQ('g', buf[0]);
65 ASSERT_EQ('h', buf[1]);
66}
67
68TEST_F(BlobCacheTest, GetOnlyWritesInsideBounds) {
69 char buf[6] = { 0xee, 0xee, 0xee, 0xee, 0xee, 0xee };
70 mBC->set("abcd", 4, "efgh", 4);
71 ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf+1, 4));
72 ASSERT_EQ(0xee, buf[0]);
73 ASSERT_EQ('e', buf[1]);
74 ASSERT_EQ('f', buf[2]);
75 ASSERT_EQ('g', buf[3]);
76 ASSERT_EQ('h', buf[4]);
77 ASSERT_EQ(0xee, buf[5]);
78}
79
80TEST_F(BlobCacheTest, GetOnlyWritesIfBufferIsLargeEnough) {
81 char buf[3] = { 0xee, 0xee, 0xee };
82 mBC->set("abcd", 4, "efgh", 4);
83 ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 3));
84 ASSERT_EQ(0xee, buf[0]);
85 ASSERT_EQ(0xee, buf[1]);
86 ASSERT_EQ(0xee, buf[2]);
87}
88
89TEST_F(BlobCacheTest, GetDoesntAccessNullBuffer) {
90 mBC->set("abcd", 4, "efgh", 4);
91 ASSERT_EQ(size_t(4), mBC->get("abcd", 4, NULL, 0));
92}
93
94TEST_F(BlobCacheTest, MultipleSetsCacheLatestValue) {
95 char buf[4] = { 0xee, 0xee, 0xee, 0xee };
96 mBC->set("abcd", 4, "efgh", 4);
97 mBC->set("abcd", 4, "ijkl", 4);
98 ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
99 ASSERT_EQ('i', buf[0]);
100 ASSERT_EQ('j', buf[1]);
101 ASSERT_EQ('k', buf[2]);
102 ASSERT_EQ('l', buf[3]);
103}
104
105TEST_F(BlobCacheTest, SecondSetKeepsFirstValueIfTooLarge) {
106 char buf[MAX_VALUE_SIZE+1] = { 0xee, 0xee, 0xee, 0xee };
107 mBC->set("abcd", 4, "efgh", 4);
108 mBC->set("abcd", 4, buf, MAX_VALUE_SIZE+1);
109 ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
110 ASSERT_EQ('e', buf[0]);
111 ASSERT_EQ('f', buf[1]);
112 ASSERT_EQ('g', buf[2]);
113 ASSERT_EQ('h', buf[3]);
114}
115
116TEST_F(BlobCacheTest, DoesntCacheIfKeyIsTooBig) {
117 char key[MAX_KEY_SIZE+1];
118 char buf[4] = { 0xee, 0xee, 0xee, 0xee };
119 for (int i = 0; i < MAX_KEY_SIZE+1; i++) {
120 key[i] = 'a';
121 }
122 mBC->set(key, MAX_KEY_SIZE+1, "bbbb", 4);
123 ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE+1, buf, 4));
124 ASSERT_EQ(0xee, buf[0]);
125 ASSERT_EQ(0xee, buf[1]);
126 ASSERT_EQ(0xee, buf[2]);
127 ASSERT_EQ(0xee, buf[3]);
128}
129
130TEST_F(BlobCacheTest, DoesntCacheIfValueIsTooBig) {
131 char buf[MAX_VALUE_SIZE+1];
132 for (int i = 0; i < MAX_VALUE_SIZE+1; i++) {
133 buf[i] = 'b';
134 }
135 mBC->set("abcd", 4, buf, MAX_VALUE_SIZE+1);
136 for (int i = 0; i < MAX_VALUE_SIZE+1; i++) {
137 buf[i] = 0xee;
138 }
139 ASSERT_EQ(size_t(0), mBC->get("abcd", 4, buf, MAX_VALUE_SIZE+1));
140 for (int i = 0; i < MAX_VALUE_SIZE+1; i++) {
141 SCOPED_TRACE(i);
142 ASSERT_EQ(0xee, buf[i]);
143 }
144}
145
146TEST_F(BlobCacheTest, DoesntCacheIfKeyValuePairIsTooBig) {
147 // Check a testing assumptions
148 ASSERT_TRUE(MAX_TOTAL_SIZE < MAX_KEY_SIZE + MAX_VALUE_SIZE);
149 ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE);
150
151 enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE + 1 };
152
153 char key[MAX_KEY_SIZE];
154 char buf[bufSize];
155 for (int i = 0; i < MAX_KEY_SIZE; i++) {
156 key[i] = 'a';
157 }
158 for (int i = 0; i < bufSize; i++) {
159 buf[i] = 'b';
160 }
161
162 mBC->set(key, MAX_KEY_SIZE, buf, MAX_VALUE_SIZE);
163 ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE, NULL, 0));
164}
165
166TEST_F(BlobCacheTest, CacheMaxKeySizeSucceeds) {
167 char key[MAX_KEY_SIZE];
168 char buf[4] = { 0xee, 0xee, 0xee, 0xee };
169 for (int i = 0; i < MAX_KEY_SIZE; i++) {
170 key[i] = 'a';
171 }
172 mBC->set(key, MAX_KEY_SIZE, "wxyz", 4);
173 ASSERT_EQ(size_t(4), mBC->get(key, MAX_KEY_SIZE, buf, 4));
174 ASSERT_EQ('w', buf[0]);
175 ASSERT_EQ('x', buf[1]);
176 ASSERT_EQ('y', buf[2]);
177 ASSERT_EQ('z', buf[3]);
178}
179
180TEST_F(BlobCacheTest, CacheMaxValueSizeSucceeds) {
181 char buf[MAX_VALUE_SIZE];
182 for (int i = 0; i < MAX_VALUE_SIZE; i++) {
183 buf[i] = 'b';
184 }
185 mBC->set("abcd", 4, buf, MAX_VALUE_SIZE);
186 for (int i = 0; i < MAX_VALUE_SIZE; i++) {
187 buf[i] = 0xee;
188 }
189 ASSERT_EQ(size_t(MAX_VALUE_SIZE), mBC->get("abcd", 4, buf,
190 MAX_VALUE_SIZE));
191 for (int i = 0; i < MAX_VALUE_SIZE; i++) {
192 SCOPED_TRACE(i);
193 ASSERT_EQ('b', buf[i]);
194 }
195}
196
197TEST_F(BlobCacheTest, CacheMaxKeyValuePairSizeSucceeds) {
198 // Check a testing assumption
199 ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE);
200
201 enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE };
202
203 char key[MAX_KEY_SIZE];
204 char buf[bufSize];
205 for (int i = 0; i < MAX_KEY_SIZE; i++) {
206 key[i] = 'a';
207 }
208 for (int i = 0; i < bufSize; i++) {
209 buf[i] = 'b';
210 }
211
212 mBC->set(key, MAX_KEY_SIZE, buf, bufSize);
213 ASSERT_EQ(size_t(bufSize), mBC->get(key, MAX_KEY_SIZE, NULL, 0));
214}
215
216TEST_F(BlobCacheTest, CacheMinKeyAndValueSizeSucceeds) {
217 char buf[1] = { 0xee };
218 mBC->set("x", 1, "y", 1);
219 ASSERT_EQ(size_t(1), mBC->get("x", 1, buf, 1));
220 ASSERT_EQ('y', buf[0]);
221}
222
223TEST_F(BlobCacheTest, CacheSizeDoesntExceedTotalLimit) {
224 for (int i = 0; i < 256; i++) {
225 uint8_t k = i;
226 mBC->set(&k, 1, "x", 1);
227 }
228 int numCached = 0;
229 for (int i = 0; i < 256; i++) {
230 uint8_t k = i;
231 if (mBC->get(&k, 1, NULL, 0) == 1) {
232 numCached++;
233 }
234 }
235 ASSERT_GE(MAX_TOTAL_SIZE / 2, numCached);
236}
237
238TEST_F(BlobCacheTest, ExceedingTotalLimitHalvesCacheSize) {
239 // Fill up the entire cache with 1 char key/value pairs.
240 const int maxEntries = MAX_TOTAL_SIZE / 2;
241 for (int i = 0; i < maxEntries; i++) {
242 uint8_t k = i;
243 mBC->set(&k, 1, "x", 1);
244 }
245 // Insert one more entry, causing a cache overflow.
246 {
247 uint8_t k = maxEntries;
248 mBC->set(&k, 1, "x", 1);
249 }
250 // Count the number of entries in the cache.
251 int numCached = 0;
252 for (int i = 0; i < maxEntries+1; i++) {
253 uint8_t k = i;
254 if (mBC->get(&k, 1, NULL, 0) == 1) {
255 numCached++;
256 }
257 }
258 ASSERT_EQ(maxEntries/2 + 1, numCached);
259}
260
Jamie Gennis7451bb42011-05-12 17:39:03 -0700261class BlobCacheFlattenTest : public BlobCacheTest {
262protected:
263 virtual void SetUp() {
264 BlobCacheTest::SetUp();
265 mBC2 = new BlobCache(MAX_KEY_SIZE, MAX_VALUE_SIZE, MAX_TOTAL_SIZE);
266 }
267
268 virtual void TearDown() {
269 mBC2.clear();
270 BlobCacheTest::TearDown();
271 }
272
273 void roundTrip() {
274 size_t size = mBC->getFlattenedSize();
275 uint8_t* flat = new uint8_t[size];
Brian Carlstrom5189f9a2013-07-31 01:08:36 -0700276 ASSERT_EQ(OK, mBC->flatten(flat, size));
277 ASSERT_EQ(OK, mBC2->unflatten(flat, size));
Jamie Gennis7451bb42011-05-12 17:39:03 -0700278 delete[] flat;
279 }
280
281 sp<BlobCache> mBC2;
282};
283
284TEST_F(BlobCacheFlattenTest, FlattenOneValue) {
285 char buf[4] = { 0xee, 0xee, 0xee, 0xee };
286 mBC->set("abcd", 4, "efgh", 4);
287 roundTrip();
288 ASSERT_EQ(size_t(4), mBC2->get("abcd", 4, buf, 4));
289 ASSERT_EQ('e', buf[0]);
290 ASSERT_EQ('f', buf[1]);
291 ASSERT_EQ('g', buf[2]);
292 ASSERT_EQ('h', buf[3]);
293}
294
295TEST_F(BlobCacheFlattenTest, FlattenFullCache) {
296 // Fill up the entire cache with 1 char key/value pairs.
297 const int maxEntries = MAX_TOTAL_SIZE / 2;
298 for (int i = 0; i < maxEntries; i++) {
299 uint8_t k = i;
300 mBC->set(&k, 1, &k, 1);
301 }
302
303 roundTrip();
304
305 // Verify the deserialized cache
306 for (int i = 0; i < maxEntries; i++) {
307 uint8_t k = i;
308 uint8_t v = 0xee;
309 ASSERT_EQ(size_t(1), mBC2->get(&k, 1, &v, 1));
310 ASSERT_EQ(k, v);
311 }
312}
313
314TEST_F(BlobCacheFlattenTest, FlattenDoesntChangeCache) {
315 // Fill up the entire cache with 1 char key/value pairs.
316 const int maxEntries = MAX_TOTAL_SIZE / 2;
317 for (int i = 0; i < maxEntries; i++) {
318 uint8_t k = i;
319 mBC->set(&k, 1, &k, 1);
320 }
321
322 size_t size = mBC->getFlattenedSize();
323 uint8_t* flat = new uint8_t[size];
Brian Carlstrom5189f9a2013-07-31 01:08:36 -0700324 ASSERT_EQ(OK, mBC->flatten(flat, size));
Jamie Gennis7451bb42011-05-12 17:39:03 -0700325 delete[] flat;
326
327 // Verify the cache that we just serialized
328 for (int i = 0; i < maxEntries; i++) {
329 uint8_t k = i;
330 uint8_t v = 0xee;
331 ASSERT_EQ(size_t(1), mBC->get(&k, 1, &v, 1));
332 ASSERT_EQ(k, v);
333 }
334}
335
336TEST_F(BlobCacheFlattenTest, FlattenCatchesBufferTooSmall) {
337 // Fill up the entire cache with 1 char key/value pairs.
338 const int maxEntries = MAX_TOTAL_SIZE / 2;
339 for (int i = 0; i < maxEntries; i++) {
340 uint8_t k = i;
341 mBC->set(&k, 1, &k, 1);
342 }
343
344 size_t size = mBC->getFlattenedSize() - 1;
345 uint8_t* flat = new uint8_t[size];
Brian Carlstrom5189f9a2013-07-31 01:08:36 -0700346 ASSERT_EQ(BAD_VALUE, mBC->flatten(flat, size));
Jamie Gennis7451bb42011-05-12 17:39:03 -0700347 delete[] flat;
348}
349
350TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadMagic) {
351 char buf[4] = { 0xee, 0xee, 0xee, 0xee };
352 mBC->set("abcd", 4, "efgh", 4);
353
354 size_t size = mBC->getFlattenedSize();
355 uint8_t* flat = new uint8_t[size];
Brian Carlstrom5189f9a2013-07-31 01:08:36 -0700356 ASSERT_EQ(OK, mBC->flatten(flat, size));
Jamie Gennis7451bb42011-05-12 17:39:03 -0700357 flat[1] = ~flat[1];
358
359 // Bad magic should cause an error.
Brian Carlstrom5189f9a2013-07-31 01:08:36 -0700360 ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size));
Jamie Gennis7451bb42011-05-12 17:39:03 -0700361 delete[] flat;
362
363 // The error should cause the unflatten to result in an empty cache
364 ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4));
365}
366
367TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheVersion) {
368 char buf[4] = { 0xee, 0xee, 0xee, 0xee };
369 mBC->set("abcd", 4, "efgh", 4);
370
371 size_t size = mBC->getFlattenedSize();
372 uint8_t* flat = new uint8_t[size];
Brian Carlstrom5189f9a2013-07-31 01:08:36 -0700373 ASSERT_EQ(OK, mBC->flatten(flat, size));
Jamie Gennis7451bb42011-05-12 17:39:03 -0700374 flat[5] = ~flat[5];
375
376 // Version mismatches shouldn't cause errors, but should not use the
377 // serialized entries
Brian Carlstrom5189f9a2013-07-31 01:08:36 -0700378 ASSERT_EQ(OK, mBC2->unflatten(flat, size));
Jamie Gennis7451bb42011-05-12 17:39:03 -0700379 delete[] flat;
380
381 // The version mismatch should cause the unflatten to result in an empty
382 // cache
383 ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4));
384}
385
386TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheDeviceVersion) {
387 char buf[4] = { 0xee, 0xee, 0xee, 0xee };
388 mBC->set("abcd", 4, "efgh", 4);
389
390 size_t size = mBC->getFlattenedSize();
391 uint8_t* flat = new uint8_t[size];
Brian Carlstrom5189f9a2013-07-31 01:08:36 -0700392 ASSERT_EQ(OK, mBC->flatten(flat, size));
Jamie Gennis7451bb42011-05-12 17:39:03 -0700393 flat[10] = ~flat[10];
394
395 // Version mismatches shouldn't cause errors, but should not use the
396 // serialized entries
Brian Carlstrom5189f9a2013-07-31 01:08:36 -0700397 ASSERT_EQ(OK, mBC2->unflatten(flat, size));
Jamie Gennis7451bb42011-05-12 17:39:03 -0700398 delete[] flat;
399
400 // The version mismatch should cause the unflatten to result in an empty
401 // cache
402 ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4));
403}
404
405TEST_F(BlobCacheFlattenTest, UnflattenCatchesBufferTooSmall) {
406 char buf[4] = { 0xee, 0xee, 0xee, 0xee };
407 mBC->set("abcd", 4, "efgh", 4);
408
409 size_t size = mBC->getFlattenedSize();
410 uint8_t* flat = new uint8_t[size];
Brian Carlstrom5189f9a2013-07-31 01:08:36 -0700411 ASSERT_EQ(OK, mBC->flatten(flat, size));
Jamie Gennis7451bb42011-05-12 17:39:03 -0700412
413 // A buffer truncation shouldt cause an error
Brian Carlstrom5189f9a2013-07-31 01:08:36 -0700414 ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size-1));
Jamie Gennis7451bb42011-05-12 17:39:03 -0700415 delete[] flat;
416
417 // The error should cause the unflatten to result in an empty cache
418 ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4));
419}
420
Jamie Gennis1a209932011-04-28 16:19:45 -0700421} // namespace android