OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include <list> | |
6 #include <map> | |
7 #include <utility> | |
8 | |
9 #include "base/bind.h" | |
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" | |
19 | |
20 namespace quota { | |
21 | |
22 class QuotaTemporaryStorageEvictorTest; | |
23 | |
24 namespace { | |
25 | |
26 class MockQuotaEvictionHandler : public quota::QuotaEvictionHandler { | |
27 public: | |
28 explicit MockQuotaEvictionHandler(QuotaTemporaryStorageEvictorTest *test) | |
29 : quota_(0), | |
30 available_space_(0), | |
31 error_on_evict_origin_data_(false), | |
32 error_on_get_usage_and_quota_(false) {} | |
33 | |
34 virtual void EvictOriginData( | |
35 const GURL& origin, | |
36 StorageType type, | |
37 const EvictOriginDataCallback& callback) OVERRIDE { | |
38 if (error_on_evict_origin_data_) { | |
39 callback.Run(quota::kQuotaErrorInvalidModification); | |
40 return; | |
41 } | |
42 int64 origin_usage = EnsureOriginRemoved(origin); | |
43 if (origin_usage >= 0) | |
44 available_space_ += origin_usage; | |
45 callback.Run(quota::kQuotaStatusOk); | |
46 } | |
47 | |
48 virtual void GetUsageAndQuotaForEviction( | |
49 const UsageAndQuotaCallback& callback) OVERRIDE { | |
50 if (error_on_get_usage_and_quota_) { | |
51 callback.Run(quota::kQuotaErrorInvalidAccess, UsageAndQuota()); | |
52 return; | |
53 } | |
54 if (!task_for_get_usage_and_quota_.is_null()) | |
55 task_for_get_usage_and_quota_.Run(); | |
56 UsageAndQuota quota_and_usage(-1, GetUsage(), quota_, available_space_); | |
57 callback.Run(quota::kQuotaStatusOk, quota_and_usage); | |
58 } | |
59 | |
60 virtual void GetLRUOrigin( | |
61 StorageType type, | |
62 const GetLRUOriginCallback& callback) OVERRIDE { | |
63 if (origin_order_.empty()) | |
64 callback.Run(GURL()); | |
65 else | |
66 callback.Run(GURL(origin_order_.front())); | |
67 } | |
68 | |
69 int64 GetUsage() const { | |
70 int64 total_usage = 0; | |
71 for (std::map<GURL, int64>::const_iterator p = origins_.begin(); | |
72 p != origins_.end(); | |
73 ++p) | |
74 total_usage += p->second; | |
75 return total_usage; | |
76 } | |
77 | |
78 void set_quota(int64 quota) { | |
79 quota_ = quota; | |
80 } | |
81 void set_available_space(int64 available_space) { | |
82 available_space_ = available_space; | |
83 } | |
84 void set_task_for_get_usage_and_quota(const base::Closure& task) { | |
85 task_for_get_usage_and_quota_= task; | |
86 } | |
87 void set_error_on_evict_origin_data(bool error_on_evict_origin_data) { | |
88 error_on_evict_origin_data_ = error_on_evict_origin_data; | |
89 } | |
90 void set_error_on_get_usage_and_quota(bool error_on_get_usage_and_quota) { | |
91 error_on_get_usage_and_quota_ = error_on_get_usage_and_quota; | |
92 } | |
93 | |
94 // Simulates an access to |origin|. It reorders the internal LRU list. | |
95 // It internally uses AddOrigin(). | |
96 void AccessOrigin(const GURL& origin) { | |
97 std::map<GURL, int64>::iterator found = origins_.find(origin); | |
98 EXPECT_TRUE(origins_.end() != found); | |
99 AddOrigin(origin, found->second); | |
100 } | |
101 | |
102 // Simulates adding or overwriting the |origin| to the internal origin set | |
103 // with the |usage|. It also adds or moves the |origin| to the end of the | |
104 // LRU list. | |
105 void AddOrigin(const GURL& origin, int64 usage) { | |
106 EnsureOriginRemoved(origin); | |
107 origin_order_.push_back(origin); | |
108 origins_[origin] = usage; | |
109 } | |
110 | |
111 private: | |
112 int64 EnsureOriginRemoved(const GURL& origin) { | |
113 int64 origin_usage; | |
114 if (origins_.find(origin) == origins_.end()) | |
115 return -1; | |
116 else | |
117 origin_usage = origins_[origin]; | |
118 | |
119 origins_.erase(origin); | |
120 origin_order_.remove(origin); | |
121 return origin_usage; | |
122 } | |
123 | |
124 int64 quota_; | |
125 int64 available_space_; | |
126 std::list<GURL> origin_order_; | |
127 std::map<GURL, int64> origins_; | |
128 bool error_on_evict_origin_data_; | |
129 bool error_on_get_usage_and_quota_; | |
130 | |
131 base::Closure task_for_get_usage_and_quota_; | |
132 }; | |
133 | |
134 } // anonymous namespace | |
135 | |
136 class QuotaTemporaryStorageEvictorTest : public testing::Test { | |
137 public: | |
138 QuotaTemporaryStorageEvictorTest() | |
139 : num_get_usage_and_quota_for_eviction_(0), | |
140 weak_factory_(this) {} | |
141 | |
142 virtual void SetUp() { | |
143 quota_eviction_handler_.reset(new MockQuotaEvictionHandler(this)); | |
144 | |
145 // Run multiple evictions in a single RunUntilIdle() when interval_ms == 0 | |
146 temporary_storage_evictor_.reset(new QuotaTemporaryStorageEvictor( | |
147 quota_eviction_handler_.get(), 0)); | |
148 } | |
149 | |
150 virtual void TearDown() { | |
151 temporary_storage_evictor_.reset(); | |
152 quota_eviction_handler_.reset(); | |
153 base::MessageLoop::current()->RunUntilIdle(); | |
154 } | |
155 | |
156 void TaskForRepeatedEvictionTest( | |
157 const std::pair<GURL, int64>& origin_to_be_added, | |
158 const GURL& origin_to_be_accessed, | |
159 int expected_usage_after_first, | |
160 int expected_usage_after_second) { | |
161 EXPECT_GE(4, num_get_usage_and_quota_for_eviction_); | |
162 switch (num_get_usage_and_quota_for_eviction_) { | |
163 case 2: | |
164 EXPECT_EQ(expected_usage_after_first, | |
165 quota_eviction_handler()->GetUsage()); | |
166 if (!origin_to_be_added.first.is_empty()) | |
167 quota_eviction_handler()->AddOrigin(origin_to_be_added.first, | |
168 origin_to_be_added.second); | |
169 if (!origin_to_be_accessed.is_empty()) | |
170 quota_eviction_handler()->AccessOrigin(origin_to_be_accessed); | |
171 break; | |
172 case 3: | |
173 EXPECT_EQ(expected_usage_after_second, | |
174 quota_eviction_handler()->GetUsage()); | |
175 temporary_storage_evictor()->set_repeated_eviction(false); | |
176 break; | |
177 } | |
178 ++num_get_usage_and_quota_for_eviction_; | |
179 } | |
180 | |
181 protected: | |
182 MockQuotaEvictionHandler* quota_eviction_handler() const { | |
183 return static_cast<MockQuotaEvictionHandler*>( | |
184 quota_eviction_handler_.get()); | |
185 } | |
186 | |
187 QuotaTemporaryStorageEvictor* temporary_storage_evictor() const { | |
188 return temporary_storage_evictor_.get(); | |
189 } | |
190 | |
191 const QuotaTemporaryStorageEvictor::Statistics& statistics() const { | |
192 return temporary_storage_evictor()->statistics_; | |
193 } | |
194 | |
195 void set_repeated_eviction(bool repeated_eviction) const { | |
196 return temporary_storage_evictor_->set_repeated_eviction(repeated_eviction); | |
197 } | |
198 | |
199 int num_get_usage_and_quota_for_eviction() const { | |
200 return num_get_usage_and_quota_for_eviction_; | |
201 } | |
202 | |
203 int64 default_min_available_disk_space_to_start_eviction() const { | |
204 return 1000 * 1000 * 500; | |
205 } | |
206 | |
207 void set_min_available_disk_space_to_start_eviction(int64 value) const { | |
208 temporary_storage_evictor_->set_min_available_disk_space_to_start_eviction( | |
209 value); | |
210 } | |
211 | |
212 void reset_min_available_disk_space_to_start_eviction() const { | |
213 temporary_storage_evictor_-> | |
214 reset_min_available_disk_space_to_start_eviction(); | |
215 } | |
216 | |
217 base::MessageLoop message_loop_; | |
218 scoped_ptr<MockQuotaEvictionHandler> quota_eviction_handler_; | |
219 scoped_ptr<QuotaTemporaryStorageEvictor> temporary_storage_evictor_; | |
220 | |
221 int num_get_usage_and_quota_for_eviction_; | |
222 | |
223 base::WeakPtrFactory<QuotaTemporaryStorageEvictorTest> weak_factory_; | |
224 | |
225 DISALLOW_COPY_AND_ASSIGN(QuotaTemporaryStorageEvictorTest); | |
226 }; | |
227 | |
228 TEST_F(QuotaTemporaryStorageEvictorTest, SimpleEvictionTest) { | |
229 quota_eviction_handler()->AddOrigin(GURL("http://www.z.com"), 3000); | |
230 quota_eviction_handler()->AddOrigin(GURL("http://www.y.com"), 200); | |
231 quota_eviction_handler()->AddOrigin(GURL("http://www.x.com"), 500); | |
232 quota_eviction_handler()->set_quota(4000); | |
233 quota_eviction_handler()->set_available_space(1000000000); | |
234 EXPECT_EQ(3000 + 200 + 500, quota_eviction_handler()->GetUsage()); | |
235 set_repeated_eviction(false); | |
236 temporary_storage_evictor()->Start(); | |
237 base::MessageLoop::current()->RunUntilIdle(); | |
238 EXPECT_EQ(200 + 500, quota_eviction_handler()->GetUsage()); | |
239 | |
240 EXPECT_EQ(0, statistics().num_errors_on_evicting_origin); | |
241 EXPECT_EQ(0, statistics().num_errors_on_getting_usage_and_quota); | |
242 EXPECT_EQ(1, statistics().num_evicted_origins); | |
243 EXPECT_EQ(1, statistics().num_eviction_rounds); | |
244 EXPECT_EQ(0, statistics().num_skipped_eviction_rounds); | |
245 } | |
246 | |
247 TEST_F(QuotaTemporaryStorageEvictorTest, MultipleEvictionTest) { | |
248 quota_eviction_handler()->AddOrigin(GURL("http://www.z.com"), 20); | |
249 quota_eviction_handler()->AddOrigin(GURL("http://www.y.com"), 2900); | |
250 quota_eviction_handler()->AddOrigin(GURL("http://www.x.com"), 450); | |
251 quota_eviction_handler()->AddOrigin(GURL("http://www.w.com"), 400); | |
252 quota_eviction_handler()->set_quota(4000); | |
253 quota_eviction_handler()->set_available_space(1000000000); | |
254 EXPECT_EQ(20 + 2900 + 450 + 400, quota_eviction_handler()->GetUsage()); | |
255 set_repeated_eviction(false); | |
256 temporary_storage_evictor()->Start(); | |
257 base::MessageLoop::current()->RunUntilIdle(); | |
258 EXPECT_EQ(450 + 400, quota_eviction_handler()->GetUsage()); | |
259 | |
260 EXPECT_EQ(0, statistics().num_errors_on_evicting_origin); | |
261 EXPECT_EQ(0, statistics().num_errors_on_getting_usage_and_quota); | |
262 EXPECT_EQ(2, statistics().num_evicted_origins); | |
263 EXPECT_EQ(1, statistics().num_eviction_rounds); | |
264 EXPECT_EQ(0, statistics().num_skipped_eviction_rounds); | |
265 } | |
266 | |
267 TEST_F(QuotaTemporaryStorageEvictorTest, RepeatedEvictionTest) { | |
268 const int64 a_size = 400; | |
269 const int64 b_size = 150; | |
270 const int64 c_size = 120; | |
271 const int64 d_size = 292; | |
272 const int64 initial_total_size = a_size + b_size + c_size + d_size; | |
273 const int64 e_size = 275; | |
274 | |
275 quota_eviction_handler()->AddOrigin(GURL("http://www.d.com"), d_size); | |
276 quota_eviction_handler()->AddOrigin(GURL("http://www.c.com"), c_size); | |
277 quota_eviction_handler()->AddOrigin(GURL("http://www.b.com"), b_size); | |
278 quota_eviction_handler()->AddOrigin(GURL("http://www.a.com"), a_size); | |
279 quota_eviction_handler()->set_quota(1000); | |
280 quota_eviction_handler()->set_available_space(1000000000); | |
281 quota_eviction_handler()->set_task_for_get_usage_and_quota( | |
282 base::Bind(&QuotaTemporaryStorageEvictorTest::TaskForRepeatedEvictionTest, | |
283 weak_factory_.GetWeakPtr(), | |
284 std::make_pair(GURL("http://www.e.com"), e_size), GURL(), | |
285 initial_total_size - d_size, | |
286 initial_total_size - d_size + e_size - c_size)); | |
287 EXPECT_EQ(initial_total_size, quota_eviction_handler()->GetUsage()); | |
288 temporary_storage_evictor()->Start(); | |
289 base::MessageLoop::current()->RunUntilIdle(); | |
290 EXPECT_EQ(initial_total_size - d_size + e_size - c_size - b_size, | |
291 quota_eviction_handler()->GetUsage()); | |
292 EXPECT_EQ(5, num_get_usage_and_quota_for_eviction()); | |
293 | |
294 EXPECT_EQ(0, statistics().num_errors_on_evicting_origin); | |
295 EXPECT_EQ(0, statistics().num_errors_on_getting_usage_and_quota); | |
296 EXPECT_EQ(3, statistics().num_evicted_origins); | |
297 EXPECT_EQ(2, statistics().num_eviction_rounds); | |
298 EXPECT_EQ(0, statistics().num_skipped_eviction_rounds); | |
299 } | |
300 | |
301 TEST_F(QuotaTemporaryStorageEvictorTest, RepeatedEvictionSkippedTest) { | |
302 const int64 a_size = 400; | |
303 const int64 b_size = 150; | |
304 const int64 c_size = 120; | |
305 const int64 d_size = 292; | |
306 const int64 initial_total_size = a_size + b_size + c_size + d_size; | |
307 | |
308 quota_eviction_handler()->AddOrigin(GURL("http://www.d.com"), d_size); | |
309 quota_eviction_handler()->AddOrigin(GURL("http://www.c.com"), c_size); | |
310 quota_eviction_handler()->AddOrigin(GURL("http://www.b.com"), b_size); | |
311 quota_eviction_handler()->AddOrigin(GURL("http://www.a.com"), a_size); | |
312 quota_eviction_handler()->set_quota(1000); | |
313 quota_eviction_handler()->set_available_space(1000000000); | |
314 quota_eviction_handler()->set_task_for_get_usage_and_quota( | |
315 base::Bind(&QuotaTemporaryStorageEvictorTest::TaskForRepeatedEvictionTest, | |
316 weak_factory_.GetWeakPtr(), std::make_pair(GURL(), 0), GURL(), | |
317 initial_total_size - d_size, initial_total_size - d_size)); | |
318 EXPECT_EQ(initial_total_size, quota_eviction_handler()->GetUsage()); | |
319 set_repeated_eviction(true); | |
320 temporary_storage_evictor()->Start(); | |
321 base::MessageLoop::current()->RunUntilIdle(); | |
322 EXPECT_EQ(initial_total_size - d_size, quota_eviction_handler()->GetUsage()); | |
323 EXPECT_EQ(4, num_get_usage_and_quota_for_eviction()); | |
324 | |
325 EXPECT_EQ(0, statistics().num_errors_on_evicting_origin); | |
326 EXPECT_EQ(0, statistics().num_errors_on_getting_usage_and_quota); | |
327 EXPECT_EQ(1, statistics().num_evicted_origins); | |
328 EXPECT_EQ(3, statistics().num_eviction_rounds); | |
329 EXPECT_EQ(2, statistics().num_skipped_eviction_rounds); | |
330 } | |
331 | |
332 TEST_F(QuotaTemporaryStorageEvictorTest, RepeatedEvictionWithAccessOriginTest) { | |
333 const int64 a_size = 400; | |
334 const int64 b_size = 150; | |
335 const int64 c_size = 120; | |
336 const int64 d_size = 292; | |
337 const int64 initial_total_size = a_size + b_size + c_size + d_size; | |
338 const int64 e_size = 275; | |
339 | |
340 quota_eviction_handler()->AddOrigin(GURL("http://www.d.com"), d_size); | |
341 quota_eviction_handler()->AddOrigin(GURL("http://www.c.com"), c_size); | |
342 quota_eviction_handler()->AddOrigin(GURL("http://www.b.com"), b_size); | |
343 quota_eviction_handler()->AddOrigin(GURL("http://www.a.com"), a_size); | |
344 quota_eviction_handler()->set_quota(1000); | |
345 quota_eviction_handler()->set_available_space(1000000000); | |
346 quota_eviction_handler()->set_task_for_get_usage_and_quota( | |
347 base::Bind(&QuotaTemporaryStorageEvictorTest::TaskForRepeatedEvictionTest, | |
348 weak_factory_.GetWeakPtr(), | |
349 std::make_pair(GURL("http://www.e.com"), e_size), | |
350 GURL("http://www.c.com"), | |
351 initial_total_size - d_size, | |
352 initial_total_size - d_size + e_size - b_size)); | |
353 EXPECT_EQ(initial_total_size, quota_eviction_handler()->GetUsage()); | |
354 temporary_storage_evictor()->Start(); | |
355 base::MessageLoop::current()->RunUntilIdle(); | |
356 EXPECT_EQ(initial_total_size - d_size + e_size - b_size - a_size, | |
357 quota_eviction_handler()->GetUsage()); | |
358 EXPECT_EQ(5, num_get_usage_and_quota_for_eviction()); | |
359 | |
360 EXPECT_EQ(0, statistics().num_errors_on_evicting_origin); | |
361 EXPECT_EQ(0, statistics().num_errors_on_getting_usage_and_quota); | |
362 EXPECT_EQ(3, statistics().num_evicted_origins); | |
363 EXPECT_EQ(2, statistics().num_eviction_rounds); | |
364 EXPECT_EQ(0, statistics().num_skipped_eviction_rounds); | |
365 } | |
366 | |
367 TEST_F(QuotaTemporaryStorageEvictorTest, DiskSpaceNonEvictionTest) { | |
368 quota_eviction_handler()->AddOrigin(GURL("http://www.z.com"), 414); | |
369 quota_eviction_handler()->AddOrigin(GURL("http://www.x.com"), 450); | |
370 quota_eviction_handler()->set_quota(10000); | |
371 quota_eviction_handler()->set_available_space( | |
372 default_min_available_disk_space_to_start_eviction() - 350); | |
373 EXPECT_EQ(414 + 450, quota_eviction_handler()->GetUsage()); | |
374 reset_min_available_disk_space_to_start_eviction(); | |
375 set_repeated_eviction(false); | |
376 temporary_storage_evictor()->Start(); | |
377 base::MessageLoop::current()->RunUntilIdle(); | |
378 EXPECT_EQ(414 + 450, quota_eviction_handler()->GetUsage()); | |
379 | |
380 EXPECT_EQ(0, statistics().num_errors_on_evicting_origin); | |
381 EXPECT_EQ(0, statistics().num_errors_on_getting_usage_and_quota); | |
382 EXPECT_EQ(0, statistics().num_evicted_origins); | |
383 EXPECT_EQ(1, statistics().num_eviction_rounds); | |
384 EXPECT_EQ(1, statistics().num_skipped_eviction_rounds); | |
385 } | |
386 | |
387 TEST_F(QuotaTemporaryStorageEvictorTest, DiskSpaceEvictionTest) { | |
388 quota_eviction_handler()->AddOrigin(GURL("http://www.z.com"), 294); | |
389 quota_eviction_handler()->AddOrigin(GURL("http://www.y.com"), 120); | |
390 quota_eviction_handler()->AddOrigin(GURL("http://www.x.com"), 150); | |
391 quota_eviction_handler()->AddOrigin(GURL("http://www.w.com"), 300); | |
392 quota_eviction_handler()->set_quota(10000); | |
393 quota_eviction_handler()->set_available_space( | |
394 default_min_available_disk_space_to_start_eviction() - 350); | |
395 EXPECT_EQ(294 + 120 + 150 + 300, quota_eviction_handler()->GetUsage()); | |
396 set_min_available_disk_space_to_start_eviction( | |
397 default_min_available_disk_space_to_start_eviction()); | |
398 set_repeated_eviction(false); | |
399 temporary_storage_evictor()->Start(); | |
400 base::MessageLoop::current()->RunUntilIdle(); | |
401 EXPECT_EQ(150 + 300, quota_eviction_handler()->GetUsage()); | |
402 | |
403 EXPECT_EQ(0, statistics().num_errors_on_evicting_origin); | |
404 EXPECT_EQ(0, statistics().num_errors_on_getting_usage_and_quota); | |
405 EXPECT_EQ(2, statistics().num_evicted_origins); | |
406 EXPECT_EQ(1, statistics().num_eviction_rounds); | |
407 EXPECT_EQ(0, statistics().num_skipped_eviction_rounds); | |
408 } | |
409 | |
410 } // namespace quota | |
OLD | NEW |