summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/components_tests.gyp6
-rw-r--r--components/signin/core/browser/DEPS6
-rw-r--r--components/signin/core/browser/test_signin_client.cc16
-rw-r--r--components/signin/core/browser/test_signin_client.h13
-rw-r--r--components/signin/ios/DEPS1
-rw-r--r--components/signin/ios/browser/profile_oauth2_token_service_ios.h15
-rw-r--r--components/signin/ios/browser/profile_oauth2_token_service_ios.mm2
-rw-r--r--components/signin/ios/browser/profile_oauth2_token_service_ios_unittest.mm276
-rw-r--r--ios/ios_tests.gyp24
-rw-r--r--ios/public/test/fake_profile_oauth2_token_service_ios_provider.h63
-rw-r--r--ios/public/test/fake_profile_oauth2_token_service_ios_provider.mm91
11 files changed, 502 insertions, 11 deletions
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index 4983e5f..9e588d8 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -115,6 +115,7 @@
'signin/core/browser/mutable_profile_oauth2_token_service_unittest.cc',
'signin/core/browser/signin_error_controller_unittest.cc',
'signin/core/browser/webdata/token_service_table_unittest.cc',
+ 'signin/ios/browser/profile_oauth2_token_service_ios_unittest.mm',
'storage_monitor/image_capture_device_manager_unittest.mm',
'storage_monitor/media_storage_util_unittest.cc',
'storage_monitor/media_transfer_protocol_device_observer_linux_unittest.cc',
@@ -298,6 +299,11 @@
['include', '^translate/'],
['include', '^variations/'],
],
+ 'dependencies': [
+ # Dependencies of signin
+ 'components.gyp:signin_ios_browser',
+ '../ios/ios_tests.gyp:test_support_ios',
+ ],
'actions': [
{
'action_name': 'copy_test_data',
diff --git a/components/signin/core/browser/DEPS b/components/signin/core/browser/DEPS
new file mode 100644
index 0000000..23ffc4d
--- /dev/null
+++ b/components/signin/core/browser/DEPS
@@ -0,0 +1,6 @@
+specific_include_rules = {
+ # Needed for test wire-up on iOS.
+ '.*test.*': [
+ "+ios/public/test/fake_profile_oauth2_token_service_ios_provider.h",
+ ],
+}
diff --git a/components/signin/core/browser/test_signin_client.cc b/components/signin/core/browser/test_signin_client.cc
index af05dd1..e197354 100644
--- a/components/signin/core/browser/test_signin_client.cc
+++ b/components/signin/core/browser/test_signin_client.cc
@@ -9,6 +9,10 @@
#include "components/webdata/common/web_database_service.h"
#include "testing/gtest/include/gtest/gtest.h"
+#if defined(OS_IOS)
+#include "ios/public/test/fake_profile_oauth2_token_service_ios_provider.h"
+#endif
+
TestSigninClient::TestSigninClient()
: request_context_(new net::TestURLRequestContextGetter(
base::MessageLoopProxy::current())) {
@@ -56,8 +60,14 @@ void TestSigninClient::SetCookieChangedCallback(
#if defined(OS_IOS)
ios::ProfileOAuth2TokenServiceIOSProvider* TestSigninClient::GetIOSProvider() {
- // Just returns NULL for now. It should be changed to return an
- // |ios::FakeProfileOAuth2TokenServiceIOSProvider|.
- return NULL;
+ return GetIOSProviderAsFake();
+}
+
+ios::FakeProfileOAuth2TokenServiceIOSProvider*
+TestSigninClient::GetIOSProviderAsFake() {
+ if (!iosProvider_) {
+ iosProvider_.reset(new ios::FakeProfileOAuth2TokenServiceIOSProvider());
+ }
+ return iosProvider_.get();
}
#endif
diff --git a/components/signin/core/browser/test_signin_client.h b/components/signin/core/browser/test_signin_client.h
index 03e0b88..0f66ef8 100644
--- a/components/signin/core/browser/test_signin_client.h
+++ b/components/signin/core/browser/test_signin_client.h
@@ -9,9 +9,14 @@
#include "base/compiler_specific.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
#include "components/signin/core/browser/signin_client.h"
#include "net/url_request/url_request_test_util.h"
+#if defined(OS_IOS)
+#include "ios/public/test/fake_profile_oauth2_token_service_ios_provider.h"
+#endif
+
// An implementation of SigninClient for use in unittests. Instantiates test
// versions of the various objects that SigninClient is required to provide as
// part of its interface.
@@ -50,6 +55,10 @@ class TestSigninClient : public SigninClient {
virtual void SetCookieChangedCallback(const CookieChangedCallback& callback)
OVERRIDE;
+#if defined(OS_IOS)
+ ios::FakeProfileOAuth2TokenServiceIOSProvider* GetIOSProviderAsFake();
+#endif
+
private:
// Loads the token database.
void LoadDatabase();
@@ -58,6 +67,10 @@ class TestSigninClient : public SigninClient {
scoped_refptr<net::TestURLRequestContextGetter> request_context_;
scoped_refptr<TokenWebData> database_;
+#if defined(OS_IOS)
+ scoped_ptr<ios::FakeProfileOAuth2TokenServiceIOSProvider> iosProvider_;
+#endif
+
DISALLOW_COPY_AND_ASSIGN(TestSigninClient);
};
diff --git a/components/signin/ios/DEPS b/components/signin/ios/DEPS
index 9af4fb8..a2fbbc5 100644
--- a/components/signin/ios/DEPS
+++ b/components/signin/ios/DEPS
@@ -1,3 +1,4 @@
include_rules = [
"+ios/public/provider/components/signin",
+ "+ios/public/test",
]
diff --git a/components/signin/ios/browser/profile_oauth2_token_service_ios.h b/components/signin/ios/browser/profile_oauth2_token_service_ios.h
index 2f32d1c..0e254ba 100644
--- a/components/signin/ios/browser/profile_oauth2_token_service_ios.h
+++ b/components/signin/ios/browser/profile_oauth2_token_service_ios.h
@@ -16,14 +16,17 @@ namespace ios{
class ProfileOAuth2TokenServiceIOSProvider;
}
-// A specialization of ProfileOAuth2TokenService for OS_IOS. It fetches access
-// tokens from the SSOAuth library if the user is signed in using shared
-// authentication or defaults to the parent class
-// |MutableProfileOAuth2TokenService| for pre-SSO signed in users.
+// A specialization of ProfileOAuth2TokenService that will be returned by
+// ProfileOAuth2TokenServiceFactory for OS_IOS when iOS authentication service
+// is used to lookup OAuth2 tokens.
//
// See |ProfileOAuth2TokenService| for usage details.
+//
+// Note: Requests should be started from the UI thread. To start a
+// request from aother thread, please use ProfileOAuth2TokenServiceRequest.
class ProfileOAuth2TokenServiceIOS : public MutableProfileOAuth2TokenService {
public:
+ ProfileOAuth2TokenServiceIOS();
virtual ~ProfileOAuth2TokenServiceIOS();
// KeyedService
@@ -84,10 +87,6 @@ class ProfileOAuth2TokenServiceIOS : public MutableProfileOAuth2TokenService {
void ForceInvalidGrantResponses();
protected:
- friend class ProfileOAuth2TokenServiceFactory;
-
- ProfileOAuth2TokenServiceIOS();
-
virtual OAuth2AccessTokenFetcher* CreateAccessTokenFetcher(
const std::string& account_id,
net::URLRequestContextGetter* getter,
diff --git a/components/signin/ios/browser/profile_oauth2_token_service_ios.mm b/components/signin/ios/browser/profile_oauth2_token_service_ios.mm
index b17a701..fb184f8 100644
--- a/components/signin/ios/browser/profile_oauth2_token_service_ios.mm
+++ b/components/signin/ios/browser/profile_oauth2_token_service_ios.mm
@@ -453,6 +453,7 @@ void ProfileOAuth2TokenServiceIOS::AddOrUpdateAccount(
const std::string& account_id) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!account_id.empty());
+ DCHECK(!use_legacy_token_service_);
bool account_present = accounts_.count(account_id) > 0;
if (account_present && accounts_[account_id]->GetAuthStatus().state() ==
@@ -476,6 +477,7 @@ void ProfileOAuth2TokenServiceIOS::RemoveAccount(
const std::string& account_id) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!account_id.empty());
+ DCHECK(!use_legacy_token_service_);
if (accounts_.count(account_id) > 0) {
CancelRequestsForAccount(account_id);
diff --git a/components/signin/ios/browser/profile_oauth2_token_service_ios_unittest.mm b/components/signin/ios/browser/profile_oauth2_token_service_ios_unittest.mm
new file mode 100644
index 0000000..cd3bf22
--- /dev/null
+++ b/components/signin/ios/browser/profile_oauth2_token_service_ios_unittest.mm
@@ -0,0 +1,276 @@
+// Copyright 2014 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 "base/run_loop.h"
+#include "components/signin/core/browser/profile_oauth2_token_service.h"
+#include "components/signin/core/browser/test_signin_client.h"
+#include "components/signin/ios/browser/profile_oauth2_token_service_ios.h"
+#include "google_apis/gaia/gaia_urls.h"
+#include "google_apis/gaia/oauth2_token_service_test_util.h"
+#include "ios/public/test/fake_profile_oauth2_token_service_ios_provider.h"
+#include "net/url_request/test_url_fetcher_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class ProfileOAuth2TokenServiceIOSTest : public testing::Test,
+ public OAuth2TokenService::Consumer,
+ public OAuth2TokenService::Observer {
+ public:
+ ProfileOAuth2TokenServiceIOSTest()
+ : OAuth2TokenService::Consumer("test_consumer_id"),
+ factory_(NULL),
+ token_available_count_(0),
+ token_revoked_count_(0),
+ tokens_loaded_count_(0),
+ access_token_success_(0),
+ access_token_failure_(0),
+ last_access_token_error_(GoogleServiceAuthError::NONE) {}
+
+ virtual void SetUp() OVERRIDE {
+ factory_.SetFakeResponse(GaiaUrls::GetInstance()->oauth2_revoke_url(),
+ "",
+ net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ fake_provider_ = client_.GetIOSProviderAsFake();
+ fake_provider_->set_using_shared_authentication(true);
+ oauth2_service_.Initialize(&client_);
+ oauth2_service_.AddObserver(this);
+ }
+
+ virtual void TearDown() OVERRIDE {
+ oauth2_service_.RemoveObserver(this);
+ oauth2_service_.Shutdown();
+ }
+
+ // OAuth2TokenService::Consumer implementation.
+ virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
+ const std::string& access_token,
+ const base::Time& expiration_time) OVERRIDE {
+ ++access_token_success_;
+ }
+
+ virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
+ const GoogleServiceAuthError& error) OVERRIDE {
+ ++access_token_failure_;
+ last_access_token_error_ = error;
+ };
+
+ // OAuth2TokenService::Observer implementation.
+ virtual void OnRefreshTokenAvailable(const std::string& account_id) OVERRIDE {
+ ++token_available_count_;
+ }
+ virtual void OnRefreshTokenRevoked(const std::string& account_id) OVERRIDE {
+ ++token_revoked_count_;
+ }
+ virtual void OnRefreshTokensLoaded() OVERRIDE { ++tokens_loaded_count_; }
+
+ void ResetObserverCounts() {
+ token_available_count_ = 0;
+ token_revoked_count_ = 0;
+ tokens_loaded_count_ = 0;
+ token_available_count_ = 0;
+ access_token_failure_ = 0;
+ }
+
+ protected:
+ base::MessageLoop message_loop_;
+ net::FakeURLFetcherFactory factory_;
+ TestSigninClient client_;
+ ios::FakeProfileOAuth2TokenServiceIOSProvider* fake_provider_;
+ ProfileOAuth2TokenServiceIOS oauth2_service_;
+ TestingOAuth2TokenServiceConsumer consumer_;
+ int token_available_count_;
+ int token_revoked_count_;
+ int tokens_loaded_count_;
+ int access_token_success_;
+ int access_token_failure_;
+ GoogleServiceAuthError last_access_token_error_;
+};
+
+TEST_F(ProfileOAuth2TokenServiceIOSTest, LoadRevokeCredentialsOneAccount) {
+ fake_provider_->AddAccount("account_id");
+ oauth2_service_.LoadCredentials("account_id");
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1, token_available_count_);
+ EXPECT_EQ(1, tokens_loaded_count_);
+ EXPECT_EQ(0, token_revoked_count_);
+ EXPECT_EQ(1U, oauth2_service_.GetAccounts().size());
+ EXPECT_TRUE(oauth2_service_.RefreshTokenIsAvailable("account_id"));
+
+ ResetObserverCounts();
+ oauth2_service_.RevokeAllCredentials();
+ EXPECT_EQ(0, token_available_count_);
+ EXPECT_EQ(0, tokens_loaded_count_);
+ EXPECT_EQ(1, token_revoked_count_);
+ EXPECT_EQ(0U, oauth2_service_.GetAccounts().size());
+ EXPECT_FALSE(oauth2_service_.RefreshTokenIsAvailable("account_id_1"));
+}
+
+TEST_F(ProfileOAuth2TokenServiceIOSTest,
+ LoadRevokeCredentialsMultipleAccounts) {
+ fake_provider_->AddAccount("account_id_1");
+ fake_provider_->AddAccount("account_id_2");
+ fake_provider_->AddAccount("account_id_3");
+ oauth2_service_.LoadCredentials("account_id_1");
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(3, token_available_count_);
+ EXPECT_EQ(1, tokens_loaded_count_);
+ EXPECT_EQ(0, token_revoked_count_);
+ EXPECT_EQ(3U, oauth2_service_.GetAccounts().size());
+ EXPECT_TRUE(oauth2_service_.RefreshTokenIsAvailable("account_id_1"));
+ EXPECT_TRUE(oauth2_service_.RefreshTokenIsAvailable("account_id_2"));
+ EXPECT_TRUE(oauth2_service_.RefreshTokenIsAvailable("account_id_3"));
+
+ ResetObserverCounts();
+ oauth2_service_.RevokeAllCredentials();
+ EXPECT_EQ(0, token_available_count_);
+ EXPECT_EQ(0, tokens_loaded_count_);
+ EXPECT_EQ(3, token_revoked_count_);
+ EXPECT_EQ(0U, oauth2_service_.GetAccounts().size());
+ EXPECT_FALSE(oauth2_service_.RefreshTokenIsAvailable("account_id_1"));
+ EXPECT_FALSE(oauth2_service_.RefreshTokenIsAvailable("account_id_2"));
+ EXPECT_FALSE(oauth2_service_.RefreshTokenIsAvailable("account_id_3"));
+}
+
+TEST_F(ProfileOAuth2TokenServiceIOSTest, ReloadCredentials) {
+ fake_provider_->AddAccount("account_id_1");
+ fake_provider_->AddAccount("account_id_2");
+ fake_provider_->AddAccount("account_id_3");
+ oauth2_service_.LoadCredentials("account_id_1");
+ base::RunLoop().RunUntilIdle();
+
+ // Change the accounts.
+ ResetObserverCounts();
+ fake_provider_->ClearAccounts();
+ fake_provider_->AddAccount("account_id_1");
+ fake_provider_->AddAccount("account_id_4");
+ oauth2_service_.ReloadCredentials();
+
+ EXPECT_EQ(1, token_available_count_);
+ EXPECT_EQ(0, tokens_loaded_count_);
+ EXPECT_EQ(2, token_revoked_count_);
+ EXPECT_EQ(2U, oauth2_service_.GetAccounts().size());
+ EXPECT_TRUE(oauth2_service_.RefreshTokenIsAvailable("account_id_1"));
+ EXPECT_FALSE(oauth2_service_.RefreshTokenIsAvailable("account_id_2"));
+ EXPECT_FALSE(oauth2_service_.RefreshTokenIsAvailable("account_id_3"));
+ EXPECT_TRUE(oauth2_service_.RefreshTokenIsAvailable("account_id_4"));
+}
+
+TEST_F(ProfileOAuth2TokenServiceIOSTest, StartRequestSuccess) {
+ fake_provider_->AddAccount("account_id_1");
+ oauth2_service_.LoadCredentials("account_id_1");
+ base::RunLoop().RunUntilIdle();
+
+ // Fetch access tokens.
+ ResetObserverCounts();
+ OAuth2TokenService::ScopeSet scopes;
+ scopes.insert("scope");
+ scoped_ptr<OAuth2TokenService::Request> request(
+ oauth2_service_.StartRequest("account_id_1", scopes, this));
+ EXPECT_EQ(0, access_token_success_);
+ EXPECT_EQ(0, access_token_failure_);
+
+ ResetObserverCounts();
+ fake_provider_->IssueAccessTokenForAllRequests();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1, access_token_success_);
+ EXPECT_EQ(0, access_token_failure_);
+}
+
+TEST_F(ProfileOAuth2TokenServiceIOSTest, StartRequestFailure) {
+ fake_provider_->AddAccount("account_id_1");
+ oauth2_service_.LoadCredentials("account_id_1");
+ base::RunLoop().RunUntilIdle();
+
+ // Fetch access tokens.
+ ResetObserverCounts();
+ OAuth2TokenService::ScopeSet scopes;
+ scopes.insert("scope");
+ scoped_ptr<OAuth2TokenService::Request> request(
+ oauth2_service_.StartRequest("account_id_1", scopes, this));
+ EXPECT_EQ(0, access_token_success_);
+ EXPECT_EQ(0, access_token_failure_);
+
+ ResetObserverCounts();
+ fake_provider_->IssueAccessTokenErrorForAllRequests();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(0, access_token_success_);
+ EXPECT_EQ(1, access_token_failure_);
+}
+
+TEST_F(ProfileOAuth2TokenServiceIOSTest, Migration) {
+ fake_provider_->set_using_shared_authentication(false);
+ oauth2_service_.LoadCredentials("account_id_1");
+ base::RunLoop().RunUntilIdle();
+
+ ResetObserverCounts();
+ oauth2_service_.UpdateCredentials("account_id_1", "pre_sso_refresh_token_1");
+ oauth2_service_.UpdateCredentials("account_id_2", "pre_sso_refresh_token_2");
+ EXPECT_EQ(2, token_available_count_);
+ EXPECT_EQ(0, tokens_loaded_count_);
+ EXPECT_EQ(0, token_revoked_count_);
+ EXPECT_EQ(2U, oauth2_service_.GetAccounts().size());
+ EXPECT_TRUE(oauth2_service_.RefreshTokenIsAvailable("account_id_1"));
+ EXPECT_TRUE(oauth2_service_.RefreshTokenIsAvailable("account_id_2"));
+ EXPECT_EQ("pre_sso_refresh_token_1",
+ oauth2_service_.GetRefreshTokenWhenNotUsingSharedAuthentication(
+ "account_id_1"));
+ EXPECT_EQ("pre_sso_refresh_token_2",
+ oauth2_service_.GetRefreshTokenWhenNotUsingSharedAuthentication(
+ "account_id_2"));
+
+ ResetObserverCounts();
+ oauth2_service_.StartUsingSharedAuthentication();
+ EXPECT_EQ(0, token_available_count_);
+ EXPECT_EQ(0, tokens_loaded_count_);
+ EXPECT_EQ(2, token_revoked_count_);
+ EXPECT_EQ(0U, oauth2_service_.GetAccounts().size());
+ EXPECT_FALSE(oauth2_service_.RefreshTokenIsAvailable("account_id_1"));
+ EXPECT_FALSE(oauth2_service_.RefreshTokenIsAvailable("account_id_2"));
+
+ ResetObserverCounts();
+ fake_provider_->AddAccount("account_id_1");
+ oauth2_service_.ReloadCredentials();
+ EXPECT_EQ(1, token_available_count_);
+ EXPECT_EQ(0, tokens_loaded_count_);
+ EXPECT_EQ(0, token_revoked_count_);
+ EXPECT_EQ(1U, oauth2_service_.GetAccounts().size());
+ EXPECT_TRUE(oauth2_service_.RefreshTokenIsAvailable("account_id_1"));
+ EXPECT_FALSE(oauth2_service_.RefreshTokenIsAvailable("account_id_2"));
+}
+
+TEST_F(ProfileOAuth2TokenServiceIOSTest, ForceInvalidGrantResponses) {
+ fake_provider_->set_using_shared_authentication(false);
+ oauth2_service_.LoadCredentials("account_id_1");
+ base::RunLoop().RunUntilIdle();
+ oauth2_service_.UpdateCredentials("account_id_1", "pre_sso_refresh_token_1");
+ EXPECT_TRUE(oauth2_service_.RefreshTokenIsAvailable("account_id_1"));
+
+ // First call revokes the existing token and then updates the credentials
+ // with a fake token.
+ ResetObserverCounts();
+ oauth2_service_.ForceInvalidGrantResponses();
+ EXPECT_EQ(1, token_available_count_);
+ EXPECT_EQ(0, tokens_loaded_count_);
+ EXPECT_EQ(1, token_revoked_count_);
+ EXPECT_TRUE(oauth2_service_.RefreshTokenIsAvailable("account_id_1"));
+
+ // Fetching access tokens fails with invalid grant responses.
+ OAuth2TokenService::ScopeSet scopes;
+ scopes.insert("scope");
+ scoped_ptr<OAuth2TokenService::Request> request(
+ oauth2_service_.StartRequest("account_id_1", scopes, this));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(0, access_token_success_);
+ EXPECT_EQ(1, access_token_failure_);
+ EXPECT_EQ(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS,
+ last_access_token_error_.state());
+
+ // Second call to force invalid grant responses is ignored.
+ ResetObserverCounts();
+ oauth2_service_.ForceInvalidGrantResponses();
+ EXPECT_EQ(0, token_available_count_);
+ EXPECT_EQ(0, tokens_loaded_count_);
+ EXPECT_EQ(0, token_revoked_count_);
+ EXPECT_TRUE(oauth2_service_.RefreshTokenIsAvailable("account_id_1"));
+}
diff --git a/ios/ios_tests.gyp b/ios/ios_tests.gyp
new file mode 100644
index 0000000..563fe49
--- /dev/null
+++ b/ios/ios_tests.gyp
@@ -0,0 +1,24 @@
+# Copyright 2014 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.
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'targets': [
+ {
+ 'target_name': 'test_support_ios',
+ 'type': 'static_library',
+ 'sources': [
+ 'public/test/fake_profile_oauth2_token_service_ios_provider.h',
+ 'public/test/fake_profile_oauth2_token_service_ios_provider.mm',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/testing/gtest.gyp:gtest',
+ ],
+ 'include_dirs': [
+ '<(DEPTH)',
+ ],
+ },
+ ],
+}
diff --git a/ios/public/test/fake_profile_oauth2_token_service_ios_provider.h b/ios/public/test/fake_profile_oauth2_token_service_ios_provider.h
new file mode 100644
index 0000000..2ca953a
--- /dev/null
+++ b/ios/public/test/fake_profile_oauth2_token_service_ios_provider.h
@@ -0,0 +1,63 @@
+// Copyright 2014 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 IOS_TEST_MOCK_PROFILE_OAUTH2_TOKEN_SERVICE_PROVIDER_IOS_H_
+#define IOS_TEST_MOCK_PROFILE_OAUTH2_TOKEN_SERVICE_PROVIDER_IOS_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "ios/public/provider/components/signin/browser/profile_oauth2_token_service_ios_provider.h"
+
+namespace ios {
+
+// Mock class of ProfileOAuth2TokenServiceIOSProvider for testing.
+class FakeProfileOAuth2TokenServiceIOSProvider
+ : public ProfileOAuth2TokenServiceIOSProvider {
+ public:
+ FakeProfileOAuth2TokenServiceIOSProvider();
+ virtual ~FakeProfileOAuth2TokenServiceIOSProvider();
+
+ // ProfileOAuth2TokenServiceIOSProvider
+ virtual bool IsUsingSharedAuthentication() const OVERRIDE;
+ virtual void InitializeSharedAuthentication() OVERRIDE;
+
+ virtual void GetAccessToken(const std::string& account_id,
+ const std::string& client_id,
+ const std::string& client_secret,
+ const std::set<std::string>& scopes,
+ const AccessTokenCallback& callback) OVERRIDE;
+
+ virtual std::vector<std::string> GetAllAccountIds() OVERRIDE;
+
+ virtual AuthenticationErrorCategory GetAuthenticationErrorCategory(
+ NSError* error) const OVERRIDE;
+
+ // Methods to configure this fake provider.
+ void AddAccount(const std::string& account_id);
+ void SetAccounts(const std::vector<std::string>& accounts);
+ void ClearAccounts();
+ void set_using_shared_authentication(bool is_using_shared_authentication) {
+ is_using_shared_authentication_ = is_using_shared_authentication;
+ }
+
+ // Issues access token responses.
+ void IssueAccessTokenForAllRequests();
+ void IssueAccessTokenErrorForAllRequests();
+
+ private:
+ typedef std::pair<std::string, AccessTokenCallback> AccessTokenRequest;
+
+ std::vector<std::string> accounts_;
+ bool is_using_shared_authentication_;
+ std::vector<AccessTokenRequest> requests_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeProfileOAuth2TokenServiceIOSProvider);
+};
+
+} // namespace ios
+
+#endif // IOS_TEST_PROVIDER_CHROME_BROWSER_SIGNIN_MOCK_PROFILE_OAUTH2_TOKEN_SERVICE_PROVIDER_IOS_H_
diff --git a/ios/public/test/fake_profile_oauth2_token_service_ios_provider.mm b/ios/public/test/fake_profile_oauth2_token_service_ios_provider.mm
new file mode 100644
index 0000000..e6ff73d
--- /dev/null
+++ b/ios/public/test/fake_profile_oauth2_token_service_ios_provider.mm
@@ -0,0 +1,91 @@
+// Copyright 2014 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 "ios/public/test/fake_profile_oauth2_token_service_ios_provider.h"
+
+#include <Foundation/Foundation.h>
+
+#include "base/logging.h"
+#include "base/strings/sys_string_conversions.h"
+
+namespace ios {
+
+FakeProfileOAuth2TokenServiceIOSProvider::
+ FakeProfileOAuth2TokenServiceIOSProvider()
+ : is_using_shared_authentication_(true) {}
+
+FakeProfileOAuth2TokenServiceIOSProvider::
+ ~FakeProfileOAuth2TokenServiceIOSProvider() {}
+
+void FakeProfileOAuth2TokenServiceIOSProvider::GetAccessToken(
+ const std::string& account_id,
+ const std::string& client_id,
+ const std::string& client_secret,
+ const std::set<std::string>& scopes,
+ const AccessTokenCallback& callback) {
+ DCHECK(is_using_shared_authentication_);
+ requests_.push_back(AccessTokenRequest(account_id, callback));
+}
+
+std::vector<std::string>
+FakeProfileOAuth2TokenServiceIOSProvider::GetAllAccountIds() {
+ return accounts_;
+}
+
+void FakeProfileOAuth2TokenServiceIOSProvider::AddAccount(
+ const std::string& account_id) {
+ accounts_.push_back(account_id);
+}
+
+void FakeProfileOAuth2TokenServiceIOSProvider::SetAccounts(
+ const std::vector<std::string>& accounts) {
+ accounts_ = accounts;
+}
+
+void FakeProfileOAuth2TokenServiceIOSProvider::ClearAccounts() {
+ accounts_.clear();
+}
+
+void
+FakeProfileOAuth2TokenServiceIOSProvider::IssueAccessTokenForAllRequests() {
+ for (auto i = requests_.begin(); i != requests_.end(); ++i) {
+ std::string account_id = i->first;
+ AccessTokenCallback callback = i->second;
+ NSString* access_token = [NSString
+ stringWithFormat:@"fake_access_token [account=%s]", account_id.c_str()];
+ NSDate* one_hour_from_now = [NSDate dateWithTimeIntervalSinceNow:3600];
+ callback.Run(access_token, one_hour_from_now, nil);
+ }
+ requests_.clear();
+}
+
+void FakeProfileOAuth2TokenServiceIOSProvider::
+ IssueAccessTokenErrorForAllRequests() {
+ for (auto i = requests_.begin(); i != requests_.end(); ++i) {
+ std::string account_id = i->first;
+ AccessTokenCallback callback = i->second;
+ NSError* error = [[[NSError alloc] initWithDomain:@"fake_access_token_error"
+ code:-1
+ userInfo:nil] autorelease];
+ callback.Run(nil, nil, error);
+ }
+ requests_.clear();
+}
+
+bool FakeProfileOAuth2TokenServiceIOSProvider::IsUsingSharedAuthentication()
+ const {
+ return is_using_shared_authentication_;
+}
+
+void
+FakeProfileOAuth2TokenServiceIOSProvider::InitializeSharedAuthentication() {}
+
+AuthenticationErrorCategory
+FakeProfileOAuth2TokenServiceIOSProvider::GetAuthenticationErrorCategory(
+ NSError* error) const {
+ DCHECK(error);
+ return ios::kAuthenticationErrorCategoryAuthorizationErrors;
+}
+
+} // namespace ios