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