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