1 // Copyright (c) 2012 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.
10 #include "base/callback.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/memory/weak_ptr.h"
13 #include "base/message_loop.h"
14 #include "base/message_loop_proxy.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "webkit/quota/mock_storage_client.h"
17 #include "webkit/quota/quota_manager.h"
18 #include "webkit/quota/quota_temporary_storage_evictor.h"
22 class QuotaTemporaryStorageEvictorTest
;
26 class MockQuotaEvictionHandler
: public quota::QuotaEvictionHandler
{
28 explicit MockQuotaEvictionHandler(QuotaTemporaryStorageEvictorTest
*test
)
32 error_on_evict_origin_data_(false),
33 error_on_get_usage_and_quota_(false) {}
35 virtual void EvictOriginData(
38 const EvictOriginDataCallback
& callback
) OVERRIDE
{
39 if (error_on_evict_origin_data_
) {
40 callback
.Run(quota::kQuotaErrorInvalidModification
);
43 int64 origin_usage
= EnsureOriginRemoved(origin
);
44 if (origin_usage
>= 0)
45 available_space_
+= origin_usage
;
46 callback
.Run(quota::kQuotaStatusOk
);
49 virtual void GetUsageAndQuotaForEviction(
50 const GetUsageAndQuotaForEvictionCallback
& callback
) OVERRIDE
{
51 if (error_on_get_usage_and_quota_
) {
52 callback
.Run(quota::kQuotaErrorInvalidAccess
, QuotaAndUsage());
55 if (!task_for_get_usage_and_quota_
.is_null())
56 task_for_get_usage_and_quota_
.Run();
57 QuotaAndUsage quota_and_usage
= {
58 GetUsage(), unlimited_usage_
, quota_
, available_space_
};
59 callback
.Run(quota::kQuotaStatusOk
, quota_and_usage
);
62 virtual void GetLRUOrigin(
64 const GetLRUOriginCallback
& callback
) OVERRIDE
{
65 if (origin_order_
.empty())
68 callback
.Run(GURL(origin_order_
.front()));
71 int64
GetUsage() const {
72 int64 total_usage
= 0;
73 for (std::map
<GURL
, int64
>::const_iterator p
= origins_
.begin();
76 total_usage
+= p
->second
;
80 void set_quota(int64 quota
) {
83 void set_unlimited_usage(int64 usage
) {
84 unlimited_usage_
= usage
;
86 void set_available_space(int64 available_space
) {
87 available_space_
= available_space
;
89 void set_task_for_get_usage_and_quota(const base::Closure
& task
) {
90 task_for_get_usage_and_quota_
= task
;
92 void set_error_on_evict_origin_data(bool error_on_evict_origin_data
) {
93 error_on_evict_origin_data_
= error_on_evict_origin_data
;
95 void set_error_on_get_usage_and_quota(bool error_on_get_usage_and_quota
) {
96 error_on_get_usage_and_quota_
= error_on_get_usage_and_quota
;
99 // Simulates an access to |origin|. It reorders the internal LRU list.
100 // It internally uses AddOrigin().
101 void AccessOrigin(const GURL
& origin
) {
102 std::map
<GURL
, int64
>::iterator found
= origins_
.find(origin
);
103 EXPECT_TRUE(origins_
.end() != found
);
104 AddOrigin(origin
, found
->second
);
107 // Simulates adding or overwriting the |origin| to the internal origin set
108 // with the |usage|. It also adds or moves the |origin| to the end of the
110 void AddOrigin(const GURL
& origin
, int64 usage
) {
111 EnsureOriginRemoved(origin
);
112 origin_order_
.push_back(origin
);
113 origins_
[origin
] = usage
;
117 int64
EnsureOriginRemoved(const GURL
& origin
) {
119 if (origins_
.find(origin
) == origins_
.end())
122 origin_usage
= origins_
[origin
];
124 origins_
.erase(origin
);
125 origin_order_
.remove(origin
);
130 int64 unlimited_usage_
;
131 int64 available_space_
;
132 std::list
<GURL
> origin_order_
;
133 std::map
<GURL
, int64
> origins_
;
134 bool error_on_evict_origin_data_
;
135 bool error_on_get_usage_and_quota_
;
137 base::Closure task_for_get_usage_and_quota_
;
140 } // anonymous namespace
142 class QuotaTemporaryStorageEvictorTest
: public testing::Test
{
144 QuotaTemporaryStorageEvictorTest()
145 : num_get_usage_and_quota_for_eviction_(0),
146 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {}
148 virtual void SetUp() {
149 quota_eviction_handler_
.reset(new MockQuotaEvictionHandler(this));
151 // Run multiple evictions in a single RunUntilIdle() when interval_ms == 0
152 temporary_storage_evictor_
.reset(new QuotaTemporaryStorageEvictor(
153 quota_eviction_handler_
.get(), 0));
156 virtual void TearDown() {
157 temporary_storage_evictor_
.reset();
158 quota_eviction_handler_
.reset();
159 MessageLoop::current()->RunUntilIdle();
162 void TaskForRepeatedEvictionTest(
163 const std::pair
<GURL
, int64
>& origin_to_be_added
,
164 const GURL
& origin_to_be_accessed
,
165 int expected_usage_after_first
,
166 int expected_usage_after_second
) {
167 EXPECT_GE(4, num_get_usage_and_quota_for_eviction_
);
168 switch (num_get_usage_and_quota_for_eviction_
) {
170 EXPECT_EQ(expected_usage_after_first
,
171 quota_eviction_handler()->GetUsage());
172 if (!origin_to_be_added
.first
.is_empty())
173 quota_eviction_handler()->AddOrigin(origin_to_be_added
.first
,
174 origin_to_be_added
.second
);
175 if (!origin_to_be_accessed
.is_empty())
176 quota_eviction_handler()->AccessOrigin(origin_to_be_accessed
);
179 EXPECT_EQ(expected_usage_after_second
,
180 quota_eviction_handler()->GetUsage());
181 temporary_storage_evictor()->set_repeated_eviction(false);
184 ++num_get_usage_and_quota_for_eviction_
;
188 MockQuotaEvictionHandler
* quota_eviction_handler() const {
189 return static_cast<MockQuotaEvictionHandler
*>(
190 quota_eviction_handler_
.get());
193 QuotaTemporaryStorageEvictor
* temporary_storage_evictor() const {
194 return temporary_storage_evictor_
.get();
197 const QuotaTemporaryStorageEvictor::Statistics
& statistics() const {
198 return temporary_storage_evictor()->statistics_
;
201 void set_repeated_eviction(bool repeated_eviction
) const {
202 return temporary_storage_evictor_
->set_repeated_eviction(repeated_eviction
);
205 int num_get_usage_and_quota_for_eviction() const {
206 return num_get_usage_and_quota_for_eviction_
;
209 int64
default_min_available_disk_space_to_start_eviction() const {
210 return 1000 * 1000 * 500;
213 void set_min_available_disk_space_to_start_eviction(int64 value
) const {
214 temporary_storage_evictor_
->set_min_available_disk_space_to_start_eviction(
218 void reset_min_available_disk_space_to_start_eviction() const {
219 temporary_storage_evictor_
->
220 reset_min_available_disk_space_to_start_eviction();
223 MessageLoop message_loop_
;
224 scoped_ptr
<MockQuotaEvictionHandler
> quota_eviction_handler_
;
225 scoped_ptr
<QuotaTemporaryStorageEvictor
> temporary_storage_evictor_
;
227 int num_get_usage_and_quota_for_eviction_
;
229 base::WeakPtrFactory
<QuotaTemporaryStorageEvictorTest
> weak_factory_
;
231 DISALLOW_COPY_AND_ASSIGN(QuotaTemporaryStorageEvictorTest
);
234 TEST_F(QuotaTemporaryStorageEvictorTest
, SimpleEvictionTest
) {
235 quota_eviction_handler()->AddOrigin(GURL("http://www.z.com"), 3000);
236 quota_eviction_handler()->AddOrigin(GURL("http://www.y.com"), 200);
237 quota_eviction_handler()->AddOrigin(GURL("http://www.x.com"), 500);
238 quota_eviction_handler()->set_quota(4000);
239 quota_eviction_handler()->set_available_space(1000000000);
240 EXPECT_EQ(3000 + 200 + 500, quota_eviction_handler()->GetUsage());
241 set_repeated_eviction(false);
242 temporary_storage_evictor()->Start();
243 MessageLoop::current()->RunUntilIdle();
244 EXPECT_EQ(200 + 500, quota_eviction_handler()->GetUsage());
246 EXPECT_EQ(0, statistics().num_errors_on_evicting_origin
);
247 EXPECT_EQ(0, statistics().num_errors_on_getting_usage_and_quota
);
248 EXPECT_EQ(1, statistics().num_evicted_origins
);
249 EXPECT_EQ(1, statistics().num_eviction_rounds
);
250 EXPECT_EQ(0, statistics().num_skipped_eviction_rounds
);
253 TEST_F(QuotaTemporaryStorageEvictorTest
, MultipleEvictionTest
) {
254 quota_eviction_handler()->AddOrigin(GURL("http://www.z.com"), 20);
255 quota_eviction_handler()->AddOrigin(GURL("http://www.y.com"), 2900);
256 quota_eviction_handler()->AddOrigin(GURL("http://www.x.com"), 450);
257 quota_eviction_handler()->AddOrigin(GURL("http://www.w.com"), 400);
258 quota_eviction_handler()->set_quota(4000);
259 quota_eviction_handler()->set_available_space(1000000000);
260 EXPECT_EQ(20 + 2900 + 450 + 400, quota_eviction_handler()->GetUsage());
261 set_repeated_eviction(false);
262 temporary_storage_evictor()->Start();
263 MessageLoop::current()->RunUntilIdle();
264 EXPECT_EQ(450 + 400, quota_eviction_handler()->GetUsage());
266 EXPECT_EQ(0, statistics().num_errors_on_evicting_origin
);
267 EXPECT_EQ(0, statistics().num_errors_on_getting_usage_and_quota
);
268 EXPECT_EQ(2, statistics().num_evicted_origins
);
269 EXPECT_EQ(1, statistics().num_eviction_rounds
);
270 EXPECT_EQ(0, statistics().num_skipped_eviction_rounds
);
273 TEST_F(QuotaTemporaryStorageEvictorTest
, RepeatedEvictionTest
) {
274 const int64 a_size
= 400;
275 const int64 b_size
= 150;
276 const int64 c_size
= 120;
277 const int64 d_size
= 292;
278 const int64 initial_total_size
= a_size
+ b_size
+ c_size
+ d_size
;
279 const int64 e_size
= 275;
281 quota_eviction_handler()->AddOrigin(GURL("http://www.d.com"), d_size
);
282 quota_eviction_handler()->AddOrigin(GURL("http://www.c.com"), c_size
);
283 quota_eviction_handler()->AddOrigin(GURL("http://www.b.com"), b_size
);
284 quota_eviction_handler()->AddOrigin(GURL("http://www.a.com"), a_size
);
285 quota_eviction_handler()->set_quota(1000);
286 quota_eviction_handler()->set_available_space(1000000000);
287 quota_eviction_handler()->set_task_for_get_usage_and_quota(
288 base::Bind(&QuotaTemporaryStorageEvictorTest::TaskForRepeatedEvictionTest
,
289 weak_factory_
.GetWeakPtr(),
290 std::make_pair(GURL("http://www.e.com"), e_size
), GURL(),
291 initial_total_size
- d_size
,
292 initial_total_size
- d_size
+ e_size
- c_size
));
293 EXPECT_EQ(initial_total_size
, quota_eviction_handler()->GetUsage());
294 temporary_storage_evictor()->Start();
295 MessageLoop::current()->RunUntilIdle();
296 EXPECT_EQ(initial_total_size
- d_size
+ e_size
- c_size
- b_size
,
297 quota_eviction_handler()->GetUsage());
298 EXPECT_EQ(5, num_get_usage_and_quota_for_eviction());
300 EXPECT_EQ(0, statistics().num_errors_on_evicting_origin
);
301 EXPECT_EQ(0, statistics().num_errors_on_getting_usage_and_quota
);
302 EXPECT_EQ(3, statistics().num_evicted_origins
);
303 EXPECT_EQ(2, statistics().num_eviction_rounds
);
304 EXPECT_EQ(0, statistics().num_skipped_eviction_rounds
);
307 TEST_F(QuotaTemporaryStorageEvictorTest
, RepeatedEvictionSkippedTest
) {
308 const int64 a_size
= 400;
309 const int64 b_size
= 150;
310 const int64 c_size
= 120;
311 const int64 d_size
= 292;
312 const int64 initial_total_size
= a_size
+ b_size
+ c_size
+ d_size
;
314 quota_eviction_handler()->AddOrigin(GURL("http://www.d.com"), d_size
);
315 quota_eviction_handler()->AddOrigin(GURL("http://www.c.com"), c_size
);
316 quota_eviction_handler()->AddOrigin(GURL("http://www.b.com"), b_size
);
317 quota_eviction_handler()->AddOrigin(GURL("http://www.a.com"), a_size
);
318 quota_eviction_handler()->set_quota(1000);
319 quota_eviction_handler()->set_available_space(1000000000);
320 quota_eviction_handler()->set_task_for_get_usage_and_quota(
321 base::Bind(&QuotaTemporaryStorageEvictorTest::TaskForRepeatedEvictionTest
,
322 weak_factory_
.GetWeakPtr(), std::make_pair(GURL(), 0), GURL(),
323 initial_total_size
- d_size
, initial_total_size
- d_size
));
324 EXPECT_EQ(initial_total_size
, quota_eviction_handler()->GetUsage());
325 set_repeated_eviction(true);
326 temporary_storage_evictor()->Start();
327 MessageLoop::current()->RunUntilIdle();
328 EXPECT_EQ(initial_total_size
- d_size
,
329 quota_eviction_handler()->GetUsage());
330 EXPECT_EQ(4, num_get_usage_and_quota_for_eviction());
332 EXPECT_EQ(0, statistics().num_errors_on_evicting_origin
);
333 EXPECT_EQ(0, statistics().num_errors_on_getting_usage_and_quota
);
334 EXPECT_EQ(1, statistics().num_evicted_origins
);
335 EXPECT_EQ(3, statistics().num_eviction_rounds
);
336 EXPECT_EQ(2, statistics().num_skipped_eviction_rounds
);
339 TEST_F(QuotaTemporaryStorageEvictorTest
, RepeatedEvictionWithAccessOriginTest
) {
340 const int64 a_size
= 400;
341 const int64 b_size
= 150;
342 const int64 c_size
= 120;
343 const int64 d_size
= 292;
344 const int64 initial_total_size
= a_size
+ b_size
+ c_size
+ d_size
;
345 const int64 e_size
= 275;
347 quota_eviction_handler()->AddOrigin(GURL("http://www.d.com"), d_size
);
348 quota_eviction_handler()->AddOrigin(GURL("http://www.c.com"), c_size
);
349 quota_eviction_handler()->AddOrigin(GURL("http://www.b.com"), b_size
);
350 quota_eviction_handler()->AddOrigin(GURL("http://www.a.com"), a_size
);
351 quota_eviction_handler()->set_quota(1000);
352 quota_eviction_handler()->set_available_space(1000000000);
353 quota_eviction_handler()->set_task_for_get_usage_and_quota(
354 base::Bind(&QuotaTemporaryStorageEvictorTest::TaskForRepeatedEvictionTest
,
355 weak_factory_
.GetWeakPtr(),
356 std::make_pair(GURL("http://www.e.com"), e_size
),
357 GURL("http://www.c.com"),
358 initial_total_size
- d_size
,
359 initial_total_size
- d_size
+ e_size
- b_size
));
360 EXPECT_EQ(initial_total_size
, quota_eviction_handler()->GetUsage());
361 temporary_storage_evictor()->Start();
362 MessageLoop::current()->RunUntilIdle();
363 EXPECT_EQ(initial_total_size
- d_size
+ e_size
- b_size
- a_size
,
364 quota_eviction_handler()->GetUsage());
365 EXPECT_EQ(5, num_get_usage_and_quota_for_eviction());
367 EXPECT_EQ(0, statistics().num_errors_on_evicting_origin
);
368 EXPECT_EQ(0, statistics().num_errors_on_getting_usage_and_quota
);
369 EXPECT_EQ(3, statistics().num_evicted_origins
);
370 EXPECT_EQ(2, statistics().num_eviction_rounds
);
371 EXPECT_EQ(0, statistics().num_skipped_eviction_rounds
);
374 TEST_F(QuotaTemporaryStorageEvictorTest
, DiskSpaceNonEvictionTest
) {
375 quota_eviction_handler()->AddOrigin(GURL("http://www.z.com"), 414);
376 quota_eviction_handler()->AddOrigin(GURL("http://www.x.com"), 450);
377 quota_eviction_handler()->set_quota(10000);
378 quota_eviction_handler()->set_available_space(
379 default_min_available_disk_space_to_start_eviction() - 350);
380 EXPECT_EQ(414 + 450, quota_eviction_handler()->GetUsage());
381 reset_min_available_disk_space_to_start_eviction();
382 set_repeated_eviction(false);
383 temporary_storage_evictor()->Start();
384 MessageLoop::current()->RunUntilIdle();
385 EXPECT_EQ(414 + 450, quota_eviction_handler()->GetUsage());
387 EXPECT_EQ(0, statistics().num_errors_on_evicting_origin
);
388 EXPECT_EQ(0, statistics().num_errors_on_getting_usage_and_quota
);
389 EXPECT_EQ(0, statistics().num_evicted_origins
);
390 EXPECT_EQ(1, statistics().num_eviction_rounds
);
391 EXPECT_EQ(1, statistics().num_skipped_eviction_rounds
);
394 TEST_F(QuotaTemporaryStorageEvictorTest
, DiskSpaceEvictionTest
) {
395 quota_eviction_handler()->AddOrigin(GURL("http://www.z.com"), 294);
396 quota_eviction_handler()->AddOrigin(GURL("http://www.y.com"), 120);
397 quota_eviction_handler()->AddOrigin(GURL("http://www.x.com"), 150);
398 quota_eviction_handler()->AddOrigin(GURL("http://www.w.com"), 300);
399 quota_eviction_handler()->set_quota(10000);
400 quota_eviction_handler()->set_available_space(
401 default_min_available_disk_space_to_start_eviction() - 350);
402 EXPECT_EQ(294 + 120 + 150 + 300, quota_eviction_handler()->GetUsage());
403 set_min_available_disk_space_to_start_eviction(
404 default_min_available_disk_space_to_start_eviction());
405 set_repeated_eviction(false);
406 temporary_storage_evictor()->Start();
407 MessageLoop::current()->RunUntilIdle();
408 EXPECT_EQ(150 + 300, quota_eviction_handler()->GetUsage());
410 EXPECT_EQ(0, statistics().num_errors_on_evicting_origin
);
411 EXPECT_EQ(0, statistics().num_errors_on_getting_usage_and_quota
);
412 EXPECT_EQ(2, statistics().num_evicted_origins
);
413 EXPECT_EQ(1, statistics().num_eviction_rounds
);
414 EXPECT_EQ(0, statistics().num_skipped_eviction_rounds
);
417 TEST_F(QuotaTemporaryStorageEvictorTest
, UnlimitedExclusionEvictionTest
) {
418 quota_eviction_handler()->AddOrigin(GURL("http://www.z.com"), 3000);
419 quota_eviction_handler()->AddOrigin(GURL("http://www.y.com"), 200);
420 quota_eviction_handler()->AddOrigin(GURL("http://www.x.com"), 500000);
421 quota_eviction_handler()->set_unlimited_usage(500000);
422 quota_eviction_handler()->set_quota(5000);
423 quota_eviction_handler()->set_available_space(1000000000);
424 EXPECT_EQ(3000 + 200 + 500000, quota_eviction_handler()->GetUsage());
425 set_repeated_eviction(false);
426 temporary_storage_evictor()->Start();
427 MessageLoop::current()->RunUntilIdle();
428 // Nothing should have been evicted.
429 EXPECT_EQ(3000 + 200 + 500000, quota_eviction_handler()->GetUsage());