[EoS] Add backoff support EoS url fetcher
Also make EoS url fetcher support immediate or background fetch with
different backoff policy.
Bug: 867488
Change-Id: If41abed1f85781cf84b9038f600e0a94c6c1524c
Reviewed-on: https://chromium-review.googlesource.com/c/1263053
Commit-Queue: Jian Li <jianli@chromium.org>
Reviewed-by: Justin DeWitt <dewittj@chromium.org>
Cr-Commit-Position: refs/heads/master@{#597231}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBackgroundTask.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBackgroundTask.java
index c4c2b87..2fefb64 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBackgroundTask.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBackgroundTask.java
@@ -65,8 +65,8 @@
}
mTaskFinishedCallback = callback;
- ExploreSitesBridge.updateCatalogFromNetwork(
- getProfile(), (ignored) -> mTaskFinishedCallback.taskFinished(false));
+ ExploreSitesBridge.updateCatalogFromNetwork(getProfile(), false /*isImmediateFetch*/,
+ (ignored) -> mTaskFinishedCallback.taskFinished(false));
}
@Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java
index 97b4f2d..35a00985 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java
@@ -48,8 +48,8 @@
* Causes a network request for updating the catalog.
*/
public static void updateCatalogFromNetwork(
- Profile profile, Callback<Boolean> finishedCallback) {
- nativeUpdateCatalogFromNetwork(profile, finishedCallback);
+ Profile profile, boolean isImmediateFetch, Callback<Boolean> finishedCallback) {
+ nativeUpdateCatalogFromNetwork(profile, isImmediateFetch, finishedCallback);
}
/**
@@ -73,5 +73,5 @@
Profile profile, int siteID, Callback<Bitmap> callback);
private static native void nativeUpdateCatalogFromNetwork(
- Profile profile, Callback<Boolean> callback);
+ Profile profile, boolean isImmediateFetch, Callback<Boolean> callback);
}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java
index b573acc..d5799a5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java
@@ -121,8 +121,8 @@
*/
private void gotEspCatalog(List<ExploreSitesCategory> categoryList) {
if (categoryList == null || categoryList.size() == 0) {
- ExploreSitesBridge.updateCatalogFromNetwork(
- mProfile, (Boolean success) -> { updateCategoryIcons(); });
+ ExploreSitesBridge.updateCatalogFromNetwork(mProfile, true /*isImmediateFetch*/,
+ (Boolean success) -> { updateCategoryIcons(); });
}
// Initialize with defaults right away.
initializeCategoryTiles(categoryList);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBackgroundTaskUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBackgroundTaskUnitTest.java
index 274cf44..a3b70ed 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBackgroundTaskUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBackgroundTaskUnitTest.java
@@ -68,7 +68,7 @@
@Implementation
public static void updateCatalogFromNetwork(
- Profile profile, Callback<Void> finishedCallback) {
+ Profile profile, boolean isImmediateFetch, Callback<Void> finishedCallback) {
mUpdateCatalogFinishedCallback = finishedCallback;
}
}
diff --git a/chrome/browser/android/explore_sites/explore_sites_bridge.cc b/chrome/browser/android/explore_sites/explore_sites_bridge.cc
index 7da3aab..e2dfde387 100644
--- a/chrome/browser/android/explore_sites/explore_sites_bridge.cc
+++ b/chrome/browser/android/explore_sites/explore_sites_bridge.cc
@@ -142,6 +142,7 @@
JNIEnv* env,
const JavaParamRef<jclass>& j_caller,
const JavaParamRef<jobject>& j_profile,
+ jboolean is_immediate_fetch,
const JavaParamRef<jobject>& j_callback_obj) {
Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
DCHECK(profile);
@@ -163,7 +164,7 @@
}
service->UpdateCatalogFromNetwork(
- accept_languages,
+ static_cast<bool>(is_immediate_fetch), accept_languages,
base::BindOnce(&UpdateCatalogDone,
ScopedJavaGlobalRef<jobject>(j_callback_obj)));
}
diff --git a/chrome/browser/android/explore_sites/explore_sites_fetcher.cc b/chrome/browser/android/explore_sites/explore_sites_fetcher.cc
index 87c5094..7adf18d6 100644
--- a/chrome/browser/android/explore_sites/explore_sites_fetcher.cc
+++ b/chrome/browser/android/explore_sites/explore_sites_fetcher.cc
@@ -91,66 +91,101 @@
} // namespace
+const net::BackoffEntry::Policy
+ ExploreSitesFetcher::kImmediateFetchBackoffPolicy = {
+ 0, // Number of initial errors to ignore without backoff.
+ 1 * 1000, // Initial delay for backoff in ms: 1 second.
+ 2, // Factor to multiply for exponential backoff.
+ 0, // Fuzzing percentage.
+ 4 * 1000, // Maximum time to delay requests in ms: 4 seconds.
+ -1, // Don't discard entry even if unused.
+ false // Don't use initial delay unless the last was an error.
+};
+const int ExploreSitesFetcher::kMaxFailureCountForImmediateFetch = 3;
+
+const net::BackoffEntry::Policy
+ ExploreSitesFetcher::kBackgroundFetchBackoffPolicy = {
+ 0, // Number of initial errors to ignore without backoff.
+ 5 * 1000, // Initial delay for backoff in ms: 5 seconds.
+ 2, // Factor to multiply for exponential backoff.
+ 0, // Fuzzing percentage.
+ 320 * 1000, // Maximum time to delay requests in ms: 320 seconds.
+ -1, // Don't discard entry even if unused.
+ false // Don't use initial delay unless the last was an error.
+};
+const int ExploreSitesFetcher::kMaxFailureCountForBackgroundFetch = 7;
+
std::unique_ptr<ExploreSitesFetcher> ExploreSitesFetcher::CreateForGetCatalog(
- Callback callback,
- const std::string catalog_version,
- const std::string accept_languages,
- scoped_refptr<network::SharedURLLoaderFactory> loader_factory) {
+ bool is_immediate_fetch,
+ const std::string& catalog_version,
+ const std::string& accept_languages,
+ scoped_refptr<network::SharedURLLoaderFactory> loader_factory,
+ Callback callback) {
GURL url = GetCatalogURL();
- return base::WrapUnique(
- new ExploreSitesFetcher(std::move(callback), url, catalog_version,
- accept_languages, loader_factory));
+ return base::WrapUnique(new ExploreSitesFetcher(
+ is_immediate_fetch, url, catalog_version, accept_languages,
+ loader_factory, std::move(callback)));
}
std::unique_ptr<ExploreSitesFetcher>
ExploreSitesFetcher::CreateForGetCategories(
- Callback callback,
- const std::string catalog_version,
- const std::string accept_languages,
- scoped_refptr<network::SharedURLLoaderFactory> loader_factory) {
+ bool is_immediate_fetch,
+ const std::string& catalog_version,
+ const std::string& accept_languages,
+ scoped_refptr<network::SharedURLLoaderFactory> loader_factory,
+ Callback callback) {
GURL url = GetCategoriesURL();
- return base::WrapUnique(
- new ExploreSitesFetcher(std::move(callback), url, catalog_version,
- accept_languages, loader_factory));
+ return base::WrapUnique(new ExploreSitesFetcher(
+ is_immediate_fetch, url, catalog_version, accept_languages,
+ loader_factory, std::move(callback)));
}
ExploreSitesFetcher::ExploreSitesFetcher(
- Callback callback,
+ bool is_immediate_fetch,
const GURL& url,
- const std::string catalog_version,
- const std::string accept_languages,
- scoped_refptr<network::SharedURLLoaderFactory> loader_factory)
- : callback_(std::move(callback)),
+ const std::string& catalog_version,
+ const std::string& accept_languages,
+ scoped_refptr<network::SharedURLLoaderFactory> loader_factory,
+ Callback callback)
+ : accept_languages_(accept_languages),
+ backoff_entry_(is_immediate_fetch ? &kImmediateFetchBackoffPolicy
+ : &kBackgroundFetchBackoffPolicy),
+ max_failure_count_(is_immediate_fetch
+ ? kMaxFailureCountForImmediateFetch
+ : kMaxFailureCountForBackgroundFetch),
+ callback_(std::move(callback)),
url_loader_factory_(loader_factory),
weak_factory_(this) {
base::Version version = version_info::GetVersion();
std::string channel_name = chrome::GetChannelName();
- std::string client_version =
- base::StringPrintf("%d.%d.%d.%s.chrome",
- version.components()[0], // Major
- version.components()[2], // Build
- version.components()[3], // Patch
- channel_name.c_str());
- GURL final_url =
+ client_version_ = base::StringPrintf("%d.%d.%d.%s.chrome",
+ version.components()[0], // Major
+ version.components()[2], // Build
+ version.components()[3], // Patch
+ channel_name.c_str());
+ request_url_ =
net::AppendOrReplaceQueryParameter(url, "country_code", GetCountry());
- final_url = net::AppendOrReplaceQueryParameter(final_url, "version_token",
- catalog_version);
- DVLOG(1) << "Final URL: " << final_url.spec();
+ request_url_ = net::AppendOrReplaceQueryParameter(
+ request_url_, "version_token", catalog_version);
+}
+ExploreSitesFetcher::~ExploreSitesFetcher() {}
+
+void ExploreSitesFetcher::Start() {
auto resource_request = std::make_unique<network::ResourceRequest>();
- resource_request->url = final_url;
+ resource_request->url = request_url_;
resource_request->method = kRequestMethod;
bool is_stable_channel =
chrome::GetChannel() == version_info::Channel::STABLE;
std::string api_key = is_stable_channel ? google_apis::GetAPIKey()
: google_apis::GetNonStableAPIKey();
resource_request->headers.SetHeader("x-goog-api-key", api_key);
- resource_request->headers.SetHeader("X-Client-Version", client_version);
+ resource_request->headers.SetHeader("X-Client-Version", client_version_);
resource_request->headers.SetHeader(net::HttpRequestHeaders::kContentType,
kRequestContentType);
- if (!accept_languages.empty()) {
+ if (!accept_languages_.empty()) {
resource_request->headers.SetHeader(
- net::HttpRequestHeaders::kAcceptLanguage, accept_languages);
+ net::HttpRequestHeaders::kAcceptLanguage, accept_languages_);
}
// Get field trial value, if any.
@@ -169,15 +204,19 @@
weak_factory_.GetWeakPtr()));
}
-ExploreSitesFetcher::~ExploreSitesFetcher() {}
-
void ExploreSitesFetcher::OnSimpleLoaderComplete(
std::unique_ptr<std::string> response_body) {
ExploreSitesRequestStatus status = HandleResponseCode();
if (response_body && response_body->empty()) {
DVLOG(1) << "Failed to get response or empty response";
- status = ExploreSitesRequestStatus::kShouldRetry;
+ status = ExploreSitesRequestStatus::kFailure;
+ }
+
+ if (status == ExploreSitesRequestStatus::kFailure &&
+ !disable_retry_for_testing_) {
+ RetryWithBackoff();
+ return;
}
std::move(callback_).Run(status, std::move(response_body));
@@ -193,18 +232,33 @@
DVLOG(1) << "Net error: " << net_error;
return (net_error == net::ERR_BLOCKED_BY_ADMINISTRATOR)
? ExploreSitesRequestStatus::kShouldSuspendBlockedByAdministrator
- : ExploreSitesRequestStatus::kShouldRetry;
+ : ExploreSitesRequestStatus::kFailure;
} else if (response_code < 200 || response_code > 299) {
DVLOG(1) << "HTTP status: " << response_code;
switch (response_code) {
case net::HTTP_BAD_REQUEST:
return ExploreSitesRequestStatus::kShouldSuspendBadRequest;
default:
- return ExploreSitesRequestStatus::kShouldRetry;
+ return ExploreSitesRequestStatus::kFailure;
}
}
return ExploreSitesRequestStatus::kSuccess;
}
+void ExploreSitesFetcher::RetryWithBackoff() {
+ backoff_entry_.InformOfRequest(false);
+
+ if (backoff_entry_.failure_count() >= max_failure_count_) {
+ std::move(callback_).Run(ExploreSitesRequestStatus::kFailure,
+ std::unique_ptr<std::string>());
+ return;
+ }
+
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&ExploreSitesFetcher::Start, weak_factory_.GetWeakPtr()),
+ backoff_entry_.GetTimeUntilRelease());
+}
+
} // namespace explore_sites
diff --git a/chrome/browser/android/explore_sites/explore_sites_fetcher.h b/chrome/browser/android/explore_sites/explore_sites_fetcher.h
index 0f319d20..8b331dd 100644
--- a/chrome/browser/android/explore_sites/explore_sites_fetcher.h
+++ b/chrome/browser/android/explore_sites/explore_sites_fetcher.h
@@ -12,6 +12,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/android/explore_sites/explore_sites_types.h"
+#include "net/base/backoff_entry.h"
namespace network {
class SimpleURLLoader;
@@ -29,38 +30,62 @@
base::OnceCallback<void(ExploreSitesRequestStatus status,
const std::unique_ptr<std::string> data)>;
+ static const net::BackoffEntry::Policy kImmediateFetchBackoffPolicy;
+ static const int kMaxFailureCountForImmediateFetch;
+ static const net::BackoffEntry::Policy kBackgroundFetchBackoffPolicy;
+ static const int kMaxFailureCountForBackgroundFetch;
+
// Creates a fetcher for the GetCatalog RPC.
static std::unique_ptr<ExploreSitesFetcher> CreateForGetCatalog(
- Callback callback,
- const std::string catalog_version,
- const std::string accept_languages,
- scoped_refptr<network::SharedURLLoaderFactory> loader_factory);
+ bool is_immediate_fetch,
+ const std::string& catalog_version,
+ const std::string& accept_languages,
+ scoped_refptr<network::SharedURLLoaderFactory> loader_factory,
+ Callback callback);
// Creates a fetcher for the GetCategories RPC.
static std::unique_ptr<ExploreSitesFetcher> CreateForGetCategories(
- Callback callback,
- const std::string catalog_version,
- const std::string accept_languages,
- scoped_refptr<network::SharedURLLoaderFactory> loader_factory);
+ bool is_immediate_fetch,
+ const std::string& catalog_version,
+ const std::string& accept_languages,
+ scoped_refptr<network::SharedURLLoaderFactory> loader_factory,
+ Callback callback);
~ExploreSitesFetcher();
+ void Start();
+
+ void disable_retry_for_testing() { disable_retry_for_testing_ = true; }
+
private:
explicit ExploreSitesFetcher(
- Callback callback,
+ bool is_immediate_fetch,
const GURL& url,
- const std::string catalog_version,
- const std::string accept_languages,
- scoped_refptr<network ::SharedURLLoaderFactory> loader_factory);
+ const std::string& catalog_version,
+ const std::string& accept_languages,
+ scoped_refptr<network ::SharedURLLoaderFactory> loader_factory,
+ Callback callback);
// Invoked from SimpleURLLoader after download is complete.
void OnSimpleLoaderComplete(std::unique_ptr<std::string> response_body);
ExploreSitesRequestStatus HandleResponseCode();
+ void RetryWithBackoff();
+
+ std::string accept_languages_;
+ std::string client_version_;
+ GURL request_url_;
+
+ net::BackoffEntry backoff_entry_;
+ int max_failure_count_;
+ bool disable_retry_for_testing_ = false;
+
Callback callback_;
+
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
std::unique_ptr<network::SimpleURLLoader> url_loader_;
+
base::WeakPtrFactory<ExploreSitesFetcher> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ExploreSitesFetcher);
diff --git a/chrome/browser/android/explore_sites/explore_sites_fetcher_unittest.cc b/chrome/browser/android/explore_sites/explore_sites_fetcher_unittest.cc
index f110f12..d720b85 100644
--- a/chrome/browser/android/explore_sites/explore_sites_fetcher_unittest.cc
+++ b/chrome/browser/android/explore_sites/explore_sites_fetcher_unittest.cc
@@ -36,6 +36,7 @@
const char kAcceptLanguages[] = "en-US,en;q=0.5";
const char kCountryOverride[] = "country_override";
const char kExperimentData[] = "FooBar";
+const char kTestData[] = "Any data.";
} // namespace
namespace explore_sites {
@@ -52,6 +53,16 @@
net::HttpStatusCode http_error);
ExploreSitesRequestStatus RunFetcherWithData(const std::string& response_data,
std::string* data_received);
+ ExploreSitesRequestStatus RunFetcherWithBackoffs(
+ bool is_immediate_fetch,
+ size_t num_of_backoffs,
+ std::vector<base::TimeDelta> backoff_delays,
+ std::vector<base::OnceCallback<void(void)>> respond_callbacks,
+ std::string* data_received);
+
+ void RespondWithData(const std::string& data);
+ void RespondWithNetError(int net_error);
+ void RespondWithHttpError(net::HttpStatusCode http_error);
void SetUpExperimentOption(std::string option, std::string data) {
const std::string kTrialName = "trial_name";
@@ -77,12 +88,11 @@
ExploreSitesFetcher::Callback StoreResult();
network::TestURLLoaderFactory::PendingRequest* GetPendingRequest(
size_t index);
+ std::unique_ptr<ExploreSitesFetcher> CreateFetcher(bool disable_retry,
+ bool is_immediate_fetch);
ExploreSitesRequestStatus RunFetcher(
base::OnceCallback<void(void)> respond_callback,
std::string* data_received);
- void RespondWithData(const std::string& data);
- void RespondWithNetError(int net_error);
- void RespondWithHttpError(net::HttpStatusCode http_error);
network::TestURLLoaderFactory test_url_loader_factory_;
scoped_refptr<network::SharedURLLoaderFactory>
@@ -192,9 +202,7 @@
base::OnceCallback<void(void)> respond_callback,
std::string* data_received) {
std::unique_ptr<ExploreSitesFetcher> fetcher =
- ExploreSitesFetcher::CreateForGetCatalog(StoreResult(), "123",
- kAcceptLanguages,
- test_shared_url_loader_factory_);
+ CreateFetcher(true /* disable_retry*/, true /*is_immediate_fetch*/);
std::move(respond_callback).Run();
task_runner_->RunUntilIdle();
@@ -204,19 +212,60 @@
return last_status_;
}
+ExploreSitesRequestStatus ExploreSitesFetcherTest::RunFetcherWithBackoffs(
+ bool is_immediate_fetch,
+ size_t num_of_backoffs,
+ std::vector<base::TimeDelta> backoff_delays,
+ std::vector<base::OnceCallback<void(void)>> respond_callbacks,
+ std::string* data_received) {
+ DCHECK_EQ(num_of_backoffs, backoff_delays.size());
+ DCHECK(num_of_backoffs <= respond_callbacks.size() &&
+ respond_callbacks.size() <= num_of_backoffs + 1);
+
+ std::unique_ptr<ExploreSitesFetcher> fetcher =
+ CreateFetcher(false /* disable_retry*/, is_immediate_fetch);
+
+ std::move(respond_callbacks[0]).Run();
+ task_runner_->RunUntilIdle();
+
+ for (size_t i = 0; i < num_of_backoffs; ++i) {
+ task_runner_->FastForwardBy(backoff_delays[i]);
+ if (i + 1 <= respond_callbacks.size() - 1)
+ std::move(respond_callbacks[i + 1]).Run();
+ task_runner_->RunUntilIdle();
+ }
+
+ if (last_data_)
+ *data_received = *last_data_;
+ return last_status_;
+}
+
+std::unique_ptr<ExploreSitesFetcher> ExploreSitesFetcherTest::CreateFetcher(
+ bool disable_retry,
+ bool is_immediate_fetch) {
+ std::unique_ptr<ExploreSitesFetcher> fetcher =
+ ExploreSitesFetcher::CreateForGetCatalog(
+ is_immediate_fetch, "123", kAcceptLanguages,
+ test_shared_url_loader_factory_, StoreResult());
+ if (disable_retry)
+ fetcher->disable_retry_for_testing();
+ fetcher->Start();
+ return fetcher;
+}
+
TEST_F(ExploreSitesFetcherTest, NetErrors) {
EXPECT_EQ(ExploreSitesRequestStatus::kShouldSuspendBlockedByAdministrator,
RunFetcherWithNetError(net::ERR_BLOCKED_BY_ADMINISTRATOR));
- EXPECT_EQ(ExploreSitesRequestStatus::kShouldRetry,
+ EXPECT_EQ(ExploreSitesRequestStatus::kFailure,
RunFetcherWithNetError(net::ERR_INTERNET_DISCONNECTED));
- EXPECT_EQ(ExploreSitesRequestStatus::kShouldRetry,
+ EXPECT_EQ(ExploreSitesRequestStatus::kFailure,
RunFetcherWithNetError(net::ERR_NETWORK_CHANGED));
- EXPECT_EQ(ExploreSitesRequestStatus::kShouldRetry,
+ EXPECT_EQ(ExploreSitesRequestStatus::kFailure,
RunFetcherWithNetError(net::ERR_CONNECTION_RESET));
- EXPECT_EQ(ExploreSitesRequestStatus::kShouldRetry,
+ EXPECT_EQ(ExploreSitesRequestStatus::kFailure,
RunFetcherWithNetError(net::ERR_CONNECTION_CLOSED));
- EXPECT_EQ(ExploreSitesRequestStatus::kShouldRetry,
+ EXPECT_EQ(ExploreSitesRequestStatus::kFailure,
RunFetcherWithNetError(net::ERR_CONNECTION_REFUSED));
}
@@ -224,37 +273,35 @@
EXPECT_EQ(ExploreSitesRequestStatus::kShouldSuspendBadRequest,
RunFetcherWithHttpError(net::HTTP_BAD_REQUEST));
- EXPECT_EQ(ExploreSitesRequestStatus::kShouldRetry,
+ EXPECT_EQ(ExploreSitesRequestStatus::kFailure,
RunFetcherWithHttpError(net::HTTP_NOT_IMPLEMENTED));
- EXPECT_EQ(ExploreSitesRequestStatus::kShouldRetry,
+ EXPECT_EQ(ExploreSitesRequestStatus::kFailure,
RunFetcherWithHttpError(net::HTTP_UNAUTHORIZED));
- EXPECT_EQ(ExploreSitesRequestStatus::kShouldRetry,
+ EXPECT_EQ(ExploreSitesRequestStatus::kFailure,
RunFetcherWithHttpError(net::HTTP_NOT_FOUND));
- EXPECT_EQ(ExploreSitesRequestStatus::kShouldRetry,
+ EXPECT_EQ(ExploreSitesRequestStatus::kFailure,
RunFetcherWithHttpError(net::HTTP_CONFLICT));
- EXPECT_EQ(ExploreSitesRequestStatus::kShouldRetry,
+ EXPECT_EQ(ExploreSitesRequestStatus::kFailure,
RunFetcherWithHttpError(net::HTTP_INTERNAL_SERVER_ERROR));
- EXPECT_EQ(ExploreSitesRequestStatus::kShouldRetry,
+ EXPECT_EQ(ExploreSitesRequestStatus::kFailure,
RunFetcherWithHttpError(net::HTTP_BAD_GATEWAY));
- EXPECT_EQ(ExploreSitesRequestStatus::kShouldRetry,
+ EXPECT_EQ(ExploreSitesRequestStatus::kFailure,
RunFetcherWithHttpError(net::HTTP_SERVICE_UNAVAILABLE));
- EXPECT_EQ(ExploreSitesRequestStatus::kShouldRetry,
+ EXPECT_EQ(ExploreSitesRequestStatus::kFailure,
RunFetcherWithHttpError(net::HTTP_GATEWAY_TIMEOUT));
}
TEST_F(ExploreSitesFetcherTest, EmptyResponse) {
std::string data;
- EXPECT_EQ(ExploreSitesRequestStatus::kShouldRetry,
- RunFetcherWithData("", &data));
+ EXPECT_EQ(ExploreSitesRequestStatus::kFailure, RunFetcherWithData("", &data));
EXPECT_TRUE(data.empty());
}
TEST_F(ExploreSitesFetcherTest, Success) {
std::string data;
EXPECT_EQ(ExploreSitesRequestStatus::kSuccess,
- RunFetcherWithData("Any data.", &data));
- EXPECT_FALSE(data.empty());
- EXPECT_EQ(data, "Any data.");
+ RunFetcherWithData(kTestData, &data));
+ EXPECT_EQ(kTestData, data);
EXPECT_EQ(last_resource_request.url.spec(),
"https://exploresites-pa.googleapis.com/v1/"
@@ -265,9 +312,8 @@
SetUpExperimentOption(kCountryOverride, "KZ");
std::string data;
EXPECT_EQ(ExploreSitesRequestStatus::kSuccess,
- RunFetcherWithData("Any data.", &data));
- EXPECT_FALSE(data.empty());
- EXPECT_EQ(data, "Any data.");
+ RunFetcherWithData(kTestData, &data));
+ EXPECT_EQ(kTestData, data);
EXPECT_EQ(last_resource_request.url.spec(),
"https://exploresites-pa.googleapis.com/v1/"
@@ -277,7 +323,7 @@
TEST_F(ExploreSitesFetcherTest, TestHeaders) {
std::string data;
EXPECT_EQ(ExploreSitesRequestStatus::kSuccess,
- RunFetcherWithData("Any data.", &data));
+ RunFetcherWithData(kTestData, &data));
net::HttpRequestHeaders headers = last_resource_request.headers;
std::string content_type;
@@ -311,7 +357,7 @@
std::string data;
EXPECT_EQ(ExploreSitesRequestStatus::kSuccess,
- RunFetcherWithData("Any data.", &data));
+ RunFetcherWithData(kTestData, &data));
net::HttpRequestHeaders headers = last_resource_request.headers;
std::string header_text;
@@ -321,4 +367,136 @@
EXPECT_EQ(std::string(kExperimentData), header_text);
}
+TEST_F(ExploreSitesFetcherTest, OneBackoffForImmediateFetch) {
+ std::string data;
+ int initial_delay_ms =
+ ExploreSitesFetcher::kImmediateFetchBackoffPolicy.initial_delay_ms;
+ std::vector<base::TimeDelta> backoff_delays = {
+ base::TimeDelta::FromMilliseconds(initial_delay_ms)};
+ std::vector<base::OnceCallback<void(void)>> respond_callbacks;
+ respond_callbacks.push_back(
+ base::BindOnce(&ExploreSitesFetcherTest::RespondWithNetError,
+ base::Unretained(this), net::ERR_INTERNET_DISCONNECTED));
+ respond_callbacks.push_back(
+ base::BindOnce(&ExploreSitesFetcherTest::RespondWithData,
+ base::Unretained(this), kTestData));
+ EXPECT_EQ(
+ ExploreSitesRequestStatus::kSuccess,
+ RunFetcherWithBackoffs(true /*is_immediate_fetch*/, 1u, backoff_delays,
+ std::move(respond_callbacks), &data));
+ EXPECT_EQ(kTestData, data);
+}
+
+TEST_F(ExploreSitesFetcherTest, OneBackoffForBackgroundFetch) {
+ std::string data;
+ int initial_delay_ms =
+ ExploreSitesFetcher::kBackgroundFetchBackoffPolicy.initial_delay_ms;
+ std::vector<base::TimeDelta> backoff_delays = {
+ base::TimeDelta::FromMilliseconds(initial_delay_ms)};
+ std::vector<base::OnceCallback<void(void)>> respond_callbacks;
+ respond_callbacks.push_back(
+ base::BindOnce(&ExploreSitesFetcherTest::RespondWithNetError,
+ base::Unretained(this), net::ERR_INTERNET_DISCONNECTED));
+ respond_callbacks.push_back(
+ base::BindOnce(&ExploreSitesFetcherTest::RespondWithData,
+ base::Unretained(this), kTestData));
+ EXPECT_EQ(
+ ExploreSitesRequestStatus::kSuccess,
+ RunFetcherWithBackoffs(false /*is_immediate_fetch*/, 1u, backoff_delays,
+ std::move(respond_callbacks), &data));
+ EXPECT_EQ(kTestData, data);
+}
+
+TEST_F(ExploreSitesFetcherTest, TwoBackoffsForImmediateFetch) {
+ std::string data;
+ int initial_delay_ms =
+ ExploreSitesFetcher::kImmediateFetchBackoffPolicy.initial_delay_ms;
+ std::vector<base::TimeDelta> backoff_delays = {
+ base::TimeDelta::FromMilliseconds(initial_delay_ms),
+ base::TimeDelta::FromMilliseconds(initial_delay_ms * 2)};
+ std::vector<base::OnceCallback<void(void)>> respond_callbacks;
+ respond_callbacks.push_back(
+ base::BindOnce(&ExploreSitesFetcherTest::RespondWithNetError,
+ base::Unretained(this), net::ERR_INTERNET_DISCONNECTED));
+ respond_callbacks.push_back(
+ base::BindOnce(&ExploreSitesFetcherTest::RespondWithHttpError,
+ base::Unretained(this), net::HTTP_INTERNAL_SERVER_ERROR));
+ respond_callbacks.push_back(
+ base::BindOnce(&ExploreSitesFetcherTest::RespondWithData,
+ base::Unretained(this), kTestData));
+ EXPECT_EQ(
+ ExploreSitesRequestStatus::kSuccess,
+ RunFetcherWithBackoffs(true /*is_immediate_fetch*/, 2u, backoff_delays,
+ std::move(respond_callbacks), &data));
+ EXPECT_EQ(kTestData, data);
+}
+
+TEST_F(ExploreSitesFetcherTest, TwoBackoffsForBackgroundFetch) {
+ std::string data;
+ int initial_delay_ms =
+ ExploreSitesFetcher::kBackgroundFetchBackoffPolicy.initial_delay_ms;
+ std::vector<base::TimeDelta> backoff_delays = {
+ base::TimeDelta::FromMilliseconds(initial_delay_ms),
+ base::TimeDelta::FromMilliseconds(initial_delay_ms * 2)};
+ std::vector<base::OnceCallback<void(void)>> respond_callbacks;
+ respond_callbacks.push_back(
+ base::BindOnce(&ExploreSitesFetcherTest::RespondWithNetError,
+ base::Unretained(this), net::ERR_INTERNET_DISCONNECTED));
+ respond_callbacks.push_back(
+ base::BindOnce(&ExploreSitesFetcherTest::RespondWithHttpError,
+ base::Unretained(this), net::HTTP_INTERNAL_SERVER_ERROR));
+ respond_callbacks.push_back(
+ base::BindOnce(&ExploreSitesFetcherTest::RespondWithData,
+ base::Unretained(this), kTestData));
+ EXPECT_EQ(
+ ExploreSitesRequestStatus::kSuccess,
+ RunFetcherWithBackoffs(false /*is_immediate_fetch*/, 2u, backoff_delays,
+ std::move(respond_callbacks), &data));
+ EXPECT_EQ(kTestData, data);
+}
+
+TEST_F(ExploreSitesFetcherTest, ExceedMaxBackoffsForImmediateFetch) {
+ std::string data;
+ int delay_ms =
+ ExploreSitesFetcher::kImmediateFetchBackoffPolicy.initial_delay_ms;
+ std::vector<base::TimeDelta> backoff_delays;
+ std::vector<base::OnceCallback<void(void)>> respond_callbacks;
+ for (int i = 0; i < ExploreSitesFetcher::kMaxFailureCountForImmediateFetch;
+ ++i) {
+ backoff_delays.push_back(base::TimeDelta::FromMilliseconds(delay_ms));
+ delay_ms *= 2;
+ respond_callbacks.push_back(
+ base::BindOnce(&ExploreSitesFetcherTest::RespondWithNetError,
+ base::Unretained(this), net::ERR_INTERNET_DISCONNECTED));
+ }
+ EXPECT_EQ(ExploreSitesRequestStatus::kFailure,
+ RunFetcherWithBackoffs(
+ true /*is_immediate_fetch*/,
+ ExploreSitesFetcher::kMaxFailureCountForImmediateFetch,
+ backoff_delays, std::move(respond_callbacks), &data));
+ EXPECT_TRUE(data.empty());
+}
+
+TEST_F(ExploreSitesFetcherTest, ExceedMaxBackoffsForBackgroundFetch) {
+ std::string data;
+ int delay_ms =
+ ExploreSitesFetcher::kBackgroundFetchBackoffPolicy.initial_delay_ms;
+ std::vector<base::TimeDelta> backoff_delays;
+ std::vector<base::OnceCallback<void(void)>> respond_callbacks;
+ for (int i = 0; i < ExploreSitesFetcher::kMaxFailureCountForBackgroundFetch;
+ ++i) {
+ backoff_delays.push_back(base::TimeDelta::FromMilliseconds(delay_ms));
+ delay_ms *= 2;
+ respond_callbacks.push_back(
+ base::BindOnce(&ExploreSitesFetcherTest::RespondWithNetError,
+ base::Unretained(this), net::ERR_INTERNET_DISCONNECTED));
+ }
+ EXPECT_EQ(ExploreSitesRequestStatus::kFailure,
+ RunFetcherWithBackoffs(
+ false /*is_immediate_fetch*/,
+ ExploreSitesFetcher::kMaxFailureCountForBackgroundFetch,
+ backoff_delays, std::move(respond_callbacks), &data));
+ EXPECT_TRUE(data.empty());
+}
+
} // namespace explore_sites
diff --git a/chrome/browser/android/explore_sites/explore_sites_service.h b/chrome/browser/android/explore_sites/explore_sites_service.h
index 9bdd70a..c3558a3 100644
--- a/chrome/browser/android/explore_sites/explore_sites_service.h
+++ b/chrome/browser/android/explore_sites/explore_sites_service.h
@@ -30,9 +30,12 @@
virtual void GetSiteImage(int site_id, BitmapCallback callback) = 0;
// Fetch the latest catalog from the network and stores it locally. Returns
- // true in the callback for success. If the accept_languages string is empty,
- // no "Accept-Language" header is created for the network request.
- virtual void UpdateCatalogFromNetwork(std::string accept_languages,
+ // true in the callback for success. |is_immediate_fetch| denotes if the
+ // fetch should be done immediately or on background. If the accept_languages
+ // string is empty, no "Accept-Language" header is created for the network
+ // request.
+ virtual void UpdateCatalogFromNetwork(bool is_immediate_fetch,
+ const std::string& accept_languages,
BooleanCallback callback) = 0;
};
diff --git a/chrome/browser/android/explore_sites/explore_sites_service_impl.cc b/chrome/browser/android/explore_sites/explore_sites_service_impl.cc
index cd46955..a47e0b0 100644
--- a/chrome/browser/android/explore_sites/explore_sites_service_impl.cc
+++ b/chrome/browser/android/explore_sites/explore_sites_service_impl.cc
@@ -79,7 +79,8 @@
}
void ExploreSitesServiceImpl::UpdateCatalogFromNetwork(
- std::string accept_languages,
+ bool is_immediate_fetch,
+ const std::string& accept_languages,
BooleanCallback callback) {
if (!IsExploreSitesEnabled())
return;
@@ -92,9 +93,11 @@
// Create a fetcher and start fetching the protobuf (async).
explore_sites_fetcher_ = ExploreSitesFetcher::CreateForGetCatalog(
+ is_immediate_fetch, catalog_version, accept_languages,
+ url_loader_factory_,
base::BindOnce(&ExploreSitesServiceImpl::OnCatalogFetched,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
- catalog_version, accept_languages, url_loader_factory_);
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+ explore_sites_fetcher_->Start();
}
void ExploreSitesServiceImpl::OnCatalogFetched(
diff --git a/chrome/browser/android/explore_sites/explore_sites_service_impl.h b/chrome/browser/android/explore_sites/explore_sites_service_impl.h
index 3b51b94..46eeaa4 100644
--- a/chrome/browser/android/explore_sites/explore_sites_service_impl.h
+++ b/chrome/browser/android/explore_sites/explore_sites_service_impl.h
@@ -36,7 +36,8 @@
void GetCatalog(CatalogCallback callback) override;
void GetCategoryImage(int category_id, BitmapCallback callback) override;
void GetSiteImage(int site_id, BitmapCallback callback) override;
- void UpdateCatalogFromNetwork(std::string accept_languages,
+ void UpdateCatalogFromNetwork(bool is_immediate_fetch,
+ const std::string& accept_languages,
BooleanCallback callback) override;
private:
diff --git a/chrome/browser/android/explore_sites/explore_sites_service_impl_unittest.cc b/chrome/browser/android/explore_sites/explore_sites_service_impl_unittest.cc
index d035698..aa0f171 100644
--- a/chrome/browser/android/explore_sites/explore_sites_service_impl_unittest.cc
+++ b/chrome/browser/android/explore_sites/explore_sites_service_impl_unittest.cc
@@ -158,7 +158,7 @@
scoped_feature_list.InitAndEnableFeature(chrome::android::kExploreSites);
service()->UpdateCatalogFromNetwork(
- kAcceptLanguages,
+ true /*is_immediate_fetch*/, kAcceptLanguages,
base::BindOnce(&ExploreSitesServiceImplTest::UpdateCatalogDoneCallback,
base::Unretained(this)));
diff --git a/chrome/browser/android/explore_sites/explore_sites_types.h b/chrome/browser/android/explore_sites/explore_sites_types.h
index 1956db0..185906c 100644
--- a/chrome/browser/android/explore_sites/explore_sites_types.h
+++ b/chrome/browser/android/explore_sites/explore_sites_types.h
@@ -69,8 +69,8 @@
enum class ExploreSitesRequestStatus {
// Request completed successfully.
kSuccess = 0,
- // Request failed due to to local network problem, caller should retry.
- kShouldRetry = 1,
+ // Request failed even after all the retries.
+ kFailure = 1,
// Request failed with error indicating that the request can not be serviced
// by the server.
kShouldSuspendBadRequest = 2,