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