diff options
author | tim@chromium.org <tim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-07 17:50:19 +0000 |
---|---|---|
committer | tim@chromium.org <tim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-07 17:50:19 +0000 |
commit | 3f8556a0cf934ee6e2e4a37b22b05dbf0a9c4a90 (patch) | |
tree | dcb6050b16ce934a4102da5ac7f2d501ceb4e988 /sync/internal_api/public | |
parent | 03c1007443b4be55364755441c83a66ec12cff81 (diff) | |
download | chromium_src-3f8556a0cf934ee6e2e4a37b22b05dbf0a9c4a90.zip chromium_src-3f8556a0cf934ee6e2e4a37b22b05dbf0a9c4a90.tar.gz chromium_src-3f8556a0cf934ee6e2e4a37b22b05dbf0a9c4a90.tar.bz2 |
sync: create internal_api/public to house sync/ files needed by chrome/browser/sync.
Note on sync.gyp changes and .cc file moves: most files in /public have .h and their .cc side by side, as they are simple implementations. In some cases like model_type.cc (and others in a follow up patch, like sync_manager.cc) have only their header exposed in /public while the impl stays behind, because it needs to include things from within sync/, and /public has a strict include DEPS policy. This is in accordance with other /public folders (like content/).
Cleans up DEPS files in sync + c/b/sync. Adds sync/{engine, sessions, syncable} to public/. There is more to come (moving things in internal_api/ into public).
Not touching /notifier as that is in flux at the moment.
BUG=131130
TEST=
Review URL: https://chromiumcodereview.appspot.com/10532019
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@141038 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sync/internal_api/public')
26 files changed, 1859 insertions, 0 deletions
diff --git a/sync/internal_api/public/DEPS b/sync/internal_api/public/DEPS new file mode 100644 index 0000000..2a51ace --- /dev/null +++ b/sync/internal_api/public/DEPS @@ -0,0 +1,5 @@ +include_rules = [ + "-sync", + "+sync/internal_api/public", + "+sync/protocol", +] diff --git a/sync/internal_api/public/engine/model_safe_worker.cc b/sync/internal_api/public/engine/model_safe_worker.cc new file mode 100644 index 0000000..2718acc --- /dev/null +++ b/sync/internal_api/public/engine/model_safe_worker.cc @@ -0,0 +1,75 @@ +// 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/internal_api/public/engine/model_safe_worker.h" + +#include "base/json/json_writer.h" +#include "base/memory/scoped_ptr.h" +#include "base/values.h" + +namespace browser_sync { + +base::DictionaryValue* ModelSafeRoutingInfoToValue( + const ModelSafeRoutingInfo& routing_info) { + base::DictionaryValue* dict = new base::DictionaryValue(); + for (ModelSafeRoutingInfo::const_iterator it = routing_info.begin(); + it != routing_info.end(); ++it) { + dict->SetString(syncable::ModelTypeToString(it->first), + ModelSafeGroupToString(it->second)); + } + return dict; +} + +std::string ModelSafeRoutingInfoToString( + const ModelSafeRoutingInfo& routing_info) { + scoped_ptr<DictionaryValue> dict(ModelSafeRoutingInfoToValue(routing_info)); + std::string json; + base::JSONWriter::Write(dict.get(), &json); + return json; +} + +syncable::ModelTypeSet GetRoutingInfoTypes( + const ModelSafeRoutingInfo& routing_info) { + syncable::ModelTypeSet types; + for (ModelSafeRoutingInfo::const_iterator it = routing_info.begin(); + it != routing_info.end(); ++it) { + types.Put(it->first); + } + return types; +} + +ModelSafeGroup GetGroupForModelType(const syncable::ModelType type, + const ModelSafeRoutingInfo& routes) { + ModelSafeRoutingInfo::const_iterator it = routes.find(type); + if (it == routes.end()) { + if (type != syncable::UNSPECIFIED && type != syncable::TOP_LEVEL_FOLDER) + LOG(WARNING) << "Entry does not belong to active ModelSafeGroup!"; + return GROUP_PASSIVE; + } + return it->second; +} + +std::string ModelSafeGroupToString(ModelSafeGroup group) { + switch (group) { + case GROUP_UI: + return "GROUP_UI"; + case GROUP_DB: + return "GROUP_DB"; + case GROUP_FILE: + return "GROUP_FILE"; + case GROUP_HISTORY: + return "GROUP_HISTORY"; + case GROUP_PASSIVE: + return "GROUP_PASSIVE"; + case GROUP_PASSWORD: + return "GROUP_PASSWORD"; + default: + NOTREACHED(); + return "INVALID"; + } +} + +ModelSafeWorker::~ModelSafeWorker() {} + +} // namespace browser_sync diff --git a/sync/internal_api/public/engine/model_safe_worker.h b/sync/internal_api/public/engine/model_safe_worker.h new file mode 100644 index 0000000..1a6c371 --- /dev/null +++ b/sync/internal_api/public/engine/model_safe_worker.h @@ -0,0 +1,87 @@ +// 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_INTERNAL_API_PUBLIC_ENGINE_MODEL_SAFE_WORKER_H_ +#define SYNC_INTERNAL_API_PUBLIC_ENGINE_MODEL_SAFE_WORKER_H_ +#pragma once + +#include <map> +#include <string> +#include <vector> + +#include "base/callback.h" +#include "base/memory/ref_counted.h" +#include "sync/internal_api/public/syncable/model_type.h" +#include "sync/internal_api/public/util/syncer_error.h" + +namespace base { +class DictionaryValue; +} // namespace + +namespace browser_sync { + +typedef base::Callback<enum SyncerError(void)> WorkCallback; + +enum ModelSafeGroup { + GROUP_PASSIVE = 0, // Models that are just "passively" being synced; e.g. + // changes to these models don't need to be pushed to a + // native model. + GROUP_UI, // Models that live on UI thread and are being synced. + GROUP_DB, // Models that live on DB thread and are being synced. + GROUP_FILE, // Models that live on FILE thread and are being synced. + GROUP_HISTORY, // Models that live on history thread and are being + // synced. + GROUP_PASSWORD, // Models that live on the password thread and are + // being synced. On windows and linux, this runs on the + // DB thread. + MODEL_SAFE_GROUP_COUNT, +}; + +std::string ModelSafeGroupToString(ModelSafeGroup group); + +// The Syncer uses a ModelSafeWorker for all tasks that could potentially +// modify syncable entries (e.g under a WriteTransaction). The ModelSafeWorker +// only knows how to do one thing, and that is take some work (in a fully +// pre-bound callback) and have it performed (as in Run()) from a thread which +// is guaranteed to be "model-safe", where "safe" refers to not allowing us to +// cause an embedding application model to fall out of sync with the +// syncable::Directory due to a race. +class ModelSafeWorker : public base::RefCountedThreadSafe<ModelSafeWorker> { + public: + // Any time the Syncer performs model modifications (e.g employing a + // WriteTransaction), it should be done by this method to ensure it is done + // from a model-safe thread. + virtual SyncerError DoWorkAndWaitUntilDone(const WorkCallback& work) = 0; + + virtual ModelSafeGroup GetModelSafeGroup() = 0; + + protected: + virtual ~ModelSafeWorker(); + + private: + friend class base::RefCountedThreadSafe<ModelSafeWorker>; +}; + +// A map that details which ModelSafeGroup each syncable::ModelType +// belongs to. Routing info can change in response to the user enabling / +// disabling sync for certain types, as well as model association completions. +typedef std::map<syncable::ModelType, ModelSafeGroup> + ModelSafeRoutingInfo; + +// Caller takes ownership of return value. +base::DictionaryValue* ModelSafeRoutingInfoToValue( + const ModelSafeRoutingInfo& routing_info); + +std::string ModelSafeRoutingInfoToString( + const ModelSafeRoutingInfo& routing_info); + +syncable::ModelTypeSet GetRoutingInfoTypes( + const ModelSafeRoutingInfo& routing_info); + +ModelSafeGroup GetGroupForModelType(const syncable::ModelType type, + const ModelSafeRoutingInfo& routes); + +} // namespace browser_sync + +#endif // SYNC_INTERNAL_API_PUBLIC_ENGINE_MODEL_SAFE_WORKER_H_ diff --git a/sync/internal_api/public/engine/model_safe_worker_unittest.cc b/sync/internal_api/public/engine/model_safe_worker_unittest.cc new file mode 100644 index 0000000..5304c13 --- /dev/null +++ b/sync/internal_api/public/engine/model_safe_worker_unittest.cc @@ -0,0 +1,55 @@ +// 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/internal_api/public/engine/model_safe_worker.h" + +#include "base/memory/scoped_ptr.h" +#include "base/values.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace browser_sync { +namespace { + +class ModelSafeWorkerTest : public ::testing::Test { +}; + +TEST_F(ModelSafeWorkerTest, ModelSafeRoutingInfoToValue) { + ModelSafeRoutingInfo routing_info; + routing_info[syncable::BOOKMARKS] = GROUP_PASSIVE; + routing_info[syncable::NIGORI] = GROUP_UI; + routing_info[syncable::PREFERENCES] = GROUP_DB; + DictionaryValue expected_value; + expected_value.SetString("Bookmarks", "GROUP_PASSIVE"); + expected_value.SetString("Encryption keys", "GROUP_UI"); + expected_value.SetString("Preferences", "GROUP_DB"); + scoped_ptr<DictionaryValue> value( + ModelSafeRoutingInfoToValue(routing_info)); + EXPECT_TRUE(value->Equals(&expected_value)); +} + +TEST_F(ModelSafeWorkerTest, ModelSafeRoutingInfoToString) { + ModelSafeRoutingInfo routing_info; + routing_info[syncable::BOOKMARKS] = GROUP_PASSIVE; + routing_info[syncable::NIGORI] = GROUP_UI; + routing_info[syncable::PREFERENCES] = GROUP_DB; + EXPECT_EQ( + "{\"Bookmarks\":\"GROUP_PASSIVE\",\"Encryption keys\":\"GROUP_UI\"," + "\"Preferences\":\"GROUP_DB\"}", + ModelSafeRoutingInfoToString(routing_info)); +} + +TEST_F(ModelSafeWorkerTest, GetRoutingInfoTypes) { + ModelSafeRoutingInfo routing_info; + routing_info[syncable::BOOKMARKS] = GROUP_PASSIVE; + routing_info[syncable::NIGORI] = GROUP_UI; + routing_info[syncable::PREFERENCES] = GROUP_DB; + const syncable::ModelTypeSet expected_types( + syncable::BOOKMARKS, + syncable::NIGORI, + syncable::PREFERENCES); + EXPECT_TRUE(GetRoutingInfoTypes(routing_info).Equals(expected_types)); +} + +} // namespace +} // namespace browser_sync diff --git a/sync/internal_api/public/engine/passive_model_worker.cc b/sync/internal_api/public/engine/passive_model_worker.cc new file mode 100644 index 0000000..26fccc1 --- /dev/null +++ b/sync/internal_api/public/engine/passive_model_worker.cc @@ -0,0 +1,28 @@ +// 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/internal_api/public/engine/passive_model_worker.h" + +#include "base/message_loop.h" + +namespace browser_sync { + +PassiveModelWorker::PassiveModelWorker(const MessageLoop* sync_loop) + : sync_loop_(sync_loop) {} + +PassiveModelWorker::~PassiveModelWorker() { +} + +SyncerError PassiveModelWorker::DoWorkAndWaitUntilDone( + const WorkCallback& work) { + DCHECK_EQ(MessageLoop::current(), sync_loop_); + // Simply do the work on the current thread. + return work.Run(); +} + +ModelSafeGroup PassiveModelWorker::GetModelSafeGroup() { + return GROUP_PASSIVE; +} + +} // namespace browser_sync diff --git a/sync/internal_api/public/engine/passive_model_worker.h b/sync/internal_api/public/engine/passive_model_worker.h new file mode 100644 index 0000000..7c0ddf3 --- /dev/null +++ b/sync/internal_api/public/engine/passive_model_worker.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_INTERNAL_API_PUBLIC_ENGINE_PASSIVE_MODEL_WORKER_H_ +#define SYNC_INTERNAL_API_PUBLIC_ENGINE_PASSIVE_MODEL_WORKER_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "sync/internal_api/public/engine/model_safe_worker.h" +#include "sync/internal_api/public/util/syncer_error.h" + +class MessageLoop; + +namespace browser_sync { + +// Implementation of ModelSafeWorker for passive types. All work is +// done on the same thread DoWorkAndWaitUntilDone (i.e., the sync +// thread). +class PassiveModelWorker : public ModelSafeWorker { + public: + explicit PassiveModelWorker(const MessageLoop* sync_loop); + + // ModelSafeWorker implementation. Called on the sync thread. + virtual SyncerError DoWorkAndWaitUntilDone( + const WorkCallback& work) OVERRIDE; + virtual ModelSafeGroup GetModelSafeGroup() OVERRIDE; + + private: + virtual ~PassiveModelWorker(); + + const MessageLoop* const sync_loop_; + + DISALLOW_COPY_AND_ASSIGN(PassiveModelWorker); +}; + +} // namespace browser_sync + +#endif // SYNC_INTERNAL_API_PUBLIC_ENGINE_PASSIVE_MODEL_WORKER_H_ diff --git a/sync/internal_api/public/engine/polling_constants.cc b/sync/internal_api/public/engine/polling_constants.cc new file mode 100644 index 0000000..d7fe753 --- /dev/null +++ b/sync/internal_api/public/engine/polling_constants.cc @@ -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. + +#include "base/basictypes.h" +#include "sync/internal_api/public/engine/polling_constants.h" + +namespace browser_sync { + +// Server can overwrite these values via client commands. +// Standard short poll. This is used when XMPP is off. +// We use high values here to ensure that failure to receive poll updates from +// the server doesn't result in rapid-fire polling from the client due to low +// local limits. +const int64 kDefaultShortPollIntervalSeconds = 3600 * 8; +// Long poll is used when XMPP is on. +const int64 kDefaultLongPollIntervalSeconds = 3600 * 12; + +// Maximum interval for exponential backoff. +const int64 kMaxBackoffSeconds = 60 * 60 * 4; // 4 hours. + +// Backoff interval randomization factor. +const int kBackoffRandomizationFactor = 2; + +} // namespace browser_sync + diff --git a/sync/internal_api/public/engine/polling_constants.h b/sync/internal_api/public/engine/polling_constants.h new file mode 100644 index 0000000..9adfe92 --- /dev/null +++ b/sync/internal_api/public/engine/polling_constants.h @@ -0,0 +1,20 @@ +// 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. +// +// Constants used by SyncScheduler when polling servers for updates. + +#ifndef SYNC_INTERNAL_API_PUBLIC_ENGINE_POLLING_CONSTANTS_H_ +#define SYNC_INTERNAL_API_PUBLIC_ENGINE_POLLING_CONSTANTS_H_ +#pragma once + +namespace browser_sync { + +extern const int64 kDefaultShortPollIntervalSeconds; +extern const int64 kDefaultLongPollIntervalSeconds; +extern const int64 kMaxBackoffSeconds; +extern const int kBackoffRandomizationFactor; + +} // namespace browser_sync + +#endif // SYNC_INTERNAL_API_PUBLIC_ENGINE_POLLING_CONSTANTS_H_ diff --git a/sync/internal_api/public/sessions/error_counters.cc b/sync/internal_api/public/sessions/error_counters.cc new file mode 100644 index 0000000..72ed2d1 --- /dev/null +++ b/sync/internal_api/public/sessions/error_counters.cc @@ -0,0 +1,17 @@ +// 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/internal_api/public/sessions/error_counters.h" + +namespace browser_sync { +namespace sessions { + +ErrorCounters::ErrorCounters() + : last_download_updates_result(UNSET), + last_post_commit_result(UNSET), + last_process_commit_response_result(UNSET) { +} + +} // namespace sessions +} // namespace browser_sync diff --git a/sync/internal_api/public/sessions/error_counters.h b/sync/internal_api/public/sessions/error_counters.h new file mode 100644 index 0000000..a2f528c --- /dev/null +++ b/sync/internal_api/public/sessions/error_counters.h @@ -0,0 +1,33 @@ +// 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_INTERNAL_API_PUBLIC_SESSIONS_ERROR_COUNTERS_H_ +#define SYNC_INTERNAL_API_PUBLIC_SESSIONS_ERROR_COUNTERS_H_ +#pragma once + +#include "base/basictypes.h" +#include "sync/internal_api/public/util/syncer_error.h" +#include "sync/protocol/sync_protocol_error.h" + +namespace browser_sync { +namespace sessions { + +// Counters for various errors that can occur repeatedly during a sync session. +// TODO(lipalani) : Rename this structure to Error. +struct ErrorCounters { + ErrorCounters(); + + // Any protocol errors that we received during this sync session. + SyncProtocolError sync_protocol_error; + + // Records the most recent results of PostCommit and GetUpdates commands. + SyncerError last_download_updates_result; + SyncerError last_post_commit_result; + SyncerError last_process_commit_response_result; +}; + +} // namespace sessions +} // namespace browser_sync + +#endif // SYNC_INTERNAL_API_PUBLIC_SESSIONS_ERROR_COUNTERS_H_ diff --git a/sync/internal_api/public/sessions/sync_session_snapshot.cc b/sync/internal_api/public/sessions/sync_session_snapshot.cc new file mode 100644 index 0000000..d058a4f --- /dev/null +++ b/sync/internal_api/public/sessions/sync_session_snapshot.cc @@ -0,0 +1,173 @@ +// 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/internal_api/public/sessions/sync_session_snapshot.h" + +#include "base/json/json_writer.h" +#include "base/values.h" + +namespace browser_sync { +namespace sessions { + +SyncSessionSnapshot::SyncSessionSnapshot() + : num_server_changes_remaining_(0), + is_share_usable_(false), + has_more_to_sync_(false), + is_silenced_(false), + num_encryption_conflicts_(0), + num_hierarchy_conflicts_(0), + num_simple_conflicts_(0), + num_server_conflicts_(0), + notifications_enabled_(false), + num_entries_(0), + retry_scheduled_(false) { +} + +SyncSessionSnapshot::SyncSessionSnapshot( + const SyncerStatus& syncer_status, + const ErrorCounters& errors, + int64 num_server_changes_remaining, + bool is_share_usable, + syncable::ModelTypeSet initial_sync_ended, + const syncable::ModelTypePayloadMap& download_progress_markers, + bool more_to_sync, + bool is_silenced, + int num_encryption_conflicts, + int num_hierarchy_conflicts, + int num_simple_conflicts, + int num_server_conflicts, + const SyncSourceInfo& source, + bool notifications_enabled, + size_t num_entries, + base::Time sync_start_time, + bool retry_scheduled) + : syncer_status_(syncer_status), + errors_(errors), + num_server_changes_remaining_(num_server_changes_remaining), + is_share_usable_(is_share_usable), + initial_sync_ended_(initial_sync_ended), + download_progress_markers_(download_progress_markers), + has_more_to_sync_(more_to_sync), + is_silenced_(is_silenced), + num_encryption_conflicts_(num_encryption_conflicts), + num_hierarchy_conflicts_(num_hierarchy_conflicts), + num_simple_conflicts_(num_simple_conflicts), + num_server_conflicts_(num_server_conflicts), + source_(source), + notifications_enabled_(notifications_enabled), + num_entries_(num_entries), + sync_start_time_(sync_start_time), + retry_scheduled_(retry_scheduled) { +} + +SyncSessionSnapshot::~SyncSessionSnapshot() {} + +DictionaryValue* SyncSessionSnapshot::ToValue() const { + DictionaryValue* value = new DictionaryValue(); + value->Set("syncerStatus", syncer_status_.ToValue()); + // We don't care too much if we lose precision here. + value->SetInteger("numServerChangesRemaining", + static_cast<int>(num_server_changes_remaining_)); + value->SetBoolean("isShareUsable", is_share_usable_); + value->Set("initialSyncEnded", + syncable::ModelTypeSetToValue(initial_sync_ended_)); + value->Set("downloadProgressMarkers", + syncable::ModelTypePayloadMapToValue(download_progress_markers_)); + value->SetBoolean("hasMoreToSync", has_more_to_sync_); + value->SetBoolean("isSilenced", is_silenced_); + // We don't care too much if we lose precision here, also. + value->SetInteger("numEncryptionConflicts", + num_encryption_conflicts_); + value->SetInteger("numHierarchyConflicts", + num_hierarchy_conflicts_); + value->SetInteger("numSimpleConflicts", + num_simple_conflicts_); + value->SetInteger("numServerConflicts", + num_server_conflicts_); + value->SetInteger("numEntries", num_entries_); + value->Set("source", source_.ToValue()); + value->SetBoolean("notificationsEnabled", notifications_enabled_); + return value; +} + +std::string SyncSessionSnapshot::ToString() const { + scoped_ptr<DictionaryValue> value(ToValue()); + std::string json; + base::JSONWriter::WriteWithOptions(value.get(), + base::JSONWriter::OPTIONS_PRETTY_PRINT, + &json); + return json; +} + +SyncerStatus SyncSessionSnapshot::syncer_status() const { + return syncer_status_; +} + +ErrorCounters SyncSessionSnapshot::errors() const { + return errors_; +} + +int64 SyncSessionSnapshot::num_server_changes_remaining() const { + return num_server_changes_remaining_; +} + +bool SyncSessionSnapshot::is_share_usable() const { + return is_share_usable_; +} + +syncable::ModelTypeSet SyncSessionSnapshot::initial_sync_ended() const { + return initial_sync_ended_; +} + +syncable::ModelTypePayloadMap + SyncSessionSnapshot::download_progress_markers() const { + return download_progress_markers_; +} + +bool SyncSessionSnapshot::has_more_to_sync() const { + return has_more_to_sync_; +} + +bool SyncSessionSnapshot::is_silenced() const { + return is_silenced_; +} + +int SyncSessionSnapshot::num_encryption_conflicts() const { + return num_encryption_conflicts_; +} + +int SyncSessionSnapshot::num_hierarchy_conflicts() const { + return num_hierarchy_conflicts_; +} + +int SyncSessionSnapshot::num_simple_conflicts() const { + return num_simple_conflicts_; +} + +int SyncSessionSnapshot::num_server_conflicts() const { + return num_server_conflicts_; +} + +SyncSourceInfo SyncSessionSnapshot::source() const { + return source_; +} + +bool SyncSessionSnapshot::notifications_enabled() const { + return notifications_enabled_; +} + +size_t SyncSessionSnapshot::num_entries() const { + return num_entries_; +} + +base::Time SyncSessionSnapshot::sync_start_time() const { + return sync_start_time_; +} + +bool SyncSessionSnapshot::retry_scheduled() const { + return retry_scheduled_; +} + +} // namespace sessions +} // namespace browser_sync diff --git a/sync/internal_api/public/sessions/sync_session_snapshot.h b/sync/internal_api/public/sessions/sync_session_snapshot.h new file mode 100644 index 0000000..9ed9465 --- /dev/null +++ b/sync/internal_api/public/sessions/sync_session_snapshot.h @@ -0,0 +1,101 @@ +// 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_INTERNAL_API_PUBLIC_SESSIONS_SYNC_SESSION_SNAPSHOT_H_ +#define SYNC_INTERNAL_API_PUBLIC_SESSIONS_SYNC_SESSION_SNAPSHOT_H_ +#pragma once + +#include <string> + +#include "base/basictypes.h" +#include "base/time.h" +#include "sync/internal_api/public/sessions/error_counters.h" +#include "sync/internal_api/public/sessions/sync_source_info.h" +#include "sync/internal_api/public/sessions/syncer_status.h" +#include "sync/internal_api/public/syncable/model_type.h" +#include "sync/internal_api/public/syncable/model_type_payload_map.h" + +namespace base { +class DictionaryValue; +} + +namespace browser_sync { +namespace sessions { + +// An immutable snapshot of state from a SyncSession. Convenient to use as +// part of notifications as it is inherently thread-safe. +// TODO(zea): if copying this all over the place starts getting expensive, +// consider passing around immutable references instead of values. +// Default copy and assign welcome. +class SyncSessionSnapshot { + public: + SyncSessionSnapshot(); + SyncSessionSnapshot( + const SyncerStatus& syncer_status, + const ErrorCounters& errors, + int64 num_server_changes_remaining, + bool is_share_usable, + syncable::ModelTypeSet initial_sync_ended, + const syncable::ModelTypePayloadMap& download_progress_markers, + bool more_to_sync, + bool is_silenced, + int num_encryption_conflicts, + int num_hierarchy_conflicts, + int num_simple_conflicts, + int num_server_conflicts, + const SyncSourceInfo& source, + bool notifications_enabled, + size_t num_entries, + base::Time sync_start_time, + bool retry_scheduled); + ~SyncSessionSnapshot(); + + // Caller takes ownership of the returned dictionary. + base::DictionaryValue* ToValue() const; + + std::string ToString() const; + + SyncerStatus syncer_status() const; + ErrorCounters errors() const; + int64 num_server_changes_remaining() const; + bool is_share_usable() const; + syncable::ModelTypeSet initial_sync_ended() const; + syncable::ModelTypePayloadMap download_progress_markers() const; + bool has_more_to_sync() const; + bool is_silenced() const; + int num_encryption_conflicts() const; + int num_hierarchy_conflicts() const; + int num_simple_conflicts() const; + int num_server_conflicts() const; + bool did_commit_items() const; + SyncSourceInfo source() const; + bool notifications_enabled() const; + size_t num_entries() const; + base::Time sync_start_time() const; + bool retry_scheduled() const; + + private: + SyncerStatus syncer_status_; + ErrorCounters errors_; + int64 num_server_changes_remaining_; + bool is_share_usable_; + syncable::ModelTypeSet initial_sync_ended_; + syncable::ModelTypePayloadMap download_progress_markers_; + bool has_more_to_sync_; + bool is_silenced_; + int num_encryption_conflicts_; + int num_hierarchy_conflicts_; + int num_simple_conflicts_; + int num_server_conflicts_; + SyncSourceInfo source_; + bool notifications_enabled_; + size_t num_entries_; + base::Time sync_start_time_; + bool retry_scheduled_; +}; + +} // namespace sessions +} // namespace browser_sync + +#endif // SYNC_INTERNAL_API_PUBLIC_SESSIONS_SYNC_SESSION_SNAPSHOT_H_ diff --git a/sync/internal_api/public/sessions/sync_source_info.cc b/sync/internal_api/public/sessions/sync_source_info.cc new file mode 100644 index 0000000..191199b --- /dev/null +++ b/sync/internal_api/public/sessions/sync_source_info.cc @@ -0,0 +1,36 @@ +// 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/internal_api/public/sessions/sync_source_info.h" + +#include "base/values.h" +#include "sync/protocol/proto_enum_conversions.h" + +namespace browser_sync { +namespace sessions { + +SyncSourceInfo::SyncSourceInfo() + : updates_source(sync_pb::GetUpdatesCallerInfo::UNKNOWN) {} + +SyncSourceInfo::SyncSourceInfo( + const syncable::ModelTypePayloadMap& t) + : updates_source(sync_pb::GetUpdatesCallerInfo::UNKNOWN), types(t) {} + +SyncSourceInfo::SyncSourceInfo( + const sync_pb::GetUpdatesCallerInfo::GetUpdatesSource& u, + const syncable::ModelTypePayloadMap& t) + : updates_source(u), types(t) {} + +SyncSourceInfo::~SyncSourceInfo() {} + +DictionaryValue* SyncSourceInfo::ToValue() const { + DictionaryValue* value = new DictionaryValue(); + value->SetString("updatesSource", + GetUpdatesSourceString(updates_source)); + value->Set("types", syncable::ModelTypePayloadMapToValue(types)); + return value; +} + +} // namespace sessions +} // namespace browser_sync diff --git a/sync/internal_api/public/sessions/sync_source_info.h b/sync/internal_api/public/sessions/sync_source_info.h new file mode 100644 index 0000000..838e094 --- /dev/null +++ b/sync/internal_api/public/sessions/sync_source_info.h @@ -0,0 +1,42 @@ +// 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_INTERNAL_API_PUBLIC_SESSIONS_SYNC_SOURCE_INFO_H_ +#define SYNC_INTERNAL_API_PUBLIC_SESSIONS_SYNC_SOURCE_INFO_H_ +#pragma once + +#include "base/basictypes.h" +#include "sync/internal_api/public/syncable/model_type.h" +#include "sync/internal_api/public/syncable/model_type_payload_map.h" +#include "sync/protocol/sync.pb.h" + +namespace base { +class DictionaryValue; +} + +namespace browser_sync { +namespace sessions { + +// A container for the source of a sync session. This includes the update +// source, the datatypes triggering the sync session, and possible session +// specific payloads which should be sent to the server. +struct SyncSourceInfo { + SyncSourceInfo(); + explicit SyncSourceInfo(const syncable::ModelTypePayloadMap& t); + SyncSourceInfo( + const sync_pb::GetUpdatesCallerInfo::GetUpdatesSource& u, + const syncable::ModelTypePayloadMap& t); + ~SyncSourceInfo(); + + // Caller takes ownership of the returned dictionary. + base::DictionaryValue* ToValue() const; + + sync_pb::GetUpdatesCallerInfo::GetUpdatesSource updates_source; + syncable::ModelTypePayloadMap types; +}; + +} // namespace sessions +} // namespace browser_sync + +#endif // SYNC_INTERNAL_API_PUBLIC_SESSIONS_SYNC_SOURCE_INFO_H_ diff --git a/sync/internal_api/public/sessions/syncer_status.cc b/sync/internal_api/public/sessions/syncer_status.cc new file mode 100644 index 0000000..efa0c43 --- /dev/null +++ b/sync/internal_api/public/sessions/syncer_status.cc @@ -0,0 +1,44 @@ +// 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/internal_api/public/sessions/syncer_status.h" + +#include "base/values.h" + +namespace browser_sync { +namespace sessions { + +SyncerStatus::SyncerStatus() + : invalid_store(false), + num_successful_commits(0), + num_successful_bookmark_commits(0), + num_updates_downloaded_total(0), + num_tombstone_updates_downloaded_total(0), + num_reflected_updates_downloaded_total(0), + num_local_overwrites(0), + num_server_overwrites(0) { +} + +SyncerStatus::~SyncerStatus() { +} + +DictionaryValue* SyncerStatus::ToValue() const { + DictionaryValue* value = new DictionaryValue(); + value->SetBoolean("invalidStore", invalid_store); + value->SetInteger("numSuccessfulCommits", num_successful_commits); + value->SetInteger("numSuccessfulBookmarkCommits", + num_successful_bookmark_commits); + value->SetInteger("numUpdatesDownloadedTotal", + num_updates_downloaded_total); + value->SetInteger("numTombstoneUpdatesDownloadedTotal", + num_tombstone_updates_downloaded_total); + value->SetInteger("numReflectedUpdatesDownloadedTotal", + num_reflected_updates_downloaded_total); + value->SetInteger("numLocalOverwrites", num_local_overwrites); + value->SetInteger("numServerOverwrites", num_server_overwrites); + return value; +} + +} // namespace sessions +} // namespace browser_sync diff --git a/sync/internal_api/public/sessions/syncer_status.h b/sync/internal_api/public/sessions/syncer_status.h new file mode 100644 index 0000000..7331ca3 --- /dev/null +++ b/sync/internal_api/public/sessions/syncer_status.h @@ -0,0 +1,50 @@ +// 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_INTERNAL_API_PUBLIC_SESSIONS_SYNCER_STATUS_H_ +#define SYNC_INTERNAL_API_PUBLIC_SESSIONS_SYNCER_STATUS_H_ +#pragma once + +#include "base/basictypes.h" +#include "sync/internal_api/public/syncable/model_type.h" + +namespace base { +class DictionaryValue; +} + +namespace browser_sync { +namespace sessions { + +// Data pertaining to the status of an active Syncer object. +struct SyncerStatus { + SyncerStatus(); + ~SyncerStatus(); + + // Caller takes ownership of the returned dictionary. + base::DictionaryValue* ToValue() const; + + // True when we get such an INVALID_STORE error from the server. + bool invalid_store; + int num_successful_commits; + // This is needed for monitoring extensions activity. + int num_successful_bookmark_commits; + + // Download event counters. + int num_updates_downloaded_total; + int num_tombstone_updates_downloaded_total; + int num_reflected_updates_downloaded_total; + + // If the syncer encountered a MIGRATION_DONE code, these are the types that + // the client must now "migrate", by purging and re-downloading all updates. + syncable::ModelTypeSet types_needing_local_migration; + + // Overwrites due to conflict resolution counters. + int num_local_overwrites; + int num_server_overwrites; +}; + +} // namespace sessions +} // namespace browser_sync + +#endif // SYNC_INTERNAL_API_PUBLIC_SESSIONS_SYNCER_STATUS_H_ diff --git a/sync/internal_api/public/syncable/model_type.h b/sync/internal_api/public/syncable/model_type.h new file mode 100644 index 0000000..b7b5fe3 --- /dev/null +++ b/sync/internal_api/public/syncable/model_type.h @@ -0,0 +1,175 @@ +// 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. + +// Enumerate the various item subtypes that are supported by sync. +// Each sync object is expected to have an immutable object type. +// An object's type is inferred from the type of data it holds. + +#ifndef SYNC_INTERNAL_API_PUBLIC_SYNCABLE_MODEL_TYPE_H_ +#define SYNC_INTERNAL_API_PUBLIC_SYNCABLE_MODEL_TYPE_H_ +#pragma once + +#include <set> +#include <string> + +#include "base/logging.h" +#include "base/time.h" +#include "sync/internal_api/public/util/enum_set.h" + +namespace base { +class ListValue; +class StringValue; +class Value; +} + +namespace sync_pb { +class EntitySpecifics; +class SyncEntity; +} + +namespace syncable { + +enum ModelType { + // Object type unknown. Objects may transition through + // the unknown state during their initial creation, before + // their properties are set. After deletion, object types + // are generally preserved. + UNSPECIFIED, + // A permanent folder whose children may be of mixed + // datatypes (e.g. the "Google Chrome" folder). + TOP_LEVEL_FOLDER, + + // ------------------------------------ Start of "real" model types. + // The model types declared before here are somewhat special, as they + // they do not correspond to any browser data model. The remaining types + // are bona fide model types; all have a related browser data model and + // can be represented in the protocol using a specific Message type in the + // EntitySpecifics protocol buffer. + // + // A bookmark folder or a bookmark URL object. + BOOKMARKS, + FIRST_REAL_MODEL_TYPE = BOOKMARKS, // Declared 2nd, for debugger prettiness. + + // A preference folder or a preference object. + PREFERENCES, + // A password folder or password object. + PASSWORDS, + // An AutofillProfile Object + AUTOFILL_PROFILE, + // An autofill folder or an autofill object. + AUTOFILL, + + // A themes folder or a themes object. + THEMES, + // A typed_url folder or a typed_url object. + TYPED_URLS, + // An extension folder or an extension object. + EXTENSIONS, + // An object representing a set of Nigori keys. + NIGORI, + // An object representing a custom search engine. + SEARCH_ENGINES, + // An object representing a browser session. + SESSIONS, + // An app folder or an app object. + APPS, + // An app setting from the extension settings API. + APP_SETTINGS, + // An extension setting from the extension settings API. + EXTENSION_SETTINGS, + // App notifications. + APP_NOTIFICATIONS, + LAST_REAL_MODEL_TYPE = APP_NOTIFICATIONS, + + // If you are adding a new sync datatype that is exposed to the user via the + // sync preferences UI, be sure to update the list in + // chrome/browser/sync/user_selectable_sync_type.h so that the UMA histograms + // for sync include your new type. + + MODEL_TYPE_COUNT, +}; + +typedef browser_sync::EnumSet< + ModelType, FIRST_REAL_MODEL_TYPE, LAST_REAL_MODEL_TYPE> ModelTypeSet; +typedef browser_sync::EnumSet< + ModelType, UNSPECIFIED, LAST_REAL_MODEL_TYPE> FullModelTypeSet; + +inline ModelType ModelTypeFromInt(int i) { + DCHECK_GE(i, 0); + DCHECK_LT(i, MODEL_TYPE_COUNT); + return static_cast<ModelType>(i); +} + +void AddDefaultFieldValue(syncable::ModelType datatype, + sync_pb::EntitySpecifics* specifics); + +// Extract the model type of a SyncEntity protocol buffer. ModelType is a +// local concept: the enum is not in the protocol. The SyncEntity's ModelType +// is inferred from the presence of particular datatype field in the +// entity specifics. +ModelType GetModelType(const sync_pb::SyncEntity& sync_entity); + +// Extract the model type from an EntitySpecifics field. Note that there +// are some ModelTypes (like TOP_LEVEL_FOLDER) that can't be inferred this way; +// prefer using GetModelType where possible. +ModelType GetModelTypeFromSpecifics(const sync_pb::EntitySpecifics& specifics); + +// If this returns false, we shouldn't bother maintaining a position +// value (sibling ordering) for this item. +bool ShouldMaintainPosition(ModelType model_type); + +// Determine a model type from the field number of its associated +// EntitySpecifics field. +ModelType GetModelTypeFromSpecificsFieldNumber(int field_number); + +// Return the field number of the EntitySpecifics field associated with +// a model type. +int GetSpecificsFieldNumberFromModelType(ModelType model_type); + +// TODO(sync): The functions below badly need some cleanup. + +// Returns a pointer to a string with application lifetime that represents +// the name of |model_type|. +const char* ModelTypeToString(ModelType model_type); + +// Handles all model types, and not just real ones. +// +// Caller takes ownership of returned value. +base::StringValue* ModelTypeToValue(ModelType model_type); + +// Converts a Value into a ModelType - complement to ModelTypeToValue(). +ModelType ModelTypeFromValue(const base::Value& value); + +// Returns the ModelType corresponding to the name |model_type_string|. +ModelType ModelTypeFromString(const std::string& model_type_string); + +std::string ModelTypeSetToString(ModelTypeSet model_types); + +// Caller takes ownership of returned list. +base::ListValue* ModelTypeSetToValue(ModelTypeSet model_types); + +ModelTypeSet ModelTypeSetFromValue(const base::ListValue& value); + +// Returns a string corresponding to the syncable tag for this datatype. +std::string ModelTypeToRootTag(ModelType type); + +// Convert a real model type to a notification type (used for +// subscribing to server-issued notifications). Returns true iff +// |model_type| was a real model type and |notification_type| was +// filled in. +bool RealModelTypeToNotificationType(ModelType model_type, + std::string* notification_type); + +// Converts a notification type to a real model type. Returns true +// iff |notification_type| was the notification type of a real model +// type and |model_type| was filled in. +bool NotificationTypeToRealModelType(const std::string& notification_type, + ModelType* model_type); + +// Returns true if |model_type| is a real datatype +bool IsRealDataType(ModelType model_type); + +} // namespace syncable + +#endif // SYNC_INTERNAL_API_PUBLIC_SYNCABLE_MODEL_TYPE_H_ diff --git a/sync/internal_api/public/syncable/model_type_payload_map.cc b/sync/internal_api/public/syncable/model_type_payload_map.cc new file mode 100644 index 0000000..cff4c92 --- /dev/null +++ b/sync/internal_api/public/syncable/model_type_payload_map.cc @@ -0,0 +1,105 @@ +// 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/internal_api/public/syncable/model_type_payload_map.h" + +#include <vector> + +#include "base/base64.h" +#include "base/json/json_writer.h" +#include "base/memory/scoped_ptr.h" +#include "base/values.h" + +using browser_sync::ModelSafeRoutingInfo; +namespace syncable { + +ModelTypePayloadMap ModelTypePayloadMapFromEnumSet( + syncable::ModelTypeSet types, + const std::string& payload) { + ModelTypePayloadMap types_with_payloads; + for (syncable::ModelTypeSet::Iterator it = types.First(); + it.Good(); it.Inc()) { + types_with_payloads[it.Get()] = payload; + } + return types_with_payloads; +} + +ModelTypeSet ModelTypePayloadMapToEnumSet( + const ModelTypePayloadMap& payload_map) { + ModelTypeSet types; + for (ModelTypePayloadMap::const_iterator it = payload_map.begin(); + it != payload_map.end(); ++it) { + types.Put(it->first); + } + return types; +} + +ModelTypePayloadMap ModelTypePayloadMapFromRoutingInfo( + const browser_sync::ModelSafeRoutingInfo& routes, + const std::string& payload) { + ModelTypePayloadMap types_with_payloads; + for (browser_sync::ModelSafeRoutingInfo::const_iterator i = routes.begin(); + i != routes.end(); ++i) { + types_with_payloads[i->first] = payload; + } + return types_with_payloads; +} + +std::string ModelTypePayloadMapToString( + const ModelTypePayloadMap& type_payloads) { + scoped_ptr<DictionaryValue> value( + ModelTypePayloadMapToValue(type_payloads)); + std::string json; + base::JSONWriter::Write(value.get(), &json); + return json; +} + +DictionaryValue* ModelTypePayloadMapToValue( + const ModelTypePayloadMap& type_payloads) { + DictionaryValue* value = new DictionaryValue(); + for (ModelTypePayloadMap::const_iterator it = type_payloads.begin(); + it != type_payloads.end(); ++it) { + // TODO(akalin): Unpack the value into a protobuf. + std::string base64_marker; + bool encoded = base::Base64Encode(it->second, &base64_marker); + DCHECK(encoded); + value->SetString(syncable::ModelTypeToString(it->first), base64_marker); + } + return value; +} + +void CoalescePayloads(ModelTypePayloadMap* original, + const ModelTypePayloadMap& update) { + for (ModelTypePayloadMap::const_iterator i = update.begin(); + i != update.end(); ++i) { + if (original->count(i->first) == 0) { + // If this datatype isn't already in our map, add it with + // whatever payload it has. + (*original)[i->first] = i->second; + } else if (i->second.length() > 0) { + // If this datatype is already in our map, we only overwrite the + // payload if the new one is non-empty. + (*original)[i->first] = i->second; + } + } +} + +void PurgeStalePayload(ModelTypePayloadMap* original, + const ModelSafeRoutingInfo& routing_info) { + std::vector<ModelTypePayloadMap::iterator> iterators_to_delete; + for (ModelTypePayloadMap::iterator i = original->begin(); + i != original->end(); ++i) { + if (routing_info.end() == routing_info.find(i->first)) { + iterators_to_delete.push_back(i); + } + } + + for (std::vector<ModelTypePayloadMap::iterator>::iterator + it = iterators_to_delete.begin(); it != iterators_to_delete.end(); + ++it) { + original->erase(*it); + } +} + +} // namespace syncable diff --git a/sync/internal_api/public/syncable/model_type_payload_map.h b/sync/internal_api/public/syncable/model_type_payload_map.h new file mode 100644 index 0000000..1bf3884 --- /dev/null +++ b/sync/internal_api/public/syncable/model_type_payload_map.h @@ -0,0 +1,60 @@ +// 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. +// +// Definition of ModelTypePayloadMap and various utility functions. + +#ifndef SYNC_INTERNAL_PUBLIC_API_SYNCABLE_MODEL_TYPE_PAYLOAD_MAP_H_ +#define SYNC_INTERNAL_PUBLIC_API_SYNCABLE_MODEL_TYPE_PAYLOAD_MAP_H_ +#pragma once + +#include <map> +#include <string> + +#include "sync/internal_api/public/engine/model_safe_worker.h" +#include "sync/internal_api/public/syncable/model_type.h" + +namespace base { +class DictionaryValue; +} + +namespace syncable { + +// A container that contains a set of datatypes with possible string +// payloads. +typedef std::map<ModelType, std::string> ModelTypePayloadMap; + +// Helper functions for building ModelTypePayloadMaps. + +// Make a TypePayloadMap from all the types in a ModelTypeSet using a +// default payload. +ModelTypePayloadMap ModelTypePayloadMapFromEnumSet( + ModelTypeSet model_types, const std::string& payload); + +ModelTypeSet ModelTypePayloadMapToEnumSet( + const ModelTypePayloadMap& payload_map); + +// Make a TypePayloadMap for all the enabled types in a +// ModelSafeRoutingInfo using a default payload. +ModelTypePayloadMap ModelTypePayloadMapFromRoutingInfo( + const browser_sync::ModelSafeRoutingInfo& routes, + const std::string& payload); + +std::string ModelTypePayloadMapToString( + const ModelTypePayloadMap& model_type_payloads); + +// Caller takes ownership of the returned dictionary. +base::DictionaryValue* ModelTypePayloadMapToValue( + const ModelTypePayloadMap& model_type_payloads); + +// Coalesce |update| into |original|, overwriting only when |update| has +// a non-empty payload. +void CoalescePayloads(ModelTypePayloadMap* original, + const ModelTypePayloadMap& update); + +void PurgeStalePayload(ModelTypePayloadMap* original, + const browser_sync::ModelSafeRoutingInfo& routing_info); + +} // namespace syncable + +#endif // SYNC_INTERNAL_PUBLIC_API_SYNCABLE_MODEL_TYPE_PAYLOAD_MAP_H_ diff --git a/sync/internal_api/public/syncable/model_type_payload_map_unittest.cc b/sync/internal_api/public/syncable/model_type_payload_map_unittest.cc new file mode 100644 index 0000000..4a18b34 --- /dev/null +++ b/sync/internal_api/public/syncable/model_type_payload_map_unittest.cc @@ -0,0 +1,46 @@ +// 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/internal_api/public/syncable/model_type_payload_map.h" + +#include <string> + +#include "base/base64.h" +#include "base/memory/scoped_ptr.h" +#include "base/test/values_test_util.h" +#include "base/values.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace syncable { +namespace { + +using base::ExpectDictStringValue; + +class ModelTypePayloadMapTest : public testing::Test {}; + +TEST_F(ModelTypePayloadMapTest, TypePayloadMapToSet) { + ModelTypePayloadMap payloads; + payloads[BOOKMARKS] = "bookmarkpayload"; + payloads[APPS] = ""; + + const ModelTypeSet types(BOOKMARKS, APPS); + EXPECT_TRUE(ModelTypePayloadMapToEnumSet(payloads).Equals(types)); +} + +TEST_F(ModelTypePayloadMapTest, TypePayloadMapToValue) { + ModelTypePayloadMap payloads; + std::string encoded; + payloads[BOOKMARKS] = "bookmarkpayload"; + base::Base64Encode(payloads[BOOKMARKS], &encoded); + payloads[APPS] = ""; + + scoped_ptr<DictionaryValue> value(ModelTypePayloadMapToValue(payloads)); + EXPECT_EQ(2u, value->size()); + ExpectDictStringValue(encoded, *value, "Bookmarks"); + ExpectDictStringValue("", *value, "Apps"); + EXPECT_FALSE(value->HasKey("Preferences")); +} + +} // namespace +} // namespace syncable diff --git a/sync/internal_api/public/syncable/model_type_test_util.cc b/sync/internal_api/public/syncable/model_type_test_util.cc new file mode 100644 index 0000000..36d1673 --- /dev/null +++ b/sync/internal_api/public/syncable/model_type_test_util.cc @@ -0,0 +1,52 @@ +// 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/internal_api/public/syncable/model_type_test_util.h" + +namespace syncable { + +void PrintTo(ModelTypeSet model_types, ::std::ostream* os) { + *os << ModelTypeSetToString(model_types); +} + +namespace { + +// Matcher implementation for HasModelTypes(). +class HasModelTypesMatcher + : public ::testing::MatcherInterface<ModelTypeSet> { + public: + explicit HasModelTypesMatcher(ModelTypeSet expected_types) + : expected_types_(expected_types) {} + + virtual ~HasModelTypesMatcher() {} + + virtual bool MatchAndExplain( + ModelTypeSet model_types, + ::testing::MatchResultListener* listener) const { + // No need to annotate listener since we already define PrintTo(). + return model_types.Equals(expected_types_); + } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "has model types " << ModelTypeSetToString(expected_types_); + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "doesn't have model types " + << ModelTypeSetToString(expected_types_); + } + + private: + const ModelTypeSet expected_types_; + + DISALLOW_COPY_AND_ASSIGN(HasModelTypesMatcher); +}; + +} // namespace + +::testing::Matcher<ModelTypeSet> HasModelTypes(ModelTypeSet expected_types) { + return ::testing::MakeMatcher(new HasModelTypesMatcher(expected_types)); +} + +} // namespace syncable diff --git a/sync/internal_api/public/syncable/model_type_test_util.h b/sync/internal_api/public/syncable/model_type_test_util.h new file mode 100644 index 0000000..173212f --- /dev/null +++ b/sync/internal_api/public/syncable/model_type_test_util.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_INTERNAL_PUBLIC_API_SYNCABLE_MODEL_TYPE_TEST_UTIL_H_ +#define SYNC_INTERNAL_PUBLIC_API_SYNCABLE_MODEL_TYPE_TEST_UTIL_H_ +#pragma once + +#include <ostream> + +#include "sync/internal_api/public/syncable/model_type.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace syncable { + +// Defined for googletest. Forwards to ModelTypeSetToString(). +void PrintTo(ModelTypeSet model_types, ::std::ostream* os); + +// A gmock matcher for ModelTypeSet. Use like: +// +// EXPECT_CALL(mock, ProcessModelTypes(HasModelTypes(expected_types))); +::testing::Matcher<ModelTypeSet> HasModelTypes(ModelTypeSet expected_types); + +} // namespace syncable + +#endif // SYNC_INTERNAL_PUBLIC_API_SYNCABLE_MODEL_TYPE_TEST_UTIL_H_ diff --git a/sync/internal_api/public/util/enum_set.h b/sync/internal_api/public/util/enum_set.h new file mode 100644 index 0000000..de270d8 --- /dev/null +++ b/sync/internal_api/public/util/enum_set.h @@ -0,0 +1,286 @@ +// 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_INTERNAL_API_PUBLIC_UTIL_ENUM_SET_H_ +#define SYNC_INTERNAL_API_PUBLIC_UTIL_ENUM_SET_H_ +#pragma once + +#include <bitset> +#include <cstddef> +#include <string> + +#include "base/basictypes.h" +#include "base/logging.h" + +namespace browser_sync { + +// Forward declarations needed for friend declarations. +template <typename E, E MinEnumValue, E MaxEnumValue> +class EnumSet; + +template <typename E, E Min, E Max> +EnumSet<E, Min, Max> Union(EnumSet<E, Min, Max> set1, + EnumSet<E, Min, Max> set2); + +template <typename E, E Min, E Max> +EnumSet<E, Min, Max> Intersection(EnumSet<E, Min, Max> set1, + EnumSet<E, Min, Max> set2); + +template <typename E, E Min, E Max> +EnumSet<E, Min, Max> Difference(EnumSet<E, Min, Max> set1, + EnumSet<E, Min, Max> set2); + +// An EnumSet is a set that can hold enum values between a min and a +// max value (inclusive of both). It's essentially a wrapper around +// std::bitset<> with stronger type enforcement, more descriptive +// member function names, and an iterator interface. +// +// If you're working with enums with a small number of possible values +// (say, fewer than 64), you can efficiently pass around an EnumSet +// for that enum around by value. + +template <typename E, E MinEnumValue, E MaxEnumValue> +class EnumSet { + public: + typedef E EnumType; + static const E kMinValue = MinEnumValue; + static const E kMaxValue = MaxEnumValue; + static const size_t kValueCount = kMaxValue - kMinValue + 1; + COMPILE_ASSERT(kMinValue < kMaxValue, + min_value_must_be_less_than_max_value); + + private: + // Declaration needed by Iterator. + typedef std::bitset<kValueCount> EnumBitSet; + + public: + // Iterator is a forward-only read-only iterator for EnumSet. Its + // interface is deliberately distinct from an STL iterator as its + // semantics are substantially different. + // + // Example usage: + // + // for (EnumSet<...>::Iterator it = enums.First(); it.Good(); it.Inc()) { + // Process(it.Get()); + // } + // + // The iterator must not be outlived by the set. In particular, the + // following is an error: + // + // EnumSet<...> SomeFn() { ... } + // + // /* ERROR */ + // for (EnumSet<...>::Iterator it = SomeFun().First(); ... + // + // Also, there are no guarantees as to what will happen if you + // modify an EnumSet while traversing it with an iterator. + class Iterator { + public: + // A default-constructed iterator can't do anything except check + // Good(). You need to call First() on an EnumSet to get a usable + // iterator. + Iterator() : enums_(NULL), i_(kValueCount) {} + ~Iterator() {} + + // Copy constructor and assignment welcome. + + // Returns true iff the iterator points to an EnumSet and it + // hasn't yet traversed the EnumSet entirely. + bool Good() const { + return enums_ && i_ < kValueCount && enums_->test(i_); + } + + // Returns the value the iterator currently points to. Good() + // must hold. + E Get() const { + CHECK(Good()); + return FromIndex(i_); + } + + // Moves the iterator to the next value in the EnumSet. Good() + // must hold. Takes linear time. + void Inc() { + CHECK(Good()); + i_ = FindNext(i_ + 1); + } + + private: + friend Iterator EnumSet::First() const; + + explicit Iterator(const EnumBitSet& enums) + : enums_(&enums), i_(FindNext(0)) {} + + size_t FindNext(size_t i) { + while ((i < kValueCount) && !enums_->test(i)) { + ++i; + } + return i; + } + + const EnumBitSet* enums_; + size_t i_; + }; + + // You can construct an EnumSet with 0, 1, 2, or 3 initial values. + + EnumSet() {} + + explicit EnumSet(E value) { + Put(value); + } + + EnumSet(E value1, E value2) { + Put(value1); + Put(value2); + } + + EnumSet(E value1, E value2, E value3) { + Put(value1); + Put(value2); + Put(value3); + } + + // Returns an EnumSet with all possible values. + static EnumSet All() { + EnumBitSet enums; + enums.set(); + return EnumSet(enums); + } + + ~EnumSet() {} + + // Copy constructor and assignment welcome. + + // Set operations. Put, Retain, and Remove are basically + // self-mutating versions of Union, Intersection, and Difference + // (defined below). + + // Adds the given value (which must be in range) to our set. + void Put(E value) { + enums_.set(ToIndex(value)); + } + + // Adds all values in the given set to our set. + void PutAll(EnumSet other) { + enums_ |= other.enums_; + } + + // There's no real need for a Retain(E) member function. + + // Removes all values not in the given set from our set. + void RetainAll(EnumSet other) { + enums_ &= other.enums_; + } + + // If the given value is in range, removes it from our set. + void Remove(E value) { + if (InRange(value)) { + enums_.reset(ToIndex(value)); + } + } + + // Removes all values in the given set from our set. + void RemoveAll(EnumSet other) { + enums_ &= ~other.enums_; + } + + // Removes all values from our set. + void Clear() { + enums_.reset(); + } + + // Returns true iff the given value is in range and a member of our + // set. + bool Has(E value) const { + return InRange(value) && enums_.test(ToIndex(value)); + } + + // Returns true iff the given set is a subset of our set. + bool HasAll(EnumSet other) const { + return (enums_ & other.enums_) == other.enums_; + } + + // Returns true iff our set and the given set contain exactly the + // same values. + bool Equals(const EnumSet& other) const { + return enums_ == other.enums_; + } + + // Returns true iff our set is empty. + bool Empty() const { + return !enums_.any(); + } + + // Returns how many values our set has. + size_t Size() const { + return enums_.count(); + } + + // Returns an iterator pointing to the first element (if any). + Iterator First() const { + return Iterator(enums_); + } + + private: + friend EnumSet Union<E, MinEnumValue, MaxEnumValue>( + EnumSet set1, EnumSet set2); + friend EnumSet Intersection<E, MinEnumValue, MaxEnumValue>( + EnumSet set1, EnumSet set2); + friend EnumSet Difference<E, MinEnumValue, MaxEnumValue>( + EnumSet set1, EnumSet set2); + + explicit EnumSet(EnumBitSet enums) : enums_(enums) {} + + static bool InRange(E value) { + return (value >= MinEnumValue) && (value <= MaxEnumValue); + } + + // Converts a value to/from an index into |enums_|. + + static size_t ToIndex(E value) { + DCHECK_GE(value, MinEnumValue); + DCHECK_LE(value, MaxEnumValue); + return value - MinEnumValue; + } + + static E FromIndex(size_t i) { + DCHECK_LT(i, kValueCount); + return static_cast<E>(MinEnumValue + i); + } + + EnumBitSet enums_; +}; + +template <typename E, E MinEnumValue, E MaxEnumValue> +const E EnumSet<E, MinEnumValue, MaxEnumValue>::kMinValue; + +template <typename E, E MinEnumValue, E MaxEnumValue> +const E EnumSet<E, MinEnumValue, MaxEnumValue>::kMaxValue; + +template <typename E, E MinEnumValue, E MaxEnumValue> +const size_t EnumSet<E, MinEnumValue, MaxEnumValue>::kValueCount; + +// The usual set operations. + +template <typename E, E Min, E Max> +EnumSet<E, Min, Max> Union(EnumSet<E, Min, Max> set1, + EnumSet<E, Min, Max> set2) { + return EnumSet<E, Min, Max>(set1.enums_ | set2.enums_); +} + +template <typename E, E Min, E Max> +EnumSet<E, Min, Max> Intersection(EnumSet<E, Min, Max> set1, + EnumSet<E, Min, Max> set2) { + return EnumSet<E, Min, Max>(set1.enums_ & set2.enums_); +} + +template <typename E, E Min, E Max> +EnumSet<E, Min, Max> Difference(EnumSet<E, Min, Max> set1, + EnumSet<E, Min, Max> set2) { + return EnumSet<E, Min, Max>(set1.enums_ & ~set2.enums_); +} + +} // namespace browser_sync + +#endif // SYNC_INTERNAL_API_PUBLIC_UTIL_ENUM_SET_H_ diff --git a/sync/internal_api/public/util/enum_set_unittest.cc b/sync/internal_api/public/util/enum_set_unittest.cc new file mode 100644 index 0000000..2caa1de --- /dev/null +++ b/sync/internal_api/public/util/enum_set_unittest.cc @@ -0,0 +1,195 @@ +// 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/internal_api/public/util/enum_set.h" + +#include "base/basictypes.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace browser_sync { +namespace { + +enum TestEnum { + TEST_0, + TEST_MIN = TEST_0, + TEST_1, + TEST_2, + TEST_3, + TEST_4, + TEST_MAX = TEST_4, + TEST_5 +}; + +typedef EnumSet<TestEnum, TEST_MIN, TEST_MAX> TestEnumSet; + +class EnumSetTest : public ::testing::Test {}; + +TEST_F(EnumSetTest, ClassConstants) { + TestEnumSet enums; + EXPECT_EQ(TEST_MIN, TestEnumSet::kMinValue); + EXPECT_EQ(TEST_MAX, TestEnumSet::kMaxValue); + EXPECT_EQ(static_cast<size_t>(5), TestEnumSet::kValueCount); +} + +TEST_F(EnumSetTest, DefaultConstructor) { + const TestEnumSet enums; + EXPECT_TRUE(enums.Empty()); + EXPECT_EQ(static_cast<size_t>(0), enums.Size()); + EXPECT_FALSE(enums.Has(TEST_0)); + EXPECT_FALSE(enums.Has(TEST_1)); + EXPECT_FALSE(enums.Has(TEST_2)); + EXPECT_FALSE(enums.Has(TEST_3)); + EXPECT_FALSE(enums.Has(TEST_4)); +} + +TEST_F(EnumSetTest, OneArgConstructor) { + const TestEnumSet enums(TEST_3); + EXPECT_FALSE(enums.Empty()); + EXPECT_EQ(static_cast<size_t>(1), enums.Size()); + EXPECT_FALSE(enums.Has(TEST_0)); + EXPECT_FALSE(enums.Has(TEST_1)); + EXPECT_FALSE(enums.Has(TEST_2)); + EXPECT_TRUE(enums.Has(TEST_3)); + EXPECT_FALSE(enums.Has(TEST_4)); +} + +TEST_F(EnumSetTest, TwoArgConstructor) { + const TestEnumSet enums(TEST_3, TEST_1); + EXPECT_FALSE(enums.Empty()); + EXPECT_EQ(static_cast<size_t>(2), enums.Size()); + EXPECT_FALSE(enums.Has(TEST_0)); + EXPECT_TRUE(enums.Has(TEST_1)); + EXPECT_FALSE(enums.Has(TEST_2)); + EXPECT_TRUE(enums.Has(TEST_3)); + EXPECT_FALSE(enums.Has(TEST_4)); +} + +TEST_F(EnumSetTest, ThreeArgConstructor) { + const TestEnumSet enums(TEST_3, TEST_1, TEST_0); + EXPECT_FALSE(enums.Empty()); + EXPECT_EQ(static_cast<size_t>(3), enums.Size()); + EXPECT_TRUE(enums.Has(TEST_0)); + EXPECT_TRUE(enums.Has(TEST_1)); + EXPECT_FALSE(enums.Has(TEST_2)); + EXPECT_TRUE(enums.Has(TEST_3)); + EXPECT_FALSE(enums.Has(TEST_4)); +} + +TEST_F(EnumSetTest, All) { + const TestEnumSet enums(TestEnumSet::All()); + EXPECT_FALSE(enums.Empty()); + EXPECT_EQ(static_cast<size_t>(5), enums.Size()); + EXPECT_TRUE(enums.Has(TEST_0)); + EXPECT_TRUE(enums.Has(TEST_1)); + EXPECT_TRUE(enums.Has(TEST_2)); + EXPECT_TRUE(enums.Has(TEST_3)); + EXPECT_TRUE(enums.Has(TEST_4)); +} + +TEST_F(EnumSetTest, Put) { + TestEnumSet enums(TEST_3); + enums.Put(TEST_2); + EXPECT_TRUE(enums.Equals(TestEnumSet(TEST_2, TEST_3))); + enums.Put(TEST_4); + EXPECT_TRUE(enums.Equals(TestEnumSet(TEST_2, TEST_3, TEST_4))); +} + +TEST_F(EnumSetTest, PutAll) { + TestEnumSet enums(TEST_3, TEST_4); + enums.PutAll(TestEnumSet(TEST_2, TEST_3)); + EXPECT_TRUE(enums.Equals(TestEnumSet(TEST_2, TEST_3, TEST_4))); +} + +TEST_F(EnumSetTest, RetainAll) { + TestEnumSet enums(TEST_3, TEST_4); + enums.RetainAll(TestEnumSet(TEST_2, TEST_3)); + EXPECT_TRUE(enums.Equals(TestEnumSet(TEST_3))); +} + +TEST_F(EnumSetTest, Remove) { + TestEnumSet enums(TEST_3, TEST_4); + enums.Remove(TEST_0); + enums.Remove(TEST_2); + EXPECT_TRUE(enums.Equals(TestEnumSet(TEST_3, TEST_4))); + enums.Remove(TEST_3); + EXPECT_TRUE(enums.Equals(TestEnumSet(TEST_4))); + enums.Remove(TEST_4); + enums.Remove(TEST_5); + EXPECT_TRUE(enums.Empty()); +} + +TEST_F(EnumSetTest, RemoveAll) { + TestEnumSet enums(TEST_3, TEST_4); + enums.RemoveAll(TestEnumSet(TEST_2, TEST_3)); + EXPECT_TRUE(enums.Equals(TestEnumSet(TEST_4))); +} + +TEST_F(EnumSetTest, Clear) { + TestEnumSet enums(TEST_3, TEST_4); + enums.Clear(); + EXPECT_TRUE(enums.Empty()); +} + +TEST_F(EnumSetTest, Has) { + const TestEnumSet enums(TEST_3, TEST_4); + EXPECT_FALSE(enums.Has(TEST_0)); + EXPECT_FALSE(enums.Has(TEST_1)); + EXPECT_FALSE(enums.Has(TEST_2)); + EXPECT_TRUE(enums.Has(TEST_3)); + EXPECT_TRUE(enums.Has(TEST_4)); + EXPECT_FALSE(enums.Has(TEST_5)); +} + +TEST_F(EnumSetTest, HasAll) { + const TestEnumSet enums1(TEST_3, TEST_4); + const TestEnumSet enums2(TEST_2, TEST_3); + const TestEnumSet enums3 = Union(enums1, enums2); + EXPECT_TRUE(enums1.HasAll(enums1)); + EXPECT_FALSE(enums1.HasAll(enums2)); + EXPECT_FALSE(enums1.HasAll(enums3)); + + EXPECT_FALSE(enums2.HasAll(enums1)); + EXPECT_TRUE(enums2.HasAll(enums2)); + EXPECT_FALSE(enums2.HasAll(enums3)); + + EXPECT_TRUE(enums3.HasAll(enums1)); + EXPECT_TRUE(enums3.HasAll(enums2)); + EXPECT_TRUE(enums3.HasAll(enums3)); +} + +TEST_F(EnumSetTest, Iterators) { + const TestEnumSet enums1(TEST_3, TEST_4); + TestEnumSet enums2; + for (TestEnumSet::Iterator it = enums1.First(); it.Good(); it.Inc()) { + enums2.Put(it.Get()); + } + EXPECT_TRUE(enums1.Equals(enums2)); +} + +TEST_F(EnumSetTest, Union) { + const TestEnumSet enums1(TEST_3, TEST_4); + const TestEnumSet enums2(TEST_2, TEST_3); + const TestEnumSet enums3 = Union(enums1, enums2); + + EXPECT_TRUE(enums3.Equals(TestEnumSet(TEST_2, TEST_3, TEST_4))); +} + +TEST_F(EnumSetTest, Intersection) { + const TestEnumSet enums1(TEST_3, TEST_4); + const TestEnumSet enums2(TEST_2, TEST_3); + const TestEnumSet enums3 = Intersection(enums1, enums2); + + EXPECT_TRUE(enums3.Equals(TestEnumSet(TEST_3))); +} + +TEST_F(EnumSetTest, Difference) { + const TestEnumSet enums1(TEST_3, TEST_4); + const TestEnumSet enums2(TEST_2, TEST_3); + const TestEnumSet enums3 = Difference(enums1, enums2); + + EXPECT_TRUE(enums3.Equals(TestEnumSet(TEST_4))); +} + +} // namespace +} // namespace browser_sync diff --git a/sync/internal_api/public/util/syncer_error.cc b/sync/internal_api/public/util/syncer_error.cc new file mode 100644 index 0000000..b4ba578 --- /dev/null +++ b/sync/internal_api/public/util/syncer_error.cc @@ -0,0 +1,36 @@ +// 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/internal_api/public/util/syncer_error.h" + +#include "base/logging.h" + +namespace browser_sync { + +#define ENUM_CASE(x) case x: return #x; break; +const char* GetSyncerErrorString(SyncerError value) { + switch (value) { + ENUM_CASE(UNSET); + ENUM_CASE(DIRECTORY_LOOKUP_FAILED); + ENUM_CASE(NETWORK_CONNECTION_UNAVAILABLE); + ENUM_CASE(NETWORK_IO_ERROR); + ENUM_CASE(SYNC_SERVER_ERROR); + ENUM_CASE(SYNC_AUTH_ERROR); + ENUM_CASE(SERVER_RETURN_INVALID_CREDENTIAL); + ENUM_CASE(SERVER_RETURN_UNKNOWN_ERROR); + ENUM_CASE(SERVER_RETURN_THROTTLED); + ENUM_CASE(SERVER_RETURN_TRANSIENT_ERROR); + ENUM_CASE(SERVER_RETURN_MIGRATION_DONE); + ENUM_CASE(SERVER_RETURN_CLEAR_PENDING); + ENUM_CASE(SERVER_RETURN_NOT_MY_BIRTHDAY); + ENUM_CASE(SERVER_RESPONSE_VALIDATION_FAILED); + ENUM_CASE(SYNCER_OK); + } + NOTREACHED(); + return "INVALID"; +} +#undef ENUM_CASE + +} // namespace browser_sync + diff --git a/sync/internal_api/public/util/syncer_error.h b/sync/internal_api/public/util/syncer_error.h new file mode 100644 index 0000000..aa6ebb3 --- /dev/null +++ b/sync/internal_api/public/util/syncer_error.h @@ -0,0 +1,46 @@ +// 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_INTERNAL_API_PUBLIC_UTIL_SYNCER_ERROR_H_ +#define SYNC_INTERNAL_API_PUBLIC_UTIL_SYNCER_ERROR_H_ +#pragma once + +namespace browser_sync { + +// This enum describes all the ways a SyncerCommand can fail. +// +// SyncerCommands do many different things, but they share a common function +// signature. This enum, the return value for all SyncerCommands, must be able +// to describe any possible failure for all SyncerComand. +// +// For convenience, functions which are invoked only by SyncerCommands may also +// return a SyncerError. It saves us having to write a conversion function, and +// it makes refactoring easier. +enum SyncerError { + UNSET = 0, // Default value. + DIRECTORY_LOOKUP_FAILED, // Local directory lookup failure. + + NETWORK_CONNECTION_UNAVAILABLE, // Connectivity failure. + NETWORK_IO_ERROR, // Response buffer read error. + SYNC_SERVER_ERROR, // Non auth HTTP error. + SYNC_AUTH_ERROR, // HTTP auth error. + + // Based on values returned by server. Most are defined in sync.proto. + SERVER_RETURN_INVALID_CREDENTIAL, + SERVER_RETURN_UNKNOWN_ERROR, + SERVER_RETURN_THROTTLED, + SERVER_RETURN_TRANSIENT_ERROR, + SERVER_RETURN_MIGRATION_DONE, + SERVER_RETURN_CLEAR_PENDING, + SERVER_RETURN_NOT_MY_BIRTHDAY, + SERVER_RESPONSE_VALIDATION_FAILED, + + SYNCER_OK +}; + +const char * GetSyncerErrorString(SyncerError); + +} // namespace browser_sync + +#endif // SYNC_INTERNAL_API_PUBLIC_UTIL_SYNCER_ERROR_H_ |