Commit 4c174803 authored by petewil's avatar petewil Committed by Commit bot

More detailed implementation of the RequestPicker

BUG=610521

Review-Url: https://codereview.chromium.org/2113383002
Cr-Commit-Position: refs/heads/master@{#407281}
parent 6021ec34
...@@ -41,6 +41,7 @@ namespace android { ...@@ -41,6 +41,7 @@ namespace android {
namespace { namespace {
const char kOfflinePageBridgeKey[] = "offline-page-bridge"; const char kOfflinePageBridgeKey[] = "offline-page-bridge";
const bool kUserRequested = true;
void ToJavaOfflinePageList(JNIEnv* env, void ToJavaOfflinePageList(JNIEnv* env,
jobject j_result_obj, jobject j_result_obj,
...@@ -371,7 +372,7 @@ void OfflinePageBridge::SavePageLater( ...@@ -371,7 +372,7 @@ void OfflinePageBridge::SavePageLater(
GetForBrowserContext(browser_context_); GetForBrowserContext(browser_context_);
coordinator->SavePageLater( coordinator->SavePageLater(
GURL(ConvertJavaStringToUTF8(env, j_url)), client_id); GURL(ConvertJavaStringToUTF8(env, j_url)), client_id, kUserRequested);
} }
void OfflinePageBridge::DeletePages( void OfflinePageBridge::DeletePages(
......
...@@ -26,6 +26,7 @@ const int64_t kRequestId = 7; ...@@ -26,6 +26,7 @@ const int64_t kRequestId = 7;
const GURL kHttpUrl("http://tunafish.com"); const GURL kHttpUrl("http://tunafish.com");
const GURL kFileUrl("file://sailfish.png"); const GURL kFileUrl("file://sailfish.png");
const ClientId kClientId("AsyncLoading", "88"); const ClientId kClientId("AsyncLoading", "88");
const bool kUserRequested = true;
// Mock Loader for testing the Offliner calls. // Mock Loader for testing the Offliner calls.
class MockPrerenderingLoader : public PrerenderingLoader { class MockPrerenderingLoader : public PrerenderingLoader {
...@@ -199,14 +200,16 @@ void PrerenderingOfflinerTest::OnCompletion(const SavePageRequest& request, ...@@ -199,14 +200,16 @@ void PrerenderingOfflinerTest::OnCompletion(const SavePageRequest& request,
TEST_F(PrerenderingOfflinerTest, LoadAndSaveBadUrl) { TEST_F(PrerenderingOfflinerTest, LoadAndSaveBadUrl) {
base::Time creation_time = base::Time::Now(); base::Time creation_time = base::Time::Now();
SavePageRequest request(kRequestId, kFileUrl, kClientId, creation_time); SavePageRequest request(
kRequestId, kFileUrl, kClientId, creation_time, kUserRequested);
EXPECT_FALSE(offliner()->LoadAndSave(request, callback())); EXPECT_FALSE(offliner()->LoadAndSave(request, callback()));
EXPECT_TRUE(loader()->IsIdle()); EXPECT_TRUE(loader()->IsIdle());
} }
TEST_F(PrerenderingOfflinerTest, LoadAndSavePrerenderingDisabled) { TEST_F(PrerenderingOfflinerTest, LoadAndSavePrerenderingDisabled) {
base::Time creation_time = base::Time::Now(); base::Time creation_time = base::Time::Now();
SavePageRequest request(kRequestId, kHttpUrl, kClientId, creation_time); SavePageRequest request(
kRequestId, kHttpUrl, kClientId, creation_time, kUserRequested);
loader()->DisablePrerendering(); loader()->DisablePrerendering();
EXPECT_FALSE(offliner()->LoadAndSave(request, callback())); EXPECT_FALSE(offliner()->LoadAndSave(request, callback()));
EXPECT_TRUE(loader()->IsIdle()); EXPECT_TRUE(loader()->IsIdle());
...@@ -214,7 +217,8 @@ TEST_F(PrerenderingOfflinerTest, LoadAndSavePrerenderingDisabled) { ...@@ -214,7 +217,8 @@ TEST_F(PrerenderingOfflinerTest, LoadAndSavePrerenderingDisabled) {
TEST_F(PrerenderingOfflinerTest, LoadAndSaveLoadStartedButFails) { TEST_F(PrerenderingOfflinerTest, LoadAndSaveLoadStartedButFails) {
base::Time creation_time = base::Time::Now(); base::Time creation_time = base::Time::Now();
SavePageRequest request(kRequestId, kHttpUrl, kClientId, creation_time); SavePageRequest request(
kRequestId, kHttpUrl, kClientId, creation_time, kUserRequested);
EXPECT_TRUE(offliner()->LoadAndSave(request, callback())); EXPECT_TRUE(offliner()->LoadAndSave(request, callback()));
EXPECT_FALSE(loader()->IsIdle()); EXPECT_FALSE(loader()->IsIdle());
EXPECT_EQ(Offliner::RequestStatus::UNKNOWN, request_status()); EXPECT_EQ(Offliner::RequestStatus::UNKNOWN, request_status());
...@@ -229,7 +233,8 @@ TEST_F(PrerenderingOfflinerTest, LoadAndSaveLoadStartedButFails) { ...@@ -229,7 +233,8 @@ TEST_F(PrerenderingOfflinerTest, LoadAndSaveLoadStartedButFails) {
TEST_F(PrerenderingOfflinerTest, CancelWhenLoading) { TEST_F(PrerenderingOfflinerTest, CancelWhenLoading) {
base::Time creation_time = base::Time::Now(); base::Time creation_time = base::Time::Now();
SavePageRequest request(kRequestId, kHttpUrl, kClientId, creation_time); SavePageRequest request(
kRequestId, kHttpUrl, kClientId, creation_time, kUserRequested);
EXPECT_TRUE(offliner()->LoadAndSave(request, callback())); EXPECT_TRUE(offliner()->LoadAndSave(request, callback()));
EXPECT_FALSE(loader()->IsIdle()); EXPECT_FALSE(loader()->IsIdle());
...@@ -239,7 +244,8 @@ TEST_F(PrerenderingOfflinerTest, CancelWhenLoading) { ...@@ -239,7 +244,8 @@ TEST_F(PrerenderingOfflinerTest, CancelWhenLoading) {
TEST_F(PrerenderingOfflinerTest, CancelWhenLoaded) { TEST_F(PrerenderingOfflinerTest, CancelWhenLoaded) {
base::Time creation_time = base::Time::Now(); base::Time creation_time = base::Time::Now();
SavePageRequest request(kRequestId, kHttpUrl, kClientId, creation_time); SavePageRequest request(
kRequestId, kHttpUrl, kClientId, creation_time, kUserRequested);
EXPECT_TRUE(offliner()->LoadAndSave(request, callback())); EXPECT_TRUE(offliner()->LoadAndSave(request, callback()));
EXPECT_FALSE(loader()->IsIdle()); EXPECT_FALSE(loader()->IsIdle());
EXPECT_EQ(Offliner::RequestStatus::UNKNOWN, request_status()); EXPECT_EQ(Offliner::RequestStatus::UNKNOWN, request_status());
...@@ -267,7 +273,8 @@ TEST_F(PrerenderingOfflinerTest, CancelWhenLoaded) { ...@@ -267,7 +273,8 @@ TEST_F(PrerenderingOfflinerTest, CancelWhenLoaded) {
TEST_F(PrerenderingOfflinerTest, LoadAndSaveLoadedButSaveFails) { TEST_F(PrerenderingOfflinerTest, LoadAndSaveLoadedButSaveFails) {
base::Time creation_time = base::Time::Now(); base::Time creation_time = base::Time::Now();
SavePageRequest request(kRequestId, kHttpUrl, kClientId, creation_time); SavePageRequest request(
kRequestId, kHttpUrl, kClientId, creation_time, kUserRequested);
EXPECT_TRUE(offliner()->LoadAndSave(request, callback())); EXPECT_TRUE(offliner()->LoadAndSave(request, callback()));
EXPECT_FALSE(loader()->IsIdle()); EXPECT_FALSE(loader()->IsIdle());
EXPECT_EQ(Offliner::RequestStatus::UNKNOWN, request_status()); EXPECT_EQ(Offliner::RequestStatus::UNKNOWN, request_status());
...@@ -288,7 +295,8 @@ TEST_F(PrerenderingOfflinerTest, LoadAndSaveLoadedButSaveFails) { ...@@ -288,7 +295,8 @@ TEST_F(PrerenderingOfflinerTest, LoadAndSaveLoadedButSaveFails) {
TEST_F(PrerenderingOfflinerTest, LoadAndSaveSuccessful) { TEST_F(PrerenderingOfflinerTest, LoadAndSaveSuccessful) {
base::Time creation_time = base::Time::Now(); base::Time creation_time = base::Time::Now();
SavePageRequest request(kRequestId, kHttpUrl, kClientId, creation_time); SavePageRequest request(
kRequestId, kHttpUrl, kClientId, creation_time, kUserRequested);
EXPECT_TRUE(offliner()->LoadAndSave(request, callback())); EXPECT_TRUE(offliner()->LoadAndSave(request, callback()));
EXPECT_FALSE(loader()->IsIdle()); EXPECT_FALSE(loader()->IsIdle());
EXPECT_EQ(Offliner::RequestStatus::UNKNOWN, request_status()); EXPECT_EQ(Offliner::RequestStatus::UNKNOWN, request_status());
...@@ -309,7 +317,8 @@ TEST_F(PrerenderingOfflinerTest, LoadAndSaveSuccessful) { ...@@ -309,7 +317,8 @@ TEST_F(PrerenderingOfflinerTest, LoadAndSaveSuccessful) {
TEST_F(PrerenderingOfflinerTest, LoadAndSaveLoadedButThenCanceledFromLoader) { TEST_F(PrerenderingOfflinerTest, LoadAndSaveLoadedButThenCanceledFromLoader) {
base::Time creation_time = base::Time::Now(); base::Time creation_time = base::Time::Now();
SavePageRequest request(kRequestId, kHttpUrl, kClientId, creation_time); SavePageRequest request(
kRequestId, kHttpUrl, kClientId, creation_time, kUserRequested);
EXPECT_TRUE(offliner()->LoadAndSave(request, callback())); EXPECT_TRUE(offliner()->LoadAndSave(request, callback()));
EXPECT_FALSE(loader()->IsIdle()); EXPECT_FALSE(loader()->IsIdle());
EXPECT_EQ(Offliner::RequestStatus::UNKNOWN, request_status()); EXPECT_EQ(Offliner::RequestStatus::UNKNOWN, request_status());
...@@ -333,7 +342,8 @@ TEST_F(PrerenderingOfflinerTest, ForegroundTransitionCancelsOnLowEndDevice) { ...@@ -333,7 +342,8 @@ TEST_F(PrerenderingOfflinerTest, ForegroundTransitionCancelsOnLowEndDevice) {
offliner()->SetLowEndDeviceForTesting(true); offliner()->SetLowEndDeviceForTesting(true);
base::Time creation_time = base::Time::Now(); base::Time creation_time = base::Time::Now();
SavePageRequest request(kRequestId, kHttpUrl, kClientId, creation_time); SavePageRequest request(
kRequestId, kHttpUrl, kClientId, creation_time, kUserRequested);
EXPECT_TRUE(offliner()->LoadAndSave(request, callback())); EXPECT_TRUE(offliner()->LoadAndSave(request, callback()));
EXPECT_FALSE(loader()->IsIdle()); EXPECT_FALSE(loader()->IsIdle());
...@@ -349,7 +359,8 @@ TEST_F(PrerenderingOfflinerTest, ForegroundTransitionIgnoredOnHighEndDevice) { ...@@ -349,7 +359,8 @@ TEST_F(PrerenderingOfflinerTest, ForegroundTransitionIgnoredOnHighEndDevice) {
offliner()->SetLowEndDeviceForTesting(false); offliner()->SetLowEndDeviceForTesting(false);
base::Time creation_time = base::Time::Now(); base::Time creation_time = base::Time::Now();
SavePageRequest request(kRequestId, kHttpUrl, kClientId, creation_time); SavePageRequest request(
kRequestId, kHttpUrl, kClientId, creation_time, kUserRequested);
EXPECT_TRUE(offliner()->LoadAndSave(request, callback())); EXPECT_TRUE(offliner()->LoadAndSave(request, callback()));
EXPECT_FALSE(loader()->IsIdle()); EXPECT_FALSE(loader()->IsIdle());
......
...@@ -20,6 +20,10 @@ class DeviceConditions { ...@@ -20,6 +20,10 @@ class DeviceConditions {
battery_percentage_(battery_percentage), battery_percentage_(battery_percentage),
net_connection_type_(net_connection_type) {} net_connection_type_(net_connection_type) {}
DeviceConditions()
: power_connected_(true), battery_percentage_(75),
net_connection_type_(net::NetworkChangeNotifier::CONNECTION_WIFI) {}
// Returns whether power is connected. // Returns whether power is connected.
bool IsPowerConnected() const { return power_connected_; } bool IsPowerConnected() const { return power_connected_; }
...@@ -35,6 +39,8 @@ class DeviceConditions { ...@@ -35,6 +39,8 @@ class DeviceConditions {
const bool power_connected_; const bool power_connected_;
const int battery_percentage_; const int battery_percentage_;
const net::NetworkChangeNotifier::ConnectionType net_connection_type_; const net::NetworkChangeNotifier::ConnectionType net_connection_type_;
// NOTE: We intentionally allow the default copy constructor and assignment.
}; };
} // namespace offline_pages } // namespace offline_pages
......
...@@ -5,6 +5,13 @@ ...@@ -5,6 +5,13 @@
#ifndef COMPONENTS_OFFLINE_PAGES_BACKGROUND_OFFLINER_POLICY_H_ #ifndef COMPONENTS_OFFLINE_PAGES_BACKGROUND_OFFLINER_POLICY_H_
#define COMPONENTS_OFFLINE_PAGES_BACKGROUND_OFFLINER_POLICY_H_ #define COMPONENTS_OFFLINE_PAGES_BACKGROUND_OFFLINER_POLICY_H_
namespace {
const int kMaxRetries = 2;
const int kBackgroundTimeBudgetSeconds = 170;
const int kSinglePageTimeBudgetSeconds = 120;
const int kMinimumBatteryPercentageForNonUserRequestOfflining = 50;
} // namespace
namespace offline_pages { namespace offline_pages {
// Policy for the Background Offlining system. Some policy will belong to the // Policy for the Background Offlining system. Some policy will belong to the
...@@ -13,8 +20,40 @@ class OfflinerPolicy { ...@@ -13,8 +20,40 @@ class OfflinerPolicy {
public: public:
OfflinerPolicy(){}; OfflinerPolicy(){};
// TODO(petewil): Implement and add a .cc file. // TODO(petewil): Numbers here are chosen arbitrarily, do the proper studies
// Eventually this should get data from a finch experiment. // to get good policy numbers.
// TODO(petewil): Eventually this should get data from a finch experiment.
// Returns true if we should prefer retrying lesser tried requests.
bool ShouldPreferUntriedRequests() { return false; }
// Returns true if we should prefer older requests of equal number of tries.
bool ShouldPreferEarlierRequests() { return true; }
// Returns true if retry count is considered more important than recency in
// picking which request to try next.
bool RetryCountIsMoreImportantThanRecency() { return true; }
// The max number of times we will retry a request.
int GetMaxRetries() { return kMaxRetries; }
// How many seconds to keep trying new pages for, before we give up, and
// return to the scheduler.
int GetBackgroundProcessingTimeBudgetSeconds() {
return kBackgroundTimeBudgetSeconds;
}
// How long do we allow a page to load before giving up on it
int GetSinglePageTimeBudgetInSeconds() {
return kSinglePageTimeBudgetSeconds;
}
// How much battery must we have before fetching a page not explicitly
// requested by the user?
int GetMinimumBatteryPercentageForNonUserRequestOfflining() {
return kMinimumBatteryPercentageForNonUserRequestOfflining;
}
}; };
} }
......
...@@ -60,22 +60,23 @@ RequestCoordinator::RequestCoordinator(std::unique_ptr<OfflinerPolicy> policy, ...@@ -60,22 +60,23 @@ RequestCoordinator::RequestCoordinator(std::unique_ptr<OfflinerPolicy> policy,
last_offlining_status_(Offliner::RequestStatus::UNKNOWN), last_offlining_status_(Offliner::RequestStatus::UNKNOWN),
weak_ptr_factory_(this) { weak_ptr_factory_(this) {
DCHECK(policy_ != nullptr); DCHECK(policy_ != nullptr);
picker_.reset(new RequestPicker(queue_.get())); picker_.reset(new RequestPicker(queue_.get(), policy_.get()));
} }
RequestCoordinator::~RequestCoordinator() {} RequestCoordinator::~RequestCoordinator() {}
bool RequestCoordinator::SavePageLater( bool RequestCoordinator::SavePageLater(
const GURL& url, const ClientId& client_id) { const GURL& url, const ClientId& client_id, bool was_user_requested) {
DVLOG(2) << "URL is " << url << " " << __FUNCTION__; DVLOG(2) << "URL is " << url << " " << __FUNCTION__;
// TODO(petewil): We need a robust scheme for allocating new IDs. // TODO(petewil): We need a robust scheme for allocating new IDs. We may need
// GUIDS for the downloads home design.
static int64_t id = 0; static int64_t id = 0;
// Build a SavePageRequest. // Build a SavePageRequest.
// TODO(petewil): Use something like base::Clock to help in testing. // TODO(petewil): Use something like base::Clock to help in testing.
offline_pages::SavePageRequest request( offline_pages::SavePageRequest request(
id++, url, client_id, base::Time::Now()); id++, url, client_id, base::Time::Now(), was_user_requested);
// Put the request on the request queue. // Put the request on the request queue.
queue_->AddRequest(request, queue_->AddRequest(request,
...@@ -116,6 +117,7 @@ void RequestCoordinator::StopProcessing() { ...@@ -116,6 +117,7 @@ void RequestCoordinator::StopProcessing() {
bool RequestCoordinator::StartProcessing( bool RequestCoordinator::StartProcessing(
const DeviceConditions& device_conditions, const DeviceConditions& device_conditions,
const base::Callback<void(bool)>& callback) { const base::Callback<void(bool)>& callback) {
current_conditions_.reset(new DeviceConditions(device_conditions));
if (is_busy_) return false; if (is_busy_) return false;
is_canceled_ = false; is_canceled_ = false;
...@@ -135,7 +137,8 @@ void RequestCoordinator::TryNextRequest() { ...@@ -135,7 +137,8 @@ void RequestCoordinator::TryNextRequest() {
base::Bind(&RequestCoordinator::RequestPicked, base::Bind(&RequestCoordinator::RequestPicked,
weak_ptr_factory_.GetWeakPtr()), weak_ptr_factory_.GetWeakPtr()),
base::Bind(&RequestCoordinator::RequestQueueEmpty, base::Bind(&RequestCoordinator::RequestQueueEmpty,
weak_ptr_factory_.GetWeakPtr())); weak_ptr_factory_.GetWeakPtr()),
current_conditions_.get());
} }
// Called by the request picker when a request has been picked. // Called by the request picker when a request has been picked.
......
...@@ -47,7 +47,8 @@ class RequestCoordinator : public KeyedService { ...@@ -47,7 +47,8 @@ class RequestCoordinator : public KeyedService {
// Queues |request| to later load and save when system conditions allow. // Queues |request| to later load and save when system conditions allow.
// Returns true if the page could be queued successfully. // Returns true if the page could be queued successfully.
bool SavePageLater(const GURL& url, const ClientId& client_id); bool SavePageLater(
const GURL& url, const ClientId& client_id, bool user_reqeusted);
// Starts processing of one or more queued save page later requests. // Starts processing of one or more queued save page later requests.
// Returns whether processing was started and that caller should expect // Returns whether processing was started and that caller should expect
...@@ -123,6 +124,10 @@ class RequestCoordinator : public KeyedService { ...@@ -123,6 +124,10 @@ class RequestCoordinator : public KeyedService {
offliner_timeout_ = timeout; offliner_timeout_ = timeout;
} }
void SetDeviceConditionsForTest(DeviceConditions& current_conditions) {
current_conditions_.reset(new DeviceConditions(current_conditions));
}
friend class RequestCoordinatorTest; friend class RequestCoordinatorTest;
// The offliner can only handle one request at a time - if the offliner is // The offliner can only handle one request at a time - if the offliner is
...@@ -135,6 +140,8 @@ class RequestCoordinator : public KeyedService { ...@@ -135,6 +140,8 @@ class RequestCoordinator : public KeyedService {
base::TimeDelta offliner_timeout_; base::TimeDelta offliner_timeout_;
// Unowned pointer to the current offliner, if any. // Unowned pointer to the current offliner, if any.
Offliner* offliner_; Offliner* offliner_;
// Last known conditions for network, battery
std::unique_ptr<DeviceConditions> current_conditions_;
// RequestCoordinator takes over ownership of the policy // RequestCoordinator takes over ownership of the policy
std::unique_ptr<OfflinerPolicy> policy_; std::unique_ptr<OfflinerPolicy> policy_;
// OfflinerFactory. Used to create offline pages. Owned. // OfflinerFactory. Used to create offline pages. Owned.
......
...@@ -35,6 +35,7 @@ const int kRequestId(1); ...@@ -35,6 +35,7 @@ const int kRequestId(1);
const long kTestTimeoutSeconds = 1; const long kTestTimeoutSeconds = 1;
const int kBatteryPercentageHigh = 75; const int kBatteryPercentageHigh = 75;
const bool kPowerRequired = true; const bool kPowerRequired = true;
const bool kUserRequested = true;
} // namespace } // namespace
class SchedulerStub : public Scheduler { class SchedulerStub : public Scheduler {
...@@ -69,7 +70,8 @@ class SchedulerStub : public Scheduler { ...@@ -69,7 +70,8 @@ class SchedulerStub : public Scheduler {
class OfflinerStub : public Offliner { class OfflinerStub : public Offliner {
public: public:
OfflinerStub() OfflinerStub()
: request_(kRequestId, kUrl, kClientId, base::Time::Now()), : request_(kRequestId, kUrl, kClientId, base::Time::Now(),
kUserRequested),
enable_callback_(false), enable_callback_(false),
cancel_called_(false) {} cancel_called_(false) {}
...@@ -170,6 +172,10 @@ class RequestCoordinatorTest ...@@ -170,6 +172,10 @@ class RequestCoordinatorTest
coordinator_->SetOfflinerTimeoutForTest(timeout); coordinator_->SetOfflinerTimeoutForTest(timeout);
} }
void SetDeviceConditionsForTest(DeviceConditions device_conditions) {
coordinator_->SetDeviceConditionsForTest(device_conditions);
}
void WaitForCallback() { void WaitForCallback() {
waiter_.Wait(); waiter_.Wait();
} }
...@@ -252,7 +258,7 @@ TEST_F(RequestCoordinatorTest, StartProcessingWithNoRequests) { ...@@ -252,7 +258,7 @@ TEST_F(RequestCoordinatorTest, StartProcessingWithNoRequests) {
TEST_F(RequestCoordinatorTest, StartProcessingWithRequestInProgress) { TEST_F(RequestCoordinatorTest, StartProcessingWithRequestInProgress) {
// Put the request on the queue. // Put the request on the queue.
EXPECT_TRUE(coordinator()->SavePageLater(kUrl, kClientId)); EXPECT_TRUE(coordinator()->SavePageLater(kUrl, kClientId, kUserRequested));
// Set up for the call to StartProcessing by building arguments. // Set up for the call to StartProcessing by building arguments.
DeviceConditions device_conditions(false, 75, DeviceConditions device_conditions(false, 75,
...@@ -275,7 +281,7 @@ TEST_F(RequestCoordinatorTest, StartProcessingWithRequestInProgress) { ...@@ -275,7 +281,7 @@ TEST_F(RequestCoordinatorTest, StartProcessingWithRequestInProgress) {
} }
TEST_F(RequestCoordinatorTest, SavePageLater) { TEST_F(RequestCoordinatorTest, SavePageLater) {
EXPECT_TRUE(coordinator()->SavePageLater(kUrl, kClientId)); EXPECT_TRUE(coordinator()->SavePageLater(kUrl, kClientId, kUserRequested));
// Expect that a request got placed on the queue. // Expect that a request got placed on the queue.
coordinator()->queue()->GetRequests( coordinator()->queue()->GetRequests(
...@@ -303,7 +309,7 @@ TEST_F(RequestCoordinatorTest, SavePageLater) { ...@@ -303,7 +309,7 @@ TEST_F(RequestCoordinatorTest, SavePageLater) {
TEST_F(RequestCoordinatorTest, OfflinerDoneRequestSucceeded) { TEST_F(RequestCoordinatorTest, OfflinerDoneRequestSucceeded) {
// Add a request to the queue, wait for callbacks to finish. // Add a request to the queue, wait for callbacks to finish.
offline_pages::SavePageRequest request( offline_pages::SavePageRequest request(
kRequestId, kUrl, kClientId, base::Time::Now()); kRequestId, kUrl, kClientId, base::Time::Now(), kUserRequested);
coordinator()->queue()->AddRequest( coordinator()->queue()->AddRequest(
request, request,
base::Bind(&RequestCoordinatorTest::AddRequestDone, base::Bind(&RequestCoordinatorTest::AddRequestDone,
...@@ -317,6 +323,11 @@ TEST_F(RequestCoordinatorTest, OfflinerDoneRequestSucceeded) { ...@@ -317,6 +323,11 @@ TEST_F(RequestCoordinatorTest, OfflinerDoneRequestSucceeded) {
base::Unretained(this)); base::Unretained(this));
coordinator()->SetProcessingCallbackForTest(callback); coordinator()->SetProcessingCallbackForTest(callback);
// Set up device conditions for the test.
DeviceConditions device_conditions(
false, 75, net::NetworkChangeNotifier::CONNECTION_3G);
SetDeviceConditionsForTest(device_conditions);
// Call the OfflinerDoneCallback to simulate the page being completed, wait // Call the OfflinerDoneCallback to simulate the page being completed, wait
// for callbacks. // for callbacks.
EnableOfflinerCallback(true); EnableOfflinerCallback(true);
...@@ -338,7 +349,7 @@ TEST_F(RequestCoordinatorTest, OfflinerDoneRequestSucceeded) { ...@@ -338,7 +349,7 @@ TEST_F(RequestCoordinatorTest, OfflinerDoneRequestSucceeded) {
TEST_F(RequestCoordinatorTest, OfflinerDoneRequestFailed) { TEST_F(RequestCoordinatorTest, OfflinerDoneRequestFailed) {
// Add a request to the queue, wait for callbacks to finish. // Add a request to the queue, wait for callbacks to finish.
offline_pages::SavePageRequest request( offline_pages::SavePageRequest request(
kRequestId, kUrl, kClientId, base::Time::Now()); kRequestId, kUrl, kClientId, base::Time::Now(), kUserRequested);
coordinator()->queue()->AddRequest( coordinator()->queue()->AddRequest(
request, request,
base::Bind(&RequestCoordinatorTest::AddRequestDone, base::Bind(&RequestCoordinatorTest::AddRequestDone,
...@@ -375,7 +386,7 @@ TEST_F(RequestCoordinatorTest, OfflinerDoneRequestFailed) { ...@@ -375,7 +386,7 @@ TEST_F(RequestCoordinatorTest, OfflinerDoneRequestFailed) {
TEST_F(RequestCoordinatorTest, StartProcessingThenStopProcessingImmediately) { TEST_F(RequestCoordinatorTest, StartProcessingThenStopProcessingImmediately) {
// Add a request to the queue, wait for callbacks to finish. // Add a request to the queue, wait for callbacks to finish.
offline_pages::SavePageRequest request( offline_pages::SavePageRequest request(
kRequestId, kUrl, kClientId, base::Time::Now()); kRequestId, kUrl, kClientId, base::Time::Now(), kUserRequested);
coordinator()->queue()->AddRequest( coordinator()->queue()->AddRequest(
request, request,
base::Bind(&RequestCoordinatorTest::AddRequestDone, base::Bind(&RequestCoordinatorTest::AddRequestDone,
...@@ -409,7 +420,7 @@ TEST_F(RequestCoordinatorTest, StartProcessingThenStopProcessingImmediately) { ...@@ -409,7 +420,7 @@ TEST_F(RequestCoordinatorTest, StartProcessingThenStopProcessingImmediately) {
TEST_F(RequestCoordinatorTest, StartProcessingThenStopProcessingLater) { TEST_F(RequestCoordinatorTest, StartProcessingThenStopProcessingLater) {
// Add a request to the queue, wait for callbacks to finish. // Add a request to the queue, wait for callbacks to finish.
offline_pages::SavePageRequest request( offline_pages::SavePageRequest request(
kRequestId, kUrl, kClientId, base::Time::Now()); kRequestId, kUrl, kClientId, base::Time::Now(), kUserRequested);
coordinator()->queue()->AddRequest( coordinator()->queue()->AddRequest(
request, request,
base::Bind(&RequestCoordinatorTest::AddRequestDone, base::Bind(&RequestCoordinatorTest::AddRequestDone,
...@@ -448,7 +459,7 @@ TEST_F(RequestCoordinatorTest, StartProcessingThenStopProcessingLater) { ...@@ -448,7 +459,7 @@ TEST_F(RequestCoordinatorTest, StartProcessingThenStopProcessingLater) {
TEST_F(RequestCoordinatorTest, PrerendererTimeout) { TEST_F(RequestCoordinatorTest, PrerendererTimeout) {
// Build a request to use with the pre-renderer, and put it on the queue. // Build a request to use with the pre-renderer, and put it on the queue.
offline_pages::SavePageRequest request( offline_pages::SavePageRequest request(
kRequestId, kUrl, kClientId, base::Time::Now()); kRequestId, kUrl, kClientId, base::Time::Now(), kUserRequested);
coordinator()->queue()->AddRequest( coordinator()->queue()->AddRequest(
request, request,
base::Bind(&RequestCoordinatorTest::AddRequestDone, base::Bind(&RequestCoordinatorTest::AddRequestDone,
......
...@@ -8,25 +8,44 @@ ...@@ -8,25 +8,44 @@
#include "base/logging.h" #include "base/logging.h"
#include "components/offline_pages/background/save_page_request.h" #include "components/offline_pages/background/save_page_request.h"
namespace {
template <typename T>
int signum(T t) {
return (T(0) < t) - (t < T(0));
}
#define CALL_MEMBER_FUNCTION(object,ptrToMember) ((object)->*(ptrToMember))
} // namespace
namespace offline_pages { namespace offline_pages {
RequestPicker::RequestPicker( RequestPicker::RequestPicker(
RequestQueue* requestQueue) RequestQueue* requestQueue, OfflinerPolicy* policy)
: queue_(requestQueue), : queue_(requestQueue),
policy_(policy),
fewer_retries_better_(false),
earlier_requests_better_(false),
weak_ptr_factory_(this) {} weak_ptr_factory_(this) {}
RequestPicker::~RequestPicker() {} RequestPicker::~RequestPicker() {}
// Entry point for the async operation to choose the next request.
void RequestPicker::ChooseNextRequest( void RequestPicker::ChooseNextRequest(
RequestCoordinator::RequestPickedCallback picked_callback, RequestCoordinator::RequestPickedCallback picked_callback,
RequestCoordinator::RequestQueueEmptyCallback empty_callback) { RequestCoordinator::RequestQueueEmptyCallback empty_callback,
DeviceConditions* device_conditions) {
picked_callback_ = picked_callback; picked_callback_ = picked_callback;
empty_callback_ = empty_callback; empty_callback_ = empty_callback;
fewer_retries_better_ = policy_->ShouldPreferUntriedRequests();
earlier_requests_better_ = policy_->ShouldPreferEarlierRequests();
current_conditions_.reset(new DeviceConditions(*device_conditions));
// Get all requests from queue (there is no filtering mechanism). // Get all requests from queue (there is no filtering mechanism).
queue_->GetRequests(base::Bind(&RequestPicker::GetRequestResultCallback, queue_->GetRequests(base::Bind(&RequestPicker::GetRequestResultCallback,
weak_ptr_factory_.GetWeakPtr())); weak_ptr_factory_.GetWeakPtr()));
} }
// When we get contents from the queue, use them to pick the next
// request to operate on (if any).
void RequestPicker::GetRequestResultCallback( void RequestPicker::GetRequestResultCallback(
RequestQueue::GetRequestsResult, RequestQueue::GetRequestsResult,
const std::vector<SavePageRequest>& requests) { const std::vector<SavePageRequest>& requests) {
...@@ -37,11 +56,151 @@ void RequestPicker::GetRequestResultCallback( ...@@ -37,11 +56,151 @@ void RequestPicker::GetRequestResultCallback(
} }
// Pick the most deserving request for our conditions. // Pick the most deserving request for our conditions.
const SavePageRequest& picked_request = requests[0]; const SavePageRequest* picked_request = nullptr;
RequestCompareFunction comparator = nullptr;
// Choose which comparison function to use based on policy.
if (policy_->RetryCountIsMoreImportantThanRecency())
comparator = &RequestPicker::RetryCountFirstCompareFunction;
else
comparator = &RequestPicker::RecencyFirstCompareFunction;
// Iterate once through the requests, keeping track of best candidate.
for (unsigned i = 0; i < requests.size(); ++i) {
if (!RequestConditionsSatisfied(requests[i]))
continue;
if (IsNewRequestBetter(picked_request, &(requests[i]), comparator))
picked_request = &(requests[i]);
}
// If we have a best request to try next, get the request coodinator to
// start it. Otherwise return that we have no candidates.
if (picked_request != nullptr) {
picked_callback_.Run(*picked_request);
} else {
empty_callback_.Run();
}
}
// Filter out requests that don't meet the current conditions. For instance, if
// this is a predictive request, and we are not on WiFi, it should be ignored
// this round.
bool RequestPicker::RequestConditionsSatisfied(const SavePageRequest& request) {
// If the user did not request the page directly, make sure we are connected
// to power and have WiFi and sufficient battery remaining before we take this
// reqeust.
// TODO(petewil): We may later want to configure whether to allow 2G for non
// user_requested items, add that to policy.
if (!request.user_requested()) {
if (!current_conditions_->IsPowerConnected())
return false;
if (current_conditions_->GetNetConnectionType() !=
net::NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI) {
return false;
}
if (current_conditions_->GetBatteryPercentage() <
policy_->GetMinimumBatteryPercentageForNonUserRequestOfflining()) {
return false;
}
}
// If we have already tried this page the max number of times, it is not
// eligible to try again.
// TODO(petewil): Instead, we should have code to remove the page from the
// queue after the last retry.
if (request.attempt_count() >= policy_->GetMaxRetries())
return false;
// If this request is not active yet, return false.
// TODO(petewil): If the only reason we return nothing to do is that we have
// inactive requests, we still want to try again later after their activation
// time elapses, we shouldn't take ourselves completely off the scheduler.
if (request.activation_time() > base::Time::Now())
return false;
return true;
}
// Look at policies to decide which requests to prefer.
bool RequestPicker::IsNewRequestBetter(const SavePageRequest* oldRequest,
const SavePageRequest* newRequest,
RequestCompareFunction comparator) {
// If there is no old request, the new one is better.
if (oldRequest == nullptr)
return true;
// User requested pages get priority.
if (newRequest->user_requested() && !oldRequest->user_requested())
return true;
// Otherwise, use the comparison function for the current policy, which
// returns true if the older request is better.
return !(CALL_MEMBER_FUNCTION(this, comparator)(oldRequest, newRequest));
}
// Compare the results, checking request count before recency. Returns true if
// left hand side is better, false otherwise.
bool RequestPicker::RetryCountFirstCompareFunction(
const SavePageRequest* left, const SavePageRequest* right) {
// Check the attempt count.
int result = CompareRetryCount(left, right);
if (result != 0)
return (result > 0);
// If we get here, the attempt counts were the same, so check recency.
result = CompareCreationTime(left, right);
return (result > 0);
}
// Compare the results, checking recency before request count. Returns true if
// left hand side is better, false otherwise.
bool RequestPicker::RecencyFirstCompareFunction(
const SavePageRequest* left, const SavePageRequest* right) {
// Check the recency.
int result = CompareCreationTime(left, right);
if (result != 0)
return (result > 0);
// If we get here, the recency was the same, so check the attempt count.
result = CompareRetryCount(left, right);
return (result > 0);
}
// Compare left and right side, returning 1 if the left side is better
// (preferred by policy), 0 if the same, and -1 if the right side is better.
int RequestPicker::CompareRetryCount(
const SavePageRequest* left, const SavePageRequest* right) {
// Check the attempt count.
int result = signum(left->attempt_count() - right->attempt_count());
// Flip the direction of comparison if policy prefers fewer retries.
if (fewer_retries_better_)
result *= -1;
return result;
}
// Compare left and right side, returning 1 if the left side is better
// (preferred by policy), 0 if the same, and -1 if the right side is better.
int RequestPicker::CompareCreationTime(
const SavePageRequest* left, const SavePageRequest* right) {
// Check the recency.
base::TimeDelta difference = left->creation_time() - right->creation_time();
int result = signum(difference.InMilliseconds());
// Flip the direction of comparison if policy prefers fewer retries.
if (earlier_requests_better_)
result *= -1;
// When we have a best request to try next, get the request coodinator to return result;
// start it.
picked_callback_.Run(picked_request);
} }
} // namespace offline_pages } // namespace offline_pages
...@@ -5,14 +5,22 @@ ...@@ -5,14 +5,22 @@
#ifndef COMPONENTS_OFFLINE_PAGES_BACKGROUND_REQUEST_PICKER_H_ #ifndef COMPONENTS_OFFLINE_PAGES_BACKGROUND_REQUEST_PICKER_H_
#define COMPONENTS_OFFLINE_PAGES_BACKGROUND_REQUEST_PICKER_H_ #define COMPONENTS_OFFLINE_PAGES_BACKGROUND_REQUEST_PICKER_H_
#include <memory>
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "components/offline_pages/background/device_conditions.h"
#include "components/offline_pages/background/offliner_policy.h"
#include "components/offline_pages/background/request_coordinator.h" #include "components/offline_pages/background/request_coordinator.h"
#include "components/offline_pages/background/request_queue.h" #include "components/offline_pages/background/request_queue.h"
namespace offline_pages { namespace offline_pages {
typedef bool (RequestPicker::*RequestCompareFunction)(
const SavePageRequest* left, const SavePageRequest* right);
class RequestPicker { class RequestPicker {
public: public:
RequestPicker(RequestQueue* requestQueue); RequestPicker(RequestQueue* requestQueue, OfflinerPolicy* policy);
~RequestPicker(); ~RequestPicker();
...@@ -20,15 +28,51 @@ class RequestPicker { ...@@ -20,15 +28,51 @@ class RequestPicker {
// conditions, and call back to the RequestCoordinator when we have one. // conditions, and call back to the RequestCoordinator when we have one.
void ChooseNextRequest( void ChooseNextRequest(
RequestCoordinator::RequestPickedCallback picked_callback, RequestCoordinator::RequestPickedCallback picked_callback,
RequestCoordinator::RequestQueueEmptyCallback empty_callback); RequestCoordinator::RequestQueueEmptyCallback empty_callback,
DeviceConditions* device_conditions);
private: private:
// Callback for the GetRequest results to be delivered. // Callback for the GetRequest results to be delivered.
void GetRequestResultCallback(RequestQueue::GetRequestsResult result, void GetRequestResultCallback(RequestQueue::GetRequestsResult result,
const std::vector<SavePageRequest>& results); const std::vector<SavePageRequest>& results);
// Filter out requests that don't meet the current conditions. For instance,
// if this is a predictive request, and we are not on WiFi, it should be
// ignored this round.
bool RequestConditionsSatisfied(const SavePageRequest& request);
// Using policies, decide if the new request is preferable to the best we have
// so far.
bool IsNewRequestBetter(const SavePageRequest* oldRequest,
const SavePageRequest* newRequest,
RequestCompareFunction comparator);
// Is the new request preferable from the retry count first standpoint?
bool RetryCountFirstCompareFunction(const SavePageRequest* left,
const SavePageRequest* right);
// Is the new request better from the recency first standpoint?
bool RecencyFirstCompareFunction(const SavePageRequest* left,
const SavePageRequest* right);
// Does the new request have better retry count?
int CompareRetryCount(const SavePageRequest* left,
const SavePageRequest* right);
// Does the new request have better creation time?
int CompareCreationTime(const SavePageRequest* left,
const SavePageRequest* right);
// unowned pointer to the request queue. // unowned pointer to the request queue.
RequestQueue* queue_; RequestQueue* queue_;
// unowned pointer to the policy object.
OfflinerPolicy* policy_;
// Current conditions on the device
std::unique_ptr<DeviceConditions> current_conditions_;
// True if we prefer less-tried requests
bool fewer_retries_better_;
// True if we prefer requests submitted more recently
bool earlier_requests_better_;
// Callback for when we are done picking a request to do next. // Callback for when we are done picking a request to do next.
RequestCoordinator::RequestPickedCallback picked_callback_; RequestCoordinator::RequestPickedCallback picked_callback_;
// Callback for when there are no more reqeusts to pick. // Callback for when there are no more reqeusts to pick.
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/test/test_simple_task_runner.h" #include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "components/offline_pages/background/device_conditions.h"
#include "components/offline_pages/background/request_queue.h" #include "components/offline_pages/background/request_queue.h"
#include "components/offline_pages/background/request_queue_in_memory_store.h" #include "components/offline_pages/background/request_queue_in_memory_store.h"
#include "components/offline_pages/background/save_page_request.h" #include "components/offline_pages/background/save_page_request.h"
...@@ -25,6 +26,7 @@ const ClientId kClientId1("bookmark", "1234"); ...@@ -25,6 +26,7 @@ const ClientId kClientId1("bookmark", "1234");
const int64_t kRequestId2 = 42; const int64_t kRequestId2 = 42;
const GURL kUrl2("http://nytimes.com"); const GURL kUrl2("http://nytimes.com");
const ClientId kClientId2("bookmark", "5678"); const ClientId kClientId2("bookmark", "5678");
const bool kUserRequested = true;
} // namespace } // namespace
class RequestPickerTest : public testing::Test { class RequestPickerTest : public testing::Test {
...@@ -50,6 +52,7 @@ class RequestPickerTest : public testing::Test { ...@@ -50,6 +52,7 @@ class RequestPickerTest : public testing::Test {
std::unique_ptr<RequestQueue> queue_; std::unique_ptr<RequestQueue> queue_;
std::unique_ptr<RequestPicker> picker_; std::unique_ptr<RequestPicker> picker_;
std::unique_ptr<SavePageRequest> last_picked_; std::unique_ptr<SavePageRequest> last_picked_;
std::unique_ptr<OfflinerPolicy> policy_;
bool request_queue_empty_called_; bool request_queue_empty_called_;
private: private:
...@@ -67,7 +70,8 @@ void RequestPickerTest::SetUp() { ...@@ -67,7 +70,8 @@ void RequestPickerTest::SetUp() {
std::unique_ptr<RequestQueueInMemoryStore> store( std::unique_ptr<RequestQueueInMemoryStore> store(
new RequestQueueInMemoryStore()); new RequestQueueInMemoryStore());
queue_.reset(new RequestQueue(std::move(store))); queue_.reset(new RequestQueue(std::move(store)));
picker_.reset(new RequestPicker(queue_.get())); policy_.reset(new OfflinerPolicy());
picker_.reset(new RequestPicker(queue_.get(), policy_.get()));
request_queue_empty_called_ = false; request_queue_empty_called_ = false;
} }
...@@ -88,8 +92,11 @@ void RequestPickerTest::RequestQueueEmpty() { ...@@ -88,8 +92,11 @@ void RequestPickerTest::RequestQueueEmpty() {
TEST_F(RequestPickerTest, ChooseNextRequest) { TEST_F(RequestPickerTest, ChooseNextRequest) {
base::Time creation_time = base::Time::Now(); base::Time creation_time = base::Time::Now();
SavePageRequest request1(kRequestId1, kUrl1, kClientId1, creation_time); DeviceConditions conditions;
SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time); SavePageRequest request1(
kRequestId1, kUrl1, kClientId1, creation_time, kUserRequested);
SavePageRequest request2(
kRequestId2, kUrl2, kClientId2, creation_time, kUserRequested);
// Put some test requests on the Queue. // Put some test requests on the Queue.
queue_->AddRequest(request1, base::Bind(&RequestPickerTest::AddRequestDone, queue_->AddRequest(request1, base::Bind(&RequestPickerTest::AddRequestDone,
base::Unretained(this))); base::Unretained(this)));
...@@ -101,23 +108,24 @@ TEST_F(RequestPickerTest, ChooseNextRequest) { ...@@ -101,23 +108,24 @@ TEST_F(RequestPickerTest, ChooseNextRequest) {
picker_->ChooseNextRequest( picker_->ChooseNextRequest(
base::Bind(&RequestPickerTest::RequestPicked, base::Unretained(this)), base::Bind(&RequestPickerTest::RequestPicked, base::Unretained(this)),
base::Bind(&RequestPickerTest::RequestQueueEmpty, base::Bind(&RequestPickerTest::RequestQueueEmpty, base::Unretained(this)),
base::Unretained(this))); &conditions);
// Pump the loop again to give the async queue the opportunity to return // Pump the loop again to give the async queue the opportunity to return
// results from the Get operation, and for the picker to call the "picked" // results from the Get operation, and for the picker to call the "picked"
// callback. // callback.
PumpLoop(); PumpLoop();
EXPECT_EQ(kRequestId1, last_picked_->request_id()); EXPECT_EQ(kRequestId2, last_picked_->request_id());
EXPECT_FALSE(request_queue_empty_called_); EXPECT_FALSE(request_queue_empty_called_);
} }
TEST_F(RequestPickerTest, PickFromEmptyQueue) { TEST_F(RequestPickerTest, PickFromEmptyQueue) {
DeviceConditions conditions;
picker_->ChooseNextRequest( picker_->ChooseNextRequest(
base::Bind(&RequestPickerTest::RequestPicked, base::Unretained(this)), base::Bind(&RequestPickerTest::RequestPicked, base::Unretained(this)),
base::Bind(&RequestPickerTest::RequestQueueEmpty, base::Bind(&RequestPickerTest::RequestQueueEmpty, base::Unretained(this)),
base::Unretained(this))); &conditions);
// Pump the loop again to give the async queue the opportunity to return // Pump the loop again to give the async queue the opportunity to return
// results from the Get operation, and for the picker to call the "QueueEmpty" // results from the Get operation, and for the picker to call the "QueueEmpty"
......
...@@ -22,6 +22,7 @@ namespace { ...@@ -22,6 +22,7 @@ namespace {
// This is a macro instead of a const so that // This is a macro instead of a const so that
// it can be used inline in other SQL statements below. // it can be used inline in other SQL statements below.
#define REQUEST_QUEUE_TABLE_NAME "request_queue_v1" #define REQUEST_QUEUE_TABLE_NAME "request_queue_v1"
const bool kUserRequested = true;
bool CreateRequestQueueTable(sql::Connection* db) { bool CreateRequestQueueTable(sql::Connection* db) {
const char kSql[] = "CREATE TABLE IF NOT EXISTS " REQUEST_QUEUE_TABLE_NAME const char kSql[] = "CREATE TABLE IF NOT EXISTS " REQUEST_QUEUE_TABLE_NAME
...@@ -93,7 +94,8 @@ SavePageRequest MakeSavePageRequest(const sql::Statement& statement) { ...@@ -93,7 +94,8 @@ SavePageRequest MakeSavePageRequest(const sql::Statement& statement) {
const ClientId client_id(statement.ColumnString(6), const ClientId client_id(statement.ColumnString(6),
statement.ColumnString(7)); statement.ColumnString(7));
SavePageRequest request(id, url, client_id, creation_time, activation_time); SavePageRequest request(
id, url, client_id, creation_time, activation_time, kUserRequested);
request.set_last_attempt_time(last_attempt_time); request.set_last_attempt_time(last_attempt_time);
request.set_attempt_count(last_attempt_count); request.set_attempt_count(last_attempt_count);
return request; return request;
......
...@@ -24,6 +24,7 @@ namespace { ...@@ -24,6 +24,7 @@ namespace {
const int64_t kRequestId = 42; const int64_t kRequestId = 42;
const GURL kUrl("http://example.com"); const GURL kUrl("http://example.com");
const ClientId kClientId("bookmark", "1234"); const ClientId kClientId("bookmark", "1234");
const bool kUserRequested = true;
enum class LastResult { enum class LastResult {
kNone, kNone,
...@@ -195,7 +196,8 @@ TYPED_TEST(RequestQueueStoreTest, GetRequestsEmpty) { ...@@ -195,7 +196,8 @@ TYPED_TEST(RequestQueueStoreTest, GetRequestsEmpty) {
TYPED_TEST(RequestQueueStoreTest, AddRequest) { TYPED_TEST(RequestQueueStoreTest, AddRequest) {
std::unique_ptr<RequestQueueStore> store(this->BuildStore()); std::unique_ptr<RequestQueueStore> store(this->BuildStore());
base::Time creation_time = base::Time::Now(); base::Time creation_time = base::Time::Now();
SavePageRequest request(kRequestId, kUrl, kClientId, creation_time); SavePageRequest request(
kRequestId, kUrl, kClientId, creation_time, kUserRequested);
store->AddOrUpdateRequest( store->AddOrUpdateRequest(
request, base::Bind(&RequestQueueStoreTestBase::AddOrUpdateDone, request, base::Bind(&RequestQueueStoreTestBase::AddOrUpdateDone,
...@@ -218,7 +220,8 @@ TYPED_TEST(RequestQueueStoreTest, AddRequest) { ...@@ -218,7 +220,8 @@ TYPED_TEST(RequestQueueStoreTest, AddRequest) {
TYPED_TEST(RequestQueueStoreTest, UpdateRequest) { TYPED_TEST(RequestQueueStoreTest, UpdateRequest) {
std::unique_ptr<RequestQueueStore> store(this->BuildStore()); std::unique_ptr<RequestQueueStore> store(this->BuildStore());
base::Time creation_time = base::Time::Now(); base::Time creation_time = base::Time::Now();
SavePageRequest original_request(kRequestId, kUrl, kClientId, creation_time); SavePageRequest original_request(
kRequestId, kUrl, kClientId, creation_time, kUserRequested);
store->AddOrUpdateRequest( store->AddOrUpdateRequest(
original_request, base::Bind(&RequestQueueStoreTestBase::AddOrUpdateDone, original_request, base::Bind(&RequestQueueStoreTestBase::AddOrUpdateDone,
base::Unretained(this))); base::Unretained(this)));
...@@ -229,7 +232,8 @@ TYPED_TEST(RequestQueueStoreTest, UpdateRequest) { ...@@ -229,7 +232,8 @@ TYPED_TEST(RequestQueueStoreTest, UpdateRequest) {
creation_time + base::TimeDelta::FromMinutes(1); creation_time + base::TimeDelta::FromMinutes(1);
base::Time activation_time = creation_time + base::TimeDelta::FromHours(6); base::Time activation_time = creation_time + base::TimeDelta::FromHours(6);
SavePageRequest updated_request(kRequestId, kUrl, kClientId, SavePageRequest updated_request(kRequestId, kUrl, kClientId,
new_creation_time, activation_time); new_creation_time, activation_time,
kUserRequested);
store->AddOrUpdateRequest( store->AddOrUpdateRequest(
updated_request, base::Bind(&RequestQueueStoreTestBase::AddOrUpdateDone, updated_request, base::Bind(&RequestQueueStoreTestBase::AddOrUpdateDone,
base::Unretained(this))); base::Unretained(this)));
...@@ -251,7 +255,8 @@ TYPED_TEST(RequestQueueStoreTest, UpdateRequest) { ...@@ -251,7 +255,8 @@ TYPED_TEST(RequestQueueStoreTest, UpdateRequest) {
TYPED_TEST(RequestQueueStoreTest, RemoveRequest) { TYPED_TEST(RequestQueueStoreTest, RemoveRequest) {
std::unique_ptr<RequestQueueStore> store(this->BuildStore()); std::unique_ptr<RequestQueueStore> store(this->BuildStore());
base::Time creation_time = base::Time::Now(); base::Time creation_time = base::Time::Now();
SavePageRequest original_request(kRequestId, kUrl, kClientId, creation_time); SavePageRequest original_request(
kRequestId, kUrl, kClientId, creation_time, kUserRequested);
store->AddOrUpdateRequest( store->AddOrUpdateRequest(
original_request, base::Bind(&RequestQueueStoreTestBase::AddOrUpdateDone, original_request, base::Bind(&RequestQueueStoreTestBase::AddOrUpdateDone,
base::Unretained(this))); base::Unretained(this)));
...@@ -290,7 +295,8 @@ TYPED_TEST(RequestQueueStoreTest, RemoveRequest) { ...@@ -290,7 +295,8 @@ TYPED_TEST(RequestQueueStoreTest, RemoveRequest) {
TYPED_TEST(RequestQueueStoreTest, ResetStore) { TYPED_TEST(RequestQueueStoreTest, ResetStore) {
std::unique_ptr<RequestQueueStore> store(this->BuildStore()); std::unique_ptr<RequestQueueStore> store(this->BuildStore());
base::Time creation_time = base::Time::Now(); base::Time creation_time = base::Time::Now();
SavePageRequest original_request(kRequestId, kUrl, kClientId, creation_time); SavePageRequest original_request(
kRequestId, kUrl, kClientId, creation_time, kUserRequested);
store->AddOrUpdateRequest( store->AddOrUpdateRequest(
original_request, base::Bind(&RequestQueueStoreTestBase::AddOrUpdateDone, original_request, base::Bind(&RequestQueueStoreTestBase::AddOrUpdateDone,
base::Unretained(this))); base::Unretained(this)));
...@@ -319,7 +325,8 @@ class RequestQueueStoreSQLTest ...@@ -319,7 +325,8 @@ class RequestQueueStoreSQLTest
TEST_F(RequestQueueStoreSQLTest, SaveCloseReopenRead) { TEST_F(RequestQueueStoreSQLTest, SaveCloseReopenRead) {
std::unique_ptr<RequestQueueStore> store(BuildStore()); std::unique_ptr<RequestQueueStore> store(BuildStore());
base::Time creation_time = base::Time::Now(); base::Time creation_time = base::Time::Now();
SavePageRequest original_request(kRequestId, kUrl, kClientId, creation_time); SavePageRequest original_request(
kRequestId, kUrl, kClientId, creation_time, kUserRequested);
store->AddOrUpdateRequest( store->AddOrUpdateRequest(
original_request, base::Bind(&RequestQueueStoreTestBase::AddOrUpdateDone, original_request, base::Bind(&RequestQueueStoreTestBase::AddOrUpdateDone,
base::Unretained(this))); base::Unretained(this)));
......
...@@ -28,6 +28,7 @@ const ClientId kClientId("bookmark", "1234"); ...@@ -28,6 +28,7 @@ const ClientId kClientId("bookmark", "1234");
const int64_t kRequestId2 = 77; const int64_t kRequestId2 = 77;
const GURL kUrl2("http://test.com"); const GURL kUrl2("http://test.com");
const ClientId kClientId2("bookmark", "567"); const ClientId kClientId2("bookmark", "567");
const bool kUserRequested = true;
} // namespace } // namespace
// TODO(fgorski): Add tests for store failures in add/remove/get. // TODO(fgorski): Add tests for store failures in add/remove/get.
...@@ -125,7 +126,8 @@ TEST_F(RequestQueueTest, GetRequestsEmpty) { ...@@ -125,7 +126,8 @@ TEST_F(RequestQueueTest, GetRequestsEmpty) {
TEST_F(RequestQueueTest, AddRequest) { TEST_F(RequestQueueTest, AddRequest) {
base::Time creation_time = base::Time::Now(); base::Time creation_time = base::Time::Now();
SavePageRequest request(kRequestId, kUrl, kClientId, creation_time); SavePageRequest request(
kRequestId, kUrl, kClientId, creation_time, kUserRequested);
queue()->AddRequest(request, base::Bind(&RequestQueueTest::AddRequestDone, queue()->AddRequest(request, base::Bind(&RequestQueueTest::AddRequestDone,
base::Unretained(this))); base::Unretained(this)));
PumpLoop(); PumpLoop();
...@@ -142,7 +144,8 @@ TEST_F(RequestQueueTest, AddRequest) { ...@@ -142,7 +144,8 @@ TEST_F(RequestQueueTest, AddRequest) {
TEST_F(RequestQueueTest, RemoveRequest) { TEST_F(RequestQueueTest, RemoveRequest) {
base::Time creation_time = base::Time::Now(); base::Time creation_time = base::Time::Now();
SavePageRequest request(kRequestId, kUrl, kClientId, creation_time); SavePageRequest request(
kRequestId, kUrl, kClientId, creation_time, kUserRequested);
queue()->AddRequest(request, base::Bind(&RequestQueueTest::AddRequestDone, queue()->AddRequest(request, base::Bind(&RequestQueueTest::AddRequestDone,
base::Unretained(this))); base::Unretained(this)));
PumpLoop(); PumpLoop();
...@@ -165,12 +168,14 @@ TEST_F(RequestQueueTest, RemoveRequest) { ...@@ -165,12 +168,14 @@ TEST_F(RequestQueueTest, RemoveRequest) {
// listing multiple items and removing the right item. // listing multiple items and removing the right item.
TEST_F(RequestQueueTest, MultipleRequestsAddGetRemove) { TEST_F(RequestQueueTest, MultipleRequestsAddGetRemove) {
base::Time creation_time = base::Time::Now(); base::Time creation_time = base::Time::Now();
SavePageRequest request1(kRequestId, kUrl, kClientId, creation_time); SavePageRequest request1(
kRequestId, kUrl, kClientId, creation_time, kUserRequested);
queue()->AddRequest(request1, base::Bind(&RequestQueueTest::AddRequestDone, queue()->AddRequest(request1, base::Bind(&RequestQueueTest::AddRequestDone,
base::Unretained(this))); base::Unretained(this)));
PumpLoop(); PumpLoop();
ASSERT_EQ(request1.request_id(), last_added_request()->request_id()); ASSERT_EQ(request1.request_id(), last_added_request()->request_id());
SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time); SavePageRequest request2(
kRequestId2, kUrl2, kClientId2, creation_time, kUserRequested);
queue()->AddRequest(request2, base::Bind(&RequestQueueTest::AddRequestDone, queue()->AddRequest(request2, base::Bind(&RequestQueueTest::AddRequestDone,
base::Unretained(this))); base::Unretained(this)));
PumpLoop(); PumpLoop();
......
...@@ -9,25 +9,29 @@ namespace offline_pages { ...@@ -9,25 +9,29 @@ namespace offline_pages {
SavePageRequest::SavePageRequest(int64_t request_id, SavePageRequest::SavePageRequest(int64_t request_id,
const GURL& url, const GURL& url,
const ClientId& client_id, const ClientId& client_id,
const base::Time& creation_time) const base::Time& creation_time,
const bool was_user_requested)
: request_id_(request_id), : request_id_(request_id),
url_(url), url_(url),
client_id_(client_id), client_id_(client_id),
creation_time_(creation_time), creation_time_(creation_time),
activation_time_(creation_time), activation_time_(creation_time),
attempt_count_(0) {} attempt_count_(0),
user_requested_(was_user_requested) {}
SavePageRequest::SavePageRequest(int64_t request_id, SavePageRequest::SavePageRequest(int64_t request_id,
const GURL& url, const GURL& url,
const ClientId& client_id, const ClientId& client_id,
const base::Time& creation_time, const base::Time& creation_time,
const base::Time& activation_time) const base::Time& activation_time,
const bool user_requested)
: request_id_(request_id), : request_id_(request_id),
url_(url), url_(url),
client_id_(client_id), client_id_(client_id),
creation_time_(creation_time), creation_time_(creation_time),
activation_time_(activation_time), activation_time_(activation_time),
attempt_count_(0) {} attempt_count_(0),
user_requested_(user_requested) {}
SavePageRequest::SavePageRequest(const SavePageRequest& other) SavePageRequest::SavePageRequest(const SavePageRequest& other)
: request_id_(other.request_id_), : request_id_(other.request_id_),
...@@ -36,7 +40,8 @@ SavePageRequest::SavePageRequest(const SavePageRequest& other) ...@@ -36,7 +40,8 @@ SavePageRequest::SavePageRequest(const SavePageRequest& other)
creation_time_(other.creation_time_), creation_time_(other.creation_time_),
activation_time_(other.activation_time_), activation_time_(other.activation_time_),
attempt_count_(other.attempt_count_), attempt_count_(other.attempt_count_),
last_attempt_time_(other.last_attempt_time_) {} last_attempt_time_(other.last_attempt_time_),
user_requested_(other.user_requested_) {}
SavePageRequest::~SavePageRequest() {} SavePageRequest::~SavePageRequest() {}
......
...@@ -30,12 +30,14 @@ class SavePageRequest { ...@@ -30,12 +30,14 @@ class SavePageRequest {
SavePageRequest(int64_t request_id, SavePageRequest(int64_t request_id,
const GURL& url, const GURL& url,
const ClientId& client_id, const ClientId& client_id,
const base::Time& creation_time); const base::Time& creation_time,
const bool user_requested);
SavePageRequest(int64_t request_id, SavePageRequest(int64_t request_id,
const GURL& url, const GURL& url,
const ClientId& client_id, const ClientId& client_id,
const base::Time& creation_time, const base::Time& creation_time,
const base::Time& activation_time); const base::Time& activation_time,
const bool user_requested);
SavePageRequest(const SavePageRequest& other); SavePageRequest(const SavePageRequest& other);
~SavePageRequest(); ~SavePageRequest();
...@@ -68,6 +70,12 @@ class SavePageRequest { ...@@ -68,6 +70,12 @@ class SavePageRequest {
last_attempt_time_ = last_attempt_time; last_attempt_time_ = last_attempt_time;
} }
bool user_requested() const { return user_requested_; }
void set_user_requested(bool user_requested) {
user_requested_ = user_requested;
}
private: private:
// ID of this request. // ID of this request.
int64_t request_id_; int64_t request_id_;
...@@ -90,6 +98,10 @@ class SavePageRequest { ...@@ -90,6 +98,10 @@ class SavePageRequest {
// Timestamp of the last request starting. // Timestamp of the last request starting.
base::Time last_attempt_time_; base::Time last_attempt_time_;
// Whether the user specifically requested this page (as opposed to a client
// like AGSA or Now.)
bool user_requested_;
}; };
} // namespace offline_pages } // namespace offline_pages
......
...@@ -12,6 +12,7 @@ namespace { ...@@ -12,6 +12,7 @@ namespace {
const int64_t kRequestId = 42; const int64_t kRequestId = 42;
const GURL kUrl("http://example.com"); const GURL kUrl("http://example.com");
const ClientId kClientId("bookmark", "1234"); const ClientId kClientId("bookmark", "1234");
const bool kUserRequested = true;
} // namespace } // namespace
class SavePageRequestTest : public testing::Test { class SavePageRequestTest : public testing::Test {
...@@ -23,7 +24,8 @@ SavePageRequestTest::~SavePageRequestTest() {} ...@@ -23,7 +24,8 @@ SavePageRequestTest::~SavePageRequestTest() {}
TEST_F(SavePageRequestTest, CreatePendingReqeust) { TEST_F(SavePageRequestTest, CreatePendingReqeust) {
base::Time creation_time = base::Time::Now(); base::Time creation_time = base::Time::Now();
SavePageRequest request(kRequestId, kUrl, kClientId, creation_time); SavePageRequest request(
kRequestId, kUrl, kClientId, creation_time, kUserRequested);
ASSERT_EQ(kRequestId, request.request_id()); ASSERT_EQ(kRequestId, request.request_id());
ASSERT_EQ(kUrl, request.url()); ASSERT_EQ(kUrl, request.url());
ASSERT_EQ(kClientId, request.client_id()); ASSERT_EQ(kClientId, request.client_id());
...@@ -41,7 +43,7 @@ TEST_F(SavePageRequestTest, CreateNotReadyRequest) { ...@@ -41,7 +43,7 @@ TEST_F(SavePageRequestTest, CreateNotReadyRequest) {
base::Time creation_time = base::Time::Now(); base::Time creation_time = base::Time::Now();
base::Time activation_time = creation_time + base::TimeDelta::FromHours(6); base::Time activation_time = creation_time + base::TimeDelta::FromHours(6);
SavePageRequest request(kRequestId, kUrl, kClientId, creation_time, SavePageRequest request(kRequestId, kUrl, kClientId, creation_time,
activation_time); activation_time, kUserRequested);
ASSERT_EQ(kRequestId, request.request_id()); ASSERT_EQ(kRequestId, request.request_id());
ASSERT_EQ(kUrl, request.url()); ASSERT_EQ(kUrl, request.url());
...@@ -63,7 +65,7 @@ TEST_F(SavePageRequestTest, StartAndCompleteRequest) { ...@@ -63,7 +65,7 @@ TEST_F(SavePageRequestTest, StartAndCompleteRequest) {
base::Time creation_time = base::Time::Now(); base::Time creation_time = base::Time::Now();
base::Time activation_time = creation_time + base::TimeDelta::FromHours(6); base::Time activation_time = creation_time + base::TimeDelta::FromHours(6);
SavePageRequest request(kRequestId, kUrl, kClientId, creation_time, SavePageRequest request(kRequestId, kUrl, kClientId, creation_time,
activation_time); activation_time, kUserRequested);
base::Time start_time = activation_time + base::TimeDelta::FromHours(3); base::Time start_time = activation_time + base::TimeDelta::FromHours(3);
request.MarkAttemptStarted(start_time); request.MarkAttemptStarted(start_time);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment