diff options
-rw-r--r-- | chrome/browser/sync/notifier/chrome_invalidation_client.cc | 54 | ||||
-rw-r--r-- | chrome/browser/sync/notifier/chrome_invalidation_client.h | 4 | ||||
-rw-r--r-- | chrome/browser/sync/notifier/invalidation_util.cc | 20 | ||||
-rw-r--r-- | chrome/browser/sync/notifier/invalidation_util.h | 7 | ||||
-rw-r--r-- | chrome/browser/sync/notifier/registration_manager.cc | 132 | ||||
-rw-r--r-- | chrome/browser/sync/notifier/registration_manager.h | 83 | ||||
-rw-r--r-- | chrome/browser/sync/notifier/registration_manager_unittest.cc | 287 | ||||
-rw-r--r-- | chrome/chrome.gyp | 2 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 2 |
9 files changed, 548 insertions, 43 deletions
diff --git a/chrome/browser/sync/notifier/chrome_invalidation_client.cc b/chrome/browser/sync/notifier/chrome_invalidation_client.cc index 0b84899..f183e61 100644 --- a/chrome/browser/sync/notifier/chrome_invalidation_client.cc +++ b/chrome/browser/sync/notifier/chrome_invalidation_client.cc @@ -10,6 +10,7 @@ #include "base/logging.h" #include "chrome/browser/sync/notifier/cache_invalidation_packet_handler.h" #include "chrome/browser/sync/notifier/invalidation_util.h" +#include "chrome/browser/sync/notifier/registration_manager.h" #include "chrome/browser/sync/syncable/model_type.h" namespace sync_notifier { @@ -46,6 +47,8 @@ void ChromeInvalidationClient::Start( cache_invalidation_packet_handler_.reset( new CacheInvalidationPacketHandler(xmpp_client, invalidation_client_.get())); + registration_manager_.reset( + new RegistrationManager(invalidation_client_.get())); RegisterTypes(); } @@ -58,6 +61,7 @@ void ChromeInvalidationClient::Stop() { chrome_system_resources_.StopScheduler(); + registration_manager_.reset(); cache_invalidation_packet_handler_.reset(); invalidation_client_.reset(); listener_ = NULL; @@ -70,35 +74,10 @@ void ChromeInvalidationClient::RegisterTypes() { // notifications for all possible types. for (int i = syncable::FIRST_REAL_MODEL_TYPE; i < syncable::MODEL_TYPE_COUNT; ++i) { - syncable::ModelType model_type = syncable::ModelTypeFromInt(i); - std::string notification_type; - if (!syncable::RealModelTypeToNotificationType( - model_type, ¬ification_type)) { - LOG(ERROR) << "Could not get notification type for model type " - << syncable::ModelTypeToString(model_type); - continue; - } - invalidation::ObjectId object_id; - object_id.mutable_name()->set_string_value(notification_type); - object_id.set_source(invalidation::ObjectId::CHROME_SYNC); - invalidation_client_->Register( - object_id, - invalidation::NewPermanentCallback( - this, &ChromeInvalidationClient::OnRegister)); + registration_manager_->RegisterType(syncable::ModelTypeFromInt(i)); } } -namespace { - -bool GetInvalidationModelType(const invalidation::Invalidation& invalidation, - syncable::ModelType* model_type) { - return - syncable::NotificationTypeToRealModelType( - invalidation.object_id().name().string_value(), model_type); -} - -} // namespace - void ChromeInvalidationClient::Invalidate( const invalidation::Invalidation& invalidation, invalidation::Closure* callback) { @@ -106,7 +85,7 @@ void ChromeInvalidationClient::Invalidate( DCHECK(invalidation::IsCallbackRepeatable(callback)); LOG(INFO) << "Invalidate: " << InvalidationToString(invalidation); syncable::ModelType model_type; - if (GetInvalidationModelType(invalidation, &model_type)) { + if (ObjectIdToRealModelType(invalidation.object_id(), &model_type)) { listener_->OnInvalidate(model_type); } else { LOG(WARNING) << "Could not get invalidation model type; " @@ -129,8 +108,8 @@ void ChromeInvalidationClient::AllRegistrationsLost( invalidation::Closure* callback) { DCHECK(non_thread_safe_.CalledOnValidThread()); DCHECK(invalidation::IsCallbackRepeatable(callback)); - LOG(INFO) << "AllRegistrationsLost; reregistering"; - RegisterTypes(); + LOG(INFO) << "AllRegistrationsLost"; + registration_manager_->MarkAllRegistrationsLost(); RunAndDeleteClosure(callback); } @@ -139,17 +118,14 @@ void ChromeInvalidationClient::RegistrationLost( invalidation::Closure* callback) { DCHECK(non_thread_safe_.CalledOnValidThread()); DCHECK(invalidation::IsCallbackRepeatable(callback)); - LOG(INFO) << "RegistrationLost; reregistering: " - << ObjectIdToString(object_id); - RegisterTypes(); + LOG(INFO) << "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::OnRegister( - const invalidation::RegistrationUpdateResult& result) { - DCHECK(non_thread_safe_.CalledOnValidThread()); - // TODO(akalin): Do something meaningful here. - LOG(INFO) << "Registered: " << RegistrationUpdateResultToString(result); -} - } // namespace sync_notifier diff --git a/chrome/browser/sync/notifier/chrome_invalidation_client.h b/chrome/browser/sync/notifier/chrome_invalidation_client.h index e227fcc..6b4f6cfe 100644 --- a/chrome/browser/sync/notifier/chrome_invalidation_client.h +++ b/chrome/browser/sync/notifier/chrome_invalidation_client.h @@ -24,6 +24,7 @@ class XmppClient; namespace sync_notifier { class CacheInvalidationPacketHandler; +class RegistrationManager; // TODO(akalin): Hook this up to a NetworkChangeNotifier so we can // properly notify invalidation_client_. @@ -77,8 +78,7 @@ class ChromeInvalidationClient : public invalidation::InvalidationListener { scoped_ptr<invalidation::InvalidationClient> invalidation_client_; scoped_ptr<CacheInvalidationPacketHandler> cache_invalidation_packet_handler_; - - void OnRegister(const invalidation::RegistrationUpdateResult& result); + scoped_ptr<RegistrationManager> registration_manager_; DISALLOW_COPY_AND_ASSIGN(ChromeInvalidationClient); }; diff --git a/chrome/browser/sync/notifier/invalidation_util.cc b/chrome/browser/sync/notifier/invalidation_util.cc index 2683fae..f61a0db 100644 --- a/chrome/browser/sync/notifier/invalidation_util.cc +++ b/chrome/browser/sync/notifier/invalidation_util.cc @@ -13,8 +13,24 @@ void RunAndDeleteClosure(invalidation::Closure* task) { delete task; } -// We need to write our own protobuf to string functions because we -// use LITE_RUNTIME, which doesn't support DebugString(). +bool RealModelTypeToObjectId(syncable::ModelType model_type, + invalidation::ObjectId* object_id) { + std::string notification_type; + if (!syncable::RealModelTypeToNotificationType( + model_type, ¬ification_type)) { + return false; + } + object_id->mutable_name()->set_string_value(notification_type); + object_id->set_source(invalidation::ObjectId::CHROME_SYNC); + return true; +} + +bool ObjectIdToRealModelType(const invalidation::ObjectId& object_id, + syncable::ModelType* model_type) { + return + syncable::NotificationTypeToRealModelType( + object_id.name().string_value(), model_type); +} std::string ObjectIdToString( const invalidation::ObjectId& object_id) { diff --git a/chrome/browser/sync/notifier/invalidation_util.h b/chrome/browser/sync/notifier/invalidation_util.h index 3ca5fe9..92e6a6e 100644 --- a/chrome/browser/sync/notifier/invalidation_util.h +++ b/chrome/browser/sync/notifier/invalidation_util.h @@ -9,12 +9,19 @@ #include <string> +#include "chrome/browser/sync/syncable/model_type.h" #include "google/cacheinvalidation/invalidation-client.h" namespace sync_notifier { void RunAndDeleteClosure(invalidation::Closure* task); +bool RealModelTypeToObjectId(syncable::ModelType model_type, + invalidation::ObjectId* object_id); + +bool ObjectIdToRealModelType(const invalidation::ObjectId& object_id, + syncable::ModelType* model_type); + // We need to write our own protobuf-to-string functions because we // use LITE_RUNTIME, which doesn't support DebugString(). diff --git a/chrome/browser/sync/notifier/registration_manager.cc b/chrome/browser/sync/notifier/registration_manager.cc new file mode 100644 index 0000000..3895c91 --- /dev/null +++ b/chrome/browser/sync/notifier/registration_manager.cc @@ -0,0 +1,132 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/sync/notifier/registration_manager.h" + +#include <string> + +#include "chrome/browser/sync/notifier/invalidation_util.h" +#include "chrome/browser/sync/syncable/model_type.h" +#include "google/cacheinvalidation/invalidation-client.h" + +namespace sync_notifier { + +RegistrationManager::RegistrationManager( + invalidation::InvalidationClient* invalidation_client) + : invalidation_client_(invalidation_client) { + DCHECK(invalidation_client_); +} + +RegistrationManager::~RegistrationManager() { + DCHECK(non_thread_safe_.CalledOnValidThread()); +} + +bool RegistrationManager::RegisterType(syncable::ModelType model_type) { + DCHECK(non_thread_safe_.CalledOnValidThread()); + invalidation::ObjectId object_id; + if (!RealModelTypeToObjectId(model_type, &object_id)) { + LOG(ERROR) << "Invalid model type: " << model_type; + return false; + } + RegistrationStatusMap::iterator it = + registration_status_.insert( + std::make_pair(model_type, UNREGISTERED)).first; + if (it->second == UNREGISTERED) { + RegisterObject(object_id, it); + } + return true; +} + +bool RegistrationManager::IsRegistered( + syncable::ModelType model_type) const { + DCHECK(non_thread_safe_.CalledOnValidThread()); + RegistrationStatusMap::const_iterator it = + registration_status_.find(model_type); + if (it == registration_status_.end()) { + return false; + } + return it->second == REGISTERED; +} + +void RegistrationManager::MarkRegistrationLost( + syncable::ModelType model_type) { + DCHECK(non_thread_safe_.CalledOnValidThread()); + invalidation::ObjectId object_id; + if (!RealModelTypeToObjectId(model_type, &object_id)) { + LOG(ERROR) << "Invalid model type: " << model_type; + return; + } + RegistrationStatusMap::iterator it = + registration_status_.find(model_type); + if (it == registration_status_.end()) { + LOG(ERROR) << "Unknown model type: " + << syncable::ModelTypeToString(model_type); + return; + } + it->second = UNREGISTERED; + RegisterObject(object_id, it); +} + +void RegistrationManager::MarkAllRegistrationsLost() { + DCHECK(non_thread_safe_.CalledOnValidThread()); + 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 = UNREGISTERED; + RegisterObject(object_id, it); + } +} + +void RegistrationManager::RegisterObject( + const invalidation::ObjectId& object_id, + RegistrationStatusMap::iterator it) { + DCHECK_EQ(it->second, UNREGISTERED); + invalidation_client_->Register( + object_id, + invalidation::NewPermanentCallback( + this, &RegistrationManager::OnRegister)); + it->second = PENDING; +} + +void RegistrationManager::OnRegister( + const invalidation::RegistrationUpdateResult& result) { + DCHECK(non_thread_safe_.CalledOnValidThread()); + LOG(INFO) << "OnRegister: " << RegistrationUpdateResultToString(result); + if (result.operation().type() != + invalidation::RegistrationUpdate::REGISTER) { + LOG(ERROR) << "Got non-register result"; + return; + } + syncable::ModelType model_type; + if (!ObjectIdToRealModelType(result.operation().object_id(), + &model_type)) { + LOG(ERROR) << "Could not get model type"; + return; + } + RegistrationStatusMap::iterator it = + registration_status_.find(model_type); + if (it == registration_status_.end()) { + LOG(ERROR) << "Unknown model type: " << model_type; + return; + } + invalidation::Status::Code code = result.status().code(); + switch (code) { + case invalidation::Status::SUCCESS: + it->second = REGISTERED; + break; + case invalidation::Status::TRANSIENT_FAILURE: + // TODO(akalin): Add retry logic. For now, just fall through. + default: + // Treat everything else as a permanent failure. + LOG(ERROR) << "Registration failed with code: " << code; + break; + } +} + +} // namespace sync_notifier diff --git a/chrome/browser/sync/notifier/registration_manager.h b/chrome/browser/sync/notifier/registration_manager.h new file mode 100644 index 0000000..52f299be --- /dev/null +++ b/chrome/browser/sync/notifier/registration_manager.h @@ -0,0 +1,83 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// A class that manages the registration of types for server-issued +// notifications. + +#ifndef CHROME_BROWSER_SYNC_NOTIFIER_REGISTRATION_MANAGER_H_ +#define CHROME_BROWSER_SYNC_NOTIFIER_REGISTRATION_MANAGER_H_ + +#include <map> + +#include "base/basictypes.h" +#include "base/non_thread_safe.h" +#include "chrome/browser/sync/syncable/model_type.h" + +namespace invalidation { +class InvalidationClient; +class ObjectId; +class RegistrationUpdateResult; +} // namespace + +namespace sync_notifier { + +class RegistrationManager { + public: + // Does not take ownership of |invalidation_client_|. + explicit RegistrationManager( + invalidation::InvalidationClient* invalidation_client); + + ~RegistrationManager(); + + // If |model_type| is valid, starts the process to register it and + // returns true. Otherwise, returns false. + bool RegisterType(syncable::ModelType model_type); + + // Returns true iff |model_type| has been successfully registered. + // Note that IsRegistered(model_type) may not immediately (or ever) + // return true after calling RegisterType(model_type). + // + // Currently only used by unit tests. + bool IsRegistered(syncable::ModelType model_type) const; + + // TODO(akalin): We will eventually need an UnregisterType(). + + // Marks the registration for the |model_type| lost and re-registers + // it. + void MarkRegistrationLost(syncable::ModelType model_type); + + // Marks all registrations lost and re-registers them. + void MarkAllRegistrationsLost(); + + private: + enum RegistrationStatus { + // Registration request has not yet been sent. + UNREGISTERED, + // Registration request has been sent; waiting on confirmation. + PENDING, + // Registration has been confirmed. + REGISTERED, + }; + + typedef std::map<syncable::ModelType, RegistrationStatus> + RegistrationStatusMap; + + // 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); + + NonThreadSafe non_thread_safe_; + // Weak pointer. + invalidation::InvalidationClient* invalidation_client_; + RegistrationStatusMap registration_status_; + + DISALLOW_COPY_AND_ASSIGN(RegistrationManager); +}; + +} // namespace sync_notifier + +#endif // CHROME_BROWSER_SYNC_NOTIFIER_REGISTRATION_MANAGER_H_ diff --git a/chrome/browser/sync/notifier/registration_manager_unittest.cc b/chrome/browser/sync/notifier/registration_manager_unittest.cc new file mode 100644 index 0000000..0f47f88 --- /dev/null +++ b/chrome/browser/sync/notifier/registration_manager_unittest.cc @@ -0,0 +1,287 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/sync/notifier/registration_manager.h" + +#include <cstddef> +#include <deque> +#include <vector> + +#include "base/basictypes.h" +#include "base/logging.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 { + +// Fake invalidation client that just stores the args of calls to +// Register(). +class FakeInvalidationClient : public invalidation::InvalidationClient { + public: + struct Args { + Args() : callback(NULL) {} + + Args(const invalidation::ObjectId& oid, + invalidation::RegistrationCallback* callback) + : oid(oid), callback(callback) {} + + invalidation::ObjectId oid; + invalidation::RegistrationCallback* callback; + }; + + FakeInvalidationClient() {} + + virtual ~FakeInvalidationClient() { + for (std::deque<Args>::iterator it = register_calls.begin(); + it != register_calls.end(); ++it) { + delete it->callback; + } + } + + void Register(const invalidation::ObjectId& oid, + invalidation::RegistrationCallback* callback) { + register_calls.push_back(Args(oid, callback)); + } + + void Unregister(const invalidation::ObjectId& oid, + invalidation::RegistrationCallback* callback) { + ADD_FAILURE(); + delete callback; + } + + invalidation::NetworkEndpoint* network_endpoint() { + ADD_FAILURE(); + return NULL; + } + + void GetClientUniquifier(invalidation::string* uniquifier) const { + ADD_FAILURE(); + } + + std::deque<Args> register_calls; + + private: + DISALLOW_COPY_AND_ASSIGN(FakeInvalidationClient); +}; + +class RegistrationManagerTest : public testing::Test { + protected: + RegistrationManagerTest() + : registration_manager_(&fake_invalidation_client_) {} + + virtual ~RegistrationManagerTest() {} + + FakeInvalidationClient fake_invalidation_client_; + RegistrationManager registration_manager_; + + private: + DISALLOW_COPY_AND_ASSIGN(RegistrationManagerTest); +}; + +invalidation::ObjectId ModelTypeToObjectId( + syncable::ModelType model_type) { + invalidation::ObjectId object_id; + EXPECT_TRUE(RealModelTypeToObjectId(model_type, &object_id)); + return object_id; +} + +syncable::ModelType ObjectIdToModelType( + const invalidation::ObjectId& object_id) { + syncable::ModelType model_type = syncable::UNSPECIFIED; + EXPECT_TRUE(ObjectIdToRealModelType(object_id, &model_type)); + return model_type; +} + +invalidation::RegistrationUpdateResult MakeRegistrationUpdateResult( + syncable::ModelType model_type) { + invalidation::RegistrationUpdateResult result; + result.mutable_operation()-> + set_type(invalidation::RegistrationUpdate::REGISTER); + *result.mutable_operation()->mutable_object_id() = + ModelTypeToObjectId(model_type); + result.mutable_status()->set_code(invalidation::Status::SUCCESS); + return result; +} + +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]); + } + + ASSERT_EQ(kModelTypeCount, + fake_invalidation_client_.register_calls.size()); + + // Nothing should be registered yet. + for (size_t i = 0; i < kModelTypeCount; ++i) { + EXPECT_FALSE(registration_manager_.IsRegistered(kModelTypes[i])); + } + + // Check object IDs. + for (size_t i = 0; i < kModelTypeCount; ++i) { + EXPECT_EQ(kModelTypes[i], + ObjectIdToModelType( + fake_invalidation_client_.register_calls[i].oid)); + } + + // Prepare results. + std::vector<invalidation::RegistrationUpdateResult> results( + kModelTypeCount); + for (size_t i = 0; i < kModelTypeCount; ++i) { + results[i] = MakeRegistrationUpdateResult(kModelTypes[i]); + } + + // Generate a variety of error conditions in all but the first + // result. + results[1].mutable_operation()->set_type( + invalidation::RegistrationUpdate::UNREGISTER); + results[2].mutable_operation()->mutable_object_id()-> + mutable_name()->set_string_value("garbage"); + results[3].mutable_status()-> + set_code(invalidation::Status::UNKNOWN_ERROR); + *results[4].mutable_operation()->mutable_object_id() = + ModelTypeToObjectId(syncable::TYPED_URLS); + + + // Send the registration results back. + for (size_t i = 0; i < kModelTypeCount; ++i) { + fake_invalidation_client_.register_calls[i].callback->Run(results[i]); + } + + // Only the first one should be registered. + EXPECT_TRUE(registration_manager_.IsRegistered(kModelTypes[0])); + for (size_t i = 1; i < kModelTypeCount; ++i) { + EXPECT_FALSE(registration_manager_.IsRegistered(kModelTypes[i])); + } +} + +TEST_F(RegistrationManagerTest, MarkRegistrationLost) { + 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]); + } + + ASSERT_EQ(kModelTypeCount, + fake_invalidation_client_.register_calls.size()); + + // Send the registration results back. + for (size_t i = 0; i < kModelTypeCount; ++i) { + fake_invalidation_client_.register_calls[i].callback->Run( + MakeRegistrationUpdateResult(kModelTypes[i])); + } + + // All should be registered. + for (size_t i = 0; i < kModelTypeCount; ++i) { + EXPECT_TRUE(registration_manager_.IsRegistered(kModelTypes[i])); + } + + // 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_.register_calls.size()); + + // Only the first one should be registered. + EXPECT_TRUE(registration_manager_.IsRegistered(kModelTypes[0])); + for (size_t i = 1; i < kModelTypeCount; ++i) { + EXPECT_FALSE(registration_manager_.IsRegistered(kModelTypes[i])); + } + + // Send more registration results back. + for (size_t i = 1; i < kModelTypeCount; ++i) { + fake_invalidation_client_.register_calls[kModelTypeCount + i - 1]. + callback->Run( + MakeRegistrationUpdateResult(kModelTypes[i])); + } + + // All should be registered. + for (size_t i = 0; i < kModelTypeCount; ++i) { + EXPECT_TRUE(registration_manager_.IsRegistered(kModelTypes[i])); + } +} + +TEST_F(RegistrationManagerTest, MarkAllRegistrationsLost) { + 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]); + } + + ASSERT_EQ(kModelTypeCount, + fake_invalidation_client_.register_calls.size()); + + // Send the registration results back. + for (size_t i = 0; i < kModelTypeCount; ++i) { + fake_invalidation_client_.register_calls[i].callback->Run( + MakeRegistrationUpdateResult(kModelTypes[i])); + } + + // All should be registered. + for (size_t i = 0; i < kModelTypeCount; ++i) { + EXPECT_TRUE(registration_manager_.IsRegistered(kModelTypes[i])); + } + + // 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(); + + ASSERT_EQ(3 * kModelTypeCount - 1, + fake_invalidation_client_.register_calls.size()); + + // None should be registered. + for (size_t i = 0; i < kModelTypeCount; ++i) { + EXPECT_FALSE(registration_manager_.IsRegistered(kModelTypes[i])); + } + + // Send more registration results back. + for (size_t i = 0; i < kModelTypeCount; ++i) { + fake_invalidation_client_.register_calls[2 * kModelTypeCount + i - 1]. + callback->Run( + MakeRegistrationUpdateResult(kModelTypes[i])); + } + + // All should be registered. + for (size_t i = 0; i < kModelTypeCount; ++i) { + EXPECT_TRUE(registration_manager_.IsRegistered(kModelTypes[i])); + } +} + +} // namespace +} // namespace notifier diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 320ab5d..d87ec30 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -993,6 +993,8 @@ 'browser/sync/notifier/chrome_system_resources.h', 'browser/sync/notifier/invalidation_util.cc', 'browser/sync/notifier/invalidation_util.h', + 'browser/sync/notifier/registration_manager.cc', + 'browser/sync/notifier/registration_manager.h', 'browser/sync/notifier/server_notifier_thread.cc', 'browser/sync/notifier/server_notifier_thread.h', ], diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index a4daba3..e8eea76 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1821,6 +1821,7 @@ 'browser/sync/engine/syncproto_unittest.cc', 'browser/sync/engine/verify_updates_command_unittest.cc', 'browser/sync/glue/change_processor_mock.h', + 'browser/sync/notifier/registration_manager_unittest.cc', 'browser/sync/profile_sync_factory_mock.cc', 'browser/sync/profile_sync_factory_mock.h', 'browser/sync/sessions/ordered_commit_set_unittest.cc', @@ -1866,6 +1867,7 @@ '../third_party/libjingle/libjingle.gyp:libjingle', 'profile_import', 'syncapi', + 'sync_notifier', 'test_support_unit', ], 'conditions': [ |