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/request_coordinator.h" | |
6 | |
7 #include <memory> | |
8 #include <string> | |
9 #include <utility> | |
10 #include <vector> | |
11 | |
12 #include "base/bind.h" | |
13 #include "base/location.h" | |
14 #include "base/logging.h" | |
15 #include "base/synchronization/waitable_event.h" | |
16 #include "base/sys_info.h" | |
17 #include "base/test/scoped_feature_list.h" | |
18 #include "base/test/test_mock_time_task_runner.h" | |
19 #include "base/threading/thread_task_runner_handle.h" | |
20 #include "base/time/time.h" | |
21 #include "components/offline_pages/background/device_conditions.h" | |
22 #include "components/offline_pages/background/offliner.h" | |
23 #include "components/offline_pages/background/offliner_factory.h" | |
24 #include "components/offline_pages/background/offliner_policy.h" | |
25 #include "components/offline_pages/background/pick_request_task_factory.h" | |
26 #include "components/offline_pages/background/request_queue.h" | |
27 #include "components/offline_pages/background/request_queue_in_memory_store.h" | |
28 #include "components/offline_pages/background/save_page_request.h" | |
29 #include "components/offline_pages/background/scheduler.h" | |
30 #include "components/offline_pages/offline_page_feature.h" | |
31 #include "testing/gtest/include/gtest/gtest.h" | |
32 | |
33 namespace offline_pages { | |
34 | |
35 namespace { | |
36 // put test constants here | |
37 const GURL kUrl1("http://universe.com/everything"); | |
38 const GURL kUrl2("http://universe.com/toinfinityandbeyond"); | |
39 const std::string kClientNamespace("bookmark"); | |
40 const std::string kId1("42"); | |
41 const std::string kId2("life*universe+everything"); | |
42 const ClientId kClientId1(kClientNamespace, kId1); | |
43 const ClientId kClientId2(kClientNamespace, kId2); | |
44 const int kRequestId1(1); | |
45 const int kRequestId2(2); | |
46 const long kTestTimeBudgetSeconds = 200; | |
47 const int kBatteryPercentageHigh = 75; | |
48 const int kMaxCompletedTries = 3; | |
49 const bool kPowerRequired = true; | |
50 const bool kUserRequested = true; | |
51 const int kAttemptCount = 1; | |
52 } // namespace | |
53 | |
54 class SchedulerStub : public Scheduler { | |
55 public: | |
56 SchedulerStub() | |
57 : schedule_called_(false), | |
58 backup_schedule_called_(false), | |
59 unschedule_called_(false), | |
60 schedule_delay_(0L), | |
61 conditions_(false, 0, false) {} | |
62 | |
63 void Schedule(const TriggerConditions& trigger_conditions) override { | |
64 schedule_called_ = true; | |
65 conditions_ = trigger_conditions; | |
66 } | |
67 | |
68 void BackupSchedule(const TriggerConditions& trigger_conditions, | |
69 long delay_in_seconds) override { | |
70 backup_schedule_called_ = true; | |
71 schedule_delay_ = delay_in_seconds; | |
72 conditions_ = trigger_conditions; | |
73 } | |
74 | |
75 // Unschedules the currently scheduled task, if any. | |
76 void Unschedule() override { | |
77 unschedule_called_ = true; | |
78 } | |
79 | |
80 bool schedule_called() const { return schedule_called_; } | |
81 | |
82 bool backup_schedule_called() const { return backup_schedule_called_;} | |
83 | |
84 bool unschedule_called() const { return unschedule_called_; } | |
85 | |
86 TriggerConditions const* conditions() const { return &conditions_; } | |
87 | |
88 private: | |
89 bool schedule_called_; | |
90 bool backup_schedule_called_; | |
91 bool unschedule_called_; | |
92 long schedule_delay_; | |
93 TriggerConditions conditions_; | |
94 }; | |
95 | |
96 class OfflinerStub : public Offliner { | |
97 public: | |
98 OfflinerStub() | |
99 : request_(kRequestId1, kUrl1, kClientId1, base::Time::Now(), | |
100 kUserRequested), | |
101 disable_loading_(false), | |
102 enable_callback_(false), | |
103 cancel_called_(false) {} | |
104 | |
105 bool LoadAndSave(const SavePageRequest& request, | |
106 const CompletionCallback& callback) override { | |
107 if (disable_loading_) | |
108 return false; | |
109 | |
110 callback_ = callback; | |
111 request_ = request; | |
112 // Post the callback on the run loop. | |
113 if (enable_callback_) { | |
114 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
115 FROM_HERE, | |
116 base::Bind(callback, request, Offliner::RequestStatus::SAVED)); | |
117 } | |
118 return true; | |
119 } | |
120 | |
121 void Cancel() override { cancel_called_ = true; } | |
122 | |
123 void disable_loading() { | |
124 disable_loading_ = true; | |
125 } | |
126 | |
127 void enable_callback(bool enable) { | |
128 enable_callback_ = enable; | |
129 } | |
130 | |
131 bool cancel_called() { return cancel_called_; } | |
132 | |
133 private: | |
134 CompletionCallback callback_; | |
135 SavePageRequest request_; | |
136 bool disable_loading_; | |
137 bool enable_callback_; | |
138 bool cancel_called_; | |
139 }; | |
140 | |
141 class OfflinerFactoryStub : public OfflinerFactory { | |
142 public: | |
143 OfflinerFactoryStub() : offliner_(nullptr) {} | |
144 | |
145 Offliner* GetOffliner(const OfflinerPolicy* policy) override { | |
146 if (offliner_.get() == nullptr) { | |
147 offliner_.reset(new OfflinerStub()); | |
148 } | |
149 return offliner_.get(); | |
150 } | |
151 | |
152 private: | |
153 std::unique_ptr<OfflinerStub> offliner_; | |
154 }; | |
155 | |
156 class NetworkQualityEstimatorStub | |
157 : public net::NetworkQualityEstimator::NetworkQualityProvider { | |
158 public: | |
159 NetworkQualityEstimatorStub() | |
160 : connection_type_( | |
161 net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_3G) {} | |
162 | |
163 net::EffectiveConnectionType GetEffectiveConnectionType() const override { | |
164 return connection_type_; | |
165 } | |
166 | |
167 void AddEffectiveConnectionTypeObserver( | |
168 net::NetworkQualityEstimator::EffectiveConnectionTypeObserver* observer) | |
169 override {} | |
170 | |
171 void RemoveEffectiveConnectionTypeObserver( | |
172 net::NetworkQualityEstimator::EffectiveConnectionTypeObserver* observer) | |
173 override {} | |
174 | |
175 void SetEffectiveConnectionTypeForTest(net::EffectiveConnectionType type) { | |
176 connection_type_ = type; | |
177 } | |
178 | |
179 private: | |
180 net::EffectiveConnectionType connection_type_; | |
181 }; | |
182 | |
183 class ObserverStub : public RequestCoordinator::Observer { | |
184 public: | |
185 ObserverStub() | |
186 : added_called_(false), | |
187 completed_called_(false), | |
188 changed_called_(false), | |
189 last_status_(RequestCoordinator::BackgroundSavePageResult::SUCCESS), | |
190 state_(SavePageRequest::RequestState::OFFLINING) {} | |
191 | |
192 void Clear() { | |
193 added_called_ = false; | |
194 completed_called_ = false; | |
195 changed_called_ = false; | |
196 state_ = SavePageRequest::RequestState::OFFLINING; | |
197 last_status_ = RequestCoordinator::BackgroundSavePageResult::SUCCESS; | |
198 } | |
199 | |
200 void OnAdded(const SavePageRequest& request) override { | |
201 added_called_ = true; | |
202 } | |
203 | |
204 void OnCompleted( | |
205 const SavePageRequest& request, | |
206 RequestCoordinator::BackgroundSavePageResult status) override { | |
207 completed_called_ = true; | |
208 last_status_ = status; | |
209 } | |
210 | |
211 void OnChanged(const SavePageRequest& request) override { | |
212 changed_called_ = true; | |
213 state_ = request.request_state(); | |
214 } | |
215 | |
216 bool added_called() { return added_called_; } | |
217 bool completed_called() { return completed_called_; } | |
218 bool changed_called() { return changed_called_; } | |
219 RequestCoordinator::BackgroundSavePageResult last_status() { | |
220 return last_status_; | |
221 } | |
222 SavePageRequest::RequestState state() { return state_; } | |
223 | |
224 private: | |
225 bool added_called_; | |
226 bool completed_called_; | |
227 bool changed_called_; | |
228 RequestCoordinator::BackgroundSavePageResult last_status_; | |
229 SavePageRequest::RequestState state_; | |
230 }; | |
231 | |
232 class RequestCoordinatorTest | |
233 : public testing::Test { | |
234 public: | |
235 RequestCoordinatorTest(); | |
236 ~RequestCoordinatorTest() override; | |
237 | |
238 void SetUp() override; | |
239 | |
240 void PumpLoop(); | |
241 | |
242 RequestCoordinator* coordinator() { | |
243 return coordinator_.get(); | |
244 } | |
245 | |
246 bool is_busy() { | |
247 return coordinator_->is_busy(); | |
248 } | |
249 | |
250 bool is_starting() { return coordinator_->is_starting(); } | |
251 | |
252 // Empty callback function. | |
253 void ImmediateScheduleCallbackFunction(bool result) { | |
254 immediate_schedule_callback_called_ = true; | |
255 immediate_schedule_callback_result_ = result; | |
256 } | |
257 | |
258 // Callback function which releases a wait for it. | |
259 void WaitingCallbackFunction(bool result) { | |
260 waiter_.Signal(); | |
261 } | |
262 | |
263 net::NetworkChangeNotifier::ConnectionType GetConnectionType() { | |
264 return coordinator()->GetConnectionType(); | |
265 } | |
266 | |
267 // Callback for Add requests. | |
268 void AddRequestDone(AddRequestResult result, const SavePageRequest& request); | |
269 | |
270 // Callback for getting requests. | |
271 void GetRequestsDone(GetRequestsResult result, | |
272 std::vector<std::unique_ptr<SavePageRequest>> requests); | |
273 | |
274 // Callback for removing requests. | |
275 void RemoveRequestsDone(const MultipleItemStatuses& results); | |
276 | |
277 // Callback for getting request statuses. | |
278 void GetQueuedRequestsDone( | |
279 std::vector<std::unique_ptr<SavePageRequest>> requests); | |
280 | |
281 void SetupForOfflinerDoneCallbackTest( | |
282 offline_pages::SavePageRequest* request); | |
283 | |
284 void SendOfflinerDoneCallback(const SavePageRequest& request, | |
285 Offliner::RequestStatus status); | |
286 | |
287 GetRequestsResult last_get_requests_result() const { | |
288 return last_get_requests_result_; | |
289 } | |
290 | |
291 const std::vector<std::unique_ptr<SavePageRequest>>& last_requests() const { | |
292 return last_requests_; | |
293 } | |
294 | |
295 const MultipleItemStatuses& last_remove_results() const { | |
296 return last_remove_results_; | |
297 } | |
298 | |
299 void DisableLoading() { | |
300 offliner_->disable_loading(); | |
301 } | |
302 | |
303 void EnableOfflinerCallback(bool enable) { | |
304 offliner_->enable_callback(enable); | |
305 } | |
306 | |
307 void SetNetworkConditionsForTest( | |
308 net::NetworkChangeNotifier::ConnectionType connection) { | |
309 coordinator()->SetNetworkConditionsForTest(connection); | |
310 } | |
311 | |
312 void SetEffectiveConnectionTypeForTest(net::EffectiveConnectionType type) { | |
313 network_quality_estimator_->SetEffectiveConnectionTypeForTest(type); | |
314 } | |
315 | |
316 void SetNetworkConnected(bool connected) { | |
317 if (connected) { | |
318 SetNetworkConditionsForTest( | |
319 net::NetworkChangeNotifier::ConnectionType::CONNECTION_3G); | |
320 SetEffectiveConnectionTypeForTest( | |
321 net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_3G); | |
322 } else { | |
323 SetNetworkConditionsForTest( | |
324 net::NetworkChangeNotifier::ConnectionType::CONNECTION_NONE); | |
325 SetEffectiveConnectionTypeForTest( | |
326 net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_OFFLINE); | |
327 } | |
328 } | |
329 | |
330 void SetIsLowEndDeviceForTest(bool is_low_end_device) { | |
331 coordinator()->is_low_end_device_ = is_low_end_device; | |
332 } | |
333 | |
334 void SetProcessingStateForTest( | |
335 RequestCoordinator::ProcessingWindowState processing_state) { | |
336 coordinator()->processing_state_ = processing_state; | |
337 } | |
338 | |
339 void SetOperationStartTimeForTest(base::Time start_time) { | |
340 coordinator()->operation_start_time_ = start_time; | |
341 } | |
342 | |
343 void ScheduleForTest() { coordinator_->ScheduleAsNeeded(); } | |
344 | |
345 void CallRequestNotPicked(bool non_user_requested_tasks_remaining, | |
346 bool disabled_tasks_remaining) { | |
347 if (disabled_tasks_remaining) | |
348 coordinator_->disabled_requests_.insert(kRequestId1); | |
349 else | |
350 coordinator_->disabled_requests_.clear(); | |
351 | |
352 coordinator_->RequestNotPicked(non_user_requested_tasks_remaining); | |
353 } | |
354 | |
355 void SetDeviceConditionsForTest(DeviceConditions device_conditions) { | |
356 coordinator_->SetDeviceConditionsForTest(device_conditions); | |
357 } | |
358 | |
359 void WaitForCallback() { | |
360 waiter_.Wait(); | |
361 } | |
362 | |
363 void AdvanceClockBy(base::TimeDelta delta) { | |
364 task_runner_->FastForwardBy(delta); | |
365 } | |
366 | |
367 SavePageRequest AddRequest1(); | |
368 | |
369 SavePageRequest AddRequest2(); | |
370 | |
371 Offliner::RequestStatus last_offlining_status() const { | |
372 return coordinator_->last_offlining_status_; | |
373 } | |
374 | |
375 bool OfflinerWasCanceled() const { return offliner_->cancel_called(); } | |
376 | |
377 ObserverStub observer() { return observer_; } | |
378 | |
379 DeviceConditions device_conditions() { return device_conditions_; } | |
380 | |
381 base::Callback<void(bool)> immediate_callback() { | |
382 return immediate_callback_; | |
383 } | |
384 | |
385 base::Callback<void(bool)> waiting_callback() { return waiting_callback_; } | |
386 bool immediate_schedule_callback_called() const { | |
387 return immediate_schedule_callback_called_; | |
388 } | |
389 | |
390 bool immediate_schedule_callback_result() const { | |
391 return immediate_schedule_callback_result_; | |
392 } | |
393 | |
394 private: | |
395 GetRequestsResult last_get_requests_result_; | |
396 MultipleItemStatuses last_remove_results_; | |
397 std::vector<std::unique_ptr<SavePageRequest>> last_requests_; | |
398 scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; | |
399 base::ThreadTaskRunnerHandle task_runner_handle_; | |
400 std::unique_ptr<NetworkQualityEstimatorStub> network_quality_estimator_; | |
401 std::unique_ptr<RequestCoordinator> coordinator_; | |
402 OfflinerStub* offliner_; | |
403 base::WaitableEvent waiter_; | |
404 ObserverStub observer_; | |
405 bool immediate_schedule_callback_called_; | |
406 bool immediate_schedule_callback_result_; | |
407 DeviceConditions device_conditions_; | |
408 base::Callback<void(bool)> immediate_callback_; | |
409 base::Callback<void(bool)> waiting_callback_; | |
410 }; | |
411 | |
412 RequestCoordinatorTest::RequestCoordinatorTest() | |
413 : last_get_requests_result_(GetRequestsResult::STORE_FAILURE), | |
414 task_runner_(new base::TestMockTimeTaskRunner), | |
415 task_runner_handle_(task_runner_), | |
416 offliner_(nullptr), | |
417 waiter_(base::WaitableEvent::ResetPolicy::MANUAL, | |
418 base::WaitableEvent::InitialState::NOT_SIGNALED), | |
419 immediate_schedule_callback_called_(false), | |
420 immediate_schedule_callback_result_(false), | |
421 device_conditions_(!kPowerRequired, | |
422 kBatteryPercentageHigh, | |
423 net::NetworkChangeNotifier::CONNECTION_3G) {} | |
424 | |
425 RequestCoordinatorTest::~RequestCoordinatorTest() {} | |
426 | |
427 void RequestCoordinatorTest::SetUp() { | |
428 std::unique_ptr<OfflinerPolicy> policy(new OfflinerPolicy()); | |
429 std::unique_ptr<OfflinerFactory> offliner_factory(new OfflinerFactoryStub()); | |
430 // Save the offliner for use by the tests. | |
431 offliner_ = reinterpret_cast<OfflinerStub*>( | |
432 offliner_factory->GetOffliner(policy.get())); | |
433 std::unique_ptr<RequestQueueInMemoryStore> | |
434 store(new RequestQueueInMemoryStore()); | |
435 std::unique_ptr<RequestQueue> queue(new RequestQueue(std::move(store))); | |
436 std::unique_ptr<Scheduler> scheduler_stub(new SchedulerStub()); | |
437 network_quality_estimator_.reset(new NetworkQualityEstimatorStub()); | |
438 coordinator_.reset(new RequestCoordinator( | |
439 std::move(policy), std::move(offliner_factory), std::move(queue), | |
440 std::move(scheduler_stub), network_quality_estimator_.get())); | |
441 coordinator_->AddObserver(&observer_); | |
442 SetNetworkConnected(true); | |
443 std::unique_ptr<PickRequestTaskFactory> picker_factory( | |
444 new PickRequestTaskFactory( | |
445 coordinator_->policy(), | |
446 static_cast<RequestNotifier*>(coordinator_.get()), | |
447 coordinator_->GetLogger())); | |
448 coordinator_->queue()->SetPickerFactory(std::move(picker_factory)); | |
449 immediate_callback_ = | |
450 base::Bind(&RequestCoordinatorTest::ImmediateScheduleCallbackFunction, | |
451 base::Unretained(this)); | |
452 // Override the normal immediate callback with a wait releasing callback. | |
453 waiting_callback_ = base::Bind( | |
454 &RequestCoordinatorTest::WaitingCallbackFunction, base::Unretained(this)); | |
455 SetDeviceConditionsForTest(device_conditions_); | |
456 EnableOfflinerCallback(true); | |
457 } | |
458 | |
459 void RequestCoordinatorTest::PumpLoop() { | |
460 task_runner_->RunUntilIdle(); | |
461 } | |
462 | |
463 void RequestCoordinatorTest::GetRequestsDone( | |
464 GetRequestsResult result, | |
465 std::vector<std::unique_ptr<SavePageRequest>> requests) { | |
466 last_get_requests_result_ = result; | |
467 last_requests_ = std::move(requests); | |
468 } | |
469 | |
470 void RequestCoordinatorTest::RemoveRequestsDone( | |
471 const MultipleItemStatuses& results) { | |
472 last_remove_results_ = results; | |
473 waiter_.Signal(); | |
474 } | |
475 | |
476 void RequestCoordinatorTest::GetQueuedRequestsDone( | |
477 std::vector<std::unique_ptr<SavePageRequest>> requests) { | |
478 last_requests_ = std::move(requests); | |
479 waiter_.Signal(); | |
480 } | |
481 | |
482 void RequestCoordinatorTest::AddRequestDone(AddRequestResult result, | |
483 const SavePageRequest& request) {} | |
484 | |
485 void RequestCoordinatorTest::SetupForOfflinerDoneCallbackTest( | |
486 offline_pages::SavePageRequest* request) { | |
487 // Mark request as started and add it to the queue, | |
488 // then wait for callback to finish. | |
489 request->MarkAttemptStarted(base::Time::Now()); | |
490 coordinator()->queue()->AddRequest( | |
491 *request, base::Bind(&RequestCoordinatorTest::AddRequestDone, | |
492 base::Unretained(this))); | |
493 PumpLoop(); | |
494 | |
495 // Override the processing callback for test visiblity. | |
496 base::Callback<void(bool)> callback = | |
497 base::Bind(&RequestCoordinatorTest::ImmediateScheduleCallbackFunction, | |
498 base::Unretained(this)); | |
499 coordinator()->SetProcessingCallbackForTest(callback); | |
500 | |
501 // Mock that coordinator is in actively processing state starting now. | |
502 SetProcessingStateForTest( | |
503 RequestCoordinator::ProcessingWindowState::IMMEDIATE_WINDOW); | |
504 SetOperationStartTimeForTest(base::Time::Now()); | |
505 } | |
506 | |
507 void RequestCoordinatorTest::SendOfflinerDoneCallback( | |
508 const SavePageRequest& request, Offliner::RequestStatus status) { | |
509 // Using the fact that the test class is a friend, call to the callback | |
510 coordinator_->OfflinerDoneCallback(request, status); | |
511 } | |
512 | |
513 SavePageRequest RequestCoordinatorTest::AddRequest1() { | |
514 offline_pages::SavePageRequest request1(kRequestId1, kUrl1, kClientId1, | |
515 base::Time::Now(), kUserRequested); | |
516 coordinator()->queue()->AddRequest( | |
517 request1, base::Bind(&RequestCoordinatorTest::AddRequestDone, | |
518 base::Unretained(this))); | |
519 return request1; | |
520 } | |
521 | |
522 SavePageRequest RequestCoordinatorTest::AddRequest2() { | |
523 offline_pages::SavePageRequest request2(kRequestId2, kUrl2, kClientId2, | |
524 base::Time::Now(), kUserRequested); | |
525 coordinator()->queue()->AddRequest( | |
526 request2, base::Bind(&RequestCoordinatorTest::AddRequestDone, | |
527 base::Unretained(this))); | |
528 return request2; | |
529 } | |
530 | |
531 TEST_F(RequestCoordinatorTest, StartProcessingWithNoRequests) { | |
532 EXPECT_TRUE(coordinator()->StartProcessing(device_conditions(), | |
533 immediate_callback())); | |
534 PumpLoop(); | |
535 | |
536 EXPECT_TRUE(immediate_schedule_callback_called()); | |
537 } | |
538 | |
539 TEST_F(RequestCoordinatorTest, StartProcessingWithRequestInProgress) { | |
540 // Start processing for this request. | |
541 EXPECT_NE( | |
542 coordinator()->SavePageLater( | |
543 kUrl1, kClientId1, kUserRequested, | |
544 RequestCoordinator::RequestAvailability::ENABLED_FOR_OFFLINER), 0); | |
545 | |
546 // Ensure that the forthcoming request does not finish - we simulate it being | |
547 // in progress by asking it to skip making the completion callback. | |
548 EnableOfflinerCallback(false); | |
549 | |
550 // Sending the request to the offliner should make it busy. | |
551 EXPECT_TRUE(coordinator()->StartProcessing(device_conditions(), | |
552 immediate_callback())); | |
553 PumpLoop(); | |
554 | |
555 EXPECT_TRUE(is_busy()); | |
556 // Since the offliner is disabled, this callback should not be called. | |
557 EXPECT_FALSE(immediate_schedule_callback_called()); | |
558 | |
559 // Now trying to start processing on another request should return false. | |
560 EXPECT_FALSE(coordinator()->StartProcessing(device_conditions(), | |
561 immediate_callback())); | |
562 } | |
563 | |
564 TEST_F(RequestCoordinatorTest, SavePageLater) { | |
565 // The user-requested request which gets processed by SavePageLater | |
566 // would invoke user request callback. | |
567 coordinator()->SetImmediateScheduleCallbackForTest(immediate_callback()); | |
568 | |
569 EXPECT_NE( | |
570 coordinator()->SavePageLater( | |
571 kUrl1, kClientId1, kUserRequested, | |
572 RequestCoordinator::RequestAvailability::ENABLED_FOR_OFFLINER), 0); | |
573 | |
574 // Expect that a request got placed on the queue. | |
575 coordinator()->queue()->GetRequests(base::Bind( | |
576 &RequestCoordinatorTest::GetRequestsDone, base::Unretained(this))); | |
577 | |
578 // Wait for callbacks to finish, both request queue and offliner. | |
579 PumpLoop(); | |
580 EXPECT_TRUE(immediate_schedule_callback_called()); | |
581 | |
582 // Check the request queue is as expected. | |
583 EXPECT_EQ(1UL, last_requests().size()); | |
584 EXPECT_EQ(kUrl1, last_requests().at(0)->url()); | |
585 EXPECT_EQ(kClientId1, last_requests().at(0)->client_id()); | |
586 | |
587 // Expect that the scheduler got notified. | |
588 SchedulerStub* scheduler_stub = | |
589 reinterpret_cast<SchedulerStub*>(coordinator()->scheduler()); | |
590 EXPECT_TRUE(scheduler_stub->schedule_called()); | |
591 EXPECT_EQ(coordinator() | |
592 ->GetTriggerConditions(last_requests()[0]->user_requested()) | |
593 .minimum_battery_percentage, | |
594 scheduler_stub->conditions()->minimum_battery_percentage); | |
595 | |
596 // Check that the observer got the notification that a page is available | |
597 EXPECT_TRUE(observer().added_called()); | |
598 } | |
599 | |
600 TEST_F(RequestCoordinatorTest, SavePageLaterFailed) { | |
601 // The user-requested request which gets processed by SavePageLater | |
602 // would invoke user request callback. | |
603 coordinator()->SetImmediateScheduleCallbackForTest(immediate_callback()); | |
604 | |
605 EXPECT_TRUE( | |
606 coordinator()->SavePageLater( | |
607 kUrl1, kClientId1, kUserRequested, | |
608 RequestCoordinator::RequestAvailability::ENABLED_FOR_OFFLINER) != 0); | |
609 | |
610 // Expect that a request got placed on the queue. | |
611 coordinator()->queue()->GetRequests( | |
612 base::Bind(&RequestCoordinatorTest::GetRequestsDone, | |
613 base::Unretained(this))); | |
614 | |
615 // Wait for callbacks to finish, both request queue and offliner. | |
616 PumpLoop(); | |
617 | |
618 // On low-end devices the callback will be called with false since the | |
619 // processing started but failed due to svelte devices. | |
620 EXPECT_TRUE(immediate_schedule_callback_called()); | |
621 if (base::SysInfo::IsLowEndDevice()) { | |
622 EXPECT_FALSE(immediate_schedule_callback_result()); | |
623 } else { | |
624 EXPECT_TRUE(immediate_schedule_callback_result()); | |
625 } | |
626 | |
627 // Check the request queue is as expected. | |
628 EXPECT_EQ(1UL, last_requests().size()); | |
629 EXPECT_EQ(kUrl1, last_requests().at(0)->url()); | |
630 EXPECT_EQ(kClientId1, last_requests().at(0)->client_id()); | |
631 | |
632 // Expect that the scheduler got notified. | |
633 SchedulerStub* scheduler_stub = reinterpret_cast<SchedulerStub*>( | |
634 coordinator()->scheduler()); | |
635 EXPECT_TRUE(scheduler_stub->schedule_called()); | |
636 EXPECT_EQ(coordinator() | |
637 ->GetTriggerConditions(last_requests()[0]->user_requested()) | |
638 .minimum_battery_percentage, | |
639 scheduler_stub->conditions()->minimum_battery_percentage); | |
640 | |
641 // Check that the observer got the notification that a page is available | |
642 EXPECT_TRUE(observer().added_called()); | |
643 } | |
644 | |
645 TEST_F(RequestCoordinatorTest, OfflinerDoneRequestSucceeded) { | |
646 // Add a request to the queue, wait for callbacks to finish. | |
647 offline_pages::SavePageRequest request( | |
648 kRequestId1, kUrl1, kClientId1, base::Time::Now(), kUserRequested); | |
649 SetupForOfflinerDoneCallbackTest(&request); | |
650 | |
651 // Call the OfflinerDoneCallback to simulate the page being completed, wait | |
652 // for callbacks. | |
653 SendOfflinerDoneCallback(request, Offliner::RequestStatus::SAVED); | |
654 PumpLoop(); | |
655 EXPECT_TRUE(immediate_schedule_callback_called()); | |
656 | |
657 // Verify the request gets removed from the queue, and wait for callbacks. | |
658 coordinator()->queue()->GetRequests( | |
659 base::Bind(&RequestCoordinatorTest::GetRequestsDone, | |
660 base::Unretained(this))); | |
661 PumpLoop(); | |
662 | |
663 // We should not find any requests in the queue anymore. | |
664 // RequestPicker should *not* have tried to start an additional job, | |
665 // because the request queue is empty now. | |
666 EXPECT_EQ(0UL, last_requests().size()); | |
667 // Check that the observer got the notification that we succeeded, and that | |
668 // the request got removed from the queue. | |
669 EXPECT_TRUE(observer().completed_called()); | |
670 EXPECT_EQ(RequestCoordinator::BackgroundSavePageResult::SUCCESS, | |
671 observer().last_status()); | |
672 } | |
673 | |
674 TEST_F(RequestCoordinatorTest, OfflinerDoneRequestFailed) { | |
675 // Add a request to the queue, wait for callbacks to finish. | |
676 offline_pages::SavePageRequest request( | |
677 kRequestId1, kUrl1, kClientId1, base::Time::Now(), kUserRequested); | |
678 request.set_completed_attempt_count(kMaxCompletedTries - 1); | |
679 SetupForOfflinerDoneCallbackTest(&request); | |
680 // Stop processing before completing the second request on the queue. | |
681 EnableOfflinerCallback(false); | |
682 | |
683 // Add second request to the queue to check handling when first fails. | |
684 AddRequest2(); | |
685 PumpLoop(); | |
686 | |
687 // Call the OfflinerDoneCallback to simulate the request failed, wait | |
688 // for callbacks. | |
689 SendOfflinerDoneCallback(request, | |
690 Offliner::RequestStatus::PRERENDERING_FAILED); | |
691 PumpLoop(); | |
692 | |
693 // For retriable failure, processing should stop and scheduler callback | |
694 // called (so that request can be retried first next processing window). | |
695 EXPECT_TRUE(immediate_schedule_callback_called()); | |
696 | |
697 // TODO(dougarnett): Consider injecting mock RequestPicker for this test | |
698 // and verifying that there is no attempt to pick another request following | |
699 // this failure code. | |
700 | |
701 coordinator()->queue()->GetRequests( | |
702 base::Bind(&RequestCoordinatorTest::GetRequestsDone, | |
703 base::Unretained(this))); | |
704 PumpLoop(); | |
705 | |
706 // Now just one request in the queue since failed request removed | |
707 // (max number of attempts exceeded). | |
708 EXPECT_EQ(1UL, last_requests().size()); | |
709 // Check that the observer got the notification that we failed (and the | |
710 // subsequent notification that the request was removed). | |
711 EXPECT_TRUE(observer().completed_called()); | |
712 EXPECT_EQ(RequestCoordinator::BackgroundSavePageResult::RETRY_COUNT_EXCEEDED, | |
713 observer().last_status()); | |
714 } | |
715 | |
716 TEST_F(RequestCoordinatorTest, OfflinerDoneRequestFailedNoRetryFailure) { | |
717 // Add a request to the queue, wait for callbacks to finish. | |
718 offline_pages::SavePageRequest request(kRequestId1, kUrl1, kClientId1, | |
719 base::Time::Now(), kUserRequested); | |
720 SetupForOfflinerDoneCallbackTest(&request); | |
721 EnableOfflinerCallback(false); | |
722 | |
723 // Add second request to the queue to check handling when first fails. | |
724 AddRequest2(); | |
725 PumpLoop(); | |
726 | |
727 // Call the OfflinerDoneCallback to simulate the request failed, wait | |
728 // for callbacks. | |
729 SendOfflinerDoneCallback( | |
730 request, Offliner::RequestStatus::PRERENDERING_FAILED_NO_RETRY); | |
731 PumpLoop(); | |
732 | |
733 // For no retry failure, processing should continue to 2nd request so | |
734 // no scheduler callback yet. | |
735 EXPECT_FALSE(immediate_schedule_callback_called()); | |
736 | |
737 // TODO(dougarnett): Consider injecting mock RequestPicker for this test | |
738 // and verifying that there is as attempt to pick another request following | |
739 // this non-retryable failure code. | |
740 | |
741 coordinator()->queue()->GetRequests(base::Bind( | |
742 &RequestCoordinatorTest::GetRequestsDone, base::Unretained(this))); | |
743 PumpLoop(); | |
744 | |
745 // Now just one request in the queue since non-retryable failure. | |
746 EXPECT_EQ(1UL, last_requests().size()); | |
747 // Check that the observer got the notification that we failed (and the | |
748 // subsequent notification that the request was removed). | |
749 EXPECT_TRUE(observer().completed_called()); | |
750 EXPECT_EQ(RequestCoordinator::BackgroundSavePageResult::PRERENDER_FAILURE, | |
751 observer().last_status()); | |
752 } | |
753 | |
754 TEST_F(RequestCoordinatorTest, OfflinerDoneForegroundCancel) { | |
755 // Add a request to the queue, wait for callbacks to finish. | |
756 offline_pages::SavePageRequest request( | |
757 kRequestId1, kUrl1, kClientId1, base::Time::Now(), kUserRequested); | |
758 SetupForOfflinerDoneCallbackTest(&request); | |
759 | |
760 // Call the OfflinerDoneCallback to simulate the request failed, wait | |
761 // for callbacks. | |
762 SendOfflinerDoneCallback(request, | |
763 Offliner::RequestStatus::FOREGROUND_CANCELED); | |
764 PumpLoop(); | |
765 EXPECT_TRUE(immediate_schedule_callback_called()); | |
766 | |
767 // Verify the request is not removed from the queue, and wait for callbacks. | |
768 coordinator()->queue()->GetRequests(base::Bind( | |
769 &RequestCoordinatorTest::GetRequestsDone, base::Unretained(this))); | |
770 PumpLoop(); | |
771 | |
772 // Request no longer in the queue (for single attempt policy). | |
773 EXPECT_EQ(1UL, last_requests().size()); | |
774 // Verify foreground cancel not counted as an attempt after all. | |
775 EXPECT_EQ(0L, last_requests().at(0)->completed_attempt_count()); | |
776 } | |
777 | |
778 TEST_F(RequestCoordinatorTest, OfflinerDonePrerenderingCancel) { | |
779 // Add a request to the queue, wait for callbacks to finish. | |
780 offline_pages::SavePageRequest request(kRequestId1, kUrl1, kClientId1, | |
781 base::Time::Now(), kUserRequested); | |
782 SetupForOfflinerDoneCallbackTest(&request); | |
783 | |
784 // Call the OfflinerDoneCallback to simulate the request failed, wait | |
785 // for callbacks. | |
786 SendOfflinerDoneCallback(request, | |
787 Offliner::RequestStatus::PRERENDERING_CANCELED); | |
788 PumpLoop(); | |
789 EXPECT_TRUE(immediate_schedule_callback_called()); | |
790 | |
791 // Verify the request is not removed from the queue, and wait for callbacks. | |
792 coordinator()->queue()->GetRequests(base::Bind( | |
793 &RequestCoordinatorTest::GetRequestsDone, base::Unretained(this))); | |
794 PumpLoop(); | |
795 | |
796 // Request still in the queue. | |
797 EXPECT_EQ(1UL, last_requests().size()); | |
798 // Verify prerendering cancel not counted as an attempt after all. | |
799 const std::unique_ptr<SavePageRequest>& found_request = | |
800 last_requests().front(); | |
801 EXPECT_EQ(0L, found_request->completed_attempt_count()); | |
802 } | |
803 | |
804 // If one item completes, and there are no more user requeted items left, | |
805 // we should make a scheduler entry for a non-user requested item. | |
806 TEST_F(RequestCoordinatorTest, RequestNotPickedDisabledItemsRemain) { | |
807 coordinator()->StartProcessing(device_conditions(), immediate_callback()); | |
808 EXPECT_TRUE(is_starting()); | |
809 | |
810 // Call RequestNotPicked, simulating a request on the disabled list. | |
811 CallRequestNotPicked(false, true); | |
812 PumpLoop(); | |
813 | |
814 EXPECT_FALSE(is_starting()); | |
815 | |
816 // The scheduler should have been called to schedule the disabled task for | |
817 // 5 minutes from now. | |
818 SchedulerStub* scheduler_stub = | |
819 reinterpret_cast<SchedulerStub*>(coordinator()->scheduler()); | |
820 EXPECT_TRUE(scheduler_stub->backup_schedule_called()); | |
821 EXPECT_TRUE(scheduler_stub->unschedule_called()); | |
822 } | |
823 | |
824 // If one item completes, and there are no more user requeted items left, | |
825 // we should make a scheduler entry for a non-user requested item. | |
826 TEST_F(RequestCoordinatorTest, RequestNotPickedNonUserRequestedItemsRemain) { | |
827 coordinator()->StartProcessing(device_conditions(), immediate_callback()); | |
828 EXPECT_TRUE(is_starting()); | |
829 | |
830 // Call RequestNotPicked, and make sure we pick schedule a task for non user | |
831 // requested conditions, with no tasks on the disabled list. | |
832 CallRequestNotPicked(true, false); | |
833 PumpLoop(); | |
834 | |
835 EXPECT_FALSE(is_starting()); | |
836 EXPECT_TRUE(immediate_schedule_callback_called()); | |
837 | |
838 // The scheduler should have been called to schedule the non-user requested | |
839 // task. | |
840 SchedulerStub* scheduler_stub = | |
841 reinterpret_cast<SchedulerStub*>(coordinator()->scheduler()); | |
842 EXPECT_TRUE(scheduler_stub->schedule_called()); | |
843 EXPECT_TRUE(scheduler_stub->unschedule_called()); | |
844 const Scheduler::TriggerConditions* conditions = scheduler_stub->conditions(); | |
845 EXPECT_EQ(conditions->require_power_connected, | |
846 coordinator()->policy()->PowerRequired(!kUserRequested)); | |
847 EXPECT_EQ( | |
848 conditions->minimum_battery_percentage, | |
849 coordinator()->policy()->BatteryPercentageRequired(!kUserRequested)); | |
850 EXPECT_EQ(conditions->require_unmetered_network, | |
851 coordinator()->policy()->UnmeteredNetworkRequired(!kUserRequested)); | |
852 } | |
853 | |
854 TEST_F(RequestCoordinatorTest, SchedulerGetsLeastRestrictiveConditions) { | |
855 // Put two requests on the queue - The first is user requested, and | |
856 // the second is not user requested. | |
857 AddRequest1(); | |
858 offline_pages::SavePageRequest request2(kRequestId2, kUrl2, kClientId2, | |
859 base::Time::Now(), !kUserRequested); | |
860 coordinator()->queue()->AddRequest( | |
861 request2, base::Bind(&RequestCoordinatorTest::AddRequestDone, | |
862 base::Unretained(this))); | |
863 PumpLoop(); | |
864 | |
865 // Trigger the scheduler to schedule for the least restrictive condition. | |
866 ScheduleForTest(); | |
867 PumpLoop(); | |
868 | |
869 // Expect that the scheduler got notified, and it is at user_requested | |
870 // priority. | |
871 SchedulerStub* scheduler_stub = | |
872 reinterpret_cast<SchedulerStub*>(coordinator()->scheduler()); | |
873 const Scheduler::TriggerConditions* conditions = scheduler_stub->conditions(); | |
874 EXPECT_TRUE(scheduler_stub->schedule_called()); | |
875 EXPECT_EQ(conditions->require_power_connected, | |
876 coordinator()->policy()->PowerRequired(kUserRequested)); | |
877 EXPECT_EQ(conditions->minimum_battery_percentage, | |
878 coordinator()->policy()->BatteryPercentageRequired(kUserRequested)); | |
879 EXPECT_EQ(conditions->require_unmetered_network, | |
880 coordinator()->policy()->UnmeteredNetworkRequired(kUserRequested)); | |
881 } | |
882 | |
883 TEST_F(RequestCoordinatorTest, StartProcessingWithLoadingDisabled) { | |
884 // Add a request to the queue, wait for callbacks to finish. | |
885 AddRequest1(); | |
886 PumpLoop(); | |
887 | |
888 DisableLoading(); | |
889 EXPECT_TRUE(coordinator()->StartProcessing(device_conditions(), | |
890 immediate_callback())); | |
891 | |
892 // Let the async callbacks in the request coordinator run. | |
893 PumpLoop(); | |
894 EXPECT_TRUE(immediate_schedule_callback_called()); | |
895 | |
896 EXPECT_FALSE(is_starting()); | |
897 EXPECT_EQ(Offliner::PRERENDERING_NOT_STARTED, last_offlining_status()); | |
898 } | |
899 | |
900 // This tests a StopProcessing call before we have actually started the | |
901 // prerenderer. | |
902 TEST_F(RequestCoordinatorTest, StartProcessingThenStopProcessingImmediately) { | |
903 // Add a request to the queue, wait for callbacks to finish. | |
904 AddRequest1(); | |
905 PumpLoop(); | |
906 | |
907 EXPECT_TRUE(coordinator()->StartProcessing(device_conditions(), | |
908 immediate_callback())); | |
909 EXPECT_TRUE(is_starting()); | |
910 | |
911 // Now, quick, before it can do much (we haven't called PumpLoop), cancel it. | |
912 coordinator()->StopProcessing(Offliner::REQUEST_COORDINATOR_CANCELED); | |
913 | |
914 // Let the async callbacks in the request coordinator run. | |
915 PumpLoop(); | |
916 EXPECT_TRUE(immediate_schedule_callback_called()); | |
917 | |
918 EXPECT_FALSE(is_starting()); | |
919 | |
920 // OfflinerDoneCallback will not end up getting called with status SAVED, | |
921 // since we cancelled the event before it called offliner_->LoadAndSave(). | |
922 EXPECT_EQ(Offliner::RequestStatus::REQUEST_COORDINATOR_CANCELED, | |
923 last_offlining_status()); | |
924 | |
925 // Since offliner was not started, it will not have seen cancel call. | |
926 EXPECT_FALSE(OfflinerWasCanceled()); | |
927 } | |
928 | |
929 // This tests a StopProcessing call after the prerenderer has been started. | |
930 TEST_F(RequestCoordinatorTest, StartProcessingThenStopProcessingLater) { | |
931 // Add a request to the queue, wait for callbacks to finish. | |
932 AddRequest1(); | |
933 PumpLoop(); | |
934 | |
935 // Ensure the start processing request stops before the completion callback. | |
936 EnableOfflinerCallback(false); | |
937 | |
938 EXPECT_TRUE(coordinator()->StartProcessing(device_conditions(), | |
939 immediate_callback())); | |
940 EXPECT_TRUE(is_starting()); | |
941 | |
942 // Let all the async parts of the start processing pipeline run to completion. | |
943 PumpLoop(); | |
944 | |
945 // Observer called for starting processing. | |
946 EXPECT_TRUE(observer().changed_called()); | |
947 EXPECT_EQ(SavePageRequest::RequestState::OFFLINING, observer().state()); | |
948 observer().Clear(); | |
949 | |
950 // Since the offliner is disabled, this callback should not be called. | |
951 EXPECT_FALSE(immediate_schedule_callback_called()); | |
952 | |
953 // Coordinator should now be busy. | |
954 EXPECT_TRUE(is_busy()); | |
955 EXPECT_FALSE(is_starting()); | |
956 | |
957 // Now we cancel it while the prerenderer is busy. | |
958 coordinator()->StopProcessing(Offliner::REQUEST_COORDINATOR_CANCELED); | |
959 | |
960 // Let the async callbacks in the cancel run. | |
961 PumpLoop(); | |
962 | |
963 // Observer called for stopped processing. | |
964 EXPECT_TRUE(observer().changed_called()); | |
965 EXPECT_EQ(SavePageRequest::RequestState::AVAILABLE, observer().state()); | |
966 observer().Clear(); | |
967 | |
968 EXPECT_FALSE(is_busy()); | |
969 | |
970 // OfflinerDoneCallback will not end up getting called with status SAVED, | |
971 // since we cancelled the event before the LoadAndSave completed. | |
972 EXPECT_EQ(Offliner::RequestStatus::REQUEST_COORDINATOR_CANCELED, | |
973 last_offlining_status()); | |
974 | |
975 // Since offliner was started, it will have seen cancel call. | |
976 EXPECT_TRUE(OfflinerWasCanceled()); | |
977 } | |
978 | |
979 // This tests that canceling a request will result in TryNextRequest() getting | |
980 // called. | |
981 TEST_F(RequestCoordinatorTest, RemoveInflightRequest) { | |
982 // Add a request to the queue, wait for callbacks to finish. | |
983 AddRequest1(); | |
984 PumpLoop(); | |
985 | |
986 // Ensure the start processing request stops before the completion callback. | |
987 EnableOfflinerCallback(false); | |
988 | |
989 EXPECT_TRUE(coordinator()->StartProcessing(device_conditions(), | |
990 immediate_callback())); | |
991 | |
992 // Let all the async parts of the start processing pipeline run to completion. | |
993 PumpLoop(); | |
994 // Since the offliner is disabled, this callback should not be called. | |
995 EXPECT_FALSE(immediate_schedule_callback_called()); | |
996 | |
997 // Remove the request while it is processing. | |
998 std::vector<int64_t> request_ids{kRequestId1}; | |
999 coordinator()->RemoveRequests( | |
1000 request_ids, base::Bind(&RequestCoordinatorTest::RemoveRequestsDone, | |
1001 base::Unretained(this))); | |
1002 | |
1003 // Let the async callbacks in the cancel run. | |
1004 PumpLoop(); | |
1005 | |
1006 // Since offliner was started, it will have seen cancel call. | |
1007 EXPECT_TRUE(OfflinerWasCanceled()); | |
1008 } | |
1009 | |
1010 TEST_F(RequestCoordinatorTest, MarkRequestCompleted) { | |
1011 int64_t request_id = coordinator()->SavePageLater( | |
1012 kUrl1, kClientId1, kUserRequested, | |
1013 RequestCoordinator::RequestAvailability::DISABLED_FOR_OFFLINER); | |
1014 PumpLoop(); | |
1015 EXPECT_NE(request_id, 0l); | |
1016 | |
1017 // Ensure the start processing request stops before the completion callback. | |
1018 EnableOfflinerCallback(false); | |
1019 | |
1020 EXPECT_TRUE(coordinator()->StartProcessing(device_conditions(), | |
1021 immediate_callback())); | |
1022 | |
1023 // Call the method under test, making sure we send SUCCESS to the observer. | |
1024 coordinator()->MarkRequestCompleted(request_id); | |
1025 PumpLoop(); | |
1026 EXPECT_TRUE(immediate_schedule_callback_called()); | |
1027 | |
1028 // Our observer should have seen SUCCESS instead of REMOVED. | |
1029 EXPECT_EQ(RequestCoordinator::BackgroundSavePageResult::SUCCESS, | |
1030 observer().last_status()); | |
1031 EXPECT_TRUE(observer().completed_called()); | |
1032 } | |
1033 | |
1034 TEST_F(RequestCoordinatorTest, WatchdogTimeoutForScheduledProcessing) { | |
1035 // Build a request to use with the pre-renderer, and put it on the queue. | |
1036 offline_pages::SavePageRequest request( | |
1037 kRequestId1, kUrl1, kClientId1, base::Time::Now(), kUserRequested); | |
1038 // Set request to allow one more completed attempt. | |
1039 int max_tries = coordinator()->policy()->GetMaxCompletedTries(); | |
1040 request.set_completed_attempt_count(max_tries - 1); | |
1041 coordinator()->queue()->AddRequest( | |
1042 request, | |
1043 base::Bind(&RequestCoordinatorTest::AddRequestDone, | |
1044 base::Unretained(this))); | |
1045 PumpLoop(); | |
1046 | |
1047 // Ensure that the new request does not finish - we simulate it being | |
1048 // in progress by asking it to skip making the completion callback. | |
1049 EnableOfflinerCallback(false); | |
1050 | |
1051 // Sending the request to the offliner. | |
1052 EXPECT_TRUE( | |
1053 coordinator()->StartProcessing(device_conditions(), waiting_callback())); | |
1054 PumpLoop(); | |
1055 | |
1056 // Advance the mock clock far enough to cause a watchdog timeout | |
1057 AdvanceClockBy(base::TimeDelta::FromSeconds( | |
1058 coordinator() | |
1059 ->policy() | |
1060 ->GetSinglePageTimeLimitWhenBackgroundScheduledInSeconds() + 1)); | |
1061 PumpLoop(); | |
1062 | |
1063 // Wait for timeout to expire. Use a TaskRunner with a DelayedTaskRunner | |
1064 // which won't time out immediately, so the watchdog thread doesn't kill valid | |
1065 // tasks too soon. | |
1066 WaitForCallback(); | |
1067 PumpLoop(); | |
1068 | |
1069 EXPECT_FALSE(is_starting()); | |
1070 EXPECT_FALSE(coordinator()->is_busy()); | |
1071 EXPECT_TRUE(OfflinerWasCanceled()); | |
1072 } | |
1073 | |
1074 TEST_F(RequestCoordinatorTest, WatchdogTimeoutForImmediateProcessing) { | |
1075 // If low end device, pretend it is not so that immediate start happens. | |
1076 SetIsLowEndDeviceForTest(false); | |
1077 | |
1078 // Ensure that the new request does not finish - we simulate it being | |
1079 // in progress by asking it to skip making the completion callback. | |
1080 EnableOfflinerCallback(false); | |
1081 | |
1082 EXPECT_NE( | |
1083 coordinator()->SavePageLater( | |
1084 kUrl1, kClientId1, kUserRequested, | |
1085 RequestCoordinator::RequestAvailability::ENABLED_FOR_OFFLINER), 0); | |
1086 PumpLoop(); | |
1087 | |
1088 // Verify that immediate start from adding the request did happen. | |
1089 EXPECT_TRUE(coordinator()->is_busy()); | |
1090 | |
1091 // Advance the mock clock 1 second before the watchdog timeout. | |
1092 AdvanceClockBy(base::TimeDelta::FromSeconds( | |
1093 coordinator() | |
1094 ->policy() | |
1095 ->GetSinglePageTimeLimitForImmediateLoadInSeconds() - 1)); | |
1096 PumpLoop(); | |
1097 | |
1098 // Verify still busy. | |
1099 EXPECT_TRUE(coordinator()->is_busy()); | |
1100 EXPECT_FALSE(OfflinerWasCanceled()); | |
1101 | |
1102 // Advance the mock clock past the watchdog timeout now. | |
1103 AdvanceClockBy(base::TimeDelta::FromSeconds(2)); | |
1104 PumpLoop(); | |
1105 | |
1106 // Verify the request timed out. | |
1107 EXPECT_TRUE(OfflinerWasCanceled()); | |
1108 } | |
1109 | |
1110 TEST_F(RequestCoordinatorTest, TimeBudgetExceeded) { | |
1111 EnableOfflinerCallback(false); | |
1112 // Build two requests to use with the pre-renderer, and put it on the queue. | |
1113 AddRequest1(); | |
1114 // The second request will have a larger completed attempt count. | |
1115 offline_pages::SavePageRequest request2(kRequestId1 + 1, kUrl1, kClientId1, | |
1116 base::Time::Now(), kUserRequested); | |
1117 request2.set_completed_attempt_count(kAttemptCount); | |
1118 coordinator()->queue()->AddRequest( | |
1119 request2, base::Bind(&RequestCoordinatorTest::AddRequestDone, | |
1120 base::Unretained(this))); | |
1121 PumpLoop(); | |
1122 | |
1123 // Sending the request to the offliner. | |
1124 EXPECT_TRUE( | |
1125 coordinator()->StartProcessing(device_conditions(), waiting_callback())); | |
1126 PumpLoop(); | |
1127 | |
1128 // Advance the mock clock far enough to exceed our time budget. | |
1129 // The first request will time out, and because we are over time budget, | |
1130 // the second request will not be started. | |
1131 AdvanceClockBy(base::TimeDelta::FromSeconds(kTestTimeBudgetSeconds)); | |
1132 PumpLoop(); | |
1133 | |
1134 // TryNextRequest should decide that there is no more work to be done, | |
1135 // and call back to the scheduler, even though there is another request in the | |
1136 // queue. Both requests should be left in the queue. | |
1137 coordinator()->queue()->GetRequests( | |
1138 base::Bind(&RequestCoordinatorTest::GetRequestsDone, | |
1139 base::Unretained(this))); | |
1140 PumpLoop(); | |
1141 | |
1142 // We should find two requests in the queue. | |
1143 // The first request should now have a completed count of 1. | |
1144 EXPECT_EQ(2UL, last_requests().size()); | |
1145 EXPECT_EQ(1L, last_requests().at(0)->completed_attempt_count()); | |
1146 } | |
1147 | |
1148 TEST_F(RequestCoordinatorTest, TryNextRequestWithNoNetwork) { | |
1149 SavePageRequest request1 = AddRequest1(); | |
1150 AddRequest2(); | |
1151 PumpLoop(); | |
1152 | |
1153 // Set up for the call to StartProcessing. | |
1154 EnableOfflinerCallback(false); | |
1155 | |
1156 // Sending the request to the offliner. | |
1157 EXPECT_TRUE( | |
1158 coordinator()->StartProcessing(device_conditions(), waiting_callback())); | |
1159 PumpLoop(); | |
1160 EXPECT_TRUE(coordinator()->is_busy()); | |
1161 | |
1162 // Now lose the network connection. | |
1163 SetNetworkConnected(false); | |
1164 | |
1165 // Complete first request and then TryNextRequest should decide not | |
1166 // to pick another request (because of no network connection). | |
1167 SendOfflinerDoneCallback(request1, Offliner::RequestStatus::SAVED); | |
1168 PumpLoop(); | |
1169 | |
1170 // Not starting nor busy with next request. | |
1171 EXPECT_FALSE(coordinator()->is_starting()); | |
1172 EXPECT_FALSE(coordinator()->is_busy()); | |
1173 | |
1174 // Get queued requests. | |
1175 coordinator()->queue()->GetRequests(base::Bind( | |
1176 &RequestCoordinatorTest::GetRequestsDone, base::Unretained(this))); | |
1177 PumpLoop(); | |
1178 | |
1179 // We should find one request in the queue. | |
1180 EXPECT_EQ(1UL, last_requests().size()); | |
1181 } | |
1182 | |
1183 TEST_F(RequestCoordinatorTest, GetAllRequests) { | |
1184 // Add two requests to the queue. | |
1185 AddRequest1(); | |
1186 AddRequest2(); | |
1187 PumpLoop(); | |
1188 | |
1189 // Start the async status fetching. | |
1190 coordinator()->GetAllRequests(base::Bind( | |
1191 &RequestCoordinatorTest::GetQueuedRequestsDone, base::Unretained(this))); | |
1192 PumpLoop(); | |
1193 | |
1194 // Wait for async get to finish. | |
1195 WaitForCallback(); | |
1196 PumpLoop(); | |
1197 | |
1198 // Check that the statuses found in the callback match what we expect. | |
1199 EXPECT_EQ(2UL, last_requests().size()); | |
1200 EXPECT_EQ(kRequestId1, last_requests().at(0)->request_id()); | |
1201 EXPECT_EQ(kRequestId2, last_requests().at(1)->request_id()); | |
1202 } | |
1203 | |
1204 #if defined(OS_IOS) | |
1205 // Flaky on IOS. http://crbug/663311 | |
1206 #define MAYBE_PauseAndResumeObserver DISABLED_PauseAndResumeObserver | |
1207 #else | |
1208 #define MAYBE_PauseAndResumeObserver PauseAndResumeObserver | |
1209 #endif | |
1210 TEST_F(RequestCoordinatorTest, MAYBE_PauseAndResumeObserver) { | |
1211 // Add a request to the queue. | |
1212 AddRequest1(); | |
1213 PumpLoop(); | |
1214 | |
1215 // Pause the request. | |
1216 std::vector<int64_t> request_ids; | |
1217 request_ids.push_back(kRequestId1); | |
1218 coordinator()->PauseRequests(request_ids); | |
1219 PumpLoop(); | |
1220 | |
1221 EXPECT_TRUE(observer().changed_called()); | |
1222 EXPECT_EQ(SavePageRequest::RequestState::PAUSED, observer().state()); | |
1223 | |
1224 // Clear out the observer before the next call. | |
1225 observer().Clear(); | |
1226 | |
1227 // Resume the request. | |
1228 coordinator()->ResumeRequests(request_ids); | |
1229 PumpLoop(); | |
1230 | |
1231 EXPECT_TRUE(observer().changed_called()); | |
1232 | |
1233 // Now whether request is offlining or just available depends on whether test | |
1234 // is run on svelte device or not. | |
1235 if (base::SysInfo::IsLowEndDevice()) { | |
1236 EXPECT_EQ(SavePageRequest::RequestState::AVAILABLE, observer().state()); | |
1237 } else { | |
1238 EXPECT_EQ(SavePageRequest::RequestState::OFFLINING, observer().state()); | |
1239 } | |
1240 } | |
1241 | |
1242 TEST_F(RequestCoordinatorTest, RemoveRequest) { | |
1243 // Add a request to the queue. | |
1244 AddRequest1(); | |
1245 PumpLoop(); | |
1246 | |
1247 // Remove the request. | |
1248 std::vector<int64_t> request_ids; | |
1249 request_ids.push_back(kRequestId1); | |
1250 coordinator()->RemoveRequests( | |
1251 request_ids, base::Bind(&RequestCoordinatorTest::RemoveRequestsDone, | |
1252 base::Unretained(this))); | |
1253 | |
1254 PumpLoop(); | |
1255 WaitForCallback(); | |
1256 PumpLoop(); | |
1257 | |
1258 EXPECT_TRUE(observer().completed_called()); | |
1259 EXPECT_EQ(RequestCoordinator::BackgroundSavePageResult::REMOVED, | |
1260 observer().last_status()); | |
1261 EXPECT_EQ(1UL, last_remove_results().size()); | |
1262 EXPECT_EQ(kRequestId1, std::get<0>(last_remove_results().at(0))); | |
1263 } | |
1264 | |
1265 TEST_F(RequestCoordinatorTest, | |
1266 SavePageStartsProcessingWhenConnectedAndNotLowEndDevice) { | |
1267 // Turn off the callback so that the request stops before processing in | |
1268 // PumpLoop. | |
1269 EnableOfflinerCallback(false); | |
1270 EXPECT_NE( | |
1271 coordinator()->SavePageLater( | |
1272 kUrl1, kClientId1, kUserRequested, | |
1273 RequestCoordinator::RequestAvailability::ENABLED_FOR_OFFLINER), 0); | |
1274 PumpLoop(); | |
1275 | |
1276 // Now whether processing triggered immediately depends on whether test | |
1277 // is run on svelte device or not. | |
1278 if (base::SysInfo::IsLowEndDevice()) { | |
1279 EXPECT_FALSE(is_busy()); | |
1280 } else { | |
1281 EXPECT_TRUE(is_busy()); | |
1282 } | |
1283 } | |
1284 | |
1285 TEST_F(RequestCoordinatorTest, | |
1286 SavePageStartsProcessingWhenConnectedOnLowEndDeviceIfFlagEnabled) { | |
1287 // Mark device as low-end device. | |
1288 SetIsLowEndDeviceForTest(true); | |
1289 EXPECT_FALSE(offline_pages::IsOfflinePagesSvelteConcurrentLoadingEnabled()); | |
1290 | |
1291 // Make a request. | |
1292 EXPECT_NE(coordinator()->SavePageLater( | |
1293 kUrl1, kClientId1, kUserRequested, | |
1294 RequestCoordinator::RequestAvailability::ENABLED_FOR_OFFLINER), | |
1295 0); | |
1296 PumpLoop(); | |
1297 | |
1298 // Verify not immediately busy (since low-end device). | |
1299 EXPECT_FALSE(is_busy()); | |
1300 | |
1301 // Set feature flag to allow concurrent loads. | |
1302 base::test::ScopedFeatureList scoped_feature_list; | |
1303 scoped_feature_list.InitAndEnableFeature( | |
1304 kOfflinePagesSvelteConcurrentLoadingFeature); | |
1305 EXPECT_TRUE(offline_pages::IsOfflinePagesSvelteConcurrentLoadingEnabled()); | |
1306 | |
1307 // Turn off the callback so that the request stops before processing in | |
1308 // PumpLoop. | |
1309 EnableOfflinerCallback(false); | |
1310 | |
1311 // Make another request. | |
1312 EXPECT_NE(coordinator()->SavePageLater( | |
1313 kUrl2, kClientId2, kUserRequested, | |
1314 RequestCoordinator::RequestAvailability::ENABLED_FOR_OFFLINER), | |
1315 0); | |
1316 PumpLoop(); | |
1317 | |
1318 // Verify immediate processing did start this time. | |
1319 EXPECT_TRUE(is_busy()); | |
1320 } | |
1321 | |
1322 TEST_F(RequestCoordinatorTest, SavePageDoesntStartProcessingWhenDisconnected) { | |
1323 SetNetworkConnected(false); | |
1324 EXPECT_NE( | |
1325 coordinator()->SavePageLater( | |
1326 kUrl1, kClientId1, kUserRequested, | |
1327 RequestCoordinator::RequestAvailability::ENABLED_FOR_OFFLINER), 0); | |
1328 PumpLoop(); | |
1329 EXPECT_FALSE(is_busy()); | |
1330 } | |
1331 | |
1332 TEST_F(RequestCoordinatorTest, | |
1333 SavePageDoesStartProcessingWhenPoorlyConnected) { | |
1334 // If low end device, pretend it is not so that immediate start can happen. | |
1335 SetIsLowEndDeviceForTest(false); | |
1336 // Set specific network type for 2G with poor effective connection. | |
1337 SetNetworkConditionsForTest( | |
1338 net::NetworkChangeNotifier::ConnectionType::CONNECTION_2G); | |
1339 SetEffectiveConnectionTypeForTest( | |
1340 net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_SLOW_2G); | |
1341 | |
1342 // Turn off the callback so that the request stops before processing in | |
1343 // PumpLoop. | |
1344 EnableOfflinerCallback(false); | |
1345 | |
1346 EXPECT_NE( | |
1347 coordinator()->SavePageLater( | |
1348 kUrl1, kClientId1, kUserRequested, | |
1349 RequestCoordinator::RequestAvailability::ENABLED_FOR_OFFLINER), 0); | |
1350 PumpLoop(); | |
1351 EXPECT_TRUE(is_busy()); | |
1352 } | |
1353 | |
1354 TEST_F(RequestCoordinatorTest, | |
1355 ResumeStartsProcessingWhenConnectedAndNotLowEndDevice) { | |
1356 // Start unconnected. | |
1357 SetNetworkConnected(false); | |
1358 | |
1359 // Turn off the callback so that the request stops before processing in | |
1360 // PumpLoop. | |
1361 EnableOfflinerCallback(false); | |
1362 | |
1363 // Add a request to the queue. | |
1364 AddRequest1(); | |
1365 PumpLoop(); | |
1366 EXPECT_FALSE(is_busy()); | |
1367 | |
1368 // Pause the request. | |
1369 std::vector<int64_t> request_ids; | |
1370 request_ids.push_back(kRequestId1); | |
1371 coordinator()->PauseRequests(request_ids); | |
1372 PumpLoop(); | |
1373 | |
1374 // Resume the request while disconnected. | |
1375 coordinator()->ResumeRequests(request_ids); | |
1376 PumpLoop(); | |
1377 EXPECT_FALSE(is_busy()); | |
1378 | |
1379 // Pause the request again. | |
1380 coordinator()->PauseRequests(request_ids); | |
1381 PumpLoop(); | |
1382 | |
1383 // Now simulate reasonable connection. | |
1384 SetNetworkConnected(true); | |
1385 | |
1386 // Resume the request while connected. | |
1387 coordinator()->ResumeRequests(request_ids); | |
1388 EXPECT_FALSE(is_busy()); | |
1389 PumpLoop(); | |
1390 | |
1391 // Now whether processing triggered immediately depends on whether test | |
1392 // is run on svelte device or not. | |
1393 if (base::SysInfo::IsLowEndDevice()) { | |
1394 EXPECT_FALSE(is_busy()); | |
1395 } else { | |
1396 EXPECT_TRUE(is_busy()); | |
1397 } | |
1398 } | |
1399 | |
1400 } // namespace offline_pages | |
OLD | NEW |