diff options
author | munjal@chromium.org <munjal@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-17 00:59:35 +0000 |
---|---|---|
committer | munjal@chromium.org <munjal@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-17 00:59:35 +0000 |
commit | 0293a70dbc055eb610e4f59ff9ffc6420ef0a719 (patch) | |
tree | 8938e913e56c80639708e16667472e846e2f235f /chrome/browser | |
parent | f256d3b5a521adddb7aaeeb8ec336038be8d6581 (diff) | |
download | chromium_src-0293a70dbc055eb610e4f59ff9ffc6420ef0a719.zip chromium_src-0293a70dbc055eb610e4f59ff9ffc6420ef0a719.tar.gz chromium_src-0293a70dbc055eb610e4f59ff9ffc6420ef0a719.tar.bz2 |
Integrate AppNotifyChannelSetup with TokenService.
Review URL: http://codereview.chromium.org/8526015
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@110410 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
3 files changed, 234 insertions, 34 deletions
diff --git a/chrome/browser/extensions/app_notify_channel_setup.cc b/chrome/browser/extensions/app_notify_channel_setup.cc index 429ea86..4712c4c 100644 --- a/chrome/browser/extensions/app_notify_channel_setup.cc +++ b/chrome/browser/extensions/app_notify_channel_setup.cc @@ -4,6 +4,7 @@ #include "chrome/browser/extensions/app_notify_channel_setup.h" +#include "base/basictypes.h" #include "base/bind.h" #include "base/command_line.h" #include "base/json/json_reader.h" @@ -11,11 +12,14 @@ #include "chrome/browser/net/gaia/token_service.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/common/chrome_notification_types.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/net/gaia/gaia_constants.h" #include "chrome/common/net/http_return.h" #include "chrome/common/pref_names.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/notification_details.h" +#include "content/public/browser/notification_service.h" #include "content/public/common/url_fetcher.h" #include "net/base/escape.h" #include "net/base/load_flags.h" @@ -46,6 +50,11 @@ static const char kOAuth2IssueTokenScope[] = static const char kCWSChannelServiceURL[] = "https://www-googleapis-staging.sandbox.google.com/chromewebstore/" "v1internal/channels/app_id/oauth_client_id"; +static const char* kRelevantGaiaServices[] = { + GaiaConstants::kCWSService, + GaiaConstants::kLSOService, +}; +static const int kRelevantGaiaServicesCount = arraysize(kRelevantGaiaServices); } // namespace. AppNotifyChannelSetup::AppNotifyChannelSetup( @@ -65,43 +74,63 @@ AppNotifyChannelSetup::AppNotifyChannelSetup( callback_id_(callback_id), delegate_(delegate), ui_(ui), - state_(INITIAL) {} + state_(INITIAL), + fetch_token_success_count_(0), + fetch_token_fail_count_(0) {} AppNotifyChannelSetup::~AppNotifyChannelSetup() {} void AppNotifyChannelSetup::Start() { - AddRef(); // Balanced in ReportResult. - - CHECK_EQ(INITIAL, state_); + AddRef(); // Balanced in ReportResult. + BeginLogin(); +} - // Check if the user is logged in to the browser. - std::string username = profile_->GetPrefs()->GetString( - prefs::kGoogleServicesUsername); +void AppNotifyChannelSetup::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + if (type == chrome::NOTIFICATION_TOKEN_AVAILABLE) { + TokenService::TokenAvailableDetails* tok_details = + content::Details<TokenService::TokenAvailableDetails>(details).ptr(); + if (IsGaiaServiceRelevant(tok_details->service())) + ++fetch_token_success_count_; + } else if (type == chrome::NOTIFICATION_TOKEN_REQUEST_FAILED) { + TokenService::TokenRequestFailedDetails* error_details = + content::Details<TokenService::TokenRequestFailedDetails>( + details).ptr(); + if (IsGaiaServiceRelevant(error_details->service())) + ++fetch_token_fail_count_; + } else { + CHECK(false) << "Received a notification not registered for."; + } - if (username.empty()) { - state_ = LOGIN_STARTED; - ui_->PromptSyncSetup(this); - return; // We'll get called back in OnSyncSetupResult + // If we already got fetch results (success + failure) for all services + // we care about, we are done with fetching tokens. + if (fetch_token_success_count_ + fetch_token_fail_count_ == + kRelevantGaiaServicesCount) { + UnregisterForTokenServiceNotifications(); + // We successfully fetched tokens if success count is equal to the + // number of services we care about. + bool success = (fetch_token_success_count_ == kRelevantGaiaServicesCount); + EndFetchTokens(success); } +} - state_ = LOGIN_DONE; - BeginRecordGrant(); +bool AppNotifyChannelSetup::ShouldFetchServiceTokens() const { + TokenService* token_service = profile_->GetTokenService(); + for (int i = 0; i < kRelevantGaiaServicesCount; ++i) { + if (!token_service->HasTokenForService(kRelevantGaiaServices[i])) + return true; + } + return false; } void AppNotifyChannelSetup::OnSyncSetupResult(bool enabled) { - CHECK_EQ(LOGIN_STARTED, state_); - if (enabled) { - state_ = LOGIN_DONE; - BeginRecordGrant(); - } else { - state_ = ERROR_STATE; - ReportResult("", kChannelSetupCanceledByUser); - } + EndLogin(enabled); } void AppNotifyChannelSetup::OnURLFetchComplete(const URLFetcher* source) { CHECK(source); - switch (state_) { case RECORD_GRANT_STARTED: EndRecordGrant(source); @@ -133,8 +162,85 @@ URLFetcher* AppNotifyChannelSetup::CreateURLFetcher( return fetcher; } -void AppNotifyChannelSetup::BeginRecordGrant() { +// static +bool AppNotifyChannelSetup::IsGaiaServiceRelevant(const std::string& service) { + for (int i = 0; i < kRelevantGaiaServicesCount; ++i) { + if (service == kRelevantGaiaServices[i]) + return true; + } + return false; +} + +void AppNotifyChannelSetup::RegisterForTokenServiceNotifications() { + content::Source<TokenService> token_service(profile_->GetTokenService()); + registrar_.Add(this, + chrome::NOTIFICATION_TOKEN_AVAILABLE, + token_service); + registrar_.Add(this, + chrome::NOTIFICATION_TOKEN_REQUEST_FAILED, + token_service); +} + +void AppNotifyChannelSetup::UnregisterForTokenServiceNotifications() { + registrar_.RemoveAll(); +} + +bool AppNotifyChannelSetup::ShouldPromptForLogin() const { + std::string username = profile_->GetPrefs()->GetString( + prefs::kGoogleServicesUsername); + return username.empty(); +} + +void AppNotifyChannelSetup::BeginLogin() { + CHECK_EQ(INITIAL, state_); + state_ = LOGIN_STARTED; + if (ShouldPromptForLogin()) { + ui_->PromptSyncSetup(this); + // We'll get called back in OnSyncSetupResult + } else { + EndLogin(true); + } +} + +void AppNotifyChannelSetup::EndLogin(bool success) { + CHECK_EQ(LOGIN_STARTED, state_); + if (success) { + state_ = LOGIN_DONE; + BeginFetchTokens(); + } else { + state_ = ERROR_STATE; + ReportResult("", kChannelSetupCanceledByUser); + } +} + +void AppNotifyChannelSetup::BeginFetchTokens() { CHECK_EQ(LOGIN_DONE, state_); + state_ = FETCH_TOKEN_STARTED; + if (ShouldFetchServiceTokens()) { + // If a user is logged in already, and a new version of Chrome is released + // with new services added to Tokenservice, TokenService will not have + // tokens for the new services. + RegisterForTokenServiceNotifications(); + profile_->GetTokenService()->StartFetchingMissingTokens(); + // Observe will get called with notifications from TokenService. + } else { + EndFetchTokens(true); + } +} + +void AppNotifyChannelSetup::EndFetchTokens(bool success) { + CHECK_EQ(FETCH_TOKEN_STARTED, state_); + if (success) { + state_ = FETCH_TOKEN_DONE; + BeginRecordGrant(); + } else { + state_ = ERROR_STATE; + ReportResult("", kChannelSetupInternalError); + } +} + +void AppNotifyChannelSetup::BeginRecordGrant() { + CHECK(FETCH_TOKEN_DONE == state_); state_ = RECORD_GRANT_STARTED; GURL url = GetOAuth2IssueTokenURL(); diff --git a/chrome/browser/extensions/app_notify_channel_setup.h b/chrome/browser/extensions/app_notify_channel_setup.h index e748e15..d960ee0 100644 --- a/chrome/browser/extensions/app_notify_channel_setup.h +++ b/chrome/browser/extensions/app_notify_channel_setup.h @@ -9,6 +9,8 @@ #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/extensions/app_notify_channel_ui.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" #include "content/public/common/url_fetcher.h" #include "content/public/common/url_fetcher_delegate.h" #include "googleurl/src/gurl.h" @@ -16,6 +18,10 @@ class AppNotifyChannelSetupTest; class Profile; +namespace content { +class NotificationDetails; +} + // This class uses the browser login credentials to setup app notifications // for a given app. // @@ -27,6 +33,7 @@ class Profile; // the above steps. class AppNotifyChannelSetup : public content::URLFetcherDelegate, + public content::NotificationObserver, public AppNotifyChannelUI::Delegate, public base::RefCountedThreadSafe<AppNotifyChannelSetup> { public: @@ -51,10 +58,16 @@ class AppNotifyChannelSetup AppNotifyChannelUI* ui, base::WeakPtr<Delegate> delegate); + AppNotifyChannelUI* ui() { return ui_.get(); } + // This begins the process of fetching the channel id using the browser login // credentials (or using |ui_| to prompt for login if needed). void Start(); + // Implementing content::NotificationObserver interface. + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; protected: // content::URLFetcherDelegate. virtual void OnURLFetchComplete(const content::URLFetcher* source) OVERRIDE; @@ -67,6 +80,8 @@ class AppNotifyChannelSetup INITIAL, LOGIN_STARTED, LOGIN_DONE, + FETCH_TOKEN_STARTED, + FETCH_TOKEN_DONE, RECORD_GRANT_STARTED, RECORD_GRANT_DONE, CHANNEL_ID_SETUP_STARTED, @@ -84,6 +99,10 @@ class AppNotifyChannelSetup // Caller owns the returned instance. content::URLFetcher* CreateURLFetcher( const GURL& url, const std::string& body, const std::string& auth_token); + void BeginLogin(); + void EndLogin(bool success); + void BeginFetchTokens(); + void EndFetchTokens(bool success); void BeginRecordGrant(); void EndRecordGrant(const content::URLFetcher* source); void BeginGetChannelId(); @@ -100,8 +119,16 @@ class AppNotifyChannelSetup std::string GetCWSAuthToken(); static bool ParseCWSChannelServiceResponse( const std::string& data, std::string* result); + static bool IsGaiaServiceRelevant(const std::string& service); + // Checks if the user needs to be prompted for login. + bool ShouldPromptForLogin() const; + // Checks if we need to fetch auth tokens for services we care about. + virtual bool ShouldFetchServiceTokens() const; + void RegisterForTokenServiceNotifications(); + void UnregisterForTokenServiceNotifications(); Profile* profile_; + content::NotificationRegistrar registrar_; std::string extension_id_; std::string client_id_; GURL requestor_url_; @@ -111,6 +138,8 @@ class AppNotifyChannelSetup scoped_ptr<content::URLFetcher> url_fetcher_; scoped_ptr<AppNotifyChannelUI> ui_; State state_; + int fetch_token_success_count_; + int fetch_token_fail_count_; DISALLOW_COPY_AND_ASSIGN(AppNotifyChannelSetup); }; diff --git a/chrome/browser/extensions/app_notify_channel_setup_unittest.cc b/chrome/browser/extensions/app_notify_channel_setup_unittest.cc index 70ce352..29c4511 100644 --- a/chrome/browser/extensions/app_notify_channel_setup_unittest.cc +++ b/chrome/browser/extensions/app_notify_channel_setup_unittest.cc @@ -8,16 +8,23 @@ #include "base/memory/weak_ptr.h" #include "base/message_loop.h" #include "chrome/browser/extensions/app_notify_channel_setup.h" +#include "chrome/browser/extensions/app_notify_channel_ui.h" +#include "chrome/browser/net/gaia/token_service.h" +#include "chrome/browser/net/gaia/token_service_unittest.h" #include "chrome/common/chrome_switches.h" +#include "chrome/common/net/gaia/gaia_urls.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/testing_pref_service.h" #include "chrome/test/base/testing_profile.h" #include "content/test/test_browser_thread.h" #include "content/test/test_url_fetcher_factory.h" #include "googleurl/src/gurl.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" using content::BrowserThread; +using testing::_; +using testing::Return; namespace { @@ -25,6 +32,36 @@ const int kRouteId = 4; const int kCallbackId = 5; const char* kFakeExtensionId = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; +class MockTokenService : public TokenService { + public: + MockTokenService() { } + virtual ~MockTokenService() { } + + bool AreCredentialsValid() const OVERRIDE { + return true; + } + + MOCK_CONST_METHOD1(HasTokenForService, bool(const char*)); +}; + +class TestProfile : public TestingProfile { + public: + TestProfile() : TestingProfile() { } + virtual ~TestProfile() { } + + virtual TokenService* GetTokenService() OVERRIDE { + return &token_service_; + } + + void SetTokenServiceHasTokenResult(bool result) { + EXPECT_CALL(token_service_, HasTokenForService(_)) + .WillRepeatedly(Return(result)); + } + + private: + MockTokenService token_service_; +}; + class TestDelegate : public AppNotifyChannelSetup::Delegate, public base::SupportsWeakPtr<TestDelegate> { public: @@ -127,13 +164,13 @@ class AppNotifyChannelSetupTest : public testing::Test { virtual AppNotifyChannelSetup* CreateInstance() { GURL page_url("http://www.google.com"); return new AppNotifyChannelSetup(&profile_, - kFakeExtensionId, - "1234", - page_url, - kRouteId, - kCallbackId, - ui_.release(), - delegate_.AsWeakPtr()); + kFakeExtensionId, + "1234", + page_url, + kRouteId, + kCallbackId, + ui_.release(), + delegate_.AsWeakPtr()); } virtual void SetupLogin(bool should_succeed) { @@ -143,6 +180,16 @@ class AppNotifyChannelSetupTest : public testing::Test { ui_->SetSyncSetupResult(false); } + virtual void SetupFetchTokens(bool should_have_tokens, bool should_succeed) { + profile_.SetTokenServiceHasTokenResult(should_have_tokens); + if (!should_have_tokens) { + factory_.SetFakeResponse( + GaiaUrls::GetInstance()->issue_auth_token_url(), + "some_token", + should_succeed); + } + } + virtual void SetupRecordGrant(bool should_succeed) { factory_.SetFakeResponse( AppNotifyChannelSetup::GetOAuth2IssueTokenURL().spec(), @@ -157,7 +204,6 @@ class AppNotifyChannelSetupTest : public testing::Test { should_succeed); } - virtual void RunServerTest(AppNotifyChannelSetup* setup, const std::string& expected_code, const std::string& expected_error) { @@ -169,22 +215,39 @@ class AppNotifyChannelSetupTest : public testing::Test { protected: MessageLoop message_loop_; content::TestBrowserThread ui_thread_; - TestingProfile profile_; + TestProfile profile_; TestDelegate delegate_; scoped_ptr<TestUI> ui_; FakeURLFetcherFactory factory_; }; TEST_F(AppNotifyChannelSetupTest, LoginFailure) { - // Set login to fail. SetupLogin(false); scoped_refptr<AppNotifyChannelSetup> setup = CreateInstance(); RunServerTest(setup, "", "canceled_by_user"); } -TEST_F(AppNotifyChannelSetupTest, RecordGrantFailure) { +TEST_F(AppNotifyChannelSetupTest, FetchTokensFailure) { + SetupLogin(true); + SetupFetchTokens(false, false); + + scoped_refptr<AppNotifyChannelSetup> setup = CreateInstance(); + RunServerTest(setup, "", "internal_error"); +} + +TEST_F(AppNotifyChannelSetupTest, TokensAvailableRecordGrantFailure) { + SetupLogin(true); + SetupFetchTokens(true, false); + SetupRecordGrant(false); + + scoped_refptr<AppNotifyChannelSetup> setup = CreateInstance(); + RunServerTest(setup, "", "internal_error"); +} + +TEST_F(AppNotifyChannelSetupTest, TokenFetchSuccessAndRecordGrantFailure) { SetupLogin(true); + SetupFetchTokens(false , true); SetupRecordGrant(false); scoped_refptr<AppNotifyChannelSetup> setup = CreateInstance(); @@ -193,6 +256,7 @@ TEST_F(AppNotifyChannelSetupTest, RecordGrantFailure) { TEST_F(AppNotifyChannelSetupTest, GetChannelIdFailure) { SetupLogin(true); + SetupFetchTokens(true, false); SetupRecordGrant(true); SetupGetChannelId(false); @@ -202,6 +266,7 @@ TEST_F(AppNotifyChannelSetupTest, GetChannelIdFailure) { TEST_F(AppNotifyChannelSetupTest, ServerSuccess) { SetupLogin(true); + SetupFetchTokens(true, false); SetupRecordGrant(true); SetupGetChannelId(true); |