summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorakalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-10 07:52:05 +0000
committerakalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-10 07:52:05 +0000
commit1a6178883cdedae4e417c219f133fa6a7151d59e (patch)
treee4b7c9bbe9593443dad916717a3572a705749fb1 /chrome/browser
parentd579359316db95b9dc1a3020bd334d4e38adc549 (diff)
downloadchromium_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')
-rw-r--r--chrome/browser/sync/notifier/chrome_invalidation_client.cc20
-rw-r--r--chrome/browser/sync/notifier/chrome_invalidation_client.h3
-rw-r--r--chrome/browser/sync/notifier/registration_manager.cc233
-rw-r--r--chrome/browser/sync/notifier/registration_manager.h117
-rw-r--r--chrome/browser/sync/notifier/registration_manager_unittest.cc364
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 = &registration_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 = &registration_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 = &registration_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 = &registration_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 = &registration_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