syncer_unittest.cc 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238
  1. // Copyright 2012 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/engine/syncer.h"
  5. #include <stddef.h>
  6. #include <algorithm>
  7. #include <limits>
  8. #include <list>
  9. #include <map>
  10. #include <memory>
  11. #include <set>
  12. #include <string>
  13. #include <utility>
  14. #include <vector>
  15. #include "base/bind.h"
  16. #include "base/callback_helpers.h"
  17. #include "base/compiler_specific.h"
  18. #include "base/location.h"
  19. #include "base/memory/raw_ptr.h"
  20. #include "base/strings/string_number_conversions.h"
  21. #include "base/strings/stringprintf.h"
  22. #include "base/test/metrics/histogram_tester.h"
  23. #include "base/test/scoped_feature_list.h"
  24. #include "base/test/task_environment.h"
  25. #include "base/time/time.h"
  26. #include "build/build_config.h"
  27. #include "components/sync/base/client_tag_hash.h"
  28. #include "components/sync/base/extensions_activity.h"
  29. #include "components/sync/base/features.h"
  30. #include "components/sync/base/time.h"
  31. #include "components/sync/base/unique_position.h"
  32. #include "components/sync/engine/active_devices_invalidation_info.h"
  33. #include "components/sync/engine/backoff_delay_provider.h"
  34. #include "components/sync/engine/cancelation_signal.h"
  35. #include "components/sync/engine/cycle/mock_debug_info_getter.h"
  36. #include "components/sync/engine/cycle/sync_cycle_context.h"
  37. #include "components/sync/engine/data_type_activation_response.h"
  38. #include "components/sync/engine/forwarding_model_type_processor.h"
  39. #include "components/sync/engine/net/server_connection_manager.h"
  40. #include "components/sync/engine/nigori/keystore_keys_handler.h"
  41. #include "components/sync/engine/sync_scheduler_impl.h"
  42. #include "components/sync/engine/syncer_proto_util.h"
  43. #include "components/sync/protocol/bookmark_specifics.pb.h"
  44. #include "components/sync/protocol/client_commands.pb.h"
  45. #include "components/sync/protocol/entity_specifics.pb.h"
  46. #include "components/sync/protocol/preference_specifics.pb.h"
  47. #include "components/sync/protocol/sync.pb.h"
  48. #include "components/sync/protocol/sync_enums.pb.h"
  49. #include "components/sync/test/fake_sync_encryption_handler.h"
  50. #include "components/sync/test/mock_connection_manager.h"
  51. #include "components/sync/test/mock_model_type_processor.h"
  52. #include "components/sync/test/mock_nudge_handler.h"
  53. #include "testing/gmock/include/gmock/gmock.h"
  54. #include "testing/gtest/include/gtest/gtest.h"
  55. namespace syncer {
  56. namespace {
  57. using testing::ElementsAre;
  58. using testing::IsEmpty;
  59. using testing::UnorderedElementsAre;
  60. sync_pb::EntitySpecifics MakeSpecifics(ModelType model_type) {
  61. sync_pb::EntitySpecifics specifics;
  62. AddDefaultFieldValue(model_type, &specifics);
  63. return specifics;
  64. }
  65. sync_pb::EntitySpecifics MakeBookmarkSpecificsToCommit() {
  66. sync_pb::EntitySpecifics specifics = MakeSpecifics(BOOKMARKS);
  67. // The worker DCHECKs for the validity of the |type| and |unique_position|
  68. // fields for outgoing commits.
  69. specifics.mutable_bookmark()->set_type(sync_pb::BookmarkSpecifics::URL);
  70. *specifics.mutable_bookmark()->mutable_unique_position() =
  71. UniquePosition::InitialPosition(UniquePosition::RandomSuffix()).ToProto();
  72. return specifics;
  73. }
  74. } // namespace
  75. // Syncer unit tests. Unfortunately a lot of these tests
  76. // are outdated and need to be reworked and updated.
  77. class SyncerTest : public testing::Test,
  78. public SyncCycle::Delegate,
  79. public SyncEngineEventListener {
  80. public:
  81. SyncerTest() = default;
  82. SyncerTest(const SyncerTest&) = delete;
  83. SyncerTest& operator=(const SyncerTest&) = delete;
  84. // SyncCycle::Delegate implementation.
  85. void OnThrottled(const base::TimeDelta& throttle_duration) override {
  86. FAIL() << "Should not get silenced.";
  87. }
  88. void OnTypesThrottled(ModelTypeSet types,
  89. const base::TimeDelta& throttle_duration) override {
  90. scheduler_->OnTypesThrottled(types, throttle_duration);
  91. }
  92. void OnTypesBackedOff(ModelTypeSet types) override {
  93. scheduler_->OnTypesBackedOff(types);
  94. }
  95. bool IsAnyThrottleOrBackoff() override { return false; }
  96. void OnReceivedPollIntervalUpdate(
  97. const base::TimeDelta& new_interval) override {
  98. last_poll_interval_received_ = new_interval;
  99. }
  100. void OnReceivedCustomNudgeDelays(
  101. const std::map<ModelType, base::TimeDelta>& delay_map) override {
  102. auto iter = delay_map.find(SESSIONS);
  103. if (iter != delay_map.end() && iter->second.is_positive())
  104. last_sessions_commit_delay_ = iter->second;
  105. iter = delay_map.find(BOOKMARKS);
  106. if (iter != delay_map.end() && iter->second.is_positive())
  107. last_bookmarks_commit_delay_ = iter->second;
  108. }
  109. void OnReceivedClientInvalidationHintBufferSize(int size) override {
  110. last_client_invalidation_hint_buffer_size_ = size;
  111. }
  112. void OnReceivedGuRetryDelay(const base::TimeDelta& delay) override {}
  113. void OnReceivedMigrationRequest(ModelTypeSet types) override {}
  114. void OnReceivedQuotaParamsForExtensionTypes(
  115. absl::optional<int> max_tokens,
  116. absl::optional<base::TimeDelta> refill_interval,
  117. absl::optional<base::TimeDelta> depleted_quota_nudge_delay) override {}
  118. void OnProtocolEvent(const ProtocolEvent& event) override {}
  119. void OnSyncProtocolError(const SyncProtocolError& error) override {}
  120. void OnSyncCycleEvent(const SyncCycleEvent& event) override {
  121. DVLOG(1) << "HandleSyncEngineEvent in unittest " << event.what_happened;
  122. }
  123. void OnActionableError(const SyncProtocolError& error) override {}
  124. void OnRetryTimeChanged(base::Time retry_time) override {}
  125. void OnThrottledTypesChanged(ModelTypeSet throttled_types) override {}
  126. void OnBackedOffTypesChanged(ModelTypeSet backed_off_types) override {}
  127. void OnMigrationRequested(ModelTypeSet types) override {}
  128. void ResetCycle() {
  129. cycle_ = std::make_unique<SyncCycle>(context_.get(), this);
  130. }
  131. bool SyncShareNudge() {
  132. ResetCycle();
  133. // Pretend we've seen a local change, to make the nudge_tracker look normal.
  134. nudge_tracker_.RecordLocalChange(BOOKMARKS);
  135. return syncer_->NormalSyncShare(context_->GetConnectedTypes(),
  136. &nudge_tracker_, cycle_.get());
  137. }
  138. bool SyncShareConfigure() {
  139. return SyncShareConfigureTypes(context_->GetConnectedTypes());
  140. }
  141. bool SyncShareConfigureTypes(ModelTypeSet types) {
  142. ResetCycle();
  143. return syncer_->ConfigureSyncShare(
  144. types, sync_pb::SyncEnums::RECONFIGURATION, cycle_.get());
  145. }
  146. void SetUp() override {
  147. mock_server_ = std::make_unique<MockConnectionManager>();
  148. debug_info_getter_ = std::make_unique<MockDebugInfoGetter>();
  149. std::vector<SyncEngineEventListener*> listeners;
  150. listeners.push_back(this);
  151. model_type_registry_ = std::make_unique<ModelTypeRegistry>(
  152. &mock_nudge_handler_, &cancelation_signal_, &encryption_handler_);
  153. EnableDatatype(BOOKMARKS);
  154. EnableDatatype(EXTENSIONS);
  155. EnableDatatype(NIGORI);
  156. EnableDatatype(PREFERENCES);
  157. context_ = std::make_unique<SyncCycleContext>(
  158. mock_server_.get(), extensions_activity_.get(), listeners,
  159. debug_info_getter_.get(), model_type_registry_.get(),
  160. "fake_invalidator_client_id", local_cache_guid(),
  161. mock_server_->store_birthday(), "fake_bag_of_chips",
  162. /*poll_interval=*/base::Minutes(30));
  163. auto syncer = std::make_unique<Syncer>(&cancelation_signal_);
  164. // The syncer is destroyed with the scheduler that owns it.
  165. syncer_ = syncer.get();
  166. scheduler_ = std::make_unique<SyncSchedulerImpl>(
  167. "TestSyncScheduler", BackoffDelayProvider::FromDefaults(),
  168. context_.get(), std::move(syncer), false);
  169. mock_server_->SetKeystoreKey("encryption_key");
  170. }
  171. void TearDown() override {
  172. mock_server_.reset();
  173. scheduler_.reset();
  174. }
  175. const std::string local_cache_guid() { return "lD16ebCGCZh+zkiZ68gWDw=="; }
  176. const std::string foreign_cache_guid() { return "kqyg7097kro6GSUod+GSg=="; }
  177. MockModelTypeProcessor* GetProcessor(ModelType model_type) {
  178. return &mock_model_type_processors_[model_type];
  179. }
  180. std::unique_ptr<DataTypeActivationResponse> MakeFakeActivationResponse(
  181. ModelType model_type) {
  182. auto response = std::make_unique<DataTypeActivationResponse>();
  183. response->model_type_state.set_initial_sync_done(true);
  184. response->model_type_state.mutable_progress_marker()->set_data_type_id(
  185. GetSpecificsFieldNumberFromModelType(model_type));
  186. response->type_processor = std::make_unique<ForwardingModelTypeProcessor>(
  187. GetProcessor(model_type));
  188. return response;
  189. }
  190. void EnableDatatype(ModelType model_type) {
  191. enabled_datatypes_.Put(model_type);
  192. model_type_registry_->ConnectDataType(
  193. model_type, MakeFakeActivationResponse(model_type));
  194. mock_server_->ExpectGetUpdatesRequestTypes(enabled_datatypes_);
  195. }
  196. void DisableDatatype(ModelType model_type) {
  197. enabled_datatypes_.Remove(model_type);
  198. model_type_registry_->DisconnectDataType(model_type);
  199. mock_server_->ExpectGetUpdatesRequestTypes(enabled_datatypes_);
  200. }
  201. // Configures SyncCycleContext and NudgeTracker so Syncer won't call
  202. // GetUpdates prior to Commit. This method can be used to ensure a Commit is
  203. // not preceeded by GetUpdates.
  204. void ConfigureNoGetUpdatesRequired() {
  205. nudge_tracker_.OnInvalidationsEnabled();
  206. nudge_tracker_.RecordSuccessfulSyncCycle(ModelTypeSet::All());
  207. ASSERT_FALSE(nudge_tracker_.IsGetUpdatesRequired(ModelTypeSet::All()));
  208. }
  209. protected:
  210. base::test::SingleThreadTaskEnvironment task_environment_;
  211. FakeSyncEncryptionHandler encryption_handler_;
  212. scoped_refptr<ExtensionsActivity> extensions_activity_ =
  213. new ExtensionsActivity;
  214. std::unique_ptr<MockConnectionManager> mock_server_;
  215. CancelationSignal cancelation_signal_;
  216. std::map<ModelType, MockModelTypeProcessor> mock_model_type_processors_;
  217. raw_ptr<Syncer> syncer_ = nullptr;
  218. std::unique_ptr<SyncCycle> cycle_;
  219. MockNudgeHandler mock_nudge_handler_;
  220. std::unique_ptr<ModelTypeRegistry> model_type_registry_;
  221. std::unique_ptr<SyncSchedulerImpl> scheduler_;
  222. std::unique_ptr<SyncCycleContext> context_;
  223. base::TimeDelta last_poll_interval_received_;
  224. base::TimeDelta last_sessions_commit_delay_;
  225. base::TimeDelta last_bookmarks_commit_delay_;
  226. int last_client_invalidation_hint_buffer_size_ = 10;
  227. ModelTypeSet enabled_datatypes_;
  228. NudgeTracker nudge_tracker_;
  229. std::unique_ptr<MockDebugInfoGetter> debug_info_getter_;
  230. };
  231. TEST_F(SyncerTest, CommitFiltersThrottledEntries) {
  232. const ModelTypeSet throttled_types(BOOKMARKS);
  233. GetProcessor(BOOKMARKS)->AppendCommitRequest(
  234. ClientTagHash::FromHashed("tag1"), MakeBookmarkSpecificsToCommit(),
  235. "id1");
  236. // Sync without enabling bookmarks.
  237. mock_server_->ExpectGetUpdatesRequestTypes(
  238. Difference(context_->GetConnectedTypes(), throttled_types));
  239. ResetCycle();
  240. syncer_->NormalSyncShare(
  241. Difference(context_->GetConnectedTypes(), throttled_types),
  242. &nudge_tracker_, cycle_.get());
  243. // Nothing should have been committed as bookmarks is throttled.
  244. EXPECT_EQ(0, GetProcessor(BOOKMARKS)->GetLocalChangesCallCount());
  245. // Sync again with bookmarks enabled.
  246. mock_server_->ExpectGetUpdatesRequestTypes(context_->GetConnectedTypes());
  247. EXPECT_TRUE(SyncShareNudge());
  248. EXPECT_EQ(1, GetProcessor(BOOKMARKS)->GetLocalChangesCallCount());
  249. }
  250. TEST_F(SyncerTest, GetUpdatesPartialThrottled) {
  251. const sync_pb::EntitySpecifics bookmark = MakeSpecifics(BOOKMARKS);
  252. const sync_pb::EntitySpecifics pref = MakeSpecifics(PREFERENCES);
  253. // Normal sync, all the data types should get synced.
  254. mock_server_->AddUpdateSpecifics("1", "0", "A", 10, 10, true, bookmark,
  255. foreign_cache_guid(), "-1");
  256. mock_server_->AddUpdateSpecifics("2", "1", "B", 10, 10, false, bookmark,
  257. foreign_cache_guid(), "-2");
  258. mock_server_->AddUpdateSpecifics("3", "1", "C", 10, 10, false, bookmark,
  259. foreign_cache_guid(), "-3");
  260. mock_server_->AddUpdateSpecifics("4", "0", "D", 10, 10, false, pref);
  261. EXPECT_TRUE(SyncShareNudge());
  262. // Initial state. Everything is normal.
  263. ASSERT_EQ(1U, GetProcessor(BOOKMARKS)->GetNumUpdateResponses());
  264. ASSERT_EQ(3U, GetProcessor(BOOKMARKS)->GetNthUpdateResponse(0).size());
  265. ASSERT_EQ(1U, GetProcessor(PREFERENCES)->GetNumUpdateResponses());
  266. ASSERT_EQ(1U, GetProcessor(PREFERENCES)->GetNthUpdateResponse(0).size());
  267. // Set BOOKMARKS throttled but PREFERENCES not,
  268. // then BOOKMARKS should not get synced but PREFERENCES should.
  269. ModelTypeSet throttled_types(BOOKMARKS);
  270. mock_server_->set_throttling(true);
  271. mock_server_->SetPartialFailureTypes(throttled_types);
  272. mock_server_->AddUpdateSpecifics("1", "0", "E", 20, 20, true, bookmark,
  273. foreign_cache_guid(), "-1");
  274. mock_server_->AddUpdateSpecifics("2", "1", "F", 20, 20, false, bookmark,
  275. foreign_cache_guid(), "-2");
  276. mock_server_->AddUpdateSpecifics("3", "1", "G", 20, 20, false, bookmark,
  277. foreign_cache_guid(), "-3");
  278. mock_server_->AddUpdateSpecifics("4", "0", "H", 20, 20, false, pref);
  279. EXPECT_TRUE(SyncShareNudge());
  280. // PREFERENCES continues to work normally (not throttled).
  281. ASSERT_EQ(2U, GetProcessor(PREFERENCES)->GetNumUpdateResponses());
  282. // BOOKMARKS throttled.
  283. EXPECT_EQ(1U, GetProcessor(BOOKMARKS)->GetNumUpdateResponses());
  284. // Unthrottled BOOKMARKS, then BOOKMARKS should get synced now.
  285. mock_server_->set_throttling(false);
  286. mock_server_->AddUpdateSpecifics("1", "0", "E", 30, 30, true, bookmark,
  287. foreign_cache_guid(), "-1");
  288. mock_server_->AddUpdateSpecifics("2", "1", "F", 30, 30, false, bookmark,
  289. foreign_cache_guid(), "-2");
  290. mock_server_->AddUpdateSpecifics("3", "1", "G", 30, 30, false, bookmark,
  291. foreign_cache_guid(), "-3");
  292. mock_server_->AddUpdateSpecifics("4", "0", "H", 30, 30, false, pref);
  293. EXPECT_TRUE(SyncShareNudge());
  294. // BOOKMARKS unthrottled.
  295. EXPECT_EQ(2U, GetProcessor(BOOKMARKS)->GetNumUpdateResponses());
  296. }
  297. TEST_F(SyncerTest, GetUpdatesPartialFailure) {
  298. const sync_pb::EntitySpecifics bookmark = MakeSpecifics(BOOKMARKS);
  299. const sync_pb::EntitySpecifics pref = MakeSpecifics(PREFERENCES);
  300. // Normal sync, all the data types should get synced.
  301. mock_server_->AddUpdateSpecifics("1", "0", "A", 10, 10, true, bookmark,
  302. foreign_cache_guid(), "-1");
  303. mock_server_->AddUpdateSpecifics("2", "1", "B", 10, 10, false, bookmark,
  304. foreign_cache_guid(), "-2");
  305. mock_server_->AddUpdateSpecifics("3", "1", "C", 10, 10, false, bookmark,
  306. foreign_cache_guid(), "-3");
  307. mock_server_->AddUpdateSpecifics("4", "0", "D", 10, 10, false, pref);
  308. EXPECT_TRUE(SyncShareNudge());
  309. // Initial state. Everything is normal.
  310. ASSERT_EQ(1U, GetProcessor(BOOKMARKS)->GetNumUpdateResponses());
  311. ASSERT_EQ(3U, GetProcessor(BOOKMARKS)->GetNthUpdateResponse(0).size());
  312. ASSERT_EQ(1U, GetProcessor(PREFERENCES)->GetNumUpdateResponses());
  313. ASSERT_EQ(1U, GetProcessor(PREFERENCES)->GetNthUpdateResponse(0).size());
  314. // Set BOOKMARKS failure but PREFERENCES not,
  315. // then BOOKMARKS should not get synced but PREFERENCES should.
  316. ModelTypeSet failed_types(BOOKMARKS);
  317. mock_server_->set_partial_failure(true);
  318. mock_server_->SetPartialFailureTypes(failed_types);
  319. mock_server_->AddUpdateSpecifics("1", "0", "E", 20, 20, true, bookmark,
  320. foreign_cache_guid(), "-1");
  321. mock_server_->AddUpdateSpecifics("2", "1", "F", 20, 20, false, bookmark,
  322. foreign_cache_guid(), "-2");
  323. mock_server_->AddUpdateSpecifics("3", "1", "G", 20, 20, false, bookmark,
  324. foreign_cache_guid(), "-3");
  325. mock_server_->AddUpdateSpecifics("4", "0", "H", 20, 20, false, pref);
  326. EXPECT_TRUE(SyncShareNudge());
  327. // PREFERENCES continues to work normally (not throttled).
  328. ASSERT_EQ(2U, GetProcessor(PREFERENCES)->GetNumUpdateResponses());
  329. // BOOKMARKS failed.
  330. EXPECT_EQ(1U, GetProcessor(BOOKMARKS)->GetNumUpdateResponses());
  331. // Set BOOKMARKS not partial failed, then BOOKMARKS should get synced now.
  332. mock_server_->set_partial_failure(false);
  333. mock_server_->AddUpdateSpecifics("1", "0", "E", 30, 30, true, bookmark,
  334. foreign_cache_guid(), "-1");
  335. mock_server_->AddUpdateSpecifics("2", "1", "F", 30, 30, false, bookmark,
  336. foreign_cache_guid(), "-2");
  337. mock_server_->AddUpdateSpecifics("3", "1", "G", 30, 30, false, bookmark,
  338. foreign_cache_guid(), "-3");
  339. mock_server_->AddUpdateSpecifics("4", "0", "H", 30, 30, false, pref);
  340. EXPECT_TRUE(SyncShareNudge());
  341. // BOOKMARKS not failed.
  342. EXPECT_EQ(2U, GetProcessor(BOOKMARKS)->GetNumUpdateResponses());
  343. }
  344. TEST_F(SyncerTest, TestSimpleCommit) {
  345. const std::string kSyncId1 = "id1";
  346. const std::string kSyncId2 = "id2";
  347. GetProcessor(PREFERENCES)
  348. ->AppendCommitRequest(ClientTagHash::FromHashed("tag1"),
  349. MakeSpecifics(PREFERENCES), kSyncId1);
  350. GetProcessor(PREFERENCES)
  351. ->AppendCommitRequest(ClientTagHash::FromHashed("tag2"),
  352. MakeSpecifics(PREFERENCES), kSyncId2);
  353. EXPECT_TRUE(SyncShareNudge());
  354. EXPECT_THAT(mock_server_->committed_ids(),
  355. UnorderedElementsAre(kSyncId1, kSyncId2));
  356. }
  357. TEST_F(SyncerTest, TestSimpleGetUpdates) {
  358. std::string id = "some_id";
  359. std::string parent_id = "0";
  360. std::string name = "in_root";
  361. int64_t version = 10;
  362. int64_t timestamp = 10;
  363. mock_server_->AddUpdateDirectory(id, parent_id, name, version, timestamp,
  364. foreign_cache_guid(), "-1");
  365. EXPECT_TRUE(SyncShareNudge());
  366. ASSERT_EQ(1U, GetProcessor(BOOKMARKS)->GetNumUpdateResponses());
  367. std::vector<const UpdateResponseData*> updates_list =
  368. GetProcessor(BOOKMARKS)->GetNthUpdateResponse(0);
  369. EXPECT_EQ(1U, updates_list.size());
  370. const UpdateResponseData& update = *updates_list.back();
  371. const EntityData& entity = update.entity;
  372. EXPECT_EQ(id, entity.id);
  373. EXPECT_EQ(version, update.response_version);
  374. // Creation time hardcoded in MockConnectionManager::AddUpdateMeta().
  375. EXPECT_EQ(ProtoTimeToTime(1), entity.creation_time);
  376. EXPECT_EQ(ProtoTimeToTime(timestamp), entity.modification_time);
  377. EXPECT_EQ(name, entity.name);
  378. EXPECT_FALSE(entity.is_deleted());
  379. }
  380. // Committing more than kDefaultMaxCommitBatchSize items requires that
  381. // we post more than one commit command to the server. This test makes
  382. // sure that scenario works as expected.
  383. TEST_F(SyncerTest, CommitManyItemsInOneGo_Success) {
  384. int num_batches = 3;
  385. int items_to_commit = kDefaultMaxCommitBatchSize * num_batches;
  386. for (int i = 0; i < items_to_commit; i++) {
  387. GetProcessor(PREFERENCES)
  388. ->AppendCommitRequest(
  389. ClientTagHash::FromHashed(base::StringPrintf("tag%d", i)),
  390. MakeSpecifics(PREFERENCES));
  391. }
  392. EXPECT_TRUE(SyncShareNudge());
  393. EXPECT_EQ(static_cast<size_t>(num_batches),
  394. mock_server_->commit_messages().size());
  395. ASSERT_EQ(static_cast<size_t>(num_batches),
  396. GetProcessor(PREFERENCES)->GetNumCommitResponses());
  397. EXPECT_EQ(static_cast<size_t>(kDefaultMaxCommitBatchSize),
  398. GetProcessor(PREFERENCES)->GetNthCommitResponse(0).size());
  399. EXPECT_EQ(static_cast<size_t>(kDefaultMaxCommitBatchSize),
  400. GetProcessor(PREFERENCES)->GetNthCommitResponse(1).size());
  401. EXPECT_EQ(static_cast<size_t>(kDefaultMaxCommitBatchSize),
  402. GetProcessor(PREFERENCES)->GetNthCommitResponse(2).size());
  403. }
  404. // Test that a single failure to contact the server will cause us to exit the
  405. // commit loop immediately.
  406. TEST_F(SyncerTest, CommitManyItemsInOneGo_PostBufferFail) {
  407. int num_batches = 3;
  408. int items_to_commit = kDefaultMaxCommitBatchSize * num_batches;
  409. for (int i = 0; i < items_to_commit; i++) {
  410. GetProcessor(PREFERENCES)
  411. ->AppendCommitRequest(
  412. ClientTagHash::FromHashed(base::StringPrintf("tag%d", i)),
  413. MakeSpecifics(PREFERENCES));
  414. }
  415. // The second commit should fail. It will be preceded by one successful
  416. // GetUpdate and one succesful commit.
  417. mock_server_->FailNthPostBufferToPathCall(3);
  418. base::HistogramTester histogram_tester;
  419. EXPECT_FALSE(SyncShareNudge());
  420. EXPECT_EQ(1U, mock_server_->commit_messages().size());
  421. EXPECT_EQ(
  422. SyncerError::SYNC_SERVER_ERROR,
  423. cycle_->status_controller().model_neutral_state().commit_result.value());
  424. // Since the second batch fails, the third one should not even be gathered.
  425. EXPECT_EQ(2, GetProcessor(PREFERENCES)->GetLocalChangesCallCount());
  426. histogram_tester.ExpectBucketCount("Sync.CommitResponse.PREFERENCE",
  427. SyncerError::SYNC_SERVER_ERROR,
  428. /*expected_count=*/1);
  429. histogram_tester.ExpectBucketCount("Sync.CommitResponse",
  430. SyncerError::SYNC_SERVER_ERROR,
  431. /*expected_count=*/1);
  432. }
  433. // Test that a single conflict response from the server will cause us to exit
  434. // the commit loop immediately.
  435. TEST_F(SyncerTest, CommitManyItemsInOneGo_CommitConflict) {
  436. int num_batches = 2;
  437. int items_to_commit = kDefaultMaxCommitBatchSize * num_batches;
  438. for (int i = 0; i < items_to_commit; i++) {
  439. GetProcessor(PREFERENCES)
  440. ->AppendCommitRequest(
  441. ClientTagHash::FromHashed(base::StringPrintf("tag%d", i)),
  442. MakeSpecifics(PREFERENCES));
  443. }
  444. // Return a CONFLICT response for the first item.
  445. mock_server_->set_conflict_n_commits(1);
  446. EXPECT_FALSE(SyncShareNudge());
  447. // We should stop looping at the first sign of trouble.
  448. EXPECT_EQ(1U, mock_server_->commit_messages().size());
  449. EXPECT_EQ(1, GetProcessor(PREFERENCES)->GetLocalChangesCallCount());
  450. }
  451. // Tests that sending debug info events works.
  452. TEST_F(SyncerTest, SendDebugInfoEventsOnGetUpdates_HappyCase) {
  453. debug_info_getter_->AddDebugEvent();
  454. debug_info_getter_->AddDebugEvent();
  455. EXPECT_TRUE(SyncShareNudge());
  456. // Verify we received one GetUpdates request with two debug info events.
  457. EXPECT_EQ(1U, mock_server_->requests().size());
  458. ASSERT_TRUE(mock_server_->last_request().has_get_updates());
  459. EXPECT_EQ(2, mock_server_->last_request().debug_info().events_size());
  460. EXPECT_TRUE(SyncShareNudge());
  461. // See that we received another GetUpdates request, but that it contains no
  462. // debug info events.
  463. EXPECT_EQ(2U, mock_server_->requests().size());
  464. ASSERT_TRUE(mock_server_->last_request().has_get_updates());
  465. EXPECT_EQ(0, mock_server_->last_request().debug_info().events_size());
  466. debug_info_getter_->AddDebugEvent();
  467. EXPECT_TRUE(SyncShareNudge());
  468. // See that we received another GetUpdates request and it contains one debug
  469. // info event.
  470. EXPECT_EQ(3U, mock_server_->requests().size());
  471. ASSERT_TRUE(mock_server_->last_request().has_get_updates());
  472. EXPECT_EQ(1, mock_server_->last_request().debug_info().events_size());
  473. }
  474. // Tests that debug info events are dropped on server error.
  475. TEST_F(SyncerTest, SendDebugInfoEventsOnGetUpdates_PostFailsDontDrop) {
  476. debug_info_getter_->AddDebugEvent();
  477. debug_info_getter_->AddDebugEvent();
  478. mock_server_->FailNextPostBufferToPathCall();
  479. EXPECT_FALSE(SyncShareNudge());
  480. // Verify we attempted to send one GetUpdates request with two debug info
  481. // events.
  482. EXPECT_EQ(1U, mock_server_->requests().size());
  483. ASSERT_TRUE(mock_server_->last_request().has_get_updates());
  484. EXPECT_EQ(2, mock_server_->last_request().debug_info().events_size());
  485. EXPECT_TRUE(SyncShareNudge());
  486. // See that the client resent the two debug info events.
  487. EXPECT_EQ(2U, mock_server_->requests().size());
  488. ASSERT_TRUE(mock_server_->last_request().has_get_updates());
  489. EXPECT_EQ(2, mock_server_->last_request().debug_info().events_size());
  490. // The previous send was successful so this next one shouldn't generate any
  491. // debug info events.
  492. EXPECT_TRUE(SyncShareNudge());
  493. EXPECT_EQ(3U, mock_server_->requests().size());
  494. ASSERT_TRUE(mock_server_->last_request().has_get_updates());
  495. EXPECT_EQ(0, mock_server_->last_request().debug_info().events_size());
  496. }
  497. // Tests that commit failure with conflict will trigger GetUpdates for next
  498. // cycle of sync
  499. TEST_F(SyncerTest, CommitFailureWithConflict) {
  500. ConfigureNoGetUpdatesRequired();
  501. GetProcessor(PREFERENCES)
  502. ->AppendCommitRequest(ClientTagHash::FromHashed("tag1"),
  503. MakeSpecifics(PREFERENCES), "id1");
  504. EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired(ModelTypeSet::All()));
  505. EXPECT_TRUE(SyncShareNudge());
  506. EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired(ModelTypeSet::All()));
  507. GetProcessor(PREFERENCES)
  508. ->AppendCommitRequest(ClientTagHash::FromHashed("tag1"),
  509. MakeSpecifics(PREFERENCES), "id1");
  510. mock_server_->set_conflict_n_commits(1);
  511. EXPECT_FALSE(SyncShareNudge());
  512. EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired(ModelTypeSet::All()));
  513. nudge_tracker_.RecordSuccessfulSyncCycle(ModelTypeSet::All());
  514. EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired(ModelTypeSet::All()));
  515. }
  516. // Tests that sending debug info events on Commit works.
  517. TEST_F(SyncerTest, SendDebugInfoEventsOnCommit_HappyCase) {
  518. // Make sure GetUpdate isn't call as it would "steal" debug info events before
  519. // Commit has a chance to send them.
  520. ConfigureNoGetUpdatesRequired();
  521. // Generate a debug info event and trigger a commit.
  522. debug_info_getter_->AddDebugEvent();
  523. GetProcessor(PREFERENCES)
  524. ->AppendCommitRequest(ClientTagHash::FromHashed("tag1"),
  525. MakeSpecifics(PREFERENCES), "id1");
  526. EXPECT_TRUE(SyncShareNudge());
  527. // Verify that the last request received is a Commit and that it contains a
  528. // debug info event.
  529. EXPECT_EQ(1U, mock_server_->requests().size());
  530. ASSERT_TRUE(mock_server_->last_request().has_commit());
  531. EXPECT_EQ(1, mock_server_->last_request().debug_info().events_size());
  532. // Generate another commit, but no debug info event.
  533. GetProcessor(PREFERENCES)
  534. ->AppendCommitRequest(ClientTagHash::FromHashed("tag2"),
  535. MakeSpecifics(PREFERENCES), "id2");
  536. EXPECT_TRUE(SyncShareNudge());
  537. // See that it was received and contains no debug info events.
  538. EXPECT_EQ(2U, mock_server_->requests().size());
  539. ASSERT_TRUE(mock_server_->last_request().has_commit());
  540. EXPECT_EQ(0, mock_server_->last_request().debug_info().events_size());
  541. }
  542. // Tests that debug info events are not dropped on server error.
  543. TEST_F(SyncerTest, SendDebugInfoEventsOnCommit_PostFailsDontDrop) {
  544. // Make sure GetUpdate isn't call as it would "steal" debug info events before
  545. // Commit has a chance to send them.
  546. ConfigureNoGetUpdatesRequired();
  547. mock_server_->FailNextPostBufferToPathCall();
  548. // Generate a debug info event and trigger a commit.
  549. debug_info_getter_->AddDebugEvent();
  550. GetProcessor(PREFERENCES)
  551. ->AppendCommitRequest(ClientTagHash::FromHashed("tag1"),
  552. MakeSpecifics(PREFERENCES), "id1");
  553. EXPECT_FALSE(SyncShareNudge());
  554. // Verify that the last request sent is a Commit and that it contains a debug
  555. // info event.
  556. EXPECT_EQ(1U, mock_server_->requests().size());
  557. ASSERT_TRUE(mock_server_->last_request().has_commit());
  558. EXPECT_EQ(1, mock_server_->last_request().debug_info().events_size());
  559. // Try again. Because of how MockModelTypeProcessor works, commit data needs
  560. // to be provided again.
  561. GetProcessor(PREFERENCES)
  562. ->AppendCommitRequest(ClientTagHash::FromHashed("tag1"),
  563. MakeSpecifics(PREFERENCES), "id1");
  564. EXPECT_TRUE(SyncShareNudge());
  565. // Verify that we've received another Commit and that it contains a debug info
  566. // event (just like the previous one).
  567. EXPECT_EQ(2U, mock_server_->requests().size());
  568. ASSERT_TRUE(mock_server_->last_request().has_commit());
  569. EXPECT_EQ(1, mock_server_->last_request().debug_info().events_size());
  570. // Generate another commit and try again.
  571. GetProcessor(PREFERENCES)
  572. ->AppendCommitRequest(ClientTagHash::FromHashed("tag2"),
  573. MakeSpecifics(PREFERENCES), "id2");
  574. EXPECT_TRUE(SyncShareNudge());
  575. // See that it was received and contains no debug info events.
  576. EXPECT_EQ(3U, mock_server_->requests().size());
  577. ASSERT_TRUE(mock_server_->last_request().has_commit());
  578. EXPECT_EQ(0, mock_server_->last_request().debug_info().events_size());
  579. }
  580. TEST_F(SyncerTest, TestClientCommandDuringUpdate) {
  581. using sync_pb::ClientCommand;
  582. auto command = std::make_unique<ClientCommand>();
  583. command->set_set_sync_poll_interval(8);
  584. command->set_set_sync_long_poll_interval(800);
  585. command->set_sessions_commit_delay_seconds(3141);
  586. sync_pb::CustomNudgeDelay* bookmark_delay =
  587. command->add_custom_nudge_delays();
  588. bookmark_delay->set_datatype_id(
  589. GetSpecificsFieldNumberFromModelType(BOOKMARKS));
  590. bookmark_delay->set_delay_ms(950);
  591. command->set_client_invalidation_hint_buffer_size(11);
  592. mock_server_->AddUpdateDirectory("1", "0", "in_root", 1, 1,
  593. foreign_cache_guid(), "-1");
  594. mock_server_->SetGUClientCommand(std::move(command));
  595. EXPECT_TRUE(SyncShareNudge());
  596. EXPECT_EQ(base::Seconds(8), last_poll_interval_received_);
  597. EXPECT_EQ(base::Seconds(3141), last_sessions_commit_delay_);
  598. EXPECT_EQ(base::Milliseconds(950), last_bookmarks_commit_delay_);
  599. EXPECT_EQ(11, last_client_invalidation_hint_buffer_size_);
  600. command = std::make_unique<ClientCommand>();
  601. command->set_set_sync_poll_interval(180);
  602. command->set_set_sync_long_poll_interval(190);
  603. command->set_sessions_commit_delay_seconds(2718);
  604. bookmark_delay = command->add_custom_nudge_delays();
  605. bookmark_delay->set_datatype_id(
  606. GetSpecificsFieldNumberFromModelType(BOOKMARKS));
  607. bookmark_delay->set_delay_ms(1050);
  608. command->set_client_invalidation_hint_buffer_size(9);
  609. mock_server_->AddUpdateDirectory("1", "0", "in_root", 1, 1,
  610. foreign_cache_guid(), "-1");
  611. mock_server_->SetGUClientCommand(std::move(command));
  612. EXPECT_TRUE(SyncShareNudge());
  613. EXPECT_EQ(base::Seconds(180), last_poll_interval_received_);
  614. EXPECT_EQ(base::Seconds(2718), last_sessions_commit_delay_);
  615. EXPECT_EQ(base::Milliseconds(1050), last_bookmarks_commit_delay_);
  616. EXPECT_EQ(9, last_client_invalidation_hint_buffer_size_);
  617. }
  618. TEST_F(SyncerTest, TestClientCommandDuringCommit) {
  619. using sync_pb::ClientCommand;
  620. auto command = std::make_unique<ClientCommand>();
  621. command->set_set_sync_poll_interval(8);
  622. command->set_set_sync_long_poll_interval(800);
  623. command->set_sessions_commit_delay_seconds(3141);
  624. sync_pb::CustomNudgeDelay* bookmark_delay =
  625. command->add_custom_nudge_delays();
  626. bookmark_delay->set_datatype_id(
  627. GetSpecificsFieldNumberFromModelType(BOOKMARKS));
  628. bookmark_delay->set_delay_ms(950);
  629. command->set_client_invalidation_hint_buffer_size(11);
  630. GetProcessor(BOOKMARKS)->AppendCommitRequest(
  631. ClientTagHash::FromHashed("tag1"), MakeBookmarkSpecificsToCommit(),
  632. "id1");
  633. mock_server_->SetCommitClientCommand(std::move(command));
  634. EXPECT_TRUE(SyncShareNudge());
  635. EXPECT_EQ(base::Seconds(8), last_poll_interval_received_);
  636. EXPECT_EQ(base::Seconds(3141), last_sessions_commit_delay_);
  637. EXPECT_EQ(base::Milliseconds(950), last_bookmarks_commit_delay_);
  638. EXPECT_EQ(11, last_client_invalidation_hint_buffer_size_);
  639. command = std::make_unique<ClientCommand>();
  640. command->set_set_sync_poll_interval(180);
  641. command->set_set_sync_long_poll_interval(190);
  642. command->set_sessions_commit_delay_seconds(2718);
  643. bookmark_delay = command->add_custom_nudge_delays();
  644. bookmark_delay->set_datatype_id(
  645. GetSpecificsFieldNumberFromModelType(BOOKMARKS));
  646. bookmark_delay->set_delay_ms(1050);
  647. command->set_client_invalidation_hint_buffer_size(9);
  648. GetProcessor(BOOKMARKS)->AppendCommitRequest(
  649. ClientTagHash::FromHashed("tag2"), MakeBookmarkSpecificsToCommit(),
  650. "id2");
  651. mock_server_->SetCommitClientCommand(std::move(command));
  652. EXPECT_TRUE(SyncShareNudge());
  653. EXPECT_EQ(base::Seconds(180), last_poll_interval_received_);
  654. EXPECT_EQ(base::Seconds(2718), last_sessions_commit_delay_);
  655. EXPECT_EQ(base::Milliseconds(1050), last_bookmarks_commit_delay_);
  656. EXPECT_EQ(9, last_client_invalidation_hint_buffer_size_);
  657. }
  658. TEST_F(SyncerTest, ShouldPopulateSingleClientFlag) {
  659. GetProcessor(BOOKMARKS)->AppendCommitRequest(
  660. ClientTagHash::FromHashed("tag1"), MakeBookmarkSpecificsToCommit(),
  661. "id1");
  662. // No other devices are interested in bookmarks.
  663. context_->set_active_devices_invalidation_info(
  664. ActiveDevicesInvalidationInfo::Create(
  665. /*all_fcm_registration_tokens=*/{},
  666. /*all_interested_data_types=*/{PREFERENCES},
  667. /*fcm_token_and_interested_data_types=*/{}));
  668. ASSERT_TRUE(SyncShareNudge());
  669. EXPECT_TRUE(
  670. mock_server_->last_request().commit().config_params().single_client());
  671. EXPECT_TRUE(mock_server_->last_request()
  672. .commit()
  673. .config_params()
  674. .single_client_with_standalone_invalidations());
  675. }
  676. TEST_F(SyncerTest,
  677. ShouldPopulateSingleClientFlagForStandaloneInvalidationsOnly) {
  678. GetProcessor(BOOKMARKS)->AppendCommitRequest(
  679. ClientTagHash::FromHashed("tag1"), MakeBookmarkSpecificsToCommit(),
  680. "id1");
  681. // No other devices with standalone invalidations are interested in bookmarks.
  682. context_->set_active_devices_invalidation_info(
  683. ActiveDevicesInvalidationInfo::Create(
  684. /*all_fcm_registration_tokens=*/{"token_1"},
  685. /*all_interested_data_types=*/{BOOKMARKS, PREFERENCES},
  686. /*fcm_token_and_interested_data_types=*/
  687. {{"token_1", {PREFERENCES}}}));
  688. ASSERT_TRUE(SyncShareNudge());
  689. EXPECT_FALSE(
  690. mock_server_->last_request().commit().config_params().single_client());
  691. EXPECT_TRUE(mock_server_->last_request()
  692. .commit()
  693. .config_params()
  694. .single_client_with_standalone_invalidations());
  695. }
  696. TEST_F(SyncerTest, ShouldPopulateFcmRegistrationTokens) {
  697. GetProcessor(BOOKMARKS)->AppendCommitRequest(
  698. ClientTagHash::FromHashed("tag1"), MakeBookmarkSpecificsToCommit(),
  699. "id1");
  700. context_->set_active_devices_invalidation_info(
  701. ActiveDevicesInvalidationInfo::Create(
  702. {"token"}, /*all_interested_data_types=*/{BOOKMARKS},
  703. /*fcm_token_and_interested_data_types=*/{{"token", {BOOKMARKS}}}));
  704. ASSERT_TRUE(SyncShareNudge());
  705. EXPECT_FALSE(
  706. mock_server_->last_request().commit().config_params().single_client());
  707. EXPECT_FALSE(mock_server_->last_request()
  708. .commit()
  709. .config_params()
  710. .single_client_with_standalone_invalidations());
  711. EXPECT_THAT(mock_server_->last_sent_commit()
  712. .config_params()
  713. .devices_fcm_registration_tokens(),
  714. ElementsAre("token"));
  715. EXPECT_THAT(mock_server_->last_sent_commit()
  716. .config_params()
  717. .fcm_registration_tokens_for_interested_clients(),
  718. ElementsAre("token"));
  719. }
  720. TEST_F(SyncerTest, ShouldPopulateFcmRegistrationTokensForInterestedTypesOnly) {
  721. GetProcessor(BOOKMARKS)->AppendCommitRequest(
  722. ClientTagHash::FromHashed("tag1"), MakeBookmarkSpecificsToCommit(),
  723. "id1");
  724. context_->set_active_devices_invalidation_info(
  725. ActiveDevicesInvalidationInfo::Create(
  726. {"token_1", "token_2"}, /*all_interested_data_types=*/{BOOKMARKS},
  727. /*fcm_token_and_interested_data_types=*/
  728. {{"token_1", {BOOKMARKS}}, {"token_2", {PREFERENCES}}}));
  729. ASSERT_TRUE(SyncShareNudge());
  730. EXPECT_FALSE(
  731. mock_server_->last_request().commit().config_params().single_client());
  732. EXPECT_FALSE(mock_server_->last_request()
  733. .commit()
  734. .config_params()
  735. .single_client_with_standalone_invalidations());
  736. EXPECT_THAT(mock_server_->last_sent_commit()
  737. .config_params()
  738. .devices_fcm_registration_tokens(),
  739. ElementsAre("token_1", "token_2"));
  740. EXPECT_THAT(mock_server_->last_sent_commit()
  741. .config_params()
  742. .fcm_registration_tokens_for_interested_clients(),
  743. ElementsAre("token_1"));
  744. }
  745. TEST_F(SyncerTest, ShouldNotPopulateTooManyFcmRegistrationTokens) {
  746. std::map<std::string, ModelTypeSet> fcm_token_and_interested_data_types;
  747. for (size_t i = 0; i < 7; ++i) {
  748. fcm_token_and_interested_data_types["token_" + base::NumberToString(i)] = {
  749. BOOKMARKS};
  750. }
  751. GetProcessor(BOOKMARKS)->AppendCommitRequest(
  752. ClientTagHash::FromHashed("tag1"), MakeBookmarkSpecificsToCommit(),
  753. "id1");
  754. context_->set_active_devices_invalidation_info(
  755. ActiveDevicesInvalidationInfo::Create(
  756. {}, /*all_interested_data_types=*/{BOOKMARKS},
  757. std::move(fcm_token_and_interested_data_types)));
  758. ASSERT_TRUE(SyncShareNudge());
  759. EXPECT_FALSE(
  760. mock_server_->last_request().commit().config_params().single_client());
  761. EXPECT_FALSE(mock_server_->last_request()
  762. .commit()
  763. .config_params()
  764. .single_client_with_standalone_invalidations());
  765. EXPECT_THAT(mock_server_->last_sent_commit()
  766. .config_params()
  767. .devices_fcm_registration_tokens(),
  768. IsEmpty());
  769. EXPECT_THAT(mock_server_->last_sent_commit()
  770. .config_params()
  771. .fcm_registration_tokens_for_interested_clients(),
  772. IsEmpty());
  773. }
  774. TEST_F(SyncerTest,
  775. ShouldNotPopulateOptimizationFlagsIfDeviceInfoRecentlyUpdated) {
  776. base::test::ScopedFeatureList override_features;
  777. override_features.InitAndEnableFeature(
  778. kSkipInvalidationOptimizationsWhenDeviceInfoUpdated);
  779. EnableDatatype(DEVICE_INFO);
  780. mock_server_->AddUpdateSpecifics("id", /*parent_id=*/"", "name",
  781. /*version=*/1, /*sync_ts=*/10,
  782. /*is_dir=*/false, /*specifics=*/
  783. MakeSpecifics(DEVICE_INFO));
  784. GetProcessor(BOOKMARKS)->AppendCommitRequest(
  785. ClientTagHash::FromHashed("tag1"), MakeBookmarkSpecificsToCommit(),
  786. "id1");
  787. // No other devices are interested in bookmarks.
  788. context_->set_active_devices_invalidation_info(
  789. ActiveDevicesInvalidationInfo::Create(
  790. {"token"}, /*all_interested_data_types=*/{PREFERENCES},
  791. /*fcm_token_and_interested_data_types=*/{{"token", {PREFERENCES}}}));
  792. ASSERT_TRUE(SyncShareNudge());
  793. // All invalidation info should be ignored due to DeviceInfo update.
  794. EXPECT_FALSE(
  795. mock_server_->last_request().commit().config_params().single_client());
  796. EXPECT_FALSE(mock_server_->last_request()
  797. .commit()
  798. .config_params()
  799. .single_client_with_standalone_invalidations());
  800. EXPECT_TRUE(mock_server_->last_sent_commit()
  801. .config_params()
  802. .devices_fcm_registration_tokens()
  803. .empty());
  804. EXPECT_TRUE(mock_server_->last_sent_commit()
  805. .config_params()
  806. .fcm_registration_tokens_for_interested_clients()
  807. .empty());
  808. }
  809. TEST_F(SyncerTest, ClientTagServerCreatedUpdatesWork) {
  810. mock_server_->AddUpdateDirectory("1", "0", "permitem1", 1, 10,
  811. foreign_cache_guid(), "-1");
  812. mock_server_->SetLastUpdateClientTag("clienttag");
  813. EXPECT_TRUE(SyncShareNudge());
  814. ASSERT_EQ(1U, GetProcessor(BOOKMARKS)->GetNumUpdateResponses());
  815. std::vector<const UpdateResponseData*> updates_list =
  816. GetProcessor(BOOKMARKS)->GetNthUpdateResponse(0);
  817. EXPECT_EQ(1U, updates_list.size());
  818. const UpdateResponseData& update = *updates_list.back();
  819. const EntityData& entity = update.entity;
  820. EXPECT_EQ("permitem1", entity.name);
  821. EXPECT_EQ(ClientTagHash::FromHashed("clienttag"), entity.client_tag_hash);
  822. EXPECT_FALSE(entity.is_deleted());
  823. }
  824. TEST_F(SyncerTest, GetUpdatesSetsRequestedTypes) {
  825. // The expectations of this test happen in the MockConnectionManager's
  826. // GetUpdates handler. EnableDatatype sets the expectation value from our
  827. // set of enabled/disabled datatypes.
  828. EXPECT_TRUE(SyncShareNudge());
  829. EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
  830. EnableDatatype(AUTOFILL);
  831. EXPECT_TRUE(SyncShareNudge());
  832. EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
  833. DisableDatatype(BOOKMARKS);
  834. EXPECT_TRUE(SyncShareNudge());
  835. EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
  836. DisableDatatype(AUTOFILL);
  837. EXPECT_TRUE(SyncShareNudge());
  838. EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
  839. DisableDatatype(PREFERENCES);
  840. EnableDatatype(AUTOFILL);
  841. EXPECT_TRUE(SyncShareNudge());
  842. EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
  843. }
  844. // A typical scenario: server and client each have one update for the other.
  845. // This is the "happy path" alternative to UpdateFailsThenDontCommit.
  846. TEST_F(SyncerTest, UpdateThenCommit) {
  847. std::string to_receive = "some_id1";
  848. std::string to_commit = "some_id2";
  849. std::string parent_id = "0";
  850. mock_server_->AddUpdateDirectory(to_receive, parent_id, "x", 1, 10,
  851. foreign_cache_guid(), "-1");
  852. GetProcessor(BOOKMARKS)->AppendCommitRequest(
  853. ClientTagHash::FromHashed("tag1"), MakeBookmarkSpecificsToCommit(),
  854. to_commit);
  855. EXPECT_TRUE(SyncShareNudge());
  856. // The sync cycle should have included a GetUpdate, then a commit.
  857. EXPECT_TRUE(mock_server_->last_request().has_commit());
  858. EXPECT_THAT(mock_server_->committed_ids(), UnorderedElementsAre(to_commit));
  859. // The update should have been received.
  860. ASSERT_EQ(1U, GetProcessor(BOOKMARKS)->GetNumUpdateResponses());
  861. std::vector<const UpdateResponseData*> updates_list =
  862. GetProcessor(BOOKMARKS)->GetNthUpdateResponse(0);
  863. ASSERT_EQ(1U, updates_list.size());
  864. EXPECT_EQ(to_receive, updates_list[0]->entity.id);
  865. }
  866. // Same as above, but this time we fail to download updates.
  867. // We should not attempt to commit anything unless we successfully downloaded
  868. // updates, otherwise we risk causing a server-side conflict.
  869. TEST_F(SyncerTest, UpdateFailsThenDontCommit) {
  870. std::string to_receive = "some_id1";
  871. std::string to_commit = "some_id2";
  872. std::string parent_id = "0";
  873. mock_server_->AddUpdateDirectory(to_receive, parent_id, "x", 1, 10,
  874. foreign_cache_guid(), "-1");
  875. GetProcessor(BOOKMARKS)->AppendCommitRequest(
  876. ClientTagHash::FromHashed("tag1"), MakeBookmarkSpecificsToCommit(),
  877. to_commit);
  878. mock_server_->FailNextPostBufferToPathCall();
  879. EXPECT_FALSE(SyncShareNudge());
  880. // We did not receive this update.
  881. EXPECT_EQ(0U, GetProcessor(BOOKMARKS)->GetNumUpdateResponses());
  882. // No commit should have been sent.
  883. EXPECT_FALSE(mock_server_->last_request().has_commit());
  884. EXPECT_THAT(mock_server_->committed_ids(), IsEmpty());
  885. // Inform the Mock we won't be fetching all updates.
  886. mock_server_->ClearUpdatesQueue();
  887. }
  888. // Downloads two updates successfully.
  889. // This is the "happy path" alternative to ConfigureFailsDontApplyUpdates.
  890. TEST_F(SyncerTest, ConfigureDownloadsTwoBatchesSuccess) {
  891. // Construct the first GetUpdates response.
  892. mock_server_->AddUpdatePref("id1", "", "one", 1, 10);
  893. mock_server_->SetChangesRemaining(1);
  894. mock_server_->NextUpdateBatch();
  895. // Construct the second GetUpdates response.
  896. mock_server_->AddUpdatePref("id2", "", "two", 2, 20);
  897. ASSERT_EQ(0U, GetProcessor(PREFERENCES)->GetNumUpdateResponses());
  898. SyncShareConfigure();
  899. // The type should have received the initial updates.
  900. EXPECT_EQ(1U, GetProcessor(PREFERENCES)->GetNumUpdateResponses());
  901. }
  902. // Same as the above case, but this time the second batch fails to download.
  903. TEST_F(SyncerTest, ConfigureFailsDontApplyUpdates) {
  904. // The scenario: we have two batches of updates with one update each. A
  905. // normal confgure step would download all the updates one batch at a time and
  906. // apply them. This configure will succeed in downloading the first batch
  907. // then fail when downloading the second.
  908. mock_server_->FailNthPostBufferToPathCall(2);
  909. // Construct the first GetUpdates response.
  910. mock_server_->AddUpdatePref("id1", "", "one", 1, 10);
  911. mock_server_->SetChangesRemaining(1);
  912. mock_server_->NextUpdateBatch();
  913. // Construct the second GetUpdates response.
  914. mock_server_->AddUpdatePref("id2", "", "two", 2, 20);
  915. ASSERT_EQ(0U, GetProcessor(PREFERENCES)->GetNumUpdateResponses());
  916. SyncShareConfigure();
  917. // The processor should not have received the initial sync data.
  918. EXPECT_EQ(0U, GetProcessor(PREFERENCES)->GetNumUpdateResponses());
  919. // One update remains undownloaded.
  920. mock_server_->ClearUpdatesQueue();
  921. }
  922. // Tests that if type is not registered with ModelTypeRegistry (e.g. because
  923. // type's LoadModels failed), Syncer::ConfigureSyncShare runs without triggering
  924. // DCHECK.
  925. TEST_F(SyncerTest, ConfigureFailedUnregisteredType) {
  926. // Simulate type being unregistered before configuration by including type
  927. // that isn't registered with ModelTypeRegistry.
  928. SyncShareConfigureTypes(ModelTypeSet(APPS));
  929. // No explicit verification, DCHECK shouldn't have been triggered.
  930. }
  931. TEST_F(SyncerTest, GetKeySuccess) {
  932. KeystoreKeysHandler* keystore_keys_handler =
  933. model_type_registry_->keystore_keys_handler();
  934. EXPECT_TRUE(keystore_keys_handler->NeedKeystoreKey());
  935. SyncShareConfigure();
  936. EXPECT_EQ(SyncerError::SYNCER_OK,
  937. cycle_->status_controller().last_get_key_result().value());
  938. EXPECT_FALSE(keystore_keys_handler->NeedKeystoreKey());
  939. }
  940. TEST_F(SyncerTest, GetKeyEmpty) {
  941. KeystoreKeysHandler* keystore_keys_handler =
  942. model_type_registry_->keystore_keys_handler();
  943. EXPECT_TRUE(keystore_keys_handler->NeedKeystoreKey());
  944. mock_server_->SetKeystoreKey(std::string());
  945. SyncShareConfigure();
  946. EXPECT_NE(SyncerError::SYNCER_OK,
  947. cycle_->status_controller().last_get_key_result().value());
  948. EXPECT_TRUE(keystore_keys_handler->NeedKeystoreKey());
  949. }
  950. // Verify that commit only types are never requested in GetUpdates, but still
  951. // make it into the commit messages. Additionally, make sure failing GU types
  952. // are correctly removed before commit.
  953. TEST_F(SyncerTest, CommitOnlyTypes) {
  954. mock_server_->set_partial_failure(true);
  955. mock_server_->SetPartialFailureTypes(ModelTypeSet(PREFERENCES));
  956. EnableDatatype(USER_EVENTS);
  957. GetProcessor(PREFERENCES)
  958. ->AppendCommitRequest(ClientTagHash::FromHashed("tag1"),
  959. MakeSpecifics(PREFERENCES), "id1");
  960. GetProcessor(EXTENSIONS)
  961. ->AppendCommitRequest(ClientTagHash::FromHashed("tag2"),
  962. MakeSpecifics(EXTENSIONS), "id2");
  963. GetProcessor(USER_EVENTS)
  964. ->AppendCommitRequest(ClientTagHash::FromHashed("tag3"),
  965. MakeSpecifics(USER_EVENTS), "id3");
  966. EXPECT_TRUE(SyncShareNudge());
  967. ASSERT_EQ(2U, mock_server_->requests().size());
  968. ASSERT_TRUE(mock_server_->requests()[0].has_get_updates());
  969. // MockConnectionManager will ensure USER_EVENTS was not included in the GU.
  970. EXPECT_EQ(
  971. 4, mock_server_->requests()[0].get_updates().from_progress_marker_size());
  972. ASSERT_TRUE(mock_server_->requests()[1].has_commit());
  973. const sync_pb::CommitMessage commit = mock_server_->requests()[1].commit();
  974. EXPECT_EQ(2, commit.entries_size());
  975. EXPECT_TRUE(commit.entries(0).specifics().has_extension());
  976. EXPECT_TRUE(commit.entries(1).specifics().has_user_event());
  977. }
  978. enum {
  979. TEST_PARAM_BOOKMARK_ENABLE_BIT,
  980. TEST_PARAM_AUTOFILL_ENABLE_BIT,
  981. TEST_PARAM_BIT_COUNT
  982. };
  983. class MixedResult : public SyncerTest,
  984. public ::testing::WithParamInterface<int> {
  985. protected:
  986. bool ShouldFailBookmarkCommit() {
  987. return (GetParam() & (1 << TEST_PARAM_BOOKMARK_ENABLE_BIT)) == 0;
  988. }
  989. bool ShouldFailAutofillCommit() {
  990. return (GetParam() & (1 << TEST_PARAM_AUTOFILL_ENABLE_BIT)) == 0;
  991. }
  992. };
  993. INSTANTIATE_TEST_SUITE_P(ExtensionsActivity,
  994. MixedResult,
  995. testing::Range(0, 1 << TEST_PARAM_BIT_COUNT));
  996. TEST_P(MixedResult, ExtensionsActivity) {
  997. GetProcessor(PREFERENCES)
  998. ->AppendCommitRequest(ClientTagHash::FromHashed("pref1"),
  999. MakeSpecifics(PREFERENCES), "prefid1");
  1000. GetProcessor(BOOKMARKS)->AppendCommitRequest(
  1001. ClientTagHash::FromHashed("bookmark1"), MakeBookmarkSpecificsToCommit(),
  1002. "bookmarkid2");
  1003. if (ShouldFailBookmarkCommit()) {
  1004. mock_server_->SetTransientErrorId("bookmarkid2");
  1005. }
  1006. if (ShouldFailAutofillCommit()) {
  1007. mock_server_->SetTransientErrorId("prefid1");
  1008. }
  1009. // Put some extensions activity records into the monitor.
  1010. {
  1011. ExtensionsActivity::Records records;
  1012. records["ABC"].extension_id = "ABC";
  1013. records["ABC"].bookmark_write_count = 2049U;
  1014. records["xyz"].extension_id = "xyz";
  1015. records["xyz"].bookmark_write_count = 4U;
  1016. context_->extensions_activity()->PutRecords(records);
  1017. }
  1018. EXPECT_EQ(!ShouldFailBookmarkCommit() && !ShouldFailAutofillCommit(),
  1019. SyncShareNudge());
  1020. ExtensionsActivity::Records final_monitor_records;
  1021. context_->extensions_activity()->GetAndClearRecords(&final_monitor_records);
  1022. if (ShouldFailBookmarkCommit()) {
  1023. ASSERT_EQ(2U, final_monitor_records.size())
  1024. << "Should restore records after unsuccessful bookmark commit.";
  1025. EXPECT_EQ("ABC", final_monitor_records["ABC"].extension_id);
  1026. EXPECT_EQ("xyz", final_monitor_records["xyz"].extension_id);
  1027. EXPECT_EQ(2049U, final_monitor_records["ABC"].bookmark_write_count);
  1028. EXPECT_EQ(4U, final_monitor_records["xyz"].bookmark_write_count);
  1029. } else {
  1030. EXPECT_TRUE(final_monitor_records.empty())
  1031. << "Should not restore records after successful bookmark commit.";
  1032. }
  1033. }
  1034. } // namespace syncer