Commit e57348fa authored by Marc Treib's avatar Marc Treib Committed by Commit Bot

Delete the Sync UssMigrator

All Sync data types have been migrated to USS, so the migrator isn't
needed anymore.

Bug: 1084499
Change-Id: I62c13ae30f686c6670bec826bbf6ecf0bd1978bb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2207384Reviewed-by: default avatarMaksim Moskvitin <mmoskvitin@google.com>
Reviewed-by: default avatarMikel Astiz <mastiz@chromium.org>
Commit-Queue: Marc Treib <treib@chromium.org>
Cr-Commit-Position: refs/heads/master@{#771595}
parent fa905ffd
......@@ -234,8 +234,6 @@ jumbo_static_library("rest_of_sync") {
"engine_impl/update_applicator.h",
"engine_impl/update_handler.cc",
"engine_impl/update_handler.h",
"engine_impl/uss_migrator.cc",
"engine_impl/uss_migrator.h",
"model/blocking_model_type_store.h",
"model/change_processor.cc",
"model/change_processor.h",
......@@ -633,7 +631,6 @@ source_set("unit_tests") {
"engine_impl/syncer_proto_util_unittest.cc",
"engine_impl/syncer_unittest.cc",
"engine_impl/syncer_util_unittest.cc",
"engine_impl/uss_migrator_unittest.cc",
"js/js_event_details_unittest.cc",
"js/sync_js_controller_unittest.cc",
"model/entity_data_unittest.cc",
......
......@@ -61,12 +61,10 @@ ModelTypeRegistry::ModelTypeRegistry(
const std::vector<scoped_refptr<ModelSafeWorker>>& workers,
UserShare* user_share,
NudgeHandler* nudge_handler,
const UssMigrator& uss_migrator,
CancelationSignal* cancelation_signal,
KeystoreKeysHandler* keystore_keys_handler)
: user_share_(user_share),
nudge_handler_(nudge_handler),
uss_migrator_(uss_migrator),
cancelation_signal_(cancelation_signal),
keystore_keys_handler_(keystore_keys_handler) {
for (size_t i = 0u; i < workers.size(); ++i) {
......@@ -75,7 +73,7 @@ ModelTypeRegistry::ModelTypeRegistry(
}
}
ModelTypeRegistry::~ModelTypeRegistry() {}
ModelTypeRegistry::~ModelTypeRegistry() = default;
void ModelTypeRegistry::ConnectNonBlockingType(
ModelType type,
......@@ -85,17 +83,6 @@ void ModelTypeRegistry::ConnectNonBlockingType(
DCHECK(commit_contributor_map_.find(type) == commit_contributor_map_.end());
DVLOG(1) << "Enabling an off-thread sync type: " << ModelTypeToString(type);
bool initial_sync_done =
activation_response->model_type_state.initial_sync_done();
// Attempt migration if the USS initial sync hasn't been done, there is a
// migrator function, and directory has data for this |type|, and |type| is
// not NIGORI. Nigori is exceptional, because it has a small amount of data,
// which is just downloaded from the server again.
bool do_migration = !initial_sync_done && !uss_migrator_.is_null() &&
directory()->InitialSyncEndedForType(type) &&
type != NIGORI;
bool trigger_initial_sync = !initial_sync_done && !do_migration;
// Save a raw pointer to the processor for connecting later.
ModelTypeProcessor* type_processor =
activation_response->type_processor.get();
......@@ -113,8 +100,11 @@ void ModelTypeRegistry::ConnectNonBlockingType(
std::make_pair(type, std::move(new_emitter)));
}
bool initial_sync_done =
activation_response->model_type_state.initial_sync_done();
auto worker = std::make_unique<ModelTypeWorker>(
type, activation_response->model_type_state, trigger_initial_sync,
type, activation_response->model_type_state,
/*trigger_initial_sync=*/!initial_sync_done,
std::move(cryptographer_copy), passphrase_type_, nudge_handler_,
std::move(activation_response->type_processor), emitter,
cancelation_signal_);
......@@ -129,33 +119,18 @@ void ModelTypeRegistry::ConnectNonBlockingType(
type_processor->ConnectSync(std::make_unique<CommitQueueProxy>(
worker_ptr->AsWeakPtr(), base::SequencedTaskRunnerHandle::Get()));
// Attempt migration if necessary.
if (do_migration && type == BOOKMARKS) {
// Almost all bookmarks are known to have migrated so let's avoid the USS
// migrator for bookmarks, since it's known to be problematic and hard to
// maintain (diverges from the data fetched from the actual server).
//
// Instead, the local copy in the directory should be purged, and the
// initial data fetched from the server.
directory()->PurgeEntriesWithTypeIn(ModelTypeSet(BOOKMARKS), ModelTypeSet(),
ModelTypeSet());
} else if (do_migration) {
// TODO(crbug.com/658002): Store a pref before attempting migration
// indicating that it was attempted so we can avoid failure loops.
int migrated_entity_count = 0;
if (uss_migrator_.Run(type, user_share_, worker_ptr,
&migrated_entity_count)) {
// If we succesfully migrated, purge the directory of data for the type.
// Purging removes the directory's local copy of the data only.
directory()->PurgeEntriesWithTypeIn(ModelTypeSet(type), ModelTypeSet(),
ModelTypeSet());
}
// If there is still data for this type left in the directory, purge it now.
// TODO(crbug.com/1084499): The purge should be safe to do even if the initial
// USS sync has already happened, and also for NIGORI.
if (!initial_sync_done && directory()->InitialSyncEndedForType(type) &&
type != NIGORI) {
directory()->PurgeEntriesWithTypeIn(/*disabled_types=*/ModelTypeSet(type),
/*types_to_journal=*/ModelTypeSet(),
/*types_to_unapply=*/ModelTypeSet());
}
// We want to check that we haven't accidentally enabled both the non-blocking
// and directory implementations for a given model type. This is true even if
// migration fails; our fallback in this case is to do an initial GetUpdates,
// not to use the directory implementation.
// and directory implementations for a given model type.
DCHECK(Intersection(GetEnabledDirectoryTypes(), GetEnabledNonBlockingTypes())
.Empty());
}
......@@ -253,14 +228,7 @@ ModelTypeSet ModelTypeRegistry::GetEnabledTypes() const {
}
ModelTypeSet ModelTypeRegistry::GetInitialSyncEndedTypes() const {
// To prevent initial sync of USS types before we reach UssMigrator, we
// collect initial sync state from Directory.
// TODO(crbug.com/981480): consider cleaning configuration flow in a way,
// that this logic is not needed.
ModelTypeSet result = directory()->InitialSyncEndedTypes();
// We don't apply UssMigrator for Nigori, so we need to check only update
// handler state.
result.Remove(NIGORI);
ModelTypeSet result;
for (const auto& kv : update_handler_map_) {
if (kv.second->IsInitialSyncEnded())
result.Put(kv.first);
......
......@@ -21,7 +21,6 @@
#include "components/sync/engine/non_blocking_sync_common.h"
#include "components/sync/engine/sync_encryption_handler.h"
#include "components/sync/engine_impl/nudge_handler.h"
#include "components/sync/engine_impl/uss_migrator.h"
#include "components/sync/syncable/user_share.h"
namespace syncer {
......@@ -45,7 +44,6 @@ class ModelTypeRegistry : public ModelTypeConnector,
ModelTypeRegistry(const std::vector<scoped_refptr<ModelSafeWorker>>& workers,
UserShare* user_share,
NudgeHandler* nudge_handler,
const UssMigrator& uss_migrator,
CancelationSignal* cancelation_signal,
KeystoreKeysHandler* keystore_keys_handler);
~ModelTypeRegistry() override;
......@@ -157,9 +155,6 @@ class ModelTypeRegistry : public ModelTypeConnector,
NudgeHandler* const nudge_handler_;
// Function to call to migrate data from the directory to USS.
UssMigrator uss_migrator_;
// CancelationSignal is signalled on engine shutdown. It is passed to
// ModelTypeWorker to cancel blocking operation.
CancelationSignal* const cancelation_signal_;
......
......@@ -37,8 +37,6 @@ class ModelTypeRegistryTest : public ::testing::Test {
registry_ = std::make_unique<ModelTypeRegistry>(
workers_, test_user_share_.user_share(), &mock_nudge_handler_,
base::BindRepeating(&ModelTypeRegistryTest::MigrateDirectory,
base::Unretained(this)),
&cancelation_signal_, test_user_share_.keystore_keys_handler());
}
......@@ -83,21 +81,11 @@ class ModelTypeRegistryTest : public ::testing::Test {
directory()->SetDownloadProgress(type, progress_marker);
}
bool migration_attempted() { return migration_attempted_; }
syncable::MetahandleSet metahandles_to_purge() {
return directory()->kernel()->metahandles_to_purge;
}
private:
bool MigrateDirectory(ModelType type,
UserShare* user_share,
ModelTypeWorker* worker,
int* migrated_entity_count) {
migration_attempted_ = true;
return true;
}
syncable::Directory* directory() {
return test_user_share_.user_share()->directory.get();
}
......@@ -109,7 +97,6 @@ class ModelTypeRegistryTest : public ::testing::Test {
std::vector<scoped_refptr<ModelSafeWorker>> workers_;
std::unique_ptr<ModelTypeRegistry> registry_;
MockNudgeHandler mock_nudge_handler_;
bool migration_attempted_ = false;
};
TEST_F(ModelTypeRegistryTest, NonBlockingTypes) {
......@@ -193,22 +180,4 @@ TEST_F(ModelTypeRegistryTest, GetInitialSyncEndedTypes) {
registry()->GetInitialSyncEndedTypes());
}
// Tests that when directory data is present for type ConnectNonBlockingType
// triggers USS migration and purges old directory data.
TEST_F(ModelTypeRegistryTest, UssMigration) {
EXPECT_FALSE(migration_attempted());
MarkInitialSyncEndedForDirectoryType(THEMES);
// Purge only proceeds in the presence of a progress marker for the type(s)
// being purged.
SetDummyProgressMarkerForType(THEMES);
EXPECT_EQ(0u, metahandles_to_purge().size());
registry()->ConnectNonBlockingType(
THEMES,
MakeDataTypeActivationResponse(MakeInitialModelTypeState(THEMES)));
EXPECT_TRUE(migration_attempted());
EXPECT_NE(0u, metahandles_to_purge().size());
}
} // namespace syncer
......@@ -31,7 +31,6 @@
#include "components/sync/engine_impl/sync_encryption_handler_impl.h"
#include "components/sync/engine_impl/sync_scheduler.h"
#include "components/sync/engine_impl/syncer_types.h"
#include "components/sync/engine_impl/uss_migrator.h"
#include "components/sync/nigori/cryptographer.h"
#include "components/sync/nigori/nigori.h"
#include "components/sync/protocol/sync.pb.h"
......@@ -347,8 +346,7 @@ void SyncManagerImpl::Init(InitArgs* args) {
}
model_type_registry_ = std::make_unique<ModelTypeRegistry>(
args->workers, share_, this, base::BindRepeating(&MigrateDirectoryData),
args->cancelation_signal,
args->workers, share_, this, args->cancelation_signal,
sync_encryption_handler_->GetKeystoreKeysHandler());
sync_encryption_handler_->AddObserver(model_type_registry_.get());
......
......@@ -136,8 +136,7 @@ class SyncSchedulerImplTest : public testing::Test {
model_type_registry_ = std::make_unique<ModelTypeRegistry>(
workers_, test_user_share_.user_share(), &mock_nudge_handler_,
UssMigrator(), &cancelation_signal_,
test_user_share_.keystore_keys_handler());
&cancelation_signal_, test_user_share_.keystore_keys_handler());
model_type_registry_->ConnectNonBlockingType(HISTORY_DELETE_DIRECTIVES,
MakeFakeActivationResponse());
model_type_registry_->RegisterDirectoryType(NIGORI, GROUP_PASSIVE);
......
......@@ -264,8 +264,7 @@ class SyncerTest : public testing::Test,
model_type_registry_ = std::make_unique<ModelTypeRegistry>(
workers_, test_user_share_.user_share(), &mock_nudge_handler_,
UssMigrator(), &cancelation_signal_,
test_user_share_.keystore_keys_handler());
&cancelation_signal_, test_user_share_.keystore_keys_handler());
model_type_registry_->RegisterDirectoryTypeDebugInfoObserver(
&debug_info_cache_);
......
// 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 "components/sync/engine_impl/uss_migrator.h"
#include <algorithm>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "components/sync/base/time.h"
#include "components/sync/engine_impl/model_type_worker.h"
#include "components/sync/protocol/sync.pb.h"
#include "components/sync/syncable/directory.h"
#include "components/sync/syncable/entry.h"
#include "components/sync/syncable/read_node.h"
#include "components/sync/syncable/read_transaction.h"
#include "components/sync/syncable/user_share.h"
namespace syncer {
namespace {
bool ExtractSyncEntity(ModelType type,
ReadTransaction* trans,
int64_t id,
sync_pb::SyncEntity* entity) {
ReadNode read_node(trans);
if (read_node.InitByIdLookup(id) != BaseNode::INIT_OK)
return false;
const syncable::Entry& entry = *read_node.GetEntry();
// Copy the fields USS cares about from the server side of the directory so
// that we don't miss things that haven't been applied yet. See
// ModelTypeWorker::ProcessGetUpdatesResponse for which fields are used.
entity->set_id_string(entry.GetId().GetServerId());
entity->set_version(entry.GetServerVersion());
entity->set_mtime(TimeToProtoTime(entry.GetServerMtime()));
entity->set_ctime(TimeToProtoTime(entry.GetServerCtime()));
entity->set_name(entry.GetServerNonUniqueName());
entity->set_deleted(entry.GetServerIsDel());
entity->set_client_defined_unique_tag(entry.GetUniqueClientTag());
// Required fields for bookmarks only.
entity->set_folder(entry.GetServerIsDir());
if (!entry.GetServerParentId().IsNull()) {
entity->set_parent_id_string(entry.GetServerParentId().GetServerId());
}
if (!entry.GetUniqueServerTag().empty()) {
// Permanent nodes don't have unique_positions and are assigned unique
// server tags.
entity->set_server_defined_unique_tag(entry.GetUniqueServerTag());
} else if (entry.GetServerUniquePosition().IsValid()) {
*entity->mutable_unique_position() =
entry.GetServerUniquePosition().ToProto();
} else {
// All boookmarks (except permanent ones with server tag) should have valid
// unique_positions including legacy bookmarks that are missing the field.
// Directory should have taken care of assigning proper unique_position
// during the first sync flow.
DCHECK_NE(BOOKMARKS, type);
}
entity->mutable_specifics()->CopyFrom(entry.GetServerSpecifics());
return true;
}
void AppendAllDescendantIds(const ReadTransaction* trans,
const ReadNode& node,
std::vector<int64_t>* all_descendant_ids) {
std::vector<int64_t> child_ids;
node.GetChildIds(&child_ids);
for (int child_id : child_ids) {
all_descendant_ids->push_back(child_id);
ReadNode child(trans);
child.InitByIdLookup(child_id);
AppendAllDescendantIds(trans, child, all_descendant_ids);
}
}
bool MigrateDirectoryDataWithBatchSize(ModelType type,
int batch_size,
UserShare* user_share,
ModelTypeWorker* worker,
int* cumulative_migrated_entity_count) {
ReadTransaction trans(FROM_HERE, user_share);
ReadNode root(&trans);
if (root.InitTypeRoot(type) != BaseNode::INIT_OK) {
LOG(ERROR) << "Missing root node for " << ModelTypeToString(type);
// Inform the worker so it can trigger a fallback initial GetUpdates.
worker->AbortMigration();
return false;
}
// Get the progress marker and context from the directory.
sync_pb::DataTypeProgressMarker progress;
sync_pb::DataTypeContext context;
user_share->directory->GetDownloadProgress(type, &progress);
user_share->directory->GetDataTypeContext(trans.GetWrappedTrans(), type,
&context);
std::vector<int64_t> child_ids;
AppendAllDescendantIds(&trans, root, &child_ids);
// Process |batch_size| entities at a time to reduce memory usage.
size_t i = 0;
// We use |do {} while| to guarantee that, even if there are no entities to
// process, we call ProcessGetUpdatesResponse() at least once in order to feed
// the progress marker.
do {
// Vector to own the temporary entities.
std::vector<std::unique_ptr<sync_pb::SyncEntity>> entities;
// Vector of raw pointers for passing to ProcessGetUpdatesResponse().
SyncEntityList entity_ptrs;
const size_t batch_limit = std::min(i + batch_size, child_ids.size());
for (; i < batch_limit; i++) {
auto entity = std::make_unique<sync_pb::SyncEntity>();
if (!ExtractSyncEntity(type, &trans, child_ids[i], entity.get())) {
LOG(ERROR) << "Failed to fetch child node for "
<< ModelTypeToString(type);
// Inform the worker so it can clear any partial data and trigger a
// fallback initial GetUpdates.
worker->AbortMigration();
return false;
}
// Ignore tombstones; they are not included for initial GetUpdates.
if (!entity->deleted()) {
entity_ptrs.push_back(entity.get());
entities.push_back(std::move(entity));
}
}
*cumulative_migrated_entity_count += entity_ptrs.size();
worker->ProcessGetUpdatesResponse(progress, context, entity_ptrs,
/*from_uss_migrator=*/true,
/*status=*/nullptr);
} while (i != child_ids.size());
worker->PassiveApplyUpdates(nullptr);
return true;
}
} // namespace
bool MigrateDirectoryData(ModelType type,
UserShare* user_share,
ModelTypeWorker* worker,
int* migrated_entity_count) {
*migrated_entity_count = 0;
return MigrateDirectoryDataWithBatchSize(type, 64, user_share, worker,
migrated_entity_count);
}
bool MigrateDirectoryDataWithBatchSizeForTesting(
ModelType type,
int batch_size,
UserShare* user_share,
ModelTypeWorker* worker,
int* cumulative_migrated_entity_count) {
return MigrateDirectoryDataWithBatchSize(type, batch_size, user_share, worker,
cumulative_migrated_entity_count);
}
} // namespace syncer
// 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 COMPONENTS_SYNC_ENGINE_IMPL_USS_MIGRATOR_H_
#define COMPONENTS_SYNC_ENGINE_IMPL_USS_MIGRATOR_H_
#include "base/callback.h"
#include "components/sync/base/model_type.h"
namespace syncer {
class ModelTypeWorker;
struct UserShare;
using UssMigrator = base::RepeatingCallback<
bool(ModelType, UserShare*, ModelTypeWorker*, int*)>;
// Pulls all the data for |type| out of the directory and sends it to |worker|
// as the result of an initial GetUpdates. Returns whether migration succeeded.
// |user_share|, |worker| and |migrated_entity_count| must not be null.
bool MigrateDirectoryData(ModelType type,
UserShare* user_share,
ModelTypeWorker* worker,
int* migrated_entity_count);
// A version of the above with |batch_size| as a parameter so it can be lowered
// for unit testing.
bool MigrateDirectoryDataWithBatchSizeForTesting(
ModelType type,
int batch_size,
UserShare* user_share,
ModelTypeWorker* worker,
int* cumulative_migrated_entity_count);
} // namespace syncer
#endif // COMPONENTS_SYNC_ENGINE_IMPL_USS_MIGRATOR_H_
// 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 "components/sync/engine_impl/uss_migrator.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "components/sync/base/cancelation_signal.h"
#include "components/sync/base/client_tag_hash.h"
#include "components/sync/engine_impl/cycle/non_blocking_type_debug_info_emitter.h"
#include "components/sync/engine_impl/model_type_worker.h"
#include "components/sync/engine_impl/test_entry_factory.h"
#include "components/sync/protocol/model_type_state.pb.h"
#include "components/sync/syncable/directory.h"
#include "components/sync/syncable/read_node.h"
#include "components/sync/syncable/read_transaction.h"
#include "components/sync/syncable/test_user_share.h"
#include "components/sync/test/engine/mock_model_type_processor.h"
#include "components/sync/test/engine/mock_nudge_handler.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace syncer {
namespace {
const ModelType kModelType = PREFERENCES;
const char kToken1[] = "token1";
const char kTag1[] = "tag1";
const char kTag2[] = "tag2";
const char kTag3[] = "tag3";
const char kValue1[] = "value1";
const char kValue2[] = "value2";
const char kValue3[] = "value3";
ClientTagHash GenerateTagHash(const std::string& tag) {
return ClientTagHash::FromUnhashed(kModelType, tag);
}
sync_pb::EntitySpecifics GenerateSpecifics(const std::string& tag,
const std::string& value) {
sync_pb::EntitySpecifics specifics;
specifics.mutable_preference()->set_name(tag);
specifics.mutable_preference()->set_value(value);
return specifics;
}
} // namespace
class UssMigratorTest : public ::testing::Test {
public:
UssMigratorTest() : debug_emitter_(kModelType, &debug_observers_) {
test_user_share_.SetUp();
entry_factory_ = std::make_unique<TestEntryFactory>(directory());
auto processor = std::make_unique<MockModelTypeProcessor>();
processor_ = processor.get();
worker_ = std::make_unique<ModelTypeWorker>(
kModelType, sync_pb::ModelTypeState(), false, /*cryptographer=*/nullptr,
PassphraseType::kImplicitPassphrase, &nudge_handler_,
std::move(processor), &debug_emitter_, &cancelation_signal_);
}
~UssMigratorTest() override { test_user_share_.TearDown(); }
void SetProgressMarkerToken(const std::string& token) {
sync_pb::DataTypeProgressMarker progress_marker;
progress_marker.set_token(token);
directory()->SetDownloadProgress(kModelType, progress_marker);
}
void CreateTypeRoot() { entry_factory_->CreateTypeRootNode(kModelType); }
int64_t InsertEntity(const std::string& key, const std::string& value) {
const sync_pb::EntitySpecifics specifics = GenerateSpecifics(key, value);
return entry_factory_->CreateSyncedItem(key, kModelType, false, specifics);
}
int64_t DeleteEntity(const std::string& key) {
return entry_factory_->CreateTombstone(key, kModelType);
}
base::Time GetCtimeForEntity(int64_t metahandle) {
ReadTransaction trans(FROM_HERE, user_share());
ReadNode read_node(&trans);
auto result = read_node.InitByIdLookup(metahandle);
DCHECK_EQ(BaseNode::INIT_OK, result);
return read_node.GetEntry()->GetServerCtime();
}
UserShare* user_share() { return test_user_share_.user_share(); }
MockNudgeHandler* nudge_handler() { return &nudge_handler_; }
ModelTypeWorker* worker() { return worker_.get(); }
MockModelTypeProcessor* processor() { return processor_; }
private:
syncable::Directory* directory() { return user_share()->directory.get(); }
base::test::SingleThreadTaskEnvironment task_environment_;
TestUserShare test_user_share_;
CancelationSignal cancelation_signal_;
std::unique_ptr<TestEntryFactory> entry_factory_;
MockNudgeHandler nudge_handler_;
base::ObserverList<TypeDebugInfoObserver>::Unchecked debug_observers_;
NonBlockingTypeDebugInfoEmitter debug_emitter_;
MockModelTypeProcessor* processor_ = nullptr;
std::unique_ptr<ModelTypeWorker> worker_;
};
TEST_F(UssMigratorTest, Migrate) {
CreateTypeRoot();
SetProgressMarkerToken(kToken1);
int64_t metahandle = InsertEntity(kTag1, kValue1);
base::Time ctime = GetCtimeForEntity(metahandle);
int migrated_entity_count;
ASSERT_TRUE(MigrateDirectoryData(kModelType, user_share(), worker(),
&migrated_entity_count));
// No nudge should happen in the happy case.
EXPECT_EQ(0, nudge_handler()->GetNumInitialDownloadNudges());
// One update with one entity in it.
EXPECT_EQ(1U, processor()->GetNumUpdateResponses());
EXPECT_EQ(1U, processor()->GetNthUpdateResponse(0).size());
EXPECT_EQ(1, migrated_entity_count);
const sync_pb::ModelTypeState& state = processor()->GetNthUpdateState(0);
EXPECT_EQ(kToken1, state.progress_marker().token());
const UpdateResponseData* update =
std::move(processor()->GetNthUpdateResponse(0).at(0));
ASSERT_TRUE(update);
const EntityData& entity = update->entity;
EXPECT_FALSE(entity.id.empty());
EXPECT_EQ(GenerateTagHash(kTag1), entity.client_tag_hash);
EXPECT_EQ(1, update->response_version);
EXPECT_EQ(ctime, entity.creation_time);
EXPECT_EQ(ctime, entity.modification_time);
EXPECT_EQ(kTag1, entity.name);
EXPECT_FALSE(entity.is_deleted());
EXPECT_EQ(kTag1, entity.specifics.preference().name());
EXPECT_EQ(kValue1, entity.specifics.preference().value());
}
TEST_F(UssMigratorTest, MigrateMultiple) {
int migrated_entity_count;
CreateTypeRoot();
SetProgressMarkerToken(kToken1);
InsertEntity(kTag1, kValue1);
InsertEntity(kTag2, kValue2);
InsertEntity(kTag3, kValue3);
ASSERT_TRUE(MigrateDirectoryData(kModelType, user_share(), worker(),
&migrated_entity_count));
EXPECT_EQ(1U, processor()->GetNumUpdateResponses());
EXPECT_EQ(3U, processor()->GetNthUpdateResponse(0).size());
EXPECT_EQ(3, migrated_entity_count);
std::vector<const UpdateResponseData*> updates =
processor()->GetNthUpdateResponse(0);
ASSERT_TRUE(updates.at(0));
EXPECT_EQ(kTag1, updates.at(0)->entity.specifics.preference().name());
ASSERT_TRUE(updates.at(1));
EXPECT_EQ(kTag2, updates.at(1)->entity.specifics.preference().name());
ASSERT_TRUE(updates.at(2));
EXPECT_EQ(kTag3, updates.at(2)->entity.specifics.preference().name());
const sync_pb::ModelTypeState& state = processor()->GetNthUpdateState(0);
EXPECT_EQ(kToken1, state.progress_marker().token());
}
TEST_F(UssMigratorTest, MigrateMultipleBatches) {
// Some arbitrary number of entities that represents entities migrated in
// previous calls to MigrateDirectoryDataWithBatchSizeForTesting().
const int kPreviouslyMigratedEntityCount = 13;
CreateTypeRoot();
SetProgressMarkerToken(kToken1);
InsertEntity(kTag1, kValue1);
InsertEntity(kTag2, kValue2);
InsertEntity(kTag3, kValue3);
int cumulative_migrated_entity_count = kPreviouslyMigratedEntityCount;
ASSERT_TRUE(MigrateDirectoryDataWithBatchSizeForTesting(
kModelType, 2, user_share(), worker(),
&cumulative_migrated_entity_count));
EXPECT_EQ(1U, processor()->GetNumUpdateResponses());
EXPECT_EQ(3U, processor()->GetNthUpdateResponse(0).size());
EXPECT_EQ(kPreviouslyMigratedEntityCount + 3,
cumulative_migrated_entity_count);
std::vector<const UpdateResponseData*> updates =
processor()->GetNthUpdateResponse(0);
ASSERT_TRUE(updates.at(0));
EXPECT_EQ(kTag1, updates.at(0)->entity.specifics.preference().name());
ASSERT_TRUE(updates.at(1));
EXPECT_EQ(kTag2, updates.at(1)->entity.specifics.preference().name());
ASSERT_TRUE(updates.at(2));
EXPECT_EQ(kTag3, updates.at(2)->entity.specifics.preference().name());
const sync_pb::ModelTypeState& state = processor()->GetNthUpdateState(0);
EXPECT_EQ(kToken1, state.progress_marker().token());
}
TEST_F(UssMigratorTest, MigrateIgnoresTombstone) {
int migrated_entity_count;
CreateTypeRoot();
SetProgressMarkerToken(kToken1);
DeleteEntity(kTag1);
ASSERT_TRUE(MigrateDirectoryData(kModelType, user_share(), worker(),
&migrated_entity_count));
EXPECT_EQ(0, nudge_handler()->GetNumInitialDownloadNudges());
EXPECT_EQ(1U, processor()->GetNumUpdateResponses());
EXPECT_EQ(0U, processor()->GetNthUpdateResponse(0).size());
EXPECT_EQ(0, migrated_entity_count);
const sync_pb::ModelTypeState& state = processor()->GetNthUpdateState(0);
EXPECT_EQ(kToken1, state.progress_marker().token());
}
TEST_F(UssMigratorTest, MigrateZero) {
int migrated_entity_count;
CreateTypeRoot();
SetProgressMarkerToken(kToken1);
ASSERT_TRUE(MigrateDirectoryData(kModelType, user_share(), worker(),
&migrated_entity_count));
EXPECT_EQ(0, nudge_handler()->GetNumInitialDownloadNudges());
EXPECT_EQ(1U, processor()->GetNumUpdateResponses());
EXPECT_EQ(0U, processor()->GetNthUpdateResponse(0).size());
EXPECT_EQ(0, migrated_entity_count);
const sync_pb::ModelTypeState& state = processor()->GetNthUpdateState(0);
EXPECT_EQ(kToken1, state.progress_marker().token());
}
TEST_F(UssMigratorTest, MissingTypeRoot) {
int migrated_entity_count;
EXPECT_EQ(0, nudge_handler()->GetNumInitialDownloadNudges());
ASSERT_FALSE(MigrateDirectoryData(kModelType, user_share(), worker(),
&migrated_entity_count));
EXPECT_EQ(1, nudge_handler()->GetNumInitialDownloadNudges());
EXPECT_EQ(0U, processor()->GetNumUpdateResponses());
EXPECT_EQ(0, migrated_entity_count);
}
} // namespace syncer
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment