12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238 |
- // Copyright 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "components/sync/engine/syncer.h"
- #include <stddef.h>
- #include <algorithm>
- #include <limits>
- #include <list>
- #include <map>
- #include <memory>
- #include <set>
- #include <string>
- #include <utility>
- #include <vector>
- #include "base/bind.h"
- #include "base/callback_helpers.h"
- #include "base/compiler_specific.h"
- #include "base/location.h"
- #include "base/memory/raw_ptr.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/strings/stringprintf.h"
- #include "base/test/metrics/histogram_tester.h"
- #include "base/test/scoped_feature_list.h"
- #include "base/test/task_environment.h"
- #include "base/time/time.h"
- #include "build/build_config.h"
- #include "components/sync/base/client_tag_hash.h"
- #include "components/sync/base/extensions_activity.h"
- #include "components/sync/base/features.h"
- #include "components/sync/base/time.h"
- #include "components/sync/base/unique_position.h"
- #include "components/sync/engine/active_devices_invalidation_info.h"
- #include "components/sync/engine/backoff_delay_provider.h"
- #include "components/sync/engine/cancelation_signal.h"
- #include "components/sync/engine/cycle/mock_debug_info_getter.h"
- #include "components/sync/engine/cycle/sync_cycle_context.h"
- #include "components/sync/engine/data_type_activation_response.h"
- #include "components/sync/engine/forwarding_model_type_processor.h"
- #include "components/sync/engine/net/server_connection_manager.h"
- #include "components/sync/engine/nigori/keystore_keys_handler.h"
- #include "components/sync/engine/sync_scheduler_impl.h"
- #include "components/sync/engine/syncer_proto_util.h"
- #include "components/sync/protocol/bookmark_specifics.pb.h"
- #include "components/sync/protocol/client_commands.pb.h"
- #include "components/sync/protocol/entity_specifics.pb.h"
- #include "components/sync/protocol/preference_specifics.pb.h"
- #include "components/sync/protocol/sync.pb.h"
- #include "components/sync/protocol/sync_enums.pb.h"
- #include "components/sync/test/fake_sync_encryption_handler.h"
- #include "components/sync/test/mock_connection_manager.h"
- #include "components/sync/test/mock_model_type_processor.h"
- #include "components/sync/test/mock_nudge_handler.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace syncer {
- namespace {
- using testing::ElementsAre;
- using testing::IsEmpty;
- using testing::UnorderedElementsAre;
- sync_pb::EntitySpecifics MakeSpecifics(ModelType model_type) {
- sync_pb::EntitySpecifics specifics;
- AddDefaultFieldValue(model_type, &specifics);
- return specifics;
- }
- sync_pb::EntitySpecifics MakeBookmarkSpecificsToCommit() {
- sync_pb::EntitySpecifics specifics = MakeSpecifics(BOOKMARKS);
- // The worker DCHECKs for the validity of the |type| and |unique_position|
- // fields for outgoing commits.
- specifics.mutable_bookmark()->set_type(sync_pb::BookmarkSpecifics::URL);
- *specifics.mutable_bookmark()->mutable_unique_position() =
- UniquePosition::InitialPosition(UniquePosition::RandomSuffix()).ToProto();
- return specifics;
- }
- } // namespace
- // Syncer unit tests. Unfortunately a lot of these tests
- // are outdated and need to be reworked and updated.
- class SyncerTest : public testing::Test,
- public SyncCycle::Delegate,
- public SyncEngineEventListener {
- public:
- SyncerTest() = default;
- SyncerTest(const SyncerTest&) = delete;
- SyncerTest& operator=(const SyncerTest&) = delete;
- // SyncCycle::Delegate implementation.
- void OnThrottled(const base::TimeDelta& throttle_duration) override {
- FAIL() << "Should not get silenced.";
- }
- void OnTypesThrottled(ModelTypeSet types,
- const base::TimeDelta& throttle_duration) override {
- scheduler_->OnTypesThrottled(types, throttle_duration);
- }
- void OnTypesBackedOff(ModelTypeSet types) override {
- scheduler_->OnTypesBackedOff(types);
- }
- bool IsAnyThrottleOrBackoff() override { return false; }
- void OnReceivedPollIntervalUpdate(
- const base::TimeDelta& new_interval) override {
- last_poll_interval_received_ = new_interval;
- }
- void OnReceivedCustomNudgeDelays(
- const std::map<ModelType, base::TimeDelta>& delay_map) override {
- auto iter = delay_map.find(SESSIONS);
- if (iter != delay_map.end() && iter->second.is_positive())
- last_sessions_commit_delay_ = iter->second;
- iter = delay_map.find(BOOKMARKS);
- if (iter != delay_map.end() && iter->second.is_positive())
- last_bookmarks_commit_delay_ = iter->second;
- }
- void OnReceivedClientInvalidationHintBufferSize(int size) override {
- last_client_invalidation_hint_buffer_size_ = size;
- }
- void OnReceivedGuRetryDelay(const base::TimeDelta& delay) override {}
- void OnReceivedMigrationRequest(ModelTypeSet types) override {}
- void OnReceivedQuotaParamsForExtensionTypes(
- absl::optional<int> max_tokens,
- absl::optional<base::TimeDelta> refill_interval,
- absl::optional<base::TimeDelta> depleted_quota_nudge_delay) override {}
- void OnProtocolEvent(const ProtocolEvent& event) override {}
- void OnSyncProtocolError(const SyncProtocolError& error) override {}
- void OnSyncCycleEvent(const SyncCycleEvent& event) override {
- DVLOG(1) << "HandleSyncEngineEvent in unittest " << event.what_happened;
- }
- void OnActionableError(const SyncProtocolError& error) override {}
- void OnRetryTimeChanged(base::Time retry_time) override {}
- void OnThrottledTypesChanged(ModelTypeSet throttled_types) override {}
- void OnBackedOffTypesChanged(ModelTypeSet backed_off_types) override {}
- void OnMigrationRequested(ModelTypeSet types) override {}
- void ResetCycle() {
- cycle_ = std::make_unique<SyncCycle>(context_.get(), this);
- }
- bool SyncShareNudge() {
- ResetCycle();
- // Pretend we've seen a local change, to make the nudge_tracker look normal.
- nudge_tracker_.RecordLocalChange(BOOKMARKS);
- return syncer_->NormalSyncShare(context_->GetConnectedTypes(),
- &nudge_tracker_, cycle_.get());
- }
- bool SyncShareConfigure() {
- return SyncShareConfigureTypes(context_->GetConnectedTypes());
- }
- bool SyncShareConfigureTypes(ModelTypeSet types) {
- ResetCycle();
- return syncer_->ConfigureSyncShare(
- types, sync_pb::SyncEnums::RECONFIGURATION, cycle_.get());
- }
- void SetUp() override {
- mock_server_ = std::make_unique<MockConnectionManager>();
- debug_info_getter_ = std::make_unique<MockDebugInfoGetter>();
- std::vector<SyncEngineEventListener*> listeners;
- listeners.push_back(this);
- model_type_registry_ = std::make_unique<ModelTypeRegistry>(
- &mock_nudge_handler_, &cancelation_signal_, &encryption_handler_);
- EnableDatatype(BOOKMARKS);
- EnableDatatype(EXTENSIONS);
- EnableDatatype(NIGORI);
- EnableDatatype(PREFERENCES);
- context_ = std::make_unique<SyncCycleContext>(
- mock_server_.get(), extensions_activity_.get(), listeners,
- debug_info_getter_.get(), model_type_registry_.get(),
- "fake_invalidator_client_id", local_cache_guid(),
- mock_server_->store_birthday(), "fake_bag_of_chips",
- /*poll_interval=*/base::Minutes(30));
- auto syncer = std::make_unique<Syncer>(&cancelation_signal_);
- // The syncer is destroyed with the scheduler that owns it.
- syncer_ = syncer.get();
- scheduler_ = std::make_unique<SyncSchedulerImpl>(
- "TestSyncScheduler", BackoffDelayProvider::FromDefaults(),
- context_.get(), std::move(syncer), false);
- mock_server_->SetKeystoreKey("encryption_key");
- }
- void TearDown() override {
- mock_server_.reset();
- scheduler_.reset();
- }
- const std::string local_cache_guid() { return "lD16ebCGCZh+zkiZ68gWDw=="; }
- const std::string foreign_cache_guid() { return "kqyg7097kro6GSUod+GSg=="; }
- MockModelTypeProcessor* GetProcessor(ModelType model_type) {
- return &mock_model_type_processors_[model_type];
- }
- std::unique_ptr<DataTypeActivationResponse> MakeFakeActivationResponse(
- ModelType model_type) {
- auto response = std::make_unique<DataTypeActivationResponse>();
- response->model_type_state.set_initial_sync_done(true);
- response->model_type_state.mutable_progress_marker()->set_data_type_id(
- GetSpecificsFieldNumberFromModelType(model_type));
- response->type_processor = std::make_unique<ForwardingModelTypeProcessor>(
- GetProcessor(model_type));
- return response;
- }
- void EnableDatatype(ModelType model_type) {
- enabled_datatypes_.Put(model_type);
- model_type_registry_->ConnectDataType(
- model_type, MakeFakeActivationResponse(model_type));
- mock_server_->ExpectGetUpdatesRequestTypes(enabled_datatypes_);
- }
- void DisableDatatype(ModelType model_type) {
- enabled_datatypes_.Remove(model_type);
- model_type_registry_->DisconnectDataType(model_type);
- mock_server_->ExpectGetUpdatesRequestTypes(enabled_datatypes_);
- }
- // Configures SyncCycleContext and NudgeTracker so Syncer won't call
- // GetUpdates prior to Commit. This method can be used to ensure a Commit is
- // not preceeded by GetUpdates.
- void ConfigureNoGetUpdatesRequired() {
- nudge_tracker_.OnInvalidationsEnabled();
- nudge_tracker_.RecordSuccessfulSyncCycle(ModelTypeSet::All());
- ASSERT_FALSE(nudge_tracker_.IsGetUpdatesRequired(ModelTypeSet::All()));
- }
- protected:
- base::test::SingleThreadTaskEnvironment task_environment_;
- FakeSyncEncryptionHandler encryption_handler_;
- scoped_refptr<ExtensionsActivity> extensions_activity_ =
- new ExtensionsActivity;
- std::unique_ptr<MockConnectionManager> mock_server_;
- CancelationSignal cancelation_signal_;
- std::map<ModelType, MockModelTypeProcessor> mock_model_type_processors_;
- raw_ptr<Syncer> syncer_ = nullptr;
- std::unique_ptr<SyncCycle> cycle_;
- MockNudgeHandler mock_nudge_handler_;
- std::unique_ptr<ModelTypeRegistry> model_type_registry_;
- std::unique_ptr<SyncSchedulerImpl> scheduler_;
- std::unique_ptr<SyncCycleContext> context_;
- base::TimeDelta last_poll_interval_received_;
- base::TimeDelta last_sessions_commit_delay_;
- base::TimeDelta last_bookmarks_commit_delay_;
- int last_client_invalidation_hint_buffer_size_ = 10;
- ModelTypeSet enabled_datatypes_;
- NudgeTracker nudge_tracker_;
- std::unique_ptr<MockDebugInfoGetter> debug_info_getter_;
- };
- TEST_F(SyncerTest, CommitFiltersThrottledEntries) {
- const ModelTypeSet throttled_types(BOOKMARKS);
- GetProcessor(BOOKMARKS)->AppendCommitRequest(
- ClientTagHash::FromHashed("tag1"), MakeBookmarkSpecificsToCommit(),
- "id1");
- // Sync without enabling bookmarks.
- mock_server_->ExpectGetUpdatesRequestTypes(
- Difference(context_->GetConnectedTypes(), throttled_types));
- ResetCycle();
- syncer_->NormalSyncShare(
- Difference(context_->GetConnectedTypes(), throttled_types),
- &nudge_tracker_, cycle_.get());
- // Nothing should have been committed as bookmarks is throttled.
- EXPECT_EQ(0, GetProcessor(BOOKMARKS)->GetLocalChangesCallCount());
- // Sync again with bookmarks enabled.
- mock_server_->ExpectGetUpdatesRequestTypes(context_->GetConnectedTypes());
- EXPECT_TRUE(SyncShareNudge());
- EXPECT_EQ(1, GetProcessor(BOOKMARKS)->GetLocalChangesCallCount());
- }
- TEST_F(SyncerTest, GetUpdatesPartialThrottled) {
- const sync_pb::EntitySpecifics bookmark = MakeSpecifics(BOOKMARKS);
- const sync_pb::EntitySpecifics pref = MakeSpecifics(PREFERENCES);
- // Normal sync, all the data types should get synced.
- mock_server_->AddUpdateSpecifics("1", "0", "A", 10, 10, true, bookmark,
- foreign_cache_guid(), "-1");
- mock_server_->AddUpdateSpecifics("2", "1", "B", 10, 10, false, bookmark,
- foreign_cache_guid(), "-2");
- mock_server_->AddUpdateSpecifics("3", "1", "C", 10, 10, false, bookmark,
- foreign_cache_guid(), "-3");
- mock_server_->AddUpdateSpecifics("4", "0", "D", 10, 10, false, pref);
- EXPECT_TRUE(SyncShareNudge());
- // Initial state. Everything is normal.
- ASSERT_EQ(1U, GetProcessor(BOOKMARKS)->GetNumUpdateResponses());
- ASSERT_EQ(3U, GetProcessor(BOOKMARKS)->GetNthUpdateResponse(0).size());
- ASSERT_EQ(1U, GetProcessor(PREFERENCES)->GetNumUpdateResponses());
- ASSERT_EQ(1U, GetProcessor(PREFERENCES)->GetNthUpdateResponse(0).size());
- // Set BOOKMARKS throttled but PREFERENCES not,
- // then BOOKMARKS should not get synced but PREFERENCES should.
- ModelTypeSet throttled_types(BOOKMARKS);
- mock_server_->set_throttling(true);
- mock_server_->SetPartialFailureTypes(throttled_types);
- mock_server_->AddUpdateSpecifics("1", "0", "E", 20, 20, true, bookmark,
- foreign_cache_guid(), "-1");
- mock_server_->AddUpdateSpecifics("2", "1", "F", 20, 20, false, bookmark,
- foreign_cache_guid(), "-2");
- mock_server_->AddUpdateSpecifics("3", "1", "G", 20, 20, false, bookmark,
- foreign_cache_guid(), "-3");
- mock_server_->AddUpdateSpecifics("4", "0", "H", 20, 20, false, pref);
- EXPECT_TRUE(SyncShareNudge());
- // PREFERENCES continues to work normally (not throttled).
- ASSERT_EQ(2U, GetProcessor(PREFERENCES)->GetNumUpdateResponses());
- // BOOKMARKS throttled.
- EXPECT_EQ(1U, GetProcessor(BOOKMARKS)->GetNumUpdateResponses());
- // Unthrottled BOOKMARKS, then BOOKMARKS should get synced now.
- mock_server_->set_throttling(false);
- mock_server_->AddUpdateSpecifics("1", "0", "E", 30, 30, true, bookmark,
- foreign_cache_guid(), "-1");
- mock_server_->AddUpdateSpecifics("2", "1", "F", 30, 30, false, bookmark,
- foreign_cache_guid(), "-2");
- mock_server_->AddUpdateSpecifics("3", "1", "G", 30, 30, false, bookmark,
- foreign_cache_guid(), "-3");
- mock_server_->AddUpdateSpecifics("4", "0", "H", 30, 30, false, pref);
- EXPECT_TRUE(SyncShareNudge());
- // BOOKMARKS unthrottled.
- EXPECT_EQ(2U, GetProcessor(BOOKMARKS)->GetNumUpdateResponses());
- }
- TEST_F(SyncerTest, GetUpdatesPartialFailure) {
- const sync_pb::EntitySpecifics bookmark = MakeSpecifics(BOOKMARKS);
- const sync_pb::EntitySpecifics pref = MakeSpecifics(PREFERENCES);
- // Normal sync, all the data types should get synced.
- mock_server_->AddUpdateSpecifics("1", "0", "A", 10, 10, true, bookmark,
- foreign_cache_guid(), "-1");
- mock_server_->AddUpdateSpecifics("2", "1", "B", 10, 10, false, bookmark,
- foreign_cache_guid(), "-2");
- mock_server_->AddUpdateSpecifics("3", "1", "C", 10, 10, false, bookmark,
- foreign_cache_guid(), "-3");
- mock_server_->AddUpdateSpecifics("4", "0", "D", 10, 10, false, pref);
- EXPECT_TRUE(SyncShareNudge());
- // Initial state. Everything is normal.
- ASSERT_EQ(1U, GetProcessor(BOOKMARKS)->GetNumUpdateResponses());
- ASSERT_EQ(3U, GetProcessor(BOOKMARKS)->GetNthUpdateResponse(0).size());
- ASSERT_EQ(1U, GetProcessor(PREFERENCES)->GetNumUpdateResponses());
- ASSERT_EQ(1U, GetProcessor(PREFERENCES)->GetNthUpdateResponse(0).size());
- // Set BOOKMARKS failure but PREFERENCES not,
- // then BOOKMARKS should not get synced but PREFERENCES should.
- ModelTypeSet failed_types(BOOKMARKS);
- mock_server_->set_partial_failure(true);
- mock_server_->SetPartialFailureTypes(failed_types);
- mock_server_->AddUpdateSpecifics("1", "0", "E", 20, 20, true, bookmark,
- foreign_cache_guid(), "-1");
- mock_server_->AddUpdateSpecifics("2", "1", "F", 20, 20, false, bookmark,
- foreign_cache_guid(), "-2");
- mock_server_->AddUpdateSpecifics("3", "1", "G", 20, 20, false, bookmark,
- foreign_cache_guid(), "-3");
- mock_server_->AddUpdateSpecifics("4", "0", "H", 20, 20, false, pref);
- EXPECT_TRUE(SyncShareNudge());
- // PREFERENCES continues to work normally (not throttled).
- ASSERT_EQ(2U, GetProcessor(PREFERENCES)->GetNumUpdateResponses());
- // BOOKMARKS failed.
- EXPECT_EQ(1U, GetProcessor(BOOKMARKS)->GetNumUpdateResponses());
- // Set BOOKMARKS not partial failed, then BOOKMARKS should get synced now.
- mock_server_->set_partial_failure(false);
- mock_server_->AddUpdateSpecifics("1", "0", "E", 30, 30, true, bookmark,
- foreign_cache_guid(), "-1");
- mock_server_->AddUpdateSpecifics("2", "1", "F", 30, 30, false, bookmark,
- foreign_cache_guid(), "-2");
- mock_server_->AddUpdateSpecifics("3", "1", "G", 30, 30, false, bookmark,
- foreign_cache_guid(), "-3");
- mock_server_->AddUpdateSpecifics("4", "0", "H", 30, 30, false, pref);
- EXPECT_TRUE(SyncShareNudge());
- // BOOKMARKS not failed.
- EXPECT_EQ(2U, GetProcessor(BOOKMARKS)->GetNumUpdateResponses());
- }
- TEST_F(SyncerTest, TestSimpleCommit) {
- const std::string kSyncId1 = "id1";
- const std::string kSyncId2 = "id2";
- GetProcessor(PREFERENCES)
- ->AppendCommitRequest(ClientTagHash::FromHashed("tag1"),
- MakeSpecifics(PREFERENCES), kSyncId1);
- GetProcessor(PREFERENCES)
- ->AppendCommitRequest(ClientTagHash::FromHashed("tag2"),
- MakeSpecifics(PREFERENCES), kSyncId2);
- EXPECT_TRUE(SyncShareNudge());
- EXPECT_THAT(mock_server_->committed_ids(),
- UnorderedElementsAre(kSyncId1, kSyncId2));
- }
- TEST_F(SyncerTest, TestSimpleGetUpdates) {
- std::string id = "some_id";
- std::string parent_id = "0";
- std::string name = "in_root";
- int64_t version = 10;
- int64_t timestamp = 10;
- mock_server_->AddUpdateDirectory(id, parent_id, name, version, timestamp,
- foreign_cache_guid(), "-1");
- EXPECT_TRUE(SyncShareNudge());
- ASSERT_EQ(1U, GetProcessor(BOOKMARKS)->GetNumUpdateResponses());
- std::vector<const UpdateResponseData*> updates_list =
- GetProcessor(BOOKMARKS)->GetNthUpdateResponse(0);
- EXPECT_EQ(1U, updates_list.size());
- const UpdateResponseData& update = *updates_list.back();
- const EntityData& entity = update.entity;
- EXPECT_EQ(id, entity.id);
- EXPECT_EQ(version, update.response_version);
- // Creation time hardcoded in MockConnectionManager::AddUpdateMeta().
- EXPECT_EQ(ProtoTimeToTime(1), entity.creation_time);
- EXPECT_EQ(ProtoTimeToTime(timestamp), entity.modification_time);
- EXPECT_EQ(name, entity.name);
- EXPECT_FALSE(entity.is_deleted());
- }
- // Committing more than kDefaultMaxCommitBatchSize items requires that
- // we post more than one commit command to the server. This test makes
- // sure that scenario works as expected.
- TEST_F(SyncerTest, CommitManyItemsInOneGo_Success) {
- int num_batches = 3;
- int items_to_commit = kDefaultMaxCommitBatchSize * num_batches;
- for (int i = 0; i < items_to_commit; i++) {
- GetProcessor(PREFERENCES)
- ->AppendCommitRequest(
- ClientTagHash::FromHashed(base::StringPrintf("tag%d", i)),
- MakeSpecifics(PREFERENCES));
- }
- EXPECT_TRUE(SyncShareNudge());
- EXPECT_EQ(static_cast<size_t>(num_batches),
- mock_server_->commit_messages().size());
- ASSERT_EQ(static_cast<size_t>(num_batches),
- GetProcessor(PREFERENCES)->GetNumCommitResponses());
- EXPECT_EQ(static_cast<size_t>(kDefaultMaxCommitBatchSize),
- GetProcessor(PREFERENCES)->GetNthCommitResponse(0).size());
- EXPECT_EQ(static_cast<size_t>(kDefaultMaxCommitBatchSize),
- GetProcessor(PREFERENCES)->GetNthCommitResponse(1).size());
- EXPECT_EQ(static_cast<size_t>(kDefaultMaxCommitBatchSize),
- GetProcessor(PREFERENCES)->GetNthCommitResponse(2).size());
- }
- // Test that a single failure to contact the server will cause us to exit the
- // commit loop immediately.
- TEST_F(SyncerTest, CommitManyItemsInOneGo_PostBufferFail) {
- int num_batches = 3;
- int items_to_commit = kDefaultMaxCommitBatchSize * num_batches;
- for (int i = 0; i < items_to_commit; i++) {
- GetProcessor(PREFERENCES)
- ->AppendCommitRequest(
- ClientTagHash::FromHashed(base::StringPrintf("tag%d", i)),
- MakeSpecifics(PREFERENCES));
- }
- // The second commit should fail. It will be preceded by one successful
- // GetUpdate and one succesful commit.
- mock_server_->FailNthPostBufferToPathCall(3);
- base::HistogramTester histogram_tester;
- EXPECT_FALSE(SyncShareNudge());
- EXPECT_EQ(1U, mock_server_->commit_messages().size());
- EXPECT_EQ(
- SyncerError::SYNC_SERVER_ERROR,
- cycle_->status_controller().model_neutral_state().commit_result.value());
- // Since the second batch fails, the third one should not even be gathered.
- EXPECT_EQ(2, GetProcessor(PREFERENCES)->GetLocalChangesCallCount());
- histogram_tester.ExpectBucketCount("Sync.CommitResponse.PREFERENCE",
- SyncerError::SYNC_SERVER_ERROR,
- /*expected_count=*/1);
- histogram_tester.ExpectBucketCount("Sync.CommitResponse",
- SyncerError::SYNC_SERVER_ERROR,
- /*expected_count=*/1);
- }
- // Test that a single conflict response from the server will cause us to exit
- // the commit loop immediately.
- TEST_F(SyncerTest, CommitManyItemsInOneGo_CommitConflict) {
- int num_batches = 2;
- int items_to_commit = kDefaultMaxCommitBatchSize * num_batches;
- for (int i = 0; i < items_to_commit; i++) {
- GetProcessor(PREFERENCES)
- ->AppendCommitRequest(
- ClientTagHash::FromHashed(base::StringPrintf("tag%d", i)),
- MakeSpecifics(PREFERENCES));
- }
- // Return a CONFLICT response for the first item.
- mock_server_->set_conflict_n_commits(1);
- EXPECT_FALSE(SyncShareNudge());
- // We should stop looping at the first sign of trouble.
- EXPECT_EQ(1U, mock_server_->commit_messages().size());
- EXPECT_EQ(1, GetProcessor(PREFERENCES)->GetLocalChangesCallCount());
- }
- // Tests that sending debug info events works.
- TEST_F(SyncerTest, SendDebugInfoEventsOnGetUpdates_HappyCase) {
- debug_info_getter_->AddDebugEvent();
- debug_info_getter_->AddDebugEvent();
- EXPECT_TRUE(SyncShareNudge());
- // Verify we received one GetUpdates request with two debug info events.
- EXPECT_EQ(1U, mock_server_->requests().size());
- ASSERT_TRUE(mock_server_->last_request().has_get_updates());
- EXPECT_EQ(2, mock_server_->last_request().debug_info().events_size());
- EXPECT_TRUE(SyncShareNudge());
- // See that we received another GetUpdates request, but that it contains no
- // debug info events.
- EXPECT_EQ(2U, mock_server_->requests().size());
- ASSERT_TRUE(mock_server_->last_request().has_get_updates());
- EXPECT_EQ(0, mock_server_->last_request().debug_info().events_size());
- debug_info_getter_->AddDebugEvent();
- EXPECT_TRUE(SyncShareNudge());
- // See that we received another GetUpdates request and it contains one debug
- // info event.
- EXPECT_EQ(3U, mock_server_->requests().size());
- ASSERT_TRUE(mock_server_->last_request().has_get_updates());
- EXPECT_EQ(1, mock_server_->last_request().debug_info().events_size());
- }
- // Tests that debug info events are dropped on server error.
- TEST_F(SyncerTest, SendDebugInfoEventsOnGetUpdates_PostFailsDontDrop) {
- debug_info_getter_->AddDebugEvent();
- debug_info_getter_->AddDebugEvent();
- mock_server_->FailNextPostBufferToPathCall();
- EXPECT_FALSE(SyncShareNudge());
- // Verify we attempted to send one GetUpdates request with two debug info
- // events.
- EXPECT_EQ(1U, mock_server_->requests().size());
- ASSERT_TRUE(mock_server_->last_request().has_get_updates());
- EXPECT_EQ(2, mock_server_->last_request().debug_info().events_size());
- EXPECT_TRUE(SyncShareNudge());
- // See that the client resent the two debug info events.
- EXPECT_EQ(2U, mock_server_->requests().size());
- ASSERT_TRUE(mock_server_->last_request().has_get_updates());
- EXPECT_EQ(2, mock_server_->last_request().debug_info().events_size());
- // The previous send was successful so this next one shouldn't generate any
- // debug info events.
- EXPECT_TRUE(SyncShareNudge());
- EXPECT_EQ(3U, mock_server_->requests().size());
- ASSERT_TRUE(mock_server_->last_request().has_get_updates());
- EXPECT_EQ(0, mock_server_->last_request().debug_info().events_size());
- }
- // Tests that commit failure with conflict will trigger GetUpdates for next
- // cycle of sync
- TEST_F(SyncerTest, CommitFailureWithConflict) {
- ConfigureNoGetUpdatesRequired();
- GetProcessor(PREFERENCES)
- ->AppendCommitRequest(ClientTagHash::FromHashed("tag1"),
- MakeSpecifics(PREFERENCES), "id1");
- EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired(ModelTypeSet::All()));
- EXPECT_TRUE(SyncShareNudge());
- EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired(ModelTypeSet::All()));
- GetProcessor(PREFERENCES)
- ->AppendCommitRequest(ClientTagHash::FromHashed("tag1"),
- MakeSpecifics(PREFERENCES), "id1");
- mock_server_->set_conflict_n_commits(1);
- EXPECT_FALSE(SyncShareNudge());
- EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired(ModelTypeSet::All()));
- nudge_tracker_.RecordSuccessfulSyncCycle(ModelTypeSet::All());
- EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired(ModelTypeSet::All()));
- }
- // Tests that sending debug info events on Commit works.
- TEST_F(SyncerTest, SendDebugInfoEventsOnCommit_HappyCase) {
- // Make sure GetUpdate isn't call as it would "steal" debug info events before
- // Commit has a chance to send them.
- ConfigureNoGetUpdatesRequired();
- // Generate a debug info event and trigger a commit.
- debug_info_getter_->AddDebugEvent();
- GetProcessor(PREFERENCES)
- ->AppendCommitRequest(ClientTagHash::FromHashed("tag1"),
- MakeSpecifics(PREFERENCES), "id1");
- EXPECT_TRUE(SyncShareNudge());
- // Verify that the last request received is a Commit and that it contains a
- // debug info event.
- EXPECT_EQ(1U, mock_server_->requests().size());
- ASSERT_TRUE(mock_server_->last_request().has_commit());
- EXPECT_EQ(1, mock_server_->last_request().debug_info().events_size());
- // Generate another commit, but no debug info event.
- GetProcessor(PREFERENCES)
- ->AppendCommitRequest(ClientTagHash::FromHashed("tag2"),
- MakeSpecifics(PREFERENCES), "id2");
- EXPECT_TRUE(SyncShareNudge());
- // See that it was received and contains no debug info events.
- EXPECT_EQ(2U, mock_server_->requests().size());
- ASSERT_TRUE(mock_server_->last_request().has_commit());
- EXPECT_EQ(0, mock_server_->last_request().debug_info().events_size());
- }
- // Tests that debug info events are not dropped on server error.
- TEST_F(SyncerTest, SendDebugInfoEventsOnCommit_PostFailsDontDrop) {
- // Make sure GetUpdate isn't call as it would "steal" debug info events before
- // Commit has a chance to send them.
- ConfigureNoGetUpdatesRequired();
- mock_server_->FailNextPostBufferToPathCall();
- // Generate a debug info event and trigger a commit.
- debug_info_getter_->AddDebugEvent();
- GetProcessor(PREFERENCES)
- ->AppendCommitRequest(ClientTagHash::FromHashed("tag1"),
- MakeSpecifics(PREFERENCES), "id1");
- EXPECT_FALSE(SyncShareNudge());
- // Verify that the last request sent is a Commit and that it contains a debug
- // info event.
- EXPECT_EQ(1U, mock_server_->requests().size());
- ASSERT_TRUE(mock_server_->last_request().has_commit());
- EXPECT_EQ(1, mock_server_->last_request().debug_info().events_size());
- // Try again. Because of how MockModelTypeProcessor works, commit data needs
- // to be provided again.
- GetProcessor(PREFERENCES)
- ->AppendCommitRequest(ClientTagHash::FromHashed("tag1"),
- MakeSpecifics(PREFERENCES), "id1");
- EXPECT_TRUE(SyncShareNudge());
- // Verify that we've received another Commit and that it contains a debug info
- // event (just like the previous one).
- EXPECT_EQ(2U, mock_server_->requests().size());
- ASSERT_TRUE(mock_server_->last_request().has_commit());
- EXPECT_EQ(1, mock_server_->last_request().debug_info().events_size());
- // Generate another commit and try again.
- GetProcessor(PREFERENCES)
- ->AppendCommitRequest(ClientTagHash::FromHashed("tag2"),
- MakeSpecifics(PREFERENCES), "id2");
- EXPECT_TRUE(SyncShareNudge());
- // See that it was received and contains no debug info events.
- EXPECT_EQ(3U, mock_server_->requests().size());
- ASSERT_TRUE(mock_server_->last_request().has_commit());
- EXPECT_EQ(0, mock_server_->last_request().debug_info().events_size());
- }
- TEST_F(SyncerTest, TestClientCommandDuringUpdate) {
- using sync_pb::ClientCommand;
- auto command = std::make_unique<ClientCommand>();
- command->set_set_sync_poll_interval(8);
- command->set_set_sync_long_poll_interval(800);
- command->set_sessions_commit_delay_seconds(3141);
- sync_pb::CustomNudgeDelay* bookmark_delay =
- command->add_custom_nudge_delays();
- bookmark_delay->set_datatype_id(
- GetSpecificsFieldNumberFromModelType(BOOKMARKS));
- bookmark_delay->set_delay_ms(950);
- command->set_client_invalidation_hint_buffer_size(11);
- mock_server_->AddUpdateDirectory("1", "0", "in_root", 1, 1,
- foreign_cache_guid(), "-1");
- mock_server_->SetGUClientCommand(std::move(command));
- EXPECT_TRUE(SyncShareNudge());
- EXPECT_EQ(base::Seconds(8), last_poll_interval_received_);
- EXPECT_EQ(base::Seconds(3141), last_sessions_commit_delay_);
- EXPECT_EQ(base::Milliseconds(950), last_bookmarks_commit_delay_);
- EXPECT_EQ(11, last_client_invalidation_hint_buffer_size_);
- command = std::make_unique<ClientCommand>();
- command->set_set_sync_poll_interval(180);
- command->set_set_sync_long_poll_interval(190);
- command->set_sessions_commit_delay_seconds(2718);
- bookmark_delay = command->add_custom_nudge_delays();
- bookmark_delay->set_datatype_id(
- GetSpecificsFieldNumberFromModelType(BOOKMARKS));
- bookmark_delay->set_delay_ms(1050);
- command->set_client_invalidation_hint_buffer_size(9);
- mock_server_->AddUpdateDirectory("1", "0", "in_root", 1, 1,
- foreign_cache_guid(), "-1");
- mock_server_->SetGUClientCommand(std::move(command));
- EXPECT_TRUE(SyncShareNudge());
- EXPECT_EQ(base::Seconds(180), last_poll_interval_received_);
- EXPECT_EQ(base::Seconds(2718), last_sessions_commit_delay_);
- EXPECT_EQ(base::Milliseconds(1050), last_bookmarks_commit_delay_);
- EXPECT_EQ(9, last_client_invalidation_hint_buffer_size_);
- }
- TEST_F(SyncerTest, TestClientCommandDuringCommit) {
- using sync_pb::ClientCommand;
- auto command = std::make_unique<ClientCommand>();
- command->set_set_sync_poll_interval(8);
- command->set_set_sync_long_poll_interval(800);
- command->set_sessions_commit_delay_seconds(3141);
- sync_pb::CustomNudgeDelay* bookmark_delay =
- command->add_custom_nudge_delays();
- bookmark_delay->set_datatype_id(
- GetSpecificsFieldNumberFromModelType(BOOKMARKS));
- bookmark_delay->set_delay_ms(950);
- command->set_client_invalidation_hint_buffer_size(11);
- GetProcessor(BOOKMARKS)->AppendCommitRequest(
- ClientTagHash::FromHashed("tag1"), MakeBookmarkSpecificsToCommit(),
- "id1");
- mock_server_->SetCommitClientCommand(std::move(command));
- EXPECT_TRUE(SyncShareNudge());
- EXPECT_EQ(base::Seconds(8), last_poll_interval_received_);
- EXPECT_EQ(base::Seconds(3141), last_sessions_commit_delay_);
- EXPECT_EQ(base::Milliseconds(950), last_bookmarks_commit_delay_);
- EXPECT_EQ(11, last_client_invalidation_hint_buffer_size_);
- command = std::make_unique<ClientCommand>();
- command->set_set_sync_poll_interval(180);
- command->set_set_sync_long_poll_interval(190);
- command->set_sessions_commit_delay_seconds(2718);
- bookmark_delay = command->add_custom_nudge_delays();
- bookmark_delay->set_datatype_id(
- GetSpecificsFieldNumberFromModelType(BOOKMARKS));
- bookmark_delay->set_delay_ms(1050);
- command->set_client_invalidation_hint_buffer_size(9);
- GetProcessor(BOOKMARKS)->AppendCommitRequest(
- ClientTagHash::FromHashed("tag2"), MakeBookmarkSpecificsToCommit(),
- "id2");
- mock_server_->SetCommitClientCommand(std::move(command));
- EXPECT_TRUE(SyncShareNudge());
- EXPECT_EQ(base::Seconds(180), last_poll_interval_received_);
- EXPECT_EQ(base::Seconds(2718), last_sessions_commit_delay_);
- EXPECT_EQ(base::Milliseconds(1050), last_bookmarks_commit_delay_);
- EXPECT_EQ(9, last_client_invalidation_hint_buffer_size_);
- }
- TEST_F(SyncerTest, ShouldPopulateSingleClientFlag) {
- GetProcessor(BOOKMARKS)->AppendCommitRequest(
- ClientTagHash::FromHashed("tag1"), MakeBookmarkSpecificsToCommit(),
- "id1");
- // No other devices are interested in bookmarks.
- context_->set_active_devices_invalidation_info(
- ActiveDevicesInvalidationInfo::Create(
- /*all_fcm_registration_tokens=*/{},
- /*all_interested_data_types=*/{PREFERENCES},
- /*fcm_token_and_interested_data_types=*/{}));
- ASSERT_TRUE(SyncShareNudge());
- EXPECT_TRUE(
- mock_server_->last_request().commit().config_params().single_client());
- EXPECT_TRUE(mock_server_->last_request()
- .commit()
- .config_params()
- .single_client_with_standalone_invalidations());
- }
- TEST_F(SyncerTest,
- ShouldPopulateSingleClientFlagForStandaloneInvalidationsOnly) {
- GetProcessor(BOOKMARKS)->AppendCommitRequest(
- ClientTagHash::FromHashed("tag1"), MakeBookmarkSpecificsToCommit(),
- "id1");
- // No other devices with standalone invalidations are interested in bookmarks.
- context_->set_active_devices_invalidation_info(
- ActiveDevicesInvalidationInfo::Create(
- /*all_fcm_registration_tokens=*/{"token_1"},
- /*all_interested_data_types=*/{BOOKMARKS, PREFERENCES},
- /*fcm_token_and_interested_data_types=*/
- {{"token_1", {PREFERENCES}}}));
- ASSERT_TRUE(SyncShareNudge());
- EXPECT_FALSE(
- mock_server_->last_request().commit().config_params().single_client());
- EXPECT_TRUE(mock_server_->last_request()
- .commit()
- .config_params()
- .single_client_with_standalone_invalidations());
- }
- TEST_F(SyncerTest, ShouldPopulateFcmRegistrationTokens) {
- GetProcessor(BOOKMARKS)->AppendCommitRequest(
- ClientTagHash::FromHashed("tag1"), MakeBookmarkSpecificsToCommit(),
- "id1");
- context_->set_active_devices_invalidation_info(
- ActiveDevicesInvalidationInfo::Create(
- {"token"}, /*all_interested_data_types=*/{BOOKMARKS},
- /*fcm_token_and_interested_data_types=*/{{"token", {BOOKMARKS}}}));
- ASSERT_TRUE(SyncShareNudge());
- EXPECT_FALSE(
- mock_server_->last_request().commit().config_params().single_client());
- EXPECT_FALSE(mock_server_->last_request()
- .commit()
- .config_params()
- .single_client_with_standalone_invalidations());
- EXPECT_THAT(mock_server_->last_sent_commit()
- .config_params()
- .devices_fcm_registration_tokens(),
- ElementsAre("token"));
- EXPECT_THAT(mock_server_->last_sent_commit()
- .config_params()
- .fcm_registration_tokens_for_interested_clients(),
- ElementsAre("token"));
- }
- TEST_F(SyncerTest, ShouldPopulateFcmRegistrationTokensForInterestedTypesOnly) {
- GetProcessor(BOOKMARKS)->AppendCommitRequest(
- ClientTagHash::FromHashed("tag1"), MakeBookmarkSpecificsToCommit(),
- "id1");
- context_->set_active_devices_invalidation_info(
- ActiveDevicesInvalidationInfo::Create(
- {"token_1", "token_2"}, /*all_interested_data_types=*/{BOOKMARKS},
- /*fcm_token_and_interested_data_types=*/
- {{"token_1", {BOOKMARKS}}, {"token_2", {PREFERENCES}}}));
- ASSERT_TRUE(SyncShareNudge());
- EXPECT_FALSE(
- mock_server_->last_request().commit().config_params().single_client());
- EXPECT_FALSE(mock_server_->last_request()
- .commit()
- .config_params()
- .single_client_with_standalone_invalidations());
- EXPECT_THAT(mock_server_->last_sent_commit()
- .config_params()
- .devices_fcm_registration_tokens(),
- ElementsAre("token_1", "token_2"));
- EXPECT_THAT(mock_server_->last_sent_commit()
- .config_params()
- .fcm_registration_tokens_for_interested_clients(),
- ElementsAre("token_1"));
- }
- TEST_F(SyncerTest, ShouldNotPopulateTooManyFcmRegistrationTokens) {
- std::map<std::string, ModelTypeSet> fcm_token_and_interested_data_types;
- for (size_t i = 0; i < 7; ++i) {
- fcm_token_and_interested_data_types["token_" + base::NumberToString(i)] = {
- BOOKMARKS};
- }
- GetProcessor(BOOKMARKS)->AppendCommitRequest(
- ClientTagHash::FromHashed("tag1"), MakeBookmarkSpecificsToCommit(),
- "id1");
- context_->set_active_devices_invalidation_info(
- ActiveDevicesInvalidationInfo::Create(
- {}, /*all_interested_data_types=*/{BOOKMARKS},
- std::move(fcm_token_and_interested_data_types)));
- ASSERT_TRUE(SyncShareNudge());
- EXPECT_FALSE(
- mock_server_->last_request().commit().config_params().single_client());
- EXPECT_FALSE(mock_server_->last_request()
- .commit()
- .config_params()
- .single_client_with_standalone_invalidations());
- EXPECT_THAT(mock_server_->last_sent_commit()
- .config_params()
- .devices_fcm_registration_tokens(),
- IsEmpty());
- EXPECT_THAT(mock_server_->last_sent_commit()
- .config_params()
- .fcm_registration_tokens_for_interested_clients(),
- IsEmpty());
- }
- TEST_F(SyncerTest,
- ShouldNotPopulateOptimizationFlagsIfDeviceInfoRecentlyUpdated) {
- base::test::ScopedFeatureList override_features;
- override_features.InitAndEnableFeature(
- kSkipInvalidationOptimizationsWhenDeviceInfoUpdated);
- EnableDatatype(DEVICE_INFO);
- mock_server_->AddUpdateSpecifics("id", /*parent_id=*/"", "name",
- /*version=*/1, /*sync_ts=*/10,
- /*is_dir=*/false, /*specifics=*/
- MakeSpecifics(DEVICE_INFO));
- GetProcessor(BOOKMARKS)->AppendCommitRequest(
- ClientTagHash::FromHashed("tag1"), MakeBookmarkSpecificsToCommit(),
- "id1");
- // No other devices are interested in bookmarks.
- context_->set_active_devices_invalidation_info(
- ActiveDevicesInvalidationInfo::Create(
- {"token"}, /*all_interested_data_types=*/{PREFERENCES},
- /*fcm_token_and_interested_data_types=*/{{"token", {PREFERENCES}}}));
- ASSERT_TRUE(SyncShareNudge());
- // All invalidation info should be ignored due to DeviceInfo update.
- EXPECT_FALSE(
- mock_server_->last_request().commit().config_params().single_client());
- EXPECT_FALSE(mock_server_->last_request()
- .commit()
- .config_params()
- .single_client_with_standalone_invalidations());
- EXPECT_TRUE(mock_server_->last_sent_commit()
- .config_params()
- .devices_fcm_registration_tokens()
- .empty());
- EXPECT_TRUE(mock_server_->last_sent_commit()
- .config_params()
- .fcm_registration_tokens_for_interested_clients()
- .empty());
- }
- TEST_F(SyncerTest, ClientTagServerCreatedUpdatesWork) {
- mock_server_->AddUpdateDirectory("1", "0", "permitem1", 1, 10,
- foreign_cache_guid(), "-1");
- mock_server_->SetLastUpdateClientTag("clienttag");
- EXPECT_TRUE(SyncShareNudge());
- ASSERT_EQ(1U, GetProcessor(BOOKMARKS)->GetNumUpdateResponses());
- std::vector<const UpdateResponseData*> updates_list =
- GetProcessor(BOOKMARKS)->GetNthUpdateResponse(0);
- EXPECT_EQ(1U, updates_list.size());
- const UpdateResponseData& update = *updates_list.back();
- const EntityData& entity = update.entity;
- EXPECT_EQ("permitem1", entity.name);
- EXPECT_EQ(ClientTagHash::FromHashed("clienttag"), entity.client_tag_hash);
- EXPECT_FALSE(entity.is_deleted());
- }
- TEST_F(SyncerTest, GetUpdatesSetsRequestedTypes) {
- // The expectations of this test happen in the MockConnectionManager's
- // GetUpdates handler. EnableDatatype sets the expectation value from our
- // set of enabled/disabled datatypes.
- EXPECT_TRUE(SyncShareNudge());
- EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
- EnableDatatype(AUTOFILL);
- EXPECT_TRUE(SyncShareNudge());
- EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
- DisableDatatype(BOOKMARKS);
- EXPECT_TRUE(SyncShareNudge());
- EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
- DisableDatatype(AUTOFILL);
- EXPECT_TRUE(SyncShareNudge());
- EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
- DisableDatatype(PREFERENCES);
- EnableDatatype(AUTOFILL);
- EXPECT_TRUE(SyncShareNudge());
- EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
- }
- // A typical scenario: server and client each have one update for the other.
- // This is the "happy path" alternative to UpdateFailsThenDontCommit.
- TEST_F(SyncerTest, UpdateThenCommit) {
- std::string to_receive = "some_id1";
- std::string to_commit = "some_id2";
- std::string parent_id = "0";
- mock_server_->AddUpdateDirectory(to_receive, parent_id, "x", 1, 10,
- foreign_cache_guid(), "-1");
- GetProcessor(BOOKMARKS)->AppendCommitRequest(
- ClientTagHash::FromHashed("tag1"), MakeBookmarkSpecificsToCommit(),
- to_commit);
- EXPECT_TRUE(SyncShareNudge());
- // The sync cycle should have included a GetUpdate, then a commit.
- EXPECT_TRUE(mock_server_->last_request().has_commit());
- EXPECT_THAT(mock_server_->committed_ids(), UnorderedElementsAre(to_commit));
- // The update should have been received.
- ASSERT_EQ(1U, GetProcessor(BOOKMARKS)->GetNumUpdateResponses());
- std::vector<const UpdateResponseData*> updates_list =
- GetProcessor(BOOKMARKS)->GetNthUpdateResponse(0);
- ASSERT_EQ(1U, updates_list.size());
- EXPECT_EQ(to_receive, updates_list[0]->entity.id);
- }
- // Same as above, but this time we fail to download updates.
- // We should not attempt to commit anything unless we successfully downloaded
- // updates, otherwise we risk causing a server-side conflict.
- TEST_F(SyncerTest, UpdateFailsThenDontCommit) {
- std::string to_receive = "some_id1";
- std::string to_commit = "some_id2";
- std::string parent_id = "0";
- mock_server_->AddUpdateDirectory(to_receive, parent_id, "x", 1, 10,
- foreign_cache_guid(), "-1");
- GetProcessor(BOOKMARKS)->AppendCommitRequest(
- ClientTagHash::FromHashed("tag1"), MakeBookmarkSpecificsToCommit(),
- to_commit);
- mock_server_->FailNextPostBufferToPathCall();
- EXPECT_FALSE(SyncShareNudge());
- // We did not receive this update.
- EXPECT_EQ(0U, GetProcessor(BOOKMARKS)->GetNumUpdateResponses());
- // No commit should have been sent.
- EXPECT_FALSE(mock_server_->last_request().has_commit());
- EXPECT_THAT(mock_server_->committed_ids(), IsEmpty());
- // Inform the Mock we won't be fetching all updates.
- mock_server_->ClearUpdatesQueue();
- }
- // Downloads two updates successfully.
- // This is the "happy path" alternative to ConfigureFailsDontApplyUpdates.
- TEST_F(SyncerTest, ConfigureDownloadsTwoBatchesSuccess) {
- // Construct the first GetUpdates response.
- mock_server_->AddUpdatePref("id1", "", "one", 1, 10);
- mock_server_->SetChangesRemaining(1);
- mock_server_->NextUpdateBatch();
- // Construct the second GetUpdates response.
- mock_server_->AddUpdatePref("id2", "", "two", 2, 20);
- ASSERT_EQ(0U, GetProcessor(PREFERENCES)->GetNumUpdateResponses());
- SyncShareConfigure();
- // The type should have received the initial updates.
- EXPECT_EQ(1U, GetProcessor(PREFERENCES)->GetNumUpdateResponses());
- }
- // Same as the above case, but this time the second batch fails to download.
- TEST_F(SyncerTest, ConfigureFailsDontApplyUpdates) {
- // The scenario: we have two batches of updates with one update each. A
- // normal confgure step would download all the updates one batch at a time and
- // apply them. This configure will succeed in downloading the first batch
- // then fail when downloading the second.
- mock_server_->FailNthPostBufferToPathCall(2);
- // Construct the first GetUpdates response.
- mock_server_->AddUpdatePref("id1", "", "one", 1, 10);
- mock_server_->SetChangesRemaining(1);
- mock_server_->NextUpdateBatch();
- // Construct the second GetUpdates response.
- mock_server_->AddUpdatePref("id2", "", "two", 2, 20);
- ASSERT_EQ(0U, GetProcessor(PREFERENCES)->GetNumUpdateResponses());
- SyncShareConfigure();
- // The processor should not have received the initial sync data.
- EXPECT_EQ(0U, GetProcessor(PREFERENCES)->GetNumUpdateResponses());
- // One update remains undownloaded.
- mock_server_->ClearUpdatesQueue();
- }
- // Tests that if type is not registered with ModelTypeRegistry (e.g. because
- // type's LoadModels failed), Syncer::ConfigureSyncShare runs without triggering
- // DCHECK.
- TEST_F(SyncerTest, ConfigureFailedUnregisteredType) {
- // Simulate type being unregistered before configuration by including type
- // that isn't registered with ModelTypeRegistry.
- SyncShareConfigureTypes(ModelTypeSet(APPS));
- // No explicit verification, DCHECK shouldn't have been triggered.
- }
- TEST_F(SyncerTest, GetKeySuccess) {
- KeystoreKeysHandler* keystore_keys_handler =
- model_type_registry_->keystore_keys_handler();
- EXPECT_TRUE(keystore_keys_handler->NeedKeystoreKey());
- SyncShareConfigure();
- EXPECT_EQ(SyncerError::SYNCER_OK,
- cycle_->status_controller().last_get_key_result().value());
- EXPECT_FALSE(keystore_keys_handler->NeedKeystoreKey());
- }
- TEST_F(SyncerTest, GetKeyEmpty) {
- KeystoreKeysHandler* keystore_keys_handler =
- model_type_registry_->keystore_keys_handler();
- EXPECT_TRUE(keystore_keys_handler->NeedKeystoreKey());
- mock_server_->SetKeystoreKey(std::string());
- SyncShareConfigure();
- EXPECT_NE(SyncerError::SYNCER_OK,
- cycle_->status_controller().last_get_key_result().value());
- EXPECT_TRUE(keystore_keys_handler->NeedKeystoreKey());
- }
- // Verify that commit only types are never requested in GetUpdates, but still
- // make it into the commit messages. Additionally, make sure failing GU types
- // are correctly removed before commit.
- TEST_F(SyncerTest, CommitOnlyTypes) {
- mock_server_->set_partial_failure(true);
- mock_server_->SetPartialFailureTypes(ModelTypeSet(PREFERENCES));
- EnableDatatype(USER_EVENTS);
- GetProcessor(PREFERENCES)
- ->AppendCommitRequest(ClientTagHash::FromHashed("tag1"),
- MakeSpecifics(PREFERENCES), "id1");
- GetProcessor(EXTENSIONS)
- ->AppendCommitRequest(ClientTagHash::FromHashed("tag2"),
- MakeSpecifics(EXTENSIONS), "id2");
- GetProcessor(USER_EVENTS)
- ->AppendCommitRequest(ClientTagHash::FromHashed("tag3"),
- MakeSpecifics(USER_EVENTS), "id3");
- EXPECT_TRUE(SyncShareNudge());
- ASSERT_EQ(2U, mock_server_->requests().size());
- ASSERT_TRUE(mock_server_->requests()[0].has_get_updates());
- // MockConnectionManager will ensure USER_EVENTS was not included in the GU.
- EXPECT_EQ(
- 4, mock_server_->requests()[0].get_updates().from_progress_marker_size());
- ASSERT_TRUE(mock_server_->requests()[1].has_commit());
- const sync_pb::CommitMessage commit = mock_server_->requests()[1].commit();
- EXPECT_EQ(2, commit.entries_size());
- EXPECT_TRUE(commit.entries(0).specifics().has_extension());
- EXPECT_TRUE(commit.entries(1).specifics().has_user_event());
- }
- enum {
- TEST_PARAM_BOOKMARK_ENABLE_BIT,
- TEST_PARAM_AUTOFILL_ENABLE_BIT,
- TEST_PARAM_BIT_COUNT
- };
- class MixedResult : public SyncerTest,
- public ::testing::WithParamInterface<int> {
- protected:
- bool ShouldFailBookmarkCommit() {
- return (GetParam() & (1 << TEST_PARAM_BOOKMARK_ENABLE_BIT)) == 0;
- }
- bool ShouldFailAutofillCommit() {
- return (GetParam() & (1 << TEST_PARAM_AUTOFILL_ENABLE_BIT)) == 0;
- }
- };
- INSTANTIATE_TEST_SUITE_P(ExtensionsActivity,
- MixedResult,
- testing::Range(0, 1 << TEST_PARAM_BIT_COUNT));
- TEST_P(MixedResult, ExtensionsActivity) {
- GetProcessor(PREFERENCES)
- ->AppendCommitRequest(ClientTagHash::FromHashed("pref1"),
- MakeSpecifics(PREFERENCES), "prefid1");
- GetProcessor(BOOKMARKS)->AppendCommitRequest(
- ClientTagHash::FromHashed("bookmark1"), MakeBookmarkSpecificsToCommit(),
- "bookmarkid2");
- if (ShouldFailBookmarkCommit()) {
- mock_server_->SetTransientErrorId("bookmarkid2");
- }
- if (ShouldFailAutofillCommit()) {
- mock_server_->SetTransientErrorId("prefid1");
- }
- // Put some extensions activity records into the monitor.
- {
- ExtensionsActivity::Records records;
- records["ABC"].extension_id = "ABC";
- records["ABC"].bookmark_write_count = 2049U;
- records["xyz"].extension_id = "xyz";
- records["xyz"].bookmark_write_count = 4U;
- context_->extensions_activity()->PutRecords(records);
- }
- EXPECT_EQ(!ShouldFailBookmarkCommit() && !ShouldFailAutofillCommit(),
- SyncShareNudge());
- ExtensionsActivity::Records final_monitor_records;
- context_->extensions_activity()->GetAndClearRecords(&final_monitor_records);
- if (ShouldFailBookmarkCommit()) {
- ASSERT_EQ(2U, final_monitor_records.size())
- << "Should restore records after unsuccessful bookmark commit.";
- EXPECT_EQ("ABC", final_monitor_records["ABC"].extension_id);
- EXPECT_EQ("xyz", final_monitor_records["xyz"].extension_id);
- EXPECT_EQ(2049U, final_monitor_records["ABC"].bookmark_write_count);
- EXPECT_EQ(4U, final_monitor_records["xyz"].bookmark_write_count);
- } else {
- EXPECT_TRUE(final_monitor_records.empty())
- << "Should not restore records after successful bookmark commit.";
- }
- }
- } // namespace syncer
|