Commit 56f7b697 authored by Rushan Suleymanov's avatar Rushan Suleymanov Committed by Commit Bot

[Sync] Postpone reupload of bookmarks until next updates received

When reupload is initiated after loading from the disk right away, it
may lead to upload bookmarks which were removed from the other device.
This would restore removed bookmarks. In practise it may be caused by
some devices which a rarely used.

Initiating reupload after receiving latest updates from the server helps
to prevent such behaviour.

Bug: 1061411
Change-Id: Ibc5646b19bf133de496140fa152b544bc06ebcf9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2299721
Commit-Queue: Rushan Suleymanov <rushans@google.com>
Reviewed-by: default avatarMikel Astiz <mastiz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#788775}
parent 6acbbb8e
...@@ -246,6 +246,9 @@ void BookmarkModelTypeProcessor::OnUpdateReceived( ...@@ -246,6 +246,9 @@ void BookmarkModelTypeProcessor::OnUpdateReceived(
bookmark_tracker_->set_model_type_state(model_type_state); bookmark_tracker_->set_model_type_state(model_type_state);
bookmark_tracker_->UpdateLastSyncTime(); bookmark_tracker_->UpdateLastSyncTime();
updates_handler.Process(updates, got_new_encryption_requirements); updates_handler.Process(updates, got_new_encryption_requirements);
if (bookmark_tracker_->ReuploadBookmarksOnLoadIfNeeded()) {
NudgeForCommitIfNeeded();
}
// There are cases when we receive non-empty updates that don't result in // There are cases when we receive non-empty updates that don't result in
// model changes (e.g. reflections). In that case, issue a write to persit the // model changes (e.g. reflections). In that case, issue a write to persit the
// progress marker in order to avoid downloading those updates again. // progress marker in order to avoid downloading those updates again.
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "components/bookmarks/test/test_bookmark_client.h" #include "components/bookmarks/test/test_bookmark_client.h"
#include "components/favicon/core/test/mock_favicon_service.h" #include "components/favicon/core/test/mock_favicon_service.h"
#include "components/sync/base/unique_position.h" #include "components/sync/base/unique_position.h"
#include "components/sync/engine/commit_queue.h"
#include "components/sync/model/data_type_activation_request.h" #include "components/sync/model/data_type_activation_request.h"
#include "components/sync_bookmarks/switches.h" #include "components/sync_bookmarks/switches.h"
#include "components/undo/bookmark_undo_service.h" #include "components/undo/bookmark_undo_service.h"
...@@ -63,6 +64,7 @@ syncer::UpdateResponseData CreateUpdateResponseData( ...@@ -63,6 +64,7 @@ syncer::UpdateResponseData CreateUpdateResponseData(
data.parent_id = bookmark_info.parent_id; data.parent_id = bookmark_info.parent_id;
data.server_defined_unique_tag = bookmark_info.server_tag; data.server_defined_unique_tag = bookmark_info.server_tag;
data.unique_position = unique_position.ToProto(); data.unique_position = unique_position.ToProto();
data.originator_client_item_id = guid;
sync_pb::BookmarkSpecifics* bookmark_specifics = sync_pb::BookmarkSpecifics* bookmark_specifics =
data.specifics.mutable_bookmark(); data.specifics.mutable_bookmark();
...@@ -149,6 +151,24 @@ void InitWithSyncedBookmarks(const std::vector<BookmarkInfo>& bookmarks, ...@@ -149,6 +151,24 @@ void InitWithSyncedBookmarks(const std::vector<BookmarkInfo>& bookmarks,
AssertState(processor, bookmarks); AssertState(processor, bookmarks);
} }
class MockCommitQueue : public syncer::CommitQueue {
public:
MOCK_METHOD0(NudgeForCommit, void());
};
class ProxyCommitQueue : public syncer::CommitQueue {
public:
explicit ProxyCommitQueue(CommitQueue* commit_queue)
: commit_queue_(commit_queue) {
DCHECK(commit_queue_);
}
void NudgeForCommit() override { commit_queue_->NudgeForCommit(); }
private:
CommitQueue* commit_queue_ = nullptr;
};
class TestBookmarkClientWithFavicon : public bookmarks::TestBookmarkClient { class TestBookmarkClientWithFavicon : public bookmarks::TestBookmarkClient {
public: public:
// This method must be used to tell the bookmark_model about favicon. // This method must be used to tell the bookmark_model about favicon.
...@@ -192,17 +212,18 @@ class TestBookmarkClientWithFavicon : public bookmarks::TestBookmarkClient { ...@@ -192,17 +212,18 @@ class TestBookmarkClientWithFavicon : public bookmarks::TestBookmarkClient {
class BookmarkModelTypeProcessorTest : public testing::Test { class BookmarkModelTypeProcessorTest : public testing::Test {
public: public:
BookmarkModelTypeProcessorTest() BookmarkModelTypeProcessorTest()
: processor_(&bookmark_undo_service_), : processor_(std::make_unique<BookmarkModelTypeProcessor>(
&bookmark_undo_service_)),
bookmark_model_(bookmarks::TestBookmarkClient::CreateModelWithClient( bookmark_model_(bookmarks::TestBookmarkClient::CreateModelWithClient(
std::make_unique<TestBookmarkClientWithFavicon>())) { std::make_unique<TestBookmarkClientWithFavicon>())) {
// TODO(crbug.com/516866): This class assumes model is loaded and sync has // TODO(crbug.com/516866): This class assumes model is loaded and sync has
// started before running tests. We should test other variations (i.e. model // started before running tests. We should test other variations (i.e. model
// isn't loaded yet and/or sync didn't start yet). // isn't loaded yet and/or sync didn't start yet).
processor_.SetFaviconService(&favicon_service_); processor_->SetFaviconService(&favicon_service_);
} }
void SimulateModelReadyToSync() { void SimulateModelReadyToSync() {
processor_.ModelReadyToSync( processor_->ModelReadyToSync(
/*metadata_str=*/std::string(), schedule_save_closure_.Get(), /*metadata_str=*/std::string(), schedule_save_closure_.Get(),
bookmark_model_.get()); bookmark_model_.get());
} }
...@@ -210,7 +231,19 @@ class BookmarkModelTypeProcessorTest : public testing::Test { ...@@ -210,7 +231,19 @@ class BookmarkModelTypeProcessorTest : public testing::Test {
void SimulateOnSyncStarting() { void SimulateOnSyncStarting() {
syncer::DataTypeActivationRequest request; syncer::DataTypeActivationRequest request;
request.cache_guid = kCacheGuid; request.cache_guid = kCacheGuid;
processor_.OnSyncStarting(request, base::DoNothing()); processor_->OnSyncStarting(request, base::DoNothing());
}
void SimulateConnectSync() {
processor_->ConnectSync(
std::make_unique<ProxyCommitQueue>(&mock_commit_queue_));
}
// Simulate browser restart.
void ResetModelTypeProcessor() {
processor_ =
std::make_unique<BookmarkModelTypeProcessor>(&bookmark_undo_service_);
processor_->SetFaviconService(&favicon_service_);
} }
void DestroyBookmarkModel() { bookmark_model_.reset(); } void DestroyBookmarkModel() { bookmark_model_.reset(); }
...@@ -224,7 +257,8 @@ class BookmarkModelTypeProcessorTest : public testing::Test { ...@@ -224,7 +257,8 @@ class BookmarkModelTypeProcessorTest : public testing::Test {
return &bookmark_undo_service_; return &bookmark_undo_service_;
} }
favicon::FaviconService* favicon_service() { return &favicon_service_; } favicon::FaviconService* favicon_service() { return &favicon_service_; }
BookmarkModelTypeProcessor* processor() { return &processor_; } MockCommitQueue* mock_commit_queue() { return &mock_commit_queue_; }
BookmarkModelTypeProcessor* processor() { return processor_.get(); }
base::MockCallback<base::RepeatingClosure>* schedule_save_closure() { base::MockCallback<base::RepeatingClosure>* schedule_save_closure() {
return &schedule_save_closure_; return &schedule_save_closure_;
} }
...@@ -242,7 +276,8 @@ class BookmarkModelTypeProcessorTest : public testing::Test { ...@@ -242,7 +276,8 @@ class BookmarkModelTypeProcessorTest : public testing::Test {
NiceMock<base::MockCallback<base::RepeatingClosure>> schedule_save_closure_; NiceMock<base::MockCallback<base::RepeatingClosure>> schedule_save_closure_;
BookmarkUndoService bookmark_undo_service_; BookmarkUndoService bookmark_undo_service_;
NiceMock<favicon::MockFaviconService> favicon_service_; NiceMock<favicon::MockFaviconService> favicon_service_;
BookmarkModelTypeProcessor processor_; NiceMock<MockCommitQueue> mock_commit_queue_;
std::unique_ptr<BookmarkModelTypeProcessor> processor_;
std::unique_ptr<bookmarks::BookmarkModel> bookmark_model_; std::unique_ptr<bookmarks::BookmarkModel> bookmark_model_;
}; };
...@@ -540,6 +575,7 @@ TEST_F(BookmarkModelTypeProcessorTest, ...@@ -540,6 +575,7 @@ TEST_F(BookmarkModelTypeProcessorTest,
ShouldNotRecommitEntitiesWhenEncryptionIsUpToDate) { ShouldNotRecommitEntitiesWhenEncryptionIsUpToDate) {
SimulateModelReadyToSync(); SimulateModelReadyToSync();
SimulateOnSyncStarting(); SimulateOnSyncStarting();
SimulateConnectSync();
// Initialize the process to make sure the tracker has been created. // Initialize the process to make sure the tracker has been created.
InitWithSyncedBookmarks({}, processor()); InitWithSyncedBookmarks({}, processor());
const SyncedBookmarkTracker* tracker = processor()->GetTrackerForTest(); const SyncedBookmarkTracker* tracker = processor()->GetTrackerForTest();
...@@ -561,6 +597,7 @@ TEST_F(BookmarkModelTypeProcessorTest, ...@@ -561,6 +597,7 @@ TEST_F(BookmarkModelTypeProcessorTest,
/*response_version=*/0); /*response_version=*/0);
response_data.encryption_key_name = kEncryptionKeyName; response_data.encryption_key_name = kEncryptionKeyName;
EXPECT_CALL(*mock_commit_queue(), NudgeForCommit()).Times(0);
syncer::UpdateResponseDataList updates; syncer::UpdateResponseDataList updates;
updates.push_back(std::move(response_data)); updates.push_back(std::move(response_data));
processor()->OnUpdateReceived(model_type_state, std::move(updates)); processor()->OnUpdateReceived(model_type_state, std::move(updates));
...@@ -687,31 +724,49 @@ TEST_F(BookmarkModelTypeProcessorTest, ShouldReuploadLegacyBookmarksOnStart) { ...@@ -687,31 +724,49 @@ TEST_F(BookmarkModelTypeProcessorTest, ShouldReuploadLegacyBookmarksOnStart) {
SimulateModelReadyToSync(); SimulateModelReadyToSync();
SimulateOnSyncStarting(); SimulateOnSyncStarting();
SimulateConnectSync();
InitWithSyncedBookmarks(bookmarks, processor()); InitWithSyncedBookmarks(bookmarks, processor());
sync_pb::BookmarkModelMetadata model_metadata = sync_pb::BookmarkModelMetadata model_metadata =
BuildBookmarkModelMetadataWithoutFullTitles(); BuildBookmarkModelMetadataWithoutFullTitles();
// Ensure that bookmark is legacy.
model_metadata.clear_bookmarks_full_title_reuploaded();
ASSERT_FALSE(processor()->GetTrackerForTest()->HasLocalChanges()); ASSERT_FALSE(processor()->GetTrackerForTest()->HasLocalChanges());
// Simulate browser restart, enable sync reupload and initialize the processor
// again.
ResetModelTypeProcessor();
base::test::ScopedFeatureList features; base::test::ScopedFeatureList features;
features.InitAndEnableFeature(switches::kSyncReuploadBookmarkFullTitles); features.InitAndEnableFeature(switches::kSyncReuploadBookmarkFullTitles);
BookmarkModelTypeProcessor new_processor(bookmark_undo_service());
std::string metadata_str; std::string metadata_str;
model_metadata.SerializeToString(&metadata_str); model_metadata.SerializeToString(&metadata_str);
new_processor.ModelReadyToSync(metadata_str, base::DoNothing(), processor()->ModelReadyToSync(metadata_str, base::DoNothing(),
bookmark_model()); bookmark_model());
SimulateOnSyncStarting();
SimulateConnectSync();
ASSERT_THAT(processor()->GetTrackerForTest(), NotNull());
const SyncedBookmarkTracker::Entity* entity =
processor()->GetTrackerForTest()->GetEntityForSyncId(kNodeId);
ASSERT_THAT(entity, NotNull());
// Entity should be synced before until first update is received.
ASSERT_FALSE(entity->IsUnsynced());
ASSERT_FALSE(processor()
->GetTrackerForTest()
->BuildBookmarkModelMetadata()
.bookmarks_full_title_reuploaded());
// Synchronize with the server and get any updates.
EXPECT_CALL(*mock_commit_queue(), NudgeForCommit());
processor()->OnUpdateReceived(CreateDummyModelTypeState(),
syncer::UpdateResponseDataList());
// Check that all entities are unsynced now and metadata is marked as // Check that all entities are unsynced now and metadata is marked as
// reuploaded. // reuploaded.
const size_t entities_count = EXPECT_TRUE(entity->IsUnsynced());
processor()->GetTrackerForTest()->GetAllEntities().size(); EXPECT_TRUE(processor()
EXPECT_EQ(1u, new_processor.GetTrackerForTest() ->GetTrackerForTest()
->GetEntitiesWithLocalChanges(entities_count)
.size());
EXPECT_TRUE(new_processor.GetTrackerForTest()
->BuildBookmarkModelMetadata() ->BuildBookmarkModelMetadata()
.bookmarks_full_title_reuploaded()); .bookmarks_full_title_reuploaded());
} }
......
...@@ -265,8 +265,6 @@ SyncedBookmarkTracker::CreateFromBookmarkModelAndMetadata( ...@@ -265,8 +265,6 @@ SyncedBookmarkTracker::CreateFromBookmarkModelAndMetadata(
return nullptr; return nullptr;
} }
tracker->ReuploadBookmarksOnLoadIfNeeded();
return tracker; return tracker;
} }
...@@ -732,11 +730,11 @@ SyncedBookmarkTracker::ReorderUnsyncedEntitiesExceptDeletions( ...@@ -732,11 +730,11 @@ SyncedBookmarkTracker::ReorderUnsyncedEntitiesExceptDeletions(
return ordered_entities; return ordered_entities;
} }
void SyncedBookmarkTracker::ReuploadBookmarksOnLoadIfNeeded() { bool SyncedBookmarkTracker::ReuploadBookmarksOnLoadIfNeeded() {
if (bookmarks_full_title_reuploaded_ || if (bookmarks_full_title_reuploaded_ ||
!base::FeatureList::IsEnabled( !base::FeatureList::IsEnabled(
switches::kSyncReuploadBookmarkFullTitles)) { switches::kSyncReuploadBookmarkFullTitles)) {
return; return false;
} }
for (const auto& sync_id_and_entity : sync_id_to_entities_map_) { for (const auto& sync_id_and_entity : sync_id_to_entities_map_) {
const SyncedBookmarkTracker::Entity* entity = const SyncedBookmarkTracker::Entity* entity =
...@@ -749,7 +747,8 @@ void SyncedBookmarkTracker::ReuploadBookmarksOnLoadIfNeeded() { ...@@ -749,7 +747,8 @@ void SyncedBookmarkTracker::ReuploadBookmarksOnLoadIfNeeded() {
} }
IncrementSequenceNumber(entity); IncrementSequenceNumber(entity);
} }
bookmarks_full_title_reuploaded_ = true; SetBookmarksFullTitleReuploaded();
return true;
} }
void SyncedBookmarkTracker::TraverseAndAppend( void SyncedBookmarkTracker::TraverseAndAppend(
......
...@@ -289,6 +289,15 @@ class SyncedBookmarkTracker { ...@@ -289,6 +289,15 @@ class SyncedBookmarkTracker {
void CheckAllNodesTracked( void CheckAllNodesTracked(
const bookmarks::BookmarkModel* bookmark_model) const; const bookmarks::BookmarkModel* bookmark_model) const;
// This method is used to mark all entities except permanent nodes as
// unsynced. This will cause reuploading of all bookmarks. The reupload
// will be initiated only when the |bookmarks_full_title_reuploaded| field in
// BookmarksMetadata is false. This field is used to prevent reuploading after
// each browser restart. Returns true if the reupload was initiated.
// TODO(crbug.com/1066962): remove this code when most of bookmarks are
// reuploaded.
bool ReuploadBookmarksOnLoadIfNeeded();
private: private:
// Enumeration of possible reasons why persisted metadata are considered // Enumeration of possible reasons why persisted metadata are considered
// corrupted and don't match the bookmark model. Used in UMA metrics. Do not // corrupted and don't match the bookmark model. Used in UMA metrics. Do not
...@@ -334,16 +343,6 @@ class SyncedBookmarkTracker { ...@@ -334,16 +343,6 @@ class SyncedBookmarkTracker {
std::vector<const Entity*> ReorderUnsyncedEntitiesExceptDeletions( std::vector<const Entity*> ReorderUnsyncedEntitiesExceptDeletions(
const std::vector<const Entity*>& entities) const; const std::vector<const Entity*>& entities) const;
// This method is used to mark all entities except permanent nodes as
// unsynced. This will cause reuploading of all bookmarks. This reupload
// should be initiated only when the |bookmarks_full_title_reuploaded| field
// in BookmarksMetadata is false. This field is used to prevent reuploading
// after each browser restart. It is set to true in
// BuildBookmarkModelMetadata.
// TODO(crbug.com/1066962): remove this code when most of bookmarks are
// reuploaded.
void ReuploadBookmarksOnLoadIfNeeded();
// Recursive method that starting from |node| appends all corresponding // Recursive method that starting from |node| appends all corresponding
// entities with updates in top-down order to |ordered_entities|. // entities with updates in top-down order to |ordered_entities|.
void TraverseAndAppend(const bookmarks::BookmarkNode* node, void TraverseAndAppend(const bookmarks::BookmarkNode* node,
......
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