Home | History | Annotate | Download | only in tests
      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 <fcntl.h>
     18 #include <stdio.h>
     19 
     20 #include <gtest/gtest.h>
     21 
     22 #include <utils/BlobCache.h>
     23 #include <utils/Errors.h>
     24 
     25 namespace android {
     26 
     27 class BlobCacheTest : public ::testing::Test {
     28 protected:
     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 
     46 TEST_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 
     56 TEST_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 
     68 TEST_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 
     80 TEST_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 
     89 TEST_F(BlobCacheTest, GetDoesntAccessNullBuffer) {
     90     mBC->set("abcd", 4, "efgh", 4);
     91     ASSERT_EQ(size_t(4), mBC->get("abcd", 4, NULL, 0));
     92 }
     93 
     94 TEST_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 
    105 TEST_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 
    116 TEST_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 
    130 TEST_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 
    146 TEST_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 
    166 TEST_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 
    180 TEST_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 
    197 TEST_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 
    216 TEST_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 
    223 TEST_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 
    238 TEST_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 
    261 class BlobCacheFlattenTest : public BlobCacheTest {
    262 protected:
    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];
    276         ASSERT_EQ(OK, mBC->flatten(flat, size, NULL, 0));
    277         ASSERT_EQ(OK, mBC2->unflatten(flat, size, NULL, 0));
    278         delete[] flat;
    279     }
    280 
    281     sp<BlobCache> mBC2;
    282 };
    283 
    284 TEST_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 
    295 TEST_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 
    314 TEST_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];
    324     ASSERT_EQ(OK, mBC->flatten(flat, size, NULL, 0));
    325     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 
    336 TEST_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];
    346     ASSERT_EQ(BAD_VALUE, mBC->flatten(flat, size, NULL, 0));
    347     delete[] flat;
    348 }
    349 
    350 TEST_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];
    356     ASSERT_EQ(OK, mBC->flatten(flat, size, NULL, 0));
    357     flat[1] = ~flat[1];
    358 
    359     // Bad magic should cause an error.
    360     ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size, NULL, 0));
    361     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 
    367 TEST_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];
    373     ASSERT_EQ(OK, mBC->flatten(flat, size, NULL, 0));
    374     flat[5] = ~flat[5];
    375 
    376     // Version mismatches shouldn't cause errors, but should not use the
    377     // serialized entries
    378     ASSERT_EQ(OK, mBC2->unflatten(flat, size, NULL, 0));
    379     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 
    386 TEST_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];
    392     ASSERT_EQ(OK, mBC->flatten(flat, size, NULL, 0));
    393     flat[10] = ~flat[10];
    394 
    395     // Version mismatches shouldn't cause errors, but should not use the
    396     // serialized entries
    397     ASSERT_EQ(OK, mBC2->unflatten(flat, size, NULL, 0));
    398     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 
    405 TEST_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];
    411     ASSERT_EQ(OK, mBC->flatten(flat, size, NULL, 0));
    412 
    413     // A buffer truncation shouldt cause an error
    414     ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size-1, NULL, 0));
    415     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 
    421 } // namespace android
    422