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. 4 5#include <string> 6 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" 11 12using base::Time; 13using base::TimeDelta; 14using content::BrowserThread; 15using blink::WebCache; 16 17namespace web_cache { 18 19class WebCacheManagerTest : public testing::Test { 20 protected: 21 typedef WebCacheManager::StatsMap StatsMap; 22 typedef WebCacheManager::Allocation Allocation; 23 typedef WebCacheManager::AllocationStrategy AllocationStrategy; 24 25 static const int kRendererID; 26 static const int kRendererID2; 27 static const WebCache::UsageStats kStats; 28 static const WebCache::UsageStats kStats2; 29 30 WebCacheManagerTest() 31 : ui_thread_(BrowserThread::UI, &message_loop_) { 32 } 33 34 // Thunks to access protected members of WebCacheManager 35 static std::map<int, WebCacheManager::RendererInfo>& stats( 36 WebCacheManager* h) { 37 return h->stats_; 38 } 39 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(); 44 } 45 46 static std::set<int>& active_renderers(WebCacheManager* h) { 47 return h->active_renderers_; 48 } 49 static std::set<int>& inactive_renderers(WebCacheManager* h) { 50 return h->inactive_renderers_; 51 } 52 static void GatherStats(WebCacheManager* h, 53 std::set<int> renderers, 54 WebCache::UsageStats* stats) { 55 h->GatherStats(renderers, stats); 56 } 57 static size_t GetSize(int tactic, 58 const WebCache::UsageStats& stats) { 59 return WebCacheManager::GetSize( 60 static_cast<WebCacheManager::AllocationTactic>(tactic), stats); 61 } 62 static bool AttemptTactic(WebCacheManager* h, 63 int active_tactic, 64 const WebCache::UsageStats& active_stats, 65 int inactive_tactic, 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), 70 active_stats, 71 static_cast<WebCacheManager::AllocationTactic>(inactive_tactic), 72 inactive_stats, 73 strategy); 74 } 75 static void AddToStrategy(WebCacheManager* h, 76 std::set<int> renderers, 77 int tactic, 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, 83 strategy); 84 } 85 86 enum { 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, 92 }; 93 94 WebCacheManager* manager() { return &manager_; } 95 96 private: 97 WebCacheManager manager_; 98 base::MessageLoop message_loop_; 99 content::TestBrowserThread ui_thread_; 100}; 101 102// static 103const int WebCacheManagerTest::kRendererID = 146; 104 105// static 106const int WebCacheManagerTest::kRendererID2 = 245; 107 108// static 109const WebCache::UsageStats WebCacheManagerTest::kStats = { 110 0, 111 1024 * 1024, 112 1024 * 1024, 113 256 * 1024, 114 512, 115 }; 116 117// static 118const WebCache::UsageStats WebCacheManagerTest::kStats2 = { 119 0, 120 2 * 1024 * 1024, 121 2 * 1024 * 1024, 122 2 * 256 * 1024, 123 2 * 512, 124 }; 125 126static bool operator==(const WebCache::UsageStats& lhs, 127 const WebCache::UsageStats& rhs) { 128 return !::memcmp(&lhs, &rhs, sizeof(WebCache::UsageStats)); 129} 130 131TEST_F(WebCacheManagerTest, AddRemoveRendererTest) { 132 EXPECT_EQ(0U, active_renderers(manager()).size()); 133 EXPECT_EQ(0U, inactive_renderers(manager()).size()); 134 135 manager()->Add(kRendererID); 136 EXPECT_EQ(1U, active_renderers(manager()).count(kRendererID)); 137 EXPECT_EQ(0U, inactive_renderers(manager()).count(kRendererID)); 138 139 manager()->Remove(kRendererID); 140 EXPECT_EQ(0U, active_renderers(manager()).size()); 141 EXPECT_EQ(0U, inactive_renderers(manager()).size()); 142} 143 144TEST_F(WebCacheManagerTest, ActiveInactiveTest) { 145 manager()->Add(kRendererID); 146 147 manager()->ObserveActivity(kRendererID); 148 EXPECT_EQ(1U, active_renderers(manager()).count(kRendererID)); 149 EXPECT_EQ(0U, inactive_renderers(manager()).count(kRendererID)); 150 151 SimulateInactivity(manager(), kRendererID); 152 EXPECT_EQ(0U, active_renderers(manager()).count(kRendererID)); 153 EXPECT_EQ(1U, inactive_renderers(manager()).count(kRendererID)); 154 155 manager()->ObserveActivity(kRendererID); 156 EXPECT_EQ(1U, active_renderers(manager()).count(kRendererID)); 157 EXPECT_EQ(0U, inactive_renderers(manager()).count(kRendererID)); 158 159 manager()->Remove(kRendererID); 160} 161 162TEST_F(WebCacheManagerTest, ObserveStatsTest) { 163 manager()->Add(kRendererID); 164 165 EXPECT_EQ(1U, stats(manager()).size()); 166 167 manager()->ObserveStats(kRendererID, kStats); 168 169 EXPECT_EQ(1U, stats(manager()).size()); 170 EXPECT_TRUE(kStats == stats(manager())[kRendererID]); 171 172 manager()->Remove(kRendererID); 173} 174 175TEST_F(WebCacheManagerTest, SetGlobalSizeLimitTest) { 176 size_t limit = manager()->GetDefaultGlobalSizeLimit(); 177 manager()->SetGlobalSizeLimit(limit); 178 EXPECT_EQ(limit, manager()->global_size_limit()); 179 180 manager()->SetGlobalSizeLimit(0); 181 EXPECT_EQ(0U, manager()->global_size_limit()); 182} 183 184TEST_F(WebCacheManagerTest, GatherStatsTest) { 185 manager()->Add(kRendererID); 186 manager()->Add(kRendererID2); 187 188 manager()->ObserveStats(kRendererID, kStats); 189 manager()->ObserveStats(kRendererID2, kStats2); 190 191 std::set<int> renderer_set; 192 renderer_set.insert(kRendererID); 193 194 WebCache::UsageStats stats; 195 GatherStats(manager(), renderer_set, &stats); 196 197 EXPECT_TRUE(kStats == stats); 198 199 renderer_set.insert(kRendererID2); 200 GatherStats(manager(), renderer_set, &stats); 201 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; 208 209 EXPECT_TRUE(expected_stats == stats); 210 211 manager()->Remove(kRendererID); 212 manager()->Remove(kRendererID2); 213} 214 215TEST_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)); 221} 222 223TEST_F(WebCacheManagerTest, AttemptTacticTest) { 224 manager()->Add(kRendererID); 225 manager()->Add(kRendererID2); 226 227 manager()->ObserveActivity(kRendererID); 228 SimulateInactivity(manager(), kRendererID2); 229 230 manager()->ObserveStats(kRendererID, kStats); 231 manager()->ObserveStats(kRendererID2, kStats2); 232 233 manager()->SetGlobalSizeLimit(kStats.liveSize + kStats.deadSize + 234 kStats2.liveSize + kStats2.deadSize/2); 235 236 AllocationStrategy strategy; 237 238 EXPECT_FALSE(AttemptTactic(manager(), 239 KEEP_CURRENT, 240 kStats, 241 KEEP_CURRENT, 242 kStats2, 243 &strategy)); 244 EXPECT_TRUE(strategy.empty()); 245 246 EXPECT_TRUE(AttemptTactic(manager(), 247 KEEP_CURRENT, 248 kStats, 249 KEEP_LIVE, 250 kStats2, 251 &strategy)); 252 EXPECT_EQ(2U, strategy.size()); 253 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); 260 else 261 ADD_FAILURE(); // Unexpected entry in strategy. 262 ++iter; 263 } 264 265 manager()->Remove(kRendererID); 266 manager()->Remove(kRendererID2); 267} 268 269TEST_F(WebCacheManagerTest, AddToStrategyTest) { 270 manager()->Add(kRendererID); 271 manager()->Add(kRendererID2); 272 273 std::set<int> renderer_set; 274 renderer_set.insert(kRendererID); 275 renderer_set.insert(kRendererID2); 276 277 manager()->ObserveStats(kRendererID, kStats); 278 manager()->ObserveStats(kRendererID2, kStats2); 279 280 const size_t kExtraBytesToAllocate = 10 * 1024; 281 282 AllocationStrategy strategy; 283 AddToStrategy(manager(), 284 renderer_set, 285 KEEP_CURRENT, 286 kExtraBytesToAllocate, 287 &strategy); 288 289 EXPECT_EQ(2U, strategy.size()); 290 291 size_t total_bytes = 0; 292 AllocationStrategy::iterator iter = strategy.begin(); 293 while (iter != strategy.end()) { 294 total_bytes += iter->second; 295 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); 300 else 301 ADD_FAILURE(); // Unexpected entry in strategy. 302 ++iter; 303 } 304 305 size_t expected_total_bytes = kExtraBytesToAllocate + 306 kStats.liveSize + kStats.deadSize + 307 kStats2.liveSize + kStats2.deadSize; 308 309 EXPECT_GE(expected_total_bytes, total_bytes); 310 311 manager()->Remove(kRendererID); 312 manager()->Remove(kRendererID2); 313} 314 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. 320TEST_F(WebCacheManagerTest, 321 CallRemoveRendererAndObserveActivityInAnyOrderShouldNotCrashTest_1) { 322 EXPECT_EQ(0U, active_renderers(manager()).size()); 323 EXPECT_EQ(0U, inactive_renderers(manager()).size()); 324 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 328 // operation. 329 manager()->Add(kRendererID); 330 manager()->ReviseAllocationStrategy(); 331 manager()->Add(kRendererID2); 332 manager()->ReviseAllocationStrategy(); 333 334 // The following order will cause a crash in http://crbug.com/12362. 335 manager()->Remove(kRendererID); 336 manager()->ReviseAllocationStrategy(); 337 338 manager()->ObserveActivity(kRendererID); 339 manager()->ReviseAllocationStrategy(); 340 341 manager()->Remove(kRendererID2); 342 manager()->ReviseAllocationStrategy(); 343} 344 345TEST_F(WebCacheManagerTest, 346 CallRemoveRendererAndObserveActivityInAnyOrderShouldNotCrashTest_2) { 347 EXPECT_EQ(0U, active_renderers(manager()).size()); 348 EXPECT_EQ(0U, inactive_renderers(manager()).size()); 349 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 353 // operation. 354 manager()->Add(kRendererID); 355 manager()->ReviseAllocationStrategy(); 356 manager()->Add(kRendererID2); 357 manager()->ReviseAllocationStrategy(); 358 359 manager()->Remove(kRendererID); 360 manager()->ReviseAllocationStrategy(); 361 362 manager()->Remove(kRendererID2); 363 manager()->ReviseAllocationStrategy(); 364 365 manager()->ObserveActivity(kRendererID); 366 manager()->ReviseAllocationStrategy(); 367 368} 369 370TEST_F(WebCacheManagerTest, 371 CallRemoveRendererAndObserveActivityInAnyOrderShouldNotCrashTest_3) { 372 EXPECT_EQ(0U, active_renderers(manager()).size()); 373 EXPECT_EQ(0U, inactive_renderers(manager()).size()); 374 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 378 // operation. 379 manager()->Add(kRendererID); 380 manager()->ReviseAllocationStrategy(); 381 manager()->Add(kRendererID2); 382 manager()->ReviseAllocationStrategy(); 383 384 manager()->ObserveActivity(kRendererID); 385 EXPECT_EQ(0U, inactive_renderers(manager()).size()); 386 387 manager()->Remove(kRendererID); 388 manager()->ReviseAllocationStrategy(); 389 390 manager()->Remove(kRendererID2); 391 manager()->ReviseAllocationStrategy(); 392} 393 394TEST_F(WebCacheManagerTest, 395 CallRemoveRendererAndObserveActivityInAnyOrderShouldNotCrashTest_4) { 396 EXPECT_EQ(0U, active_renderers(manager()).size()); 397 EXPECT_EQ(0U, inactive_renderers(manager()).size()); 398 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 402 // operation. 403 manager()->Add(kRendererID); 404 manager()->ReviseAllocationStrategy(); 405 manager()->Add(kRendererID2); 406 manager()->ReviseAllocationStrategy(); 407 408 manager()->ObserveActivity(kRendererID); 409 EXPECT_EQ(0U, inactive_renderers(manager()).size()); 410 411 manager()->Remove(kRendererID2); 412 manager()->ReviseAllocationStrategy(); 413 414 manager()->Remove(kRendererID); 415 manager()->ReviseAllocationStrategy(); 416} 417 418TEST_F(WebCacheManagerTest, 419 CallRemoveRendererAndObserveActivityInAnyOrderShouldNotCrashTest_5) { 420 EXPECT_EQ(0U, active_renderers(manager()).size()); 421 EXPECT_EQ(0U, inactive_renderers(manager()).size()); 422 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 426 // operation. 427 manager()->Add(kRendererID); 428 manager()->ReviseAllocationStrategy(); 429 manager()->Add(kRendererID2); 430 manager()->ReviseAllocationStrategy(); 431 432 manager()->Remove(kRendererID2); 433 manager()->ReviseAllocationStrategy(); 434 435 manager()->ObserveActivity(kRendererID); 436 manager()->ReviseAllocationStrategy(); 437 438 manager()->Remove(kRendererID); 439 manager()->ReviseAllocationStrategy(); 440} 441 442TEST_F(WebCacheManagerTest, 443 CallRemoveRendererAndObserveActivityInAnyOrderShouldNotCrashTest_6) { 444 EXPECT_EQ(0U, active_renderers(manager()).size()); 445 EXPECT_EQ(0U, inactive_renderers(manager()).size()); 446 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 450 // operation. 451 manager()->Add(kRendererID); 452 manager()->ReviseAllocationStrategy(); 453 manager()->Add(kRendererID2); 454 manager()->ReviseAllocationStrategy(); 455 456 manager()->Remove(kRendererID2); 457 manager()->ReviseAllocationStrategy(); 458 459 manager()->Remove(kRendererID); 460 manager()->ReviseAllocationStrategy(); 461 462 manager()->ObserveActivity(kRendererID); 463 manager()->ReviseAllocationStrategy(); 464} 465 466} // namespace web_cache 467