Home | History | Annotate | Download | only in cache
      1 /*
      2  * Copyright (c) 2013, Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "core/loader/cache/MemoryCache.h"
     33 
     34 #include "core/loader/cache/MockImageResourceClient.h"
     35 #include "core/loader/cache/RawResource.h"
     36 #include "core/loader/cache/ResourcePtr.h"
     37 #include "core/platform/network/ResourceRequest.h"
     38 #include "wtf/OwnPtr.h"
     39 
     40 #include <gtest/gtest.h>
     41 
     42 namespace WebCore {
     43 
     44 class MemoryCacheTest : public ::testing::Test {
     45 public:
     46     class MockImageResource : public WebCore::Resource {
     47     public:
     48         MockImageResource(const ResourceRequest& request, Type type)
     49             : Resource(request, type)
     50         {
     51         }
     52 
     53         virtual void appendData(const char* data, int len)
     54         {
     55             Resource::appendData(data, len);
     56             setDecodedSize(this->size());
     57         }
     58 
     59         virtual void destroyDecodedData()
     60         {
     61             setDecodedSize(0);
     62         }
     63     };
     64 
     65 protected:
     66     virtual void SetUp()
     67     {
     68         // Save the global memory cache to restore it upon teardown.
     69         m_globalMemoryCache = adoptPtr(memoryCache());
     70         // Create the test memory cache instance and hook it in.
     71         m_testingMemoryCache = adoptPtr(new MemoryCache());
     72         setMemoryCacheForTesting(m_testingMemoryCache.leakPtr());
     73     }
     74 
     75     virtual void TearDown()
     76     {
     77         // Regain the ownership of testing memory cache, so that it will be
     78         // destroyed.
     79         m_testingMemoryCache = adoptPtr(memoryCache());
     80         // Yield the ownership of the global memory cache back.
     81         setMemoryCacheForTesting(m_globalMemoryCache.leakPtr());
     82     }
     83 
     84     OwnPtr<MemoryCache> m_testingMemoryCache;
     85     OwnPtr<MemoryCache> m_globalMemoryCache;
     86 };
     87 
     88 // Verifies that setters and getters for cache capacities work correcty.
     89 TEST_F(MemoryCacheTest, CapacityAccounting)
     90 {
     91     const unsigned totalCapacity = 100;
     92     const unsigned minDeadCapacity = 10;
     93     const unsigned maxDeadCapacity = 50;
     94     memoryCache()->setCapacities(minDeadCapacity, maxDeadCapacity, totalCapacity);
     95 
     96     ASSERT_EQ(totalCapacity, memoryCache()->capacity());
     97     ASSERT_EQ(minDeadCapacity, memoryCache()->minDeadCapacity());
     98     ASSERT_EQ(maxDeadCapacity, memoryCache()->maxDeadCapacity());
     99 }
    100 
    101 // Verifies that dead resources that exceed dead resource capacity are evicted
    102 // from cache when pruning.
    103 TEST_F(MemoryCacheTest, DeadResourceEviction)
    104 {
    105     const unsigned totalCapacity = 1000000;
    106     const unsigned minDeadCapacity = 0;
    107     const unsigned maxDeadCapacity = 0;
    108     memoryCache()->setCapacities(minDeadCapacity, maxDeadCapacity, totalCapacity);
    109 
    110     ResourcePtr<Resource> cachedResource =
    111         new Resource(ResourceRequest(""), Resource::Raw);
    112     const char data[5] = "abcd";
    113     cachedResource->appendData(data, 3);
    114     // The resource size has to be nonzero for this test to be meaningful, but
    115     // we do not rely on it having any particular value.
    116     ASSERT_GT(cachedResource->size(), 0u);
    117 
    118     ASSERT_EQ(0u, memoryCache()->deadSize());
    119     ASSERT_EQ(0u, memoryCache()->liveSize());
    120 
    121     memoryCache()->add(cachedResource.get());
    122     ASSERT_EQ(cachedResource->size(), memoryCache()->deadSize());
    123     ASSERT_EQ(0u, memoryCache()->liveSize());
    124 
    125     memoryCache()->prune();
    126     ASSERT_EQ(0u, memoryCache()->deadSize());
    127     ASSERT_EQ(0u, memoryCache()->liveSize());
    128 }
    129 
    130 // Verifies that CachedResources are evicted from the decode cache
    131 // according to their DecodeCachePriority.
    132 TEST_F(MemoryCacheTest, DecodeCacheOrder)
    133 {
    134     memoryCache()->setDelayBeforeLiveDecodedPrune(0);
    135     ResourcePtr<MockImageResource> cachedImageLowPriority =
    136         new MockImageResource(ResourceRequest(""), Resource::Raw);
    137     ResourcePtr<MockImageResource> cachedImageHighPriority =
    138         new MockImageResource(ResourceRequest(""), Resource::Raw);
    139 
    140     MockImageResourceClient clientLowPriority;
    141     MockImageResourceClient clientHighPriority;
    142     cachedImageLowPriority->addClient(&clientLowPriority);
    143     cachedImageHighPriority->addClient(&clientHighPriority);
    144 
    145     const char data[5] = "abcd";
    146     cachedImageLowPriority->appendData(data, 1);
    147     cachedImageHighPriority->appendData(data, 4);
    148     const unsigned lowPrioritySize = cachedImageLowPriority->size();
    149     const unsigned highPrioritySize = cachedImageHighPriority->size();
    150     const unsigned lowPriorityMockDecodeSize = cachedImageLowPriority->decodedSize();
    151     const unsigned highPriorityMockDecodeSize = cachedImageHighPriority->decodedSize();
    152     const unsigned totalSize = lowPrioritySize + highPrioritySize;
    153 
    154     // Verify that the sizes are different to ensure that we can test eviction order.
    155     ASSERT_GT(lowPrioritySize, 0u);
    156     ASSERT_NE(lowPrioritySize, highPrioritySize);
    157     ASSERT_GT(lowPriorityMockDecodeSize, 0u);
    158     ASSERT_NE(lowPriorityMockDecodeSize, highPriorityMockDecodeSize);
    159 
    160     ASSERT_EQ(memoryCache()->deadSize(), 0u);
    161     ASSERT_EQ(memoryCache()->liveSize(), 0u);
    162 
    163     // Add the items. The item added first would normally be evicted first.
    164     memoryCache()->add(cachedImageHighPriority.get());
    165     ASSERT_EQ(memoryCache()->deadSize(), 0u);
    166     ASSERT_EQ(memoryCache()->liveSize(), highPrioritySize);
    167 
    168     memoryCache()->add(cachedImageLowPriority.get());
    169     ASSERT_EQ(memoryCache()->deadSize(), 0u);
    170     ASSERT_EQ(memoryCache()->liveSize(), highPrioritySize + lowPrioritySize);
    171 
    172     // Insert all items in the decoded items list with the same priority
    173     memoryCache()->insertInLiveDecodedResourcesList(cachedImageHighPriority.get());
    174     memoryCache()->insertInLiveDecodedResourcesList(cachedImageLowPriority.get());
    175     ASSERT_EQ(memoryCache()->deadSize(), 0u);
    176     ASSERT_EQ(memoryCache()->liveSize(), totalSize);
    177 
    178     // Now we will assign their priority and make sure they are moved to the correct buckets.
    179     cachedImageLowPriority->setCacheLiveResourcePriority(Resource::CacheLiveResourcePriorityLow);
    180     cachedImageHighPriority->setCacheLiveResourcePriority(Resource::CacheLiveResourcePriorityHigh);
    181 
    182     // Should first prune the LowPriority item.
    183     memoryCache()->setCapacities(memoryCache()->minDeadCapacity(), memoryCache()->liveSize() - 10, memoryCache()->liveSize() - 10);
    184     memoryCache()->prune();
    185     ASSERT_EQ(memoryCache()->deadSize(), 0u);
    186     ASSERT_EQ(memoryCache()->liveSize(), totalSize - lowPriorityMockDecodeSize);
    187 
    188     // Should prune the HighPriority item.
    189     memoryCache()->setCapacities(memoryCache()->minDeadCapacity(), memoryCache()->liveSize() - 10, memoryCache()->liveSize() - 10);
    190     memoryCache()->prune();
    191     ASSERT_EQ(memoryCache()->deadSize(), 0u);
    192     ASSERT_EQ(memoryCache()->liveSize(), totalSize - lowPriorityMockDecodeSize - highPriorityMockDecodeSize);
    193 }
    194 } // namespace
    195