Chromium Code Reviews| 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 | |
| 119 std::string GetTestJson(const std::vector<std::string>& snippets, | 170 std::string GetTestJson(const std::vector<std::string>& snippets, |
|
tschumann
2016/12/15 18:23:13
that's nice! can you add a TODO() to get rid of th
vitaliii
2016/12/16 08:15:43
Done.
| |
| 120 const std::string& category_title) { | 171 const std::string& category_title) { |
| 121 return base::StringPrintf( | 172 return MultiCategoryJsonBuilder() |
| 122 "{\n" | 173 .AddCategoryWithCustomTitle(snippets, /*remote_category_id=*/1, |
| 123 " \"categories\": [{\n" | 174 category_title) |
| 124 " \"id\": 1,\n" | 175 .Build(); |
| 125 " \"localizedTitle\": \"%s\",\n" | |
| 126 " \"suggestions\": [%s]\n" | |
| 127 " }]\n" | |
| 128 "}\n", | |
| 129 category_title.c_str(), base::JoinString(snippets, ", ").c_str()); | |
| 130 } | 176 } |
| 131 | 177 |
| 132 std::string GetTestJson(const std::vector<std::string>& snippets) { | 178 std::string GetTestJson(const std::vector<std::string>& snippets) { |
| 133 return GetTestJson(snippets, kTestJsonDefaultCategoryTitle); | 179 return GetTestJson(snippets, kTestJsonDefaultCategoryTitle); |
| 134 } | 180 } |
| 135 | 181 |
| 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) { | 182 std::string FormatTime(const base::Time& t) { |
| 160 base::Time::Exploded x; | 183 base::Time::Exploded x; |
| 161 t.UTCExplode(&x); | 184 t.UTCExplode(&x); |
| 162 return base::StringPrintf("%04d-%02d-%02dT%02d:%02d:%02dZ", x.year, x.month, | 185 return base::StringPrintf("%04d-%02d-%02dT%02d:%02d:%02dZ", x.year, x.month, |
| 163 x.day_of_month, x.hour, x.minute, x.second); | 186 x.day_of_month, x.hour, x.minute, x.second); |
| 164 } | 187 } |
| 165 | 188 |
| 166 std::string GetSnippetWithUrlAndTimesAndSource( | 189 std::string GetSnippetWithUrlAndTimesAndSource( |
| 167 const std::vector<std::string>& ids, | 190 const std::vector<std::string>& ids, |
| 168 const std::string& url, | 191 const std::string& url, |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 394 class RemoteSuggestionsProviderTest : public ::testing::Test { | 417 class RemoteSuggestionsProviderTest : public ::testing::Test { |
| 395 public: | 418 public: |
| 396 RemoteSuggestionsProviderTest() | 419 RemoteSuggestionsProviderTest() |
| 397 : params_manager_(ntp_snippets::kStudyName, | 420 : params_manager_(ntp_snippets::kStudyName, |
| 398 {{"content_suggestions_backend", | 421 {{"content_suggestions_backend", |
| 399 kTestContentSuggestionsServerEndpoint}, | 422 kTestContentSuggestionsServerEndpoint}, |
| 400 {"fetching_personalization", "non_personal"}}), | 423 {"fetching_personalization", "non_personal"}}), |
| 401 fake_url_fetcher_factory_( | 424 fake_url_fetcher_factory_( |
| 402 /*default_factory=*/&failing_url_fetcher_factory_), | 425 /*default_factory=*/&failing_url_fetcher_factory_), |
| 403 test_url_(kTestContentSuggestionsServerWithAPIKey), | 426 test_url_(kTestContentSuggestionsServerWithAPIKey), |
| 427 category_ranker_(base::MakeUnique<ConstantCategoryRanker>()), | |
| 404 user_classifier_(/*pref_service=*/nullptr), | 428 user_classifier_(/*pref_service=*/nullptr), |
| 405 image_fetcher_(nullptr), | 429 image_fetcher_(nullptr), |
| 406 image_decoder_(nullptr), | 430 image_decoder_(nullptr), |
| 407 database_(nullptr) { | 431 database_(nullptr) { |
| 408 RemoteSuggestionsProvider::RegisterProfilePrefs( | 432 RemoteSuggestionsProvider::RegisterProfilePrefs( |
| 409 utils_.pref_service()->registry()); | 433 utils_.pref_service()->registry()); |
| 410 RequestThrottler::RegisterProfilePrefs(utils_.pref_service()->registry()); | 434 RequestThrottler::RegisterProfilePrefs(utils_.pref_service()->registry()); |
| 411 | 435 |
| 412 EXPECT_TRUE(database_dir_.CreateUniqueTempDir()); | 436 EXPECT_TRUE(database_dir_.CreateUniqueTempDir()); |
| 413 } | 437 } |
| 414 | 438 |
| 415 ~RemoteSuggestionsProviderTest() override { | 439 ~RemoteSuggestionsProviderTest() override { |
| 416 // We need to run the message loop after deleting the database, because | 440 // We need to run the message loop after deleting the database, because |
| 417 // ProtoDatabaseImpl deletes the actual LevelDB asynchronously on the task | 441 // ProtoDatabaseImpl deletes the actual LevelDB asynchronously on the task |
| 418 // runner. Without this, we'd get reports of memory leaks. | 442 // runner. Without this, we'd get reports of memory leaks. |
| 419 base::RunLoop().RunUntilIdle(); | 443 base::RunLoop().RunUntilIdle(); |
| 420 } | 444 } |
| 421 | 445 |
| 446 // TODO(vitaliii): Rewrite this function to initialize a test class member | |
| 447 // instead of creating a new service. | |
| 422 std::unique_ptr<RemoteSuggestionsProvider> MakeSnippetsService( | 448 std::unique_ptr<RemoteSuggestionsProvider> MakeSnippetsService( |
| 423 bool set_empty_response = true) { | 449 bool set_empty_response = true) { |
| 424 auto service = MakeSnippetsServiceWithoutInitialization(); | 450 auto service = MakeSnippetsServiceWithoutInitialization(); |
| 425 WaitForSnippetsServiceInitialization(service.get(), set_empty_response); | 451 WaitForSnippetsServiceInitialization(service.get(), set_empty_response); |
| 426 return service; | 452 return service; |
| 427 } | 453 } |
| 428 | 454 |
| 429 std::unique_ptr<RemoteSuggestionsProvider> | 455 std::unique_ptr<RemoteSuggestionsProvider> |
| 430 MakeSnippetsServiceWithoutInitialization() { | 456 MakeSnippetsServiceWithoutInitialization() { |
| 431 scoped_refptr<base::SingleThreadTaskRunner> task_runner( | 457 scoped_refptr<base::SingleThreadTaskRunner> task_runner( |
| 432 base::ThreadTaskRunnerHandle::Get()); | 458 base::ThreadTaskRunnerHandle::Get()); |
| 433 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter = | 459 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter = |
| 434 new net::TestURLRequestContextGetter(task_runner.get()); | 460 new net::TestURLRequestContextGetter(task_runner.get()); |
| 435 | 461 |
| 436 utils_.ResetSigninManager(); | 462 utils_.ResetSigninManager(); |
| 437 std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher = | 463 std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher = |
| 438 base::MakeUnique<NTPSnippetsFetcher>( | 464 base::MakeUnique<NTPSnippetsFetcher>( |
| 439 utils_.fake_signin_manager(), fake_token_service_.get(), | 465 utils_.fake_signin_manager(), fake_token_service_.get(), |
| 440 std::move(request_context_getter), utils_.pref_service(), | 466 std::move(request_context_getter), utils_.pref_service(), nullptr, |
| 441 &category_factory_, nullptr, base::Bind(&ParseJson), kAPIKey, | 467 base::Bind(&ParseJson), kAPIKey, &user_classifier_); |
| 442 &user_classifier_); | |
| 443 | 468 |
| 444 utils_.fake_signin_manager()->SignIn("foo@bar.com"); | 469 utils_.fake_signin_manager()->SignIn("foo@bar.com"); |
| 445 | 470 |
| 446 auto image_fetcher = base::MakeUnique<NiceMock<MockImageFetcher>>(); | 471 auto image_fetcher = base::MakeUnique<NiceMock<MockImageFetcher>>(); |
| 447 | 472 |
| 448 image_fetcher_ = image_fetcher.get(); | 473 image_fetcher_ = image_fetcher.get(); |
| 449 EXPECT_CALL(*image_fetcher, SetImageFetcherDelegate(_)); | 474 EXPECT_CALL(*image_fetcher, SetImageFetcherDelegate(_)); |
| 450 auto image_decoder = base::MakeUnique<FakeImageDecoder>(); | 475 auto image_decoder = base::MakeUnique<FakeImageDecoder>(); |
| 451 image_decoder_ = image_decoder.get(); | 476 image_decoder_ = image_decoder.get(); |
| 452 EXPECT_FALSE(observer_); | 477 EXPECT_FALSE(observer_); |
| 453 observer_ = base::MakeUnique<FakeContentSuggestionsProviderObserver>(); | 478 observer_ = base::MakeUnique<FakeContentSuggestionsProviderObserver>(); |
| 454 auto database = base::MakeUnique<RemoteSuggestionsDatabase>( | 479 auto database = base::MakeUnique<RemoteSuggestionsDatabase>( |
| 455 database_dir_.GetPath(), task_runner); | 480 database_dir_.GetPath(), task_runner); |
| 456 database_ = database.get(); | 481 database_ = database.get(); |
| 457 return base::MakeUnique<RemoteSuggestionsProvider>( | 482 return base::MakeUnique<RemoteSuggestionsProvider>( |
| 458 observer_.get(), &category_factory_, utils_.pref_service(), "fr", | 483 observer_.get(), utils_.pref_service(), "fr", category_ranker_.get(), |
| 459 &user_classifier_, &scheduler_, std::move(snippets_fetcher), | 484 &user_classifier_, &scheduler_, std::move(snippets_fetcher), |
| 460 std::move(image_fetcher), std::move(image_decoder), | 485 std::move(image_fetcher), std::move(image_decoder), std::move(database), |
| 461 std::move(database), | |
| 462 base::MakeUnique<RemoteSuggestionsStatusService>( | 486 base::MakeUnique<RemoteSuggestionsStatusService>( |
| 463 utils_.fake_signin_manager(), utils_.pref_service())); | 487 utils_.fake_signin_manager(), utils_.pref_service())); |
| 464 } | 488 } |
| 465 | 489 |
| 466 void WaitForSnippetsServiceInitialization(RemoteSuggestionsProvider* service, | 490 void WaitForSnippetsServiceInitialization(RemoteSuggestionsProvider* service, |
| 467 bool set_empty_response) { | 491 bool set_empty_response) { |
| 468 EXPECT_EQ(RemoteSuggestionsProvider::State::NOT_INITED, service->state_); | 492 EXPECT_EQ(RemoteSuggestionsProvider::State::NOT_INITED, service->state_); |
| 469 | 493 |
| 470 // Add an initial fetch response, as the service tries to fetch when there | 494 // Add an initial fetch response, as the service tries to fetch when there |
| 471 // is nothing in the DB. | 495 // is nothing in the DB. |
| 472 if (set_empty_response) { | 496 if (set_empty_response) { |
| 473 SetUpFetchResponse(GetTestJson(std::vector<std::string>())); | 497 SetUpFetchResponse(GetTestJson(std::vector<std::string>())); |
| 474 } | 498 } |
| 475 | 499 |
| 476 // TODO(treib): Find a better way to wait for initialization to finish. | 500 // TODO(treib): Find a better way to wait for initialization to finish. |
| 477 base::RunLoop().RunUntilIdle(); | 501 base::RunLoop().RunUntilIdle(); |
| 478 EXPECT_NE(RemoteSuggestionsProvider::State::NOT_INITED, service->state_); | 502 EXPECT_NE(RemoteSuggestionsProvider::State::NOT_INITED, service->state_); |
| 479 } | 503 } |
| 480 | 504 |
| 481 void ResetSnippetsService( | 505 void ResetSnippetsService(std::unique_ptr<RemoteSuggestionsProvider>* service, |
| 482 std::unique_ptr<RemoteSuggestionsProvider>* service) { | 506 bool set_empty_response) { |
| 483 service->reset(); | 507 service->reset(); |
| 484 observer_.reset(); | 508 observer_.reset(); |
| 485 *service = MakeSnippetsService(); | 509 *service = MakeSnippetsService(set_empty_response); |
| 510 } | |
| 511 | |
| 512 void SetCategoryRanker(std::unique_ptr<CategoryRanker> category_ranker) { | |
| 513 category_ranker_ = std::move(category_ranker); | |
| 486 } | 514 } |
| 487 | 515 |
| 488 ContentSuggestion::ID MakeArticleID(const std::string& id_within_category) { | 516 ContentSuggestion::ID MakeArticleID(const std::string& id_within_category) { |
| 489 return ContentSuggestion::ID(articles_category(), id_within_category); | 517 return ContentSuggestion::ID(articles_category(), id_within_category); |
| 490 } | 518 } |
| 491 | 519 |
| 492 Category articles_category() { | 520 Category articles_category() { |
| 493 return category_factory_.FromKnownCategory(KnownCategories::ARTICLES); | 521 return Category::FromKnownCategory(KnownCategories::ARTICLES); |
| 494 } | 522 } |
| 495 | 523 |
| 496 ContentSuggestion::ID MakeOtherID(const std::string& id_within_category) { | 524 ContentSuggestion::ID MakeOtherID(const std::string& id_within_category) { |
| 497 return ContentSuggestion::ID(other_category(), id_within_category); | 525 return ContentSuggestion::ID(other_category(), id_within_category); |
| 498 } | 526 } |
| 499 | 527 |
| 500 Category other_category() { return category_factory_.FromRemoteCategory(2); } | 528 // TODO(tschumann): Get rid of the convenience other_category() and |
| 529 // unknown_category() helpers -- tests can just define their own. | |
| 530 Category other_category() { return Category::FromRemoteCategory(2); } | |
| 501 | 531 |
| 502 Category unknown_category() { | 532 Category unknown_category() { |
| 503 return category_factory_.FromRemoteCategory(kUnknownRemoteCategoryId); | 533 return Category::FromRemoteCategory(kUnknownRemoteCategoryId); |
| 504 } | 534 } |
| 505 | 535 |
| 506 protected: | 536 protected: |
| 507 const GURL& test_url() { return test_url_; } | 537 const GURL& test_url() { return test_url_; } |
| 508 FakeContentSuggestionsProviderObserver& observer() { return *observer_; } | 538 FakeContentSuggestionsProviderObserver& observer() { return *observer_; } |
| 509 MockScheduler& mock_scheduler() { return scheduler_; } | 539 MockScheduler& mock_scheduler() { return scheduler_; } |
| 510 // TODO(tschumann): Make this a strict-mock. We want to avoid unneccesary | 540 // TODO(tschumann): Make this a strict-mock. We want to avoid unneccesary |
| 511 // network requests. | 541 // network requests. |
| 512 NiceMock<MockImageFetcher>* image_fetcher() { return image_fetcher_; } | 542 NiceMock<MockImageFetcher>* image_fetcher() { return image_fetcher_; } |
| 513 FakeImageDecoder* image_decoder() { return image_decoder_; } | 543 FakeImageDecoder* image_decoder() { return image_decoder_; } |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 539 | 569 |
| 540 private: | 570 private: |
| 541 variations::testing::VariationParamsManager params_manager_; | 571 variations::testing::VariationParamsManager params_manager_; |
| 542 test::RemoteSuggestionsTestUtils utils_; | 572 test::RemoteSuggestionsTestUtils utils_; |
| 543 base::MessageLoop message_loop_; | 573 base::MessageLoop message_loop_; |
| 544 FailingFakeURLFetcherFactory failing_url_fetcher_factory_; | 574 FailingFakeURLFetcherFactory failing_url_fetcher_factory_; |
| 545 // Instantiation of factory automatically sets itself as URLFetcher's factory. | 575 // Instantiation of factory automatically sets itself as URLFetcher's factory. |
| 546 net::FakeURLFetcherFactory fake_url_fetcher_factory_; | 576 net::FakeURLFetcherFactory fake_url_fetcher_factory_; |
| 547 const GURL test_url_; | 577 const GURL test_url_; |
| 548 std::unique_ptr<OAuth2TokenService> fake_token_service_; | 578 std::unique_ptr<OAuth2TokenService> fake_token_service_; |
| 579 std::unique_ptr<CategoryRanker> category_ranker_; | |
| 549 UserClassifier user_classifier_; | 580 UserClassifier user_classifier_; |
| 550 NiceMock<MockScheduler> scheduler_; | 581 NiceMock<MockScheduler> scheduler_; |
| 551 std::unique_ptr<FakeContentSuggestionsProviderObserver> observer_; | 582 std::unique_ptr<FakeContentSuggestionsProviderObserver> observer_; |
| 552 CategoryFactory category_factory_; | |
| 553 NiceMock<MockImageFetcher>* image_fetcher_; | 583 NiceMock<MockImageFetcher>* image_fetcher_; |
| 554 FakeImageDecoder* image_decoder_; | 584 FakeImageDecoder* image_decoder_; |
| 555 | 585 |
| 556 base::ScopedTempDir database_dir_; | 586 base::ScopedTempDir database_dir_; |
| 557 RemoteSuggestionsDatabase* database_; | 587 RemoteSuggestionsDatabase* database_; |
| 558 | 588 |
| 559 DISALLOW_COPY_AND_ASSIGN(RemoteSuggestionsProviderTest); | 589 DISALLOW_COPY_AND_ASSIGN(RemoteSuggestionsProviderTest); |
| 560 }; | 590 }; |
| 561 | 591 |
| 562 TEST_F(RemoteSuggestionsProviderTest, ScheduleOnStart) { | 592 TEST_F(RemoteSuggestionsProviderTest, ScheduleOnStart) { |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 577 SetUpFetchResponse(GetTestJson({GetSnippet()})); | 607 SetUpFetchResponse(GetTestJson({GetSnippet()})); |
| 578 auto service = MakeSnippetsService(/*set_empty_response=*/false); | 608 auto service = MakeSnippetsService(/*set_empty_response=*/false); |
| 579 | 609 |
| 580 // When recreating the service, we should not get any |Schedule| calls: | 610 // When recreating the service, we should not get any |Schedule| calls: |
| 581 // The tasks are already scheduled with the correct intervals, so nothing on | 611 // The tasks are already scheduled with the correct intervals, so nothing on |
| 582 // initialization, and the service has data from the DB, so no automatic fetch | 612 // initialization, and the service has data from the DB, so no automatic fetch |
| 583 // should happen. | 613 // should happen. |
| 584 Mock::VerifyAndClearExpectations(&mock_scheduler()); | 614 Mock::VerifyAndClearExpectations(&mock_scheduler()); |
| 585 EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(0); | 615 EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(0); |
| 586 EXPECT_CALL(mock_scheduler(), Unschedule()).Times(0); | 616 EXPECT_CALL(mock_scheduler(), Unschedule()).Times(0); |
| 587 ResetSnippetsService(&service); | 617 ResetSnippetsService(&service, /*set_empty_response=*/true); |
| 588 } | 618 } |
| 589 | 619 |
| 590 TEST_F(RemoteSuggestionsProviderTest, RescheduleAfterSuccessfulFetch) { | 620 TEST_F(RemoteSuggestionsProviderTest, RescheduleAfterSuccessfulFetch) { |
| 591 // We should get two |Schedule| calls: The first when initialization | 621 // We should get two |Schedule| calls: The first when initialization |
| 592 // completes, the second one after the automatic (since the service doesn't | 622 // completes, the second one after the automatic (since the service doesn't |
| 593 // have any data yet) fetch finishes. | 623 // have any data yet) fetch finishes. |
| 594 EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(2); | 624 EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(2); |
| 595 auto service = MakeSnippetsService(); | 625 auto service = MakeSnippetsService(); |
| 596 | 626 |
| 597 // A successful fetch should trigger another |Schedule|. | 627 // A successful fetch should trigger another |Schedule|. |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 728 CategoryInfo info_with_title = service->GetCategoryInfo(articles_category()); | 758 CategoryInfo info_with_title = service->GetCategoryInfo(articles_category()); |
| 729 EXPECT_THAT(info_before.title(), Not(Eq(info_with_title.title()))); | 759 EXPECT_THAT(info_before.title(), Not(Eq(info_with_title.title()))); |
| 730 EXPECT_THAT(test_default_title, Eq(info_with_title.title())); | 760 EXPECT_THAT(test_default_title, Eq(info_with_title.title())); |
| 731 EXPECT_THAT(info_before.has_more_action(), Eq(true)); | 761 EXPECT_THAT(info_before.has_more_action(), Eq(true)); |
| 732 EXPECT_THAT(info_before.has_reload_action(), Eq(true)); | 762 EXPECT_THAT(info_before.has_reload_action(), Eq(true)); |
| 733 EXPECT_THAT(info_before.has_view_all_action(), Eq(false)); | 763 EXPECT_THAT(info_before.has_view_all_action(), Eq(false)); |
| 734 EXPECT_THAT(info_before.show_if_empty(), Eq(true)); | 764 EXPECT_THAT(info_before.show_if_empty(), Eq(true)); |
| 735 } | 765 } |
| 736 | 766 |
| 737 TEST_F(RemoteSuggestionsProviderTest, MultipleCategories) { | 767 TEST_F(RemoteSuggestionsProviderTest, MultipleCategories) { |
| 738 std::string json_str( | |
| 739 GetMultiCategoryJson({GetSnippetN(0)}, {GetSnippetN(1)})); | |
| 740 | |
| 741 auto service = MakeSnippetsService(); | 768 auto service = MakeSnippetsService(); |
| 742 | 769 std::string json_str = |
| 770 MultiCategoryJsonBuilder() | |
| 771 .AddCategory({GetSnippetN(0)}, /*remote_category_id=*/1) | |
| 772 .AddCategory({GetSnippetN(1)}, /*remote_category_id=*/2) | |
| 773 .Build(); | |
| 743 LoadFromJSONString(service.get(), json_str); | 774 LoadFromJSONString(service.get(), json_str); |
| 744 | 775 |
| 745 ASSERT_THAT(observer().statuses(), | 776 ASSERT_THAT(observer().statuses(), |
| 746 Eq(std::map<Category, CategoryStatus, Category::CompareByID>{ | 777 Eq(std::map<Category, CategoryStatus, Category::CompareByID>{ |
| 747 {articles_category(), CategoryStatus::AVAILABLE}, | 778 {articles_category(), CategoryStatus::AVAILABLE}, |
| 748 {other_category(), CategoryStatus::AVAILABLE}, | 779 {other_category(), CategoryStatus::AVAILABLE}, |
| 749 })); | 780 })); |
| 750 | 781 |
| 751 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1)); | 782 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1)); |
| 752 EXPECT_THAT(service->GetSnippetsForTesting(other_category()), SizeIs(1)); | 783 EXPECT_THAT(service->GetSnippetsForTesting(other_category()), SizeIs(1)); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 785 auto service = MakeSnippetsService(); | 816 auto service = MakeSnippetsService(); |
| 786 CategoryInfo article_info = service->GetCategoryInfo(articles_category()); | 817 CategoryInfo article_info = service->GetCategoryInfo(articles_category()); |
| 787 EXPECT_THAT(article_info.has_more_action(), Eq(true)); | 818 EXPECT_THAT(article_info.has_more_action(), Eq(true)); |
| 788 EXPECT_THAT(article_info.has_reload_action(), Eq(true)); | 819 EXPECT_THAT(article_info.has_reload_action(), Eq(true)); |
| 789 EXPECT_THAT(article_info.has_view_all_action(), Eq(false)); | 820 EXPECT_THAT(article_info.has_view_all_action(), Eq(false)); |
| 790 EXPECT_THAT(article_info.show_if_empty(), Eq(true)); | 821 EXPECT_THAT(article_info.show_if_empty(), Eq(true)); |
| 791 } | 822 } |
| 792 | 823 |
| 793 TEST_F(RemoteSuggestionsProviderTest, ExperimentalCategoryInfo) { | 824 TEST_F(RemoteSuggestionsProviderTest, ExperimentalCategoryInfo) { |
| 794 auto service = MakeSnippetsService(); | 825 auto service = MakeSnippetsService(); |
| 795 | 826 std::string json_str = |
| 827 MultiCategoryJsonBuilder() | |
| 828 .AddCategory({GetSnippetN(0)}, /*remote_category_id=*/1) | |
| 829 .AddCategory({GetSnippetN(1)}, kUnknownRemoteCategoryId) | |
| 830 .Build(); | |
| 796 // Load data with multiple categories so that a new experimental category gets | 831 // Load data with multiple categories so that a new experimental category gets |
| 797 // registered. | 832 // registered. |
| 798 LoadFromJSONString(service.get(), | 833 LoadFromJSONString(service.get(), json_str); |
| 799 GetMultiCategoryJson({GetSnippetN(0)}, {GetSnippetN(1)}, | 834 |
| 800 kUnknownRemoteCategoryId)); | |
| 801 CategoryInfo info = service->GetCategoryInfo(unknown_category()); | 835 CategoryInfo info = service->GetCategoryInfo(unknown_category()); |
| 802 EXPECT_THAT(info.has_more_action(), Eq(false)); | 836 EXPECT_THAT(info.has_more_action(), Eq(false)); |
| 803 EXPECT_THAT(info.has_reload_action(), Eq(false)); | 837 EXPECT_THAT(info.has_reload_action(), Eq(false)); |
| 804 EXPECT_THAT(info.has_view_all_action(), Eq(false)); | 838 EXPECT_THAT(info.has_view_all_action(), Eq(false)); |
| 805 EXPECT_THAT(info.show_if_empty(), Eq(false)); | 839 EXPECT_THAT(info.show_if_empty(), Eq(false)); |
| 806 } | 840 } |
| 807 | 841 |
| 842 TEST_F(RemoteSuggestionsProviderTest, AddRemoteCategoriesToCategoryRanker) { | |
| 843 auto mock_ranker = base::MakeUnique<MockCategoryRanker>(); | |
| 844 MockCategoryRanker* raw_mock_ranker = mock_ranker.get(); | |
| 845 SetCategoryRanker(std::move(mock_ranker)); | |
| 846 std::string json_str = | |
| 847 MultiCategoryJsonBuilder() | |
| 848 .AddCategory({GetSnippetN(0)}, /*remote_category_id=*/11) | |
| 849 .AddCategory({GetSnippetN(1)}, /*remote_category_id=*/13) | |
| 850 .AddCategory({GetSnippetN(2)}, /*remote_category_id=*/12) | |
| 851 .Build(); | |
| 852 SetUpFetchResponse(json_str); | |
| 853 { | |
| 854 InSequence s; | |
|
tschumann
2016/12/15 18:23:13
please add a comment explaining what you test. ie.
vitaliii
2016/12/16 08:15:43
Done.
| |
| 855 EXPECT_CALL(*raw_mock_ranker, | |
| 856 AppendCategoryIfNecessary(Category::FromRemoteCategory(11))); | |
| 857 EXPECT_CALL(*raw_mock_ranker, | |
| 858 AppendCategoryIfNecessary(Category::FromRemoteCategory(13))); | |
| 859 EXPECT_CALL(*raw_mock_ranker, | |
| 860 AppendCategoryIfNecessary(Category::FromRemoteCategory(12))); | |
| 861 } | |
| 862 auto service = MakeSnippetsService(/*set_empty_response=*/false); | |
| 863 } | |
| 864 | |
| 808 TEST_F(RemoteSuggestionsProviderTest, PersistCategoryInfos) { | 865 TEST_F(RemoteSuggestionsProviderTest, PersistCategoryInfos) { |
| 809 auto service = MakeSnippetsService(); | 866 auto service = MakeSnippetsService(); |
| 810 | 867 // TODO(vitaliii): Use |articles_category()| instead of constant ID below. |
| 811 LoadFromJSONString(service.get(), | 868 std::string json_str = |
| 812 GetMultiCategoryJson({GetSnippetN(0)}, {GetSnippetN(1)}, | 869 MultiCategoryJsonBuilder() |
| 813 kUnknownRemoteCategoryId)); | 870 .AddCategoryWithCustomTitle( |
| 871 {GetSnippetN(0)}, /*remote_category_id=*/1, "Articles for You") | |
| 872 .AddCategoryWithCustomTitle({GetSnippetN(1)}, | |
| 873 kUnknownRemoteCategoryId, "Other Things") | |
| 874 .Build(); | |
| 875 LoadFromJSONString(service.get(), json_str); | |
| 814 | 876 |
| 815 ASSERT_EQ(observer().StatusForCategory(articles_category()), | 877 ASSERT_EQ(observer().StatusForCategory(articles_category()), |
| 816 CategoryStatus::AVAILABLE); | 878 CategoryStatus::AVAILABLE); |
| 817 ASSERT_EQ(observer().StatusForCategory(unknown_category()), | 879 ASSERT_EQ(observer().StatusForCategory(unknown_category()), |
| 818 CategoryStatus::AVAILABLE); | 880 CategoryStatus::AVAILABLE); |
| 819 | 881 |
| 820 CategoryInfo info_articles_before = | 882 CategoryInfo info_articles_before = |
| 821 service->GetCategoryInfo(articles_category()); | 883 service->GetCategoryInfo(articles_category()); |
| 822 CategoryInfo info_unknown_before = | 884 CategoryInfo info_unknown_before = |
| 823 service->GetCategoryInfo(unknown_category()); | 885 service->GetCategoryInfo(unknown_category()); |
| 824 | 886 |
| 825 // Recreate the service to simulate a Chrome restart. | 887 // Recreate the service to simulate a Chrome restart. |
| 826 ResetSnippetsService(&service); | 888 ResetSnippetsService(&service, /*set_empty_response=*/true); |
| 827 | 889 |
| 828 // The categories should have been restored. | 890 // The categories should have been restored. |
| 829 ASSERT_NE(observer().StatusForCategory(articles_category()), | 891 ASSERT_NE(observer().StatusForCategory(articles_category()), |
| 830 CategoryStatus::NOT_PROVIDED); | 892 CategoryStatus::NOT_PROVIDED); |
| 831 ASSERT_NE(observer().StatusForCategory(unknown_category()), | 893 ASSERT_NE(observer().StatusForCategory(unknown_category()), |
| 832 CategoryStatus::NOT_PROVIDED); | 894 CategoryStatus::NOT_PROVIDED); |
| 833 | 895 |
| 834 EXPECT_EQ(observer().StatusForCategory(articles_category()), | 896 EXPECT_EQ(observer().StatusForCategory(articles_category()), |
| 835 CategoryStatus::AVAILABLE); | 897 CategoryStatus::AVAILABLE); |
| 836 EXPECT_EQ(observer().StatusForCategory(unknown_category()), | 898 EXPECT_EQ(observer().StatusForCategory(unknown_category()), |
| 837 CategoryStatus::AVAILABLE); | 899 CategoryStatus::AVAILABLE); |
| 838 | 900 |
| 839 CategoryInfo info_articles_after = | 901 CategoryInfo info_articles_after = |
| 840 service->GetCategoryInfo(articles_category()); | 902 service->GetCategoryInfo(articles_category()); |
| 841 CategoryInfo info_unknown_after = | 903 CategoryInfo info_unknown_after = |
| 842 service->GetCategoryInfo(unknown_category()); | 904 service->GetCategoryInfo(unknown_category()); |
| 843 | 905 |
| 844 EXPECT_EQ(info_articles_before.title(), info_articles_after.title()); | 906 EXPECT_EQ(info_articles_before.title(), info_articles_after.title()); |
| 845 EXPECT_EQ(info_unknown_before.title(), info_unknown_after.title()); | 907 EXPECT_EQ(info_unknown_before.title(), info_unknown_after.title()); |
| 846 } | 908 } |
| 847 | 909 |
| 910 TEST_F(RemoteSuggestionsProviderTest, PersistRemoteCategoryOrder) { | |
| 911 // We create a service with a normal ranker to store the order. | |
| 912 std::string json_str = | |
| 913 MultiCategoryJsonBuilder() | |
| 914 .AddCategory({GetSnippetN(0)}, /*remote_category_id=*/11) | |
| 915 .AddCategory({GetSnippetN(1)}, /*remote_category_id=*/13) | |
| 916 .AddCategory({GetSnippetN(2)}, /*remote_category_id=*/12) | |
| 917 .Build(); | |
| 918 SetUpFetchResponse(json_str); | |
| 919 auto service = MakeSnippetsService(/*set_empty_response=*/false); | |
| 920 | |
| 921 // We manually recreate the service to simulate Chrome restart and enforce a | |
| 922 // mock ranker. The response is cleared to ensure that the order is not | |
| 923 // fetched. | |
| 924 SetUpFetchResponse(""); | |
| 925 auto mock_ranker = base::MakeUnique<MockCategoryRanker>(); | |
| 926 MockCategoryRanker* raw_mock_ranker = mock_ranker.get(); | |
| 927 SetCategoryRanker(std::move(mock_ranker)); | |
| 928 { | |
| 929 InSequence s; | |
| 930 // Article category always exists and, therefore, it is stored in prefs too. | |
| 931 EXPECT_CALL(*raw_mock_ranker, | |
| 932 AppendCategoryIfNecessary(Category::FromRemoteCategory(1))); | |
|
tschumann
2016/12/15 18:23:13
do we have a constant we can use for the article c
vitaliii
2016/12/16 08:15:43
Done.
| |
| 933 | |
| 934 EXPECT_CALL(*raw_mock_ranker, | |
| 935 AppendCategoryIfNecessary(Category::FromRemoteCategory(11))); | |
| 936 EXPECT_CALL(*raw_mock_ranker, | |
| 937 AppendCategoryIfNecessary(Category::FromRemoteCategory(13))); | |
| 938 EXPECT_CALL(*raw_mock_ranker, | |
| 939 AppendCategoryIfNecessary(Category::FromRemoteCategory(12))); | |
| 940 } | |
| 941 ResetSnippetsService(&service, /*set_empty_response=*/false); | |
| 942 } | |
| 943 | |
| 848 TEST_F(RemoteSuggestionsProviderTest, PersistSuggestions) { | 944 TEST_F(RemoteSuggestionsProviderTest, PersistSuggestions) { |
| 849 auto service = MakeSnippetsService(); | 945 auto service = MakeSnippetsService(); |
| 850 | 946 std::string json_str = |
| 851 LoadFromJSONString(service.get(), | 947 MultiCategoryJsonBuilder() |
| 852 GetMultiCategoryJson({GetSnippetN(0)}, {GetSnippetN(1)})); | 948 .AddCategory({GetSnippetN(0)}, /*remote_category_id=*/1) |
| 949 .AddCategory({GetSnippetN(2)}, /*remote_category_id=*/2) | |
| 950 .Build(); | |
| 951 LoadFromJSONString(service.get(), json_str); | |
| 853 | 952 |
| 854 ASSERT_THAT(observer().SuggestionsForCategory(articles_category()), | 953 ASSERT_THAT(observer().SuggestionsForCategory(articles_category()), |
| 855 SizeIs(1)); | 954 SizeIs(1)); |
| 856 ASSERT_THAT(observer().SuggestionsForCategory(other_category()), SizeIs(1)); | 955 ASSERT_THAT(observer().SuggestionsForCategory(other_category()), SizeIs(1)); |
| 857 | 956 |
| 858 // Recreate the service to simulate a Chrome restart. | 957 // Recreate the service to simulate a Chrome restart. |
| 859 ResetSnippetsService(&service); | 958 ResetSnippetsService(&service, /*set_empty_response=*/true); |
| 860 | 959 |
| 861 // The suggestions in both categories should have been restored. | 960 // The suggestions in both categories should have been restored. |
| 862 EXPECT_THAT(observer().SuggestionsForCategory(articles_category()), | 961 EXPECT_THAT(observer().SuggestionsForCategory(articles_category()), |
| 863 SizeIs(1)); | 962 SizeIs(1)); |
| 864 EXPECT_THAT(observer().SuggestionsForCategory(other_category()), SizeIs(1)); | 963 EXPECT_THAT(observer().SuggestionsForCategory(other_category()), SizeIs(1)); |
| 865 } | 964 } |
| 866 | 965 |
| 867 TEST_F(RemoteSuggestionsProviderTest, DontNotifyIfNotAvailable) { | 966 TEST_F(RemoteSuggestionsProviderTest, DontNotifyIfNotAvailable) { |
| 868 // Get some suggestions into the database. | 967 // Get some suggestions into the database. |
| 869 auto service = MakeSnippetsService(); | 968 auto service = MakeSnippetsService(); |
| 870 LoadFromJSONString(service.get(), | 969 std::string json_str = |
| 871 GetMultiCategoryJson({GetSnippetN(0)}, {GetSnippetN(1)})); | 970 MultiCategoryJsonBuilder() |
| 971 .AddCategory({GetSnippetN(0)}, | |
| 972 /*remote_category_id=*/1) | |
| 973 .AddCategory({GetSnippetN(1)}, /*remote_category_id=*/2) | |
| 974 .Build(); | |
| 975 LoadFromJSONString(service.get(), json_str); | |
| 976 | |
| 872 ASSERT_THAT(observer().SuggestionsForCategory(articles_category()), | 977 ASSERT_THAT(observer().SuggestionsForCategory(articles_category()), |
| 873 SizeIs(1)); | 978 SizeIs(1)); |
| 874 ASSERT_THAT(observer().SuggestionsForCategory(other_category()), SizeIs(1)); | 979 ASSERT_THAT(observer().SuggestionsForCategory(other_category()), SizeIs(1)); |
| 875 | 980 |
| 876 service.reset(); | 981 service.reset(); |
| 877 | 982 |
| 878 // Set the pref that disables remote suggestions. | 983 // Set the pref that disables remote suggestions. |
| 879 pref_service()->SetBoolean(prefs::kEnableSnippets, false); | 984 pref_service()->SetBoolean(prefs::kEnableSnippets, false); |
| 880 | 985 |
| 881 // Recreate the service to simulate a Chrome start. | 986 // Recreate the service to simulate a Chrome start. |
| 882 ResetSnippetsService(&service); | 987 ResetSnippetsService(&service, /*set_empty_response=*/true); |
| 883 | 988 |
| 884 ASSERT_THAT(RemoteSuggestionsProvider::State::DISABLED, Eq(service->state_)); | 989 ASSERT_THAT(RemoteSuggestionsProvider::State::DISABLED, Eq(service->state_)); |
| 885 | 990 |
| 886 // Now the observer should not have received any suggestions. | 991 // Now the observer should not have received any suggestions. |
| 887 EXPECT_THAT(observer().SuggestionsForCategory(articles_category()), | 992 EXPECT_THAT(observer().SuggestionsForCategory(articles_category()), |
| 888 IsEmpty()); | 993 IsEmpty()); |
| 889 EXPECT_THAT(observer().SuggestionsForCategory(other_category()), IsEmpty()); | 994 EXPECT_THAT(observer().SuggestionsForCategory(other_category()), IsEmpty()); |
| 890 } | 995 } |
| 891 | 996 |
| 892 TEST_F(RemoteSuggestionsProviderTest, Clear) { | 997 TEST_F(RemoteSuggestionsProviderTest, Clear) { |
| (...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1195 image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1)); | 1300 image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1)); |
| 1196 image = FetchImage(service.get(), MakeArticleID(kSnippetUrl)); | 1301 image = FetchImage(service.get(), MakeArticleID(kSnippetUrl)); |
| 1197 EXPECT_FALSE(image.IsEmpty()); | 1302 EXPECT_FALSE(image.IsEmpty()); |
| 1198 EXPECT_EQ(1, image.Width()); | 1303 EXPECT_EQ(1, image.Width()); |
| 1199 | 1304 |
| 1200 // Make sure that fetching the same snippet again does not re-add it. | 1305 // Make sure that fetching the same snippet again does not re-add it. |
| 1201 LoadFromJSONString(service.get(), json_str); | 1306 LoadFromJSONString(service.get(), json_str); |
| 1202 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty()); | 1307 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty()); |
| 1203 | 1308 |
| 1204 // The snippet should stay dismissed even after re-creating the service. | 1309 // The snippet should stay dismissed even after re-creating the service. |
| 1205 ResetSnippetsService(&service); | 1310 ResetSnippetsService(&service, /*set_empty_response=*/true); |
| 1206 LoadFromJSONString(service.get(), json_str); | 1311 LoadFromJSONString(service.get(), json_str); |
| 1207 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty()); | 1312 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty()); |
| 1208 | 1313 |
| 1209 // The snippet can be added again after clearing dismissed snippets. | 1314 // The snippet can be added again after clearing dismissed snippets. |
| 1210 service->ClearDismissedSuggestionsForDebugging(articles_category()); | 1315 service->ClearDismissedSuggestionsForDebugging(articles_category()); |
| 1211 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty()); | 1316 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty()); |
| 1212 LoadFromJSONString(service.get(), json_str); | 1317 LoadFromJSONString(service.get(), json_str); |
| 1213 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1)); | 1318 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1)); |
| 1214 } | 1319 } |
| 1215 | 1320 |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1391 EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"), | 1496 EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"), |
| 1392 ElementsAre(base::Bucket(/*min=*/0, /*count=*/1), | 1497 ElementsAre(base::Bucket(/*min=*/0, /*count=*/1), |
| 1393 base::Bucket(/*min=*/1, /*count=*/3))); | 1498 base::Bucket(/*min=*/1, /*count=*/3))); |
| 1394 EXPECT_THAT( | 1499 EXPECT_THAT( |
| 1395 tester.GetAllSamples("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded"), | 1500 tester.GetAllSamples("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded"), |
| 1396 ElementsAre(base::Bucket(/*min=*/1, /*count=*/1))); | 1501 ElementsAre(base::Bucket(/*min=*/1, /*count=*/1))); |
| 1397 | 1502 |
| 1398 // There is only a single, dismissed snippet in the database, so recreating | 1503 // There is only a single, dismissed snippet in the database, so recreating |
| 1399 // the service will require us to re-fetch. | 1504 // the service will require us to re-fetch. |
| 1400 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 4); | 1505 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 4); |
| 1401 ResetSnippetsService(&service); | 1506 ResetSnippetsService(&service, /*set_empty_response=*/true); |
| 1402 EXPECT_EQ(observer().StatusForCategory(articles_category()), | 1507 EXPECT_EQ(observer().StatusForCategory(articles_category()), |
| 1403 CategoryStatus::AVAILABLE); | 1508 CategoryStatus::AVAILABLE); |
| 1404 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 5); | 1509 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 5); |
| 1405 EXPECT_THAT( | 1510 EXPECT_THAT( |
| 1406 tester.GetAllSamples("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded"), | 1511 tester.GetAllSamples("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded"), |
| 1407 ElementsAre(base::Bucket(/*min=*/1, /*count=*/2))); | 1512 ElementsAre(base::Bucket(/*min=*/1, /*count=*/2))); |
| 1408 | 1513 |
| 1409 // But if there's a non-dismissed snippet in the database, recreating it | 1514 // But if there's a non-dismissed snippet in the database, recreating it |
| 1410 // shouldn't trigger a fetch. | 1515 // shouldn't trigger a fetch. |
| 1411 LoadFromJSONString( | 1516 LoadFromJSONString( |
| 1412 service.get(), | 1517 service.get(), |
| 1413 GetTestJson({GetSnippetWithUrl("http://not-dismissed.com")})); | 1518 GetTestJson({GetSnippetWithUrl("http://not-dismissed.com")})); |
| 1414 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 6); | 1519 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 6); |
| 1415 ResetSnippetsService(&service); | 1520 ResetSnippetsService(&service, /*set_empty_response=*/true); |
| 1416 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 6); | 1521 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 6); |
| 1417 } | 1522 } |
| 1418 | 1523 |
| 1419 TEST_F(RemoteSuggestionsProviderTest, DismissShouldRespectAllKnownUrls) { | 1524 TEST_F(RemoteSuggestionsProviderTest, DismissShouldRespectAllKnownUrls) { |
| 1420 auto service = MakeSnippetsService(); | 1525 auto service = MakeSnippetsService(); |
| 1421 | 1526 |
| 1422 const base::Time creation = GetDefaultCreationTime(); | 1527 const base::Time creation = GetDefaultCreationTime(); |
| 1423 const base::Time expiry = GetDefaultExpirationTime(); | 1528 const base::Time expiry = GetDefaultExpirationTime(); |
| 1424 const std::vector<std::string> source_urls = { | 1529 const std::vector<std::string> source_urls = { |
| 1425 "http://mashable.com/2016/05/11/stolen", | 1530 "http://mashable.com/2016/05/11/stolen", |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1602 gfx::Image image = FetchImage(service.get(), MakeArticleID(kSnippetUrl)); | 1707 gfx::Image image = FetchImage(service.get(), MakeArticleID(kSnippetUrl)); |
| 1603 EXPECT_EQ(1, image.Width()); | 1708 EXPECT_EQ(1, image.Width()); |
| 1604 EXPECT_FALSE(image.IsEmpty()); | 1709 EXPECT_FALSE(image.IsEmpty()); |
| 1605 | 1710 |
| 1606 // Send new suggestion which don't include the snippet referencing the image. | 1711 // Send new suggestion which don't include the snippet referencing the image. |
| 1607 LoadFromJSONString(service.get(), | 1712 LoadFromJSONString(service.get(), |
| 1608 GetTestJson({GetSnippetWithUrl( | 1713 GetTestJson({GetSnippetWithUrl( |
| 1609 "http://something.com/pletely/unrelated")})); | 1714 "http://something.com/pletely/unrelated")})); |
| 1610 // The image should still be available until a restart happens. | 1715 // The image should still be available until a restart happens. |
| 1611 EXPECT_FALSE(FetchImage(service.get(), MakeArticleID(kSnippetUrl)).IsEmpty()); | 1716 EXPECT_FALSE(FetchImage(service.get(), MakeArticleID(kSnippetUrl)).IsEmpty()); |
| 1612 ResetSnippetsService(&service); | 1717 ResetSnippetsService(&service, /*set_empty_response=*/true); |
| 1613 // After the restart, the image should be garbage collected. | 1718 // After the restart, the image should be garbage collected. |
| 1614 EXPECT_TRUE(FetchImage(service.get(), MakeArticleID(kSnippetUrl)).IsEmpty()); | 1719 EXPECT_TRUE(FetchImage(service.get(), MakeArticleID(kSnippetUrl)).IsEmpty()); |
| 1615 } | 1720 } |
| 1616 | 1721 |
| 1617 TEST_F(RemoteSuggestionsProviderTest, | 1722 TEST_F(RemoteSuggestionsProviderTest, |
| 1618 ShouldHandleMoreThanMaxSnippetsInResponse) { | 1723 ShouldHandleMoreThanMaxSnippetsInResponse) { |
| 1619 auto service = MakeSnippetsService(); | 1724 auto service = MakeSnippetsService(); |
| 1620 | 1725 |
| 1621 std::vector<std::string> suggestions; | 1726 std::vector<std::string> suggestions; |
| 1622 for (int i = 0; i < service->GetMaxSnippetCountForTesting() + 1; ++i) { | 1727 for (int i = 0; i < service->GetMaxSnippetCountForTesting() + 1; ++i) { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1656 service->FetchSnippetsInTheBackground(); | 1761 service->FetchSnippetsInTheBackground(); |
| 1657 base::RunLoop().RunUntilIdle(); | 1762 base::RunLoop().RunUntilIdle(); |
| 1658 EXPECT_EQ( | 1763 EXPECT_EQ( |
| 1659 simple_test_clock_ptr->Now().ToInternalValue(), | 1764 simple_test_clock_ptr->Now().ToInternalValue(), |
| 1660 pref_service()->GetInt64(prefs::kLastSuccessfulBackgroundFetchTime)); | 1765 pref_service()->GetInt64(prefs::kLastSuccessfulBackgroundFetchTime)); |
| 1661 // TODO(markusheintz): Add a test that simulates a browser restart once the | 1766 // TODO(markusheintz): Add a test that simulates a browser restart once the |
| 1662 // scheduler refactoring is done (crbug.com/672434). | 1767 // scheduler refactoring is done (crbug.com/672434). |
| 1663 } | 1768 } |
| 1664 | 1769 |
| 1665 } // namespace ntp_snippets | 1770 } // namespace ntp_snippets |
| OLD | NEW |