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