OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "components/sync_driver/device_info_service.h" | |
6 | |
7 #include <map> | |
8 #include <memory> | |
9 #include <set> | |
10 #include <string> | |
11 #include <utility> | |
12 | |
13 #include "base/bind.h" | |
14 #include "base/memory/ptr_util.h" | |
15 #include "base/message_loop/message_loop.h" | |
16 #include "base/run_loop.h" | |
17 #include "base/strings/stringprintf.h" | |
18 #include "components/sync/api/data_batch.h" | |
19 #include "components/sync/api/entity_data.h" | |
20 #include "components/sync/api/fake_model_type_change_processor.h" | |
21 #include "components/sync/api/metadata_batch.h" | |
22 #include "components/sync/api/model_type_store.h" | |
23 #include "components/sync/base/time.h" | |
24 #include "components/sync/core/test/data_type_error_handler_mock.h" | |
25 #include "components/sync/core/test/model_type_store_test_util.h" | |
26 #include "components/sync/protocol/data_type_state.pb.h" | |
27 #include "components/sync_driver/local_device_info_provider_mock.h" | |
28 #include "testing/gtest/include/gtest/gtest.h" | |
29 | |
30 namespace sync_driver_v2 { | |
31 | |
32 using base::Time; | |
33 using base::TimeDelta; | |
34 using syncer::SyncError; | |
35 using syncer_v2::DataBatch; | |
36 using syncer_v2::EntityChange; | |
37 using syncer_v2::EntityChangeList; | |
38 using syncer_v2::EntityData; | |
39 using syncer_v2::EntityDataMap; | |
40 using syncer_v2::EntityDataPtr; | |
41 using syncer_v2::MetadataBatch; | |
42 using syncer_v2::MetadataChangeList; | |
43 using syncer_v2::ModelTypeChangeProcessor; | |
44 using syncer_v2::ModelTypeService; | |
45 using syncer_v2::ModelTypeStore; | |
46 using syncer_v2::ModelTypeStoreTestUtil; | |
47 using syncer_v2::KeyAndData; | |
48 using sync_driver::DeviceInfo; | |
49 using sync_driver::DeviceInfoTracker; | |
50 using sync_driver::LocalDeviceInfoProviderMock; | |
51 using sync_pb::DataTypeState; | |
52 using sync_pb::DeviceInfoSpecifics; | |
53 using sync_pb::EntitySpecifics; | |
54 | |
55 using StorageKeyList = ModelTypeService::StorageKeyList; | |
56 using RecordList = ModelTypeStore::RecordList; | |
57 using Result = ModelTypeStore::Result; | |
58 using StartCallback = ModelTypeChangeProcessor::StartCallback; | |
59 using WriteBatch = ModelTypeStore::WriteBatch; | |
60 | |
61 namespace { | |
62 | |
63 std::unique_ptr<DeviceInfo> CreateDeviceInfo() { | |
64 return base::MakeUnique<DeviceInfo>( | |
65 "guid_1", "client_1", "Chromium 10k", "Chrome 10k", | |
66 sync_pb::SyncEnums_DeviceType_TYPE_LINUX, "device_id"); | |
67 } | |
68 | |
69 void AssertResultIsSuccess(Result result) { | |
70 ASSERT_EQ(Result::SUCCESS, result); | |
71 } | |
72 | |
73 void AssertEqual(const DeviceInfoSpecifics& s1, const DeviceInfoSpecifics& s2) { | |
74 ASSERT_EQ(s1.cache_guid(), s2.cache_guid()); | |
75 ASSERT_EQ(s1.client_name(), s2.client_name()); | |
76 ASSERT_EQ(s1.device_type(), s2.device_type()); | |
77 ASSERT_EQ(s1.sync_user_agent(), s2.sync_user_agent()); | |
78 ASSERT_EQ(s1.chrome_version(), s2.chrome_version()); | |
79 ASSERT_EQ(s1.signin_scoped_device_id(), s2.signin_scoped_device_id()); | |
80 } | |
81 | |
82 void AssertEqual(const DeviceInfoSpecifics& specifics, | |
83 const DeviceInfo& model) { | |
84 ASSERT_EQ(specifics.cache_guid(), model.guid()); | |
85 ASSERT_EQ(specifics.client_name(), model.client_name()); | |
86 ASSERT_EQ(specifics.device_type(), model.device_type()); | |
87 ASSERT_EQ(specifics.sync_user_agent(), model.sync_user_agent()); | |
88 ASSERT_EQ(specifics.chrome_version(), model.chrome_version()); | |
89 ASSERT_EQ(specifics.signin_scoped_device_id(), | |
90 model.signin_scoped_device_id()); | |
91 } | |
92 | |
93 void AssertExpectedFromDataBatch( | |
94 std::map<std::string, DeviceInfoSpecifics> expected, | |
95 SyncError error, | |
96 std::unique_ptr<DataBatch> batch) { | |
97 ASSERT_FALSE(error.IsSet()); | |
98 while (batch->HasNext()) { | |
99 const KeyAndData& pair = batch->Next(); | |
100 std::map<std::string, DeviceInfoSpecifics>::iterator iter = | |
101 expected.find(pair.first); | |
102 ASSERT_NE(iter, expected.end()); | |
103 AssertEqual(iter->second, pair.second->specifics.device_info()); | |
104 // Removing allows us to verify we don't see the same item multiple times, | |
105 // and that we saw everything we expected. | |
106 expected.erase(iter); | |
107 } | |
108 ASSERT_TRUE(expected.empty()); | |
109 } | |
110 | |
111 // Creates an EntityData/EntityDataPtr around a copy of the given specifics. | |
112 EntityDataPtr SpecificsToEntity(const DeviceInfoSpecifics& specifics) { | |
113 EntityData data; | |
114 // These tests do not care about the tag hash, but EntityData and friends | |
115 // cannot differentiate between the default EntityData object if the hash | |
116 // is unset, which causes pass/copy operations to no-op and things start to | |
117 // break, so we throw in a junk value and forget about it. | |
118 data.client_tag_hash = "junk"; | |
119 *data.specifics.mutable_device_info() = specifics; | |
120 return data.PassToPtr(); | |
121 } | |
122 | |
123 std::string CacheGuidToTag(const std::string& guid) { | |
124 return "DeviceInfo_" + guid; | |
125 } | |
126 | |
127 // Helper method to reduce duplicated code between tests. Wraps the given | |
128 // specifics object in an EntityData and EntityChange of type ACTION_ADD, and | |
129 // pushes them onto the given change list. The corresponding guid of the data | |
130 // is returned, which happens to be the storage key. | |
131 std::string PushBackEntityChangeAdd(const DeviceInfoSpecifics& specifics, | |
132 EntityChangeList* changes) { | |
133 EntityDataPtr ptr = SpecificsToEntity(specifics); | |
134 changes->push_back(EntityChange::CreateAdd(specifics.cache_guid(), ptr)); | |
135 return specifics.cache_guid(); | |
136 } | |
137 | |
138 // Instead of actually processing anything, simply accumulates all instructions | |
139 // in members that can then be accessed. TODO(skym): If this ends up being | |
140 // useful for other model type unittests it should be moved out to a shared | |
141 // location. | |
142 class RecordingModelTypeChangeProcessor | |
143 : public syncer_v2::FakeModelTypeChangeProcessor { | |
144 public: | |
145 RecordingModelTypeChangeProcessor() {} | |
146 ~RecordingModelTypeChangeProcessor() override {} | |
147 | |
148 void Put(const std::string& storage_key, | |
149 std::unique_ptr<EntityData> entity_data, | |
150 MetadataChangeList* metadata_changes) override { | |
151 put_map_.insert(std::make_pair(storage_key, std::move(entity_data))); | |
152 } | |
153 | |
154 void Delete(const std::string& storage_key, | |
155 MetadataChangeList* metadata_changes) override { | |
156 delete_set_.insert(storage_key); | |
157 } | |
158 | |
159 void OnMetadataLoaded(syncer::SyncError error, | |
160 std::unique_ptr<MetadataBatch> batch) override { | |
161 std::swap(metadata_, batch); | |
162 } | |
163 | |
164 const std::map<std::string, std::unique_ptr<EntityData>>& put_map() const { | |
165 return put_map_; | |
166 } | |
167 const std::set<std::string>& delete_set() const { return delete_set_; } | |
168 const MetadataBatch* metadata() const { return metadata_.get(); } | |
169 | |
170 private: | |
171 std::map<std::string, std::unique_ptr<EntityData>> put_map_; | |
172 std::set<std::string> delete_set_; | |
173 std::unique_ptr<MetadataBatch> metadata_; | |
174 }; | |
175 | |
176 } // namespace | |
177 | |
178 class DeviceInfoServiceTest : public testing::Test, | |
179 public DeviceInfoTracker::Observer { | |
180 protected: | |
181 DeviceInfoServiceTest() | |
182 : change_count_(0), | |
183 store_(ModelTypeStoreTestUtil::CreateInMemoryStoreForTest()), | |
184 local_device_(new LocalDeviceInfoProviderMock()) { | |
185 local_device_->Initialize(CreateDeviceInfo()); | |
186 } | |
187 | |
188 ~DeviceInfoServiceTest() override { | |
189 // Some tests may never initialize the service. | |
190 if (service_) | |
191 service_->RemoveObserver(this); | |
192 | |
193 // Force all remaining (store) tasks to execute so we don't leak memory. | |
194 base::RunLoop().RunUntilIdle(); | |
195 } | |
196 | |
197 void OnDeviceInfoChange() override { change_count_++; } | |
198 | |
199 std::unique_ptr<ModelTypeChangeProcessor> CreateModelTypeChangeProcessor( | |
200 syncer::ModelType type, | |
201 ModelTypeService* service) { | |
202 processor_ = new RecordingModelTypeChangeProcessor(); | |
203 return base::WrapUnique(processor_); | |
204 } | |
205 | |
206 // Initialized the service based on the current local device and store. Can | |
207 // only be called once per run, as it passes |store_|. | |
208 void InitializeService() { | |
209 ASSERT_TRUE(store_); | |
210 service_.reset(new DeviceInfoService( | |
211 local_device_.get(), | |
212 base::Bind(&ModelTypeStoreTestUtil::MoveStoreToCallback, | |
213 base::Passed(&store_)), | |
214 base::Bind(&DeviceInfoServiceTest::CreateModelTypeChangeProcessor, | |
215 base::Unretained(this)))); | |
216 service_->AddObserver(this); | |
217 } | |
218 | |
219 void OnSyncStarting() { | |
220 service()->OnSyncStarting(&error_handler_, StartCallback()); | |
221 } | |
222 | |
223 // Creates the service and runs any outstanding tasks. This will typically | |
224 // cause all initialization callbacks between the sevice and store to fire. | |
225 void InitializeAndPump() { | |
226 InitializeService(); | |
227 base::RunLoop().RunUntilIdle(); | |
228 } | |
229 | |
230 // Creates the service, runs any outstanding tasks, and then indicates to the | |
231 // service that sync wants to start and forces the processor to be created. | |
232 void InitializeAndPumpAndStart() { | |
233 InitializeAndPump(); | |
234 OnSyncStarting(); | |
235 ASSERT_TRUE(processor_); | |
236 } | |
237 | |
238 // Generates a specifics object with slightly differing values. Will generate | |
239 // the same values on each run of a test because a simple counter is used to | |
240 // vary field values. | |
241 DeviceInfoSpecifics GenerateTestSpecifics() { | |
242 int label = ++generated_count_; | |
243 DeviceInfoSpecifics specifics; | |
244 specifics.set_cache_guid(base::StringPrintf("cache guid %d", label)); | |
245 specifics.set_client_name(base::StringPrintf("client name %d", label)); | |
246 specifics.set_device_type(sync_pb::SyncEnums_DeviceType_TYPE_LINUX); | |
247 specifics.set_sync_user_agent( | |
248 base::StringPrintf("sync user agent %d", label)); | |
249 specifics.set_chrome_version( | |
250 base::StringPrintf("chrome version %d", label)); | |
251 specifics.set_signin_scoped_device_id( | |
252 base::StringPrintf("signin scoped device id %d", label)); | |
253 return specifics; | |
254 } | |
255 | |
256 std::unique_ptr<DeviceInfoSpecifics> CopyToSpecifics(const DeviceInfo& info) { | |
257 return DeviceInfoService::CopyToSpecifics(info); | |
258 } | |
259 | |
260 // Override to allow specific cache guids. | |
261 DeviceInfoSpecifics GenerateTestSpecifics(const std::string& guid) { | |
262 DeviceInfoSpecifics specifics(GenerateTestSpecifics()); | |
263 specifics.set_cache_guid(guid); | |
264 return specifics; | |
265 } | |
266 | |
267 // Allows access to the store before that will ultimately be used to | |
268 // initialize the service. | |
269 ModelTypeStore* store() { | |
270 EXPECT_TRUE(store_); | |
271 return store_.get(); | |
272 } | |
273 | |
274 // Get the number of times the service notifies observers of changes. | |
275 int change_count() { return change_count_; } | |
276 | |
277 // Allows overriding the provider before the service is initialized. | |
278 void set_local_device(std::unique_ptr<LocalDeviceInfoProviderMock> provider) { | |
279 ASSERT_FALSE(service_); | |
280 std::swap(local_device_, provider); | |
281 } | |
282 LocalDeviceInfoProviderMock* local_device() { return local_device_.get(); } | |
283 | |
284 // Allows access to the service after InitializeService() is called. | |
285 DeviceInfoService* service() { | |
286 EXPECT_TRUE(service_); | |
287 return service_.get(); | |
288 } | |
289 | |
290 RecordingModelTypeChangeProcessor* processor() { | |
291 EXPECT_TRUE(processor_); | |
292 return processor_; | |
293 } | |
294 | |
295 // Should only be called after the service has been initialized. Will first | |
296 // recover the service's store, so another can be initialized later, and then | |
297 // deletes the service. | |
298 void PumpAndShutdown() { | |
299 ASSERT_TRUE(service_); | |
300 base::RunLoop().RunUntilIdle(); | |
301 std::swap(store_, service_->store_); | |
302 service_->RemoveObserver(this); | |
303 service_.reset(); | |
304 } | |
305 | |
306 void RestartService() { | |
307 PumpAndShutdown(); | |
308 InitializeAndPump(); | |
309 } | |
310 | |
311 Time GetLastUpdateTime(const DeviceInfoSpecifics& specifics) { | |
312 return DeviceInfoService::GetLastUpdateTime(specifics); | |
313 } | |
314 | |
315 private: | |
316 int change_count_; | |
317 | |
318 // In memory model type store needs a MessageLoop. | |
319 base::MessageLoop message_loop_; | |
320 | |
321 // Holds the store while the service is not initialized. | |
322 std::unique_ptr<ModelTypeStore> store_; | |
323 | |
324 std::unique_ptr<LocalDeviceInfoProviderMock> local_device_; | |
325 | |
326 // Mock error handler passed to the processor. | |
327 syncer::DataTypeErrorHandlerMock error_handler_; | |
328 | |
329 // Not initialized immediately (upon test's constructor). This allows each | |
330 // test case to modify the dependencies the service will be constructed with. | |
331 std::unique_ptr<DeviceInfoService> service_; | |
332 | |
333 // A non-owning pointer to the processor given to the service. Will be nullptr | |
334 // before being given to the service, to make ownership easier. | |
335 RecordingModelTypeChangeProcessor* processor_ = nullptr; | |
336 | |
337 // A monotonically increasing label for generated specifics objects with data | |
338 // that is slightly different from eachother. | |
339 int generated_count_ = 0; | |
340 }; | |
341 | |
342 namespace { | |
343 | |
344 TEST_F(DeviceInfoServiceTest, EmptyDataReconciliation) { | |
345 InitializeAndPump(); | |
346 ASSERT_EQ(0u, service()->GetAllDeviceInfo().size()); | |
347 OnSyncStarting(); | |
348 ScopedVector<DeviceInfo> all_device_info(service()->GetAllDeviceInfo()); | |
349 ASSERT_EQ(1u, all_device_info.size()); | |
350 ASSERT_TRUE( | |
351 local_device()->GetLocalDeviceInfo()->Equals(*all_device_info[0])); | |
352 } | |
353 | |
354 TEST_F(DeviceInfoServiceTest, EmptyDataReconciliationSlowLoad) { | |
355 InitializeService(); | |
356 OnSyncStarting(); | |
357 ASSERT_EQ(0u, service()->GetAllDeviceInfo().size()); | |
358 base::RunLoop().RunUntilIdle(); | |
359 ScopedVector<DeviceInfo> all_device_info(service()->GetAllDeviceInfo()); | |
360 ASSERT_EQ(1u, all_device_info.size()); | |
361 ASSERT_TRUE( | |
362 local_device()->GetLocalDeviceInfo()->Equals(*all_device_info[0])); | |
363 } | |
364 | |
365 TEST_F(DeviceInfoServiceTest, LocalProviderSubscription) { | |
366 set_local_device(base::WrapUnique(new LocalDeviceInfoProviderMock())); | |
367 InitializeAndPumpAndStart(); | |
368 | |
369 ASSERT_EQ(0u, service()->GetAllDeviceInfo().size()); | |
370 local_device()->Initialize(CreateDeviceInfo()); | |
371 base::RunLoop().RunUntilIdle(); | |
372 | |
373 ScopedVector<DeviceInfo> all_device_info(service()->GetAllDeviceInfo()); | |
374 ASSERT_EQ(1u, all_device_info.size()); | |
375 ASSERT_TRUE( | |
376 local_device()->GetLocalDeviceInfo()->Equals(*all_device_info[0])); | |
377 } | |
378 | |
379 // Metadata shouldn't be loaded before the provider is initialized. | |
380 TEST_F(DeviceInfoServiceTest, LocalProviderInitRace) { | |
381 set_local_device(base::WrapUnique(new LocalDeviceInfoProviderMock())); | |
382 InitializeAndPump(); | |
383 OnSyncStarting(); | |
384 EXPECT_FALSE(processor()->metadata()); | |
385 | |
386 ASSERT_EQ(0u, service()->GetAllDeviceInfo().size()); | |
387 local_device()->Initialize(CreateDeviceInfo()); | |
388 base::RunLoop().RunUntilIdle(); | |
389 | |
390 ScopedVector<DeviceInfo> all_device_info(service()->GetAllDeviceInfo()); | |
391 ASSERT_EQ(1u, all_device_info.size()); | |
392 ASSERT_TRUE( | |
393 local_device()->GetLocalDeviceInfo()->Equals(*all_device_info[0])); | |
394 | |
395 EXPECT_TRUE(processor()->metadata()); | |
396 } | |
397 | |
398 TEST_F(DeviceInfoServiceTest, GetClientTagNormal) { | |
399 InitializeService(); | |
400 const std::string guid = "abc"; | |
401 EntitySpecifics entity_specifics; | |
402 entity_specifics.mutable_device_info()->set_cache_guid(guid); | |
403 EntityData entity_data; | |
404 entity_data.specifics = entity_specifics; | |
405 EXPECT_EQ(CacheGuidToTag(guid), service()->GetClientTag(entity_data)); | |
406 } | |
407 | |
408 TEST_F(DeviceInfoServiceTest, GetClientTagEmpty) { | |
409 InitializeService(); | |
410 EntitySpecifics entity_specifics; | |
411 entity_specifics.mutable_device_info(); | |
412 EntityData entity_data; | |
413 entity_data.specifics = entity_specifics; | |
414 EXPECT_EQ(CacheGuidToTag(""), service()->GetClientTag(entity_data)); | |
415 } | |
416 | |
417 TEST_F(DeviceInfoServiceTest, TestWithLocalData) { | |
418 std::unique_ptr<WriteBatch> batch = store()->CreateWriteBatch(); | |
419 DeviceInfoSpecifics specifics(GenerateTestSpecifics()); | |
420 store()->WriteData(batch.get(), specifics.cache_guid(), | |
421 specifics.SerializeAsString()); | |
422 store()->CommitWriteBatch(std::move(batch), | |
423 base::Bind(&AssertResultIsSuccess)); | |
424 | |
425 InitializeAndPump(); | |
426 | |
427 ScopedVector<DeviceInfo> all_device_info(service()->GetAllDeviceInfo()); | |
428 ASSERT_EQ(1u, all_device_info.size()); | |
429 AssertEqual(specifics, *all_device_info[0]); | |
430 AssertEqual(specifics, | |
431 *service()->GetDeviceInfo(specifics.cache_guid()).get()); | |
432 } | |
433 | |
434 TEST_F(DeviceInfoServiceTest, TestWithLocalMetadata) { | |
435 std::unique_ptr<WriteBatch> batch = store()->CreateWriteBatch(); | |
436 DataTypeState state; | |
437 state.set_encryption_key_name("ekn"); | |
438 store()->WriteGlobalMetadata(batch.get(), state.SerializeAsString()); | |
439 store()->CommitWriteBatch(std::move(batch), | |
440 base::Bind(&AssertResultIsSuccess)); | |
441 InitializeAndPump(); | |
442 ScopedVector<DeviceInfo> all_device_info(service()->GetAllDeviceInfo()); | |
443 ASSERT_EQ(1u, all_device_info.size()); | |
444 ASSERT_TRUE( | |
445 local_device()->GetLocalDeviceInfo()->Equals(*all_device_info[0])); | |
446 EXPECT_EQ(1u, processor()->put_map().size()); | |
447 } | |
448 | |
449 TEST_F(DeviceInfoServiceTest, TestWithLocalDataAndMetadata) { | |
450 std::unique_ptr<WriteBatch> batch = store()->CreateWriteBatch(); | |
451 DeviceInfoSpecifics specifics(GenerateTestSpecifics()); | |
452 store()->WriteData(batch.get(), specifics.cache_guid(), | |
453 specifics.SerializeAsString()); | |
454 DataTypeState state; | |
455 state.set_encryption_key_name("ekn"); | |
456 store()->WriteGlobalMetadata(batch.get(), state.SerializeAsString()); | |
457 store()->CommitWriteBatch(std::move(batch), | |
458 base::Bind(&AssertResultIsSuccess)); | |
459 | |
460 InitializeAndPump(); | |
461 | |
462 ScopedVector<DeviceInfo> all_device_info(service()->GetAllDeviceInfo()); | |
463 ASSERT_EQ(2u, all_device_info.size()); | |
464 AssertEqual(specifics, | |
465 *service()->GetDeviceInfo(specifics.cache_guid()).get()); | |
466 ASSERT_TRUE(processor()->metadata()); | |
467 ASSERT_EQ(state.encryption_key_name(), | |
468 processor()->metadata()->GetDataTypeState().encryption_key_name()); | |
469 } | |
470 | |
471 TEST_F(DeviceInfoServiceTest, GetData) { | |
472 std::unique_ptr<WriteBatch> batch = store()->CreateWriteBatch(); | |
473 DeviceInfoSpecifics specifics1(GenerateTestSpecifics()); | |
474 DeviceInfoSpecifics specifics2(GenerateTestSpecifics()); | |
475 DeviceInfoSpecifics specifics3(GenerateTestSpecifics()); | |
476 store()->WriteData(batch.get(), specifics1.cache_guid(), | |
477 specifics1.SerializeAsString()); | |
478 store()->WriteData(batch.get(), specifics2.cache_guid(), | |
479 specifics2.SerializeAsString()); | |
480 store()->WriteData(batch.get(), specifics3.cache_guid(), | |
481 specifics3.SerializeAsString()); | |
482 store()->CommitWriteBatch(std::move(batch), | |
483 base::Bind(&AssertResultIsSuccess)); | |
484 | |
485 InitializeAndPump(); | |
486 | |
487 std::map<std::string, DeviceInfoSpecifics> expected; | |
488 expected[specifics1.cache_guid()] = specifics1; | |
489 expected[specifics3.cache_guid()] = specifics3; | |
490 StorageKeyList storage_keys; | |
491 storage_keys.push_back(specifics1.cache_guid()); | |
492 storage_keys.push_back(specifics3.cache_guid()); | |
493 service()->GetData(storage_keys, | |
494 base::Bind(&AssertExpectedFromDataBatch, expected)); | |
495 } | |
496 | |
497 TEST_F(DeviceInfoServiceTest, GetDataMissing) { | |
498 InitializeAndPump(); | |
499 std::map<std::string, DeviceInfoSpecifics> expected; | |
500 StorageKeyList storage_keys; | |
501 storage_keys.push_back("does_not_exist"); | |
502 service()->GetData(storage_keys, | |
503 base::Bind(&AssertExpectedFromDataBatch, expected)); | |
504 } | |
505 | |
506 TEST_F(DeviceInfoServiceTest, GetAllData) { | |
507 std::unique_ptr<WriteBatch> batch = store()->CreateWriteBatch(); | |
508 DeviceInfoSpecifics specifics1(GenerateTestSpecifics()); | |
509 DeviceInfoSpecifics specifics2(GenerateTestSpecifics()); | |
510 const std::string& guid1 = specifics1.cache_guid(); | |
511 const std::string& guid2 = specifics2.cache_guid(); | |
512 store()->WriteData(batch.get(), specifics1.cache_guid(), | |
513 specifics1.SerializeAsString()); | |
514 store()->WriteData(batch.get(), specifics2.cache_guid(), | |
515 specifics2.SerializeAsString()); | |
516 store()->CommitWriteBatch(std::move(batch), | |
517 base::Bind(&AssertResultIsSuccess)); | |
518 | |
519 InitializeAndPump(); | |
520 | |
521 std::map<std::string, DeviceInfoSpecifics> expected; | |
522 expected[guid1] = specifics1; | |
523 expected[guid2] = specifics2; | |
524 StorageKeyList storage_keys; | |
525 storage_keys.push_back(guid1); | |
526 storage_keys.push_back(guid2); | |
527 service()->GetData(storage_keys, | |
528 base::Bind(&AssertExpectedFromDataBatch, expected)); | |
529 } | |
530 | |
531 TEST_F(DeviceInfoServiceTest, ApplySyncChangesEmpty) { | |
532 InitializeAndPump(); | |
533 const SyncError error = service()->ApplySyncChanges( | |
534 service()->CreateMetadataChangeList(), EntityChangeList()); | |
535 EXPECT_FALSE(error.IsSet()); | |
536 EXPECT_EQ(0, change_count()); | |
537 } | |
538 | |
539 TEST_F(DeviceInfoServiceTest, ApplySyncChangesInMemory) { | |
540 InitializeAndPump(); | |
541 | |
542 DeviceInfoSpecifics specifics = GenerateTestSpecifics(); | |
543 EntityChangeList add_changes; | |
544 PushBackEntityChangeAdd(specifics, &add_changes); | |
545 SyncError error = service()->ApplySyncChanges( | |
546 service()->CreateMetadataChangeList(), add_changes); | |
547 | |
548 EXPECT_FALSE(error.IsSet()); | |
549 std::unique_ptr<DeviceInfo> info = | |
550 service()->GetDeviceInfo(specifics.cache_guid()); | |
551 ASSERT_TRUE(info); | |
552 AssertEqual(specifics, *info.get()); | |
553 EXPECT_EQ(1, change_count()); | |
554 | |
555 EntityChangeList delete_changes; | |
556 delete_changes.push_back(EntityChange::CreateDelete(specifics.cache_guid())); | |
557 error = service()->ApplySyncChanges(service()->CreateMetadataChangeList(), | |
558 delete_changes); | |
559 | |
560 EXPECT_FALSE(error.IsSet()); | |
561 EXPECT_FALSE(service()->GetDeviceInfo(specifics.cache_guid())); | |
562 EXPECT_EQ(2, change_count()); | |
563 } | |
564 | |
565 TEST_F(DeviceInfoServiceTest, ApplySyncChangesStore) { | |
566 InitializeAndPump(); | |
567 | |
568 DeviceInfoSpecifics specifics = GenerateTestSpecifics(); | |
569 EntityChangeList data_changes; | |
570 PushBackEntityChangeAdd(specifics, &data_changes); | |
571 DataTypeState state; | |
572 state.set_encryption_key_name("ekn"); | |
573 std::unique_ptr<MetadataChangeList> metadata_changes( | |
574 service()->CreateMetadataChangeList()); | |
575 metadata_changes->UpdateDataTypeState(state); | |
576 | |
577 const SyncError error = | |
578 service()->ApplySyncChanges(std::move(metadata_changes), data_changes); | |
579 EXPECT_FALSE(error.IsSet()); | |
580 EXPECT_EQ(1, change_count()); | |
581 | |
582 RestartService(); | |
583 | |
584 std::unique_ptr<DeviceInfo> info = | |
585 service()->GetDeviceInfo(specifics.cache_guid()); | |
586 ASSERT_TRUE(info); | |
587 AssertEqual(specifics, *info.get()); | |
588 | |
589 EXPECT_TRUE(processor()->metadata()); | |
590 EXPECT_EQ(state.encryption_key_name(), | |
591 processor()->metadata()->GetDataTypeState().encryption_key_name()); | |
592 } | |
593 | |
594 TEST_F(DeviceInfoServiceTest, ApplySyncChangesWithLocalGuid) { | |
595 InitializeAndPumpAndStart(); | |
596 | |
597 // The point of this test is to try to apply remote changes that have the same | |
598 // cache guid as the local device. The service should ignore these changes | |
599 // since only it should be performing writes on its data. | |
600 DeviceInfoSpecifics specifics = | |
601 GenerateTestSpecifics(local_device()->GetLocalDeviceInfo()->guid()); | |
602 EntityChangeList change_list; | |
603 PushBackEntityChangeAdd(specifics, &change_list); | |
604 | |
605 // Should have a single change from reconciliation. | |
606 EXPECT_TRUE( | |
607 service()->GetDeviceInfo(local_device()->GetLocalDeviceInfo()->guid())); | |
608 EXPECT_EQ(1, change_count()); | |
609 // Ensure |last_updated| is about now, plus or minus a little bit. | |
610 Time last_updated( | |
611 syncer::ProtoTimeToTime(processor() | |
612 ->put_map() | |
613 .begin() | |
614 ->second->specifics.device_info() | |
615 .last_updated_timestamp())); | |
616 EXPECT_LT(Time::Now() - TimeDelta::FromMinutes(1), last_updated); | |
617 EXPECT_GT(Time::Now() + TimeDelta::FromMinutes(1), last_updated); | |
618 | |
619 EXPECT_FALSE( | |
620 service() | |
621 ->ApplySyncChanges(service()->CreateMetadataChangeList(), change_list) | |
622 .IsSet()); | |
623 EXPECT_EQ(1, change_count()); | |
624 | |
625 change_list.clear(); | |
626 change_list.push_back(EntityChange::CreateDelete(specifics.cache_guid())); | |
627 EXPECT_FALSE( | |
628 service() | |
629 ->ApplySyncChanges(service()->CreateMetadataChangeList(), change_list) | |
630 .IsSet()); | |
631 EXPECT_EQ(1, change_count()); | |
632 } | |
633 | |
634 TEST_F(DeviceInfoServiceTest, ApplyDeleteNonexistent) { | |
635 InitializeAndPumpAndStart(); | |
636 EXPECT_EQ(1, change_count()); | |
637 EntityChangeList delete_changes; | |
638 delete_changes.push_back(EntityChange::CreateDelete("guid")); | |
639 const SyncError error = service()->ApplySyncChanges( | |
640 service()->CreateMetadataChangeList(), delete_changes); | |
641 EXPECT_FALSE(error.IsSet()); | |
642 EXPECT_EQ(1, change_count()); | |
643 } | |
644 | |
645 TEST_F(DeviceInfoServiceTest, MergeEmpty) { | |
646 InitializeAndPumpAndStart(); | |
647 EXPECT_EQ(1, change_count()); | |
648 const SyncError error = service()->MergeSyncData( | |
649 service()->CreateMetadataChangeList(), EntityDataMap()); | |
650 EXPECT_FALSE(error.IsSet()); | |
651 EXPECT_EQ(1, change_count()); | |
652 EXPECT_EQ(1u, processor()->put_map().size()); | |
653 EXPECT_EQ(0u, processor()->delete_set().size()); | |
654 } | |
655 | |
656 TEST_F(DeviceInfoServiceTest, MergeWithData) { | |
657 const std::string conflict_guid = "conflict_guid"; | |
658 const DeviceInfoSpecifics unique_local( | |
659 GenerateTestSpecifics("unique_local_guid")); | |
660 const DeviceInfoSpecifics conflict_local( | |
661 GenerateTestSpecifics(conflict_guid)); | |
662 const DeviceInfoSpecifics conflict_remote( | |
663 GenerateTestSpecifics(conflict_guid)); | |
664 const DeviceInfoSpecifics unique_remote( | |
665 GenerateTestSpecifics("unique_remote_guid")); | |
666 | |
667 std::unique_ptr<WriteBatch> batch = store()->CreateWriteBatch(); | |
668 store()->WriteData(batch.get(), unique_local.cache_guid(), | |
669 unique_local.SerializeAsString()); | |
670 store()->WriteData(batch.get(), conflict_local.cache_guid(), | |
671 conflict_local.SerializeAsString()); | |
672 store()->CommitWriteBatch(std::move(batch), | |
673 base::Bind(&AssertResultIsSuccess)); | |
674 | |
675 InitializeAndPumpAndStart(); | |
676 EXPECT_EQ(1, change_count()); | |
677 | |
678 EntityDataMap remote_input; | |
679 remote_input[conflict_remote.cache_guid()] = | |
680 SpecificsToEntity(conflict_remote); | |
681 remote_input[unique_remote.cache_guid()] = SpecificsToEntity(unique_remote); | |
682 | |
683 DataTypeState state; | |
684 state.set_encryption_key_name("ekn"); | |
685 std::unique_ptr<MetadataChangeList> metadata_changes( | |
686 service()->CreateMetadataChangeList()); | |
687 metadata_changes->UpdateDataTypeState(state); | |
688 | |
689 const SyncError error = | |
690 service()->MergeSyncData(std::move(metadata_changes), remote_input); | |
691 EXPECT_FALSE(error.IsSet()); | |
692 EXPECT_EQ(2, change_count()); | |
693 | |
694 // The remote should beat the local in conflict. | |
695 EXPECT_EQ(4u, service()->GetAllDeviceInfo().size()); | |
696 AssertEqual(unique_local, | |
697 *service()->GetDeviceInfo(unique_local.cache_guid()).get()); | |
698 AssertEqual(unique_remote, | |
699 *service()->GetDeviceInfo(unique_remote.cache_guid()).get()); | |
700 AssertEqual(conflict_remote, *service()->GetDeviceInfo(conflict_guid).get()); | |
701 | |
702 // Service should have told the processor about the existance of unique_local. | |
703 EXPECT_TRUE(processor()->delete_set().empty()); | |
704 EXPECT_EQ(2u, processor()->put_map().size()); | |
705 const auto& it = processor()->put_map().find(unique_local.cache_guid()); | |
706 ASSERT_NE(processor()->put_map().end(), it); | |
707 AssertEqual(unique_local, it->second->specifics.device_info()); | |
708 | |
709 RestartService(); | |
710 ASSERT_EQ(state.encryption_key_name(), | |
711 processor()->metadata()->GetDataTypeState().encryption_key_name()); | |
712 } | |
713 | |
714 TEST_F(DeviceInfoServiceTest, MergeLocalGuid) { | |
715 const DeviceInfo* local_device_info = local_device()->GetLocalDeviceInfo(); | |
716 std::unique_ptr<DeviceInfoSpecifics> specifics( | |
717 CopyToSpecifics(*local_device_info)); | |
718 specifics->set_last_updated_timestamp(syncer::TimeToProtoTime(Time::Now())); | |
719 const std::string guid = local_device_info->guid(); | |
720 | |
721 std::unique_ptr<WriteBatch> batch = store()->CreateWriteBatch(); | |
722 store()->WriteData(batch.get(), guid, specifics->SerializeAsString()); | |
723 store()->CommitWriteBatch(std::move(batch), | |
724 base::Bind(&AssertResultIsSuccess)); | |
725 | |
726 InitializeAndPumpAndStart(); | |
727 | |
728 EntityDataMap remote_input; | |
729 remote_input[guid] = SpecificsToEntity(*specifics); | |
730 | |
731 const SyncError error = service()->MergeSyncData( | |
732 service()->CreateMetadataChangeList(), remote_input); | |
733 EXPECT_FALSE(error.IsSet()); | |
734 EXPECT_EQ(0, change_count()); | |
735 EXPECT_EQ(1u, service()->GetAllDeviceInfo().size()); | |
736 EXPECT_TRUE(processor()->delete_set().empty()); | |
737 EXPECT_TRUE(processor()->put_map().empty()); | |
738 } | |
739 | |
740 TEST_F(DeviceInfoServiceTest, GetLastUpdateTime) { | |
741 Time time1(Time() + TimeDelta::FromDays(1)); | |
742 | |
743 DeviceInfoSpecifics specifics1(GenerateTestSpecifics()); | |
744 DeviceInfoSpecifics specifics2(GenerateTestSpecifics()); | |
745 specifics2.set_last_updated_timestamp(syncer::TimeToProtoTime(time1)); | |
746 | |
747 EXPECT_EQ(Time(), GetLastUpdateTime(specifics1)); | |
748 EXPECT_EQ(time1, GetLastUpdateTime(specifics2)); | |
749 } | |
750 | |
751 TEST_F(DeviceInfoServiceTest, CountActiveDevices) { | |
752 InitializeAndPump(); | |
753 EXPECT_EQ(0, service()->CountActiveDevices()); | |
754 | |
755 DeviceInfoSpecifics specifics = | |
756 GenerateTestSpecifics(local_device()->GetLocalDeviceInfo()->guid()); | |
757 EntityChangeList change_list; | |
758 PushBackEntityChangeAdd(specifics, &change_list); | |
759 service()->ApplySyncChanges(service()->CreateMetadataChangeList(), | |
760 change_list); | |
761 EXPECT_EQ(0, service()->CountActiveDevices()); | |
762 | |
763 change_list.clear(); | |
764 specifics.set_last_updated_timestamp(syncer::TimeToProtoTime(Time::Now())); | |
765 PushBackEntityChangeAdd(specifics, &change_list); | |
766 service()->ApplySyncChanges(service()->CreateMetadataChangeList(), | |
767 change_list); | |
768 EXPECT_EQ(0, service()->CountActiveDevices()); | |
769 | |
770 change_list.clear(); | |
771 specifics.set_cache_guid("non-local"); | |
772 PushBackEntityChangeAdd(specifics, &change_list); | |
773 service()->ApplySyncChanges(service()->CreateMetadataChangeList(), | |
774 change_list); | |
775 EXPECT_EQ(1, service()->CountActiveDevices()); | |
776 } | |
777 | |
778 } // namespace | |
779 | |
780 } // namespace sync_driver_v2 | |
OLD | NEW |