| 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 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 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/threading/thread_task_runner_handle.h" | 23 #include "base/threading/thread_task_runner_handle.h" |
| 24 #include "base/time/time.h" | 24 #include "base/time/time.h" |
| 25 #include "components/image_fetcher/image_decoder.h" | 25 #include "components/image_fetcher/image_decoder.h" |
| 26 #include "components/image_fetcher/image_fetcher.h" | 26 #include "components/image_fetcher/image_fetcher.h" |
| 27 #include "components/image_fetcher/image_fetcher_delegate.h" | 27 #include "components/image_fetcher/image_fetcher_delegate.h" |
| 28 #include "components/ntp_snippets/category_factory.h" | 28 #include "components/ntp_snippets/category_factory.h" |
| 29 #include "components/ntp_snippets/category_info.h" | 29 #include "components/ntp_snippets/category_info.h" |
| 30 #include "components/ntp_snippets/ntp_snippets_constants.h" | 30 #include "components/ntp_snippets/ntp_snippets_constants.h" |
| 31 #include "components/ntp_snippets/pref_names.h" |
| 31 #include "components/ntp_snippets/remote/ntp_snippet.h" | 32 #include "components/ntp_snippets/remote/ntp_snippet.h" |
| 32 #include "components/ntp_snippets/remote/ntp_snippets_database.h" | 33 #include "components/ntp_snippets/remote/ntp_snippets_database.h" |
| 33 #include "components/ntp_snippets/remote/ntp_snippets_fetcher.h" | 34 #include "components/ntp_snippets/remote/ntp_snippets_fetcher.h" |
| 34 #include "components/ntp_snippets/remote/ntp_snippets_scheduler.h" | 35 #include "components/ntp_snippets/remote/ntp_snippets_scheduler.h" |
| 35 #include "components/ntp_snippets/remote/ntp_snippets_test_utils.h" | 36 #include "components/ntp_snippets/remote/ntp_snippets_test_utils.h" |
| 36 #include "components/ntp_snippets/user_classifier.h" | 37 #include "components/ntp_snippets/user_classifier.h" |
| 37 #include "components/prefs/testing_pref_service.h" | 38 #include "components/prefs/testing_pref_service.h" |
| 38 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h" | 39 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h" |
| 39 #include "components/signin/core/browser/fake_signin_manager.h" | 40 #include "components/signin/core/browser/fake_signin_manager.h" |
| 40 #include "components/variations/variations_associated_data.h" | 41 #include "components/variations/variations_associated_data.h" |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 320 MOCK_METHOD3( | 321 MOCK_METHOD3( |
| 321 StartOrQueueNetworkRequest, | 322 StartOrQueueNetworkRequest, |
| 322 void(const std::string&, | 323 void(const std::string&, |
| 323 const GURL&, | 324 const GURL&, |
| 324 base::Callback<void(const std::string&, const gfx::Image&)>)); | 325 base::Callback<void(const std::string&, const gfx::Image&)>)); |
| 325 }; | 326 }; |
| 326 | 327 |
| 327 class FakeContentSuggestionsProviderObserver | 328 class FakeContentSuggestionsProviderObserver |
| 328 : public ContentSuggestionsProvider::Observer { | 329 : public ContentSuggestionsProvider::Observer { |
| 329 public: | 330 public: |
| 330 FakeContentSuggestionsProviderObserver() | 331 FakeContentSuggestionsProviderObserver() = default; |
| 331 : loaded_(base::WaitableEvent::ResetPolicy::MANUAL, | |
| 332 base::WaitableEvent::InitialState::NOT_SIGNALED) {} | |
| 333 | 332 |
| 334 void OnNewSuggestions(ContentSuggestionsProvider* provider, | 333 void OnNewSuggestions(ContentSuggestionsProvider* provider, |
| 335 Category category, | 334 Category category, |
| 336 std::vector<ContentSuggestion> suggestions) override { | 335 std::vector<ContentSuggestion> suggestions) override { |
| 337 suggestions_[category] = std::move(suggestions); | 336 suggestions_[category] = std::move(suggestions); |
| 338 } | 337 } |
| 339 | 338 |
| 340 void OnCategoryStatusChanged(ContentSuggestionsProvider* provider, | 339 void OnCategoryStatusChanged(ContentSuggestionsProvider* provider, |
| 341 Category category, | 340 Category category, |
| 342 CategoryStatus new_status) override { | 341 CategoryStatus new_status) override { |
| 343 if (category.IsKnownCategory(KnownCategories::ARTICLES) && | |
| 344 IsCategoryStatusAvailable(new_status)) { | |
| 345 loaded_.Signal(); | |
| 346 } | |
| 347 statuses_[category] = new_status; | 342 statuses_[category] = new_status; |
| 348 } | 343 } |
| 349 | 344 |
| 350 void OnSuggestionInvalidated( | 345 void OnSuggestionInvalidated( |
| 351 ContentSuggestionsProvider* provider, | 346 ContentSuggestionsProvider* provider, |
| 352 const ContentSuggestion::ID& suggestion_id) override {} | 347 const ContentSuggestion::ID& suggestion_id) override {} |
| 353 | 348 |
| 354 const std::map<Category, CategoryStatus, Category::CompareByID>& statuses() | 349 const std::map<Category, CategoryStatus, Category::CompareByID>& statuses() |
| 355 const { | 350 const { |
| 356 return statuses_; | 351 return statuses_; |
| 357 } | 352 } |
| 358 | 353 |
| 359 CategoryStatus StatusForCategory(Category category) const { | 354 CategoryStatus StatusForCategory(Category category) const { |
| 360 auto it = statuses_.find(category); | 355 auto it = statuses_.find(category); |
| 361 if (it == statuses_.end()) { | 356 if (it == statuses_.end()) { |
| 362 return CategoryStatus::NOT_PROVIDED; | 357 return CategoryStatus::NOT_PROVIDED; |
| 363 } | 358 } |
| 364 return it->second; | 359 return it->second; |
| 365 } | 360 } |
| 366 | 361 |
| 367 const std::vector<ContentSuggestion>& SuggestionsForCategory( | 362 const std::vector<ContentSuggestion>& SuggestionsForCategory( |
| 368 Category category) { | 363 Category category) { |
| 369 return suggestions_[category]; | 364 return suggestions_[category]; |
| 370 } | 365 } |
| 371 | 366 |
| 372 void WaitForLoad() { loaded_.Wait(); } | |
| 373 bool Loaded() { return loaded_.IsSignaled(); } | |
| 374 | |
| 375 void Reset() { | |
| 376 loaded_.Reset(); | |
| 377 statuses_.clear(); | |
| 378 } | |
| 379 | |
| 380 private: | 367 private: |
| 381 base::WaitableEvent loaded_; | |
| 382 std::map<Category, CategoryStatus, Category::CompareByID> statuses_; | 368 std::map<Category, CategoryStatus, Category::CompareByID> statuses_; |
| 383 std::map<Category, std::vector<ContentSuggestion>, Category::CompareByID> | 369 std::map<Category, std::vector<ContentSuggestion>, Category::CompareByID> |
| 384 suggestions_; | 370 suggestions_; |
| 385 | 371 |
| 386 DISALLOW_COPY_AND_ASSIGN(FakeContentSuggestionsProviderObserver); | 372 DISALLOW_COPY_AND_ASSIGN(FakeContentSuggestionsProviderObserver); |
| 387 }; | 373 }; |
| 388 | 374 |
| 389 class FakeImageDecoder : public image_fetcher::ImageDecoder { | 375 class FakeImageDecoder : public image_fetcher::ImageDecoder { |
| 390 public: | 376 public: |
| 391 FakeImageDecoder() {} | 377 FakeImageDecoder() {} |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 426 ~RemoteSuggestionsProviderTest() override { | 412 ~RemoteSuggestionsProviderTest() override { |
| 427 // We need to run the message loop after deleting the database, because | 413 // We need to run the message loop after deleting the database, because |
| 428 // ProtoDatabaseImpl deletes the actual LevelDB asynchronously on the task | 414 // ProtoDatabaseImpl deletes the actual LevelDB asynchronously on the task |
| 429 // runner. Without this, we'd get reports of memory leaks. | 415 // runner. Without this, we'd get reports of memory leaks. |
| 430 base::RunLoop().RunUntilIdle(); | 416 base::RunLoop().RunUntilIdle(); |
| 431 } | 417 } |
| 432 | 418 |
| 433 std::unique_ptr<RemoteSuggestionsProvider> MakeSnippetsService( | 419 std::unique_ptr<RemoteSuggestionsProvider> MakeSnippetsService( |
| 434 bool set_empty_response = true) { | 420 bool set_empty_response = true) { |
| 435 auto service = MakeSnippetsServiceWithoutInitialization(); | 421 auto service = MakeSnippetsServiceWithoutInitialization(); |
| 436 WaitForSnippetsServiceInitialization(set_empty_response); | 422 WaitForSnippetsServiceInitialization(service.get(), set_empty_response); |
| 437 return service; | 423 return service; |
| 438 } | 424 } |
| 439 | 425 |
| 440 std::unique_ptr<RemoteSuggestionsProvider> | 426 std::unique_ptr<RemoteSuggestionsProvider> |
| 441 MakeSnippetsServiceWithoutInitialization() { | 427 MakeSnippetsServiceWithoutInitialization() { |
| 442 scoped_refptr<base::SingleThreadTaskRunner> task_runner( | 428 scoped_refptr<base::SingleThreadTaskRunner> task_runner( |
| 443 base::ThreadTaskRunnerHandle::Get()); | 429 base::ThreadTaskRunnerHandle::Get()); |
| 444 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter = | 430 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter = |
| 445 new net::TestURLRequestContextGetter(task_runner.get()); | 431 new net::TestURLRequestContextGetter(task_runner.get()); |
| 446 | 432 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 467 return base::MakeUnique<RemoteSuggestionsProvider>( | 453 return base::MakeUnique<RemoteSuggestionsProvider>( |
| 468 observer_.get(), &category_factory_, utils_.pref_service(), "fr", | 454 observer_.get(), &category_factory_, utils_.pref_service(), "fr", |
| 469 &user_classifier_, &scheduler_, std::move(snippets_fetcher), | 455 &user_classifier_, &scheduler_, std::move(snippets_fetcher), |
| 470 std::move(image_fetcher), std::move(image_decoder), | 456 std::move(image_fetcher), std::move(image_decoder), |
| 471 base::MakeUnique<NTPSnippetsDatabase>(database_dir_.GetPath(), | 457 base::MakeUnique<NTPSnippetsDatabase>(database_dir_.GetPath(), |
| 472 task_runner), | 458 task_runner), |
| 473 base::MakeUnique<NTPSnippetsStatusService>(utils_.fake_signin_manager(), | 459 base::MakeUnique<NTPSnippetsStatusService>(utils_.fake_signin_manager(), |
| 474 utils_.pref_service())); | 460 utils_.pref_service())); |
| 475 } | 461 } |
| 476 | 462 |
| 477 void WaitForSnippetsServiceInitialization(bool set_empty_response) { | 463 void WaitForSnippetsServiceInitialization(RemoteSuggestionsProvider* service, |
| 478 EXPECT_TRUE(observer_); | 464 bool set_empty_response) { |
| 479 EXPECT_FALSE(observer_->Loaded()); | 465 EXPECT_EQ(RemoteSuggestionsProvider::State::NOT_INITED, service->state_); |
| 480 | 466 |
| 481 // Add an initial fetch response, as the service tries to fetch when there | 467 // Add an initial fetch response, as the service tries to fetch when there |
| 482 // is nothing in the DB. | 468 // is nothing in the DB. |
| 483 if (set_empty_response) | 469 if (set_empty_response) |
| 484 SetUpFetchResponse(GetTestJson(std::vector<std::string>())); | 470 SetUpFetchResponse(GetTestJson(std::vector<std::string>())); |
| 485 | 471 |
| 472 // TODO(treib): Find a better way to wait for initialization to finish. |
| 486 base::RunLoop().RunUntilIdle(); | 473 base::RunLoop().RunUntilIdle(); |
| 487 observer_->WaitForLoad(); | 474 EXPECT_NE(RemoteSuggestionsProvider::State::NOT_INITED, service->state_); |
| 488 } | 475 } |
| 489 | 476 |
| 490 void ResetSnippetsService( | 477 void ResetSnippetsService( |
| 491 std::unique_ptr<RemoteSuggestionsProvider>* service) { | 478 std::unique_ptr<RemoteSuggestionsProvider>* service) { |
| 492 service->reset(); | 479 service->reset(); |
| 493 observer_.reset(); | 480 observer_.reset(); |
| 494 *service = MakeSnippetsService(); | 481 *service = MakeSnippetsService(); |
| 495 } | 482 } |
| 496 | 483 |
| 497 ContentSuggestion::ID MakeArticleID(const std::string& id_within_category) { | 484 ContentSuggestion::ID MakeArticleID(const std::string& id_within_category) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 511 Category unknown_category() { | 498 Category unknown_category() { |
| 512 return category_factory_.FromRemoteCategory(kUnknownRemoteCategoryId); | 499 return category_factory_.FromRemoteCategory(kUnknownRemoteCategoryId); |
| 513 } | 500 } |
| 514 | 501 |
| 515 protected: | 502 protected: |
| 516 const GURL& test_url() { return test_url_; } | 503 const GURL& test_url() { return test_url_; } |
| 517 FakeContentSuggestionsProviderObserver& observer() { return *observer_; } | 504 FakeContentSuggestionsProviderObserver& observer() { return *observer_; } |
| 518 MockScheduler& mock_scheduler() { return scheduler_; } | 505 MockScheduler& mock_scheduler() { return scheduler_; } |
| 519 NiceMock<MockImageFetcher>* image_fetcher() { return image_fetcher_; } | 506 NiceMock<MockImageFetcher>* image_fetcher() { return image_fetcher_; } |
| 520 FakeImageDecoder* image_decoder() { return image_decoder_; } | 507 FakeImageDecoder* image_decoder() { return image_decoder_; } |
| 508 PrefService* pref_service() { return utils_.pref_service(); } |
| 521 | 509 |
| 522 // Provide the json to be returned by the fake fetcher. | 510 // Provide the json to be returned by the fake fetcher. |
| 523 void SetUpFetchResponse(const std::string& json) { | 511 void SetUpFetchResponse(const std::string& json) { |
| 524 fake_url_fetcher_factory_.SetFakeResponse(test_url_, json, net::HTTP_OK, | 512 fake_url_fetcher_factory_.SetFakeResponse(test_url_, json, net::HTTP_OK, |
| 525 net::URLRequestStatus::SUCCESS); | 513 net::URLRequestStatus::SUCCESS); |
| 526 } | 514 } |
| 527 | 515 |
| 528 void LoadFromJSONString(RemoteSuggestionsProvider* service, | 516 void LoadFromJSONString(RemoteSuggestionsProvider* service, |
| 529 const std::string& json) { | 517 const std::string& json) { |
| 530 SetUpFetchResponse(json); | 518 SetUpFetchResponse(json); |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 618 TEST_F(RemoteSuggestionsProviderTest, IgnoreRescheduleBeforeInit) { | 606 TEST_F(RemoteSuggestionsProviderTest, IgnoreRescheduleBeforeInit) { |
| 619 // We should get two |Schedule| calls: The first when initialization | 607 // We should get two |Schedule| calls: The first when initialization |
| 620 // completes, the second one after the automatic (since the service doesn't | 608 // completes, the second one after the automatic (since the service doesn't |
| 621 // have any data yet) fetch finishes. | 609 // have any data yet) fetch finishes. |
| 622 EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(2); | 610 EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(2); |
| 623 // The |RescheduleFetching| call shouldn't do anything (in particular not | 611 // The |RescheduleFetching| call shouldn't do anything (in particular not |
| 624 // result in an |Unschedule|), since the service isn't initialized yet. | 612 // result in an |Unschedule|), since the service isn't initialized yet. |
| 625 EXPECT_CALL(mock_scheduler(), Unschedule()).Times(0); | 613 EXPECT_CALL(mock_scheduler(), Unschedule()).Times(0); |
| 626 auto service = MakeSnippetsServiceWithoutInitialization(); | 614 auto service = MakeSnippetsServiceWithoutInitialization(); |
| 627 service->RescheduleFetching(false); | 615 service->RescheduleFetching(false); |
| 628 WaitForSnippetsServiceInitialization(/*set_empty_response=*/true); | 616 WaitForSnippetsServiceInitialization(service.get(), |
| 617 /*set_empty_response=*/true); |
| 629 } | 618 } |
| 630 | 619 |
| 631 TEST_F(RemoteSuggestionsProviderTest, HandleForcedRescheduleBeforeInit) { | 620 TEST_F(RemoteSuggestionsProviderTest, HandleForcedRescheduleBeforeInit) { |
| 632 { | 621 { |
| 633 InSequence s; | 622 InSequence s; |
| 634 // The |RescheduleFetching| call with force=true should result in an | 623 // The |RescheduleFetching| call with force=true should result in an |
| 635 // |Unschedule|, since the service isn't initialized yet. | 624 // |Unschedule|, since the service isn't initialized yet. |
| 636 EXPECT_CALL(mock_scheduler(), Unschedule()).Times(1); | 625 EXPECT_CALL(mock_scheduler(), Unschedule()).Times(1); |
| 637 // We should get two |Schedule| calls: The first when initialization | 626 // We should get two |Schedule| calls: The first when initialization |
| 638 // completes, the second one after the automatic (since the service doesn't | 627 // completes, the second one after the automatic (since the service doesn't |
| 639 // have any data yet) fetch finishes. | 628 // have any data yet) fetch finishes. |
| 640 EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(2); | 629 EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(2); |
| 641 } | 630 } |
| 642 auto service = MakeSnippetsServiceWithoutInitialization(); | 631 auto service = MakeSnippetsServiceWithoutInitialization(); |
| 643 service->RescheduleFetching(true); | 632 service->RescheduleFetching(true); |
| 644 WaitForSnippetsServiceInitialization(/*set_empty_response=*/true); | 633 WaitForSnippetsServiceInitialization(service.get(), |
| 634 /*set_empty_response=*/true); |
| 645 } | 635 } |
| 646 | 636 |
| 647 TEST_F(RemoteSuggestionsProviderTest, RescheduleOnStateChange) { | 637 TEST_F(RemoteSuggestionsProviderTest, RescheduleOnStateChange) { |
| 648 { | 638 { |
| 649 InSequence s; | 639 InSequence s; |
| 650 // Initial startup. | 640 // Initial startup. |
| 651 EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(2); | 641 EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(2); |
| 652 // Service gets disabled. | 642 // Service gets disabled. |
| 653 EXPECT_CALL(mock_scheduler(), Unschedule()); | 643 EXPECT_CALL(mock_scheduler(), Unschedule()); |
| 654 // Service gets enabled again. | 644 // Service gets enabled again. |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 859 | 849 |
| 860 // Recreate the service to simulate a Chrome restart. | 850 // Recreate the service to simulate a Chrome restart. |
| 861 ResetSnippetsService(&service); | 851 ResetSnippetsService(&service); |
| 862 | 852 |
| 863 // The suggestions in both categories should have been restored. | 853 // The suggestions in both categories should have been restored. |
| 864 EXPECT_THAT(observer().SuggestionsForCategory(articles_category()), | 854 EXPECT_THAT(observer().SuggestionsForCategory(articles_category()), |
| 865 SizeIs(1)); | 855 SizeIs(1)); |
| 866 EXPECT_THAT(observer().SuggestionsForCategory(other_category()), SizeIs(1)); | 856 EXPECT_THAT(observer().SuggestionsForCategory(other_category()), SizeIs(1)); |
| 867 } | 857 } |
| 868 | 858 |
| 859 TEST_F(RemoteSuggestionsProviderTest, DontNotifyIfNotAvailable) { |
| 860 // Get some suggestions into the database. |
| 861 auto service = MakeSnippetsService(); |
| 862 LoadFromJSONString(service.get(), |
| 863 GetMultiCategoryJson({GetSnippetN(0)}, {GetSnippetN(1)})); |
| 864 ASSERT_THAT(observer().SuggestionsForCategory(articles_category()), |
| 865 SizeIs(1)); |
| 866 ASSERT_THAT(observer().SuggestionsForCategory(other_category()), SizeIs(1)); |
| 867 |
| 868 service.reset(); |
| 869 |
| 870 // Set the pref that disables remote suggestions. |
| 871 pref_service()->SetBoolean(prefs::kEnableSnippets, false); |
| 872 |
| 873 // Recreate the service to simulate a Chrome start. |
| 874 ResetSnippetsService(&service); |
| 875 |
| 876 ASSERT_THAT(RemoteSuggestionsProvider::State::DISABLED, Eq(service->state_)); |
| 877 |
| 878 // Now the observer should not have received any suggestions. |
| 879 EXPECT_THAT(observer().SuggestionsForCategory(articles_category()), |
| 880 IsEmpty()); |
| 881 EXPECT_THAT(observer().SuggestionsForCategory(other_category()), IsEmpty()); |
| 882 } |
| 883 |
| 869 TEST_F(RemoteSuggestionsProviderTest, Clear) { | 884 TEST_F(RemoteSuggestionsProviderTest, Clear) { |
| 870 auto service = MakeSnippetsService(); | 885 auto service = MakeSnippetsService(); |
| 871 | 886 |
| 872 std::string json_str(GetTestJson({GetSnippet()})); | 887 std::string json_str(GetTestJson({GetSnippet()})); |
| 873 | 888 |
| 874 LoadFromJSONString(service.get(), json_str); | 889 LoadFromJSONString(service.get(), json_str); |
| 875 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1)); | 890 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1)); |
| 876 | 891 |
| 877 service->ClearCachedSuggestions(articles_category()); | 892 service->ClearCachedSuggestions(articles_category()); |
| 878 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty()); | 893 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty()); |
| (...skipping 661 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1540 base::StringPrintf("http://localhost/snippet-id-%d", i))); | 1555 base::StringPrintf("http://localhost/snippet-id-%d", i))); |
| 1541 } | 1556 } |
| 1542 LoadFromJSONString(service.get(), GetTestJson(suggestions)); | 1557 LoadFromJSONString(service.get(), GetTestJson(suggestions)); |
| 1543 // TODO(tschumann): We should probably trim out any additional results and | 1558 // TODO(tschumann): We should probably trim out any additional results and |
| 1544 // only serve the MaxSnippetCount items. | 1559 // only serve the MaxSnippetCount items. |
| 1545 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), | 1560 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), |
| 1546 SizeIs(service->GetMaxSnippetCountForTesting() + 1)); | 1561 SizeIs(service->GetMaxSnippetCountForTesting() + 1)); |
| 1547 } | 1562 } |
| 1548 | 1563 |
| 1549 } // namespace ntp_snippets | 1564 } // namespace ntp_snippets |
| OLD | NEW |