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, |
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 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
382 const image_fetcher::ImageDecodedCallback& callback) override { | 405 const image_fetcher::ImageDecodedCallback& callback) override { |
383 callback.Run(decoded_image_); | 406 callback.Run(decoded_image_); |
384 } | 407 } |
385 | 408 |
386 void SetDecodedImage(const gfx::Image& image) { decoded_image_ = image; } | 409 void SetDecodedImage(const gfx::Image& image) { decoded_image_ = image; } |
387 | 410 |
388 private: | 411 private: |
389 gfx::Image decoded_image_; | 412 gfx::Image decoded_image_; |
390 }; | 413 }; |
391 | 414 |
415 std::unique_ptr<CategoryRanker> MakeConstantCategoryRanker() { | |
416 return base::MakeUnique<ConstantCategoryRanker>(); | |
Marc Treib
2016/12/15 16:01:18
No need for a helper function for this; just call
vitaliii
2016/12/15 16:53:50
Done.
| |
417 } | |
418 | |
392 } // namespace | 419 } // namespace |
393 | 420 |
394 class RemoteSuggestionsProviderTest : public ::testing::Test { | 421 class RemoteSuggestionsProviderTest : public ::testing::Test { |
395 public: | 422 public: |
396 RemoteSuggestionsProviderTest() | 423 RemoteSuggestionsProviderTest() |
397 : params_manager_(ntp_snippets::kStudyName, | 424 : params_manager_(ntp_snippets::kStudyName, |
398 {{"content_suggestions_backend", | 425 {{"content_suggestions_backend", |
399 kTestContentSuggestionsServerEndpoint}, | 426 kTestContentSuggestionsServerEndpoint}, |
400 {"fetching_personalization", "non_personal"}}), | 427 {"fetching_personalization", "non_personal"}}), |
401 fake_url_fetcher_factory_( | 428 fake_url_fetcher_factory_( |
402 /*default_factory=*/&failing_url_fetcher_factory_), | 429 /*default_factory=*/&failing_url_fetcher_factory_), |
403 test_url_(kTestContentSuggestionsServerWithAPIKey), | 430 test_url_(kTestContentSuggestionsServerWithAPIKey), |
431 category_ranker_(MakeConstantCategoryRanker()), | |
404 user_classifier_(/*pref_service=*/nullptr), | 432 user_classifier_(/*pref_service=*/nullptr), |
405 image_fetcher_(nullptr), | 433 image_fetcher_(nullptr), |
406 image_decoder_(nullptr) { | 434 image_decoder_(nullptr) { |
407 RemoteSuggestionsProvider::RegisterProfilePrefs( | 435 RemoteSuggestionsProvider::RegisterProfilePrefs( |
408 utils_.pref_service()->registry()); | 436 utils_.pref_service()->registry()); |
409 RequestThrottler::RegisterProfilePrefs(utils_.pref_service()->registry()); | 437 RequestThrottler::RegisterProfilePrefs(utils_.pref_service()->registry()); |
410 | 438 |
411 EXPECT_TRUE(database_dir_.CreateUniqueTempDir()); | 439 EXPECT_TRUE(database_dir_.CreateUniqueTempDir()); |
412 } | 440 } |
413 | 441 |
414 ~RemoteSuggestionsProviderTest() override { | 442 ~RemoteSuggestionsProviderTest() override { |
415 // We need to run the message loop after deleting the database, because | 443 // We need to run the message loop after deleting the database, because |
416 // ProtoDatabaseImpl deletes the actual LevelDB asynchronously on the task | 444 // ProtoDatabaseImpl deletes the actual LevelDB asynchronously on the task |
417 // runner. Without this, we'd get reports of memory leaks. | 445 // runner. Without this, we'd get reports of memory leaks. |
418 base::RunLoop().RunUntilIdle(); | 446 base::RunLoop().RunUntilIdle(); |
419 } | 447 } |
420 | 448 |
449 // TODO(vitaliii): Rewrite this function to initialize a test class member | |
450 // instead of creating a new service. | |
421 std::unique_ptr<RemoteSuggestionsProvider> MakeSnippetsService( | 451 std::unique_ptr<RemoteSuggestionsProvider> MakeSnippetsService( |
422 bool set_empty_response = true) { | 452 bool set_empty_response = true) { |
423 auto service = MakeSnippetsServiceWithoutInitialization(); | 453 auto service = MakeSnippetsServiceWithoutInitialization(); |
424 WaitForSnippetsServiceInitialization(service.get(), set_empty_response); | 454 WaitForSnippetsServiceInitialization(service.get(), set_empty_response); |
425 return service; | 455 return service; |
426 } | 456 } |
427 | 457 |
428 std::unique_ptr<RemoteSuggestionsProvider> | 458 std::unique_ptr<RemoteSuggestionsProvider> |
429 MakeSnippetsServiceWithoutInitialization() { | 459 MakeSnippetsServiceWithoutInitialization() { |
430 scoped_refptr<base::SingleThreadTaskRunner> task_runner( | 460 scoped_refptr<base::SingleThreadTaskRunner> task_runner( |
431 base::ThreadTaskRunnerHandle::Get()); | 461 base::ThreadTaskRunnerHandle::Get()); |
432 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter = | 462 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter = |
433 new net::TestURLRequestContextGetter(task_runner.get()); | 463 new net::TestURLRequestContextGetter(task_runner.get()); |
434 | 464 |
435 utils_.ResetSigninManager(); | 465 utils_.ResetSigninManager(); |
436 std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher = | 466 std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher = |
437 base::MakeUnique<NTPSnippetsFetcher>( | 467 base::MakeUnique<NTPSnippetsFetcher>( |
438 utils_.fake_signin_manager(), fake_token_service_.get(), | 468 utils_.fake_signin_manager(), fake_token_service_.get(), |
439 std::move(request_context_getter), utils_.pref_service(), | 469 std::move(request_context_getter), utils_.pref_service(), nullptr, |
440 &category_factory_, nullptr, base::Bind(&ParseJson), kAPIKey, | 470 base::Bind(&ParseJson), kAPIKey, &user_classifier_); |
441 &user_classifier_); | |
442 | 471 |
443 utils_.fake_signin_manager()->SignIn("foo@bar.com"); | 472 utils_.fake_signin_manager()->SignIn("foo@bar.com"); |
444 | 473 |
445 auto image_fetcher = base::MakeUnique<NiceMock<MockImageFetcher>>(); | 474 auto image_fetcher = base::MakeUnique<NiceMock<MockImageFetcher>>(); |
446 | 475 |
447 image_fetcher_ = image_fetcher.get(); | 476 image_fetcher_ = image_fetcher.get(); |
448 EXPECT_CALL(*image_fetcher, SetImageFetcherDelegate(_)); | 477 EXPECT_CALL(*image_fetcher, SetImageFetcherDelegate(_)); |
449 auto image_decoder = base::MakeUnique<FakeImageDecoder>(); | 478 auto image_decoder = base::MakeUnique<FakeImageDecoder>(); |
450 image_decoder_ = image_decoder.get(); | 479 image_decoder_ = image_decoder.get(); |
451 EXPECT_FALSE(observer_); | 480 EXPECT_FALSE(observer_); |
452 observer_ = base::MakeUnique<FakeContentSuggestionsProviderObserver>(); | 481 observer_ = base::MakeUnique<FakeContentSuggestionsProviderObserver>(); |
453 return base::MakeUnique<RemoteSuggestionsProvider>( | 482 return base::MakeUnique<RemoteSuggestionsProvider>( |
454 observer_.get(), &category_factory_, utils_.pref_service(), "fr", | 483 observer_.get(), utils_.pref_service(), "fr", category_ranker_.get(), |
455 &user_classifier_, &scheduler_, std::move(snippets_fetcher), | 484 &user_classifier_, &scheduler_, std::move(snippets_fetcher), |
456 std::move(image_fetcher), std::move(image_decoder), | 485 std::move(image_fetcher), std::move(image_decoder), |
457 base::MakeUnique<RemoteSuggestionsDatabase>(database_dir_.GetPath(), | 486 base::MakeUnique<RemoteSuggestionsDatabase>(database_dir_.GetPath(), |
458 task_runner), | 487 task_runner), |
459 base::MakeUnique<RemoteSuggestionsStatusService>( | 488 base::MakeUnique<RemoteSuggestionsStatusService>( |
460 utils_.fake_signin_manager(), utils_.pref_service())); | 489 utils_.fake_signin_manager(), utils_.pref_service())); |
461 } | 490 } |
462 | 491 |
463 void WaitForSnippetsServiceInitialization(RemoteSuggestionsProvider* service, | 492 void WaitForSnippetsServiceInitialization(RemoteSuggestionsProvider* service, |
464 bool set_empty_response) { | 493 bool set_empty_response) { |
465 EXPECT_EQ(RemoteSuggestionsProvider::State::NOT_INITED, service->state_); | 494 EXPECT_EQ(RemoteSuggestionsProvider::State::NOT_INITED, service->state_); |
466 | 495 |
467 // 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 |
468 // is nothing in the DB. | 497 // is nothing in the DB. |
469 if (set_empty_response) { | 498 if (set_empty_response) { |
470 SetUpFetchResponse(GetTestJson(std::vector<std::string>())); | 499 SetUpFetchResponse(GetTestJson(std::vector<std::string>())); |
471 } | 500 } |
472 | 501 |
473 // 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. |
474 base::RunLoop().RunUntilIdle(); | 503 base::RunLoop().RunUntilIdle(); |
475 EXPECT_NE(RemoteSuggestionsProvider::State::NOT_INITED, service->state_); | 504 EXPECT_NE(RemoteSuggestionsProvider::State::NOT_INITED, service->state_); |
476 } | 505 } |
477 | 506 |
478 void ResetSnippetsService( | 507 void ResetSnippetsService(std::unique_ptr<RemoteSuggestionsProvider>* service, |
479 std::unique_ptr<RemoteSuggestionsProvider>* service) { | 508 bool set_empty_response) { |
480 service->reset(); | 509 service->reset(); |
481 observer_.reset(); | 510 observer_.reset(); |
482 *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); | |
483 } | 516 } |
484 | 517 |
485 ContentSuggestion::ID MakeArticleID(const std::string& id_within_category) { | 518 ContentSuggestion::ID MakeArticleID(const std::string& id_within_category) { |
486 return ContentSuggestion::ID(articles_category(), id_within_category); | 519 return ContentSuggestion::ID(articles_category(), id_within_category); |
487 } | 520 } |
488 | 521 |
489 Category articles_category() { | 522 Category articles_category() { |
490 return category_factory_.FromKnownCategory(KnownCategories::ARTICLES); | 523 return Category::FromKnownCategory(KnownCategories::ARTICLES); |
491 } | 524 } |
492 | 525 |
493 ContentSuggestion::ID MakeOtherID(const std::string& id_within_category) { | 526 ContentSuggestion::ID MakeOtherID(const std::string& id_within_category) { |
494 return ContentSuggestion::ID(other_category(), id_within_category); | 527 return ContentSuggestion::ID(other_category(), id_within_category); |
495 } | 528 } |
496 | 529 |
497 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); } | |
498 | 533 |
499 Category unknown_category() { | 534 Category unknown_category() { |
500 return category_factory_.FromRemoteCategory(kUnknownRemoteCategoryId); | 535 return Category::FromRemoteCategory(kUnknownRemoteCategoryId); |
501 } | 536 } |
502 | 537 |
503 protected: | 538 protected: |
504 const GURL& test_url() { return test_url_; } | 539 const GURL& test_url() { return test_url_; } |
505 FakeContentSuggestionsProviderObserver& observer() { return *observer_; } | 540 FakeContentSuggestionsProviderObserver& observer() { return *observer_; } |
506 MockScheduler& mock_scheduler() { return scheduler_; } | 541 MockScheduler& mock_scheduler() { return scheduler_; } |
507 // 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 |
508 // network requests. | 543 // network requests. |
509 NiceMock<MockImageFetcher>* image_fetcher() { return image_fetcher_; } | 544 NiceMock<MockImageFetcher>* image_fetcher() { return image_fetcher_; } |
510 FakeImageDecoder* image_decoder() { return image_decoder_; } | 545 FakeImageDecoder* image_decoder() { return image_decoder_; } |
(...skipping 24 matching lines...) Expand all Loading... | |
535 | 570 |
536 private: | 571 private: |
537 variations::testing::VariationParamsManager params_manager_; | 572 variations::testing::VariationParamsManager params_manager_; |
538 test::RemoteSuggestionsTestUtils utils_; | 573 test::RemoteSuggestionsTestUtils utils_; |
539 base::MessageLoop message_loop_; | 574 base::MessageLoop message_loop_; |
540 FailingFakeURLFetcherFactory failing_url_fetcher_factory_; | 575 FailingFakeURLFetcherFactory failing_url_fetcher_factory_; |
541 // Instantiation of factory automatically sets itself as URLFetcher's factory. | 576 // Instantiation of factory automatically sets itself as URLFetcher's factory. |
542 net::FakeURLFetcherFactory fake_url_fetcher_factory_; | 577 net::FakeURLFetcherFactory fake_url_fetcher_factory_; |
543 const GURL test_url_; | 578 const GURL test_url_; |
544 std::unique_ptr<OAuth2TokenService> fake_token_service_; | 579 std::unique_ptr<OAuth2TokenService> fake_token_service_; |
580 std::unique_ptr<CategoryRanker> category_ranker_; | |
545 UserClassifier user_classifier_; | 581 UserClassifier user_classifier_; |
546 NiceMock<MockScheduler> scheduler_; | 582 NiceMock<MockScheduler> scheduler_; |
547 std::unique_ptr<FakeContentSuggestionsProviderObserver> observer_; | 583 std::unique_ptr<FakeContentSuggestionsProviderObserver> observer_; |
548 CategoryFactory category_factory_; | |
549 NiceMock<MockImageFetcher>* image_fetcher_; | 584 NiceMock<MockImageFetcher>* image_fetcher_; |
550 FakeImageDecoder* image_decoder_; | 585 FakeImageDecoder* image_decoder_; |
551 | 586 |
552 base::ScopedTempDir database_dir_; | 587 base::ScopedTempDir database_dir_; |
553 | 588 |
554 DISALLOW_COPY_AND_ASSIGN(RemoteSuggestionsProviderTest); | 589 DISALLOW_COPY_AND_ASSIGN(RemoteSuggestionsProviderTest); |
555 }; | 590 }; |
556 | 591 |
557 TEST_F(RemoteSuggestionsProviderTest, ScheduleOnStart) { | 592 TEST_F(RemoteSuggestionsProviderTest, ScheduleOnStart) { |
558 // We should get two |Schedule| calls: The first when initialization | 593 // We should get two |Schedule| calls: The first when initialization |
(...skipping 13 matching lines...) Expand all Loading... | |
572 SetUpFetchResponse(GetTestJson({GetSnippet()})); | 607 SetUpFetchResponse(GetTestJson({GetSnippet()})); |
573 auto service = MakeSnippetsService(/*set_empty_response=*/false); | 608 auto service = MakeSnippetsService(/*set_empty_response=*/false); |
574 | 609 |
575 // When recreating the service, we should not get any |Schedule| calls: | 610 // When recreating the service, we should not get any |Schedule| calls: |
576 // 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 |
577 // 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 |
578 // should happen. | 613 // should happen. |
579 Mock::VerifyAndClearExpectations(&mock_scheduler()); | 614 Mock::VerifyAndClearExpectations(&mock_scheduler()); |
580 EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(0); | 615 EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(0); |
581 EXPECT_CALL(mock_scheduler(), Unschedule()).Times(0); | 616 EXPECT_CALL(mock_scheduler(), Unschedule()).Times(0); |
582 ResetSnippetsService(&service); | 617 ResetSnippetsService(&service, /*set_empty_response=*/true); |
583 } | 618 } |
584 | 619 |
585 TEST_F(RemoteSuggestionsProviderTest, RescheduleAfterSuccessfulFetch) { | 620 TEST_F(RemoteSuggestionsProviderTest, RescheduleAfterSuccessfulFetch) { |
586 // We should get two |Schedule| calls: The first when initialization | 621 // We should get two |Schedule| calls: The first when initialization |
587 // 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 |
588 // have any data yet) fetch finishes. | 623 // have any data yet) fetch finishes. |
589 EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(2); | 624 EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(2); |
590 auto service = MakeSnippetsService(); | 625 auto service = MakeSnippetsService(); |
591 | 626 |
592 // 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... | |
723 CategoryInfo info_with_title = service->GetCategoryInfo(articles_category()); | 758 CategoryInfo info_with_title = service->GetCategoryInfo(articles_category()); |
724 EXPECT_THAT(info_before.title(), Not(Eq(info_with_title.title()))); | 759 EXPECT_THAT(info_before.title(), Not(Eq(info_with_title.title()))); |
725 EXPECT_THAT(test_default_title, Eq(info_with_title.title())); | 760 EXPECT_THAT(test_default_title, Eq(info_with_title.title())); |
726 EXPECT_THAT(info_before.has_more_action(), Eq(true)); | 761 EXPECT_THAT(info_before.has_more_action(), Eq(true)); |
727 EXPECT_THAT(info_before.has_reload_action(), Eq(true)); | 762 EXPECT_THAT(info_before.has_reload_action(), Eq(true)); |
728 EXPECT_THAT(info_before.has_view_all_action(), Eq(false)); | 763 EXPECT_THAT(info_before.has_view_all_action(), Eq(false)); |
729 EXPECT_THAT(info_before.show_if_empty(), Eq(true)); | 764 EXPECT_THAT(info_before.show_if_empty(), Eq(true)); |
730 } | 765 } |
731 | 766 |
732 TEST_F(RemoteSuggestionsProviderTest, MultipleCategories) { | 767 TEST_F(RemoteSuggestionsProviderTest, MultipleCategories) { |
733 std::string json_str( | |
734 GetMultiCategoryJson({GetSnippetN(0)}, {GetSnippetN(1)})); | |
735 | |
736 auto service = MakeSnippetsService(); | 768 auto service = MakeSnippetsService(); |
737 | 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(); | |
738 LoadFromJSONString(service.get(), json_str); | 774 LoadFromJSONString(service.get(), json_str); |
739 | 775 |
740 ASSERT_THAT(observer().statuses(), | 776 ASSERT_THAT(observer().statuses(), |
741 Eq(std::map<Category, CategoryStatus, Category::CompareByID>{ | 777 Eq(std::map<Category, CategoryStatus, Category::CompareByID>{ |
742 {articles_category(), CategoryStatus::AVAILABLE}, | 778 {articles_category(), CategoryStatus::AVAILABLE}, |
743 {other_category(), CategoryStatus::AVAILABLE}, | 779 {other_category(), CategoryStatus::AVAILABLE}, |
744 })); | 780 })); |
745 | 781 |
746 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1)); | 782 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1)); |
747 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... | |
780 auto service = MakeSnippetsService(); | 816 auto service = MakeSnippetsService(); |
781 CategoryInfo article_info = service->GetCategoryInfo(articles_category()); | 817 CategoryInfo article_info = service->GetCategoryInfo(articles_category()); |
782 EXPECT_THAT(article_info.has_more_action(), Eq(true)); | 818 EXPECT_THAT(article_info.has_more_action(), Eq(true)); |
783 EXPECT_THAT(article_info.has_reload_action(), Eq(true)); | 819 EXPECT_THAT(article_info.has_reload_action(), Eq(true)); |
784 EXPECT_THAT(article_info.has_view_all_action(), Eq(false)); | 820 EXPECT_THAT(article_info.has_view_all_action(), Eq(false)); |
785 EXPECT_THAT(article_info.show_if_empty(), Eq(true)); | 821 EXPECT_THAT(article_info.show_if_empty(), Eq(true)); |
786 } | 822 } |
787 | 823 |
788 TEST_F(RemoteSuggestionsProviderTest, ExperimentalCategoryInfo) { | 824 TEST_F(RemoteSuggestionsProviderTest, ExperimentalCategoryInfo) { |
789 auto service = MakeSnippetsService(); | 825 auto service = MakeSnippetsService(); |
790 | 826 std::string json_str = |
827 MultiCategoryJsonBuilder() | |
828 .AddCategory({GetSnippetN(0)}, /*remote_category_id=*/1) | |
829 .AddCategory({GetSnippetN(1)}, kUnknownRemoteCategoryId) | |
830 .Build(); | |
791 // 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 |
792 // registered. | 832 // registered. |
793 LoadFromJSONString(service.get(), | 833 LoadFromJSONString(service.get(), json_str); |
794 GetMultiCategoryJson({GetSnippetN(0)}, {GetSnippetN(1)}, | 834 |
795 kUnknownRemoteCategoryId)); | |
796 CategoryInfo info = service->GetCategoryInfo(unknown_category()); | 835 CategoryInfo info = service->GetCategoryInfo(unknown_category()); |
797 EXPECT_THAT(info.has_more_action(), Eq(false)); | 836 EXPECT_THAT(info.has_more_action(), Eq(false)); |
798 EXPECT_THAT(info.has_reload_action(), Eq(false)); | 837 EXPECT_THAT(info.has_reload_action(), Eq(false)); |
799 EXPECT_THAT(info.has_view_all_action(), Eq(false)); | 838 EXPECT_THAT(info.has_view_all_action(), Eq(false)); |
800 EXPECT_THAT(info.show_if_empty(), Eq(false)); | 839 EXPECT_THAT(info.show_if_empty(), Eq(false)); |
801 } | 840 } |
802 | 841 |
842 TEST_F(RemoteSuggestionsProviderTest, AddRemoteCategoriesToCategoryRanker) { | |
843 auto mock_ranker = new MockCategoryRanker(); | |
844 SetCategoryRanker(std::unique_ptr<CategoryRanker>(mock_ranker)); | |
Marc Treib
2016/12/15 16:01:18
This is a bit yucky, ownership-wise. How about:
au
vitaliii
2016/12/15 16:53:50
Done.
| |
845 std::string json_str = | |
846 MultiCategoryJsonBuilder() | |
847 .AddCategory({GetSnippetN(0)}, /*remote_category_id=*/11) | |
848 .AddCategory({GetSnippetN(1)}, /*remote_category_id=*/13) | |
849 .AddCategory({GetSnippetN(2)}, /*remote_category_id=*/12) | |
850 .Build(); | |
851 SetUpFetchResponse(json_str); | |
852 { | |
853 InSequence s; | |
854 EXPECT_CALL(*mock_ranker, | |
855 AppendCategoryIfNecessary(Category::FromRemoteCategory(11))); | |
856 EXPECT_CALL(*mock_ranker, | |
857 AppendCategoryIfNecessary(Category::FromRemoteCategory(13))); | |
858 EXPECT_CALL(*mock_ranker, | |
859 AppendCategoryIfNecessary(Category::FromRemoteCategory(12))); | |
860 } | |
861 auto service = MakeSnippetsService(/*set_empty_response=*/false); | |
862 } | |
863 | |
803 TEST_F(RemoteSuggestionsProviderTest, PersistCategoryInfos) { | 864 TEST_F(RemoteSuggestionsProviderTest, PersistCategoryInfos) { |
804 auto service = MakeSnippetsService(); | 865 auto service = MakeSnippetsService(); |
805 | 866 // TODO(vitaliii): Use |articles_category()| instead of constant ID below. |
806 LoadFromJSONString(service.get(), | 867 std::string json_str = |
807 GetMultiCategoryJson({GetSnippetN(0)}, {GetSnippetN(1)}, | 868 MultiCategoryJsonBuilder() |
808 kUnknownRemoteCategoryId)); | 869 .AddCategoryWithCustomTitle( |
870 {GetSnippetN(0)}, /*remote_category_id=*/1, "Articles for You") | |
871 .AddCategoryWithCustomTitle({GetSnippetN(1)}, | |
872 kUnknownRemoteCategoryId, "Other Things") | |
873 .Build(); | |
874 LoadFromJSONString(service.get(), json_str); | |
809 | 875 |
810 ASSERT_EQ(observer().StatusForCategory(articles_category()), | 876 ASSERT_EQ(observer().StatusForCategory(articles_category()), |
811 CategoryStatus::AVAILABLE); | 877 CategoryStatus::AVAILABLE); |
812 ASSERT_EQ(observer().StatusForCategory(unknown_category()), | 878 ASSERT_EQ(observer().StatusForCategory(unknown_category()), |
813 CategoryStatus::AVAILABLE); | 879 CategoryStatus::AVAILABLE); |
814 | 880 |
815 CategoryInfo info_articles_before = | 881 CategoryInfo info_articles_before = |
816 service->GetCategoryInfo(articles_category()); | 882 service->GetCategoryInfo(articles_category()); |
817 CategoryInfo info_unknown_before = | 883 CategoryInfo info_unknown_before = |
818 service->GetCategoryInfo(unknown_category()); | 884 service->GetCategoryInfo(unknown_category()); |
819 | 885 |
820 // Recreate the service to simulate a Chrome restart. | 886 // Recreate the service to simulate a Chrome restart. |
821 ResetSnippetsService(&service); | 887 ResetSnippetsService(&service, /*set_empty_response=*/true); |
822 | 888 |
823 // The categories should have been restored. | 889 // The categories should have been restored. |
824 ASSERT_NE(observer().StatusForCategory(articles_category()), | 890 ASSERT_NE(observer().StatusForCategory(articles_category()), |
825 CategoryStatus::NOT_PROVIDED); | 891 CategoryStatus::NOT_PROVIDED); |
826 ASSERT_NE(observer().StatusForCategory(unknown_category()), | 892 ASSERT_NE(observer().StatusForCategory(unknown_category()), |
827 CategoryStatus::NOT_PROVIDED); | 893 CategoryStatus::NOT_PROVIDED); |
828 | 894 |
829 EXPECT_EQ(observer().StatusForCategory(articles_category()), | 895 EXPECT_EQ(observer().StatusForCategory(articles_category()), |
830 CategoryStatus::AVAILABLE); | 896 CategoryStatus::AVAILABLE); |
831 EXPECT_EQ(observer().StatusForCategory(unknown_category()), | 897 EXPECT_EQ(observer().StatusForCategory(unknown_category()), |
832 CategoryStatus::AVAILABLE); | 898 CategoryStatus::AVAILABLE); |
833 | 899 |
834 CategoryInfo info_articles_after = | 900 CategoryInfo info_articles_after = |
835 service->GetCategoryInfo(articles_category()); | 901 service->GetCategoryInfo(articles_category()); |
836 CategoryInfo info_unknown_after = | 902 CategoryInfo info_unknown_after = |
837 service->GetCategoryInfo(unknown_category()); | 903 service->GetCategoryInfo(unknown_category()); |
838 | 904 |
839 EXPECT_EQ(info_articles_before.title(), info_articles_after.title()); | 905 EXPECT_EQ(info_articles_before.title(), info_articles_after.title()); |
840 EXPECT_EQ(info_unknown_before.title(), info_unknown_after.title()); | 906 EXPECT_EQ(info_unknown_before.title(), info_unknown_after.title()); |
841 } | 907 } |
842 | 908 |
909 TEST_F(RemoteSuggestionsProviderTest, PersistRemoteCategoryOrder) { | |
910 // We create a service with a normal ranker to store the order. | |
911 std::string json_str = | |
912 MultiCategoryJsonBuilder() | |
913 .AddCategory({GetSnippetN(0)}, /*remote_category_id=*/11) | |
914 .AddCategory({GetSnippetN(1)}, /*remote_category_id=*/13) | |
915 .AddCategory({GetSnippetN(2)}, /*remote_category_id=*/12) | |
916 .Build(); | |
917 SetUpFetchResponse(json_str); | |
918 auto service = MakeSnippetsService(/*set_empty_response=*/false); | |
919 | |
920 // We manually recreate the service to simulate Chrome restart and enforce a | |
921 // mock ranker. The response is cleared to ensure that the order is not | |
922 // fetched. | |
923 SetUpFetchResponse(""); | |
924 auto mock_ranker = new MockCategoryRanker(); | |
Marc Treib
2016/12/15 16:01:18
Same here.
vitaliii
2016/12/15 16:53:50
Done.
| |
925 SetCategoryRanker(std::unique_ptr<CategoryRanker>(mock_ranker)); | |
926 { | |
927 InSequence s; | |
928 // Article category always exists and, therefore, it is stored in prefs too. | |
929 EXPECT_CALL(*mock_ranker, | |
930 AppendCategoryIfNecessary(Category::FromRemoteCategory(1))); | |
931 | |
932 EXPECT_CALL(*mock_ranker, | |
933 AppendCategoryIfNecessary(Category::FromRemoteCategory(11))); | |
934 EXPECT_CALL(*mock_ranker, | |
935 AppendCategoryIfNecessary(Category::FromRemoteCategory(13))); | |
936 EXPECT_CALL(*mock_ranker, | |
937 AppendCategoryIfNecessary(Category::FromRemoteCategory(12))); | |
938 } | |
939 ResetSnippetsService(&service, /*set_empty_response=*/false); | |
940 } | |
941 | |
843 TEST_F(RemoteSuggestionsProviderTest, PersistSuggestions) { | 942 TEST_F(RemoteSuggestionsProviderTest, PersistSuggestions) { |
844 auto service = MakeSnippetsService(); | 943 auto service = MakeSnippetsService(); |
845 | 944 std::string json_str = |
846 LoadFromJSONString(service.get(), | 945 MultiCategoryJsonBuilder() |
847 GetMultiCategoryJson({GetSnippetN(0)}, {GetSnippetN(1)})); | 946 .AddCategory({GetSnippetN(0)}, /*remote_category_id=*/1) |
947 .AddCategory({GetSnippetN(2)}, /*remote_category_id=*/2) | |
948 .Build(); | |
949 LoadFromJSONString(service.get(), json_str); | |
848 | 950 |
849 ASSERT_THAT(observer().SuggestionsForCategory(articles_category()), | 951 ASSERT_THAT(observer().SuggestionsForCategory(articles_category()), |
850 SizeIs(1)); | 952 SizeIs(1)); |
851 ASSERT_THAT(observer().SuggestionsForCategory(other_category()), SizeIs(1)); | 953 ASSERT_THAT(observer().SuggestionsForCategory(other_category()), SizeIs(1)); |
852 | 954 |
853 // Recreate the service to simulate a Chrome restart. | 955 // Recreate the service to simulate a Chrome restart. |
854 ResetSnippetsService(&service); | 956 ResetSnippetsService(&service, /*set_empty_response=*/true); |
855 | 957 |
856 // The suggestions in both categories should have been restored. | 958 // The suggestions in both categories should have been restored. |
857 EXPECT_THAT(observer().SuggestionsForCategory(articles_category()), | 959 EXPECT_THAT(observer().SuggestionsForCategory(articles_category()), |
858 SizeIs(1)); | 960 SizeIs(1)); |
859 EXPECT_THAT(observer().SuggestionsForCategory(other_category()), SizeIs(1)); | 961 EXPECT_THAT(observer().SuggestionsForCategory(other_category()), SizeIs(1)); |
860 } | 962 } |
861 | 963 |
862 TEST_F(RemoteSuggestionsProviderTest, DontNotifyIfNotAvailable) { | 964 TEST_F(RemoteSuggestionsProviderTest, DontNotifyIfNotAvailable) { |
863 // Get some suggestions into the database. | 965 // Get some suggestions into the database. |
864 auto service = MakeSnippetsService(); | 966 auto service = MakeSnippetsService(); |
865 LoadFromJSONString(service.get(), | 967 std::string json_str = |
866 GetMultiCategoryJson({GetSnippetN(0)}, {GetSnippetN(1)})); | 968 MultiCategoryJsonBuilder() |
969 .AddCategory({GetSnippetN(0)}, | |
970 /*remote_category_id=*/1) | |
971 .AddCategory({GetSnippetN(1)}, /*remote_category_id=*/2) | |
972 .Build(); | |
973 LoadFromJSONString(service.get(), json_str); | |
974 | |
867 ASSERT_THAT(observer().SuggestionsForCategory(articles_category()), | 975 ASSERT_THAT(observer().SuggestionsForCategory(articles_category()), |
868 SizeIs(1)); | 976 SizeIs(1)); |
869 ASSERT_THAT(observer().SuggestionsForCategory(other_category()), SizeIs(1)); | 977 ASSERT_THAT(observer().SuggestionsForCategory(other_category()), SizeIs(1)); |
870 | 978 |
871 service.reset(); | 979 service.reset(); |
872 | 980 |
873 // Set the pref that disables remote suggestions. | 981 // Set the pref that disables remote suggestions. |
874 pref_service()->SetBoolean(prefs::kEnableSnippets, false); | 982 pref_service()->SetBoolean(prefs::kEnableSnippets, false); |
875 | 983 |
876 // Recreate the service to simulate a Chrome start. | 984 // Recreate the service to simulate a Chrome start. |
877 ResetSnippetsService(&service); | 985 ResetSnippetsService(&service, /*set_empty_response=*/true); |
878 | 986 |
879 ASSERT_THAT(RemoteSuggestionsProvider::State::DISABLED, Eq(service->state_)); | 987 ASSERT_THAT(RemoteSuggestionsProvider::State::DISABLED, Eq(service->state_)); |
880 | 988 |
881 // Now the observer should not have received any suggestions. | 989 // Now the observer should not have received any suggestions. |
882 EXPECT_THAT(observer().SuggestionsForCategory(articles_category()), | 990 EXPECT_THAT(observer().SuggestionsForCategory(articles_category()), |
883 IsEmpty()); | 991 IsEmpty()); |
884 EXPECT_THAT(observer().SuggestionsForCategory(other_category()), IsEmpty()); | 992 EXPECT_THAT(observer().SuggestionsForCategory(other_category()), IsEmpty()); |
885 } | 993 } |
886 | 994 |
887 TEST_F(RemoteSuggestionsProviderTest, Clear) { | 995 TEST_F(RemoteSuggestionsProviderTest, Clear) { |
(...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1188 image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1)); | 1296 image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1)); |
1189 image = FetchImage(service.get(), MakeArticleID(kSnippetUrl)); | 1297 image = FetchImage(service.get(), MakeArticleID(kSnippetUrl)); |
1190 EXPECT_FALSE(image.IsEmpty()); | 1298 EXPECT_FALSE(image.IsEmpty()); |
1191 EXPECT_EQ(1, image.Width()); | 1299 EXPECT_EQ(1, image.Width()); |
1192 | 1300 |
1193 // Make sure that fetching the same snippet again does not re-add it. | 1301 // Make sure that fetching the same snippet again does not re-add it. |
1194 LoadFromJSONString(service.get(), json_str); | 1302 LoadFromJSONString(service.get(), json_str); |
1195 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty()); | 1303 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty()); |
1196 | 1304 |
1197 // The snippet should stay dismissed even after re-creating the service. | 1305 // The snippet should stay dismissed even after re-creating the service. |
1198 ResetSnippetsService(&service); | 1306 ResetSnippetsService(&service, /*set_empty_response=*/true); |
1199 LoadFromJSONString(service.get(), json_str); | 1307 LoadFromJSONString(service.get(), json_str); |
1200 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty()); | 1308 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty()); |
1201 | 1309 |
1202 // The snippet can be added again after clearing dismissed snippets. | 1310 // The snippet can be added again after clearing dismissed snippets. |
1203 service->ClearDismissedSuggestionsForDebugging(articles_category()); | 1311 service->ClearDismissedSuggestionsForDebugging(articles_category()); |
1204 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty()); | 1312 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty()); |
1205 LoadFromJSONString(service.get(), json_str); | 1313 LoadFromJSONString(service.get(), json_str); |
1206 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1)); | 1314 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1)); |
1207 } | 1315 } |
1208 | 1316 |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1383 EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"), | 1491 EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"), |
1384 ElementsAre(base::Bucket(/*min=*/0, /*count=*/1), | 1492 ElementsAre(base::Bucket(/*min=*/0, /*count=*/1), |
1385 base::Bucket(/*min=*/1, /*count=*/3))); | 1493 base::Bucket(/*min=*/1, /*count=*/3))); |
1386 EXPECT_THAT( | 1494 EXPECT_THAT( |
1387 tester.GetAllSamples("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded"), | 1495 tester.GetAllSamples("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded"), |
1388 ElementsAre(base::Bucket(/*min=*/1, /*count=*/1))); | 1496 ElementsAre(base::Bucket(/*min=*/1, /*count=*/1))); |
1389 | 1497 |
1390 // There is only a single, dismissed snippet in the database, so recreating | 1498 // There is only a single, dismissed snippet in the database, so recreating |
1391 // the service will require us to re-fetch. | 1499 // the service will require us to re-fetch. |
1392 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 4); | 1500 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 4); |
1393 ResetSnippetsService(&service); | 1501 ResetSnippetsService(&service, /*set_empty_response=*/true); |
1394 EXPECT_EQ(observer().StatusForCategory(articles_category()), | 1502 EXPECT_EQ(observer().StatusForCategory(articles_category()), |
1395 CategoryStatus::AVAILABLE); | 1503 CategoryStatus::AVAILABLE); |
1396 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 5); | 1504 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 5); |
1397 EXPECT_THAT( | 1505 EXPECT_THAT( |
1398 tester.GetAllSamples("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded"), | 1506 tester.GetAllSamples("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded"), |
1399 ElementsAre(base::Bucket(/*min=*/1, /*count=*/2))); | 1507 ElementsAre(base::Bucket(/*min=*/1, /*count=*/2))); |
1400 | 1508 |
1401 // But if there's a non-dismissed snippet in the database, recreating it | 1509 // But if there's a non-dismissed snippet in the database, recreating it |
1402 // shouldn't trigger a fetch. | 1510 // shouldn't trigger a fetch. |
1403 LoadFromJSONString( | 1511 LoadFromJSONString( |
1404 service.get(), | 1512 service.get(), |
1405 GetTestJson({GetSnippetWithUrl("http://not-dismissed.com")})); | 1513 GetTestJson({GetSnippetWithUrl("http://not-dismissed.com")})); |
1406 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 6); | 1514 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 6); |
1407 ResetSnippetsService(&service); | 1515 ResetSnippetsService(&service, /*set_empty_response=*/true); |
1408 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 6); | 1516 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 6); |
1409 } | 1517 } |
1410 | 1518 |
1411 TEST_F(RemoteSuggestionsProviderTest, DismissShouldRespectAllKnownUrls) { | 1519 TEST_F(RemoteSuggestionsProviderTest, DismissShouldRespectAllKnownUrls) { |
1412 auto service = MakeSnippetsService(); | 1520 auto service = MakeSnippetsService(); |
1413 | 1521 |
1414 const base::Time creation = GetDefaultCreationTime(); | 1522 const base::Time creation = GetDefaultCreationTime(); |
1415 const base::Time expiry = GetDefaultExpirationTime(); | 1523 const base::Time expiry = GetDefaultExpirationTime(); |
1416 const std::vector<std::string> source_urls = { | 1524 const std::vector<std::string> source_urls = { |
1417 "http://mashable.com/2016/05/11/stolen", | 1525 "http://mashable.com/2016/05/11/stolen", |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1566 gfx::Image image = FetchImage(service.get(), MakeArticleID(kSnippetUrl)); | 1674 gfx::Image image = FetchImage(service.get(), MakeArticleID(kSnippetUrl)); |
1567 EXPECT_EQ(1, image.Width()); | 1675 EXPECT_EQ(1, image.Width()); |
1568 EXPECT_FALSE(image.IsEmpty()); | 1676 EXPECT_FALSE(image.IsEmpty()); |
1569 | 1677 |
1570 // Send new suggestion which don't include the snippet referencing the image. | 1678 // Send new suggestion which don't include the snippet referencing the image. |
1571 LoadFromJSONString(service.get(), | 1679 LoadFromJSONString(service.get(), |
1572 GetTestJson({GetSnippetWithUrl( | 1680 GetTestJson({GetSnippetWithUrl( |
1573 "http://something.com/pletely/unrelated")})); | 1681 "http://something.com/pletely/unrelated")})); |
1574 // The image should still be available until a restart happens. | 1682 // The image should still be available until a restart happens. |
1575 EXPECT_FALSE(FetchImage(service.get(), MakeArticleID(kSnippetUrl)).IsEmpty()); | 1683 EXPECT_FALSE(FetchImage(service.get(), MakeArticleID(kSnippetUrl)).IsEmpty()); |
1576 ResetSnippetsService(&service); | 1684 ResetSnippetsService(&service, /*set_empty_response=*/true); |
1577 // After the restart, the image should be garbage collected. | 1685 // After the restart, the image should be garbage collected. |
1578 EXPECT_TRUE(FetchImage(service.get(), MakeArticleID(kSnippetUrl)).IsEmpty()); | 1686 EXPECT_TRUE(FetchImage(service.get(), MakeArticleID(kSnippetUrl)).IsEmpty()); |
1579 } | 1687 } |
1580 | 1688 |
1581 TEST_F(RemoteSuggestionsProviderTest, | 1689 TEST_F(RemoteSuggestionsProviderTest, |
1582 ShouldHandleMoreThanMaxSnippetsInResponse) { | 1690 ShouldHandleMoreThanMaxSnippetsInResponse) { |
1583 auto service = MakeSnippetsService(); | 1691 auto service = MakeSnippetsService(); |
1584 | 1692 |
1585 std::vector<std::string> suggestions; | 1693 std::vector<std::string> suggestions; |
1586 for (int i = 0; i < service->GetMaxSnippetCountForTesting() + 1; ++i) { | 1694 for (int i = 0; i < service->GetMaxSnippetCountForTesting() + 1; ++i) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1620 service->FetchSnippetsInTheBackground(); | 1728 service->FetchSnippetsInTheBackground(); |
1621 base::RunLoop().RunUntilIdle(); | 1729 base::RunLoop().RunUntilIdle(); |
1622 EXPECT_EQ( | 1730 EXPECT_EQ( |
1623 simple_test_clock_ptr->Now().ToInternalValue(), | 1731 simple_test_clock_ptr->Now().ToInternalValue(), |
1624 pref_service()->GetInt64(prefs::kLastSuccessfulBackgroundFetchTime)); | 1732 pref_service()->GetInt64(prefs::kLastSuccessfulBackgroundFetchTime)); |
1625 // TODO(markusheintz): Add a test that simulates a browser restart once the | 1733 // TODO(markusheintz): Add a test that simulates a browser restart once the |
1626 // scheduler refactoring is done (crbug.com/672434). | 1734 // scheduler refactoring is done (crbug.com/672434). |
1627 } | 1735 } |
1628 | 1736 |
1629 } // namespace ntp_snippets | 1737 } // namespace ntp_snippets |
OLD | NEW |