• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
SendResponseDelegate()69   SendResponseDelegate() : should_post_quit_(false) {}
70 
~SendResponseDelegate()71   virtual ~SendResponseDelegate() {}
72 
set_should_post_quit(bool should_quit)73   void set_should_post_quit(bool should_quit) {
74     should_post_quit_ = should_quit;
75   }
76 
HasResponse()77   bool HasResponse() {
78     return response_.get() != NULL;
79   }
80 
GetResponse()81   bool GetResponse() {
82     EXPECT_TRUE(HasResponse());
83     return *response_.get();
84   }
85 
OnSendResponse(UIThreadExtensionFunction * function,bool success,bool bad_message)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.
RunFunctionAsync(UIThreadExtensionFunction * function,const std::string & args)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 
WaitForError(UIThreadExtensionFunction * function)128   std::string WaitForError(UIThreadExtensionFunction* function) {
129     RunMessageLoopUntilResponse();
130     EXPECT_FALSE(function->GetResultList()) << "Did not expect a result";
131     return function->GetError();
132   }
133 
WaitForSingleResult(UIThreadExtensionFunction * function)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:
RunMessageLoopUntilResponse()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:
TestHangOAuth2MintTokenFlow()162   TestHangOAuth2MintTokenFlow()
163       : OAuth2MintTokenFlow(NULL, NULL, OAuth2MintTokenFlow::Parameters()) {}
164 
Start()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 
TestOAuth2MintTokenFlow(ResultType result,OAuth2MintTokenFlow::Delegate * delegate)180   TestOAuth2MintTokenFlow(ResultType result,
181                           OAuth2MintTokenFlow::Delegate* delegate)
182     : OAuth2MintTokenFlow(NULL, delegate, OAuth2MintTokenFlow::Parameters()),
183       result_(result),
184       delegate_(delegate) {
185   }
186 
Start()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:
WaitForGURLAndCloseWindow(GURL url)228   explicit WaitForGURLAndCloseWindow(GURL url)
229       : WindowedNotificationObserver(
230             content::NOTIFICATION_LOAD_STOP,
231             content::NotificationService::AllSources()),
232         url_(url) {}
233 
234   // NotificationObserver:
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)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.)
CloseEmbedderWebContents()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:
MockGetAuthTokenFunction()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 
set_login_access_token_result(bool result)279   void set_login_access_token_result(bool result) {
280     login_access_token_result_ = result;
281   }
282 
set_login_ui_result(bool result)283   void set_login_ui_result(bool result) {
284     login_ui_result_ = result;
285   }
286 
set_scope_ui_failure(GaiaWebAuthFlow::Failure failure)287   void set_scope_ui_failure(GaiaWebAuthFlow::Failure failure) {
288     scope_ui_result_ = false;
289     scope_ui_failure_ = failure;
290   }
291 
set_scope_ui_oauth_error(const std::string & oauth_error)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 
login_ui_shown() const298   bool login_ui_shown() const {
299     return login_ui_shown_;
300   }
301 
scope_ui_shown() const302   bool scope_ui_shown() const {
303     return scope_ui_shown_;
304   }
305 
extension_token_key()306   const ExtensionTokenKey* extension_token_key() { return token_key_.get(); }
307 
StartLoginAccessTokenRequest()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 
ShowLoginPopup()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 
ShowOAuthApprovalDialog(const IssueAdviceInfo & issue_advice)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:
~MockGetAuthTokenFunction()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:
FakeGetAuthTokenFunction()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 
set_login_access_token_result(bool result)370   void set_login_access_token_result(bool result) {
371     login_access_token_result_ = result;
372   }
373 
set_login_ui_result(bool result)374   void set_login_ui_result(bool result) { login_ui_result_ = result; }
375 
set_mint_token_flow(scoped_ptr<OAuth2MintTokenFlow> flow)376   void set_mint_token_flow(scoped_ptr<OAuth2MintTokenFlow> flow) {
377     flow_ = flow.Pass();
378   }
379 
set_scope_ui_failure(GaiaWebAuthFlow::Failure failure)380   void set_scope_ui_failure(GaiaWebAuthFlow::Failure failure) {
381     scope_ui_result_ = false;
382     scope_ui_failure_ = failure;
383   }
384 
set_scope_ui_oauth_error(const std::string & oauth_error)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 
login_ui_shown() const391   bool login_ui_shown() const { return login_ui_shown_; }
392 
scope_ui_shown() const393   bool scope_ui_shown() const { return scope_ui_shown_; }
394 
login_access_token() const395   std::string login_access_token() const { return login_access_token_; }
396 
ShowLoginPopup()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 
ShowOAuthApprovalDialog(const IssueAdviceInfo & issue_advice)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 
CreateMintTokenFlow(const std::string & login_access_token)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:
~FakeGetAuthTokenFunction()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 
CreateIds(std::string email,std::string obfid)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 {
SetUpCommandLine(CommandLine * command_line)457   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
458     ExtensionBrowserTest::SetUpCommandLine(command_line);
459     command_line->AppendSwitch(switches::kExtensionsMultiAccount);
460   }
461 
462  protected:
SetAccountState(AccountIds ids,bool is_signed_in)463   void SetAccountState(AccountIds ids, bool is_signed_in) {
464     IdentityAPI::GetFactoryInstance()->Get(profile())->SetAccountStateForTest(
465         ids, is_signed_in);
466   }
467 
ExpectGetAccounts(const std::vector<std::string> & accounts)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 
GenerateFailureResult(const::std::vector<std::string> & accounts,const base::ListValue * results)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 
IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest,MultiAccountOn)542 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, MultiAccountOn) {
543   EXPECT_TRUE(switches::IsExtensionsMultiAccount());
544 }
545 
IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest,NoneSignedIn)546 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, NoneSignedIn) {
547   EXPECT_TRUE(ExpectGetAccounts(std::vector<std::string>()));
548 }
549 
IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest,PrimaryAccountSignedIn)550 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest,
551                        PrimaryAccountSignedIn) {
552   SetAccountState(CreateIds("primary@example.com", "1"), true);
553   std::vector<std::string> primary;
554   primary.push_back("1");
555   EXPECT_TRUE(ExpectGetAccounts(primary));
556 }
557 
IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest,TwoAccountsSignedIn)558 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, TwoAccountsSignedIn) {
559   SetAccountState(CreateIds("primary@example.com", "1"), true);
560   SetAccountState(CreateIds("secondary@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 {
SetUpCommandLine(CommandLine * command_line)569   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
570     // Don't add the multi-account switch that parent class would have.
571   }
572 };
573 
IN_PROC_BROWSER_TEST_F(IdentityOldProfilesGetAccountsFunctionTest,MultiAccountOff)574 IN_PROC_BROWSER_TEST_F(IdentityOldProfilesGetAccountsFunctionTest,
575                        MultiAccountOff) {
576   EXPECT_FALSE(switches::IsExtensionsMultiAccount());
577 }
578 
IN_PROC_BROWSER_TEST_F(IdentityOldProfilesGetAccountsFunctionTest,TwoAccountsSignedIn)579 IN_PROC_BROWSER_TEST_F(IdentityOldProfilesGetAccountsFunctionTest,
580                        TwoAccountsSignedIn) {
581   SetAccountState(CreateIds("primary@example.com", "1"), true);
582   SetAccountState(CreateIds("secondary@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:
RunGetProfileUserInfo()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 
RunGetProfileUserInfoWithEmail()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:
CreateExtensionWithEmailPermission()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 
IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest,NotSignedIn)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 
IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest,SignedIn)625 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest, SignedIn) {
626   profile()->GetPrefs()
627       ->SetString(prefs::kGoogleServicesUsername, "president@example.com");
628   profile()->GetPrefs()
629       ->SetString(prefs::kGoogleServicesUserAccountId, "12345");
630 
631   scoped_ptr<api::identity::ProfileUserInfo> info =
632       RunGetProfileUserInfoWithEmail();
633   EXPECT_EQ("president@example.com", info->email);
634   EXPECT_EQ("12345", info->id);
635 }
636 
IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest,NotSignedInNoEmail)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 
IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest,SignedInNoEmail)644 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest,
645                        SignedInNoEmail) {
646   profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
647                                    "president@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:
SetUpCommandLine(CommandLine * command_line)658   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
659     AsyncExtensionBrowserTest::SetUpCommandLine(command_line);
660     command_line->AppendSwitch(switches::kExtensionsMultiAccount);
661   }
662 
SetUpInProcessBrowserTestFixture()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 
OnWillCreateBrowserContextServices(content::BrowserContext * context)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 
SetUpOnMainThread()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 
SignIn(const std::string account_key)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 
SetAccountState(AccountIds ids,bool is_signed_in)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 
~GetAuthTokenFunctionTest()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.
CreateExtension(int fields_to_set)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 
id_api()751   IdentityAPI* id_api() {
752     return IdentityAPI::GetFactoryInstance()->Get(browser()->profile());
753   }
754 
GetPrimaryAccountId()755   const std::string GetPrimaryAccountId() {
756     SigninManagerBase* signin_manager =
757         SigninManagerFactory::GetForProfile(browser()->profile());
758     return signin_manager->GetAuthenticatedAccountId();
759   }
760 
SetCachedToken(const IdentityTokenCacheValue & token_data)761   void SetCachedToken(const IdentityTokenCacheValue& token_data) {
762     ExtensionTokenKey key(extension_id_, GetPrimaryAccountId(), oauth_scopes_);
763     id_api()->SetCachedToken(key, token_data);
764   }
765 
GetCachedToken(std::string account_id)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 
QueueRequestStart(IdentityMintRequestQueue::MintType type,IdentityMintRequestQueue::Request * request)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 
QueueRequestComplete(IdentityMintRequestQueue::MintType type,IdentityMintRequestQueue::Request * request)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NoClientId)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NoScopes)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NonInteractiveNotSignedIn)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NonInteractiveMintFailure)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NonInteractiveLoginAccessTokenFailure)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NonInteractiveMintAdviceSuccess)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NonInteractiveMintBadCredentials)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NonInteractiveMintServiceError)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NoOptionsSuccess)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NonInteractiveSuccess)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveLoginCanceled)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveMintBadCredentialsLoginCanceled)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveLoginSuccessNoToken)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveLoginSuccessMintFailure)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveLoginSuccessLoginAccessTokenFailure)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveLoginSuccessMintSuccess)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveLoginSuccessApprovalAborted)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveLoginSuccessApprovalSuccess)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveApprovalAborted)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveApprovalLoadFailed)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveApprovalInvalidRedirect)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveApprovalConnectionFailure)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveApprovalOAuthErrors)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveApprovalSuccess)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NoninteractiveQueue)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveQueue)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveQueueShutdown)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NoninteractiveShutdown)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveQueuedNoninteractiveFails)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NonInteractiveCacheHit)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NonInteractiveIssueAdviceCacheHit)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveCacheHit)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,LoginInvalidatesTokenCache)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,ComponentWithChromeClientId)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,ComponentWithNormalClientId)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,MultiDefaultUser)1499 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiDefaultUser) {
1500   SignIn("primary@example.com");
1501   token_service_->IssueRefreshTokenForUser("primary@example.com",
1502                                            "refresh_token");
1503   SetAccountState(CreateIds("primary@example.com", "1"), true);
1504   SetAccountState(CreateIds("secondary@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@example.com",
1517       "access_token-primary@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@example.com", func->login_access_token());
1527 }
1528 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,MultiPrimaryUser)1529 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiPrimaryUser) {
1530   SignIn("primary@example.com");
1531   token_service_->IssueRefreshTokenForUser("primary@example.com",
1532                                            "refresh_token");
1533   SetAccountState(CreateIds("primary@example.com", "1"), true);
1534   SetAccountState(CreateIds("secondary@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@example.com",
1547       "access_token-primary@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@example.com", func->login_access_token());
1557 }
1558 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,MultiSecondaryUser)1559 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiSecondaryUser) {
1560   SignIn("primary@example.com");
1561   token_service_->IssueRefreshTokenForUser("secondary@example.com",
1562                                            "refresh_token");
1563   SetAccountState(CreateIds("primary@example.com", "1"), true);
1564   SetAccountState(CreateIds("secondary@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@example.com",
1577       "access_token-secondary@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@example.com").status());
1586   EXPECT_EQ("access_token-secondary@example.com", func->login_access_token());
1587 }
1588 
1589 // TODO(courage): negative cases for secondary accounts
1590 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,ScopesDefault)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,ScopesEmpty)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,ScopesEmail)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 
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,ScopesEmailFooBar)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:
InvalidateDefaultToken()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 
id_api()1675   IdentityAPI* id_api() {
1676     return IdentityAPI::GetFactoryInstance()->Get(browser()->profile());
1677   }
1678 
SetCachedToken(IdentityTokenCacheValue & token_data)1679   void SetCachedToken(IdentityTokenCacheValue& token_data) {
1680     ExtensionTokenKey key(extensions::id_util::GenerateId(kExtensionId),
1681                           "test@example.com",
1682                           std::set<std::string>());
1683     id_api()->SetCachedToken(key, token_data);
1684   }
1685 
GetCachedToken()1686   const IdentityTokenCacheValue& GetCachedToken() {
1687     return id_api()->GetCachedToken(
1688         ExtensionTokenKey(extensions::id_util::GenerateId(kExtensionId),
1689                           "test@example.com",
1690                           std::set<std::string>()));
1691   }
1692 };
1693 
IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest,NotFound)1694 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, NotFound) {
1695   EXPECT_TRUE(InvalidateDefaultToken());
1696   EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND,
1697             GetCachedToken().status());
1698 }
1699 
IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest,Advice)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 
IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest,NonMatchingToken)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 
IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest,MatchingToken)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:
SetUpCommandLine(CommandLine * command_line)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 
IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest,UserCloseWindow)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 
IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest,InteractionRequired)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 
IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest,LoadFailed)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 
IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest,NonInteractiveSuccess)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 
IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest,InteractiveFirstNavigationSuccess)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 
IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest,DISABLED_InteractiveSecondNavigationSuccess)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 .
IN_PROC_BROWSER_TEST_F(ExtensionApiTest,ChromeIdentityJsBindings)1896 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ChromeIdentityJsBindings) {
1897   ASSERT_TRUE(RunExtensionTest("identity/js_bindings")) << message_;
1898 }
1899