Chromium Code Reviews| Index: components/ntp_snippets/offline_pages/recent_tab_suggestions_provider_unittest.cc |
| diff --git a/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider_unittest.cc b/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider_unittest.cc |
| index bc3d6d2f7f00a875bb94981200df1a53a62c2228..fc12a383adad5fcdcae6a2169307e9076248a730 100644 |
| --- a/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider_unittest.cc |
| +++ b/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider_unittest.cc |
| @@ -10,14 +10,18 @@ |
| #include "base/bind.h" |
| #include "base/files/file_path.h" |
| #include "base/strings/string_number_conversions.h" |
| +#include "base/test/test_simple_task_runner.h" |
| +#include "base/threading/thread_task_runner_handle.h" |
| #include "base/time/time.h" |
| #include "components/ntp_snippets/category.h" |
| #include "components/ntp_snippets/content_suggestions_provider.h" |
| #include "components/ntp_snippets/mock_content_suggestions_provider_observer.h" |
| #include "components/ntp_snippets/offline_pages/offline_pages_test_utils.h" |
| +#include "components/offline_pages/core/background/request_coordinator_stub_taco.h" |
| #include "components/offline_pages/core/client_namespace_constants.h" |
| +#include "components/offline_pages/core/downloads/download_ui_adapter.h" |
| #include "components/offline_pages/core/offline_page_item.h" |
| -#include "components/offline_pages/core/stub_offline_page_model.h" |
| +#include "components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.h" |
| #include "components/prefs/testing_pref_service.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| @@ -27,7 +31,6 @@ using ntp_snippets::test::FakeOfflinePageModel; |
| using offline_pages::ClientId; |
| using offline_pages::MultipleOfflinePageItemCallback; |
| using offline_pages::OfflinePageItem; |
| -using offline_pages::StubOfflinePageModel; |
| using testing::_; |
| using testing::IsEmpty; |
| using testing::Mock; |
| @@ -38,11 +41,16 @@ namespace ntp_snippets { |
| namespace { |
| -OfflinePageItem CreateDummyRecentTab(int id) { |
| - OfflinePageItem item = |
| - test::CreateDummyOfflinePageItem(id, offline_pages::kLastNNamespace); |
| - item.client_id.id = base::IntToString(id); |
| - return item; |
| +// This global is used to assign unique tab IDs to pages. Since offline IDs are |
| +// typically small integers like 1, 2, 3 etc, we start at 100 to ensure that |
| +// they are different, and can catch bugs where offline page ID is used in place |
| +// of tab ID and vice versa. |
| +int current_tab_id = 100; |
|
vitaliii
2017/02/15 10:12:16
Since tab_id is never checked in the tests explici
dewittj
2017/02/15 19:49:45
Good idea, done.
|
| + |
| +OfflinePageItem CreateDummyRecentTab(int offline_id) { |
| + std::string tab_id = base::IntToString(++current_tab_id); |
| + ClientId client_id(offline_pages::kLastNNamespace, tab_id); |
| + return test::CreateDummyOfflinePageItem(offline_id, client_id); |
| } |
| std::vector<OfflinePageItem> CreateDummyRecentTabs( |
| @@ -66,12 +74,24 @@ OfflinePageItem CreateDummyRecentTab(int id, base::Time time) { |
| class RecentTabSuggestionsProviderTest : public testing::Test { |
| public: |
| RecentTabSuggestionsProviderTest() |
| - : pref_service_(new TestingPrefServiceSimple()) { |
| + : task_runner_(new base::TestSimpleTaskRunner()), |
| + task_runner_handle_(task_runner_), |
| + pref_service_(new TestingPrefServiceSimple()) { |
| RecentTabSuggestionsProvider::RegisterProfilePrefs( |
| pref_service()->registry()); |
| - provider_.reset( |
| - new RecentTabSuggestionsProvider(&observer_, &model_, pref_service())); |
| + taco_ = base::MakeUnique<offline_pages::RequestCoordinatorStubTaco>(); |
| + taco_->CreateRequestCoordinator(); |
| + |
| + provider_.reset(new RecentTabSuggestionsProvider( |
| + &observer_, &model_, taco_->request_coordinator(), pref_service())); |
| + |
| + ui_adapter_ = offline_pages::RecentTabsUIAdapterDelegate:: |
| + GetOrCreateRecentTabsUIAdapter(&model_, taco_->request_coordinator()); |
| + // The UI adapter always fires asynchronously upon loading, so we want to |
| + // run past that moment before each test. |
| + task_runner_->RunUntilIdle(); |
| + Mock::VerifyAndClearExpectations(observer()); |
| } |
| Category recent_tabs_category() { |
| @@ -82,18 +102,36 @@ class RecentTabSuggestionsProviderTest : public testing::Test { |
| return ContentSuggestion::ID(recent_tabs_category(), base::IntToString(id)); |
| } |
| + void AddTabAndOfflinePageToModel(const OfflinePageItem& item) { |
| + AddTab(offline_pages::RecentTabsUIAdapterDelegate::TabIdFromClientId( |
| + item.client_id)); |
| + AddOfflinePageToModel(item); |
| + } |
| + |
| + void AddTab(int tab_id) { |
| + offline_pages::RecentTabsUIAdapterDelegate* delegate_ = |
|
vitaliii
2017/02/15 10:12:15
Why does this have trailing underscore?
Should we
dewittj
2017/02/15 19:49:45
Done.
|
| + offline_pages::RecentTabsUIAdapterDelegate::FromDownloadUIAdapter( |
| + ui_adapter_); |
| + delegate_->RegisterTab(tab_id); |
| + } |
| + |
| + void RemoveTab(int tab_id) { |
| + offline_pages::RecentTabsUIAdapterDelegate* delegate_ = |
| + offline_pages::RecentTabsUIAdapterDelegate::FromDownloadUIAdapter( |
| + ui_adapter_); |
| + delegate_->UnregisterTab(tab_id); |
| + } |
| + |
| void AddOfflinePageToModel(const OfflinePageItem& item) { |
| - model_.mutable_items()->push_back(item); |
| - provider_->OfflinePageAdded(&model_, item); |
| + ui_adapter_->OfflinePageAdded(&model_, item); |
| } |
| void FireOfflinePageDeleted(const OfflinePageItem& item) { |
| - auto iter = std::remove(model_.mutable_items()->begin(), |
| - model_.mutable_items()->end(), item); |
| - auto end = model_.mutable_items()->end(); |
| - model_.mutable_items()->erase(iter, end); |
| + ui_adapter_->OfflinePageDeleted(item.offline_id, item.client_id); |
| - provider_->OfflinePageDeleted(item.offline_id, item.client_id); |
| + int tab_id = offline_pages::RecentTabsUIAdapterDelegate::TabIdFromClientId( |
| + item.client_id); |
| + RemoveTab(tab_id); |
|
vitaliii
2017/02/15 10:12:15
Wouldn't removing tab before |OfflinePageDeleted|
dewittj
2017/02/15 19:49:45
Done.
|
| } |
| std::set<std::string> ReadDismissedIDsFromPrefs() { |
| @@ -101,12 +139,15 @@ class RecentTabSuggestionsProviderTest : public testing::Test { |
| } |
| RecentTabSuggestionsProvider* provider() { return provider_.get(); } |
| - FakeOfflinePageModel* model() { return &model_; } |
| MockContentSuggestionsProviderObserver* observer() { return &observer_; } |
| TestingPrefServiceSimple* pref_service() { return pref_service_.get(); } |
| private: |
| FakeOfflinePageModel model_; |
| + offline_pages::DownloadUIAdapter* ui_adapter_; |
| + scoped_refptr<base::TestSimpleTaskRunner> task_runner_; |
| + base::ThreadTaskRunnerHandle task_runner_handle_; |
| + std::unique_ptr<offline_pages::RequestCoordinatorStubTaco> taco_; |
| MockContentSuggestionsProviderObserver observer_; |
| std::unique_ptr<TestingPrefServiceSimple> pref_service_; |
| // Last so that the dependencies are deleted after the provider. |
| @@ -116,11 +157,7 @@ class RecentTabSuggestionsProviderTest : public testing::Test { |
| }; |
| TEST_F(RecentTabSuggestionsProviderTest, ShouldConvertToSuggestions) { |
| - auto recent_tabs_list = CreateDummyRecentTabs({1, 2}); |
| EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(2); |
| - for (OfflinePageItem& recent_tab : recent_tabs_list) |
| - AddOfflinePageToModel(recent_tab); |
| - |
| EXPECT_CALL( |
| *observer(), |
| OnNewSuggestions(_, recent_tabs_category(), |
| @@ -131,7 +168,10 @@ TEST_F(RecentTabSuggestionsProviderTest, ShouldConvertToSuggestions) { |
| GURL("http://dummy.com/2")), |
| Property(&ContentSuggestion::url, |
| GURL("http://dummy.com/3"))))); |
| - AddOfflinePageToModel(CreateDummyRecentTab(3)); |
| + |
| + auto recent_tabs_list = CreateDummyRecentTabs({1, 2, 3}); |
| + for (OfflinePageItem& recent_tab : recent_tabs_list) |
|
vitaliii
2017/02/15 10:12:15
Please add curly brackets { }. In NTP we use curly
dewittj
2017/02/15 19:49:45
Done.
|
| + AddTabAndOfflinePageToModel(recent_tab); |
| } |
| TEST_F(RecentTabSuggestionsProviderTest, ShouldSortByCreationTime) { |
| @@ -148,7 +188,7 @@ TEST_F(RecentTabSuggestionsProviderTest, ShouldSortByCreationTime) { |
| OnNewSuggestions(_, recent_tabs_category(), |
| ElementsAre(Property(&ContentSuggestion::url, |
| GURL("http://dummy.com/1"))))); |
| - AddOfflinePageToModel(CreateDummyRecentTab(1, now)); |
| + AddTabAndOfflinePageToModel(CreateDummyRecentTab(1, now)); |
| EXPECT_CALL( |
| *observer(), |
| @@ -157,7 +197,7 @@ TEST_F(RecentTabSuggestionsProviderTest, ShouldSortByCreationTime) { |
| ElementsAre( |
| Property(&ContentSuggestion::url, GURL("http://dummy.com/1")), |
| Property(&ContentSuggestion::url, GURL("http://dummy.com/2"))))); |
| - AddOfflinePageToModel(CreateDummyRecentTab(2, yesterday)); |
| + AddTabAndOfflinePageToModel(CreateDummyRecentTab(2, yesterday)); |
| offline_pages[1].last_access_time = |
| offline_pages[0].last_access_time + base::TimeDelta::FromHours(1); |
| @@ -172,7 +212,7 @@ TEST_F(RecentTabSuggestionsProviderTest, ShouldSortByCreationTime) { |
| GURL("http://dummy.com/1")), |
| Property(&ContentSuggestion::url, |
| GURL("http://dummy.com/2"))))); |
| - AddOfflinePageToModel(CreateDummyRecentTab(3, tomorrow)); |
| + AddTabAndOfflinePageToModel(CreateDummyRecentTab(3, tomorrow)); |
| } |
| TEST_F(RecentTabSuggestionsProviderTest, ShouldDeliverCorrectCategoryInfo) { |
| @@ -189,9 +229,11 @@ TEST_F(RecentTabSuggestionsProviderTest, ShouldDismiss) { |
| EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(3); |
| auto recent_tabs_list = CreateDummyRecentTabs({1, 2, 3}); |
| for (OfflinePageItem& recent_tab : recent_tabs_list) { |
| - AddOfflinePageToModel(recent_tab); |
| + AddTabAndOfflinePageToModel(recent_tab); |
| } |
| + Mock::VerifyAndClearExpectations(observer()); |
|
vitaliii
2017/02/15 10:12:15
Why is this needed here?
dewittj
2017/02/15 19:49:45
I think I added it during testing. It separates th
vitaliii
2017/02/16 08:11:04
I guess it implicitly resets the expected number o
tschumann
2017/02/16 09:22:11
drive-by:
gmock builds up a stack of expectations.
|
| + |
| // Dismiss 2 and 3. |
| EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(0); |
| provider()->DismissSuggestion(GetDummySuggestionId(2)); |
| @@ -207,7 +249,7 @@ TEST_F(RecentTabSuggestionsProviderTest, ShouldDismiss) { |
| Property(&ContentSuggestion::url, GURL("http://dummy.com/1")), |
| Property(&ContentSuggestion::url, GURL("http://dummy.com/4"))))); |
| - AddOfflinePageToModel(CreateDummyRecentTab(4)); |
| + AddTabAndOfflinePageToModel(CreateDummyRecentTab(4)); |
| Mock::VerifyAndClearExpectations(observer()); |
| // And appear in the dismissed suggestions. |
| @@ -235,7 +277,7 @@ TEST_F(RecentTabSuggestionsProviderTest, ShouldDismiss) { |
| // And appear in the reported suggestions for the category again. |
| EXPECT_CALL(*observer(), |
| OnNewSuggestions(_, recent_tabs_category(), SizeIs(5))); |
| - AddOfflinePageToModel(CreateDummyRecentTab(5)); |
| + AddTabAndOfflinePageToModel(CreateDummyRecentTab(5)); |
| Mock::VerifyAndClearExpectations(observer()); |
| } |
| @@ -244,7 +286,7 @@ TEST_F(RecentTabSuggestionsProviderTest, |
| EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(3); |
| std::vector<OfflinePageItem> offline_pages = CreateDummyRecentTabs({1, 2, 3}); |
| for (OfflinePageItem& recent_tab : offline_pages) |
| - AddOfflinePageToModel(recent_tab); |
| + AddTabAndOfflinePageToModel(recent_tab); |
| // Invalidation of suggestion 2 should be forwarded. |
| EXPECT_CALL(*observer(), OnSuggestionInvalidated(_, GetDummySuggestionId(2))); |
| @@ -255,7 +297,7 @@ TEST_F(RecentTabSuggestionsProviderTest, ShouldClearDismissedOnInvalidate) { |
| EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(3); |
| std::vector<OfflinePageItem> offline_pages = CreateDummyRecentTabs({1, 2, 3}); |
| for (OfflinePageItem& recent_tab : offline_pages) |
| - AddOfflinePageToModel(recent_tab); |
| + AddTabAndOfflinePageToModel(recent_tab); |
| EXPECT_THAT(ReadDismissedIDsFromPrefs(), IsEmpty()); |
| provider()->DismissSuggestion(GetDummySuggestionId(2)); |
| @@ -269,7 +311,7 @@ TEST_F(RecentTabSuggestionsProviderTest, ShouldClearDismissedOnFetch) { |
| EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(3); |
| std::vector<OfflinePageItem> offline_pages = CreateDummyRecentTabs({1, 2, 3}); |
| for (OfflinePageItem& recent_tab : offline_pages) |
| - AddOfflinePageToModel(recent_tab); |
| + AddTabAndOfflinePageToModel(recent_tab); |
| provider()->DismissSuggestion(GetDummySuggestionId(2)); |
| provider()->DismissSuggestion(GetDummySuggestionId(3)); |
| @@ -294,8 +336,8 @@ TEST_F(RecentTabSuggestionsProviderTest, ShouldNotShowSameUrlMutlipleTimes) { |
| // We leave IDs different, but make the URLs the same. |
| offline_pages[2].url = offline_pages[0].url; |
| - AddOfflinePageToModel(offline_pages[0]); |
| - AddOfflinePageToModel(offline_pages[1]); |
| + AddTabAndOfflinePageToModel(offline_pages[0]); |
| + AddTabAndOfflinePageToModel(offline_pages[1]); |
| Mock::VerifyAndClearExpectations(observer()); |
| EXPECT_CALL(*observer(), |
| OnNewSuggestions( |
| @@ -304,13 +346,11 @@ TEST_F(RecentTabSuggestionsProviderTest, ShouldNotShowSameUrlMutlipleTimes) { |
| Property(&ContentSuggestion::publish_date, now), |
| Property(&ContentSuggestion::publish_date, tomorrow)))); |
| - AddOfflinePageToModel(offline_pages[2]); |
| + AddTabAndOfflinePageToModel(offline_pages[2]); |
| } |
| TEST_F(RecentTabSuggestionsProviderTest, |
| ShouldNotFetchIfAddedOfflinePageIsNotRecentTab) { |
| - // The provider is not notified about the first recent tab yet. |
| - model()->mutable_items()->push_back(CreateDummyRecentTab(1)); |
| // It should not fetch when not a recent tab is added, thus, it should not |
| // report the first recent tab (which it is not aware about). |
| EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(0); |
|
vitaliii
2017/02/15 10:12:16
Removal of the recent tab changes meaning a bit. C
dewittj
2017/02/15 19:49:45
It's not clear what exactly you are trying to test
vitaliii
2017/02/16 08:11:04
Previously, if an offline page is added, the provi
|
| @@ -321,7 +361,7 @@ TEST_F(RecentTabSuggestionsProviderTest, |
| TEST_F(RecentTabSuggestionsProviderTest, |
| ShouldFetchIfAddedOfflinePageIsRecentTab) { |
| // The provider is not notified about the first recent tab yet. |
|
vitaliii
2017/02/15 10:12:15
I am confused. In the test above you removed exact
dewittj
2017/02/15 19:49:45
I think the premise of this test doesn't exist any
vitaliii
2017/02/16 08:11:03
ACK.
Yes, fair enough!
|
| - model()->mutable_items()->push_back(CreateDummyRecentTab(1)); |
| + AddTabAndOfflinePageToModel(CreateDummyRecentTab(1)); |
| // However, it must return the first recent tab (i.e. manually fetch it) even |
| // when notified about a different recent tab. |
| EXPECT_CALL( |
| @@ -331,7 +371,44 @@ TEST_F(RecentTabSuggestionsProviderTest, |
| UnorderedElementsAre( |
| Property(&ContentSuggestion::url, GURL("http://dummy.com/1")), |
| Property(&ContentSuggestion::url, GURL("http://dummy.com/2"))))); |
| - AddOfflinePageToModel(CreateDummyRecentTab(2)); |
| + AddTabAndOfflinePageToModel(CreateDummyRecentTab(2)); |
| +} |
| + |
| +TEST_F(RecentTabSuggestionsProviderTest, ShouldNotShowPagesWithoutTab) { |
|
vitaliii
2017/02/15 10:12:15
Could you also test that InvalidateSuggestion is f
dewittj
2017/02/15 19:49:45
Done.
|
| + EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(0); |
| + // The provider is not notified about the first recent tab yet (no tab). |
| + OfflinePageItem tab = CreateDummyRecentTab(1); |
| + AddOfflinePageToModel(tab); |
|
vitaliii
2017/02/15 10:12:15
I guess this actually notifies the provider and so
dewittj
2017/02/15 19:49:45
No, this doesn't add the tab, but the name of the
|
| + |
| + Mock::VerifyAndClearExpectations(observer()); |
| + EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(1); |
| + EXPECT_CALL( |
| + *observer(), |
| + OnNewSuggestions( |
| + _, recent_tabs_category(), |
| + UnorderedElementsAre( |
| + Property(&ContentSuggestion::url, GURL("http://dummy.com/1")), |
| + Property(&ContentSuggestion::url, GURL("http://dummy.com/2"))))); |
| + |
| + AddTab(offline_pages::RecentTabsUIAdapterDelegate::TabIdFromClientId( |
| + tab.client_id)); |
| + OfflinePageItem tab2 = CreateDummyRecentTab(2); |
|
vitaliii
2017/02/15 10:12:16
Could you please use "first_tab" and "second_tab"
dewittj
2017/02/15 19:49:45
Done.
|
| + AddTabAndOfflinePageToModel(tab2); |
| + |
| + Mock::VerifyAndClearExpectations(observer()); |
| + |
| + EXPECT_CALL( |
| + *observer(), |
| + OnNewSuggestions( |
| + _, recent_tabs_category(), |
| + UnorderedElementsAre( |
| + Property(&ContentSuggestion::url, GURL("http://dummy.com/1")), |
| + Property(&ContentSuggestion::url, GURL("http://dummy.com/3"))))); |
| + |
| + // Remove Tab by itself doesn't cause OnNewSuggestions to be called. |
|
vitaliii
2017/02/15 10:12:15
|RemoveTab| or "Tab removal"
If it does not cause
dewittj
2017/02/15 19:49:45
Done.
I added another expectation in addition.
|
| + RemoveTab(offline_pages::RecentTabsUIAdapterDelegate::TabIdFromClientId( |
| + tab2.client_id)); |
| + AddTabAndOfflinePageToModel(CreateDummyRecentTab(3)); |
| } |
| } // namespace ntp_snippets |