Home | History | Annotate | Download | only in identity
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <set>
      6 #include <string>
      7 #include <vector>
      8 
      9 #include "base/command_line.h"
     10 #include "base/prefs/pref_service.h"
     11 #include "base/strings/string_util.h"
     12 #include "base/strings/stringprintf.h"
     13 #include "base/values.h"
     14 #include "chrome/browser/chrome_notification_types.h"
     15 #include "chrome/browser/extensions/api/identity/identity_api.h"
     16 #include "chrome/browser/extensions/component_loader.h"
     17 #include "chrome/browser/extensions/extension_apitest.h"
     18 #include "chrome/browser/extensions/extension_browsertest.h"
     19 #include "chrome/browser/extensions/extension_function_test_utils.h"
     20 #include "chrome/browser/extensions/extension_service.h"
     21 #include "chrome/browser/profiles/profile.h"
     22 #include "chrome/browser/signin/account_reconcilor_factory.h"
     23 #include "chrome/browser/signin/fake_account_reconcilor.h"
     24 #include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
     25 #include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
     26 #include "chrome/browser/signin/fake_signin_manager.h"
     27 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
     28 #include "chrome/browser/signin/signin_manager_factory.h"
     29 #include "chrome/browser/ui/browser.h"
     30 #include "chrome/browser/ui/browser_window.h"
     31 #include "chrome/common/chrome_switches.h"
     32 #include "chrome/common/extensions/api/identity.h"
     33 #include "chrome/common/extensions/api/identity/oauth2_manifest_handler.h"
     34 #include "chrome/test/base/in_process_browser_test.h"
     35 #include "chrome/test/base/test_switches.h"
     36 #include "components/crx_file/id_util.h"
     37 #include "components/signin/core/browser/signin_manager.h"
     38 #include "components/signin/core/common/profile_management_switches.h"
     39 #include "components/signin/core/common/signin_pref_names.h"
     40 #include "content/public/browser/notification_service.h"
     41 #include "content/public/browser/notification_source.h"
     42 #include "content/public/test/test_utils.h"
     43 #include "extensions/browser/guest_view/guest_view_base.h"
     44 #include "extensions/common/test_util.h"
     45 #include "google_apis/gaia/google_service_auth_error.h"
     46 #include "google_apis/gaia/oauth2_mint_token_flow.h"
     47 #include "net/test/spawned_test_server/spawned_test_server.h"
     48 #include "testing/gmock/include/gmock/gmock.h"
     49 #include "testing/gtest/include/gtest/gtest.h"
     50 #include "url/gurl.h"
     51 
     52 using testing::_;
     53 using testing::Return;
     54 using testing::ReturnRef;
     55 
     56 namespace extensions {
     57 
     58 namespace {
     59 
     60 namespace errors = identity_constants;
     61 namespace utils = extension_function_test_utils;
     62 
     63 static const char kAccessToken[] = "auth_token";
     64 static const char kExtensionId[] = "ext_id";
     65 
     66 // This helps us be able to wait until an UIThreadExtensionFunction calls
     67 // SendResponse.
     68 class SendResponseDelegate
     69     : public UIThreadExtensionFunction::DelegateForTests {
     70  public:
     71   SendResponseDelegate() : should_post_quit_(false) {}
     72 
     73   virtual ~SendResponseDelegate() {}
     74 
     75   void set_should_post_quit(bool should_quit) {
     76     should_post_quit_ = should_quit;
     77   }
     78 
     79   bool HasResponse() {
     80     return response_.get() != NULL;
     81   }
     82 
     83   bool GetResponse() {
     84     EXPECT_TRUE(HasResponse());
     85     return *response_.get();
     86   }
     87 
     88   virtual void OnSendResponse(UIThreadExtensionFunction* function,
     89                               bool success,
     90                               bool bad_message) OVERRIDE {
     91     ASSERT_FALSE(bad_message);
     92     ASSERT_FALSE(HasResponse());
     93     response_.reset(new bool);
     94     *response_ = success;
     95     if (should_post_quit_) {
     96       base::MessageLoopForUI::current()->Quit();
     97     }
     98   }
     99 
    100  private:
    101   scoped_ptr<bool> response_;
    102   bool should_post_quit_;
    103 };
    104 
    105 class AsyncExtensionBrowserTest : public ExtensionBrowserTest {
    106  protected:
    107   // Asynchronous function runner allows tests to manipulate the browser window
    108   // after the call happens.
    109   void RunFunctionAsync(
    110       UIThreadExtensionFunction* function,
    111       const std::string& args) {
    112     response_delegate_.reset(new SendResponseDelegate);
    113     function->set_test_delegate(response_delegate_.get());
    114     scoped_ptr<base::ListValue> parsed_args(utils::ParseList(args));
    115     EXPECT_TRUE(parsed_args.get()) <<
    116         "Could not parse extension function arguments: " << args;
    117     function->SetArgs(parsed_args.get());
    118 
    119     if (!function->extension()) {
    120       scoped_refptr<Extension> empty_extension(
    121           test_util::CreateEmptyExtension());
    122       function->set_extension(empty_extension.get());
    123     }
    124 
    125     function->set_browser_context(browser()->profile());
    126     function->set_has_callback(true);
    127     function->Run()->Execute();
    128   }
    129 
    130   std::string WaitForError(UIThreadExtensionFunction* function) {
    131     RunMessageLoopUntilResponse();
    132     EXPECT_FALSE(function->GetResultList()) << "Did not expect a result";
    133     return function->GetError();
    134   }
    135 
    136   base::Value* WaitForSingleResult(UIThreadExtensionFunction* function) {
    137     RunMessageLoopUntilResponse();
    138     EXPECT_TRUE(function->GetError().empty()) << "Unexpected error: "
    139                                               << function->GetError();
    140     const base::Value* single_result = NULL;
    141     if (function->GetResultList() != NULL &&
    142         function->GetResultList()->Get(0, &single_result)) {
    143       return single_result->DeepCopy();
    144     }
    145     return NULL;
    146   }
    147 
    148  private:
    149   void RunMessageLoopUntilResponse() {
    150     // If the RunAsync of |function| didn't already call SendResponse, run the
    151     // message loop until they do.
    152     if (!response_delegate_->HasResponse()) {
    153       response_delegate_->set_should_post_quit(true);
    154       content::RunMessageLoop();
    155     }
    156     EXPECT_TRUE(response_delegate_->HasResponse());
    157   }
    158 
    159   scoped_ptr<SendResponseDelegate> response_delegate_;
    160 };
    161 
    162 class TestHangOAuth2MintTokenFlow : public OAuth2MintTokenFlow {
    163  public:
    164   TestHangOAuth2MintTokenFlow()
    165       : OAuth2MintTokenFlow(NULL, NULL, OAuth2MintTokenFlow::Parameters()) {}
    166 
    167   virtual void Start() OVERRIDE {
    168     // Do nothing, simulating a hanging network call.
    169   }
    170 };
    171 
    172 class TestOAuth2MintTokenFlow : public OAuth2MintTokenFlow {
    173  public:
    174   enum ResultType {
    175     ISSUE_ADVICE_SUCCESS,
    176     MINT_TOKEN_SUCCESS,
    177     MINT_TOKEN_FAILURE,
    178     MINT_TOKEN_BAD_CREDENTIALS,
    179     MINT_TOKEN_SERVICE_ERROR
    180   };
    181 
    182   TestOAuth2MintTokenFlow(ResultType result,
    183                           OAuth2MintTokenFlow::Delegate* delegate)
    184     : OAuth2MintTokenFlow(NULL, delegate, OAuth2MintTokenFlow::Parameters()),
    185       result_(result),
    186       delegate_(delegate) {
    187   }
    188 
    189   virtual void Start() OVERRIDE {
    190     switch (result_) {
    191       case ISSUE_ADVICE_SUCCESS: {
    192         IssueAdviceInfo info;
    193         delegate_->OnIssueAdviceSuccess(info);
    194         break;
    195       }
    196       case MINT_TOKEN_SUCCESS: {
    197         delegate_->OnMintTokenSuccess(kAccessToken, 3600);
    198         break;
    199       }
    200       case MINT_TOKEN_FAILURE: {
    201         GoogleServiceAuthError error(GoogleServiceAuthError::CONNECTION_FAILED);
    202         delegate_->OnMintTokenFailure(error);
    203         break;
    204       }
    205       case MINT_TOKEN_BAD_CREDENTIALS: {
    206         GoogleServiceAuthError error(
    207             GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
    208         delegate_->OnMintTokenFailure(error);
    209         break;
    210       }
    211       case MINT_TOKEN_SERVICE_ERROR: {
    212         GoogleServiceAuthError error =
    213             GoogleServiceAuthError::FromServiceError("invalid_scope");
    214         delegate_->OnMintTokenFailure(error);
    215         break;
    216       }
    217     }
    218   }
    219 
    220  private:
    221   ResultType result_;
    222   OAuth2MintTokenFlow::Delegate* delegate_;
    223 };
    224 
    225 // Waits for a specific GURL to generate a NOTIFICATION_LOAD_STOP event and
    226 // saves a pointer to the window embedding the WebContents, which can be later
    227 // closed.
    228 class WaitForGURLAndCloseWindow : public content::WindowedNotificationObserver {
    229  public:
    230   explicit WaitForGURLAndCloseWindow(GURL url)
    231       : WindowedNotificationObserver(
    232             content::NOTIFICATION_LOAD_STOP,
    233             content::NotificationService::AllSources()),
    234         url_(url) {}
    235 
    236   // NotificationObserver:
    237   virtual void Observe(int type,
    238                        const content::NotificationSource& source,
    239                        const content::NotificationDetails& details) OVERRIDE {
    240     content::NavigationController* web_auth_flow_controller =
    241         content::Source<content::NavigationController>(source).ptr();
    242     content::WebContents* web_contents =
    243         web_auth_flow_controller->GetWebContents();
    244 
    245     if (web_contents->GetURL() == url_) {
    246       // It is safe to keep the pointer here, because we know in a test, that
    247       // the WebContents won't go away before CloseEmbedderWebContents is
    248       // called. Don't copy this code to production.
    249       GuestViewBase* guest = GuestViewBase::FromWebContents(web_contents);
    250       embedder_web_contents_ = guest->embedder_web_contents();
    251       // Condtionally invoke parent class so that Wait will not exit
    252       // until the target URL arrives.
    253       content::WindowedNotificationObserver::Observe(type, source, details);
    254     }
    255   }
    256 
    257   // Closes the window embedding the WebContents. The action is separated from
    258   // the Observe method to make sure the list of observers is not deleted,
    259   // while some event is already being processed. (That causes ASAN failures.)
    260   void CloseEmbedderWebContents() {
    261     if (embedder_web_contents_)
    262       embedder_web_contents_->Close();
    263   }
    264 
    265  private:
    266   GURL url_;
    267   content::WebContents* embedder_web_contents_;
    268 };
    269 
    270 }  // namespace
    271 
    272 class FakeGetAuthTokenFunction : public IdentityGetAuthTokenFunction {
    273  public:
    274   FakeGetAuthTokenFunction()
    275       : login_access_token_result_(true),
    276         auto_login_access_token_(true),
    277         login_ui_result_(true),
    278         scope_ui_result_(true),
    279         login_ui_shown_(false),
    280         scope_ui_shown_(false) {}
    281 
    282   void set_login_access_token_result(bool result) {
    283     login_access_token_result_ = result;
    284   }
    285 
    286   void set_auto_login_access_token(bool automatic) {
    287     auto_login_access_token_ = automatic;
    288   }
    289 
    290   void set_login_ui_result(bool result) { login_ui_result_ = result; }
    291 
    292   void set_mint_token_flow(scoped_ptr<OAuth2MintTokenFlow> flow) {
    293     flow_ = flow.Pass();
    294   }
    295 
    296   void set_mint_token_result(TestOAuth2MintTokenFlow::ResultType result_type) {
    297     set_mint_token_flow(scoped_ptr<TestOAuth2MintTokenFlow>(
    298                             new TestOAuth2MintTokenFlow(result_type, this))
    299                             .PassAs<OAuth2MintTokenFlow>());
    300   }
    301 
    302   void set_scope_ui_failure(GaiaWebAuthFlow::Failure failure) {
    303     scope_ui_result_ = false;
    304     scope_ui_failure_ = failure;
    305   }
    306 
    307   void set_scope_ui_oauth_error(const std::string& oauth_error) {
    308     scope_ui_result_ = false;
    309     scope_ui_failure_ = GaiaWebAuthFlow::OAUTH_ERROR;
    310     scope_ui_oauth_error_ = oauth_error;
    311   }
    312 
    313   bool login_ui_shown() const { return login_ui_shown_; }
    314 
    315   bool scope_ui_shown() const { return scope_ui_shown_; }
    316 
    317   std::string login_access_token() const { return login_access_token_; }
    318 
    319   virtual void StartLoginAccessTokenRequest() OVERRIDE {
    320     if (auto_login_access_token_) {
    321       if (login_access_token_result_) {
    322         OnGetTokenSuccess(login_token_request_.get(),
    323                           "access_token",
    324                           base::Time::Now() + base::TimeDelta::FromHours(1LL));
    325       } else {
    326         GoogleServiceAuthError error(
    327             GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
    328         OnGetTokenFailure(login_token_request_.get(), error);
    329       }
    330     } else {
    331       // Make a request to the token service. The test now must tell
    332       // the token service to issue an access token (or an error).
    333       IdentityGetAuthTokenFunction::StartLoginAccessTokenRequest();
    334     }
    335   }
    336 
    337   virtual void ShowLoginPopup() OVERRIDE {
    338     EXPECT_FALSE(login_ui_shown_);
    339     login_ui_shown_ = true;
    340     if (login_ui_result_)
    341       SigninSuccess();
    342     else
    343       SigninFailed();
    344   }
    345 
    346   virtual void ShowOAuthApprovalDialog(
    347       const IssueAdviceInfo& issue_advice) OVERRIDE {
    348     scope_ui_shown_ = true;
    349 
    350     if (scope_ui_result_) {
    351       OnGaiaFlowCompleted(kAccessToken, "3600");
    352     } else if (scope_ui_failure_ == GaiaWebAuthFlow::SERVICE_AUTH_ERROR) {
    353       GoogleServiceAuthError error(GoogleServiceAuthError::CONNECTION_FAILED);
    354       OnGaiaFlowFailure(scope_ui_failure_, error, "");
    355     } else {
    356       GoogleServiceAuthError error(GoogleServiceAuthError::NONE);
    357       OnGaiaFlowFailure(scope_ui_failure_, error, scope_ui_oauth_error_);
    358     }
    359   }
    360 
    361   virtual OAuth2MintTokenFlow* CreateMintTokenFlow(
    362       const std::string& login_access_token) OVERRIDE {
    363     EXPECT_TRUE(login_access_token_.empty());
    364     // Save the login token used to create the flow so tests can see
    365     // what account was used.
    366     login_access_token_ = login_access_token;
    367     return flow_.release();
    368   }
    369 
    370  private:
    371   virtual ~FakeGetAuthTokenFunction() {}
    372   bool login_access_token_result_;
    373   bool auto_login_access_token_;
    374   bool login_ui_result_;
    375   bool scope_ui_result_;
    376   GaiaWebAuthFlow::Failure scope_ui_failure_;
    377   std::string scope_ui_oauth_error_;
    378   bool login_ui_shown_;
    379   bool scope_ui_shown_;
    380 
    381   scoped_ptr<OAuth2MintTokenFlow> flow_;
    382 
    383   std::string login_access_token_;
    384 };
    385 
    386 class MockQueuedMintRequest : public IdentityMintRequestQueue::Request {
    387  public:
    388   MOCK_METHOD1(StartMintToken, void(IdentityMintRequestQueue::MintType));
    389 };
    390 
    391 gaia::AccountIds CreateIds(std::string email, std::string obfid) {
    392   gaia::AccountIds ids;
    393   ids.account_key = email;
    394   ids.email = email;
    395   ids.gaia = obfid;
    396   return ids;
    397 }
    398 
    399 class IdentityGetAccountsFunctionTest : public ExtensionBrowserTest {
    400   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    401     ExtensionBrowserTest::SetUpCommandLine(command_line);
    402     command_line->AppendSwitch(switches::kExtensionsMultiAccount);
    403   }
    404 
    405  protected:
    406   void SetAccountState(gaia::AccountIds ids, bool is_signed_in) {
    407     IdentityAPI::GetFactoryInstance()->Get(profile())->SetAccountStateForTest(
    408         ids, is_signed_in);
    409   }
    410 
    411   testing::AssertionResult ExpectGetAccounts(
    412       const std::vector<std::string>& accounts) {
    413     scoped_refptr<IdentityGetAccountsFunction> func(
    414         new IdentityGetAccountsFunction);
    415     func->set_extension(test_util::CreateEmptyExtension(kExtensionId).get());
    416     if (!utils::RunFunction(
    417             func.get(), std::string("[]"), browser(), utils::NONE)) {
    418       return GenerateFailureResult(accounts, NULL)
    419              << "getAccounts did not return a result.";
    420     }
    421     const base::ListValue* callback_arguments = func->GetResultList();
    422     if (!callback_arguments)
    423       return GenerateFailureResult(accounts, NULL) << "NULL result";
    424 
    425     if (callback_arguments->GetSize() != 1) {
    426       return GenerateFailureResult(accounts, NULL)
    427              << "Expected 1 argument but got " << callback_arguments->GetSize();
    428     }
    429 
    430     const base::ListValue* results;
    431     if (!callback_arguments->GetList(0, &results))
    432       GenerateFailureResult(accounts, NULL) << "Result was not an array";
    433 
    434     std::set<std::string> result_ids;
    435     for (base::ListValue::const_iterator it = results->begin();
    436          it != results->end();
    437          ++it) {
    438       scoped_ptr<api::identity::AccountInfo> info =
    439           api::identity::AccountInfo::FromValue(**it);
    440       if (info.get())
    441         result_ids.insert(info->id);
    442       else
    443         return GenerateFailureResult(accounts, results);
    444     }
    445 
    446     for (std::vector<std::string>::const_iterator it = accounts.begin();
    447          it != accounts.end();
    448          ++it) {
    449       if (result_ids.find(*it) == result_ids.end())
    450         return GenerateFailureResult(accounts, results);
    451     }
    452 
    453     return testing::AssertionResult(true);
    454   }
    455 
    456   testing::AssertionResult GenerateFailureResult(
    457       const ::std::vector<std::string>& accounts,
    458       const base::ListValue* results) {
    459     testing::Message msg("Expected: ");
    460     for (std::vector<std::string>::const_iterator it = accounts.begin();
    461          it != accounts.end();
    462          ++it) {
    463       msg << *it << " ";
    464     }
    465     msg << "Actual: ";
    466     if (!results) {
    467       msg << "NULL";
    468     } else {
    469       for (base::ListValue::const_iterator it = results->begin();
    470            it != results->end();
    471            ++it) {
    472         scoped_ptr<api::identity::AccountInfo> info =
    473             api::identity::AccountInfo::FromValue(**it);
    474         if (info.get())
    475           msg << info->id << " ";
    476         else
    477           msg << *it << "<-" << (*it)->GetType() << " ";
    478       }
    479     }
    480 
    481     return testing::AssertionFailure(msg);
    482   }
    483 };
    484 
    485 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, MultiAccountOn) {
    486   EXPECT_TRUE(switches::IsExtensionsMultiAccount());
    487 }
    488 
    489 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, NoneSignedIn) {
    490   EXPECT_TRUE(ExpectGetAccounts(std::vector<std::string>()));
    491 }
    492 
    493 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest,
    494                        PrimaryAccountSignedIn) {
    495   SetAccountState(CreateIds("primary (at) example.com", "1"), true);
    496   std::vector<std::string> primary;
    497   primary.push_back("1");
    498   EXPECT_TRUE(ExpectGetAccounts(primary));
    499 }
    500 
    501 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, TwoAccountsSignedIn) {
    502   SetAccountState(CreateIds("primary (at) example.com", "1"), true);
    503   SetAccountState(CreateIds("secondary (at) example.com", "2"), true);
    504   std::vector<std::string> two_accounts;
    505   two_accounts.push_back("1");
    506   two_accounts.push_back("2");
    507   EXPECT_TRUE(ExpectGetAccounts(two_accounts));
    508 }
    509 
    510 class IdentityOldProfilesGetAccountsFunctionTest
    511     : public IdentityGetAccountsFunctionTest {
    512   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    513     // Don't add the multi-account switch that parent class would have.
    514   }
    515 };
    516 
    517 IN_PROC_BROWSER_TEST_F(IdentityOldProfilesGetAccountsFunctionTest,
    518                        MultiAccountOff) {
    519   EXPECT_FALSE(switches::IsExtensionsMultiAccount());
    520 }
    521 
    522 IN_PROC_BROWSER_TEST_F(IdentityOldProfilesGetAccountsFunctionTest,
    523                        TwoAccountsSignedIn) {
    524   SetAccountState(CreateIds("primary (at) example.com", "1"), true);
    525   SetAccountState(CreateIds("secondary (at) example.com", "2"), true);
    526   std::vector<std::string> only_primary;
    527   only_primary.push_back("1");
    528   EXPECT_TRUE(ExpectGetAccounts(only_primary));
    529 }
    530 
    531 class IdentityGetProfileUserInfoFunctionTest : public ExtensionBrowserTest {
    532  protected:
    533   scoped_ptr<api::identity::ProfileUserInfo> RunGetProfileUserInfo() {
    534     scoped_refptr<IdentityGetProfileUserInfoFunction> func(
    535         new IdentityGetProfileUserInfoFunction);
    536     func->set_extension(test_util::CreateEmptyExtension(kExtensionId).get());
    537     scoped_ptr<base::Value> value(
    538         utils::RunFunctionAndReturnSingleResult(func.get(), "[]", browser()));
    539     return api::identity::ProfileUserInfo::FromValue(*value.get());
    540   }
    541 
    542   scoped_ptr<api::identity::ProfileUserInfo> RunGetProfileUserInfoWithEmail() {
    543     scoped_refptr<IdentityGetProfileUserInfoFunction> func(
    544         new IdentityGetProfileUserInfoFunction);
    545     func->set_extension(CreateExtensionWithEmailPermission());
    546     scoped_ptr<base::Value> value(
    547         utils::RunFunctionAndReturnSingleResult(func.get(), "[]", browser()));
    548     return api::identity::ProfileUserInfo::FromValue(*value.get());
    549   }
    550 
    551  private:
    552   scoped_refptr<Extension> CreateExtensionWithEmailPermission() {
    553     scoped_ptr<base::DictionaryValue> test_extension_value(
    554         utils::ParseDictionary(
    555             "{\"name\": \"Test\", \"version\": \"1.0\", "
    556             "\"permissions\": [\"identity.email\"]}"));
    557     return utils::CreateExtension(test_extension_value.get());
    558   }
    559 };
    560 
    561 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest, NotSignedIn) {
    562   scoped_ptr<api::identity::ProfileUserInfo> info =
    563       RunGetProfileUserInfoWithEmail();
    564   EXPECT_TRUE(info->email.empty());
    565   EXPECT_TRUE(info->id.empty());
    566 }
    567 
    568 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest, SignedIn) {
    569   profile()->GetPrefs()
    570       ->SetString(prefs::kGoogleServicesUsername, "president (at) example.com");
    571   profile()->GetPrefs()
    572       ->SetString(prefs::kGoogleServicesUserAccountId, "12345");
    573 
    574   scoped_ptr<api::identity::ProfileUserInfo> info =
    575       RunGetProfileUserInfoWithEmail();
    576   EXPECT_EQ("president (at) example.com", info->email);
    577   EXPECT_EQ("12345", info->id);
    578 }
    579 
    580 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest,
    581                        NotSignedInNoEmail) {
    582   scoped_ptr<api::identity::ProfileUserInfo> info = RunGetProfileUserInfo();
    583   EXPECT_TRUE(info->email.empty());
    584   EXPECT_TRUE(info->id.empty());
    585 }
    586 
    587 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest,
    588                        SignedInNoEmail) {
    589   profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
    590                                    "president (at) example.com");
    591   profile()->GetPrefs()->SetString(prefs::kGoogleServicesUserAccountId,
    592                                    "12345");
    593 
    594   scoped_ptr<api::identity::ProfileUserInfo> info = RunGetProfileUserInfo();
    595   EXPECT_TRUE(info->email.empty());
    596   EXPECT_EQ("12345", info->id);
    597 }
    598 
    599 class GetAuthTokenFunctionTest : public AsyncExtensionBrowserTest {
    600  public:
    601   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    602     AsyncExtensionBrowserTest::SetUpCommandLine(command_line);
    603     command_line->AppendSwitch(switches::kExtensionsMultiAccount);
    604   }
    605 
    606   virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
    607     AsyncExtensionBrowserTest::SetUpInProcessBrowserTestFixture();
    608 
    609     will_create_browser_context_services_subscription_ =
    610         BrowserContextDependencyManager::GetInstance()
    611             ->RegisterWillCreateBrowserContextServicesCallbackForTesting(
    612                   base::Bind(&GetAuthTokenFunctionTest::
    613                                  OnWillCreateBrowserContextServices,
    614                              base::Unretained(this)))
    615             .Pass();
    616   }
    617 
    618   void OnWillCreateBrowserContextServices(content::BrowserContext* context) {
    619     // Replace the signin manager and token service with fakes. Do this ahead of
    620     // creating the browser so that a bunch of classes don't register as
    621     // observers and end up needing to unregister when the fake is substituted.
    622     SigninManagerFactory::GetInstance()->SetTestingFactory(
    623         context, &FakeSigninManagerBase::Build);
    624     ProfileOAuth2TokenServiceFactory::GetInstance()->SetTestingFactory(
    625         context, &BuildFakeProfileOAuth2TokenService);
    626     AccountReconcilorFactory::GetInstance()->SetTestingFactory(
    627         context, &FakeAccountReconcilor::Build);
    628   }
    629 
    630   virtual void SetUpOnMainThread() OVERRIDE {
    631     AsyncExtensionBrowserTest::SetUpOnMainThread();
    632 
    633     // Grab references to the fake signin manager and token service.
    634     signin_manager_ = static_cast<FakeSigninManagerForTesting*>(
    635         SigninManagerFactory::GetInstance()->GetForProfile(profile()));
    636     ASSERT_TRUE(signin_manager_);
    637     token_service_ = static_cast<FakeProfileOAuth2TokenService*>(
    638         ProfileOAuth2TokenServiceFactory::GetInstance()->GetForProfile(
    639             profile()));
    640     ASSERT_TRUE(token_service_);
    641   }
    642 
    643   void SignIn(const std::string account_key) {
    644 #if defined(OS_CHROMEOS)
    645     signin_manager_->SetAuthenticatedUsername(account_key);
    646 #else
    647     signin_manager_->SignIn(account_key, "password");
    648 #endif
    649     token_service_->IssueRefreshTokenForUser(account_key, "refresh_token");
    650   }
    651 
    652   void IssueLoginRefreshTokenForAccount(const std::string account_key) {
    653     token_service_->IssueRefreshTokenForUser(account_key, "refresh_token");
    654   }
    655 
    656   void IssueLoginAccessTokenForAccount(const std::string account_key) {
    657     token_service_->IssueAllTokensForAccount(
    658         account_key,
    659         "access_token-" + account_key,
    660         base::Time::Now() + base::TimeDelta::FromSeconds(3600));
    661   }
    662 
    663   void SetAccountState(gaia::AccountIds ids, bool is_signed_in) {
    664     IdentityAPI::GetFactoryInstance()->Get(profile())->SetAccountStateForTest(
    665         ids, is_signed_in);
    666   }
    667 
    668  protected:
    669   enum OAuth2Fields {
    670     NONE = 0,
    671     CLIENT_ID = 1,
    672     SCOPES = 2,
    673     AS_COMPONENT = 4
    674   };
    675 
    676   FakeSigninManagerForTesting* signin_manager_;
    677   FakeProfileOAuth2TokenService* token_service_;
    678 
    679   virtual ~GetAuthTokenFunctionTest() {}
    680 
    681   // Helper to create an extension with specific OAuth2Info fields set.
    682   // |fields_to_set| should be computed by using fields of Oauth2Fields enum.
    683   const Extension* CreateExtension(int fields_to_set) {
    684     const Extension* ext;
    685     base::FilePath manifest_path =
    686         test_data_dir_.AppendASCII("platform_apps/oauth2");
    687     base::FilePath component_manifest_path =
    688         test_data_dir_.AppendASCII("packaged_app/component_oauth2");
    689     if ((fields_to_set & AS_COMPONENT) == 0)
    690       ext = LoadExtension(manifest_path);
    691     else
    692       ext = LoadExtensionAsComponent(component_manifest_path);
    693     OAuth2Info& oauth2_info =
    694         const_cast<OAuth2Info&>(OAuth2Info::GetOAuth2Info(ext));
    695     if ((fields_to_set & CLIENT_ID) != 0)
    696       oauth2_info.client_id = "client1";
    697     if ((fields_to_set & SCOPES) != 0) {
    698       oauth2_info.scopes.push_back("scope1");
    699       oauth2_info.scopes.push_back("scope2");
    700     }
    701 
    702     extension_id_ = ext->id();
    703     oauth_scopes_ = std::set<std::string>(oauth2_info.scopes.begin(),
    704                                           oauth2_info.scopes.end());
    705     return ext;
    706   }
    707 
    708   IdentityAPI* id_api() {
    709     return IdentityAPI::GetFactoryInstance()->Get(browser()->profile());
    710   }
    711 
    712   const std::string GetPrimaryAccountId() {
    713     SigninManagerBase* signin_manager =
    714         SigninManagerFactory::GetForProfile(browser()->profile());
    715     return signin_manager->GetAuthenticatedAccountId();
    716   }
    717 
    718   void SetCachedToken(const IdentityTokenCacheValue& token_data) {
    719     ExtensionTokenKey key(extension_id_, GetPrimaryAccountId(), oauth_scopes_);
    720     id_api()->SetCachedToken(key, token_data);
    721   }
    722 
    723   const IdentityTokenCacheValue& GetCachedToken(std::string account_id) {
    724     if (account_id.empty())
    725       account_id = GetPrimaryAccountId();
    726     ExtensionTokenKey key(extension_id_, account_id, oauth_scopes_);
    727     return id_api()->GetCachedToken(key);
    728   }
    729 
    730   void QueueRequestStart(IdentityMintRequestQueue::MintType type,
    731                          IdentityMintRequestQueue::Request* request) {
    732     ExtensionTokenKey key(extension_id_, GetPrimaryAccountId(), oauth_scopes_);
    733     id_api()->mint_queue()->RequestStart(type, key, request);
    734   }
    735 
    736   void QueueRequestComplete(IdentityMintRequestQueue::MintType type,
    737                             IdentityMintRequestQueue::Request* request) {
    738     ExtensionTokenKey key(extension_id_, GetPrimaryAccountId(), oauth_scopes_);
    739     id_api()->mint_queue()->RequestComplete(type, key, request);
    740   }
    741 
    742  private:
    743   std::string extension_id_;
    744   std::set<std::string> oauth_scopes_;
    745 
    746   scoped_ptr<base::CallbackList<void(content::BrowserContext*)>::Subscription>
    747       will_create_browser_context_services_subscription_;
    748 };
    749 
    750 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
    751                        NoClientId) {
    752   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
    753   func->set_extension(CreateExtension(SCOPES));
    754   std::string error = utils::RunFunctionAndReturnError(
    755       func.get(), "[{}]", browser());
    756   EXPECT_EQ(std::string(errors::kInvalidClientId), error);
    757   EXPECT_FALSE(func->login_ui_shown());
    758   EXPECT_FALSE(func->scope_ui_shown());
    759 }
    760 
    761 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
    762                        NoScopes) {
    763   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
    764   func->set_extension(CreateExtension(CLIENT_ID));
    765   std::string error = utils::RunFunctionAndReturnError(
    766       func.get(), "[{}]", browser());
    767   EXPECT_EQ(std::string(errors::kInvalidScopes), error);
    768   EXPECT_FALSE(func->login_ui_shown());
    769   EXPECT_FALSE(func->scope_ui_shown());
    770 }
    771 
    772 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
    773                        NonInteractiveNotSignedIn) {
    774   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
    775   func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
    776   std::string error = utils::RunFunctionAndReturnError(
    777       func.get(), "[{}]", browser());
    778   EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
    779   EXPECT_FALSE(func->login_ui_shown());
    780   EXPECT_FALSE(func->scope_ui_shown());
    781 }
    782 
    783 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
    784                        NonInteractiveMintFailure) {
    785   SignIn("primary (at) example.com");
    786   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
    787   func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
    788   func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE);
    789   std::string error =
    790       utils::RunFunctionAndReturnError(func.get(), "[{}]", browser());
    791   EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
    792   EXPECT_FALSE(func->login_ui_shown());
    793   EXPECT_FALSE(func->scope_ui_shown());
    794 }
    795 
    796 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
    797                        NonInteractiveLoginAccessTokenFailure) {
    798   SignIn("primary (at) example.com");
    799   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
    800   func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
    801   func->set_login_access_token_result(false);
    802   std::string error = utils::RunFunctionAndReturnError(
    803       func.get(), "[{}]", browser());
    804   EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
    805 }
    806 
    807 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
    808                        NonInteractiveMintAdviceSuccess) {
    809   SignIn("primary (at) example.com");
    810   scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
    811   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
    812   func->set_extension(extension.get());
    813   func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
    814   std::string error =
    815       utils::RunFunctionAndReturnError(func.get(), "[{}]", browser());
    816   EXPECT_EQ(std::string(errors::kNoGrant), error);
    817   EXPECT_FALSE(func->login_ui_shown());
    818   EXPECT_FALSE(func->scope_ui_shown());
    819 
    820   EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_ADVICE,
    821             GetCachedToken(std::string()).status());
    822 }
    823 
    824 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
    825                        NonInteractiveMintBadCredentials) {
    826   SignIn("primary (at) example.com");
    827   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
    828   func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
    829   func->set_mint_token_result(
    830       TestOAuth2MintTokenFlow::MINT_TOKEN_BAD_CREDENTIALS);
    831   std::string error =
    832       utils::RunFunctionAndReturnError(func.get(), "[{}]", browser());
    833   EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
    834   EXPECT_FALSE(func->login_ui_shown());
    835   EXPECT_FALSE(func->scope_ui_shown());
    836 }
    837 
    838 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
    839                        NonInteractiveMintServiceError) {
    840   SignIn("primary (at) example.com");
    841   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
    842   func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
    843   func->set_mint_token_result(
    844       TestOAuth2MintTokenFlow::MINT_TOKEN_SERVICE_ERROR);
    845   std::string error =
    846       utils::RunFunctionAndReturnError(func.get(), "[{}]", browser());
    847   EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
    848   EXPECT_FALSE(func->login_ui_shown());
    849   EXPECT_FALSE(func->scope_ui_shown());
    850 }
    851 
    852 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
    853                        NoOptionsSuccess) {
    854   SignIn("primary (at) example.com");
    855 #if defined(OS_WIN) && defined(USE_ASH)
    856   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
    857   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
    858     return;
    859 #endif
    860 
    861   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
    862   scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
    863   func->set_extension(extension.get());
    864   func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
    865   scoped_ptr<base::Value> value(
    866       utils::RunFunctionAndReturnSingleResult(func.get(), "[]", browser()));
    867   std::string access_token;
    868   EXPECT_TRUE(value->GetAsString(&access_token));
    869   EXPECT_EQ(std::string(kAccessToken), access_token);
    870   EXPECT_FALSE(func->login_ui_shown());
    871   EXPECT_FALSE(func->scope_ui_shown());
    872   EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
    873             GetCachedToken(std::string()).status());
    874 }
    875 
    876 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
    877                        NonInteractiveSuccess) {
    878   SignIn("primary (at) example.com");
    879 #if defined(OS_WIN) && defined(USE_ASH)
    880   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
    881   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
    882     return;
    883 #endif
    884 
    885   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
    886   scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
    887   func->set_extension(extension.get());
    888   func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
    889   scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
    890       func.get(), "[{}]", browser()));
    891   std::string access_token;
    892   EXPECT_TRUE(value->GetAsString(&access_token));
    893   EXPECT_EQ(std::string(kAccessToken), access_token);
    894   EXPECT_FALSE(func->login_ui_shown());
    895   EXPECT_FALSE(func->scope_ui_shown());
    896   EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
    897             GetCachedToken(std::string()).status());
    898 }
    899 
    900 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
    901                        InteractiveLoginCanceled) {
    902   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
    903   func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
    904   func->set_login_ui_result(false);
    905   std::string error = utils::RunFunctionAndReturnError(
    906       func.get(), "[{\"interactive\": true}]", browser());
    907   EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
    908   EXPECT_TRUE(func->login_ui_shown());
    909   EXPECT_FALSE(func->scope_ui_shown());
    910 }
    911 
    912 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
    913                        InteractiveMintBadCredentialsLoginCanceled) {
    914   SignIn("primary (at) example.com");
    915   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
    916   func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
    917   func->set_mint_token_result(
    918       TestOAuth2MintTokenFlow::MINT_TOKEN_BAD_CREDENTIALS);
    919   func->set_login_ui_result(false);
    920   std::string error = utils::RunFunctionAndReturnError(
    921       func.get(), "[{\"interactive\": true}]", browser());
    922   EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
    923   EXPECT_TRUE(func->login_ui_shown());
    924   EXPECT_FALSE(func->scope_ui_shown());
    925 }
    926 
    927 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
    928                        InteractiveLoginSuccessNoToken) {
    929   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
    930   func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
    931   func->set_login_ui_result(false);
    932   std::string error = utils::RunFunctionAndReturnError(
    933       func.get(), "[{\"interactive\": true}]", browser());
    934   EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
    935   EXPECT_TRUE(func->login_ui_shown());
    936   EXPECT_FALSE(func->scope_ui_shown());
    937 }
    938 
    939 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
    940                        InteractiveLoginSuccessMintFailure) {
    941   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
    942   func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
    943   func->set_login_ui_result(true);
    944   func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE);
    945   std::string error = utils::RunFunctionAndReturnError(
    946       func.get(), "[{\"interactive\": true}]", browser());
    947   EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
    948   EXPECT_TRUE(func->login_ui_shown());
    949   EXPECT_FALSE(func->scope_ui_shown());
    950 }
    951 
    952 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
    953                        InteractiveLoginSuccessLoginAccessTokenFailure) {
    954   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
    955   func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
    956   func->set_login_ui_result(true);
    957   func->set_login_access_token_result(false);
    958   std::string error = utils::RunFunctionAndReturnError(
    959       func.get(), "[{\"interactive\": true}]", browser());
    960   EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
    961   EXPECT_TRUE(func->login_ui_shown());
    962   EXPECT_FALSE(func->scope_ui_shown());
    963 }
    964 
    965 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
    966                        InteractiveLoginSuccessMintSuccess) {
    967   // TODO(courage): verify that account_id in token service requests
    968   // is correct once manual token minting for tests is implemented.
    969   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
    970   func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
    971   func->set_login_ui_result(true);
    972   func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
    973   scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
    974       func.get(), "[{\"interactive\": true}]", browser()));
    975   std::string access_token;
    976   EXPECT_TRUE(value->GetAsString(&access_token));
    977   EXPECT_EQ(std::string(kAccessToken), access_token);
    978   EXPECT_TRUE(func->login_ui_shown());
    979   EXPECT_FALSE(func->scope_ui_shown());
    980 }
    981 
    982 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
    983                        InteractiveLoginSuccessApprovalAborted) {
    984   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
    985   func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
    986   func->set_login_ui_result(true);
    987   func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
    988   func->set_scope_ui_failure(GaiaWebAuthFlow::WINDOW_CLOSED);
    989   std::string error = utils::RunFunctionAndReturnError(
    990       func.get(), "[{\"interactive\": true}]", browser());
    991   EXPECT_EQ(std::string(errors::kUserRejected), error);
    992   EXPECT_TRUE(func->login_ui_shown());
    993   EXPECT_TRUE(func->scope_ui_shown());
    994 }
    995 
    996 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
    997                        InteractiveLoginSuccessApprovalSuccess) {
    998   scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
    999   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1000   func->set_extension(extension.get());
   1001   func->set_login_ui_result(true);
   1002   func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
   1003 
   1004   scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
   1005       func.get(), "[{\"interactive\": true}]", browser()));
   1006   std::string access_token;
   1007   EXPECT_TRUE(value->GetAsString(&access_token));
   1008   EXPECT_EQ(std::string(kAccessToken), access_token);
   1009   EXPECT_TRUE(func->login_ui_shown());
   1010   EXPECT_TRUE(func->scope_ui_shown());
   1011 }
   1012 
   1013 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
   1014                        InteractiveApprovalAborted) {
   1015   SignIn("primary (at) example.com");
   1016   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1017   func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
   1018   func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
   1019   func->set_scope_ui_failure(GaiaWebAuthFlow::WINDOW_CLOSED);
   1020   std::string error = utils::RunFunctionAndReturnError(
   1021       func.get(), "[{\"interactive\": true}]", browser());
   1022   EXPECT_EQ(std::string(errors::kUserRejected), error);
   1023   EXPECT_FALSE(func->login_ui_shown());
   1024   EXPECT_TRUE(func->scope_ui_shown());
   1025 }
   1026 
   1027 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
   1028                        InteractiveApprovalLoadFailed) {
   1029   SignIn("primary (at) example.com");
   1030   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1031   func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
   1032   func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
   1033   func->set_scope_ui_failure(GaiaWebAuthFlow::LOAD_FAILED);
   1034   std::string error = utils::RunFunctionAndReturnError(
   1035       func.get(), "[{\"interactive\": true}]", browser());
   1036   EXPECT_EQ(std::string(errors::kPageLoadFailure), error);
   1037   EXPECT_FALSE(func->login_ui_shown());
   1038   EXPECT_TRUE(func->scope_ui_shown());
   1039 }
   1040 
   1041 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
   1042                        InteractiveApprovalInvalidRedirect) {
   1043   SignIn("primary (at) example.com");
   1044   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1045   func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
   1046   func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
   1047   func->set_scope_ui_failure(GaiaWebAuthFlow::INVALID_REDIRECT);
   1048   std::string error = utils::RunFunctionAndReturnError(
   1049       func.get(), "[{\"interactive\": true}]", browser());
   1050   EXPECT_EQ(std::string(errors::kInvalidRedirect), error);
   1051   EXPECT_FALSE(func->login_ui_shown());
   1052   EXPECT_TRUE(func->scope_ui_shown());
   1053 }
   1054 
   1055 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
   1056                        InteractiveApprovalConnectionFailure) {
   1057   SignIn("primary (at) example.com");
   1058   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1059   func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
   1060   func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
   1061   func->set_scope_ui_failure(GaiaWebAuthFlow::SERVICE_AUTH_ERROR);
   1062   std::string error = utils::RunFunctionAndReturnError(
   1063       func.get(), "[{\"interactive\": true}]", browser());
   1064   EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
   1065   EXPECT_FALSE(func->login_ui_shown());
   1066   EXPECT_TRUE(func->scope_ui_shown());
   1067 }
   1068 
   1069 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
   1070                        InteractiveApprovalOAuthErrors) {
   1071   SignIn("primary (at) example.com");
   1072   scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
   1073 
   1074   std::map<std::string, std::string> error_map;
   1075   error_map.insert(std::make_pair("access_denied", errors::kUserRejected));
   1076   error_map.insert(std::make_pair("invalid_scope", errors::kInvalidScopes));
   1077   error_map.insert(std::make_pair(
   1078       "unmapped_error", std::string(errors::kAuthFailure) + "unmapped_error"));
   1079 
   1080   for (std::map<std::string, std::string>::const_iterator
   1081            it = error_map.begin();
   1082        it != error_map.end();
   1083        ++it) {
   1084     scoped_refptr<FakeGetAuthTokenFunction> func(
   1085         new FakeGetAuthTokenFunction());
   1086     func->set_extension(extension.get());
   1087     // Make sure we don't get a cached issue_advice result, which would cause
   1088     // flow to be leaked.
   1089     id_api()->EraseAllCachedTokens();
   1090     func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
   1091     func->set_scope_ui_oauth_error(it->first);
   1092     std::string error = utils::RunFunctionAndReturnError(
   1093         func.get(), "[{\"interactive\": true}]", browser());
   1094     EXPECT_EQ(it->second, error);
   1095     EXPECT_FALSE(func->login_ui_shown());
   1096     EXPECT_TRUE(func->scope_ui_shown());
   1097   }
   1098 }
   1099 
   1100 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
   1101                        InteractiveApprovalSuccess) {
   1102   SignIn("primary (at) example.com");
   1103   scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
   1104   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1105   func->set_extension(extension.get());
   1106   func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
   1107 
   1108   scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
   1109       func.get(), "[{\"interactive\": true}]", browser()));
   1110   std::string access_token;
   1111   EXPECT_TRUE(value->GetAsString(&access_token));
   1112   EXPECT_EQ(std::string(kAccessToken), access_token);
   1113   EXPECT_FALSE(func->login_ui_shown());
   1114   EXPECT_TRUE(func->scope_ui_shown());
   1115 
   1116   EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
   1117             GetCachedToken(std::string()).status());
   1118 }
   1119 
   1120 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, NoninteractiveQueue) {
   1121   SignIn("primary (at) example.com");
   1122   scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
   1123   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1124   func->set_extension(extension.get());
   1125 
   1126   // Create a fake request to block the queue.
   1127   MockQueuedMintRequest queued_request;
   1128   IdentityMintRequestQueue::MintType type =
   1129       IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE;
   1130 
   1131   EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
   1132   QueueRequestStart(type, &queued_request);
   1133 
   1134   // The real request will start processing, but wait in the queue behind
   1135   // the blocker.
   1136   RunFunctionAsync(func.get(), "[{}]");
   1137   // Verify that we have fetched the login token at this point.
   1138   testing::Mock::VerifyAndClearExpectations(func.get());
   1139 
   1140   // The flow will be created after the first queued request clears.
   1141   func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
   1142 
   1143   QueueRequestComplete(type, &queued_request);
   1144 
   1145   scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
   1146   std::string access_token;
   1147   EXPECT_TRUE(value->GetAsString(&access_token));
   1148   EXPECT_EQ(std::string(kAccessToken), access_token);
   1149   EXPECT_FALSE(func->login_ui_shown());
   1150   EXPECT_FALSE(func->scope_ui_shown());
   1151 }
   1152 
   1153 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, InteractiveQueue) {
   1154   SignIn("primary (at) example.com");
   1155   scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
   1156   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1157   func->set_extension(extension.get());
   1158 
   1159   // Create a fake request to block the queue.
   1160   MockQueuedMintRequest queued_request;
   1161   IdentityMintRequestQueue::MintType type =
   1162       IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
   1163 
   1164   EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
   1165   QueueRequestStart(type, &queued_request);
   1166 
   1167   // The real request will start processing, but wait in the queue behind
   1168   // the blocker.
   1169   func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
   1170   RunFunctionAsync(func.get(), "[{\"interactive\": true}]");
   1171   // Verify that we have fetched the login token and run the first flow.
   1172   testing::Mock::VerifyAndClearExpectations(func.get());
   1173   EXPECT_FALSE(func->scope_ui_shown());
   1174 
   1175   // The UI will be displayed and a token retrieved after the first
   1176   // queued request clears.
   1177   QueueRequestComplete(type, &queued_request);
   1178 
   1179   scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
   1180   std::string access_token;
   1181   EXPECT_TRUE(value->GetAsString(&access_token));
   1182   EXPECT_EQ(std::string(kAccessToken), access_token);
   1183   EXPECT_FALSE(func->login_ui_shown());
   1184   EXPECT_TRUE(func->scope_ui_shown());
   1185 }
   1186 
   1187 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, InteractiveQueueShutdown) {
   1188   SignIn("primary (at) example.com");
   1189   scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
   1190   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1191   func->set_extension(extension.get());
   1192 
   1193   // Create a fake request to block the queue.
   1194   MockQueuedMintRequest queued_request;
   1195   IdentityMintRequestQueue::MintType type =
   1196       IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
   1197 
   1198   EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
   1199   QueueRequestStart(type, &queued_request);
   1200 
   1201   // The real request will start processing, but wait in the queue behind
   1202   // the blocker.
   1203   func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
   1204   RunFunctionAsync(func.get(), "[{\"interactive\": true}]");
   1205   // Verify that we have fetched the login token and run the first flow.
   1206   testing::Mock::VerifyAndClearExpectations(func.get());
   1207   EXPECT_FALSE(func->scope_ui_shown());
   1208 
   1209   // After the request is canceled, the function will complete.
   1210   func->OnShutdown();
   1211   EXPECT_EQ(std::string(errors::kCanceled), WaitForError(func.get()));
   1212   EXPECT_FALSE(func->login_ui_shown());
   1213   EXPECT_FALSE(func->scope_ui_shown());
   1214 
   1215   QueueRequestComplete(type, &queued_request);
   1216 }
   1217 
   1218 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, NoninteractiveShutdown) {
   1219   SignIn("primary (at) example.com");
   1220   scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
   1221   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1222   func->set_extension(extension.get());
   1223 
   1224   scoped_ptr<TestHangOAuth2MintTokenFlow> flow(
   1225       new TestHangOAuth2MintTokenFlow());
   1226   func->set_mint_token_flow(flow.PassAs<OAuth2MintTokenFlow>());
   1227   RunFunctionAsync(func.get(), "[{\"interactive\": false}]");
   1228 
   1229   // After the request is canceled, the function will complete.
   1230   func->OnShutdown();
   1231   EXPECT_EQ(std::string(errors::kCanceled), WaitForError(func.get()));
   1232 }
   1233 
   1234 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
   1235                        InteractiveQueuedNoninteractiveFails) {
   1236   SignIn("primary (at) example.com");
   1237   scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
   1238   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1239   func->set_extension(extension.get());
   1240 
   1241   // Create a fake request to block the interactive queue.
   1242   MockQueuedMintRequest queued_request;
   1243   IdentityMintRequestQueue::MintType type =
   1244       IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
   1245 
   1246   EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
   1247   QueueRequestStart(type, &queued_request);
   1248 
   1249   // Non-interactive requests fail without hitting GAIA, because a
   1250   // consent UI is known to be up.
   1251   std::string error = utils::RunFunctionAndReturnError(
   1252       func.get(), "[{}]", browser());
   1253   EXPECT_EQ(std::string(errors::kNoGrant), error);
   1254   EXPECT_FALSE(func->login_ui_shown());
   1255   EXPECT_FALSE(func->scope_ui_shown());
   1256 
   1257   QueueRequestComplete(type, &queued_request);
   1258 }
   1259 
   1260 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
   1261                        NonInteractiveCacheHit) {
   1262   SignIn("primary (at) example.com");
   1263   scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
   1264   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1265   func->set_extension(extension.get());
   1266 
   1267   // pre-populate the cache with a token
   1268   IdentityTokenCacheValue token(kAccessToken,
   1269                                 base::TimeDelta::FromSeconds(3600));
   1270   SetCachedToken(token);
   1271 
   1272   // Get a token. Should not require a GAIA request.
   1273   scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
   1274       func.get(), "[{}]", browser()));
   1275   std::string access_token;
   1276   EXPECT_TRUE(value->GetAsString(&access_token));
   1277   EXPECT_EQ(std::string(kAccessToken), access_token);
   1278   EXPECT_FALSE(func->login_ui_shown());
   1279   EXPECT_FALSE(func->scope_ui_shown());
   1280 }
   1281 
   1282 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
   1283                        NonInteractiveIssueAdviceCacheHit) {
   1284   SignIn("primary (at) example.com");
   1285   scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
   1286   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1287   func->set_extension(extension.get());
   1288 
   1289   // pre-populate the cache with advice
   1290   IssueAdviceInfo info;
   1291   IdentityTokenCacheValue token(info);
   1292   SetCachedToken(token);
   1293 
   1294   // Should return an error without a GAIA request.
   1295   std::string error = utils::RunFunctionAndReturnError(
   1296       func.get(), "[{}]", browser());
   1297   EXPECT_EQ(std::string(errors::kNoGrant), error);
   1298   EXPECT_FALSE(func->login_ui_shown());
   1299   EXPECT_FALSE(func->scope_ui_shown());
   1300 }
   1301 
   1302 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
   1303                        InteractiveCacheHit) {
   1304   SignIn("primary (at) example.com");
   1305   scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
   1306   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1307   func->set_extension(extension.get());
   1308 
   1309   // Create a fake request to block the queue.
   1310   MockQueuedMintRequest queued_request;
   1311   IdentityMintRequestQueue::MintType type =
   1312       IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
   1313 
   1314   EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
   1315   QueueRequestStart(type, &queued_request);
   1316 
   1317   // The real request will start processing, but wait in the queue behind
   1318   // the blocker.
   1319   func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
   1320   RunFunctionAsync(func.get(), "[{\"interactive\": true}]");
   1321 
   1322   // Populate the cache with a token while the request is blocked.
   1323   IdentityTokenCacheValue token(kAccessToken,
   1324                                 base::TimeDelta::FromSeconds(3600));
   1325   SetCachedToken(token);
   1326 
   1327   // When we wake up the request, it returns the cached token without
   1328   // displaying a UI, or hitting GAIA.
   1329 
   1330   QueueRequestComplete(type, &queued_request);
   1331 
   1332   scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
   1333   std::string access_token;
   1334   EXPECT_TRUE(value->GetAsString(&access_token));
   1335   EXPECT_EQ(std::string(kAccessToken), access_token);
   1336   EXPECT_FALSE(func->login_ui_shown());
   1337   EXPECT_FALSE(func->scope_ui_shown());
   1338 }
   1339 
   1340 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
   1341                        LoginInvalidatesTokenCache) {
   1342   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1343   scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
   1344   func->set_extension(extension.get());
   1345 
   1346   // pre-populate the cache with a token
   1347   IdentityTokenCacheValue token(kAccessToken,
   1348                                 base::TimeDelta::FromSeconds(3600));
   1349   SetCachedToken(token);
   1350 
   1351   // Because the user is not signed in, the token will be removed,
   1352   // and we'll hit GAIA for new tokens.
   1353   func->set_login_ui_result(true);
   1354   func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
   1355 
   1356   scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
   1357       func.get(), "[{\"interactive\": true}]", browser()));
   1358   std::string access_token;
   1359   EXPECT_TRUE(value->GetAsString(&access_token));
   1360   EXPECT_EQ(std::string(kAccessToken), access_token);
   1361   EXPECT_TRUE(func->login_ui_shown());
   1362   EXPECT_TRUE(func->scope_ui_shown());
   1363   EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
   1364             GetCachedToken(std::string()).status());
   1365 }
   1366 
   1367 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ComponentWithChromeClientId) {
   1368   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1369   scoped_refptr<const Extension> extension(
   1370       CreateExtension(SCOPES | AS_COMPONENT));
   1371   func->set_extension(extension.get());
   1372   const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension.get());
   1373   EXPECT_TRUE(oauth2_info.client_id.empty());
   1374   EXPECT_FALSE(func->GetOAuth2ClientId().empty());
   1375   EXPECT_NE("client1", func->GetOAuth2ClientId());
   1376 }
   1377 
   1378 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ComponentWithNormalClientId) {
   1379   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1380   scoped_refptr<const Extension> extension(
   1381       CreateExtension(CLIENT_ID | SCOPES | AS_COMPONENT));
   1382   func->set_extension(extension.get());
   1383   EXPECT_EQ("client1", func->GetOAuth2ClientId());
   1384 }
   1385 
   1386 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiDefaultUser) {
   1387   SignIn("primary (at) example.com");
   1388   SetAccountState(CreateIds("primary (at) example.com", "1"), true);
   1389   SetAccountState(CreateIds("secondary (at) example.com", "2"), true);
   1390 
   1391   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1392   scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
   1393   func->set_extension(extension.get());
   1394   func->set_auto_login_access_token(false);
   1395   func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
   1396 
   1397   RunFunctionAsync(func.get(), "[{}]");
   1398 
   1399   IssueLoginAccessTokenForAccount("primary (at) example.com");
   1400 
   1401   scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
   1402   std::string access_token;
   1403   EXPECT_TRUE(value->GetAsString(&access_token));
   1404   EXPECT_EQ(std::string(kAccessToken), access_token);
   1405   EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
   1406             GetCachedToken(std::string()).status());
   1407   EXPECT_EQ("access_token-primary (at) example.com", func->login_access_token());
   1408 }
   1409 
   1410 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiPrimaryUser) {
   1411   SignIn("primary (at) example.com");
   1412   IssueLoginRefreshTokenForAccount("secondary (at) example.com");
   1413   SetAccountState(CreateIds("primary (at) example.com", "1"), true);
   1414   SetAccountState(CreateIds("secondary (at) example.com", "2"), true);
   1415 
   1416   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1417   scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
   1418   func->set_extension(extension.get());
   1419   func->set_auto_login_access_token(false);
   1420   func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
   1421 
   1422   RunFunctionAsync(func.get(), "[{\"account\": { \"id\": \"1\" } }]");
   1423 
   1424   IssueLoginAccessTokenForAccount("primary (at) example.com");
   1425 
   1426   scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
   1427   std::string access_token;
   1428   EXPECT_TRUE(value->GetAsString(&access_token));
   1429   EXPECT_EQ(std::string(kAccessToken), access_token);
   1430   EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
   1431             GetCachedToken(std::string()).status());
   1432   EXPECT_EQ("access_token-primary (at) example.com", func->login_access_token());
   1433 }
   1434 
   1435 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiSecondaryUser) {
   1436   SignIn("primary (at) example.com");
   1437   IssueLoginRefreshTokenForAccount("secondary (at) example.com");
   1438   SetAccountState(CreateIds("primary (at) example.com", "1"), true);
   1439   SetAccountState(CreateIds("secondary (at) example.com", "2"), true);
   1440 
   1441   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1442   scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
   1443   func->set_extension(extension.get());
   1444   func->set_auto_login_access_token(false);
   1445   func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
   1446 
   1447   RunFunctionAsync(func.get(), "[{\"account\": { \"id\": \"2\" } }]");
   1448 
   1449   IssueLoginAccessTokenForAccount("secondary (at) example.com");
   1450 
   1451   scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
   1452   std::string access_token;
   1453   EXPECT_TRUE(value->GetAsString(&access_token));
   1454   EXPECT_EQ(std::string(kAccessToken), access_token);
   1455   EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
   1456             GetCachedToken("secondary (at) example.com").status());
   1457   EXPECT_EQ("access_token-secondary (at) example.com", func->login_access_token());
   1458 }
   1459 
   1460 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiUnknownUser) {
   1461   SignIn("primary (at) example.com");
   1462   IssueLoginRefreshTokenForAccount("secondary (at) example.com");
   1463   SetAccountState(CreateIds("primary (at) example.com", "1"), true);
   1464   SetAccountState(CreateIds("secondary (at) example.com", "2"), true);
   1465 
   1466   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1467   scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
   1468   func->set_extension(extension.get());
   1469   func->set_auto_login_access_token(false);
   1470 
   1471   std::string error = utils::RunFunctionAndReturnError(
   1472       func.get(), "[{\"account\": { \"id\": \"3\" } }]", browser());
   1473   EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
   1474 }
   1475 
   1476 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
   1477                        MultiSecondaryNonInteractiveMintFailure) {
   1478   SignIn("primary (at) example.com");
   1479   IssueLoginRefreshTokenForAccount("secondary (at) example.com");
   1480   SetAccountState(CreateIds("primary (at) example.com", "1"), true);
   1481   SetAccountState(CreateIds("secondary (at) example.com", "2"), true);
   1482 
   1483   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1484   func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
   1485   func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE);
   1486   std::string error = utils::RunFunctionAndReturnError(
   1487       func.get(), "[{\"account\": { \"id\": \"2\" } }]", browser());
   1488   EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
   1489   EXPECT_FALSE(func->login_ui_shown());
   1490   EXPECT_FALSE(func->scope_ui_shown());
   1491 }
   1492 
   1493 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
   1494                        MultiSecondaryNonInteractiveLoginAccessTokenFailure) {
   1495   SignIn("primary (at) example.com");
   1496   IssueLoginRefreshTokenForAccount("secondary (at) example.com");
   1497   SetAccountState(CreateIds("primary (at) example.com", "1"), true);
   1498   SetAccountState(CreateIds("secondary (at) example.com", "2"), true);
   1499 
   1500   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1501   func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
   1502   func->set_login_access_token_result(false);
   1503   std::string error = utils::RunFunctionAndReturnError(
   1504       func.get(), "[{\"account\": { \"id\": \"2\" } }]", browser());
   1505   EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
   1506 }
   1507 
   1508 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
   1509                        MultiSecondaryInteractiveApprovalAborted) {
   1510   SignIn("primary (at) example.com");
   1511   IssueLoginRefreshTokenForAccount("secondary (at) example.com");
   1512   SetAccountState(CreateIds("primary (at) example.com", "1"), true);
   1513   SetAccountState(CreateIds("secondary (at) example.com", "2"), true);
   1514 
   1515   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1516   func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
   1517   func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
   1518   func->set_scope_ui_failure(GaiaWebAuthFlow::WINDOW_CLOSED);
   1519   std::string error = utils::RunFunctionAndReturnError(
   1520       func.get(),
   1521       "[{\"account\": { \"id\": \"2\" }, \"interactive\": true}]",
   1522       browser());
   1523   EXPECT_EQ(std::string(errors::kUserRejected), error);
   1524   EXPECT_FALSE(func->login_ui_shown());
   1525   EXPECT_TRUE(func->scope_ui_shown());
   1526 }
   1527 
   1528 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesDefault) {
   1529   SignIn("primary (at) example.com");
   1530   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1531   scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
   1532   func->set_extension(extension.get());
   1533   func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
   1534   scoped_ptr<base::Value> value(
   1535       utils::RunFunctionAndReturnSingleResult(func.get(), "[{}]", browser()));
   1536   std::string access_token;
   1537   EXPECT_TRUE(value->GetAsString(&access_token));
   1538   EXPECT_EQ(std::string(kAccessToken), access_token);
   1539 
   1540   const ExtensionTokenKey* token_key = func->GetExtensionTokenKeyForTest();
   1541   EXPECT_EQ(2ul, token_key->scopes.size());
   1542   EXPECT_TRUE(ContainsKey(token_key->scopes, "scope1"));
   1543   EXPECT_TRUE(ContainsKey(token_key->scopes, "scope2"));
   1544 }
   1545 
   1546 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesEmpty) {
   1547   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1548   scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
   1549   func->set_extension(extension.get());
   1550 
   1551   std::string error(utils::RunFunctionAndReturnError(
   1552       func.get(), "[{\"scopes\": []}]", browser()));
   1553 
   1554   EXPECT_EQ(errors::kInvalidScopes, error);
   1555 }
   1556 
   1557 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesEmail) {
   1558   SignIn("primary (at) example.com");
   1559   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1560   scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
   1561   func->set_extension(extension.get());
   1562   func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
   1563   scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
   1564       func.get(), "[{\"scopes\": [\"email\"]}]", browser()));
   1565   std::string access_token;
   1566   EXPECT_TRUE(value->GetAsString(&access_token));
   1567   EXPECT_EQ(std::string(kAccessToken), access_token);
   1568 
   1569   const ExtensionTokenKey* token_key = func->GetExtensionTokenKeyForTest();
   1570   EXPECT_EQ(1ul, token_key->scopes.size());
   1571   EXPECT_TRUE(ContainsKey(token_key->scopes, "email"));
   1572 }
   1573 
   1574 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesEmailFooBar) {
   1575   SignIn("primary (at) example.com");
   1576   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   1577   scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
   1578   func->set_extension(extension.get());
   1579   func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
   1580   scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
   1581       func.get(), "[{\"scopes\": [\"email\", \"foo\", \"bar\"]}]", browser()));
   1582   std::string access_token;
   1583   EXPECT_TRUE(value->GetAsString(&access_token));
   1584   EXPECT_EQ(std::string(kAccessToken), access_token);
   1585 
   1586   const ExtensionTokenKey* token_key = func->GetExtensionTokenKeyForTest();
   1587   EXPECT_EQ(3ul, token_key->scopes.size());
   1588   EXPECT_TRUE(ContainsKey(token_key->scopes, "email"));
   1589   EXPECT_TRUE(ContainsKey(token_key->scopes, "foo"));
   1590   EXPECT_TRUE(ContainsKey(token_key->scopes, "bar"));
   1591 }
   1592 
   1593 class RemoveCachedAuthTokenFunctionTest : public ExtensionBrowserTest {
   1594  protected:
   1595   bool InvalidateDefaultToken() {
   1596     scoped_refptr<IdentityRemoveCachedAuthTokenFunction> func(
   1597         new IdentityRemoveCachedAuthTokenFunction);
   1598     func->set_extension(test_util::CreateEmptyExtension(kExtensionId).get());
   1599     return utils::RunFunction(
   1600         func.get(),
   1601         std::string("[{\"token\": \"") + kAccessToken + "\"}]",
   1602         browser(),
   1603         extension_function_test_utils::NONE);
   1604   }
   1605 
   1606   IdentityAPI* id_api() {
   1607     return IdentityAPI::GetFactoryInstance()->Get(browser()->profile());
   1608   }
   1609 
   1610   void SetCachedToken(IdentityTokenCacheValue& token_data) {
   1611     ExtensionTokenKey key(
   1612         kExtensionId, "test (at) example.com", std::set<std::string>());
   1613     id_api()->SetCachedToken(key, token_data);
   1614   }
   1615 
   1616   const IdentityTokenCacheValue& GetCachedToken() {
   1617     return id_api()->GetCachedToken(ExtensionTokenKey(
   1618         kExtensionId, "test (at) example.com", std::set<std::string>()));
   1619   }
   1620 };
   1621 
   1622 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, NotFound) {
   1623   EXPECT_TRUE(InvalidateDefaultToken());
   1624   EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND,
   1625             GetCachedToken().status());
   1626 }
   1627 
   1628 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, Advice) {
   1629   IssueAdviceInfo info;
   1630   IdentityTokenCacheValue advice(info);
   1631   SetCachedToken(advice);
   1632   EXPECT_TRUE(InvalidateDefaultToken());
   1633   EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_ADVICE,
   1634             GetCachedToken().status());
   1635 }
   1636 
   1637 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, NonMatchingToken) {
   1638   IdentityTokenCacheValue token("non_matching_token",
   1639                                 base::TimeDelta::FromSeconds(3600));
   1640   SetCachedToken(token);
   1641   EXPECT_TRUE(InvalidateDefaultToken());
   1642   EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
   1643             GetCachedToken().status());
   1644   EXPECT_EQ("non_matching_token", GetCachedToken().token());
   1645 }
   1646 
   1647 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, MatchingToken) {
   1648   IdentityTokenCacheValue token(kAccessToken,
   1649                                 base::TimeDelta::FromSeconds(3600));
   1650   SetCachedToken(token);
   1651   EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
   1652             GetCachedToken().status());
   1653   EXPECT_TRUE(InvalidateDefaultToken());
   1654   EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND,
   1655             GetCachedToken().status());
   1656 }
   1657 
   1658 class LaunchWebAuthFlowFunctionTest : public AsyncExtensionBrowserTest {
   1659  public:
   1660   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
   1661     AsyncExtensionBrowserTest::SetUpCommandLine(command_line);
   1662     // Reduce performance test variance by disabling background networking.
   1663     command_line->AppendSwitch(switches::kDisableBackgroundNetworking);
   1664   }
   1665 };
   1666 
   1667 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, UserCloseWindow) {
   1668   net::SpawnedTestServer https_server(
   1669       net::SpawnedTestServer::TYPE_HTTPS,
   1670       net::SpawnedTestServer::kLocalhost,
   1671       base::FilePath(FILE_PATH_LITERAL(
   1672           "chrome/test/data/extensions/api_test/identity")));
   1673   ASSERT_TRUE(https_server.Start());
   1674   GURL auth_url(https_server.GetURL("files/interaction_required.html"));
   1675 
   1676   scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
   1677       new IdentityLaunchWebAuthFlowFunction());
   1678   scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
   1679   function->set_extension(empty_extension.get());
   1680 
   1681   WaitForGURLAndCloseWindow popup_observer(auth_url);
   1682 
   1683   std::string args = "[{\"interactive\": true, \"url\": \"" +
   1684       auth_url.spec() + "\"}]";
   1685   RunFunctionAsync(function.get(), args);
   1686 
   1687   popup_observer.Wait();
   1688   popup_observer.CloseEmbedderWebContents();
   1689 
   1690   EXPECT_EQ(std::string(errors::kUserRejected), WaitForError(function.get()));
   1691 }
   1692 
   1693 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, InteractionRequired) {
   1694   net::SpawnedTestServer https_server(
   1695       net::SpawnedTestServer::TYPE_HTTPS,
   1696       net::SpawnedTestServer::kLocalhost,
   1697       base::FilePath(FILE_PATH_LITERAL(
   1698           "chrome/test/data/extensions/api_test/identity")));
   1699   ASSERT_TRUE(https_server.Start());
   1700   GURL auth_url(https_server.GetURL("files/interaction_required.html"));
   1701 
   1702   scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
   1703       new IdentityLaunchWebAuthFlowFunction());
   1704   scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
   1705   function->set_extension(empty_extension.get());
   1706 
   1707   std::string args = "[{\"interactive\": false, \"url\": \"" +
   1708       auth_url.spec() + "\"}]";
   1709   std::string error =
   1710       utils::RunFunctionAndReturnError(function.get(), args, browser());
   1711 
   1712   EXPECT_EQ(std::string(errors::kInteractionRequired), error);
   1713 }
   1714 
   1715 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, LoadFailed) {
   1716   net::SpawnedTestServer https_server(
   1717       net::SpawnedTestServer::TYPE_HTTPS,
   1718       net::SpawnedTestServer::kLocalhost,
   1719       base::FilePath(FILE_PATH_LITERAL(
   1720           "chrome/test/data/extensions/api_test/identity")));
   1721   ASSERT_TRUE(https_server.Start());
   1722   GURL auth_url(https_server.GetURL("files/five_hundred.html"));
   1723 
   1724   scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
   1725       new IdentityLaunchWebAuthFlowFunction());
   1726   scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
   1727   function->set_extension(empty_extension.get());
   1728 
   1729   std::string args = "[{\"interactive\": true, \"url\": \"" +
   1730       auth_url.spec() + "\"}]";
   1731   std::string error =
   1732       utils::RunFunctionAndReturnError(function.get(), args, browser());
   1733 
   1734   EXPECT_EQ(std::string(errors::kPageLoadFailure), error);
   1735 }
   1736 
   1737 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, NonInteractiveSuccess) {
   1738 #if defined(OS_WIN) && defined(USE_ASH)
   1739   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
   1740   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
   1741     return;
   1742 #endif
   1743 
   1744   scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
   1745       new IdentityLaunchWebAuthFlowFunction());
   1746   scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
   1747   function->set_extension(empty_extension.get());
   1748 
   1749   function->InitFinalRedirectURLPrefixForTest("abcdefghij");
   1750   scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
   1751       function.get(),
   1752       "[{\"interactive\": false,"
   1753       "\"url\": \"https://abcdefghij.chromiumapp.org/callback#test\"}]",
   1754       browser()));
   1755 
   1756   std::string url;
   1757   EXPECT_TRUE(value->GetAsString(&url));
   1758   EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"),
   1759             url);
   1760 }
   1761 
   1762 IN_PROC_BROWSER_TEST_F(
   1763     LaunchWebAuthFlowFunctionTest, InteractiveFirstNavigationSuccess) {
   1764 #if defined(OS_WIN) && defined(USE_ASH)
   1765   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
   1766   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
   1767     return;
   1768 #endif
   1769 
   1770   scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
   1771       new IdentityLaunchWebAuthFlowFunction());
   1772   scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
   1773   function->set_extension(empty_extension.get());
   1774 
   1775   function->InitFinalRedirectURLPrefixForTest("abcdefghij");
   1776   scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
   1777       function.get(),
   1778       "[{\"interactive\": true,"
   1779       "\"url\": \"https://abcdefghij.chromiumapp.org/callback#test\"}]",
   1780       browser()));
   1781 
   1782   std::string url;
   1783   EXPECT_TRUE(value->GetAsString(&url));
   1784   EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"),
   1785             url);
   1786 }
   1787 
   1788 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest,
   1789                        DISABLED_InteractiveSecondNavigationSuccess) {
   1790   net::SpawnedTestServer https_server(
   1791       net::SpawnedTestServer::TYPE_HTTPS,
   1792       net::SpawnedTestServer::kLocalhost,
   1793       base::FilePath(FILE_PATH_LITERAL(
   1794           "chrome/test/data/extensions/api_test/identity")));
   1795   ASSERT_TRUE(https_server.Start());
   1796   GURL auth_url(https_server.GetURL("files/redirect_to_chromiumapp.html"));
   1797 
   1798   scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
   1799       new IdentityLaunchWebAuthFlowFunction());
   1800   scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
   1801   function->set_extension(empty_extension.get());
   1802 
   1803   function->InitFinalRedirectURLPrefixForTest("abcdefghij");
   1804   std::string args = "[{\"interactive\": true, \"url\": \"" +
   1805       auth_url.spec() + "\"}]";
   1806   scoped_ptr<base::Value> value(
   1807       utils::RunFunctionAndReturnSingleResult(function.get(), args, browser()));
   1808 
   1809   std::string url;
   1810   EXPECT_TRUE(value->GetAsString(&url));
   1811   EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"),
   1812             url);
   1813 }
   1814 
   1815 }  // namespace extensions
   1816 
   1817 // Tests the chrome.identity API implemented by custom JS bindings .
   1818 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ChromeIdentityJsBindings) {
   1819   ASSERT_TRUE(RunExtensionTest("identity/js_bindings")) << message_;
   1820 }
   1821