1// Copyright (c) 2006-2008 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.h"
8#include "chrome/browser/renderer_host/web_cache_manager.h"
9#include "content/browser/browser_thread.h"
10#include "testing/gtest/include/gtest/gtest.h"
11
12using base::Time;
13using base::TimeDelta;
14using WebKit::WebCache;
15
16class WebCacheManagerTest : public testing::Test {
17 protected:
18  typedef WebCacheManager::StatsMap StatsMap;
19  typedef WebCacheManager::Allocation Allocation;
20  typedef WebCacheManager::AllocationStrategy AllocationStrategy;
21
22  static const int kRendererID;
23  static const int kRendererID2;
24  static const WebCache::UsageStats kStats;
25  static const WebCache::UsageStats kStats2;
26
27  WebCacheManagerTest()
28      : ui_thread_(BrowserThread::UI, &message_loop_) {
29  }
30
31  // Thunks to access protected members of WebCacheManager
32  static std::map<int, WebCacheManager::RendererInfo>& stats(
33        WebCacheManager* h) {
34    return h->stats_;
35  }
36
37  static void SimulateInactivity(WebCacheManager* h, int renderer_id) {
38    stats(h)[renderer_id].access = Time::Now() - TimeDelta::FromMinutes(
39        WebCacheManager::kRendererInactiveThresholdMinutes);
40    h->FindInactiveRenderers();
41  }
42
43  static std::set<int>& active_renderers(WebCacheManager* h) {
44    return h->active_renderers_;
45  }
46  static std::set<int>& inactive_renderers(WebCacheManager* h) {
47    return h->inactive_renderers_;
48  }
49  static void GatherStats(WebCacheManager* h,
50                          std::set<int> renderers,
51                          WebCache::UsageStats* stats) {
52    h->GatherStats(renderers, stats);
53  }
54  static size_t GetSize(int tactic,
55                        const WebCache::UsageStats& stats) {
56    return WebCacheManager::GetSize(
57        static_cast<WebCacheManager::AllocationTactic>(tactic), stats);
58  }
59  static bool AttemptTactic(WebCacheManager* h,
60                            int active_tactic,
61                            const WebCache::UsageStats& active_stats,
62                            int inactive_tactic,
63                            const WebCache::UsageStats& inactive_stats,
64                            std::list< std::pair<int,size_t> >* strategy) {
65    return h->AttemptTactic(
66        static_cast<WebCacheManager::AllocationTactic>(active_tactic),
67        active_stats,
68        static_cast<WebCacheManager::AllocationTactic>(inactive_tactic),
69        inactive_stats,
70        strategy);
71  }
72  static void AddToStrategy(WebCacheManager* h,
73                            std::set<int> renderers,
74                            int tactic,
75                            size_t extra_bytes_to_allocate,
76                            std::list< std::pair<int,size_t> >* strategy) {
77    h->AddToStrategy(renderers,
78                     static_cast<WebCacheManager::AllocationTactic>(tactic),
79                     extra_bytes_to_allocate,
80                     strategy);
81  }
82
83  enum {
84    DIVIDE_EVENLY = WebCacheManager::DIVIDE_EVENLY,
85    KEEP_CURRENT_WITH_HEADROOM = WebCacheManager::KEEP_CURRENT_WITH_HEADROOM,
86    KEEP_CURRENT = WebCacheManager::KEEP_CURRENT,
87    KEEP_LIVE_WITH_HEADROOM = WebCacheManager::KEEP_LIVE_WITH_HEADROOM,
88    KEEP_LIVE = WebCacheManager::KEEP_LIVE,
89  };
90
91  WebCacheManager* manager() { return &manager_; }
92
93 private:
94  WebCacheManager manager_;
95  MessageLoop message_loop_;
96  BrowserThread ui_thread_;
97};
98
99// static
100const int WebCacheManagerTest::kRendererID = 146;
101
102// static
103const int WebCacheManagerTest::kRendererID2 = 245;
104
105// static
106const WebCache::UsageStats WebCacheManagerTest::kStats = {
107    0,
108    1024 * 1024,
109    1024 * 1024,
110    256 * 1024,
111    512,
112  };
113
114// static
115const WebCache::UsageStats WebCacheManagerTest::kStats2 = {
116    0,
117    2 * 1024 * 1024,
118    2 * 1024 * 1024,
119    2 * 256 * 1024,
120    2 * 512,
121  };
122
123static bool operator==(const WebCache::UsageStats& lhs,
124                       const WebCache::UsageStats& rhs) {
125  return !::memcmp(&lhs, &rhs, sizeof(WebCache::UsageStats));
126}
127
128TEST_F(WebCacheManagerTest, AddRemoveRendererTest) {
129  EXPECT_EQ(0U, active_renderers(manager()).size());
130  EXPECT_EQ(0U, inactive_renderers(manager()).size());
131
132  manager()->Add(kRendererID);
133  EXPECT_EQ(1U, active_renderers(manager()).count(kRendererID));
134  EXPECT_EQ(0U, inactive_renderers(manager()).count(kRendererID));
135
136  manager()->Remove(kRendererID);
137  EXPECT_EQ(0U, active_renderers(manager()).size());
138  EXPECT_EQ(0U, inactive_renderers(manager()).size());
139}
140
141TEST_F(WebCacheManagerTest, ActiveInactiveTest) {
142  manager()->Add(kRendererID);
143
144  manager()->ObserveActivity(kRendererID);
145  EXPECT_EQ(1U, active_renderers(manager()).count(kRendererID));
146  EXPECT_EQ(0U, inactive_renderers(manager()).count(kRendererID));
147
148  SimulateInactivity(manager(), kRendererID);
149  EXPECT_EQ(0U, active_renderers(manager()).count(kRendererID));
150  EXPECT_EQ(1U, inactive_renderers(manager()).count(kRendererID));
151
152  manager()->ObserveActivity(kRendererID);
153  EXPECT_EQ(1U, active_renderers(manager()).count(kRendererID));
154  EXPECT_EQ(0U, inactive_renderers(manager()).count(kRendererID));
155
156  manager()->Remove(kRendererID);
157}
158
159TEST_F(WebCacheManagerTest, ObserveStatsTest) {
160  manager()->Add(kRendererID);
161
162  EXPECT_EQ(1U, stats(manager()).size());
163
164  manager()->ObserveStats(kRendererID, kStats);
165
166  EXPECT_EQ(1U, stats(manager()).size());
167  EXPECT_TRUE(kStats == stats(manager())[kRendererID]);
168
169  manager()->Remove(kRendererID);
170}
171
172TEST_F(WebCacheManagerTest, SetGlobalSizeLimitTest) {
173  size_t limit = manager()->GetDefaultGlobalSizeLimit();
174  manager()->SetGlobalSizeLimit(limit);
175  EXPECT_EQ(limit, manager()->global_size_limit());
176
177  manager()->SetGlobalSizeLimit(0);
178  EXPECT_EQ(0U, manager()->global_size_limit());
179}
180
181TEST_F(WebCacheManagerTest, GatherStatsTest) {
182  manager()->Add(kRendererID);
183  manager()->Add(kRendererID2);
184
185  manager()->ObserveStats(kRendererID, kStats);
186  manager()->ObserveStats(kRendererID2, kStats2);
187
188  std::set<int> renderer_set;
189  renderer_set.insert(kRendererID);
190
191  WebCache::UsageStats stats;
192  GatherStats(manager(), renderer_set, &stats);
193
194  EXPECT_TRUE(kStats == stats);
195
196  renderer_set.insert(kRendererID2);
197  GatherStats(manager(), renderer_set, &stats);
198
199  WebCache::UsageStats expected_stats = kStats;
200  expected_stats.minDeadCapacity += kStats2.minDeadCapacity;
201  expected_stats.maxDeadCapacity += kStats2.maxDeadCapacity;
202  expected_stats.capacity += kStats2.capacity;
203  expected_stats.liveSize += kStats2.liveSize;
204  expected_stats.deadSize += kStats2.deadSize;
205
206  EXPECT_TRUE(expected_stats == stats);
207
208  manager()->Remove(kRendererID);
209  manager()->Remove(kRendererID2);
210}
211
212TEST_F(WebCacheManagerTest, GetSizeTest) {
213  EXPECT_EQ(0U, GetSize(DIVIDE_EVENLY, kStats));
214  EXPECT_LT(256 * 1024u + 512, GetSize(KEEP_CURRENT_WITH_HEADROOM, kStats));
215  EXPECT_EQ(256 * 1024u + 512, GetSize(KEEP_CURRENT, kStats));
216  EXPECT_LT(256 * 1024u, GetSize(KEEP_LIVE_WITH_HEADROOM, kStats));
217  EXPECT_EQ(256 * 1024u, GetSize(KEEP_LIVE, kStats));
218}
219
220TEST_F(WebCacheManagerTest, AttemptTacticTest) {
221  manager()->Add(kRendererID);
222  manager()->Add(kRendererID2);
223
224  manager()->ObserveActivity(kRendererID);
225  SimulateInactivity(manager(), kRendererID2);
226
227  manager()->ObserveStats(kRendererID, kStats);
228  manager()->ObserveStats(kRendererID2, kStats2);
229
230  manager()->SetGlobalSizeLimit(kStats.liveSize + kStats.deadSize +
231                        kStats2.liveSize + kStats2.deadSize/2);
232
233  AllocationStrategy strategy;
234
235  EXPECT_FALSE(AttemptTactic(manager(),
236                             KEEP_CURRENT,
237                             kStats,
238                             KEEP_CURRENT,
239                             kStats2,
240                             &strategy));
241  EXPECT_TRUE(strategy.empty());
242
243  EXPECT_TRUE(AttemptTactic(manager(),
244                            KEEP_CURRENT,
245                            kStats,
246                            KEEP_LIVE,
247                            kStats2,
248                            &strategy));
249  EXPECT_EQ(2U, strategy.size());
250
251  AllocationStrategy::iterator iter = strategy.begin();
252  while (iter != strategy.end()) {
253    if (iter->first == kRendererID)
254      EXPECT_LE(kStats.liveSize + kStats.deadSize, iter->second);
255    else if (iter->first == kRendererID2)
256      EXPECT_LE(kStats2.liveSize, iter->second);
257    else
258      EXPECT_FALSE("Unexpected entry in strategy");
259    ++iter;
260  }
261
262  manager()->Remove(kRendererID);
263  manager()->Remove(kRendererID2);
264}
265
266TEST_F(WebCacheManagerTest, AddToStrategyTest) {
267  manager()->Add(kRendererID);
268  manager()->Add(kRendererID2);
269
270  std::set<int> renderer_set;
271  renderer_set.insert(kRendererID);
272  renderer_set.insert(kRendererID2);
273
274  manager()->ObserveStats(kRendererID, kStats);
275  manager()->ObserveStats(kRendererID2, kStats2);
276
277  const size_t kExtraBytesToAllocate = 10 * 1024;
278
279  AllocationStrategy strategy;
280  AddToStrategy(manager(),
281                renderer_set,
282                KEEP_CURRENT,
283                kExtraBytesToAllocate,
284                &strategy);
285
286  EXPECT_EQ(2U, strategy.size());
287
288  size_t total_bytes = 0;
289  AllocationStrategy::iterator iter = strategy.begin();
290  while (iter != strategy.end()) {
291    total_bytes += iter->second;
292
293    if (iter->first == kRendererID)
294      EXPECT_LE(kStats.liveSize + kStats.deadSize, iter->second);
295    else if (iter->first == kRendererID2)
296      EXPECT_LE(kStats2.liveSize + kStats2.deadSize, iter->second);
297    else
298      EXPECT_FALSE("Unexpected entry in strategy");
299    ++iter;
300  }
301
302  size_t expected_total_bytes = kExtraBytesToAllocate +
303                                kStats.liveSize + kStats.deadSize +
304                                kStats2.liveSize + kStats2.deadSize;
305
306  EXPECT_GE(expected_total_bytes, total_bytes);
307
308  manager()->Remove(kRendererID);
309  manager()->Remove(kRendererID2);
310}
311