Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(248)

Side by Side Diff: chrome/browser/extensions/api/identity/identity_apitest.cc

Issue 14270007: Identity API: getAuthToken request queues (token cache prelude) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@lkgr
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/string_util.h" 5 #include "base/string_util.h"
6 #include "base/stringprintf.h" 6 #include "base/stringprintf.h"
7 #include "base/values.h" 7 #include "base/values.h"
8 #include "chrome/browser/extensions/api/identity/identity_api.h" 8 #include "chrome/browser/extensions/api/identity/identity_api.h"
9 #include "chrome/browser/extensions/api/identity/web_auth_flow.h" 9 #include "chrome/browser/extensions/api/identity/web_auth_flow.h"
10 #include "chrome/browser/extensions/extension_apitest.h" 10 #include "chrome/browser/extensions/extension_apitest.h"
(...skipping 20 matching lines...) Expand all
31 31
32 namespace extensions { 32 namespace extensions {
33 33
34 namespace { 34 namespace {
35 35
36 namespace errors = identity_constants; 36 namespace errors = identity_constants;
37 namespace utils = extension_function_test_utils; 37 namespace utils = extension_function_test_utils;
38 38
39 static const char kAccessToken[] = "auth_token"; 39 static const char kAccessToken[] = "auth_token";
40 40
41 // This helps us be able to wait until an AsyncExtensionFunction calls
42 // SendResponse.
43 class SendResponseDelegate
44 : public UIThreadExtensionFunction::DelegateForTests {
45 public:
46 SendResponseDelegate() : should_post_quit_(false) {}
47
48 virtual ~SendResponseDelegate() {}
49
50 void set_should_post_quit(bool should_quit) {
51 should_post_quit_ = should_quit;
52 }
53
54 bool HasResponse() {
55 return response_.get() != NULL;
56 }
57
58 bool GetResponse() {
59 EXPECT_TRUE(HasResponse());
60 return *response_.get();
61 }
62
63 virtual void OnSendResponse(UIThreadExtensionFunction* function,
64 bool success,
65 bool bad_message) OVERRIDE {
66 ASSERT_FALSE(bad_message);
67 ASSERT_FALSE(HasResponse());
68 response_.reset(new bool);
69 *response_ = success;
70 if (should_post_quit_) {
71 MessageLoopForUI::current()->Quit();
72 }
73 }
74
75 private:
76 scoped_ptr<bool> response_;
77 bool should_post_quit_;
78 };
79
80 class AsyncExtensionBrowserTest : public ExtensionBrowserTest {
81 protected:
82 // Asynchronous function runner allows tests to manipulate the browser window
83 // after the call happens.
84 void RunFunctionAsync(
85 UIThreadExtensionFunction* function,
86 const std::string& args) {
87 response_delegate_.reset(new SendResponseDelegate);
88 function->set_test_delegate(response_delegate_.get());
89 scoped_ptr<base::ListValue> parsed_args(utils::ParseList(args));
90 EXPECT_TRUE(parsed_args.get()) <<
91 "Could not parse extension function arguments: " << args;
92 function->SetArgs(parsed_args.get());
93
94 if (!function->GetExtension()) {
95 scoped_refptr<Extension> empty_extension(
96 utils::CreateEmptyExtension());
97 function->set_extension(empty_extension.get());
98 }
99
100 function->set_profile(browser()->profile());
101 function->set_has_callback(true);
102 function->Run();
103 }
104
105 std::string WaitForError(UIThreadExtensionFunction* function) {
106 RunMessageLoopUntilResponse();
107 EXPECT_FALSE(function->GetResultList()) << "Did not expect a result";
108 return function->GetError();
109 }
110
111 base::Value* WaitForSingleResult(UIThreadExtensionFunction* function) {
112 RunMessageLoopUntilResponse();
113 EXPECT_TRUE(function->GetError().empty()) << "Unexpected error: "
114 << function->GetError();
115 const base::Value* single_result = NULL;
116 if (function->GetResultList() != NULL &&
117 function->GetResultList()->Get(0, &single_result)) {
118 return single_result->DeepCopy();
119 }
120 return NULL;
121 }
122
123 private:
124 void RunMessageLoopUntilResponse() {
125 // If the RunImpl of |function| didn't already call SendResponse, run the
126 // message loop until they do.
127 if (!response_delegate_->HasResponse()) {
128 response_delegate_->set_should_post_quit(true);
129 content::RunMessageLoop();
130 }
131 EXPECT_TRUE(response_delegate_->HasResponse());
132 }
133
134 scoped_ptr<SendResponseDelegate> response_delegate_;
135 };
136
41 class TestOAuth2MintTokenFlow : public OAuth2MintTokenFlow { 137 class TestOAuth2MintTokenFlow : public OAuth2MintTokenFlow {
42 public: 138 public:
43 enum ResultType { 139 enum ResultType {
44 ISSUE_ADVICE_SUCCESS, 140 ISSUE_ADVICE_SUCCESS,
45 MINT_TOKEN_SUCCESS, 141 MINT_TOKEN_SUCCESS,
46 MINT_TOKEN_FAILURE, 142 MINT_TOKEN_FAILURE,
47 MINT_TOKEN_BAD_CREDENTIALS 143 MINT_TOKEN_BAD_CREDENTIALS
48 }; 144 };
49 145
50 TestOAuth2MintTokenFlow(ResultType result, 146 TestOAuth2MintTokenFlow(ResultType result,
(...skipping 26 matching lines...) Expand all
77 break; 173 break;
78 } 174 }
79 } 175 }
80 } 176 }
81 177
82 private: 178 private:
83 ResultType result_; 179 ResultType result_;
84 OAuth2MintTokenFlow::Delegate* delegate_; 180 OAuth2MintTokenFlow::Delegate* delegate_;
85 }; 181 };
86 182
183 ProfileKeyedService* IdentityAPITestFactory(Profile* profile) {
184 return new IdentityAPI(profile);
185 }
186
87 } // namespace 187 } // namespace
88 188
89 class MockGetAuthTokenFunction : public IdentityGetAuthTokenFunction { 189 class MockGetAuthTokenFunction : public IdentityGetAuthTokenFunction {
90 public: 190 public:
91 MockGetAuthTokenFunction() : login_ui_result_(true), 191 MockGetAuthTokenFunction() : login_ui_result_(true),
92 install_ui_result_(false), 192 install_ui_result_(false),
93 login_ui_shown_(false), 193 login_ui_shown_(false),
94 install_ui_shown_(false) { 194 install_ui_shown_(false) {
95 } 195 }
96 196
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 OAuth2MintTokenFlow* (OAuth2MintTokenFlow::Mode mode)); 235 OAuth2MintTokenFlow* (OAuth2MintTokenFlow::Mode mode));
136 236
137 private: 237 private:
138 ~MockGetAuthTokenFunction() {} 238 ~MockGetAuthTokenFunction() {}
139 bool login_ui_result_; 239 bool login_ui_result_;
140 bool install_ui_result_; 240 bool install_ui_result_;
141 bool login_ui_shown_; 241 bool login_ui_shown_;
142 bool install_ui_shown_; 242 bool install_ui_shown_;
143 }; 243 };
144 244
145 class GetAuthTokenFunctionTest : public ExtensionBrowserTest { 245 class MockQueuedMintRequest : public IdentityMintRequestQueue::Request {
246 public:
247 MOCK_METHOD1(StartMintToken, void(IdentityMintRequestQueue::MintType));
248 };
249
250 class GetAuthTokenFunctionTest : public AsyncExtensionBrowserTest {
146 protected: 251 protected:
147 enum OAuth2Fields { 252 enum OAuth2Fields {
148 NONE = 0, 253 NONE = 0,
149 CLIENT_ID = 1, 254 CLIENT_ID = 1,
150 SCOPES = 2 255 SCOPES = 2
151 }; 256 };
152 257
153 virtual ~GetAuthTokenFunctionTest() {} 258 virtual ~GetAuthTokenFunctionTest() {}
154 259
260 virtual void SetUp() OVERRIDE {
261 AsyncExtensionBrowserTest::SetUp();
262 IdentityAPI::GetFactoryInstance()->SetTestingFactory(
263 browser()->profile(), &IdentityAPITestFactory);
264 }
265
155 // Helper to create an extension with specific OAuth2Info fields set. 266 // Helper to create an extension with specific OAuth2Info fields set.
156 // |fields_to_set| should be computed by using fields of Oauth2Fields enum. 267 // |fields_to_set| should be computed by using fields of Oauth2Fields enum.
157 const Extension* CreateExtension(int fields_to_set) { 268 const Extension* CreateExtension(int fields_to_set) {
158 const Extension* ext = LoadExtension( 269 const Extension* ext = LoadExtension(
159 test_data_dir_.AppendASCII("platform_apps/oauth2")); 270 test_data_dir_.AppendASCII("platform_apps/oauth2"));
160 OAuth2Info& oauth2_info = const_cast<OAuth2Info&>( 271 OAuth2Info& oauth2_info = const_cast<OAuth2Info&>(
161 OAuth2Info::GetOAuth2Info(ext)); 272 OAuth2Info::GetOAuth2Info(ext));
162 if ((fields_to_set & CLIENT_ID) != 0) 273 if ((fields_to_set & CLIENT_ID) != 0)
163 oauth2_info.client_id = "client1"; 274 oauth2_info.client_id = "client1";
164 if ((fields_to_set & SCOPES) != 0) { 275 if ((fields_to_set & SCOPES) != 0) {
(...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after
454 .WillOnce(Return(flow2)); 565 .WillOnce(Return(flow2));
455 566
456 func->set_install_ui_result(true); 567 func->set_install_ui_result(true);
457 std::string error = utils::RunFunctionAndReturnError( 568 std::string error = utils::RunFunctionAndReturnError(
458 func.get(), "[{\"interactive\": true}]", browser()); 569 func.get(), "[{\"interactive\": true}]", browser());
459 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false)); 570 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
460 EXPECT_FALSE(func->login_ui_shown()); 571 EXPECT_FALSE(func->login_ui_shown());
461 EXPECT_TRUE(func->install_ui_shown()); 572 EXPECT_TRUE(func->install_ui_shown());
462 } 573 }
463 574
464 // This helps us be able to wait until an AsyncExtensionFunction calls 575 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, NoninteractiveQueue) {
465 // SendResponse. 576 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
466 class SendResponseDelegate 577 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
467 : public UIThreadExtensionFunction::DelegateForTests { 578 func->set_extension(extension);
468 public:
469 SendResponseDelegate() : should_post_quit_(false) {}
470 579
471 virtual ~SendResponseDelegate() {} 580 // Create a fake request to block the queue.
581 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension);
582 std::set<std::string> scopes(oauth2_info.scopes.begin(),
583 oauth2_info.scopes.end());
584 IdentityAPI* id_api =
585 extensions::IdentityAPI::GetFactoryInstance()->GetForProfile(
586 browser()->profile());
587 IdentityMintRequestQueue* queue = id_api->mint_queue();
588 MockQueuedMintRequest queued_request;
589 IdentityMintRequestQueue::MintType type =
590 IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE;
472 591
473 void set_should_post_quit(bool should_quit) { 592 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
474 should_post_quit_ = should_quit; 593 queue->RequestStart(type, extension->id(), scopes, &queued_request);
475 }
476 594
477 bool HasResponse() { 595 // The real request will start processing, but wait in the queue behind
478 return response_.get() != NULL; 596 // the blocker.
479 } 597 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true));
598 RunFunctionAsync(func, "[{}]");
599 // Verify that we have fetched the login token at this point.
600 testing::Mock::VerifyAndClearExpectations(func);
480 601
481 bool GetResponse() { 602 // The flow will be created after the first queued request clears.
482 EXPECT_TRUE(HasResponse()); 603 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
483 return *response_.get(); 604 TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get());
484 } 605 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
485 606
486 virtual void OnSendResponse(UIThreadExtensionFunction* function, 607 queue->RequestComplete(type, extension->id(), scopes, &queued_request);
487 bool success,
488 bool bad_message) OVERRIDE {
489 ASSERT_FALSE(bad_message);
490 ASSERT_FALSE(HasResponse());
491 response_.reset(new bool);
492 *response_ = success;
493 if (should_post_quit_) {
494 MessageLoopForUI::current()->Quit();
495 }
496 }
497 608
498 private: 609 scoped_ptr<base::Value> value(WaitForSingleResult(func));
499 scoped_ptr<bool> response_; 610 std::string access_token;
500 bool should_post_quit_; 611 EXPECT_TRUE(value->GetAsString(&access_token));
501 }; 612 EXPECT_EQ(std::string(kAccessToken), access_token);
613 EXPECT_FALSE(func->login_ui_shown());
614 EXPECT_FALSE(func->install_ui_shown());
615 }
502 616
503 class LaunchWebAuthFlowFunctionTest : public ExtensionBrowserTest { 617 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, InteractiveQueue) {
618 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
619 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
620 func->set_extension(extension);
621
622 // Create a fake request to block the queue.
623 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension);
624 std::set<std::string> scopes(oauth2_info.scopes.begin(),
625 oauth2_info.scopes.end());
626 IdentityAPI* id_api =
627 extensions::IdentityAPI::GetFactoryInstance()->GetForProfile(
628 browser()->profile());
629 IdentityMintRequestQueue* queue = id_api->mint_queue();
630 MockQueuedMintRequest queued_request;
631 IdentityMintRequestQueue::MintType type =
632 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
633
634 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
635 queue->RequestStart(type, extension->id(), scopes, &queued_request);
636
637 // The real request will start processing, but wait in the queue behind
638 // the blocker.
639 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true));
640 TestOAuth2MintTokenFlow* flow1 = new TestOAuth2MintTokenFlow(
641 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
642 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow1));
643 RunFunctionAsync(func, "[{\"interactive\": true}]");
644 // Verify that we have fetched the login token and run the first flow.
645 testing::Mock::VerifyAndClearExpectations(func);
646 EXPECT_FALSE(func->install_ui_shown());
647
648 // The UI will be displayed and the second flow will be created
649 // after the first queued request clears.
650 func->set_install_ui_result(true);
651 TestOAuth2MintTokenFlow* flow2 = new TestOAuth2MintTokenFlow(
652 TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get());
653 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow2));
654
655 queue->RequestComplete(type, extension->id(), scopes, &queued_request);
656
657 scoped_ptr<base::Value> value(WaitForSingleResult(func));
658 std::string access_token;
659 EXPECT_TRUE(value->GetAsString(&access_token));
660 EXPECT_EQ(std::string(kAccessToken), access_token);
661 EXPECT_FALSE(func->login_ui_shown());
662 EXPECT_TRUE(func->install_ui_shown());
663 }
664
665 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
666 InteractiveQueuedNoninteractiveFails) {
667 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
668 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
669 func->set_extension(extension);
670
671 // Create a fake request to block the interactive queue.
672 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension);
673 std::set<std::string> scopes(oauth2_info.scopes.begin(),
674 oauth2_info.scopes.end());
675 IdentityAPI* id_api =
676 extensions::IdentityAPI::GetFactoryInstance()->GetForProfile(
677 browser()->profile());
678 IdentityMintRequestQueue* queue = id_api->mint_queue();
679 MockQueuedMintRequest queued_request;
680 IdentityMintRequestQueue::MintType type =
681 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
682
683 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
684 queue->RequestStart(type, extension->id(), scopes, &queued_request);
685
686 // Non-interactive requests fail without hitting GAIA, because a
687 // consent UI is known to be up.
688 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true));
689 std::string error = utils::RunFunctionAndReturnError(
690 func.get(), "[{}]", browser());
691 EXPECT_EQ(std::string(errors::kNoGrant), error);
692 EXPECT_FALSE(func->login_ui_shown());
693 EXPECT_FALSE(func->install_ui_shown());
694
695 queue->RequestComplete(type, extension->id(), scopes, &queued_request);
696 }
697
698 class LaunchWebAuthFlowFunctionTest : public AsyncExtensionBrowserTest {
504 protected: 699 protected:
505 void RunAndCheckBounds( 700 void RunAndCheckBounds(
506 const std::string& extra_params, 701 const std::string& extra_params,
507 int expected_x, 702 int expected_x,
508 int expected_y, 703 int expected_y,
509 int expected_width, 704 int expected_width,
510 int expected_height) { 705 int expected_height) {
511 content::WindowedNotificationObserver observer( 706 content::WindowedNotificationObserver observer(
512 chrome::NOTIFICATION_BROWSER_WINDOW_READY, 707 chrome::NOTIFICATION_BROWSER_WINDOW_READY,
513 content::NotificationService::AllSources()); 708 content::NotificationService::AllSources());
(...skipping 13 matching lines...) Expand all
527 Browser* web_auth_flow_browser = 722 Browser* web_auth_flow_browser =
528 content::Source<Browser>(observer.source()).ptr(); 723 content::Source<Browser>(observer.source()).ptr();
529 EXPECT_EQ(expected_x, web_auth_flow_browser->override_bounds().x()); 724 EXPECT_EQ(expected_x, web_auth_flow_browser->override_bounds().x());
530 EXPECT_EQ(expected_y, web_auth_flow_browser->override_bounds().y()); 725 EXPECT_EQ(expected_y, web_auth_flow_browser->override_bounds().y());
531 EXPECT_EQ(expected_width, web_auth_flow_browser->override_bounds().width()); 726 EXPECT_EQ(expected_width, web_auth_flow_browser->override_bounds().width());
532 EXPECT_EQ( 727 EXPECT_EQ(
533 expected_height, web_auth_flow_browser->override_bounds().height()); 728 expected_height, web_auth_flow_browser->override_bounds().height());
534 729
535 web_auth_flow_browser->window()->Close(); 730 web_auth_flow_browser->window()->Close();
536 } 731 }
537
538 // Asynchronous function runner allows tests to manipulate the browser window
539 // after the call happens.
540 void RunFunctionAsync(
541 UIThreadExtensionFunction* function,
542 const std::string& args) {
543 response_delegate_.reset(new SendResponseDelegate);
544 function->set_test_delegate(response_delegate_.get());
545 scoped_ptr<base::ListValue> parsed_args(utils::ParseList(args));
546 EXPECT_TRUE(parsed_args.get()) <<
547 "Could not parse extension function arguments: " << args;
548 function->SetArgs(parsed_args.get());
549
550 scoped_refptr<Extension> empty_extension(
551 utils::CreateEmptyExtension());
552 function->set_extension(empty_extension.get());
553
554 function->set_profile(browser()->profile());
555 function->set_has_callback(true);
556 function->Run();
557 }
558
559 std::string WaitForError(UIThreadExtensionFunction* function) {
560 // If the RunImpl of |function| didn't already call SendResponse, run the
561 // message loop until they do.
562 if (!response_delegate_->HasResponse()) {
563 response_delegate_->set_should_post_quit(true);
564 content::RunMessageLoop();
565 }
566
567 EXPECT_TRUE(response_delegate_->HasResponse());
568 return function->GetError();
569 }
570
571 private:
572 scoped_ptr<SendResponseDelegate> response_delegate_;
573 }; 732 };
574 733
575 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, Bounds) { 734 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, Bounds) {
576 RunAndCheckBounds(std::string(), 0, 0, 0, 0); 735 RunAndCheckBounds(std::string(), 0, 0, 0, 0);
577 RunAndCheckBounds("\"width\": 100, \"height\": 200", 0, 0, 100, 200); 736 RunAndCheckBounds("\"width\": 100, \"height\": 200", 0, 0, 100, 200);
578 RunAndCheckBounds("\"left\": 100, \"top\": 200", 100, 200, 0, 0); 737 RunAndCheckBounds("\"left\": 100, \"top\": 200", 100, 200, 0, 0);
579 RunAndCheckBounds( 738 RunAndCheckBounds(
580 "\"left\": 100, \"top\": 200, \"width\": 300, \"height\": 400", 739 "\"left\": 100, \"top\": 200, \"width\": 300, \"height\": 400",
581 100, 200, 300, 400); 740 100, 200, 300, 400);
582 } 741 }
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
700 "https://abcdefghij.chromiumapp.org/callback#test')</script>\"}]", 859 "https://abcdefghij.chromiumapp.org/callback#test')</script>\"}]",
701 browser())); 860 browser()));
702 861
703 std::string url; 862 std::string url;
704 EXPECT_TRUE(value->GetAsString(&url)); 863 EXPECT_TRUE(value->GetAsString(&url));
705 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"), 864 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"),
706 url); 865 url);
707 } 866 }
708 867
709 } // namespace extensions 868 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698