Index: chrome/browser/extensions/api/identity/web_auth_flow_unittest.cc |
=================================================================== |
--- chrome/browser/extensions/api/identity/web_auth_flow_unittest.cc (revision 0) |
+++ chrome/browser/extensions/api/identity/web_auth_flow_unittest.cc (revision 0) |
@@ -0,0 +1,259 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "base/message_loop.h" |
+#include "chrome/browser/extensions/api/identity/web_auth_flow.h" |
+#include "chrome/browser/ui/extensions/web_auth_flow_window.h" |
+#include "chrome/test/base/testing_profile.h" |
+#include "content/browser/web_contents/navigation_controller_impl.h" |
+#include "content/browser/web_contents/web_contents_impl.h" |
+#include "content/public/browser/invalidate_type.h" |
+#include "content/public/browser/navigation_controller.h" |
+#include "content/public/common/page_transition_types.h" |
+#include "content/public/common/referrer.h" |
+#include "testing/gmock/include/gmock/gmock.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+using content::BrowserContext; |
+using content::NavigationController; |
+using content::WebContents; |
+using content::WebContentsDelegate; |
+using extensions::WebAuthFlow; |
+using testing::Return; |
+using testing::ReturnRef; |
+ |
+namespace { |
+ |
+class MockDelegate : public WebAuthFlow::Delegate { |
+ public: |
+ MOCK_METHOD1(OnAuthFlowSuccess, void(const std::string& redirect_url)); |
+ MOCK_METHOD0(OnAuthFlowFailure, void()); |
+}; |
+ |
+class MockNavigationController : public NavigationControllerImpl { |
+ public: |
+ explicit MockNavigationController(BrowserContext* browser_context) |
+ : NavigationControllerImpl(NULL, browser_context, NULL) { |
+ } |
+ |
+ void LoadURL(const GURL& url, |
+ const content::Referrer& referrer, |
+ content::PageTransition type, |
+ const std::string& extra_headers) OVERRIDE { |
+ // Do nothing in tests. |
+ } |
+}; |
+ |
+class MockWebContents : public WebContentsImpl { |
+ public: |
+ explicit MockWebContents(BrowserContext* browser_context) |
+ : WebContentsImpl(browser_context, NULL, MSG_ROUTING_NONE, |
+ NULL, NULL, NULL), |
+ delegate_(NULL), |
+ controller_(browser_context) { } |
+ virtual ~MockWebContents() { } |
+ |
+ void SetDelegate(WebContentsDelegate* delegate) OVERRIDE { |
+ delegate_ = delegate; |
+ } |
+ |
+ NavigationController& GetController() OVERRIDE { |
+ return controller_; |
+ } |
+ |
+ const NavigationController& GetController() const OVERRIDE { |
+ return controller_; |
+ } |
+ |
+ MockNavigationController& mock_controller() { |
+ return controller_; |
+ } |
+ |
+ MOCK_CONST_METHOD0(GetURL, const GURL& ()); |
+ MOCK_CONST_METHOD0(IsLoading, bool ()); |
+ |
+ private: |
+ WebContentsDelegate* delegate_; |
+ MockNavigationController controller_; |
+}; |
+ |
+class MockWebAuthFlowWindow : public WebAuthFlowWindow { |
+ public: |
+ MockWebAuthFlowWindow() : WebAuthFlowWindow(NULL, NULL, NULL) { |
+ } |
+ |
+ virtual void Show() OVERRIDE { |
+ // Do nothing in tests. |
+ } |
+}; |
+ |
+class MockWebAuthFlow : public WebAuthFlow { |
+ public: |
+ MockWebAuthFlow( |
+ MockDelegate* delegate, |
+ BrowserContext* browser_context, |
+ const std::string& extension_id, |
+ const GURL& provider_url) |
+ : WebAuthFlow(delegate, |
+ browser_context, |
+ extension_id, |
+ provider_url), |
+ browser_context_(browser_context), |
+ web_contents(NULL), |
+ window_(NULL) { } |
+ |
+ virtual WebContents* CreateWebContents() OVERRIDE { |
+ web_contents = new MockWebContents(browser_context_); |
+ return web_contents; |
+ } |
+ |
+ virtual WebAuthFlowWindow* CreateAuthWindow() OVERRIDE { |
+ window_ = new MockWebAuthFlowWindow(); |
+ return window_; |
+ } |
+ |
+ MockWebContents& contents() { |
+ return *web_contents; |
+ } |
+ |
+ MockWebAuthFlowWindow& window() { |
+ return *window_; |
+ } |
+ |
+ bool HasWindow() const { |
+ return window_ != NULL; |
+ } |
+ |
+ virtual ~MockWebAuthFlow() { } |
+ |
+ private: |
+ BrowserContext* browser_context_; |
+ MockWebContents* web_contents; |
+ MockWebAuthFlowWindow* window_; |
+}; |
+ |
+} // namespace |
+ |
+class WebAuthFlowTest : public testing::Test { |
+ protected: |
+ void CreateAuthFlow(const std::string& extension_id, const GURL& url) { |
+ flow_.reset(new MockWebAuthFlow(&delegate_, &profile_, extension_id, url)); |
+ } |
+ |
+ MockWebAuthFlow& flow() { |
+ return *flow_.get(); |
+ } |
+ |
+ // Wrapper methods to call private methods of the WebAuthFlow. |
+ void CallLoadingStateChanged(bool loading) { |
+ EXPECT_CALL(flow_->contents(), IsLoading()).WillOnce(Return(loading)); |
+ flow_->LoadingStateChanged(&flow_->contents()); |
+ } |
+ void CallNavigationStateChanged(unsigned changed_flags) { |
+ flow_->NavigationStateChanged(&flow_->contents(), changed_flags); |
+ } |
+ bool CallIsValidRedirectUrl(const GURL& url) { |
+ return flow_->IsValidRedirectUrl(url); |
+ } |
+ void CallOnClose() { |
+ flow_->OnClose(); |
+ } |
+ |
+ ~WebAuthFlowTest() { |
+ // Delete flow_ before we run pending tasks in the message loop. |
+ flow_.reset(); |
+ // Finish running the message loop to run clean up tasks. |
+ message_loop_.RunAllPending(); |
+ } |
+ |
+ MessageLoop message_loop_; |
+ scoped_ptr<MockWebAuthFlow> flow_; |
+ MockDelegate delegate_; |
+ TestingProfile profile_; |
+}; |
+ |
+TEST_F(WebAuthFlowTest, SilentRedirectToChromiumAppUrl) { |
+ std::string ext_id = "abcdefghij"; |
+ GURL url("https://accounts.google.com/o/oauth2/auth"); |
+ GURL result("https://abcdefghij.chromiumapp.org/google_cb"); |
+ |
+ CreateAuthFlow(ext_id, url); |
+ EXPECT_CALL(delegate_, OnAuthFlowSuccess(result.spec())).Times(1); |
+ flow_->Start(); |
+ EXPECT_CALL(flow_->contents(), GetURL()).WillRepeatedly(ReturnRef(result)); |
+ |
+ CallNavigationStateChanged(content::INVALIDATE_TYPE_URL); |
+} |
+ |
+TEST_F(WebAuthFlowTest, SilentRedirectToChromeExtensionSchemeUrl) { |
+ std::string ext_id = "abcdefghij"; |
+ GURL url("https://accounts.google.com/o/oauth2/auth"); |
+ GURL result("chrome-extension://abcdefghij/google_cb"); |
+ |
+ CreateAuthFlow(ext_id, url); |
+ |
+ EXPECT_CALL(delegate_, OnAuthFlowSuccess(result.spec())).Times(1); |
+ flow_->Start(); |
+ EXPECT_CALL(flow_->contents(), GetURL()).WillRepeatedly(ReturnRef(result)); |
+ |
+ CallNavigationStateChanged(content::INVALIDATE_TYPE_URL); |
+} |
+ |
+TEST_F(WebAuthFlowTest, UIResultsInSuccess) { |
+ std::string ext_id = "abcdefghij"; |
+ GURL url("https://accounts.google.com/o/oauth2/auth"); |
+ GURL result("chrome-extension://abcdefghij/google_cb"); |
+ |
+ CreateAuthFlow(ext_id, url); |
+ |
+ EXPECT_CALL(delegate_, OnAuthFlowSuccess(result.spec())).Times(1); |
+ flow_->Start(); |
+ CallLoadingStateChanged(false); |
+ EXPECT_TRUE(flow_->HasWindow()); |
+ EXPECT_CALL(flow_->contents(), GetURL()).WillOnce(ReturnRef(result)); |
+ CallNavigationStateChanged(content::INVALIDATE_TYPE_URL); |
+} |
+ |
+TEST_F(WebAuthFlowTest, UIClosedByUser) { |
+ std::string ext_id = "abcdefghij"; |
+ GURL url("https://accounts.google.com/o/oauth2/auth"); |
+ GURL result("chrome-extension://abcdefghij/google_cb"); |
+ |
+ CreateAuthFlow(ext_id, url); |
+ |
+ EXPECT_CALL(delegate_, OnAuthFlowFailure()).Times(1); |
+ flow_->Start(); |
+ CallLoadingStateChanged(false); |
+ EXPECT_TRUE(flow_->HasWindow()); |
+ CallOnClose(); |
+} |
+ |
+TEST_F(WebAuthFlowTest, IsValidRedirectUrl) { |
+ std::string ext_id = "abcdefghij"; |
+ GURL url("https://accounts.google.com/o/oauth2/auth"); |
+ CreateAuthFlow(ext_id, url); |
+ |
+ // Positive cases. |
+ EXPECT_TRUE(CallIsValidRedirectUrl( |
+ GURL("https://abcdefghij.chromiumapp.org/"))); |
+ EXPECT_TRUE(CallIsValidRedirectUrl( |
+ GURL("https://abcdefghij.chromiumapp.org/callback"))); |
+ EXPECT_TRUE(CallIsValidRedirectUrl( |
+ GURL("chrome-extension://abcdefghij/"))); |
+ EXPECT_TRUE(CallIsValidRedirectUrl( |
+ GURL("chrome-extension://abcdefghij/callback"))); |
+ |
+ // Negative cases. |
+ EXPECT_FALSE(CallIsValidRedirectUrl( |
+ GURL("https://www.foo.com/"))); |
+ // http scheme is not allowed. |
+ EXPECT_FALSE(CallIsValidRedirectUrl( |
+ GURL("http://abcdefghij.chromiumapp.org/callback"))); |
+ EXPECT_FALSE(CallIsValidRedirectUrl( |
+ GURL("https://abcd.chromiumapp.org/callback"))); |
+ EXPECT_FALSE(CallIsValidRedirectUrl( |
+ GURL("chrome-extension://abcd/callback"))); |
+ EXPECT_FALSE(CallIsValidRedirectUrl( |
+ GURL("chrome-extension://abcdefghijkl/"))); |
+} |