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

Side by Side Diff: chrome/browser/search/suggestions/suggestions_service_unittest.cc

Issue 410673002: [Suggestions] Moving suggestions code to a new component (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix deps Created 6 years, 5 months 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/search/suggestions/suggestions_service.h"
6
7 #include <map>
8 #include <sstream>
9 #include <string>
10
11 #include "base/bind.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/metrics/field_trial.h"
14 #include "base/prefs/pref_service.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "chrome/browser/search/suggestions/blacklist_store.h"
17 #include "chrome/browser/search/suggestions/image_manager.h"
18 #include "chrome/browser/search/suggestions/proto/suggestions.pb.h"
19 #include "chrome/browser/search/suggestions/suggestions_service_factory.h"
20 #include "chrome/browser/search/suggestions/suggestions_store.h"
21 #include "components/variations/entropy_provider.h"
22 #include "components/variations/variations_associated_data.h"
23 #include "content/public/test/test_browser_thread_bundle.h"
24 #include "net/http/http_response_headers.h"
25 #include "net/http/http_status_code.h"
26 #include "net/url_request/test_url_fetcher_factory.h"
27 #include "net/url_request/url_request_status.h"
28 #include "net/url_request/url_request_test_util.h"
29 #include "testing/gmock/include/gmock/gmock.h"
30 #include "testing/gtest/include/gtest/gtest.h"
31
32 using testing::DoAll;
33 using ::testing::Eq;
34 using ::testing::Return;
35 using testing::SetArgPointee;
36 using ::testing::NiceMock;
37 using ::testing::StrictMock;
38 using ::testing::_;
39
40 namespace {
41
42 const char kFakeSuggestionsURL[] = "https://mysuggestions.com/proto";
43 const char kFakeSuggestionsCommonParams[] = "foo=bar";
44 const char kFakeBlacklistPath[] = "/blacklist";
45 const char kFakeBlacklistUrlParam[] = "baz";
46
47 const char kTestTitle[] = "a title";
48 const char kTestUrl[] = "http://go.com";
49 const char kBlacklistUrl[] = "http://blacklist.com";
50
51 scoped_ptr<net::FakeURLFetcher> CreateURLFetcher(
52 const GURL& url, net::URLFetcherDelegate* delegate,
53 const std::string& response_data, net::HttpStatusCode response_code,
54 net::URLRequestStatus::Status status) {
55 scoped_ptr<net::FakeURLFetcher> fetcher(new net::FakeURLFetcher(
56 url, delegate, response_data, response_code, status));
57
58 if (response_code == net::HTTP_OK) {
59 scoped_refptr<net::HttpResponseHeaders> download_headers(
60 new net::HttpResponseHeaders(""));
61 download_headers->AddHeader("Content-Type: text/html");
62 fetcher->set_response_headers(download_headers);
63 }
64 return fetcher.Pass();
65 }
66
67 std::string GetExpectedBlacklistRequestUrl(const GURL& blacklist_url) {
68 std::stringstream request_url;
69 request_url << kFakeSuggestionsURL << kFakeBlacklistPath << "?"
70 << kFakeSuggestionsCommonParams << "&" << kFakeBlacklistUrlParam
71 << "=" << net::EscapeQueryParamValue(blacklist_url.spec(), true);
72 return request_url.str();
73 }
74
75 // GMock matcher for protobuf equality.
76 MATCHER_P(EqualsProto, message, "") {
77 // This implementation assumes protobuf serialization is deterministic, which
78 // is true in practice but technically not something that code is supposed
79 // to rely on. However, it vastly simplifies the implementation.
80 std::string expected_serialized, actual_serialized;
81 message.SerializeToString(&expected_serialized);
82 arg.SerializeToString(&actual_serialized);
83 return expected_serialized == actual_serialized;
84 }
85
86 } // namespace
87
88 namespace suggestions {
89
90 scoped_ptr<SuggestionsProfile> CreateSuggestionsProfile() {
91 scoped_ptr<SuggestionsProfile> profile(new SuggestionsProfile());
92 ChromeSuggestion* suggestion = profile->add_suggestions();
93 suggestion->set_title(kTestTitle);
94 suggestion->set_url(kTestUrl);
95 return profile.Pass();
96 }
97
98 class MockSuggestionsStore : public suggestions::SuggestionsStore {
99 public:
100 MOCK_METHOD1(LoadSuggestions, bool(SuggestionsProfile*));
101 MOCK_METHOD1(StoreSuggestions, bool(const SuggestionsProfile&));
102 MOCK_METHOD0(ClearSuggestions, void());
103 };
104
105 class MockImageManager : public suggestions::ImageManager {
106 public:
107 MockImageManager() {}
108 virtual ~MockImageManager() {}
109 MOCK_METHOD1(Initialize, void(const SuggestionsProfile&));
110 MOCK_METHOD2(GetImageForURL,
111 void(const GURL&,
112 base::Callback<void(const GURL&, const SkBitmap*)>));
113 };
114
115 class MockBlacklistStore : public suggestions::BlacklistStore {
116 public:
117 MOCK_METHOD1(BlacklistUrl, bool(const GURL&));
118 MOCK_METHOD1(GetFirstUrlFromBlacklist, bool(GURL*));
119 MOCK_METHOD1(RemoveUrl, bool(const GURL&));
120 MOCK_METHOD1(FilterSuggestions, void(SuggestionsProfile*));
121 };
122
123 class SuggestionsServiceTest : public testing::Test {
124 public:
125 void CheckSuggestionsData(const SuggestionsProfile& suggestions_profile) {
126 EXPECT_EQ(1, suggestions_profile.suggestions_size());
127 EXPECT_EQ(kTestTitle, suggestions_profile.suggestions(0).title());
128 EXPECT_EQ(kTestUrl, suggestions_profile.suggestions(0).url());
129 ++suggestions_data_check_count_;
130 }
131
132 void ExpectEmptySuggestionsProfile(const SuggestionsProfile& profile) {
133 EXPECT_EQ(0, profile.suggestions_size());
134 ++suggestions_empty_data_count_;
135 }
136
137 int suggestions_data_check_count_;
138 int suggestions_empty_data_count_;
139
140 protected:
141 SuggestionsServiceTest()
142 : suggestions_data_check_count_(0),
143 suggestions_empty_data_count_(0),
144 factory_(NULL, base::Bind(&CreateURLFetcher)),
145 mock_suggestions_store_(NULL),
146 mock_thumbnail_manager_(NULL) {}
147
148 virtual ~SuggestionsServiceTest() {}
149
150 virtual void SetUp() OVERRIDE {
151 request_context_ =
152 new net::TestURLRequestContextGetter(base::MessageLoopProxy::current());
153 }
154
155 // Enables the "ChromeSuggestions.Group1" field trial.
156 void EnableFieldTrial(const std::string& url,
157 const std::string& common_params,
158 const std::string& blacklist_path,
159 const std::string& blacklist_url_param,
160 bool control_group) {
161 // Clear the existing |field_trial_list_| to avoid firing a DCHECK.
162 field_trial_list_.reset(NULL);
163 field_trial_list_.reset(
164 new base::FieldTrialList(new metrics::SHA1EntropyProvider("foo")));
165
166 chrome_variations::testing::ClearAllVariationParams();
167 std::map<std::string, std::string> params;
168 params[kSuggestionsFieldTrialStateParam] =
169 kSuggestionsFieldTrialStateEnabled;
170 if (control_group) {
171 params[kSuggestionsFieldTrialControlParam] =
172 kSuggestionsFieldTrialStateEnabled;
173 }
174 params[kSuggestionsFieldTrialURLParam] = url;
175 params[kSuggestionsFieldTrialCommonParamsParam] = common_params;
176 params[kSuggestionsFieldTrialBlacklistPathParam] = blacklist_path;
177 params[kSuggestionsFieldTrialBlacklistUrlParam] = blacklist_url_param;
178 chrome_variations::AssociateVariationParams(kSuggestionsFieldTrialName,
179 "Group1", params);
180 field_trial_ = base::FieldTrialList::CreateFieldTrial(
181 kSuggestionsFieldTrialName, "Group1");
182 field_trial_->group();
183 }
184
185 // Should not be called more than once per test since it stashes the
186 // SuggestionsStore in |mock_suggestions_store_|.
187 SuggestionsService* CreateSuggestionsServiceWithMocks() {
188 mock_suggestions_store_ = new StrictMock<MockSuggestionsStore>();
189 mock_thumbnail_manager_ = new NiceMock<MockImageManager>();
190 mock_blacklist_store_ = new MockBlacklistStore();
191 return new SuggestionsService(
192 request_context_, scoped_ptr<SuggestionsStore>(mock_suggestions_store_),
193 scoped_ptr<ImageManager>(mock_thumbnail_manager_),
194 scoped_ptr<BlacklistStore>(mock_blacklist_store_));
195 }
196
197 void FetchSuggestionsDataNoTimeoutHelper(bool interleaved_requests) {
198 // Field trial enabled with a specific suggestions URL.
199 EnableFieldTrial(kFakeSuggestionsURL, kFakeSuggestionsCommonParams,
200 kFakeBlacklistPath, kFakeBlacklistUrlParam, false);
201 scoped_ptr<SuggestionsService> suggestions_service(
202 CreateSuggestionsServiceWithMocks());
203 EXPECT_TRUE(suggestions_service != NULL);
204 scoped_ptr<SuggestionsProfile> suggestions_profile(
205 CreateSuggestionsProfile());
206
207 // Set up net::FakeURLFetcherFactory.
208 std::string expected_url =
209 (std::string(kFakeSuggestionsURL) + "?") + kFakeSuggestionsCommonParams;
210 factory_.SetFakeResponse(GURL(expected_url),
211 suggestions_profile->SerializeAsString(),
212 net::HTTP_OK, net::URLRequestStatus::SUCCESS);
213
214 // Set up expectations on the SuggestionsStore. The number depends on
215 // whether the second request is issued (it won't be issued if the second
216 // fetch occurs before the first request has completed).
217 int expected_count = interleaved_requests ? 1 : 2;
218 EXPECT_CALL(*mock_suggestions_store_,
219 StoreSuggestions(EqualsProto(*suggestions_profile)))
220 .Times(expected_count)
221 .WillRepeatedly(Return(true));
222
223 // Expect a call to the blacklist store. Return that there's nothing to
224 // blacklist.
225 EXPECT_CALL(*mock_blacklist_store_, FilterSuggestions(_))
226 .Times(expected_count);
227 EXPECT_CALL(*mock_blacklist_store_, GetFirstUrlFromBlacklist(_))
228 .Times(expected_count)
229 .WillRepeatedly(Return(false));
230
231 // Send the request. The data will be returned to the callback.
232 suggestions_service->FetchSuggestionsDataNoTimeout(base::Bind(
233 &SuggestionsServiceTest::CheckSuggestionsData, base::Unretained(this)));
234
235 if (!interleaved_requests)
236 base::MessageLoop::current()->RunUntilIdle(); // Let request complete.
237
238 // Send the request a second time.
239 suggestions_service->FetchSuggestionsDataNoTimeout(base::Bind(
240 &SuggestionsServiceTest::CheckSuggestionsData, base::Unretained(this)));
241
242 // (Testing only) wait until suggestion fetch is complete.
243 base::MessageLoop::current()->RunUntilIdle();
244
245 // Ensure that CheckSuggestionsData() ran twice.
246 EXPECT_EQ(2, suggestions_data_check_count_);
247 }
248
249 protected:
250 net::FakeURLFetcherFactory factory_;
251 // Only used if the SuggestionsService is built with mocks. Not owned.
252 MockSuggestionsStore* mock_suggestions_store_;
253 MockImageManager* mock_thumbnail_manager_;
254 MockBlacklistStore* mock_blacklist_store_;
255 scoped_refptr<net::TestURLRequestContextGetter> request_context_;
256
257 private:
258 content::TestBrowserThreadBundle thread_bundle_;
259 scoped_ptr<base::FieldTrialList> field_trial_list_;
260 scoped_refptr<base::FieldTrial> field_trial_;
261
262 DISALLOW_COPY_AND_ASSIGN(SuggestionsServiceTest);
263 };
264
265 TEST_F(SuggestionsServiceTest, IsControlGroup) {
266 // Field trial enabled.
267 EnableFieldTrial("", "", "", "", false);
268 EXPECT_FALSE(SuggestionsService::IsControlGroup());
269
270 EnableFieldTrial("", "", "", "", true);
271 EXPECT_TRUE(SuggestionsService::IsControlGroup());
272 }
273
274 TEST_F(SuggestionsServiceTest, FetchSuggestionsDataNoTimeout) {
275 FetchSuggestionsDataNoTimeoutHelper(false);
276 }
277
278 TEST_F(SuggestionsServiceTest, FetchSuggestionsDataNoTimeoutInterleaved) {
279 FetchSuggestionsDataNoTimeoutHelper(true);
280 }
281
282 TEST_F(SuggestionsServiceTest, FetchSuggestionsDataRequestError) {
283 // Field trial enabled with a specific suggestions URL.
284 EnableFieldTrial(kFakeSuggestionsURL, kFakeSuggestionsCommonParams,
285 kFakeBlacklistPath, kFakeBlacklistUrlParam, false);
286 scoped_ptr<SuggestionsService> suggestions_service(
287 CreateSuggestionsServiceWithMocks());
288 EXPECT_TRUE(suggestions_service != NULL);
289
290 // Fake a request error.
291 std::string expected_url =
292 (std::string(kFakeSuggestionsURL) + "?") + kFakeSuggestionsCommonParams;
293 factory_.SetFakeResponse(GURL(expected_url), "irrelevant", net::HTTP_OK,
294 net::URLRequestStatus::FAILED);
295
296 // Set up expectations on the SuggestionsStore.
297 EXPECT_CALL(*mock_suggestions_store_, LoadSuggestions(_))
298 .WillOnce(Return(true));
299
300 // Expect a call to the blacklist store. Return that there's nothing to
301 // blacklist.
302 EXPECT_CALL(*mock_blacklist_store_, FilterSuggestions(_));
303 EXPECT_CALL(*mock_blacklist_store_, GetFirstUrlFromBlacklist(_))
304 .WillOnce(Return(false));
305
306 // Send the request. Empty data will be returned to the callback.
307 suggestions_service->FetchSuggestionsData(
308 base::Bind(&SuggestionsServiceTest::ExpectEmptySuggestionsProfile,
309 base::Unretained(this)));
310
311 // (Testing only) wait until suggestion fetch is complete.
312 base::MessageLoop::current()->RunUntilIdle();
313
314 // Ensure that ExpectEmptySuggestionsProfile ran once.
315 EXPECT_EQ(1, suggestions_empty_data_count_);
316 }
317
318 TEST_F(SuggestionsServiceTest, FetchSuggestionsDataResponseNotOK) {
319 // Field trial enabled with a specific suggestions URL.
320 EnableFieldTrial(kFakeSuggestionsURL, kFakeSuggestionsCommonParams,
321 kFakeBlacklistPath, kFakeBlacklistUrlParam, false);
322 scoped_ptr<SuggestionsService> suggestions_service(
323 CreateSuggestionsServiceWithMocks());
324 EXPECT_TRUE(suggestions_service != NULL);
325
326 // Response code != 200.
327 std::string expected_url =
328 (std::string(kFakeSuggestionsURL) + "?") + kFakeSuggestionsCommonParams;
329 factory_.SetFakeResponse(GURL(expected_url), "irrelevant",
330 net::HTTP_BAD_REQUEST,
331 net::URLRequestStatus::SUCCESS);
332
333 // Set up expectations on the SuggestionsStore.
334 EXPECT_CALL(*mock_suggestions_store_, ClearSuggestions());
335
336 // Expect a call to the blacklist store. Return that there's nothing to
337 // blacklist.
338 EXPECT_CALL(*mock_blacklist_store_, GetFirstUrlFromBlacklist(_))
339 .WillOnce(Return(false));
340
341 // Send the request. Empty data will be returned to the callback.
342 suggestions_service->FetchSuggestionsData(
343 base::Bind(&SuggestionsServiceTest::ExpectEmptySuggestionsProfile,
344 base::Unretained(this)));
345
346 // (Testing only) wait until suggestion fetch is complete.
347 base::MessageLoop::current()->RunUntilIdle();
348
349 // Ensure that ExpectEmptySuggestionsProfile ran once.
350 EXPECT_EQ(1, suggestions_empty_data_count_);
351 }
352
353 TEST_F(SuggestionsServiceTest, BlacklistURL) {
354 EnableFieldTrial(kFakeSuggestionsURL, kFakeSuggestionsCommonParams,
355 kFakeBlacklistPath, kFakeBlacklistUrlParam, false);
356 scoped_ptr<SuggestionsService> suggestions_service(
357 CreateSuggestionsServiceWithMocks());
358 EXPECT_TRUE(suggestions_service != NULL);
359
360 GURL blacklist_url(kBlacklistUrl);
361 std::string request_url = GetExpectedBlacklistRequestUrl(blacklist_url);
362 scoped_ptr<SuggestionsProfile> suggestions_profile(
363 CreateSuggestionsProfile());
364 factory_.SetFakeResponse(GURL(request_url),
365 suggestions_profile->SerializeAsString(),
366 net::HTTP_OK, net::URLRequestStatus::SUCCESS);
367
368 // Set up expectations on the SuggestionsStore.
369 EXPECT_CALL(*mock_suggestions_store_,
370 StoreSuggestions(EqualsProto(*suggestions_profile)))
371 .WillOnce(Return(true));
372
373 // Expected calls to the blacklist store.
374 EXPECT_CALL(*mock_blacklist_store_, BlacklistUrl(Eq(blacklist_url)))
375 .WillOnce(Return(true));
376 EXPECT_CALL(*mock_blacklist_store_, RemoveUrl(Eq(blacklist_url)))
377 .WillOnce(Return(true));
378 EXPECT_CALL(*mock_blacklist_store_, FilterSuggestions(_));
379 EXPECT_CALL(*mock_blacklist_store_, GetFirstUrlFromBlacklist(_))
380 .WillOnce(Return(false));
381
382 // Send the request. The data will be returned to the callback.
383 suggestions_service->BlacklistURL(
384 blacklist_url, base::Bind(&SuggestionsServiceTest::CheckSuggestionsData,
385 base::Unretained(this)));
386
387 // (Testing only) wait until blacklist request is complete.
388 base::MessageLoop::current()->RunUntilIdle();
389
390 // Ensure that CheckSuggestionsData() ran once.
391 EXPECT_EQ(1, suggestions_data_check_count_);
392 }
393
394 // Initial blacklist request fails, triggering a scheduled upload which
395 // succeeds.
396 TEST_F(SuggestionsServiceTest, BlacklistURLFails) {
397 EnableFieldTrial(kFakeSuggestionsURL, kFakeSuggestionsCommonParams,
398 kFakeBlacklistPath, kFakeBlacklistUrlParam, false);
399 scoped_ptr<SuggestionsService> suggestions_service(
400 CreateSuggestionsServiceWithMocks());
401 EXPECT_TRUE(suggestions_service != NULL);
402 suggestions_service->set_blacklist_delay(0); // Don't wait during a test!
403 scoped_ptr<SuggestionsProfile> suggestions_profile(
404 CreateSuggestionsProfile());
405 GURL blacklist_url(kBlacklistUrl);
406
407 // Set up behavior for the first call to blacklist.
408 std::string request_url = GetExpectedBlacklistRequestUrl(blacklist_url);
409 factory_.SetFakeResponse(GURL(request_url), "irrelevant", net::HTTP_OK,
410 net::URLRequestStatus::FAILED);
411
412 // Expectations specific to the first request.
413 EXPECT_CALL(*mock_blacklist_store_, BlacklistUrl(Eq(blacklist_url)))
414 .WillOnce(Return(true));
415 EXPECT_CALL(*mock_suggestions_store_, LoadSuggestions(_))
416 .WillOnce(DoAll(SetArgPointee<0>(*suggestions_profile), Return(true)));
417
418 // Expectations specific to the second request.
419 EXPECT_CALL(*mock_suggestions_store_,
420 StoreSuggestions(EqualsProto(*suggestions_profile)))
421 .WillOnce(Return(true));
422 EXPECT_CALL(*mock_blacklist_store_, RemoveUrl(Eq(blacklist_url)))
423 .WillOnce(Return(true));
424
425 // Expectations pertaining to both requests.
426 EXPECT_CALL(*mock_blacklist_store_, FilterSuggestions(_)).Times(2);
427 EXPECT_CALL(*mock_blacklist_store_, GetFirstUrlFromBlacklist(_))
428 .WillOnce(Return(true))
429 .WillOnce(DoAll(SetArgPointee<0>(blacklist_url), Return(true)))
430 .WillOnce(Return(false));
431
432 // Send the request. The data will be returned to the callback.
433 suggestions_service->BlacklistURL(
434 blacklist_url, base::Bind(&SuggestionsServiceTest::CheckSuggestionsData,
435 base::Unretained(this)));
436
437 // The first FakeURLFetcher was created; we can now set up behavior for the
438 // second call to blacklist.
439 factory_.SetFakeResponse(GURL(request_url),
440 suggestions_profile->SerializeAsString(),
441 net::HTTP_OK, net::URLRequestStatus::SUCCESS);
442
443 // (Testing only) wait until both requests are complete.
444 base::MessageLoop::current()->RunUntilIdle();
445
446 // Ensure that CheckSuggestionsData() ran once.
447 EXPECT_EQ(1, suggestions_data_check_count_);
448 }
449
450 TEST_F(SuggestionsServiceTest, GetBlacklistedUrl) {
451 EnableFieldTrial(kFakeSuggestionsURL, kFakeSuggestionsCommonParams,
452 kFakeBlacklistPath, kFakeBlacklistUrlParam, false);
453
454 scoped_ptr<GURL> request_url;
455 scoped_ptr<net::FakeURLFetcher> fetcher;
456 GURL retrieved_url;
457
458 // Not a blacklist request.
459 request_url.reset(new GURL("http://not-blacklisting.com/a?b=c"));
460 fetcher = CreateURLFetcher(*request_url, NULL, "", net::HTTP_OK,
461 net::URLRequestStatus::SUCCESS);
462 EXPECT_FALSE(SuggestionsService::GetBlacklistedUrl(*fetcher, &retrieved_url));
463
464 // An actual blacklist request.
465 string blacklisted_url = "http://blacklisted.com/a?b=c&d=e";
466 string encoded_blacklisted_url =
467 "http%3A%2F%2Fblacklisted.com%2Fa%3Fb%3Dc%26d%3De";
468 string blacklist_request_prefix =
469 "https://mysuggestions.com/proto/blacklist?foo=bar&baz=";
470 request_url.reset(
471 new GURL(blacklist_request_prefix + encoded_blacklisted_url));
472 fetcher.reset();
473 fetcher = CreateURLFetcher(*request_url, NULL, "", net::HTTP_OK,
474 net::URLRequestStatus::SUCCESS);
475 EXPECT_TRUE(SuggestionsService::GetBlacklistedUrl(*fetcher, &retrieved_url));
476 EXPECT_EQ(blacklisted_url, retrieved_url.spec());
477 }
478
479 TEST_F(SuggestionsServiceTest, UpdateBlacklistDelay) {
480 scoped_ptr<SuggestionsService> suggestions_service(
481 CreateSuggestionsServiceWithMocks());
482 int initial_delay = suggestions_service->blacklist_delay();
483
484 // Delay unchanged on success.
485 suggestions_service->UpdateBlacklistDelay(true);
486 EXPECT_EQ(initial_delay, suggestions_service->blacklist_delay());
487
488 // Delay increases on failure.
489 suggestions_service->UpdateBlacklistDelay(false);
490 EXPECT_GT(suggestions_service->blacklist_delay(), initial_delay);
491
492 // Delay resets on success.
493 suggestions_service->UpdateBlacklistDelay(true);
494 EXPECT_EQ(initial_delay, suggestions_service->blacklist_delay());
495 }
496
497 } // namespace suggestions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698