Commit 4d77b5d2 authored by Rushan Suleymanov's avatar Rushan Suleymanov Committed by Commit Bot

[Sync] Add a unit test for redundant local deletions

This CL adds a unit test for the case from CL
https://crrev.com/c/2027407.

There is also a fix of use-after-free bug in client tag based remote
update handler.

Bug: 1046309
Change-Id: I00302c5772aa960b1af5064d768bcd5e0f8dd45d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2346431
Commit-Queue: Rushan Suleymanov <rushans@google.com>
Reviewed-by: default avatarMaksim Moskvitin <mmoskvitin@google.com>
Cr-Commit-Position: refs/heads/master@{#796885}
parent 2f74ce61
...@@ -105,17 +105,18 @@ ClientTagBasedRemoteUpdateHandler::ProcessIncrementalUpdate( ...@@ -105,17 +105,18 @@ ClientTagBasedRemoteUpdateHandler::ProcessIncrementalUpdate(
DCHECK(storage_key_to_clear.empty()); DCHECK(storage_key_to_clear.empty());
if (got_new_encryption_requirements) {
already_updated.insert(entity->storage_key());
}
if (entity->CanClearMetadata()) { if (entity->CanClearMetadata()) {
metadata_changes->ClearMetadata(entity->storage_key()); metadata_changes->ClearMetadata(entity->storage_key());
// The line below frees |entity| and it shouldn't be used afterwards.
entity_tracker_->RemoveEntityForStorageKey(entity->storage_key()); entity_tracker_->RemoveEntityForStorageKey(entity->storage_key());
} else { } else {
metadata_changes->UpdateMetadata(entity->storage_key(), metadata_changes->UpdateMetadata(entity->storage_key(),
entity->metadata()); entity->metadata());
} }
if (got_new_encryption_requirements) {
already_updated.insert(entity->storage_key());
}
} }
if (got_new_encryption_requirements) { if (got_new_encryption_requirements) {
......
...@@ -14,11 +14,9 @@ ...@@ -14,11 +14,9 @@
#include "components/sync/test/engine/mock_model_type_worker.h" #include "components/sync/test/engine/mock_model_type_worker.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace { namespace syncer {
using syncer::FakeModelTypeSyncBridge; namespace {
using syncer::UpdateResponseData;
using syncer::UpdateResponseDataList;
const char kKey1[] = "key1"; const char kKey1[] = "key1";
const char kKey2[] = "key2"; const char kKey2[] = "key2";
...@@ -34,31 +32,35 @@ class ClientTagBasedRemoteUpdateHandlerTest : public ::testing::Test { ...@@ -34,31 +32,35 @@ class ClientTagBasedRemoteUpdateHandlerTest : public ::testing::Test {
public: public:
ClientTagBasedRemoteUpdateHandlerTest() ClientTagBasedRemoteUpdateHandlerTest()
: processor_entity_tracker_(GenerateModelTypeState(), : processor_entity_tracker_(GenerateModelTypeState(),
syncer::EntityMetadataMap()), EntityMetadataMap()),
model_type_sync_bridge_(change_processor_.CreateForwardingProcessor()), model_type_sync_bridge_(change_processor_.CreateForwardingProcessor()),
remote_update_handler_(syncer::PREFERENCES, remote_update_handler_(PREFERENCES,
&model_type_sync_bridge_, &model_type_sync_bridge_,
&processor_entity_tracker_), &processor_entity_tracker_),
worker_(GenerateModelTypeState(), &model_type_processor_) {} worker_(GenerateModelTypeState(), &model_type_processor_) {}
~ClientTagBasedRemoteUpdateHandlerTest() override = default; ~ClientTagBasedRemoteUpdateHandlerTest() override = default;
void ProcessSingleUpdate(UpdateResponseData update) { void ProcessSingleUpdate(const sync_pb::ModelTypeState& model_type_state,
UpdateResponseData update) {
UpdateResponseDataList updates; UpdateResponseDataList updates;
updates.push_back(std::move(update)); updates.push_back(std::move(update));
remote_update_handler_.ProcessIncrementalUpdate(GenerateModelTypeState(), remote_update_handler_.ProcessIncrementalUpdate(model_type_state,
std::move(updates)); std::move(updates));
} }
syncer::UpdateResponseData GenerateUpdate(const std::string& key, void ProcessSingleUpdate(UpdateResponseData update) {
ProcessSingleUpdate(GenerateModelTypeState(), std::move(update));
}
UpdateResponseData GenerateUpdate(const std::string& key,
const std::string& value) { const std::string& value) {
const syncer::ClientTagHash client_tag_hash = const ClientTagHash client_tag_hash =
FakeModelTypeSyncBridge::TagHashFromKey(key); FakeModelTypeSyncBridge::TagHashFromKey(key);
return GenerateUpdate(client_tag_hash, key, value); return GenerateUpdate(client_tag_hash, key, value);
} }
syncer::UpdateResponseData GenerateUpdate( UpdateResponseData GenerateUpdate(const ClientTagHash& client_tag_hash,
const syncer::ClientTagHash& client_tag_hash,
const std::string& key, const std::string& key,
const std::string& value) { const std::string& value) {
return worker()->GenerateUpdateData( return worker()->GenerateUpdateData(
...@@ -66,10 +68,10 @@ class ClientTagBasedRemoteUpdateHandlerTest : public ::testing::Test { ...@@ -66,10 +68,10 @@ class ClientTagBasedRemoteUpdateHandlerTest : public ::testing::Test {
FakeModelTypeSyncBridge::GenerateSpecifics(key, value)); FakeModelTypeSyncBridge::GenerateSpecifics(key, value));
} }
syncer::UpdateResponseData GenerateUpdate(const std::string& key, UpdateResponseData GenerateUpdate(const std::string& key,
const std::string& value, const std::string& value,
int64_t version_offset) { int64_t version_offset) {
const syncer::ClientTagHash client_tag_hash = const ClientTagHash client_tag_hash =
FakeModelTypeSyncBridge::TagHashFromKey(key); FakeModelTypeSyncBridge::TagHashFromKey(key);
const sync_pb::ModelTypeState model_type_state = GenerateModelTypeState(); const sync_pb::ModelTypeState model_type_state = GenerateModelTypeState();
const sync_pb::EntitySpecifics specifics = const sync_pb::EntitySpecifics specifics =
...@@ -84,25 +86,25 @@ class ClientTagBasedRemoteUpdateHandlerTest : public ::testing::Test { ...@@ -84,25 +86,25 @@ class ClientTagBasedRemoteUpdateHandlerTest : public ::testing::Test {
} }
FakeModelTypeSyncBridge* bridge() { return &model_type_sync_bridge_; } FakeModelTypeSyncBridge* bridge() { return &model_type_sync_bridge_; }
syncer::ClientTagBasedRemoteUpdateHandler* remote_update_handler() { ClientTagBasedRemoteUpdateHandler* remote_update_handler() {
return &remote_update_handler_; return &remote_update_handler_;
} }
FakeModelTypeSyncBridge::Store* db() { return bridge()->mutable_db(); } FakeModelTypeSyncBridge::Store* db() { return bridge()->mutable_db(); }
syncer::ProcessorEntityTracker* entity_tracker() { ProcessorEntityTracker* entity_tracker() {
return &processor_entity_tracker_; return &processor_entity_tracker_;
} }
testing::NiceMock<syncer::MockModelTypeChangeProcessor>* change_processor() { testing::NiceMock<MockModelTypeChangeProcessor>* change_processor() {
return &change_processor_; return &change_processor_;
} }
syncer::MockModelTypeWorker* worker() { return &worker_; } MockModelTypeWorker* worker() { return &worker_; }
private: private:
testing::NiceMock<syncer::MockModelTypeChangeProcessor> change_processor_; testing::NiceMock<MockModelTypeChangeProcessor> change_processor_;
syncer::ProcessorEntityTracker processor_entity_tracker_; ProcessorEntityTracker processor_entity_tracker_;
FakeModelTypeSyncBridge model_type_sync_bridge_; FakeModelTypeSyncBridge model_type_sync_bridge_;
syncer::ClientTagBasedRemoteUpdateHandler remote_update_handler_; ClientTagBasedRemoteUpdateHandler remote_update_handler_;
testing::NiceMock<syncer::MockModelTypeProcessor> model_type_processor_; testing::NiceMock<MockModelTypeProcessor> model_type_processor_;
syncer::MockModelTypeWorker worker_; MockModelTypeWorker worker_;
}; };
// Thoroughly tests the data generated by a server item creation. // Thoroughly tests the data generated by a server item creation.
...@@ -111,7 +113,7 @@ TEST_F(ClientTagBasedRemoteUpdateHandlerTest, ShouldProcessRemoteCreation) { ...@@ -111,7 +113,7 @@ TEST_F(ClientTagBasedRemoteUpdateHandlerTest, ShouldProcessRemoteCreation) {
EXPECT_EQ(1u, db()->data_count()); EXPECT_EQ(1u, db()->data_count());
EXPECT_EQ(1u, db()->metadata_count()); EXPECT_EQ(1u, db()->metadata_count());
const syncer::EntityData& data = db()->GetData(kKey1); const EntityData& data = db()->GetData(kKey1);
EXPECT_FALSE(data.id.empty()); EXPECT_FALSE(data.id.empty());
EXPECT_EQ(kKey1, data.specifics.preference().name()); EXPECT_EQ(kKey1, data.specifics.preference().name());
EXPECT_EQ(kValue1, data.specifics.preference().value()); EXPECT_EQ(kValue1, data.specifics.preference().value());
...@@ -136,7 +138,7 @@ TEST_F(ClientTagBasedRemoteUpdateHandlerTest, ...@@ -136,7 +138,7 @@ TEST_F(ClientTagBasedRemoteUpdateHandlerTest,
ShouldIgnoreRemoteUpdatesForRootNodes) { ShouldIgnoreRemoteUpdatesForRootNodes) {
ASSERT_EQ(0U, ProcessorEntityCount()); ASSERT_EQ(0U, ProcessorEntityCount());
ProcessSingleUpdate( ProcessSingleUpdate(
worker()->GenerateTypeRootUpdateData(syncer::ModelType::SESSIONS)); worker()->GenerateTypeRootUpdateData(ModelType::SESSIONS));
// Root node update should be filtered out. // Root node update should be filtered out.
EXPECT_EQ(0U, db()->data_count()); EXPECT_EQ(0U, db()->data_count());
EXPECT_EQ(0U, db()->metadata_count()); EXPECT_EQ(0U, db()->metadata_count());
...@@ -222,4 +224,28 @@ TEST_F(ClientTagBasedRemoteUpdateHandlerTest, ...@@ -222,4 +224,28 @@ TEST_F(ClientTagBasedRemoteUpdateHandlerTest,
EXPECT_FALSE(entity_tracker()->HasLocalChanges()); EXPECT_FALSE(entity_tracker()->HasLocalChanges());
} }
// Test for the case from crbug.com/1046309. Tests that there is no redundant
// deletion when processing remote deletion with different encryption key.
TEST_F(ClientTagBasedRemoteUpdateHandlerTest,
ShouldNotIssueDeletionUponRemoteDeletion) {
const std::string kTestEncryptionKeyName = "TestEncryptionKey";
const std::string kDifferentEncryptionKeyName = "DifferentEncryptionKey";
const ClientTagHash kClientTagHash =
FakeModelTypeSyncBridge::TagHashFromKey(kKey1);
sync_pb::ModelTypeState model_type_state = GenerateModelTypeState();
model_type_state.set_encryption_key_name(kTestEncryptionKeyName);
ProcessSingleUpdate(GenerateUpdate(kClientTagHash, kKey1, kValue1));
// Generate a remote deletion with a different encryption key.
model_type_state.set_encryption_key_name(kDifferentEncryptionKeyName);
ProcessSingleUpdate(model_type_state,
worker()->GenerateTombstoneUpdateData(kClientTagHash));
EXPECT_EQ(0u, ProcessorEntityCount());
}
} // namespace } // namespace
} // 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