processor_entity_tracker_unittest.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  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/processor_entity_tracker.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.h"
  10. #include "testing/gmock/include/gmock/gmock.h"
  11. #include "testing/gtest/include/gtest/gtest.h"
  12. namespace syncer {
  13. namespace {
  14. using testing::ElementsAre;
  15. using testing::IsNull;
  16. using testing::NotNull;
  17. using testing::UnorderedElementsAre;
  18. constexpr char kEmptyStorageKey[] = "";
  19. constexpr char kStorageKey1[] = "key1";
  20. constexpr char kStorageKey2[] = "key2";
  21. constexpr int64_t kServerVersion = 5;
  22. sync_pb::ModelTypeState GenerateModelTypeState() {
  23. sync_pb::ModelTypeState model_type_state;
  24. model_type_state.set_initial_sync_done(true);
  25. return model_type_state;
  26. }
  27. std::unique_ptr<sync_pb::EntityMetadata> GenerateMetadata(
  28. const std::string& storage_key,
  29. const ClientTagHash& client_tag_hash) {
  30. sync_pb::EntityMetadata metadata;
  31. metadata.set_creation_time(1);
  32. metadata.set_modification_time(1);
  33. metadata.set_client_tag_hash(client_tag_hash.value());
  34. metadata.set_specifics_hash("specifics_hash");
  35. return std::make_unique<sync_pb::EntityMetadata>(std::move(metadata));
  36. }
  37. std::unique_ptr<sync_pb::EntityMetadata> GenerateTombstoneMetadata(
  38. const std::string& storage_key,
  39. const ClientTagHash& client_tag_hash) {
  40. std::unique_ptr<sync_pb::EntityMetadata> metadata =
  41. GenerateMetadata(storage_key, client_tag_hash);
  42. metadata->set_is_deleted(true);
  43. metadata->set_base_specifics_hash(metadata->specifics_hash());
  44. metadata->clear_specifics_hash();
  45. return metadata;
  46. }
  47. EntityData GenerateEntityData(const std::string& storage_key,
  48. const ClientTagHash& client_tag_hash) {
  49. EntityData entity_data;
  50. entity_data.client_tag_hash = client_tag_hash;
  51. entity_data.creation_time = base::Time::Now();
  52. entity_data.modification_time = entity_data.creation_time;
  53. entity_data.name = storage_key;
  54. // The tracker requires non-empty specifics with any data type.
  55. entity_data.specifics.mutable_preference();
  56. return entity_data;
  57. }
  58. UpdateResponseData GenerateUpdate(const std::string& storage_key,
  59. const ClientTagHash& client_tag_hash,
  60. int64_t response_version) {
  61. auto entity = absl::make_unique<EntityData>(
  62. GenerateEntityData(storage_key, client_tag_hash));
  63. UpdateResponseData update;
  64. update.entity = std::move(*entity);
  65. update.response_version = response_version;
  66. return update;
  67. }
  68. class ProcessorEntityTrackerTest : public ::testing::Test {
  69. public:
  70. ProcessorEntityTrackerTest()
  71. : entity_tracker_(GenerateModelTypeState(), {}) {}
  72. ~ProcessorEntityTrackerTest() override = default;
  73. const ClientTagHash kClientTagHash1 =
  74. ClientTagHash::FromHashed("client_tag_hash_1");
  75. const ClientTagHash kClientTagHash2 =
  76. ClientTagHash::FromHashed("client_tag_hash_2");
  77. protected:
  78. ProcessorEntityTracker entity_tracker_;
  79. };
  80. TEST_F(ProcessorEntityTrackerTest, ShouldLoadFromMetadata) {
  81. EntityMetadataMap metadata_map;
  82. metadata_map.emplace(kStorageKey1,
  83. GenerateMetadata(kStorageKey1, kClientTagHash1));
  84. metadata_map.emplace(
  85. kStorageKey2, GenerateTombstoneMetadata(kStorageKey2, kClientTagHash2));
  86. ProcessorEntityTracker entity_tracker(GenerateModelTypeState(),
  87. std::move(metadata_map));
  88. // Check some getters for the entity tracker.
  89. EXPECT_EQ(2u, entity_tracker.size());
  90. EXPECT_EQ(1u, entity_tracker.CountNonTombstoneEntries());
  91. EXPECT_TRUE(entity_tracker.model_type_state().initial_sync_done());
  92. EXPECT_TRUE(entity_tracker.AllStorageKeysPopulated());
  93. EXPECT_FALSE(entity_tracker.HasLocalChanges());
  94. // Check each entity thoroughly.
  95. const ProcessorEntity* entity =
  96. entity_tracker.GetEntityForStorageKey(kStorageKey1);
  97. ASSERT_THAT(entity, NotNull());
  98. EXPECT_EQ(entity, entity_tracker.GetEntityForTagHash(kClientTagHash1));
  99. EXPECT_EQ(kStorageKey1, entity->storage_key());
  100. EXPECT_EQ(1u, entity->metadata().creation_time());
  101. EXPECT_EQ(1u, entity->metadata().modification_time());
  102. EXPECT_EQ("specifics_hash", entity->metadata().specifics_hash());
  103. EXPECT_EQ(entity->metadata().client_tag_hash(), kClientTagHash1.value());
  104. EXPECT_FALSE(entity->metadata().is_deleted());
  105. const ProcessorEntity* tombstone_entity =
  106. entity_tracker.GetEntityForStorageKey(kStorageKey2);
  107. ASSERT_THAT(tombstone_entity, NotNull());
  108. EXPECT_EQ(kStorageKey2, tombstone_entity->storage_key());
  109. EXPECT_EQ(1u, tombstone_entity->metadata().creation_time());
  110. EXPECT_EQ(1u, tombstone_entity->metadata().modification_time());
  111. EXPECT_EQ("specifics_hash",
  112. tombstone_entity->metadata().base_specifics_hash());
  113. EXPECT_FALSE(tombstone_entity->metadata().has_specifics_hash());
  114. EXPECT_EQ(tombstone_entity->metadata().client_tag_hash(),
  115. kClientTagHash2.value());
  116. EXPECT_TRUE(tombstone_entity->metadata().is_deleted());
  117. const std::vector<const ProcessorEntity*> all_entities =
  118. entity_tracker.GetAllEntitiesIncludingTombstones();
  119. EXPECT_THAT(all_entities, UnorderedElementsAre(entity, tombstone_entity));
  120. }
  121. TEST_F(ProcessorEntityTrackerTest, ShouldAddNewLocalEntity) {
  122. std::unique_ptr<EntityData> entity_data = absl::make_unique<EntityData>(
  123. GenerateEntityData(kStorageKey1, kClientTagHash1));
  124. EntityData* entity_data_ptr = entity_data.get();
  125. const ProcessorEntity* entity = entity_tracker_.AddUnsyncedLocal(
  126. kStorageKey1, std::move(entity_data), /*trimmed_specifics=*/{});
  127. ASSERT_THAT(entity, NotNull());
  128. EXPECT_EQ(1u, entity_tracker_.size());
  129. EXPECT_EQ(1u, entity_tracker_.CountNonTombstoneEntries());
  130. EXPECT_EQ(entity, entity_tracker_.GetEntityForTagHash(
  131. entity_data_ptr->client_tag_hash));
  132. EXPECT_EQ(entity, entity_tracker_.GetEntityForStorageKey(kStorageKey1));
  133. EXPECT_TRUE(entity_tracker_.HasLocalChanges());
  134. EXPECT_EQ(kStorageKey1, entity->storage_key());
  135. EXPECT_EQ(entity->metadata().client_tag_hash(),
  136. entity_data_ptr->client_tag_hash.value());
  137. EXPECT_FALSE(entity->metadata().is_deleted());
  138. EXPECT_TRUE(entity->IsUnsynced());
  139. EXPECT_TRUE(entity->HasCommitData());
  140. }
  141. TEST_F(ProcessorEntityTrackerTest, ShouldAddNewRemoteEntity) {
  142. UpdateResponseData update =
  143. GenerateUpdate(kStorageKey1, kClientTagHash1, kServerVersion);
  144. const ProcessorEntity* entity =
  145. entity_tracker_.AddRemote(kStorageKey1, update, /*trimmed_specifics=*/{});
  146. ASSERT_THAT(entity, NotNull());
  147. EXPECT_EQ(1u, entity_tracker_.size());
  148. EXPECT_EQ(1u, entity_tracker_.CountNonTombstoneEntries());
  149. EXPECT_EQ(entity,
  150. entity_tracker_.GetEntityForTagHash(update.entity.client_tag_hash));
  151. EXPECT_EQ(entity, entity_tracker_.GetEntityForStorageKey(kStorageKey1));
  152. EXPECT_FALSE(entity_tracker_.HasLocalChanges());
  153. EXPECT_EQ(kStorageKey1, entity->storage_key());
  154. EXPECT_EQ(entity->metadata().client_tag_hash(),
  155. update.entity.client_tag_hash.value());
  156. EXPECT_FALSE(entity->metadata().is_deleted());
  157. }
  158. TEST_F(ProcessorEntityTrackerTest, ShouldAddEntityWithoutStorageKey) {
  159. UpdateResponseData update =
  160. GenerateUpdate(kStorageKey1, kClientTagHash1, kServerVersion);
  161. const ProcessorEntity* entity = entity_tracker_.AddRemote(
  162. kEmptyStorageKey, update, /*trimmed_specifics=*/{});
  163. ASSERT_THAT(entity, NotNull());
  164. // The entity should be available by the client tag hash only.
  165. EXPECT_EQ(kEmptyStorageKey, entity->storage_key());
  166. EXPECT_EQ(entity, entity_tracker_.GetEntityForTagHash(kClientTagHash1));
  167. // The empty storage key must not be used.
  168. EXPECT_THAT(entity_tracker_.GetEntityForStorageKey(kEmptyStorageKey),
  169. IsNull());
  170. EXPECT_EQ(1u, entity_tracker_.size());
  171. EXPECT_EQ(1u, entity_tracker_.CountNonTombstoneEntries());
  172. EXPECT_EQ(entity->metadata().client_tag_hash(),
  173. update.entity.client_tag_hash.value());
  174. EXPECT_FALSE(entity->metadata().is_deleted());
  175. // Check that tracker is waiting for the storage key to be populated.
  176. EXPECT_FALSE(entity_tracker_.AllStorageKeysPopulated());
  177. entity_tracker_.UpdateOrOverrideStorageKey(kClientTagHash1, kStorageKey1);
  178. EXPECT_EQ(entity, entity_tracker_.GetEntityForStorageKey(kStorageKey1));
  179. EXPECT_EQ(1u, entity_tracker_.size());
  180. EXPECT_EQ(1u, entity_tracker_.CountNonTombstoneEntries());
  181. EXPECT_TRUE(entity_tracker_.AllStorageKeysPopulated());
  182. }
  183. TEST_F(ProcessorEntityTrackerTest, ShouldClearStorageKeyForTombstone) {
  184. ProcessorEntity* entity = entity_tracker_.AddRemote(
  185. kStorageKey1,
  186. GenerateUpdate(kStorageKey1, kClientTagHash1, kServerVersion),
  187. /*trimmed_specifics=*/{});
  188. ASSERT_EQ(entity, entity_tracker_.GetEntityForStorageKey(kStorageKey1));
  189. ASSERT_EQ(kStorageKey1, entity->storage_key());
  190. // Mark the entity as removed.
  191. entity->RecordLocalDeletion();
  192. ASSERT_EQ(1u, entity_tracker_.size());
  193. ASSERT_EQ(0u, entity_tracker_.CountNonTombstoneEntries());
  194. entity_tracker_.ClearStorageKey(kStorageKey1);
  195. EXPECT_THAT(entity_tracker_.GetEntityForStorageKey(kStorageKey1), IsNull());
  196. EXPECT_TRUE(entity->storage_key().empty());
  197. EXPECT_EQ(1u, entity_tracker_.size());
  198. EXPECT_EQ(0u, entity_tracker_.CountNonTombstoneEntries());
  199. }
  200. TEST_F(ProcessorEntityTrackerTest, ShouldOverrideTombstone) {
  201. ProcessorEntity* entity = entity_tracker_.AddRemote(
  202. kStorageKey1,
  203. GenerateUpdate(kStorageKey1, kClientTagHash1, kServerVersion),
  204. /*trimmed_specifics=*/{});
  205. ASSERT_THAT(entity, NotNull());
  206. ASSERT_EQ(entity, entity_tracker_.GetEntityForStorageKey(kStorageKey1));
  207. ASSERT_EQ(kStorageKey1, entity->storage_key());
  208. // Mark the entity as removed.
  209. entity->RecordLocalDeletion();
  210. ASSERT_EQ(1u, entity_tracker_.size());
  211. ASSERT_EQ(0u, entity_tracker_.CountNonTombstoneEntries());
  212. // Mimic an entity being created with the same client tag hash.
  213. entity_tracker_.UpdateOrOverrideStorageKey(kClientTagHash1, kStorageKey2);
  214. EXPECT_EQ(kStorageKey2, entity->storage_key());
  215. EXPECT_THAT(entity_tracker_.GetEntityForStorageKey(kStorageKey1), IsNull());
  216. EXPECT_EQ(entity, entity_tracker_.GetEntityForStorageKey(kStorageKey2));
  217. EXPECT_EQ(1u, entity_tracker_.size());
  218. EXPECT_EQ(0u, entity_tracker_.CountNonTombstoneEntries());
  219. }
  220. TEST_F(ProcessorEntityTrackerTest, ShouldRemoveEntityForStorageKey) {
  221. const ProcessorEntity* entity = entity_tracker_.AddRemote(
  222. kStorageKey1,
  223. GenerateUpdate(kStorageKey1, kClientTagHash1, kServerVersion),
  224. /*trimmed_specifics=*/{});
  225. ASSERT_THAT(entity, NotNull());
  226. ASSERT_EQ(1u, entity_tracker_.size());
  227. entity_tracker_.RemoveEntityForStorageKey(kStorageKey1);
  228. EXPECT_EQ(0u, entity_tracker_.size());
  229. }
  230. TEST_F(ProcessorEntityTrackerTest, ShouldRemoveEntityForClientTagHash) {
  231. const ProcessorEntity* entity = entity_tracker_.AddRemote(
  232. kStorageKey1,
  233. GenerateUpdate(kStorageKey1, kClientTagHash1, kServerVersion),
  234. /*trimmed_specifics=*/{});
  235. ASSERT_THAT(entity, NotNull());
  236. ASSERT_EQ(entity, entity_tracker_.GetEntityForTagHash(kClientTagHash1));
  237. const ProcessorEntity* entity_no_key = entity_tracker_.AddRemote(
  238. kEmptyStorageKey,
  239. GenerateUpdate(kStorageKey2, kClientTagHash2, kServerVersion),
  240. /*trimmed_specifics=*/{});
  241. ASSERT_THAT(entity_no_key, NotNull());
  242. ASSERT_EQ(entity_no_key,
  243. entity_tracker_.GetEntityForTagHash(kClientTagHash2));
  244. ASSERT_EQ(2u, entity_tracker_.size());
  245. entity_tracker_.RemoveEntityForClientTagHash(kClientTagHash2);
  246. EXPECT_EQ(1u, entity_tracker_.size());
  247. EXPECT_THAT(entity_tracker_.GetEntityForTagHash(kClientTagHash2), IsNull());
  248. // A second call does not affect anything.
  249. entity_tracker_.RemoveEntityForClientTagHash(kClientTagHash2);
  250. EXPECT_EQ(1u, entity_tracker_.size());
  251. entity_tracker_.RemoveEntityForClientTagHash(kClientTagHash1);
  252. EXPECT_EQ(0u, entity_tracker_.size());
  253. }
  254. TEST_F(ProcessorEntityTrackerTest, ShouldReturnLocalChanges) {
  255. std::unique_ptr<EntityData> entity_data = absl::make_unique<EntityData>(
  256. GenerateEntityData(kStorageKey1, kClientTagHash1));
  257. ProcessorEntity* entity = entity_tracker_.AddUnsyncedLocal(
  258. kStorageKey1, std::move(entity_data), /*trimmed_specifics=*/{});
  259. ASSERT_THAT(entity, NotNull());
  260. ASSERT_TRUE(entity->IsUnsynced());
  261. ASSERT_TRUE(entity->HasCommitData());
  262. ASSERT_TRUE(entity_tracker_.HasLocalChanges());
  263. ASSERT_FALSE(
  264. entity_tracker_.GetEntitiesWithLocalChanges(/*max_entries=*/1).empty());
  265. // Make some local changes.
  266. entity->RecordLocalUpdate(std::make_unique<EntityData>(GenerateEntityData(
  267. kStorageKey1, kClientTagHash1)),
  268. /*trimmed_specifics=*/{});
  269. entity_tracker_.IncrementSequenceNumberForAllExcept({});
  270. EXPECT_TRUE(entity->IsUnsynced());
  271. EXPECT_TRUE(entity->HasCommitData());
  272. EXPECT_TRUE(entity_tracker_.HasLocalChanges());
  273. EXPECT_THAT(entity_tracker_.GetEntitiesWithLocalChanges(/*max_entries=*/2),
  274. ElementsAre(entity));
  275. }
  276. TEST_F(ProcessorEntityTrackerTest, ShouldUpdateSpecificsCacheOnLocalCreation) {
  277. base::test::ScopedFeatureList feature_list;
  278. feature_list.InitAndEnableFeature(kCacheBaseEntitySpecificsInMetadata);
  279. std::unique_ptr<EntityData> entity_data = absl::make_unique<EntityData>(
  280. GenerateEntityData(kStorageKey1, kClientTagHash1));
  281. sync_pb::EntitySpecifics specifics_for_caching;
  282. specifics_for_caching.mutable_preference()->set_name("name");
  283. specifics_for_caching.mutable_preference()->set_value("value");
  284. ProcessorEntity* entity = entity_tracker_.AddUnsyncedLocal(
  285. kStorageKey1, std::move(entity_data), specifics_for_caching);
  286. EXPECT_EQ(
  287. specifics_for_caching.SerializeAsString(),
  288. entity->metadata().possibly_trimmed_base_specifics().SerializeAsString());
  289. }
  290. TEST_F(ProcessorEntityTrackerTest, ShouldUpdateSpecificsCacheOnRemoteCreation) {
  291. base::test::ScopedFeatureList feature_list;
  292. feature_list.InitAndEnableFeature(kCacheBaseEntitySpecificsInMetadata);
  293. sync_pb::EntitySpecifics specifics_for_caching;
  294. specifics_for_caching.mutable_preference()->set_name("name");
  295. specifics_for_caching.mutable_preference()->set_value("value");
  296. ProcessorEntity* entity = entity_tracker_.AddRemote(
  297. kStorageKey1,
  298. GenerateUpdate(kStorageKey1, kClientTagHash1, kServerVersion),
  299. specifics_for_caching);
  300. EXPECT_EQ(
  301. specifics_for_caching.SerializeAsString(),
  302. entity->metadata().possibly_trimmed_base_specifics().SerializeAsString());
  303. }
  304. } // namespace
  305. } // namespace syncer