OLD | NEW |
| (Empty) |
1 // Copyright 2016 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 "components/offline_pages/background/pick_request_task.h" | |
6 | |
7 #include <memory> | |
8 #include <set> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/test/test_simple_task_runner.h" | |
12 #include "base/threading/thread_task_runner_handle.h" | |
13 #include "components/offline_pages/background/device_conditions.h" | |
14 #include "components/offline_pages/background/offliner_policy.h" | |
15 #include "components/offline_pages/background/request_coordinator.h" | |
16 #include "components/offline_pages/background/request_coordinator_event_logger.h
" | |
17 #include "components/offline_pages/background/request_notifier.h" | |
18 #include "components/offline_pages/background/request_queue_in_memory_store.h" | |
19 #include "components/offline_pages/background/request_queue_store.h" | |
20 #include "components/offline_pages/background/save_page_request.h" | |
21 #include "testing/gtest/include/gtest/gtest.h" | |
22 | |
23 namespace offline_pages { | |
24 | |
25 namespace { | |
26 // Data for request 1. | |
27 const int64_t kRequestId1 = 17; | |
28 const GURL kUrl1("https://google.com"); | |
29 const ClientId kClientId1("bookmark", "1234"); | |
30 // Data for request 2. | |
31 const int64_t kRequestId2 = 42; | |
32 const GURL kUrl2("http://nytimes.com"); | |
33 const ClientId kClientId2("bookmark", "5678"); | |
34 const bool kUserRequested = true; | |
35 const int kAttemptCount = 1; | |
36 const int kMaxStartedTries = 5; | |
37 const int kMaxCompletedTries = 1; | |
38 | |
39 // Constants for policy values - These settings represent the default values. | |
40 const bool kPreferUntried = false; | |
41 const bool kPreferEarlier = true; | |
42 const bool kPreferRetryCount = true; | |
43 const int kBackgroundProcessingTimeBudgetSeconds = 170; | |
44 | |
45 // Default request | |
46 const SavePageRequest kEmptyRequest(0UL, | |
47 GURL(""), | |
48 ClientId("", ""), | |
49 base::Time(), | |
50 true); | |
51 } // namespace | |
52 | |
53 // Helper class needed by the PickRequestTask | |
54 class RequestNotifierStub : public RequestNotifier { | |
55 public: | |
56 RequestNotifierStub() | |
57 : last_expired_request_(kEmptyRequest), total_expired_requests_(0) {} | |
58 | |
59 void NotifyAdded(const SavePageRequest& request) override {} | |
60 void NotifyChanged(const SavePageRequest& request) override {} | |
61 | |
62 void NotifyCompleted(const SavePageRequest& request, | |
63 BackgroundSavePageResult status) override { | |
64 last_expired_request_ = request; | |
65 last_request_expiration_status_ = status; | |
66 total_expired_requests_++; | |
67 } | |
68 | |
69 const SavePageRequest& last_expired_request() { | |
70 return last_expired_request_; | |
71 } | |
72 | |
73 RequestCoordinator::BackgroundSavePageResult | |
74 last_request_expiration_status() { | |
75 return last_request_expiration_status_; | |
76 } | |
77 | |
78 int32_t total_expired_requests() { return total_expired_requests_; } | |
79 | |
80 private: | |
81 BackgroundSavePageResult last_request_expiration_status_; | |
82 SavePageRequest last_expired_request_; | |
83 int32_t total_expired_requests_; | |
84 }; | |
85 | |
86 class PickRequestTaskTest : public testing::Test { | |
87 public: | |
88 PickRequestTaskTest(); | |
89 | |
90 ~PickRequestTaskTest() override; | |
91 | |
92 void SetUp() override; | |
93 | |
94 void PumpLoop(); | |
95 | |
96 void AddRequestDone(ItemActionStatus status); | |
97 | |
98 void RequestPicked(const SavePageRequest& request); | |
99 | |
100 void RequestNotPicked(const bool non_user_requested_tasks_remaining); | |
101 | |
102 void QueueRequests(const SavePageRequest& request1, | |
103 const SavePageRequest& request2); | |
104 | |
105 // Reset the factory and the task using the current policy. | |
106 void MakeFactoryAndTask(); | |
107 | |
108 RequestNotifierStub* GetNotifier() { return notifier_.get(); } | |
109 | |
110 PickRequestTask* task() { return task_.get(); } | |
111 | |
112 void TaskCompletionCallback(Task* completed_task); | |
113 | |
114 protected: | |
115 std::unique_ptr<RequestQueueStore> store_; | |
116 std::unique_ptr<RequestNotifierStub> notifier_; | |
117 std::unique_ptr<SavePageRequest> last_picked_; | |
118 std::unique_ptr<OfflinerPolicy> policy_; | |
119 RequestCoordinatorEventLogger event_logger_; | |
120 std::set<int64_t> disabled_requests_; | |
121 std::unique_ptr<PickRequestTaskFactory> factory_; | |
122 std::unique_ptr<PickRequestTask> task_; | |
123 bool request_queue_not_picked_called_; | |
124 bool task_complete_called_; | |
125 | |
126 private: | |
127 scoped_refptr<base::TestSimpleTaskRunner> task_runner_; | |
128 base::ThreadTaskRunnerHandle task_runner_handle_; | |
129 }; | |
130 | |
131 PickRequestTaskTest::PickRequestTaskTest() | |
132 : task_runner_(new base::TestSimpleTaskRunner), | |
133 task_runner_handle_(task_runner_) {} | |
134 | |
135 PickRequestTaskTest::~PickRequestTaskTest() {} | |
136 | |
137 void PickRequestTaskTest::SetUp() { | |
138 DeviceConditions conditions; | |
139 store_.reset(new RequestQueueInMemoryStore()); | |
140 policy_.reset(new OfflinerPolicy()); | |
141 notifier_.reset(new RequestNotifierStub()); | |
142 MakeFactoryAndTask(); | |
143 request_queue_not_picked_called_ = false; | |
144 task_complete_called_ = false; | |
145 last_picked_.reset(); | |
146 } | |
147 | |
148 void PickRequestTaskTest::PumpLoop() { | |
149 task_runner_->RunUntilIdle(); | |
150 } | |
151 | |
152 void PickRequestTaskTest::TaskCompletionCallback(Task* completed_task) { | |
153 task_complete_called_ = true; | |
154 } | |
155 | |
156 void PickRequestTaskTest::AddRequestDone(ItemActionStatus status) {} | |
157 | |
158 void PickRequestTaskTest::RequestPicked(const SavePageRequest& request) { | |
159 last_picked_.reset(new SavePageRequest(request)); | |
160 } | |
161 | |
162 void PickRequestTaskTest::RequestNotPicked( | |
163 const bool non_user_requested_tasks_remaining) { | |
164 request_queue_not_picked_called_ = true; | |
165 } | |
166 | |
167 // Test helper to queue the two given requests. | |
168 void PickRequestTaskTest::QueueRequests(const SavePageRequest& request1, | |
169 const SavePageRequest& request2) { | |
170 DeviceConditions conditions; | |
171 std::set<int64_t> disabled_requests; | |
172 // Add test requests on the Queue. | |
173 store_->AddRequest(request1, base::Bind(&PickRequestTaskTest::AddRequestDone, | |
174 base::Unretained(this))); | |
175 store_->AddRequest(request2, base::Bind(&PickRequestTaskTest::AddRequestDone, | |
176 base::Unretained(this))); | |
177 | |
178 // Pump the loop to give the async queue the opportunity to do the adds. | |
179 PumpLoop(); | |
180 } | |
181 | |
182 void PickRequestTaskTest::MakeFactoryAndTask() { | |
183 factory_.reset(new PickRequestTaskFactory(policy_.get(), notifier_.get(), | |
184 &event_logger_)); | |
185 DeviceConditions conditions; | |
186 task_ = factory_->CreatePickerTask( | |
187 store_.get(), | |
188 base::Bind(&PickRequestTaskTest::RequestPicked, base::Unretained(this)), | |
189 base::Bind(&PickRequestTaskTest::RequestNotPicked, | |
190 base::Unretained(this)), | |
191 conditions, disabled_requests_); | |
192 task_->SetTaskCompletionCallbackForTesting( | |
193 task_runner_.get(), | |
194 base::Bind(&PickRequestTaskTest::TaskCompletionCallback, | |
195 base::Unretained(this))); | |
196 } | |
197 | |
198 TEST_F(PickRequestTaskTest, PickFromEmptyQueue) { | |
199 task()->Run(); | |
200 PumpLoop(); | |
201 | |
202 // Pump the loop again to give the async queue the opportunity to return | |
203 // results from the Get operation, and for the picker to call the "QueueEmpty" | |
204 // callback. | |
205 PumpLoop(); | |
206 | |
207 EXPECT_TRUE(request_queue_not_picked_called_); | |
208 EXPECT_TRUE(task_complete_called_); | |
209 } | |
210 | |
211 TEST_F(PickRequestTaskTest, ChooseRequestWithHigherRetryCount) { | |
212 // Set up policy to prefer higher retry count. | |
213 policy_.reset(new OfflinerPolicy( | |
214 kPreferUntried, kPreferEarlier, kPreferRetryCount, kMaxStartedTries, | |
215 kMaxCompletedTries + 1, kBackgroundProcessingTimeBudgetSeconds)); | |
216 MakeFactoryAndTask(); | |
217 | |
218 base::Time creation_time = base::Time::Now(); | |
219 SavePageRequest request1(kRequestId1, kUrl1, kClientId1, creation_time, | |
220 kUserRequested); | |
221 SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time, | |
222 kUserRequested); | |
223 request2.set_completed_attempt_count(kAttemptCount); | |
224 | |
225 QueueRequests(request1, request2); | |
226 | |
227 task()->Run(); | |
228 PumpLoop(); | |
229 | |
230 EXPECT_EQ(kRequestId2, last_picked_->request_id()); | |
231 EXPECT_FALSE(request_queue_not_picked_called_); | |
232 EXPECT_TRUE(task_complete_called_); | |
233 } | |
234 | |
235 TEST_F(PickRequestTaskTest, ChooseRequestWithSameRetryCountButEarlier) { | |
236 base::Time creation_time1 = | |
237 base::Time::Now() - base::TimeDelta::FromSeconds(10); | |
238 base::Time creation_time2 = base::Time::Now(); | |
239 SavePageRequest request1(kRequestId1, kUrl1, kClientId1, creation_time1, | |
240 kUserRequested); | |
241 SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time2, | |
242 kUserRequested); | |
243 | |
244 QueueRequests(request1, request2); | |
245 | |
246 task()->Run(); | |
247 PumpLoop(); | |
248 | |
249 EXPECT_EQ(kRequestId1, last_picked_->request_id()); | |
250 EXPECT_FALSE(request_queue_not_picked_called_); | |
251 EXPECT_TRUE(task_complete_called_); | |
252 } | |
253 | |
254 TEST_F(PickRequestTaskTest, ChooseEarlierRequest) { | |
255 // We need a custom policy object prefering recency to retry count. | |
256 policy_.reset(new OfflinerPolicy( | |
257 kPreferUntried, kPreferEarlier, !kPreferRetryCount, kMaxStartedTries, | |
258 kMaxCompletedTries, kBackgroundProcessingTimeBudgetSeconds)); | |
259 MakeFactoryAndTask(); | |
260 | |
261 base::Time creation_time1 = | |
262 base::Time::Now() - base::TimeDelta::FromSeconds(10); | |
263 base::Time creation_time2 = base::Time::Now(); | |
264 SavePageRequest request1(kRequestId1, kUrl1, kClientId1, creation_time1, | |
265 kUserRequested); | |
266 SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time2, | |
267 kUserRequested); | |
268 request2.set_completed_attempt_count(kAttemptCount); | |
269 | |
270 QueueRequests(request1, request2); | |
271 | |
272 task()->Run(); | |
273 PumpLoop(); | |
274 | |
275 EXPECT_EQ(kRequestId1, last_picked_->request_id()); | |
276 EXPECT_FALSE(request_queue_not_picked_called_); | |
277 EXPECT_TRUE(task_complete_called_); | |
278 } | |
279 | |
280 TEST_F(PickRequestTaskTest, ChooseSameTimeRequestWithHigherRetryCount) { | |
281 // We need a custom policy object preferring recency to retry count. | |
282 policy_.reset(new OfflinerPolicy( | |
283 kPreferUntried, kPreferEarlier, !kPreferRetryCount, kMaxStartedTries, | |
284 kMaxCompletedTries + 1, kBackgroundProcessingTimeBudgetSeconds)); | |
285 MakeFactoryAndTask(); | |
286 | |
287 base::Time creation_time = base::Time::Now(); | |
288 SavePageRequest request1(kRequestId1, kUrl1, kClientId1, creation_time, | |
289 kUserRequested); | |
290 SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time, | |
291 kUserRequested); | |
292 request2.set_completed_attempt_count(kAttemptCount); | |
293 | |
294 QueueRequests(request1, request2); | |
295 | |
296 task()->Run(); | |
297 PumpLoop(); | |
298 | |
299 EXPECT_EQ(kRequestId2, last_picked_->request_id()); | |
300 EXPECT_FALSE(request_queue_not_picked_called_); | |
301 EXPECT_TRUE(task_complete_called_); | |
302 } | |
303 | |
304 TEST_F(PickRequestTaskTest, ChooseRequestWithLowerRetryCount) { | |
305 // We need a custom policy object preferring lower retry count. | |
306 policy_.reset(new OfflinerPolicy( | |
307 !kPreferUntried, kPreferEarlier, kPreferRetryCount, kMaxStartedTries, | |
308 kMaxCompletedTries + 1, kBackgroundProcessingTimeBudgetSeconds)); | |
309 MakeFactoryAndTask(); | |
310 | |
311 base::Time creation_time = base::Time::Now(); | |
312 SavePageRequest request1(kRequestId1, kUrl1, kClientId1, creation_time, | |
313 kUserRequested); | |
314 SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time, | |
315 kUserRequested); | |
316 request2.set_completed_attempt_count(kAttemptCount); | |
317 | |
318 QueueRequests(request1, request2); | |
319 | |
320 task()->Run(); | |
321 PumpLoop(); | |
322 | |
323 EXPECT_EQ(kRequestId1, last_picked_->request_id()); | |
324 EXPECT_FALSE(request_queue_not_picked_called_); | |
325 EXPECT_TRUE(task_complete_called_); | |
326 } | |
327 | |
328 TEST_F(PickRequestTaskTest, ChooseLaterRequest) { | |
329 // We need a custom policy preferring recency over retry, and later requests. | |
330 policy_.reset(new OfflinerPolicy( | |
331 kPreferUntried, !kPreferEarlier, !kPreferRetryCount, kMaxStartedTries, | |
332 kMaxCompletedTries, kBackgroundProcessingTimeBudgetSeconds)); | |
333 MakeFactoryAndTask(); | |
334 | |
335 base::Time creation_time1 = | |
336 base::Time::Now() - base::TimeDelta::FromSeconds(10); | |
337 base::Time creation_time2 = base::Time::Now(); | |
338 SavePageRequest request1(kRequestId1, kUrl1, kClientId1, creation_time1, | |
339 kUserRequested); | |
340 SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time2, | |
341 kUserRequested); | |
342 | |
343 QueueRequests(request1, request2); | |
344 | |
345 task()->Run(); | |
346 PumpLoop(); | |
347 | |
348 EXPECT_EQ(kRequestId2, last_picked_->request_id()); | |
349 EXPECT_FALSE(request_queue_not_picked_called_); | |
350 EXPECT_TRUE(task_complete_called_); | |
351 } | |
352 | |
353 TEST_F(PickRequestTaskTest, ChooseNonExpiredRequest) { | |
354 base::Time creation_time = base::Time::Now(); | |
355 base::Time expired_time = | |
356 creation_time - base::TimeDelta::FromSeconds( | |
357 policy_->GetRequestExpirationTimeInSeconds() + 60); | |
358 SavePageRequest request1(kRequestId1, kUrl1, kClientId1, creation_time, | |
359 kUserRequested); | |
360 SavePageRequest request2(kRequestId2, kUrl2, kClientId2, expired_time, | |
361 kUserRequested); | |
362 | |
363 QueueRequests(request1, request2); | |
364 | |
365 task()->Run(); | |
366 PumpLoop(); | |
367 | |
368 EXPECT_EQ(kRequestId1, last_picked_->request_id()); | |
369 EXPECT_FALSE(request_queue_not_picked_called_); | |
370 EXPECT_EQ(kRequestId2, GetNotifier()->last_expired_request().request_id()); | |
371 EXPECT_EQ(RequestNotifier::BackgroundSavePageResult::EXPIRED, | |
372 GetNotifier()->last_request_expiration_status()); | |
373 EXPECT_EQ(1, GetNotifier()->total_expired_requests()); | |
374 EXPECT_TRUE(task_complete_called_); | |
375 } | |
376 | |
377 TEST_F(PickRequestTaskTest, ChooseRequestThatHasNotExceededStartLimit) { | |
378 base::Time creation_time1 = | |
379 base::Time::Now() - base::TimeDelta::FromSeconds(1); | |
380 base::Time creation_time2 = base::Time::Now(); | |
381 SavePageRequest request1(kRequestId1, kUrl1, kClientId1, creation_time1, | |
382 kUserRequested); | |
383 SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time2, | |
384 kUserRequested); | |
385 | |
386 // With default policy settings, we should choose the earlier request. | |
387 // However, we will make the earlier reqeust exceed the limit. | |
388 request1.set_started_attempt_count(policy_->GetMaxStartedTries()); | |
389 | |
390 QueueRequests(request1, request2); | |
391 | |
392 task()->Run(); | |
393 PumpLoop(); | |
394 | |
395 EXPECT_EQ(kRequestId2, last_picked_->request_id()); | |
396 EXPECT_FALSE(request_queue_not_picked_called_); | |
397 EXPECT_TRUE(task_complete_called_); | |
398 } | |
399 | |
400 TEST_F(PickRequestTaskTest, ChooseRequestThatHasNotExceededCompletionLimit) { | |
401 base::Time creation_time1 = | |
402 base::Time::Now() - base::TimeDelta::FromSeconds(1); | |
403 base::Time creation_time2 = base::Time::Now(); | |
404 SavePageRequest request1(kRequestId1, kUrl1, kClientId1, creation_time1, | |
405 kUserRequested); | |
406 SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time2, | |
407 kUserRequested); | |
408 | |
409 // With default policy settings, we should choose the earlier request. | |
410 // However, we will make the earlier reqeust exceed the limit. | |
411 request1.set_completed_attempt_count(policy_->GetMaxCompletedTries()); | |
412 | |
413 QueueRequests(request1, request2); | |
414 | |
415 task()->Run(); | |
416 PumpLoop(); | |
417 | |
418 EXPECT_EQ(kRequestId2, last_picked_->request_id()); | |
419 EXPECT_FALSE(request_queue_not_picked_called_); | |
420 EXPECT_TRUE(task_complete_called_); | |
421 } | |
422 | |
423 TEST_F(PickRequestTaskTest, ChooseRequestThatIsNotDisabled) { | |
424 policy_.reset(new OfflinerPolicy( | |
425 kPreferUntried, kPreferEarlier, kPreferRetryCount, kMaxStartedTries, | |
426 kMaxCompletedTries + 1, kBackgroundProcessingTimeBudgetSeconds)); | |
427 | |
428 // put request 2 on disabled list, ensure request1 picked instead, | |
429 // even though policy would prefer 2. | |
430 disabled_requests_.insert(kRequestId2); | |
431 MakeFactoryAndTask(); | |
432 | |
433 base::Time creation_time = base::Time::Now(); | |
434 SavePageRequest request1(kRequestId1, kUrl1, kClientId1, creation_time, | |
435 kUserRequested); | |
436 SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time, | |
437 kUserRequested); | |
438 request2.set_completed_attempt_count(kAttemptCount); | |
439 | |
440 // Add test requests on the Queue. | |
441 QueueRequests(request1, request2); | |
442 | |
443 task()->Run(); | |
444 PumpLoop(); | |
445 | |
446 // Pump the loop again to give the async queue the opportunity to return | |
447 // results from the Get operation, and for the picker to call the "picked" | |
448 // callback. | |
449 PumpLoop(); | |
450 | |
451 EXPECT_EQ(kRequestId1, last_picked_->request_id()); | |
452 EXPECT_FALSE(request_queue_not_picked_called_); | |
453 EXPECT_TRUE(task_complete_called_); | |
454 } | |
455 | |
456 } // namespace offline_pages | |
OLD | NEW |