user_event_sync_bridge_unittest.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. // Copyright 2017 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_user_events/user_event_sync_bridge.h"
  5. #include <map>
  6. #include <set>
  7. #include <utility>
  8. #include "base/bind.h"
  9. #include "base/callback_helpers.h"
  10. #include "base/run_loop.h"
  11. #include "base/test/task_environment.h"
  12. #include "components/sync/model/data_batch.h"
  13. #include "components/sync/protocol/entity_specifics.pb.h"
  14. #include "components/sync/protocol/user_event_specifics.pb.h"
  15. #include "components/sync/test/mock_model_type_change_processor.h"
  16. #include "components/sync/test/model_type_store_test_util.h"
  17. #include "testing/gmock/include/gmock/gmock.h"
  18. #include "testing/gtest/include/gtest/gtest.h"
  19. namespace syncer {
  20. namespace {
  21. using sync_pb::UserEventSpecifics;
  22. using testing::_;
  23. using testing::ElementsAre;
  24. using testing::InvokeWithoutArgs;
  25. using testing::IsEmpty;
  26. using testing::IsNull;
  27. using testing::NotNull;
  28. using testing::Pair;
  29. using testing::Pointee;
  30. using testing::Return;
  31. using testing::SaveArg;
  32. using testing::SizeIs;
  33. using testing::UnorderedElementsAre;
  34. using testing::WithArg;
  35. using WriteBatch = ModelTypeStore::WriteBatch;
  36. MATCHER_P(MatchesUserEvent, expected, "") {
  37. if (!arg.has_user_event()) {
  38. *result_listener << "which is not a user event";
  39. return false;
  40. }
  41. const UserEventSpecifics& actual = arg.user_event();
  42. if (actual.event_time_usec() != expected.event_time_usec()) {
  43. return false;
  44. }
  45. if (actual.navigation_id() != expected.navigation_id()) {
  46. return false;
  47. }
  48. if (actual.session_id() != expected.session_id()) {
  49. return false;
  50. }
  51. return true;
  52. }
  53. UserEventSpecifics CreateSpecifics(int64_t event_time_usec,
  54. int64_t navigation_id,
  55. uint64_t session_id) {
  56. UserEventSpecifics specifics;
  57. specifics.set_event_time_usec(event_time_usec);
  58. specifics.set_navigation_id(navigation_id);
  59. specifics.set_session_id(session_id);
  60. return specifics;
  61. }
  62. std::unique_ptr<UserEventSpecifics> SpecificsUniquePtr(int64_t event_time_usec,
  63. int64_t navigation_id,
  64. uint64_t session_id) {
  65. return std::make_unique<UserEventSpecifics>(
  66. CreateSpecifics(event_time_usec, navigation_id, session_id));
  67. }
  68. class TestGlobalIdMapper : public GlobalIdMapper {
  69. public:
  70. void AddGlobalIdChangeObserver(GlobalIdChange callback) override {
  71. callback_ = std::move(callback);
  72. }
  73. int64_t GetLatestGlobalId(int64_t global_id) override {
  74. auto iter = id_map_.find(global_id);
  75. return iter == id_map_.end() ? global_id : iter->second;
  76. }
  77. void ChangeId(int64_t old_id, int64_t new_id) {
  78. id_map_[old_id] = new_id;
  79. callback_.Run(old_id, new_id);
  80. }
  81. private:
  82. GlobalIdChange callback_;
  83. std::map<int64_t, int64_t> id_map_;
  84. };
  85. class UserEventSyncBridgeTest : public testing::Test {
  86. protected:
  87. UserEventSyncBridgeTest() { ResetBridge(); }
  88. void ResetBridge() {
  89. OnceModelTypeStoreFactory store_factory;
  90. if (bridge_) {
  91. // Carry over the underlying store from previous bridge instances.
  92. std::unique_ptr<ModelTypeStore> store = bridge_->StealStoreForTest();
  93. bridge_.reset();
  94. store_factory =
  95. ModelTypeStoreTestUtil::MoveStoreToFactory(std::move(store));
  96. } else {
  97. store_factory = ModelTypeStoreTestUtil::FactoryForInMemoryStoreForTest();
  98. }
  99. bridge_ = std::make_unique<UserEventSyncBridge>(
  100. std::move(store_factory), mock_processor_.CreateForwardingProcessor(),
  101. &test_global_id_mapper_);
  102. }
  103. void WaitUntilModelReadyToSync(
  104. const std::string& account_id = "test_account_id") {
  105. base::RunLoop loop;
  106. base::RepeatingClosure quit_closure = loop.QuitClosure();
  107. // Let the bridge initialize fully, which should run ModelReadyToSync().
  108. ON_CALL(*processor(), ModelReadyToSync)
  109. .WillByDefault(InvokeWithoutArgs([=]() { quit_closure.Run(); }));
  110. loop.Run();
  111. ON_CALL(*processor(), IsTrackingMetadata()).WillByDefault(Return(true));
  112. ON_CALL(*processor(), TrackedAccountId()).WillByDefault(Return(account_id));
  113. }
  114. static std::string GetStorageKey(const UserEventSpecifics& specifics) {
  115. return UserEventSyncBridge::GetStorageKeyFromSpecificsForTest(specifics);
  116. }
  117. UserEventSyncBridge* bridge() { return bridge_.get(); }
  118. MockModelTypeChangeProcessor* processor() { return &mock_processor_; }
  119. TestGlobalIdMapper* mapper() { return &test_global_id_mapper_; }
  120. std::map<std::string, sync_pb::EntitySpecifics> GetAllData() {
  121. base::RunLoop loop;
  122. std::unique_ptr<DataBatch> batch;
  123. bridge_->GetAllDataForDebugging(base::BindOnce(
  124. [](base::RunLoop* loop, std::unique_ptr<DataBatch>* out_batch,
  125. std::unique_ptr<DataBatch> batch) {
  126. *out_batch = std::move(batch);
  127. loop->Quit();
  128. },
  129. &loop, &batch));
  130. loop.Run();
  131. EXPECT_NE(nullptr, batch);
  132. std::map<std::string, sync_pb::EntitySpecifics> storage_key_to_specifics;
  133. if (batch != nullptr) {
  134. while (batch->HasNext()) {
  135. auto [key, data] = batch->Next();
  136. storage_key_to_specifics[key] = data->specifics;
  137. }
  138. }
  139. return storage_key_to_specifics;
  140. }
  141. std::unique_ptr<sync_pb::EntitySpecifics> GetData(
  142. const std::string& storage_key) {
  143. base::RunLoop loop;
  144. std::unique_ptr<DataBatch> batch;
  145. bridge_->GetData(
  146. {storage_key},
  147. base::BindOnce(
  148. [](base::RunLoop* loop, std::unique_ptr<DataBatch>* out_batch,
  149. std::unique_ptr<DataBatch> batch) {
  150. *out_batch = std::move(batch);
  151. loop->Quit();
  152. },
  153. &loop, &batch));
  154. loop.Run();
  155. EXPECT_NE(nullptr, batch);
  156. std::unique_ptr<sync_pb::EntitySpecifics> specifics;
  157. if (batch != nullptr && batch->HasNext()) {
  158. auto [key, data] = batch->Next();
  159. specifics = std::make_unique<sync_pb::EntitySpecifics>(data->specifics);
  160. EXPECT_FALSE(batch->HasNext());
  161. }
  162. return specifics;
  163. }
  164. private:
  165. base::test::TaskEnvironment task_environment_;
  166. testing::NiceMock<MockModelTypeChangeProcessor> mock_processor_;
  167. TestGlobalIdMapper test_global_id_mapper_;
  168. std::unique_ptr<UserEventSyncBridge> bridge_;
  169. };
  170. TEST_F(UserEventSyncBridgeTest, MetadataIsInitialized) {
  171. EXPECT_CALL(*processor(), ModelReadyToSync(NotNull()));
  172. WaitUntilModelReadyToSync();
  173. }
  174. TEST_F(UserEventSyncBridgeTest, SingleRecord) {
  175. WaitUntilModelReadyToSync();
  176. const UserEventSpecifics specifics(CreateSpecifics(1u, 2u, 3u));
  177. std::string storage_key;
  178. EXPECT_CALL(*processor(), Put).WillOnce(WithArg<0>(SaveArg<0>(&storage_key)));
  179. bridge()->RecordUserEvent(std::make_unique<UserEventSpecifics>(specifics));
  180. EXPECT_THAT(GetData(storage_key), Pointee(MatchesUserEvent(specifics)));
  181. EXPECT_THAT(GetData("bogus"), IsNull());
  182. EXPECT_THAT(GetAllData(),
  183. ElementsAre(Pair(storage_key, MatchesUserEvent(specifics))));
  184. }
  185. TEST_F(UserEventSyncBridgeTest, ApplyStopSyncChanges) {
  186. WaitUntilModelReadyToSync();
  187. const UserEventSpecifics specifics(CreateSpecifics(1u, 2u, 3u));
  188. bridge()->RecordUserEvent(std::make_unique<UserEventSpecifics>(specifics));
  189. ASSERT_THAT(GetAllData(), SizeIs(1));
  190. bridge()->ApplyStopSyncChanges(WriteBatch::CreateMetadataChangeList());
  191. // The bridge may asynchronously query the store to choose what to delete.
  192. base::RunLoop().RunUntilIdle();
  193. EXPECT_THAT(GetAllData(), IsEmpty());
  194. }
  195. TEST_F(UserEventSyncBridgeTest, MultipleRecords) {
  196. WaitUntilModelReadyToSync();
  197. std::set<std::string> unique_storage_keys;
  198. EXPECT_CALL(*processor(), Put)
  199. .Times(4)
  200. .WillRepeatedly(
  201. [&unique_storage_keys](const std::string& storage_key,
  202. std::unique_ptr<EntityData> entity_data,
  203. MetadataChangeList* metadata_change_list) {
  204. unique_storage_keys.insert(storage_key);
  205. });
  206. bridge()->RecordUserEvent(SpecificsUniquePtr(1u, 1u, 1u));
  207. bridge()->RecordUserEvent(SpecificsUniquePtr(1u, 1u, 2u));
  208. bridge()->RecordUserEvent(SpecificsUniquePtr(1u, 2u, 2u));
  209. bridge()->RecordUserEvent(SpecificsUniquePtr(2u, 2u, 2u));
  210. EXPECT_EQ(2u, unique_storage_keys.size());
  211. EXPECT_THAT(GetAllData(), SizeIs(2));
  212. }
  213. TEST_F(UserEventSyncBridgeTest, ApplySyncChanges) {
  214. WaitUntilModelReadyToSync();
  215. std::string storage_key1;
  216. std::string storage_key2;
  217. EXPECT_CALL(*processor(), Put)
  218. .WillOnce(WithArg<0>(SaveArg<0>(&storage_key1)))
  219. .WillOnce(WithArg<0>(SaveArg<0>(&storage_key2)));
  220. bridge()->RecordUserEvent(SpecificsUniquePtr(1u, 1u, 1u));
  221. bridge()->RecordUserEvent(SpecificsUniquePtr(2u, 2u, 2u));
  222. EXPECT_THAT(GetAllData(), SizeIs(2));
  223. syncer::EntityChangeList entity_change_list;
  224. entity_change_list.push_back(EntityChange::CreateDelete(storage_key1));
  225. auto error_on_delete = bridge()->ApplySyncChanges(
  226. bridge()->CreateMetadataChangeList(), std::move(entity_change_list));
  227. EXPECT_FALSE(error_on_delete);
  228. EXPECT_THAT(GetAllData(), SizeIs(1));
  229. EXPECT_THAT(GetData(storage_key1), IsNull());
  230. EXPECT_THAT(GetData(storage_key2), NotNull());
  231. }
  232. TEST_F(UserEventSyncBridgeTest, HandleGlobalIdChange) {
  233. WaitUntilModelReadyToSync();
  234. int64_t first_id = 11;
  235. int64_t second_id = 12;
  236. int64_t third_id = 13;
  237. int64_t fourth_id = 14;
  238. std::string storage_key;
  239. EXPECT_CALL(*processor(), Put).WillOnce(WithArg<0>(SaveArg<0>(&storage_key)));
  240. // This id update should be applied to the event as it is initially
  241. // recorded.
  242. mapper()->ChangeId(first_id, second_id);
  243. bridge()->RecordUserEvent(SpecificsUniquePtr(1u, first_id, 2u));
  244. EXPECT_THAT(GetAllData(),
  245. ElementsAre(Pair(storage_key, MatchesUserEvent(CreateSpecifics(
  246. 1u, second_id, 2u)))));
  247. // This id update is done while the event is "in flight", and should result in
  248. // it being updated and re-sent to sync.
  249. EXPECT_CALL(*processor(), Put(storage_key, _, _));
  250. mapper()->ChangeId(second_id, third_id);
  251. EXPECT_THAT(GetAllData(),
  252. ElementsAre(Pair(storage_key, MatchesUserEvent(CreateSpecifics(
  253. 1u, third_id, 2u)))));
  254. syncer::EntityChangeList entity_change_list;
  255. entity_change_list.push_back(EntityChange::CreateDelete(storage_key));
  256. auto error_on_delete = bridge()->ApplySyncChanges(
  257. bridge()->CreateMetadataChangeList(), std::move(entity_change_list));
  258. EXPECT_FALSE(error_on_delete);
  259. EXPECT_THAT(GetAllData(), IsEmpty());
  260. // This id update should be ignored, since we received commit confirmation
  261. // above.
  262. EXPECT_CALL(*processor(), Put).Times(0);
  263. mapper()->ChangeId(third_id, fourth_id);
  264. EXPECT_THAT(GetAllData(), IsEmpty());
  265. }
  266. TEST_F(UserEventSyncBridgeTest, MulipleEventsChanging) {
  267. WaitUntilModelReadyToSync();
  268. int64_t first_id = 11;
  269. int64_t second_id = 12;
  270. int64_t third_id = 13;
  271. int64_t fourth_id = 14;
  272. const UserEventSpecifics specifics1 = CreateSpecifics(101u, first_id, 2u);
  273. const UserEventSpecifics specifics2 = CreateSpecifics(102u, second_id, 4u);
  274. const UserEventSpecifics specifics3 = CreateSpecifics(103u, third_id, 6u);
  275. const std::string key1 = GetStorageKey(specifics1);
  276. const std::string key2 = GetStorageKey(specifics2);
  277. const std::string key3 = GetStorageKey(specifics3);
  278. ASSERT_NE(key1, key2);
  279. ASSERT_NE(key1, key3);
  280. ASSERT_NE(key2, key3);
  281. bridge()->RecordUserEvent(std::make_unique<UserEventSpecifics>(specifics1));
  282. bridge()->RecordUserEvent(std::make_unique<UserEventSpecifics>(specifics2));
  283. bridge()->RecordUserEvent(std::make_unique<UserEventSpecifics>(specifics3));
  284. ASSERT_THAT(GetAllData(),
  285. UnorderedElementsAre(Pair(key1, MatchesUserEvent(specifics1)),
  286. Pair(key2, MatchesUserEvent(specifics2)),
  287. Pair(key3, MatchesUserEvent(specifics3))));
  288. mapper()->ChangeId(second_id, fourth_id);
  289. EXPECT_THAT(
  290. GetAllData(),
  291. UnorderedElementsAre(
  292. Pair(key1, MatchesUserEvent(specifics1)),
  293. Pair(key2, MatchesUserEvent(CreateSpecifics(102u, fourth_id, 4u))),
  294. Pair(key3, MatchesUserEvent(specifics3))));
  295. mapper()->ChangeId(first_id, fourth_id);
  296. mapper()->ChangeId(third_id, fourth_id);
  297. EXPECT_THAT(
  298. GetAllData(),
  299. UnorderedElementsAre(
  300. Pair(key1, MatchesUserEvent(CreateSpecifics(101u, fourth_id, 2u))),
  301. Pair(key2, MatchesUserEvent(CreateSpecifics(102u, fourth_id, 4u))),
  302. Pair(key3, MatchesUserEvent(CreateSpecifics(103u, fourth_id, 6u)))));
  303. }
  304. TEST_F(UserEventSyncBridgeTest, RecordBeforeMetadataLoads) {
  305. ON_CALL(*processor(), IsTrackingMetadata()).WillByDefault(Return(false));
  306. ON_CALL(*processor(), TrackedAccountId()).WillByDefault(Return(""));
  307. bridge()->RecordUserEvent(SpecificsUniquePtr(1u, 2u, 3u));
  308. EXPECT_CALL(*processor(), ModelReadyToSync);
  309. WaitUntilModelReadyToSync("account_id");
  310. EXPECT_THAT(GetAllData(), IsEmpty());
  311. }
  312. } // namespace
  313. } // namespace syncer