1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 #include "base/message_loop/message_loop.h"
8 #include "components/web_cache/browser/web_cache_manager.h"
9 #include "content/public/test/test_browser_thread.h"
10 #include "testing/gtest/include/gtest/gtest.h"
13 using base::TimeDelta
;
14 using content::BrowserThread
;
15 using blink::WebCache
;
19 class WebCacheManagerTest
: public testing::Test
{
21 typedef WebCacheManager::StatsMap StatsMap
;
22 typedef WebCacheManager::Allocation Allocation
;
23 typedef WebCacheManager::AllocationStrategy AllocationStrategy
;
25 static const int kRendererID
;
26 static const int kRendererID2
;
27 static const WebCache::UsageStats kStats
;
28 static const WebCache::UsageStats kStats2
;
31 : ui_thread_(BrowserThread::UI
, &message_loop_
) {
34 // Thunks to access protected members of WebCacheManager
35 static std::map
<int, WebCacheManager::RendererInfo
>& stats(
40 static void SimulateInactivity(WebCacheManager
* h
, int renderer_id
) {
41 stats(h
)[renderer_id
].access
= Time::Now() - TimeDelta::FromMinutes(
42 WebCacheManager::kRendererInactiveThresholdMinutes
);
43 h
->FindInactiveRenderers();
46 static std::set
<int>& active_renderers(WebCacheManager
* h
) {
47 return h
->active_renderers_
;
49 static std::set
<int>& inactive_renderers(WebCacheManager
* h
) {
50 return h
->inactive_renderers_
;
52 static void GatherStats(WebCacheManager
* h
,
53 std::set
<int> renderers
,
54 WebCache::UsageStats
* stats
) {
55 h
->GatherStats(renderers
, stats
);
57 static size_t GetSize(int tactic
,
58 const WebCache::UsageStats
& stats
) {
59 return WebCacheManager::GetSize(
60 static_cast<WebCacheManager::AllocationTactic
>(tactic
), stats
);
62 static bool AttemptTactic(WebCacheManager
* h
,
64 const WebCache::UsageStats
& active_stats
,
66 const WebCache::UsageStats
& inactive_stats
,
67 std::list
< std::pair
<int,size_t> >* strategy
) {
68 return h
->AttemptTactic(
69 static_cast<WebCacheManager::AllocationTactic
>(active_tactic
),
71 static_cast<WebCacheManager::AllocationTactic
>(inactive_tactic
),
75 static void AddToStrategy(WebCacheManager
* h
,
76 std::set
<int> renderers
,
78 size_t extra_bytes_to_allocate
,
79 std::list
< std::pair
<int,size_t> >* strategy
) {
80 h
->AddToStrategy(renderers
,
81 static_cast<WebCacheManager::AllocationTactic
>(tactic
),
82 extra_bytes_to_allocate
,
87 DIVIDE_EVENLY
= WebCacheManager::DIVIDE_EVENLY
,
88 KEEP_CURRENT_WITH_HEADROOM
= WebCacheManager::KEEP_CURRENT_WITH_HEADROOM
,
89 KEEP_CURRENT
= WebCacheManager::KEEP_CURRENT
,
90 KEEP_LIVE_WITH_HEADROOM
= WebCacheManager::KEEP_LIVE_WITH_HEADROOM
,
91 KEEP_LIVE
= WebCacheManager::KEEP_LIVE
,
94 WebCacheManager
* manager() { return &manager_
; }
97 WebCacheManager manager_
;
98 base::MessageLoop message_loop_
;
99 content::TestBrowserThread ui_thread_
;
103 const int WebCacheManagerTest::kRendererID
= 146;
106 const int WebCacheManagerTest::kRendererID2
= 245;
109 const WebCache::UsageStats
WebCacheManagerTest::kStats
= {
118 const WebCache::UsageStats
WebCacheManagerTest::kStats2
= {
126 static bool operator==(const WebCache::UsageStats
& lhs
,
127 const WebCache::UsageStats
& rhs
) {
128 return !::memcmp(&lhs
, &rhs
, sizeof(WebCache::UsageStats
));
131 TEST_F(WebCacheManagerTest
, AddRemoveRendererTest
) {
132 EXPECT_EQ(0U, active_renderers(manager()).size());
133 EXPECT_EQ(0U, inactive_renderers(manager()).size());
135 manager()->Add(kRendererID
);
136 EXPECT_EQ(1U, active_renderers(manager()).count(kRendererID
));
137 EXPECT_EQ(0U, inactive_renderers(manager()).count(kRendererID
));
139 manager()->Remove(kRendererID
);
140 EXPECT_EQ(0U, active_renderers(manager()).size());
141 EXPECT_EQ(0U, inactive_renderers(manager()).size());
144 TEST_F(WebCacheManagerTest
, ActiveInactiveTest
) {
145 manager()->Add(kRendererID
);
147 manager()->ObserveActivity(kRendererID
);
148 EXPECT_EQ(1U, active_renderers(manager()).count(kRendererID
));
149 EXPECT_EQ(0U, inactive_renderers(manager()).count(kRendererID
));
151 SimulateInactivity(manager(), kRendererID
);
152 EXPECT_EQ(0U, active_renderers(manager()).count(kRendererID
));
153 EXPECT_EQ(1U, inactive_renderers(manager()).count(kRendererID
));
155 manager()->ObserveActivity(kRendererID
);
156 EXPECT_EQ(1U, active_renderers(manager()).count(kRendererID
));
157 EXPECT_EQ(0U, inactive_renderers(manager()).count(kRendererID
));
159 manager()->Remove(kRendererID
);
162 TEST_F(WebCacheManagerTest
, ObserveStatsTest
) {
163 manager()->Add(kRendererID
);
165 EXPECT_EQ(1U, stats(manager()).size());
167 manager()->ObserveStats(kRendererID
, kStats
);
169 EXPECT_EQ(1U, stats(manager()).size());
170 EXPECT_TRUE(kStats
== stats(manager())[kRendererID
]);
172 manager()->Remove(kRendererID
);
175 TEST_F(WebCacheManagerTest
, SetGlobalSizeLimitTest
) {
176 size_t limit
= manager()->GetDefaultGlobalSizeLimit();
177 manager()->SetGlobalSizeLimit(limit
);
178 EXPECT_EQ(limit
, manager()->global_size_limit());
180 manager()->SetGlobalSizeLimit(0);
181 EXPECT_EQ(0U, manager()->global_size_limit());
184 TEST_F(WebCacheManagerTest
, GatherStatsTest
) {
185 manager()->Add(kRendererID
);
186 manager()->Add(kRendererID2
);
188 manager()->ObserveStats(kRendererID
, kStats
);
189 manager()->ObserveStats(kRendererID2
, kStats2
);
191 std::set
<int> renderer_set
;
192 renderer_set
.insert(kRendererID
);
194 WebCache::UsageStats stats
;
195 GatherStats(manager(), renderer_set
, &stats
);
197 EXPECT_TRUE(kStats
== stats
);
199 renderer_set
.insert(kRendererID2
);
200 GatherStats(manager(), renderer_set
, &stats
);
202 WebCache::UsageStats expected_stats
= kStats
;
203 expected_stats
.minDeadCapacity
+= kStats2
.minDeadCapacity
;
204 expected_stats
.maxDeadCapacity
+= kStats2
.maxDeadCapacity
;
205 expected_stats
.capacity
+= kStats2
.capacity
;
206 expected_stats
.liveSize
+= kStats2
.liveSize
;
207 expected_stats
.deadSize
+= kStats2
.deadSize
;
209 EXPECT_TRUE(expected_stats
== stats
);
211 manager()->Remove(kRendererID
);
212 manager()->Remove(kRendererID2
);
215 TEST_F(WebCacheManagerTest
, GetSizeTest
) {
216 EXPECT_EQ(0U, GetSize(DIVIDE_EVENLY
, kStats
));
217 EXPECT_LT(256 * 1024u + 512, GetSize(KEEP_CURRENT_WITH_HEADROOM
, kStats
));
218 EXPECT_EQ(256 * 1024u + 512, GetSize(KEEP_CURRENT
, kStats
));
219 EXPECT_LT(256 * 1024u, GetSize(KEEP_LIVE_WITH_HEADROOM
, kStats
));
220 EXPECT_EQ(256 * 1024u, GetSize(KEEP_LIVE
, kStats
));
223 TEST_F(WebCacheManagerTest
, AttemptTacticTest
) {
224 manager()->Add(kRendererID
);
225 manager()->Add(kRendererID2
);
227 manager()->ObserveActivity(kRendererID
);
228 SimulateInactivity(manager(), kRendererID2
);
230 manager()->ObserveStats(kRendererID
, kStats
);
231 manager()->ObserveStats(kRendererID2
, kStats2
);
233 manager()->SetGlobalSizeLimit(kStats
.liveSize
+ kStats
.deadSize
+
234 kStats2
.liveSize
+ kStats2
.deadSize
/2);
236 AllocationStrategy strategy
;
238 EXPECT_FALSE(AttemptTactic(manager(),
244 EXPECT_TRUE(strategy
.empty());
246 EXPECT_TRUE(AttemptTactic(manager(),
252 EXPECT_EQ(2U, strategy
.size());
254 AllocationStrategy::iterator iter
= strategy
.begin();
255 while (iter
!= strategy
.end()) {
256 if (iter
->first
== kRendererID
)
257 EXPECT_LE(kStats
.liveSize
+ kStats
.deadSize
, iter
->second
);
258 else if (iter
->first
== kRendererID2
)
259 EXPECT_LE(kStats2
.liveSize
, iter
->second
);
261 ADD_FAILURE(); // Unexpected entry in strategy.
265 manager()->Remove(kRendererID
);
266 manager()->Remove(kRendererID2
);
269 TEST_F(WebCacheManagerTest
, AddToStrategyTest
) {
270 manager()->Add(kRendererID
);
271 manager()->Add(kRendererID2
);
273 std::set
<int> renderer_set
;
274 renderer_set
.insert(kRendererID
);
275 renderer_set
.insert(kRendererID2
);
277 manager()->ObserveStats(kRendererID
, kStats
);
278 manager()->ObserveStats(kRendererID2
, kStats2
);
280 const size_t kExtraBytesToAllocate
= 10 * 1024;
282 AllocationStrategy strategy
;
283 AddToStrategy(manager(),
286 kExtraBytesToAllocate
,
289 EXPECT_EQ(2U, strategy
.size());
291 size_t total_bytes
= 0;
292 AllocationStrategy::iterator iter
= strategy
.begin();
293 while (iter
!= strategy
.end()) {
294 total_bytes
+= iter
->second
;
296 if (iter
->first
== kRendererID
)
297 EXPECT_LE(kStats
.liveSize
+ kStats
.deadSize
, iter
->second
);
298 else if (iter
->first
== kRendererID2
)
299 EXPECT_LE(kStats2
.liveSize
+ kStats2
.deadSize
, iter
->second
);
301 ADD_FAILURE(); // Unexpected entry in strategy.
305 size_t expected_total_bytes
= kExtraBytesToAllocate
+
306 kStats
.liveSize
+ kStats
.deadSize
+
307 kStats2
.liveSize
+ kStats2
.deadSize
;
309 EXPECT_GE(expected_total_bytes
, total_bytes
);
311 manager()->Remove(kRendererID
);
312 manager()->Remove(kRendererID2
);
315 // Regression test for http://crbug.com/12362.
316 // There are three operations in the following order will cause the crash:
317 // Remove(kRendererID) -> ObserveActivity(kRendererID) -> Remove(kRendererID2)
318 // To prevent similar failures in the future, 6 tests are added in total to
319 // cover all the possible orderings of these three operations.
320 TEST_F(WebCacheManagerTest
,
321 CallRemoveRendererAndObserveActivityInAnyOrderShouldNotCrashTest_1
) {
322 EXPECT_EQ(0U, active_renderers(manager()).size());
323 EXPECT_EQ(0U, inactive_renderers(manager()).size());
325 // Add, Remove, and ObserveActivity trigger deferred
326 // calls to ReviseAllocationStrategy and that we call it directly after each
327 // operation to sidestep the need to wait for an unobservable background
329 manager()->Add(kRendererID
);
330 manager()->ReviseAllocationStrategy();
331 manager()->Add(kRendererID2
);
332 manager()->ReviseAllocationStrategy();
334 // The following order will cause a crash in http://crbug.com/12362.
335 manager()->Remove(kRendererID
);
336 manager()->ReviseAllocationStrategy();
338 manager()->ObserveActivity(kRendererID
);
339 manager()->ReviseAllocationStrategy();
341 manager()->Remove(kRendererID2
);
342 manager()->ReviseAllocationStrategy();
345 TEST_F(WebCacheManagerTest
,
346 CallRemoveRendererAndObserveActivityInAnyOrderShouldNotCrashTest_2
) {
347 EXPECT_EQ(0U, active_renderers(manager()).size());
348 EXPECT_EQ(0U, inactive_renderers(manager()).size());
350 // Add, Remove, and ObserveActivity trigger deferred
351 // calls to ReviseAllocationStrategy and that we call it directly after each
352 // operation to sidestep the need to wait for an unobservable background
354 manager()->Add(kRendererID
);
355 manager()->ReviseAllocationStrategy();
356 manager()->Add(kRendererID2
);
357 manager()->ReviseAllocationStrategy();
359 manager()->Remove(kRendererID
);
360 manager()->ReviseAllocationStrategy();
362 manager()->Remove(kRendererID2
);
363 manager()->ReviseAllocationStrategy();
365 manager()->ObserveActivity(kRendererID
);
366 manager()->ReviseAllocationStrategy();
370 TEST_F(WebCacheManagerTest
,
371 CallRemoveRendererAndObserveActivityInAnyOrderShouldNotCrashTest_3
) {
372 EXPECT_EQ(0U, active_renderers(manager()).size());
373 EXPECT_EQ(0U, inactive_renderers(manager()).size());
375 // Add, Remove, and ObserveActivity trigger deferred
376 // calls to ReviseAllocationStrategy and that we call it directly after each
377 // operation to sidestep the need to wait for an unobservable background
379 manager()->Add(kRendererID
);
380 manager()->ReviseAllocationStrategy();
381 manager()->Add(kRendererID2
);
382 manager()->ReviseAllocationStrategy();
384 manager()->ObserveActivity(kRendererID
);
385 EXPECT_EQ(0U, inactive_renderers(manager()).size());
387 manager()->Remove(kRendererID
);
388 manager()->ReviseAllocationStrategy();
390 manager()->Remove(kRendererID2
);
391 manager()->ReviseAllocationStrategy();
394 TEST_F(WebCacheManagerTest
,
395 CallRemoveRendererAndObserveActivityInAnyOrderShouldNotCrashTest_4
) {
396 EXPECT_EQ(0U, active_renderers(manager()).size());
397 EXPECT_EQ(0U, inactive_renderers(manager()).size());
399 // Add, Remove, and ObserveActivity trigger deferred
400 // calls to ReviseAllocationStrategy and that we call it directly after each
401 // operation to sidestep the need to wait for an unobservable background
403 manager()->Add(kRendererID
);
404 manager()->ReviseAllocationStrategy();
405 manager()->Add(kRendererID2
);
406 manager()->ReviseAllocationStrategy();
408 manager()->ObserveActivity(kRendererID
);
409 EXPECT_EQ(0U, inactive_renderers(manager()).size());
411 manager()->Remove(kRendererID2
);
412 manager()->ReviseAllocationStrategy();
414 manager()->Remove(kRendererID
);
415 manager()->ReviseAllocationStrategy();
418 TEST_F(WebCacheManagerTest
,
419 CallRemoveRendererAndObserveActivityInAnyOrderShouldNotCrashTest_5
) {
420 EXPECT_EQ(0U, active_renderers(manager()).size());
421 EXPECT_EQ(0U, inactive_renderers(manager()).size());
423 // Add, Remove, and ObserveActivity trigger deferred
424 // calls to ReviseAllocationStrategy and that we call it directly after each
425 // operation to sidestep the need to wait for an unobservable background
427 manager()->Add(kRendererID
);
428 manager()->ReviseAllocationStrategy();
429 manager()->Add(kRendererID2
);
430 manager()->ReviseAllocationStrategy();
432 manager()->Remove(kRendererID2
);
433 manager()->ReviseAllocationStrategy();
435 manager()->ObserveActivity(kRendererID
);
436 manager()->ReviseAllocationStrategy();
438 manager()->Remove(kRendererID
);
439 manager()->ReviseAllocationStrategy();
442 TEST_F(WebCacheManagerTest
,
443 CallRemoveRendererAndObserveActivityInAnyOrderShouldNotCrashTest_6
) {
444 EXPECT_EQ(0U, active_renderers(manager()).size());
445 EXPECT_EQ(0U, inactive_renderers(manager()).size());
447 // Add, Remove, and ObserveActivity trigger deferred
448 // calls to ReviseAllocationStrategy and that we call it directly after each
449 // operation to sidestep the need to wait for an unobservable background
451 manager()->Add(kRendererID
);
452 manager()->ReviseAllocationStrategy();
453 manager()->Add(kRendererID2
);
454 manager()->ReviseAllocationStrategy();
456 manager()->Remove(kRendererID2
);
457 manager()->ReviseAllocationStrategy();
459 manager()->Remove(kRendererID
);
460 manager()->ReviseAllocationStrategy();
462 manager()->ObserveActivity(kRendererID
);
463 manager()->ReviseAllocationStrategy();
466 } // namespace web_cache