summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbartfab <bartfab@chromium.org>2015-01-28 04:08:02 -0800
committerCommit bot <commit-bot@chromium.org>2015-01-28 12:10:02 +0000
commit465d8a5a1709bce5780c697407f7a7c4146dfea8 (patch)
tree10500f114499704b65bcaf74210275c8e5823f86
parentac59daacf5d6dfd47ea67bc6ddd930b499215698 (diff)
downloadchromium_src-465d8a5a1709bce5780c697407f7a7c4146dfea8.zip
chromium_src-465d8a5a1709bce5780c697407f7a7c4146dfea8.tar.gz
chromium_src-465d8a5a1709bce5780c697407f7a7c4146dfea8.tar.bz2
Add AffiliatedInvalidationServiceProvider
Device policy pushing requires a connected invalidation service which belongs to an account that is affiliated with the device's enrollment domain. If an affiliated user is logged in and has a connected per-profile invalidation service, that service is used. Otherwise, a device-global invalidation service is spun up. This CL extracts the mechanism from DeviceCloudPolicyInvalidator and generalizes it so that it can be used by any number of consumers. This will allow the same invalidation service to be resued by e.g. device policy pushing, device-local account policy pushing and device remote commands. The CL adds a new AffiliatedInvalidationServiceProvider with tests but does not switch the DeviceCloudPolicyInvalidator to this new infrastructure yet. That will be done in a follow-up CL. BUG=442800 TEST=New unit tests Review URL: https://codereview.chromium.org/828953004 Cr-Commit-Position: refs/heads/master@{#313488}
-rw-r--r--chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.cc343
-rw-r--r--chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.h140
-rw-r--r--chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_unittest.cc627
-rw-r--r--chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc11
-rw-r--r--chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h3
-rw-r--r--chrome/browser/invalidation/profile_invalidation_provider_factory.h2
-rw-r--r--chrome/chrome_browser_chromeos.gypi2
-rw-r--r--chrome/chrome_tests_unit.gypi1
8 files changed, 1129 insertions, 0 deletions
diff --git a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.cc b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.cc
new file mode 100644
index 0000000..7fbbdf3
--- /dev/null
+++ b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.cc
@@ -0,0 +1,343 @@
+// Copyright 2015 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/chromeos/policy/affiliated_invalidation_service_provider.h"
+
+#include <vector>
+
+#include "base/logging.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part_chromeos.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
+#include "chrome/browser/chromeos/policy/ticl_device_settings_provider.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/chromeos/settings/device_identity_provider.h"
+#include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
+#include "chrome/browser/invalidation/profile_invalidation_provider_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/common/chrome_content_client.h"
+#include "components/invalidation/invalidation_handler.h"
+#include "components/invalidation/invalidation_service.h"
+#include "components/invalidation/invalidation_state_tracker.h"
+#include "components/invalidation/invalidator_state.h"
+#include "components/invalidation/invalidator_storage.h"
+#include "components/invalidation/profile_invalidation_provider.h"
+#include "components/invalidation/ticl_invalidation_service.h"
+#include "components/invalidation/ticl_settings_provider.h"
+#include "components/policy/core/common/cloud/cloud_policy_constants.h"
+#include "components/user_manager/user.h"
+#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_service.h"
+#include "google_apis/gaia/identity_provider.h"
+
+namespace policy {
+
+AffiliatedInvalidationServiceProvider::Consumer::~Consumer() {
+}
+
+class AffiliatedInvalidationServiceProvider::InvalidationServiceObserver
+ : public syncer::InvalidationHandler {
+ public:
+ explicit InvalidationServiceObserver(
+ AffiliatedInvalidationServiceProvider* parent,
+ invalidation::InvalidationService* invalidation_service);
+ ~InvalidationServiceObserver() override;
+
+ invalidation::InvalidationService* GetInvalidationService();
+ bool IsServiceConnected() const;
+
+ // public syncer::InvalidationHandler:
+ void OnInvalidatorStateChange(syncer::InvalidatorState state) override;
+ void OnIncomingInvalidation(
+ const syncer::ObjectIdInvalidationMap& invalidation_map) override;
+ std::string GetOwnerName() const override;
+
+ private:
+ AffiliatedInvalidationServiceProvider* parent_;
+ invalidation::InvalidationService* invalidation_service_;
+ bool is_service_connected_;
+ bool is_observer_ready_;
+
+ DISALLOW_COPY_AND_ASSIGN(InvalidationServiceObserver);
+};
+
+AffiliatedInvalidationServiceProvider::InvalidationServiceObserver::
+ InvalidationServiceObserver(
+ AffiliatedInvalidationServiceProvider* parent,
+ invalidation::InvalidationService* invalidation_service)
+ : parent_(parent),
+ invalidation_service_(invalidation_service),
+ is_service_connected_(false),
+ is_observer_ready_(false) {
+ invalidation_service_->RegisterInvalidationHandler(this);
+ is_service_connected_ = invalidation_service->GetInvalidatorState() ==
+ syncer::INVALIDATIONS_ENABLED;
+ is_observer_ready_ = true;
+}
+
+AffiliatedInvalidationServiceProvider::InvalidationServiceObserver::
+ ~InvalidationServiceObserver() {
+ is_observer_ready_ = false;
+ invalidation_service_->UnregisterInvalidationHandler(this);
+}
+
+invalidation::InvalidationService*
+AffiliatedInvalidationServiceProvider::InvalidationServiceObserver::
+ GetInvalidationService() {
+ return invalidation_service_;
+}
+
+bool AffiliatedInvalidationServiceProvider::InvalidationServiceObserver::
+ IsServiceConnected() const {
+ return is_service_connected_;
+}
+
+void AffiliatedInvalidationServiceProvider::InvalidationServiceObserver::
+ OnInvalidatorStateChange(syncer::InvalidatorState state) {
+ if (!is_observer_ready_)
+ return;
+
+ const bool is_service_connected = (state == syncer::INVALIDATIONS_ENABLED);
+ if (is_service_connected == is_service_connected_)
+ return;
+
+ is_service_connected_ = is_service_connected;
+ if (is_service_connected_)
+ parent_->OnInvalidationServiceConnected(invalidation_service_);
+ else
+ parent_->OnInvalidationServiceDisconnected(invalidation_service_);
+}
+
+void AffiliatedInvalidationServiceProvider::InvalidationServiceObserver::
+ OnIncomingInvalidation(
+ const syncer::ObjectIdInvalidationMap& invalidation_map) {
+}
+
+std::string AffiliatedInvalidationServiceProvider::InvalidationServiceObserver::
+ GetOwnerName() const {
+ return "AffiliatedInvalidationService";
+}
+
+AffiliatedInvalidationServiceProvider::AffiliatedInvalidationServiceProvider()
+ : invalidation_service_(nullptr),
+ consumer_count_(0),
+ is_shut_down_(false) {
+ // The AffiliatedInvalidationServiceProvider should be created before any user
+ // Profiles.
+ DCHECK(g_browser_process->profile_manager()->GetLoadedProfiles().empty());
+
+ // Subscribe to notification about new user profiles becoming available.
+ registrar_.Add(this,
+ chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
+ content::NotificationService::AllSources());
+}
+
+AffiliatedInvalidationServiceProvider::
+~AffiliatedInvalidationServiceProvider() {
+ // Verify that the provider was shut down first.
+ DCHECK(is_shut_down_);
+}
+
+void AffiliatedInvalidationServiceProvider::Observe(
+ int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ DCHECK_EQ(chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED, type);
+ DCHECK(!is_shut_down_);
+ Profile* profile = content::Details<Profile>(details).ptr();
+ invalidation::ProfileInvalidationProvider* invalidation_provider =
+ invalidation::ProfileInvalidationProviderFactory::GetForProfile(profile);
+ if (!invalidation_provider) {
+ // If the Profile does not support invalidation (e.g. guest, incognito),
+ // ignore it.
+ return;
+ }
+ user_manager::User* user =
+ chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+ if (!user ||
+ g_browser_process->platform_part()->browser_policy_connector_chromeos()->
+ GetUserAffiliation(user->email()) != USER_AFFILIATION_MANAGED) {
+ // If the Profile belongs to a user who is not affiliated with the device's
+ // enrollment domain, ignore it.
+ return;
+ }
+
+ // Create a state observer for the user's invalidation service.
+ invalidation::InvalidationService* invalidation_service =
+ invalidation_provider->GetInvalidationService();
+ profile_invalidation_service_observers_.push_back(
+ new InvalidationServiceObserver(this, invalidation_service));
+
+ if (profile_invalidation_service_observers_.back()->IsServiceConnected()) {
+ // If the invalidation service is connected, check whether to switch to it.
+ OnInvalidationServiceConnected(invalidation_service);
+ }
+}
+
+void AffiliatedInvalidationServiceProvider::RegisterConsumer(
+ Consumer* consumer) {
+ if (consumers_.HasObserver(consumer) || is_shut_down_)
+ return;
+
+ consumers_.AddObserver(consumer);
+ ++consumer_count_;
+
+ if (invalidation_service_)
+ consumer->OnInvalidationServiceSet(invalidation_service_);
+ else if (consumer_count_ == 1)
+ FindConnectedInvalidationService();
+}
+
+void AffiliatedInvalidationServiceProvider::UnregisterConsumer(
+ Consumer* consumer) {
+ if (!consumers_.HasObserver(consumer))
+ return;
+
+ consumers_.RemoveObserver(consumer);
+ --consumer_count_;
+
+ if (invalidation_service_ && consumer_count_ == 0) {
+ invalidation_service_ = nullptr;
+ DestroyDeviceInvalidationService();
+ }
+}
+
+void AffiliatedInvalidationServiceProvider::Shutdown() {
+ is_shut_down_ = true;
+
+ registrar_.RemoveAll();
+ profile_invalidation_service_observers_.clear();
+ DestroyDeviceInvalidationService();
+
+ if (invalidation_service_) {
+ invalidation_service_ = nullptr;
+ // Explicitly notify consumers that the invalidation service they were using
+ // is no longer available.
+ SetInvalidationService(nullptr);
+ }
+}
+
+invalidation::TiclInvalidationService*
+AffiliatedInvalidationServiceProvider::
+ GetDeviceInvalidationServiceForTest() const {
+ return device_invalidation_service_.get();
+}
+
+void AffiliatedInvalidationServiceProvider::OnInvalidationServiceConnected(
+ invalidation::InvalidationService* invalidation_service) {
+ DCHECK(!is_shut_down_);
+
+ if (consumer_count_ == 0) {
+ // If there are no consumers, no invalidation service is required.
+ return;
+ }
+
+ if (!device_invalidation_service_) {
+ // The lack of a device-global invalidation service implies that another
+ // connected invalidation service is being made available to consumers
+ // already. There is no need to switch from that to the service which just
+ // connected.
+ return;
+ }
+
+ if (invalidation_service != device_invalidation_service_.get()) {
+ // If an invalidation service other than the device-global one connected,
+ // destroy the device-global service.
+ invalidation_service_ = nullptr;
+ DestroyDeviceInvalidationService();
+ }
+
+ // Make the invalidation service that just connected available to consumers.
+ SetInvalidationService(invalidation_service);
+}
+
+void AffiliatedInvalidationServiceProvider::OnInvalidationServiceDisconnected(
+ invalidation::InvalidationService* invalidation_service) {
+ DCHECK(!is_shut_down_);
+
+ if (invalidation_service != invalidation_service_) {
+ // If the invalidation service which disconnected was not being made
+ // available to consumers, return.
+ return;
+ }
+
+ // The invalidation service which disconnected was being made available to
+ // consumers. Stop making it available.
+ DCHECK(consumer_count_);
+ invalidation_service_ = nullptr;
+
+ // Try to make another invalidation service available to consumers.
+ FindConnectedInvalidationService();
+
+ // If no other connected invalidation service was found, explicitly notify
+ // consumers that the invalidation service they were using is no longer
+ // available.
+ if (!invalidation_service_)
+ SetInvalidationService(nullptr);
+}
+
+void AffiliatedInvalidationServiceProvider::FindConnectedInvalidationService() {
+ DCHECK(!invalidation_service_);
+ DCHECK(consumer_count_);
+ DCHECK(!is_shut_down_);
+
+ for (ScopedVector<InvalidationServiceObserver>::const_iterator it =
+ profile_invalidation_service_observers_.begin();
+ it != profile_invalidation_service_observers_.end(); ++it) {
+ if ((*it)->IsServiceConnected()) {
+ // If a connected invalidation service belonging to an affiliated
+ // logged-in user is found, make it available to consumers.
+ DestroyDeviceInvalidationService();
+ SetInvalidationService((*it)->GetInvalidationService());
+ return;
+ }
+ }
+
+ if (!device_invalidation_service_) {
+ // If no other connected invalidation service was found and no device-global
+ // invalidation service exists, create one.
+ device_invalidation_service_.reset(
+ new invalidation::TiclInvalidationService(
+ GetUserAgent(),
+ scoped_ptr<IdentityProvider>(new chromeos::DeviceIdentityProvider(
+ chromeos::DeviceOAuth2TokenServiceFactory::Get())),
+ scoped_ptr<invalidation::TiclSettingsProvider>(
+ new TiclDeviceSettingsProvider),
+ g_browser_process->gcm_driver(),
+ g_browser_process->system_request_context()));
+ device_invalidation_service_->Init(
+ scoped_ptr<syncer::InvalidationStateTracker>(
+ new invalidation::InvalidatorStorage(
+ g_browser_process->local_state())));
+ device_invalidation_service_observer_.reset(
+ new InvalidationServiceObserver(
+ this,
+ device_invalidation_service_.get()));
+ }
+
+ if (device_invalidation_service_observer_->IsServiceConnected()) {
+ // If the device-global invalidation service is connected already, make it
+ // available to consumers immediately. Otherwise, the invalidation service
+ // will be made available to clients when it successfully connects.
+ OnInvalidationServiceConnected(device_invalidation_service_.get());
+ }
+}
+
+void AffiliatedInvalidationServiceProvider::SetInvalidationService(
+ invalidation::InvalidationService* invalidation_service) {
+ DCHECK(!invalidation_service_);
+ invalidation_service_ = invalidation_service;
+ FOR_EACH_OBSERVER(Consumer,
+ consumers_,
+ OnInvalidationServiceSet(invalidation_service_));
+}
+
+void AffiliatedInvalidationServiceProvider::DestroyDeviceInvalidationService() {
+ device_invalidation_service_observer_.reset();
+ device_invalidation_service_.reset();
+}
+
+} // namespace policy
diff --git a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.h b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.h
new file mode 100644
index 0000000..5484355
--- /dev/null
+++ b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.h
@@ -0,0 +1,140 @@
+// Copyright 2015 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_POLICY_AFFILIATED_INVALIDATION_SERVICE_PROVIDER_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_AFFILIATED_INVALIDATION_SERVICE_PROVIDER_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/observer_list.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+
+namespace invalidation {
+class InvalidationService;
+class TiclInvalidationService;
+}
+
+namespace policy {
+
+// This class provides access to an |InvalidationService| that can be used to
+// subscribe to invalidations generated by the device's enrollment domain, e.g.
+// policy pushing and remote commands for:
+// * the device itself
+// * device-local accounts
+// * other users affiliated with the enrollment domain
+//
+// If an affiliated user with a connected invalidation service is logged in,
+// that invalidation service will be used to conserve server resources. If there
+// are no logged-in users matching these criteria, a device-global
+// |TiclInvalidationService| is spun up.
+// The class monitors the status of the invalidation services and switches
+// between them whenever the service currently in use disconnects or the
+// device-global invalidation service can be replaced with another service that
+// just connected.
+class AffiliatedInvalidationServiceProvider
+ : public content::NotificationObserver {
+ public:
+ class Consumer {
+ public:
+ // This method is called when the invalidation service that the consumer
+ // should use changes:
+ // * If |invalidation_service| is a nullptr, no invalidation service is
+ // currently available for use.
+ // * Otherwise, |invalidation_service| is the invalidation service that the
+ // consumer should use. It is guaranteed to be connected. Any previously
+ // provided invalidation services must no longer be used.
+ virtual void OnInvalidationServiceSet(
+ invalidation::InvalidationService* invalidation_service) = 0;
+
+ protected:
+ virtual ~Consumer();
+ };
+
+ AffiliatedInvalidationServiceProvider();
+ ~AffiliatedInvalidationServiceProvider() override;
+
+ // content::NotificationObserver:
+ void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) override;
+
+ // Indicates that |consumer| is interested in using the shared
+ // |InvalidationService|. The consumer's OnInvalidationServiceSet() method
+ // will be called back when a connected invalidation service becomes
+ // available. If an invalidation service is available already, the callback
+ // will occur synchronously. The |consumer| must be unregistered before |this|
+ // is destroyed.
+ void RegisterConsumer(Consumer* consumer);
+
+ // Indicates that |consumer| is no longer interested in using the
+ // shared |InvalidationService|.
+ void UnregisterConsumer(Consumer* consumer);
+
+ // Shuts down the provider. Once the provider is shut down, it no longer makes
+ // any invalidation service available to consumers, no longer observes any
+ // per-profile invalidation services and no longer maintains a device-global
+ // invalidation service.
+ void Shutdown();
+
+ invalidation::TiclInvalidationService*
+ GetDeviceInvalidationServiceForTest() const;
+
+ private:
+ // Helper that monitors the status of a single |InvalidationService|.
+ class InvalidationServiceObserver;
+
+ // Status updates received from |InvalidationServiceObserver|s.
+ void OnInvalidationServiceConnected(
+ invalidation::InvalidationService* invalidation_service);
+ void OnInvalidationServiceDisconnected(
+ invalidation::InvalidationService* invalidation_service);
+
+ // Checks whether a connected |InvalidationService| affiliated with the
+ // device's enrollment domain is available. If so, notifies the consumers.
+ // Otherwise, consumers will be notified once such an invalidation service
+ // becomes available.
+ // Further ensures that a device-global invalidation service is running iff
+ // there is no other connected service available for use and there is at least
+ // one registered consumer.
+ void FindConnectedInvalidationService();
+
+ // Choose |invalidation_service| as the shared invalidation service and notify
+ // consumers.
+ void SetInvalidationService(
+ invalidation::InvalidationService* invalidation_service);
+
+ // Destroy the device-global invalidation service, if any.
+ void DestroyDeviceInvalidationService();
+
+ content::NotificationRegistrar registrar_;
+
+ // Device-global invalidation service.
+ scoped_ptr<invalidation::TiclInvalidationService>
+ device_invalidation_service_;
+
+ // State observer for the device-global invalidation service.
+ scoped_ptr<InvalidationServiceObserver> device_invalidation_service_observer_;
+
+ // State observers for logged-in users' invalidation services.
+ ScopedVector<InvalidationServiceObserver>
+ profile_invalidation_service_observers_;
+
+ // The invalidation service currently used by consumers. nullptr if there are
+ // no registered consumers or no connected invalidation service is available
+ // for use.
+ invalidation::InvalidationService* invalidation_service_;
+
+ ObserverList<Consumer, true> consumers_;
+ int consumer_count_;
+
+ bool is_shut_down_;
+
+ DISALLOW_COPY_AND_ASSIGN(AffiliatedInvalidationServiceProvider);
+};
+
+} // namespace policy
+
+#endif // CHROME_BROWSER_CHROMEOS_POLICY_AFFILIATED_INVALIDATION_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_unittest.cc b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_unittest.cc
new file mode 100644
index 0000000..5c1cb60
--- /dev/null
+++ b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_unittest.cc
@@ -0,0 +1,627 @@
+// Copyright 2015 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/chromeos/policy/affiliated_invalidation_service_provider.h"
+
+#include <string>
+
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
+#include "chrome/browser/chromeos/policy/stub_enterprise_install_attributes.h"
+#include "chrome/browser/chromeos/settings/cros_settings.h"
+#include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
+#include "chrome/browser/chromeos/settings/device_settings_service.h"
+#include "chrome/browser/invalidation/fake_invalidation_service.h"
+#include "chrome/browser/invalidation/profile_invalidation_provider_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/testing_profile_manager.h"
+#include "chromeos/cryptohome/system_salt_getter.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "components/invalidation/invalidation_service.h"
+#include "components/invalidation/invalidator_state.h"
+#include "components/invalidation/profile_invalidation_provider.h"
+#include "components/invalidation/ticl_invalidation_service.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/policy/core/common/cloud/cloud_policy_constants.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::Mock;
+using testing::StrictMock;
+
+namespace policy {
+
+namespace {
+
+const char kAffiliatedUserID1[] = "test_1@example.com";
+const char kAffiliatedUserID2[] = "test_2@example.com";
+const char kUnaffiliatedUserID[] = "test@other_domain.test";
+
+KeyedService* BuildProfileInvalidationProvider(
+ content::BrowserContext* context) {
+ scoped_ptr<invalidation::FakeInvalidationService> invalidation_service(
+ new invalidation::FakeInvalidationService);
+ invalidation_service->SetInvalidatorState(
+ syncer::TRANSIENT_INVALIDATION_ERROR);
+ return new invalidation::ProfileInvalidationProvider(
+ invalidation_service.Pass());
+}
+
+} // namespace
+
+class MockConsumer : public AffiliatedInvalidationServiceProvider::Consumer {
+ public:
+ MockConsumer();
+ ~MockConsumer() override;
+
+ MOCK_METHOD1(OnInvalidationServiceSet,
+ void(invalidation::InvalidationService*));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockConsumer);
+};
+
+class AffiliatedInvalidationServiceProviderTest : public testing::Test {
+ public:
+ AffiliatedInvalidationServiceProviderTest();
+
+ // testing::Test:
+ virtual void SetUp() override;
+ virtual void TearDown() override;
+
+ // Ownership is not passed. The Profile is owned by the global ProfileManager.
+ Profile* LogInAndReturnProfile(const std::string& user_id);
+
+ // Logs in as an affiliated user and indicates that the per-profile
+ // invalidation service for this user connected. Verifies that this
+ // invalidation service is made available to the |consumer_| and the
+ // device-global invalidation service is destroyed.
+ void LogInAsAffiliatedUserAndConnectInvalidationService();
+
+ // Logs in as an unaffiliated user and indicates that the per-profile
+ // invalidation service for this user connected. Verifies that this
+ // invalidation service is ignored and the device-global invalidation service
+ // is not destroyed.
+ void LogInAsUnaffiliatedUserAndConnectInvalidationService();
+
+ // Indicates that the device-global invalidation service connected. Verifies
+ // that the |consumer_| is informed about this.
+ void ConnectDeviceGlobalInvalidationService();
+
+ // Indicates that the logged-in user's per-profile invalidation service
+ // disconnected. Verifies that the |consumer_| is informed about this and a
+ // device-global invalidation service is created.
+ void DisconnectPerProfileInvalidationService();
+
+ invalidation::FakeInvalidationService* GetProfileInvalidationService(
+ Profile* profile,
+ bool create);
+
+ protected:
+ scoped_ptr<AffiliatedInvalidationServiceProvider> provider_;
+ StrictMock<MockConsumer> consumer_;
+ invalidation::TiclInvalidationService* device_invalidation_service_;
+ invalidation::FakeInvalidationService* profile_invalidation_service_;
+
+ private:
+ content::TestBrowserThreadBundle thread_bundle_;
+ chromeos::FakeUserManager* fake_user_manager_;
+ chromeos::ScopedUserManagerEnabler user_manager_enabler_;
+ ScopedStubEnterpriseInstallAttributes install_attributes_;
+ scoped_ptr<chromeos::ScopedTestDeviceSettingsService>
+ test_device_settings_service_;
+ scoped_ptr<chromeos::ScopedTestCrosSettings> test_cros_settings_;
+ TestingProfileManager profile_manager_;
+};
+
+MockConsumer::MockConsumer() {
+}
+
+MockConsumer::~MockConsumer() {
+}
+
+AffiliatedInvalidationServiceProviderTest::
+AffiliatedInvalidationServiceProviderTest()
+ : device_invalidation_service_(nullptr),
+ profile_invalidation_service_(nullptr),
+ fake_user_manager_(new chromeos::FakeUserManager),
+ user_manager_enabler_(fake_user_manager_),
+ install_attributes_("example.com",
+ "user@example.com",
+ "device_id",
+ DEVICE_MODE_ENTERPRISE),
+ profile_manager_(TestingBrowserProcess::GetGlobal()) {
+}
+
+void AffiliatedInvalidationServiceProviderTest::SetUp() {
+ chromeos::SystemSaltGetter::Initialize();
+ chromeos::DBusThreadManager::Initialize();
+ chromeos::DeviceOAuth2TokenServiceFactory::Initialize();
+ ASSERT_TRUE(profile_manager_.SetUp());
+
+ test_device_settings_service_.reset(new
+ chromeos::ScopedTestDeviceSettingsService);
+ test_cros_settings_.reset(new chromeos::ScopedTestCrosSettings);
+
+ invalidation::ProfileInvalidationProviderFactory::GetInstance()->
+ RegisterTestingFactory(BuildProfileInvalidationProvider);
+
+ provider_.reset(new AffiliatedInvalidationServiceProvider);
+}
+
+void AffiliatedInvalidationServiceProviderTest::TearDown() {
+ provider_->Shutdown();
+ provider_.reset();
+
+ invalidation::ProfileInvalidationProviderFactory::GetInstance()->
+ RegisterTestingFactory(nullptr);
+ chromeos::DeviceOAuth2TokenServiceFactory::Shutdown();
+ chromeos::DBusThreadManager::Shutdown();
+ chromeos::SystemSaltGetter::Shutdown();
+}
+
+Profile* AffiliatedInvalidationServiceProviderTest::LogInAndReturnProfile(
+ const std::string& user_id) {
+ fake_user_manager_->AddUser(user_id);
+ Profile* profile = profile_manager_.CreateTestingProfile(user_id);
+ content::NotificationService::current()->Notify(
+ chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
+ content::NotificationService::AllSources(),
+ content::Details<Profile>(profile));
+ return profile;
+}
+
+void AffiliatedInvalidationServiceProviderTest::
+ LogInAsAffiliatedUserAndConnectInvalidationService() {
+ Mock::VerifyAndClearExpectations(&consumer_);
+
+ // Log in as an affiliated user.
+ Profile* profile = LogInAndReturnProfile(kAffiliatedUserID1);
+ EXPECT_TRUE(profile);
+ Mock::VerifyAndClearExpectations(&consumer_);
+
+ // Verify that a per-profile invalidation service has been created.
+ profile_invalidation_service_ =
+ GetProfileInvalidationService(profile, false /* create */);
+ ASSERT_TRUE(profile_invalidation_service_);
+
+ // Verify that the device-global invalidation service still exists.
+ EXPECT_TRUE(provider_->GetDeviceInvalidationServiceForTest());
+
+ // Indicate that the per-profile invalidation service has connected. Verify
+ // that the consumer is informed about this.
+ EXPECT_CALL(consumer_,
+ OnInvalidationServiceSet(profile_invalidation_service_)).Times(1);
+ profile_invalidation_service_->SetInvalidatorState(
+ syncer::INVALIDATIONS_ENABLED);
+ Mock::VerifyAndClearExpectations(&consumer_);
+
+ // Verify that the device-global invalidation service has been destroyed.
+ EXPECT_FALSE(provider_->GetDeviceInvalidationServiceForTest());
+
+ Mock::VerifyAndClearExpectations(&consumer_);
+}
+
+void AffiliatedInvalidationServiceProviderTest::
+ LogInAsUnaffiliatedUserAndConnectInvalidationService() {
+ Mock::VerifyAndClearExpectations(&consumer_);
+
+ // Log in as an unaffiliated user.
+ Profile* profile = LogInAndReturnProfile(kUnaffiliatedUserID);
+ EXPECT_TRUE(profile);
+
+ // Verify that a per-profile invalidation service has been created.
+ profile_invalidation_service_ =
+ GetProfileInvalidationService(profile, false /* create */);
+ ASSERT_TRUE(profile_invalidation_service_);
+
+ // Verify that the device-global invalidation service still exists.
+ EXPECT_TRUE(provider_->GetDeviceInvalidationServiceForTest());
+
+ // Indicate that the per-profile invalidation service has connected. Verify
+ // that the consumer is not called back.
+ profile_invalidation_service_->SetInvalidatorState(
+ syncer::INVALIDATIONS_ENABLED);
+
+ // Verify that the device-global invalidation service still exists.
+ EXPECT_TRUE(provider_->GetDeviceInvalidationServiceForTest());
+
+ Mock::VerifyAndClearExpectations(&consumer_);
+}
+
+void AffiliatedInvalidationServiceProviderTest::
+ ConnectDeviceGlobalInvalidationService() {
+ Mock::VerifyAndClearExpectations(&consumer_);
+
+ // Verify that a device-global invalidation service has been created.
+ device_invalidation_service_ =
+ provider_->GetDeviceInvalidationServiceForTest();
+ ASSERT_TRUE(device_invalidation_service_);
+
+ // Indicate that the device-global invalidation service has connected. Verify
+ // that the consumer is informed about this.
+ EXPECT_CALL(consumer_, OnInvalidationServiceSet(device_invalidation_service_))
+ .Times(1);
+ device_invalidation_service_->OnInvalidatorStateChange(
+ syncer::INVALIDATIONS_ENABLED);
+
+ Mock::VerifyAndClearExpectations(&consumer_);
+}
+
+void AffiliatedInvalidationServiceProviderTest::
+ DisconnectPerProfileInvalidationService() {
+ Mock::VerifyAndClearExpectations(&consumer_);
+
+ ASSERT_TRUE(profile_invalidation_service_);
+
+ // Indicate that the per-profile invalidation service has disconnected. Verify
+ // that the consumer is informed about this.
+ EXPECT_CALL(consumer_, OnInvalidationServiceSet(nullptr)).Times(1);
+ profile_invalidation_service_->SetInvalidatorState(
+ syncer::INVALIDATION_CREDENTIALS_REJECTED);
+
+ // Verify that a device-global invalidation service has been created.
+ EXPECT_TRUE(provider_->GetDeviceInvalidationServiceForTest());
+
+ Mock::VerifyAndClearExpectations(&consumer_);
+}
+
+invalidation::FakeInvalidationService*
+AffiliatedInvalidationServiceProviderTest::GetProfileInvalidationService(
+ Profile* profile, bool create) {
+ invalidation::ProfileInvalidationProvider* invalidation_provider =
+ static_cast<invalidation::ProfileInvalidationProvider*>(
+ invalidation::ProfileInvalidationProviderFactory::GetInstance()->
+ GetServiceForBrowserContext(profile, create));
+ if (!invalidation_provider)
+ return nullptr;
+ return static_cast<invalidation::FakeInvalidationService*>(
+ invalidation_provider->GetInvalidationService());
+}
+
+// No consumers are registered with the AffiliatedInvalidationServiceProvider.
+// Verifies that no device-global invalidation service is created, whether an
+// affiliated user is logged in or not.
+TEST_F(AffiliatedInvalidationServiceProviderTest, NoConsumers) {
+ // Verify that no device-global invalidation service has been created.
+ EXPECT_FALSE(provider_->GetDeviceInvalidationServiceForTest());
+
+ // Log in as an affiliated user.
+ EXPECT_TRUE(LogInAndReturnProfile(kAffiliatedUserID1));
+
+ // Verify that no device-global invalidation service has been created.
+ EXPECT_FALSE(provider_->GetDeviceInvalidationServiceForTest());
+}
+
+// A consumer is registered with the AffiliatedInvalidationServiceProvider.
+// Verifies that when no per-profile invalidation service belonging to an
+// affiliated user is available, a device-global invalidation service is
+// created. Further verifies that when the device-global invalidation service
+// connects, it is made available to the consumer.
+TEST_F(AffiliatedInvalidationServiceProviderTest,
+ UseDeviceInvalidationService) {
+ // Register a consumer. Verify that the consumer is not called back
+ // immediately as no connected invalidation service exists yet.
+ provider_->RegisterConsumer(&consumer_);
+
+ // Indicate that the device-global invalidation service connected. Verify that
+ // that the consumer is informed about this.
+ ConnectDeviceGlobalInvalidationService();
+
+ // Indicate that the device-global invalidation service has disconnected.
+ // Verify that the consumer is informed about this.
+ EXPECT_CALL(consumer_, OnInvalidationServiceSet(nullptr)).Times(1);
+ device_invalidation_service_->OnInvalidatorStateChange(
+ syncer::INVALIDATION_CREDENTIALS_REJECTED);
+ Mock::VerifyAndClearExpectations(&consumer_);
+
+ // Verify that the device-global invalidation service still exists.
+ EXPECT_TRUE(provider_->GetDeviceInvalidationServiceForTest());
+
+ // Unregister the consumer.
+ provider_->UnregisterConsumer(&consumer_);
+ Mock::VerifyAndClearExpectations(&consumer_);
+}
+
+// A consumer is registered with the AffiliatedInvalidationServiceProvider.
+// Verifies that when a per-profile invalidation service belonging to an
+// affiliated user connects, it is made available to the consumer.
+TEST_F(AffiliatedInvalidationServiceProviderTest,
+ UseAffiliatedProfileInvalidationService) {
+ // Register a consumer. Verify that the consumer is not called back
+ // immediately as no connected invalidation service exists yet.
+ provider_->RegisterConsumer(&consumer_);
+
+ // Verify that a device-global invalidation service has been created.
+ EXPECT_TRUE(provider_->GetDeviceInvalidationServiceForTest());
+
+ // Log in as an affiliated user and indicate that the per-profile invalidation
+ // service for this user connected. Verify that this invalidation service is
+ // made available to the |consumer_| and the device-global invalidation
+ // service is destroyed.
+ LogInAsAffiliatedUserAndConnectInvalidationService();
+
+ // Indicate that the logged-in user's per-profile invalidation service
+ // disconnected. Verify that the consumer is informed about this and a
+ // device-global invalidation service is created.
+ DisconnectPerProfileInvalidationService();
+
+ // Unregister the consumer.
+ provider_->UnregisterConsumer(&consumer_);
+ Mock::VerifyAndClearExpectations(&consumer_);
+}
+
+// A consumer is registered with the AffiliatedInvalidationServiceProvider.
+// Verifies that when a per-profile invalidation service belonging to an
+// unaffiliated user connects, it is ignored.
+TEST_F(AffiliatedInvalidationServiceProviderTest,
+ DoNotUseUnaffiliatedProfileInvalidationService) {
+ // Register a consumer. Verify that the consumer is not called back
+ // immediately as no connected invalidation service exists yet.
+ provider_->RegisterConsumer(&consumer_);
+
+ // Verify that a device-global invalidation service has been created.
+ EXPECT_TRUE(provider_->GetDeviceInvalidationServiceForTest());
+
+ // Log in as an unaffiliated user and indicate that the per-profile
+ // invalidation service for this user connected. Verify that this invalidation
+ // service is ignored and the device-global invalidation service is not
+ // destroyed.
+ LogInAsUnaffiliatedUserAndConnectInvalidationService();
+
+ // Unregister the consumer.
+ provider_->UnregisterConsumer(&consumer_);
+ Mock::VerifyAndClearExpectations(&consumer_);
+}
+
+// A consumer is registered with the AffiliatedInvalidationServiceProvider. A
+// device-global invalidation service exists, is connected and is made available
+// to the consumer. Verifies that when a per-profile invalidation service
+// belonging to an affiliated user connects, it is made available to the
+// consumer instead and the device-global invalidation service is destroyed.
+TEST_F(AffiliatedInvalidationServiceProviderTest,
+ SwitchToAffiliatedProfileInvalidationService) {
+ // Register a consumer. Verify that the consumer is not called back
+ // immediately as no connected invalidation service exists yet.
+ provider_->RegisterConsumer(&consumer_);
+
+ // Indicate that the device-global invalidation service connected. Verify that
+ // that the consumer is informed about this.
+ ConnectDeviceGlobalInvalidationService();
+
+ // Log in as an affiliated user and indicate that the per-profile invalidation
+ // service for this user connected. Verify that this invalidation service is
+ // made available to the |consumer_| and the device-global invalidation
+ // service is destroyed.
+ LogInAsAffiliatedUserAndConnectInvalidationService();
+
+ // Unregister the consumer.
+ provider_->UnregisterConsumer(&consumer_);
+ Mock::VerifyAndClearExpectations(&consumer_);
+}
+
+// A consumer is registered with the AffiliatedInvalidationServiceProvider. A
+// device-global invalidation service exists, is connected and is made available
+// to the consumer. Verifies that when a per-profile invalidation service
+// belonging to an unaffiliated user connects, it is ignored and the
+// device-global invalidation service continues to be made available to the
+// consumer.
+TEST_F(AffiliatedInvalidationServiceProviderTest,
+ DoNotSwitchToUnaffiliatedProfileInvalidationService) {
+ // Register a consumer. Verify that the consumer is not called back
+ // immediately as no connected invalidation service exists yet.
+ provider_->RegisterConsumer(&consumer_);
+
+ // Indicate that the device-global invalidation service connected. Verify that
+ // that the consumer is informed about this.
+ ConnectDeviceGlobalInvalidationService();
+
+ // Log in as an unaffiliated user and indicate that the per-profile
+ // invalidation service for this user connected. Verify that this invalidation
+ // service is ignored and the device-global invalidation service is not
+ // destroyed.
+ LogInAsUnaffiliatedUserAndConnectInvalidationService();
+
+ // Unregister the consumer.
+ provider_->UnregisterConsumer(&consumer_);
+ Mock::VerifyAndClearExpectations(&consumer_);
+}
+
+// A consumer is registered with the AffiliatedInvalidationServiceProvider. A
+// per-profile invalidation service belonging to an affiliated user exists, is
+// connected and is made available to the consumer. Verifies that when the
+// per-profile invalidation service disconnects, a device-global invalidation
+// service is created. Further verifies that when the device-global invalidation
+// service connects, it is made available to the consumer.
+TEST_F(AffiliatedInvalidationServiceProviderTest,
+ SwitchToDeviceInvalidationService) {
+ // Register a consumer. Verify that the consumer is not called back
+ // immediately as no connected invalidation service exists yet.
+ provider_->RegisterConsumer(&consumer_);
+
+ // Verify that a device-global invalidation service has been created.
+ EXPECT_TRUE(provider_->GetDeviceInvalidationServiceForTest());
+
+ // Log in as an affiliated user and indicate that the per-profile invalidation
+ // service for this user connected. Verify that this invalidation service is
+ // made available to the |consumer_| and the device-global invalidation
+ // service is destroyed.
+ LogInAsAffiliatedUserAndConnectInvalidationService();
+
+ // Indicate that the logged-in user's per-profile invalidation service
+ // disconnected. Verify that the consumer is informed about this and a
+ // device-global invalidation service is created.
+ DisconnectPerProfileInvalidationService();
+
+ // Indicate that the device-global invalidation service connected. Verify that
+ // that the consumer is informed about this.
+ ConnectDeviceGlobalInvalidationService();
+
+ // Unregister the consumer.
+ provider_->UnregisterConsumer(&consumer_);
+ Mock::VerifyAndClearExpectations(&consumer_);
+}
+
+// A consumer is registered with the AffiliatedInvalidationServiceProvider. A
+// per-profile invalidation service belonging to a first affiliated user exists,
+// is connected and is made available to the consumer. A per-profile
+// invalidation service belonging to a second affiliated user also exists and is
+// connected. Verifies that when the per-profile invalidation service belonging
+// to the first user disconnects, the per-profile invalidation service belonging
+// to the second user is made available to the consumer instead.
+TEST_F(AffiliatedInvalidationServiceProviderTest,
+ SwitchBetweenAffiliatedProfileInvalidationServices) {
+ // Register a consumer. Verify that the consumer is not called back
+ // immediately as no connected invalidation service exists yet.
+ provider_->RegisterConsumer(&consumer_);
+
+ // Verify that a device-global invalidation service has been created.
+ EXPECT_TRUE(provider_->GetDeviceInvalidationServiceForTest());
+
+ // Log in as a first affiliated user and indicate that the per-profile
+ // invalidation service for this user connected. Verify that this invalidation
+ // service is made available to the |consumer_| and the device-global
+ // invalidation service is destroyed.
+ LogInAsAffiliatedUserAndConnectInvalidationService();
+
+ // Log in as a second affiliated user.
+ Profile* second_profile = LogInAndReturnProfile(kAffiliatedUserID2);
+ EXPECT_TRUE(second_profile);
+
+ // Verify that the device-global invalidation service still does not exist.
+ EXPECT_FALSE(provider_->GetDeviceInvalidationServiceForTest());
+
+ // Verify that a per-profile invalidation service for the second user has been
+ // created.
+ invalidation::FakeInvalidationService* second_profile_invalidation_service =
+ GetProfileInvalidationService(second_profile, false /* create */);
+ ASSERT_TRUE(second_profile_invalidation_service);
+
+ // Indicate that the second user's per-profile invalidation service has
+ // connected. Verify that the consumer is not called back.
+ second_profile_invalidation_service->SetInvalidatorState(
+ syncer::INVALIDATIONS_ENABLED);
+ Mock::VerifyAndClearExpectations(&consumer_);
+
+ // Indicate that the first user's per-profile invalidation service has
+ // disconnected. Verify that the consumer is informed that the second user's
+ // per-profile invalidation service should be used instead of the first
+ // user's.
+ EXPECT_CALL(consumer_,
+ OnInvalidationServiceSet(second_profile_invalidation_service))
+ .Times(1);
+ profile_invalidation_service_->SetInvalidatorState(
+ syncer::INVALIDATION_CREDENTIALS_REJECTED);
+ Mock::VerifyAndClearExpectations(&consumer_);
+
+ // Verify that the device-global invalidation service still does not exist.
+ EXPECT_FALSE(provider_->GetDeviceInvalidationServiceForTest());
+
+ // Unregister the consumer.
+ provider_->UnregisterConsumer(&consumer_);
+ Mock::VerifyAndClearExpectations(&consumer_);
+}
+
+// A consumer is registered with the AffiliatedInvalidationServiceProvider. A
+// device-global invalidation service exists, is connected and is made available
+// to the consumer. Verifies that when a second consumer registers, the
+// device-global invalidation service is made available to it as well. Further
+// verifies that when the first consumer unregisters, the device-global
+// invalidation service is not destroyed and remains available to the second
+// consumer. Further verifies that when the second consumer also unregisters,
+// the device-global invalidation service is destroyed.
+TEST_F(AffiliatedInvalidationServiceProviderTest, MultipleConsumers) {
+ // Register a first consumer. Verify that the consumer is not called back
+ // immediately as no connected invalidation service exists yet.
+ provider_->RegisterConsumer(&consumer_);
+
+ // Indicate that the device-global invalidation service connected. Verify that
+ // that the consumer is informed about this.
+ ConnectDeviceGlobalInvalidationService();
+
+ // Register a second consumer. Verify that the consumer is called back
+ // immediately as a connected invalidation service is available.
+ StrictMock<MockConsumer> second_consumer;
+ EXPECT_CALL(second_consumer,
+ OnInvalidationServiceSet(device_invalidation_service_)).Times(1);
+ provider_->RegisterConsumer(&second_consumer);
+ Mock::VerifyAndClearExpectations(&second_consumer);
+
+ // Unregister the first consumer.
+ provider_->UnregisterConsumer(&consumer_);
+
+ // Verify that the device-global invalidation service still exists.
+ EXPECT_TRUE(provider_->GetDeviceInvalidationServiceForTest());
+
+ // Unregister the second consumer.
+ provider_->UnregisterConsumer(&second_consumer);
+
+ // Verify that the device-global invalidation service has been destroyed.
+ EXPECT_FALSE(provider_->GetDeviceInvalidationServiceForTest());
+ Mock::VerifyAndClearExpectations(&consumer_);
+ Mock::VerifyAndClearExpectations(&second_consumer);
+}
+
+// A consumer is registered with the AffiliatedInvalidationServiceProvider. A
+// per-profile invalidation service belonging to a first affiliated user exists,
+// is connected and is made available to the consumer. Verifies that when the
+// provider is shut down, the consumer is informed that no invalidation service
+// is available for use anymore. Also verifies that no device-global
+// invalidation service is created and a per-profile invalidation service
+// belonging to a second affiliated user that subsequently connects is ignored.
+TEST_F(AffiliatedInvalidationServiceProviderTest, NoServiceAfterShutdown) {
+ // Register a consumer. Verify that the consumer is not called back
+ // immediately as no connected invalidation service exists yet.
+ provider_->RegisterConsumer(&consumer_);
+
+ // Verify that a device-global invalidation service has been created.
+ EXPECT_TRUE(provider_->GetDeviceInvalidationServiceForTest());
+
+ // Log in as a first affiliated user and indicate that the per-profile
+ // invalidation service for this user connected. Verify that this invalidation
+ // service is made available to the |consumer_| and the device-global
+ // invalidation service is destroyed.
+ LogInAsAffiliatedUserAndConnectInvalidationService();
+
+ // Shut down the |provider_|. Verify that the |consumer_| is informed that no
+ // invalidation service is available for use anymore.
+ EXPECT_CALL(consumer_, OnInvalidationServiceSet(nullptr)).Times(1);
+ provider_->Shutdown();
+ Mock::VerifyAndClearExpectations(&consumer_);
+
+ // Verify that the device-global invalidation service still does not exist.
+ EXPECT_FALSE(provider_->GetDeviceInvalidationServiceForTest());
+
+ // Log in as a second affiliated user.
+ Profile* second_profile = LogInAndReturnProfile(kAffiliatedUserID2);
+ EXPECT_TRUE(second_profile);
+
+ // Verify that the device-global invalidation service still does not exist.
+ EXPECT_FALSE(provider_->GetDeviceInvalidationServiceForTest());
+
+ // Create a per-profile invalidation service for the second user.
+ invalidation::FakeInvalidationService* second_profile_invalidation_service =
+ GetProfileInvalidationService(second_profile, true /* create */);
+ ASSERT_TRUE(second_profile_invalidation_service);
+
+ // Indicate that the second user's per-profile invalidation service has
+ // connected. Verify that the consumer is not called back.
+ second_profile_invalidation_service->SetInvalidatorState(
+ syncer::INVALIDATIONS_ENABLED);
+
+ // Verify that the device-global invalidation service still does not exist.
+ EXPECT_FALSE(provider_->GetDeviceInvalidationServiceForTest());
+
+ // Unregister the consumer.
+ provider_->UnregisterConsumer(&consumer_);
+ Mock::VerifyAndClearExpectations(&consumer_);
+}
+
+} // namespace policy
diff --git a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
index dd7dd53..9c91387 100644
--- a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
+++ b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
@@ -17,6 +17,7 @@
#include "base/sequenced_task_runner.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/sequenced_worker_pool.h"
+#include "chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.h"
#include "chrome/browser/chromeos/policy/consumer_management_service.h"
#include "chrome/browser/chromeos/policy/device_cloud_policy_initializer.h"
#include "chrome/browser/chromeos/policy/device_cloud_policy_invalidator.h"
@@ -152,6 +153,9 @@ void BrowserPolicyConnectorChromeOS::Init(
local_state_ = local_state;
ChromeBrowserPolicyConnector::Init(local_state, request_context);
+ affiliated_invalidation_service_provider_.reset(
+ new AffiliatedInvalidationServiceProvider);
+
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(chromeos::switches::kEnableConsumerManagement)) {
@@ -201,6 +205,13 @@ void BrowserPolicyConnectorChromeOS::Init(
}
void BrowserPolicyConnectorChromeOS::PreShutdown() {
+ // Let the |affiliated_invalidation_service_provider_| unregister itself as an
+ // observer of per-Profile InvalidationServices and the device-global
+ // invalidation::TiclInvalidationService it may have created as an observer of
+ // the DeviceOAuth2TokenService that is destroyed before Shutdown() is called.
+ if (affiliated_invalidation_service_provider_)
+ affiliated_invalidation_service_provider_->Shutdown();
+
// Let the |device_cloud_policy_invalidator_| unregister itself as an
// observer of per-Profile InvalidationServices and the device-global
// invalidation::TiclInvalidationService it may have created as an observer of
diff --git a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h
index 1917e53..cb3ec6f 100644
--- a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h
+++ b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h
@@ -24,6 +24,7 @@ class URLRequestContextGetter;
namespace policy {
+class AffiliatedInvalidationServiceProvider;
class ConsumerManagementService;
class DeviceCloudPolicyInitializer;
class DeviceCloudPolicyInvalidator;
@@ -150,6 +151,8 @@ class BrowserPolicyConnectorChromeOS
// Components of the device cloud policy implementation.
scoped_ptr<ServerBackedStateKeysBroker> state_keys_broker_;
scoped_ptr<EnterpriseInstallAttributes> install_attributes_;
+ scoped_ptr<AffiliatedInvalidationServiceProvider>
+ affiliated_invalidation_service_provider_;
scoped_ptr<ConsumerManagementService> consumer_management_service_;
DeviceCloudPolicyManagerChromeOS* device_cloud_policy_manager_;
PrefService* local_state_;
diff --git a/chrome/browser/invalidation/profile_invalidation_provider_factory.h b/chrome/browser/invalidation/profile_invalidation_provider_factory.h
index 49c5e84..2e45328 100644
--- a/chrome/browser/invalidation/profile_invalidation_provider_factory.h
+++ b/chrome/browser/invalidation/profile_invalidation_provider_factory.h
@@ -10,6 +10,7 @@
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
namespace policy {
+class AffiliatedInvalidationServiceProviderTest;
class DeviceCloudPolicyInvalidatorTest;
}
@@ -48,6 +49,7 @@ class ProfileInvalidationProviderFactory
private:
friend class ProfileInvalidationProviderFactoryTestBase;
+ friend class policy::AffiliatedInvalidationServiceProviderTest;
friend class policy::DeviceCloudPolicyInvalidatorTest;
friend struct DefaultSingletonTraits<ProfileInvalidationProviderFactory>;
diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi
index efcf2de..c751c02 100644
--- a/chrome/chrome_browser_chromeos.gypi
+++ b/chrome/chrome_browser_chromeos.gypi
@@ -727,6 +727,8 @@
'browser/chromeos/platform_keys/platform_keys_service.h',
'browser/chromeos/platform_keys/platform_keys_service_factory.cc',
'browser/chromeos/platform_keys/platform_keys_service_factory.h',
+ 'browser/chromeos/policy/affiliated_invalidation_service_provider.cc',
+ 'browser/chromeos/policy/affiliated_invalidation_service_provider.h',
'browser/chromeos/policy/auto_enrollment_client.cc',
'browser/chromeos/policy/auto_enrollment_client.h',
'browser/chromeos/policy/browser_policy_connector_chromeos.cc',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index a235300..e220c63 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -1244,6 +1244,7 @@
'browser/chromeos/ownership/fake_owner_settings_service.cc',
'browser/chromeos/ownership/fake_owner_settings_service.h',
'browser/chromeos/ownership/owner_settings_service_chromeos_unittest.cc',
+ 'browser/chromeos/policy/affiliated_invalidation_service_provider_unittest.cc',
'browser/chromeos/policy/auto_enrollment_client_unittest.cc',
'browser/chromeos/policy/cloud_external_data_manager_base_unittest.cc',
'browser/chromeos/policy/cloud_external_data_policy_observer_unittest.cc',