summaryrefslogtreecommitdiffstats
path: root/sync
diff options
context:
space:
mode:
authorstanisc <stanisc@chromium.org>2016-01-12 14:20:16 -0800
committerCommit bot <commit-bot@chromium.org>2016-01-12 22:21:41 +0000
commit227d3214f2b02d201d695faa2f8ea2223b6b62bf (patch)
tree4fd36b43416197d59220bb3648bf159836008b17 /sync
parenta9c0cb389711e755c41bd20c9335b5dee7b1d097 (diff)
downloadchromium_src-227d3214f2b02d201d695faa2f8ea2223b6b62bf.zip
chromium_src-227d3214f2b02d201d695faa2f8ea2223b6b62bf.tar.gz
chromium_src-227d3214f2b02d201d695faa2f8ea2223b6b62bf.tar.bz2
Use MetadataChangeList and EntityChangeList in SharedModelTypeProcessor
BUG=569678,569636 Review URL: https://codereview.chromium.org/1565503003 Cr-Commit-Position: refs/heads/master@{#369009}
Diffstat (limited to 'sync')
-rw-r--r--sync/BUILD.gn2
-rw-r--r--sync/api/entity_change.h6
-rw-r--r--sync/api/metadata_change_list.h30
-rw-r--r--sync/api/model_type_service.h4
-rw-r--r--sync/internal_api/public/shared_model_type_processor.h1
-rw-r--r--sync/internal_api/public/simple_metadata_change_list.cc19
-rw-r--r--sync/internal_api/public/simple_metadata_change_list.h6
-rw-r--r--sync/internal_api/public/test/fake_metadata_change_list.h57
-rw-r--r--sync/internal_api/public/test/fake_model_type_service.h1
-rw-r--r--sync/internal_api/shared_model_type_processor.cc128
-rw-r--r--sync/internal_api/shared_model_type_processor_unittest.cc282
-rw-r--r--sync/internal_api/test/fake_metadata_change_list.cc59
-rw-r--r--sync/sync_tests.gypi2
13 files changed, 521 insertions, 76 deletions
diff --git a/sync/BUILD.gn b/sync/BUILD.gn
index f38a415..04065d6 100644
--- a/sync/BUILD.gn
+++ b/sync/BUILD.gn
@@ -555,6 +555,7 @@ static_library("test_support_sync_core") {
static_library("test_support_sync_internal_api") {
testonly = true
sources = [
+ "internal_api/public/test/fake_metadata_change_list.h",
"internal_api/public/test/fake_model_type_service.h",
"internal_api/public/test/fake_sync_manager.h",
"internal_api/public/test/null_sync_context_proxy.h",
@@ -562,6 +563,7 @@ static_library("test_support_sync_internal_api") {
"internal_api/public/test/test_entry_factory.h",
"internal_api/public/test/test_internal_components_factory.h",
"internal_api/public/test/test_user_share.h",
+ "internal_api/test/fake_metadata_change_list.cc",
"internal_api/test/fake_model_type_service.cc",
"internal_api/test/fake_sync_manager.cc",
"internal_api/test/null_sync_context_proxy.cc",
diff --git a/sync/api/entity_change.h b/sync/api/entity_change.h
index 88e3812..866d38c 100644
--- a/sync/api/entity_change.h
+++ b/sync/api/entity_change.h
@@ -34,9 +34,9 @@ class SYNC_EXPORT EntityChange {
private:
EntityChange(std::string client_key, ChangeType type, EntityDataPtr data);
- const std::string client_key_;
- const ChangeType type_;
- const EntityDataPtr data_;
+ std::string client_key_;
+ ChangeType type_;
+ EntityDataPtr data_;
};
typedef std::vector<EntityChange> EntityChangeList;
diff --git a/sync/api/metadata_change_list.h b/sync/api/metadata_change_list.h
index e4435a8..a8c0d95 100644
--- a/sync/api/metadata_change_list.h
+++ b/sync/api/metadata_change_list.h
@@ -5,15 +5,45 @@
#ifndef SYNC_API_METADATA_CHANGE_LIST_H_
#define SYNC_API_METADATA_CHANGE_LIST_H_
+#include <string>
+
#include "sync/base/sync_export.h"
+namespace sync_pb {
+class EntityMetadata;
+} // namespace sync_pb
+
namespace syncer_v2 {
+struct DataTypeState;
// Interface used by the processor and service to communicate about metadata.
+// The purpose of the interface is to record changes to data type global and
+// per entity metadata for the purpose of propagating changes to the datatype
+// specific storage implementation.
+// The implementation of the interface is supposed to keep the record of all
+// updated / deleted metadata records and provide a mechanism to enumerate
+// them. If there are multiple UpdateMetadata / ClearMetadata calls made for the
+// same metadata record the last one is supposed to win.
class SYNC_EXPORT MetadataChangeList {
public:
MetadataChangeList() {}
virtual ~MetadataChangeList() {}
+
+ // Requests DataTypeState to be updated in the storage.
+ virtual void UpdateDataTypeState(const DataTypeState& data_type_state) = 0;
+
+ // Requests DataTypeState to be cleared from the storage.
+ virtual void ClearDataTypeState() = 0;
+
+ // Requests metadata entry to be updated in the storage.
+ // Please note that the update might contain a deleted entry if
+ // metadata.is_deleted() is true (as opposed to clearing the entry from the
+ // storage completely by calling the Clear method).
+ virtual void UpdateMetadata(const std::string& client_tag,
+ const sync_pb::EntityMetadata& metadata) = 0;
+
+ // Requests metadata entry to be cleared from the storage.
+ virtual void ClearMetadata(const std::string& client_tag) = 0;
};
} // namespace syncer_v2
diff --git a/sync/api/model_type_service.h b/sync/api/model_type_service.h
index f7ad9cd..48acdbe 100644
--- a/sync/api/model_type_service.h
+++ b/sync/api/model_type_service.h
@@ -48,6 +48,10 @@ class SYNC_EXPORT ModelTypeService {
EntityDataList entity_data_list) = 0;
// Apply changes from the sync server locally.
+ // Please note that |entity_changes| might have fewer entries than
+ // |metadata_change_list| in case when some of the data changes are filtered
+ // out, or even be empty in case when a commit confirmation is processed and
+ // only the metadata needs to persisted.
virtual syncer::SyncError ApplySyncChanges(
scoped_ptr<MetadataChangeList> metadata_change_list,
EntityChangeList entity_changes) = 0;
diff --git a/sync/internal_api/public/shared_model_type_processor.h b/sync/internal_api/public/shared_model_type_processor.h
index eb47d93..6c9382aa 100644
--- a/sync/internal_api/public/shared_model_type_processor.h
+++ b/sync/internal_api/public/shared_model_type_processor.h
@@ -11,6 +11,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/non_thread_safe.h"
+#include "sync/api/metadata_change_list.h"
#include "sync/api/model_type_change_processor.h"
#include "sync/api/model_type_service.h"
#include "sync/api/sync_error.h"
diff --git a/sync/internal_api/public/simple_metadata_change_list.cc b/sync/internal_api/public/simple_metadata_change_list.cc
index 27d2b41..c1bb25f 100644
--- a/sync/internal_api/public/simple_metadata_change_list.cc
+++ b/sync/internal_api/public/simple_metadata_change_list.cc
@@ -10,6 +10,25 @@ SimpleMetadataChangeList::SimpleMetadataChangeList() {}
SimpleMetadataChangeList::~SimpleMetadataChangeList() {}
+void SimpleMetadataChangeList::UpdateDataTypeState(
+ const DataTypeState& data_type_state) {
+ // TODO(skym): Implementation.
+}
+
+void SimpleMetadataChangeList::UpdateMetadata(
+ const std::string& client_tag,
+ const sync_pb::EntityMetadata& metadata) {
+ // TODO(skym): Implementation.
+}
+
+void SimpleMetadataChangeList::ClearDataTypeState() {
+ // TODO(skym): Implementation.
+}
+
+void SimpleMetadataChangeList::ClearMetadata(const std::string& client_tag) {
+ // TODO(skym): Implementation.
+}
+
void SimpleMetadataChangeList::TranfserChanges(
ModelTypeStore* store,
ModelTypeStore::WriteBatch* write_batch) {
diff --git a/sync/internal_api/public/simple_metadata_change_list.h b/sync/internal_api/public/simple_metadata_change_list.h
index 12bbe59..aca0e69 100644
--- a/sync/internal_api/public/simple_metadata_change_list.h
+++ b/sync/internal_api/public/simple_metadata_change_list.h
@@ -19,6 +19,12 @@ class SYNC_EXPORT SimpleMetadataChangeList : public MetadataChangeList {
SimpleMetadataChangeList();
~SimpleMetadataChangeList() override;
+ void UpdateDataTypeState(const DataTypeState& data_type_state) override;
+ void ClearDataTypeState() override;
+ void UpdateMetadata(const std::string& client_tag,
+ const sync_pb::EntityMetadata& metadata) override;
+ void ClearMetadata(const std::string& client_tag) override;
+
// Moves all currently accumulated changes into the write batch, clear out
// local copies. Calling this multiple times will work, but should not be
// necessary.
diff --git a/sync/internal_api/public/test/fake_metadata_change_list.h b/sync/internal_api/public/test/fake_metadata_change_list.h
new file mode 100644
index 0000000..6359602
--- /dev/null
+++ b/sync/internal_api/public/test/fake_metadata_change_list.h
@@ -0,0 +1,57 @@
+// Copyright 2016 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_TEST_FAKE_METADATA_CHANGE_LIST_H_
+#define SYNC_INTERNAL_API_PUBLIC_TEST_FAKE_METADATA_CHANGE_LIST_H_
+
+#include <vector>
+
+#include "sync/api/metadata_change_list.h"
+#include "sync/internal_api/public/non_blocking_sync_common.h"
+#include "sync/protocol/entity_metadata.pb.h"
+
+namespace syncer_v2 {
+
+// A non-functional implementation of MetadataChangeList for
+// testing purposes.
+// This class simply records all calls with all arguments for further
+// analysis by the test code.
+class FakeMetadataChangeList : public MetadataChangeList {
+ public:
+ FakeMetadataChangeList();
+ ~FakeMetadataChangeList() override;
+
+ void UpdateDataTypeState(const DataTypeState& data_type_state) override;
+ void ClearDataTypeState() override;
+ void UpdateMetadata(const std::string& client_tag,
+ const sync_pb::EntityMetadata& metadata) override;
+ void ClearMetadata(const std::string& client_tag) override;
+
+ enum Action {
+ UPDATE_DATA_TYPE_STATE,
+ CLEAR_DATA_TYPE_STATE,
+ UPDATE_METADATA,
+ CLEAR_METADATA
+ };
+
+ struct Record {
+ Record();
+ virtual ~Record();
+
+ Action action;
+ std::string tag;
+ DataTypeState data_type_state;
+ sync_pb::EntityMetadata metadata;
+ };
+
+ size_t GetNumRecords() const;
+ const Record& GetNthRecord(size_t n) const;
+
+ private:
+ std::vector<Record> records_;
+};
+
+} // namespace syncer_v2
+
+#endif // SYNC_INTERNAL_API_PUBLIC_TEST_FAKE_METADATA_CHANGE_LIST_H_
diff --git a/sync/internal_api/public/test/fake_model_type_service.h b/sync/internal_api/public/test/fake_model_type_service.h
index 9361483..a5ba17e 100644
--- a/sync/internal_api/public/test/fake_model_type_service.h
+++ b/sync/internal_api/public/test/fake_model_type_service.h
@@ -8,6 +8,7 @@
#include <string>
#include "sync/api/data_batch.h"
+#include "sync/api/entity_change.h"
#include "sync/api/metadata_batch.h"
#include "sync/api/metadata_change_list.h"
#include "sync/api/model_type_service.h"
diff --git a/sync/internal_api/shared_model_type_processor.cc b/sync/internal_api/shared_model_type_processor.cc
index a6ed683..f6573be 100644
--- a/sync/internal_api/shared_model_type_processor.cc
+++ b/sync/internal_api/shared_model_type_processor.cc
@@ -151,16 +151,15 @@ void SharedModelTypeProcessor::OnConnect(scoped_ptr<CommitQueue> worker) {
void SharedModelTypeProcessor::Put(const std::string& client_tag,
scoped_ptr<EntityData> entity_data,
MetadataChangeList* metadata_change_list) {
- // TODO(skym): Add metadata to persist to MetadataChangeList, crbug/569636.
-
DCHECK(entity_data.get());
DCHECK(!entity_data->is_deleted());
DCHECK(!entity_data->non_unique_name.empty());
DCHECK_EQ(type_, syncer::GetModelTypeFromSpecifics(entity_data->specifics));
// If the service specified an overriding hash, use that, otherwise generate
- // one from the tag. TODO(skym): This behavior should be delayed, once
- // crbug/561818 is fixed we will only perform this logic in the create case.
+ // one from the tag.
+ // TODO(skym): This behavior should be delayed, once crbug.com/561818 is fixed
+ // we will only perform this logic in the create case.
const std::string client_tag_hash(
entity_data->client_tag_hash.empty()
? syncer::syncable::GenerateSyncableHash(type_, client_tag)
@@ -169,9 +168,9 @@ void SharedModelTypeProcessor::Put(const std::string& client_tag,
base::Time now = base::Time::Now();
ModelTypeEntity* entity = nullptr;
- // TODO(stanisc): crbug/561818: Search by client_tag rather than
+ // TODO(stanisc): crbug.com/561818: Search by client_tag rather than
// client_tag_hash.
- EntityMap::const_iterator it = entities_.find(client_tag_hash);
+ auto it = entities_.find(client_tag_hash);
if (it == entities_.end()) {
// The service is creating a new entity.
scoped_ptr<ModelTypeEntity> scoped_entity = ModelTypeEntity::CreateNew(
@@ -182,32 +181,39 @@ void SharedModelTypeProcessor::Put(const std::string& client_tag,
} else {
// The service is updating an existing entity.
entity = it->second.get();
+ DCHECK_EQ(client_tag, entity->client_key());
}
+ // TODO(stanisc): crbug.com/561829: Avoid committing a change if there is no
+ // actual change.
entity->MakeLocalChange(std::move(entity_data), now);
+ metadata_change_list->UpdateMetadata(client_tag, entity->metadata());
+
FlushPendingCommitRequests();
}
void SharedModelTypeProcessor::Delete(
const std::string& client_key,
MetadataChangeList* metadata_change_list) {
- // TODO(skym): Add metadata to persist to MetadataChangeList, crbug/569636.
-
const std::string client_tag_hash(
syncer::syncable::GenerateSyncableHash(type_, client_key));
- // TODO(skym): crbug/561818: Search by client_tag rather than client_tag_hash.
- EntityMap::const_iterator it = entities_.find(client_tag_hash);
+ // TODO(skym): crbug.com/561818: Search by client_tag rather than
+ // client_tag_hash.
+ auto it = entities_.find(client_tag_hash);
if (it == entities_.end()) {
// That's unusual, but not necessarily a bad thing.
// Missing is as good as deleted as far as the model is concerned.
DLOG(WARNING) << "Attempted to delete missing item."
<< " client tag: " << client_key;
- } else {
- ModelTypeEntity* entity = it->second.get();
- entity->Delete();
+ return;
}
+ ModelTypeEntity* entity = it->second.get();
+ entity->Delete();
+
+ metadata_change_list->UpdateMetadata(client_key, entity->metadata());
+
FlushPendingCommitRequests();
}
@@ -223,8 +229,7 @@ void SharedModelTypeProcessor::FlushPendingCommitRequests() {
return;
// TODO(rlarocque): Do something smarter than iterate here.
- for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end();
- ++it) {
+ for (auto it = entities_.begin(); it != entities_.end(); ++it) {
if (it->second->RequiresCommitRequest()) {
CommitRequestData request;
it->second->InitializeCommitRequestData(&request);
@@ -240,14 +245,18 @@ void SharedModelTypeProcessor::FlushPendingCommitRequests() {
void SharedModelTypeProcessor::OnCommitCompleted(
const DataTypeState& type_state,
const CommitResponseDataList& response_list) {
+ scoped_ptr<MetadataChangeList> change_list =
+ service_->CreateMetadataChangeList();
+
data_type_state_ = type_state;
+ change_list->UpdateDataTypeState(data_type_state_);
- for (CommitResponseDataList::const_iterator list_it = response_list.begin();
- list_it != response_list.end(); ++list_it) {
+ for (auto list_it = response_list.begin(); list_it != response_list.end();
+ ++list_it) {
const CommitResponseData& response_data = *list_it;
const std::string& client_tag_hash = response_data.client_tag_hash;
- EntityMap::const_iterator it = entities_.find(client_tag_hash);
+ auto it = entities_.find(client_tag_hash);
if (it == entities_.end()) {
NOTREACHED() << "Received commit response for missing item."
<< " type: " << type_ << " client_tag: " << client_tag_hash;
@@ -256,21 +265,35 @@ void SharedModelTypeProcessor::OnCommitCompleted(
it->second->ReceiveCommitResponse(
response_data.id, response_data.sequence_number,
response_data.response_version, data_type_state_.encryption_key_name);
+ // TODO(stanisc): crbug.com/573333: Delete case.
+ // This might be the right place to clear a metadata entry that has
+ // been deleted locally and confirmed deleted by the server.
+ change_list->UpdateMetadata(it->second->client_key(),
+ it->second->metadata());
}
}
+
+ // TODO(stanisc): What is the right method to submit metadata changes to the
+ // service? Is using empty EntityChangeList OK?
+ // TODO(stanisc): crbug.com/570085: Error handling.
+ service_->ApplySyncChanges(std::move(change_list), EntityChangeList());
}
void SharedModelTypeProcessor::OnUpdateReceived(
const DataTypeState& data_type_state,
const UpdateResponseDataList& response_list,
const UpdateResponseDataList& pending_updates) {
+ scoped_ptr<MetadataChangeList> metadata_changes =
+ service_->CreateMetadataChangeList();
+ EntityChangeList entity_changes;
+
+ metadata_changes->UpdateDataTypeState(data_type_state);
bool got_new_encryption_requirements = data_type_state_.encryption_key_name !=
data_type_state.encryption_key_name;
-
data_type_state_ = data_type_state;
- for (UpdateResponseDataList::const_iterator list_it = response_list.begin();
- list_it != response_list.end(); ++list_it) {
+ for (auto list_it = response_list.begin(); list_it != response_list.end();
+ ++list_it) {
const UpdateResponseData& response_data = *list_it;
const EntityData& data = response_data.entity.value();
const std::string& client_tag_hash = data.client_tag_hash;
@@ -280,24 +303,47 @@ void SharedModelTypeProcessor::OnUpdateReceived(
pending_updates_map_.erase(client_tag_hash);
ModelTypeEntity* entity = nullptr;
- EntityMap::const_iterator it = entities_.find(client_tag_hash);
+ auto it = entities_.find(client_tag_hash);
if (it == entities_.end()) {
+ if (data.is_deleted()) {
+ DLOG(WARNING) << "Received remote delete for a non-existing item."
+ << " client_tag_hash: " << client_tag_hash;
+ continue;
+ }
+
// Let the service define |client_tag| based on the entity data.
- std::string client_tag = service_->GetClientTag(data);
+ std::string client_key = service_->GetClientTag(data);
scoped_ptr<ModelTypeEntity> scoped_entity = ModelTypeEntity::CreateNew(
- client_tag, client_tag_hash, data.id, data.creation_time);
+ client_key, client_tag_hash, data.id, data.creation_time);
entity = scoped_entity.get();
entities_.insert(
std::make_pair(client_tag_hash, std::move(scoped_entity)));
+ entity_changes.push_back(
+ EntityChange::CreateAdd(client_key, response_data.entity));
+
} else {
entity = it->second.get();
+ if (data.is_deleted()) {
+ entity_changes.push_back(
+ EntityChange::CreateDelete(entity->client_key()));
+ } else {
+ // TODO(stanisc): crbug.com/561829: Avoid sending an update to the
+ // service if there is no actual change.
+ entity_changes.push_back(EntityChange::CreateUpdate(
+ entity->client_key(), response_data.entity));
+ }
}
entity->ApplyUpdateFromServer(response_data);
+ // TODO(stanisc): crbug.com/573333: Delete case.
+ // This might be the right place to clear metadata entry instead of
+ // updating it.
+ metadata_changes->UpdateMetadata(entity->client_key(), entity->metadata());
- // TODO(stanisc): Do something special when conflicts are detected.
+ // TODO(stanisc): crbug.com/521867: Do something special when conflicts are
+ // detected.
// If the received entity has out of date encryption, we schedule another
// commit to fix it.
@@ -306,20 +352,20 @@ void SharedModelTypeProcessor::OnUpdateReceived(
DVLOG(2) << ModelTypeToString(type_) << ": Requesting re-encrypt commit "
<< response_data.encryption_key_name << " -> "
<< data_type_state_.encryption_key_name;
- EntityMap::const_iterator it2 = entities_.find(client_tag_hash);
+ auto it2 = entities_.find(client_tag_hash);
it2->second->UpdateDesiredEncryptionKey(
data_type_state_.encryption_key_name);
}
}
+ // TODO: crbug.com/529498: stop saving pending updates.
// Save pending updates in the appropriate data structure.
- for (UpdateResponseDataList::const_iterator list_it = pending_updates.begin();
- list_it != pending_updates.end(); ++list_it) {
+ for (auto list_it = pending_updates.begin(); list_it != pending_updates.end();
+ ++list_it) {
const UpdateResponseData& update = *list_it;
const std::string& client_tag_hash = update.entity->client_tag_hash;
- UpdateMap::const_iterator lookup_it =
- pending_updates_map_.find(client_tag_hash);
+ auto lookup_it = pending_updates_map_.find(client_tag_hash);
if (lookup_it == pending_updates_map_.end()) {
pending_updates_map_.insert(std::make_pair(
client_tag_hash, make_scoped_ptr(new UpdateResponseData(update))));
@@ -333,43 +379,43 @@ void SharedModelTypeProcessor::OnUpdateReceived(
}
if (got_new_encryption_requirements) {
- for (EntityMap::const_iterator it = entities_.begin();
- it != entities_.end(); ++it) {
+ for (auto it = entities_.begin(); it != entities_.end(); ++it) {
it->second->UpdateDesiredEncryptionKey(
data_type_state_.encryption_key_name);
}
}
+ // Inform the service of the new or updated data.
+ // TODO(stanisc): crbug.com/570085: Error handling.
+ service_->ApplySyncChanges(std::move(metadata_changes), entity_changes);
+
// We may have new reasons to commit by the time this function is done.
FlushPendingCommitRequests();
-
- // TODO(rlarocque): Inform the model of the new or updated data.
- // TODO(rlarocque): Persist the new data on disk.
}
UpdateResponseDataList SharedModelTypeProcessor::GetPendingUpdates() {
UpdateResponseDataList pending_updates_list;
- for (UpdateMap::const_iterator it = pending_updates_map_.begin();
- it != pending_updates_map_.end(); ++it) {
+ for (auto it = pending_updates_map_.begin(); it != pending_updates_map_.end();
+ ++it) {
pending_updates_list.push_back(*it->second);
}
return pending_updates_list;
}
void SharedModelTypeProcessor::ClearTransientSyncState() {
- for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end();
- ++it) {
+ for (auto it = entities_.begin(); it != entities_.end(); ++it) {
it->second->ClearTransientSyncState();
}
}
void SharedModelTypeProcessor::ClearSyncState() {
- for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end();
- ++it) {
+ for (auto it = entities_.begin(); it != entities_.end(); ++it) {
it->second->ClearSyncState();
}
pending_updates_map_.clear();
data_type_state_ = DataTypeState();
+ // TODO(stanisc): crbug.com/561830, crbug.com/573333: Update the service to
+ // let it know that all metadata need to be cleared from the storage.
}
} // namespace syncer_v2
diff --git a/sync/internal_api/shared_model_type_processor_unittest.cc b/sync/internal_api/shared_model_type_processor_unittest.cc
index 411e8b1..eb23793 100644
--- a/sync/internal_api/shared_model_type_processor_unittest.cc
+++ b/sync/internal_api/shared_model_type_processor_unittest.cc
@@ -14,6 +14,7 @@
#include "sync/internal_api/public/activation_context.h"
#include "sync/internal_api/public/base/model_type.h"
#include "sync/internal_api/public/non_blocking_sync_common.h"
+#include "sync/internal_api/public/test/fake_metadata_change_list.h"
#include "sync/internal_api/public/test/fake_model_type_service.h"
#include "sync/protocol/sync.pb.h"
#include "sync/syncable/syncable_util.h"
@@ -32,7 +33,7 @@ static const syncer::ModelType kModelType = syncer::PREFERENCES;
// to be re-tested here.
//
// These tests skip past initialization and focus on steady state sync engine
-// behvior. This is where we test how the type sync proxy responds to the
+// behavior. This is where we test how the processor responds to the
// model's requests to make changes to its data, the messages incoming from the
// sync server, and what happens when the two conflict.
//
@@ -69,8 +70,10 @@ class SharedModelTypeProcessorTest : public ::testing::Test,
void Restart();
// Local data modification. Emulates signals from the model thread.
- void WriteItem(const std::string& tag, const std::string& value);
- void DeleteItem(const std::string& tag);
+ void WriteItem(const std::string& tag,
+ const std::string& value,
+ MetadataChangeList* change_list);
+ void DeleteItem(const std::string& tag, MetadataChangeList* change_list);
// Emulates an "initial sync done" message from the
// CommitQueue.
@@ -122,6 +125,9 @@ class SharedModelTypeProcessorTest : public ::testing::Test,
MockCommitQueue* mock_queue();
SharedModelTypeProcessor* type_processor();
+ const EntityChangeList* entity_change_list() const;
+ const FakeMetadataChangeList* metadata_change_list() const;
+
private:
static std::string GenerateTagHash(const std::string& tag);
static sync_pb::EntitySpecifics GenerateSpecifics(const std::string& tag,
@@ -139,6 +145,10 @@ class SharedModelTypeProcessorTest : public ::testing::Test,
// FakeModelTypeService overrides.
std::string GetClientTag(const EntityData& entity_data) override;
+ scoped_ptr<MetadataChangeList> CreateMetadataChangeList() override;
+ syncer::SyncError ApplySyncChanges(
+ scoped_ptr<MetadataChangeList> metadata_change_list,
+ EntityChangeList entity_changes) override;
// This sets ThreadTaskRunnerHandle on the current thread, which the type
// processor will pick up as the sync task runner.
@@ -151,6 +161,11 @@ class SharedModelTypeProcessorTest : public ::testing::Test,
scoped_ptr<SharedModelTypeProcessor> type_processor_;
DataTypeState data_type_state_;
+
+ // The last received EntityChangeList.
+ scoped_ptr<EntityChangeList> entity_change_list_;
+ // The last received MetadataChangeList.
+ scoped_ptr<FakeMetadataChangeList> metadata_change_list_;
};
SharedModelTypeProcessorTest::SharedModelTypeProcessorTest()
@@ -209,21 +224,25 @@ void SharedModelTypeProcessorTest::StartDone(
}
void SharedModelTypeProcessorTest::WriteItem(const std::string& tag,
- const std::string& value) {
+ const std::string& value,
+ MetadataChangeList* change_list) {
scoped_ptr<EntityData> entity_data = make_scoped_ptr(new EntityData());
entity_data->specifics = GenerateSpecifics(tag, value);
entity_data->non_unique_name = tag;
- type_processor_->Put(tag, std::move(entity_data), nullptr);
+ type_processor_->Put(tag, std::move(entity_data), change_list);
}
-void SharedModelTypeProcessorTest::DeleteItem(const std::string& tag) {
- type_processor_->Delete(tag, nullptr);
+void SharedModelTypeProcessorTest::DeleteItem(const std::string& tag,
+ MetadataChangeList* change_list) {
+ type_processor_->Delete(tag, change_list);
}
void SharedModelTypeProcessorTest::OnInitialSyncDone() {
data_type_state_.initial_sync_done = true;
UpdateResponseDataList empty_update_list;
+ // TODO(stanisc): crbug/569645: replace this with loading the initial state
+ // via LoadMetadata callback.
type_processor_->OnUpdateReceived(data_type_state_, empty_update_list,
empty_update_list);
}
@@ -328,6 +347,16 @@ SharedModelTypeProcessor* SharedModelTypeProcessorTest::type_processor() {
return type_processor_.get();
}
+const EntityChangeList* SharedModelTypeProcessorTest::entity_change_list()
+ const {
+ return entity_change_list_.get();
+}
+
+const FakeMetadataChangeList*
+SharedModelTypeProcessorTest::metadata_change_list() const {
+ return metadata_change_list_.get();
+}
+
std::string SharedModelTypeProcessorTest::GenerateTagHash(
const std::string& tag) {
return syncer::syncable::GenerateSyncableHash(kModelType, tag);
@@ -362,6 +391,26 @@ std::string SharedModelTypeProcessorTest::GetClientTag(
return entity_data.specifics.preference().name();
}
+scoped_ptr<MetadataChangeList>
+SharedModelTypeProcessorTest::CreateMetadataChangeList() {
+ // Reset the current first and return a new one.
+ metadata_change_list_.reset();
+ return scoped_ptr<MetadataChangeList>(new FakeMetadataChangeList());
+}
+
+syncer::SyncError SharedModelTypeProcessorTest::ApplySyncChanges(
+ scoped_ptr<MetadataChangeList> metadata_change_list,
+ EntityChangeList entity_changes) {
+ EXPECT_FALSE(metadata_change_list_);
+ // |metadata_change_list| is expected to be an instance of
+ // FakeMetadataChangeList - see above.
+ metadata_change_list_.reset(
+ static_cast<FakeMetadataChangeList*>(metadata_change_list.release()));
+ EXPECT_TRUE(metadata_change_list_);
+ entity_change_list_.reset(new EntityChangeList(entity_changes));
+ return syncer::SyncError();
+}
+
size_t SharedModelTypeProcessorTest::GetNumCommitRequestLists() {
return mock_queue_->GetNumCommitRequestLists();
}
@@ -389,7 +438,8 @@ TEST_F(SharedModelTypeProcessorTest, CreateLocalItem) {
InitializeToReadyState();
EXPECT_EQ(0U, GetNumCommitRequestLists());
- WriteItem("tag1", "value1");
+ FakeMetadataChangeList change_list;
+ WriteItem("tag1", "value1", &change_list);
// Verify the commit request this operation has triggered.
EXPECT_EQ(1U, GetNumCommitRequestLists());
@@ -406,6 +456,21 @@ TEST_F(SharedModelTypeProcessorTest, CreateLocalItem) {
EXPECT_FALSE(tag1_data.is_deleted());
EXPECT_EQ("tag1", tag1_data.specifics.preference().name());
EXPECT_EQ("value1", tag1_data.specifics.preference().value());
+
+ EXPECT_EQ(1U, change_list.GetNumRecords());
+
+ const FakeMetadataChangeList::Record& record = change_list.GetNthRecord(0);
+ EXPECT_EQ(FakeMetadataChangeList::UPDATE_METADATA, record.action);
+ EXPECT_EQ("tag1", record.tag);
+ EXPECT_TRUE(record.metadata.has_client_tag_hash());
+ EXPECT_FALSE(record.metadata.has_server_id());
+ EXPECT_FALSE(record.metadata.is_deleted());
+ EXPECT_EQ(1, record.metadata.sequence_number());
+ EXPECT_EQ(0, record.metadata.acked_sequence_number());
+ EXPECT_EQ(kUncommittedVersion, record.metadata.server_version());
+ EXPECT_TRUE(record.metadata.has_creation_time());
+ EXPECT_TRUE(record.metadata.has_modification_time());
+ EXPECT_TRUE(record.metadata.has_specifics_hash());
}
// The purpose of this test case is to test setting |client_tag_hash| and |id|
@@ -416,14 +481,16 @@ TEST_F(SharedModelTypeProcessorTest, CreateAndModifyWithOverrides) {
InitializeToReadyState();
EXPECT_EQ(0U, GetNumCommitRequestLists());
+ FakeMetadataChangeList change_list;
+
scoped_ptr<EntityData> entity_data = make_scoped_ptr(new EntityData());
- entity_data->specifics.mutable_preference()->set_name("tag1");
+ entity_data->specifics.mutable_preference()->set_name("name1");
entity_data->specifics.mutable_preference()->set_value("value1");
- entity_data->non_unique_name = "tag1";
+ entity_data->non_unique_name = "name1";
entity_data->client_tag_hash = "hash";
entity_data->id = "cid1";
- type_processor()->Put("tag1", std::move(entity_data), nullptr);
+ type_processor()->Put("tag1", std::move(entity_data), &change_list);
// Don't access through tag because we forced a specific hash.
EXPECT_EQ(1U, GetNumCommitRequestLists());
@@ -435,13 +502,18 @@ TEST_F(SharedModelTypeProcessorTest, CreateAndModifyWithOverrides) {
EXPECT_EQ("cid1", out_entity1.id);
EXPECT_EQ("value1", out_entity1.specifics.preference().value());
+ EXPECT_EQ(1U, change_list.GetNumRecords());
+
entity_data.reset(new EntityData());
- entity_data->specifics.mutable_preference()->set_name("tag2");
+ entity_data->specifics.mutable_preference()->set_name("name2");
entity_data->specifics.mutable_preference()->set_value("value2");
- entity_data->non_unique_name = "tag2";
+ entity_data->non_unique_name = "name2";
entity_data->client_tag_hash = "hash";
+ // TODO (skym): Consider removing this. The ID should never be changed by the
+ // client once established.
entity_data->id = "cid2";
- type_processor()->Put("tag2", std::move(entity_data), nullptr);
+
+ type_processor()->Put("tag1", std::move(entity_data), &change_list);
EXPECT_EQ(2U, GetNumCommitRequestLists());
ASSERT_TRUE(mock_queue()->HasCommitRequestForTagHash("hash"));
@@ -452,6 +524,24 @@ TEST_F(SharedModelTypeProcessorTest, CreateAndModifyWithOverrides) {
EXPECT_EQ("hash", out_entity2.client_tag_hash);
EXPECT_EQ("cid1", out_entity2.id);
EXPECT_EQ("value2", out_entity2.specifics.preference().value());
+
+ EXPECT_EQ(2U, change_list.GetNumRecords());
+
+ const FakeMetadataChangeList::Record& record1 = change_list.GetNthRecord(0);
+ EXPECT_EQ(FakeMetadataChangeList::UPDATE_METADATA, record1.action);
+ EXPECT_EQ("tag1", record1.tag);
+ EXPECT_EQ("cid1", record1.metadata.server_id());
+ EXPECT_EQ("hash", record1.metadata.client_tag_hash());
+
+ const FakeMetadataChangeList::Record& record2 = change_list.GetNthRecord(1);
+ EXPECT_EQ(FakeMetadataChangeList::UPDATE_METADATA, record2.action);
+ EXPECT_EQ("tag1", record2.tag);
+ // TODO (skym): Is this correct?
+ EXPECT_EQ("cid1", record2.metadata.server_id());
+ EXPECT_EQ("hash", record2.metadata.client_tag_hash());
+
+ EXPECT_NE(record1.metadata.specifics_hash(),
+ record2.metadata.specifics_hash());
}
// Creates a new local item then modifies it.
@@ -460,14 +550,16 @@ TEST_F(SharedModelTypeProcessorTest, CreateAndModifyLocalItem) {
InitializeToReadyState();
EXPECT_EQ(0U, GetNumCommitRequestLists());
- WriteItem("tag1", "value1");
+ FakeMetadataChangeList change_list;
+
+ WriteItem("tag1", "value1", &change_list);
EXPECT_EQ(1U, GetNumCommitRequestLists());
ASSERT_TRUE(HasCommitRequestForTag("tag1"));
const CommitRequestData& tag1_v1_request_data =
GetLatestCommitRequestForTag("tag1");
const EntityData& tag1_v1_data = tag1_v1_request_data.entity.value();
- WriteItem("tag1", "value2");
+ WriteItem("tag1", "value2", &change_list);
EXPECT_EQ(2U, GetNumCommitRequestLists());
ASSERT_TRUE(HasCommitRequestForTag("tag1"));
@@ -489,6 +581,31 @@ TEST_F(SharedModelTypeProcessorTest, CreateAndModifyLocalItem) {
EXPECT_FALSE(tag1_v2_data.is_deleted());
EXPECT_EQ("tag1", tag1_v2_data.specifics.preference().name());
EXPECT_EQ("value2", tag1_v2_data.specifics.preference().value());
+
+ EXPECT_EQ(2U, change_list.GetNumRecords());
+
+ const FakeMetadataChangeList::Record& record1 = change_list.GetNthRecord(0);
+ EXPECT_EQ(FakeMetadataChangeList::UPDATE_METADATA, record1.action);
+ EXPECT_EQ("tag1", record1.tag);
+ EXPECT_FALSE(record1.metadata.has_server_id());
+ EXPECT_FALSE(record1.metadata.is_deleted());
+ EXPECT_EQ(1, record1.metadata.sequence_number());
+ EXPECT_EQ(0, record1.metadata.acked_sequence_number());
+ EXPECT_EQ(kUncommittedVersion, record1.metadata.server_version());
+
+ const FakeMetadataChangeList::Record& record2 = change_list.GetNthRecord(1);
+ EXPECT_EQ(FakeMetadataChangeList::UPDATE_METADATA, record1.action);
+ EXPECT_EQ("tag1", record2.tag);
+ EXPECT_FALSE(record2.metadata.has_server_id());
+ EXPECT_FALSE(record2.metadata.is_deleted());
+ EXPECT_EQ(2, record2.metadata.sequence_number());
+ EXPECT_EQ(0, record2.metadata.acked_sequence_number());
+ EXPECT_EQ(kUncommittedVersion, record2.metadata.server_version());
+
+ EXPECT_EQ(record1.metadata.client_tag_hash(),
+ record2.metadata.client_tag_hash());
+ EXPECT_NE(record1.metadata.specifics_hash(),
+ record2.metadata.specifics_hash());
}
// Deletes an item we've never seen before.
@@ -496,8 +613,12 @@ TEST_F(SharedModelTypeProcessorTest, CreateAndModifyLocalItem) {
TEST_F(SharedModelTypeProcessorTest, DeleteUnknown) {
InitializeToReadyState();
- DeleteItem("tag1");
+ FakeMetadataChangeList change_list;
+
+ DeleteItem("tag1", &change_list);
EXPECT_EQ(0U, GetNumCommitRequestLists());
+
+ EXPECT_EQ(0U, change_list.GetNumRecords());
}
// Creates an item locally then deletes it.
@@ -508,12 +629,19 @@ TEST_F(SharedModelTypeProcessorTest, DeleteUnknown) {
TEST_F(SharedModelTypeProcessorTest, DeleteServerUnknown) {
InitializeToReadyState();
- WriteItem("tag1", "value1");
+ FakeMetadataChangeList change_list;
+
+ // TODO(stanisc): crbug.com/573333: Review this case. If the flush of
+ // all locally modified items was scheduled to run on a separate task, than
+ // the correct behavior would be to commit just the detele, or perhaps no
+ // commit at all.
+
+ WriteItem("tag1", "value1", &change_list);
EXPECT_EQ(1U, GetNumCommitRequestLists());
ASSERT_TRUE(HasCommitRequestForTag("tag1"));
const CommitRequestData& tag1_v1_data = GetLatestCommitRequestForTag("tag1");
- DeleteItem("tag1");
+ DeleteItem("tag1", &change_list);
EXPECT_EQ(2U, GetNumCommitRequestLists());
ASSERT_TRUE(HasCommitRequestForTag("tag1"));
const CommitRequestData& tag1_v2_data = GetLatestCommitRequestForTag("tag1");
@@ -523,6 +651,31 @@ TEST_F(SharedModelTypeProcessorTest, DeleteServerUnknown) {
EXPECT_TRUE(tag1_v2_data.entity->id.empty());
EXPECT_EQ(kUncommittedVersion, tag1_v2_data.base_version);
EXPECT_TRUE(tag1_v2_data.entity->is_deleted());
+
+ EXPECT_EQ(2U, change_list.GetNumRecords());
+
+ const FakeMetadataChangeList::Record& record1 = change_list.GetNthRecord(0);
+ EXPECT_EQ(FakeMetadataChangeList::UPDATE_METADATA, record1.action);
+ EXPECT_EQ("tag1", record1.tag);
+ EXPECT_FALSE(record1.metadata.is_deleted());
+ EXPECT_EQ(1, record1.metadata.sequence_number());
+ EXPECT_EQ(0, record1.metadata.acked_sequence_number());
+ EXPECT_EQ(kUncommittedVersion, record1.metadata.server_version());
+
+ // TODO(stanisc): crbug.com/573333: Review this case. Depending on the
+ // implementation the second action performed on metadata change list might
+ // be CLEAR_METADATA. For a real implementation of MetadataChangeList this
+ // might also mean that the change list wouldn't contain any metadata
+ // records at all - the first call would create an entry and the second would
+ // remove it.
+
+ const FakeMetadataChangeList::Record& record2 = change_list.GetNthRecord(1);
+ EXPECT_EQ(FakeMetadataChangeList::UPDATE_METADATA, record1.action);
+ EXPECT_EQ("tag1", record2.tag);
+ EXPECT_TRUE(record2.metadata.is_deleted());
+ EXPECT_EQ(2, record2.metadata.sequence_number());
+ EXPECT_EQ(0, record2.metadata.acked_sequence_number());
+ EXPECT_EQ(kUncommittedVersion, record2.metadata.server_version());
}
// Creates an item locally then deletes it.
@@ -533,12 +686,14 @@ TEST_F(SharedModelTypeProcessorTest, DeleteServerUnknown) {
TEST_F(SharedModelTypeProcessorTest, DeleteServerUnknown_RacyCommitResponse) {
InitializeToReadyState();
- WriteItem("tag1", "value1");
+ FakeMetadataChangeList change_list;
+
+ WriteItem("tag1", "value1", &change_list);
EXPECT_EQ(1U, GetNumCommitRequestLists());
ASSERT_TRUE(HasCommitRequestForTag("tag1"));
const CommitRequestData& tag1_v1_data = GetLatestCommitRequestForTag("tag1");
- DeleteItem("tag1");
+ DeleteItem("tag1", &change_list);
EXPECT_EQ(2U, GetNumCommitRequestLists());
ASSERT_TRUE(HasCommitRequestForTag("tag1"));
@@ -547,6 +702,33 @@ TEST_F(SharedModelTypeProcessorTest, DeleteServerUnknown_RacyCommitResponse) {
// the sync thread. It will update some metadata, but won't do much else.
SuccessfulCommitResponse(tag1_v1_data);
+ // In reality the change list used to commit local changes should never
+ // overlap with the changelist used to deliver commit confirmation. In this
+ // test setup the two change lists are isolated - one is on the stack and
+ // another is the class member.
+
+ // Local metadata changes.
+ EXPECT_EQ(2U, change_list.GetNumRecords());
+
+ // Metadata changes from commit response.
+ EXPECT_TRUE(metadata_change_list());
+ EXPECT_EQ(2U, metadata_change_list()->GetNumRecords());
+
+ const FakeMetadataChangeList::Record& record1 =
+ metadata_change_list()->GetNthRecord(0);
+ EXPECT_EQ(FakeMetadataChangeList::UPDATE_DATA_TYPE_STATE, record1.action);
+
+ const FakeMetadataChangeList::Record& record2 =
+ metadata_change_list()->GetNthRecord(1);
+ EXPECT_EQ(FakeMetadataChangeList::UPDATE_METADATA, record2.action);
+ EXPECT_EQ("tag1", record2.tag);
+ // Deleted from the second local modification.
+ EXPECT_TRUE(record2.metadata.is_deleted());
+ // sequence_number = 2 from the second local modification.
+ EXPECT_EQ(2, record2.metadata.sequence_number());
+ // acked_sequence_number = 1 from the first commit response.
+ EXPECT_EQ(1, record2.metadata.acked_sequence_number());
+
// TODO(rlarocque): Verify the state of the item is correct once we get
// storage hooked up in these tests. For example, verify the item is still
// marked as deleted.
@@ -558,19 +740,39 @@ TEST_F(SharedModelTypeProcessorTest, TwoIndependentItems) {
InitializeToReadyState();
EXPECT_EQ(0U, GetNumCommitRequestLists());
- WriteItem("tag1", "value1");
+ FakeMetadataChangeList change_list;
+
+ WriteItem("tag1", "value1", &change_list);
// There should be one commit request for this item only.
ASSERT_EQ(1U, GetNumCommitRequestLists());
EXPECT_EQ(1U, GetNthCommitRequestList(0).size());
ASSERT_TRUE(HasCommitRequestForTag("tag1"));
- WriteItem("tag2", "value2");
+ WriteItem("tag2", "value2", &change_list);
// The second write should trigger another single-item commit request.
ASSERT_EQ(2U, GetNumCommitRequestLists());
EXPECT_EQ(1U, GetNthCommitRequestList(1).size());
ASSERT_TRUE(HasCommitRequestForTag("tag2"));
+
+ EXPECT_EQ(2U, change_list.GetNumRecords());
+
+ const FakeMetadataChangeList::Record& record1 = change_list.GetNthRecord(0);
+ EXPECT_EQ(FakeMetadataChangeList::UPDATE_METADATA, record1.action);
+ EXPECT_EQ("tag1", record1.tag);
+ EXPECT_FALSE(record1.metadata.is_deleted());
+ EXPECT_EQ(1, record1.metadata.sequence_number());
+ EXPECT_EQ(0, record1.metadata.acked_sequence_number());
+ EXPECT_EQ(kUncommittedVersion, record1.metadata.server_version());
+
+ const FakeMetadataChangeList::Record& record2 = change_list.GetNthRecord(1);
+ EXPECT_EQ(FakeMetadataChangeList::UPDATE_METADATA, record2.action);
+ EXPECT_EQ("tag2", record2.tag);
+ EXPECT_FALSE(record2.metadata.is_deleted());
+ EXPECT_EQ(1, record2.metadata.sequence_number());
+ EXPECT_EQ(0, record2.metadata.acked_sequence_number());
+ EXPECT_EQ(kUncommittedVersion, record2.metadata.server_version());
}
// Starts the type sync proxy with no local state.
@@ -579,9 +781,19 @@ TEST_F(SharedModelTypeProcessorTest, TwoIndependentItems) {
TEST_F(SharedModelTypeProcessorTest, NoCommitsUntilInitialSyncDone) {
Start();
- WriteItem("tag1", "value1");
+ FakeMetadataChangeList change_list;
+
+ WriteItem("tag1", "value1", &change_list);
EXPECT_EQ(0U, GetNumCommitRequestLists());
+ // Even though there the item hasn't been committed its metadata should have
+ // already been updated and the sequence number changed.
+ EXPECT_EQ(1U, change_list.GetNumRecords());
+ const FakeMetadataChangeList::Record& record1 = change_list.GetNthRecord(0);
+ EXPECT_EQ(FakeMetadataChangeList::UPDATE_METADATA, record1.action);
+ EXPECT_EQ("tag1", record1.tag);
+ EXPECT_EQ(1, record1.metadata.sequence_number());
+
OnInitialSyncDone();
EXPECT_EQ(1U, GetNumCommitRequestLists());
EXPECT_TRUE(HasCommitRequestForTag("tag1"));
@@ -594,19 +806,21 @@ TEST_F(SharedModelTypeProcessorTest, NoCommitsUntilInitialSyncDone) {
TEST_F(SharedModelTypeProcessorTest, Stop) {
InitializeToReadyState();
+ FakeMetadataChangeList change_list;
+
// The first item is fully committed.
- WriteItem("tag1", "value1");
+ WriteItem("tag1", "value1", &change_list);
ASSERT_TRUE(HasCommitRequestForTag("tag1"));
SuccessfulCommitResponse(GetLatestCommitRequestForTag("tag1"));
// The second item has a commit request in progress.
- WriteItem("tag2", "value2");
+ WriteItem("tag2", "value2", &change_list);
EXPECT_TRUE(HasCommitRequestForTag("tag2"));
Stop();
// The third item is added after stopping.
- WriteItem("tag3", "value3");
+ WriteItem("tag3", "value3", &change_list);
Restart();
@@ -630,19 +844,21 @@ TEST_F(SharedModelTypeProcessorTest, Stop) {
TEST_F(SharedModelTypeProcessorTest, Disable) {
InitializeToReadyState();
+ FakeMetadataChangeList change_list;
+
// The first item is fully committed.
- WriteItem("tag1", "value1");
+ WriteItem("tag1", "value1", &change_list);
ASSERT_TRUE(HasCommitRequestForTag("tag1"));
SuccessfulCommitResponse(GetLatestCommitRequestForTag("tag1"));
// The second item has a commit request in progress.
- WriteItem("tag2", "value2");
+ WriteItem("tag2", "value2", &change_list);
EXPECT_TRUE(HasCommitRequestForTag("tag2"));
Disable();
// The third item is added after disable.
- WriteItem("tag3", "value3");
+ WriteItem("tag3", "value3", &change_list);
// Now we re-enable.
Restart();
@@ -728,14 +944,16 @@ TEST_F(SharedModelTypeProcessorTest, StopWithPendingUpdates) {
TEST_F(SharedModelTypeProcessorTest, DISABLED_ReEncryptCommitsWithNewKey) {
InitializeToReadyState();
+ FakeMetadataChangeList change_list;
+
// Commit an item.
- WriteItem("tag1", "value1");
+ WriteItem("tag1", "value1", &change_list);
ASSERT_TRUE(HasCommitRequestForTag("tag1"));
const CommitRequestData& tag1_v1_data = GetLatestCommitRequestForTag("tag1");
SuccessfulCommitResponse(tag1_v1_data);
// Create another item and don't wait for its commit response.
- WriteItem("tag2", "value2");
+ WriteItem("tag2", "value2", &change_list);
ASSERT_EQ(2U, GetNumCommitRequestLists());
diff --git a/sync/internal_api/test/fake_metadata_change_list.cc b/sync/internal_api/test/fake_metadata_change_list.cc
new file mode 100644
index 0000000..407066d
--- /dev/null
+++ b/sync/internal_api/test/fake_metadata_change_list.cc
@@ -0,0 +1,59 @@
+// Copyright 2016 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 <string>
+
+#include "sync/internal_api/public/test/fake_metadata_change_list.h"
+
+namespace syncer_v2 {
+
+FakeMetadataChangeList::FakeMetadataChangeList() {}
+
+FakeMetadataChangeList::~FakeMetadataChangeList() {}
+
+FakeMetadataChangeList::Record::Record() {}
+
+FakeMetadataChangeList::Record::~Record() {}
+
+void FakeMetadataChangeList::UpdateDataTypeState(
+ const DataTypeState& data_type_state) {
+ Record record;
+ record.action = UPDATE_DATA_TYPE_STATE;
+ record.data_type_state = data_type_state;
+ records_.push_back(record);
+}
+
+void FakeMetadataChangeList::ClearDataTypeState() {
+ Record record;
+ record.action = CLEAR_DATA_TYPE_STATE;
+ records_.push_back(record);
+}
+
+void FakeMetadataChangeList::UpdateMetadata(
+ const std::string& client_tag,
+ const sync_pb::EntityMetadata& metadata) {
+ Record record;
+ record.action = UPDATE_METADATA;
+ record.tag = client_tag;
+ record.metadata.CopyFrom(metadata);
+ records_.push_back(record);
+}
+
+void FakeMetadataChangeList::ClearMetadata(const std::string& client_tag) {
+ Record record;
+ record.action = CLEAR_METADATA;
+ record.tag = client_tag;
+ records_.push_back(record);
+}
+
+size_t FakeMetadataChangeList::GetNumRecords() const {
+ return records_.size();
+}
+
+const FakeMetadataChangeList::Record& FakeMetadataChangeList::GetNthRecord(
+ size_t n) const {
+ return records_[n];
+}
+
+} // namespace syncer_v2
diff --git a/sync/sync_tests.gypi b/sync/sync_tests.gypi
index 079812c..c9ec6ed 100644
--- a/sync/sync_tests.gypi
+++ b/sync/sync_tests.gypi
@@ -183,6 +183,7 @@
'test_support_sync_core',
],
'sources': [
+ 'internal_api/public/test/fake_metadata_change_list.h',
'internal_api/public/test/fake_model_type_service.h',
'internal_api/public/test/fake_sync_manager.h',
'internal_api/public/test/null_sync_context_proxy.h',
@@ -190,6 +191,7 @@
'internal_api/public/test/test_entry_factory.h',
'internal_api/public/test/test_internal_components_factory.h',
'internal_api/public/test/test_user_share.h',
+ 'internal_api/test/fake_metadata_change_list.cc',
'internal_api/test/fake_model_type_service.cc',
'internal_api/test/fake_sync_manager.cc',
'internal_api/test/null_sync_context_proxy.cc',