OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/remote_suggestions_provider.h" | 5 #include "components/ntp_snippets/remote/remote_suggestions_provider.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 #include <utility> | 8 #include <utility> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
12 #include "base/files/file_path.h" | 12 #include "base/files/file_path.h" |
13 #include "base/files/scoped_temp_dir.h" | 13 #include "base/files/scoped_temp_dir.h" |
14 #include "base/json/json_reader.h" | 14 #include "base/json/json_reader.h" |
15 #include "base/macros.h" | 15 #include "base/macros.h" |
16 #include "base/memory/ptr_util.h" | 16 #include "base/memory/ptr_util.h" |
17 #include "base/message_loop/message_loop.h" | 17 #include "base/message_loop/message_loop.h" |
18 #include "base/run_loop.h" | 18 #include "base/run_loop.h" |
19 #include "base/strings/string_number_conversions.h" | 19 #include "base/strings/string_number_conversions.h" |
20 #include "base/strings/string_util.h" | 20 #include "base/strings/string_util.h" |
21 #include "base/strings/stringprintf.h" | 21 #include "base/strings/stringprintf.h" |
22 #include "base/test/histogram_tester.h" | 22 #include "base/test/histogram_tester.h" |
23 #include "base/test/simple_test_clock.h" | 23 #include "base/test/simple_test_clock.h" |
24 #include "base/threading/thread_task_runner_handle.h" | 24 #include "base/threading/thread_task_runner_handle.h" |
25 #include "base/time/time.h" | 25 #include "base/time/time.h" |
26 #include "components/image_fetcher/image_decoder.h" | 26 #include "components/image_fetcher/image_decoder.h" |
27 #include "components/image_fetcher/image_fetcher.h" | 27 #include "components/image_fetcher/image_fetcher.h" |
28 #include "components/image_fetcher/image_fetcher_delegate.h" | 28 #include "components/image_fetcher/image_fetcher_delegate.h" |
29 #include "components/ntp_snippets/category_factory.h" | 29 #include "components/ntp_snippets/category.h" |
30 #include "components/ntp_snippets/category_info.h" | 30 #include "components/ntp_snippets/category_info.h" |
| 31 #include "components/ntp_snippets/category_rankers/category_ranker.h" |
| 32 #include "components/ntp_snippets/category_rankers/constant_category_ranker.h" |
| 33 #include "components/ntp_snippets/category_rankers/mock_category_ranker.h" |
31 #include "components/ntp_snippets/ntp_snippets_constants.h" | 34 #include "components/ntp_snippets/ntp_snippets_constants.h" |
32 #include "components/ntp_snippets/pref_names.h" | 35 #include "components/ntp_snippets/pref_names.h" |
33 #include "components/ntp_snippets/remote/ntp_snippet.h" | 36 #include "components/ntp_snippets/remote/ntp_snippet.h" |
34 #include "components/ntp_snippets/remote/ntp_snippets_fetcher.h" | 37 #include "components/ntp_snippets/remote/ntp_snippets_fetcher.h" |
35 #include "components/ntp_snippets/remote/ntp_snippets_scheduler.h" | 38 #include "components/ntp_snippets/remote/ntp_snippets_scheduler.h" |
36 #include "components/ntp_snippets/remote/remote_suggestions_database.h" | 39 #include "components/ntp_snippets/remote/remote_suggestions_database.h" |
37 #include "components/ntp_snippets/remote/test_utils.h" | 40 #include "components/ntp_snippets/remote/test_utils.h" |
38 #include "components/ntp_snippets/user_classifier.h" | 41 #include "components/ntp_snippets/user_classifier.h" |
39 #include "components/prefs/testing_pref_service.h" | 42 #include "components/prefs/testing_pref_service.h" |
40 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h" | 43 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h" |
41 #include "components/signin/core/browser/fake_signin_manager.h" | 44 #include "components/signin/core/browser/fake_signin_manager.h" |
42 #include "components/variations/variations_params_manager.h" | 45 #include "components/variations/variations_params_manager.h" |
43 #include "net/url_request/test_url_fetcher_factory.h" | 46 #include "net/url_request/test_url_fetcher_factory.h" |
44 #include "net/url_request/url_request_test_util.h" | 47 #include "net/url_request/url_request_test_util.h" |
45 #include "testing/gmock/include/gmock/gmock.h" | 48 #include "testing/gmock/include/gmock/gmock.h" |
46 #include "testing/gtest/include/gtest/gtest.h" | 49 #include "testing/gtest/include/gtest/gtest.h" |
47 #include "ui/gfx/image/image.h" | 50 #include "ui/gfx/image/image.h" |
48 #include "ui/gfx/image/image_unittest_util.h" | 51 #include "ui/gfx/image/image_unittest_util.h" |
49 | 52 |
50 using image_fetcher::ImageFetcher; | 53 using image_fetcher::ImageFetcher; |
51 using image_fetcher::ImageFetcherDelegate; | 54 using image_fetcher::ImageFetcherDelegate; |
| 55 using testing::_; |
52 using testing::ElementsAre; | 56 using testing::ElementsAre; |
53 using testing::Eq; | 57 using testing::Eq; |
54 using testing::InSequence; | 58 using testing::InSequence; |
55 using testing::Invoke; | 59 using testing::Invoke; |
56 using testing::IsEmpty; | 60 using testing::IsEmpty; |
57 using testing::Mock; | 61 using testing::Mock; |
58 using testing::MockFunction; | 62 using testing::MockFunction; |
59 using testing::NiceMock; | 63 using testing::NiceMock; |
60 using testing::Not; | 64 using testing::Not; |
61 using testing::SaveArg; | 65 using testing::SaveArg; |
62 using testing::SizeIs; | 66 using testing::SizeIs; |
63 using testing::StartsWith; | 67 using testing::StartsWith; |
64 using testing::WithArgs; | 68 using testing::WithArgs; |
65 using testing::_; | |
66 | 69 |
67 namespace ntp_snippets { | 70 namespace ntp_snippets { |
68 | 71 |
69 namespace { | 72 namespace { |
70 | 73 |
71 MATCHER_P(IdEq, value, "") { | 74 MATCHER_P(IdEq, value, "") { |
72 return arg->id() == value; | 75 return arg->id() == value; |
73 } | 76 } |
74 | 77 |
75 MATCHER_P(IdWithinCategoryEq, expected_id, "") { | 78 MATCHER_P(IdWithinCategoryEq, expected_id, "") { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
109 base::Time GetDefaultCreationTime() { | 112 base::Time GetDefaultCreationTime() { |
110 base::Time out_time; | 113 base::Time out_time; |
111 EXPECT_TRUE(base::Time::FromUTCExploded(kDefaultCreationTime, &out_time)); | 114 EXPECT_TRUE(base::Time::FromUTCExploded(kDefaultCreationTime, &out_time)); |
112 return out_time; | 115 return out_time; |
113 } | 116 } |
114 | 117 |
115 base::Time GetDefaultExpirationTime() { | 118 base::Time GetDefaultExpirationTime() { |
116 return base::Time::Now() + base::TimeDelta::FromHours(1); | 119 return base::Time::Now() + base::TimeDelta::FromHours(1); |
117 } | 120 } |
118 | 121 |
| 122 std::string GetCategoryJson(const std::vector<std::string>& snippets, |
| 123 int remote_category_id, |
| 124 const std::string& category_title) { |
| 125 return base::StringPrintf( |
| 126 " {\n" |
| 127 " \"id\": %d,\n" |
| 128 " \"localizedTitle\": \"%s\",\n" |
| 129 " \"suggestions\": [%s]\n" |
| 130 " }\n", |
| 131 remote_category_id, category_title.c_str(), |
| 132 base::JoinString(snippets, ", ").c_str()); |
| 133 } |
| 134 |
| 135 class MultiCategoryJsonBuilder { |
| 136 public: |
| 137 MultiCategoryJsonBuilder() {} |
| 138 |
| 139 MultiCategoryJsonBuilder& AddCategoryWithCustomTitle( |
| 140 const std::vector<std::string>& snippets, |
| 141 int remote_category_id, |
| 142 const std::string& category_title) { |
| 143 category_json_.push_back( |
| 144 GetCategoryJson(snippets, remote_category_id, category_title)); |
| 145 return *this; |
| 146 } |
| 147 |
| 148 MultiCategoryJsonBuilder& AddCategory( |
| 149 const std::vector<std::string>& snippets, |
| 150 int remote_category_id) { |
| 151 return AddCategoryWithCustomTitle( |
| 152 snippets, remote_category_id, |
| 153 "Title" + base::IntToString(remote_category_id)); |
| 154 } |
| 155 |
| 156 std::string Build() { |
| 157 return base::StringPrintf( |
| 158 "{\n" |
| 159 " \"categories\": [\n" |
| 160 "%s\n" |
| 161 " ]\n" |
| 162 "}\n", |
| 163 base::JoinString(category_json_, " ,\n").c_str()); |
| 164 } |
| 165 |
| 166 private: |
| 167 std::vector<std::string> category_json_; |
| 168 }; |
| 169 |
| 170 // TODO(vitaliii): Remove these convenience functions as they do not provide |
| 171 // that much value and add additional redirections obscuring the code. |
119 std::string GetTestJson(const std::vector<std::string>& snippets, | 172 std::string GetTestJson(const std::vector<std::string>& snippets, |
120 const std::string& category_title) { | 173 const std::string& category_title) { |
121 return base::StringPrintf( | 174 return MultiCategoryJsonBuilder() |
122 "{\n" | 175 .AddCategoryWithCustomTitle(snippets, /*remote_category_id=*/1, |
123 " \"categories\": [{\n" | 176 category_title) |
124 " \"id\": 1,\n" | 177 .Build(); |
125 " \"localizedTitle\": \"%s\",\n" | |
126 " \"suggestions\": [%s]\n" | |
127 " }]\n" | |
128 "}\n", | |
129 category_title.c_str(), base::JoinString(snippets, ", ").c_str()); | |
130 } | 178 } |
131 | 179 |
132 std::string GetTestJson(const std::vector<std::string>& snippets) { | 180 std::string GetTestJson(const std::vector<std::string>& snippets) { |
133 return GetTestJson(snippets, kTestJsonDefaultCategoryTitle); | 181 return GetTestJson(snippets, kTestJsonDefaultCategoryTitle); |
134 } | 182 } |
135 | 183 |
136 // TODO(tschumann): Remove the default parameter other_id. It makes the tests | |
137 // less explicit and hard to read. Also get rid of the convenience | |
138 // other_category() and unknown_category() helpers -- tests can just define | |
139 // their own. | |
140 std::string GetMultiCategoryJson(const std::vector<std::string>& articles, | |
141 const std::vector<std::string>& others, | |
142 int other_id = 2) { | |
143 return base::StringPrintf( | |
144 "{\n" | |
145 " \"categories\": [{\n" | |
146 " \"id\": 1,\n" | |
147 " \"localizedTitle\": \"Articles for You\",\n" | |
148 " \"suggestions\": [%s]\n" | |
149 " }, {\n" | |
150 " \"id\": %i,\n" | |
151 " \"localizedTitle\": \"Other Things\",\n" | |
152 " \"suggestions\": [%s]\n" | |
153 " }]\n" | |
154 "}\n", | |
155 base::JoinString(articles, ", ").c_str(), other_id, | |
156 base::JoinString(others, ", ").c_str()); | |
157 } | |
158 | |
159 std::string FormatTime(const base::Time& t) { | 184 std::string FormatTime(const base::Time& t) { |
160 base::Time::Exploded x; | 185 base::Time::Exploded x; |
161 t.UTCExplode(&x); | 186 t.UTCExplode(&x); |
162 return base::StringPrintf("%04d-%02d-%02dT%02d:%02d:%02dZ", x.year, x.month, | 187 return base::StringPrintf("%04d-%02d-%02dT%02d:%02d:%02dZ", x.year, x.month, |
163 x.day_of_month, x.hour, x.minute, x.second); | 188 x.day_of_month, x.hour, x.minute, x.second); |
164 } | 189 } |
165 | 190 |
166 std::string GetSnippetWithUrlAndTimesAndSource( | 191 std::string GetSnippetWithUrlAndTimesAndSource( |
167 const std::vector<std::string>& ids, | 192 const std::vector<std::string>& ids, |
168 const std::string& url, | 193 const std::string& url, |
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
394 class RemoteSuggestionsProviderTest : public ::testing::Test { | 419 class RemoteSuggestionsProviderTest : public ::testing::Test { |
395 public: | 420 public: |
396 RemoteSuggestionsProviderTest() | 421 RemoteSuggestionsProviderTest() |
397 : params_manager_(ntp_snippets::kStudyName, | 422 : params_manager_(ntp_snippets::kStudyName, |
398 {{"content_suggestions_backend", | 423 {{"content_suggestions_backend", |
399 kTestContentSuggestionsServerEndpoint}, | 424 kTestContentSuggestionsServerEndpoint}, |
400 {"fetching_personalization", "non_personal"}}), | 425 {"fetching_personalization", "non_personal"}}), |
401 fake_url_fetcher_factory_( | 426 fake_url_fetcher_factory_( |
402 /*default_factory=*/&failing_url_fetcher_factory_), | 427 /*default_factory=*/&failing_url_fetcher_factory_), |
403 test_url_(kTestContentSuggestionsServerWithAPIKey), | 428 test_url_(kTestContentSuggestionsServerWithAPIKey), |
| 429 category_ranker_(base::MakeUnique<ConstantCategoryRanker>()), |
404 user_classifier_(/*pref_service=*/nullptr), | 430 user_classifier_(/*pref_service=*/nullptr), |
405 image_fetcher_(nullptr), | 431 image_fetcher_(nullptr), |
406 image_decoder_(nullptr), | 432 image_decoder_(nullptr), |
407 database_(nullptr) { | 433 database_(nullptr) { |
408 RemoteSuggestionsProvider::RegisterProfilePrefs( | 434 RemoteSuggestionsProvider::RegisterProfilePrefs( |
409 utils_.pref_service()->registry()); | 435 utils_.pref_service()->registry()); |
410 RequestThrottler::RegisterProfilePrefs(utils_.pref_service()->registry()); | 436 RequestThrottler::RegisterProfilePrefs(utils_.pref_service()->registry()); |
411 | 437 |
412 EXPECT_TRUE(database_dir_.CreateUniqueTempDir()); | 438 EXPECT_TRUE(database_dir_.CreateUniqueTempDir()); |
413 } | 439 } |
414 | 440 |
415 ~RemoteSuggestionsProviderTest() override { | 441 ~RemoteSuggestionsProviderTest() override { |
416 // We need to run the message loop after deleting the database, because | 442 // We need to run the message loop after deleting the database, because |
417 // ProtoDatabaseImpl deletes the actual LevelDB asynchronously on the task | 443 // ProtoDatabaseImpl deletes the actual LevelDB asynchronously on the task |
418 // runner. Without this, we'd get reports of memory leaks. | 444 // runner. Without this, we'd get reports of memory leaks. |
419 base::RunLoop().RunUntilIdle(); | 445 base::RunLoop().RunUntilIdle(); |
420 } | 446 } |
421 | 447 |
| 448 // TODO(vitaliii): Rewrite this function to initialize a test class member |
| 449 // instead of creating a new service. |
422 std::unique_ptr<RemoteSuggestionsProvider> MakeSnippetsService( | 450 std::unique_ptr<RemoteSuggestionsProvider> MakeSnippetsService( |
423 bool set_empty_response = true) { | 451 bool set_empty_response = true) { |
424 auto service = MakeSnippetsServiceWithoutInitialization(); | 452 auto service = MakeSnippetsServiceWithoutInitialization(); |
425 WaitForSnippetsServiceInitialization(service.get(), set_empty_response); | 453 WaitForSnippetsServiceInitialization(service.get(), set_empty_response); |
426 return service; | 454 return service; |
427 } | 455 } |
428 | 456 |
429 std::unique_ptr<RemoteSuggestionsProvider> | 457 std::unique_ptr<RemoteSuggestionsProvider> |
430 MakeSnippetsServiceWithoutInitialization() { | 458 MakeSnippetsServiceWithoutInitialization() { |
431 scoped_refptr<base::SingleThreadTaskRunner> task_runner( | 459 scoped_refptr<base::SingleThreadTaskRunner> task_runner( |
432 base::ThreadTaskRunnerHandle::Get()); | 460 base::ThreadTaskRunnerHandle::Get()); |
433 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter = | 461 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter = |
434 new net::TestURLRequestContextGetter(task_runner.get()); | 462 new net::TestURLRequestContextGetter(task_runner.get()); |
435 | 463 |
436 utils_.ResetSigninManager(); | 464 utils_.ResetSigninManager(); |
437 std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher = | 465 std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher = |
438 base::MakeUnique<NTPSnippetsFetcher>( | 466 base::MakeUnique<NTPSnippetsFetcher>( |
439 utils_.fake_signin_manager(), fake_token_service_.get(), | 467 utils_.fake_signin_manager(), fake_token_service_.get(), |
440 std::move(request_context_getter), utils_.pref_service(), | 468 std::move(request_context_getter), utils_.pref_service(), nullptr, |
441 &category_factory_, nullptr, base::Bind(&ParseJson), kAPIKey, | 469 base::Bind(&ParseJson), kAPIKey, &user_classifier_); |
442 &user_classifier_); | |
443 | 470 |
444 utils_.fake_signin_manager()->SignIn("foo@bar.com"); | 471 utils_.fake_signin_manager()->SignIn("foo@bar.com"); |
445 | 472 |
446 auto image_fetcher = base::MakeUnique<NiceMock<MockImageFetcher>>(); | 473 auto image_fetcher = base::MakeUnique<NiceMock<MockImageFetcher>>(); |
447 | 474 |
448 image_fetcher_ = image_fetcher.get(); | 475 image_fetcher_ = image_fetcher.get(); |
449 EXPECT_CALL(*image_fetcher, SetImageFetcherDelegate(_)); | 476 EXPECT_CALL(*image_fetcher, SetImageFetcherDelegate(_)); |
450 auto image_decoder = base::MakeUnique<FakeImageDecoder>(); | 477 auto image_decoder = base::MakeUnique<FakeImageDecoder>(); |
451 image_decoder_ = image_decoder.get(); | 478 image_decoder_ = image_decoder.get(); |
452 EXPECT_FALSE(observer_); | 479 EXPECT_FALSE(observer_); |
453 observer_ = base::MakeUnique<FakeContentSuggestionsProviderObserver>(); | 480 observer_ = base::MakeUnique<FakeContentSuggestionsProviderObserver>(); |
454 auto database = base::MakeUnique<RemoteSuggestionsDatabase>( | 481 auto database = base::MakeUnique<RemoteSuggestionsDatabase>( |
455 database_dir_.GetPath(), task_runner); | 482 database_dir_.GetPath(), task_runner); |
456 database_ = database.get(); | 483 database_ = database.get(); |
457 return base::MakeUnique<RemoteSuggestionsProvider>( | 484 return base::MakeUnique<RemoteSuggestionsProvider>( |
458 observer_.get(), &category_factory_, utils_.pref_service(), "fr", | 485 observer_.get(), utils_.pref_service(), "fr", category_ranker_.get(), |
459 &user_classifier_, &scheduler_, std::move(snippets_fetcher), | 486 &user_classifier_, &scheduler_, std::move(snippets_fetcher), |
460 std::move(image_fetcher), std::move(image_decoder), | 487 std::move(image_fetcher), std::move(image_decoder), std::move(database), |
461 std::move(database), | |
462 base::MakeUnique<RemoteSuggestionsStatusService>( | 488 base::MakeUnique<RemoteSuggestionsStatusService>( |
463 utils_.fake_signin_manager(), utils_.pref_service())); | 489 utils_.fake_signin_manager(), utils_.pref_service())); |
464 } | 490 } |
465 | 491 |
466 void WaitForSnippetsServiceInitialization(RemoteSuggestionsProvider* service, | 492 void WaitForSnippetsServiceInitialization(RemoteSuggestionsProvider* service, |
467 bool set_empty_response) { | 493 bool set_empty_response) { |
468 EXPECT_EQ(RemoteSuggestionsProvider::State::NOT_INITED, service->state_); | 494 EXPECT_EQ(RemoteSuggestionsProvider::State::NOT_INITED, service->state_); |
469 | 495 |
470 // Add an initial fetch response, as the service tries to fetch when there | 496 // Add an initial fetch response, as the service tries to fetch when there |
471 // is nothing in the DB. | 497 // is nothing in the DB. |
472 if (set_empty_response) { | 498 if (set_empty_response) { |
473 SetUpFetchResponse(GetTestJson(std::vector<std::string>())); | 499 SetUpFetchResponse(GetTestJson(std::vector<std::string>())); |
474 } | 500 } |
475 | 501 |
476 // TODO(treib): Find a better way to wait for initialization to finish. | 502 // TODO(treib): Find a better way to wait for initialization to finish. |
477 base::RunLoop().RunUntilIdle(); | 503 base::RunLoop().RunUntilIdle(); |
478 EXPECT_NE(RemoteSuggestionsProvider::State::NOT_INITED, service->state_); | 504 EXPECT_NE(RemoteSuggestionsProvider::State::NOT_INITED, service->state_); |
479 } | 505 } |
480 | 506 |
481 void ResetSnippetsService( | 507 void ResetSnippetsService(std::unique_ptr<RemoteSuggestionsProvider>* service, |
482 std::unique_ptr<RemoteSuggestionsProvider>* service) { | 508 bool set_empty_response) { |
483 service->reset(); | 509 service->reset(); |
484 observer_.reset(); | 510 observer_.reset(); |
485 *service = MakeSnippetsService(); | 511 *service = MakeSnippetsService(set_empty_response); |
| 512 } |
| 513 |
| 514 void SetCategoryRanker(std::unique_ptr<CategoryRanker> category_ranker) { |
| 515 category_ranker_ = std::move(category_ranker); |
486 } | 516 } |
487 | 517 |
488 ContentSuggestion::ID MakeArticleID(const std::string& id_within_category) { | 518 ContentSuggestion::ID MakeArticleID(const std::string& id_within_category) { |
489 return ContentSuggestion::ID(articles_category(), id_within_category); | 519 return ContentSuggestion::ID(articles_category(), id_within_category); |
490 } | 520 } |
491 | 521 |
492 Category articles_category() { | 522 Category articles_category() { |
493 return category_factory_.FromKnownCategory(KnownCategories::ARTICLES); | 523 return Category::FromKnownCategory(KnownCategories::ARTICLES); |
494 } | 524 } |
495 | 525 |
496 ContentSuggestion::ID MakeOtherID(const std::string& id_within_category) { | 526 ContentSuggestion::ID MakeOtherID(const std::string& id_within_category) { |
497 return ContentSuggestion::ID(other_category(), id_within_category); | 527 return ContentSuggestion::ID(other_category(), id_within_category); |
498 } | 528 } |
499 | 529 |
500 Category other_category() { return category_factory_.FromRemoteCategory(2); } | 530 // TODO(tschumann): Get rid of the convenience other_category() and |
| 531 // unknown_category() helpers -- tests can just define their own. |
| 532 Category other_category() { return Category::FromRemoteCategory(2); } |
501 | 533 |
502 Category unknown_category() { | 534 Category unknown_category() { |
503 return category_factory_.FromRemoteCategory(kUnknownRemoteCategoryId); | 535 return Category::FromRemoteCategory(kUnknownRemoteCategoryId); |
504 } | 536 } |
505 | 537 |
506 protected: | 538 protected: |
507 const GURL& test_url() { return test_url_; } | 539 const GURL& test_url() { return test_url_; } |
508 FakeContentSuggestionsProviderObserver& observer() { return *observer_; } | 540 FakeContentSuggestionsProviderObserver& observer() { return *observer_; } |
509 MockScheduler& mock_scheduler() { return scheduler_; } | 541 MockScheduler& mock_scheduler() { return scheduler_; } |
510 // TODO(tschumann): Make this a strict-mock. We want to avoid unneccesary | 542 // TODO(tschumann): Make this a strict-mock. We want to avoid unneccesary |
511 // network requests. | 543 // network requests. |
512 NiceMock<MockImageFetcher>* image_fetcher() { return image_fetcher_; } | 544 NiceMock<MockImageFetcher>* image_fetcher() { return image_fetcher_; } |
513 FakeImageDecoder* image_decoder() { return image_decoder_; } | 545 FakeImageDecoder* image_decoder() { return image_decoder_; } |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
546 | 578 |
547 private: | 579 private: |
548 variations::testing::VariationParamsManager params_manager_; | 580 variations::testing::VariationParamsManager params_manager_; |
549 test::RemoteSuggestionsTestUtils utils_; | 581 test::RemoteSuggestionsTestUtils utils_; |
550 base::MessageLoop message_loop_; | 582 base::MessageLoop message_loop_; |
551 FailingFakeURLFetcherFactory failing_url_fetcher_factory_; | 583 FailingFakeURLFetcherFactory failing_url_fetcher_factory_; |
552 // Instantiation of factory automatically sets itself as URLFetcher's factory. | 584 // Instantiation of factory automatically sets itself as URLFetcher's factory. |
553 net::FakeURLFetcherFactory fake_url_fetcher_factory_; | 585 net::FakeURLFetcherFactory fake_url_fetcher_factory_; |
554 const GURL test_url_; | 586 const GURL test_url_; |
555 std::unique_ptr<OAuth2TokenService> fake_token_service_; | 587 std::unique_ptr<OAuth2TokenService> fake_token_service_; |
| 588 std::unique_ptr<CategoryRanker> category_ranker_; |
556 UserClassifier user_classifier_; | 589 UserClassifier user_classifier_; |
557 NiceMock<MockScheduler> scheduler_; | 590 NiceMock<MockScheduler> scheduler_; |
558 std::unique_ptr<FakeContentSuggestionsProviderObserver> observer_; | 591 std::unique_ptr<FakeContentSuggestionsProviderObserver> observer_; |
559 CategoryFactory category_factory_; | |
560 NiceMock<MockImageFetcher>* image_fetcher_; | 592 NiceMock<MockImageFetcher>* image_fetcher_; |
561 FakeImageDecoder* image_decoder_; | 593 FakeImageDecoder* image_decoder_; |
562 | 594 |
563 base::ScopedTempDir database_dir_; | 595 base::ScopedTempDir database_dir_; |
564 RemoteSuggestionsDatabase* database_; | 596 RemoteSuggestionsDatabase* database_; |
565 | 597 |
566 DISALLOW_COPY_AND_ASSIGN(RemoteSuggestionsProviderTest); | 598 DISALLOW_COPY_AND_ASSIGN(RemoteSuggestionsProviderTest); |
567 }; | 599 }; |
568 | 600 |
569 TEST_F(RemoteSuggestionsProviderTest, ScheduleOnStart) { | 601 TEST_F(RemoteSuggestionsProviderTest, ScheduleOnStart) { |
(...skipping 14 matching lines...) Expand all Loading... |
584 SetUpFetchResponse(GetTestJson({GetSnippet()})); | 616 SetUpFetchResponse(GetTestJson({GetSnippet()})); |
585 auto service = MakeSnippetsService(/*set_empty_response=*/false); | 617 auto service = MakeSnippetsService(/*set_empty_response=*/false); |
586 | 618 |
587 // When recreating the service, we should not get any |Schedule| calls: | 619 // When recreating the service, we should not get any |Schedule| calls: |
588 // The tasks are already scheduled with the correct intervals, so nothing on | 620 // The tasks are already scheduled with the correct intervals, so nothing on |
589 // initialization, and the service has data from the DB, so no automatic fetch | 621 // initialization, and the service has data from the DB, so no automatic fetch |
590 // should happen. | 622 // should happen. |
591 Mock::VerifyAndClearExpectations(&mock_scheduler()); | 623 Mock::VerifyAndClearExpectations(&mock_scheduler()); |
592 EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(0); | 624 EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(0); |
593 EXPECT_CALL(mock_scheduler(), Unschedule()).Times(0); | 625 EXPECT_CALL(mock_scheduler(), Unschedule()).Times(0); |
594 ResetSnippetsService(&service); | 626 ResetSnippetsService(&service, /*set_empty_response=*/true); |
595 } | 627 } |
596 | 628 |
597 TEST_F(RemoteSuggestionsProviderTest, RescheduleAfterSuccessfulFetch) { | 629 TEST_F(RemoteSuggestionsProviderTest, RescheduleAfterSuccessfulFetch) { |
598 // We should get two |Schedule| calls: The first when initialization | 630 // We should get two |Schedule| calls: The first when initialization |
599 // completes, the second one after the automatic (since the service doesn't | 631 // completes, the second one after the automatic (since the service doesn't |
600 // have any data yet) fetch finishes. | 632 // have any data yet) fetch finishes. |
601 EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(2); | 633 EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(2); |
602 auto service = MakeSnippetsService(); | 634 auto service = MakeSnippetsService(); |
603 | 635 |
604 // A successful fetch should trigger another |Schedule|. | 636 // A successful fetch should trigger another |Schedule|. |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
735 CategoryInfo info_with_title = service->GetCategoryInfo(articles_category()); | 767 CategoryInfo info_with_title = service->GetCategoryInfo(articles_category()); |
736 EXPECT_THAT(info_before.title(), Not(Eq(info_with_title.title()))); | 768 EXPECT_THAT(info_before.title(), Not(Eq(info_with_title.title()))); |
737 EXPECT_THAT(test_default_title, Eq(info_with_title.title())); | 769 EXPECT_THAT(test_default_title, Eq(info_with_title.title())); |
738 EXPECT_THAT(info_before.has_more_action(), Eq(true)); | 770 EXPECT_THAT(info_before.has_more_action(), Eq(true)); |
739 EXPECT_THAT(info_before.has_reload_action(), Eq(true)); | 771 EXPECT_THAT(info_before.has_reload_action(), Eq(true)); |
740 EXPECT_THAT(info_before.has_view_all_action(), Eq(false)); | 772 EXPECT_THAT(info_before.has_view_all_action(), Eq(false)); |
741 EXPECT_THAT(info_before.show_if_empty(), Eq(true)); | 773 EXPECT_THAT(info_before.show_if_empty(), Eq(true)); |
742 } | 774 } |
743 | 775 |
744 TEST_F(RemoteSuggestionsProviderTest, MultipleCategories) { | 776 TEST_F(RemoteSuggestionsProviderTest, MultipleCategories) { |
745 std::string json_str( | |
746 GetMultiCategoryJson({GetSnippetN(0)}, {GetSnippetN(1)})); | |
747 | |
748 auto service = MakeSnippetsService(); | 777 auto service = MakeSnippetsService(); |
749 | 778 std::string json_str = |
| 779 MultiCategoryJsonBuilder() |
| 780 .AddCategory({GetSnippetN(0)}, /*remote_category_id=*/1) |
| 781 .AddCategory({GetSnippetN(1)}, /*remote_category_id=*/2) |
| 782 .Build(); |
750 LoadFromJSONString(service.get(), json_str); | 783 LoadFromJSONString(service.get(), json_str); |
751 | 784 |
752 ASSERT_THAT(observer().statuses(), | 785 ASSERT_THAT(observer().statuses(), |
753 Eq(std::map<Category, CategoryStatus, Category::CompareByID>{ | 786 Eq(std::map<Category, CategoryStatus, Category::CompareByID>{ |
754 {articles_category(), CategoryStatus::AVAILABLE}, | 787 {articles_category(), CategoryStatus::AVAILABLE}, |
755 {other_category(), CategoryStatus::AVAILABLE}, | 788 {other_category(), CategoryStatus::AVAILABLE}, |
756 })); | 789 })); |
757 | 790 |
758 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1)); | 791 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1)); |
759 EXPECT_THAT(service->GetSnippetsForTesting(other_category()), SizeIs(1)); | 792 EXPECT_THAT(service->GetSnippetsForTesting(other_category()), SizeIs(1)); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
792 auto service = MakeSnippetsService(); | 825 auto service = MakeSnippetsService(); |
793 CategoryInfo article_info = service->GetCategoryInfo(articles_category()); | 826 CategoryInfo article_info = service->GetCategoryInfo(articles_category()); |
794 EXPECT_THAT(article_info.has_more_action(), Eq(true)); | 827 EXPECT_THAT(article_info.has_more_action(), Eq(true)); |
795 EXPECT_THAT(article_info.has_reload_action(), Eq(true)); | 828 EXPECT_THAT(article_info.has_reload_action(), Eq(true)); |
796 EXPECT_THAT(article_info.has_view_all_action(), Eq(false)); | 829 EXPECT_THAT(article_info.has_view_all_action(), Eq(false)); |
797 EXPECT_THAT(article_info.show_if_empty(), Eq(true)); | 830 EXPECT_THAT(article_info.show_if_empty(), Eq(true)); |
798 } | 831 } |
799 | 832 |
800 TEST_F(RemoteSuggestionsProviderTest, ExperimentalCategoryInfo) { | 833 TEST_F(RemoteSuggestionsProviderTest, ExperimentalCategoryInfo) { |
801 auto service = MakeSnippetsService(); | 834 auto service = MakeSnippetsService(); |
802 | 835 std::string json_str = |
| 836 MultiCategoryJsonBuilder() |
| 837 .AddCategory({GetSnippetN(0)}, /*remote_category_id=*/1) |
| 838 .AddCategory({GetSnippetN(1)}, kUnknownRemoteCategoryId) |
| 839 .Build(); |
803 // Load data with multiple categories so that a new experimental category gets | 840 // Load data with multiple categories so that a new experimental category gets |
804 // registered. | 841 // registered. |
805 LoadFromJSONString(service.get(), | 842 LoadFromJSONString(service.get(), json_str); |
806 GetMultiCategoryJson({GetSnippetN(0)}, {GetSnippetN(1)}, | 843 |
807 kUnknownRemoteCategoryId)); | |
808 CategoryInfo info = service->GetCategoryInfo(unknown_category()); | 844 CategoryInfo info = service->GetCategoryInfo(unknown_category()); |
809 EXPECT_THAT(info.has_more_action(), Eq(false)); | 845 EXPECT_THAT(info.has_more_action(), Eq(false)); |
810 EXPECT_THAT(info.has_reload_action(), Eq(false)); | 846 EXPECT_THAT(info.has_reload_action(), Eq(false)); |
811 EXPECT_THAT(info.has_view_all_action(), Eq(false)); | 847 EXPECT_THAT(info.has_view_all_action(), Eq(false)); |
812 EXPECT_THAT(info.show_if_empty(), Eq(false)); | 848 EXPECT_THAT(info.show_if_empty(), Eq(false)); |
813 } | 849 } |
814 | 850 |
| 851 TEST_F(RemoteSuggestionsProviderTest, AddRemoteCategoriesToCategoryRanker) { |
| 852 auto mock_ranker = base::MakeUnique<MockCategoryRanker>(); |
| 853 MockCategoryRanker* raw_mock_ranker = mock_ranker.get(); |
| 854 SetCategoryRanker(std::move(mock_ranker)); |
| 855 std::string json_str = |
| 856 MultiCategoryJsonBuilder() |
| 857 .AddCategory({GetSnippetN(0)}, /*remote_category_id=*/11) |
| 858 .AddCategory({GetSnippetN(1)}, /*remote_category_id=*/13) |
| 859 .AddCategory({GetSnippetN(2)}, /*remote_category_id=*/12) |
| 860 .Build(); |
| 861 SetUpFetchResponse(json_str); |
| 862 { |
| 863 // The order of categories is determined by the order in which they are |
| 864 // added. Thus, the latter is tested here. |
| 865 InSequence s; |
| 866 EXPECT_CALL(*raw_mock_ranker, |
| 867 AppendCategoryIfNecessary(Category::FromRemoteCategory(11))); |
| 868 EXPECT_CALL(*raw_mock_ranker, |
| 869 AppendCategoryIfNecessary(Category::FromRemoteCategory(13))); |
| 870 EXPECT_CALL(*raw_mock_ranker, |
| 871 AppendCategoryIfNecessary(Category::FromRemoteCategory(12))); |
| 872 } |
| 873 auto service = MakeSnippetsService(/*set_empty_response=*/false); |
| 874 } |
| 875 |
815 TEST_F(RemoteSuggestionsProviderTest, PersistCategoryInfos) { | 876 TEST_F(RemoteSuggestionsProviderTest, PersistCategoryInfos) { |
816 auto service = MakeSnippetsService(); | 877 auto service = MakeSnippetsService(); |
817 | 878 // TODO(vitaliii): Use |articles_category()| instead of constant ID below. |
818 LoadFromJSONString(service.get(), | 879 std::string json_str = |
819 GetMultiCategoryJson({GetSnippetN(0)}, {GetSnippetN(1)}, | 880 MultiCategoryJsonBuilder() |
820 kUnknownRemoteCategoryId)); | 881 .AddCategoryWithCustomTitle( |
| 882 {GetSnippetN(0)}, /*remote_category_id=*/1, "Articles for You") |
| 883 .AddCategoryWithCustomTitle({GetSnippetN(1)}, |
| 884 kUnknownRemoteCategoryId, "Other Things") |
| 885 .Build(); |
| 886 LoadFromJSONString(service.get(), json_str); |
821 | 887 |
822 ASSERT_EQ(observer().StatusForCategory(articles_category()), | 888 ASSERT_EQ(observer().StatusForCategory(articles_category()), |
823 CategoryStatus::AVAILABLE); | 889 CategoryStatus::AVAILABLE); |
824 ASSERT_EQ(observer().StatusForCategory(unknown_category()), | 890 ASSERT_EQ(observer().StatusForCategory(unknown_category()), |
825 CategoryStatus::AVAILABLE); | 891 CategoryStatus::AVAILABLE); |
826 | 892 |
827 CategoryInfo info_articles_before = | 893 CategoryInfo info_articles_before = |
828 service->GetCategoryInfo(articles_category()); | 894 service->GetCategoryInfo(articles_category()); |
829 CategoryInfo info_unknown_before = | 895 CategoryInfo info_unknown_before = |
830 service->GetCategoryInfo(unknown_category()); | 896 service->GetCategoryInfo(unknown_category()); |
831 | 897 |
832 // Recreate the service to simulate a Chrome restart. | 898 // Recreate the service to simulate a Chrome restart. |
833 ResetSnippetsService(&service); | 899 ResetSnippetsService(&service, /*set_empty_response=*/true); |
834 | 900 |
835 // The categories should have been restored. | 901 // The categories should have been restored. |
836 ASSERT_NE(observer().StatusForCategory(articles_category()), | 902 ASSERT_NE(observer().StatusForCategory(articles_category()), |
837 CategoryStatus::NOT_PROVIDED); | 903 CategoryStatus::NOT_PROVIDED); |
838 ASSERT_NE(observer().StatusForCategory(unknown_category()), | 904 ASSERT_NE(observer().StatusForCategory(unknown_category()), |
839 CategoryStatus::NOT_PROVIDED); | 905 CategoryStatus::NOT_PROVIDED); |
840 | 906 |
841 EXPECT_EQ(observer().StatusForCategory(articles_category()), | 907 EXPECT_EQ(observer().StatusForCategory(articles_category()), |
842 CategoryStatus::AVAILABLE); | 908 CategoryStatus::AVAILABLE); |
843 EXPECT_EQ(observer().StatusForCategory(unknown_category()), | 909 EXPECT_EQ(observer().StatusForCategory(unknown_category()), |
844 CategoryStatus::AVAILABLE); | 910 CategoryStatus::AVAILABLE); |
845 | 911 |
846 CategoryInfo info_articles_after = | 912 CategoryInfo info_articles_after = |
847 service->GetCategoryInfo(articles_category()); | 913 service->GetCategoryInfo(articles_category()); |
848 CategoryInfo info_unknown_after = | 914 CategoryInfo info_unknown_after = |
849 service->GetCategoryInfo(unknown_category()); | 915 service->GetCategoryInfo(unknown_category()); |
850 | 916 |
851 EXPECT_EQ(info_articles_before.title(), info_articles_after.title()); | 917 EXPECT_EQ(info_articles_before.title(), info_articles_after.title()); |
852 EXPECT_EQ(info_unknown_before.title(), info_unknown_after.title()); | 918 EXPECT_EQ(info_unknown_before.title(), info_unknown_after.title()); |
853 } | 919 } |
854 | 920 |
| 921 TEST_F(RemoteSuggestionsProviderTest, PersistRemoteCategoryOrder) { |
| 922 // We create a service with a normal ranker to store the order. |
| 923 std::string json_str = |
| 924 MultiCategoryJsonBuilder() |
| 925 .AddCategory({GetSnippetN(0)}, /*remote_category_id=*/11) |
| 926 .AddCategory({GetSnippetN(1)}, /*remote_category_id=*/13) |
| 927 .AddCategory({GetSnippetN(2)}, /*remote_category_id=*/12) |
| 928 .Build(); |
| 929 SetUpFetchResponse(json_str); |
| 930 auto service = MakeSnippetsService(/*set_empty_response=*/false); |
| 931 |
| 932 // We manually recreate the service to simulate Chrome restart and enforce a |
| 933 // mock ranker. The response is cleared to ensure that the order is not |
| 934 // fetched. |
| 935 SetUpFetchResponse(""); |
| 936 auto mock_ranker = base::MakeUnique<MockCategoryRanker>(); |
| 937 MockCategoryRanker* raw_mock_ranker = mock_ranker.get(); |
| 938 SetCategoryRanker(std::move(mock_ranker)); |
| 939 { |
| 940 // The order of categories is determined by the order in which they are |
| 941 // added. Thus, the latter is tested here. |
| 942 InSequence s; |
| 943 // Article category always exists and, therefore, it is stored in prefs too. |
| 944 EXPECT_CALL(*raw_mock_ranker, |
| 945 AppendCategoryIfNecessary(articles_category())); |
| 946 |
| 947 EXPECT_CALL(*raw_mock_ranker, |
| 948 AppendCategoryIfNecessary(Category::FromRemoteCategory(11))); |
| 949 EXPECT_CALL(*raw_mock_ranker, |
| 950 AppendCategoryIfNecessary(Category::FromRemoteCategory(13))); |
| 951 EXPECT_CALL(*raw_mock_ranker, |
| 952 AppendCategoryIfNecessary(Category::FromRemoteCategory(12))); |
| 953 } |
| 954 ResetSnippetsService(&service, /*set_empty_response=*/false); |
| 955 } |
| 956 |
855 TEST_F(RemoteSuggestionsProviderTest, PersistSuggestions) { | 957 TEST_F(RemoteSuggestionsProviderTest, PersistSuggestions) { |
856 auto service = MakeSnippetsService(); | 958 auto service = MakeSnippetsService(); |
857 | 959 std::string json_str = |
858 LoadFromJSONString(service.get(), | 960 MultiCategoryJsonBuilder() |
859 GetMultiCategoryJson({GetSnippetN(0)}, {GetSnippetN(1)})); | 961 .AddCategory({GetSnippetN(0)}, /*remote_category_id=*/1) |
| 962 .AddCategory({GetSnippetN(2)}, /*remote_category_id=*/2) |
| 963 .Build(); |
| 964 LoadFromJSONString(service.get(), json_str); |
860 | 965 |
861 ASSERT_THAT(observer().SuggestionsForCategory(articles_category()), | 966 ASSERT_THAT(observer().SuggestionsForCategory(articles_category()), |
862 SizeIs(1)); | 967 SizeIs(1)); |
863 ASSERT_THAT(observer().SuggestionsForCategory(other_category()), SizeIs(1)); | 968 ASSERT_THAT(observer().SuggestionsForCategory(other_category()), SizeIs(1)); |
864 | 969 |
865 // Recreate the service to simulate a Chrome restart. | 970 // Recreate the service to simulate a Chrome restart. |
866 ResetSnippetsService(&service); | 971 ResetSnippetsService(&service, /*set_empty_response=*/true); |
867 | 972 |
868 // The suggestions in both categories should have been restored. | 973 // The suggestions in both categories should have been restored. |
869 EXPECT_THAT(observer().SuggestionsForCategory(articles_category()), | 974 EXPECT_THAT(observer().SuggestionsForCategory(articles_category()), |
870 SizeIs(1)); | 975 SizeIs(1)); |
871 EXPECT_THAT(observer().SuggestionsForCategory(other_category()), SizeIs(1)); | 976 EXPECT_THAT(observer().SuggestionsForCategory(other_category()), SizeIs(1)); |
872 } | 977 } |
873 | 978 |
874 TEST_F(RemoteSuggestionsProviderTest, DontNotifyIfNotAvailable) { | 979 TEST_F(RemoteSuggestionsProviderTest, DontNotifyIfNotAvailable) { |
875 // Get some suggestions into the database. | 980 // Get some suggestions into the database. |
876 auto service = MakeSnippetsService(); | 981 auto service = MakeSnippetsService(); |
877 LoadFromJSONString(service.get(), | 982 std::string json_str = |
878 GetMultiCategoryJson({GetSnippetN(0)}, {GetSnippetN(1)})); | 983 MultiCategoryJsonBuilder() |
| 984 .AddCategory({GetSnippetN(0)}, |
| 985 /*remote_category_id=*/1) |
| 986 .AddCategory({GetSnippetN(1)}, /*remote_category_id=*/2) |
| 987 .Build(); |
| 988 LoadFromJSONString(service.get(), json_str); |
| 989 |
879 ASSERT_THAT(observer().SuggestionsForCategory(articles_category()), | 990 ASSERT_THAT(observer().SuggestionsForCategory(articles_category()), |
880 SizeIs(1)); | 991 SizeIs(1)); |
881 ASSERT_THAT(observer().SuggestionsForCategory(other_category()), SizeIs(1)); | 992 ASSERT_THAT(observer().SuggestionsForCategory(other_category()), SizeIs(1)); |
882 | 993 |
883 service.reset(); | 994 service.reset(); |
884 | 995 |
885 // Set the pref that disables remote suggestions. | 996 // Set the pref that disables remote suggestions. |
886 pref_service()->SetBoolean(prefs::kEnableSnippets, false); | 997 pref_service()->SetBoolean(prefs::kEnableSnippets, false); |
887 | 998 |
888 // Recreate the service to simulate a Chrome start. | 999 // Recreate the service to simulate a Chrome start. |
889 ResetSnippetsService(&service); | 1000 ResetSnippetsService(&service, /*set_empty_response=*/true); |
890 | 1001 |
891 ASSERT_THAT(RemoteSuggestionsProvider::State::DISABLED, Eq(service->state_)); | 1002 ASSERT_THAT(RemoteSuggestionsProvider::State::DISABLED, Eq(service->state_)); |
892 | 1003 |
893 // Now the observer should not have received any suggestions. | 1004 // Now the observer should not have received any suggestions. |
894 EXPECT_THAT(observer().SuggestionsForCategory(articles_category()), | 1005 EXPECT_THAT(observer().SuggestionsForCategory(articles_category()), |
895 IsEmpty()); | 1006 IsEmpty()); |
896 EXPECT_THAT(observer().SuggestionsForCategory(other_category()), IsEmpty()); | 1007 EXPECT_THAT(observer().SuggestionsForCategory(other_category()), IsEmpty()); |
897 } | 1008 } |
898 | 1009 |
899 TEST_F(RemoteSuggestionsProviderTest, Clear) { | 1010 TEST_F(RemoteSuggestionsProviderTest, Clear) { |
(...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1252 image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1)); | 1363 image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1)); |
1253 image = FetchImage(service.get(), MakeArticleID(kSnippetUrl)); | 1364 image = FetchImage(service.get(), MakeArticleID(kSnippetUrl)); |
1254 EXPECT_FALSE(image.IsEmpty()); | 1365 EXPECT_FALSE(image.IsEmpty()); |
1255 EXPECT_EQ(1, image.Width()); | 1366 EXPECT_EQ(1, image.Width()); |
1256 | 1367 |
1257 // Make sure that fetching the same snippet again does not re-add it. | 1368 // Make sure that fetching the same snippet again does not re-add it. |
1258 LoadFromJSONString(service.get(), json_str); | 1369 LoadFromJSONString(service.get(), json_str); |
1259 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty()); | 1370 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty()); |
1260 | 1371 |
1261 // The snippet should stay dismissed even after re-creating the service. | 1372 // The snippet should stay dismissed even after re-creating the service. |
1262 ResetSnippetsService(&service); | 1373 ResetSnippetsService(&service, /*set_empty_response=*/true); |
1263 LoadFromJSONString(service.get(), json_str); | 1374 LoadFromJSONString(service.get(), json_str); |
1264 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty()); | 1375 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty()); |
1265 | 1376 |
1266 // The snippet can be added again after clearing dismissed snippets. | 1377 // The snippet can be added again after clearing dismissed snippets. |
1267 service->ClearDismissedSuggestionsForDebugging(articles_category()); | 1378 service->ClearDismissedSuggestionsForDebugging(articles_category()); |
1268 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty()); | 1379 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty()); |
1269 LoadFromJSONString(service.get(), json_str); | 1380 LoadFromJSONString(service.get(), json_str); |
1270 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1)); | 1381 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1)); |
1271 } | 1382 } |
1272 | 1383 |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1448 EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"), | 1559 EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"), |
1449 ElementsAre(base::Bucket(/*min=*/0, /*count=*/1), | 1560 ElementsAre(base::Bucket(/*min=*/0, /*count=*/1), |
1450 base::Bucket(/*min=*/1, /*count=*/3))); | 1561 base::Bucket(/*min=*/1, /*count=*/3))); |
1451 EXPECT_THAT( | 1562 EXPECT_THAT( |
1452 tester.GetAllSamples("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded"), | 1563 tester.GetAllSamples("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded"), |
1453 ElementsAre(base::Bucket(/*min=*/1, /*count=*/1))); | 1564 ElementsAre(base::Bucket(/*min=*/1, /*count=*/1))); |
1454 | 1565 |
1455 // There is only a single, dismissed snippet in the database, so recreating | 1566 // There is only a single, dismissed snippet in the database, so recreating |
1456 // the service will require us to re-fetch. | 1567 // the service will require us to re-fetch. |
1457 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 4); | 1568 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 4); |
1458 ResetSnippetsService(&service); | 1569 ResetSnippetsService(&service, /*set_empty_response=*/true); |
1459 EXPECT_EQ(observer().StatusForCategory(articles_category()), | 1570 EXPECT_EQ(observer().StatusForCategory(articles_category()), |
1460 CategoryStatus::AVAILABLE); | 1571 CategoryStatus::AVAILABLE); |
1461 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 5); | 1572 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 5); |
1462 EXPECT_THAT( | 1573 EXPECT_THAT( |
1463 tester.GetAllSamples("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded"), | 1574 tester.GetAllSamples("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded"), |
1464 ElementsAre(base::Bucket(/*min=*/1, /*count=*/2))); | 1575 ElementsAre(base::Bucket(/*min=*/1, /*count=*/2))); |
1465 | 1576 |
1466 // But if there's a non-dismissed snippet in the database, recreating it | 1577 // But if there's a non-dismissed snippet in the database, recreating it |
1467 // shouldn't trigger a fetch. | 1578 // shouldn't trigger a fetch. |
1468 LoadFromJSONString( | 1579 LoadFromJSONString( |
1469 service.get(), | 1580 service.get(), |
1470 GetTestJson({GetSnippetWithUrl("http://not-dismissed.com")})); | 1581 GetTestJson({GetSnippetWithUrl("http://not-dismissed.com")})); |
1471 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 6); | 1582 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 6); |
1472 ResetSnippetsService(&service); | 1583 ResetSnippetsService(&service, /*set_empty_response=*/true); |
1473 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 6); | 1584 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 6); |
1474 } | 1585 } |
1475 | 1586 |
1476 TEST_F(RemoteSuggestionsProviderTest, DismissShouldRespectAllKnownUrls) { | 1587 TEST_F(RemoteSuggestionsProviderTest, DismissShouldRespectAllKnownUrls) { |
1477 auto service = MakeSnippetsService(); | 1588 auto service = MakeSnippetsService(); |
1478 | 1589 |
1479 const base::Time creation = GetDefaultCreationTime(); | 1590 const base::Time creation = GetDefaultCreationTime(); |
1480 const base::Time expiry = GetDefaultExpirationTime(); | 1591 const base::Time expiry = GetDefaultExpirationTime(); |
1481 const std::vector<std::string> source_urls = { | 1592 const std::vector<std::string> source_urls = { |
1482 "http://mashable.com/2016/05/11/stolen", | 1593 "http://mashable.com/2016/05/11/stolen", |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1659 gfx::Image image = FetchImage(service.get(), MakeArticleID(kSnippetUrl)); | 1770 gfx::Image image = FetchImage(service.get(), MakeArticleID(kSnippetUrl)); |
1660 EXPECT_EQ(1, image.Width()); | 1771 EXPECT_EQ(1, image.Width()); |
1661 EXPECT_FALSE(image.IsEmpty()); | 1772 EXPECT_FALSE(image.IsEmpty()); |
1662 | 1773 |
1663 // Send new suggestion which don't include the snippet referencing the image. | 1774 // Send new suggestion which don't include the snippet referencing the image. |
1664 LoadFromJSONString(service.get(), | 1775 LoadFromJSONString(service.get(), |
1665 GetTestJson({GetSnippetWithUrl( | 1776 GetTestJson({GetSnippetWithUrl( |
1666 "http://something.com/pletely/unrelated")})); | 1777 "http://something.com/pletely/unrelated")})); |
1667 // The image should still be available until a restart happens. | 1778 // The image should still be available until a restart happens. |
1668 EXPECT_FALSE(FetchImage(service.get(), MakeArticleID(kSnippetUrl)).IsEmpty()); | 1779 EXPECT_FALSE(FetchImage(service.get(), MakeArticleID(kSnippetUrl)).IsEmpty()); |
1669 ResetSnippetsService(&service); | 1780 ResetSnippetsService(&service, /*set_empty_response=*/true); |
1670 // After the restart, the image should be garbage collected. | 1781 // After the restart, the image should be garbage collected. |
1671 EXPECT_TRUE(FetchImage(service.get(), MakeArticleID(kSnippetUrl)).IsEmpty()); | 1782 EXPECT_TRUE(FetchImage(service.get(), MakeArticleID(kSnippetUrl)).IsEmpty()); |
1672 } | 1783 } |
1673 | 1784 |
1674 TEST_F(RemoteSuggestionsProviderTest, | 1785 TEST_F(RemoteSuggestionsProviderTest, |
1675 ShouldHandleMoreThanMaxSnippetsInResponse) { | 1786 ShouldHandleMoreThanMaxSnippetsInResponse) { |
1676 auto service = MakeSnippetsService(); | 1787 auto service = MakeSnippetsService(); |
1677 | 1788 |
1678 std::vector<std::string> suggestions; | 1789 std::vector<std::string> suggestions; |
1679 for (int i = 0; i < service->GetMaxSnippetCountForTesting() + 1; ++i) { | 1790 for (int i = 0; i < service->GetMaxSnippetCountForTesting() + 1; ++i) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1713 service->FetchSnippetsInTheBackground(); | 1824 service->FetchSnippetsInTheBackground(); |
1714 base::RunLoop().RunUntilIdle(); | 1825 base::RunLoop().RunUntilIdle(); |
1715 EXPECT_EQ( | 1826 EXPECT_EQ( |
1716 simple_test_clock_ptr->Now().ToInternalValue(), | 1827 simple_test_clock_ptr->Now().ToInternalValue(), |
1717 pref_service()->GetInt64(prefs::kLastSuccessfulBackgroundFetchTime)); | 1828 pref_service()->GetInt64(prefs::kLastSuccessfulBackgroundFetchTime)); |
1718 // TODO(markusheintz): Add a test that simulates a browser restart once the | 1829 // TODO(markusheintz): Add a test that simulates a browser restart once the |
1719 // scheduler refactoring is done (crbug.com/672434). | 1830 // scheduler refactoring is done (crbug.com/672434). |
1720 } | 1831 } |
1721 | 1832 |
1722 } // namespace ntp_snippets | 1833 } // namespace ntp_snippets |
OLD | NEW |