send_tab_to_self_bridge_unittest.cc 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936
  1. // Copyright 2019 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/send_tab_to_self/send_tab_to_self_bridge.h"
  5. #include <map>
  6. #include <set>
  7. #include <utility>
  8. #include "base/bind.h"
  9. #include "base/run_loop.h"
  10. #include "base/strings/stringprintf.h"
  11. #include "base/test/simple_test_clock.h"
  12. #include "base/test/task_environment.h"
  13. #include "components/history/core/browser/history_service.h"
  14. #include "components/send_tab_to_self/features.h"
  15. #include "components/send_tab_to_self/proto/send_tab_to_self.pb.h"
  16. #include "components/send_tab_to_self/target_device_info.h"
  17. #include "components/sync/model/entity_change.h"
  18. #include "components/sync/model/in_memory_metadata_change_list.h"
  19. #include "components/sync/model/metadata_batch.h"
  20. #include "components/sync/protocol/entity_data.h"
  21. #include "components/sync/protocol/model_type_state.pb.h"
  22. #include "components/sync/test/mock_model_type_change_processor.h"
  23. #include "components/sync/test/model_type_store_test_util.h"
  24. #include "components/sync/test/test_matchers.h"
  25. #include "components/sync_device_info/device_info.h"
  26. #include "components/sync_device_info/device_info_util.h"
  27. #include "components/sync_device_info/fake_device_info_tracker.h"
  28. #include "testing/gmock/include/gmock/gmock.h"
  29. #include "testing/gtest/include/gtest/gtest.h"
  30. namespace send_tab_to_self {
  31. namespace {
  32. using testing::_;
  33. using testing::AllOf;
  34. using testing::ElementsAre;
  35. using testing::IsEmpty;
  36. using testing::Return;
  37. using testing::SizeIs;
  38. using testing::UnorderedElementsAre;
  39. const char kGuidFormat[] = "guid %d";
  40. const char kURLFormat[] = "https://www.url%d.com/";
  41. const char kTitleFormat[] = "title %d";
  42. const char kDeviceFormat[] = "device %d";
  43. const char kLocalDeviceCacheGuid[] = "local_device_guid";
  44. const char kLocalDeviceName[] = "local_device_name";
  45. // Action SaveArgPointeeMove<k>(pointer) saves the value pointed to by the k-th
  46. // (0-based) argument of the mock function by moving it to *pointer.
  47. ACTION_TEMPLATE(SaveArgPointeeMove,
  48. HAS_1_TEMPLATE_PARAMS(int, k),
  49. AND_1_VALUE_PARAMS(pointer)) {
  50. *pointer = std::move(*testing::get<k>(args));
  51. }
  52. sync_pb::SendTabToSelfSpecifics CreateSpecifics(
  53. int suffix,
  54. base::Time shared_time = base::Time::Now()) {
  55. sync_pb::SendTabToSelfSpecifics specifics;
  56. specifics.set_guid(base::StringPrintf(kGuidFormat, suffix));
  57. specifics.set_url(base::StringPrintf(kURLFormat, suffix));
  58. specifics.set_device_name(base::StringPrintf(kDeviceFormat, suffix));
  59. specifics.set_title(base::StringPrintf(kTitleFormat, suffix));
  60. specifics.set_target_device_sync_cache_guid(kLocalDeviceCacheGuid);
  61. specifics.set_shared_time_usec(
  62. shared_time.ToDeltaSinceWindowsEpoch().InMicroseconds());
  63. return specifics;
  64. }
  65. std::unique_ptr<syncer::DeviceInfo> CreateDevice(
  66. const std::string& guid,
  67. const std::string& name,
  68. base::Time last_updated_timestamp,
  69. bool send_tab_to_self_receiving_enabled = true) {
  70. return std::make_unique<syncer::DeviceInfo>(
  71. guid, name, "chrome_version", "user_agent",
  72. sync_pb::SyncEnums_DeviceType_TYPE_LINUX, "scoped_id", "manufacturer",
  73. "model", "full_hardware_class", last_updated_timestamp,
  74. syncer::DeviceInfoUtil::GetPulseInterval(),
  75. send_tab_to_self_receiving_enabled, /*sharing_info=*/absl::nullopt,
  76. /*paask_info=*/absl::nullopt,
  77. /*fcm_registration_token=*/std::string(),
  78. /*interested_data_types=*/syncer::ModelTypeSet());
  79. }
  80. sync_pb::ModelTypeState StateWithEncryption(
  81. const std::string& encryption_key_name) {
  82. sync_pb::ModelTypeState state;
  83. state.set_encryption_key_name(encryption_key_name);
  84. return state;
  85. }
  86. class MockSendTabToSelfModelObserver : public SendTabToSelfModelObserver {
  87. public:
  88. MOCK_METHOD0(SendTabToSelfModelLoaded, void());
  89. MOCK_METHOD1(EntriesAddedRemotely,
  90. void(const std::vector<const SendTabToSelfEntry*>&));
  91. MOCK_METHOD1(EntriesOpenedRemotely,
  92. void(const std::vector<const SendTabToSelfEntry*>&));
  93. MOCK_METHOD1(EntriesRemovedRemotely, void(const std::vector<std::string>&));
  94. };
  95. MATCHER_P(GuidIs, e, "") {
  96. return testing::ExplainMatchResult(e, arg->GetGUID(), result_listener);
  97. }
  98. class SendTabToSelfBridgeTest : public testing::Test {
  99. public:
  100. SendTabToSelfBridgeTest(const SendTabToSelfBridgeTest&) = delete;
  101. SendTabToSelfBridgeTest& operator=(const SendTabToSelfBridgeTest&) = delete;
  102. protected:
  103. SendTabToSelfBridgeTest()
  104. : store_(syncer::ModelTypeStoreTestUtil::CreateInMemoryStoreForTest()) {}
  105. void InitializeLocalDeviceIfNeeded() {
  106. if (local_device_) {
  107. return;
  108. }
  109. SetLocalDeviceCacheGuid(kLocalDeviceCacheGuid);
  110. local_device_ = CreateDevice(kLocalDeviceCacheGuid, "device",
  111. clock()->Now() - base::Days(1));
  112. AddTestDevice(local_device_.get(), /*local=*/true);
  113. }
  114. // Initialized the bridge based on the current local device and store. Can
  115. // only be called once per run, as it passes |store_|.
  116. void InitializeBridge() {
  117. InitializeLocalDeviceIfNeeded();
  118. InitializeBridgeWithoutDevice();
  119. }
  120. // Initializes only the bridge without creating local device. This is useful
  121. // to test the case when the device info tracker is not initialized yet.
  122. void InitializeBridgeWithoutDevice() {
  123. ON_CALL(mock_processor_, IsTrackingMetadata()).WillByDefault(Return(true));
  124. bridge_ = std::make_unique<SendTabToSelfBridge>(
  125. mock_processor_.CreateForwardingProcessor(), &clock_,
  126. syncer::ModelTypeStoreTestUtil::MoveStoreToFactory(std::move(store_)),
  127. /*history_service=*/nullptr, &device_info_tracker_);
  128. bridge_->AddObserver(&mock_observer_);
  129. base::RunLoop().RunUntilIdle();
  130. }
  131. void ShutdownBridge() {
  132. bridge_->RemoveObserver(&mock_observer_);
  133. store_ =
  134. SendTabToSelfBridge::DestroyAndStealStoreForTest(std::move(bridge_));
  135. base::RunLoop().RunUntilIdle();
  136. }
  137. base::Time AdvanceAndGetTime(base::TimeDelta delta = base::Milliseconds(10)) {
  138. clock_.Advance(delta);
  139. return clock_.Now();
  140. }
  141. void DisableBridge() {
  142. ON_CALL(mock_processor_, IsTrackingMetadata()).WillByDefault(Return(false));
  143. }
  144. syncer::EntityData MakeEntityData(const SendTabToSelfEntry& entry) {
  145. SendTabToSelfLocal specifics = entry.AsLocalProto();
  146. syncer::EntityData entity_data;
  147. *entity_data.specifics.mutable_send_tab_to_self() = specifics.specifics();
  148. entity_data.name = entry.GetURL().spec();
  149. return entity_data;
  150. }
  151. // Helper method to reduce duplicated code between tests. Wraps the given
  152. // specifics objects in an EntityData and EntityChange of type ACTION_ADD, and
  153. // returns an EntityChangeList containing them all. Order is maintained.
  154. syncer::EntityChangeList EntityAddList(
  155. const std::vector<sync_pb::SendTabToSelfSpecifics>& specifics_list) {
  156. syncer::EntityChangeList changes;
  157. for (const auto& specifics : specifics_list) {
  158. syncer::EntityData entity_data;
  159. *entity_data.specifics.mutable_send_tab_to_self() = specifics;
  160. entity_data.name = specifics.url();
  161. changes.push_back(syncer::EntityChange::CreateAdd(
  162. specifics.guid(), std::move(entity_data)));
  163. }
  164. return changes;
  165. }
  166. // For Model Tests.
  167. void AddSampleEntries() {
  168. // Adds timer to avoid having two entries with the same shared timestamp.
  169. bridge_->AddEntry(GURL("http://a.com"), "a", kLocalDeviceCacheGuid);
  170. bridge_->AddEntry(GURL("http://b.com"), "b", kLocalDeviceCacheGuid);
  171. bridge_->AddEntry(GURL("http://c.com"), "c", kLocalDeviceCacheGuid);
  172. bridge_->AddEntry(GURL("http://d.com"), "d", kLocalDeviceCacheGuid);
  173. }
  174. void SetLocalDeviceCacheGuid(const std::string& cache_guid) {
  175. ON_CALL(mock_processor_, TrackedCacheGuid())
  176. .WillByDefault(Return(cache_guid));
  177. }
  178. void AddTestDevice(const syncer::DeviceInfo* device, bool local = false) {
  179. device_info_tracker_.Add(device);
  180. if (local) {
  181. device_info_tracker_.SetLocalCacheGuid(device->guid());
  182. }
  183. }
  184. syncer::MockModelTypeChangeProcessor* processor() { return &mock_processor_; }
  185. SendTabToSelfBridge* bridge() { return bridge_.get(); }
  186. MockSendTabToSelfModelObserver* mock_observer() { return &mock_observer_; }
  187. base::SimpleTestClock* clock() { return &clock_; }
  188. syncer::FakeDeviceInfoTracker* device_info_tracker() {
  189. return &device_info_tracker_;
  190. }
  191. private:
  192. base::SimpleTestClock clock_;
  193. // In memory model type store needs to be able to post tasks.
  194. base::test::TaskEnvironment task_environment_;
  195. std::unique_ptr<syncer::ModelTypeStore> store_;
  196. testing::NiceMock<syncer::MockModelTypeChangeProcessor> mock_processor_;
  197. syncer::FakeDeviceInfoTracker device_info_tracker_;
  198. std::unique_ptr<SendTabToSelfBridge> bridge_;
  199. testing::NiceMock<MockSendTabToSelfModelObserver> mock_observer_;
  200. std::unique_ptr<syncer::DeviceInfo> local_device_;
  201. };
  202. TEST_F(SendTabToSelfBridgeTest, CheckEmpties) {
  203. InitializeBridge();
  204. EXPECT_CALL(*mock_observer(), EntriesAddedRemotely(_)).Times(0);
  205. EXPECT_EQ(0ul, bridge()->GetAllGuids().size());
  206. AddSampleEntries();
  207. EXPECT_EQ(4ul, bridge()->GetAllGuids().size());
  208. }
  209. TEST_F(SendTabToSelfBridgeTest, SyncAddOneEntry) {
  210. InitializeBridge();
  211. syncer::EntityChangeList remote_input;
  212. SendTabToSelfEntry entry("guid1", GURL("http://www.example.com/"), "title",
  213. AdvanceAndGetTime(), "device",
  214. kLocalDeviceCacheGuid);
  215. remote_input.push_back(
  216. syncer::EntityChange::CreateAdd("guid1", MakeEntityData(entry)));
  217. auto metadata_change_list =
  218. std::make_unique<syncer::InMemoryMetadataChangeList>();
  219. EXPECT_CALL(*mock_observer(), EntriesAddedRemotely(SizeIs(1)));
  220. bridge()->MergeSyncData(std::move(metadata_change_list),
  221. std::move(remote_input));
  222. EXPECT_EQ(1ul, bridge()->GetAllGuids().size());
  223. }
  224. TEST_F(SendTabToSelfBridgeTest, ApplySyncChangesAddTwoSpecifics) {
  225. InitializeBridge();
  226. const sync_pb::SendTabToSelfSpecifics specifics1 = CreateSpecifics(1);
  227. const sync_pb::SendTabToSelfSpecifics specifics2 = CreateSpecifics(2);
  228. sync_pb::ModelTypeState state = StateWithEncryption("ekn");
  229. std::unique_ptr<syncer::MetadataChangeList> metadata_changes =
  230. bridge()->CreateMetadataChangeList();
  231. metadata_changes->UpdateModelTypeState(state);
  232. EXPECT_CALL(*mock_observer(), EntriesAddedRemotely(SizeIs(2)));
  233. auto error = bridge()->ApplySyncChanges(
  234. std::move(metadata_changes), EntityAddList({specifics1, specifics2}));
  235. EXPECT_FALSE(error);
  236. }
  237. TEST_F(SendTabToSelfBridgeTest, ApplySyncChangesOneAdd) {
  238. InitializeBridge();
  239. SendTabToSelfEntry entry("guid1", GURL("http://www.example.com/"), "title",
  240. AdvanceAndGetTime(), "device",
  241. kLocalDeviceCacheGuid);
  242. syncer::EntityChangeList add_changes;
  243. add_changes.push_back(
  244. syncer::EntityChange::CreateAdd("guid1", MakeEntityData(entry)));
  245. auto metadata_change_list =
  246. std::make_unique<syncer::InMemoryMetadataChangeList>();
  247. EXPECT_CALL(*mock_observer(), EntriesAddedRemotely(SizeIs(1)));
  248. bridge()->ApplySyncChanges(std::move(metadata_change_list),
  249. std::move(add_changes));
  250. EXPECT_EQ(1ul, bridge()->GetAllGuids().size());
  251. }
  252. // Tests that the send tab to self entry is correctly removed.
  253. TEST_F(SendTabToSelfBridgeTest, ApplySyncChangesOneDeletion) {
  254. InitializeBridge();
  255. SendTabToSelfEntry entry("guid1", GURL("http://www.example.com/"), "title",
  256. AdvanceAndGetTime(), "device",
  257. kLocalDeviceCacheGuid);
  258. syncer::EntityChangeList add_changes;
  259. add_changes.push_back(
  260. syncer::EntityChange::CreateAdd("guid1", MakeEntityData(entry)));
  261. EXPECT_CALL(*mock_observer(), EntriesAddedRemotely(SizeIs(1)));
  262. bridge()->ApplySyncChanges(bridge()->CreateMetadataChangeList(),
  263. std::move(add_changes));
  264. EXPECT_EQ(1ul, bridge()->GetAllGuids().size());
  265. syncer::EntityChangeList delete_changes;
  266. delete_changes.push_back(syncer::EntityChange::CreateDelete("guid1"));
  267. EXPECT_CALL(*mock_observer(), EntriesRemovedRemotely(SizeIs(1)));
  268. bridge()->ApplySyncChanges(bridge()->CreateMetadataChangeList(),
  269. std::move(delete_changes));
  270. EXPECT_EQ(0ul, bridge()->GetAllGuids().size());
  271. }
  272. // Tests that the send tab to self entry is correctly removed.
  273. TEST_F(SendTabToSelfBridgeTest, LocalHistoryDeletion) {
  274. InitializeBridge();
  275. SendTabToSelfEntry entry1("guid1", GURL("http://www.example.com/"), "title",
  276. AdvanceAndGetTime(), "device",
  277. kLocalDeviceCacheGuid);
  278. SendTabToSelfEntry entry2("guid2", GURL("http://www.example2.com/"), "title2",
  279. AdvanceAndGetTime(), "device2",
  280. kLocalDeviceCacheGuid);
  281. SendTabToSelfEntry entry3("guid3", GURL("http://www.example3.com/"), "title3",
  282. AdvanceAndGetTime(), "device3",
  283. kLocalDeviceCacheGuid);
  284. syncer::EntityChangeList add_changes;
  285. add_changes.push_back(
  286. syncer::EntityChange::CreateAdd("guid1", MakeEntityData(entry1)));
  287. add_changes.push_back(
  288. syncer::EntityChange::CreateAdd("guid2", MakeEntityData(entry2)));
  289. add_changes.push_back(
  290. syncer::EntityChange::CreateAdd("guid3", MakeEntityData(entry3)));
  291. bridge()->ApplySyncChanges(bridge()->CreateMetadataChangeList(),
  292. std::move(add_changes));
  293. ASSERT_EQ(3ul, bridge()->GetAllGuids().size());
  294. history::URLRows urls_to_remove;
  295. urls_to_remove.push_back(history::URLRow(GURL("http://www.example.com/")));
  296. urls_to_remove.push_back(history::URLRow(GURL("http://www.example2.com/")));
  297. EXPECT_CALL(*mock_observer(), EntriesRemovedRemotely(SizeIs(2)));
  298. EXPECT_CALL(*processor(), Delete("guid1", _));
  299. EXPECT_CALL(*processor(), Delete("guid2", _));
  300. bridge()->OnURLsDeleted(nullptr, history::DeletionInfo::ForUrls(
  301. urls_to_remove, std::set<GURL>()));
  302. EXPECT_EQ(1ul, bridge()->GetAllGuids().size());
  303. }
  304. TEST_F(SendTabToSelfBridgeTest, ApplySyncChangesEmpty) {
  305. InitializeBridge();
  306. EXPECT_CALL(*mock_observer(), EntriesAddedRemotely(_)).Times(0);
  307. auto error = bridge()->ApplySyncChanges(bridge()->CreateMetadataChangeList(),
  308. syncer::EntityChangeList());
  309. EXPECT_FALSE(error);
  310. }
  311. TEST_F(SendTabToSelfBridgeTest, AddEntryAndRestartBridge) {
  312. InitializeBridge();
  313. const sync_pb::SendTabToSelfSpecifics specifics = CreateSpecifics(1);
  314. sync_pb::ModelTypeState state = StateWithEncryption("ekn");
  315. std::unique_ptr<syncer::MetadataChangeList> metadata_changes =
  316. bridge()->CreateMetadataChangeList();
  317. metadata_changes->UpdateModelTypeState(state);
  318. auto error = bridge()->ApplySyncChanges(std::move(metadata_changes),
  319. EntityAddList({specifics}));
  320. ASSERT_FALSE(error);
  321. ShutdownBridge();
  322. EXPECT_CALL(*processor(),
  323. ModelReadyToSync(MetadataBatchContains(
  324. syncer::HasEncryptionKeyName(state.encryption_key_name()),
  325. /*entities=*/IsEmpty())));
  326. EXPECT_CALL(*mock_observer(), EntriesAddedRemotely(_)).Times(0);
  327. InitializeBridge();
  328. std::vector<std::string> guids = bridge()->GetAllGuids();
  329. ASSERT_EQ(1ul, guids.size());
  330. EXPECT_EQ(specifics.url(),
  331. bridge()->GetEntryByGUID(guids[0])->GetURL().spec());
  332. }
  333. TEST_F(SendTabToSelfBridgeTest, ApplySyncChangesInMemory) {
  334. InitializeBridge();
  335. const sync_pb::SendTabToSelfSpecifics specifics = CreateSpecifics(1);
  336. std::unique_ptr<syncer::MetadataChangeList> metadata_changes =
  337. bridge()->CreateMetadataChangeList();
  338. EXPECT_CALL(*mock_observer(), EntriesAddedRemotely(SizeIs(1)));
  339. auto error_on_add = bridge()->ApplySyncChanges(
  340. bridge()->CreateMetadataChangeList(), EntityAddList({specifics}));
  341. EXPECT_FALSE(error_on_add);
  342. EXPECT_EQ(1ul, bridge()->GetAllGuids().size());
  343. EXPECT_CALL(*mock_observer(), EntriesRemovedRemotely(SizeIs(1)));
  344. syncer::EntityChangeList entity_change_list;
  345. entity_change_list.push_back(
  346. syncer::EntityChange::CreateDelete(specifics.guid()));
  347. auto error_on_delete = bridge()->ApplySyncChanges(
  348. bridge()->CreateMetadataChangeList(), std::move(entity_change_list));
  349. EXPECT_FALSE(error_on_delete);
  350. EXPECT_EQ(0ul, bridge()->GetAllGuids().size());
  351. }
  352. TEST_F(SendTabToSelfBridgeTest, ApplyDeleteNonexistent) {
  353. InitializeBridge();
  354. EXPECT_CALL(*mock_observer(), EntriesAddedRemotely(_)).Times(0);
  355. std::unique_ptr<syncer::MetadataChangeList> metadata_changes =
  356. bridge()->CreateMetadataChangeList();
  357. EXPECT_CALL(*processor(), Delete(_, _)).Times(0);
  358. syncer::EntityChangeList entity_change_list;
  359. entity_change_list.push_back(syncer::EntityChange::CreateDelete("guid"));
  360. auto error = bridge()->ApplySyncChanges(std::move(metadata_changes),
  361. std::move(entity_change_list));
  362. EXPECT_FALSE(error);
  363. }
  364. TEST_F(SendTabToSelfBridgeTest, MarkEntryOpenedInformsServer) {
  365. InitializeBridge();
  366. SendTabToSelfEntry entry("guid", GURL("http://g.com/"), "title",
  367. AdvanceAndGetTime(), "remote", "remote");
  368. syncer::EntityChangeList remote_data;
  369. remote_data.push_back(
  370. syncer::EntityChange::CreateAdd("guid", MakeEntityData(entry)));
  371. bridge()->MergeSyncData(bridge()->CreateMetadataChangeList(),
  372. std::move(remote_data));
  373. ASSERT_THAT(bridge()->GetAllGuids(), UnorderedElementsAre("guid"));
  374. syncer::EntityData uploaded_opened_entity;
  375. EXPECT_CALL(*processor(), Put("guid", _, _))
  376. .WillOnce(SaveArgPointeeMove<1>(&uploaded_opened_entity));
  377. bridge()->MarkEntryOpened("guid");
  378. EXPECT_TRUE(uploaded_opened_entity.specifics.send_tab_to_self().opened());
  379. }
  380. TEST_F(SendTabToSelfBridgeTest, DismissEntryInformsServer) {
  381. InitializeBridge();
  382. SendTabToSelfEntry entry("guid", GURL("http://g.com/"), "title",
  383. AdvanceAndGetTime(), "remote", "remote");
  384. syncer::EntityChangeList remote_data;
  385. remote_data.push_back(
  386. syncer::EntityChange::CreateAdd("guid", MakeEntityData(entry)));
  387. bridge()->MergeSyncData(bridge()->CreateMetadataChangeList(),
  388. std::move(remote_data));
  389. ASSERT_THAT(bridge()->GetAllGuids(), UnorderedElementsAre("guid"));
  390. syncer::EntityData uploaded_dismissed_entity;
  391. EXPECT_CALL(*processor(), Put("guid", _, _))
  392. .WillOnce(SaveArgPointeeMove<1>(&uploaded_dismissed_entity));
  393. bridge()->DismissEntry("guid");
  394. EXPECT_TRUE(uploaded_dismissed_entity.specifics.send_tab_to_self()
  395. .notification_dismissed());
  396. }
  397. TEST_F(SendTabToSelfBridgeTest, PreserveDissmissalAfterRestartBridge) {
  398. InitializeBridge();
  399. const sync_pb::SendTabToSelfSpecifics specifics = CreateSpecifics(1);
  400. std::unique_ptr<syncer::MetadataChangeList> metadata_changes =
  401. bridge()->CreateMetadataChangeList();
  402. auto error = bridge()->ApplySyncChanges(std::move(metadata_changes),
  403. EntityAddList({specifics}));
  404. ASSERT_FALSE(error);
  405. EXPECT_CALL(*processor(), Put(_, _, _));
  406. bridge()->DismissEntry(specifics.guid());
  407. ShutdownBridge();
  408. InitializeBridge();
  409. std::vector<std::string> guids = bridge()->GetAllGuids();
  410. ASSERT_EQ(1ul, guids.size());
  411. EXPECT_TRUE(bridge()->GetEntryByGUID(guids[0])->GetNotificationDismissed());
  412. }
  413. TEST_F(SendTabToSelfBridgeTest, ExpireEntryDuringInit) {
  414. InitializeBridge();
  415. const sync_pb::SendTabToSelfSpecifics expired_specifics =
  416. CreateSpecifics(1, AdvanceAndGetTime());
  417. AdvanceAndGetTime(kExpiryTime / 2.0);
  418. const sync_pb::SendTabToSelfSpecifics not_expired_specifics =
  419. CreateSpecifics(2, AdvanceAndGetTime());
  420. sync_pb::ModelTypeState state = StateWithEncryption("ekn");
  421. std::unique_ptr<syncer::MetadataChangeList> metadata_changes =
  422. bridge()->CreateMetadataChangeList();
  423. metadata_changes->UpdateModelTypeState(state);
  424. auto error = bridge()->ApplySyncChanges(
  425. std::move(metadata_changes),
  426. EntityAddList({expired_specifics, not_expired_specifics}));
  427. ASSERT_FALSE(error);
  428. ShutdownBridge();
  429. AdvanceAndGetTime(kExpiryTime / 2.0);
  430. EXPECT_CALL(*mock_observer(), EntriesRemovedRemotely(SizeIs(1)));
  431. EXPECT_CALL(*processor(), Delete(_, _));
  432. InitializeBridge();
  433. std::vector<std::string> guids = bridge()->GetAllGuids();
  434. EXPECT_EQ(1ul, guids.size());
  435. EXPECT_EQ(not_expired_specifics.url(),
  436. bridge()->GetEntryByGUID(guids[0])->GetURL().spec());
  437. }
  438. TEST_F(SendTabToSelfBridgeTest, AddExpiredEntry) {
  439. InitializeBridge();
  440. sync_pb::ModelTypeState state = StateWithEncryption("ekn");
  441. std::unique_ptr<syncer::MetadataChangeList> metadata_changes =
  442. bridge()->CreateMetadataChangeList();
  443. metadata_changes->UpdateModelTypeState(state);
  444. const sync_pb::SendTabToSelfSpecifics expired_specifics =
  445. CreateSpecifics(1, AdvanceAndGetTime());
  446. AdvanceAndGetTime(kExpiryTime);
  447. const sync_pb::SendTabToSelfSpecifics not_expired_specifics =
  448. CreateSpecifics(2, AdvanceAndGetTime());
  449. EXPECT_CALL(*processor(), Delete(_, _));
  450. auto error = bridge()->ApplySyncChanges(
  451. std::move(metadata_changes),
  452. EntityAddList({expired_specifics, not_expired_specifics}));
  453. ASSERT_FALSE(error);
  454. std::vector<std::string> guids = bridge()->GetAllGuids();
  455. EXPECT_EQ(1ul, guids.size());
  456. EXPECT_EQ(not_expired_specifics.url(),
  457. bridge()->GetEntryByGUID(guids[0])->GetURL().spec());
  458. }
  459. TEST_F(SendTabToSelfBridgeTest, AddInvalidEntries) {
  460. InitializeBridge();
  461. EXPECT_CALL(*mock_observer(), EntriesAddedRemotely(_)).Times(0);
  462. // Add Entry should succeed in this case.
  463. EXPECT_CALL(*processor(), Put(_, _, _));
  464. EXPECT_NE(nullptr, bridge()->AddEntry(GURL("http://www.example.com/"), "d",
  465. kLocalDeviceCacheGuid));
  466. // Add Entry should fail on invalid URLs.
  467. EXPECT_CALL(*processor(), Put(_, _, _)).Times(0);
  468. EXPECT_EQ(nullptr, bridge()->AddEntry(GURL(), "d", kLocalDeviceCacheGuid));
  469. EXPECT_EQ(nullptr, bridge()->AddEntry(GURL("http://?k=v"), "d",
  470. kLocalDeviceCacheGuid));
  471. EXPECT_EQ(nullptr, bridge()->AddEntry(GURL("http//google.com"), "d",
  472. kLocalDeviceCacheGuid));
  473. }
  474. TEST_F(SendTabToSelfBridgeTest, IsBridgeReady) {
  475. InitializeBridge();
  476. ASSERT_TRUE(bridge()->IsReady());
  477. DisableBridge();
  478. ASSERT_FALSE(bridge()->IsReady());
  479. }
  480. TEST_F(SendTabToSelfBridgeTest, AddDuplicateEntries) {
  481. InitializeBridge();
  482. EXPECT_CALL(*mock_observer(), EntriesAddedRemotely(_)).Times(0);
  483. // The de-duplication code does not use the title as a comparator.
  484. // So they are intentionally different here.
  485. EXPECT_CALL(*processor(), Put(_, _, _)).Times(1);
  486. bridge()->AddEntry(GURL("http://a.com"), "a", kLocalDeviceCacheGuid);
  487. bridge()->AddEntry(GURL("http://a.com"), "b", kLocalDeviceCacheGuid);
  488. EXPECT_EQ(1ul, bridge()->GetAllGuids().size());
  489. // Wait for more than the current dedupe time (5 seconds).
  490. AdvanceAndGetTime(base::Seconds(6));
  491. EXPECT_CALL(*processor(), Put(_, _, _)).Times(2);
  492. bridge()->AddEntry(GURL("http://a.com"), "a", kLocalDeviceCacheGuid);
  493. bridge()->AddEntry(GURL("http://b.com"), "b", kLocalDeviceCacheGuid);
  494. EXPECT_EQ(3ul, bridge()->GetAllGuids().size());
  495. }
  496. TEST_F(SendTabToSelfBridgeTest, NotifyRemoteSendTabToSelfEntryAdded) {
  497. const std::string kRemoteGuid = "RemoteDevice";
  498. InitializeBridge();
  499. // Add on entry targeting this device and another targeting another device.
  500. syncer::EntityChangeList remote_input;
  501. SendTabToSelfEntry entry1("guid1", GURL("http://www.example.com/"), "title",
  502. AdvanceAndGetTime(), "device",
  503. kLocalDeviceCacheGuid);
  504. SendTabToSelfEntry entry2("guid2", GURL("http://www.example.com/"), "title",
  505. AdvanceAndGetTime(), "device", kRemoteGuid);
  506. remote_input.push_back(
  507. syncer::EntityChange::CreateAdd("guid1", MakeEntityData(entry1)));
  508. remote_input.push_back(
  509. syncer::EntityChange::CreateAdd("guid2", MakeEntityData(entry2)));
  510. auto metadata_change_list =
  511. std::make_unique<syncer::InMemoryMetadataChangeList>();
  512. // There should only be one entry sent to the observers.
  513. EXPECT_CALL(*mock_observer(), EntriesAddedRemotely(SizeIs(1)));
  514. bridge()->MergeSyncData(std::move(metadata_change_list),
  515. std::move(remote_input));
  516. EXPECT_EQ(2ul, bridge()->GetAllGuids().size());
  517. }
  518. // Tests that only the most recent device's guid is returned when multiple
  519. // devices have the same name.
  520. TEST_F(SendTabToSelfBridgeTest,
  521. GetTargetDeviceInfoSortedList_OneDevicePerName) {
  522. const std::string kRecentGuid = "guid1";
  523. const std::string kOldGuid = "guid2";
  524. const std::string kOlderGuid = "guid3";
  525. InitializeBridge();
  526. // Create multiple DeviceInfo objects with the same name but different guids.
  527. std::unique_ptr<syncer::DeviceInfo> recent_device =
  528. CreateDevice(kRecentGuid, "device_name", clock()->Now() - base::Days(1));
  529. AddTestDevice(recent_device.get());
  530. std::unique_ptr<syncer::DeviceInfo> old_device =
  531. CreateDevice(kOldGuid, "device_name", clock()->Now() - base::Days(3));
  532. AddTestDevice(old_device.get());
  533. std::unique_ptr<syncer::DeviceInfo> older_device =
  534. CreateDevice(kOlderGuid, "device_name", clock()->Now() - base::Days(5));
  535. AddTestDevice(older_device.get());
  536. TargetDeviceInfo target_device_info(
  537. recent_device->client_name(), recent_device->client_name(),
  538. recent_device->guid(), recent_device->device_type(),
  539. recent_device->last_updated_timestamp());
  540. EXPECT_THAT(bridge()->GetTargetDeviceInfoSortedList(),
  541. ElementsAre(target_device_info));
  542. }
  543. // Tests that only devices that have the send tab to self receiving feature
  544. // enabled are returned.
  545. TEST_F(SendTabToSelfBridgeTest,
  546. GetTargetDeviceInfoSortedList_OnlyReceivingEnabled) {
  547. InitializeBridge();
  548. std::unique_ptr<syncer::DeviceInfo> enabled_device =
  549. CreateDevice("enabled_guid", "enabled_device_name", clock()->Now());
  550. AddTestDevice(enabled_device.get());
  551. std::unique_ptr<syncer::DeviceInfo> disabled_device =
  552. CreateDevice("disabled_guid", "disabled_device_name", clock()->Now(),
  553. /*send_tab_to_self_receiving_enabled=*/false);
  554. AddTestDevice(disabled_device.get());
  555. TargetDeviceInfo target_device_info(
  556. enabled_device->client_name(), enabled_device->client_name(),
  557. enabled_device->guid(), enabled_device->device_type(),
  558. enabled_device->last_updated_timestamp());
  559. EXPECT_THAT(bridge()->GetTargetDeviceInfoSortedList(),
  560. ElementsAre(target_device_info));
  561. }
  562. // Tests that only devices that are not expired are returned.
  563. TEST_F(SendTabToSelfBridgeTest,
  564. GetTargetDeviceInfoSortedList_NoExpiredDevices) {
  565. InitializeBridge();
  566. std::unique_ptr<syncer::DeviceInfo> expired_device = CreateDevice(
  567. "expired_guid", "expired_device_name", clock()->Now() - base::Days(11));
  568. AddTestDevice(expired_device.get());
  569. std::unique_ptr<syncer::DeviceInfo> valid_device = CreateDevice(
  570. "valid_guid", "valid_device_name", clock()->Now() - base::Days(1));
  571. AddTestDevice(valid_device.get());
  572. TargetDeviceInfo target_device_info(
  573. valid_device->client_name(), valid_device->client_name(),
  574. valid_device->guid(), valid_device->device_type(),
  575. valid_device->last_updated_timestamp());
  576. EXPECT_THAT(bridge()->GetTargetDeviceInfoSortedList(),
  577. ElementsAre(target_device_info));
  578. }
  579. // Tests that the local device is not returned.
  580. TEST_F(SendTabToSelfBridgeTest, GetTargetDeviceInfoSortedList_NoLocalDevice) {
  581. InitializeBridge();
  582. bridge()->SetLocalDeviceNameForTest(kLocalDeviceName);
  583. std::unique_ptr<syncer::DeviceInfo> local_device =
  584. CreateDevice(kLocalDeviceCacheGuid, kLocalDeviceName, clock()->Now());
  585. AddTestDevice(local_device.get());
  586. std::unique_ptr<syncer::DeviceInfo> other_local_device =
  587. CreateDevice("other_local_guid", kLocalDeviceName, clock()->Now());
  588. AddTestDevice(other_local_device.get());
  589. std::unique_ptr<syncer::DeviceInfo> other_device =
  590. CreateDevice("other_guid", "other_device_name", clock()->Now());
  591. AddTestDevice(other_device.get());
  592. TargetDeviceInfo target_device_info(
  593. other_device->client_name(), other_device->client_name(),
  594. other_device->guid(), other_device->device_type(),
  595. other_device->last_updated_timestamp());
  596. EXPECT_THAT(bridge()->GetTargetDeviceInfoSortedList(),
  597. ElementsAre(target_device_info));
  598. }
  599. // Tests that a device is no longer returned after time advances and it expires.
  600. TEST_F(SendTabToSelfBridgeTest,
  601. GetTargetDeviceInfoSortedList_Updated_DeviceExpired) {
  602. InitializeBridge();
  603. // Set a device that is about to expire and a more recent device.
  604. std::unique_ptr<syncer::DeviceInfo> older_device =
  605. CreateDevice("older_guid", "older_name", clock()->Now() - base::Days(9));
  606. AddTestDevice(older_device.get());
  607. std::unique_ptr<syncer::DeviceInfo> recent_device = CreateDevice(
  608. "recent_guid", "recent_name", clock()->Now() - base::Days(1));
  609. AddTestDevice(recent_device.get());
  610. TargetDeviceInfo older_device_info(
  611. older_device->client_name(), older_device->client_name(),
  612. older_device->guid(), older_device->device_type(),
  613. older_device->last_updated_timestamp());
  614. TargetDeviceInfo recent_device_info(
  615. recent_device->client_name(), recent_device->client_name(),
  616. recent_device->guid(), recent_device->device_type(),
  617. recent_device->last_updated_timestamp());
  618. // Make sure the list has the 2 devices.
  619. EXPECT_THAT(bridge()->GetTargetDeviceInfoSortedList(),
  620. ElementsAre(recent_device_info, older_device_info));
  621. // Advance the time so that the older device expires.
  622. clock()->Advance(base::Days(5));
  623. // Make sure only the recent device is in the list.
  624. EXPECT_THAT(bridge()->GetTargetDeviceInfoSortedList(),
  625. ElementsAre(recent_device_info));
  626. }
  627. // Tests that a new device is also returned after it is added.
  628. TEST_F(SendTabToSelfBridgeTest,
  629. GetTargetDeviceInfoSortedList_Updated_NewEntries) {
  630. InitializeBridge();
  631. // Set a valid device.
  632. std::unique_ptr<syncer::DeviceInfo> device =
  633. CreateDevice("guid", "name", clock()->Now());
  634. AddTestDevice(device.get());
  635. // Make sure the list has the device.
  636. TargetDeviceInfo device_info(device->client_name(), device->client_name(),
  637. device->guid(), device->device_type(),
  638. device->last_updated_timestamp());
  639. EXPECT_THAT(bridge()->GetTargetDeviceInfoSortedList(),
  640. ElementsAre(device_info));
  641. // Add a new device.
  642. std::unique_ptr<syncer::DeviceInfo> new_device =
  643. CreateDevice("new_guid", "new_name", clock()->Now());
  644. AddTestDevice(new_device.get());
  645. // Make sure both devices are in the list.
  646. TargetDeviceInfo new_device_info(
  647. new_device->client_name(), new_device->client_name(), new_device->guid(),
  648. new_device->device_type(), new_device->last_updated_timestamp());
  649. EXPECT_THAT(bridge()->GetTargetDeviceInfoSortedList(),
  650. ElementsAre(device_info, new_device_info));
  651. }
  652. // Tests the device list is updated if the last_updated_timestamp of one of
  653. // them changes. Regression test for crbug.com/1257573.
  654. TEST_F(SendTabToSelfBridgeTest,
  655. GetTargetDeviceInfoSortedList_Updated_LastUpdatedTimestampChanged) {
  656. InitializeBridge();
  657. std::unique_ptr<syncer::DeviceInfo> device1 =
  658. CreateDevice("guid1", "name1", clock()->Now() - base::Days(1));
  659. AddTestDevice(device1.get());
  660. std::unique_ptr<syncer::DeviceInfo> device2_old =
  661. CreateDevice("guid2", "name2", clock()->Now() - base::Days(2));
  662. AddTestDevice(device2_old.get());
  663. EXPECT_THAT(
  664. bridge()->GetTargetDeviceInfoSortedList(),
  665. ElementsAre(
  666. TargetDeviceInfo(device1->client_name(), device1->client_name(),
  667. device1->guid(), device1->device_type(),
  668. device1->last_updated_timestamp()),
  669. TargetDeviceInfo(device2_old->client_name(),
  670. device2_old->client_name(), device2_old->guid(),
  671. device2_old->device_type(),
  672. device2_old->last_updated_timestamp())));
  673. // Simulate device 2 being used today.
  674. std::unique_ptr<syncer::DeviceInfo> device2_new = CreateDevice(
  675. device2_old->guid(), device2_old->client_name(), clock()->Now());
  676. device_info_tracker()->Replace(device2_old.get(), device2_new.get());
  677. // Device 2 is now the most recently used and should be the first on the list.
  678. EXPECT_THAT(
  679. bridge()->GetTargetDeviceInfoSortedList(),
  680. ElementsAre(
  681. TargetDeviceInfo(device2_new->client_name(),
  682. device2_new->client_name(), device2_new->guid(),
  683. device2_new->device_type(),
  684. device2_new->last_updated_timestamp()),
  685. TargetDeviceInfo(device1->client_name(), device1->client_name(),
  686. device1->guid(), device1->device_type(),
  687. device1->last_updated_timestamp())));
  688. }
  689. TEST_F(SendTabToSelfBridgeTest, NotifyRemoteSendTabToSelfEntryOpened) {
  690. InitializeBridge();
  691. SetLocalDeviceCacheGuid("Device1");
  692. // Add on entry targeting this device and another targeting another device.
  693. syncer::EntityChangeList remote_input;
  694. SendTabToSelfEntry entry1("guid1", GURL("http://www.example.com/"), "title",
  695. AdvanceAndGetTime(), "device", "Device1");
  696. SendTabToSelfEntry entry2("guid2", GURL("http://www.example.com/"), "title",
  697. AdvanceAndGetTime(), "device", "Device2");
  698. remote_input.push_back(
  699. syncer::EntityChange::CreateAdd("guid1", MakeEntityData(entry1)));
  700. remote_input.push_back(
  701. syncer::EntityChange::CreateAdd("guid2", MakeEntityData(entry2)));
  702. entry1.MarkOpened();
  703. remote_input.push_back(
  704. syncer::EntityChange::CreateUpdate("guid1", MakeEntityData(entry1)));
  705. auto metadata_change_list =
  706. std::make_unique<syncer::InMemoryMetadataChangeList>();
  707. // an entry with "guid1" should be sent to the observers.
  708. EXPECT_CALL(*mock_observer(),
  709. EntriesOpenedRemotely(
  710. AllOf(SizeIs(1), UnorderedElementsAre(GuidIs("guid1")))));
  711. bridge()->MergeSyncData(std::move(metadata_change_list),
  712. std::move(remote_input));
  713. EXPECT_EQ(2ul, bridge()->GetAllGuids().size());
  714. }
  715. TEST_F(SendTabToSelfBridgeTest,
  716. ShouldHaveEmptyTargetDeviceInfoListWhileEmptyDeviceInfo) {
  717. InitializeBridgeWithoutDevice();
  718. SetLocalDeviceCacheGuid("cache_guid");
  719. ASSERT_FALSE(bridge()->change_processor()->TrackedCacheGuid().empty());
  720. ASSERT_FALSE(device_info_tracker()->IsSyncing());
  721. EXPECT_FALSE(bridge()->HasValidTargetDevice());
  722. }
  723. TEST_F(SendTabToSelfBridgeTest, CollapseWhitespacesOfEntryTitle) {
  724. InitializeBridge();
  725. const SendTabToSelfEntry* result =
  726. bridge()->AddEntry(GURL("http://a.com"), " a b ", kLocalDeviceCacheGuid);
  727. EXPECT_EQ("a b", result->GetTitle());
  728. result =
  729. bridge()->AddEntry(GURL("http://b.com"), "입", kLocalDeviceCacheGuid);
  730. EXPECT_EQ("입", result->GetTitle());
  731. }
  732. } // namespace
  733. } // namespace send_tab_to_self