| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "components/reading_list/reading_list_store.h" | |
| 6 | |
| 7 #include <map> | |
| 8 #include <set> | |
| 9 | |
| 10 #include "base/bind.h" | |
| 11 #include "base/memory/ptr_util.h" | |
| 12 #include "base/message_loop/message_loop.h" | |
| 13 #include "base/run_loop.h" | |
| 14 #import "base/test/ios/wait_util.h" | |
| 15 #include "components/reading_list/reading_list_model_impl.h" | |
| 16 #include "components/sync/model/fake_model_type_change_processor.h" | |
| 17 #include "components/sync/model/model_type_store_test_util.h" | |
| 18 #include "testing/gtest/include/gtest/gtest.h" | |
| 19 | |
| 20 class FakeModelTypeChangeProcessorObserver { | |
| 21 public: | |
| 22 virtual void Put(const std::string& client_tag, | |
| 23 std::unique_ptr<syncer::EntityData> entity_data, | |
| 24 syncer::MetadataChangeList* metadata_change_list) = 0; | |
| 25 | |
| 26 virtual void Delete(const std::string& client_tag, | |
| 27 syncer::MetadataChangeList* metadata_change_list) = 0; | |
| 28 }; | |
| 29 | |
| 30 class TestModelTypeChangeProcessor | |
| 31 : public syncer::FakeModelTypeChangeProcessor { | |
| 32 public: | |
| 33 void SetObserver(FakeModelTypeChangeProcessorObserver* observer) { | |
| 34 observer_ = observer; | |
| 35 } | |
| 36 | |
| 37 void Put(const std::string& client_tag, | |
| 38 std::unique_ptr<syncer::EntityData> entity_data, | |
| 39 syncer::MetadataChangeList* metadata_change_list) override { | |
| 40 observer_->Put(client_tag, std::move(entity_data), metadata_change_list); | |
| 41 } | |
| 42 | |
| 43 void Delete(const std::string& client_tag, | |
| 44 syncer::MetadataChangeList* metadata_change_list) override { | |
| 45 observer_->Delete(client_tag, metadata_change_list); | |
| 46 } | |
| 47 | |
| 48 private: | |
| 49 FakeModelTypeChangeProcessorObserver* observer_; | |
| 50 }; | |
| 51 | |
| 52 class ReadingListStoreTest : public testing::Test, | |
| 53 public FakeModelTypeChangeProcessorObserver, | |
| 54 public ReadingListStoreDelegate { | |
| 55 protected: | |
| 56 ReadingListStoreTest() | |
| 57 : store_(syncer::ModelTypeStoreTestUtil::CreateInMemoryStoreForTest()) { | |
| 58 ClearState(); | |
| 59 reading_list_store_ = base::MakeUnique<ReadingListStore>( | |
| 60 base::Bind(&syncer::ModelTypeStoreTestUtil::MoveStoreToCallback, | |
| 61 base::Passed(&store_)), | |
| 62 base::Bind(&ReadingListStoreTest::CreateModelTypeChangeProcessor, | |
| 63 base::Unretained(this))); | |
| 64 model_ = base::MakeUnique<ReadingListModelImpl>(nullptr, nullptr); | |
| 65 reading_list_store_->SetReadingListModel(model_.get(), this); | |
| 66 | |
| 67 base::RunLoop().RunUntilIdle(); | |
| 68 } | |
| 69 | |
| 70 std::unique_ptr<syncer::ModelTypeChangeProcessor> | |
| 71 CreateModelTypeChangeProcessor(syncer::ModelType type, | |
| 72 syncer::ModelTypeSyncBridge* service) { | |
| 73 auto processor = base::MakeUnique<TestModelTypeChangeProcessor>(); | |
| 74 processor->SetObserver(this); | |
| 75 return std::move(processor); | |
| 76 } | |
| 77 | |
| 78 void Put(const std::string& storage_key, | |
| 79 std::unique_ptr<syncer::EntityData> entity_data, | |
| 80 syncer::MetadataChangeList* metadata_changes) override { | |
| 81 put_multimap_.insert(std::make_pair(storage_key, std::move(entity_data))); | |
| 82 put_called_++; | |
| 83 } | |
| 84 | |
| 85 void Delete(const std::string& storage_key, | |
| 86 syncer::MetadataChangeList* metadata_changes) override { | |
| 87 delete_set_.insert(storage_key); | |
| 88 delete_called_++; | |
| 89 } | |
| 90 | |
| 91 void AssertCounts(int put_called, | |
| 92 int delete_called, | |
| 93 int sync_add_called, | |
| 94 int sync_remove_called, | |
| 95 int sync_merge_called) { | |
| 96 EXPECT_EQ(put_called, put_called_); | |
| 97 EXPECT_EQ(delete_called, delete_called_); | |
| 98 EXPECT_EQ(sync_add_called, sync_add_called_); | |
| 99 EXPECT_EQ(sync_remove_called, sync_remove_called_); | |
| 100 EXPECT_EQ(sync_merge_called, sync_merge_called_); | |
| 101 } | |
| 102 | |
| 103 void ClearState() { | |
| 104 delete_called_ = 0; | |
| 105 put_called_ = 0; | |
| 106 delete_set_.clear(); | |
| 107 put_multimap_.clear(); | |
| 108 sync_add_called_ = 0; | |
| 109 sync_remove_called_ = 0; | |
| 110 sync_merge_called_ = 0; | |
| 111 sync_added_.clear(); | |
| 112 sync_removed_.clear(); | |
| 113 sync_merged_.clear(); | |
| 114 } | |
| 115 | |
| 116 // These three mathods handle callbacks from a ReadingListStore. | |
| 117 void StoreLoaded(std::unique_ptr<ReadingListEntries> unread, | |
| 118 std::unique_ptr<ReadingListEntries> read) override {} | |
| 119 | |
| 120 // Handle sync events. | |
| 121 void SyncAddEntry(std::unique_ptr<ReadingListEntry> entry, | |
| 122 bool read) override { | |
| 123 sync_add_called_++; | |
| 124 sync_added_[entry->URL().spec()] = read; | |
| 125 } | |
| 126 | |
| 127 void SyncRemoveEntry(const GURL& gurl) override { | |
| 128 sync_remove_called_++; | |
| 129 sync_removed_.insert(gurl.spec()); | |
| 130 } | |
| 131 | |
| 132 ReadingListEntry* SyncMergeEntry(std::unique_ptr<ReadingListEntry> entry, | |
| 133 bool read) override { | |
| 134 sync_merge_called_++; | |
| 135 sync_merged_[entry->URL().spec()] = read; | |
| 136 return model_->SyncMergeEntry(std::move(entry), read); | |
| 137 } | |
| 138 | |
| 139 // In memory model type store needs a MessageLoop. | |
| 140 base::MessageLoop message_loop_; | |
| 141 | |
| 142 std::unique_ptr<syncer::ModelTypeStore> store_; | |
| 143 std::unique_ptr<ReadingListModelImpl> model_; | |
| 144 std::unique_ptr<ReadingListStore> reading_list_store_; | |
| 145 int put_called_; | |
| 146 int delete_called_; | |
| 147 int sync_add_called_; | |
| 148 int sync_remove_called_; | |
| 149 int sync_merge_called_; | |
| 150 std::map<std::string, std::unique_ptr<syncer::EntityData>> put_multimap_; | |
| 151 std::set<std::string> delete_set_; | |
| 152 std::map<std::string, bool> sync_added_; | |
| 153 std::set<std::string> sync_removed_; | |
| 154 std::map<std::string, bool> sync_merged_; | |
| 155 }; | |
| 156 | |
| 157 TEST_F(ReadingListStoreTest, CheckEmpties) { | |
| 158 EXPECT_EQ(0ul, model_->unread_size()); | |
| 159 EXPECT_EQ(0ul, model_->read_size()); | |
| 160 } | |
| 161 | |
| 162 TEST_F(ReadingListStoreTest, SaveOneRead) { | |
| 163 ReadingListEntry entry(GURL("http://read.example.com/"), "read title"); | |
| 164 reading_list_store_->SaveEntry(entry, true); | |
| 165 AssertCounts(1, 0, 0, 0, 0); | |
| 166 syncer::EntityData* data = put_multimap_["http://read.example.com/"].get(); | |
| 167 const sync_pb::ReadingListSpecifics& specifics = | |
| 168 data->specifics.reading_list(); | |
| 169 EXPECT_EQ(specifics.title(), "read title"); | |
| 170 EXPECT_EQ(specifics.url(), "http://read.example.com/"); | |
| 171 EXPECT_EQ(specifics.status(), sync_pb::ReadingListSpecifics::READ); | |
| 172 } | |
| 173 | |
| 174 TEST_F(ReadingListStoreTest, SaveOneUnread) { | |
| 175 ReadingListEntry entry(GURL("http://unread.example.com/"), "unread title"); | |
| 176 reading_list_store_->SaveEntry(entry, false); | |
| 177 AssertCounts(1, 0, 0, 0, 0); | |
| 178 syncer::EntityData* data = put_multimap_["http://unread.example.com/"].get(); | |
| 179 const sync_pb::ReadingListSpecifics& specifics = | |
| 180 data->specifics.reading_list(); | |
| 181 EXPECT_EQ(specifics.title(), "unread title"); | |
| 182 EXPECT_EQ(specifics.url(), "http://unread.example.com/"); | |
| 183 EXPECT_EQ(specifics.status(), sync_pb::ReadingListSpecifics::UNREAD); | |
| 184 } | |
| 185 | |
| 186 TEST_F(ReadingListStoreTest, SyncMergeOneEntry) { | |
| 187 syncer::EntityDataMap remote_input; | |
| 188 ReadingListEntry entry(GURL("http://read.example.com/"), "read title"); | |
| 189 std::unique_ptr<sync_pb::ReadingListSpecifics> specifics = | |
| 190 entry.AsReadingListSpecifics(true); | |
| 191 | |
| 192 syncer::EntityData data; | |
| 193 data.client_tag_hash = "http://read.example.com/"; | |
| 194 *data.specifics.mutable_reading_list() = *specifics; | |
| 195 | |
| 196 remote_input["http://read.example.com/"] = data.PassToPtr(); | |
| 197 | |
| 198 std::unique_ptr<syncer::MetadataChangeList> metadata_changes( | |
| 199 reading_list_store_->CreateMetadataChangeList()); | |
| 200 const syncer::SyncError error = reading_list_store_->MergeSyncData( | |
| 201 std::move(metadata_changes), remote_input); | |
| 202 AssertCounts(0, 0, 1, 0, 0); | |
| 203 EXPECT_EQ(sync_added_.size(), 1u); | |
| 204 EXPECT_EQ(sync_added_.count("http://read.example.com/"), 1u); | |
| 205 EXPECT_EQ(sync_added_["http://read.example.com/"], true); | |
| 206 } | |
| 207 | |
| 208 TEST_F(ReadingListStoreTest, ApplySyncChangesOneAdd) { | |
| 209 syncer::EntityDataMap remote_input; | |
| 210 ReadingListEntry entry(GURL("http://read.example.com/"), "read title"); | |
| 211 std::unique_ptr<sync_pb::ReadingListSpecifics> specifics = | |
| 212 entry.AsReadingListSpecifics(true); | |
| 213 syncer::EntityData data; | |
| 214 data.client_tag_hash = "http://read.example.com/"; | |
| 215 *data.specifics.mutable_reading_list() = *specifics; | |
| 216 | |
| 217 syncer::EntityChangeList add_changes; | |
| 218 | |
| 219 add_changes.push_back(syncer::EntityChange::CreateAdd( | |
| 220 "http://read.example.com/", data.PassToPtr())); | |
| 221 syncer::SyncError error = reading_list_store_->ApplySyncChanges( | |
| 222 reading_list_store_->CreateMetadataChangeList(), add_changes); | |
| 223 AssertCounts(0, 0, 1, 0, 0); | |
| 224 EXPECT_EQ(sync_added_.size(), 1u); | |
| 225 EXPECT_EQ(sync_added_.count("http://read.example.com/"), 1u); | |
| 226 EXPECT_EQ(sync_added_["http://read.example.com/"], true); | |
| 227 } | |
| 228 | |
| 229 TEST_F(ReadingListStoreTest, ApplySyncChangesOneMerge) { | |
| 230 syncer::EntityDataMap remote_input; | |
| 231 model_->AddEntry(GURL("http://unread.example.com/"), "unread title"); | |
| 232 base::test::ios::SpinRunLoopWithMinDelay( | |
| 233 base::TimeDelta::FromMilliseconds(10)); | |
| 234 | |
| 235 ReadingListEntry new_entry(GURL("http://unread.example.com/"), | |
| 236 "unread title"); | |
| 237 std::unique_ptr<sync_pb::ReadingListSpecifics> specifics = | |
| 238 new_entry.AsReadingListSpecifics(true); | |
| 239 syncer::EntityData data; | |
| 240 data.client_tag_hash = "http://unread.example.com/"; | |
| 241 *data.specifics.mutable_reading_list() = *specifics; | |
| 242 | |
| 243 syncer::EntityChangeList add_changes; | |
| 244 add_changes.push_back(syncer::EntityChange::CreateAdd( | |
| 245 "http://unread.example.com/", data.PassToPtr())); | |
| 246 syncer::SyncError error = reading_list_store_->ApplySyncChanges( | |
| 247 reading_list_store_->CreateMetadataChangeList(), add_changes); | |
| 248 AssertCounts(1, 0, 0, 0, 1); | |
| 249 EXPECT_EQ(sync_merged_.size(), 1u); | |
| 250 EXPECT_EQ(sync_merged_.count("http://unread.example.com/"), 1u); | |
| 251 EXPECT_EQ(sync_merged_["http://unread.example.com/"], true); | |
| 252 } | |
| 253 | |
| 254 TEST_F(ReadingListStoreTest, ApplySyncChangesOneIgnored) { | |
| 255 ReadingListEntry old_entry(GURL("http://unread.example.com/"), | |
| 256 "unread title"); | |
| 257 base::test::ios::SpinRunLoopWithMinDelay( | |
| 258 base::TimeDelta::FromMilliseconds(10)); | |
| 259 syncer::EntityDataMap remote_input; | |
| 260 model_->AddEntry(GURL("http://unread.example.com/"), "unread title"); | |
| 261 AssertCounts(0, 0, 0, 0, 0); | |
| 262 | |
| 263 std::unique_ptr<sync_pb::ReadingListSpecifics> specifics = | |
| 264 old_entry.AsReadingListSpecifics(true); | |
| 265 syncer::EntityData data; | |
| 266 data.client_tag_hash = "http://unread.example.com/"; | |
| 267 *data.specifics.mutable_reading_list() = *specifics; | |
| 268 | |
| 269 syncer::EntityChangeList add_changes; | |
| 270 add_changes.push_back(syncer::EntityChange::CreateAdd( | |
| 271 "http://unread.example.com/", data.PassToPtr())); | |
| 272 syncer::SyncError error = reading_list_store_->ApplySyncChanges( | |
| 273 reading_list_store_->CreateMetadataChangeList(), add_changes); | |
| 274 AssertCounts(1, 0, 0, 0, 0); | |
| 275 EXPECT_EQ(sync_merged_.size(), 0u); | |
| 276 } | |
| 277 | |
| 278 TEST_F(ReadingListStoreTest, ApplySyncChangesOneRemove) { | |
| 279 syncer::EntityChangeList delete_changes; | |
| 280 delete_changes.push_back( | |
| 281 syncer::EntityChange::CreateDelete("http://read.example.com/")); | |
| 282 syncer::SyncError error = reading_list_store_->ApplySyncChanges( | |
| 283 reading_list_store_->CreateMetadataChangeList(), delete_changes); | |
| 284 AssertCounts(0, 0, 0, 1, 0); | |
| 285 EXPECT_EQ(sync_removed_.size(), 1u); | |
| 286 EXPECT_EQ(sync_removed_.count("http://read.example.com/"), 1u); | |
| 287 } | |
| OLD | NEW |