summaryrefslogtreecommitdiffstats
path: root/chrome/browser/sync
diff options
context:
space:
mode:
authorakalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-10 23:41:40 +0000
committerakalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-10 23:41:40 +0000
commit2b85b67a2938a787ecb3344bb555937e6ef87c9a (patch)
tree31e8769ffbf4244af44baa91f69a9cc6f7f62df2 /chrome/browser/sync
parent8fe16d6423f526223016df11b2ae0630672efe8c (diff)
downloadchromium_src-2b85b67a2938a787ecb3344bb555937e6ef87c9a.zip
chromium_src-2b85b67a2938a787ecb3344bb555937e6ef87c9a.tar.gz
chromium_src-2b85b67a2938a787ecb3344bb555937e6ef87c9a.tar.bz2
[Sync] Add more conversions to Value for sync types
This is a prerequisite for exposing some functions to chrome://sync-internals. Cleaned up some test code also. BUG=69500 Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=74489 Review URL: http://codereview.chromium.org/6476016 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@74521 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/sync')
-rw-r--r--chrome/browser/sync/engine/syncapi.cc58
-rw-r--r--chrome/browser/sync/engine/syncapi.h19
-rw-r--r--chrome/browser/sync/engine/syncapi_unittest.cc236
-rw-r--r--chrome/browser/sync/protocol/proto_enum_conversions.cc17
-rw-r--r--chrome/browser/sync/protocol/proto_enum_conversions.h3
-rw-r--r--chrome/browser/sync/protocol/proto_enum_conversions_unittest.cc7
-rw-r--r--chrome/browser/sync/protocol/proto_value_conversions.cc104
-rw-r--r--chrome/browser/sync/protocol/proto_value_conversions.h6
-rw-r--r--chrome/browser/sync/protocol/proto_value_conversions_unittest.cc42
-rw-r--r--chrome/browser/sync/protocol/sync.proto2
-rw-r--r--chrome/browser/sync/sessions/session_state.cc92
-rw-r--r--chrome/browser/sync/sessions/session_state.h26
-rw-r--r--chrome/browser/sync/sessions/session_state_unittest.cc191
-rw-r--r--chrome/browser/sync/syncable/model_type.cc13
-rw-r--r--chrome/browser/sync/syncable/model_type.h5
-rw-r--r--chrome/browser/sync/syncable/model_type_unittest.cc33
16 files changed, 728 insertions, 126 deletions
diff --git a/chrome/browser/sync/engine/syncapi.cc b/chrome/browser/sync/engine/syncapi.cc
index d2b8ecd..69e9e21 100644
--- a/chrome/browser/sync/engine/syncapi.cc
+++ b/chrome/browser/sync/engine/syncapi.cc
@@ -933,18 +933,70 @@ syncable::BaseTransaction* WriteTransaction::GetWrappedTrans() const {
return transaction_;
}
+SyncManager::ExtraChangeRecordData::~ExtraChangeRecordData() {}
+
SyncManager::ChangeRecord::ChangeRecord()
: id(kInvalidId), action(ACTION_ADD) {}
-SyncManager::ChangeRecord::~ChangeRecord() {}
+DictionaryValue* SyncManager::ChangeRecord::ToValue(
+ const BaseTransaction* trans) const {
+ DictionaryValue* value = new DictionaryValue();
+ std::string action_str;
+ switch (action) {
+ case ACTION_ADD:
+ action_str = "Add";
+ break;
+ case ACTION_DELETE:
+ action_str = "Delete";
+ break;
+ case ACTION_UPDATE:
+ action_str = "Update";
+ break;
+ default:
+ NOTREACHED();
+ action_str = "Unknown";
+ break;
+ }
+ value->SetString("action", action_str);
+ Value* node_value = NULL;
+ if (action == ACTION_DELETE) {
+ DictionaryValue* node_dict = new DictionaryValue();
+ node_dict->SetString("id", base::Int64ToString(id));
+ node_dict->Set("specifics",
+ browser_sync::EntitySpecificsToValue(specifics));
+ if (extra.get()) {
+ node_dict->Set("extra", extra->ToValue());
+ }
+ node_value = node_dict;
+ } else {
+ ReadNode node(trans);
+ if (node.InitByIdLookup(id)) {
+ node_value = node.ToValue();
+ }
+ }
+ if (!node_value) {
+ NOTREACHED();
+ node_value = Value::CreateNullValue();
+ }
+ value->Set("node", node_value);
+ return value;
+}
SyncManager::ExtraPasswordChangeRecordData::ExtraPasswordChangeRecordData(
const sync_pb::PasswordSpecificsData& data)
- : unencrypted_(data) {
-}
+ : unencrypted_(data) {}
SyncManager::ExtraPasswordChangeRecordData::~ExtraPasswordChangeRecordData() {}
+DictionaryValue* SyncManager::ExtraPasswordChangeRecordData::ToValue() const {
+ return browser_sync::PasswordSpecificsDataToValue(unencrypted_);
+}
+
+const sync_pb::PasswordSpecificsData&
+ SyncManager::ExtraPasswordChangeRecordData::unencrypted() const {
+ return unencrypted_;
+}
+
//////////////////////////////////////////////////////////////////////////
// SyncManager's implementation: SyncManager::SyncInternal
class SyncManager::SyncInternal
diff --git a/chrome/browser/sync/engine/syncapi.h b/chrome/browser/sync/engine/syncapi.h
index 2737b6c..e39a71f 100644
--- a/chrome/browser/sync/engine/syncapi.h
+++ b/chrome/browser/sync/engine/syncapi.h
@@ -592,8 +592,10 @@ class SyncManager {
// wrapper / add a templated method to return unencrypted protobufs.
class ExtraChangeRecordData {
public:
- ExtraChangeRecordData() {}
- virtual ~ExtraChangeRecordData() {}
+ virtual ~ExtraChangeRecordData();
+
+ // Transfers ownership of the DictionaryValue to the caller.
+ virtual DictionaryValue* ToValue() const = 0;
};
// ChangeRecord indicates a single item that changed as a result of a sync
@@ -607,7 +609,9 @@ class SyncManager {
ACTION_UPDATE,
};
ChangeRecord();
- ~ChangeRecord();
+
+ // Transfers ownership of the DictionaryValue to the caller.
+ DictionaryValue* ToValue(const BaseTransaction* trans) const;
int64 id;
Action action;
@@ -622,9 +626,12 @@ class SyncManager {
explicit ExtraPasswordChangeRecordData(
const sync_pb::PasswordSpecificsData& data);
virtual ~ExtraPasswordChangeRecordData();
- const sync_pb::PasswordSpecificsData& unencrypted() {
- return unencrypted_;
- }
+
+ // Transfers ownership of the DictionaryValue to the caller.
+ virtual DictionaryValue* ToValue() const;
+
+ const sync_pb::PasswordSpecificsData& unencrypted() const;
+
private:
sync_pb::PasswordSpecificsData unencrypted_;
};
diff --git a/chrome/browser/sync/engine/syncapi_unittest.cc b/chrome/browser/sync/engine/syncapi_unittest.cc
index f4a05a5..c2e3584 100644
--- a/chrome/browser/sync/engine/syncapi_unittest.cc
+++ b/chrome/browser/sync/engine/syncapi_unittest.cc
@@ -25,6 +25,7 @@
#include "chrome/browser/sync/syncable/directory_manager.h"
#include "chrome/browser/sync/syncable/syncable.h"
#include "chrome/test/sync/engine/test_directory_setter_upper.h"
+#include "chrome/test/values_test_util.h"
#include "jingle/notifier/base/notifier_options.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -34,12 +35,42 @@ using browser_sync::KeyParams;
using browser_sync::JsArgList;
using browser_sync::MockJsEventHandler;
using browser_sync::MockJsEventRouter;
+using test::ExpectDictionaryValue;
+using test::ExpectStringValue;
using testing::_;
+using testing::Invoke;
using testing::SaveArg;
using testing::StrictMock;
namespace sync_api {
+namespace {
+
+void ExpectInt64Value(int64 expected_value,
+ const DictionaryValue& value, const std::string& key) {
+ std::string int64_str;
+ EXPECT_TRUE(value.GetString(key, &int64_str));
+ int64 val = 0;
+ EXPECT_TRUE(base::StringToInt64(int64_str, &val));
+ EXPECT_EQ(expected_value, val);
+}
+
+// Makes a non-folder child of the root node. Returns the id of the
+// newly-created node.
+int64 MakeNode(UserShare* share,
+ syncable::ModelType model_type,
+ const std::string& client_tag) {
+ WriteTransaction trans(share);
+ ReadNode root_node(&trans);
+ root_node.InitByRootLookup();
+ WriteNode node(&trans);
+ EXPECT_TRUE(node.InitUniqueByCreation(model_type, root_node, client_tag));
+ node.SetIsFolder(false);
+ return node.GetId();
+}
+
+} // namespace
+
class SyncApiTest : public testing::Test {
public:
virtual void SetUp() {
@@ -79,16 +110,14 @@ TEST_F(SyncApiTest, SanityCheckTest) {
TEST_F(SyncApiTest, BasicTagWrite) {
{
- WriteTransaction trans(&share_);
+ ReadTransaction trans(&share_);
ReadNode root_node(&trans);
root_node.InitByRootLookup();
EXPECT_EQ(root_node.GetFirstChildId(), 0);
-
- WriteNode wnode(&trans);
- EXPECT_TRUE(wnode.InitUniqueByCreation(syncable::BOOKMARKS,
- root_node, "testtag"));
- wnode.SetIsFolder(false);
}
+
+ ignore_result(MakeNode(&share_, syncable::BOOKMARKS, "testtag"));
+
{
ReadTransaction trans(&share_);
ReadNode node(&trans);
@@ -124,22 +153,12 @@ TEST_F(SyncApiTest, ModelTypesSiloed) {
ReadNode root_node(&trans);
root_node.InitByRootLookup();
EXPECT_EQ(root_node.GetFirstChildId(), 0);
+ }
- WriteNode bookmarknode(&trans);
- EXPECT_TRUE(bookmarknode.InitUniqueByCreation(syncable::BOOKMARKS,
- root_node, "collideme"));
- bookmarknode.SetIsFolder(false);
-
- WriteNode prefnode(&trans);
- EXPECT_TRUE(prefnode.InitUniqueByCreation(syncable::PREFERENCES,
- root_node, "collideme"));
- prefnode.SetIsFolder(false);
+ ignore_result(MakeNode(&share_, syncable::BOOKMARKS, "collideme"));
+ ignore_result(MakeNode(&share_, syncable::PREFERENCES, "collideme"));
+ ignore_result(MakeNode(&share_, syncable::AUTOFILL, "collideme"));
- WriteNode autofillnode(&trans);
- EXPECT_TRUE(autofillnode.InitUniqueByCreation(syncable::AUTOFILL,
- root_node, "collideme"));
- autofillnode.SetIsFolder(false);
- }
{
ReadTransaction trans(&share_);
@@ -286,29 +305,16 @@ TEST_F(SyncApiTest, WriteAndReadPassword) {
namespace {
-int64 GetInt64Value(const DictionaryValue& value, const std::string& key) {
- std::string str;
- EXPECT_TRUE(value.GetString(key, &str));
- int64 val = 0;
- EXPECT_TRUE(base::StringToInt64(str, &val));
- return val;
-}
-
void CheckNodeValue(const BaseNode& node, const DictionaryValue& value) {
- EXPECT_EQ(node.GetId(), GetInt64Value(value, "id"));
- EXPECT_EQ(node.GetModificationTime(),
- GetInt64Value(value, "modificationTime"));
- EXPECT_EQ(node.GetParentId(), GetInt64Value(value, "parentId"));
+ ExpectInt64Value(node.GetId(), value, "id");
+ ExpectInt64Value(node.GetModificationTime(), value, "modificationTime");
+ ExpectInt64Value(node.GetParentId(), value, "parentId");
{
bool is_folder = false;
EXPECT_TRUE(value.GetBoolean("isFolder", &is_folder));
EXPECT_EQ(node.GetIsFolder(), is_folder);
}
- {
- std::string title;
- EXPECT_TRUE(value.GetString("title", &title));
- EXPECT_EQ(node.GetTitle(), UTF8ToWide(title));
- }
+ ExpectStringValue(WideToUTF8(node.GetTitle()), value, "title");
{
syncable::ModelType expected_model_type = node.GetModelType();
std::string type_str;
@@ -333,10 +339,10 @@ void CheckNodeValue(const BaseNode& node, const DictionaryValue& value) {
EXPECT_TRUE(value.Get("specifics", &specifics));
EXPECT_TRUE(Value::Equals(specifics, expected_specifics.get()));
}
- EXPECT_EQ(node.GetExternalId(), GetInt64Value(value, "externalId"));
- EXPECT_EQ(node.GetPredecessorId(), GetInt64Value(value, "predecessorId"));
- EXPECT_EQ(node.GetSuccessorId(), GetInt64Value(value, "successorId"));
- EXPECT_EQ(node.GetFirstChildId(), GetInt64Value(value, "firstChildId"));
+ ExpectInt64Value(node.GetExternalId(), value, "externalId");
+ ExpectInt64Value(node.GetPredecessorId(), value, "predecessorId");
+ ExpectInt64Value(node.GetSuccessorId(), value, "successorId");
+ ExpectInt64Value(node.GetFirstChildId(), value, "firstChildId");
EXPECT_EQ(11u, value.size());
}
@@ -356,6 +362,139 @@ TEST_F(SyncApiTest, BaseNodeToValue) {
namespace {
+void ExpectChangeRecordActionValue(SyncManager::ChangeRecord::Action
+ expected_value,
+ const DictionaryValue& value,
+ const std::string& key) {
+ std::string str_value;
+ EXPECT_TRUE(value.GetString(key, &str_value));
+ switch (expected_value) {
+ case SyncManager::ChangeRecord::ACTION_ADD:
+ EXPECT_EQ("Add", str_value);
+ break;
+ case SyncManager::ChangeRecord::ACTION_UPDATE:
+ EXPECT_EQ("Update", str_value);
+ break;
+ case SyncManager::ChangeRecord::ACTION_DELETE:
+ EXPECT_EQ("Delete", str_value);
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+void CheckNonDeleteChangeRecordValue(const SyncManager::ChangeRecord& record,
+ const DictionaryValue& value,
+ BaseTransaction* trans) {
+ EXPECT_NE(SyncManager::ChangeRecord::ACTION_DELETE, record.action);
+ ExpectChangeRecordActionValue(record.action, value, "action");
+ {
+ ReadNode node(trans);
+ EXPECT_TRUE(node.InitByIdLookup(record.id));
+ scoped_ptr<DictionaryValue> expected_node_value(node.ToValue());
+ ExpectDictionaryValue(*expected_node_value, value, "node");
+ }
+}
+
+void CheckDeleteChangeRecordValue(const SyncManager::ChangeRecord& record,
+ const DictionaryValue& value) {
+ EXPECT_EQ(SyncManager::ChangeRecord::ACTION_DELETE, record.action);
+ ExpectChangeRecordActionValue(record.action, value, "action");
+ DictionaryValue* node_value = NULL;
+ EXPECT_TRUE(value.GetDictionary("node", &node_value));
+ if (node_value) {
+ ExpectInt64Value(record.id, *node_value, "id");
+ scoped_ptr<DictionaryValue> expected_specifics_value(
+ browser_sync::EntitySpecificsToValue(record.specifics));
+ ExpectDictionaryValue(*expected_specifics_value,
+ *node_value, "specifics");
+ scoped_ptr<DictionaryValue> expected_extra_value;
+ if (record.extra.get()) {
+ expected_extra_value.reset(record.extra->ToValue());
+ }
+ Value* extra_value = NULL;
+ EXPECT_EQ(record.extra.get() != NULL,
+ node_value->Get("extra", &extra_value));
+ EXPECT_TRUE(Value::Equals(extra_value, expected_extra_value.get()));
+ }
+}
+
+class MockExtraChangeRecordData : public SyncManager::ExtraChangeRecordData {
+ public:
+ MOCK_CONST_METHOD0(ToValue, DictionaryValue*());
+};
+
+} // namespace
+
+TEST_F(SyncApiTest, ChangeRecordToValue) {
+ int64 child_id = MakeNode(&share_, syncable::BOOKMARKS, "testtag");
+ sync_pb::EntitySpecifics child_specifics;
+ {
+ ReadTransaction trans(&share_);
+ ReadNode node(&trans);
+ EXPECT_TRUE(node.InitByIdLookup(child_id));
+ child_specifics = node.GetEntry()->Get(syncable::SPECIFICS);
+ }
+
+ // Add
+ {
+ ReadTransaction trans(&share_);
+ SyncManager::ChangeRecord record;
+ record.action = SyncManager::ChangeRecord::ACTION_ADD;
+ record.id = 1;
+ record.specifics = child_specifics;
+ record.extra.reset(new StrictMock<MockExtraChangeRecordData>());
+ scoped_ptr<DictionaryValue> value(record.ToValue(&trans));
+ CheckNonDeleteChangeRecordValue(record, *value, &trans);
+ }
+
+ // Update
+ {
+ ReadTransaction trans(&share_);
+ SyncManager::ChangeRecord record;
+ record.action = SyncManager::ChangeRecord::ACTION_UPDATE;
+ record.id = child_id;
+ record.specifics = child_specifics;
+ record.extra.reset(new StrictMock<MockExtraChangeRecordData>());
+ scoped_ptr<DictionaryValue> value(record.ToValue(&trans));
+ CheckNonDeleteChangeRecordValue(record, *value, &trans);
+ }
+
+ // Delete (no extra)
+ {
+ ReadTransaction trans(&share_);
+ SyncManager::ChangeRecord record;
+ record.action = SyncManager::ChangeRecord::ACTION_DELETE;
+ record.id = child_id + 1;
+ record.specifics = child_specifics;
+ scoped_ptr<DictionaryValue> value(record.ToValue(&trans));
+ CheckDeleteChangeRecordValue(record, *value);
+ }
+
+ // Delete (with extra)
+ {
+ ReadTransaction trans(&share_);
+ SyncManager::ChangeRecord record;
+ record.action = SyncManager::ChangeRecord::ACTION_DELETE;
+ record.id = child_id + 1;
+ record.specifics = child_specifics;
+
+ DictionaryValue extra_value;
+ extra_value.SetString("foo", "bar");
+ scoped_ptr<StrictMock<MockExtraChangeRecordData> > extra(
+ new StrictMock<MockExtraChangeRecordData>());
+ EXPECT_CALL(*extra, ToValue()).Times(2).WillRepeatedly(
+ Invoke(&extra_value, &DictionaryValue::DeepCopy));
+
+ record.extra.reset(extra.release());
+ scoped_ptr<DictionaryValue> value(record.ToValue(&trans));
+ CheckDeleteChangeRecordValue(record, *value);
+ }
+}
+
+namespace {
+
class TestHttpPostProviderFactory : public HttpPostProviderFactory {
public:
virtual ~TestHttpPostProviderFactory() {}
@@ -506,19 +645,8 @@ void CheckGetNodeByIdReturnArgs(const SyncManager& sync_manager,
}
TEST_F(SyncManagerTest, ProcessMessageGetNodeById) {
- int64 child_id = kInvalidId;
- {
- WriteTransaction trans(sync_manager_.GetUserShare());
-
- ReadNode root_node(&trans);
- root_node.InitByRootLookup();
-
- WriteNode node(&trans);
- EXPECT_TRUE(node.InitUniqueByCreation(syncable::BOOKMARKS,
- root_node, "testtag"));
- node.SetIsFolder(false);
- child_id = node.GetId();
- }
+ int64 child_id =
+ MakeNode(sync_manager_.GetUserShare(), syncable::BOOKMARKS, "testtag");
browser_sync::JsBackend* js_backend = sync_manager_.GetJsBackend();
diff --git a/chrome/browser/sync/protocol/proto_enum_conversions.cc b/chrome/browser/sync/protocol/proto_enum_conversions.cc
index 7421711..df3d184 100644
--- a/chrome/browser/sync/protocol/proto_enum_conversions.cc
+++ b/chrome/browser/sync/protocol/proto_enum_conversions.cc
@@ -68,6 +68,23 @@ const char* GetPageTransitionQualifierString(
return "";
}
+const char* GetUpdatesSourceString(
+ sync_pb::GetUpdatesCallerInfo::GetUpdatesSource updates_source) {
+ ASSERT_ENUM_BOUNDS(sync_pb::GetUpdatesCallerInfo, GetUpdatesSource,
+ UNKNOWN, CLEAR_PRIVATE_DATA);
+ switch (updates_source) {
+ ENUM_CASE(sync_pb::GetUpdatesCallerInfo, UNKNOWN);
+ ENUM_CASE(sync_pb::GetUpdatesCallerInfo, FIRST_UPDATE);
+ ENUM_CASE(sync_pb::GetUpdatesCallerInfo, LOCAL);
+ ENUM_CASE(sync_pb::GetUpdatesCallerInfo, NOTIFICATION);
+ ENUM_CASE(sync_pb::GetUpdatesCallerInfo, PERIODIC);
+ ENUM_CASE(sync_pb::GetUpdatesCallerInfo, SYNC_CYCLE_CONTINUATION);
+ ENUM_CASE(sync_pb::GetUpdatesCallerInfo, CLEAR_PRIVATE_DATA);
+ }
+ NOTREACHED();
+ return "";
+}
+
#undef ASSERT_ENUM_BOUNDS
#undef ENUM_CASE
diff --git a/chrome/browser/sync/protocol/proto_enum_conversions.h b/chrome/browser/sync/protocol/proto_enum_conversions.h
index 62b6157..fd1142d 100644
--- a/chrome/browser/sync/protocol/proto_enum_conversions.h
+++ b/chrome/browser/sync/protocol/proto_enum_conversions.h
@@ -28,6 +28,9 @@ const char* GetPageTransitionQualifierString(
sync_pb::TabNavigation::PageTransitionQualifier
page_transition_qualifier);
+const char* GetUpdatesSourceString(
+ sync_pb::GetUpdatesCallerInfo::GetUpdatesSource updates_source);
+
} // namespace browser_sync
#endif // CHROME_BROWSER_SYNC_PROTOCOL_PROTO_ENUM_CONVERSIONS_H_
diff --git a/chrome/browser/sync/protocol/proto_enum_conversions_unittest.cc b/chrome/browser/sync/protocol/proto_enum_conversions_unittest.cc
index 8825458..648cfe6 100644
--- a/chrome/browser/sync/protocol/proto_enum_conversions_unittest.cc
+++ b/chrome/browser/sync/protocol/proto_enum_conversions_unittest.cc
@@ -51,5 +51,12 @@ TEST_F(ProtoEnumConversionsTest, GetPageTransitionQualifierString) {
sync_pb::TabNavigation::PageTransitionQualifier_MAX);
}
+TEST_F(ProtoEnumConversionsTest, GetUpdatesSourceString) {
+ TestEnumStringFunction(
+ GetUpdatesSourceString,
+ sync_pb::GetUpdatesCallerInfo::GetUpdatesSource_MIN,
+ sync_pb::GetUpdatesCallerInfo::GetUpdatesSource_MAX);
+}
+
} // namespace
} // namespace browser_sync
diff --git a/chrome/browser/sync/protocol/proto_value_conversions.cc b/chrome/browser/sync/protocol/proto_value_conversions.cc
index 57be094..12ece6e 100644
--- a/chrome/browser/sync/protocol/proto_value_conversions.cc
+++ b/chrome/browser/sync/protocol/proto_value_conversions.cc
@@ -99,6 +99,67 @@ DictionaryValue* EncryptedDataToValue(const sync_pb::EncryptedData& proto) {
return value;
}
+DictionaryValue* SessionHeaderToValue(
+ const sync_pb::SessionHeader& proto) {
+ DictionaryValue* value = new DictionaryValue();
+ SET_REP(window, SessionWindowToValue);
+ return value;
+}
+
+DictionaryValue* SessionTabToValue(
+ const sync_pb::SessionTab& proto) {
+ DictionaryValue* value = new DictionaryValue();
+ SET_INT32(tab_id);
+ SET_INT32(window_id);
+ SET_INT32(tab_visual_index);
+ SET_INT32(current_navigation_index);
+ SET_BOOL(pinned);
+ SET_STR(extension_app_id);
+ SET_REP(navigation, TabNavigationToValue);
+ return value;
+}
+
+DictionaryValue* SessionWindowToValue(
+ const sync_pb::SessionWindow& proto) {
+ DictionaryValue* value = new DictionaryValue();
+ SET_INT32(window_id);
+ SET_INT32(selected_tab_index);
+ SET_INT32_REP(tab);
+ SET_ENUM(browser_type, GetBrowserTypeString);
+ return value;
+}
+
+DictionaryValue* TabNavigationToValue(
+ const sync_pb::TabNavigation& proto) {
+ DictionaryValue* value = new DictionaryValue();
+ SET_INT32(index);
+ SET_STR(virtual_url);
+ SET_STR(referrer);
+ SET_STR(title);
+ SET_STR(state);
+ SET_ENUM(page_transition, GetPageTransitionString);
+ SET_ENUM(navigation_qualifier, GetPageTransitionQualifierString);
+ return value;
+}
+
+DictionaryValue* PasswordSpecificsDataToValue(
+ const sync_pb::PasswordSpecificsData& proto) {
+ DictionaryValue* value = new DictionaryValue();
+ SET_INT32(scheme);
+ SET_STR(signon_realm);
+ SET_STR(origin);
+ SET_STR(action);
+ SET_STR(username_element);
+ SET_STR(username_value);
+ SET_STR(password_element);
+ value->SetString("password_value", "<redacted>");
+ SET_BOOL(ssl_valid);
+ SET_BOOL(preferred);
+ SET_INT64(date_created);
+ SET_BOOL(blacklisted);
+ return value;
+}
+
DictionaryValue* AppSpecificsToValue(
const sync_pb::AppSpecifics& proto) {
DictionaryValue* value = new DictionaryValue();
@@ -200,49 +261,6 @@ DictionaryValue* PreferenceSpecificsToValue(
return value;
}
-DictionaryValue* SessionHeaderToValue(
- const sync_pb::SessionHeader& proto) {
- DictionaryValue* value = new DictionaryValue();
- SET_REP(window, SessionWindowToValue);
- return value;
-}
-
-DictionaryValue* SessionTabToValue(
- const sync_pb::SessionTab& proto) {
- DictionaryValue* value = new DictionaryValue();
- SET_INT32(tab_id);
- SET_INT32(window_id);
- SET_INT32(tab_visual_index);
- SET_INT32(current_navigation_index);
- SET_BOOL(pinned);
- SET_STR(extension_app_id);
- SET_REP(navigation, TabNavigationToValue);
- return value;
-}
-
-DictionaryValue* SessionWindowToValue(
- const sync_pb::SessionWindow& proto) {
- DictionaryValue* value = new DictionaryValue();
- SET_INT32(window_id);
- SET_INT32(selected_tab_index);
- SET_INT32_REP(tab);
- SET_ENUM(browser_type, GetBrowserTypeString);
- return value;
-}
-
-DictionaryValue* TabNavigationToValue(
- const sync_pb::TabNavigation& proto) {
- DictionaryValue* value = new DictionaryValue();
- SET_INT32(index);
- SET_STR(virtual_url);
- SET_STR(referrer);
- SET_STR(title);
- SET_STR(state);
- SET_ENUM(page_transition, GetPageTransitionString);
- SET_ENUM(navigation_qualifier, GetPageTransitionQualifierString);
- return value;
-}
-
DictionaryValue* SessionSpecificsToValue(
const sync_pb::SessionSpecifics& proto) {
DictionaryValue* value = new DictionaryValue();
diff --git a/chrome/browser/sync/protocol/proto_value_conversions.h b/chrome/browser/sync/protocol/proto_value_conversions.h
index c6e4b1d..c2c1ab53 100644
--- a/chrome/browser/sync/protocol/proto_value_conversions.h
+++ b/chrome/browser/sync/protocol/proto_value_conversions.h
@@ -21,6 +21,7 @@ class EntitySpecifics;
class ExtensionSpecifics;
class NigoriSpecifics;
class PasswordSpecifics;
+class PasswordSpecificsData;
class PreferenceSpecifics;
class SessionHeader;
class SessionSpecifics;
@@ -63,6 +64,11 @@ DictionaryValue* SessionWindowToValue(
DictionaryValue* TabNavigationToValue(
const sync_pb::TabNavigation& tab_navigation);
+// Sub-protocol of PasswordSpecifics.
+
+DictionaryValue* PasswordSpecificsDataToValue(
+ const sync_pb::PasswordSpecificsData& password_specifics_data);
+
// Main *SpecificsToValue functions.
DictionaryValue* AppSpecificsToValue(
diff --git a/chrome/browser/sync/protocol/proto_value_conversions_unittest.cc b/chrome/browser/sync/protocol/proto_value_conversions_unittest.cc
index 3416282..20e73e4 100644
--- a/chrome/browser/sync/protocol/proto_value_conversions_unittest.cc
+++ b/chrome/browser/sync/protocol/proto_value_conversions_unittest.cc
@@ -56,6 +56,32 @@ TEST_F(ProtoValueConversionsTest, EncryptedDataToValue) {
TestSpecificsToValue(EncryptedDataToValue);
}
+TEST_F(ProtoValueConversionsTest, SessionHeaderToValue) {
+ TestSpecificsToValue(SessionHeaderToValue);
+}
+
+TEST_F(ProtoValueConversionsTest, SessionTabToValue) {
+ TestSpecificsToValue(SessionTabToValue);
+}
+
+TEST_F(ProtoValueConversionsTest, SessionWindowToValue) {
+ TestSpecificsToValue(SessionWindowToValue);
+}
+
+TEST_F(ProtoValueConversionsTest, TabNavigationToValue) {
+ TestSpecificsToValue(TabNavigationToValue);
+}
+
+TEST_F(ProtoValueConversionsTest, PasswordSpecificsData) {
+ sync_pb::PasswordSpecificsData specifics;
+ specifics.set_password_value("secret");
+ scoped_ptr<DictionaryValue> value(PasswordSpecificsDataToValue(specifics));
+ EXPECT_FALSE(value->empty());
+ std::string password_value;
+ EXPECT_TRUE(value->GetString("password_value", &password_value));
+ EXPECT_EQ("<redacted>", password_value);
+}
+
TEST_F(ProtoValueConversionsTest, AppSpecificsToValue) {
TestSpecificsToValue(AppSpecificsToValue);
}
@@ -92,26 +118,10 @@ TEST_F(ProtoValueConversionsTest, PreferenceSpecificsToValue) {
TestSpecificsToValue(PreferenceSpecificsToValue);
}
-TEST_F(ProtoValueConversionsTest, SessionHeaderToValue) {
- TestSpecificsToValue(SessionHeaderToValue);
-}
-
TEST_F(ProtoValueConversionsTest, SessionSpecificsToValue) {
TestSpecificsToValue(SessionSpecificsToValue);
}
-TEST_F(ProtoValueConversionsTest, SessionTabToValue) {
- TestSpecificsToValue(SessionTabToValue);
-}
-
-TEST_F(ProtoValueConversionsTest, SessionWindowToValue) {
- TestSpecificsToValue(SessionWindowToValue);
-}
-
-TEST_F(ProtoValueConversionsTest, TabNavigationToValue) {
- TestSpecificsToValue(TabNavigationToValue);
-}
-
TEST_F(ProtoValueConversionsTest, ThemeSpecificsToValue) {
TestSpecificsToValue(ThemeSpecificsToValue);
}
diff --git a/chrome/browser/sync/protocol/sync.proto b/chrome/browser/sync/protocol/sync.proto
index e60d209..6af021b 100644
--- a/chrome/browser/sync/protocol/sync.proto
+++ b/chrome/browser/sync/protocol/sync.proto
@@ -266,7 +266,7 @@ message GetUpdatesCallerInfo {
// continuation of a previous update.
CLEAR_PRIVATE_DATA = 6; // Source is a call to remove all private data
}
-
+
required GetUpdatesSource source = 1;
// True only if notifications were enabled for this GetUpdateMessage.
diff --git a/chrome/browser/sync/sessions/session_state.cc b/chrome/browser/sync/sessions/session_state.cc
index 3c9887b..e52ebdc 100644
--- a/chrome/browser/sync/sessions/session_state.cc
+++ b/chrome/browser/sync/sessions/session_state.cc
@@ -7,6 +7,10 @@
#include <set>
#include <vector>
+#include "base/base64.h"
+#include "base/values.h"
+#include "chrome/browser/sync/protocol/proto_enum_conversions.h"
+
using std::set;
using std::vector;
@@ -37,6 +41,15 @@ TypePayloadMap MakeTypePayloadMapFromRoutingInfo(
return types_with_payloads;
}
+DictionaryValue* TypePayloadMapToValue(const TypePayloadMap& type_payloads) {
+ DictionaryValue* value = new DictionaryValue();
+ for (TypePayloadMap::const_iterator it = type_payloads.begin();
+ it != type_payloads.end(); ++it) {
+ value->SetString(syncable::ModelTypeToString(it->first), it->second);
+ }
+ return value;
+}
+
void CoalescePayloads(TypePayloadMap* original,
const TypePayloadMap& update) {
for (TypePayloadMap::const_iterator i = update.begin();
@@ -63,6 +76,14 @@ SyncSourceInfo::SyncSourceInfo(
SyncSourceInfo::~SyncSourceInfo() {}
+DictionaryValue* SyncSourceInfo::ToValue() const {
+ DictionaryValue* value = new DictionaryValue();
+ value->SetString("updatesSource",
+ GetUpdatesSourceString(updates_source));
+ value->Set("types", TypePayloadMapToValue(types));
+ return value;
+}
+
SyncerStatus::SyncerStatus()
: invalid_store(false),
syncer_stuck(false),
@@ -73,19 +94,62 @@ SyncerStatus::SyncerStatus()
num_tombstone_updates_downloaded_total(0) {
}
+DictionaryValue* SyncerStatus::ToValue() const {
+ DictionaryValue* value = new DictionaryValue();
+ value->SetBoolean("invalidStore", invalid_store);
+ value->SetBoolean("syncerStuck", syncer_stuck);
+ value->SetBoolean("syncing", syncing);
+ 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);
+ return value;
+}
+
+DictionaryValue* DownloadProgressMarkersToValue(
+ const std::string
+ (&download_progress_markers)[syncable::MODEL_TYPE_COUNT]) {
+ DictionaryValue* value = new DictionaryValue();
+ for (int i = syncable::FIRST_REAL_MODEL_TYPE;
+ i < syncable::MODEL_TYPE_COUNT; ++i) {
+ // TODO(akalin): Unpack the value into a protobuf.
+ std::string base64_marker;
+ bool encoded =
+ base::Base64Encode(download_progress_markers[i], &base64_marker);
+ DCHECK(encoded);
+ value->SetString(
+ syncable::ModelTypeToString(syncable::ModelTypeFromInt(i)),
+ base64_marker);
+ }
+ return value;
+}
+
ErrorCounters::ErrorCounters()
: num_conflicting_commits(0),
consecutive_transient_error_commits(0),
consecutive_errors(0) {
}
+DictionaryValue* ErrorCounters::ToValue() const {
+ DictionaryValue* value = new DictionaryValue();
+ value->SetInteger("numConflictingCommits", num_conflicting_commits);
+ value->SetInteger("consecutiveTransientErrorCommits",
+ consecutive_transient_error_commits);
+ value->SetInteger("consecutiveErrors", consecutive_errors);
+ return value;
+}
+
SyncSessionSnapshot::SyncSessionSnapshot(
const SyncerStatus& syncer_status,
const ErrorCounters& errors,
int64 num_server_changes_remaining,
bool is_share_usable,
const syncable::ModelTypeBitSet& initial_sync_ended,
- std::string download_progress_markers[syncable::MODEL_TYPE_COUNT],
+ const std::string
+ (&download_progress_markers)[syncable::MODEL_TYPE_COUNT],
bool more_to_sync,
bool is_silenced,
int64 unsynced_count,
@@ -104,7 +168,8 @@ SyncSessionSnapshot::SyncSessionSnapshot(
num_conflicting_updates(num_conflicting_updates),
did_commit_items(did_commit_items),
source(source) {
- for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) {
+ for (int i = syncable::FIRST_REAL_MODEL_TYPE;
+ i < syncable::MODEL_TYPE_COUNT; ++i) {
const_cast<std::string&>(this->download_progress_markers[i]).assign(
download_progress_markers[i]);
}
@@ -112,6 +177,29 @@ SyncSessionSnapshot::SyncSessionSnapshot(
SyncSessionSnapshot::~SyncSessionSnapshot() {}
+DictionaryValue* SyncSessionSnapshot::ToValue() const {
+ DictionaryValue* value = new DictionaryValue();
+ value->Set("syncerStatus", syncer_status.ToValue());
+ value->Set("errors", errors.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::ModelTypeBitSetToValue(initial_sync_ended));
+ value->Set("downloadProgressMarkers",
+ DownloadProgressMarkersToValue(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("unsyncedCount",
+ static_cast<int>(unsynced_count));
+ value->SetInteger("numConflictingUpdates", num_conflicting_updates);
+ value->SetBoolean("didCommitItems", did_commit_items);
+ value->Set("source", source.ToValue());
+ return value;
+}
+
ConflictProgress::ConflictProgress(bool* dirty_flag) : dirty_(dirty_flag) {}
ConflictProgress::~ConflictProgress() {
diff --git a/chrome/browser/sync/sessions/session_state.h b/chrome/browser/sync/sessions/session_state.h
index d1a6e17..69fbf7a 100644
--- a/chrome/browser/sync/sessions/session_state.h
+++ b/chrome/browser/sync/sessions/session_state.h
@@ -23,6 +23,8 @@
#include "chrome/browser/sync/syncable/model_type.h"
#include "chrome/browser/sync/syncable/syncable.h"
+class DictionaryValue;
+
namespace syncable {
class DirectoryManager;
}
@@ -48,6 +50,9 @@ TypePayloadMap MakeTypePayloadMapFromRoutingInfo(
const ModelSafeRoutingInfo& routes,
const std::string& payload);
+// Caller takes ownership of the returned dictionary.
+DictionaryValue* TypePayloadMapToValue(const TypePayloadMap& type_payloads);
+
// Coalesce |update| into |original|, overwriting only when |update| has
// a non-empty payload.
void CoalescePayloads(TypePayloadMap* original, const TypePayloadMap& update);
@@ -62,6 +67,9 @@ struct SyncSourceInfo {
const TypePayloadMap& t);
~SyncSourceInfo();
+ // Caller takes ownership of the returned dictionary.
+ DictionaryValue* ToValue() const;
+
sync_pb::GetUpdatesCallerInfo::GetUpdatesSource updates_source;
TypePayloadMap types;
};
@@ -70,6 +78,9 @@ struct SyncSourceInfo {
struct SyncerStatus {
SyncerStatus();
+ // Caller takes ownership of the returned dictionary.
+ DictionaryValue* ToValue() const;
+
// True when we get such an INVALID_STORE error from the server.
bool invalid_store;
// True iff we're stuck.
@@ -87,6 +98,10 @@ struct SyncerStatus {
// Counters for various errors that can occur repeatedly during a sync session.
struct ErrorCounters {
ErrorCounters();
+
+ // Caller takes ownership of the returned dictionary.
+ DictionaryValue* ToValue() const;
+
int num_conflicting_commits;
// Number of commits hitting transient errors since the last successful
@@ -99,6 +114,11 @@ struct ErrorCounters {
int consecutive_errors;
};
+// Caller takes ownership of the returned dictionary.
+DictionaryValue* DownloadProgressMarkersToValue(
+ const std::string
+ (&download_progress_markers)[syncable::MODEL_TYPE_COUNT]);
+
// An immutable snapshot of state from a SyncSession. Convenient to use as
// part of notifications as it is inherently thread-safe.
struct SyncSessionSnapshot {
@@ -108,7 +128,8 @@ struct SyncSessionSnapshot {
int64 num_server_changes_remaining,
bool is_share_usable,
const syncable::ModelTypeBitSet& initial_sync_ended,
- std::string download_progress_markers[syncable::MODEL_TYPE_COUNT],
+ const std::string
+ (&download_progress_markers)[syncable::MODEL_TYPE_COUNT],
bool more_to_sync,
bool is_silenced,
int64 unsynced_count,
@@ -117,6 +138,9 @@ struct SyncSessionSnapshot {
const SyncSourceInfo& source);
~SyncSessionSnapshot();
+ // Caller takes ownership of the returned dictionary.
+ DictionaryValue* ToValue() const;
+
const SyncerStatus syncer_status;
const ErrorCounters errors;
const int64 num_server_changes_remaining;
diff --git a/chrome/browser/sync/sessions/session_state_unittest.cc b/chrome/browser/sync/sessions/session_state_unittest.cc
new file mode 100644
index 0000000..3ac832f
--- /dev/null
+++ b/chrome/browser/sync/sessions/session_state_unittest.cc
@@ -0,0 +1,191 @@
+// Copyright (c) 2011 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 "chrome/browser/sync/sessions/session_state.h"
+
+#include <string>
+
+#include "base/base64.h"
+#include "base/scoped_ptr.h"
+#include "base/values.h"
+#include "chrome/test/values_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace browser_sync {
+namespace sessions {
+namespace {
+
+using test::ExpectBooleanValue;
+using test::ExpectDictionaryValue;
+using test::ExpectIntegerValue;
+using test::ExpectListValue;
+using test::ExpectStringValue;
+
+class SessionStateTest : public testing::Test {};
+
+TEST_F(SessionStateTest, TypePayloadMapToValue) {
+ TypePayloadMap payloads;
+ payloads[syncable::BOOKMARKS] = "bookmarkpayload";
+ payloads[syncable::APPS] = "";
+
+ scoped_ptr<DictionaryValue> value(TypePayloadMapToValue(payloads));
+ EXPECT_EQ(2u, value->size());
+ ExpectStringValue("bookmarkpayload", *value, "Bookmarks");
+ ExpectStringValue("", *value, "Apps");
+ EXPECT_FALSE(value->HasKey("Preferences"));
+}
+
+TEST_F(SessionStateTest, SyncSourceInfoToValue) {
+ sync_pb::GetUpdatesCallerInfo::GetUpdatesSource updates_source =
+ sync_pb::GetUpdatesCallerInfo::PERIODIC;
+ TypePayloadMap types;
+ types[syncable::PREFERENCES] = "preferencespayload";
+ types[syncable::EXTENSIONS] = "";
+ scoped_ptr<DictionaryValue> expected_types_value(
+ TypePayloadMapToValue(types));
+
+ SyncSourceInfo source_info(updates_source, types);
+
+ scoped_ptr<DictionaryValue> value(source_info.ToValue());
+ EXPECT_EQ(2u, value->size());
+ ExpectStringValue("PERIODIC", *value, "updatesSource");
+ ExpectDictionaryValue(*expected_types_value, *value, "types");
+}
+
+TEST_F(SessionStateTest, SyncerStatusToValue) {
+ SyncerStatus status;
+ status.invalid_store = true;
+ status.syncer_stuck = false;
+ status.syncing = true;
+ status.num_successful_commits = 5;
+ status.num_successful_bookmark_commits = 10;
+ status.num_updates_downloaded_total = 100;
+ status.num_tombstone_updates_downloaded_total = 200;
+
+ scoped_ptr<DictionaryValue> value(status.ToValue());
+ EXPECT_EQ(7u, value->size());
+ ExpectBooleanValue(status.invalid_store, *value, "invalidStore");
+ ExpectBooleanValue(status.syncer_stuck, *value, "syncerStuck");
+ ExpectBooleanValue(status.syncing, *value, "syncing");
+ ExpectIntegerValue(status.num_successful_commits,
+ *value, "numSuccessfulCommits");
+ ExpectIntegerValue(status.num_successful_bookmark_commits,
+ *value, "numSuccessfulBookmarkCommits");
+ ExpectIntegerValue(status.num_updates_downloaded_total,
+ *value, "numUpdatesDownloadedTotal");
+ ExpectIntegerValue(status.num_tombstone_updates_downloaded_total,
+ *value, "numTombstoneUpdatesDownloadedTotal");
+}
+
+TEST_F(SessionStateTest, ErrorCountersToValue) {
+ ErrorCounters counters;
+ counters.num_conflicting_commits = 1;
+ counters.consecutive_transient_error_commits = 5;
+ counters.consecutive_errors = 3;
+
+ scoped_ptr<DictionaryValue> value(counters.ToValue());
+ EXPECT_EQ(3u, value->size());
+ ExpectIntegerValue(counters.num_conflicting_commits,
+ *value, "numConflictingCommits");
+ ExpectIntegerValue(counters.consecutive_transient_error_commits,
+ *value, "consecutiveTransientErrorCommits");
+ ExpectIntegerValue(counters.consecutive_errors,
+ *value, "consecutiveErrors");
+}
+
+TEST_F(SessionStateTest, DownloadProgressMarkersToValue) {
+ std::string download_progress_markers[syncable::MODEL_TYPE_COUNT];
+ for (int i = syncable::FIRST_REAL_MODEL_TYPE;
+ i < syncable::MODEL_TYPE_COUNT; ++i) {
+ std::string marker(i, i);
+ download_progress_markers[i] = marker;
+ }
+
+ scoped_ptr<DictionaryValue> value(
+ DownloadProgressMarkersToValue(download_progress_markers));
+ EXPECT_EQ(syncable::MODEL_TYPE_COUNT - syncable::FIRST_REAL_MODEL_TYPE,
+ static_cast<int>(value->size()));
+ for (int i = syncable::FIRST_REAL_MODEL_TYPE;
+ i < syncable::MODEL_TYPE_COUNT; ++i) {
+ syncable::ModelType model_type = syncable::ModelTypeFromInt(i);
+ std::string marker(i, i);
+ std::string expected_value;
+ EXPECT_TRUE(base::Base64Encode(marker, &expected_value));
+ ExpectStringValue(expected_value,
+ *value, syncable::ModelTypeToString(model_type));
+ }
+}
+
+TEST_F(SessionStateTest, SyncSessionSnapshotToValue) {
+ SyncerStatus syncer_status;
+ syncer_status.num_successful_commits = 500;
+ scoped_ptr<DictionaryValue> expected_syncer_status_value(
+ syncer_status.ToValue());
+
+ ErrorCounters errors;
+ errors.num_conflicting_commits = 250;
+ scoped_ptr<DictionaryValue> expected_errors_value(
+ errors.ToValue());
+
+ const int kNumServerChangesRemaining = 105;
+ const bool kIsShareUsable = true;
+
+ syncable::ModelTypeBitSet initial_sync_ended;
+ initial_sync_ended.set(syncable::BOOKMARKS);
+ initial_sync_ended.set(syncable::PREFERENCES);
+ scoped_ptr<ListValue> expected_initial_sync_ended_value(
+ syncable::ModelTypeBitSetToValue(initial_sync_ended));
+
+ std::string download_progress_markers[syncable::MODEL_TYPE_COUNT];
+ download_progress_markers[syncable::BOOKMARKS] = "test";
+ download_progress_markers[syncable::APPS] = "apps";
+ scoped_ptr<DictionaryValue> expected_download_progress_markers_value(
+ DownloadProgressMarkersToValue(download_progress_markers));
+
+ const bool kHasMoreToSync = false;
+ const bool kIsSilenced = true;
+ const int kUnsyncedCount = 1053;
+ const int kNumConflictingUpdates = 1055;
+ const bool kDidCommitItems = true;
+
+ SyncSourceInfo source;
+ scoped_ptr<DictionaryValue> expected_source_value(source.ToValue());
+
+ SyncSessionSnapshot snapshot(syncer_status,
+ errors,
+ kNumServerChangesRemaining,
+ kIsShareUsable,
+ initial_sync_ended,
+ download_progress_markers,
+ kHasMoreToSync,
+ kIsSilenced,
+ kUnsyncedCount,
+ kNumConflictingUpdates,
+ kDidCommitItems,
+ source);
+ scoped_ptr<DictionaryValue> value(snapshot.ToValue());
+ EXPECT_EQ(12u, value->size());
+ ExpectDictionaryValue(*expected_syncer_status_value, *value,
+ "syncerStatus");
+ ExpectDictionaryValue(*expected_errors_value, *value, "errors");
+ ExpectIntegerValue(kNumServerChangesRemaining, *value,
+ "numServerChangesRemaining");
+ ExpectBooleanValue(kIsShareUsable, *value, "isShareUsable");
+ ExpectListValue(*expected_initial_sync_ended_value, *value,
+ "initialSyncEnded");
+ ExpectDictionaryValue(*expected_download_progress_markers_value,
+ *value, "downloadProgressMarkers");
+ ExpectBooleanValue(kHasMoreToSync, *value, "hasMoreToSync");
+ ExpectBooleanValue(kIsSilenced, *value, "isSilenced");
+ ExpectIntegerValue(kUnsyncedCount, *value, "unsyncedCount");
+ ExpectIntegerValue(kNumConflictingUpdates, *value,
+ "numConflictingUpdates");
+ ExpectBooleanValue(kDidCommitItems, *value,
+ "didCommitItems");
+ ExpectDictionaryValue(*expected_source_value, *value, "source");
+}
+
+} // namespace
+} // namespace sessions
+} // namespace browser_sync
diff --git a/chrome/browser/sync/syncable/model_type.cc b/chrome/browser/sync/syncable/model_type.cc
index 1aea654..0ff67bd 100644
--- a/chrome/browser/sync/syncable/model_type.cc
+++ b/chrome/browser/sync/syncable/model_type.cc
@@ -7,6 +7,7 @@
#include <sstream>
#include "base/metrics/histogram.h"
+#include "base/values.h"
#include "chrome/browser/sync/engine/syncproto.h"
#include "chrome/browser/sync/protocol/app_specifics.pb.h"
#include "chrome/browser/sync/protocol/autofill_specifics.pb.h"
@@ -255,6 +256,18 @@ bool ModelTypeBitSetFromString(
return iss.eof();
}
+ListValue* ModelTypeBitSetToValue(const ModelTypeBitSet& model_types) {
+ ListValue* value = new ListValue();
+ for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) {
+ if (model_types[i]) {
+ value->Append(
+ Value::CreateStringValue(
+ ModelTypeToString(ModelTypeFromInt(i))));
+ }
+ }
+ return value;
+}
+
// For now, this just implements UMA_HISTOGRAM_LONG_TIMES. This can be adjusted
// if we feel the min, max, or bucket count amount are not appropriate.
#define SYNC_FREQ_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES( \
diff --git a/chrome/browser/sync/syncable/model_type.h b/chrome/browser/sync/syncable/model_type.h
index 308f516..62f1787 100644
--- a/chrome/browser/sync/syncable/model_type.h
+++ b/chrome/browser/sync/syncable/model_type.h
@@ -17,6 +17,8 @@
#include "base/logging.h"
#include "base/time.h"
+class ListValue;
+
namespace sync_pb {
class EntitySpecifics;
class SyncEntity;
@@ -113,6 +115,9 @@ bool ModelTypeBitSetFromString(
const std::string& model_type_bitset_string,
ModelTypeBitSet* model_types);
+// Caller takes ownership of returned list.
+ListValue* ModelTypeBitSetToValue(const ModelTypeBitSet& model_types);
+
// Posts timedeltas to histogram of datatypes. Allows tracking of the frequency
// at which datatypes cause syncs.
void PostTimeToTypeHistogram(ModelType model_type, base::TimeDelta time);
diff --git a/chrome/browser/sync/syncable/model_type_unittest.cc b/chrome/browser/sync/syncable/model_type_unittest.cc
new file mode 100644
index 0000000..b15f0a0
--- /dev/null
+++ b/chrome/browser/sync/syncable/model_type_unittest.cc
@@ -0,0 +1,33 @@
+// Copyright (c) 2011 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 "chrome/browser/sync/syncable/model_type.h"
+
+#include <string>
+
+#include "base/scoped_ptr.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace syncable {
+namespace {
+
+class ModelTypeTest : public testing::Test {};
+
+TEST_F(ModelTypeTest, ModelTypeBitSetToValue) {
+ ModelTypeBitSet model_types;
+ model_types.set(syncable::BOOKMARKS);
+ model_types.set(syncable::APPS);
+
+ scoped_ptr<ListValue> value(ModelTypeBitSetToValue(model_types));
+ EXPECT_EQ(2u, value->GetSize());
+ std::string types[2];
+ EXPECT_TRUE(value->GetString(0, &types[0]));
+ EXPECT_TRUE(value->GetString(1, &types[1]));
+ EXPECT_EQ("Bookmarks", types[0]);
+ EXPECT_EQ("Apps", types[1]);
+}
+
+} // namespace
+} // namespace syncable