Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(318)

Side by Side Diff: components/ntp_snippets/remote/remote_suggestions_provider_unittest.cc

Issue 2496163002: [NTP Snippets] Don't notify about new suggestion when in a not-available state (Closed)
Patch Set: add test; fix Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « components/ntp_snippets/remote/remote_suggestions_provider.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « components/ntp_snippets/remote/remote_suggestions_provider.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698