diff options
Diffstat (limited to 'chromium/components/offline_items_collection/core/offline_content_aggregator_unittest.cc')
-rw-r--r-- | chromium/components/offline_items_collection/core/offline_content_aggregator_unittest.cc | 477 |
1 files changed, 477 insertions, 0 deletions
diff --git a/chromium/components/offline_items_collection/core/offline_content_aggregator_unittest.cc b/chromium/components/offline_items_collection/core/offline_content_aggregator_unittest.cc new file mode 100644 index 00000000000..36193408445 --- /dev/null +++ b/chromium/components/offline_items_collection/core/offline_content_aggregator_unittest.cc @@ -0,0 +1,477 @@ +// Copyright (c) 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/offline_items_collection/core/offline_content_aggregator.h" + +#include <map> + +#include "base/memory/ptr_util.h" +#include "base/test/test_mock_time_task_runner.h" +#include "base/threading/thread_task_runner_handle.h" +#include "components/offline_items_collection/core/offline_item.h" +#include "components/offline_items_collection/core/test_support/mock_offline_content_provider.h" +#include "components/offline_items_collection/core/test_support/scoped_mock_offline_content_provider.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; +using testing::ContainerEq; +using testing::Return; + +namespace offline_items_collection { +namespace { + +struct CompareOfflineItemsById { + bool operator()(const OfflineItem& a, const OfflineItem& b) const { + return a.id < b.id; + } +}; + +// A custom comparator that makes sure two vectors contain the same elements. +// TODO(dtrainor): Look into building a better matcher that works with gmock. +template <typename T> +bool VectorContentsEq(const std::vector<T>& list1, + const std::vector<T>& list2) { + if (list1.size() != list2.size()) + return false; + + std::map<T, int, CompareOfflineItemsById> occurance_counts; + for (auto it = list1.begin(); it != list1.end(); it++) + occurance_counts[*it]++; + + for (auto it = list2.begin(); it != list2.end(); it++) + occurance_counts[*it]--; + + for (auto it = occurance_counts.begin(); it != occurance_counts.end(); it++) { + if (it->second != 0) + return false; + } + + return true; +} + +// Helper class that automatically unregisters itself from the aggregator in the +// case that someone calls OpenItem on it. +class OpenItemRemovalOfflineContentProvider + : public ScopedMockOfflineContentProvider { + public: + OpenItemRemovalOfflineContentProvider(const std::string& name_space, + OfflineContentAggregator* aggregator) + : ScopedMockOfflineContentProvider(name_space, aggregator) {} + ~OpenItemRemovalOfflineContentProvider() override {} + + void OpenItem(const ContentId& id) override { + ScopedMockOfflineContentProvider::OpenItem(id); + Unregister(); + } +}; + +class OfflineContentAggregatorTest : public testing::Test { + public: + OfflineContentAggregatorTest() + : task_runner_(new base::TestMockTimeTaskRunner), handle_(task_runner_) {} + ~OfflineContentAggregatorTest() override {} + + protected: + scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; + base::ThreadTaskRunnerHandle handle_; + OfflineContentAggregator aggregator_; +}; + +TEST_F(OfflineContentAggregatorTest, ObserversAddedBeforeProvidersAvailable) { + ScopedMockOfflineContentProvider provider1("1", &aggregator_); + ScopedMockOfflineContentProvider provider2("2", &aggregator_); + EXPECT_FALSE(aggregator_.AreItemsAvailable()); + EXPECT_TRUE(provider1.HasObserver(&aggregator_)); + EXPECT_TRUE(provider2.HasObserver(&aggregator_)); + + ScopedMockOfflineContentProvider::ScopedMockObserver observer1(&aggregator_); + ScopedMockOfflineContentProvider::ScopedMockObserver observer2(&aggregator_); + task_runner_->RunUntilIdle(); + + { + EXPECT_CALL(observer1, OnItemsAvailable(&aggregator_)).Times(0); + EXPECT_CALL(observer2, OnItemsAvailable(&aggregator_)).Times(0); + provider1.NotifyOnItemsAvailable(); + } + + { + EXPECT_CALL(observer1, OnItemsAvailable(&aggregator_)).Times(1); + EXPECT_CALL(observer2, OnItemsAvailable(&aggregator_)).Times(1); + provider2.NotifyOnItemsAvailable(); + } +} + +TEST_F(OfflineContentAggregatorTest, ObserversAddedAfterProvidersAvailable) { + ScopedMockOfflineContentProvider provider1("1", &aggregator_); + ScopedMockOfflineContentProvider provider2("2", &aggregator_); + EXPECT_FALSE(aggregator_.AreItemsAvailable()); + EXPECT_TRUE(provider1.HasObserver(&aggregator_)); + EXPECT_TRUE(provider2.HasObserver(&aggregator_)); + + provider1.NotifyOnItemsAvailable(); + provider2.NotifyOnItemsAvailable(); + + { + ScopedMockOfflineContentProvider::ScopedMockObserver observer1( + &aggregator_); + ScopedMockOfflineContentProvider::ScopedMockObserver observer2( + &aggregator_); + EXPECT_CALL(observer1, OnItemsAvailable(&aggregator_)).Times(1); + EXPECT_CALL(observer2, OnItemsAvailable(&aggregator_)).Times(1); + task_runner_->RunUntilIdle(); + } +} + +TEST_F(OfflineContentAggregatorTest, + ProvidersAddedAfterObserversNotifiedAvailable) { + ScopedMockOfflineContentProvider provider1("1", &aggregator_); + EXPECT_FALSE(aggregator_.AreItemsAvailable()); + EXPECT_TRUE(provider1.HasObserver(&aggregator_)); + + ScopedMockOfflineContentProvider::ScopedMockObserver observer1(&aggregator_); + ScopedMockOfflineContentProvider::ScopedMockObserver observer2(&aggregator_); + task_runner_->RunUntilIdle(); + + { + EXPECT_CALL(observer1, OnItemsAvailable(&aggregator_)).Times(1); + EXPECT_CALL(observer2, OnItemsAvailable(&aggregator_)).Times(1); + provider1.NotifyOnItemsAvailable(); + } + + { + OfflineContentProvider::OfflineItemList items; + items.push_back(OfflineItem()); + + ScopedMockOfflineContentProvider provider2("2", &aggregator_); + EXPECT_TRUE(provider2.HasObserver(&aggregator_)); + + EXPECT_CALL(provider2, GetAllItems()).WillOnce(Return(items)); + EXPECT_CALL(observer1, OnItemsAvailable(&aggregator_)).Times(0); + EXPECT_CALL(observer2, OnItemsAvailable(&aggregator_)).Times(0); + EXPECT_CALL(observer1, OnItemsAdded(items)).Times(1); + EXPECT_CALL(observer2, OnItemsAdded(items)).Times(1); + provider2.NotifyOnItemsAvailable(); + } +} + +TEST_F(OfflineContentAggregatorTest, QueryingItemsWithProviderThatIsntReady) { + ScopedMockOfflineContentProvider provider1("1", &aggregator_); + ScopedMockOfflineContentProvider provider2("2", &aggregator_); + EXPECT_FALSE(aggregator_.AreItemsAvailable()); + + OfflineContentProvider::OfflineItemList items1; + items1.push_back(OfflineItem(ContentId("1", "A"))); + items1.push_back(OfflineItem(ContentId("1", "B"))); + + OfflineContentProvider::OfflineItemList items2; + items2.push_back(OfflineItem(ContentId("2", "C"))); + items2.push_back(OfflineItem(ContentId("2", "D"))); + + EXPECT_CALL(provider1, GetAllItems()).WillRepeatedly(Return(items1)); + EXPECT_CALL(provider2, GetAllItems()).WillRepeatedly(Return(items2)); + + provider1.NotifyOnItemsAvailable(); + EXPECT_TRUE(VectorContentsEq(items1, aggregator_.GetAllItems())); + + OfflineContentProvider::OfflineItemList combined_items(items1); + combined_items.insert(combined_items.end(), items2.begin(), items2.end()); + provider2.NotifyOnItemsAvailable(); + + EXPECT_TRUE(VectorContentsEq(combined_items, aggregator_.GetAllItems())); +} + +TEST_F(OfflineContentAggregatorTest, QueryingItemFromRemovedProvider) { + ContentId id("1", "A"); + OfflineItem item(id); + + { + ScopedMockOfflineContentProvider provider("1", &aggregator_); + provider.NotifyOnItemsAvailable(); + EXPECT_TRUE(aggregator_.AreItemsAvailable()); + + EXPECT_CALL(provider, GetItemById(id)).WillRepeatedly(Return(&item)); + EXPECT_EQ(&item, aggregator_.GetItemById(id)); + } + + EXPECT_EQ(nullptr, aggregator_.GetItemById(id)); +} + +TEST_F(OfflineContentAggregatorTest, QueryingItemWithProviderThatIsntReady) { + ScopedMockOfflineContentProvider provider1("1", &aggregator_); + ScopedMockOfflineContentProvider provider2("2", &aggregator_); + EXPECT_FALSE(aggregator_.AreItemsAvailable()); + + ContentId id1("1", "A"); + ContentId id2("2", "B"); + ContentId id3("3", "C"); + + OfflineItem item1(id1); + OfflineItem item2(id2); + + EXPECT_CALL(provider1, GetItemById(id1)).WillRepeatedly(Return(&item1)); + EXPECT_CALL(provider2, GetItemById(id2)).WillRepeatedly(Return(&item2)); + + EXPECT_EQ(nullptr, aggregator_.GetItemById(id1)); + EXPECT_EQ(nullptr, aggregator_.GetItemById(id2)); + EXPECT_EQ(nullptr, aggregator_.GetItemById(id3)); + + provider1.NotifyOnItemsAvailable(); + EXPECT_EQ(&item1, aggregator_.GetItemById(id1)); + EXPECT_EQ(nullptr, aggregator_.GetItemById(id2)); + EXPECT_EQ(nullptr, aggregator_.GetItemById(id3)); + + provider2.NotifyOnItemsAvailable(); + EXPECT_EQ(&item1, aggregator_.GetItemById(id1)); + EXPECT_EQ(&item2, aggregator_.GetItemById(id2)); + EXPECT_EQ(nullptr, aggregator_.GetItemById(id3)); +} + +TEST_F(OfflineContentAggregatorTest, GetItemByIdPropagatesToRightProvider) { + ScopedMockOfflineContentProvider provider1("1", &aggregator_); + ScopedMockOfflineContentProvider provider2("2", &aggregator_); + provider1.NotifyOnItemsAvailable(); + provider2.NotifyOnItemsAvailable(); + + ContentId id1("1", "A"); + ContentId id2("2", "B"); + ContentId id3("1", "C"); + ContentId id4("3", "D"); + OfflineItem item1(id1); + OfflineItem item2(id2); + + EXPECT_CALL(provider1, GetItemById(id1)).WillRepeatedly(Return(&item1)); + EXPECT_CALL(provider2, GetItemById(id2)).WillRepeatedly(Return(&item2)); + EXPECT_CALL(provider1, GetItemById(id3)).WillRepeatedly(Return(nullptr)); + + EXPECT_EQ(&item1, aggregator_.GetItemById(id1)); + EXPECT_EQ(&item2, aggregator_.GetItemById(id2)); + EXPECT_EQ(nullptr, aggregator_.GetItemById(id3)); + EXPECT_EQ(nullptr, aggregator_.GetItemById(id4)); +} + +TEST_F(OfflineContentAggregatorTest, AreItemsAvailable) { + ScopedMockOfflineContentProvider provider1("1", &aggregator_); + ScopedMockOfflineContentProvider provider2("2", &aggregator_); + + ScopedMockOfflineContentProvider::ScopedMockObserver observer1(&aggregator_); + ScopedMockOfflineContentProvider::ScopedMockObserver observer2(&aggregator_); + task_runner_->RunUntilIdle(); + + EXPECT_FALSE(aggregator_.AreItemsAvailable()); + + { + EXPECT_CALL(observer1, OnItemsAvailable(&aggregator_)).Times(0); + EXPECT_CALL(observer2, OnItemsAvailable(&aggregator_)).Times(0); + + provider1.NotifyOnItemsAvailable(); + } + + EXPECT_FALSE(aggregator_.AreItemsAvailable()); + + { + EXPECT_CALL(observer1, OnItemsAvailable(&aggregator_)).Times(1); + EXPECT_CALL(observer2, OnItemsAvailable(&aggregator_)).Times(1); + + provider2.NotifyOnItemsAvailable(); + } + + EXPECT_TRUE(aggregator_.AreItemsAvailable()); +} + +TEST_F(OfflineContentAggregatorTest, ActionPropagatesToRightProvider) { + ScopedMockOfflineContentProvider provider1("1", &aggregator_); + ScopedMockOfflineContentProvider provider2("2", &aggregator_); + provider1.NotifyOnItemsAvailable(); + provider2.NotifyOnItemsAvailable(); + + testing::InSequence sequence; + ContentId id1("1", "A"); + ContentId id2("2", "B"); + EXPECT_CALL(provider1, OpenItem(id1)).Times(1); + EXPECT_CALL(provider2, OpenItem(id2)).Times(1); + EXPECT_CALL(provider1, RemoveItem(id1)).Times(1); + EXPECT_CALL(provider2, RemoveItem(id2)).Times(1); + EXPECT_CALL(provider1, CancelDownload(id1)).Times(1); + EXPECT_CALL(provider2, CancelDownload(id2)).Times(1); + EXPECT_CALL(provider1, ResumeDownload(id1)).Times(1); + EXPECT_CALL(provider2, ResumeDownload(id2)).Times(1); + EXPECT_CALL(provider1, PauseDownload(id1)).Times(1); + EXPECT_CALL(provider2, PauseDownload(id2)).Times(1); + aggregator_.OpenItem(id1); + aggregator_.OpenItem(id2); + aggregator_.RemoveItem(id1); + aggregator_.RemoveItem(id2); + aggregator_.CancelDownload(id1); + aggregator_.CancelDownload(id2); + aggregator_.ResumeDownload(id1); + aggregator_.ResumeDownload(id2); + aggregator_.PauseDownload(id1); + aggregator_.PauseDownload(id2); +} + +TEST_F(OfflineContentAggregatorTest, ActionPropagatesAfterInitialize) { + ScopedMockOfflineContentProvider provider1("1", &aggregator_); + ScopedMockOfflineContentProvider provider2("2", &aggregator_); + + ContentId id1("1", "A"); + ContentId id2("2", "B"); + ContentId id3("2", "C"); + + { + EXPECT_CALL(provider1, PauseDownload(id1)).Times(0); + aggregator_.PauseDownload(id1); + } + + { + testing::InSequence sequence; + EXPECT_CALL(provider1, PauseDownload(id1)).Times(1); + EXPECT_CALL(provider1, ResumeDownload(id1)).Times(1); + EXPECT_CALL(provider1, OpenItem(id1)).Times(1); + EXPECT_CALL(provider2, OpenItem(id2)).Times(0); + + aggregator_.ResumeDownload(id1); + aggregator_.OpenItem(id1); + provider1.NotifyOnItemsAvailable(); + aggregator_.OpenItem(id2); + } + + { + testing::InSequence sequence; + EXPECT_CALL(provider2, OpenItem(id2)).Times(1); + EXPECT_CALL(provider2, RemoveItem(id3)).Times(1); + aggregator_.RemoveItem(id3); + provider2.NotifyOnItemsAvailable(); + } +} + +TEST_F(OfflineContentAggregatorTest, OnItemsAddedPropagatedToObservers) { + ScopedMockOfflineContentProvider provider1("1", &aggregator_); + ScopedMockOfflineContentProvider provider2("2", &aggregator_); + provider1.NotifyOnItemsAvailable(); + provider2.NotifyOnItemsAvailable(); + + ScopedMockOfflineContentProvider::ScopedMockObserver observer1(&aggregator_); + ScopedMockOfflineContentProvider::ScopedMockObserver observer2(&aggregator_); + + EXPECT_CALL(observer1, OnItemsAvailable(&aggregator_)).Times(1); + EXPECT_CALL(observer2, OnItemsAvailable(&aggregator_)).Times(1); + task_runner_->RunUntilIdle(); + + OfflineContentProvider::OfflineItemList items1; + items1.push_back(OfflineItem(ContentId("1", "A"))); + items1.push_back(OfflineItem(ContentId("1", "B"))); + + OfflineContentProvider::OfflineItemList items2; + items2.push_back(OfflineItem(ContentId("2", "C"))); + items2.push_back(OfflineItem(ContentId("2", "D"))); + + EXPECT_CALL(observer1, OnItemsAdded(items1)).Times(1); + EXPECT_CALL(observer1, OnItemsAdded(items2)).Times(1); + EXPECT_CALL(observer2, OnItemsAdded(items1)).Times(1); + EXPECT_CALL(observer2, OnItemsAdded(items2)).Times(1); + provider1.NotifyOnItemsAdded(items1); + provider2.NotifyOnItemsAdded(items2); +} + +TEST_F(OfflineContentAggregatorTest, OnItemRemovedPropagatedToObservers) { + ScopedMockOfflineContentProvider provider1("1", &aggregator_); + ScopedMockOfflineContentProvider provider2("2", &aggregator_); + provider1.NotifyOnItemsAvailable(); + provider2.NotifyOnItemsAvailable(); + + ScopedMockOfflineContentProvider::ScopedMockObserver observer1(&aggregator_); + ScopedMockOfflineContentProvider::ScopedMockObserver observer2(&aggregator_); + + EXPECT_CALL(observer1, OnItemsAvailable(&aggregator_)).Times(1); + EXPECT_CALL(observer2, OnItemsAvailable(&aggregator_)).Times(1); + task_runner_->RunUntilIdle(); + + ContentId id1("1", "A"); + ContentId id2("2", "B"); + + EXPECT_CALL(observer1, OnItemRemoved(id1)).Times(1); + EXPECT_CALL(observer1, OnItemRemoved(id2)).Times(1); + EXPECT_CALL(observer2, OnItemRemoved(id1)).Times(1); + EXPECT_CALL(observer2, OnItemRemoved(id2)).Times(1); + provider1.NotifyOnItemRemoved(id1); + provider2.NotifyOnItemRemoved(id2); +} + +TEST_F(OfflineContentAggregatorTest, OnItemUpdatedPropagatedToObservers) { + ScopedMockOfflineContentProvider provider1("1", &aggregator_); + ScopedMockOfflineContentProvider provider2("2", &aggregator_); + provider1.NotifyOnItemsAvailable(); + provider2.NotifyOnItemsAvailable(); + + ScopedMockOfflineContentProvider::ScopedMockObserver observer1(&aggregator_); + ScopedMockOfflineContentProvider::ScopedMockObserver observer2(&aggregator_); + + EXPECT_CALL(observer1, OnItemsAvailable(&aggregator_)).Times(1); + EXPECT_CALL(observer2, OnItemsAvailable(&aggregator_)).Times(1); + task_runner_->RunUntilIdle(); + + OfflineItem item1(ContentId("1", "A")); + OfflineItem item2(ContentId("2", "B")); + + EXPECT_CALL(observer1, OnItemUpdated(item1)).Times(1); + EXPECT_CALL(observer1, OnItemUpdated(item2)).Times(1); + EXPECT_CALL(observer2, OnItemUpdated(item1)).Times(1); + EXPECT_CALL(observer2, OnItemUpdated(item2)).Times(1); + provider1.NotifyOnItemUpdated(item1); + provider2.NotifyOnItemUpdated(item2); +} + +TEST_F(OfflineContentAggregatorTest, ProviderRemovedDuringCallbackFlush) { + OpenItemRemovalOfflineContentProvider provider1("1", &aggregator_); + + ContentId id1("1", "A"); + ContentId id2("1", "B"); + aggregator_.OpenItem(id1); + aggregator_.OpenItem(id2); + aggregator_.RemoveItem(id2); + + EXPECT_CALL(provider1, OpenItem(id1)).Times(1); + EXPECT_CALL(provider1, RemoveItem(id2)).Times(0); + provider1.NotifyOnItemsAvailable(); +} + +TEST_F(OfflineContentAggregatorTest, SameProviderWithMultipleNamespaces) { + MockOfflineContentProvider provider; + ScopedMockOfflineContentProvider::ScopedMockObserver observer(&aggregator_); + + ContentId id1("1", "A"); + ContentId id2("2", "B"); + OfflineItem item1(id1); + OfflineItem item2(id2); + OfflineContentProvider::OfflineItemList items; + items.push_back(item1); + items.push_back(item2); + + aggregator_.RegisterProvider("1", &provider); + aggregator_.RegisterProvider("2", &provider); + EXPECT_TRUE(provider.HasObserver(&aggregator_)); + + EXPECT_CALL(provider, GetAllItems()).WillRepeatedly(Return(items)); + EXPECT_CALL(provider, GetItemById(id1)).WillRepeatedly(Return(&item1)); + EXPECT_CALL(provider, GetItemById(id2)).WillRepeatedly(Return(&item2)); + + EXPECT_CALL(observer, OnItemsAvailable(&aggregator_)).Times(1); + provider.NotifyOnItemsAvailable(); + + EXPECT_TRUE(VectorContentsEq(items, aggregator_.GetAllItems())); + EXPECT_EQ(&item1, aggregator_.GetItemById(id1)); + EXPECT_EQ(&item2, aggregator_.GetItemById(id2)); + + aggregator_.UnregisterProvider("1"); + EXPECT_TRUE(provider.HasObserver(&aggregator_)); + EXPECT_EQ(nullptr, aggregator_.GetItemById(id1)); + EXPECT_EQ(&item2, aggregator_.GetItemById(id2)); + + aggregator_.UnregisterProvider("2"); + EXPECT_FALSE(provider.HasObserver(&aggregator_)); +} + +} // namespace +} // namespace offline_items_collection |