Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(101)

Side by Side Diff: components/ntp_snippets/remote/ntp_snippets_fetcher_unittest.cc

Issue 2548343002: NTPSnippets: Set MaxRetriesOn5xx only for interactive requests. (Closed)
Patch Set: Rebased. Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « components/ntp_snippets/remote/ntp_snippets_fetcher.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/ntp_snippets/remote/ntp_snippets_fetcher.h" 5 #include "components/ntp_snippets/remote/ntp_snippets_fetcher.h"
6 6
7 #include <deque>
7 #include <map> 8 #include <map>
8 #include <utility> 9 #include <utility>
9 10
10 #include "base/json/json_reader.h" 11 #include "base/json/json_reader.h"
11 #include "base/memory/ptr_util.h" 12 #include "base/memory/ptr_util.h"
12 #include "base/strings/stringprintf.h" 13 #include "base/strings/stringprintf.h"
13 #include "base/test/histogram_tester.h" 14 #include "base/test/histogram_tester.h"
14 #include "base/test/test_mock_time_task_runner.h" 15 #include "base/test/test_mock_time_task_runner.h"
15 #include "base/threading/thread_task_runner_handle.h" 16 #include "base/threading/thread_task_runner_handle.h"
16 #include "base/time/time.h" 17 #include "base/time/time.h"
17 #include "base/values.h" 18 #include "base/values.h"
18 #include "components/ntp_snippets/category_factory.h" 19 #include "components/ntp_snippets/category_factory.h"
20 #include "components/ntp_snippets/features.h"
19 #include "components/ntp_snippets/ntp_snippets_constants.h" 21 #include "components/ntp_snippets/ntp_snippets_constants.h"
20 #include "components/ntp_snippets/remote/ntp_snippet.h" 22 #include "components/ntp_snippets/remote/ntp_snippet.h"
21 #include "components/ntp_snippets/user_classifier.h" 23 #include "components/ntp_snippets/user_classifier.h"
22 #include "components/prefs/testing_pref_service.h" 24 #include "components/prefs/testing_pref_service.h"
23 #include "components/signin/core/browser/account_tracker_service.h" 25 #include "components/signin/core/browser/account_tracker_service.h"
24 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h" 26 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
25 #include "components/signin/core/browser/fake_signin_manager.h" 27 #include "components/signin/core/browser/fake_signin_manager.h"
26 #include "components/signin/core/browser/test_signin_client.h" 28 #include "components/signin/core/browser/test_signin_client.h"
27 #include "components/variations/entropy_provider.h" 29 #include "components/variations/entropy_provider.h"
28 #include "components/variations/variations_params_manager.h" 30 #include "components/variations/variations_params_manager.h"
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
153 NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories) { 155 NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories) {
154 Run(fetch_result, &fetched_categories); 156 Run(fetch_result, &fetched_categories);
155 } 157 }
156 158
157 MOCK_METHOD2( 159 MOCK_METHOD2(
158 Run, 160 Run,
159 void(NTPSnippetsFetcher::FetchResult fetch_result, 161 void(NTPSnippetsFetcher::FetchResult fetch_result,
160 NTPSnippetsFetcher::OptionalFetchedCategories* fetched_categories)); 162 NTPSnippetsFetcher::OptionalFetchedCategories* fetched_categories));
161 }; 163 };
162 164
165 // DelegateCallingTestURLFetcherFactory can be used to temporarily inject
166 // TestURLFetcher instances into a scope.
167 // Client code can access the last created fetcher to verify expected
168 // properties. When the factory gets destroyed, all available delegates of still
169 // valid fetchers will be called.
170 // This ensures once-bound callbacks (like SnippetsAvailableCallback) will be
171 // called at some point and are not leaked.
172 class DelegateCallingTestURLFetcherFactory
173 : public net::TestURLFetcherFactory,
174 public net::TestURLFetcherDelegateForTests {
175 public:
176 DelegateCallingTestURLFetcherFactory() {
177 SetDelegateForTests(this);
178 set_remove_fetcher_on_delete(true);
179 }
180
181 ~DelegateCallingTestURLFetcherFactory() override {
182 while (!fetchers_.empty()) {
183 DropAndCallDelegate(fetchers_.front());
184 }
185 }
186
187 std::unique_ptr<net::URLFetcher> CreateURLFetcher(
188 int id,
189 const GURL& url,
190 net::URLFetcher::RequestType request_type,
191 net::URLFetcherDelegate* d) override {
192 if (GetFetcherByID(id)) {
193 LOG(WARNING) << "The ID " << id << " was already assigned to a fetcher."
194 << "Its delegate will thereforde be called right now.";
195 DropAndCallDelegate(id);
196 }
197 fetchers_.push_back(id);
198 return TestURLFetcherFactory::CreateURLFetcher(id, url, request_type, d);
199 }
200
201 // Returns the raw pointer of the last created URL fetcher.
202 // If it was destroyed or no fetcher was created, it will return a nulltpr.
203 net::TestURLFetcher* GetLastCreatedFetcher() {
204 if (fetchers_.empty()) {
205 return nullptr;
206 }
207 return GetFetcherByID(fetchers_.front());
208 }
209
210 private:
211 // The fetcher can either be destroyed because the delegate was called during
212 // execution or because we called it on destruction.
213 void DropAndCallDelegate(int fetcher_id) {
214 auto found_id_iter =
215 std::find(fetchers_.begin(), fetchers_.end(), fetcher_id);
216 if (found_id_iter == fetchers_.end()) {
217 return;
218 }
219 fetchers_.erase(found_id_iter);
220 net::TestURLFetcher* fetcher = GetFetcherByID(fetcher_id);
221 if (!fetcher || !fetcher->delegate()) {
222 return;
Marc Treib 2016/12/12 10:17:16 When would |fetcher| be null here? Add a comment t
fhorschig 2016/12/12 11:05:10 Removed. It cannot be 0. If it is, crashing is an
223 }
224 fetcher->delegate()->OnURLFetchComplete(fetcher);
225 }
226
227 // net::TestURLFetcherDelegateForTests overrides:
228 void OnRequestStart(int fetcher_id) override {}
229 void OnChunkUpload(int fetcher_id) override {}
230 void OnRequestEnd(int fetcher_id) override {
231 DropAndCallDelegate(fetcher_id);
232 }
233
234 std::deque<int> fetchers_; // std::queue doesn't support std::find.
235 };
236
163 // Factory for FakeURLFetcher objects that always generate errors. 237 // Factory for FakeURLFetcher objects that always generate errors.
164 class FailingFakeURLFetcherFactory : public net::URLFetcherFactory { 238 class FailingFakeURLFetcherFactory : public net::URLFetcherFactory {
165 public: 239 public:
166 std::unique_ptr<net::URLFetcher> CreateURLFetcher( 240 std::unique_ptr<net::URLFetcher> CreateURLFetcher(
167 int id, const GURL& url, net::URLFetcher::RequestType request_type, 241 int id, const GURL& url, net::URLFetcher::RequestType request_type,
168 net::URLFetcherDelegate* d) override { 242 net::URLFetcherDelegate* d) override {
169 return base::MakeUnique<net::FakeURLFetcher>( 243 return base::MakeUnique<net::FakeURLFetcher>(
170 url, d, /*response_data=*/std::string(), net::HTTP_NOT_FOUND, 244 url, d, /*response_data=*/std::string(), net::HTTP_NOT_FOUND,
171 net::URLRequestStatus::FAILED); 245 net::URLRequestStatus::FAILED);
172 } 246 }
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 class RequestBuilderWithMockedFlagsForTesting 278 class RequestBuilderWithMockedFlagsForTesting
205 : public NTPSnippetsFetcher::RequestBuilder { 279 : public NTPSnippetsFetcher::RequestBuilder {
206 public: 280 public:
207 RequestBuilderWithMockedFlagsForTesting() : RequestBuilder() {} 281 RequestBuilderWithMockedFlagsForTesting() : RequestBuilder() {}
208 282
209 private: 283 private:
210 bool IsSendingUserClassEnabled() const override { return true; } 284 bool IsSendingUserClassEnabled() const override { return true; }
211 bool IsSendingTopLanguagesEnabled() const override { return true; } 285 bool IsSendingTopLanguagesEnabled() const override { return true; }
212 }; 286 };
213 287
288 struct ExpectationForVariationParam {
Marc Treib 2016/12/12 10:17:16 nit: Move this into the test that uses it.
fhorschig 2016/12/12 11:05:10 Done.
289 std::string param_value;
290 int expected_value;
291 };
292
214 NTPSnippetsFetcherTest() 293 NTPSnippetsFetcherTest()
215 : NTPSnippetsFetcherTest(GURL(kTestChromeReaderUrl), 294 : NTPSnippetsFetcherTest(GURL(kTestChromeReaderUrl),
216 std::map<std::string, std::string>()) {} 295 std::map<std::string, std::string>()) {}
217 296
218 NTPSnippetsFetcherTest(const GURL& gurl, 297 NTPSnippetsFetcherTest(const GURL& gurl,
219 const std::map<std::string, std::string>& params) 298 const std::map<std::string, std::string>& params)
220 : params_manager_( 299 : params_manager_(
221 base::MakeUnique<variations::testing::VariationParamsManager>( 300 base::MakeUnique<variations::testing::VariationParamsManager>(
222 ntp_snippets::kStudyName, 301 ntp_snippets::kStudyName,
223 params)), 302 params)),
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
285 void SetFetchingPersonalizationVariation( 364 void SetFetchingPersonalizationVariation(
286 const std::string& personalization_string) { 365 const std::string& personalization_string) {
287 params_manager_.reset(); 366 params_manager_.reset();
288 std::map<std::string, std::string> params = { 367 std::map<std::string, std::string> params = {
289 {"fetching_personalization", personalization_string}}; 368 {"fetching_personalization", personalization_string}};
290 params_manager_ = 369 params_manager_ =
291 base::MakeUnique<variations::testing::VariationParamsManager>( 370 base::MakeUnique<variations::testing::VariationParamsManager>(
292 ntp_snippets::kStudyName, params); 371 ntp_snippets::kStudyName, params);
293 } 372 }
294 373
374 void SetVariationParametersForFeatures(
375 const std::map<std::string, std::string>& params,
376 const std::set<std::string>& features) {
377 params_manager_.reset();
378 params_manager_ =
379 base::MakeUnique<variations::testing::VariationParamsManager>(
380 ntp_snippets::kStudyName, params, features);
381 }
382
295 void SetFakeResponse(const std::string& response_data, 383 void SetFakeResponse(const std::string& response_data,
296 net::HttpStatusCode response_code, 384 net::HttpStatusCode response_code,
297 net::URLRequestStatus::Status status) { 385 net::URLRequestStatus::Status status) {
298 InitFakeURLFetcherFactory(); 386 InitFakeURLFetcherFactory();
299 fake_url_fetcher_factory_->SetFakeResponse(test_url_, response_data, 387 fake_url_fetcher_factory_->SetFakeResponse(test_url_, response_data,
300 response_code, status); 388 response_code, status);
301 } 389 }
302 390
303 std::unique_ptr<translate::LanguageModel> MakeLanguageModel( 391 std::unique_ptr<translate::LanguageModel> MakeLanguageModel(
304 const std::vector<std::string>& codes) { 392 const std::vector<std::string>& codes) {
(...skipping 600 matching lines...) Expand 10 before | Expand all | Expand 10 after
905 EXPECT_THAT(snippets_fetcher().last_json(), Eq(kJsonStr)); 993 EXPECT_THAT(snippets_fetcher().last_json(), Eq(kJsonStr));
906 EXPECT_THAT( 994 EXPECT_THAT(
907 histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"), 995 histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"),
908 ElementsAre(base::Bucket(/*min=*/0, /*count=*/1))); 996 ElementsAre(base::Bucket(/*min=*/0, /*count=*/1)));
909 EXPECT_THAT(histogram_tester().GetAllSamples( 997 EXPECT_THAT(histogram_tester().GetAllSamples(
910 "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"), 998 "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"),
911 ElementsAre(base::Bucket(/*min=*/200, /*count=*/1))); 999 ElementsAre(base::Bucket(/*min=*/200, /*count=*/1)));
912 } 1000 }
913 1001
914 TEST_F(NTPSnippetsFetcherTest, ShouldRestrictToHosts) { 1002 TEST_F(NTPSnippetsFetcherTest, ShouldRestrictToHosts) {
915 net::TestURLFetcherFactory test_url_fetcher_factory; 1003 DelegateCallingTestURLFetcherFactory fetcher_factory;
916 NTPSnippetsFetcher::Params params = test_params(); 1004 NTPSnippetsFetcher::Params params = test_params();
917 params.hosts = {"www.somehost1.com", "www.somehost2.com"}; 1005 params.hosts = {"www.somehost1.com", "www.somehost2.com"};
918 params.count_to_fetch = 17; 1006 params.count_to_fetch = 17;
1007
919 snippets_fetcher().FetchSnippets( 1008 snippets_fetcher().FetchSnippets(
920 params, ToSnippetsAvailableCallback(&mock_callback())); 1009 params, ToSnippetsAvailableCallback(&mock_callback()));
921 net::TestURLFetcher* fetcher = test_url_fetcher_factory.GetFetcherByID(0); 1010
1011 net::TestURLFetcher* fetcher = fetcher_factory.GetLastCreatedFetcher();
922 ASSERT_THAT(fetcher, NotNull()); 1012 ASSERT_THAT(fetcher, NotNull());
923 std::unique_ptr<base::Value> value = 1013 std::unique_ptr<base::Value> value =
924 base::JSONReader::Read(fetcher->upload_data()); 1014 base::JSONReader::Read(fetcher->upload_data());
925 ASSERT_TRUE(value) << " failed to parse JSON: " 1015 ASSERT_TRUE(value) << " failed to parse JSON: "
926 << PrintToString(fetcher->upload_data()); 1016 << PrintToString(fetcher->upload_data());
927 const base::DictionaryValue* dict = nullptr; 1017 const base::DictionaryValue* dict = nullptr;
928 ASSERT_TRUE(value->GetAsDictionary(&dict)); 1018 ASSERT_TRUE(value->GetAsDictionary(&dict));
929 const base::DictionaryValue* local_scoring_params = nullptr; 1019 const base::DictionaryValue* local_scoring_params = nullptr;
930 ASSERT_TRUE(dict->GetDictionary("advanced_options.local_scoring_params", 1020 ASSERT_TRUE(dict->GetDictionary("advanced_options.local_scoring_params",
931 &local_scoring_params)); 1021 &local_scoring_params));
932 const base::ListValue* content_selectors = nullptr; 1022 const base::ListValue* content_selectors = nullptr;
933 ASSERT_TRUE( 1023 ASSERT_TRUE(
934 local_scoring_params->GetList("content_selectors", &content_selectors)); 1024 local_scoring_params->GetList("content_selectors", &content_selectors));
935 ASSERT_THAT(content_selectors->GetSize(), Eq(static_cast<size_t>(2))); 1025 ASSERT_THAT(content_selectors->GetSize(), Eq(static_cast<size_t>(2)));
936 const base::DictionaryValue* content_selector = nullptr; 1026 const base::DictionaryValue* content_selector = nullptr;
937 ASSERT_TRUE(content_selectors->GetDictionary(0, &content_selector)); 1027 ASSERT_TRUE(content_selectors->GetDictionary(0, &content_selector));
938 std::string content_selector_value; 1028 std::string content_selector_value;
939 EXPECT_TRUE(content_selector->GetString("value", &content_selector_value)); 1029 EXPECT_TRUE(content_selector->GetString("value", &content_selector_value));
940 EXPECT_THAT(content_selector_value, Eq("www.somehost1.com")); 1030 EXPECT_THAT(content_selector_value, Eq("www.somehost1.com"));
941 ASSERT_TRUE(content_selectors->GetDictionary(1, &content_selector)); 1031 ASSERT_TRUE(content_selectors->GetDictionary(1, &content_selector));
942 EXPECT_TRUE(content_selector->GetString("value", &content_selector_value)); 1032 EXPECT_TRUE(content_selector->GetString("value", &content_selector_value));
943 EXPECT_THAT(content_selector_value, Eq("www.somehost2.com")); 1033 EXPECT_THAT(content_selector_value, Eq("www.somehost2.com"));
944 // Call the delegate callback manually as the TestURLFetcher deletes any 1034 }
945 // call to the delegate that usually happens on |Start|. 1035
946 // Without the call to the delegate, it leaks the request that owns itself. 1036 TEST_F(NTPSnippetsFetcherTest, RetryOnInteractiveRequests) {
947 ASSERT_THAT(fetcher->delegate(), NotNull()); 1037 DelegateCallingTestURLFetcherFactory fetcher_factory;
948 EXPECT_CALL(mock_callback(), 1038 NTPSnippetsFetcher::Params params = test_params();
949 Run(NTPSnippetsFetcher::FetchResult::URL_REQUEST_STATUS_ERROR, 1039 params.interactive_request = true;
950 /*snippets=*/Not(HasValue()))) 1040
951 .Times(1); 1041 snippets_fetcher().FetchSnippets(
952 // An 4XX response needs the least configuration to successfully invoke the 1042 params, ToSnippetsAvailableCallback(&mock_callback()));
953 // callback properly as the results are not important in this test. 1043
954 fetcher->set_response_code(net::HTTP_NOT_FOUND); 1044 net::TestURLFetcher* fetcher = fetcher_factory.GetLastCreatedFetcher();
955 fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::FAILED, -2)); 1045 ASSERT_THAT(fetcher, NotNull());
956 fetcher->delegate()->OnURLFetchComplete(fetcher); 1046 EXPECT_THAT(fetcher->GetMaxRetriesOn5xx(), Eq(2));
1047 }
1048
1049 TEST_F(NTPSnippetsFetcherTest, RetriesConfigurableOnNonInteractiveRequests) {
1050 NTPSnippetsFetcher::Params params = test_params();
1051 params.interactive_request = false;
1052 const std::vector<ExpectationForVariationParam> retry_config_expectation = {
1053 {"", 0}, // Keep 2 retries if no variation is set.
Marc Treib 2016/12/12 10:17:16 Comment is out of date. One alternative is adding
fhorschig 2016/12/12 11:05:10 Good idea.
tschumann 2016/12/12 11:55:48 This is fine by me, but we're getting close into t
fhorschig 2016/12/12 12:16:45 Looks like a valid concern even though this very e
1054 {"0", 0},
1055 {"-1", 0}, // Allow no negative retry count.
1056 {"3", 3}};
1057
1058 for (const auto& retry_config : retry_config_expectation) {
1059 DelegateCallingTestURLFetcherFactory fetcher_factory;
1060 SetVariationParametersForFeatures(
1061 {{"background_5xx_retries_count", retry_config.param_value}},
1062 {ntp_snippets::kArticleSuggestionsFeature.name});
1063
1064 snippets_fetcher().FetchSnippets(
1065 params, ToSnippetsAvailableCallback(&mock_callback()));
1066
1067 net::TestURLFetcher* fetcher = fetcher_factory.GetLastCreatedFetcher();
1068 ASSERT_THAT(fetcher, NotNull());
1069 EXPECT_THAT(fetcher->GetMaxRetriesOn5xx(), Eq(retry_config.expected_value));
1070 }
957 } 1071 }
958 1072
959 TEST_F(NTPSnippetsFetcherTest, ShouldReportUrlStatusError) { 1073 TEST_F(NTPSnippetsFetcherTest, ShouldReportUrlStatusError) {
960 SetFakeResponse(/*response_data=*/std::string(), net::HTTP_NOT_FOUND, 1074 SetFakeResponse(/*response_data=*/std::string(), net::HTTP_NOT_FOUND,
961 net::URLRequestStatus::FAILED); 1075 net::URLRequestStatus::FAILED);
962 EXPECT_CALL(mock_callback(), 1076 EXPECT_CALL(mock_callback(),
963 Run(NTPSnippetsFetcher::FetchResult::URL_REQUEST_STATUS_ERROR, 1077 Run(NTPSnippetsFetcher::FetchResult::URL_REQUEST_STATUS_ERROR,
964 /*snippets=*/Not(HasValue()))) 1078 /*snippets=*/Not(HasValue())))
965 .Times(1); 1079 .Times(1);
966 snippets_fetcher().FetchSnippets( 1080 snippets_fetcher().FetchSnippets(
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
1116 const NTPSnippetsFetcher::OptionalFetchedCategories& fetched_categories) { 1230 const NTPSnippetsFetcher::OptionalFetchedCategories& fetched_categories) {
1117 if (fetched_categories) { 1231 if (fetched_categories) {
1118 // Matchers above aren't any more precise than this, so this is sufficient 1232 // Matchers above aren't any more precise than this, so this is sufficient
1119 // for test-failure diagnostics. 1233 // for test-failure diagnostics.
1120 return os << "list with " << fetched_categories->size() << " elements"; 1234 return os << "list with " << fetched_categories->size() << " elements";
1121 } 1235 }
1122 return os << "null"; 1236 return os << "null";
1123 } 1237 }
1124 1238
1125 } // namespace ntp_snippets 1239 } // namespace ntp_snippets
OLDNEW
« no previous file with comments | « components/ntp_snippets/remote/ntp_snippets_fetcher.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698