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 |