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

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: Ability of FetcherFactory to warn about multiple |Create| calls. 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 <list>
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 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
151 void WrappedRun( 153 void WrappedRun(
152 NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories) { 154 NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories) {
153 Run(&fetched_categories); 155 Run(&fetched_categories);
154 } 156 }
155 157
156 MOCK_METHOD1( 158 MOCK_METHOD1(
157 Run, 159 Run,
158 void(NTPSnippetsFetcher::OptionalFetchedCategories* fetched_categories)); 160 void(NTPSnippetsFetcher::OptionalFetchedCategories* fetched_categories));
159 }; 161 };
160 162
163 // DelegateCallingTestURLFetcherFactory can be used to temporarily inject fake
164 // url fetcher instances into a scope.
Marc Treib 2016/12/09 12:59:24 s/fake url fetcher/TestURLFetcher/ ? Since both Te
fhorschig 2016/12/12 09:54:03 Done.
165 // Client code can access the last created fetcher to verify expected
166 // properties. When the factory gets destroyed, all available delegates of still
167 // valid fetchers will be called.
168 // This ensures once-bound callbacks (like SnippetsAvailableCallback) will be
169 // called at some point and are not leaked.
170 class DelegateCallingTestURLFetcherFactory
tschumann 2016/12/09 12:53:38 hmm... I wonder why the previous (much simpler ver
fhorschig 2016/12/12 09:54:03 Yes, you mentioned that. I replaced that multiple
tschumann 2016/12/12 10:00:42 to be more precise, what's the new bit of function
fhorschig 2016/12/12 11:05:10 It's true that we deal with a lot of implementatio
171 : public net::TestURLFetcherFactory,
172 public net::TestURLFetcherDelegateForTests {
173 public:
174 DelegateCallingTestURLFetcherFactory() {
175 SetDelegateForTests(this);
176 set_remove_fetcher_on_delete(true);
177 }
178
179 ~DelegateCallingTestURLFetcherFactory() override {
180 while (!fetcher_id_queue_.empty()) {
181 DropAndCallDelegate(fetcher_id_queue_.front());
182 }
183 }
184
185 std::unique_ptr<net::URLFetcher> CreateURLFetcher(
186 int id,
187 const GURL& url,
188 net::URLFetcher::RequestType request_type,
189 net::URLFetcherDelegate* d) override {
190 if (GetFetcherByID(id)) {
191 LOG(ERROR) << "The ID " << id << " was already assigned to a fetcher."
Marc Treib 2016/12/09 12:59:24 Is this actually an error? If so, should we just f
fhorschig 2016/12/12 09:54:03 It's a warning now. I thought about just failing
192 << "Its delegate will thereforde be called right now.";
193 DropAndCallDelegate(id);
194 }
195 fetcher_id_queue_.push_back(id);
196 return TestURLFetcherFactory::CreateURLFetcher(id, url, request_type, d);
197 }
198
199 // Returns the raw pointer of the last created URL fetcher.
200 // If it was destroyed or no fetcher was created, it will return a nulltpr.
201 net::TestURLFetcher* GetLastCreatedFetcher() {
202 if (fetcher_id_queue_.empty()) {
203 return nullptr;
204 }
205 return GetFetcherByID(fetcher_id_queue_.front());
tschumann 2016/12/09 12:53:38 shouldn't this be back?
fhorschig 2016/12/12 09:54:03 What came in first should be handled first (--> qu
206 }
207
208 private:
209 std::list<int> fetcher_id_queue_; // Use a list as searching is essential.
tschumann 2016/12/09 12:53:38 drop the type in the variable name (it's outdated
Marc Treib 2016/12/09 12:59:24 You mean, this can't be std::queue because that do
fhorschig 2016/12/12 09:54:03 @tschumann: Done. @treib: std::deque it is. And do
210
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 = std::find(fetcher_id_queue_.begin(),
215 fetcher_id_queue_.end(), fetcher_id);
216 if (found_id_iter == fetcher_id_queue_.end()) {
217 return;
218 }
219 fetcher_id_queue_.erase(found_id_iter);
220 net::TestURLFetcher* fetcher = GetFetcherByID(fetcher_id);
221 if (!fetcher) {
222 return;
223 }
224 if (!fetcher->delegate()) {
Marc Treib 2016/12/09 12:59:24 nit: Could merge the two ifs: if (!fetcher || !fet
fhorschig 2016/12/12 09:54:03 Okay.
225 return;
226 }
227 fetcher->delegate()->OnURLFetchComplete(fetcher);
228 }
229
230 // net::TestURLFetcherDelegateForTests overrides:
231 void OnRequestStart(int fetcher_id) override {}
232 void OnChunkUpload(int fetcher_id) override {}
233 void OnRequestEnd(int fetcher_id) override {
234 DropAndCallDelegate(fetcher_id);
235 }
236 };
237
161 // Factory for FakeURLFetcher objects that always generate errors. 238 // Factory for FakeURLFetcher objects that always generate errors.
162 class FailingFakeURLFetcherFactory : public net::URLFetcherFactory { 239 class FailingFakeURLFetcherFactory : public net::URLFetcherFactory {
163 public: 240 public:
164 std::unique_ptr<net::URLFetcher> CreateURLFetcher( 241 std::unique_ptr<net::URLFetcher> CreateURLFetcher(
165 int id, const GURL& url, net::URLFetcher::RequestType request_type, 242 int id, const GURL& url, net::URLFetcher::RequestType request_type,
166 net::URLFetcherDelegate* d) override { 243 net::URLFetcherDelegate* d) override {
167 return base::MakeUnique<net::FakeURLFetcher>( 244 return base::MakeUnique<net::FakeURLFetcher>(
168 url, d, /*response_data=*/std::string(), net::HTTP_NOT_FOUND, 245 url, d, /*response_data=*/std::string(), net::HTTP_NOT_FOUND,
169 net::URLRequestStatus::FAILED); 246 net::URLRequestStatus::FAILED);
170 } 247 }
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
202 class RequestBuilderWithMockedFlagsForTesting 279 class RequestBuilderWithMockedFlagsForTesting
203 : public NTPSnippetsFetcher::RequestBuilder { 280 : public NTPSnippetsFetcher::RequestBuilder {
204 public: 281 public:
205 RequestBuilderWithMockedFlagsForTesting() : RequestBuilder() {} 282 RequestBuilderWithMockedFlagsForTesting() : RequestBuilder() {}
206 283
207 private: 284 private:
208 bool IsSendingUserClassEnabled() const override { return true; } 285 bool IsSendingUserClassEnabled() const override { return true; }
209 bool IsSendingTopLanguagesEnabled() const override { return true; } 286 bool IsSendingTopLanguagesEnabled() const override { return true; }
210 }; 287 };
211 288
289 struct ExpectationForVariationParam {
290 std::string param_value;
291 int expected_value;
292 };
293
212 NTPSnippetsFetcherTest() 294 NTPSnippetsFetcherTest()
213 : NTPSnippetsFetcherTest(GURL(kTestChromeReaderUrl), 295 : NTPSnippetsFetcherTest(GURL(kTestChromeReaderUrl),
214 std::map<std::string, std::string>()) {} 296 std::map<std::string, std::string>()) {}
215 297
216 NTPSnippetsFetcherTest(const GURL& gurl, 298 NTPSnippetsFetcherTest(const GURL& gurl,
217 const std::map<std::string, std::string>& params) 299 const std::map<std::string, std::string>& params)
218 : params_manager_( 300 : params_manager_(
219 base::MakeUnique<variations::testing::VariationParamsManager>( 301 base::MakeUnique<variations::testing::VariationParamsManager>(
220 ntp_snippets::kStudyName, 302 ntp_snippets::kStudyName,
221 params)), 303 params)),
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
283 void SetFetchingPersonalizationVariation( 365 void SetFetchingPersonalizationVariation(
284 const std::string& personalization_string) { 366 const std::string& personalization_string) {
285 params_manager_.reset(); 367 params_manager_.reset();
286 std::map<std::string, std::string> params = { 368 std::map<std::string, std::string> params = {
287 {"fetching_personalization", personalization_string}}; 369 {"fetching_personalization", personalization_string}};
288 params_manager_ = 370 params_manager_ =
289 base::MakeUnique<variations::testing::VariationParamsManager>( 371 base::MakeUnique<variations::testing::VariationParamsManager>(
290 ntp_snippets::kStudyName, params); 372 ntp_snippets::kStudyName, params);
291 } 373 }
292 374
375 void SetVariationParametersForFeatures(
Marc Treib 2016/12/09 12:59:24 Hm, now SetFetchingPersonalizationVariation and Se
fhorschig 2016/12/12 09:54:03 The basic difference is that one is tied to a feat
376 const std::map<std::string, std::string>& params,
377 const std::set<std::string>& features) {
378 params_manager_.reset();
379 params_manager_ =
380 base::MakeUnique<variations::testing::VariationParamsManager>(
381 ntp_snippets::kStudyName, params, features);
382 }
383
293 void SetFakeResponse(const std::string& response_data, 384 void SetFakeResponse(const std::string& response_data,
294 net::HttpStatusCode response_code, 385 net::HttpStatusCode response_code,
295 net::URLRequestStatus::Status status) { 386 net::URLRequestStatus::Status status) {
296 InitFakeURLFetcherFactory(); 387 InitFakeURLFetcherFactory();
297 fake_url_fetcher_factory_->SetFakeResponse(test_url_, response_data, 388 fake_url_fetcher_factory_->SetFakeResponse(test_url_, response_data,
298 response_code, status); 389 response_code, status);
299 } 390 }
300 391
301 std::unique_ptr<translate::LanguageModel> MakeLanguageModel( 392 std::unique_ptr<translate::LanguageModel> MakeLanguageModel(
302 const std::vector<std::string>& codes) { 393 const std::vector<std::string>& codes) {
(...skipping 597 matching lines...) Expand 10 before | Expand all | Expand 10 after
900 EXPECT_THAT(snippets_fetcher().last_json(), Eq(kJsonStr)); 991 EXPECT_THAT(snippets_fetcher().last_json(), Eq(kJsonStr));
901 EXPECT_THAT( 992 EXPECT_THAT(
902 histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"), 993 histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"),
903 ElementsAre(base::Bucket(/*min=*/0, /*count=*/1))); 994 ElementsAre(base::Bucket(/*min=*/0, /*count=*/1)));
904 EXPECT_THAT(histogram_tester().GetAllSamples( 995 EXPECT_THAT(histogram_tester().GetAllSamples(
905 "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"), 996 "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"),
906 ElementsAre(base::Bucket(/*min=*/200, /*count=*/1))); 997 ElementsAre(base::Bucket(/*min=*/200, /*count=*/1)));
907 } 998 }
908 999
909 TEST_F(NTPSnippetsFetcherTest, ShouldRestrictToHosts) { 1000 TEST_F(NTPSnippetsFetcherTest, ShouldRestrictToHosts) {
910 net::TestURLFetcherFactory test_url_fetcher_factory; 1001 DelegateCallingTestURLFetcherFactory fetcher_factory;
911 NTPSnippetsFetcher::Params params = test_params(); 1002 NTPSnippetsFetcher::Params params = test_params();
912 params.hosts = {"www.somehost1.com", "www.somehost2.com"}; 1003 params.hosts = {"www.somehost1.com", "www.somehost2.com"};
913 params.count_to_fetch = 17; 1004 params.count_to_fetch = 17;
1005
914 snippets_fetcher().FetchSnippets( 1006 snippets_fetcher().FetchSnippets(
915 params, ToSnippetsAvailableCallback(&mock_callback())); 1007 params, ToSnippetsAvailableCallback(&mock_callback()));
916 net::TestURLFetcher* fetcher = test_url_fetcher_factory.GetFetcherByID(0); 1008
1009 net::TestURLFetcher* fetcher = fetcher_factory.GetLastCreatedFetcher();
917 ASSERT_THAT(fetcher, NotNull()); 1010 ASSERT_THAT(fetcher, NotNull());
918 std::unique_ptr<base::Value> value = 1011 std::unique_ptr<base::Value> value =
919 base::JSONReader::Read(fetcher->upload_data()); 1012 base::JSONReader::Read(fetcher->upload_data());
920 ASSERT_TRUE(value) << " failed to parse JSON: " 1013 ASSERT_TRUE(value) << " failed to parse JSON: "
921 << PrintToString(fetcher->upload_data()); 1014 << PrintToString(fetcher->upload_data());
922 const base::DictionaryValue* dict = nullptr; 1015 const base::DictionaryValue* dict = nullptr;
923 ASSERT_TRUE(value->GetAsDictionary(&dict)); 1016 ASSERT_TRUE(value->GetAsDictionary(&dict));
924 const base::DictionaryValue* local_scoring_params = nullptr; 1017 const base::DictionaryValue* local_scoring_params = nullptr;
925 ASSERT_TRUE(dict->GetDictionary("advanced_options.local_scoring_params", 1018 ASSERT_TRUE(dict->GetDictionary("advanced_options.local_scoring_params",
926 &local_scoring_params)); 1019 &local_scoring_params));
927 const base::ListValue* content_selectors = nullptr; 1020 const base::ListValue* content_selectors = nullptr;
928 ASSERT_TRUE( 1021 ASSERT_TRUE(
929 local_scoring_params->GetList("content_selectors", &content_selectors)); 1022 local_scoring_params->GetList("content_selectors", &content_selectors));
930 ASSERT_THAT(content_selectors->GetSize(), Eq(static_cast<size_t>(2))); 1023 ASSERT_THAT(content_selectors->GetSize(), Eq(static_cast<size_t>(2)));
931 const base::DictionaryValue* content_selector = nullptr; 1024 const base::DictionaryValue* content_selector = nullptr;
932 ASSERT_TRUE(content_selectors->GetDictionary(0, &content_selector)); 1025 ASSERT_TRUE(content_selectors->GetDictionary(0, &content_selector));
933 std::string content_selector_value; 1026 std::string content_selector_value;
934 EXPECT_TRUE(content_selector->GetString("value", &content_selector_value)); 1027 EXPECT_TRUE(content_selector->GetString("value", &content_selector_value));
935 EXPECT_THAT(content_selector_value, Eq("www.somehost1.com")); 1028 EXPECT_THAT(content_selector_value, Eq("www.somehost1.com"));
936 ASSERT_TRUE(content_selectors->GetDictionary(1, &content_selector)); 1029 ASSERT_TRUE(content_selectors->GetDictionary(1, &content_selector));
937 EXPECT_TRUE(content_selector->GetString("value", &content_selector_value)); 1030 EXPECT_TRUE(content_selector->GetString("value", &content_selector_value));
938 EXPECT_THAT(content_selector_value, Eq("www.somehost2.com")); 1031 EXPECT_THAT(content_selector_value, Eq("www.somehost2.com"));
939 // Call the delegate callback manually as the TestURLFetcher deletes any 1032 }
940 // call to the delegate that usually happens on |Start|. 1033
941 // Without the call to the delegate, it leaks the request that owns itself. 1034 TEST_F(NTPSnippetsFetcherTest, RetryOnInteractiveRequests) {
942 ASSERT_THAT(fetcher->delegate(), NotNull()); 1035 DelegateCallingTestURLFetcherFactory fetcher_factory;
943 EXPECT_CALL(mock_callback(), Run(/*snippets=*/Not(HasValue()))).Times(1); 1036 NTPSnippetsFetcher::Params params = test_params();
944 // An 4XX response needs the least configuration to successfully invoke the 1037 params.interactive_request = true;
945 // callback properly as the results are not important in this test. 1038
946 fetcher->set_response_code(net::HTTP_NOT_FOUND); 1039 snippets_fetcher().FetchSnippets(
947 fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::FAILED, -2)); 1040 params, ToSnippetsAvailableCallback(&mock_callback()));
948 fetcher->delegate()->OnURLFetchComplete(fetcher); 1041
1042 net::TestURLFetcher* fetcher = fetcher_factory.GetLastCreatedFetcher();
1043 ASSERT_THAT(fetcher, NotNull());
1044 EXPECT_THAT(fetcher->GetMaxRetriesOn5xx(), Eq(2));
1045 }
1046
1047 TEST_F(NTPSnippetsFetcherTest, RetriesConfigurableOnNonInteractiveRequests) {
1048 NTPSnippetsFetcher::Params params = test_params();
1049 params.interactive_request = false;
1050 const std::vector<ExpectationForVariationParam> retry_config_expectation = {
1051 {"", 0}, // Keep 2 retries if no variation is set.
1052 {"0", 0},
1053 {"-1", 0}, // Allow no negative retry count.
1054 {"3", 3}};
1055
1056 for (const auto& retry_config : retry_config_expectation) {
1057 DelegateCallingTestURLFetcherFactory fetcher_factory;
1058 SetVariationParametersForFeatures(
1059 {{"background_5xx_retries_count", retry_config.param_value}},
1060 {ntp_snippets::kArticleSuggestionsFeature.name});
1061
1062 snippets_fetcher().FetchSnippets(
1063 params, ToSnippetsAvailableCallback(&mock_callback()));
1064
1065 net::TestURLFetcher* fetcher = fetcher_factory.GetLastCreatedFetcher();
1066 ASSERT_THAT(fetcher, NotNull());
1067 EXPECT_THAT(fetcher->GetMaxRetriesOn5xx(), Eq(retry_config.expected_value));
1068 }
949 } 1069 }
950 1070
951 TEST_F(NTPSnippetsFetcherTest, ShouldReportUrlStatusError) { 1071 TEST_F(NTPSnippetsFetcherTest, ShouldReportUrlStatusError) {
952 SetFakeResponse(/*response_data=*/std::string(), net::HTTP_NOT_FOUND, 1072 SetFakeResponse(/*response_data=*/std::string(), net::HTTP_NOT_FOUND,
953 net::URLRequestStatus::FAILED); 1073 net::URLRequestStatus::FAILED);
954 EXPECT_CALL(mock_callback(), Run(/*snippets=*/Not(HasValue()))).Times(1); 1074 EXPECT_CALL(mock_callback(), Run(/*snippets=*/Not(HasValue()))).Times(1);
955 snippets_fetcher().FetchSnippets( 1075 snippets_fetcher().FetchSnippets(
956 test_params(), ToSnippetsAvailableCallback(&mock_callback())); 1076 test_params(), ToSnippetsAvailableCallback(&mock_callback()));
957 FastForwardUntilNoTasksRemain(); 1077 FastForwardUntilNoTasksRemain();
958 EXPECT_THAT(snippets_fetcher().last_status(), 1078 EXPECT_THAT(snippets_fetcher().last_status(),
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
1088 const NTPSnippetsFetcher::OptionalFetchedCategories& fetched_categories) { 1208 const NTPSnippetsFetcher::OptionalFetchedCategories& fetched_categories) {
1089 if (fetched_categories) { 1209 if (fetched_categories) {
1090 // Matchers above aren't any more precise than this, so this is sufficient 1210 // Matchers above aren't any more precise than this, so this is sufficient
1091 // for test-failure diagnostics. 1211 // for test-failure diagnostics.
1092 return os << "list with " << fetched_categories->size() << " elements"; 1212 return os << "list with " << fetched_categories->size() << " elements";
1093 } 1213 }
1094 return os << "null"; 1214 return os << "null";
1095 } 1215 }
1096 1216
1097 } // namespace ntp_snippets 1217 } // 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