Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / components / suggestions / suggestions_service_unittest.cc
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 "components/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/message_loop/message_loop.h"
14 #include "base/metrics/field_trial.h"
15 #include "base/prefs/pref_service.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "components/suggestions/blacklist_store.h"
18 #include "components/suggestions/image_manager.h"
19 #include "components/suggestions/proto/suggestions.pb.h"
20 #include "components/suggestions/suggestions_store.h"
21 #include "components/suggestions/suggestions_utils.h"
22 #include "components/variations/entropy_provider.h"
23 #include "components/variations/variations_associated_data.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 const int64 kTestDefaultExpiry = 1402200000000000;
51 const int64 kTestSetExpiry = 1404792000000000;
52
53 scoped_ptr<net::FakeURLFetcher> CreateURLFetcher(
54     const GURL& url, net::URLFetcherDelegate* delegate,
55     const std::string& response_data, net::HttpStatusCode response_code,
56     net::URLRequestStatus::Status status) {
57   scoped_ptr<net::FakeURLFetcher> fetcher(new net::FakeURLFetcher(
58       url, delegate, response_data, response_code, status));
59
60   if (response_code == net::HTTP_OK) {
61     scoped_refptr<net::HttpResponseHeaders> download_headers(
62         new net::HttpResponseHeaders(""));
63     download_headers->AddHeader("Content-Type: text/html");
64     fetcher->set_response_headers(download_headers);
65   }
66   return fetcher.Pass();
67 }
68
69 std::string GetExpectedBlacklistRequestUrl(const GURL& blacklist_url) {
70   std::stringstream request_url;
71   request_url << kFakeSuggestionsURL << kFakeBlacklistPath << "?"
72               << kFakeSuggestionsCommonParams << "&" << kFakeBlacklistUrlParam
73               << "=" << net::EscapeQueryParamValue(blacklist_url.spec(), true);
74   return request_url.str();
75 }
76
77 // GMock matcher for protobuf equality.
78 MATCHER_P(EqualsProto, message, "") {
79   // This implementation assumes protobuf serialization is deterministic, which
80   // is true in practice but technically not something that code is supposed
81   // to rely on.  However, it vastly simplifies the implementation.
82   std::string expected_serialized, actual_serialized;
83   message.SerializeToString(&expected_serialized);
84   arg.SerializeToString(&actual_serialized);
85   return expected_serialized == actual_serialized;
86 }
87
88 }  // namespace
89
90 namespace suggestions {
91
92 scoped_ptr<SuggestionsProfile> CreateSuggestionsProfile() {
93   scoped_ptr<SuggestionsProfile> profile(new SuggestionsProfile());
94   ChromeSuggestion* suggestion = profile->add_suggestions();
95   suggestion->set_title(kTestTitle);
96   suggestion->set_url(kTestUrl);
97   suggestion->set_expiry_ts(kTestSetExpiry);
98   return profile.Pass();
99 }
100
101 // Creates one suggestion with expiry timestamp and one without.
102 SuggestionsProfile CreateSuggestionsProfileWithExpiryTimestamps() {
103   SuggestionsProfile profile;
104   ChromeSuggestion* suggestion = profile.add_suggestions();
105   suggestion->set_title(kTestTitle);
106   suggestion->set_url(kTestUrl);
107   suggestion->set_expiry_ts(kTestSetExpiry);
108
109   suggestion = profile.add_suggestions();
110   suggestion->set_title(kTestTitle);
111   suggestion->set_url(kTestUrl);
112
113   return profile;
114 }
115
116 class MockSuggestionsStore : public suggestions::SuggestionsStore {
117  public:
118   MOCK_METHOD1(LoadSuggestions, bool(SuggestionsProfile*));
119   MOCK_METHOD1(StoreSuggestions, bool(const SuggestionsProfile&));
120   MOCK_METHOD0(ClearSuggestions, void());
121 };
122
123 class MockImageManager : public suggestions::ImageManager {
124  public:
125   MockImageManager() {}
126   virtual ~MockImageManager() {}
127   MOCK_METHOD1(Initialize, void(const SuggestionsProfile&));
128   MOCK_METHOD2(GetImageForURL,
129                void(const GURL&,
130                     base::Callback<void(const GURL&, const SkBitmap*)>));
131 };
132
133 class MockBlacklistStore : public suggestions::BlacklistStore {
134  public:
135   MOCK_METHOD1(BlacklistUrl, bool(const GURL&));
136   MOCK_METHOD1(GetFirstUrlFromBlacklist, bool(GURL*));
137   MOCK_METHOD1(RemoveUrl, bool(const GURL&));
138   MOCK_METHOD1(FilterSuggestions, void(SuggestionsProfile*));
139 };
140
141 class SuggestionsServiceTest : public testing::Test {
142  public:
143   void CheckSuggestionsData(const SuggestionsProfile& suggestions_profile) {
144     EXPECT_EQ(1, suggestions_profile.suggestions_size());
145     EXPECT_EQ(kTestTitle, suggestions_profile.suggestions(0).title());
146     EXPECT_EQ(kTestUrl, suggestions_profile.suggestions(0).url());
147     ++suggestions_data_check_count_;
148   }
149
150   void ExpectEmptySuggestionsProfile(const SuggestionsProfile& profile) {
151     EXPECT_EQ(0, profile.suggestions_size());
152     ++suggestions_empty_data_count_;
153   }
154
155   int suggestions_data_check_count_;
156   int suggestions_empty_data_count_;
157
158  protected:
159   SuggestionsServiceTest()
160       : suggestions_data_check_count_(0),
161         suggestions_empty_data_count_(0),
162         factory_(NULL, base::Bind(&CreateURLFetcher)),
163         mock_suggestions_store_(NULL),
164         mock_thumbnail_manager_(NULL) {}
165
166   virtual ~SuggestionsServiceTest() {}
167
168   virtual void SetUp() OVERRIDE {
169     request_context_ = new net::TestURLRequestContextGetter(
170         io_message_loop_.message_loop_proxy());
171   }
172
173   // Enables the "ChromeSuggestions.Group1" field trial.
174   void EnableFieldTrial(const std::string& url,
175                         const std::string& common_params,
176                         const std::string& blacklist_path,
177                         const std::string& blacklist_url_param,
178                         bool control_group) {
179     // Clear the existing |field_trial_list_| to avoid firing a DCHECK.
180     field_trial_list_.reset(NULL);
181     field_trial_list_.reset(
182         new base::FieldTrialList(new metrics::SHA1EntropyProvider("foo")));
183
184     variations::testing::ClearAllVariationParams();
185     std::map<std::string, std::string> params;
186     params[kSuggestionsFieldTrialStateParam] =
187         kSuggestionsFieldTrialStateEnabled;
188     if (control_group) {
189       params[kSuggestionsFieldTrialControlParam] =
190           kSuggestionsFieldTrialStateEnabled;
191     }
192     params[kSuggestionsFieldTrialURLParam] = url;
193     params[kSuggestionsFieldTrialCommonParamsParam] = common_params;
194     params[kSuggestionsFieldTrialBlacklistPathParam] = blacklist_path;
195     params[kSuggestionsFieldTrialBlacklistUrlParam] = blacklist_url_param;
196     variations::AssociateVariationParams(kSuggestionsFieldTrialName, "Group1",
197                                          params);
198     field_trial_ = base::FieldTrialList::CreateFieldTrial(
199         kSuggestionsFieldTrialName, "Group1");
200     field_trial_->group();
201   }
202
203   // Should not be called more than once per test since it stashes the
204   // SuggestionsStore in |mock_suggestions_store_|.
205   SuggestionsService* CreateSuggestionsServiceWithMocks() {
206     mock_suggestions_store_ = new StrictMock<MockSuggestionsStore>();
207     mock_thumbnail_manager_ = new StrictMock<MockImageManager>();
208     mock_blacklist_store_ = new MockBlacklistStore();
209     return new SuggestionsService(
210         request_context_.get(),
211         scoped_ptr<SuggestionsStore>(mock_suggestions_store_),
212         scoped_ptr<ImageManager>(mock_thumbnail_manager_),
213         scoped_ptr<BlacklistStore>(mock_blacklist_store_));
214   }
215
216   void FetchSuggestionsDataNoTimeoutHelper(bool interleaved_requests) {
217     // Field trial enabled with a specific suggestions URL.
218     EnableFieldTrial(kFakeSuggestionsURL, kFakeSuggestionsCommonParams,
219                      kFakeBlacklistPath, kFakeBlacklistUrlParam, false);
220     scoped_ptr<SuggestionsService> suggestions_service(
221         CreateSuggestionsServiceWithMocks());
222     EXPECT_TRUE(suggestions_service != NULL);
223     scoped_ptr<SuggestionsProfile> suggestions_profile(
224         CreateSuggestionsProfile());
225     // Set up net::FakeURLFetcherFactory.
226     std::string expected_url =
227         (std::string(kFakeSuggestionsURL) + "?") + kFakeSuggestionsCommonParams;
228     factory_.SetFakeResponse(GURL(expected_url),
229                              suggestions_profile->SerializeAsString(),
230                              net::HTTP_OK, net::URLRequestStatus::SUCCESS);
231     // Set up expectations on the SuggestionsStore. The number depends on
232     // whether the second request is issued (it won't be issued if the second
233     // fetch occurs before the first request has completed).
234     int expected_count = interleaved_requests ? 1 : 2;
235     EXPECT_CALL(*mock_suggestions_store_,
236                 StoreSuggestions(EqualsProto(*suggestions_profile)))
237         .Times(expected_count)
238         .WillRepeatedly(Return(true));
239
240     // Since there are two requests below, Initialize() will be called twice.
241     EXPECT_CALL(*mock_thumbnail_manager_,
242                 Initialize(EqualsProto(*suggestions_profile)))
243         .Times(expected_count);
244
245     // Expect a call to the blacklist store. Return that there's nothing to
246     // blacklist.
247     EXPECT_CALL(*mock_blacklist_store_, FilterSuggestions(_))
248         .Times(expected_count);
249     EXPECT_CALL(*mock_blacklist_store_, GetFirstUrlFromBlacklist(_))
250         .Times(expected_count)
251         .WillRepeatedly(Return(false));
252
253     // Send the request. The data will be returned to the callback.
254     suggestions_service->FetchSuggestionsDataNoTimeout(base::Bind(
255         &SuggestionsServiceTest::CheckSuggestionsData, base::Unretained(this)));
256
257     if (!interleaved_requests)
258       io_message_loop_.RunUntilIdle();  // Let request complete.
259
260     // Send the request a second time.
261     suggestions_service->FetchSuggestionsDataNoTimeout(base::Bind(
262         &SuggestionsServiceTest::CheckSuggestionsData, base::Unretained(this)));
263
264     // (Testing only) wait until suggestion fetch is complete.
265     io_message_loop_.RunUntilIdle();
266
267     // Ensure that CheckSuggestionsData() ran twice.
268     EXPECT_EQ(2, suggestions_data_check_count_);
269   }
270
271  protected:
272   base::MessageLoopForIO io_message_loop_;
273   net::FakeURLFetcherFactory factory_;
274   // Only used if the SuggestionsService is built with mocks. Not owned.
275   MockSuggestionsStore* mock_suggestions_store_;
276   MockImageManager* mock_thumbnail_manager_;
277   MockBlacklistStore* mock_blacklist_store_;
278   scoped_refptr<net::TestURLRequestContextGetter> request_context_;
279
280  private:
281   scoped_ptr<base::FieldTrialList> field_trial_list_;
282   scoped_refptr<base::FieldTrial> field_trial_;
283
284   DISALLOW_COPY_AND_ASSIGN(SuggestionsServiceTest);
285 };
286
287 TEST_F(SuggestionsServiceTest, IsControlGroup) {
288   // Field trial enabled.
289   EnableFieldTrial("", "", "", "", false);
290   EXPECT_FALSE(SuggestionsService::IsControlGroup());
291
292   EnableFieldTrial("", "", "", "", true);
293   EXPECT_TRUE(SuggestionsService::IsControlGroup());
294 }
295
296 TEST_F(SuggestionsServiceTest, FetchSuggestionsDataNoTimeout) {
297   FetchSuggestionsDataNoTimeoutHelper(false);
298 }
299
300 TEST_F(SuggestionsServiceTest, FetchSuggestionsDataNoTimeoutInterleaved) {
301   FetchSuggestionsDataNoTimeoutHelper(true);
302 }
303
304 TEST_F(SuggestionsServiceTest, FetchSuggestionsDataRequestError) {
305   // Field trial enabled with a specific suggestions URL.
306   EnableFieldTrial(kFakeSuggestionsURL, kFakeSuggestionsCommonParams,
307                    kFakeBlacklistPath, kFakeBlacklistUrlParam, false);
308   scoped_ptr<SuggestionsService> suggestions_service(
309       CreateSuggestionsServiceWithMocks());
310   EXPECT_TRUE(suggestions_service != NULL);
311
312   // Fake a request error.
313   std::string expected_url =
314       (std::string(kFakeSuggestionsURL) + "?") + kFakeSuggestionsCommonParams;
315   factory_.SetFakeResponse(GURL(expected_url), "irrelevant", net::HTTP_OK,
316                            net::URLRequestStatus::FAILED);
317
318   // Set up expectations on the SuggestionsStore.
319   EXPECT_CALL(*mock_suggestions_store_, LoadSuggestions(_))
320       .WillOnce(Return(true));
321   EXPECT_CALL(*mock_thumbnail_manager_, Initialize(_));
322
323   // Expect a call to the blacklist store. Return that there's nothing to
324   // blacklist.
325   EXPECT_CALL(*mock_blacklist_store_, FilterSuggestions(_));
326   EXPECT_CALL(*mock_blacklist_store_, GetFirstUrlFromBlacklist(_))
327       .WillOnce(Return(false));
328
329   // Send the request. Empty data will be returned to the callback.
330   suggestions_service->FetchSuggestionsData(
331       INITIALIZED_ENABLED_HISTORY,  // Normal mode.
332       base::Bind(&SuggestionsServiceTest::ExpectEmptySuggestionsProfile,
333                  base::Unretained(this)));
334
335   // (Testing only) wait until suggestion fetch is complete.
336   io_message_loop_.RunUntilIdle();
337
338   // Ensure that ExpectEmptySuggestionsProfile ran once.
339   EXPECT_EQ(1, suggestions_empty_data_count_);
340 }
341
342 TEST_F(SuggestionsServiceTest, FetchSuggestionsDataResponseNotOK) {
343   // Field trial enabled with a specific suggestions URL.
344   EnableFieldTrial(kFakeSuggestionsURL, kFakeSuggestionsCommonParams,
345                    kFakeBlacklistPath, kFakeBlacklistUrlParam, false);
346   scoped_ptr<SuggestionsService> suggestions_service(
347       CreateSuggestionsServiceWithMocks());
348   EXPECT_TRUE(suggestions_service != NULL);
349
350   // Response code != 200.
351   std::string expected_url =
352       (std::string(kFakeSuggestionsURL) + "?") + kFakeSuggestionsCommonParams;
353   factory_.SetFakeResponse(GURL(expected_url), "irrelevant",
354                            net::HTTP_BAD_REQUEST,
355                            net::URLRequestStatus::SUCCESS);
356
357   // Set up expectations on the SuggestionsStore.
358   EXPECT_CALL(*mock_suggestions_store_, ClearSuggestions());
359
360   // Expect a call to the blacklist store. Return that there's nothing to
361   // blacklist.
362   EXPECT_CALL(*mock_blacklist_store_, GetFirstUrlFromBlacklist(_))
363       .WillOnce(Return(false));
364
365   // Send the request. Empty data will be returned to the callback.
366   suggestions_service->FetchSuggestionsData(
367       INITIALIZED_ENABLED_HISTORY,  // Normal mode.
368       base::Bind(&SuggestionsServiceTest::ExpectEmptySuggestionsProfile,
369                  base::Unretained(this)));
370
371   // (Testing only) wait until suggestion fetch is complete.
372   io_message_loop_.RunUntilIdle();
373
374   // Ensure that ExpectEmptySuggestionsProfile ran once.
375   EXPECT_EQ(1, suggestions_empty_data_count_);
376 }
377
378 TEST_F(SuggestionsServiceTest, FetchSuggestionsDataSyncDisabled) {
379   // Field trial enabled with a specific suggestions URL.
380   EnableFieldTrial(kFakeSuggestionsURL, kFakeSuggestionsCommonParams,
381                    kFakeBlacklistPath, kFakeBlacklistUrlParam, false);
382   scoped_ptr<SuggestionsService> suggestions_service(
383       CreateSuggestionsServiceWithMocks());
384   EXPECT_TRUE(suggestions_service != NULL);
385
386   // Set up expectations on the SuggestionsStore.
387   EXPECT_CALL(*mock_suggestions_store_, ClearSuggestions());
388
389   // Send the request. Cache is cleared and empty data will be returned to the
390   // callback.
391   suggestions_service->FetchSuggestionsData(
392       SYNC_OR_HISTORY_SYNC_DISABLED,
393       base::Bind(&SuggestionsServiceTest::ExpectEmptySuggestionsProfile,
394                  base::Unretained(this)));
395
396   // Wait for posted task to complete.
397   base::MessageLoop::current()->RunUntilIdle();
398
399   // Ensure that ExpectEmptySuggestionsProfile ran once.
400   EXPECT_EQ(1, suggestions_empty_data_count_);
401 }
402
403 TEST_F(SuggestionsServiceTest, FetchSuggestionsDataSyncNotInitializedEnabled) {
404   // Field trial enabled with a specific suggestions URL.
405   EnableFieldTrial(kFakeSuggestionsURL, kFakeSuggestionsCommonParams,
406                    kFakeBlacklistPath, kFakeBlacklistUrlParam, false);
407   scoped_ptr<SuggestionsService> suggestions_service(
408       CreateSuggestionsServiceWithMocks());
409   EXPECT_TRUE(suggestions_service != NULL);
410   scoped_ptr<SuggestionsProfile> suggestions_profile(
411       CreateSuggestionsProfile());
412
413   // Expectations.
414   EXPECT_CALL(*mock_suggestions_store_, LoadSuggestions(_))
415       .WillOnce(DoAll(SetArgPointee<0>(*suggestions_profile), Return(true)));
416   EXPECT_CALL(*mock_thumbnail_manager_,
417               Initialize(EqualsProto(*suggestions_profile)));
418   EXPECT_CALL(*mock_blacklist_store_, FilterSuggestions(_));
419
420   // Send the request. In this state, cached data will be returned to the
421   // caller.
422   suggestions_service->FetchSuggestionsData(
423       NOT_INITIALIZED_ENABLED,
424       base::Bind(&SuggestionsServiceTest::CheckSuggestionsData,
425                  base::Unretained(this)));
426
427   // Wait for posted task to complete.
428   base::MessageLoop::current()->RunUntilIdle();
429
430   // Ensure that CheckSuggestionsData ran once.
431   EXPECT_EQ(1, suggestions_data_check_count_);
432 }
433
434 TEST_F(SuggestionsServiceTest, BlacklistURL) {
435   EnableFieldTrial(kFakeSuggestionsURL, kFakeSuggestionsCommonParams,
436                    kFakeBlacklistPath, kFakeBlacklistUrlParam, false);
437   scoped_ptr<SuggestionsService> suggestions_service(
438       CreateSuggestionsServiceWithMocks());
439   EXPECT_TRUE(suggestions_service != NULL);
440
441   GURL blacklist_url(kBlacklistUrl);
442   std::string request_url = GetExpectedBlacklistRequestUrl(blacklist_url);
443   scoped_ptr<SuggestionsProfile> suggestions_profile(
444       CreateSuggestionsProfile());
445   factory_.SetFakeResponse(GURL(request_url),
446                            suggestions_profile->SerializeAsString(),
447                            net::HTTP_OK, net::URLRequestStatus::SUCCESS);
448
449   // Set up expectations on the SuggestionsStore.
450   EXPECT_CALL(*mock_suggestions_store_,
451               StoreSuggestions(EqualsProto(*suggestions_profile)))
452       .WillOnce(Return(true));
453   EXPECT_CALL(*mock_thumbnail_manager_,
454               Initialize(EqualsProto(*suggestions_profile)));
455
456   // Expected calls to the blacklist store.
457   EXPECT_CALL(*mock_blacklist_store_, BlacklistUrl(Eq(blacklist_url)))
458       .WillOnce(Return(true));
459   EXPECT_CALL(*mock_blacklist_store_, RemoveUrl(Eq(blacklist_url)))
460       .WillOnce(Return(true));
461   EXPECT_CALL(*mock_blacklist_store_, FilterSuggestions(_));
462   EXPECT_CALL(*mock_blacklist_store_, GetFirstUrlFromBlacklist(_))
463       .WillOnce(Return(false));
464
465   // Send the request. The data will be returned to the callback.
466   suggestions_service->BlacklistURL(
467       blacklist_url, base::Bind(&SuggestionsServiceTest::CheckSuggestionsData,
468                                 base::Unretained(this)));
469
470   // (Testing only) wait until blacklist request is complete.
471   io_message_loop_.RunUntilIdle();
472
473   // Ensure that CheckSuggestionsData() ran once.
474   EXPECT_EQ(1, suggestions_data_check_count_);
475 }
476
477 // Initial blacklist request fails, triggering a scheduled upload which
478 // succeeds.
479 TEST_F(SuggestionsServiceTest, BlacklistURLFails) {
480   EnableFieldTrial(kFakeSuggestionsURL, kFakeSuggestionsCommonParams,
481                    kFakeBlacklistPath, kFakeBlacklistUrlParam, false);
482   scoped_ptr<SuggestionsService> suggestions_service(
483       CreateSuggestionsServiceWithMocks());
484   EXPECT_TRUE(suggestions_service != NULL);
485   suggestions_service->set_blacklist_delay(0);  // Don't wait during a test!
486   scoped_ptr<SuggestionsProfile> suggestions_profile(
487       CreateSuggestionsProfile());
488   GURL blacklist_url(kBlacklistUrl);
489
490   // Set up behavior for the first call to blacklist.
491   std::string request_url = GetExpectedBlacklistRequestUrl(blacklist_url);
492   factory_.SetFakeResponse(GURL(request_url), "irrelevant", net::HTTP_OK,
493                            net::URLRequestStatus::FAILED);
494
495   // Expectations specific to the first request.
496   EXPECT_CALL(*mock_blacklist_store_, BlacklistUrl(Eq(blacklist_url)))
497       .WillOnce(Return(true));
498   EXPECT_CALL(*mock_suggestions_store_, LoadSuggestions(_))
499       .WillOnce(DoAll(SetArgPointee<0>(*suggestions_profile), Return(true)));
500
501   // Expectations specific to the second request.
502   EXPECT_CALL(*mock_suggestions_store_,
503               StoreSuggestions(EqualsProto(*suggestions_profile)))
504       .WillOnce(Return(true));
505   EXPECT_CALL(*mock_blacklist_store_, RemoveUrl(Eq(blacklist_url)))
506       .WillOnce(Return(true));
507
508   // Expectations pertaining to both requests.
509   EXPECT_CALL(*mock_blacklist_store_, FilterSuggestions(_)).Times(2);
510   EXPECT_CALL(*mock_blacklist_store_, GetFirstUrlFromBlacklist(_))
511       .WillOnce(Return(true))
512       .WillOnce(DoAll(SetArgPointee<0>(blacklist_url), Return(true)))
513       .WillOnce(Return(false));
514   // There will be two calls to Initialize() (one store, one load).
515   EXPECT_CALL(*mock_thumbnail_manager_,
516               Initialize(EqualsProto(*suggestions_profile)))
517       .Times(2);
518
519   // Send the request. The data will be returned to the callback.
520   suggestions_service->BlacklistURL(
521       blacklist_url, base::Bind(&SuggestionsServiceTest::CheckSuggestionsData,
522                                 base::Unretained(this)));
523
524   // The first FakeURLFetcher was created; we can now set up behavior for the
525   // second call to blacklist.
526   factory_.SetFakeResponse(GURL(request_url),
527                            suggestions_profile->SerializeAsString(),
528                            net::HTTP_OK, net::URLRequestStatus::SUCCESS);
529
530   // (Testing only) wait until both requests are complete.
531   io_message_loop_.RunUntilIdle();
532   // ... Other task gets posted to the message loop.
533   base::MessageLoop::current()->RunUntilIdle();
534   // ... And completes.
535   io_message_loop_.RunUntilIdle();
536
537   // Ensure that CheckSuggestionsData() ran once.
538   EXPECT_EQ(1, suggestions_data_check_count_);
539 }
540
541 TEST_F(SuggestionsServiceTest, GetBlacklistedUrl) {
542   EnableFieldTrial(kFakeSuggestionsURL, kFakeSuggestionsCommonParams,
543                    kFakeBlacklistPath, kFakeBlacklistUrlParam, false);
544
545   scoped_ptr<GURL> request_url;
546   scoped_ptr<net::FakeURLFetcher> fetcher;
547   GURL retrieved_url;
548
549   // Not a blacklist request.
550   request_url.reset(new GURL("http://not-blacklisting.com/a?b=c"));
551   fetcher = CreateURLFetcher(*request_url, NULL, "", net::HTTP_OK,
552                              net::URLRequestStatus::SUCCESS);
553   EXPECT_FALSE(SuggestionsService::GetBlacklistedUrl(*fetcher, &retrieved_url));
554
555   // An actual blacklist request.
556   string blacklisted_url = "http://blacklisted.com/a?b=c&d=e";
557   string encoded_blacklisted_url =
558       "http%3A%2F%2Fblacklisted.com%2Fa%3Fb%3Dc%26d%3De";
559   string blacklist_request_prefix =
560       "https://mysuggestions.com/proto/blacklist?foo=bar&baz=";
561   request_url.reset(
562       new GURL(blacklist_request_prefix + encoded_blacklisted_url));
563   fetcher.reset();
564   fetcher = CreateURLFetcher(*request_url, NULL, "", net::HTTP_OK,
565                              net::URLRequestStatus::SUCCESS);
566   EXPECT_TRUE(SuggestionsService::GetBlacklistedUrl(*fetcher, &retrieved_url));
567   EXPECT_EQ(blacklisted_url, retrieved_url.spec());
568 }
569
570 TEST_F(SuggestionsServiceTest, UpdateBlacklistDelay) {
571   scoped_ptr<SuggestionsService> suggestions_service(
572       CreateSuggestionsServiceWithMocks());
573   int initial_delay = suggestions_service->blacklist_delay();
574
575   // Delay unchanged on success.
576   suggestions_service->UpdateBlacklistDelay(true);
577   EXPECT_EQ(initial_delay, suggestions_service->blacklist_delay());
578
579   // Delay increases on failure.
580   suggestions_service->UpdateBlacklistDelay(false);
581   EXPECT_GT(suggestions_service->blacklist_delay(), initial_delay);
582
583   // Delay resets on success.
584   suggestions_service->UpdateBlacklistDelay(true);
585   EXPECT_EQ(initial_delay, suggestions_service->blacklist_delay());
586 }
587
588 TEST_F(SuggestionsServiceTest, CheckDefaultTimeStamps) {
589   scoped_ptr<SuggestionsService> suggestions_service(
590       CreateSuggestionsServiceWithMocks());
591   SuggestionsProfile suggestions =
592       CreateSuggestionsProfileWithExpiryTimestamps();
593   suggestions_service->SetDefaultExpiryTimestamp(&suggestions,
594                                                  kTestDefaultExpiry);
595   EXPECT_EQ(kTestSetExpiry, suggestions.suggestions(0).expiry_ts());
596   EXPECT_EQ(kTestDefaultExpiry, suggestions.suggestions(1).expiry_ts());
597 }
598 }  // namespace suggestions