diff options
author | Ben Murdoch <benm@google.com> | 2013-07-23 11:17:05 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2013-07-23 11:17:05 +0100 |
commit | ca12bfac764ba476d6cd062bf1dde12cc64c3f40 (patch) | |
tree | 1cd09db25ea5de98e73c8efbe572e103daee8b2b /sync | |
parent | fcb3e05bdd21d752df9c3dff28b6bbf29b5b733b (diff) | |
download | chromium_org-ca12bfac764ba476d6cd062bf1dde12cc64c3f40.tar.gz |
Merge from Chromium at DEPS revision r213057
This commit was generated by merge_to_master.py.
Change-Id: I3e2e2506eb9b0080157e9c5f133559df3e600388
Diffstat (limited to 'sync')
34 files changed, 338 insertions, 34 deletions
diff --git a/sync/engine/sync_scheduler_impl.cc b/sync/engine/sync_scheduler_impl.cc index fe377d4019..3a904d1dc5 100644 --- a/sync/engine/sync_scheduler_impl.cc +++ b/sync/engine/sync_scheduler_impl.cc @@ -616,7 +616,8 @@ void SyncSchedulerImpl::UpdateNudgeTimeRecords(ModelTypeSet types) { void SyncSchedulerImpl::AdjustPolling(PollAdjustType type) { DCHECK(CalledOnValidThread()); - TimeDelta poll = (!session_context_->notifications_enabled()) ? + TimeDelta poll = (!session_context_->notifications_enabled() || + !session_context_->ShouldFetchUpdatesBeforeCommit()) ? syncer_short_poll_interval_seconds_ : syncer_long_poll_interval_seconds_; bool rate_changed = !poll_timer_.IsRunning() || diff --git a/sync/engine/sync_scheduler_unittest.cc b/sync/engine/sync_scheduler_unittest.cc index a55eb7f1bb..3fb2042fe0 100644 --- a/sync/engine/sync_scheduler_unittest.cc +++ b/sync/engine/sync_scheduler_unittest.cc @@ -150,6 +150,7 @@ class SyncSchedulerTest : public testing::Test { &extensions_activity_monitor_, std::vector<SyncEngineEventListener*>(), NULL, NULL, true, // enable keystore encryption + false, // force enable pre-commit GU avoidance "fake_invalidator_client_id")); context_->set_routing_info(routing_info_); context_->set_notifications_enabled(true); diff --git a/sync/engine/syncer.cc b/sync/engine/syncer.cc index 8ebbff1170..8005459fb8 100644 --- a/sync/engine/syncer.cc +++ b/sync/engine/syncer.cc @@ -64,14 +64,17 @@ bool Syncer::NormalSyncShare(ModelTypeSet request_types, SyncSession* session) { HandleCycleBegin(session); VLOG(1) << "Downloading types " << ModelTypeSetToString(request_types); - if (!DownloadAndApplyUpdates( - session, - base::Bind(&NormalDownloadUpdates, - session, - kCreateMobileBookmarksFolder, - request_types, - base::ConstRef(nudge_tracker)))) { - return HandleCycleEnd(session); + if (nudge_tracker.IsGetUpdatesRequired() || + session->context()->ShouldFetchUpdatesBeforeCommit()) { + if (!DownloadAndApplyUpdates( + session, + base::Bind(&NormalDownloadUpdates, + session, + kCreateMobileBookmarksFolder, + request_types, + base::ConstRef(nudge_tracker)))) { + return HandleCycleEnd(session); + } } VLOG(1) << "Committing from types " << ModelTypeSetToString(request_types); diff --git a/sync/engine/syncer_unittest.cc b/sync/engine/syncer_unittest.cc index 61f7f9b838..a2ccccfb23 100644 --- a/sync/engine/syncer_unittest.cc +++ b/sync/engine/syncer_unittest.cc @@ -239,6 +239,7 @@ class SyncerTest : public testing::Test, &extensions_activity_monitor_, listeners, NULL, &traffic_recorder_, true, // enable keystore encryption + false, // force enable pre-commit GU avoidance experiment "fake_invalidator_client_id")); context_->set_routing_info(routing_info); syncer_ = new Syncer(); diff --git a/sync/internal_api/internal_components_factory_impl.cc b/sync/internal_api/internal_components_factory_impl.cc index f4fd94232e..1cc3b112c6 100644 --- a/sync/internal_api/internal_components_factory_impl.cc +++ b/sync/internal_api/internal_components_factory_impl.cc @@ -48,6 +48,8 @@ InternalComponentsFactoryImpl::BuildContext( listeners, debug_info_getter, traffic_recorder, switches_.encryption_method == ENCRYPTION_KEYSTORE, + switches_.pre_commit_updates_policy == + FORCE_ENABLE_PRE_COMMIT_UPDATE_AVOIDANCE, invalidation_client_id)); } diff --git a/sync/internal_api/public/base/invalidation.cc b/sync/internal_api/public/base/invalidation.cc index 472fad2c3c..b503d07c4a 100644 --- a/sync/internal_api/public/base/invalidation.cc +++ b/sync/internal_api/public/base/invalidation.cc @@ -64,19 +64,23 @@ AckHandle::AckHandle(const std::string& state, base::Time timestamp) AckHandle::~AckHandle() { } +const int64 Invalidation::kUnknownVersion = -1; + Invalidation::Invalidation() - : ack_handle(AckHandle::InvalidAckHandle()) { + : version(kUnknownVersion), ack_handle(AckHandle::InvalidAckHandle()) { } Invalidation::~Invalidation() { } bool Invalidation::Equals(const Invalidation& other) const { - return (payload == other.payload) && ack_handle.Equals(other.ack_handle); + return (version == other.version) && (payload == other.payload) && + ack_handle.Equals(other.ack_handle); } scoped_ptr<base::DictionaryValue> Invalidation::ToValue() const { scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue()); + value->SetString("version", base::Int64ToString(version)); value->SetString("payload", payload); value->Set("ackHandle", ack_handle.ToValue().release()); return value.Pass(); @@ -84,6 +88,13 @@ scoped_ptr<base::DictionaryValue> Invalidation::ToValue() const { bool Invalidation::ResetFromValue(const base::DictionaryValue& value) { const base::DictionaryValue* ack_handle_value = NULL; + std::string version_as_string; + if (value.GetString("version", &version_as_string)) { + if (!base::StringToInt64(version_as_string, &version)) + return false; + } else { + version = kUnknownVersion; + } return value.GetString("payload", &payload) && value.GetDictionary("ackHandle", &ack_handle_value) && diff --git a/sync/internal_api/public/base/invalidation.h b/sync/internal_api/public/base/invalidation.h index e1e274ed13..851dbed747 100644 --- a/sync/internal_api/public/base/invalidation.h +++ b/sync/internal_api/public/base/invalidation.h @@ -43,11 +43,14 @@ class SYNC_EXPORT AckHandle { }; // Represents a local invalidation, and is roughly analogous to -// invalidation::Invalidation. It contains a payload (which may be empty) and an +// invalidation::Invalidation. It contains a version (which may be +// kUnknownVersion), a payload (which may be empty) and an // associated ack handle that an InvalidationHandler implementation can use to // acknowledge receipt of the invalidation. It does not embed the object ID, // since it is typically associated with it through ObjectIdInvalidationMap. struct SYNC_EXPORT Invalidation { + static const int64 kUnknownVersion; + Invalidation(); ~Invalidation(); @@ -56,6 +59,7 @@ struct SYNC_EXPORT Invalidation { scoped_ptr<base::DictionaryValue> ToValue() const; bool ResetFromValue(const base::DictionaryValue& value); + int64 version; std::string payload; AckHandle ack_handle; }; diff --git a/sync/internal_api/public/base/model_type.h b/sync/internal_api/public/base/model_type.h index 59f970fd86..247d351375 100644 --- a/sync/internal_api/public/base/model_type.h +++ b/sync/internal_api/public/base/model_type.h @@ -207,6 +207,14 @@ SYNC_EXPORT ModelTypeSet ControlTypes(); // See comment above for more information on what makes these types special. SYNC_EXPORT bool IsControlType(ModelType model_type); +// Core types are those data types used by sync's core functionality (i.e. not +// user data types). These types are always enabled, and include ControlTypes(). +// +// The set of all core types. +SYNC_EXPORT ModelTypeSet CoreTypes(); +// Those core types that have high priority (includes ControlTypes()). +SYNC_EXPORT ModelTypeSet PriorityCoreTypes(); + // Determine a model type from the field number of its associated // EntitySpecifics field. Returns UNSPECIFIED if the field number is // not recognized. diff --git a/sync/internal_api/public/internal_components_factory.h b/sync/internal_api/public/internal_components_factory.h index 6b79ddd2f9..96fd640737 100644 --- a/sync/internal_api/public/internal_components_factory.h +++ b/sync/internal_api/public/internal_components_factory.h @@ -50,6 +50,16 @@ class SYNC_EXPORT InternalComponentsFactory { BACKOFF_SHORT_INITIAL_RETRY_OVERRIDE }; + enum PreCommitUpdatesPolicy { + // By default, the server will enable or disable this experiment through the + // sync protocol's experiments data type. + SERVER_CONTROLLED_PRE_COMMIT_UPDATE_AVOIANCE, + + // This flag overrides the server's decision and enables the pre-commit + // update avoidance experiment. + FORCE_ENABLE_PRE_COMMIT_UPDATE_AVOIDANCE, + }; + // Configuration options for internal components. This struct is expected // to grow and shrink over time with transient features / experiments, // roughly following command line flags in chrome. Implementations of @@ -58,6 +68,7 @@ class SYNC_EXPORT InternalComponentsFactory { struct Switches { EncryptionMethod encryption_method; BackoffOverride backoff_override; + PreCommitUpdatesPolicy pre_commit_updates_policy; }; virtual ~InternalComponentsFactory() {} diff --git a/sync/internal_api/public/util/experiments.h b/sync/internal_api/public/util/experiments.h index 6c53e30120..144687d968 100644 --- a/sync/internal_api/public/util/experiments.h +++ b/sync/internal_api/public/util/experiments.h @@ -11,6 +11,7 @@ namespace syncer { const char kAutofillCullingTag[] = "autofill_culling"; const char kFaviconSyncTag[] = "favicon_sync"; +const char kPreCommitUpdateAvoidanceTag[] = "pre_commit_update_avoidance"; // A structure to hold the enable status of experimental sync features. struct Experiments { diff --git a/sync/internal_api/sync_manager_impl.cc b/sync/internal_api/sync_manager_impl.cc index e9eeea1832..3d6158d8a1 100644 --- a/sync/internal_api/sync_manager_impl.cc +++ b/sync/internal_api/sync_manager_impl.cc @@ -1295,6 +1295,17 @@ bool SyncManagerImpl::ReceivedExperiment(Experiments* experiments) { found_experiment = true; } + ReadNode pre_commit_update_avoidance_node(&trans); + if (pre_commit_update_avoidance_node.InitByClientTagLookup( + syncer::EXPERIMENTS, + syncer::kPreCommitUpdateAvoidanceTag) == BaseNode::INIT_OK) { + session_context_->set_server_enabled_pre_commit_update_avoidance( + pre_commit_update_avoidance_node.GetExperimentsSpecifics(). + pre_commit_update_avoidance().enabled()); + // We don't bother setting found_experiment. The frontend doesn't need to + // know about this. + } + return found_experiment; } diff --git a/sync/internal_api/test/test_internal_components_factory.cc b/sync/internal_api/test/test_internal_components_factory.cc index beb249e743..154c58cc99 100644 --- a/sync/internal_api/test/test_internal_components_factory.cc +++ b/sync/internal_api/test/test_internal_components_factory.cc @@ -45,6 +45,8 @@ TestInternalComponentsFactory::BuildContext( empty_listeners, debug_info_getter, traffic_recorder, switches_.encryption_method == ENCRYPTION_KEYSTORE, + switches_.pre_commit_updates_policy == + FORCE_ENABLE_PRE_COMMIT_UPDATE_AVOIDANCE, invalidator_client_id)); } diff --git a/sync/notifier/object_id_invalidation_map.cc b/sync/notifier/object_id_invalidation_map.cc index 47b08e684a..3dc7514b97 100644 --- a/sync/notifier/object_id_invalidation_map.cc +++ b/sync/notifier/object_id_invalidation_map.cc @@ -22,10 +22,11 @@ ObjectIdSet ObjectIdInvalidationMapToSet( } ObjectIdInvalidationMap ObjectIdSetToInvalidationMap( - const ObjectIdSet& ids, const std::string& payload) { + const ObjectIdSet& ids, int64 version, const std::string& payload) { ObjectIdInvalidationMap invalidation_map; for (ObjectIdSet::const_iterator it = ids.begin(); it != ids.end(); ++it) { // TODO(dcheng): Do we need to provide a way to set AckHandle? + invalidation_map[*it].version = version; invalidation_map[*it].payload = payload; } return invalidation_map; diff --git a/sync/notifier/object_id_invalidation_map.h b/sync/notifier/object_id_invalidation_map.h index 6560b3b51a..0a6a95ede4 100644 --- a/sync/notifier/object_id_invalidation_map.h +++ b/sync/notifier/object_id_invalidation_map.h @@ -8,6 +8,7 @@ #include <map> #include <string> +#include "base/basictypes.h" #include "base/memory/scoped_ptr.h" #include "google/cacheinvalidation/include/types.h" #include "sync/base/sync_export.h" @@ -29,7 +30,7 @@ typedef std::map<invalidation::ObjectId, ObjectIdSet ObjectIdInvalidationMapToSet( const ObjectIdInvalidationMap& invalidation_map); SYNC_EXPORT ObjectIdInvalidationMap ObjectIdSetToInvalidationMap( - const ObjectIdSet& ids, const std::string& payload); + const ObjectIdSet& ids, int64 version, const std::string& payload); SYNC_EXPORT bool ObjectIdInvalidationMapEquals( const ObjectIdInvalidationMap& invalidation_map1, @@ -51,4 +52,4 @@ SYNC_EXPORT ObjectIdInvalidationMap } // namespace syncer -#endif // HOME_DCHENG_SRC_CHROMIUM_SRC_SYNC_NOTIFIER_OBJECT_ID_STATE_MAP_H_ +#endif // SYNC_NOTIFIER_OBJECT_ID_INVALIDATION_MAP_H_ diff --git a/sync/notifier/p2p_invalidator.cc b/sync/notifier/p2p_invalidator.cc index 8b54c0417e..05ec183537 100644 --- a/sync/notifier/p2p_invalidator.cc +++ b/sync/notifier/p2p_invalidator.cc @@ -173,7 +173,9 @@ void P2PInvalidator::UpdateRegisteredIds(InvalidationHandler* handler, const P2PNotificationData notification_data( invalidator_client_id_, NOTIFY_SELF, - ObjectIdSetToInvalidationMap(new_ids, std::string())); + ObjectIdSetToInvalidationMap(new_ids, + Invalidation::kUnknownVersion, + std::string())); SendNotificationData(notification_data); } @@ -228,6 +230,7 @@ void P2PInvalidator::OnNotificationsEnabled() { invalidator_client_id_, NOTIFY_SELF, ObjectIdSetToInvalidationMap(registrar_.GetAllRegisteredIds(), + Invalidation::kUnknownVersion, std::string())); SendNotificationData(notification_data); } @@ -263,6 +266,7 @@ void P2PInvalidator::OnIncomingNotification( invalidator_client_id_, NOTIFY_ALL, ObjectIdSetToInvalidationMap(registrar_.GetAllRegisteredIds(), + Invalidation::kUnknownVersion, std::string())); } if (!notification_data.IsTargeted(invalidator_client_id_)) { diff --git a/sync/notifier/p2p_invalidator_unittest.cc b/sync/notifier/p2p_invalidator_unittest.cc index 6acc3d1703..be9ee3f970 100644 --- a/sync/notifier/p2p_invalidator_unittest.cc +++ b/sync/notifier/p2p_invalidator_unittest.cc @@ -180,6 +180,7 @@ TEST_F(P2PInvalidatorTest, P2PNotificationDataNonDefault) { const ObjectIdInvalidationMap& invalidation_map = ObjectIdSetToInvalidationMap( ModelTypeSetToObjectIdSet(ModelTypeSet(BOOKMARKS, THEMES)), + Invalidation::kUnknownVersion, std::string()); const P2PNotificationData notification_data( "sender", NOTIFY_ALL, invalidation_map); @@ -193,10 +194,10 @@ TEST_F(P2PInvalidatorTest, P2PNotificationDataNonDefault) { "{\"idInvalidationMap\":[" "{\"objectId\":{\"name\":\"BOOKMARK\",\"source\":1004}," "\"state\":{\"ackHandle\":{\"state\":\"\",\"timestamp\":\"0\"}," - "\"payload\":\"\"}}," + "\"payload\":\"\",\"version\":\"-1\"}}," "{\"objectId\":{\"name\":\"THEME\",\"source\":1004}," "\"state\":{\"ackHandle\":{\"state\":\"\",\"timestamp\":\"0\"}," - "\"payload\":\"\"}}" + "\"payload\":\"\",\"version\":\"-1\"}}" "],\"notificationType\":\"notifyAll\"," "\"senderId\":\"sender\"}", notification_data_str); @@ -249,6 +250,7 @@ TEST_F(P2PInvalidatorTest, NotificationsBasic) { const ObjectIdInvalidationMap& invalidation_map = ObjectIdSetToInvalidationMap( ModelTypeSetToObjectIdSet(ModelTypeSet(THEMES, APPS)), + Invalidation::kUnknownVersion, std::string()); invalidator->SendInvalidation(invalidation_map); } @@ -267,6 +269,7 @@ TEST_F(P2PInvalidatorTest, SendNotificationData) { const ObjectIdInvalidationMap& invalidation_map = ObjectIdSetToInvalidationMap(ModelTypeSetToObjectIdSet(changed_types), + Invalidation::kUnknownVersion, std::string()); P2PInvalidator* const invalidator = delegate_.GetInvalidator(); diff --git a/sync/notifier/sync_invalidation_listener.cc b/sync/notifier/sync_invalidation_listener.cc index ddb9e35184..ed07f2070b 100644 --- a/sync/notifier/sync_invalidation_listener.cc +++ b/sync/notifier/sync_invalidation_listener.cc @@ -205,7 +205,7 @@ void SyncInvalidationListener::Invalidate( ObjectIdSet ids; ids.insert(id); - PrepareInvalidation(ids, payload, client, ack_handle); + PrepareInvalidation(ids, invalidation.version(), payload, client, ack_handle); } void SyncInvalidationListener::InvalidateUnknownVersion( @@ -218,7 +218,12 @@ void SyncInvalidationListener::InvalidateUnknownVersion( ObjectIdSet ids; ids.insert(object_id); - PrepareInvalidation(ids, std::string(), client, ack_handle); + PrepareInvalidation( + ids, + Invalidation::kUnknownVersion, + std::string(), + client, + ack_handle); } // This should behave as if we got an invalidation with version @@ -230,11 +235,17 @@ void SyncInvalidationListener::InvalidateAll( DCHECK_EQ(client, invalidation_client_.get()); DVLOG(1) << "InvalidateAll"; - PrepareInvalidation(registered_ids_, std::string(), client, ack_handle); + PrepareInvalidation( + registered_ids_, + Invalidation::kUnknownVersion, + std::string(), + client, + ack_handle); } void SyncInvalidationListener::PrepareInvalidation( const ObjectIdSet& ids, + int64 version, const std::string& payload, invalidation::InvalidationClient* client, const invalidation::AckHandle& ack_handle) { @@ -250,6 +261,7 @@ void SyncInvalidationListener::PrepareInvalidation( base::Bind(&SyncInvalidationListener::EmitInvalidation, weak_ptr_factory_.GetWeakPtr(), ids, + version, payload, client, ack_handle)); @@ -257,13 +269,14 @@ void SyncInvalidationListener::PrepareInvalidation( void SyncInvalidationListener::EmitInvalidation( const ObjectIdSet& ids, + int64 version, const std::string& payload, invalidation::InvalidationClient* client, const invalidation::AckHandle& ack_handle, const AckHandleMap& local_ack_handles) { DCHECK(CalledOnValidThread()); ObjectIdInvalidationMap invalidation_map = - ObjectIdSetToInvalidationMap(ids, payload); + ObjectIdSetToInvalidationMap(ids, version, payload); for (AckHandleMap::const_iterator it = local_ack_handles.begin(); it != local_ack_handles.end(); ++it) { // Update in-memory copy of the invalidation state. @@ -280,6 +293,7 @@ void SyncInvalidationListener::OnTimeout(const ObjectIdSet& ids) { for (ObjectIdSet::const_iterator it = ids.begin(); it != ids.end(); ++it) { Invalidation invalidation; invalidation.ack_handle = invalidation_state_map_[*it].expected; + invalidation.version = invalidation_state_map_[*it].version; invalidation.payload = invalidation_state_map_[*it].payload; invalidation_map.insert(std::make_pair(*it, invalidation)); } diff --git a/sync/notifier/sync_invalidation_listener.h b/sync/notifier/sync_invalidation_listener.h index 3613551460..d280e2e5c6 100644 --- a/sync/notifier/sync_invalidation_listener.h +++ b/sync/notifier/sync_invalidation_listener.h @@ -151,10 +151,12 @@ class SYNC_EXPORT_PRIVATE SyncInvalidationListener void EmitStateChange(); void PrepareInvalidation(const ObjectIdSet& ids, + int64 version, const std::string& payload, invalidation::InvalidationClient* client, const invalidation::AckHandle& ack_handle); void EmitInvalidation(const ObjectIdSet& ids, + int64 version, const std::string& payload, invalidation::InvalidationClient* client, const invalidation::AckHandle& ack_handle, diff --git a/sync/notifier/sync_invalidation_listener_unittest.cc b/sync/notifier/sync_invalidation_listener_unittest.cc index 3dee40cd08..d3aa712b7d 100644 --- a/sync/notifier/sync_invalidation_listener_unittest.cc +++ b/sync/notifier/sync_invalidation_listener_unittest.cc @@ -146,6 +146,11 @@ class FakeDelegate : public SyncInvalidationListener::Delegate { return (it == invalidation_counts_.end()) ? 0 : it->second; } + int64 GetVersion(const ObjectId& id) const { + ObjectIdInvalidationMap::const_iterator it = invalidations_.find(id); + return (it == invalidations_.end()) ? 0 : it->second.version; + } + std::string GetPayload(const ObjectId& id) const { ObjectIdInvalidationMap::const_iterator it = invalidations_.find(id); return (it == invalidations_.end()) ? std::string() : it->second.payload; @@ -295,6 +300,10 @@ class SyncInvalidationListenerTest : public testing::Test { return fake_delegate_.GetInvalidationCount(id); } + int64 GetVersion(const ObjectId& id) const { + return fake_delegate_.GetVersion(id); + } + std::string GetPayload(const ObjectId& id) const { return fake_delegate_.GetPayload(id); } @@ -437,6 +446,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateNoPayload) { FireInvalidate(id, kVersion1, NULL); EXPECT_EQ(1, GetInvalidationCount(id)); + EXPECT_EQ(kVersion1, GetVersion(id)); EXPECT_EQ("", GetPayload(id)); EXPECT_EQ(kVersion1, GetMaxVersion(id)); AcknowledgeAndVerify(id); @@ -451,6 +461,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateEmptyPayload) { FireInvalidate(id, kVersion1, ""); EXPECT_EQ(1, GetInvalidationCount(id)); + EXPECT_EQ(kVersion1, GetVersion(id)); EXPECT_EQ("", GetPayload(id)); EXPECT_EQ(kVersion1, GetMaxVersion(id)); AcknowledgeAndVerify(id); @@ -464,6 +475,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateWithPayload) { FireInvalidate(id, kVersion1, kPayload1); EXPECT_EQ(1, GetInvalidationCount(id)); + EXPECT_EQ(kVersion1, GetVersion(id)); EXPECT_EQ(kPayload1, GetPayload(id)); EXPECT_EQ(kVersion1, GetMaxVersion(id)); AcknowledgeAndVerify(id); @@ -483,6 +495,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateUnregisteredWithPayload) { FireInvalidate(id, kVersion1, "unregistered payload"); EXPECT_EQ(1, GetInvalidationCount(id)); + EXPECT_EQ(kVersion1, GetVersion(id)); EXPECT_EQ("unregistered payload", GetPayload(id)); EXPECT_EQ(kVersion1, GetMaxVersion(id)); AcknowledgeAndVerify(id); @@ -497,6 +510,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateVersion) { FireInvalidate(id, kVersion2, kPayload2); EXPECT_EQ(1, GetInvalidationCount(id)); + EXPECT_EQ(kVersion2, GetVersion(id)); EXPECT_EQ(kPayload2, GetPayload(id)); EXPECT_EQ(kVersion2, GetMaxVersion(id)); AcknowledgeAndVerify(id); @@ -504,6 +518,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateVersion) { FireInvalidate(id, kVersion1, kPayload1); EXPECT_EQ(1, GetInvalidationCount(id)); + EXPECT_EQ(kVersion2, GetVersion(id)); EXPECT_EQ(kPayload2, GetPayload(id)); EXPECT_EQ(kVersion2, GetMaxVersion(id)); VerifyAcknowledged(id); @@ -518,6 +533,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateUnknownVersion) { FireInvalidateUnknownVersion(id); EXPECT_EQ(1, GetInvalidationCount(id)); + EXPECT_EQ(Invalidation::kUnknownVersion, GetVersion(id)); EXPECT_EQ("", GetPayload(id)); EXPECT_EQ(kMinVersion, GetMaxVersion(id)); AcknowledgeAndVerify(id); @@ -525,6 +541,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateUnknownVersion) { FireInvalidateUnknownVersion(id); EXPECT_EQ(2, GetInvalidationCount(id)); + EXPECT_EQ(Invalidation::kUnknownVersion, GetVersion(id)); EXPECT_EQ("", GetPayload(id)); EXPECT_EQ(kMinVersion, GetMaxVersion(id)); AcknowledgeAndVerify(id); @@ -538,6 +555,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateAll) { for (ObjectIdSet::const_iterator it = registered_ids_.begin(); it != registered_ids_.end(); ++it) { EXPECT_EQ(1, GetInvalidationCount(*it)); + EXPECT_EQ(Invalidation::kUnknownVersion, GetVersion(*it)); EXPECT_EQ("", GetPayload(*it)); EXPECT_EQ(kMinVersion, GetMaxVersion(*it)); AcknowledgeAndVerify(*it); @@ -549,6 +567,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateMultipleIds) { FireInvalidate(kBookmarksId_, 3, NULL); EXPECT_EQ(1, GetInvalidationCount(kBookmarksId_)); + EXPECT_EQ(3, GetVersion(kBookmarksId_)); EXPECT_EQ("", GetPayload(kBookmarksId_)); EXPECT_EQ(3, GetMaxVersion(kBookmarksId_)); AcknowledgeAndVerify(kBookmarksId_); @@ -556,6 +575,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateMultipleIds) { FireInvalidate(kExtensionsId_, 2, NULL); EXPECT_EQ(1, GetInvalidationCount(kExtensionsId_)); + EXPECT_EQ(2, GetVersion(kExtensionsId_)); EXPECT_EQ("", GetPayload(kExtensionsId_)); EXPECT_EQ(2, GetMaxVersion(kExtensionsId_)); AcknowledgeAndVerify(kExtensionsId_); @@ -565,12 +585,14 @@ TEST_F(SyncInvalidationListenerTest, InvalidateMultipleIds) { FireInvalidate(kBookmarksId_, 1, NULL); EXPECT_EQ(1, GetInvalidationCount(kBookmarksId_)); + EXPECT_EQ(3, GetVersion(kBookmarksId_)); EXPECT_EQ("", GetPayload(kBookmarksId_)); EXPECT_EQ(3, GetMaxVersion(kBookmarksId_)); FireInvalidate(kExtensionsId_, 1, NULL); EXPECT_EQ(1, GetInvalidationCount(kExtensionsId_)); + EXPECT_EQ(2, GetVersion(kExtensionsId_)); EXPECT_EQ("", GetPayload(kExtensionsId_)); EXPECT_EQ(2, GetMaxVersion(kExtensionsId_)); @@ -579,11 +601,13 @@ TEST_F(SyncInvalidationListenerTest, InvalidateMultipleIds) { FireInvalidateAll(); EXPECT_EQ(2, GetInvalidationCount(kBookmarksId_)); + EXPECT_EQ(Invalidation::kUnknownVersion, GetVersion(kBookmarksId_)); EXPECT_EQ("", GetPayload(kBookmarksId_)); EXPECT_EQ(3, GetMaxVersion(kBookmarksId_)); AcknowledgeAndVerify(kBookmarksId_); EXPECT_EQ(1, GetInvalidationCount(kPreferencesId_)); + EXPECT_EQ(Invalidation::kUnknownVersion, GetVersion(kPreferencesId_)); EXPECT_EQ("", GetPayload(kPreferencesId_)); EXPECT_EQ(kMinVersion, GetMaxVersion(kPreferencesId_)); AcknowledgeAndVerify(kPreferencesId_); @@ -591,6 +615,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateMultipleIds) { // Note that kExtensionsId_ is not registered, so InvalidateAll() shouldn't // affect it. EXPECT_EQ(1, GetInvalidationCount(kExtensionsId_)); + EXPECT_EQ(2, GetVersion(kExtensionsId_)); EXPECT_EQ("", GetPayload(kExtensionsId_)); EXPECT_EQ(2, GetMaxVersion(kExtensionsId_)); VerifyAcknowledged(kExtensionsId_); @@ -599,18 +624,21 @@ TEST_F(SyncInvalidationListenerTest, InvalidateMultipleIds) { FireInvalidate(kPreferencesId_, 5, NULL); EXPECT_EQ(2, GetInvalidationCount(kPreferencesId_)); + EXPECT_EQ(5, GetVersion(kPreferencesId_)); EXPECT_EQ("", GetPayload(kPreferencesId_)); EXPECT_EQ(5, GetMaxVersion(kPreferencesId_)); AcknowledgeAndVerify(kPreferencesId_); FireInvalidate(kExtensionsId_, 3, NULL); EXPECT_EQ(2, GetInvalidationCount(kExtensionsId_)); + EXPECT_EQ(3, GetVersion(kExtensionsId_)); EXPECT_EQ("", GetPayload(kExtensionsId_)); EXPECT_EQ(3, GetMaxVersion(kExtensionsId_)); AcknowledgeAndVerify(kExtensionsId_); FireInvalidate(kBookmarksId_, 4, NULL); EXPECT_EQ(3, GetInvalidationCount(kBookmarksId_)); + EXPECT_EQ(4, GetVersion(kBookmarksId_)); EXPECT_EQ("", GetPayload(kBookmarksId_)); EXPECT_EQ(4, GetMaxVersion(kBookmarksId_)); AcknowledgeAndVerify(kBookmarksId_); @@ -628,6 +656,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateOneTimeout) { // Trigger the initial invalidation. FireInvalidate(kBookmarksId_, 3, NULL); EXPECT_EQ(1, GetInvalidationCount(kBookmarksId_)); + EXPECT_EQ(3, GetVersion(kBookmarksId_)); EXPECT_EQ("", GetPayload(kBookmarksId_)); EXPECT_EQ(3, GetMaxVersion(kBookmarksId_)); VerifyUnacknowledged(kBookmarksId_); @@ -638,6 +667,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateOneTimeout) { tick_clock_.NowTicks())); EXPECT_EQ(2, GetInvalidationCount(kBookmarksId_)); // Other properties should remain the same. + EXPECT_EQ(3, GetVersion(kBookmarksId_)); EXPECT_EQ("", GetPayload(kBookmarksId_)); EXPECT_EQ(3, GetMaxVersion(kBookmarksId_)); @@ -655,6 +685,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidationTimeoutRestart) { FireInvalidate(kBookmarksId_, 3, NULL); EXPECT_EQ(1, GetInvalidationCount(kBookmarksId_)); + EXPECT_EQ(3, GetVersion(kBookmarksId_)); EXPECT_EQ("", GetPayload(kBookmarksId_)); EXPECT_EQ(3, GetMaxVersion(kBookmarksId_)); @@ -664,6 +695,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidationTimeoutRestart) { tick_clock_.NowTicks())); EXPECT_EQ(2, GetInvalidationCount(kBookmarksId_)); // Other properties should remain the same. + EXPECT_EQ(3, GetVersion(kBookmarksId_)); EXPECT_EQ("", GetPayload(kBookmarksId_)); EXPECT_EQ(3, GetMaxVersion(kBookmarksId_)); @@ -676,6 +708,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidationTimeoutRestart) { // The bookmark invalidation state should not have changed. EXPECT_EQ(2, GetInvalidationCount(kBookmarksId_)); + EXPECT_EQ(3, GetVersion(kBookmarksId_)); EXPECT_EQ("", GetPayload(kBookmarksId_)); EXPECT_EQ(3, GetMaxVersion(kBookmarksId_)); @@ -685,6 +718,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidationTimeoutRestart) { tick_clock_.NowTicks())); EXPECT_EQ(3, GetInvalidationCount(kBookmarksId_)); // Other properties should remain the same. + EXPECT_EQ(3, GetVersion(kBookmarksId_)); EXPECT_EQ("", GetPayload(kBookmarksId_)); EXPECT_EQ(3, GetMaxVersion(kBookmarksId_)); diff --git a/sync/protocol/experiments_specifics.proto b/sync/protocol/experiments_specifics.proto index f834cb91c0..1e8732fd02 100644 --- a/sync/protocol/experiments_specifics.proto +++ b/sync/protocol/experiments_specifics.proto @@ -34,6 +34,11 @@ message FaviconSyncFlags { optional int32 favicon_sync_limit = 2 [default = 200]; } +// Flags for enabling the experimental no-precommit GU feature. +message PreCommitUpdateAvoidanceFlags { + optional bool enabled = 1; +} + // Contains one flag or set of related flags. Each node of the experiments type // will have a unique_client_tag identifying which flags it contains. By // convention, the tag name should match the sub-message name. @@ -42,4 +47,5 @@ message ExperimentsSpecifics { optional HistoryDeleteDirectives history_delete_directives = 2; optional AutofillCullingFlags autofill_culling = 3; optional FaviconSyncFlags favicon_sync = 4; + optional PreCommitUpdateAvoidanceFlags pre_commit_update_avoidance = 5; } diff --git a/sync/protocol/proto_value_conversions.cc b/sync/protocol/proto_value_conversions.cc index f0a2011c27..9ccc5eb0c8 100644 --- a/sync/protocol/proto_value_conversions.cc +++ b/sync/protocol/proto_value_conversions.cc @@ -352,6 +352,7 @@ base::DictionaryValue* ExperimentsSpecificsToValue( SET_EXPERIMENT_ENABLED_FIELD(keystore_encryption); SET_EXPERIMENT_ENABLED_FIELD(history_delete_directives); SET_EXPERIMENT_ENABLED_FIELD(autofill_culling); + SET_EXPERIMENT_ENABLED_FIELD(pre_commit_update_avoidance); if (proto.has_favicon_sync()) SET(favicon_sync, FaviconSyncFlagsToValue); return value; diff --git a/sync/sessions/data_type_tracker.cc b/sync/sessions/data_type_tracker.cc index 3eabbbe758..a061679839 100644 --- a/sync/sessions/data_type_tracker.cc +++ b/sync/sessions/data_type_tracker.cc @@ -59,7 +59,17 @@ bool DataTypeTracker::IsSyncRequired() const { return !IsThrottled() && (local_nudge_count_ > 0 || local_refresh_request_count_ > 0 || - !pending_payloads_.empty()); + HasPendingInvalidation() || + local_payload_overflow_ || + server_payload_overflow_); +} + +bool DataTypeTracker::IsGetUpdatesRequired() const { + return !IsThrottled() && + (local_refresh_request_count_ > 0 || + HasPendingInvalidation() || + local_payload_overflow_ || + server_payload_overflow_); } bool DataTypeTracker::HasLocalChangePending() const { diff --git a/sync/sessions/data_type_tracker.h b/sync/sessions/data_type_tracker.h index 6488f8e105..30bc3b6dbb 100644 --- a/sync/sessions/data_type_tracker.h +++ b/sync/sessions/data_type_tracker.h @@ -49,6 +49,10 @@ class DataTypeTracker { // cycle. That's for the scheduler to decide. bool IsSyncRequired() const; + // Returns true if there is a good reason to fetch updates for this type as + // part of the next sync cycle. + bool IsGetUpdatesRequired() const; + // Returns true if there is an uncommitted local change. bool HasLocalChangePending() const; diff --git a/sync/sessions/nudge_tracker.cc b/sync/sessions/nudge_tracker.cc index 144860b1a8..f9b90386f5 100644 --- a/sync/sessions/nudge_tracker.cc +++ b/sync/sessions/nudge_tracker.cc @@ -38,6 +38,16 @@ bool NudgeTracker::IsSyncRequired() const { return false; } +bool NudgeTracker::IsGetUpdatesRequired() const { + for (TypeTrackerMap::const_iterator it = type_trackers_.begin(); + it != type_trackers_.end(); ++it) { + if (it->second.IsGetUpdatesRequired()) { + return true; + } + } + return false; +} + void NudgeTracker::RecordSuccessfulSyncCycle() { updates_source_ = sync_pb::GetUpdatesCallerInfo::UNKNOWN; diff --git a/sync/sessions/nudge_tracker.h b/sync/sessions/nudge_tracker.h index 0e8ab51202..f8109a42d3 100644 --- a/sync/sessions/nudge_tracker.h +++ b/sync/sessions/nudge_tracker.h @@ -34,6 +34,10 @@ class SYNC_EXPORT_PRIVATE NudgeTracker { // perform a sync cycle; that's the scheduler's job. bool IsSyncRequired() const; + // Returns true if there is a good reason for performing a get updates + // request as part of the next sync cycle. + bool IsGetUpdatesRequired() const; + // Tells this class that all required update fetching and committing has // completed successfully. void RecordSuccessfulSyncCycle(); diff --git a/sync/sessions/nudge_tracker_unittest.cc b/sync/sessions/nudge_tracker_unittest.cc index 8439af1d82..598a3e6b43 100644 --- a/sync/sessions/nudge_tracker_unittest.cc +++ b/sync/sessions/nudge_tracker_unittest.cc @@ -61,6 +61,7 @@ TEST_F(NudgeTrackerTest, EmptyNudgeTracker) { NudgeTracker nudge_tracker; EXPECT_FALSE(nudge_tracker.IsSyncRequired()); + EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired()); EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::UNKNOWN, nudge_tracker.updates_source()); @@ -300,6 +301,33 @@ TEST_F(NudgeTrackerTest, IsSyncRequired) { EXPECT_FALSE(nudge_tracker.IsSyncRequired()); } +// Basic tests for the IsGetUpdatesRequired() flag. +TEST_F(NudgeTrackerTest, IsGetUpdatesRequired) { + NudgeTracker nudge_tracker; + EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired()); + + // Local changes. + nudge_tracker.RecordLocalChange(ModelTypeSet(SESSIONS)); + EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired()); + nudge_tracker.RecordSuccessfulSyncCycle(); + EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired()); + + // Refresh requests. + nudge_tracker.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS)); + EXPECT_TRUE(nudge_tracker.IsGetUpdatesRequired()); + nudge_tracker.RecordSuccessfulSyncCycle(); + EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired()); + + // Invalidations. + ModelTypeInvalidationMap invalidation_map = + ModelTypeSetToInvalidationMap(ModelTypeSet(PREFERENCES), + std::string("hint")); + nudge_tracker.RecordRemoteInvalidation(invalidation_map); + EXPECT_TRUE(nudge_tracker.IsGetUpdatesRequired()); + nudge_tracker.RecordSuccessfulSyncCycle(); + EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired()); +} + // Test IsSyncRequired() responds correctly to data type throttling. TEST_F(NudgeTrackerTest, IsSyncRequired_Throttling) { NudgeTracker nudge_tracker; @@ -320,7 +348,7 @@ TEST_F(NudgeTrackerTest, IsSyncRequired_Throttling) { EXPECT_FALSE(nudge_tracker.IsSyncRequired()); // A refresh request for bookmarks means we have reason to sync again. - nudge_tracker.RecordLocalChange(ModelTypeSet(BOOKMARKS)); + nudge_tracker.RecordLocalRefreshRequest(ModelTypeSet(BOOKMARKS)); EXPECT_TRUE(nudge_tracker.IsSyncRequired()); // A successful sync cycle means we took care of bookmarks. @@ -335,6 +363,41 @@ TEST_F(NudgeTrackerTest, IsSyncRequired_Throttling) { EXPECT_TRUE(nudge_tracker.IsSyncRequired()); } +// Test IsGetUpdatesRequired() responds correctly to data type throttling. +TEST_F(NudgeTrackerTest, IsGetUpdatesRequired_Throttling) { + NudgeTracker nudge_tracker; + const base::TimeTicks t0 = base::TimeTicks::FromInternalValue(1234); + const base::TimeDelta throttle_length = base::TimeDelta::FromMinutes(10); + const base::TimeTicks t1 = t0 + throttle_length; + + EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired()); + + // A refresh request to sessions enables the flag. + nudge_tracker.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS)); + EXPECT_TRUE(nudge_tracker.IsGetUpdatesRequired()); + + // But the throttling of sessions unsets it. + nudge_tracker.SetTypesThrottledUntil(ModelTypeSet(SESSIONS), + throttle_length, + t0); + EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired()); + + // A refresh request for bookmarks means we have reason to sync again. + nudge_tracker.RecordLocalRefreshRequest(ModelTypeSet(BOOKMARKS)); + EXPECT_TRUE(nudge_tracker.IsGetUpdatesRequired()); + + // A successful sync cycle means we took care of bookmarks. + nudge_tracker.RecordSuccessfulSyncCycle(); + EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired()); + + // But we still haven't dealt with sessions. We'll need to remember + // that sessions are out of sync and re-enable the flag when their + // throttling interval expires. + nudge_tracker.UpdateTypeThrottlingState(t1); + EXPECT_FALSE(nudge_tracker.IsTypeThrottled(SESSIONS)); + EXPECT_TRUE(nudge_tracker.IsGetUpdatesRequired()); +} + // Tests throttling-related getter functions when no types are throttled. TEST_F(NudgeTrackerTest, NoTypesThrottled) { NudgeTracker nudge_tracker; diff --git a/sync/sessions/sync_session_context.cc b/sync/sessions/sync_session_context.cc index 9043db3cba..c48c32b31e 100644 --- a/sync/sessions/sync_session_context.cc +++ b/sync/sessions/sync_session_context.cc @@ -22,6 +22,7 @@ SyncSessionContext::SyncSessionContext( DebugInfoGetter* debug_info_getter, TrafficRecorder* traffic_recorder, bool keystore_encryption_enabled, + bool client_enabled_pre_commit_update_avoidance, const std::string& invalidator_client_id) : connection_manager_(connection_manager), directory_(directory), @@ -31,7 +32,10 @@ SyncSessionContext::SyncSessionContext( debug_info_getter_(debug_info_getter), traffic_recorder_(traffic_recorder), keystore_encryption_enabled_(keystore_encryption_enabled), - invalidator_client_id_(invalidator_client_id) { + invalidator_client_id_(invalidator_client_id), + server_enabled_pre_commit_update_avoidance_(false), + client_enabled_pre_commit_update_avoidance_( + client_enabled_pre_commit_update_avoidance) { for (size_t i = 0u; i < workers.size(); ++i) workers_.push_back(workers[i]); diff --git a/sync/sessions/sync_session_context.h b/sync/sessions/sync_session_context.h index b694162c15..76170958ec 100644 --- a/sync/sessions/sync_session_context.h +++ b/sync/sessions/sync_session_context.h @@ -55,6 +55,7 @@ class SYNC_EXPORT_PRIVATE SyncSessionContext { DebugInfoGetter* debug_info_getter, TrafficRecorder* traffic_recorder, bool keystore_encryption_enabled, + bool client_enabled_pre_commit_update_avoidance, const std::string& invalidator_client_id); ~SyncSessionContext(); @@ -129,6 +130,15 @@ class SYNC_EXPORT_PRIVATE SyncSessionContext { return invalidator_client_id_; } + bool ShouldFetchUpdatesBeforeCommit() const { + return !(server_enabled_pre_commit_update_avoidance_ || + client_enabled_pre_commit_update_avoidance_); + } + + void set_server_enabled_pre_commit_update_avoidance(bool value) { + server_enabled_pre_commit_update_avoidance_ = value; + } + private: // Rather than force clients to set and null-out various context members, we // extend our encapsulation boundary to scoped helpers that take care of this @@ -181,6 +191,15 @@ class SYNC_EXPORT_PRIVATE SyncSessionContext { // prevent us from receiving notifications of changes we make ourselves. const std::string invalidator_client_id_; + // Flag to enable or disable the no pre-commit GetUpdates experiment. When + // this flag is set to false, the syncer has the option of not performing at + // GetUpdates request when there is nothing to fetch. + bool server_enabled_pre_commit_update_avoidance_; + + // If true, indicates that we've been passed a command-line flag to force + // enable the pre-commit update avoidance experiment described above. + const bool client_enabled_pre_commit_update_avoidance_; + DISALLOW_COPY_AND_ASSIGN(SyncSessionContext); }; diff --git a/sync/sessions/sync_session_unittest.cc b/sync/sessions/sync_session_unittest.cc index c98b63923f..4acee569fe 100644 --- a/sync/sessions/sync_session_unittest.cc +++ b/sync/sessions/sync_session_unittest.cc @@ -65,6 +65,7 @@ class SyncSessionTest : public testing::Test, NULL, NULL, true, // enable keystore encryption + false, // force enable pre-commit GU avoidance experiment "fake_invalidator_client_id")); context_->set_routing_info(routes_); diff --git a/sync/syncable/model_type.cc b/sync/syncable/model_type.cc index 5e227948b7..b9dacbecf1 100644 --- a/sync/syncable/model_type.cc +++ b/sync/syncable/model_type.cc @@ -367,7 +367,7 @@ ModelTypeSet EncryptableUserTypes() { encryptable_user_types.Remove(SYNCED_NOTIFICATIONS); // Priority preferences are not encrypted because they might be synced before // encryption is ready. - encryptable_user_types.RemoveAll(PriorityUserTypes()); + encryptable_user_types.Remove(PRIORITY_PREFERENCES); // Managed user settings are not encrypted since they are set server-side. encryptable_user_types.Remove(MANAGED_USER_SETTINGS); // Managed users are not encrypted since they are managed server-side. @@ -380,7 +380,7 @@ ModelTypeSet EncryptableUserTypes() { } ModelTypeSet PriorityUserTypes() { - return ModelTypeSet(PRIORITY_PREFERENCES, MANAGED_USERS); + return ModelTypeSet(PRIORITY_PREFERENCES); } ModelTypeSet ControlTypes() { @@ -405,6 +405,26 @@ bool IsControlType(ModelType model_type) { return ControlTypes().Has(model_type); } +ModelTypeSet CoreTypes() { + syncer::ModelTypeSet result; + result.PutAll(PriorityCoreTypes()); + + // The following are low priority core types. + result.Put(SYNCED_NOTIFICATIONS); + + return result; +} + +ModelTypeSet PriorityCoreTypes() { + syncer::ModelTypeSet result; + result.PutAll(ControlTypes()); + + // The following are non-control core types. + result.Put(MANAGED_USERS); + + return result; +} + const char* ModelTypeToString(ModelType model_type) { // This is used in serialization routines as well as for displaying debug // information. Do not attempt to change these string values unless you know diff --git a/sync/test/android/javatests/src/org/chromium/sync/test/util/MockAccountManager.java b/sync/test/android/javatests/src/org/chromium/sync/test/util/MockAccountManager.java index b79abcf5d5..da16fae2ae 100644 --- a/sync/test/android/javatests/src/org/chromium/sync/test/util/MockAccountManager.java +++ b/sync/test/android/javatests/src/org/chromium/sync/test/util/MockAccountManager.java @@ -238,7 +238,8 @@ public class MockAccountManager implements AccountManagerDelegate { } else { Log.d(TAG, "getAuthTokenFuture: Account " + ah.getAccount() + " is asking for permission for " + authTokenType); - final Intent intent = newGrantCredentialsPermissionIntent(true, account, authTokenType); + final Intent intent = newGrantCredentialsPermissionIntent( + activity != null, account, authTokenType); return runTask(mExecutor, new AccountManagerAuthTokenTask(activity, handler, callback, account, authTokenType, @@ -495,10 +496,13 @@ public class MockAccountManager implements AccountManagerDelegate { try { Bundle bundle = mCallable.call(); Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT); - if (intent != null && mActivity != null) { - // Since the user provided an Activity we will silently start intents we see. - // Starting activity and waiting for it to finish. - waitForActivity(mActivity, intent); + if (intent != null) { + // Start the intent activity and wait for it to finish. + if (mActivity != null) { + waitForActivity(mActivity, intent); + } else { + waitForActivity(mContext, intent); + } if (mAccountAuthTokenPreparation == null) { throw new IllegalStateException("No account preparation ready for " + mAccount + ", authTokenType = " + mAuthTokenType + diff --git a/sync/test/engine/syncer_command_test.h b/sync/test/engine/syncer_command_test.h index c292fe0b96..93106b9933 100644 --- a/sync/test/engine/syncer_command_test.h +++ b/sync/test/engine/syncer_command_test.h @@ -136,6 +136,7 @@ class SyncerCommandTestBase : public testing::Test, &mock_debug_info_getter_, &traffic_recorder_, true, // enable keystore encryption + false, // force enable pre-commit GU avoidance experiment "fake_invalidator_client_id")); context_->set_routing_info(routing_info_); context_->set_account_name(directory()->name()); diff --git a/sync/tools/testserver/chromiumsync.py b/sync/tools/testserver/chromiumsync.py index 7aac4deeaa..834765ff71 100644 --- a/sync/tools/testserver/chromiumsync.py +++ b/sync/tools/testserver/chromiumsync.py @@ -129,8 +129,9 @@ UNIX_TIME_EPOCH = (1970, 1, 1, 0, 0, 0, 3, 1, 0) # The number of characters in the server-generated encryption key. KEYSTORE_KEY_LENGTH = 16 -# The hashed client tag for the keystore encryption experiment node. +# The hashed client tags for some experiment nodes. KEYSTORE_ENCRYPTION_EXPERIMENT_TAG = "pis8ZRzh98/MKLtVEio2mr42LQA=" +PRE_COMMIT_GU_AVOIDANCE_EXPERIMENT_TAG = "Z1xgeh3QUBa50vdEPd8C/4c7jfE=" class Error(Exception): """Error class for this module.""" @@ -1101,6 +1102,25 @@ class SyncDataModel(object): user.specifics.managed_user.acknowledged = True self._SaveEntry(user) + def TriggerEnablePreCommitGetUpdateAvoidance(self): + """Sets the experiment to enable pre-commit GetUpdate avoidance.""" + experiment_id = self._ServerTagToId("google_chrome_experiments") + pre_commit_gu_avoidance_id = self._ClientTagToId( + EXPERIMENTS, + PRE_COMMIT_GU_AVOIDANCE_EXPERIMENT_TAG) + entry = self._entries.get(pre_commit_gu_avoidance_id) + if entry is None: + entry = sync_pb2.SyncEntity() + entry.id_string = pre_commit_gu_avoidance_id + entry.name = "Pre-commit GU avoidance" + entry.client_defined_unique_tag = PRE_COMMIT_GU_AVOIDANCE_EXPERIMENT_TAG + entry.folder = False + entry.deleted = False + entry.specifics.CopyFrom(GetDefaultEntitySpecifics(EXPERIMENTS)) + self._WritePosition(entry, experiment_id) + entry.specifics.experiments.pre_commit_update_avoidance.enabled = True + self._SaveEntry(entry) + def SetInducedError(self, error, error_frequency, sync_count_before_errors): self.induced_error = error @@ -1281,6 +1301,14 @@ class TestServer(object): '<html><title>Enable Managed User Acknowledgement</title>' '<h1>Enable Managed User Acknowledgement</h1></html>') + def HandleEnablePreCommitGetUpdateAvoidance(self): + """Enables the pre-commit GU avoidance experiment.""" + self.account.TriggerEnablePreCommitGetUpdateAvoidance() + return ( + 200, + '<html><title>Enable pre-commit GU avoidance</title>' + '<H1>Enable pre-commit GU avoidance</H1></html>') + def HandleCommand(self, query, raw_request): """Decode and handle a sync command from a raw input of bytes. diff --git a/sync/tools/testserver/sync_testserver.py b/sync/tools/testserver/sync_testserver.py index 4fbfdaf9ac..53532cb5b7 100755 --- a/sync/tools/testserver/sync_testserver.py +++ b/sync/tools/testserver/sync_testserver.py @@ -150,7 +150,8 @@ class SyncPageHandler(testserver_base.BasePageHandler): self.ChromiumSyncCreateSyncedBookmarksOpHandler, self.ChromiumSyncEnableKeystoreEncryptionOpHandler, self.ChromiumSyncRotateKeystoreKeysOpHandler, - self.ChromiumSyncEnableManagedUserAcknowledgementHandler] + self.ChromiumSyncEnableManagedUserAcknowledgementHandler, + self.ChromiumSyncEnablePreCommitGetUpdateAvoidanceHandler] post_handlers = [self.ChromiumSyncCommandHandler, self.ChromiumSyncTimeHandler] @@ -427,6 +428,19 @@ class SyncPageHandler(testserver_base.BasePageHandler): self.wfile.write(raw_reply) return True + def ChromiumSyncEnablePreCommitGetUpdateAvoidanceHandler(self): + test_name = "/chromiumsync/enableprecommitgetupdateavoidance" + if not self._ShouldHandleRequest(test_name): + return False + result, raw_reply = ( + self.server._sync_handler.HandleEnablePreCommitGetUpdateAvoidance()) + self.send_response(result) + self.send_header('Content-Type', 'text/html') + self.send_header('Content-Length', len(raw_reply)) + self.end_headers() + self.wfile.write(raw_reply) + return True + class SyncServerRunner(testserver_base.TestServerRunner): """TestServerRunner for the net test servers.""" |