client_tag_based_remote_update_handler_unittest.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/sync/model/client_tag_based_remote_update_handler.h"
  5. #include <utility>
  6. #include "base/test/scoped_feature_list.h"
  7. #include "components/sync/base/features.h"
  8. #include "components/sync/model/metadata_batch.h"
  9. #include "components/sync/model/processor_entity_tracker.h"
  10. #include "components/sync/protocol/entity_metadata.pb.h"
  11. #include "components/sync/protocol/entity_specifics.pb.h"
  12. #include "components/sync/protocol/model_type_state.pb.h"
  13. #include "components/sync/test/fake_model_type_sync_bridge.h"
  14. #include "components/sync/test/mock_model_type_change_processor.h"
  15. #include "components/sync/test/mock_model_type_processor.h"
  16. #include "components/sync/test/mock_model_type_worker.h"
  17. #include "testing/gtest/include/gtest/gtest.h"
  18. namespace syncer {
  19. namespace {
  20. const char kKey1[] = "key1";
  21. const char kKey2[] = "key2";
  22. const char kValue1[] = "value1";
  23. const char kValue2[] = "value2";
  24. sync_pb::ModelTypeState GenerateModelTypeState() {
  25. sync_pb::ModelTypeState model_type_state;
  26. model_type_state.set_initial_sync_done(true);
  27. return model_type_state;
  28. }
  29. ClientTagHash GetPrefHash(const std::string& key) {
  30. return ClientTagHash::FromUnhashed(
  31. PREFERENCES, FakeModelTypeSyncBridge::ClientTagFromKey(key));
  32. }
  33. sync_pb::EntitySpecifics GeneratePrefSpecifics(const std::string& key,
  34. const std::string& value) {
  35. sync_pb::EntitySpecifics specifics;
  36. specifics.mutable_preference()->set_name(key);
  37. specifics.mutable_preference()->set_value(value);
  38. return specifics;
  39. }
  40. class ClientTagBasedRemoteUpdateHandlerTest : public ::testing::Test {
  41. public:
  42. ClientTagBasedRemoteUpdateHandlerTest()
  43. : processor_entity_tracker_(GenerateModelTypeState(),
  44. EntityMetadataMap()),
  45. model_type_sync_bridge_(PREFERENCES,
  46. change_processor_.CreateForwardingProcessor()),
  47. remote_update_handler_(PREFERENCES,
  48. &model_type_sync_bridge_,
  49. &processor_entity_tracker_),
  50. worker_(GenerateModelTypeState(), &model_type_processor_) {}
  51. ~ClientTagBasedRemoteUpdateHandlerTest() override = default;
  52. void ProcessSingleUpdate(const sync_pb::ModelTypeState& model_type_state,
  53. UpdateResponseData update) {
  54. UpdateResponseDataList updates;
  55. updates.push_back(std::move(update));
  56. remote_update_handler_.ProcessIncrementalUpdate(model_type_state,
  57. std::move(updates));
  58. }
  59. void ProcessSingleUpdate(UpdateResponseData update) {
  60. ProcessSingleUpdate(GenerateModelTypeState(), std::move(update));
  61. }
  62. UpdateResponseData GenerateUpdate(const std::string& key,
  63. const std::string& value) {
  64. const ClientTagHash client_tag_hash = GetPrefHash(key);
  65. return GenerateUpdate(client_tag_hash, key, value);
  66. }
  67. UpdateResponseData GenerateUpdate(const ClientTagHash& client_tag_hash,
  68. const std::string& key,
  69. const std::string& value) {
  70. return worker()->GenerateUpdateData(client_tag_hash,
  71. GeneratePrefSpecifics(key, value));
  72. }
  73. UpdateResponseData GenerateUpdate(const std::string& key,
  74. const std::string& value,
  75. int64_t version_offset) {
  76. const ClientTagHash client_tag_hash = GetPrefHash(key);
  77. const sync_pb::ModelTypeState model_type_state = GenerateModelTypeState();
  78. const sync_pb::EntitySpecifics specifics =
  79. GeneratePrefSpecifics(key, value);
  80. return worker()->GenerateUpdateData(client_tag_hash, specifics,
  81. version_offset,
  82. model_type_state.encryption_key_name());
  83. }
  84. size_t ProcessorEntityCount() const {
  85. return processor_entity_tracker_.GetAllEntitiesIncludingTombstones().size();
  86. }
  87. FakeModelTypeSyncBridge* bridge() { return &model_type_sync_bridge_; }
  88. ClientTagBasedRemoteUpdateHandler* remote_update_handler() {
  89. return &remote_update_handler_;
  90. }
  91. FakeModelTypeSyncBridge::Store* db() { return bridge()->mutable_db(); }
  92. ProcessorEntityTracker* entity_tracker() {
  93. return &processor_entity_tracker_;
  94. }
  95. testing::NiceMock<MockModelTypeChangeProcessor>* change_processor() {
  96. return &change_processor_;
  97. }
  98. MockModelTypeWorker* worker() { return &worker_; }
  99. private:
  100. testing::NiceMock<MockModelTypeChangeProcessor> change_processor_;
  101. ProcessorEntityTracker processor_entity_tracker_;
  102. FakeModelTypeSyncBridge model_type_sync_bridge_;
  103. ClientTagBasedRemoteUpdateHandler remote_update_handler_;
  104. testing::NiceMock<MockModelTypeProcessor> model_type_processor_;
  105. MockModelTypeWorker worker_;
  106. };
  107. // Thoroughly tests the data generated by a server item creation.
  108. TEST_F(ClientTagBasedRemoteUpdateHandlerTest, ShouldProcessRemoteCreation) {
  109. base::test::ScopedFeatureList feature_list;
  110. feature_list.InitAndEnableFeature(kCacheBaseEntitySpecificsInMetadata);
  111. ProcessSingleUpdate(GenerateUpdate(kKey1, kValue1));
  112. EXPECT_EQ(1u, db()->data_count());
  113. EXPECT_EQ(1u, db()->metadata_count());
  114. EXPECT_EQ(0u, bridge()->trimmed_specifics_change_count());
  115. const EntityData& data = db()->GetData(kKey1);
  116. EXPECT_FALSE(data.id.empty());
  117. EXPECT_EQ(kKey1, data.specifics.preference().name());
  118. EXPECT_EQ(kValue1, data.specifics.preference().value());
  119. EXPECT_FALSE(data.creation_time.is_null());
  120. EXPECT_FALSE(data.modification_time.is_null());
  121. EXPECT_EQ(kKey1, data.name);
  122. EXPECT_FALSE(data.is_deleted());
  123. const sync_pb::EntityMetadata& metadata = db()->GetMetadata(kKey1);
  124. EXPECT_TRUE(metadata.has_client_tag_hash());
  125. EXPECT_TRUE(metadata.has_server_id());
  126. EXPECT_FALSE(metadata.is_deleted());
  127. EXPECT_EQ(0, metadata.sequence_number());
  128. EXPECT_EQ(0, metadata.acked_sequence_number());
  129. EXPECT_EQ(1, metadata.server_version());
  130. EXPECT_TRUE(metadata.has_creation_time());
  131. EXPECT_TRUE(metadata.has_modification_time());
  132. EXPECT_TRUE(metadata.has_specifics_hash());
  133. EXPECT_TRUE(metadata.has_possibly_trimmed_base_specifics());
  134. }
  135. TEST_F(ClientTagBasedRemoteUpdateHandlerTest,
  136. ShouldIgnoreRemoteUpdatesForRootNodes) {
  137. ASSERT_EQ(0U, ProcessorEntityCount());
  138. ProcessSingleUpdate(
  139. worker()->GenerateTypeRootUpdateData(ModelType::SESSIONS));
  140. // Root node update should be filtered out.
  141. EXPECT_EQ(0U, db()->data_count());
  142. EXPECT_EQ(0U, db()->metadata_count());
  143. EXPECT_EQ(0U, ProcessorEntityCount());
  144. }
  145. TEST_F(ClientTagBasedRemoteUpdateHandlerTest,
  146. ShouldIgnoreRemoteUpdatesWithUnexpectedClientTagHash) {
  147. ASSERT_EQ(0U, ProcessorEntityCount());
  148. ProcessSingleUpdate(GenerateUpdate(GetPrefHash(kKey2), kKey1, kValue1));
  149. EXPECT_EQ(0U, db()->data_count());
  150. EXPECT_EQ(0U, db()->metadata_count());
  151. EXPECT_EQ(0U, ProcessorEntityCount());
  152. }
  153. TEST_F(ClientTagBasedRemoteUpdateHandlerTest,
  154. ShouldNotClearTrimmedSpecificsOnNoopRemoteUpdates) {
  155. base::test::ScopedFeatureList feature_list;
  156. feature_list.InitAndEnableFeature(kCacheBaseEntitySpecificsInMetadata);
  157. const std::string kUnknownField = "unknown_field";
  158. // Initial update containing unsupported fields.
  159. UpdateResponseData update1 = GenerateUpdate(kKey1, kValue1);
  160. *update1.entity.specifics.mutable_unknown_fields() = kUnknownField;
  161. ProcessSingleUpdate(std::move(update1));
  162. ASSERT_EQ(1U, ProcessorEntityCount());
  163. ASSERT_EQ(1U, db()->data_change_count());
  164. ASSERT_EQ(1U, db()->metadata_change_count());
  165. ASSERT_EQ(1U, bridge()->trimmed_specifics_change_count());
  166. // Redundant update should not clear trimmed specifics.
  167. UpdateResponseData update2 = GenerateUpdate(kKey1, kValue1);
  168. *update2.entity.specifics.mutable_unknown_fields() = kUnknownField;
  169. ProcessSingleUpdate(std::move(update2));
  170. EXPECT_EQ(1U, db()->data_change_count());
  171. EXPECT_EQ(2U, db()->metadata_change_count());
  172. ASSERT_EQ(2U, bridge()->trimmed_specifics_change_count());
  173. EXPECT_EQ(kUnknownField, db()->GetMetadata(kKey1)
  174. .possibly_trimmed_base_specifics()
  175. .unknown_fields());
  176. }
  177. TEST_F(ClientTagBasedRemoteUpdateHandlerTest,
  178. ShouldUpdateMetadataOnNoopRemoteUpdates) {
  179. ProcessSingleUpdate(GenerateUpdate(kKey1, kValue1));
  180. ASSERT_EQ(1U, ProcessorEntityCount());
  181. ASSERT_EQ(1U, db()->data_change_count());
  182. ASSERT_EQ(1U, db()->metadata_change_count());
  183. // Redundant update from server doesn't write data but updates metadata.
  184. const int64_t time_before_update =
  185. db()->GetMetadata(kKey1).modification_time();
  186. ProcessSingleUpdate(GenerateUpdate(kKey1, kValue1));
  187. EXPECT_EQ(1U, db()->data_change_count());
  188. EXPECT_EQ(2U, db()->metadata_change_count());
  189. // Check that `modification_time` was updated.
  190. EXPECT_NE(time_before_update, db()->GetMetadata(kKey1).modification_time());
  191. }
  192. TEST_F(ClientTagBasedRemoteUpdateHandlerTest,
  193. ShouldIgnoreReflectionsOnRemoteUpdates) {
  194. ProcessSingleUpdate(GenerateUpdate(kKey1, kValue1));
  195. ASSERT_EQ(1U, ProcessorEntityCount());
  196. ASSERT_EQ(1U, db()->data_change_count());
  197. ASSERT_EQ(1U, db()->metadata_change_count());
  198. // A reflection (update already received) is ignored completely.
  199. ProcessSingleUpdate(GenerateUpdate(kKey1, kValue1, /*version_offset=*/0));
  200. EXPECT_EQ(1U, db()->data_change_count());
  201. EXPECT_EQ(1U, db()->metadata_change_count());
  202. }
  203. TEST_F(ClientTagBasedRemoteUpdateHandlerTest, ShouldProcessRemoteUpdates) {
  204. base::test::ScopedFeatureList feature_list;
  205. feature_list.InitAndEnableFeature(kCacheBaseEntitySpecificsInMetadata);
  206. ProcessSingleUpdate(GenerateUpdate(kKey1, kValue1));
  207. ASSERT_EQ(1U, ProcessorEntityCount());
  208. ASSERT_EQ(1U, db()->data_change_count());
  209. ASSERT_EQ(1U, db()->metadata_change_count());
  210. ASSERT_EQ(0U, bridge()->trimmed_specifics_change_count());
  211. // Should update both data and metadata.
  212. ProcessSingleUpdate(GenerateUpdate(kKey1, kValue2));
  213. ASSERT_EQ(2U, db()->data_change_count());
  214. ASSERT_EQ(2U, db()->metadata_change_count());
  215. EXPECT_EQ(1U, db()->data_count());
  216. EXPECT_EQ(1U, db()->metadata_count());
  217. EXPECT_EQ(kValue2, db()->GetData(kKey1).specifics.preference().value());
  218. const sync_pb::EntityMetadata& metadata = db()->GetMetadata(kKey1);
  219. EXPECT_EQ(0, metadata.sequence_number());
  220. EXPECT_EQ(0, metadata.acked_sequence_number());
  221. EXPECT_EQ(2, metadata.server_version());
  222. EXPECT_TRUE(metadata.has_possibly_trimmed_base_specifics());
  223. }
  224. TEST_F(ClientTagBasedRemoteUpdateHandlerTest, ShouldProcessRemoteDeletion) {
  225. ProcessSingleUpdate(GenerateUpdate(kKey1, kValue1));
  226. ASSERT_EQ(1U, ProcessorEntityCount());
  227. ASSERT_EQ(1U, db()->data_change_count());
  228. ASSERT_EQ(1U, db()->metadata_change_count());
  229. ProcessSingleUpdate(
  230. worker()->GenerateTombstoneUpdateData(GetPrefHash(kKey1)));
  231. // Delete from server should clear the data and all the metadata.
  232. EXPECT_EQ(0U, db()->data_count());
  233. EXPECT_EQ(0U, db()->metadata_count());
  234. EXPECT_EQ(0U, ProcessorEntityCount());
  235. }
  236. // Deletes an item we've never seen before. Should have no effect and not crash.
  237. TEST_F(ClientTagBasedRemoteUpdateHandlerTest,
  238. ShouldIgnoreRemoteDeletionOfUnknownEntity) {
  239. ASSERT_EQ(0U, ProcessorEntityCount());
  240. ProcessSingleUpdate(
  241. worker()->GenerateTombstoneUpdateData(GetPrefHash(kKey1)));
  242. EXPECT_EQ(0U, db()->data_count());
  243. EXPECT_EQ(0U, db()->metadata_count());
  244. EXPECT_EQ(0U, ProcessorEntityCount());
  245. }
  246. TEST_F(ClientTagBasedRemoteUpdateHandlerTest,
  247. ShouldNotTreatMatchingChangesAsConflict) {
  248. UpdateResponseData update = GenerateUpdate(kKey1, kValue1);
  249. sync_pb::EntitySpecifics specifics = update.entity.specifics;
  250. ProcessSingleUpdate(std::move(update));
  251. ASSERT_EQ(1U, ProcessorEntityCount());
  252. ASSERT_EQ(1U, db()->data_change_count());
  253. ASSERT_EQ(1U, db()->metadata_change_count());
  254. ASSERT_EQ(1U, db()->GetMetadata(kKey1).server_version());
  255. ASSERT_EQ(0U, bridge()->trimmed_specifics_change_count());
  256. // Mark local entity as changed.
  257. entity_tracker()->IncrementSequenceNumberForAllExcept({});
  258. ASSERT_TRUE(entity_tracker()->HasLocalChanges());
  259. update = GenerateUpdate(kKey1, kValue1);
  260. // Make sure to have the same specifics.
  261. update.entity.specifics = specifics;
  262. // Changes match doesn't call ResolveConflict.
  263. ProcessSingleUpdate(std::move(update));
  264. EXPECT_EQ(1U, db()->data_change_count());
  265. ASSERT_EQ(0U, bridge()->trimmed_specifics_change_count());
  266. EXPECT_EQ(2U, db()->GetMetadata(kKey1).server_version());
  267. EXPECT_EQ(1U, ProcessorEntityCount());
  268. EXPECT_FALSE(entity_tracker()->HasLocalChanges());
  269. }
  270. // Test for the case from crbug.com/1046309. Tests that there is no redundant
  271. // deletion when processing remote deletion with different encryption key.
  272. TEST_F(ClientTagBasedRemoteUpdateHandlerTest,
  273. ShouldNotIssueDeletionUponRemoteDeletion) {
  274. const std::string kTestEncryptionKeyName = "TestEncryptionKey";
  275. const std::string kDifferentEncryptionKeyName = "DifferentEncryptionKey";
  276. const ClientTagHash kClientTagHash = GetPrefHash(kKey1);
  277. sync_pb::ModelTypeState model_type_state = GenerateModelTypeState();
  278. model_type_state.set_encryption_key_name(kTestEncryptionKeyName);
  279. ProcessSingleUpdate(GenerateUpdate(kClientTagHash, kKey1, kValue1));
  280. // Generate a remote deletion with a different encryption key.
  281. model_type_state.set_encryption_key_name(kDifferentEncryptionKeyName);
  282. ProcessSingleUpdate(model_type_state,
  283. worker()->GenerateTombstoneUpdateData(kClientTagHash));
  284. EXPECT_EQ(0u, ProcessorEntityCount());
  285. }
  286. } // namespace
  287. } // namespace syncer