diff options
author | akalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-15 02:50:12 +0000 |
---|---|---|
committer | akalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-15 02:50:12 +0000 |
commit | 895a1e5bb93fa9a86fac22f5492598cf99636e47 (patch) | |
tree | 0f2e965b0014a64656ef378930710a16ad8c79d8 /sync | |
parent | 49f47568522c5a83c851f4333592521a1dae86dd (diff) | |
download | chromium_src-895a1e5bb93fa9a86fac22f5492598cf99636e47.zip chromium_src-895a1e5bb93fa9a86fac22f5492598cf99636e47.tar.gz chromium_src-895a1e5bb93fa9a86fac22f5492598cf99636e47.tar.bz2 |
[Sync] Move chrome/browser/sync/api to sync/api
Update all references.
BUG=128061
TEST=
TBR=sky@chromium.org
Review URL: https://chromiumcodereview.appspot.com/10389134
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@137062 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sync')
-rw-r--r-- | sync/api/DEPS | 6 | ||||
-rw-r--r-- | sync/api/fake_syncable_service.cc | 58 | ||||
-rw-r--r-- | sync/api/fake_syncable_service.h | 48 | ||||
-rw-r--r-- | sync/api/sync_change.cc | 73 | ||||
-rw-r--r-- | sync/api/sync_change.h | 67 | ||||
-rw-r--r-- | sync/api/sync_change_processor.cc | 9 | ||||
-rw-r--r-- | sync/api/sync_change_processor.h | 40 | ||||
-rw-r--r-- | sync/api/sync_change_unittest.cc | 130 | ||||
-rw-r--r-- | sync/api/sync_data.cc | 140 | ||||
-rw-r--r-- | sync/api/sync_data.h | 121 | ||||
-rw-r--r-- | sync/api/sync_error.cc | 108 | ||||
-rw-r--r-- | sync/api/sync_error.h | 85 | ||||
-rw-r--r-- | sync/api/sync_error_factory.cc | 11 | ||||
-rw-r--r-- | sync/api/sync_error_factory.h | 26 | ||||
-rw-r--r-- | sync/api/sync_error_factory_mock.cc | 12 | ||||
-rw-r--r-- | sync/api/sync_error_factory_mock.h | 23 | ||||
-rw-r--r-- | sync/api/sync_error_unittest.cc | 132 | ||||
-rw-r--r-- | sync/api/syncable_service.cc | 7 | ||||
-rw-r--r-- | sync/api/syncable_service.h | 65 | ||||
-rw-r--r-- | sync/sync.gyp | 96 |
20 files changed, 1257 insertions, 0 deletions
diff --git a/sync/api/DEPS b/sync/api/DEPS new file mode 100644 index 0000000..157d02f --- /dev/null +++ b/sync/api/DEPS @@ -0,0 +1,6 @@ +include_rules = [ + "+sync/internal_api/base_node.h", + "+sync/protocol", + "+sync/syncable/model_type.h", + "+sync/util/immutable.h", +] diff --git a/sync/api/fake_syncable_service.cc b/sync/api/fake_syncable_service.cc new file mode 100644 index 0000000..f5738eb --- /dev/null +++ b/sync/api/fake_syncable_service.cc @@ -0,0 +1,58 @@ +// Copyright (c) 2012 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 "sync/api/fake_syncable_service.h" + +#include "base/location.h" +#include "sync/api/sync_error_factory.h" + +FakeSyncableService::FakeSyncableService() + : syncing_(false), + type_(syncable::UNSPECIFIED) {} + +FakeSyncableService::~FakeSyncableService() {} + +void FakeSyncableService::set_merge_data_and_start_syncing_error( + const SyncError& error) { + merge_data_and_start_syncing_error_ = error; +} + +void FakeSyncableService::set_process_sync_changes_error( + const SyncError& error) { + process_sync_changes_error_ = error; +} + +bool FakeSyncableService::syncing() const { + return syncing_; +} + +// SyncableService implementation. +SyncError FakeSyncableService::MergeDataAndStartSyncing( + syncable::ModelType type, + const SyncDataList& initial_sync_data, + scoped_ptr<SyncChangeProcessor> sync_processor, + scoped_ptr<SyncErrorFactory> sync_error_factory) { + sync_processor_ = sync_processor.Pass(); + type_ = type; + if (!merge_data_and_start_syncing_error_.IsSet()) { + syncing_ = true; + } + return merge_data_and_start_syncing_error_; +} + +void FakeSyncableService::StopSyncing(syncable::ModelType type) { + syncing_ = false; + sync_processor_.reset(); +} + +SyncDataList FakeSyncableService::GetAllSyncData( + syncable::ModelType type) const { + return SyncDataList(); +} + +SyncError FakeSyncableService::ProcessSyncChanges( + const tracked_objects::Location& from_here, + const SyncChangeList& change_list) { + return process_sync_changes_error_; +} diff --git a/sync/api/fake_syncable_service.h b/sync/api/fake_syncable_service.h new file mode 100644 index 0000000..9f10a65 --- /dev/null +++ b/sync/api/fake_syncable_service.h @@ -0,0 +1,48 @@ +// Copyright (c) 2012 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 SYNC_API_FAKE_SYNCABLE_SERVICE_H_ +#define SYNC_API_FAKE_SYNCABLE_SERVICE_H_ +#pragma once + +#include "sync/api/syncable_service.h" + +class SyncErrorFactory; + +// A fake SyncableService that can return arbitrary values and maintains the +// syncing status. +class FakeSyncableService : public SyncableService { + public: + FakeSyncableService(); + virtual ~FakeSyncableService(); + + // Setters for SyncableService implementation results. + void set_merge_data_and_start_syncing_error(const SyncError& error); + void set_process_sync_changes_error(const SyncError& error); + + // Whether we're syncing or not. Set on a successful MergeDataAndStartSyncing, + // unset on StopSyncing. False by default. + bool syncing() const; + + // SyncableService implementation. + virtual SyncError MergeDataAndStartSyncing( + syncable::ModelType type, + const SyncDataList& initial_sync_data, + scoped_ptr<SyncChangeProcessor> sync_processor, + scoped_ptr<SyncErrorFactory> sync_error_factory) OVERRIDE; + virtual void StopSyncing(syncable::ModelType type) OVERRIDE; + virtual SyncDataList GetAllSyncData(syncable::ModelType type) const OVERRIDE; + virtual SyncError ProcessSyncChanges( + const tracked_objects::Location& from_here, + const SyncChangeList& change_list) OVERRIDE; + + private: + scoped_ptr<SyncChangeProcessor> sync_processor_; + SyncError merge_data_and_start_syncing_error_; + SyncError process_sync_changes_error_; + bool syncing_; + syncable::ModelType type_; +}; + +#endif // SYNC_API_FAKE_SYNCABLE_SERVICE_H_ diff --git a/sync/api/sync_change.cc b/sync/api/sync_change.cc new file mode 100644 index 0000000..627c19b --- /dev/null +++ b/sync/api/sync_change.cc @@ -0,0 +1,73 @@ +// Copyright (c) 2012 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 "sync/api/sync_change.h" + +#include <ostream> + +SyncChange::SyncChange() : change_type_(ACTION_INVALID) { +} + +SyncChange::SyncChange(SyncChangeType change_type, const SyncData& sync_data) + : change_type_(change_type), + sync_data_(sync_data) { + DCHECK(IsValid()); +} + +SyncChange::~SyncChange() {} + +bool SyncChange::IsValid() const { + if (change_type_ == ACTION_INVALID || !sync_data_.IsValid()) + return false; + + // Data from the syncer must always have valid specifics. + if (!sync_data_.IsLocal()) + return syncable::IsRealDataType(sync_data_.GetDataType()); + + // Local changes must always have a tag and specify a valid datatype. + if (sync_data_.GetTag().empty() || + !syncable::IsRealDataType(sync_data_.GetDataType())) { + return false; + } + + // Adds and updates must have a non-unique-title. + if (change_type_ == ACTION_ADD || change_type_ == ACTION_UPDATE) + return (!sync_data_.GetTitle().empty()); + + return true; +} + +SyncChange::SyncChangeType SyncChange::change_type() const { + return change_type_; +} + +SyncData SyncChange::sync_data() const { + return sync_data_; +} + +// static +std::string SyncChange::ChangeTypeToString(SyncChangeType change_type) { + switch (change_type) { + case ACTION_INVALID: + return "ACTION_INVALID"; + case ACTION_ADD: + return "ACTION_ADD"; + case ACTION_UPDATE: + return "ACTION_UPDATE"; + case ACTION_DELETE: + return "ACTION_DELETE"; + default: + NOTREACHED(); + } + return std::string(); +} + +std::string SyncChange::ToString() const { + return "{ changeType: " + ChangeTypeToString(change_type_) + + ", syncData: " + sync_data_.ToString() + "}"; +} + +void PrintTo(const SyncChange& sync_change, std::ostream* os) { + *os << sync_change.ToString(); +} diff --git a/sync/api/sync_change.h b/sync/api/sync_change.h new file mode 100644 index 0000000..19218f5 --- /dev/null +++ b/sync/api/sync_change.h @@ -0,0 +1,67 @@ +// Copyright (c) 2012 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 SYNC_API_SYNC_CHANGE_H_ +#define SYNC_API_SYNC_CHANGE_H_ +#pragma once + +#include <iosfwd> +#include <string> +#include <vector> + +#include "sync/api/sync_data.h" + +// A SyncChange object reflects a change to a piece of synced data. The change +// can be either a delete, add, or an update. All data relevant to the change +// is encapsulated within the SyncChange, which, once created, is immutable. +// Note: it is safe and cheap to pass these by value or make copies, as they do +// not create deep copies of their internal data. +class SyncChange { + public: + enum SyncChangeType { + ACTION_INVALID, + ACTION_ADD, + ACTION_UPDATE, + ACTION_DELETE + }; + + // Default constructor creates an invalid change. + SyncChange(); + // Create a new change with the specified sync data. + SyncChange(SyncChangeType change_type, const SyncData& sync_data); + ~SyncChange(); + + // Copy constructor and assignment operator welcome. + + // Whether this change is valid. This must be true before attempting to access + // the data. + // Deletes: Requires valid tag when going to the syncer. Requires valid + // specifics when coming from the syncer. + // Adds, Updates: Require valid tag and specifics when going to the syncer. + // Require only valid specifics when coming from the syncer. + bool IsValid() const; + + // Getters. + SyncChangeType change_type() const; + SyncData sync_data() const; + + // Returns a string representation of |change_type|. + static std::string ChangeTypeToString(SyncChangeType change_type); + + // Returns a string representation of the entire object. Used for gmock + // printing method, PrintTo. + std::string ToString() const; + + private: + SyncChangeType change_type_; + + // An immutable container for the data of this SyncChange. Whenever + // SyncChanges are copied, they copy references to this data. + SyncData sync_data_; +}; + +// gmock printer helper. +void PrintTo(const SyncChange& sync_change, std::ostream* os); + +#endif // SYNC_API_SYNC_CHANGE_H_ diff --git a/sync/api/sync_change_processor.cc b/sync/api/sync_change_processor.cc new file mode 100644 index 0000000..74e6401 --- /dev/null +++ b/sync/api/sync_change_processor.cc @@ -0,0 +1,9 @@ +// Copyright (c) 2012 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 "sync/api/sync_change_processor.h" + +SyncChangeProcessor::SyncChangeProcessor() {} + +SyncChangeProcessor::~SyncChangeProcessor() {} diff --git a/sync/api/sync_change_processor.h b/sync/api/sync_change_processor.h new file mode 100644 index 0000000..1eed159 --- /dev/null +++ b/sync/api/sync_change_processor.h @@ -0,0 +1,40 @@ +// Copyright (c) 2012 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 SYNC_API_SYNC_CHANGE_PROCESSOR_H_ +#define SYNC_API_SYNC_CHANGE_PROCESSOR_H_ +#pragma once + +#include <vector> + +#include "sync/api/sync_error.h" + +class SyncChange; + +namespace tracked_objects { +class Location; +} // namespace tracked_objects + +typedef std::vector<SyncChange> SyncChangeList; + +// An interface for services that handle receiving SyncChanges. +class SyncChangeProcessor { + public: + SyncChangeProcessor(); + virtual ~SyncChangeProcessor(); + + // Process a list of SyncChanges. + // Returns: A default SyncError (IsSet() == false) if no errors were + // encountered, and a filled SyncError (IsSet() == true) + // otherwise. + // Inputs: + // |from_here|: allows tracking of where sync changes originate. + // |change_list|: is the list of sync changes in need of processing. + virtual SyncError ProcessSyncChanges( + const tracked_objects::Location& from_here, + const SyncChangeList& change_list) = 0; + protected: +}; + +#endif // SYNC_API_SYNC_CHANGE_PROCESSOR_H_ diff --git a/sync/api/sync_change_unittest.cc b/sync/api/sync_change_unittest.cc new file mode 100644 index 0000000..263abdd --- /dev/null +++ b/sync/api/sync_change_unittest.cc @@ -0,0 +1,130 @@ +// Copyright (c) 2012 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 "sync/api/sync_change.h" + +#include <string> + +#include "base/memory/scoped_ptr.h" +#include "base/values.h" +#include "sync/protocol/preference_specifics.pb.h" +#include "sync/protocol/proto_value_conversions.h" +#include "sync/protocol/sync.pb.h" +#include "testing/gtest/include/gtest/gtest.h" + +using browser_sync::EntitySpecificsToValue; + +// Ordered list of SyncChange's. +typedef std::vector<SyncChange> SyncChangeList; + +namespace { + +typedef testing::Test SyncChangeTest; + +TEST_F(SyncChangeTest, LocalDelete) { + SyncChange::SyncChangeType change_type = SyncChange::ACTION_DELETE; + std::string tag = "client_tag"; + SyncChange e(change_type, + SyncData::CreateLocalDelete(tag, syncable::PREFERENCES)); + EXPECT_EQ(change_type, e.change_type()); + EXPECT_EQ(tag, e.sync_data().GetTag()); + EXPECT_EQ(syncable::PREFERENCES, e.sync_data().GetDataType()); +} + +TEST_F(SyncChangeTest, LocalUpdate) { + SyncChange::SyncChangeType change_type = SyncChange::ACTION_UPDATE; + sync_pb::EntitySpecifics specifics; + sync_pb::PreferenceSpecifics* pref_specifics = specifics.mutable_preference(); + pref_specifics->set_name("test"); + std::string tag = "client_tag"; + std::string title = "client_title"; + SyncChange e(change_type, + SyncData::CreateLocalData(tag, title, specifics)); + EXPECT_EQ(change_type, e.change_type()); + EXPECT_EQ(tag, e.sync_data().GetTag()); + EXPECT_EQ(title, e.sync_data().GetTitle()); + EXPECT_EQ(syncable::PREFERENCES, e.sync_data().GetDataType()); + scoped_ptr<DictionaryValue> ref_spec(EntitySpecificsToValue(specifics)); + scoped_ptr<DictionaryValue> e_spec(EntitySpecificsToValue( + e.sync_data().GetSpecifics())); + EXPECT_TRUE(ref_spec->Equals(e_spec.get())); +} + +TEST_F(SyncChangeTest, LocalAdd) { + SyncChange::SyncChangeType change_type = SyncChange::ACTION_ADD; + sync_pb::EntitySpecifics specifics; + sync_pb::PreferenceSpecifics* pref_specifics = specifics.mutable_preference(); + pref_specifics->set_name("test"); + std::string tag = "client_tag"; + std::string title = "client_title"; + SyncChange e(change_type, + SyncData::CreateLocalData(tag, title, specifics)); + EXPECT_EQ(change_type, e.change_type()); + EXPECT_EQ(tag, e.sync_data().GetTag()); + EXPECT_EQ(title, e.sync_data().GetTitle()); + EXPECT_EQ(syncable::PREFERENCES, e.sync_data().GetDataType()); + scoped_ptr<DictionaryValue> ref_spec(EntitySpecificsToValue(specifics)); + scoped_ptr<DictionaryValue> e_spec(EntitySpecificsToValue( + e.sync_data().GetSpecifics())); + EXPECT_TRUE(ref_spec->Equals(e_spec.get())); +} + +TEST_F(SyncChangeTest, SyncerChanges) { + SyncChangeList change_list; + + // Create an update. + sync_pb::EntitySpecifics update_specifics; + sync_pb::PreferenceSpecifics* pref_specifics = + update_specifics.mutable_preference(); + pref_specifics->set_name("update"); + change_list.push_back(SyncChange( + SyncChange::ACTION_UPDATE, + SyncData::CreateRemoteData(1, update_specifics))); + + // Create an add. + sync_pb::EntitySpecifics add_specifics; + pref_specifics = add_specifics.mutable_preference(); + pref_specifics->set_name("add"); + change_list.push_back(SyncChange( + SyncChange::ACTION_ADD, + SyncData::CreateRemoteData(2, add_specifics))); + + // Create a delete. + sync_pb::EntitySpecifics delete_specifics; + pref_specifics = delete_specifics.mutable_preference(); + pref_specifics->set_name("add"); + change_list.push_back(SyncChange( + SyncChange::ACTION_DELETE, + SyncData::CreateRemoteData(3, delete_specifics))); + + ASSERT_EQ(3U, change_list.size()); + + // Verify update. + SyncChange e = change_list[0]; + EXPECT_EQ(SyncChange::ACTION_UPDATE, e.change_type()); + EXPECT_EQ(syncable::PREFERENCES, e.sync_data().GetDataType()); + scoped_ptr<DictionaryValue> ref_spec(EntitySpecificsToValue( + update_specifics)); + scoped_ptr<DictionaryValue> e_spec(EntitySpecificsToValue( + e.sync_data().GetSpecifics())); + EXPECT_TRUE(ref_spec->Equals(e_spec.get())); + + // Verify add. + e = change_list[1]; + EXPECT_EQ(SyncChange::ACTION_ADD, e.change_type()); + EXPECT_EQ(syncable::PREFERENCES, e.sync_data().GetDataType()); + ref_spec.reset(EntitySpecificsToValue(add_specifics)); + e_spec.reset(EntitySpecificsToValue(e.sync_data().GetSpecifics())); + EXPECT_TRUE(ref_spec->Equals(e_spec.get())); + + // Verify delete. + e = change_list[2]; + EXPECT_EQ(SyncChange::ACTION_DELETE, e.change_type()); + EXPECT_EQ(syncable::PREFERENCES, e.sync_data().GetDataType()); + ref_spec.reset(EntitySpecificsToValue(delete_specifics)); + e_spec.reset(EntitySpecificsToValue(e.sync_data().GetSpecifics())); + EXPECT_TRUE(ref_spec->Equals(e_spec.get())); +} + +} // namespace diff --git a/sync/api/sync_data.cc b/sync/api/sync_data.cc new file mode 100644 index 0000000..679c547 --- /dev/null +++ b/sync/api/sync_data.cc @@ -0,0 +1,140 @@ +// Copyright (c) 2012 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 "sync/api/sync_data.h" + +#include <ostream> + +#include "base/json/json_writer.h" +#include "base/memory/scoped_ptr.h" +#include "base/string_number_conversions.h" +#include "base/values.h" +#include "sync/internal_api/base_node.h" +#include "sync/protocol/proto_value_conversions.h" +#include "sync/protocol/sync.pb.h" +#include "sync/syncable/model_type.h" + +void SyncData::ImmutableSyncEntityTraits::InitializeWrapper( + Wrapper* wrapper) { + *wrapper = new sync_pb::SyncEntity(); +} + +void SyncData::ImmutableSyncEntityTraits::DestroyWrapper( + Wrapper* wrapper) { + delete *wrapper; +} + +const sync_pb::SyncEntity& SyncData::ImmutableSyncEntityTraits::Unwrap( + const Wrapper& wrapper) { + return *wrapper; +} + +sync_pb::SyncEntity* SyncData::ImmutableSyncEntityTraits::UnwrapMutable( + Wrapper* wrapper) { + return *wrapper; +} + +void SyncData::ImmutableSyncEntityTraits::Swap(sync_pb::SyncEntity* t1, + sync_pb::SyncEntity* t2) { + t1->Swap(t2); +} + +SyncData::SyncData() + : is_valid_(false), + id_(sync_api::kInvalidId) {} + +SyncData::SyncData(int64 id, sync_pb::SyncEntity* entity) + : is_valid_(true), + id_(id), + immutable_entity_(entity) {} + +SyncData::~SyncData() {} + +// Static. +SyncData SyncData::CreateLocalDelete( + const std::string& sync_tag, + syncable::ModelType datatype) { + sync_pb::EntitySpecifics specifics; + syncable::AddDefaultFieldValue(datatype, &specifics); + return CreateLocalData(sync_tag, "", specifics); +} + +// Static. +SyncData SyncData::CreateLocalData( + const std::string& sync_tag, + const std::string& non_unique_title, + const sync_pb::EntitySpecifics& specifics) { + sync_pb::SyncEntity entity; + entity.set_client_defined_unique_tag(sync_tag); + entity.set_non_unique_name(non_unique_title); + entity.mutable_specifics()->CopyFrom(specifics); + return SyncData(sync_api::kInvalidId, &entity); +} + +// Static. +SyncData SyncData::CreateRemoteData( + int64 id, const sync_pb::EntitySpecifics& specifics) { + DCHECK_NE(id, sync_api::kInvalidId); + sync_pb::SyncEntity entity; + entity.mutable_specifics()->CopyFrom(specifics); + return SyncData(id, &entity); +} + +bool SyncData::IsValid() const { + return is_valid_; +} + +const sync_pb::EntitySpecifics& SyncData::GetSpecifics() const { + return immutable_entity_.Get().specifics(); +} + +syncable::ModelType SyncData::GetDataType() const { + return syncable::GetModelTypeFromSpecifics(GetSpecifics()); +} + +const std::string& SyncData::GetTag() const { + DCHECK(IsLocal()); + return immutable_entity_.Get().client_defined_unique_tag(); +} + +const std::string& SyncData::GetTitle() const { + // TODO(zea): set this for data coming from the syncer too. + DCHECK(immutable_entity_.Get().has_non_unique_name()); + return immutable_entity_.Get().non_unique_name(); +} + +int64 SyncData::GetRemoteId() const { + DCHECK(!IsLocal()); + return id_; +} + +bool SyncData::IsLocal() const { + return id_ == sync_api::kInvalidId; +} + +std::string SyncData::ToString() const { + if (!IsValid()) + return "<Invalid SyncData>"; + + std::string type = syncable::ModelTypeToString(GetDataType()); + std::string specifics; + scoped_ptr<DictionaryValue> value( + browser_sync::EntitySpecificsToValue(GetSpecifics())); + base::JSONWriter::WriteWithOptions(value.get(), + base::JSONWriter::OPTIONS_PRETTY_PRINT, + &specifics); + + if (IsLocal()) { + return "{ isLocal: true, type: " + type + ", tag: " + GetTag() + + ", title: " + GetTitle() + ", specifics: " + specifics + "}"; + } + + std::string id = base::Int64ToString(GetRemoteId()); + return "{ isLocal: false, type: " + type + ", specifics: " + specifics + + ", id: " + id + "}"; +} + +void PrintTo(const SyncData& sync_data, std::ostream* os) { + *os << sync_data.ToString(); +} diff --git a/sync/api/sync_data.h b/sync/api/sync_data.h new file mode 100644 index 0000000..cef132b --- /dev/null +++ b/sync/api/sync_data.h @@ -0,0 +1,121 @@ +// Copyright (c) 2012 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 SYNC_API_SYNC_DATA_H_ +#define SYNC_API_SYNC_DATA_H_ +#pragma once + +#include <iosfwd> +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "sync/syncable/model_type.h" +#include "sync/util/immutable.h" + +namespace sync_pb { +class EntitySpecifics; +class SyncEntity; +} // namespace sync_pb + +typedef syncable::ModelType SyncDataType; + +// A light-weight container for immutable sync data. Pass-by-value and storage +// in STL containers are supported and encouraged if helpful. +class SyncData { + public: + // Creates an empty and invalid SyncData. + SyncData(); + ~SyncData(); + + // Default copy and assign welcome. + + // Helper methods for creating SyncData objects for local data. + // The sync tag must be a string unique to this datatype and is used as a node + // identifier server-side. + // For deletes: |datatype| must specify the datatype who node is being + // deleted. + // For adds/updates: the specifics must be valid and the non-unique title (can + // be the same as sync tag) must be specfied. + // Note: the non_unique_title is primarily for debug purposes, and will be + // overwritten if the datatype is encrypted. + static SyncData CreateLocalDelete( + const std::string& sync_tag, + syncable::ModelType datatype); + static SyncData CreateLocalData( + const std::string& sync_tag, + const std::string& non_unique_title, + const sync_pb::EntitySpecifics& specifics); + + // Helper method for creating SyncData objects originating from the syncer. + static SyncData CreateRemoteData( + int64 id, const sync_pb::EntitySpecifics& specifics); + + // Whether this SyncData holds valid data. The only way to have a SyncData + // without valid data is to use the default constructor. + bool IsValid() const; + + // Return the datatype we're holding information about. Derived from the sync + // datatype specifics. + SyncDataType GetDataType() const; + + // Return the current sync datatype specifics. + const sync_pb::EntitySpecifics& GetSpecifics() const; + + // Returns the value of the unique client tag. This is only set for data going + // TO the syncer, not coming from. + const std::string& GetTag() const; + + // Returns the non unique title (for debugging). Currently only set for data + // going TO the syncer, not from. + const std::string& GetTitle() const; + + // Should only be called by sync code when IsLocal() is false. + int64 GetRemoteId() const; + + // Whether this sync data is for local data or data coming from the syncer. + bool IsLocal() const; + + std::string ToString() const; + + // TODO(zea): Query methods for other sync properties: parent, successor, etc. + + private: + // Necessary since we forward-declare sync_pb::SyncEntity; see + // comments in immutable.h. + struct ImmutableSyncEntityTraits { + typedef sync_pb::SyncEntity* Wrapper; + + static void InitializeWrapper(Wrapper* wrapper); + + static void DestroyWrapper(Wrapper* wrapper); + + static const sync_pb::SyncEntity& Unwrap(const Wrapper& wrapper); + + static sync_pb::SyncEntity* UnwrapMutable(Wrapper* wrapper); + + static void Swap(sync_pb::SyncEntity* t1, sync_pb::SyncEntity* t2); + }; + + typedef browser_sync::Immutable< + sync_pb::SyncEntity, ImmutableSyncEntityTraits> + ImmutableSyncEntity; + + // Clears |entity|. + SyncData(int64 id, sync_pb::SyncEntity* entity); + + // Whether this SyncData holds valid data. + bool is_valid_; + + // Equal to sync_api::kInvalidId iff this is local. + int64 id_; + + // The actual shared sync entity being held. + ImmutableSyncEntity immutable_entity_; +}; + +// gmock printer helper. +void PrintTo(const SyncData& sync_data, std::ostream* os); + +#endif // SYNC_API_SYNC_DATA_H_ diff --git a/sync/api/sync_error.cc b/sync/api/sync_error.cc new file mode 100644 index 0000000..49bf74b --- /dev/null +++ b/sync/api/sync_error.cc @@ -0,0 +1,108 @@ +// Copyright (c) 2012 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 "sync/api/sync_error.h" + +#include <ostream> + +#include "base/location.h" +#include "base/logging.h" +#include "sync/syncable/model_type.h" + +SyncError::SyncError() { + Clear(); +} + +SyncError::SyncError(const tracked_objects::Location& location, + const std::string& message, + syncable::ModelType type) { + Init(location, message, type); + PrintLogError(); +} + +SyncError::SyncError(const SyncError& other) { + Copy(other); +} + +SyncError::~SyncError() { +} + +SyncError& SyncError::operator=(const SyncError& other) { + if (this == &other) { + return *this; + } + Copy(other); + return *this; +} + +void SyncError::Copy(const SyncError& other) { + if (other.IsSet()) { + Init(other.location(), + other.message(), + other.type()); + } else { + Clear(); + } +} + +void SyncError::Clear() { + location_.reset(); + message_ = std::string(); + type_ = syncable::UNSPECIFIED; +} + +void SyncError::Reset(const tracked_objects::Location& location, + const std::string& message, + syncable::ModelType type) { + Init(location, message, type); + PrintLogError(); +} + +void SyncError::Init(const tracked_objects::Location& location, + const std::string& message, + syncable::ModelType type) { + location_.reset(new tracked_objects::Location(location)); + message_ = message; + type_ = type; +} + +bool SyncError::IsSet() const { + return location_.get() != NULL; +} + + +const tracked_objects::Location& SyncError::location() const { + CHECK(IsSet()); + return *location_; +} + +const std::string& SyncError::message() const { + CHECK(IsSet()); + return message_; +} + +syncable::ModelType SyncError::type() const { + CHECK(IsSet()); + return type_; +} + +std::string SyncError::ToString() const { + if (!IsSet()) { + return std::string(); + } + return location_->ToString() + ", " + syncable::ModelTypeToString(type_) + + ", Sync Error: " + message_; +} + +void SyncError::PrintLogError() const { + LAZY_STREAM(logging::LogMessage(location_->file_name(), + location_->line_number(), + logging::LOG_ERROR).stream(), + LOG_IS_ON(ERROR)) + << syncable::ModelTypeToString(type_) << ", Sync Error: " << message_; +} + +void PrintTo(const SyncError& sync_error, std::ostream* os) { + *os << sync_error.ToString(); +} diff --git a/sync/api/sync_error.h b/sync/api/sync_error.h new file mode 100644 index 0000000..2b6dc93 --- /dev/null +++ b/sync/api/sync_error.h @@ -0,0 +1,85 @@ +// Copyright (c) 2012 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 SYNC_API_SYNC_ERROR_H_ +#define SYNC_API_SYNC_ERROR_H_ +#pragma once + +#include <iosfwd> +#include <string> + +#include "base/memory/scoped_ptr.h" +#include "sync/syncable/model_type.h" + +namespace tracked_objects { +class Location; +} // namespace tracked_objects + +// Sync errors are used for debug purposes and handled internally and/or +// exposed through Chrome's "about:sync" internal page. They are considered +// unrecoverable for the datatype creating them, and should only be used as +// such. +// This class is copy-friendly and thread-safe. +class SyncError { + public: + // Default constructor refers to "no error", and IsSet() will return false. + SyncError(); + + // Create a new Sync error triggered by datatype |type| with debug message + // |message| from the specified location. IsSet() will return true. + // Will print the new error to LOG(ERROR). + SyncError(const tracked_objects::Location& location, + const std::string& message, + syncable::ModelType type); + + // Copy and assign via deep copy. + SyncError(const SyncError& other); + SyncError& operator=(const SyncError& other); + + ~SyncError(); + + // Reset the current error to a new error. May be called irrespective of + // whether IsSet() is true. After this is called, IsSet() will return true. + // Will print the new error to LOG(ERROR). + void Reset(const tracked_objects::Location& location, + const std::string& message, + syncable::ModelType type); + + // Whether this is a valid error or not. + bool IsSet() const; + + // These must only be called if IsSet() is true. + const tracked_objects::Location& location() const; + const std::string& message() const; + syncable::ModelType type() const; + + // Returns empty string is IsSet() is false. + std::string ToString() const; + private: + // Print error information to log. + void PrintLogError() const; + + // Make a copy of a SyncError. If other.IsSet() == false, this->IsSet() will + // now return false. + void Copy(const SyncError& other); + + // Initialize the local error data with the specified error data. After this + // is called, IsSet() will return true. + void Init(const tracked_objects::Location& location, + const std::string& message, + syncable::ModelType type); + + // Reset the error to it's default (unset) values. + void Clear(); + + // scoped_ptr is necessary because Location objects aren't assignable. + scoped_ptr<tracked_objects::Location> location_; + std::string message_; + syncable::ModelType type_; +}; + +// gmock printer helper. +void PrintTo(const SyncError& sync_error, std::ostream* os); + +#endif // SYNC_API_SYNC_ERROR_H_ diff --git a/sync/api/sync_error_factory.cc b/sync/api/sync_error_factory.cc new file mode 100644 index 0000000..0e9b451 --- /dev/null +++ b/sync/api/sync_error_factory.cc @@ -0,0 +1,11 @@ +// Copyright (c) 2012 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 "sync/api/sync_error_factory.h" + +SyncErrorFactory::SyncErrorFactory() { +} + +SyncErrorFactory::~SyncErrorFactory() { +} diff --git a/sync/api/sync_error_factory.h b/sync/api/sync_error_factory.h new file mode 100644 index 0000000..72f317e --- /dev/null +++ b/sync/api/sync_error_factory.h @@ -0,0 +1,26 @@ +// Copyright (c) 2012 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 SYNC_API_SYNC_ERROR_FACTORY_H_ +#define SYNC_API_SYNC_ERROR_FACTORY_H_ +#pragma once + +#include <string> + +#include "base/location.h" +#include "sync/api/sync_error.h" + +class SyncErrorFactory { + public: + SyncErrorFactory(); + virtual ~SyncErrorFactory(); + + // Creates a SyncError object and uploads this call stack to breakpad. + virtual SyncError CreateAndUploadError( + const tracked_objects::Location& location, + const std::string& message) = 0; +}; + +#endif // SYNC_API_SYNC_ERROR_FACTORY_H_ + diff --git a/sync/api/sync_error_factory_mock.cc b/sync/api/sync_error_factory_mock.cc new file mode 100644 index 0000000..e730b88 --- /dev/null +++ b/sync/api/sync_error_factory_mock.cc @@ -0,0 +1,12 @@ +// Copyright (c) 2012 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 "sync/api/sync_error_factory_mock.h" + +SyncErrorFactoryMock::SyncErrorFactoryMock() { +} + +SyncErrorFactoryMock::~SyncErrorFactoryMock() { +} + diff --git a/sync/api/sync_error_factory_mock.h b/sync/api/sync_error_factory_mock.h new file mode 100644 index 0000000..6fc58074 --- /dev/null +++ b/sync/api/sync_error_factory_mock.h @@ -0,0 +1,23 @@ +// Copyright (c) 2012 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 SYNC_API_SYNC_ERROR_FACTORY_MOCK_H_ +#define SYNC_API_SYNC_ERROR_FACTORY_MOCK_H_ +#pragma once + +#include "sync/api/sync_error_factory.h" + +#include "testing/gmock/include/gmock/gmock.h" + +class SyncErrorFactoryMock : public SyncErrorFactory { + public: + SyncErrorFactoryMock(); + virtual ~SyncErrorFactoryMock(); + + MOCK_METHOD2(CreateAndUploadError, SyncError( + const tracked_objects::Location& location, + const std::string& message)); +}; + +#endif // SYNC_API_SYNC_ERROR_FACTORY_MOCK_H_ diff --git a/sync/api/sync_error_unittest.cc b/sync/api/sync_error_unittest.cc new file mode 100644 index 0000000..c700db55 --- /dev/null +++ b/sync/api/sync_error_unittest.cc @@ -0,0 +1,132 @@ +// Copyright (c) 2012 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 "sync/api/sync_error.h" + +#include <string> + +#include "base/location.h" +#include "testing/gtest/include/gtest/gtest.h" + +using std::string; +using syncable::ModelType; + +namespace { + +typedef testing::Test SyncErrorTest; + +TEST_F(SyncErrorTest, Unset) { + SyncError error; + EXPECT_FALSE(error.IsSet()); +} + +TEST_F(SyncErrorTest, Default) { + tracked_objects::Location location = FROM_HERE; + std::string msg = "test"; + ModelType type = syncable::PREFERENCES; + SyncError error(location, msg, type); + ASSERT_TRUE(error.IsSet()); + EXPECT_EQ(location.line_number(), error.location().line_number()); + EXPECT_EQ(msg, error.message()); + EXPECT_EQ(type, error.type()); +} + +TEST_F(SyncErrorTest, Reset) { + tracked_objects::Location location = FROM_HERE; + std::string msg = "test"; + ModelType type = syncable::PREFERENCES; + + SyncError error; + EXPECT_FALSE(error.IsSet()); + + error.Reset(location, msg, type); + ASSERT_TRUE(error.IsSet()); + EXPECT_EQ(location.line_number(), error.location().line_number()); + EXPECT_EQ(msg, error.message()); + EXPECT_EQ(type, error.type()); + + tracked_objects::Location location2 = FROM_HERE; + std::string msg2 = "test"; + ModelType type2 = syncable::PREFERENCES; + error.Reset(location2, msg2, type2); + ASSERT_TRUE(error.IsSet()); + EXPECT_EQ(location2.line_number(), error.location().line_number()); + EXPECT_EQ(msg2, error.message()); + EXPECT_EQ(type2, error.type()); +} + +TEST_F(SyncErrorTest, Copy) { + tracked_objects::Location location = FROM_HERE; + std::string msg = "test"; + ModelType type = syncable::PREFERENCES; + + SyncError error1; + EXPECT_FALSE(error1.IsSet()); + SyncError error2(error1); + EXPECT_FALSE(error2.IsSet()); + + error1.Reset(location, msg, type); + ASSERT_TRUE(error1.IsSet()); + EXPECT_EQ(location.line_number(), error1.location().line_number()); + EXPECT_EQ(msg, error1.message()); + EXPECT_EQ(type, error1.type()); + + SyncError error3(error1); + ASSERT_TRUE(error3.IsSet()); + EXPECT_EQ(error1.location().line_number(), error3.location().line_number()); + EXPECT_EQ(error1.message(), error3.message()); + EXPECT_EQ(error1.type(), error3.type()); + + SyncError error4; + EXPECT_FALSE(error4.IsSet()); + SyncError error5(error4); + EXPECT_FALSE(error5.IsSet()); +} + +TEST_F(SyncErrorTest, Assign) { + tracked_objects::Location location = FROM_HERE; + std::string msg = "test"; + ModelType type = syncable::PREFERENCES; + + SyncError error1; + EXPECT_FALSE(error1.IsSet()); + SyncError error2; + error2 = error1; + EXPECT_FALSE(error2.IsSet()); + + error1.Reset(location, msg, type); + ASSERT_TRUE(error1.IsSet()); + EXPECT_EQ(location.line_number(), error1.location().line_number()); + EXPECT_EQ(msg, error1.message()); + EXPECT_EQ(type, error1.type()); + + error2 = error1; + ASSERT_TRUE(error2.IsSet()); + EXPECT_EQ(error1.location().line_number(), error2.location().line_number()); + EXPECT_EQ(error1.message(), error2.message()); + EXPECT_EQ(error1.type(), error2.type()); + + error2 = SyncError(); + EXPECT_FALSE(error2.IsSet()); +} + +TEST_F(SyncErrorTest, ToString) { + tracked_objects::Location location = FROM_HERE; + std::string msg = "test"; + ModelType type = syncable::PREFERENCES; + std::string expected = "Preferences, Sync Error: test"; + SyncError error(location, msg, type); + EXPECT_TRUE(error.IsSet()); + EXPECT_NE(string::npos, error.ToString().find(expected)); + + SyncError error2; + EXPECT_FALSE(error2.IsSet()); + EXPECT_EQ(std::string(), error2.ToString()); + + error2 = error; + EXPECT_TRUE(error2.IsSet()); + EXPECT_NE(string::npos, error.ToString().find(expected)); +} + +} // namespace diff --git a/sync/api/syncable_service.cc b/sync/api/syncable_service.cc new file mode 100644 index 0000000..198173a --- /dev/null +++ b/sync/api/syncable_service.cc @@ -0,0 +1,7 @@ +// Copyright (c) 2012 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 "sync/api/syncable_service.h" + +SyncableService::~SyncableService() {} diff --git a/sync/api/syncable_service.h b/sync/api/syncable_service.h new file mode 100644 index 0000000..bfcab3a --- /dev/null +++ b/sync/api/syncable_service.h @@ -0,0 +1,65 @@ +// Copyright (c) 2012 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 SYNC_API_SYNCABLE_SERVICE_H_ +#define SYNC_API_SYNCABLE_SERVICE_H_ +#pragma once + +#include <vector> + +#include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "sync/api/sync_change_processor.h" +#include "sync/api/sync_data.h" +#include "sync/api/sync_error.h" +#include "sync/syncable/model_type.h" + +class SyncErrorFactory; + +typedef std::vector<SyncData> SyncDataList; + +// TODO(zea): remove SupportsWeakPtr in favor of having all SyncableService +// implementers provide a way of getting a weak pointer to themselves. +// See crbug.com/100114. +class SyncableService : public SyncChangeProcessor, + public base::SupportsWeakPtr<SyncableService> { + public: + // Informs the service to begin syncing the specified synced datatype |type|. + // The service should then merge |initial_sync_data| into it's local data, + // calling |sync_processor|'s ProcessSyncChanges as necessary to reconcile the + // two. After this, the SyncableService's local data should match the server + // data, and the service should be ready to receive and process any further + // SyncChange's as they occur. + // Returns: A default SyncError (IsSet() == false) if no errors were + // encountered, and a filled SyncError (IsSet() == true) + // otherwise. + virtual SyncError MergeDataAndStartSyncing( + syncable::ModelType type, + const SyncDataList& initial_sync_data, + scoped_ptr<SyncChangeProcessor> sync_processor, + scoped_ptr<SyncErrorFactory> error_handler) = 0; + + // Stop syncing the specified type and reset state. + virtual void StopSyncing(syncable::ModelType type) = 0; + + // Fills a list of SyncData from the local data. This should create an up + // to date representation of the SyncableService's view of that datatype, and + // should match/be a subset of the server's view of that datatype. + virtual SyncDataList GetAllSyncData(syncable::ModelType type) const = 0; + + // SyncChangeProcessor interface. + // Process a list of new SyncChanges and update the local data as necessary. + // Returns: A default SyncError (IsSet() == false) if no errors were + // encountered, and a filled SyncError (IsSet() == true) + // otherwise. + virtual SyncError ProcessSyncChanges( + const tracked_objects::Location& from_here, + const SyncChangeList& change_list) OVERRIDE = 0; + + protected: + virtual ~SyncableService(); +}; + +#endif // SYNC_API_SYNCABLE_SERVICE_H_ diff --git a/sync/sync.gyp b/sync/sync.gyp index 97d493e..ba97a47 100644 --- a/sync/sync.gyp +++ b/sync/sync.gyp @@ -299,6 +299,39 @@ ], }, + # The sync external API library. + { + 'target_name': 'syncapi_service', + 'type': 'static_library', + 'variables': { 'enable_wexit_time_destructors': 1, }, + 'include_dirs': [ + '..', + ], + 'dependencies': [ + '../base/base.gyp:base', + 'protocol/sync_proto.gyp:sync_proto', + 'sync', + ], + # Even though this target depends on sync_proto, it doesn't + # need to export a hard dependency since we explicitly avoid + # including the generated proto header files from this target's + # header files. + 'sources': [ + 'api/syncable_service.cc', + 'api/syncable_service.h', + 'api/sync_data.h', + 'api/sync_data.cc', + 'api/sync_change.h', + 'api/sync_change.cc', + 'api/sync_change_processor.h', + 'api/sync_change_processor.cc', + 'api/sync_error.h', + 'api/sync_error.cc', + 'api/sync_error_factory.h', + 'api/sync_error_factory.cc', + ], + }, + # Test support files for the 'sync' target. { 'target_name': 'test_support_sync', @@ -405,6 +438,29 @@ ], }, + # Test support files for the 'syncapi_service' target. + { + 'target_name': 'test_support_syncapi_service', + 'type': 'static_library', + 'include_dirs': [ + '..', + ], + 'dependencies': [ + '../testing/gmock.gyp:gmock', + 'syncapi_service', + ], + 'export_dependent_settings': [ + '../testing/gmock.gyp:gmock', + 'syncapi_service', + ], + 'sources': [ + 'api/fake_syncable_service.cc', + 'api/fake_syncable_service.h', + 'api/sync_error_factory_mock.cc', + 'api/sync_error_factory_mock.h', + ], + }, + # Unit tests for the 'sync' target. This cannot be a static # library because the unit test files have to be compiled directly # into the executable, so we push the target files to the @@ -593,6 +649,45 @@ }, }, + # Unit tests for the 'syncapi_service' target. This cannot be a static + # library because the unit test files have to be compiled directly + # into the executable, so we push the target files to the + # depending executable target via direct_dependent_settings. + { + 'target_name': 'syncapi_service_tests', + 'type': 'none', + # We only want unit test executables to include this target. + 'suppress_wildcard': 1, + 'dependencies': [ + '../base/base.gyp:base', + '../testing/gtest.gyp:gtest', + 'protocol/sync_proto.gyp:sync_proto', + 'sync', + 'syncapi_service', + 'test_support_syncapi_service', + ], + # Propagate all dependencies since the actual compilation + # happens in the dependents. + 'export_dependent_settings': [ + '../base/base.gyp:base', + '../testing/gtest.gyp:gtest', + 'protocol/sync_proto.gyp:sync_proto', + 'sync', + 'syncapi_service', + 'test_support_syncapi_service', + ], + 'direct_dependent_settings': { + 'variables': { 'enable_wexit_time_destructors': 1, }, + 'include_dirs': [ + '..', + ], + 'sources': [ + 'api/sync_change_unittest.cc', + 'api/sync_error_unittest.cc', + ], + }, + }, + # The unit test executable for sync tests. { 'target_name': 'sync_unit_tests', @@ -602,6 +697,7 @@ 'sync_tests', 'sync_notifier_tests', 'syncapi_core_tests', + 'syncapi_service_tests', ], # TODO(akalin): This is needed because histogram.cc uses # leak_annotations.h, which pulls this in. Make 'base' |