diff options
author | akalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-10 07:52:05 +0000 |
---|---|---|
committer | akalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-10 07:52:05 +0000 |
commit | 1a6178883cdedae4e417c219f133fa6a7151d59e (patch) | |
tree | e4b7c9bbe9593443dad916717a3572a705749fb1 /chrome/browser | |
parent | d579359316db95b9dc1a3020bd334d4e38adc549 (diff) | |
download | chromium_src-1a6178883cdedae4e417c219f133fa6a7151d59e.zip chromium_src-1a6178883cdedae4e417c219f133fa6a7151d59e.tar.gz chromium_src-1a6178883cdedae4e417c219f133fa6a7151d59e.tar.bz2 |
Revert 77607 - [Sync] Refactor notification RegistrationManager, implement backoff
Currently, we retry immediately if we lose a registration, which can
cause problems if the failure is permanent. Exponential backoff should
avoid killing our notification servers.
BUG=75209
TEST=
Review URL: http://codereview.chromium.org/6649010
TBR=akalin@chromium.org
Review URL: http://codereview.chromium.org/6646043
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@77614 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
5 files changed, 252 insertions, 485 deletions
diff --git a/chrome/browser/sync/notifier/chrome_invalidation_client.cc b/chrome/browser/sync/notifier/chrome_invalidation_client.cc index 81614ae..0c38936 100644 --- a/chrome/browser/sync/notifier/chrome_invalidation_client.cc +++ b/chrome/browser/sync/notifier/chrome_invalidation_client.cc @@ -159,8 +159,9 @@ void ChromeInvalidationClient::RegistrationStateChanged( } if (new_state != invalidation::RegistrationState_REGISTERED) { - // We don't care about |unknown_hint|; we let - // |registration_manager_| handle the registration backoff policy. + // TODO(akalin): Figure out something else to do if the failure + // isn't transient. Even if it is transient, we may still want to + // add exponential back-off or limit the number of attempts. registration_manager_->MarkRegistrationLost(model_type); } } @@ -174,6 +175,21 @@ void ChromeInvalidationClient::AllRegistrationsLost( RunAndDeleteClosure(callback); } +void ChromeInvalidationClient::RegistrationLost( + const invalidation::ObjectId& object_id, + invalidation::Closure* callback) { + DCHECK(non_thread_safe_.CalledOnValidThread()); + DCHECK(invalidation::IsCallbackRepeatable(callback)); + VLOG(1) << "RegistrationLost: " << ObjectIdToString(object_id); + syncable::ModelType model_type; + if (ObjectIdToRealModelType(object_id, &model_type)) { + registration_manager_->MarkRegistrationLost(model_type); + } else { + LOG(WARNING) << "Could not get object id model type; ignoring"; + } + RunAndDeleteClosure(callback); +} + void ChromeInvalidationClient::WriteState(const std::string& state) { DCHECK(non_thread_safe_.CalledOnValidThread()); CHECK(state_writer_); diff --git a/chrome/browser/sync/notifier/chrome_invalidation_client.h b/chrome/browser/sync/notifier/chrome_invalidation_client.h index ddde72d..904b91d 100644 --- a/chrome/browser/sync/notifier/chrome_invalidation_client.h +++ b/chrome/browser/sync/notifier/chrome_invalidation_client.h @@ -87,6 +87,9 @@ class ChromeInvalidationClient virtual void AllRegistrationsLost(invalidation::Closure* callback); + virtual void RegistrationLost(const invalidation::ObjectId& object_id, + invalidation::Closure* callback); + // StateWriter implementation. virtual void WriteState(const std::string& state); diff --git a/chrome/browser/sync/notifier/registration_manager.cc b/chrome/browser/sync/notifier/registration_manager.cc index e5006f3..69181a4 100644 --- a/chrome/browser/sync/notifier/registration_manager.cc +++ b/chrome/browser/sync/notifier/registration_manager.cc @@ -4,51 +4,17 @@ #include "chrome/browser/sync/notifier/registration_manager.h" -#include <algorithm> -#include <cstddef> #include <string> -#include "base/rand_util.h" #include "chrome/browser/sync/notifier/invalidation_util.h" #include "chrome/browser/sync/syncable/model_type.h" namespace sync_notifier { -RegistrationManager::RegistrationStatus::RegistrationStatus() - : model_type(syncable::UNSPECIFIED), - registration_manager(NULL), - state(invalidation::RegistrationState_UNREGISTERED) {} - -void RegistrationManager::RegistrationStatus::DoRegister() { - DCHECK_NE(model_type, syncable::UNSPECIFIED); - DCHECK(registration_manager); - // We might be called explicitly, so stop the timer manually and - // reset the delay. - registration_timer.Stop(); - delay = base::TimeDelta(); - registration_manager->DoRegisterType(model_type); - DCHECK(!last_registration_request.is_null()); -} - -const int RegistrationManager::kInitialRegistrationDelaySeconds = 5; -const int RegistrationManager::kRegistrationDelayExponent = 2; -const double RegistrationManager::kRegistrationDelayMaxJitter = 0.5; -const int RegistrationManager::kMinRegistrationDelaySeconds = 1; -// 1 hour. -const int RegistrationManager::kMaxRegistrationDelaySeconds = 60 * 60; - RegistrationManager::RegistrationManager( invalidation::InvalidationClient* invalidation_client) : invalidation_client_(invalidation_client) { DCHECK(invalidation_client_); - // Initialize statuses. - for (int i = syncable::FIRST_REAL_MODEL_TYPE; - i < syncable::MODEL_TYPE_COUNT; ++i) { - syncable::ModelType model_type = syncable::ModelTypeFromInt(i); - RegistrationStatus* status = ®istration_statuses_[model_type]; - status->model_type = model_type; - status->registration_manager = this; - } } RegistrationManager::~RegistrationManager() { @@ -59,162 +25,76 @@ void RegistrationManager::SetRegisteredTypes( const syncable::ModelTypeSet& types) { DCHECK(non_thread_safe_.CalledOnValidThread()); - for (int i = syncable::FIRST_REAL_MODEL_TYPE; - i < syncable::MODEL_TYPE_COUNT; ++i) { - syncable::ModelType model_type = syncable::ModelTypeFromInt(i); - if (types.count(model_type) > 0) { - if (!IsTypeRegistered(model_type)) { - TryRegisterType(model_type, false /* is_retry */); - } + for (int i = syncable::FIRST_REAL_MODEL_TYPE; i < syncable::MODEL_TYPE_COUNT; + ++i) { + syncable::ModelType type = syncable::ModelTypeFromInt(i); + if (types.count(type) > 0) { + RegisterType(type); } else { - if (IsTypeRegistered(model_type)) { - UnregisterType(model_type); - } + UnregisterType(type); } } } -void RegistrationManager::MarkRegistrationLost( - syncable::ModelType model_type) { - DCHECK(non_thread_safe_.CalledOnValidThread()); - registration_statuses_[model_type].state = - invalidation::RegistrationState_UNREGISTERED; - TryRegisterType(model_type, true /* is_retry */); -} - -void RegistrationManager::MarkAllRegistrationsLost() { +bool RegistrationManager::IsRegistered( + syncable::ModelType model_type) const { DCHECK(non_thread_safe_.CalledOnValidThread()); - for (int i = syncable::FIRST_REAL_MODEL_TYPE; - i < syncable::MODEL_TYPE_COUNT; ++i) { - syncable::ModelType model_type = syncable::ModelTypeFromInt(i); - if (IsTypeRegistered(model_type)) { - MarkRegistrationLost(model_type); - } + RegistrationStatusMap::const_iterator it = + registration_status_.find(model_type); + if (it == registration_status_.end()) { + return false; } + return it->second == invalidation::RegistrationState_REGISTERED; } -syncable::ModelTypeSet RegistrationManager::GetRegisteredTypes() const { +void RegistrationManager::MarkRegistrationLost( + syncable::ModelType model_type) { DCHECK(non_thread_safe_.CalledOnValidThread()); - syncable::ModelTypeSet registered_types; - for (int i = syncable::FIRST_REAL_MODEL_TYPE; - i < syncable::MODEL_TYPE_COUNT; ++i) { - syncable::ModelType model_type = syncable::ModelTypeFromInt(i); - if (IsTypeRegistered(model_type)) { - registered_types.insert(model_type); - } + invalidation::ObjectId object_id; + if (!RealModelTypeToObjectId(model_type, &object_id)) { + LOG(ERROR) << "Invalid model type: " << model_type; + return; } - return registered_types; -} - -RegistrationManager::PendingRegistrationMap - RegistrationManager::GetPendingRegistrations() const { - DCHECK(non_thread_safe_.CalledOnValidThread()); - PendingRegistrationMap pending_registrations; - for (int i = syncable::FIRST_REAL_MODEL_TYPE; - i < syncable::MODEL_TYPE_COUNT; ++i) { - syncable::ModelType model_type = syncable::ModelTypeFromInt(i); - const RegistrationStatus& status = registration_statuses_[model_type]; - if (status.registration_timer.IsRunning()) { - pending_registrations[model_type].last_registration_request = - status.last_registration_request; - pending_registrations[model_type].registration_attempt = - status.last_registration_attempt; - pending_registrations[model_type].delay = status.delay; - pending_registrations[model_type].actual_delay = - status.registration_timer.GetCurrentDelay(); - } + RegistrationStatusMap::iterator it = + registration_status_.find(model_type); + if (it == registration_status_.end()) { + LOG(ERROR) << "Unknown model type: " << model_type; + return; } - return pending_registrations; + it->second = invalidation::RegistrationState_UNREGISTERED; + RegisterObject(object_id, it); } -void RegistrationManager::FirePendingRegistrationsForTest() { +void RegistrationManager::MarkAllRegistrationsLost() { DCHECK(non_thread_safe_.CalledOnValidThread()); - for (int i = syncable::FIRST_REAL_MODEL_TYPE; - i < syncable::MODEL_TYPE_COUNT; ++i) { - syncable::ModelType model_type = syncable::ModelTypeFromInt(i); - RegistrationStatus* status = ®istration_statuses_[model_type]; - if (status->registration_timer.IsRunning()) { - status->DoRegister(); + for (RegistrationStatusMap::iterator it = + registration_status_.begin(); + it != registration_status_.end(); ++it) { + invalidation::ObjectId object_id; + if (!RealModelTypeToObjectId(it->first, &object_id)) { + LOG(DFATAL) << "Invalid model type: " << it->first; + continue; } + it->second = invalidation::RegistrationState_UNREGISTERED; + RegisterObject(object_id, it); } } -namespace { - -double CalculateBackoff(double retry_interval, - double initial_retry_interval, - double min_retry_interval, - double max_retry_interval, - double backoff_exponent, double max_jitter) { - double new_retry_interval = - (retry_interval == 0.0) ? - initial_retry_interval : (retry_interval * backoff_exponent); - // |jitter| lies in [-1.0, 1.0), which is low-biased, but only - // barely. - // - // TODO(akalin): Fix the bias. - double jitter = 2.0 * base::RandDouble() - 1.0; - new_retry_interval *= (1.0 + jitter * max_jitter); - return std::max(min_retry_interval, - std::min(max_retry_interval, new_retry_interval)); -} - -} // namespace - -void RegistrationManager::TryRegisterType(syncable::ModelType model_type, - bool is_retry) { - DCHECK(non_thread_safe_.CalledOnValidThread()); - RegistrationStatus* status = ®istration_statuses_[model_type]; - status->last_registration_attempt = base::Time::Now(); - if (is_retry) { - // If we're a retry, we must have tried at least once before. - DCHECK(!status->last_registration_request.is_null()); - // delay = max(0, (now - last request) + next_delay) - status->delay = - (status->last_registration_request - - status->last_registration_attempt) + - status->next_delay; - base::TimeDelta delay = - (status->delay <= base::TimeDelta()) ? - base::TimeDelta() : status->delay; - VLOG(2) << "Registering " - << syncable::ModelTypeToString(model_type) << " in " - << delay.InMilliseconds() << " ms"; - status->registration_timer.Stop(); - status->registration_timer.Start( - delay, status, &RegistrationManager::RegistrationStatus::DoRegister); - double next_delay_seconds = - CalculateBackoff(static_cast<double>(status->next_delay.InSeconds()), - kInitialRegistrationDelaySeconds, - kMinRegistrationDelaySeconds, - kMaxRegistrationDelaySeconds, - kRegistrationDelayExponent, - kRegistrationDelayMaxJitter); - status->next_delay = - base::TimeDelta::FromSeconds(static_cast<int64>(next_delay_seconds)); - VLOG(2) << "New next delay for " - << syncable::ModelTypeToString(model_type) << " is " - << status->next_delay.InSeconds() << " seconds"; - } else { - VLOG(2) << "Not a retry -- registering " - << syncable::ModelTypeToString(model_type) << " immediately"; - status->delay = base::TimeDelta(); - status->next_delay = base::TimeDelta(); - status->DoRegister(); - } -} - -void RegistrationManager::DoRegisterType(syncable::ModelType model_type) { +void RegistrationManager::RegisterType(syncable::ModelType model_type) { DCHECK(non_thread_safe_.CalledOnValidThread()); invalidation::ObjectId object_id; if (!RealModelTypeToObjectId(model_type, &object_id)) { LOG(DFATAL) << "Invalid model type: " << model_type; return; } - invalidation_client_->Register(object_id); - RegistrationStatus* status = ®istration_statuses_[model_type]; - status->state = invalidation::RegistrationState_REGISTERED; - status->last_registration_request = base::Time::Now(); + RegistrationStatusMap::iterator it = + registration_status_.insert( + std::make_pair( + model_type, + invalidation::RegistrationState_UNREGISTERED)).first; + if (it->second == invalidation::RegistrationState_UNREGISTERED) { + RegisterObject(object_id, it); + } } void RegistrationManager::UnregisterType(syncable::ModelType model_type) { @@ -224,16 +104,21 @@ void RegistrationManager::UnregisterType(syncable::ModelType model_type) { LOG(DFATAL) << "Invalid model type: " << model_type; return; } - invalidation_client_->Unregister(object_id); - RegistrationStatus* status = ®istration_statuses_[model_type]; - status->state = invalidation::RegistrationState_UNREGISTERED; -} + RegistrationStatusMap::iterator it = registration_status_.find(model_type); -bool RegistrationManager::IsTypeRegistered( - syncable::ModelType model_type) const { - DCHECK(non_thread_safe_.CalledOnValidThread()); - return registration_statuses_[model_type].state == - invalidation::RegistrationState_REGISTERED; + if (it != registration_status_.end()) { + if (it->second == invalidation::RegistrationState_REGISTERED) { + invalidation_client_->Unregister(object_id); + } + registration_status_.erase(it); + } } +void RegistrationManager::RegisterObject( + const invalidation::ObjectId& object_id, + RegistrationStatusMap::iterator it) { + DCHECK_EQ(it->second, invalidation::RegistrationState_UNREGISTERED); + invalidation_client_->Register(object_id); + it->second = invalidation::RegistrationState_REGISTERED; +} } // namespace sync_notifier diff --git a/chrome/browser/sync/notifier/registration_manager.h b/chrome/browser/sync/notifier/registration_manager.h index ea46127..d7edb04 100644 --- a/chrome/browser/sync/notifier/registration_manager.h +++ b/chrome/browser/sync/notifier/registration_manager.h @@ -12,59 +12,35 @@ #include <map> #include "base/basictypes.h" -#include "base/time.h" -#include "base/timer.h" +#include "base/gtest_prod_util.h" #include "base/threading/non_thread_safe.h" #include "chrome/browser/sync/syncable/model_type.h" -// For invalidation::RegistrationState. #include "google/cacheinvalidation/invalidation-client.h" namespace sync_notifier { -// Manages the details of registering types for invalidation. -// Implements exponential backoff for repeated registration attempts -// to the invalidation client. -// -// TODO(akalin): Consolidate exponential backoff code. Other -// implementations include the syncer thread (both versions) and XMPP -// retries. The most sophisticated one is URLRequestThrottler; making -// that generic should work for everyone. class RegistrationManager { - public: - // Constants for exponential backoff (used by tests). - static const int kInitialRegistrationDelaySeconds; - static const int kRegistrationDelayExponent; - static const double kRegistrationDelayMaxJitter; - static const int kMinRegistrationDelaySeconds; - static const int kMaxRegistrationDelaySeconds; - - // Types used by testing functions. - struct PendingRegistrationInfo { - // Last time a registration request was actually sent. - base::Time last_registration_request; - // Time the registration was attempted. - base::Time registration_attempt; - // The calculated delay of the pending registration (which may be - // negative). - base::TimeDelta delay; - // The delay of the timer, which should be max(delay, 0). - base::TimeDelta actual_delay; - }; - // Map from types with pending registrations to info about the - // pending registration. - typedef std::map<syncable::ModelType, PendingRegistrationInfo> - PendingRegistrationMap; + friend class RegistrationManagerTest; + + FRIEND_TEST_ALL_PREFIXES(RegistrationManagerTest, RegisterType); + FRIEND_TEST_ALL_PREFIXES(RegistrationManagerTest, UnregisterType); + FRIEND_TEST_ALL_PREFIXES(RegistrationManagerTest, MarkRegistrationLost); + FRIEND_TEST_ALL_PREFIXES(RegistrationManagerTest, MarkAllRegistrationsLost); + public: // Does not take ownership of |invalidation_client_|. explicit RegistrationManager( invalidation::InvalidationClient* invalidation_client); ~RegistrationManager(); - // Registers all types included in the given set and sets all other - // types to be unregistered. void SetRegisteredTypes(const syncable::ModelTypeSet& types); + // Returns true iff |model_type| is currently registered. + // + // Currently only used by unit tests. + bool IsRegistered(syncable::ModelType model_type) const; + // Marks the registration for the |model_type| lost and re-registers // it. void MarkRegistrationLost(syncable::ModelType model_type); @@ -72,69 +48,26 @@ class RegistrationManager { // Marks all registrations lost and re-registers them. void MarkAllRegistrationsLost(); - // The functions below should only be used in tests. - - // Gets all currently-registered types. - syncable::ModelTypeSet GetRegisteredTypes() const; - - // Gets all pending registrations and their next min delays. - PendingRegistrationMap GetPendingRegistrations() const; + private: + typedef std::map<syncable::ModelType, invalidation::RegistrationState> + RegistrationStatusMap; - // Run pending registrations immediately. - void FirePendingRegistrationsForTest(); + // Registers the given |model_type|, which must be valid. + void RegisterType(syncable::ModelType model_type); - private: - struct RegistrationStatus { - // The model type for which this is the status. - syncable::ModelType model_type; - // The parent registration manager. - RegistrationManager* registration_manager; - - // The current registration state. - invalidation::RegistrationState state; - // When we last sent a registration request. - base::Time last_registration_request; - // When we last tried to register. - base::Time last_registration_attempt; - // The calculated delay of any pending registration (which may be - // negative). - base::TimeDelta delay; - // The minimum time to wait until any next registration attempt. - // Increased after each consecutive failure. - base::TimeDelta next_delay; - // The actual timer for registration. - base::OneShotTimer<RegistrationStatus> registration_timer; - - RegistrationStatus(); - - // Calls registration_manager->DoRegister(model_type). (needed by - // |registration_timer|). - void DoRegister(); - }; - - // If |is_retry| is not set, registers the given type immediately - // and resets all backoff parameters. If |is_retry| is set, - // registers the given type at some point in the future and - // increases the delay until the next retry. - void TryRegisterType(syncable::ModelType model_type, - bool is_retry); - - // Registers the given type, which must be valid, immediately. - // Updates |last_registration| in the appropriate - // RegistrationStatus. Should only be called by - // RegistrationStatus::DoRegister(). - void DoRegisterType(syncable::ModelType model_type); - - // Unregisters the given type, which must be valid. void UnregisterType(syncable::ModelType model_type); - // Returns true iff the given type, which must be valid, is registered. - bool IsTypeRegistered(syncable::ModelType model_type) const; + // Calls invalidation_client_->Register() on |object_id|. sets + // it->second to UNREGISTERED -> PENDING. + void RegisterObject(const invalidation::ObjectId& object_id, + RegistrationStatusMap::iterator it); + + void OnRegister(const invalidation::RegistrationUpdateResult& result); base::NonThreadSafe non_thread_safe_; - RegistrationStatus registration_statuses_[syncable::MODEL_TYPE_COUNT]; // Weak pointer. invalidation::InvalidationClient* invalidation_client_; + RegistrationStatusMap registration_status_; DISALLOW_COPY_AND_ASSIGN(RegistrationManager); }; diff --git a/chrome/browser/sync/notifier/registration_manager_unittest.cc b/chrome/browser/sync/notifier/registration_manager_unittest.cc index 5f80221..ac5b236 100644 --- a/chrome/browser/sync/notifier/registration_manager_unittest.cc +++ b/chrome/browser/sync/notifier/registration_manager_unittest.cc @@ -10,14 +10,12 @@ #include <vector> #include "base/basictypes.h" -#include "base/message_loop.h" #include "chrome/browser/sync/notifier/invalidation_util.h" #include "chrome/browser/sync/syncable/model_type.h" #include "google/cacheinvalidation/invalidation-client.h" #include "testing/gtest/include/gtest/gtest.h" namespace sync_notifier { -namespace { syncable::ModelType ObjectIdToModelType( const invalidation::ObjectId& object_id) { @@ -26,37 +24,33 @@ syncable::ModelType ObjectIdToModelType( return model_type; } -// Fake invalidation client that just stores the currently-registered -// model types. +// Fake invalidation client that just stores the args of calls to +// Register(). class FakeInvalidationClient : public invalidation::InvalidationClient { public: FakeInvalidationClient() {} virtual ~FakeInvalidationClient() {} - void LoseRegistration(syncable::ModelType model_type) { - EXPECT_GT(registered_types_.count(model_type), 0u); - registered_types_.erase(model_type); - } - - void LoseAllRegistrations() { - registered_types_.clear(); - } - - // invalidation::InvalidationClient implementation. - virtual void Start(const std::string& state) {} virtual void Register(const invalidation::ObjectId& oid) { - syncable::ModelType model_type = ObjectIdToModelType(oid); - EXPECT_EQ(0u, registered_types_.count(model_type)); - registered_types_.insert(model_type); + registered_types.push_back(ObjectIdToModelType(oid)); } virtual void Unregister(const invalidation::ObjectId& oid) { - syncable::ModelType model_type = ObjectIdToModelType(oid); - EXPECT_GT(registered_types_.count(model_type), 0u); - registered_types_.erase(model_type); + syncable::ModelType type_to_unregister = ObjectIdToModelType(oid); + std::vector<syncable::ModelType>::iterator it = std::find( + registered_types.begin(), + registered_types.end(), + type_to_unregister); + + if(it == registered_types.end()) { + // We should not be unregistering a thing that is not yet registered. + ADD_FAILURE(); + } else { + registered_types.erase(it); + } } virtual invalidation::NetworkEndpoint* network_endpoint() { @@ -64,14 +58,10 @@ class FakeInvalidationClient : public invalidation::InvalidationClient { return NULL; } - const syncable::ModelTypeSet GetRegisteredTypes() const { - return registered_types_; - } + std::vector<syncable::ModelType> registered_types; private: DISALLOW_COPY_AND_ASSIGN(FakeInvalidationClient); - - syncable::ModelTypeSet registered_types_; }; class RegistrationManagerTest : public testing::Test { @@ -81,224 +71,164 @@ class RegistrationManagerTest : public testing::Test { virtual ~RegistrationManagerTest() {} - void LoseRegistrations(const syncable::ModelTypeSet& types) { - for (syncable::ModelTypeSet::const_iterator it = types.begin(); - it != types.end(); ++it) { - fake_invalidation_client_.LoseRegistration(*it); - registration_manager_.MarkRegistrationLost(*it); - } - } - FakeInvalidationClient fake_invalidation_client_; RegistrationManager registration_manager_; private: - // Needed by timers in RegistrationManager. - MessageLoop message_loop_; - DISALLOW_COPY_AND_ASSIGN(RegistrationManagerTest); }; -const syncable::ModelType kModelTypes[] = { - syncable::BOOKMARKS, - syncable::PREFERENCES, - syncable::THEMES, - syncable::AUTOFILL, - syncable::EXTENSIONS, -}; -const size_t kModelTypeCount = arraysize(kModelTypes); - -TEST_F(RegistrationManagerTest, SetRegisteredTypes) { - syncable::ModelTypeSet no_types; - syncable::ModelTypeSet types(kModelTypes, kModelTypes + kModelTypeCount); +TEST_F(RegistrationManagerTest, RegisterType) { + const syncable::ModelType kModelTypes[] = { + syncable::BOOKMARKS, + syncable::PREFERENCES, + syncable::THEMES, + syncable::AUTOFILL, + syncable::EXTENSIONS, + }; + const size_t kModelTypeCount = arraysize(kModelTypes); + + // Register types. + for (size_t i = 0; i < kModelTypeCount; ++i) { + // Register twice; it shouldn't matter. + registration_manager_.RegisterType(kModelTypes[i]); + registration_manager_.RegisterType(kModelTypes[i]); + } - EXPECT_EQ(no_types, registration_manager_.GetRegisteredTypes()); - EXPECT_EQ(no_types, fake_invalidation_client_.GetRegisteredTypes()); + ASSERT_EQ(kModelTypeCount, + fake_invalidation_client_.registered_types.size()); - registration_manager_.SetRegisteredTypes(types); - EXPECT_EQ(types, registration_manager_.GetRegisteredTypes()); - EXPECT_EQ(types, fake_invalidation_client_.GetRegisteredTypes()); + // Everything should be registered. + for (size_t i = 0; i < kModelTypeCount; ++i) { + EXPECT_TRUE(registration_manager_.IsRegistered(kModelTypes[i])); + } - types.insert(syncable::APPS); - types.erase(syncable::BOOKMARKS); - registration_manager_.SetRegisteredTypes(types); - EXPECT_EQ(types, registration_manager_.GetRegisteredTypes()); - EXPECT_EQ(types, fake_invalidation_client_.GetRegisteredTypes()); + // Check object IDs. + for (size_t i = 0; i < kModelTypeCount; ++i) { + EXPECT_EQ(kModelTypes[i], + fake_invalidation_client_.registered_types[i]); + } } -void ExpectPendingRegistrations( - const syncable::ModelTypeSet& expected_pending_types, - double expected_min_delay_seconds, double expected_max_delay_seconds, - const RegistrationManager::PendingRegistrationMap& pending_registrations) { - syncable::ModelTypeSet pending_types; - for (RegistrationManager::PendingRegistrationMap::const_iterator it = - pending_registrations.begin(); it != pending_registrations.end(); - ++it) { - SCOPED_TRACE(syncable::ModelTypeToString(it->first)); - pending_types.insert(it->first); - base::TimeDelta offset = - it->second.last_registration_request - - it->second.registration_attempt; - base::TimeDelta expected_min_delay = - base::TimeDelta::FromSeconds( - static_cast<int64>(expected_min_delay_seconds)) + offset; - base::TimeDelta expected_max_delay = - base::TimeDelta::FromSeconds( - static_cast<int64>(expected_max_delay_seconds)) + offset; - // TODO(akalin): Add base::PrintTo() for base::Time and - // base::TimeDeltas. - EXPECT_GE(it->second.delay, expected_min_delay) - << it->second.delay.InMicroseconds() - << ", " << expected_min_delay.InMicroseconds(); - EXPECT_LE(it->second.delay, expected_max_delay) - << it->second.delay.InMicroseconds() - << ", " << expected_max_delay.InMicroseconds(); - if (it->second.delay <= base::TimeDelta()) { - EXPECT_EQ(it->second.actual_delay, base::TimeDelta()); - } else { - EXPECT_EQ(it->second.delay, it->second.actual_delay); - } +TEST_F(RegistrationManagerTest, UnregisterType) { + const syncable::ModelType kModelTypes[] = { + syncable::BOOKMARKS, + syncable::PREFERENCES, + syncable::THEMES, + syncable::AUTOFILL, + syncable::EXTENSIONS, + }; + const size_t kModelTypeCount = arraysize(kModelTypes); + + // Register types. + for (size_t i = 0; i < kModelTypeCount; ++i) { + // Register twice; it shouldn't matter. + registration_manager_.RegisterType(kModelTypes[i]); + } + + ASSERT_EQ(kModelTypeCount, + fake_invalidation_client_.registered_types.size()); + + // Everything should be registered. + for (size_t i = 0; i < kModelTypeCount; ++i) { + EXPECT_TRUE(registration_manager_.IsRegistered(kModelTypes[i])); + } + + // Check object IDs. + for (size_t i = 0; i < kModelTypeCount; ++i) { + EXPECT_EQ(kModelTypes[i], + fake_invalidation_client_.registered_types[i]); + } + + // Now unregister the extension. + registration_manager_.UnregisterType(syncable::EXTENSIONS); + + // Check the count and the types currently registered to ensure extensions + // is unregistered. + ASSERT_EQ(kModelTypeCount - 1, + fake_invalidation_client_.registered_types.size()); + + // Check object IDs. + for (size_t i = 0; i < kModelTypeCount - 1; ++i) { + EXPECT_EQ(kModelTypes[i], + fake_invalidation_client_.registered_types[i]); } - EXPECT_EQ(expected_pending_types, pending_types); } TEST_F(RegistrationManagerTest, MarkRegistrationLost) { - syncable::ModelTypeSet types(kModelTypes, kModelTypes + kModelTypeCount); - - registration_manager_.SetRegisteredTypes(types); - EXPECT_TRUE(registration_manager_.GetPendingRegistrations().empty()); - - // Lose some types. - syncable::ModelTypeSet lost_types( - kModelTypes, kModelTypes + 3); - syncable::ModelTypeSet non_lost_types( - kModelTypes + 3, kModelTypes + kModelTypeCount); - LoseRegistrations(lost_types); - ExpectPendingRegistrations(lost_types, 0.0, 0.0, - registration_manager_.GetPendingRegistrations()); - EXPECT_EQ(non_lost_types, registration_manager_.GetRegisteredTypes()); - EXPECT_EQ(non_lost_types, fake_invalidation_client_.GetRegisteredTypes()); - - // Pretend we waited long enough to re-register. - registration_manager_.FirePendingRegistrationsForTest(); - EXPECT_EQ(types, registration_manager_.GetRegisteredTypes()); - EXPECT_EQ(types, fake_invalidation_client_.GetRegisteredTypes()); -} + const syncable::ModelType kModelTypes[] = { + syncable::BOOKMARKS, + syncable::PREFERENCES, + syncable::THEMES, + syncable::AUTOFILL, + syncable::EXTENSIONS, + }; + const size_t kModelTypeCount = arraysize(kModelTypes); + + // Register types. + for (size_t i = 0; i < kModelTypeCount; ++i) { + registration_manager_.RegisterType(kModelTypes[i]); + } -TEST_F(RegistrationManagerTest, MarkRegistrationLostBackoff) { - syncable::ModelTypeSet types(kModelTypes, kModelTypes + kModelTypeCount); - - registration_manager_.SetRegisteredTypes(types); - - // Lose some types. - syncable::ModelTypeSet lost_types(kModelTypes, kModelTypes + 2); - LoseRegistrations(lost_types); - ExpectPendingRegistrations(lost_types, 0.0, 0.0, - registration_manager_.GetPendingRegistrations()); - - // Trigger another failure to start delaying. - registration_manager_.FirePendingRegistrationsForTest(); - LoseRegistrations(lost_types); - double min_delay = - RegistrationManager::kInitialRegistrationDelaySeconds * - (1.0 - RegistrationManager::kRegistrationDelayMaxJitter); - double max_delay = - RegistrationManager::kInitialRegistrationDelaySeconds * - (1.0 + RegistrationManager::kRegistrationDelayMaxJitter); - ExpectPendingRegistrations(lost_types, min_delay, max_delay, - registration_manager_.GetPendingRegistrations()); - - // Trigger another failure. - registration_manager_.FirePendingRegistrationsForTest(); - LoseRegistrations(lost_types); - min_delay *= - RegistrationManager::kRegistrationDelayExponent - - RegistrationManager::kRegistrationDelayMaxJitter; - max_delay *= - RegistrationManager::kRegistrationDelayExponent + - RegistrationManager::kRegistrationDelayMaxJitter; - ExpectPendingRegistrations(lost_types, min_delay, max_delay, - registration_manager_.GetPendingRegistrations()); - - // Trigger enough failures to hit the ceiling. - while (min_delay < RegistrationManager::kMaxRegistrationDelaySeconds) { - registration_manager_.FirePendingRegistrationsForTest(); - LoseRegistrations(lost_types); - min_delay *= - RegistrationManager::kRegistrationDelayExponent - - RegistrationManager::kRegistrationDelayMaxJitter; + ASSERT_EQ(kModelTypeCount, + fake_invalidation_client_.registered_types.size()); + + // All should be registered. + for (size_t i = 0; i < kModelTypeCount; ++i) { + EXPECT_TRUE(registration_manager_.IsRegistered(kModelTypes[i])); } - ExpectPendingRegistrations( - lost_types, - RegistrationManager::kMaxRegistrationDelaySeconds, - RegistrationManager::kMaxRegistrationDelaySeconds, - registration_manager_.GetPendingRegistrations()); -} -TEST_F(RegistrationManagerTest, MarkRegistrationLostBackoffReset) { - syncable::ModelTypeSet types(kModelTypes, kModelTypes + kModelTypeCount); - - registration_manager_.SetRegisteredTypes(types); - - // Lose some types. - syncable::ModelTypeSet lost_types(kModelTypes, kModelTypes + 2); - LoseRegistrations(lost_types); - ExpectPendingRegistrations(lost_types, 0.0, 0.0, - registration_manager_.GetPendingRegistrations()); - - // Trigger another failure to start delaying. - registration_manager_.FirePendingRegistrationsForTest(); - LoseRegistrations(lost_types); - double min_delay = - RegistrationManager::kInitialRegistrationDelaySeconds * - (1.0 - RegistrationManager::kRegistrationDelayMaxJitter); - double max_delay = - RegistrationManager::kInitialRegistrationDelaySeconds * - (1.0 + RegistrationManager::kRegistrationDelayMaxJitter); - ExpectPendingRegistrations( - lost_types, min_delay, max_delay, - registration_manager_.GetPendingRegistrations()); - - // Set types again. - registration_manager_.SetRegisteredTypes(types); - ExpectPendingRegistrations(syncable::ModelTypeSet(), 0.0, 0.0, - registration_manager_.GetPendingRegistrations()); + // Mark the registrations of all but the first one lost. + for (size_t i = 1; i < kModelTypeCount; ++i) { + registration_manager_.MarkRegistrationLost(kModelTypes[i]); + } + + ASSERT_EQ(2 * kModelTypeCount - 1, + fake_invalidation_client_.registered_types.size()); + + // All should still be registered. + for (size_t i = 0; i < kModelTypeCount; ++i) { + EXPECT_TRUE(registration_manager_.IsRegistered(kModelTypes[i])); + } } TEST_F(RegistrationManagerTest, MarkAllRegistrationsLost) { - syncable::ModelTypeSet types(kModelTypes, kModelTypes + kModelTypeCount); + const syncable::ModelType kModelTypes[] = { + syncable::BOOKMARKS, + syncable::PREFERENCES, + syncable::THEMES, + syncable::AUTOFILL, + syncable::EXTENSIONS, + }; + const size_t kModelTypeCount = arraysize(kModelTypes); + + // Register types. + for (size_t i = 0; i < kModelTypeCount; ++i) { + registration_manager_.RegisterType(kModelTypes[i]); + } - registration_manager_.SetRegisteredTypes(types); + ASSERT_EQ(kModelTypeCount, + fake_invalidation_client_.registered_types.size()); - fake_invalidation_client_.LoseAllRegistrations(); - registration_manager_.MarkAllRegistrationsLost(); + // All should be registered. + for (size_t i = 0; i < kModelTypeCount; ++i) { + EXPECT_TRUE(registration_manager_.IsRegistered(kModelTypes[i])); + } - syncable::ModelTypeSet expected_types; - EXPECT_EQ(expected_types, registration_manager_.GetRegisteredTypes()); - EXPECT_EQ(expected_types, fake_invalidation_client_.GetRegisteredTypes()); + // Mark the registrations of all but the first one lost. Then mark + // everything lost. + for (size_t i = 1; i < kModelTypeCount; ++i) { + registration_manager_.MarkRegistrationLost(kModelTypes[i]); + } + registration_manager_.MarkAllRegistrationsLost(); - ExpectPendingRegistrations(types, 0.0, 0.0, - registration_manager_.GetPendingRegistrations()); + ASSERT_EQ(3 * kModelTypeCount - 1, + fake_invalidation_client_.registered_types.size()); - // Trigger another failure to start delaying. - registration_manager_.FirePendingRegistrationsForTest(); - fake_invalidation_client_.LoseAllRegistrations(); - registration_manager_.MarkAllRegistrationsLost(); - double min_delay = - RegistrationManager::kInitialRegistrationDelaySeconds * - (1.0 - RegistrationManager::kRegistrationDelayMaxJitter); - double max_delay = - RegistrationManager::kInitialRegistrationDelaySeconds * - (1.0 + RegistrationManager::kRegistrationDelayMaxJitter); - ExpectPendingRegistrations( - types, min_delay, max_delay, - registration_manager_.GetPendingRegistrations()); - - // Pretend we waited long enough to re-register. - registration_manager_.FirePendingRegistrationsForTest(); - EXPECT_EQ(types, registration_manager_.GetRegisteredTypes()); - EXPECT_EQ(types, fake_invalidation_client_.GetRegisteredTypes()); + // All should still be registered. + for (size_t i = 0; i < kModelTypeCount; ++i) { + EXPECT_TRUE(registration_manager_.IsRegistered(kModelTypes[i])); + } } -} // namespace } // namespace notifier |