diff options
33 files changed, 660 insertions, 1365 deletions
diff --git a/chrome/browser/ui/webui/sync_setup_handler.cc b/chrome/browser/ui/webui/sync_setup_handler.cc index 47d3aa3..281fa3c 100644 --- a/chrome/browser/ui/webui/sync_setup_handler.cc +++ b/chrome/browser/ui/webui/sync_setup_handler.cc @@ -4,8 +4,8 @@ #include "chrome/browser/ui/webui/sync_setup_handler.h" -#include "base/bind.h" #include "base/basictypes.h" +#include "base/bind.h" #include "base/bind_helpers.h" #include "base/command_line.h" #include "base/compiler_specific.h" @@ -29,15 +29,14 @@ #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h" #include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h" #include "chrome/common/chrome_switches.h" -#include "chrome/common/url_constants.h" #include "chrome/common/net/gaia/gaia_constants.h" +#include "chrome/common/url_constants.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_view_host_delegate.h" #include "content/public/browser/web_contents.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" #include "grit/locale_settings.h" -#include "sync/protocol/service_constants.h" #include "ui/base/l10n/l10n_util.h" using l10n_util::GetStringFUTF16; @@ -93,6 +92,8 @@ static const size_t kNumDataTypes = arraysize(kDataTypes); COMPILE_ASSERT(arraysize(kDataTypeNames) == arraysize(kDataTypes), kDataTypes_does_not_match_kDataTypeNames); +static const char kDefaultSigninDomain[] = "gmail.com"; + bool GetAuthData(const std::string& json, std::string* username, std::string* password, @@ -177,7 +178,7 @@ bool GetPassphrase(const std::string& json, std::string* passphrase) { string16 NormalizeUserName(const string16& user) { if (user.find_first_of(ASCIIToUTF16("@")) != string16::npos) return user; - return user + ASCIIToUTF16("@") + ASCIIToUTF16(DEFAULT_SIGNIN_DOMAIN); + return user + ASCIIToUTF16("@") + ASCIIToUTF16(kDefaultSigninDomain); } bool AreUserNamesEqual(const string16& user1, const string16& user2) { diff --git a/chrome/service/cloud_print/cloud_print_consts.cc b/chrome/service/cloud_print/cloud_print_consts.cc index ee3f42b..eb65207 100644 --- a/chrome/service/cloud_print/cloud_print_consts.cc +++ b/chrome/service/cloud_print/cloud_print_consts.cc @@ -34,7 +34,6 @@ const char kTagDryRunFlag[] = "__cp__dry_run"; const char kDefaultCloudPrintServerUrl[] = "https://www.google.com/cloudprint"; const char kCloudPrintGaiaServiceId[] = "cloudprint"; -const char kSyncGaiaServiceId[] = "chromiumsync"; const char kProxyAuthUserAgent[] = "ChromiumBrowser"; const char kCloudPrintPushNotificationsSource[] = "cloudprint.google.com"; diff --git a/chrome/service/cloud_print/cloud_print_consts.h b/chrome/service/cloud_print/cloud_print_consts.h index c860448..b06c225 100644 --- a/chrome/service/cloud_print/cloud_print_consts.h +++ b/chrome/service/cloud_print/cloud_print_consts.h @@ -36,7 +36,6 @@ extern const char kTagsHashTagName[]; extern const char kTagDryRunFlag[]; extern const char kDefaultCloudPrintServerUrl[]; extern const char kCloudPrintGaiaServiceId[]; -extern const char kSyncGaiaServiceId[]; extern const char kProxyAuthUserAgent[]; extern const char kCloudPrintPushNotificationsSource[]; extern const char kCloudPrintUserAgent[]; diff --git a/chrome/service/cloud_print/cloud_print_proxy_backend.cc b/chrome/service/cloud_print/cloud_print_proxy_backend.cc index fd11cae..e318c1a 100644 --- a/chrome/service/cloud_print/cloud_print_proxy_backend.cc +++ b/chrome/service/cloud_print/cloud_print_proxy_backend.cc @@ -8,6 +8,7 @@ #include <vector> #include "base/bind.h" +#include "base/compiler_specific.h" #include "base/file_util.h" #include "base/rand_util.h" #include "base/values.h" @@ -24,8 +25,7 @@ #include "googleurl/src/gurl.h" #include "grit/generated_resources.h" #include "jingle/notifier/base/notifier_options.h" -#include "jingle/notifier/listener/mediator_thread_impl.h" -#include "jingle/notifier/listener/talk_mediator_impl.h" +#include "jingle/notifier/listener/push_client.h" #include "ui/base/l10n/l10n_util.h" // The real guts of CloudPrintProxyBackend, to keep the public client API clean. @@ -33,7 +33,7 @@ class CloudPrintProxyBackend::Core : public base::RefCountedThreadSafe<CloudPrintProxyBackend::Core>, public CloudPrintAuth::Client, public CloudPrintConnector::Client, - public notifier::TalkMediator::Delegate { + public notifier::PushClient::Observer { public: // It is OK for print_server_url to be empty. In this case system should // use system default (local) print server. @@ -80,18 +80,17 @@ class CloudPrintProxyBackend::Core const std::string& access_token, const std::string& robot_oauth_refresh_token, const std::string& robot_email, - const std::string& user_email); - virtual void OnInvalidCredentials(); + const std::string& user_email) OVERRIDE; + virtual void OnInvalidCredentials() OVERRIDE; // CloudPrintConnector::Client implementation. - virtual void OnAuthFailed(); + virtual void OnAuthFailed() OVERRIDE; - // notifier::TalkMediator::Delegate implementation. + // notifier::PushClient::Delegate implementation. virtual void OnNotificationStateChange( - bool notifications_enabled); + bool notifications_enabled) OVERRIDE; virtual void OnIncomingNotification( - const notifier::Notification& notification); - virtual void OnOutgoingNotification(); + const notifier::Notification& notification) OVERRIDE; private: friend class base::RefCountedThreadSafe<Core>; @@ -143,7 +142,7 @@ class CloudPrintProxyBackend::Core // OAuth client info. gaia::OAuthClientInfo oauth_client_info_; // Notification (xmpp) handler. - scoped_ptr<notifier::TalkMediator> talk_mediator_; + scoped_ptr<notifier::PushClient> push_client_; // Indicates whether XMPP notifications are currently enabled. bool notifications_enabled_; // The time when notifications were enabled. Valid only when @@ -351,10 +350,8 @@ void CloudPrintProxyBackend::Core::OnAuthenticationComplete( InitNotifications(robot_email, access_token); } else { // If we are refreshing a token, update the XMPP token too. - DCHECK(talk_mediator_.get()); - talk_mediator_->SetAuthToken(robot_email, - access_token, - kSyncGaiaServiceId); + DCHECK(push_client_.get()); + push_client_->UpdateCredentials(robot_email, access_token); } // Start cloud print connector if needed. if (!connector_->IsRunning()) { @@ -393,16 +390,14 @@ void CloudPrintProxyBackend::Core::InitNotifications( notifier_options.request_context_getter = g_service_process->GetServiceURLRequestContextGetter(); notifier_options.auth_mechanism = "X-OAUTH2"; - talk_mediator_.reset(new notifier::TalkMediatorImpl( - new notifier::MediatorThreadImpl(notifier_options), - notifier_options)); + push_client_.reset(new notifier::PushClient(notifier_options)); + push_client_->AddObserver(this); notifier::Subscription subscription; subscription.channel = kCloudPrintPushNotificationsSource; subscription.from = kCloudPrintPushNotificationsSource; - talk_mediator_->AddSubscription(subscription); - talk_mediator_->SetDelegate(this); - talk_mediator_->SetAuthToken(robot_email, access_token, kSyncGaiaServiceId); - talk_mediator_->Login(); + push_client_->UpdateSubscriptions( + notifier::SubscriptionList(1, subscription)); + push_client_->UpdateCredentials(robot_email, access_token); } void CloudPrintProxyBackend::Core::DoShutdown() { @@ -412,10 +407,11 @@ void CloudPrintProxyBackend::Core::DoShutdown() { if (connector_->IsRunning()) connector_->Stop(); - // Important to delete the TalkMediator on this thread. - if (talk_mediator_.get()) - talk_mediator_->Logout(); - talk_mediator_.reset(); + // Important to delete the PushClient on this thread. + if (push_client_.get()) { + push_client_->RemoveObserver(this); + } + push_client_.reset(); notifications_enabled_ = false; notifications_enabled_since_ = base::TimeTicks(); token_store_.reset(); @@ -536,5 +532,3 @@ void CloudPrintProxyBackend::Core::OnIncomingNotification( notification.channel.c_str())) HandlePrinterNotification(notification.data); } - -void CloudPrintProxyBackend::Core::OnOutgoingNotification() {} diff --git a/jingle/jingle.gyp b/jingle/jingle.gyp index 02a5a05..9f9af8b 100644 --- a/jingle/jingle.gyp +++ b/jingle/jingle.gyp @@ -75,9 +75,8 @@ 'notifier/communicator/login_settings.h', 'notifier/communicator/single_login_attempt.cc', 'notifier/communicator/single_login_attempt.h', - 'notifier/listener/mediator_thread.h', - 'notifier/listener/mediator_thread_impl.cc', - 'notifier/listener/mediator_thread_impl.h', + 'notifier/listener/push_client.cc', + 'notifier/listener/push_client.h', 'notifier/listener/notification_constants.cc', 'notifier/listener/notification_constants.h', 'notifier/listener/notification_defines.cc', @@ -88,9 +87,6 @@ 'notifier/listener/push_notifications_send_update_task.h', 'notifier/listener/push_notifications_subscribe_task.cc', 'notifier/listener/push_notifications_subscribe_task.h', - 'notifier/listener/talk_mediator.h', - 'notifier/listener/talk_mediator_impl.cc', - 'notifier/listener/talk_mediator_impl.h', 'notifier/listener/xml_element_util.cc', 'notifier/listener/xml_element_util.h', ], @@ -164,12 +160,9 @@ 'notifier/communicator/connection_settings_unittest.cc', 'notifier/communicator/login_settings_unittest.cc', 'notifier/communicator/single_login_attempt_unittest.cc', - 'notifier/listener/mediator_thread_mock.cc', - 'notifier/listener/mediator_thread_mock.h', - 'notifier/listener/mediator_thread_unittest.cc', + 'notifier/listener/push_client_unittest.cc', 'notifier/listener/push_notifications_send_update_task_unittest.cc', 'notifier/listener/push_notifications_subscribe_task_unittest.cc', - 'notifier/listener/talk_mediator_unittest.cc', 'notifier/listener/xml_element_util_unittest.cc', 'run_all_unittests.cc', ], diff --git a/jingle/notifier/base/notifier_options_util.cc b/jingle/notifier/base/notifier_options_util.cc index 9e107bc..67620a0 100644 --- a/jingle/notifier/base/notifier_options_util.cc +++ b/jingle/notifier/base/notifier_options_util.cc @@ -13,8 +13,7 @@ namespace notifier { buzz::XmppClientSettings MakeXmppClientSettings( const NotifierOptions& notifier_options, - const std::string& email, const std::string& token, - const std::string& token_service) { + const std::string& email, const std::string& token) { buzz::Jid jid = buzz::Jid(email); DCHECK(!jid.node().empty()); DCHECK(jid.IsValid()); @@ -27,7 +26,7 @@ buzz::XmppClientSettings MakeXmppClientSettings( xmpp_client_settings.set_auth_cookie( notifier_options.invalidate_xmpp_login ? token + "bogus" : token); - xmpp_client_settings.set_token_service(token_service); + xmpp_client_settings.set_token_service("chromiumsync"); if (notifier_options.allow_insecure_connection) { xmpp_client_settings.set_allow_plain(true); xmpp_client_settings.set_use_tls(buzz::TLS_DISABLED); diff --git a/jingle/notifier/base/notifier_options_util.h b/jingle/notifier/base/notifier_options_util.h index 4278329..6ba2471 100644 --- a/jingle/notifier/base/notifier_options_util.h +++ b/jingle/notifier/base/notifier_options_util.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. // @@ -19,8 +19,7 @@ struct NotifierOptions; buzz::XmppClientSettings MakeXmppClientSettings( const NotifierOptions& notifier_options, - const std::string& email, const std::string& token, - const std::string& token_service); + const std::string& email, const std::string& token); ServerList GetServerList(const NotifierOptions& notifier_options); diff --git a/jingle/notifier/listener/mediator_thread.h b/jingle/notifier/listener/mediator_thread.h deleted file mode 100644 index 157639e..0000000 --- a/jingle/notifier/listener/mediator_thread.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2009 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. -// -// These methods should post messages to a queue which a different thread will -// later come back and read from. - -#ifndef JINGLE_NOTIFIER_LISTENER_MEDIATOR_THREAD_H_ -#define JINGLE_NOTIFIER_LISTENER_MEDIATOR_THREAD_H_ - -#include <string> -#include <vector> - -#include "jingle/notifier/listener/notification_defines.h" - -namespace buzz { -class XmppClientSettings; -} // namespace buzz - -namespace notifier { - -class MediatorThread { - public: - virtual ~MediatorThread() {} - - class Observer { - public: - virtual ~Observer() {} - - virtual void OnConnectionStateChange(bool logged_in) = 0; - - virtual void OnSubscriptionStateChange(bool subscribed) = 0; - - virtual void OnIncomingNotification(const Notification& notification) = 0; - - virtual void OnOutgoingNotification() = 0; - }; - - // Must be thread-safe (i.e., callable on any thread). - virtual void AddObserver(Observer* observer) = 0; - - // Must be called on the same thread that AddObserver() was called - // with the given observer. - virtual void RemoveObserver(Observer* observer) = 0; - - virtual void Login(const buzz::XmppClientSettings& settings) = 0; - virtual void Logout() = 0; - virtual void Start() = 0; - virtual void SubscribeForUpdates(const SubscriptionList& subscriptions) = 0; - virtual void ListenForUpdates() = 0; - virtual void SendNotification(const Notification& data) = 0; - // UpdateXmppSettings is used to update the user information (typically the - // auth token) AFTER a call to Login and BEFORE a call to Logout(). This will - // not cause an immediate reconnect. The updated settings will be used the - // next time we attempt a reconnect because of a broken connection. - // The typical use-case for this is to update OAuth2 access tokens which - // expire every hour. - virtual void UpdateXmppSettings(const buzz::XmppClientSettings& settings) = 0; -}; - -} // namespace notifier - -#endif // JINGLE_NOTIFIER_LISTENER_MEDIATOR_THREAD_H_ diff --git a/jingle/notifier/listener/mediator_thread_impl.cc b/jingle/notifier/listener/mediator_thread_impl.cc deleted file mode 100644 index ea6d18d..0000000 --- a/jingle/notifier/listener/mediator_thread_impl.cc +++ /dev/null @@ -1,299 +0,0 @@ -// Copyright (c) 2012 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 "jingle/notifier/listener/mediator_thread_impl.h" - -#include "base/bind.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" -#include "base/message_loop.h" -#include "base/observer_list_threadsafe.h" -#include "base/threading/thread.h" -#include "jingle/notifier/base/const_communicator.h" -#include "jingle/notifier/base/notifier_options_util.h" -#include "jingle/notifier/base/task_pump.h" -#include "jingle/notifier/communicator/login.h" -#include "jingle/notifier/listener/push_notifications_listen_task.h" -#include "jingle/notifier/listener/push_notifications_send_update_task.h" -#include "jingle/notifier/listener/push_notifications_subscribe_task.h" -#include "net/base/host_port_pair.h" -#include "net/url_request/url_request_context.h" -#include "net/url_request/url_request_context_getter.h" -#include "talk/xmpp/xmppclientsettings.h" - -namespace notifier { - -class MediatorThreadImpl::Core - : public base::RefCountedThreadSafe<MediatorThreadImpl::Core>, - public LoginDelegate, - public PushNotificationsListenTaskDelegate, - public PushNotificationsSubscribeTaskDelegate { - public: - // Invoked on the caller thread. - explicit Core(const NotifierOptions& notifier_options); - void AddObserver(Observer* observer); - void RemoveObserver(Observer* observer); - - // Login::Delegate implementation. Called on I/O thread. - virtual void OnConnect( - base::WeakPtr<buzz::XmppTaskParentInterface> base_task); - virtual void OnDisconnect(); - - // PushNotificationsListenTaskDelegate implementation. Called on I/O thread. - virtual void OnNotificationReceived( - const Notification& notification); - // PushNotificationsSubscribeTaskDelegate implementation. Called on I/O - // thread. - virtual void OnSubscribed(); - virtual void OnSubscriptionError(); - - // Helpers invoked on I/O thread. - void Login(const buzz::XmppClientSettings& settings); - void Disconnect(); - void ListenForPushNotifications(); - void SubscribeForPushNotifications( - const SubscriptionList& subscriptions); - void SendNotification(const Notification& data); - void UpdateXmppSettings(const buzz::XmppClientSettings& settings); - - private: - friend class base::RefCountedThreadSafe<MediatorThreadImpl::Core>; - // Invoked on either the caller thread or the I/O thread. - virtual ~Core(); - scoped_refptr<ObserverListThreadSafe<Observer> > observers_; - base::WeakPtr<buzz::XmppTaskParentInterface> base_task_; - - const NotifierOptions notifier_options_; - - scoped_ptr<notifier::Login> login_; - - std::vector<Notification> pending_notifications_to_send_; - - DISALLOW_COPY_AND_ASSIGN(Core); -}; - -MediatorThreadImpl::Core::Core( - const NotifierOptions& notifier_options) - : observers_(new ObserverListThreadSafe<Observer>()), - notifier_options_(notifier_options) { - DCHECK(notifier_options_.request_context_getter); -} - -MediatorThreadImpl::Core::~Core() { -} - -void MediatorThreadImpl::Core::AddObserver(Observer* observer) { - observers_->AddObserver(observer); -} - -void MediatorThreadImpl::Core::RemoveObserver(Observer* observer) { - observers_->RemoveObserver(observer); -} - -void MediatorThreadImpl::Core::Login(const buzz::XmppClientSettings& settings) { - DCHECK(notifier_options_.request_context_getter->GetIOMessageLoopProxy()-> - BelongsToCurrentThread()); - VLOG(1) << "P2P: Thread logging into talk network."; - - base_task_.reset(); - login_.reset(new notifier::Login(this, - settings, - notifier_options_.request_context_getter, - GetServerList(notifier_options_), - notifier_options_.try_ssltcp_first, - notifier_options_.auth_mechanism)); - login_->StartConnection(); -} - -void MediatorThreadImpl::Core::Disconnect() { - DCHECK(notifier_options_.request_context_getter->GetIOMessageLoopProxy()-> - BelongsToCurrentThread()); - VLOG(1) << "P2P: Thread logging out of talk network."; - login_.reset(); - base_task_.reset(); -} - -void MediatorThreadImpl::Core::ListenForPushNotifications() { - DCHECK(notifier_options_.request_context_getter->GetIOMessageLoopProxy()-> - BelongsToCurrentThread()); - if (!base_task_.get()) - return; - PushNotificationsListenTask* listener = - new PushNotificationsListenTask(base_task_, this); - listener->Start(); -} - -void MediatorThreadImpl::Core::SubscribeForPushNotifications( - const SubscriptionList& subscriptions) { - DCHECK(notifier_options_.request_context_getter->GetIOMessageLoopProxy()-> - BelongsToCurrentThread()); - if (!base_task_.get()) - return; - PushNotificationsSubscribeTask* subscribe_task = - new PushNotificationsSubscribeTask(base_task_, subscriptions, this); - subscribe_task->Start(); -} - -void MediatorThreadImpl::Core::OnSubscribed() { - DCHECK(notifier_options_.request_context_getter->GetIOMessageLoopProxy()-> - BelongsToCurrentThread()); - observers_->Notify(&Observer::OnSubscriptionStateChange, true); -} - -void MediatorThreadImpl::Core::OnSubscriptionError() { - DCHECK(notifier_options_.request_context_getter->GetIOMessageLoopProxy()-> - BelongsToCurrentThread()); - observers_->Notify(&Observer::OnSubscriptionStateChange, false); -} - -void MediatorThreadImpl::Core::OnNotificationReceived( - const Notification& notification) { - DCHECK(notifier_options_.request_context_getter->GetIOMessageLoopProxy()-> - BelongsToCurrentThread()); - observers_->Notify(&Observer::OnIncomingNotification, notification); -} - -void MediatorThreadImpl::Core::SendNotification(const Notification& data) { - DCHECK(notifier_options_.request_context_getter->GetIOMessageLoopProxy()-> - BelongsToCurrentThread()); - if (!base_task_.get()) { - VLOG(1) << "P2P: Cannot send notification " << data.ToString() - << "; sending later"; - pending_notifications_to_send_.push_back(data); - return; - } - // Owned by |base_task_|. - PushNotificationsSendUpdateTask* task = - new PushNotificationsSendUpdateTask(base_task_, data); - task->Start(); - observers_->Notify(&Observer::OnOutgoingNotification); -} - -void MediatorThreadImpl::Core::UpdateXmppSettings( - const buzz::XmppClientSettings& settings) { - DCHECK(notifier_options_.request_context_getter->GetIOMessageLoopProxy()-> - BelongsToCurrentThread()); - VLOG(1) << "P2P: Thread Updating login settings."; - // The caller should only call UpdateXmppSettings after a Login call. - if (login_.get()) - login_->UpdateXmppSettings(settings); - else - NOTREACHED() << - "P2P: Thread UpdateXmppSettings called when login_ was NULL"; -} - -void MediatorThreadImpl::Core::OnConnect( - base::WeakPtr<buzz::XmppTaskParentInterface> base_task) { - DCHECK(notifier_options_.request_context_getter->GetIOMessageLoopProxy()-> - BelongsToCurrentThread()); - base_task_ = base_task; - observers_->Notify(&Observer::OnConnectionStateChange, true); - std::vector<Notification> notifications_to_send; - notifications_to_send.swap(pending_notifications_to_send_); - for (std::vector<Notification>::const_iterator it = - notifications_to_send.begin(); - it != notifications_to_send.end(); ++it) { - VLOG(1) << "P2P: Sending pending notification " << it->ToString(); - SendNotification(*it); - } -} - -void MediatorThreadImpl::Core::OnDisconnect() { - DCHECK(notifier_options_.request_context_getter->GetIOMessageLoopProxy()-> - BelongsToCurrentThread()); - base_task_.reset(); - observers_->Notify(&Observer::OnConnectionStateChange, false); -} - - -MediatorThreadImpl::MediatorThreadImpl(const NotifierOptions& notifier_options) - : core_(new Core(notifier_options)), - parent_message_loop_proxy_( - base::MessageLoopProxy::current()), - io_message_loop_proxy_( - notifier_options.request_context_getter->GetIOMessageLoopProxy()) { -} - -MediatorThreadImpl::~MediatorThreadImpl() { - DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); - LogoutImpl(); -} - -void MediatorThreadImpl::AddObserver(Observer* observer) { - DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); - core_->AddObserver(observer); -} - -void MediatorThreadImpl::RemoveObserver(Observer* observer) { - DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); - core_->RemoveObserver(observer); -} - -void MediatorThreadImpl::Start() { - DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); -} - -void MediatorThreadImpl::Login(const buzz::XmppClientSettings& settings) { - DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); - io_message_loop_proxy_->PostTask( - FROM_HERE, - base::Bind(&MediatorThreadImpl::Core::Login, core_.get(), settings)); -} - -void MediatorThreadImpl::Logout() { - DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); - LogoutImpl(); -} - -void MediatorThreadImpl::ListenForUpdates() { - DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); - io_message_loop_proxy_->PostTask( - FROM_HERE, - base::Bind(&MediatorThreadImpl::Core::ListenForPushNotifications, - core_.get())); -} - -void MediatorThreadImpl::SubscribeForUpdates( - const SubscriptionList& subscriptions) { - DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); - io_message_loop_proxy_->PostTask( - FROM_HERE, - base::Bind(&MediatorThreadImpl::Core::SubscribeForPushNotifications, - core_.get(), subscriptions)); -} - -void MediatorThreadImpl::SendNotification( - const Notification& data) { - DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); - io_message_loop_proxy_->PostTask( - FROM_HERE, - base::Bind(&MediatorThreadImpl::Core::SendNotification, core_.get(), - data)); -} - -void MediatorThreadImpl::UpdateXmppSettings( - const buzz::XmppClientSettings& settings) { - DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); - io_message_loop_proxy_->PostTask( - FROM_HERE, - base::Bind(&MediatorThreadImpl::Core::UpdateXmppSettings, core_.get(), - settings)); -} - -void MediatorThreadImpl::TriggerOnConnectForTest( - base::WeakPtr<buzz::XmppTaskParentInterface> base_task) { - DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); - io_message_loop_proxy_->PostTask( - FROM_HERE, - base::Bind(&MediatorThreadImpl::Core::OnConnect, core_.get(), base_task)); -} - -void MediatorThreadImpl::LogoutImpl() { - io_message_loop_proxy_->PostTask( - FROM_HERE, - base::Bind(&MediatorThreadImpl::Core::Disconnect, core_.get())); -} - -} // namespace notifier diff --git a/jingle/notifier/listener/mediator_thread_impl.h b/jingle/notifier/listener/mediator_thread_impl.h deleted file mode 100644 index bf86933..0000000 --- a/jingle/notifier/listener/mediator_thread_impl.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) 2011 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. -// -// This object runs on a thread and knows how to interpret messages sent by the -// talk mediator. The mediator posts messages to a queue which the thread polls -// (in a super class). -// -// Example usage: -// -// MediatorThread m = new MediatorThreadImpl(pass in stuff); -// m.start(); // Start the thread -// // Once the thread is started, you can do server stuff. -// m.Login(loginInformation); -// // Events happen, the mediator finds out through its pump more messages -// // are dispatched to the thread eventually we want to log out. -// m.Logout(); -// delete m; // Also stops the thread. - -#ifndef JINGLE_NOTIFIER_LISTENER_MEDIATOR_THREAD_IMPL_H_ -#define JINGLE_NOTIFIER_LISTENER_MEDIATOR_THREAD_IMPL_H_ - -#include <string> -#include <vector> - -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "jingle/notifier/base/notifier_options.h" -#include "jingle/notifier/listener/mediator_thread.h" - -namespace base { -class MessageLoopProxy; -} - -namespace buzz { -class XmppClientSettings; -class XmppTaskParentInterface; -} // namespace buzz - -namespace talk_base { -class Task; -} // namespace talk_base - -namespace notifier { - -class MediatorThreadImpl : public MediatorThread { - public: - explicit MediatorThreadImpl(const NotifierOptions& notifier_options); - virtual ~MediatorThreadImpl(); - - virtual void AddObserver(Observer* observer) OVERRIDE; - virtual void RemoveObserver(Observer* observer) OVERRIDE; - - // Start the thread. - virtual void Start() OVERRIDE; - - // These are called from outside threads, by the talk mediator object. - // They add messages to a queue which we poll in this thread. - virtual void Login(const buzz::XmppClientSettings& settings) OVERRIDE; - virtual void Logout() OVERRIDE; - virtual void ListenForUpdates() OVERRIDE; - virtual void SubscribeForUpdates( - const SubscriptionList& subscriptions) OVERRIDE; - virtual void SendNotification(const Notification& data) OVERRIDE; - virtual void UpdateXmppSettings( - const buzz::XmppClientSettings& settings) OVERRIDE; - - // Used by unit tests. Make sure that tests that use this have the - // IO message loop proxy passed in via |notifier_options| pointing - // to the current thread. - void TriggerOnConnectForTest( - base::WeakPtr<buzz::XmppTaskParentInterface> base_task); - - private: - // The logic of Logout without the thread check so it can be called in the - // d'tor. - void LogoutImpl(); - // The real guts of MediatorThreadImpl, which allows this class to not be - // refcounted. - class Core; - scoped_refptr<Core> core_; - scoped_refptr<base::MessageLoopProxy> parent_message_loop_proxy_; - scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_; - DISALLOW_COPY_AND_ASSIGN(MediatorThreadImpl); -}; - -} // namespace notifier - -#endif // JINGLE_NOTIFIER_LISTENER_MEDIATOR_THREAD_IMPL_H_ diff --git a/jingle/notifier/listener/mediator_thread_mock.cc b/jingle/notifier/listener/mediator_thread_mock.cc deleted file mode 100644 index 980f81a2..0000000 --- a/jingle/notifier/listener/mediator_thread_mock.cc +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2011 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 "jingle/notifier/listener/mediator_thread_mock.h" - -#include "talk/xmpp/xmppclientsettings.h" - -namespace notifier { - -MockMediatorThread::MockMediatorThread() : observer_(NULL) { - Reset(); -} - -MockMediatorThread::~MockMediatorThread() {} - -void MockMediatorThread::Reset() { - login_calls = 0; - logout_calls = 0; - start_calls = 0; - subscribe_calls = 0; - listen_calls = 0; - send_calls = 0; - update_settings_calls = 0; -} - -void MockMediatorThread::AddObserver(Observer* observer) { - observer_ = observer; -} - -void MockMediatorThread::RemoveObserver(Observer* observer) { - observer_ = NULL; -} - -// Overridden from MediatorThread -void MockMediatorThread::Login(const buzz::XmppClientSettings& settings) { - login_calls++; - if (observer_) { - observer_->OnConnectionStateChange(true); - } -} - -void MockMediatorThread::Logout() { - logout_calls++; - if (observer_) { - observer_->OnConnectionStateChange(false); - } -} - -void MockMediatorThread::Start() { - start_calls++; -} - -void MockMediatorThread::SubscribeForUpdates( - const SubscriptionList& subscriptions) { - subscribe_calls++; - if (observer_) { - observer_->OnSubscriptionStateChange(true); - } -} - -void MockMediatorThread::ListenForUpdates() { - listen_calls++; -} - -void MockMediatorThread::SendNotification(const Notification &) { - send_calls++; - if (observer_) { - observer_->OnOutgoingNotification(); - } -} - -void MockMediatorThread::ReceiveNotification( - const Notification& data) { - if (observer_) { - observer_->OnIncomingNotification(data); - } -} - -void MockMediatorThread::UpdateXmppSettings( - const buzz::XmppClientSettings& settings) { - update_settings_calls++; -} - -} // namespace notifier diff --git a/jingle/notifier/listener/mediator_thread_mock.h b/jingle/notifier/listener/mediator_thread_mock.h deleted file mode 100644 index 44b2043..0000000 --- a/jingle/notifier/listener/mediator_thread_mock.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2011 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. - -// This is mock for delicious testing. -// It's very primitive, and it would have been better to use gmock, except -// that gmock is only for linux. - -#ifndef JINGLE_NOTIFIER_LISTENER_MEDIATOR_THREAD_MOCK_H_ -#define JINGLE_NOTIFIER_LISTENER_MEDIATOR_THREAD_MOCK_H_ - -#include <string> -#include <vector> - -#include "base/compiler_specific.h" -#include "jingle/notifier/listener/mediator_thread.h" - -namespace buzz { -class XmppClientSettings; -} - -namespace notifier { - -class MockMediatorThread : public MediatorThread { - public: - MockMediatorThread(); - - virtual ~MockMediatorThread(); - - void Reset(); - - virtual void AddObserver(Observer* observer) OVERRIDE; - - virtual void RemoveObserver(Observer* observer) OVERRIDE; - - // Overridden from MediatorThread - virtual void Login(const buzz::XmppClientSettings& settings) OVERRIDE; - - virtual void Logout() OVERRIDE; - - virtual void Start() OVERRIDE; - - virtual void SubscribeForUpdates( - const SubscriptionList& subscriptions) OVERRIDE; - - virtual void ListenForUpdates() OVERRIDE; - - virtual void SendNotification(const Notification &) OVERRIDE; - virtual void UpdateXmppSettings( - const buzz::XmppClientSettings& settings) OVERRIDE; - - - void ReceiveNotification(const Notification& data); - - Observer* observer_; - // Internal State - int login_calls; - int logout_calls; - int start_calls; - int subscribe_calls; - int listen_calls; - int send_calls; - int update_settings_calls; -}; - -} // namespace notifier - -#endif // JINGLE_NOTIFIER_LISTENER_MEDIATOR_THREAD_MOCK_H_ diff --git a/jingle/notifier/listener/mediator_thread_unittest.cc b/jingle/notifier/listener/mediator_thread_unittest.cc deleted file mode 100644 index afb8ce1..0000000 --- a/jingle/notifier/listener/mediator_thread_unittest.cc +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2012 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 "jingle/notifier/listener/mediator_thread_impl.h" - -#include "base/basictypes.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop.h" -#include "jingle/notifier/base/fake_base_task.h" -#include "jingle/notifier/base/notifier_options.h" -#include "jingle/notifier/listener/notification_defines.h" -#include "net/base/capturing_net_log.h" -#include "net/url_request/url_request_context_getter.h" -#include "net/url_request/url_request_test_util.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace notifier { - -namespace { - -using ::testing::StrictMock; - -class MockObserver : public MediatorThread::Observer { - public: - MOCK_METHOD1(OnConnectionStateChange, void(bool)); - MOCK_METHOD1(OnSubscriptionStateChange, void(bool)); - MOCK_METHOD1(OnIncomingNotification, void(const Notification&)); - MOCK_METHOD0(OnOutgoingNotification, void()); -}; - -} // namespace - -class MediatorThreadTest : public testing::Test { - protected: - MediatorThreadTest() { - notifier_options_.request_context_getter = - new TestURLRequestContextGetter(message_loop_.message_loop_proxy()); - } - - virtual ~MediatorThreadTest() {} - - virtual void SetUp() { - mediator_thread_.reset(new MediatorThreadImpl(notifier_options_)); - mediator_thread_->AddObserver(&mock_observer_); - } - - virtual void TearDown() { - // Clear out any messages posted by MediatorThread's - // destructor. - message_loop_.RunAllPending(); - mediator_thread_->RemoveObserver(&mock_observer_); - mediator_thread_.reset(); - } - - MessageLoop message_loop_; - NotifierOptions notifier_options_; - StrictMock<MockObserver> mock_observer_; - scoped_ptr<MediatorThreadImpl> mediator_thread_; - FakeBaseTask fake_base_task_; -}; - -TEST_F(MediatorThreadTest, SendNotificationBasic) { - EXPECT_CALL(mock_observer_, OnConnectionStateChange(true)); - EXPECT_CALL(mock_observer_, OnOutgoingNotification()); - - mediator_thread_->TriggerOnConnectForTest(fake_base_task_.AsWeakPtr()); - mediator_thread_->SendNotification(Notification()); - mediator_thread_->Logout(); - - // Shouldn't trigger. - mediator_thread_->SendNotification(Notification()); -} - -TEST_F(MediatorThreadTest, SendNotificationDelayed) { - EXPECT_CALL(mock_observer_, OnConnectionStateChange(true)); - EXPECT_CALL(mock_observer_, OnOutgoingNotification()).Times(5); - - for (int i = 0; i < 5; ++i) { - mediator_thread_->SendNotification(Notification()); - } - mediator_thread_->TriggerOnConnectForTest(fake_base_task_.AsWeakPtr()); -} - -TEST_F(MediatorThreadTest, SendNotificationDelayedTwice) { - EXPECT_CALL(mock_observer_, OnConnectionStateChange(true)).Times(2); - EXPECT_CALL(mock_observer_, OnOutgoingNotification()).Times(5); - - for (int i = 0; i < 5; ++i) { - mediator_thread_->SendNotification(Notification()); - } - mediator_thread_->TriggerOnConnectForTest( - base::WeakPtr<buzz::XmppTaskParentInterface>()); - mediator_thread_->TriggerOnConnectForTest(fake_base_task_.AsWeakPtr()); -} - -} // namespace notifier diff --git a/jingle/notifier/listener/push_client.cc b/jingle/notifier/listener/push_client.cc new file mode 100644 index 0000000..8c82b44 --- /dev/null +++ b/jingle/notifier/listener/push_client.cc @@ -0,0 +1,320 @@ +// Copyright (c) 2012 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 "jingle/notifier/listener/push_client.h" + +#include "base/bind.h" +#include "base/compiler_specific.h" +#include "base/location.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/observer_list_threadsafe.h" +#include "jingle/notifier/base/notifier_options_util.h" +#include "jingle/notifier/communicator/login.h" +#include "jingle/notifier/listener/push_notifications_listen_task.h" +#include "jingle/notifier/listener/push_notifications_send_update_task.h" +#include "jingle/notifier/listener/push_notifications_subscribe_task.h" +#include "talk/xmpp/xmppclientsettings.h" + +namespace notifier { + +PushClient::Observer::~Observer() {} + +// All member functions except for the constructor, destructor, and +// {Add,Remove}Observer() must be called on the IO thread (as taken from +// |notifier_options|). +class PushClient::Core + : public base::RefCountedThreadSafe<PushClient::Core>, + public LoginDelegate, + public PushNotificationsListenTaskDelegate, + public PushNotificationsSubscribeTaskDelegate { + public: + // Called on the parent thread. + explicit Core(const NotifierOptions& notifier_options); + + // Must be called before being destroyed. + void DestroyOnIOThread(); + + // Login::Delegate implementation. + virtual void OnConnect( + base::WeakPtr<buzz::XmppTaskParentInterface> base_task) OVERRIDE; + virtual void OnDisconnect(); + + // PushNotificationsListenTaskDelegate implementation. + virtual void OnNotificationReceived( + const Notification& notification) OVERRIDE; + + // PushNotificationsSubscribeTaskDelegate implementation. + virtual void OnSubscribed() OVERRIDE; + virtual void OnSubscriptionError() OVERRIDE; + + // Called on the parent thread. + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); + + void UpdateSubscriptions(const SubscriptionList& subscriptions); + void UpdateCredentials(const std::string& email, const std::string& token); + void SendNotification(const Notification& data); + + // Any notifications sent after this is called will be reflected, + // i.e. will be treated as an incoming notification also. + void ReflectSentNotificationsForTest(); + + private: + friend class base::RefCountedThreadSafe<PushClient::Core>; + + // Called on either the parent thread or the I/O thread. + virtual ~Core(); + + const NotifierOptions notifier_options_; + const scoped_refptr<base::MessageLoopProxy> parent_message_loop_proxy_; + const scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_; + const scoped_refptr<ObserverListThreadSafe<Observer> > observers_; + + // XMPP connection settings. + SubscriptionList subscriptions_; + buzz::XmppClientSettings xmpp_settings_; + + // Must be created/used/destroyed only on the IO thread. + scoped_ptr<notifier::Login> login_; + + // The XMPP connection. + base::WeakPtr<buzz::XmppTaskParentInterface> base_task_; + + std::vector<Notification> pending_notifications_to_send_; + + bool reflect_sent_notifications_for_test_; + + DISALLOW_COPY_AND_ASSIGN(Core); +}; + +PushClient::Core::Core(const NotifierOptions& notifier_options) + : notifier_options_(notifier_options), + parent_message_loop_proxy_(base::MessageLoopProxy::current()), + io_message_loop_proxy_( + notifier_options_.request_context_getter->GetIOMessageLoopProxy()), + observers_(new ObserverListThreadSafe<Observer>()), + reflect_sent_notifications_for_test_(false) {} + +PushClient::Core::~Core() { + DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread() || + io_message_loop_proxy_->BelongsToCurrentThread()); + DCHECK(!login_.get()); + DCHECK(!base_task_.get()); + observers_->AssertEmpty(); +} + +void PushClient::Core::DestroyOnIOThread() { + DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); + login_.reset(); + base_task_.reset(); +} + +void PushClient::Core::OnConnect( + base::WeakPtr<buzz::XmppTaskParentInterface> base_task) { + DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); + base_task_ = base_task; + + if (!base_task_.get()) { + NOTREACHED(); + return; + } + + // Listen for notifications. + { + // Owned by |base_task_|. + PushNotificationsListenTask* listener = + new PushNotificationsListenTask(base_task_, this); + listener->Start(); + } + + // Send subscriptions. + { + // Owned by |base_task_|. + PushNotificationsSubscribeTask* subscribe_task = + new PushNotificationsSubscribeTask(base_task_, subscriptions_, this); + subscribe_task->Start(); + } + + std::vector<Notification> notifications_to_send; + notifications_to_send.swap(pending_notifications_to_send_); + for (std::vector<Notification>::const_iterator it = + notifications_to_send.begin(); + it != notifications_to_send.end(); ++it) { + DVLOG(1) << "Push: Sending pending notification " << it->ToString(); + SendNotification(*it); + } +} + +void PushClient::Core::OnDisconnect() { + DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); + base_task_.reset(); + observers_->Notify(&Observer::OnNotificationStateChange, false); +} + +void PushClient::Core::OnNotificationReceived( + const Notification& notification) { + DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); + observers_->Notify(&Observer::OnIncomingNotification, notification); +} + +void PushClient::Core::OnSubscribed() { + DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); + observers_->Notify(&Observer::OnNotificationStateChange, true); +} + +void PushClient::Core::OnSubscriptionError() { + DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); + observers_->Notify(&Observer::OnNotificationStateChange, false); +} + +void PushClient::Core::AddObserver(Observer* observer) { + DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); + observers_->AddObserver(observer); +} + +void PushClient::Core::RemoveObserver(Observer* observer) { + DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); + observers_->RemoveObserver(observer); +} + +void PushClient::Core::UpdateSubscriptions( + const SubscriptionList& subscriptions) { + DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); + subscriptions_ = subscriptions; +} + +void PushClient::Core::UpdateCredentials( + const std::string& email, const std::string& token) { + DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); + DVLOG(1) << "Push: Updating credentials for " << email; + xmpp_settings_ = MakeXmppClientSettings(notifier_options_, email, token); + if (login_.get()) { + login_->UpdateXmppSettings(xmpp_settings_); + } else { + DVLOG(1) << "Push: Starting XMPP connection"; + base_task_.reset(); + login_.reset(new notifier::Login(this, + xmpp_settings_, + notifier_options_.request_context_getter, + GetServerList(notifier_options_), + notifier_options_.try_ssltcp_first, + notifier_options_.auth_mechanism)); + login_->StartConnection(); + } +} + +void PushClient::Core::SendNotification(const Notification& notification) { + DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); + if (!base_task_.get()) { + DVLOG(1) << "Push: Cannot send notification " + << notification.ToString() << "; sending later"; + pending_notifications_to_send_.push_back(notification); + return; + } + // Owned by |base_task_|. + PushNotificationsSendUpdateTask* task = + new PushNotificationsSendUpdateTask(base_task_, notification); + task->Start(); + + if (reflect_sent_notifications_for_test_) { + OnNotificationReceived(notification); + } +} + +void PushClient::Core::ReflectSentNotificationsForTest() { + DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); + reflect_sent_notifications_for_test_ = true; +} + +PushClient::PushClient(const NotifierOptions& notifier_options) + : core_(new Core(notifier_options)), + parent_message_loop_proxy_(base::MessageLoopProxy::current()), + io_message_loop_proxy_( + notifier_options.request_context_getter->GetIOMessageLoopProxy()) { +} + +PushClient::~PushClient() { + DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); + io_message_loop_proxy_->PostTask( + FROM_HERE, + base::Bind(&PushClient::Core::DestroyOnIOThread, core_.get())); +} + +void PushClient::AddObserver(Observer* observer) { + DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); + core_->AddObserver(observer); +} + +void PushClient::RemoveObserver(Observer* observer) { + DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); + core_->RemoveObserver(observer); +} + +void PushClient::UpdateSubscriptions(const SubscriptionList& subscriptions) { + DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); + io_message_loop_proxy_->PostTask( + FROM_HERE, + base::Bind(&PushClient::Core::UpdateSubscriptions, + core_.get(), subscriptions)); +} + +void PushClient::UpdateCredentials( + const std::string& email, const std::string& token) { + DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); + io_message_loop_proxy_->PostTask( + FROM_HERE, + base::Bind(&PushClient::Core::UpdateCredentials, + core_.get(), email, token)); +} + +void PushClient::SendNotification(const Notification& notification) { + DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); + io_message_loop_proxy_->PostTask( + FROM_HERE, + base::Bind(&PushClient::Core::SendNotification, core_.get(), + notification)); +} + +void PushClient::SimulateOnNotificationReceivedForTest( + const Notification& notification) { + DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); + io_message_loop_proxy_->PostTask( + FROM_HERE, + base::Bind(&PushClient::Core::OnNotificationReceived, + core_.get(), notification)); +} + +void PushClient::SimulateConnectAndSubscribeForTest( + base::WeakPtr<buzz::XmppTaskParentInterface> base_task) { + DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); + io_message_loop_proxy_->PostTask( + FROM_HERE, + base::Bind(&PushClient::Core::OnConnect, core_.get(), base_task)); + io_message_loop_proxy_->PostTask( + FROM_HERE, + base::Bind(&PushClient::Core::OnSubscribed, core_.get())); +} + +void PushClient::SimulateDisconnectForTest() { + DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); + io_message_loop_proxy_->PostTask( + FROM_HERE, + base::Bind(&PushClient::Core::OnDisconnect, core_.get())); +} + +void PushClient::SimulateSubscriptionErrorForTest() { + io_message_loop_proxy_->PostTask( + FROM_HERE, + base::Bind(&PushClient::Core::OnSubscriptionError, core_.get())); +} + +void PushClient::ReflectSentNotificationsForTest() { + io_message_loop_proxy_->PostTask( + FROM_HERE, + base::Bind(&PushClient::Core::ReflectSentNotificationsForTest, + core_.get())); +} + +} // namespace notifier diff --git a/jingle/notifier/listener/push_client.h b/jingle/notifier/listener/push_client.h new file mode 100644 index 0000000..fdac8ba --- /dev/null +++ b/jingle/notifier/listener/push_client.h @@ -0,0 +1,98 @@ +// Copyright (c) 2012 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 JINGLE_NOTIFIER_LISTENER_PUSH_CLIENT_H_ +#define JINGLE_NOTIFIER_LISTENER_PUSH_CLIENT_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "jingle/notifier/base/notifier_options.h" +#include "jingle/notifier/listener/notification_defines.h" + +namespace base { +class MessageLoopProxy; +} // namespace base + +namespace buzz { +class XmppTaskParentInterface; +} // namespace buzz + +namespace notifier { + +// This class implements a client for the XMPP google:push protocol. +// +// This class must be used on a single thread. +class PushClient { + public: + // An Observer is sent messages whenever a notification is received + // or when the state of the push client changes. + class Observer { + public: + // Called when the state of the push client changes. If + // |notifications_enabled| is true, that means notifications can + // be sent and received freely. If it is false, that means no + // notifications can be sent or received. + virtual void OnNotificationStateChange(bool notifications_enabled) = 0; + + // Called when a notification is received. The details of the + // notification are in |notification|. + virtual void OnIncomingNotification(const Notification& notification) = 0; + + protected: + virtual ~Observer(); + }; + + explicit PushClient(const NotifierOptions& notifier_options); + ~PushClient(); + + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); + + // Takes effect only on the next (re-)connection. Therefore, you + // probably want to call this before UpdateCredentials(). + void UpdateSubscriptions(const SubscriptionList& subscriptions); + + // If not connected, connects with the given credentials. If + // already connected, the next connection attempt will use the given + // credentials. + void UpdateCredentials(const std::string& email, const std::string& token); + + // Sends a notification. Can be called when notifications are + // disabled; the notification will be sent when notifications become + // enabled. + void SendNotification(const Notification& notification); + + void SimulateOnNotificationReceivedForTest( + const Notification& notification); + + void SimulateConnectAndSubscribeForTest( + base::WeakPtr<buzz::XmppTaskParentInterface> base_task); + + void SimulateDisconnectForTest(); + + void SimulateSubscriptionErrorForTest(); + + // Any notifications sent after this is called will be reflected, + // i.e. will be treated as an incoming notification also. + void ReflectSentNotificationsForTest(); + + private: + class Core; + + // The real guts of PushClient, which allows this class to not be + // refcounted. + const scoped_refptr<Core> core_; + const scoped_refptr<base::MessageLoopProxy> parent_message_loop_proxy_; + const scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_; + + DISALLOW_COPY_AND_ASSIGN(PushClient); +}; + +} // namespace notifier + +#endif // JINGLE_NOTIFIER_LISTENER_PUSH_CLIENT_H_ diff --git a/jingle/notifier/listener/push_client_unittest.cc b/jingle/notifier/listener/push_client_unittest.cc new file mode 100644 index 0000000..a5663d7 --- /dev/null +++ b/jingle/notifier/listener/push_client_unittest.cc @@ -0,0 +1,105 @@ +// Copyright (c) 2012 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 "jingle/notifier/listener/push_client.h" + +#include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop.h" +#include "jingle/notifier/base/fake_base_task.h" +#include "jingle/notifier/base/notifier_options.h" +#include "net/url_request/url_request_test_util.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace notifier { + +namespace { + +using ::testing::_; +using ::testing::Mock; +using ::testing::StrictMock; + +class MockObserver : public PushClient::Observer { + public: + MOCK_METHOD1(OnNotificationStateChange, void(bool)); + MOCK_METHOD1(OnIncomingNotification, void(const Notification&)); +}; + +} // namespace + +class PushClientTest : public testing::Test { + protected: + PushClientTest() { + notifier_options_.request_context_getter = + new TestURLRequestContextGetter(message_loop_.message_loop_proxy()); + } + + virtual ~PushClientTest() {} + + virtual void SetUp() OVERRIDE { + push_client_.reset(new PushClient(notifier_options_)); + push_client_->AddObserver(&mock_observer_); + } + + virtual void TearDown() OVERRIDE { + // Clear out any messages posted by PushClient. + message_loop_.RunAllPending(); + push_client_->RemoveObserver(&mock_observer_); + push_client_.reset(); + } + + // The sockets created by the XMPP code expect an IO loop. + MessageLoopForIO message_loop_; + NotifierOptions notifier_options_; + StrictMock<MockObserver> mock_observer_; + scoped_ptr<PushClient> push_client_; + FakeBaseTask fake_base_task_; +}; + +TEST_F(PushClientTest, OnIncomingNotification) { + EXPECT_CALL(mock_observer_, OnIncomingNotification(_)); + push_client_->SimulateOnNotificationReceivedForTest(Notification()); +} + +TEST_F(PushClientTest, ConnectAndSubscribe) { + EXPECT_CALL(mock_observer_, OnNotificationStateChange(true)); + push_client_->SimulateConnectAndSubscribeForTest( + fake_base_task_.AsWeakPtr()); +} + +TEST_F(PushClientTest, Disconnect) { + EXPECT_CALL(mock_observer_, OnNotificationStateChange(false)); + push_client_->SimulateDisconnectForTest(); +} + +TEST_F(PushClientTest, SubscriptionError) { + EXPECT_CALL(mock_observer_, OnNotificationStateChange(false)); + push_client_->SimulateSubscriptionErrorForTest(); +} + +TEST_F(PushClientTest, SendNotification) { + EXPECT_CALL(mock_observer_, OnNotificationStateChange(true)); + EXPECT_CALL(mock_observer_, OnIncomingNotification(_)); + + push_client_->SimulateConnectAndSubscribeForTest( + fake_base_task_.AsWeakPtr()); + push_client_->ReflectSentNotificationsForTest(); + push_client_->SendNotification(Notification()); +} + +TEST_F(PushClientTest, SendNotificationPending) { + push_client_->ReflectSentNotificationsForTest(); + push_client_->SendNotification(Notification()); + + Mock::VerifyAndClearExpectations(&mock_observer_); + + EXPECT_CALL(mock_observer_, OnNotificationStateChange(true)); + EXPECT_CALL(mock_observer_, OnIncomingNotification(_)); + + push_client_->SimulateConnectAndSubscribeForTest( + fake_base_task_.AsWeakPtr()); +} + +} // namespace notifier diff --git a/jingle/notifier/listener/talk_mediator.h b/jingle/notifier/listener/talk_mediator.h deleted file mode 100644 index 7a6fa79..0000000 --- a/jingle/notifier/listener/talk_mediator.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2011 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. -// -// Interface to the code which handles talk logic. Used to initialize SSL -// before the underlying talk login occurs. -// -// Example usage: -// -// TalkMediator mediator(); -// mediator.SetAuthToken("email", "token", "service_id"); -// mediator.Login(); -// ... -// mediator.Logout(); - -#ifndef JINGLE_NOTIFIER_LISTENER_TALK_MEDIATOR_H_ -#define JINGLE_NOTIFIER_LISTENER_TALK_MEDIATOR_H_ - -#include <string> - -#include "jingle/notifier/listener/notification_defines.h" - -namespace notifier { - -class TalkMediator { - public: - TalkMediator() {} - virtual ~TalkMediator() {} - - class Delegate { - public: - virtual ~Delegate() {} - - virtual void OnNotificationStateChange(bool notifications_enabled) = 0; - - virtual void OnIncomingNotification(const Notification& notification) = 0; - - virtual void OnOutgoingNotification() = 0; - }; - - // |delegate| may be NULL. - virtual void SetDelegate(Delegate* delegate) = 0; - - // The following methods are for authorizaiton of the xmpp client. - virtual void SetAuthToken(const std::string& email, - const std::string& token, - const std::string& token_service) = 0; - virtual bool Login() = 0; - virtual bool Logout() = 0; - - // Method for the owner of this object to notify peers that an update has - // occurred. - virtual void SendNotification(const Notification& data) = 0; - - // Add a subscription to subscribe to. - virtual void AddSubscription(const Subscription& subscription) = 0; -}; - -} // namespace notifier - -#endif // JINGLE_NOTIFIER_LISTENER_TALK_MEDIATOR_H_ diff --git a/jingle/notifier/listener/talk_mediator_impl.cc b/jingle/notifier/listener/talk_mediator_impl.cc deleted file mode 100644 index 7760261..0000000 --- a/jingle/notifier/listener/talk_mediator_impl.cc +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (c) 2011 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 "jingle/notifier/listener/talk_mediator_impl.h" - -#include "base/logging.h" -#include "base/message_loop.h" -#include "jingle/notifier/base/notifier_options_util.h" - -namespace notifier { - -TalkMediatorImpl::TalkMediatorImpl( - MediatorThread* mediator_thread, - const NotifierOptions& notifier_options) - : delegate_(NULL), - mediator_thread_(mediator_thread), - notifier_options_(notifier_options), - parent_message_loop_(MessageLoop::current()) { - mediator_thread_->Start(); - state_.started = 1; -} - -TalkMediatorImpl::~TalkMediatorImpl() { - DCHECK_EQ(MessageLoop::current(), parent_message_loop_); - DCHECK(!state_.started); -} - -bool TalkMediatorImpl::Login() { - DCHECK_EQ(MessageLoop::current(), parent_message_loop_); - // Connect to the mediator thread and start processing messages. - mediator_thread_->AddObserver(this); - if (state_.initialized && !state_.logging_in && !state_.logged_in) { - state_.logging_in = true; - mediator_thread_->Login(xmpp_settings_); - return true; - } - return false; -} - -bool TalkMediatorImpl::Logout() { - DCHECK_EQ(MessageLoop::current(), parent_message_loop_); - if (state_.started) { - state_.started = 0; - state_.logging_in = 0; - state_.logged_in = 0; - // We do not want to be called back during logout since we may be - // closing. - mediator_thread_->RemoveObserver(this); - mediator_thread_->Logout(); - return true; - } - return false; -} - -void TalkMediatorImpl::SendNotification(const Notification& data) { - DCHECK_EQ(MessageLoop::current(), parent_message_loop_); - mediator_thread_->SendNotification(data); -} - -void TalkMediatorImpl::SetDelegate(TalkMediator::Delegate* delegate) { - DCHECK_EQ(MessageLoop::current(), parent_message_loop_); - delegate_ = delegate; -} - -void TalkMediatorImpl::SetAuthToken(const std::string& email, - const std::string& token, - const std::string& token_service) { - DCHECK_EQ(MessageLoop::current(), parent_message_loop_); - xmpp_settings_ = - MakeXmppClientSettings(notifier_options_, email, token, token_service); - - // The auth token got updated and we are already in the logging_in or - // logged_in state. Update the token. - if (state_.logging_in || state_.logged_in) { - mediator_thread_->UpdateXmppSettings(xmpp_settings_); - } - - state_.initialized = 1; -} - -void TalkMediatorImpl::AddSubscription(const Subscription& subscription) { - DCHECK_EQ(MessageLoop::current(), parent_message_loop_); - subscriptions_.push_back(subscription); - if (state_.logged_in) { - VLOG(1) << "Resubscribing for updates, a new service got added"; - mediator_thread_->SubscribeForUpdates(subscriptions_); - } -} - - -void TalkMediatorImpl::OnConnectionStateChange(bool logged_in) { - DCHECK_EQ(MessageLoop::current(), parent_message_loop_); - // If we just lost connection, then the MediatorThread implementation will - // try to log in again. We need to set state_.logging_in to true in that case. - state_.logging_in = !logged_in; - state_.logged_in = logged_in; - if (logged_in) { - VLOG(1) << "P2P: Logged in."; - // ListenForUpdates enables the ListenTask. This is done before - // SubscribeForUpdates. - mediator_thread_->ListenForUpdates(); - // Now subscribe for updates to all the services we are interested in - mediator_thread_->SubscribeForUpdates(subscriptions_); - } else { - VLOG(1) << "P2P: Logged off."; - OnSubscriptionStateChange(false); - } -} - -void TalkMediatorImpl::OnSubscriptionStateChange(bool subscribed) { - DCHECK_EQ(MessageLoop::current(), parent_message_loop_); - VLOG(1) << "P2P: " << (subscribed ? "subscribed" : "unsubscribed"); - if (delegate_) - delegate_->OnNotificationStateChange(subscribed); -} - -void TalkMediatorImpl::OnIncomingNotification( - const Notification& notification) { - DCHECK_EQ(MessageLoop::current(), parent_message_loop_); - VLOG(1) << "P2P: Updates are available on the server."; - if (delegate_) - delegate_->OnIncomingNotification(notification); -} - -void TalkMediatorImpl::OnOutgoingNotification() { - DCHECK_EQ(MessageLoop::current(), parent_message_loop_); - VLOG(1) << "P2P: Peers were notified that updates are available on the " - "server."; - if (delegate_) - delegate_->OnOutgoingNotification(); -} - -} // namespace notifier diff --git a/jingle/notifier/listener/talk_mediator_impl.h b/jingle/notifier/listener/talk_mediator_impl.h deleted file mode 100644 index d49e054..0000000 --- a/jingle/notifier/listener/talk_mediator_impl.h +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 2011 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. -// -// This class is the interface between talk code and the client code proper -// It will manage all aspects of the connection and call back into the client -// when it needs attention (for instance if updates are available for syncing). - -#ifndef JINGLE_NOTIFIER_LISTENER_TALK_MEDIATOR_IMPL_H_ -#define JINGLE_NOTIFIER_LISTENER_TALK_MEDIATOR_IMPL_H_ - -#include <string> -#include <vector> - -#include "base/compiler_specific.h" -#include "base/gtest_prod_util.h" -#include "base/memory/scoped_ptr.h" -#include "base/threading/non_thread_safe.h" -#include "jingle/notifier/base/notifier_options.h" -#include "jingle/notifier/listener/mediator_thread.h" -#include "jingle/notifier/listener/talk_mediator.h" -#include "talk/xmpp/xmppclientsettings.h" - -class MessageLoop; - -namespace notifier { - -class TalkMediatorImpl - : public TalkMediator, public MediatorThread::Observer { - public: - // Takes ownership of |mediator_thread|. It is guaranteed that - // |mediator_thread| is destroyed only when this object is destroyed. - // This means that you can store a pointer to mediator_thread separately - // and use it until this object is destroyed. - TalkMediatorImpl( - MediatorThread* mediator_thread, - const NotifierOptions& notifier_options); - virtual ~TalkMediatorImpl(); - - // TalkMediator implementation. - - // Should be called on the same thread as the constructor. - virtual void SetDelegate(TalkMediator::Delegate* delegate) OVERRIDE; - - // All the methods below should be called on the same thread. It may or may - // not be same as the thread on which the object was constructed. - - // |email| must be a valid email address (e.g., foo@bar.com). - virtual void SetAuthToken(const std::string& email, - const std::string& token, - const std::string& token_service) OVERRIDE; - virtual bool Login() OVERRIDE; - // Users must call Logout once Login is called. - virtual bool Logout() OVERRIDE; - - virtual void SendNotification(const Notification& data) OVERRIDE; - - virtual void AddSubscription(const Subscription& subscription) OVERRIDE; - - // MediatorThread::Delegate implementation. - - virtual void OnConnectionStateChange(bool logged_in) OVERRIDE; - - virtual void OnSubscriptionStateChange(bool subscribed) OVERRIDE; - - virtual void OnIncomingNotification( - const Notification& notification) OVERRIDE; - - virtual void OnOutgoingNotification() OVERRIDE; - - private: - struct TalkMediatorState { - TalkMediatorState() - : started(0), initialized(0), logging_in(0), logged_in(0) { - } - - unsigned int started : 1; // Background thread has started. - unsigned int initialized : 1; // Initialized with login information. - unsigned int logging_in : 1; // Logging in to the mediator's - // authenticator. - unsigned int logged_in : 1; // Logged in the mediator's authenticator. - }; - - // Delegate, which we don't own. May be NULL. - TalkMediator::Delegate* delegate_; - - // Internal state. - TalkMediatorState state_; - - // Cached and verfied from the SetAuthToken method. - buzz::XmppClientSettings xmpp_settings_; - - // The worker thread through which talk events are posted and received. - scoped_ptr<MediatorThread> mediator_thread_; - - const NotifierOptions notifier_options_; - - SubscriptionList subscriptions_; - - MessageLoop* parent_message_loop_; - - FRIEND_TEST_ALL_PREFIXES(TalkMediatorImplTest, SetAuthToken); - FRIEND_TEST_ALL_PREFIXES(TalkMediatorImplTest, SendNotification); - FRIEND_TEST_ALL_PREFIXES(TalkMediatorImplTest, MediatorThreadCallbacks); - - DISALLOW_COPY_AND_ASSIGN(TalkMediatorImpl); -}; - -} // namespace notifier - -#endif // JINGLE_NOTIFIER_LISTENER_TALK_MEDIATOR_IMPL_H_ diff --git a/jingle/notifier/listener/talk_mediator_unittest.cc b/jingle/notifier/listener/talk_mediator_unittest.cc deleted file mode 100644 index c72e0e9..0000000 --- a/jingle/notifier/listener/talk_mediator_unittest.cc +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright (c) 2011 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 <string> - -#include "base/basictypes.h" -#include "base/message_loop.h" -#include "jingle/notifier/base/notifier_options.h" -#include "jingle/notifier/listener/mediator_thread_mock.h" -#include "jingle/notifier/listener/mediator_thread_impl.h" -#include "jingle/notifier/listener/talk_mediator_impl.h" -#include "talk/xmpp/xmppengine.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace notifier { - -using ::testing::_; - -class MockTalkMediatorDelegate : public TalkMediator::Delegate { - public: - MockTalkMediatorDelegate() {} - virtual ~MockTalkMediatorDelegate() {} - - MOCK_METHOD1(OnNotificationStateChange, - void(bool notification_changed)); - MOCK_METHOD1(OnIncomingNotification, - void(const Notification& data)); - MOCK_METHOD0(OnOutgoingNotification, void()); - - private: - DISALLOW_COPY_AND_ASSIGN(MockTalkMediatorDelegate); -}; - -class TalkMediatorImplTest : public testing::Test { - protected: - TalkMediatorImplTest() {} - virtual ~TalkMediatorImplTest() {} - - TalkMediatorImpl* NewMockedTalkMediator( - MockMediatorThread* mock_mediator_thread) { - return new TalkMediatorImpl(mock_mediator_thread, - NotifierOptions()); - } - - int last_message_; - - private: - // TalkMediatorImpl expects a message loop. - MessageLoop message_loop_; - - DISALLOW_COPY_AND_ASSIGN(TalkMediatorImplTest); -}; - -TEST_F(TalkMediatorImplTest, SetAuthToken) { - scoped_ptr<TalkMediatorImpl> talk1( - NewMockedTalkMediator(new MockMediatorThread())); - talk1->SetAuthToken("chromium@gmail.com", "token", "fake_service"); - EXPECT_TRUE(talk1->state_.initialized); - talk1->Logout(); - - scoped_ptr<TalkMediatorImpl> talk2( - NewMockedTalkMediator(new MockMediatorThread())); - talk2->SetAuthToken("chromium@mail.google.com", "token", "fake_service"); - EXPECT_TRUE(talk2->state_.initialized); - talk2->Logout(); - - scoped_ptr<TalkMediatorImpl> talk3( - NewMockedTalkMediator(new MockMediatorThread())); - talk3->SetAuthToken("chromium@mail.google.com", "token", "fake_service"); - EXPECT_TRUE(talk3->state_.initialized); - talk3->Logout(); -} - -TEST_F(TalkMediatorImplTest, LoginWiring) { - // The TalkMediatorImpl owns the mock. - MockMediatorThread* mock = new MockMediatorThread(); - scoped_ptr<TalkMediatorImpl> talk1(NewMockedTalkMediator(mock)); - - // Login checks states for initialization. - EXPECT_FALSE(talk1->Login()); - EXPECT_EQ(0, mock->login_calls); - - talk1->SetAuthToken("chromium@gmail.com", "token", "fake_service"); - EXPECT_EQ(0, mock->update_settings_calls); - - EXPECT_TRUE(talk1->Login()); - EXPECT_EQ(1, mock->login_calls); - - // We call SetAuthToken again to update the settings after an update. - talk1->SetAuthToken("chromium@gmail.com", "token", "fake_service"); - EXPECT_EQ(1, mock->update_settings_calls); - - // Successive calls to login will fail. One needs to create a new talk - // mediator object. - EXPECT_FALSE(talk1->Login()); - EXPECT_EQ(1, mock->login_calls); - - EXPECT_TRUE(talk1->Logout()); - EXPECT_EQ(1, mock->logout_calls); - - // Successive logout calls do nothing. - EXPECT_FALSE(talk1->Logout()); - EXPECT_EQ(1, mock->logout_calls); -} - -TEST_F(TalkMediatorImplTest, SendNotification) { - // The TalkMediatorImpl owns the mock. - MockMediatorThread* mock = new MockMediatorThread(); - scoped_ptr<TalkMediatorImpl> talk1(NewMockedTalkMediator(mock)); - - Notification data; - talk1->SendNotification(data); - EXPECT_EQ(1, mock->send_calls); - - talk1->SetAuthToken("chromium@gmail.com", "token", "fake_service"); - EXPECT_TRUE(talk1->Login()); - talk1->OnConnectionStateChange(true); - EXPECT_EQ(1, mock->login_calls); - - talk1->SendNotification(data); - EXPECT_EQ(2, mock->send_calls); - talk1->SendNotification(data); - EXPECT_EQ(3, mock->send_calls); - - EXPECT_TRUE(talk1->Logout()); - EXPECT_EQ(1, mock->logout_calls); - - talk1->SendNotification(data); - EXPECT_EQ(4, mock->send_calls); -} - -TEST_F(TalkMediatorImplTest, MediatorThreadCallbacks) { - // The TalkMediatorImpl owns the mock. - MockMediatorThread* mock = new MockMediatorThread(); - scoped_ptr<TalkMediatorImpl> talk1(NewMockedTalkMediator(mock)); - - MockTalkMediatorDelegate mock_delegate; - EXPECT_CALL(mock_delegate, OnNotificationStateChange(true)); - EXPECT_CALL(mock_delegate, OnIncomingNotification(_)); - EXPECT_CALL(mock_delegate, OnOutgoingNotification()); - - talk1->SetDelegate(&mock_delegate); - - talk1->SetAuthToken("chromium@gmail.com", "token", "fake_service"); - EXPECT_TRUE(talk1->Login()); - EXPECT_EQ(1, mock->login_calls); - - // The message triggers calls to listen and subscribe. - EXPECT_EQ(1, mock->listen_calls); - EXPECT_EQ(1, mock->subscribe_calls); - - // After subscription success is receieved, the talk mediator will allow - // sending of notifications. - Notification outgoing_data; - talk1->SendNotification(outgoing_data); - EXPECT_EQ(1, mock->send_calls); - - Notification incoming_data; - incoming_data.channel = "service_url"; - incoming_data.data = "service_data"; - mock->ReceiveNotification(incoming_data); - - // Shouldn't trigger a call to the delegate since we disconnect - // it before we logout the mediator thread. - talk1->Logout(); - talk1.reset(); -} - -} // namespace notifier diff --git a/sync/engine/conflict_resolver.cc b/sync/engine/conflict_resolver.cc index 705567d..7409197 100644 --- a/sync/engine/conflict_resolver.cc +++ b/sync/engine/conflict_resolver.cc @@ -14,7 +14,6 @@ #include "sync/engine/syncer.h" #include "sync/engine/syncer_util.h" #include "sync/protocol/nigori_specifics.pb.h" -#include "sync/protocol/service_constants.h" #include "sync/sessions/status_controller.h" #include "sync/syncable/syncable.h" #include "sync/util/cryptographer.h" diff --git a/sync/engine/syncer_proto_util.cc b/sync/engine/syncer_proto_util.cc index 141c7e9..23bdf45 100644 --- a/sync/engine/syncer_proto_util.cc +++ b/sync/engine/syncer_proto_util.cc @@ -10,7 +10,6 @@ #include "sync/engine/syncer.h" #include "sync/engine/syncer_types.h" #include "sync/engine/traffic_logger.h" -#include "sync/protocol/service_constants.h" #include "sync/protocol/sync.pb.h" #include "sync/protocol/sync_enums.pb.h" #include "sync/protocol/sync_protocol_error.h" diff --git a/sync/internal_api/all_status.cc b/sync/internal_api/all_status.cc index 3cbfb8f..1f15f1e 100644 --- a/sync/internal_api/all_status.cc +++ b/sync/internal_api/all_status.cc @@ -9,7 +9,6 @@ #include "base/logging.h" #include "base/port.h" #include "sync/engine/net/server_connection_manager.h" -#include "sync/protocol/service_constants.h" #include "sync/sessions/session_state.h" #include "sync/syncable/model_type.h" diff --git a/sync/notifier/invalidation_notifier.cc b/sync/notifier/invalidation_notifier.cc index ed16e1c..56ee668e 100644 --- a/sync/notifier/invalidation_notifier.cc +++ b/sync/notifier/invalidation_notifier.cc @@ -10,7 +10,6 @@ #include "jingle/notifier/base/notifier_options_util.h" #include "net/url_request/url_request_context.h" #include "sync/notifier/sync_notifier_observer.h" -#include "sync/protocol/service_constants.h" #include "sync/syncable/model_type_payload_map.h" #include "talk/xmpp/jid.h" #include "talk/xmpp/xmppclientsettings.h" @@ -69,8 +68,7 @@ void InvalidationNotifier::UpdateCredentials( CHECK(!invalidation_client_id_.empty()); DVLOG(1) << "Updating credentials for " << email; buzz::XmppClientSettings xmpp_client_settings = - notifier::MakeXmppClientSettings(notifier_options_, - email, token, SYNC_SERVICE_NAME); + notifier::MakeXmppClientSettings(notifier_options_, email, token); if (state_ >= CONNECTING) { login_->UpdateXmppSettings(xmpp_client_settings); } else { diff --git a/sync/notifier/invalidation_notifier.h b/sync/notifier/invalidation_notifier.h index 385fbfc..bd30eed5 100644 --- a/sync/notifier/invalidation_notifier.h +++ b/sync/notifier/invalidation_notifier.h @@ -110,6 +110,7 @@ class InvalidationNotifier std::string invalidation_state_; // The XMPP connection manager. + // TODO(akalin): Use PushClient instead. scoped_ptr<notifier::Login> login_; // The invalidation client. diff --git a/sync/notifier/p2p_notifier.cc b/sync/notifier/p2p_notifier.cc index 49462ce..3e9def1 100644 --- a/sync/notifier/p2p_notifier.cc +++ b/sync/notifier/p2p_notifier.cc @@ -12,7 +12,6 @@ #include "base/message_loop_proxy.h" #include "base/values.h" #include "sync/notifier/sync_notifier_observer.h" -#include "sync/protocol/service_constants.h" #include "sync/syncable/model_type_payload_map.h" namespace sync_notifier { @@ -141,21 +140,21 @@ bool P2PNotificationData::ResetFromString(const std::string& str) { return true; } -P2PNotifier::P2PNotifier(notifier::TalkMediator* talk_mediator, +P2PNotifier::P2PNotifier(const notifier::NotifierOptions& notifier_options, P2PNotificationTarget send_notification_target) - : talk_mediator_(talk_mediator), + : push_client_(notifier_options), logged_in_(false), notifications_enabled_(false), send_notification_target_(send_notification_target), - parent_message_loop_proxy_( - base::MessageLoopProxy::current()) { + parent_message_loop_proxy_(base::MessageLoopProxy::current()) { DCHECK(send_notification_target_ == NOTIFY_OTHERS || send_notification_target_ == NOTIFY_ALL); - talk_mediator_->SetDelegate(this); + push_client_.AddObserver(this); } P2PNotifier::~P2PNotifier() { DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); + push_client_.RemoveObserver(this); } void P2PNotifier::AddObserver(SyncNotifierObserver* observer) { @@ -163,18 +162,9 @@ void P2PNotifier::AddObserver(SyncNotifierObserver* observer) { observer_list_.AddObserver(observer); } -// Note: Since we need to shutdown TalkMediator on the method_thread, we are -// calling Logout on TalkMediator when the last observer is removed. -// Users will need to call UpdateCredentials again to use the same object. -// TODO(akalin): Think of a better solution to fix this. void P2PNotifier::RemoveObserver(SyncNotifierObserver* observer) { DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); observer_list_.RemoveObserver(observer); - - // Logout after the last observer is removed. - if (observer_list_.size() == 0) { - talk_mediator_->Logout(); - } } void P2PNotifier::SetUniqueId(const std::string& unique_id) { @@ -189,25 +179,19 @@ void P2PNotifier::SetState(const std::string& state) { void P2PNotifier::UpdateCredentials( const std::string& email, const std::string& token) { DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); + notifier::Subscription subscription; + subscription.channel = kSyncP2PNotificationChannel; + // There may be some subtle issues around case sensitivity of the + // from field, but it doesn't matter too much since this is only + // used in p2p mode (which is only used in testing). + subscription.from = email; + push_client_.UpdateSubscriptions( + notifier::SubscriptionList(1, subscription)); + // If already logged in, the new credentials will take effect on the // next reconnection. - talk_mediator_->SetAuthToken(email, token, SYNC_SERVICE_NAME); - if (!logged_in_) { - if (!talk_mediator_->Login()) { - LOG(DFATAL) << "Could not login for " << email; - return; - } - - notifier::Subscription subscription; - subscription.channel = kSyncP2PNotificationChannel; - // There may be some subtle issues around case sensitivity of the - // from field, but it doesn't matter too much since this is only - // used in p2p mode (which is only used in testing). - subscription.from = email; - talk_mediator_->AddSubscription(subscription); - - logged_in_ = true; - } + push_client_.UpdateCredentials(email, token); + logged_in_ = true; } void P2PNotifier::UpdateEnabledTypes( @@ -281,10 +265,20 @@ void P2PNotifier::OnIncomingNotification( OnIncomingNotification(type_payloads, REMOTE_NOTIFICATION)); } -void P2PNotifier::OnOutgoingNotification() {} +void P2PNotifier::SimulateConnectForTest( + base::WeakPtr<buzz::XmppTaskParentInterface> base_task) { + DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); + push_client_.SimulateConnectAndSubscribeForTest(base_task); +} + +void P2PNotifier::ReflectSentNotificationsForTest() { + DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); + push_client_.ReflectSentNotificationsForTest(); +} void P2PNotifier::SendNotificationDataForTest( const P2PNotificationData& notification_data) { + DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); SendNotificationData(notification_data); } @@ -295,7 +289,7 @@ void P2PNotifier::SendNotificationData( notification.channel = kSyncP2PNotificationChannel; notification.data = notification_data.ToString(); DVLOG(1) << "Sending XMPP notification: " << notification.ToString(); - talk_mediator_->SendNotification(notification); + push_client_.SendNotification(notification); } } // namespace sync_notifier diff --git a/sync/notifier/p2p_notifier.h b/sync/notifier/p2p_notifier.h index 093d023..24b0ab3 100644 --- a/sync/notifier/p2p_notifier.h +++ b/sync/notifier/p2p_notifier.h @@ -13,8 +13,10 @@ #include "base/compiler_specific.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" #include "base/observer_list.h" -#include "jingle/notifier/listener/talk_mediator.h" +#include "jingle/notifier/base/notifier_options.h" +#include "jingle/notifier/listener/push_client.h" #include "sync/notifier/sync_notifier.h" #include "sync/syncable/model_type.h" @@ -22,6 +24,9 @@ namespace base { class MessageLoopProxy; } +namespace buzz { +class XmppTaskParentInterface; +} // namespace buzz namespace sync_notifier { @@ -81,17 +86,14 @@ class P2PNotificationData { class P2PNotifier : public SyncNotifier, - public notifier::TalkMediator::Delegate { + public notifier::PushClient::Observer { public: - // Takes ownership of |talk_mediator|, but it is guaranteed that - // |talk_mediator| is destroyed only when this object is destroyed. - // // The |send_notification_target| parameter was added to allow us to send // self-notifications in some cases, but not others. The value should be // either NOTIFY_ALL to send notifications to all clients, or NOTIFY_OTHERS - // to send notificaitons to all clients except for the one that triggered the + // to send notifications to all clients except for the one that triggered the // notification. See crbug.com/97780. - P2PNotifier(notifier::TalkMediator* talk_mediator, + P2PNotifier(const notifier::NotifierOptions& notifier_options, P2PNotificationTarget send_notification_target); virtual ~P2PNotifier(); @@ -108,13 +110,20 @@ class P2PNotifier virtual void SendNotification( syncable::ModelTypeSet changed_types) OVERRIDE; - // TalkMediator::Delegate implementation. + // PushClient::Delegate implementation. virtual void OnNotificationStateChange(bool notifications_enabled) OVERRIDE; virtual void OnIncomingNotification( const notifier::Notification& notification) OVERRIDE; - virtual void OnOutgoingNotification() OVERRIDE; // For testing. + + void SimulateConnectForTest( + base::WeakPtr<buzz::XmppTaskParentInterface> base_task); + + // Any notifications sent after this is called will be reflected, + // i.e. will be treated as an incoming notification also. + void ReflectSentNotificationsForTest(); + void SendNotificationDataForTest( const P2PNotificationData& notification_data); @@ -123,13 +132,13 @@ class P2PNotifier ObserverList<SyncNotifierObserver> observer_list_; - // The actual notification listener. - scoped_ptr<notifier::TalkMediator> talk_mediator_; + // The XMPP push client. + notifier::PushClient push_client_; // Our unique ID. std::string unique_id_; - // Whether we called Login() on |talk_mediator_| yet. + // Whether we have called UpdateCredentials() yet. bool logged_in_; - // Whether |talk_mediator_| has notified us that notifications are + // Whether |push_client_| has notified us that notifications are // enabled. bool notifications_enabled_; // Which set of clients should be sent notifications. diff --git a/sync/notifier/p2p_notifier_unittest.cc b/sync/notifier/p2p_notifier_unittest.cc index a9f8db9..ea85433 100644 --- a/sync/notifier/p2p_notifier_unittest.cc +++ b/sync/notifier/p2p_notifier_unittest.cc @@ -9,6 +9,10 @@ #include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop.h" +#include "jingle/notifier/base/fake_base_task.h" +#include "jingle/notifier/base/notifier_options.h" +#include "jingle/notifier/listener/push_client.h" +#include "net/url_request/url_request_test_util.h" #include "sync/notifier/mock_sync_notifier_observer.h" #include "sync/syncable/model_type.h" #include "testing/gtest/include/gtest/gtest.h" @@ -21,57 +25,25 @@ using ::testing::_; using ::testing::Mock; using ::testing::StrictMock; -class FakeTalkMediator : public notifier::TalkMediator { - public: - FakeTalkMediator() : delegate_(NULL) {} - virtual ~FakeTalkMediator() {} - - // notifier::TalkMediator implementation. - virtual void SetDelegate(Delegate* delegate) OVERRIDE { - delegate_ = delegate; - } - virtual void SetAuthToken(const std::string& email, - const std::string& token, - const std::string& token_service) OVERRIDE {} - virtual bool Login() OVERRIDE { - if (delegate_) { - delegate_->OnNotificationStateChange(true /* notifications_enabled */); - } - return true; - } - virtual bool Logout() OVERRIDE { - if (delegate_) { - delegate_->OnNotificationStateChange(false /* notifiations_enabled */); - } - return true; - } - virtual void SendNotification(const notifier::Notification& data) OVERRIDE { - if (delegate_) { - delegate_->OnOutgoingNotification(); - delegate_->OnIncomingNotification(data); - } - } - virtual void AddSubscription( - const notifier::Subscription& subscription) OVERRIDE {} - - private: - Delegate* delegate_; -}; - class P2PNotifierTest : public testing::Test { protected: - P2PNotifierTest() : talk_mediator_(NULL) {} + P2PNotifierTest() { + notifier_options_.request_context_getter = + new TestURLRequestContextGetter(message_loop_.message_loop_proxy()); + } + + virtual ~P2PNotifierTest() {} - virtual void SetUp() { - talk_mediator_ = new FakeTalkMediator(); - p2p_notifier_.reset(new P2PNotifier(talk_mediator_, NOTIFY_OTHERS)); + virtual void SetUp() OVERRIDE { + p2p_notifier_.reset(new P2PNotifier(notifier_options_, NOTIFY_OTHERS)); p2p_notifier_->AddObserver(&mock_observer_); } - virtual void TearDown() { + virtual void TearDown() OVERRIDE { + message_loop_.RunAllPending(); p2p_notifier_->RemoveObserver(&mock_observer_); p2p_notifier_.reset(); - talk_mediator_ = NULL; + message_loop_.RunAllPending(); } syncable::ModelTypePayloadMap MakePayloadMap( @@ -79,11 +51,12 @@ class P2PNotifierTest : public testing::Test { return syncable::ModelTypePayloadMapFromEnumSet(types, ""); } - MessageLoop message_loop_; - // Owned by |p2p_notifier_|. - notifier::TalkMediator* talk_mediator_; + // The sockets created by the XMPP code expect an IO loop. + MessageLoopForIO message_loop_; + notifier::NotifierOptions notifier_options_; scoped_ptr<P2PNotifier> p2p_notifier_; StrictMock<MockSyncNotifierObserver> mock_observer_; + notifier::FakeBaseTask fake_base_task_; }; TEST_F(P2PNotifierTest, P2PNotificationTarget) { @@ -166,9 +139,14 @@ TEST_F(P2PNotifierTest, NotificationsBasic) { OnIncomingNotification(MakePayloadMap(enabled_types), REMOTE_NOTIFICATION)); + p2p_notifier_->ReflectSentNotificationsForTest(); + p2p_notifier_->SetUniqueId("sender"); p2p_notifier_->UpdateCredentials("foo@bar.com", "fake_token"); p2p_notifier_->UpdateEnabledTypes(enabled_types); + + p2p_notifier_->SimulateConnectForTest(fake_base_task_.AsWeakPtr()); + // Sent with target NOTIFY_OTHERS so should not be propagated to // |mock_observer_|. { @@ -193,14 +171,22 @@ TEST_F(P2PNotifierTest, SendNotificationData) { OnIncomingNotification(MakePayloadMap(enabled_types), REMOTE_NOTIFICATION)); + p2p_notifier_->ReflectSentNotificationsForTest(); + p2p_notifier_->SetUniqueId("sender"); p2p_notifier_->UpdateCredentials("foo@bar.com", "fake_token"); p2p_notifier_->UpdateEnabledTypes(enabled_types); + p2p_notifier_->SimulateConnectForTest(fake_base_task_.AsWeakPtr()); + + message_loop_.RunAllPending(); + // Should be dropped. Mock::VerifyAndClearExpectations(&mock_observer_); p2p_notifier_->SendNotificationDataForTest(P2PNotificationData()); + message_loop_.RunAllPending(); + // Should be propagated. Mock::VerifyAndClearExpectations(&mock_observer_); EXPECT_CALL(mock_observer_, OnIncomingNotification(changed_payload_map, @@ -208,20 +194,28 @@ TEST_F(P2PNotifierTest, SendNotificationData) { p2p_notifier_->SendNotificationDataForTest( P2PNotificationData("sender", NOTIFY_SELF, changed_types)); + message_loop_.RunAllPending(); + // Should be dropped. Mock::VerifyAndClearExpectations(&mock_observer_); p2p_notifier_->SendNotificationDataForTest( P2PNotificationData("sender2", NOTIFY_SELF, changed_types)); + message_loop_.RunAllPending(); + // Should be dropped. Mock::VerifyAndClearExpectations(&mock_observer_); p2p_notifier_->SendNotificationDataForTest( P2PNotificationData("sender", NOTIFY_SELF, syncable::ModelTypeSet())); + message_loop_.RunAllPending(); + // Should be dropped. p2p_notifier_->SendNotificationDataForTest( P2PNotificationData("sender", NOTIFY_OTHERS, changed_types)); + message_loop_.RunAllPending(); + // Should be propagated. Mock::VerifyAndClearExpectations(&mock_observer_); EXPECT_CALL(mock_observer_, OnIncomingNotification(changed_payload_map, @@ -229,11 +223,15 @@ TEST_F(P2PNotifierTest, SendNotificationData) { p2p_notifier_->SendNotificationDataForTest( P2PNotificationData("sender2", NOTIFY_OTHERS, changed_types)); + message_loop_.RunAllPending(); + // Should be dropped. Mock::VerifyAndClearExpectations(&mock_observer_); p2p_notifier_->SendNotificationDataForTest( P2PNotificationData("sender2", NOTIFY_OTHERS, syncable::ModelTypeSet())); + message_loop_.RunAllPending(); + // Should be propagated. Mock::VerifyAndClearExpectations(&mock_observer_); EXPECT_CALL(mock_observer_, OnIncomingNotification(changed_payload_map, @@ -241,6 +239,8 @@ TEST_F(P2PNotifierTest, SendNotificationData) { p2p_notifier_->SendNotificationDataForTest( P2PNotificationData("sender", NOTIFY_ALL, changed_types)); + message_loop_.RunAllPending(); + // Should be propagated. Mock::VerifyAndClearExpectations(&mock_observer_); EXPECT_CALL(mock_observer_, OnIncomingNotification(changed_payload_map, @@ -248,10 +248,14 @@ TEST_F(P2PNotifierTest, SendNotificationData) { p2p_notifier_->SendNotificationDataForTest( P2PNotificationData("sender2", NOTIFY_ALL, changed_types)); + message_loop_.RunAllPending(); + // Should be dropped. Mock::VerifyAndClearExpectations(&mock_observer_); p2p_notifier_->SendNotificationDataForTest( P2PNotificationData("sender2", NOTIFY_ALL, syncable::ModelTypeSet())); + + message_loop_.RunAllPending(); } } // namespace diff --git a/sync/notifier/sync_notifier_factory.cc b/sync/notifier/sync_notifier_factory.cc index eaaf2ef..1062106 100644 --- a/sync/notifier/sync_notifier_factory.cc +++ b/sync/notifier/sync_notifier_factory.cc @@ -7,8 +7,6 @@ #include <string> #include "base/logging.h" -#include "jingle/notifier/listener/mediator_thread_impl.h" -#include "jingle/notifier/listener/talk_mediator_impl.h" #include "sync/notifier/non_blocking_invalidation_notifier.h" #include "sync/notifier/p2p_notifier.h" #include "sync/notifier/sync_notifier.h" @@ -23,17 +21,11 @@ SyncNotifier* CreateDefaultSyncNotifier( invalidation_version_tracker, const std::string& client_info) { if (notifier_options.notification_method == notifier::NOTIFICATION_P2P) { - notifier::TalkMediator* const talk_mediator = - new notifier::TalkMediatorImpl( - new notifier::MediatorThreadImpl(notifier_options), - notifier_options); // TODO(rlarocque): Ideally, the notification target would be // NOTIFY_OTHERS. There's no good reason to notify ourselves of our own // commits. We self-notify for now only because the integration tests rely // on this behaviour. See crbug.com/97780. - // - // Takes ownership of |talk_mediator|. - return new P2PNotifier(talk_mediator, NOTIFY_ALL); + return new P2PNotifier(notifier_options, NOTIFY_ALL); } return new NonBlockingInvalidationNotifier( diff --git a/sync/protocol/service_constants.h b/sync/protocol/service_constants.h deleted file mode 100644 index 83a65b1..0000000 --- a/sync/protocol/service_constants.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2012 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. -// -// Product-specific constants. - -#ifndef SYNC_PROTOCOL_SERVICE_CONSTANTS_H_ -#define SYNC_PROTOCOL_SERVICE_CONSTANTS_H_ -#pragma once - -// These fixed service names are used to obtain auth cookies for the -// corresponding services. It might be interesting to make these updateable -// as well as have the ability to add new ones. -#define SYNC_SERVICE_NAME "chromiumsync" - -#define DEFAULT_SIGNIN_DOMAIN "gmail.com" - -#define PRODUCT_NAME_STRING_NARROW "Chromium Browser Sync" - -#define PRODUCT_NAME_STRING PRODUCT_NAME_STRING_NARROW -#define PRODUCT_NAME_STRING_WIDE L##PRODUCT_NAME_STRING - -#endif // SYNC_PROTOCOL_SERVICE_CONSTANTS_H_ diff --git a/sync/sync.gyp b/sync/sync.gyp index ba97a47..f4a8790 100644 --- a/sync/sync.gyp +++ b/sync/sync.gyp @@ -109,7 +109,6 @@ 'protocol/proto_enum_conversions.h', 'protocol/proto_value_conversions.cc', 'protocol/proto_value_conversions.h', - 'protocol/service_constants.h', 'protocol/sync_protocol_error.cc', 'protocol/sync_protocol_error.h', 'sessions/debug_info_getter.h', diff --git a/sync/syncable/directory_backing_store.cc b/sync/syncable/directory_backing_store.cc index fda6d71..8447eff 100644 --- a/sync/syncable/directory_backing_store.cc +++ b/sync/syncable/directory_backing_store.cc @@ -22,7 +22,6 @@ #include "sql/statement.h" #include "sql/transaction.h" #include "sync/protocol/bookmark_specifics.pb.h" -#include "sync/protocol/service_constants.h" #include "sync/protocol/sync.pb.h" #include "sync/syncable/syncable-inl.h" #include "sync/syncable/syncable_columns.h" diff --git a/sync/syncable/syncable.cc b/sync/syncable/syncable.cc index 68b5bab..0d112dc 100644 --- a/sync/syncable/syncable.cc +++ b/sync/syncable/syncable.cc @@ -30,7 +30,6 @@ #include "base/utf_string_conversions.h" #include "base/values.h" #include "sync/protocol/proto_value_conversions.h" -#include "sync/protocol/service_constants.h" #include "sync/syncable/directory_backing_store.h" #include "sync/syncable/directory_change_delegate.h" #include "sync/syncable/in_memory_directory_backing_store.h" |