Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / fetch / MemoryCacheTest.cpp
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/fetch/MemoryCache.h"
33
34 #include "core/fetch/MockImageResourceClient.h"
35 #include "core/fetch/RawResource.h"
36 #include "core/fetch/ResourcePtr.h"
37 #include "platform/network/ResourceRequest.h"
38 #include "public/platform/Platform.h"
39 #include "wtf/OwnPtr.h"
40
41 #include <gtest/gtest.h>
42
43 namespace blink {
44
45 class MemoryCacheTest : public ::testing::Test {
46 public:
47     class FakeDecodedResource : public blink::Resource {
48     public:
49         FakeDecodedResource(const ResourceRequest& request, Type type)
50             : Resource(request, type)
51         {
52         }
53
54         virtual void appendData(const char* data, unsigned len)
55         {
56             Resource::appendData(data, len);
57             setDecodedSize(this->size());
58         }
59
60     protected:
61         virtual void destroyDecodedDataIfPossible() override
62         {
63             setDecodedSize(0);
64         }
65     };
66
67     class FakeResource : public blink::Resource {
68     public:
69         FakeResource(const ResourceRequest& request, Type type)
70             : Resource(request, type)
71         {
72         }
73
74         void fakeEncodedSize(size_t size)
75         {
76             setEncodedSize(size);
77         }
78     };
79
80 protected:
81     virtual void SetUp()
82     {
83         // Save the global memory cache to restore it upon teardown.
84         m_globalMemoryCache = replaceMemoryCacheForTesting(MemoryCache::create());
85     }
86
87     virtual void TearDown()
88     {
89         replaceMemoryCacheForTesting(m_globalMemoryCache.release());
90     }
91
92     OwnPtrWillBePersistent<MemoryCache> m_globalMemoryCache;
93 };
94
95 // Verifies that setters and getters for cache capacities work correcty.
96 TEST_F(MemoryCacheTest, CapacityAccounting)
97 {
98     const size_t sizeMax = ~static_cast<size_t>(0);
99     const size_t totalCapacity = sizeMax / 4;
100     const size_t minDeadCapacity = sizeMax / 16;
101     const size_t maxDeadCapacity = sizeMax / 8;
102     memoryCache()->setCapacities(minDeadCapacity, maxDeadCapacity, totalCapacity);
103     ASSERT_EQ(totalCapacity, memoryCache()->capacity());
104     ASSERT_EQ(minDeadCapacity, memoryCache()->minDeadCapacity());
105     ASSERT_EQ(maxDeadCapacity, memoryCache()->maxDeadCapacity());
106 }
107
108 TEST_F(MemoryCacheTest, VeryLargeResourceAccounting)
109 {
110     const size_t sizeMax = ~static_cast<size_t>(0);
111     const size_t totalCapacity = sizeMax / 4;
112     const size_t minDeadCapacity = sizeMax / 16;
113     const size_t maxDeadCapacity = sizeMax / 8;
114     const size_t resourceSize1 = sizeMax / 16;
115     const size_t resourceSize2 = sizeMax / 20;
116     memoryCache()->setCapacities(minDeadCapacity, maxDeadCapacity, totalCapacity);
117     ResourcePtr<FakeResource> cachedResource =
118         new FakeResource(ResourceRequest("http://test/resource"), Resource::Raw);
119     cachedResource->fakeEncodedSize(resourceSize1);
120
121     ASSERT_EQ(0u, memoryCache()->deadSize());
122     ASSERT_EQ(0u, memoryCache()->liveSize());
123     memoryCache()->add(cachedResource.get());
124     ASSERT_EQ(cachedResource->size(), memoryCache()->deadSize());
125     ASSERT_EQ(0u, memoryCache()->liveSize());
126
127     MockImageResourceClient client;
128     cachedResource->addClient(&client);
129     ASSERT_EQ(0u, memoryCache()->deadSize());
130     ASSERT_EQ(cachedResource->size(), memoryCache()->liveSize());
131
132     cachedResource->fakeEncodedSize(resourceSize2);
133     ASSERT_EQ(0u, memoryCache()->deadSize());
134     ASSERT_EQ(cachedResource->size(), memoryCache()->liveSize());
135
136     cachedResource->removeClient(&client);
137 }
138
139 // Verifies that dead resources that exceed dead resource capacity are evicted
140 // from cache when pruning.
141 static void TestDeadResourceEviction(Resource* resource1, Resource* resource2)
142 {
143     memoryCache()->setDelayBeforeLiveDecodedPrune(0);
144     memoryCache()->setMaxPruneDeferralDelay(0);
145     const unsigned totalCapacity = 1000000;
146     const unsigned minDeadCapacity = 0;
147     const unsigned maxDeadCapacity = 0;
148     memoryCache()->setCapacities(minDeadCapacity, maxDeadCapacity, totalCapacity);
149
150     const char data[5] = "abcd";
151     resource1->appendData(data, 3u);
152     resource2->appendData(data, 2u);
153
154     // The resource size has to be nonzero for this test to be meaningful, but
155     // we do not rely on it having any particular value.
156     ASSERT_GT(resource1->size(), 0u);
157     ASSERT_GT(resource2->size(), 0u);
158
159     ASSERT_EQ(0u, memoryCache()->deadSize());
160     ASSERT_EQ(0u, memoryCache()->liveSize());
161
162     memoryCache()->add(resource1);
163     ASSERT_EQ(resource1->size(), memoryCache()->deadSize());
164     ASSERT_EQ(0u, memoryCache()->liveSize());
165
166     memoryCache()->add(resource2);
167     ASSERT_EQ(resource1->size() + resource2->size(), memoryCache()->deadSize());
168     ASSERT_EQ(0u, memoryCache()->liveSize());
169
170     memoryCache()->prune();
171     ASSERT_EQ(0u, memoryCache()->deadSize());
172     ASSERT_EQ(0u, memoryCache()->liveSize());
173 }
174
175 TEST_F(MemoryCacheTest, DeadResourceEviction_Basic)
176 {
177     Resource* resource1 =
178         new Resource(ResourceRequest("http://test/resource1"), Resource::Raw);
179     Resource* resource2 =
180         new Resource(ResourceRequest("http://test/resource2"), Resource::Raw);
181     TestDeadResourceEviction(resource1, resource2);
182 }
183
184 TEST_F(MemoryCacheTest, DeadResourceEviction_MultipleResourceMaps)
185 {
186     Resource* resource1 =
187         new Resource(ResourceRequest("http://test/resource1"), Resource::Raw);
188     Resource* resource2 =
189         new Resource(ResourceRequest("http://test/resource2"), Resource::Raw);
190     resource2->setCacheIdentifier("foo");
191     TestDeadResourceEviction(resource1, resource2);
192 }
193
194 static void TestLiveResourceEvictionAtEndOfTask(Resource* cachedDeadResource, const ResourcePtr<Resource>& cachedLiveResource)
195 {
196     memoryCache()->setDelayBeforeLiveDecodedPrune(0);
197     const unsigned totalCapacity = 1;
198     const unsigned minDeadCapacity = 0;
199     const unsigned maxDeadCapacity = 0;
200     memoryCache()->setCapacities(minDeadCapacity, maxDeadCapacity, totalCapacity);
201     const char data[6] = "abcde";
202     cachedDeadResource->appendData(data, 3u);
203     MockImageResourceClient client;
204     cachedLiveResource->addClient(&client);
205     cachedLiveResource->appendData(data, 4u);
206
207     class Task1 : public blink::WebThread::Task {
208     public:
209         Task1(const ResourcePtr<Resource>& live, Resource* dead)
210             : m_live(live)
211             , m_dead(dead)
212         { }
213
214         virtual void run() override
215         {
216             // The resource size has to be nonzero for this test to be meaningful, but
217             // we do not rely on it having any particular value.
218             ASSERT_GT(m_live->size(), 0u);
219             ASSERT_GT(m_dead->size(), 0u);
220
221             ASSERT_EQ(0u, memoryCache()->deadSize());
222             ASSERT_EQ(0u, memoryCache()->liveSize());
223
224             memoryCache()->add(m_dead);
225             memoryCache()->add(m_live.get());
226             memoryCache()->updateDecodedResource(m_live.get(), UpdateForPropertyChange);
227             ASSERT_EQ(m_dead->size(), memoryCache()->deadSize());
228             ASSERT_EQ(m_live->size(), memoryCache()->liveSize());
229             ASSERT_GT(m_live->decodedSize(), 0u);
230
231             memoryCache()->prune(); // Dead resources are pruned immediately
232             ASSERT_EQ(m_dead->size(), memoryCache()->deadSize());
233             ASSERT_EQ(m_live->size(), memoryCache()->liveSize());
234             ASSERT_GT(m_live->decodedSize(), 0u);
235         }
236
237     private:
238         ResourcePtr<Resource> m_live;
239         Resource* m_dead;
240     };
241
242     class Task2 : public blink::WebThread::Task {
243     public:
244         Task2(unsigned liveSizeWithoutDecode)
245             : m_liveSizeWithoutDecode(liveSizeWithoutDecode) { }
246
247         virtual void run() override
248         {
249             // Next task: now, the live resource was evicted.
250             ASSERT_EQ(0u, memoryCache()->deadSize());
251             ASSERT_EQ(m_liveSizeWithoutDecode, memoryCache()->liveSize());
252             blink::Platform::current()->currentThread()->exitRunLoop();
253         }
254
255     private:
256         unsigned m_liveSizeWithoutDecode;
257     };
258
259
260     blink::Platform::current()->currentThread()->postTask(new Task1(cachedLiveResource, cachedDeadResource));
261     blink::Platform::current()->currentThread()->postTask(new Task2(cachedLiveResource->encodedSize() + cachedLiveResource->overheadSize()));
262     blink::Platform::current()->currentThread()->enterRunLoop();
263     cachedLiveResource->removeClient(&client);
264 }
265
266 // Verified that when ordering a prune in a runLoop task, the prune
267 // is deferred to the end of the task.
268 TEST_F(MemoryCacheTest, LiveResourceEvictionAtEndOfTask_Basic)
269 {
270     Resource* cachedDeadResource =
271         new Resource(ResourceRequest("hhtp://foo"), Resource::Raw);
272     ResourcePtr<Resource> cachedLiveResource =
273         new FakeDecodedResource(ResourceRequest("http://test/resource"), Resource::Raw);
274     TestLiveResourceEvictionAtEndOfTask(cachedDeadResource, cachedLiveResource);
275 }
276
277 TEST_F(MemoryCacheTest, LiveResourceEvictionAtEndOfTask_MultipleResourceMaps)
278 {
279     {
280         Resource* cachedDeadResource =
281             new Resource(ResourceRequest("hhtp://foo"), Resource::Raw);
282         cachedDeadResource->setCacheIdentifier("foo");
283         ResourcePtr<Resource> cachedLiveResource =
284             new FakeDecodedResource(ResourceRequest("http://test/resource"), Resource::Raw);
285         TestLiveResourceEvictionAtEndOfTask(cachedDeadResource, cachedLiveResource);
286         memoryCache()->evictResources();
287     }
288     {
289         Resource* cachedDeadResource =
290             new Resource(ResourceRequest("hhtp://foo"), Resource::Raw);
291         ResourcePtr<Resource> cachedLiveResource =
292             new FakeDecodedResource(ResourceRequest("http://test/resource"), Resource::Raw);
293         cachedLiveResource->setCacheIdentifier("foo");
294         TestLiveResourceEvictionAtEndOfTask(cachedDeadResource, cachedLiveResource);
295         memoryCache()->evictResources();
296     }
297     {
298         Resource* cachedDeadResource =
299             new Resource(ResourceRequest("hhtp://test/resource"), Resource::Raw);
300         cachedDeadResource->setCacheIdentifier("foo");
301         ResourcePtr<Resource> cachedLiveResource =
302             new FakeDecodedResource(ResourceRequest("http://test/resource"), Resource::Raw);
303         cachedLiveResource->setCacheIdentifier("bar");
304         TestLiveResourceEvictionAtEndOfTask(cachedDeadResource, cachedLiveResource);
305         memoryCache()->evictResources();
306     }
307 }
308
309 // Verifies that cached resources are evicted immediately after release when
310 // the total dead resource size is more than double the dead resource capacity.
311 static void TestClientRemoval(const ResourcePtr<Resource>& resource1, const ResourcePtr<Resource>& resource2)
312 {
313     const char data[6] = "abcde";
314     MockImageResourceClient client1;
315     resource1->addClient(&client1);
316     resource1->appendData(data, 4u);
317     MockImageResourceClient client2;
318     resource2->addClient(&client2);
319     resource2->appendData(data, 4u);
320
321     const unsigned minDeadCapacity = 0;
322     const unsigned maxDeadCapacity = ((resource1->size() + resource2->size()) / 2) - 1;
323     const unsigned totalCapacity = maxDeadCapacity;
324     memoryCache()->setCapacities(minDeadCapacity, maxDeadCapacity, totalCapacity);
325     memoryCache()->add(resource1.get());
326     memoryCache()->add(resource2.get());
327     // Call prune. There is nothing to prune, but this will initialize
328     // the prune timestamp, allowing future prunes to be deferred.
329     memoryCache()->prune();
330     ASSERT_GT(resource1->decodedSize(), 0u);
331     ASSERT_GT(resource2->decodedSize(), 0u);
332     ASSERT_EQ(memoryCache()->deadSize(), 0u);
333     ASSERT_EQ(memoryCache()->liveSize(), resource1->size() + resource2->size());
334
335     // Removing the client from resource1 should result in all resources
336     // remaining in cache since the prune is deferred.
337     resource1->removeClient(&client1);
338     ASSERT_GT(resource1->decodedSize(), 0u);
339     ASSERT_GT(resource2->decodedSize(), 0u);
340     ASSERT_EQ(memoryCache()->deadSize(), resource1->size());
341     ASSERT_EQ(memoryCache()->liveSize(), resource2->size());
342     ASSERT_TRUE(memoryCache()->contains(resource1.get()));
343     ASSERT_TRUE(memoryCache()->contains(resource2.get()));
344
345     // Removing the client from resource2 should result in immediate
346     // eviction of resource2 because we are over the prune deferral limit.
347     resource2->removeClient(&client2);
348     ASSERT_GT(resource1->decodedSize(), 0u);
349     ASSERT_GT(resource2->decodedSize(), 0u);
350     ASSERT_EQ(memoryCache()->deadSize(), resource1->size());
351     ASSERT_EQ(memoryCache()->liveSize(), 0u);
352     ASSERT_TRUE(memoryCache()->contains(resource1.get()));
353     ASSERT_FALSE(memoryCache()->contains(resource2.get()));
354 }
355
356 TEST_F(MemoryCacheTest, ClientRemoval_Basic)
357 {
358     ResourcePtr<Resource> resource1 =
359         new FakeDecodedResource(ResourceRequest("http://foo.com"), Resource::Raw);
360     ResourcePtr<Resource> resource2 =
361         new FakeDecodedResource(ResourceRequest("http://test/resource"), Resource::Raw);
362     TestClientRemoval(resource1, resource2);
363 }
364
365 TEST_F(MemoryCacheTest, ClientRemoval_MultipleResourceMaps)
366 {
367     {
368         ResourcePtr<Resource> resource1 =
369             new FakeDecodedResource(ResourceRequest("http://foo.com"), Resource::Raw);
370         resource1->setCacheIdentifier("foo");
371         ResourcePtr<Resource> resource2 =
372             new FakeDecodedResource(ResourceRequest("http://test/resource"), Resource::Raw);
373         TestClientRemoval(resource1, resource2);
374         memoryCache()->evictResources();
375     }
376     {
377         ResourcePtr<Resource> resource1 =
378             new FakeDecodedResource(ResourceRequest("http://foo.com"), Resource::Raw);
379         ResourcePtr<Resource> resource2 =
380             new FakeDecodedResource(ResourceRequest("http://test/resource"), Resource::Raw);
381         resource2->setCacheIdentifier("foo");
382         TestClientRemoval(resource1, resource2);
383         memoryCache()->evictResources();
384     }
385     {
386         ResourcePtr<Resource> resource1 =
387             new FakeDecodedResource(ResourceRequest("http://test/resource"), Resource::Raw);
388         resource1->setCacheIdentifier("foo");
389         ResourcePtr<Resource> resource2 =
390             new FakeDecodedResource(ResourceRequest("http://test/resource"), Resource::Raw);
391         resource2->setCacheIdentifier("bar");
392         TestClientRemoval(resource1, resource2);
393         memoryCache()->evictResources();
394     }
395 }
396
397 // Verifies that CachedResources are evicted from the decode cache
398 // according to their DecodeCachePriority.
399 static void TestDecodeCacheOrder(const ResourcePtr<Resource>& cachedImageLowPriority, const ResourcePtr<Resource>& cachedImageHighPriority)
400 {
401     memoryCache()->setDelayBeforeLiveDecodedPrune(0);
402     memoryCache()->setMaxPruneDeferralDelay(0);
403
404     MockImageResourceClient clientLowPriority;
405     MockImageResourceClient clientHighPriority;
406     cachedImageLowPriority->addClient(&clientLowPriority);
407     cachedImageHighPriority->addClient(&clientHighPriority);
408
409     const char data[5] = "abcd";
410     cachedImageLowPriority->appendData(data, 1u);
411     cachedImageHighPriority->appendData(data, 4u);
412     const unsigned lowPrioritySize = cachedImageLowPriority->size();
413     const unsigned highPrioritySize = cachedImageHighPriority->size();
414     const unsigned lowPriorityMockDecodeSize = cachedImageLowPriority->decodedSize();
415     const unsigned highPriorityMockDecodeSize = cachedImageHighPriority->decodedSize();
416     const unsigned totalSize = lowPrioritySize + highPrioritySize;
417
418     // Verify that the sizes are different to ensure that we can test eviction order.
419     ASSERT_GT(lowPrioritySize, 0u);
420     ASSERT_NE(lowPrioritySize, highPrioritySize);
421     ASSERT_GT(lowPriorityMockDecodeSize, 0u);
422     ASSERT_NE(lowPriorityMockDecodeSize, highPriorityMockDecodeSize);
423
424     ASSERT_EQ(memoryCache()->deadSize(), 0u);
425     ASSERT_EQ(memoryCache()->liveSize(), 0u);
426
427     // Add the items. The item added first would normally be evicted first.
428     memoryCache()->add(cachedImageHighPriority.get());
429     ASSERT_EQ(memoryCache()->deadSize(), 0u);
430     ASSERT_EQ(memoryCache()->liveSize(), highPrioritySize);
431
432     memoryCache()->add(cachedImageLowPriority.get());
433     ASSERT_EQ(memoryCache()->deadSize(), 0u);
434     ASSERT_EQ(memoryCache()->liveSize(), highPrioritySize + lowPrioritySize);
435
436     // Insert all items in the decoded items list with the same priority
437     memoryCache()->updateDecodedResource(cachedImageHighPriority.get(), UpdateForPropertyChange);
438     memoryCache()->updateDecodedResource(cachedImageLowPriority.get(), UpdateForPropertyChange);
439     ASSERT_EQ(memoryCache()->deadSize(), 0u);
440     ASSERT_EQ(memoryCache()->liveSize(), totalSize);
441
442     // Now we will assign their priority and make sure they are moved to the correct buckets.
443     memoryCache()->updateDecodedResource(cachedImageLowPriority.get(), UpdateForPropertyChange, MemoryCacheLiveResourcePriorityLow);
444     memoryCache()->updateDecodedResource(cachedImageHighPriority.get(), UpdateForPropertyChange, MemoryCacheLiveResourcePriorityHigh);
445
446     // Should first prune the LowPriority item.
447     memoryCache()->setCapacities(memoryCache()->minDeadCapacity(), memoryCache()->liveSize() - 10, memoryCache()->liveSize() - 10);
448     memoryCache()->prune();
449     ASSERT_EQ(memoryCache()->deadSize(), 0u);
450     ASSERT_EQ(memoryCache()->liveSize(), totalSize - lowPriorityMockDecodeSize);
451
452     // Should prune the HighPriority item.
453     memoryCache()->setCapacities(memoryCache()->minDeadCapacity(), memoryCache()->liveSize() - 10, memoryCache()->liveSize() - 10);
454     memoryCache()->prune();
455     ASSERT_EQ(memoryCache()->deadSize(), 0u);
456     ASSERT_EQ(memoryCache()->liveSize(), totalSize - lowPriorityMockDecodeSize - highPriorityMockDecodeSize);
457
458     cachedImageLowPriority->removeClient(&clientLowPriority);
459     cachedImageHighPriority->removeClient(&clientHighPriority);
460 }
461
462 TEST_F(MemoryCacheTest, DecodeCacheOrder_Basic)
463 {
464     ResourcePtr<FakeDecodedResource> cachedImageLowPriority =
465         new FakeDecodedResource(ResourceRequest("http://foo.com"), Resource::Raw);
466     ResourcePtr<FakeDecodedResource> cachedImageHighPriority =
467         new FakeDecodedResource(ResourceRequest("http://test/resource"), Resource::Raw);
468     TestDecodeCacheOrder(cachedImageLowPriority, cachedImageHighPriority);
469 }
470
471 TEST_F(MemoryCacheTest, DecodeCacheOrder_MultipleResourceMaps)
472 {
473     {
474         ResourcePtr<FakeDecodedResource> cachedImageLowPriority =
475             new FakeDecodedResource(ResourceRequest("http://foo.com"), Resource::Raw);
476         ResourcePtr<FakeDecodedResource> cachedImageHighPriority =
477             new FakeDecodedResource(ResourceRequest("http://test/resource"), Resource::Raw);
478         cachedImageLowPriority->setCacheIdentifier("foo");
479         TestDecodeCacheOrder(cachedImageLowPriority, cachedImageHighPriority);
480         memoryCache()->evictResources();
481     }
482     {
483         ResourcePtr<FakeDecodedResource> cachedImageLowPriority =
484             new FakeDecodedResource(ResourceRequest("http://foo.com"), Resource::Raw);
485         ResourcePtr<FakeDecodedResource> cachedImageHighPriority =
486             new FakeDecodedResource(ResourceRequest("http://test/resource"), Resource::Raw);
487         cachedImageHighPriority->setCacheIdentifier("foo");
488         TestDecodeCacheOrder(cachedImageLowPriority, cachedImageHighPriority);
489         memoryCache()->evictResources();
490     }
491     {
492         ResourcePtr<FakeDecodedResource> cachedImageLowPriority =
493             new FakeDecodedResource(ResourceRequest("http://test/resource"), Resource::Raw);
494         cachedImageLowPriority->setCacheIdentifier("foo");
495         ResourcePtr<FakeDecodedResource> cachedImageHighPriority =
496             new FakeDecodedResource(ResourceRequest("http://test/resource"), Resource::Raw);
497         cachedImageHighPriority->setCacheIdentifier("bar");
498         TestDecodeCacheOrder(cachedImageLowPriority, cachedImageHighPriority);
499         memoryCache()->evictResources();
500     }
501 }
502
503 TEST_F(MemoryCacheTest, MultipleReplace)
504 {
505     ResourcePtr<FakeResource> resource1 = new FakeResource(ResourceRequest("http://test/resource"), Resource::Raw);
506     memoryCache()->add(resource1.get());
507
508     ResourcePtr<FakeResource> resource2 = new FakeResource(ResourceRequest("http://test/resource"), Resource::Raw);
509     memoryCache()->replace(resource2.get(), resource1.get());
510     EXPECT_TRUE(memoryCache()->contains(resource2.get()));
511     EXPECT_FALSE(memoryCache()->contains(resource1.get()));
512
513     ResourcePtr<FakeResource> resource3 = new FakeResource(ResourceRequest("http://test/resource"), Resource::Raw);
514     memoryCache()->replace(resource3.get(), resource2.get());
515     EXPECT_TRUE(memoryCache()->contains(resource3.get()));
516     EXPECT_FALSE(memoryCache()->contains(resource2.get()));
517 }
518
519 TEST_F(MemoryCacheTest, RemoveDuringRevalidation)
520 {
521     ResourcePtr<FakeResource> resource1 = new FakeResource(ResourceRequest("http://test/resource"), Resource::Raw);
522     memoryCache()->add(resource1.get());
523
524     ResourcePtr<FakeResource> resource2 = new FakeResource(ResourceRequest("http://test/resource"), Resource::Raw);
525     memoryCache()->remove(resource1.get());
526     memoryCache()->add(resource2.get());
527     EXPECT_TRUE(memoryCache()->contains(resource2.get()));
528     EXPECT_FALSE(memoryCache()->contains(resource1.get()));
529
530     ResourcePtr<FakeResource> resource3 = new FakeResource(ResourceRequest("http://test/resource"), Resource::Raw);
531     memoryCache()->remove(resource2.get());
532     memoryCache()->add(resource3.get());
533     EXPECT_TRUE(memoryCache()->contains(resource3.get()));
534     EXPECT_FALSE(memoryCache()->contains(resource2.get()));
535
536     memoryCache()->replace(resource1.get(), resource2.get());
537     EXPECT_TRUE(memoryCache()->contains(resource1.get()));
538     EXPECT_FALSE(memoryCache()->contains(resource2.get()));
539     EXPECT_FALSE(memoryCache()->contains(resource3.get()));
540 }
541
542 TEST_F(MemoryCacheTest, ResourceMapIsolation)
543 {
544     ResourcePtr<FakeResource> resource1 = new FakeResource(ResourceRequest("http://test/resource"), Resource::Raw);
545     memoryCache()->add(resource1.get());
546
547     ResourcePtr<FakeResource> resource2 = new FakeResource(ResourceRequest("http://test/resource"), Resource::Raw);
548     resource2->setCacheIdentifier("foo");
549     memoryCache()->add(resource2.get());
550     EXPECT_TRUE(memoryCache()->contains(resource1.get()));
551     EXPECT_TRUE(memoryCache()->contains(resource2.get()));
552
553     const KURL url = KURL(ParsedURLString, "http://test/resource");
554     EXPECT_EQ(resource1.get(), memoryCache()->resourceForURL(url));
555     EXPECT_EQ(resource1.get(), memoryCache()->resourceForURL(url, memoryCache()->defaultCacheIdentifier()));
556     EXPECT_EQ(resource2.get(), memoryCache()->resourceForURL(url, "foo"));
557
558     ResourcePtr<FakeResource> resource3 = new FakeResource(ResourceRequest("http://test/resource"), Resource::Raw);
559     resource3->setCacheIdentifier("foo");
560     memoryCache()->remove(resource2.get());
561     memoryCache()->add(resource3.get());
562     EXPECT_TRUE(memoryCache()->contains(resource1.get()));
563     EXPECT_FALSE(memoryCache()->contains(resource2.get()));
564     EXPECT_TRUE(memoryCache()->contains(resource3.get()));
565
566     ResourcePtr<FakeResource> resource4 = new FakeResource(ResourceRequest("http://test/resource"), Resource::Raw);
567     resource4->setCacheIdentifier("foo");
568     memoryCache()->replace(resource4.get(), resource3.get());
569     EXPECT_TRUE(memoryCache()->contains(resource1.get()));
570     EXPECT_FALSE(memoryCache()->contains(resource3.get()));
571     EXPECT_TRUE(memoryCache()->contains(resource4.get()));
572
573     WillBeHeapVector<Member<Resource>> resources = memoryCache()->resourcesForURL(url);
574     EXPECT_EQ(2u, resources.size());
575
576     memoryCache()->evictResources();
577     EXPECT_FALSE(memoryCache()->contains(resource1.get()));
578     EXPECT_FALSE(memoryCache()->contains(resource3.get()));
579 }
580
581 } // namespace