diff options
author | stanisc <stanisc@chromium.org> | 2014-09-30 13:38:12 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-09-30 20:38:53 +0000 |
commit | 2b537d62aecf6a6c982eec5ba6d14a0e966297ed (patch) | |
tree | cc721a0dae06561765c7fb0c2733ec9bb36da9df /components/sync_driver | |
parent | 83cbc0eb332701e4cf15061326a129a0155f02b4 (diff) | |
download | chromium_src-2b537d62aecf6a6c982eec5ba6d14a0e966297ed.zip chromium_src-2b537d62aecf6a6c982eec5ba6d14a0e966297ed.tar.gz chromium_src-2b537d62aecf6a6c982eec5ba6d14a0e966297ed.tar.bz2 |
Device info datatype should be moved to components/sync_driver.
This change moves mock and test classes related to DeviceInfo
datatype to components/sync_driver and removes dependencies
on chrome and content layers.
The change is mostly trivial / mechanical renaming.
BUG=396136
TBR=jyasskin@chromium.org,pkasting@chromium.org,ben@chromium.org
Review URL: https://codereview.chromium.org/612103005
Cr-Commit-Position: refs/heads/master@{#297494}
Diffstat (limited to 'components/sync_driver')
5 files changed, 797 insertions, 0 deletions
diff --git a/components/sync_driver/BUILD.gn b/components/sync_driver/BUILD.gn index 5a04237..f55383a 100644 --- a/components/sync_driver/BUILD.gn +++ b/components/sync_driver/BUILD.gn @@ -83,6 +83,8 @@ static_library("test_support") { "fake_data_type_controller.h", "fake_generic_change_processor.cc", "fake_generic_change_processor.h", + "local_device_info_provider_mock.cc", + "local_device_info_provider_mock.h", "model_associator_mock.cc", "model_associator_mock.h", "non_ui_data_type_controller_mock.cc", diff --git a/components/sync_driver/device_info_data_type_controller_unittest.cc b/components/sync_driver/device_info_data_type_controller_unittest.cc new file mode 100644 index 0000000..a025913 --- /dev/null +++ b/components/sync_driver/device_info_data_type_controller_unittest.cc @@ -0,0 +1,132 @@ +// Copyright 2014 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 "base/bind.h" +#include "base/callback.h" +#include "base/memory/weak_ptr.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "components/sync_driver/device_info_data_type_controller.h" +#include "components/sync_driver/local_device_info_provider_mock.h" +#include "components/sync_driver/sync_api_component_factory.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace sync_driver { + +namespace { + +class DeviceInfoDataTypeControllerTest : public testing::Test, + public SyncApiComponentFactory { + public: + DeviceInfoDataTypeControllerTest() + : load_finished_(false), + weak_ptr_factory_(this), + last_type_(syncer::UNSPECIFIED) {} + virtual ~DeviceInfoDataTypeControllerTest() {} + + virtual void SetUp() OVERRIDE { + local_device_.reset(new LocalDeviceInfoProviderMock( + "cache_guid", + "Wayne Gretzky's Hacking Box", + "Chromium 10k", + "Chrome 10k", + sync_pb::SyncEnums_DeviceType_TYPE_LINUX, + "device_id")); + + controller_ = new DeviceInfoDataTypeController( + base::MessageLoopProxy::current(), + base::Closure(), + this, + local_device_.get()); + + load_finished_ = false; + last_type_ = syncer::UNSPECIFIED; + last_error_ = syncer::SyncError(); + } + + virtual void TearDown() OVERRIDE { + controller_ = NULL; + local_device_.reset(); + } + + void Start() { + controller_->LoadModels( + base::Bind(&DeviceInfoDataTypeControllerTest::OnLoadFinished, + weak_ptr_factory_.GetWeakPtr())); + } + + virtual base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType( + syncer::ModelType type) OVERRIDE { + // Shouldn't be called for this test. + NOTREACHED(); + return base::WeakPtr<syncer::SyncableService>(); + } + + virtual scoped_ptr<syncer::AttachmentService> CreateAttachmentService( + const scoped_refptr<syncer::AttachmentStore>& attachment_store, + const syncer::UserShare& user_share, + syncer::AttachmentService::Delegate* delegate) OVERRIDE { + // Shouldn't be called for this test. + NOTREACHED(); + return scoped_ptr<syncer::AttachmentService>(); + } + + void OnLoadFinished(syncer::ModelType type, syncer::SyncError error) { + load_finished_ = true; + last_type_ = type; + last_error_ = error; + } + + testing::AssertionResult LoadResult() { + if (!load_finished_) { + return testing::AssertionFailure() << "OnLoadFinished wasn't called"; + } + + if (last_error_.IsSet()) { + return testing::AssertionFailure() + << "OnLoadFinished was called with a SyncError: " + << last_error_.ToString(); + } + + if (last_type_ != syncer::DEVICE_INFO) { + return testing::AssertionFailure() + << "OnLoadFinished was called with a wrong sync type: " + << last_type_; + } + + return testing::AssertionSuccess(); + } + + protected: + scoped_refptr<DeviceInfoDataTypeController> controller_; + scoped_ptr<LocalDeviceInfoProviderMock> local_device_; + bool load_finished_; + + private: + base::MessageLoopForUI message_loop_; + base::WeakPtrFactory<DeviceInfoDataTypeControllerTest> weak_ptr_factory_; + syncer::ModelType last_type_; + syncer::SyncError last_error_; +}; + +TEST_F(DeviceInfoDataTypeControllerTest, StartModels) { + Start(); + EXPECT_EQ(DataTypeController::MODEL_LOADED, controller_->state()); + EXPECT_TRUE(LoadResult()); +} + +TEST_F(DeviceInfoDataTypeControllerTest, StartModelsDelayedByLocalDevice) { + local_device_->SetInitialized(false); + Start(); + EXPECT_FALSE(load_finished_); + EXPECT_EQ(DataTypeController::MODEL_STARTING, controller_->state()); + + local_device_->SetInitialized(true); + EXPECT_EQ(DataTypeController::MODEL_LOADED, controller_->state()); + EXPECT_TRUE(LoadResult()); +} + +} // namespace + +} // namespace sync_driver diff --git a/components/sync_driver/device_info_sync_service_unittest.cc b/components/sync_driver/device_info_sync_service_unittest.cc new file mode 100644 index 0000000..c1200d76 --- /dev/null +++ b/components/sync_driver/device_info_sync_service_unittest.cc @@ -0,0 +1,556 @@ +// Copyright 2014 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 "base/message_loop/message_loop.h" +#include "components/sync_driver/device_info_sync_service.h" +#include "components/sync_driver/local_device_info_provider_mock.h" +#include "sync/api/sync_change.h" +#include "sync/api/sync_change_processor.h" +#include "sync/api/sync_change_processor_wrapper_for_test.h" +#include "sync/api/sync_error_factory_mock.h" +#include "sync/internal_api/public/attachments/attachment_service_proxy_for_test.h" +#include "sync/util/time.h" +#include "testing/gtest/include/gtest/gtest.h" + +using syncer::AttachmentIdList; +using syncer::AttachmentServiceProxyForTest; +using syncer::ModelType; +using syncer::SyncChange; +using syncer::SyncChangeList; +using syncer::SyncChangeProcessor; +using syncer::SyncChangeProcessorWrapperForTest; +using syncer::SyncData; +using syncer::SyncDataList; +using syncer::SyncError; +using syncer::SyncErrorFactory; +using syncer::SyncErrorFactoryMock; +using syncer::SyncMergeResult; + +namespace sync_driver { + +namespace { + +class TestChangeProcessor : public SyncChangeProcessor { + public: + TestChangeProcessor() {} + virtual ~TestChangeProcessor() {} + + // SyncChangeProcessor implementation. + // Store a copy of all the changes passed in so we can examine them later. + virtual SyncError ProcessSyncChanges( + const tracked_objects::Location& from_here, + const SyncChangeList& change_list) OVERRIDE { + change_list_ = change_list; + return SyncError(); + } + + // This method isn't used in these tests. + virtual SyncDataList GetAllSyncData(ModelType type) const OVERRIDE { + return SyncDataList(); + } + + size_t change_list_size() const { return change_list_.size(); } + + SyncChange::SyncChangeType change_type_at(size_t index) const { + CHECK_LT(index, change_list_size()); + return change_list_[index].change_type(); + } + + const sync_pb::DeviceInfoSpecifics& device_info_at(size_t index) const { + CHECK_LT(index, change_list_size()); + return change_list_[index].sync_data().GetSpecifics().device_info(); + } + + const std::string& cache_guid_at(size_t index) const { + return device_info_at(index).cache_guid(); + } + + const std::string& client_name_at(size_t index) const { + return device_info_at(index).client_name(); + } + + private: + SyncChangeList change_list_; +}; + +class DeviceInfoSyncServiceTest : public testing::Test, + public DeviceInfoTracker::Observer { + public: + DeviceInfoSyncServiceTest() : num_device_info_changed_callbacks_(0) {} + virtual ~DeviceInfoSyncServiceTest() {} + + virtual void SetUp() OVERRIDE { + local_device_.reset(new LocalDeviceInfoProviderMock( + "guid_1", + "client_1", + "Chromium 10k", + "Chrome 10k", + sync_pb::SyncEnums_DeviceType_TYPE_LINUX, + "device_id")); + sync_service_.reset(new DeviceInfoSyncService(local_device_.get())); + sync_processor_.reset(new TestChangeProcessor()); + // Register observer + sync_service_->AddObserver(this); + } + + virtual void TearDown() OVERRIDE { + sync_service_->RemoveObserver(this); + } + + virtual void OnDeviceInfoChange() OVERRIDE { + num_device_info_changed_callbacks_++; + } + + scoped_ptr<SyncChangeProcessor> PassProcessor() { + return scoped_ptr<SyncChangeProcessor>( + new SyncChangeProcessorWrapperForTest(sync_processor_.get())); + } + + scoped_ptr<SyncErrorFactory> CreateAndPassSyncErrorFactory() { + return scoped_ptr<SyncErrorFactory>(new SyncErrorFactoryMock()); + } + + SyncData CreateRemoteData(const std::string& client_id, + const std::string& client_name, + int64 backup_timestamp = 0) { + sync_pb::EntitySpecifics entity; + sync_pb::DeviceInfoSpecifics& specifics = *entity.mutable_device_info(); + + specifics.set_cache_guid(client_id); + specifics.set_client_name(client_name); + specifics.set_chrome_version("Chromium 10k"); + specifics.set_sync_user_agent("Chrome 10k"); + specifics.set_device_type(sync_pb::SyncEnums_DeviceType_TYPE_LINUX); + specifics.set_signin_scoped_device_id("device_id"); + + if (backup_timestamp != 0) { + specifics.set_backup_timestamp(backup_timestamp); + } + + return SyncData::CreateRemoteData(1, + entity, + base::Time(), + AttachmentIdList(), + AttachmentServiceProxyForTest::Create()); + } + + void AddInitialData(SyncDataList& sync_data_list, + const std::string& client_id, + const std::string& client_name) { + SyncData sync_data = CreateRemoteData(client_id, client_name); + sync_data_list.push_back(sync_data); + } + + void AddChange(SyncChangeList& change_list, + SyncChange::SyncChangeType change_type, + const std::string& client_id, + const std::string& client_name) { + SyncData sync_data = CreateRemoteData(client_id, client_name); + SyncChange sync_change(FROM_HERE, change_type, sync_data); + change_list.push_back(sync_change); + } + + protected: + int num_device_info_changed_callbacks_; + scoped_ptr<LocalDeviceInfoProviderMock> local_device_; + scoped_ptr<DeviceInfoSyncService> sync_service_; + scoped_ptr<TestChangeProcessor> sync_processor_; + base::MessageLoopForUI message_loop_; +}; + +// Sync with empty initial data. +TEST_F(DeviceInfoSyncServiceTest, StartSyncEmptyInitialData) { + SyncMergeResult merge_result = + sync_service_->MergeDataAndStartSyncing(syncer::DEVICE_INFO, + SyncDataList(), + PassProcessor(), + CreateAndPassSyncErrorFactory()); + + EXPECT_EQ(0, merge_result.num_items_added()); + EXPECT_EQ(0, merge_result.num_items_modified()); + EXPECT_EQ(0, merge_result.num_items_deleted()); + EXPECT_EQ(1, merge_result.num_items_before_association()); + EXPECT_EQ(1, merge_result.num_items_after_association()); + EXPECT_EQ(SyncChange::ACTION_ADD, sync_processor_->change_type_at(0)); + + EXPECT_EQ(1U, sync_processor_->change_list_size()); + EXPECT_EQ("guid_1", sync_processor_->cache_guid_at(0)); + + // Should have one device info corresponding to local device info. + EXPECT_EQ(1U, sync_service_->GetAllSyncData(syncer::DEVICE_INFO).size()); + EXPECT_EQ(1U, sync_service_->GetAllDeviceInfo().size()); + EXPECT_TRUE(sync_service_->GetDeviceInfo("guid_1")); + EXPECT_FALSE(sync_service_->GetDeviceInfo("guid_0")); +} + +// Sync with initial data matching the local device data. +TEST_F(DeviceInfoSyncServiceTest, StartSyncMatchingInitialData) { + SyncDataList sync_data; + AddInitialData(sync_data, "guid_1", "client_1"); + + SyncMergeResult merge_result = + sync_service_->MergeDataAndStartSyncing(syncer::DEVICE_INFO, + sync_data, + PassProcessor(), + CreateAndPassSyncErrorFactory()); + EXPECT_EQ(0, merge_result.num_items_added()); + EXPECT_EQ(0, merge_result.num_items_modified()); + EXPECT_EQ(0, merge_result.num_items_deleted()); + EXPECT_EQ(1, merge_result.num_items_before_association()); + EXPECT_EQ(1, merge_result.num_items_after_association()); + + // No changes expected because the device info matches. + EXPECT_EQ(0U, sync_processor_->change_list_size()); + + EXPECT_EQ(1U, sync_service_->GetAllSyncData(syncer::DEVICE_INFO).size()); + EXPECT_EQ(1U, sync_service_->GetAllDeviceInfo().size()); + EXPECT_TRUE(sync_service_->GetDeviceInfo("guid_1")); + EXPECT_FALSE(sync_service_->GetDeviceInfo("guid_0")); +} + +// Sync with misc initial data. +TEST_F(DeviceInfoSyncServiceTest, StartSync) { + SyncDataList sync_data; + AddInitialData(sync_data, "guid_2", "foo"); + AddInitialData(sync_data, "guid_3", "bar"); + // This guid matches the local device but the client name is different. + AddInitialData(sync_data, "guid_1", "baz"); + + SyncMergeResult merge_result = + sync_service_->MergeDataAndStartSyncing(syncer::DEVICE_INFO, + sync_data, + PassProcessor(), + CreateAndPassSyncErrorFactory()); + + EXPECT_EQ(2, merge_result.num_items_added()); + EXPECT_EQ(1, merge_result.num_items_modified()); + EXPECT_EQ(0, merge_result.num_items_deleted()); + EXPECT_EQ(1, merge_result.num_items_before_association()); + EXPECT_EQ(3, merge_result.num_items_after_association()); + + EXPECT_EQ(1U, sync_processor_->change_list_size()); + EXPECT_EQ(SyncChange::ACTION_UPDATE, sync_processor_->change_type_at(0)); + EXPECT_EQ("client_1", sync_processor_->client_name_at(0)); + + EXPECT_EQ(3U, sync_service_->GetAllSyncData(syncer::DEVICE_INFO).size()); + EXPECT_EQ(3U, sync_service_->GetAllDeviceInfo().size()); + EXPECT_TRUE(sync_service_->GetDeviceInfo("guid_1")); + EXPECT_TRUE(sync_service_->GetDeviceInfo("guid_2")); + EXPECT_TRUE(sync_service_->GetDeviceInfo("guid_3")); + EXPECT_FALSE(sync_service_->GetDeviceInfo("guid_0")); +} + +// Process sync change with ACTION_ADD. +// Verify callback. +TEST_F(DeviceInfoSyncServiceTest, ProcessAddChange) { + EXPECT_EQ(0, num_device_info_changed_callbacks_); + + // Start with an empty initial data. + SyncMergeResult merge_result = + sync_service_->MergeDataAndStartSyncing(syncer::DEVICE_INFO, + SyncDataList(), + PassProcessor(), + CreateAndPassSyncErrorFactory()); + // There should be only one item corresponding to the local device + EXPECT_EQ(1, merge_result.num_items_after_association()); + EXPECT_EQ(1, num_device_info_changed_callbacks_); + + // Add a new device info with a non-matching guid. + SyncChangeList change_list; + AddChange(change_list, SyncChange::ACTION_ADD, "guid_2", "foo"); + + SyncError error = sync_service_->ProcessSyncChanges(FROM_HERE, change_list); + EXPECT_FALSE(error.IsSet()); + EXPECT_EQ(2, num_device_info_changed_callbacks_); + + EXPECT_EQ(2U, sync_service_->GetAllDeviceInfo().size()); + + EXPECT_TRUE(sync_service_->GetDeviceInfo("guid_1")); + EXPECT_TRUE(sync_service_->GetDeviceInfo("guid_2")); + EXPECT_FALSE(sync_service_->GetDeviceInfo("guid_0")); +} + +// Process multiple sync change with ACTION_UPDATE and ACTION_ADD. +// Verify that callback is called multiple times. +TEST_F(DeviceInfoSyncServiceTest, ProcessMultipleChanges) { + SyncDataList sync_data; + AddInitialData(sync_data, "guid_2", "foo"); + AddInitialData(sync_data, "guid_3", "bar"); + + SyncMergeResult merge_result = + sync_service_->MergeDataAndStartSyncing(syncer::DEVICE_INFO, + sync_data, + PassProcessor(), + CreateAndPassSyncErrorFactory()); + EXPECT_EQ(3, merge_result.num_items_after_association()); + // reset callbacks counter + num_device_info_changed_callbacks_ = 0; + + SyncChangeList change_list; + AddChange(change_list, SyncChange::ACTION_UPDATE, "guid_2", "foo_2"); + + SyncError error = sync_service_->ProcessSyncChanges(FROM_HERE, change_list); + EXPECT_FALSE(error.IsSet()); + + EXPECT_EQ(1, num_device_info_changed_callbacks_); + EXPECT_EQ(3U, sync_service_->GetAllDeviceInfo().size()); + EXPECT_EQ("foo_2", sync_service_->GetDeviceInfo("guid_2")->client_name()); + + change_list.clear(); + AddChange(change_list, SyncChange::ACTION_UPDATE, "guid_3", "bar_3"); + AddChange(change_list, SyncChange::ACTION_ADD, "guid_4", "baz_4"); + + error = sync_service_->ProcessSyncChanges(FROM_HERE, change_list); + EXPECT_FALSE(error.IsSet()); + + EXPECT_EQ(2, num_device_info_changed_callbacks_); + EXPECT_EQ(4U, sync_service_->GetAllDeviceInfo().size()); + EXPECT_EQ("bar_3", sync_service_->GetDeviceInfo("guid_3")->client_name()); + EXPECT_EQ("baz_4", sync_service_->GetDeviceInfo("guid_4")->client_name()); +} + +// Process update to the local device info and verify that it is ignored. +TEST_F(DeviceInfoSyncServiceTest, ProcessUpdateChangeMatchingLocalDevice) { + SyncMergeResult merge_result = + sync_service_->MergeDataAndStartSyncing(syncer::DEVICE_INFO, + SyncDataList(), + PassProcessor(), + CreateAndPassSyncErrorFactory()); + EXPECT_EQ(1, merge_result.num_items_after_association()); + // reset callbacks counter + num_device_info_changed_callbacks_ = 0; + + SyncChangeList change_list; + AddChange(change_list, SyncChange::ACTION_UPDATE, "guid_1", "foo_1"); + + SyncError error = sync_service_->ProcessSyncChanges(FROM_HERE, change_list); + EXPECT_FALSE(error.IsSet()); + // Callback shouldn't be sent in this case. + EXPECT_EQ(0, num_device_info_changed_callbacks_); + // Should still have the old local device Info. + EXPECT_EQ(1U, sync_service_->GetAllDeviceInfo().size()); + EXPECT_EQ("client_1", sync_service_->GetDeviceInfo("guid_1")->client_name()); +} + +// Process sync change with ACTION_DELETE. +TEST_F(DeviceInfoSyncServiceTest, ProcessDeleteChange) { + SyncDataList sync_data; + AddInitialData(sync_data, "guid_2", "foo"); + AddInitialData(sync_data, "guid_3", "bar"); + + SyncMergeResult merge_result = + sync_service_->MergeDataAndStartSyncing(syncer::DEVICE_INFO, + sync_data, + PassProcessor(), + CreateAndPassSyncErrorFactory()); + EXPECT_EQ(3, merge_result.num_items_after_association()); + // reset callbacks counter + num_device_info_changed_callbacks_ = 0; + + SyncChangeList change_list; + AddChange(change_list, SyncChange::ACTION_DELETE, "guid_2", "foo_2"); + + SyncError error = sync_service_->ProcessSyncChanges(FROM_HERE, change_list); + EXPECT_FALSE(error.IsSet()); + + EXPECT_EQ(1, num_device_info_changed_callbacks_); + EXPECT_EQ(2U, sync_service_->GetAllDeviceInfo().size()); + EXPECT_FALSE(sync_service_->GetDeviceInfo("guid_2")); +} + +// Process sync change with unexpected action. +TEST_F(DeviceInfoSyncServiceTest, ProcessInvalidChange) { + SyncMergeResult merge_result = + sync_service_->MergeDataAndStartSyncing(syncer::DEVICE_INFO, + SyncDataList(), + PassProcessor(), + CreateAndPassSyncErrorFactory()); + EXPECT_EQ(1, merge_result.num_items_after_association()); + // reset callbacks counter + num_device_info_changed_callbacks_ = 0; + + SyncChangeList change_list; + AddChange(change_list, (SyncChange::SyncChangeType)100, "guid_2", "foo_2"); + + SyncError error = sync_service_->ProcessSyncChanges(FROM_HERE, change_list); + EXPECT_TRUE(error.IsSet()); + + // The number of callback should still be zero. + EXPECT_EQ(0, num_device_info_changed_callbacks_); + EXPECT_EQ(1U, sync_service_->GetAllDeviceInfo().size()); +} + +// Process sync change after unsubscribing from notifications. +TEST_F(DeviceInfoSyncServiceTest, ProcessChangesAfterUnsubscribing) { + SyncMergeResult merge_result = + sync_service_->MergeDataAndStartSyncing(syncer::DEVICE_INFO, + SyncDataList(), + PassProcessor(), + CreateAndPassSyncErrorFactory()); + EXPECT_EQ(1, merge_result.num_items_after_association()); + // reset callbacks counter + num_device_info_changed_callbacks_ = 0; + + SyncChangeList change_list; + AddChange(change_list, SyncChange::ACTION_ADD, "guid_2", "foo_2"); + + // Unsubscribe observer before processing changes. + sync_service_->RemoveObserver(this); + + SyncError error = sync_service_->ProcessSyncChanges(FROM_HERE, change_list); + EXPECT_FALSE(error.IsSet()); + + // The number of callback should still be zero. + EXPECT_EQ(0, num_device_info_changed_callbacks_); +} + +// Verifies setting backup timestamp after the initial sync. +TEST_F(DeviceInfoSyncServiceTest, UpdateLocalDeviceBackupTime) { + // Shouldn't have backuptime initially. + base::Time backup_time = sync_service_->GetLocalDeviceBackupTime(); + EXPECT_TRUE(backup_time.is_null()); + + // Perform the initial sync with empty data. + SyncMergeResult merge_result = + sync_service_->MergeDataAndStartSyncing(syncer::DEVICE_INFO, + SyncDataList(), + PassProcessor(), + CreateAndPassSyncErrorFactory()); + + // Should have local device after the initial sync. + EXPECT_EQ(1U, sync_processor_->change_list_size()); + EXPECT_EQ(SyncChange::ACTION_ADD, sync_processor_->change_type_at(0)); + + // Shouldn't have backup time initially. + EXPECT_EQ("guid_1", sync_processor_->cache_guid_at(0)); + EXPECT_FALSE(sync_processor_->device_info_at(0).has_backup_timestamp()); + + sync_service_->UpdateLocalDeviceBackupTime(base::Time::FromTimeT(1000)); + + // Should have local device info updated with the specified backup timestamp. + EXPECT_EQ(1U, sync_processor_->change_list_size()); + EXPECT_EQ(SyncChange::ACTION_UPDATE, sync_processor_->change_type_at(0)); + EXPECT_EQ("guid_1", sync_processor_->cache_guid_at(0)); + EXPECT_TRUE(sync_processor_->device_info_at(0).has_backup_timestamp()); + + backup_time = syncer::ProtoTimeToTime( + sync_processor_->device_info_at(0).backup_timestamp()); + EXPECT_EQ(1000, backup_time.ToTimeT()); + + // Also verify that we get the same backup time directly from the service. + backup_time = sync_service_->GetLocalDeviceBackupTime(); + EXPECT_EQ(1000, backup_time.ToTimeT()); +} + +// Verifies setting backup timestamp prior to the initial sync. +TEST_F(DeviceInfoSyncServiceTest, UpdateLocalDeviceBackupTimeBeforeSync) { + // Set the backup timestamp. + sync_service_->UpdateLocalDeviceBackupTime(base::Time::FromTimeT(2000)); + // Verify that we get it back. + base::Time backup_time = sync_service_->GetLocalDeviceBackupTime(); + EXPECT_EQ(2000, backup_time.ToTimeT()); + + // Now perform the initial sync with empty data. + SyncMergeResult merge_result = + sync_service_->MergeDataAndStartSyncing(syncer::DEVICE_INFO, + SyncDataList(), + PassProcessor(), + CreateAndPassSyncErrorFactory()); + + // Should have local device after the initial sync. + // Should have the backup timestamp set. + EXPECT_EQ(1U, sync_processor_->change_list_size()); + EXPECT_EQ(SyncChange::ACTION_ADD, sync_processor_->change_type_at(0)); + EXPECT_EQ("guid_1", sync_processor_->cache_guid_at(0)); + EXPECT_TRUE(sync_processor_->device_info_at(0).has_backup_timestamp()); + + backup_time = syncer::ProtoTimeToTime( + sync_processor_->device_info_at(0).backup_timestamp()); + EXPECT_EQ(2000, backup_time.ToTimeT()); +} + +// Verifies that the backup timestamp that comes in the intial sync data +// gets preserved when there are no changes to the local device. +TEST_F(DeviceInfoSyncServiceTest, PreserveBackupTimeWithMatchingLocalDevice) { + base::Time backup_time = base::Time::FromTimeT(3000); + SyncDataList sync_data; + sync_data.push_back(CreateRemoteData( + "guid_1", "client_1", syncer::TimeToProtoTime(backup_time))); + + SyncMergeResult merge_result = + sync_service_->MergeDataAndStartSyncing(syncer::DEVICE_INFO, + sync_data, + PassProcessor(), + CreateAndPassSyncErrorFactory()); + + // Everything is matching so there should be no updates. + EXPECT_EQ(0U, sync_processor_->change_list_size()); + + // Verify that we get back the same time. + backup_time = sync_service_->GetLocalDeviceBackupTime(); + EXPECT_EQ(3000, backup_time.ToTimeT()); +} + +// Verifies that the backup timestamp that comes in the intial sync data +// gets merged with the local device data. +TEST_F(DeviceInfoSyncServiceTest, MergeBackupTimeWithMatchingLocalDevice) { + base::Time backup_time = base::Time::FromTimeT(4000); + SyncDataList sync_data; + sync_data.push_back(CreateRemoteData( + "guid_1", "foo_1", syncer::TimeToProtoTime(backup_time))); + + SyncMergeResult merge_result = + sync_service_->MergeDataAndStartSyncing(syncer::DEVICE_INFO, + sync_data, + PassProcessor(), + CreateAndPassSyncErrorFactory()); + + // Should be one change because of the client name mismatch. + // However the backup time passed in the initial data should be merged into + // the change. + EXPECT_EQ(1U, sync_processor_->change_list_size()); + + EXPECT_EQ(SyncChange::ACTION_UPDATE, sync_processor_->change_type_at(0)); + EXPECT_EQ("guid_1", sync_processor_->cache_guid_at(0)); + EXPECT_EQ("client_1", sync_processor_->client_name_at(0)); + + backup_time = syncer::ProtoTimeToTime( + sync_processor_->device_info_at(0).backup_timestamp()); + EXPECT_EQ(4000, backup_time.ToTimeT()); +} + +// Verifies that mismatching backup timestamp generates an update even +// when the rest of local device data is matching. +TEST_F(DeviceInfoSyncServiceTest, + MergeMismatchingBackupTimeWithMatchingLocalDevice) { + base::Time backup_time = base::Time::FromTimeT(5000); + SyncDataList sync_data; + sync_data.push_back(CreateRemoteData( + "guid_1", "client_1", syncer::TimeToProtoTime(backup_time))); + + // Set the backup timestamp different than the one in the sync data. + sync_service_->UpdateLocalDeviceBackupTime(base::Time::FromTimeT(6000)); + + SyncMergeResult merge_result = + sync_service_->MergeDataAndStartSyncing(syncer::DEVICE_INFO, + sync_data, + PassProcessor(), + CreateAndPassSyncErrorFactory()); + + // Should generate and update due to timestamp mismatch. + // The locally set timestamp wins. + EXPECT_EQ(1U, sync_processor_->change_list_size()); + + EXPECT_EQ(SyncChange::ACTION_UPDATE, sync_processor_->change_type_at(0)); + EXPECT_EQ("guid_1", sync_processor_->cache_guid_at(0)); + EXPECT_EQ("client_1", sync_processor_->client_name_at(0)); + + backup_time = syncer::ProtoTimeToTime( + sync_processor_->device_info_at(0).backup_timestamp()); + EXPECT_EQ(6000, backup_time.ToTimeT()); +} + +} // namespace + +} // namespace sync_driver diff --git a/components/sync_driver/local_device_info_provider_mock.cc b/components/sync_driver/local_device_info_provider_mock.cc new file mode 100644 index 0000000..2acf49d --- /dev/null +++ b/components/sync_driver/local_device_info_provider_mock.cc @@ -0,0 +1,60 @@ +// Copyright 2014 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/sync_driver/local_device_info_provider_mock.h" + +namespace sync_driver { + +LocalDeviceInfoProviderMock::LocalDeviceInfoProviderMock() + : is_initialized_(false) {} + +LocalDeviceInfoProviderMock::LocalDeviceInfoProviderMock( + const std::string& guid, + const std::string& client_name, + const std::string& chrome_version, + const std::string& sync_user_agent, + const sync_pb::SyncEnums::DeviceType device_type, + const std::string& signin_scoped_device_id) + : is_initialized_(true) { + local_device_info_.reset( + new DeviceInfo( + guid, + client_name, + chrome_version, + sync_user_agent, + device_type, + signin_scoped_device_id)); +} + +LocalDeviceInfoProviderMock::~LocalDeviceInfoProviderMock() {} + +const DeviceInfo* LocalDeviceInfoProviderMock::GetLocalDeviceInfo() const { + return is_initialized_ ? local_device_info_.get() : NULL; +} + +std::string LocalDeviceInfoProviderMock::GetLocalSyncCacheGUID() const { + return local_device_info_.get() ? local_device_info_->guid() : ""; +} + +void LocalDeviceInfoProviderMock::Initialize( + const std::string& cache_guid, const std::string& signin_scoped_device_id) { + // Ignored for the mock provider. +} + +scoped_ptr<LocalDeviceInfoProvider::Subscription> +LocalDeviceInfoProviderMock::RegisterOnInitializedCallback( + const base::Closure& callback) { + DCHECK(!is_initialized_); + return callback_list_.Add(callback); +} + +void LocalDeviceInfoProviderMock::SetInitialized(bool is_initialized) { + is_initialized_ = is_initialized; + if (is_initialized_) { + callback_list_.Notify(); + } +} + +} // namespace sync_driver + diff --git a/components/sync_driver/local_device_info_provider_mock.h b/components/sync_driver/local_device_info_provider_mock.h new file mode 100644 index 0000000..5218c6b --- /dev/null +++ b/components/sync_driver/local_device_info_provider_mock.h @@ -0,0 +1,47 @@ +// Copyright 2014 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. + +#ifndef COMPONENTS_SYNC_DRIVER_LOCAL_DEVICE_INFO_PROVIDER_MOCK_H_ +#define COMPONENTS_SYNC_DRIVER_LOCAL_DEVICE_INFO_PROVIDER_MOCK_H_ + +#include "components/sync_driver/device_info.h" +#include "components/sync_driver/local_device_info_provider.h" + +namespace sync_driver { + +class LocalDeviceInfoProviderMock + : public sync_driver::LocalDeviceInfoProvider { + public: + // Creates uninitialized provider. + LocalDeviceInfoProviderMock(); + // Creates initialized provider with the specified device info. + LocalDeviceInfoProviderMock( + const std::string& guid, + const std::string& client_name, + const std::string& chrome_version, + const std::string& sync_user_agent, + const sync_pb::SyncEnums::DeviceType device_type, + const std::string& signin_scoped_device_id); + virtual ~LocalDeviceInfoProviderMock(); + + virtual const DeviceInfo* GetLocalDeviceInfo() const OVERRIDE; + virtual std::string GetLocalSyncCacheGUID() const OVERRIDE; + virtual void Initialize( + const std::string& cache_guid, + const std::string& signin_scoped_device_id) OVERRIDE; + virtual scoped_ptr<Subscription> RegisterOnInitializedCallback( + const base::Closure& callback) OVERRIDE; + + void SetInitialized(bool is_initialized); + + private: + bool is_initialized_; + + scoped_ptr<DeviceInfo> local_device_info_; + base::CallbackList<void(void)> callback_list_; +}; + +} // namespace sync_driver + +#endif // COMPONENTS_SYNC_DRIVER_LOCAL_DEVICE_INFO_PROVIDER_MOCK_H_ |