summaryrefslogtreecommitdiffstats
path: root/google_apis
diff options
context:
space:
mode:
authormaniscalco@chromium.org <maniscalco@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-02 16:09:04 +0000
committermaniscalco@chromium.org <maniscalco@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-02 16:09:04 +0000
commit0dae69276ba560251e1f4c079ffd0a6130b57b06 (patch)
tree6464d23d0de1e9d3697da1f594b5347673ec1f35 /google_apis
parenta4205207e8e6bba4ebe0946b9d0b34abe946065f (diff)
downloadchromium_src-0dae69276ba560251e1f4c079ffd0a6130b57b06.zip
chromium_src-0dae69276ba560251e1f4c079ffd0a6130b57b06.tar.gz
chromium_src-0dae69276ba560251e1f4c079ffd0a6130b57b06.tar.bz2
Componentize and rename ProfileOAuth2TokenServiceRequest.
The purpose of this change is to move ProfileOAuth2TokenServiceRequest into google_apis/gaia and drop any browser dependencies. ProfileOAuth2TokenServiceRequest becomes OAuth2TokenServiceRequest. Add support for invalidating tokens. Review URL: https://codereview.chromium.org/299943003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@274255 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'google_apis')
-rw-r--r--google_apis/gaia/oauth2_token_service_request.cc348
-rw-r--r--google_apis/gaia/oauth2_token_service_request.h96
-rw-r--r--google_apis/gaia/oauth2_token_service_request_unittest.cc257
-rw-r--r--google_apis/google_apis.gyp3
4 files changed, 704 insertions, 0 deletions
diff --git a/google_apis/gaia/oauth2_token_service_request.cc b/google_apis/gaia/oauth2_token_service_request.cc
new file mode 100644
index 0000000..c946fde
--- /dev/null
+++ b/google_apis/gaia/oauth2_token_service_request.cc
@@ -0,0 +1,348 @@
+// 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 "google_apis/gaia/oauth2_token_service_request.h"
+
+#include "base/bind.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "google_apis/gaia/google_service_auth_error.h"
+#include "google_apis/gaia/oauth2_access_token_consumer.h"
+
+OAuth2TokenServiceRequest::TokenServiceProvider::TokenServiceProvider() {
+}
+
+OAuth2TokenServiceRequest::TokenServiceProvider::~TokenServiceProvider() {
+}
+
+// Core serves as the base class for OAuth2TokenService operations. Each
+// operation should be modeled as a derived type.
+//
+// Core is used like this:
+//
+// 1. Constructed on owner thread.
+//
+// 2. Start() is called on owner thread, which calls StartOnTokenServiceThread()
+// on token service thread.
+//
+// 3. Request is executed.
+//
+// 4. Stop() is called on owner thread, which calls StopOnTokenServiceThread()
+// on token service thread.
+//
+// 5. Core is destroyed on owner thread.
+class OAuth2TokenServiceRequest::Core
+ : public base::NonThreadSafe,
+ public base::RefCountedThreadSafe<OAuth2TokenServiceRequest::Core> {
+ public:
+ // Note the thread where an instance of Core is constructed is referred to as
+ // the "owner thread" here.
+ Core(OAuth2TokenServiceRequest* owner, TokenServiceProvider* provider);
+
+ // Starts the core. Must be called on the owner thread.
+ void Start();
+
+ // Stops the core. Must be called on the owner thread.
+ void Stop();
+
+ // Returns true if this object has been stopped. Must be called on the owner
+ // thread.
+ bool IsStopped() const;
+
+ protected:
+ // Core must be destroyed on the owner thread. If data members must be
+ // cleaned up or destroyed on the token service thread, do so in the
+ // StopOnTokenServiceThread method.
+ virtual ~Core();
+
+ // Called on the token service thread.
+ virtual void StartOnTokenServiceThread() = 0;
+
+ // Called on the token service thread.
+ virtual void StopOnTokenServiceThread() = 0;
+
+ base::SingleThreadTaskRunner* token_service_task_runner();
+ OAuth2TokenService* token_service();
+ OAuth2TokenServiceRequest* owner();
+
+ private:
+ friend class base::RefCountedThreadSafe<OAuth2TokenServiceRequest::Core>;
+
+ scoped_refptr<base::SingleThreadTaskRunner> token_service_task_runner_;
+ OAuth2TokenServiceRequest* owner_;
+ TokenServiceProvider* provider_;
+ DISALLOW_COPY_AND_ASSIGN(Core);
+};
+
+OAuth2TokenServiceRequest::Core::Core(OAuth2TokenServiceRequest* owner,
+ TokenServiceProvider* provider)
+ : owner_(owner), provider_(provider) {
+ DCHECK(owner_);
+ DCHECK(provider_);
+ token_service_task_runner_ = provider_->GetTokenServiceTaskRunner();
+ DCHECK(token_service_task_runner_);
+}
+
+OAuth2TokenServiceRequest::Core::~Core() {
+}
+
+void OAuth2TokenServiceRequest::Core::Start() {
+ DCHECK(CalledOnValidThread());
+ token_service_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&OAuth2TokenServiceRequest::Core::StartOnTokenServiceThread,
+ this));
+}
+
+void OAuth2TokenServiceRequest::Core::Stop() {
+ DCHECK(CalledOnValidThread());
+ DCHECK(!IsStopped());
+
+ // Detaches |owner_| from this instance so |owner_| will be called back only
+ // if |Stop()| has never been called.
+ owner_ = NULL;
+ token_service_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&OAuth2TokenServiceRequest::Core::StopOnTokenServiceThread,
+ this));
+}
+
+bool OAuth2TokenServiceRequest::Core::IsStopped() const {
+ DCHECK(CalledOnValidThread());
+ return owner_ == NULL;
+}
+
+base::SingleThreadTaskRunner*
+OAuth2TokenServiceRequest::Core::token_service_task_runner() {
+ return token_service_task_runner_;
+}
+
+OAuth2TokenService* OAuth2TokenServiceRequest::Core::token_service() {
+ DCHECK(token_service_task_runner_->BelongsToCurrentThread());
+ return provider_->GetTokenService();
+}
+
+OAuth2TokenServiceRequest* OAuth2TokenServiceRequest::Core::owner() {
+ DCHECK(CalledOnValidThread());
+ return owner_;
+}
+
+namespace {
+
+// An implementation of Core for getting an access token.
+class RequestCore : public OAuth2TokenServiceRequest::Core,
+ public OAuth2TokenService::Consumer {
+ public:
+ RequestCore(OAuth2TokenServiceRequest* owner,
+ OAuth2TokenServiceRequest::TokenServiceProvider* provider,
+ OAuth2TokenService::Consumer* consumer,
+ const std::string& account_id,
+ const OAuth2TokenService::ScopeSet& scopes);
+
+ // OAuth2TokenService::Consumer. Must be called on the token service thread.
+ virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
+ const std::string& access_token,
+ const base::Time& expiration_time) OVERRIDE;
+ virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
+ const GoogleServiceAuthError& error) OVERRIDE;
+
+ private:
+ friend class base::RefCountedThreadSafe<RequestCore>;
+
+ // Must be destroyed on the owner thread.
+ virtual ~RequestCore();
+
+ // Core implementation.
+ virtual void StartOnTokenServiceThread() OVERRIDE;
+ virtual void StopOnTokenServiceThread() OVERRIDE;
+
+ void InformOwnerOnGetTokenSuccess(std::string access_token,
+ base::Time expiration_time);
+ void InformOwnerOnGetTokenFailure(GoogleServiceAuthError error);
+
+ scoped_refptr<base::SingleThreadTaskRunner> owner_task_runner_;
+ OAuth2TokenService::Consumer* const consumer_;
+ std::string account_id_;
+ OAuth2TokenService::ScopeSet scopes_;
+
+ // OAuth2TokenService request for fetching OAuth2 access token; it should be
+ // created, reset and accessed only on the token service thread.
+ scoped_ptr<OAuth2TokenService::Request> request_;
+
+ DISALLOW_COPY_AND_ASSIGN(RequestCore);
+};
+
+RequestCore::RequestCore(
+ OAuth2TokenServiceRequest* owner,
+ OAuth2TokenServiceRequest::TokenServiceProvider* provider,
+ OAuth2TokenService::Consumer* consumer,
+ const std::string& account_id,
+ const OAuth2TokenService::ScopeSet& scopes)
+ : OAuth2TokenServiceRequest::Core(owner, provider),
+ OAuth2TokenService::Consumer("oauth2_token_service"),
+ owner_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ consumer_(consumer),
+ account_id_(account_id),
+ scopes_(scopes) {
+ DCHECK(consumer_);
+ DCHECK(!account_id_.empty());
+ DCHECK(!scopes_.empty());
+}
+
+RequestCore::~RequestCore() {
+}
+
+void RequestCore::StartOnTokenServiceThread() {
+ DCHECK(token_service_task_runner()->BelongsToCurrentThread());
+ request_ = token_service()->StartRequest(account_id_, scopes_, this).Pass();
+}
+
+void RequestCore::StopOnTokenServiceThread() {
+ DCHECK(token_service_task_runner()->BelongsToCurrentThread());
+ request_.reset();
+}
+
+void RequestCore::OnGetTokenSuccess(const OAuth2TokenService::Request* request,
+ const std::string& access_token,
+ const base::Time& expiration_time) {
+ DCHECK(token_service_task_runner()->BelongsToCurrentThread());
+ DCHECK_EQ(request_.get(), request);
+ owner_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&RequestCore::InformOwnerOnGetTokenSuccess,
+ this,
+ access_token,
+ expiration_time));
+ request_.reset();
+}
+
+void RequestCore::OnGetTokenFailure(const OAuth2TokenService::Request* request,
+ const GoogleServiceAuthError& error) {
+ DCHECK(token_service_task_runner()->BelongsToCurrentThread());
+ DCHECK_EQ(request_.get(), request);
+ owner_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&RequestCore::InformOwnerOnGetTokenFailure, this, error));
+ request_.reset();
+}
+
+void RequestCore::InformOwnerOnGetTokenSuccess(std::string access_token,
+ base::Time expiration_time) {
+ DCHECK(CalledOnValidThread());
+ if (!IsStopped()) {
+ consumer_->OnGetTokenSuccess(owner(), access_token, expiration_time);
+ }
+}
+
+void RequestCore::InformOwnerOnGetTokenFailure(GoogleServiceAuthError error) {
+ DCHECK(CalledOnValidThread());
+ if (!IsStopped()) {
+ consumer_->OnGetTokenFailure(owner(), error);
+ }
+}
+
+// An implementation of Core for invalidating an access token.
+class InvalidateCore : public OAuth2TokenServiceRequest::Core {
+ public:
+ InvalidateCore(OAuth2TokenServiceRequest* owner,
+ OAuth2TokenServiceRequest::TokenServiceProvider* provider,
+ const std::string& access_token,
+ const std::string& account_id,
+ const OAuth2TokenService::ScopeSet& scopes);
+
+ private:
+ friend class base::RefCountedThreadSafe<InvalidateCore>;
+
+ // Must be destroyed on the owner thread.
+ virtual ~InvalidateCore();
+
+ // Core implementation.
+ virtual void StartOnTokenServiceThread() OVERRIDE;
+ virtual void StopOnTokenServiceThread() OVERRIDE;
+
+ std::string access_token_;
+ std::string account_id_;
+ OAuth2TokenService::ScopeSet scopes_;
+
+ DISALLOW_COPY_AND_ASSIGN(InvalidateCore);
+};
+
+InvalidateCore::InvalidateCore(
+ OAuth2TokenServiceRequest* owner,
+ OAuth2TokenServiceRequest::TokenServiceProvider* provider,
+ const std::string& access_token,
+ const std::string& account_id,
+ const OAuth2TokenService::ScopeSet& scopes)
+ : OAuth2TokenServiceRequest::Core(owner, provider),
+ access_token_(access_token),
+ account_id_(account_id),
+ scopes_(scopes) {
+ DCHECK(!access_token_.empty());
+ DCHECK(!account_id_.empty());
+ DCHECK(!scopes.empty());
+}
+
+InvalidateCore::~InvalidateCore() {
+}
+
+void InvalidateCore::StartOnTokenServiceThread() {
+ DCHECK(token_service_task_runner()->BelongsToCurrentThread());
+ token_service()->InvalidateToken(account_id_, scopes_, access_token_);
+}
+
+void InvalidateCore::StopOnTokenServiceThread() {
+ DCHECK(token_service_task_runner()->BelongsToCurrentThread());
+ // Nothing to do.
+}
+
+} // namespace
+
+// static
+scoped_ptr<OAuth2TokenServiceRequest> OAuth2TokenServiceRequest::CreateAndStart(
+ TokenServiceProvider* provider,
+ const std::string& account_id,
+ const OAuth2TokenService::ScopeSet& scopes,
+ OAuth2TokenService::Consumer* consumer) {
+ scoped_ptr<OAuth2TokenServiceRequest> request(
+ new OAuth2TokenServiceRequest(account_id));
+ scoped_refptr<Core> core(
+ new RequestCore(request.get(), provider, consumer, account_id, scopes));
+ request->StartWithCore(core);
+ return request.Pass();
+}
+
+// static
+void OAuth2TokenServiceRequest::InvalidateToken(
+ OAuth2TokenServiceRequest::TokenServiceProvider* provider,
+ const std::string& account_id,
+ const OAuth2TokenService::ScopeSet& scopes,
+ const std::string& access_token) {
+ scoped_ptr<OAuth2TokenServiceRequest> request(
+ new OAuth2TokenServiceRequest(account_id));
+ scoped_refptr<Core> core(new InvalidateCore(
+ request.get(), provider, access_token, account_id, scopes));
+ request->StartWithCore(core);
+}
+
+OAuth2TokenServiceRequest::~OAuth2TokenServiceRequest() {
+ core_->Stop();
+}
+
+std::string OAuth2TokenServiceRequest::GetAccountId() const {
+ return account_id_;
+}
+
+OAuth2TokenServiceRequest::OAuth2TokenServiceRequest(
+ const std::string& account_id)
+ : account_id_(account_id) {
+ DCHECK(!account_id_.empty());
+}
+
+void OAuth2TokenServiceRequest::StartWithCore(const scoped_refptr<Core>& core) {
+ DCHECK(core);
+ core_ = core;
+ core_->Start();
+}
diff --git a/google_apis/gaia/oauth2_token_service_request.h b/google_apis/gaia/oauth2_token_service_request.h
new file mode 100644
index 0000000..972e518
--- /dev/null
+++ b/google_apis/gaia/oauth2_token_service_request.h
@@ -0,0 +1,96 @@
+// 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 GOOGLE_APIS_GAIA_OAUTH2_TOKEN_SERVICE_REQUEST_H_
+#define GOOGLE_APIS_GAIA_OAUTH2_TOKEN_SERVICE_REQUEST_H_
+
+#include <set>
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/non_thread_safe.h"
+#include "google_apis/gaia/oauth2_token_service.h"
+
+// OAuth2TokenServiceRequest represents an asynchronous request to an
+// OAuth2TokenService that may live in another thread.
+//
+// An OAuth2TokenServiceRequest can be created and started from any thread.
+class OAuth2TokenServiceRequest : public OAuth2TokenService::Request,
+ public base::NonThreadSafe {
+ public:
+ class Core;
+
+ // Interface for providing an OAuth2TokenService.
+ class TokenServiceProvider {
+ public:
+ TokenServiceProvider();
+ virtual ~TokenServiceProvider();
+
+ // Returns the task runner on which the token service lives.
+ //
+ // This method may be called from any thread.
+ virtual scoped_refptr<base::SingleThreadTaskRunner>
+ GetTokenServiceTaskRunner() = 0;
+
+ // Returns a pointer to a token service.
+ //
+ // Caller does not own the token service and must not delete it. The token
+ // service must outlive all instances of OAuth2TokenServiceRequest.
+ //
+ // This method may only be called from the task runner returned by
+ // |GetTokenServiceTaskRunner|.
+ virtual OAuth2TokenService* GetTokenService() = 0;
+ };
+
+ // Creates and starts an access token request for |account_id| and |scopes|.
+ //
+ // |provider| is used to get the OAuth2TokenService and must outlive the
+ // returned request object.
+ //
+ // |account_id| must not be empty.
+ //
+ // |scopes| must not be empty.
+ //
+ // |consumer| will be invoked in the same thread that invoked CreateAndStart
+ // and must outlive the returned request object. Destroying the request
+ // object ensure that |consumer| will not be called. However, the actual
+ // network activities may not be canceled and the cache in OAuth2TokenService
+ // may be populated with the fetched results.
+ static scoped_ptr<OAuth2TokenServiceRequest> CreateAndStart(
+ TokenServiceProvider* provider,
+ const std::string& account_id,
+ const OAuth2TokenService::ScopeSet& scopes,
+ OAuth2TokenService::Consumer* consumer);
+
+ // Invalidates |access_token| for |account_id| and |scopes|.
+ //
+ // |provider| is used to get the OAuth2TokenService and must outlive the
+ // returned request object.
+ //
+ // |account_id| must not be empty.
+ //
+ // |scopes| must not be empty.
+ static void InvalidateToken(TokenServiceProvider* provider,
+ const std::string& account_id,
+ const OAuth2TokenService::ScopeSet& scopes,
+ const std::string& access_token);
+
+ virtual ~OAuth2TokenServiceRequest();
+
+ // OAuth2TokenService::Request.
+ virtual std::string GetAccountId() const OVERRIDE;
+
+ private:
+ OAuth2TokenServiceRequest(const std::string& account_id);
+
+ void StartWithCore(const scoped_refptr<Core>& core);
+
+ const std::string account_id_;
+ scoped_refptr<Core> core_;
+
+ DISALLOW_COPY_AND_ASSIGN(OAuth2TokenServiceRequest);
+};
+
+#endif // GOOGLE_APIS_GAIA_OAUTH2_TOKEN_SERVICE_REQUEST_H_
diff --git a/google_apis/gaia/oauth2_token_service_request_unittest.cc b/google_apis/gaia/oauth2_token_service_request_unittest.cc
new file mode 100644
index 0000000..b627006
--- /dev/null
+++ b/google_apis/gaia/oauth2_token_service_request_unittest.cc
@@ -0,0 +1,257 @@
+// 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 "google_apis/gaia/oauth2_token_service_request.h"
+
+#include <set>
+#include <string>
+#include <vector>
+#include "base/threading/thread.h"
+#include "google_apis/gaia/fake_oauth2_token_service.h"
+#include "google_apis/gaia/google_service_auth_error.h"
+#include "google_apis/gaia/oauth2_token_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kAccessToken[] = "access_token";
+const char kAccountId[] = "test_user@gmail.com";
+const char kScope[] = "SCOPE";
+
+class TestingOAuth2TokenServiceConsumer : public OAuth2TokenService::Consumer {
+ public:
+ TestingOAuth2TokenServiceConsumer();
+ virtual ~TestingOAuth2TokenServiceConsumer();
+
+ virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
+ const std::string& access_token,
+ const base::Time& expiration_time) OVERRIDE;
+ virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
+ const GoogleServiceAuthError& error) OVERRIDE;
+
+ int num_get_token_success_;
+ int num_get_token_failure_;
+ std::string last_token_;
+ GoogleServiceAuthError last_error_;
+};
+
+TestingOAuth2TokenServiceConsumer::TestingOAuth2TokenServiceConsumer()
+ : OAuth2TokenService::Consumer("test"),
+ num_get_token_success_(0),
+ num_get_token_failure_(0),
+ last_error_(GoogleServiceAuthError::AuthErrorNone()) {
+}
+
+TestingOAuth2TokenServiceConsumer::~TestingOAuth2TokenServiceConsumer() {
+}
+
+void TestingOAuth2TokenServiceConsumer::OnGetTokenSuccess(
+ const OAuth2TokenService::Request* request,
+ const std::string& token,
+ const base::Time& expiration_date) {
+ last_token_ = token;
+ ++num_get_token_success_;
+}
+
+void TestingOAuth2TokenServiceConsumer::OnGetTokenFailure(
+ const OAuth2TokenService::Request* request,
+ const GoogleServiceAuthError& error) {
+ last_error_ = error;
+ ++num_get_token_failure_;
+}
+
+// A mock implementation of an OAuth2TokenService.
+//
+// Use SetResponse to vary the response to token requests.
+class MockOAuth2TokenService : public FakeOAuth2TokenService {
+ public:
+ MockOAuth2TokenService();
+ virtual ~MockOAuth2TokenService();
+
+ void SetResponse(const GoogleServiceAuthError& error,
+ const std::string& access_token,
+ const base::Time& expiration);
+
+ int num_invalidate_token() const { return num_invalidate_token_; }
+
+ const std::string& last_token_invalidated() const {
+ return last_token_invalidated_;
+ }
+
+ protected:
+ virtual void FetchOAuth2Token(RequestImpl* request,
+ const std::string& account_id,
+ net::URLRequestContextGetter* getter,
+ const std::string& client_id,
+ const std::string& client_secret,
+ const ScopeSet& scopes) OVERRIDE;
+
+ virtual void InvalidateOAuth2Token(const std::string& account_id,
+ const std::string& client_id,
+ const ScopeSet& scopes,
+ const std::string& access_token) OVERRIDE;
+
+ private:
+ GoogleServiceAuthError response_error_;
+ std::string response_access_token_;
+ base::Time response_expiration_;
+ int num_invalidate_token_;
+ std::string last_token_invalidated_;
+};
+
+MockOAuth2TokenService::MockOAuth2TokenService()
+ : response_error_(GoogleServiceAuthError::AuthErrorNone()),
+ response_access_token_(kAccessToken),
+ response_expiration_(base::Time::Max()),
+ num_invalidate_token_(0) {
+}
+
+MockOAuth2TokenService::~MockOAuth2TokenService() {
+}
+
+void MockOAuth2TokenService::SetResponse(const GoogleServiceAuthError& error,
+ const std::string& access_token,
+ const base::Time& expiration) {
+ response_error_ = error;
+ response_access_token_ = access_token;
+ response_expiration_ = expiration;
+}
+
+void MockOAuth2TokenService::FetchOAuth2Token(
+ RequestImpl* request,
+ const std::string& account_id,
+ net::URLRequestContextGetter* getter,
+ const std::string& client_id,
+ const std::string& client_secret,
+ const ScopeSet& scopes) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&OAuth2TokenService::RequestImpl::InformConsumer,
+ request->AsWeakPtr(),
+ response_error_,
+ response_access_token_,
+ response_expiration_));
+}
+
+void MockOAuth2TokenService::InvalidateOAuth2Token(
+ const std::string& account_id,
+ const std::string& client_id,
+ const ScopeSet& scopes,
+ const std::string& access_token) {
+ ++num_invalidate_token_;
+ last_token_invalidated_ = access_token;
+}
+
+class OAuth2TokenServiceRequestTest : public testing::Test {
+ public:
+ virtual void SetUp() OVERRIDE;
+
+ protected:
+ class Provider : public OAuth2TokenServiceRequest::TokenServiceProvider {
+ public:
+ Provider(const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+ OAuth2TokenService* token_service);
+
+ virtual scoped_refptr<base::SingleThreadTaskRunner>
+ GetTokenServiceTaskRunner() OVERRIDE;
+ virtual OAuth2TokenService* GetTokenService() OVERRIDE;
+
+ private:
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ OAuth2TokenService* token_service_;
+ };
+
+ base::MessageLoop ui_loop_;
+ OAuth2TokenService::ScopeSet scopes_;
+ scoped_ptr<MockOAuth2TokenService> oauth2_service_;
+ scoped_ptr<OAuth2TokenServiceRequest::TokenServiceProvider> provider_;
+ TestingOAuth2TokenServiceConsumer consumer_;
+};
+
+void OAuth2TokenServiceRequestTest::SetUp() {
+ scopes_.insert(kScope);
+ oauth2_service_.reset(new MockOAuth2TokenService);
+ oauth2_service_->AddAccount(kAccountId);
+ provider_.reset(
+ new Provider(base::MessageLoopProxy::current(), oauth2_service_.get()));
+}
+
+OAuth2TokenServiceRequestTest::Provider::Provider(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+ OAuth2TokenService* token_service)
+ : task_runner_(task_runner), token_service_(token_service) {
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+OAuth2TokenServiceRequestTest::Provider::GetTokenServiceTaskRunner() {
+ return task_runner_;
+}
+
+OAuth2TokenService* OAuth2TokenServiceRequestTest::Provider::GetTokenService() {
+ return token_service_;
+}
+
+TEST_F(OAuth2TokenServiceRequestTest, CreateAndStart_Failure) {
+ oauth2_service_->SetResponse(
+ GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE),
+ std::string(),
+ base::Time());
+ scoped_ptr<OAuth2TokenServiceRequest> request(
+ OAuth2TokenServiceRequest::CreateAndStart(
+ provider_.get(), kAccountId, scopes_, &consumer_));
+ ui_loop_.RunUntilIdle();
+ EXPECT_EQ(0, consumer_.num_get_token_success_);
+ EXPECT_EQ(1, consumer_.num_get_token_failure_);
+ EXPECT_EQ(GoogleServiceAuthError::SERVICE_UNAVAILABLE,
+ consumer_.last_error_.state());
+ EXPECT_EQ(0, oauth2_service_->num_invalidate_token());
+}
+
+TEST_F(OAuth2TokenServiceRequestTest, CreateAndStart_Success) {
+ scoped_ptr<OAuth2TokenServiceRequest> request(
+ OAuth2TokenServiceRequest::CreateAndStart(
+ provider_.get(), kAccountId, scopes_, &consumer_));
+ ui_loop_.RunUntilIdle();
+ EXPECT_EQ(1, consumer_.num_get_token_success_);
+ EXPECT_EQ(0, consumer_.num_get_token_failure_);
+ EXPECT_EQ(kAccessToken, consumer_.last_token_);
+ EXPECT_EQ(0, oauth2_service_->num_invalidate_token());
+}
+
+TEST_F(OAuth2TokenServiceRequestTest,
+ CreateAndStart_DestroyRequestBeforeCompletes) {
+ scoped_ptr<OAuth2TokenServiceRequest> request(
+ OAuth2TokenServiceRequest::CreateAndStart(
+ provider_.get(), kAccountId, scopes_, &consumer_));
+ request.reset();
+ ui_loop_.RunUntilIdle();
+ EXPECT_EQ(0, consumer_.num_get_token_success_);
+ EXPECT_EQ(0, consumer_.num_get_token_failure_);
+ EXPECT_EQ(0, oauth2_service_->num_invalidate_token());
+}
+
+TEST_F(OAuth2TokenServiceRequestTest,
+ CreateAndStart_DestroyRequestAfterCompletes) {
+ scoped_ptr<OAuth2TokenServiceRequest> request(
+ OAuth2TokenServiceRequest::CreateAndStart(
+ provider_.get(), kAccountId, scopes_, &consumer_));
+ ui_loop_.RunUntilIdle();
+ request.reset();
+ EXPECT_EQ(1, consumer_.num_get_token_success_);
+ EXPECT_EQ(0, consumer_.num_get_token_failure_);
+ EXPECT_EQ(kAccessToken, consumer_.last_token_);
+ EXPECT_EQ(0, oauth2_service_->num_invalidate_token());
+}
+
+TEST_F(OAuth2TokenServiceRequestTest, InvalidateToken) {
+ OAuth2TokenServiceRequest::InvalidateToken(
+ provider_.get(), kAccountId, scopes_, kAccessToken);
+ ui_loop_.RunUntilIdle();
+ EXPECT_EQ(0, consumer_.num_get_token_success_);
+ EXPECT_EQ(0, consumer_.num_get_token_failure_);
+ EXPECT_EQ(kAccessToken, oauth2_service_->last_token_invalidated());
+ EXPECT_EQ(1, oauth2_service_->num_invalidate_token());
+}
+
+} // namespace
diff --git a/google_apis/google_apis.gyp b/google_apis/google_apis.gyp
index ec9c8c8..1fa476c 100644
--- a/google_apis/google_apis.gyp
+++ b/google_apis/google_apis.gyp
@@ -128,6 +128,8 @@
'gaia/oauth2_mint_token_flow.h',
'gaia/oauth2_token_service.cc',
'gaia/oauth2_token_service.h',
+ 'gaia/oauth2_token_service_request.cc',
+ 'gaia/oauth2_token_service_request.h',
'gaia/ubertoken_fetcher.cc',
'gaia/ubertoken_fetcher.h',
'google_api_keys.cc',
@@ -175,6 +177,7 @@
'gaia/oauth2_access_token_fetcher_impl_unittest.cc',
'gaia/oauth2_api_call_flow_unittest.cc',
'gaia/oauth2_mint_token_flow_unittest.cc',
+ 'gaia/oauth2_token_service_request_unittest.cc',
'gaia/oauth2_token_service_unittest.cc',
'gaia/ubertoken_fetcher_unittest.cc',
],