Index: chrome/browser/ui/login/login_prompt_browsertest.cc |
diff --git a/chrome/browser/ui/login/login_prompt_browsertest.cc b/chrome/browser/ui/login/login_prompt_browsertest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ef5d37b9b2f45cb1f17afea0bea2ed3ff4898490 |
--- /dev/null |
+++ b/chrome/browser/ui/login/login_prompt_browsertest.cc |
@@ -0,0 +1,346 @@ |
+// Copyright (c) 2011 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 <algorithm> |
+#include <list> |
+#include <map> |
+ |
+#include "chrome/browser/browser_thread.h" |
+#include "chrome/browser/ui/browser.h" |
+#include "chrome/browser/ui/login/login_prompt.h" |
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
+#include "chrome/common/notification_service.h" |
+#include "chrome/test/in_process_browser_test.h" |
+#include "chrome/test/ui_test_utils.h" |
+#include "net/base/auth.h" |
+ |
+namespace { |
+ |
+class LoginPromptBrowserTest : public InProcessBrowserTest { |
+ public: |
+ LoginPromptBrowserTest() |
+ : bad_password_(L"incorrect"), bad_username_(L"nouser") { |
+ set_show_window(true); |
+ |
+ auth_map_[L"foo"] = AuthInfo(L"testuser", L"foopassword"); |
+ auth_map_[L"bar"] = AuthInfo(L"testuser", L"barpassword"); |
+ } |
+ |
+ protected: |
+ void SetAuthFor(LoginHandler* handler); |
+ |
+ struct AuthInfo { |
+ std::wstring username_; |
+ std::wstring password_; |
+ |
+ AuthInfo() {} |
+ |
+ AuthInfo(const std::wstring username, |
+ const std::wstring password) |
+ : username_(username), password_(password) {} |
+ }; |
+ |
+ std::map<std::wstring, AuthInfo> auth_map_; |
+ std::wstring bad_password_; |
+ std::wstring bad_username_; |
+}; |
+ |
+void LoginPromptBrowserTest::SetAuthFor(LoginHandler* handler) { |
+ const net::AuthChallengeInfo* challenge = handler->auth_info(); |
+ |
+ ASSERT_TRUE(challenge); |
+ std::map<std::wstring, AuthInfo>::iterator i = |
+ auth_map_.find(challenge->realm); |
+ EXPECT_TRUE(auth_map_.end() != i); |
+ if (i != auth_map_.end()) { |
+ const AuthInfo& info = i->second; |
+ handler->SetAuth(info.username_, info.password_); |
+ } |
+} |
+ |
+// Maintains a set of LoginHandlers that are currently active and |
+// keeps a count of the notifications that were observed. |
+class LoginPromptBrowserTestObserver : public NotificationObserver { |
+ public: |
+ LoginPromptBrowserTestObserver() |
+ : auth_needed_count_(0), |
+ auth_supplied_count_(0), |
+ auth_cancelled_count_(0) {} |
+ |
+ virtual void Observe(NotificationType type, |
+ const NotificationSource& source, |
+ const NotificationDetails& details); |
+ |
+ void AddHandler(LoginHandler* handler); |
+ |
+ void RemoveHandler(LoginHandler* handler); |
+ |
+ void Register(const NotificationSource& source); |
+ |
+ std::list<LoginHandler*> handlers_; |
+ |
+ // The exact number of notifications we receive is depedent on the |
+ // number of requests that were dispatched and is subject to a |
+ // number of factors that we don't directly control here. The |
+ // values below should only be used qualitatively. |
+ int auth_needed_count_; |
+ int auth_supplied_count_; |
+ int auth_cancelled_count_; |
+ |
+ private: |
+ NotificationRegistrar registrar_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(LoginPromptBrowserTestObserver); |
+}; |
+ |
+void LoginPromptBrowserTestObserver::Observe( |
+ NotificationType type, |
+ const NotificationSource& source, |
+ const NotificationDetails& details) { |
+ if (type == NotificationType::AUTH_NEEDED) { |
+ LoginNotificationDetails* login_details = |
+ Details<LoginNotificationDetails>(details).ptr(); |
+ AddHandler(login_details->handler()); |
+ auth_needed_count_++; |
+ } else if (type == NotificationType::AUTH_SUPPLIED) { |
+ AuthSuppliedLoginNotificationDetails* login_details = |
+ Details<AuthSuppliedLoginNotificationDetails>(details).ptr(); |
+ RemoveHandler(login_details->handler()); |
+ auth_supplied_count_++; |
+ } else if (type == NotificationType::AUTH_CANCELLED) { |
+ LoginNotificationDetails* login_details = |
+ Details<LoginNotificationDetails>(details).ptr(); |
+ RemoveHandler(login_details->handler()); |
+ auth_cancelled_count_++; |
+ } |
+} |
+ |
+void LoginPromptBrowserTestObserver::AddHandler(LoginHandler* handler) { |
+ std::list<LoginHandler*>::iterator i = std::find(handlers_.begin(), |
+ handlers_.end(), |
+ handler); |
+ EXPECT_TRUE(i == handlers_.end()); |
+ if (i == handlers_.end()) |
+ handlers_.push_back(handler); |
+} |
+ |
+void LoginPromptBrowserTestObserver::RemoveHandler(LoginHandler* handler) { |
+ std::list<LoginHandler*>::iterator i = std::find(handlers_.begin(), |
+ handlers_.end(), |
+ handler); |
+ EXPECT_TRUE(i != handlers_.end()); |
+ if (i != handlers_.end()) |
+ handlers_.erase(i); |
+} |
+ |
+void LoginPromptBrowserTestObserver::Register( |
+ const NotificationSource& source) { |
+ registrar_.Add(this, NotificationType::AUTH_NEEDED, source); |
+ registrar_.Add(this, NotificationType::AUTH_SUPPLIED, source); |
+ registrar_.Add(this, NotificationType::AUTH_CANCELLED, source); |
+} |
+ |
+template <NotificationType::Type T> |
+class WindowedNavigationObserver |
+ : public ui_test_utils::WindowedNotificationObserver { |
+ public: |
+ explicit WindowedNavigationObserver(NavigationController* controller) |
+ : ui_test_utils::WindowedNotificationObserver( |
+ T, Source<NavigationController>(controller)) {} |
+}; |
+ |
+typedef WindowedNavigationObserver<NotificationType::LOAD_STOP> |
+ WindowedLoadStopObserver; |
+ |
+typedef WindowedNavigationObserver<NotificationType::AUTH_NEEDED> |
+ WindowedAuthNeededObserver; |
+ |
+typedef WindowedNavigationObserver<NotificationType::AUTH_CANCELLED> |
+ WindowedAuthCancelledObserver; |
+ |
+typedef WindowedNavigationObserver<NotificationType::AUTH_SUPPLIED> |
+ WindowedAuthSuppliedObserver; |
+ |
+const char* kMultiRealmTestPage = "files/login/multi_realm.html"; |
+const int kMultiRealmTestRealmCount = 2; |
+const int kMultiRealmTestResourceCount = 4; |
+ |
+const char* kSingleRealmTestPage = "files/login/single_realm.html"; |
+const int kSingleRealmTestResourceCount = 6; |
+ |
+// Test handling of resources that require authentication even though |
+// the page they are included on doesn't. In this case we should only |
+// present the minimal number of prompts necessary for successfully |
+// displaying the page. First we check whether cancelling works as |
+// expected. |
+IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, MultipleRealmCancellation) { |
+ ASSERT_TRUE(test_server()->Start()); |
+ GURL test_page = test_server()->GetURL(kMultiRealmTestPage); |
+ |
+ TabContentsWrapper* contents = |
+ browser()->GetSelectedTabContentsWrapper(); |
+ ASSERT_TRUE(contents); |
+ |
+ NavigationController* controller = &contents->controller(); |
+ LoginPromptBrowserTestObserver observer; |
+ |
+ observer.Register(Source<NavigationController>(controller)); |
+ |
+ WindowedLoadStopObserver load_stop_waiter(controller); |
+ |
+ { |
+ WindowedAuthNeededObserver auth_needed_waiter(controller); |
+ browser()->OpenURL(test_page, GURL(), CURRENT_TAB, PageTransition::TYPED); |
+ auth_needed_waiter.Wait(); |
+ } |
+ |
+ int n_handlers = 0; |
+ |
+ while (n_handlers < kMultiRealmTestRealmCount) { |
+ WindowedAuthNeededObserver auth_needed_waiter(controller); |
+ |
+ while (!observer.handlers_.empty()) { |
+ WindowedAuthCancelledObserver auth_cancelled_waiter(controller); |
+ LoginHandler* handler = *observer.handlers_.begin(); |
+ |
+ ASSERT_TRUE(handler); |
+ n_handlers++; |
+ handler->CancelAuth(); |
+ auth_cancelled_waiter.Wait(); |
+ } |
+ |
+ if (n_handlers < kMultiRealmTestRealmCount) |
+ auth_needed_waiter.Wait(); |
+ } |
+ |
+ load_stop_waiter.Wait(); |
+ |
+ EXPECT_EQ(kMultiRealmTestRealmCount, n_handlers); |
+ EXPECT_EQ(0, observer.auth_supplied_count_); |
+ EXPECT_LT(0, observer.auth_needed_count_); |
+ EXPECT_LT(0, observer.auth_cancelled_count_); |
+ EXPECT_TRUE(test_server()->Stop()); |
+} |
+ |
+// Similar to the MultipleRealmCancellation test above, but tests |
+// whether supplying credentials work as exepcted. |
+IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, MultipleRealmConfirmation) { |
+ ASSERT_TRUE(test_server()->Start()); |
+ GURL test_page = test_server()->GetURL(kMultiRealmTestPage); |
+ |
+ TabContentsWrapper* contents = |
+ browser()->GetSelectedTabContentsWrapper(); |
+ ASSERT_TRUE(contents); |
+ |
+ NavigationController* controller = &contents->controller(); |
+ LoginPromptBrowserTestObserver observer; |
+ |
+ observer.Register(Source<NavigationController>(controller)); |
+ |
+ WindowedLoadStopObserver load_stop_waiter(controller); |
+ int n_handlers = 0; |
+ |
+ { |
+ WindowedAuthNeededObserver auth_needed_waiter(controller); |
+ |
+ browser()->OpenURL(test_page, GURL(), CURRENT_TAB, PageTransition::TYPED); |
+ auth_needed_waiter.Wait(); |
+ } |
+ |
+ while (n_handlers < kMultiRealmTestRealmCount) { |
+ WindowedAuthNeededObserver auth_needed_waiter(controller); |
+ |
+ while (!observer.handlers_.empty()) { |
+ WindowedAuthSuppliedObserver auth_supplied_waiter(controller); |
+ LoginHandler* handler = *observer.handlers_.begin(); |
+ |
+ ASSERT_TRUE(handler); |
+ n_handlers++; |
+ SetAuthFor(handler); |
+ auth_supplied_waiter.Wait(); |
+ } |
+ |
+ if (n_handlers < kMultiRealmTestRealmCount) |
+ auth_needed_waiter.Wait(); |
+ } |
+ |
+ load_stop_waiter.Wait(); |
+ |
+ EXPECT_EQ(kMultiRealmTestRealmCount, n_handlers); |
+ EXPECT_LT(0, observer.auth_needed_count_); |
+ EXPECT_LT(0, observer.auth_supplied_count_); |
+ EXPECT_EQ(0, observer.auth_cancelled_count_); |
+ EXPECT_TRUE(test_server()->Stop()); |
+} |
+ |
+// Testing for recovery from an incorrect password for the case where |
+// there are multiple authenticated resources. |
+IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, IncorrectConfirmation) { |
+ ASSERT_TRUE(test_server()->Start()); |
+ GURL test_page = test_server()->GetURL(kSingleRealmTestPage); |
+ |
+ TabContentsWrapper* contents = |
+ browser()->GetSelectedTabContentsWrapper(); |
+ ASSERT_TRUE(contents); |
+ |
+ NavigationController* controller = &contents->controller(); |
+ LoginPromptBrowserTestObserver observer; |
+ |
+ observer.Register(Source<NavigationController>(controller)); |
+ |
+ WindowedLoadStopObserver load_stop_waiter(controller); |
+ |
+ { |
+ WindowedAuthNeededObserver auth_needed_waiter(controller); |
+ browser()->OpenURL(test_page, GURL(), CURRENT_TAB, PageTransition::TYPED); |
+ auth_needed_waiter.Wait(); |
+ } |
+ |
+ EXPECT_FALSE(observer.handlers_.empty()); |
+ |
+ if (!observer.handlers_.empty()) { |
+ WindowedAuthNeededObserver auth_needed_waiter(controller); |
+ WindowedAuthSuppliedObserver auth_supplied_waiter(controller); |
+ LoginHandler* handler = *observer.handlers_.begin(); |
+ |
+ ASSERT_TRUE(handler); |
+ handler->SetAuth(bad_username_, bad_password_); |
+ auth_supplied_waiter.Wait(); |
+ |
+ // The request should be retried after the incorrect password is |
+ // supplied. This should result in a new AUTH_NEEDED notification |
+ // for the same realm. |
+ auth_needed_waiter.Wait(); |
+ } |
+ |
+ int n_handlers = 0; |
+ |
+ while (n_handlers < 1) { |
+ WindowedAuthNeededObserver auth_needed_waiter(controller); |
+ |
+ while (!observer.handlers_.empty()) { |
+ WindowedAuthSuppliedObserver auth_supplied_waiter(controller); |
+ LoginHandler* handler = *observer.handlers_.begin(); |
+ |
+ ASSERT_TRUE(handler); |
+ n_handlers++; |
+ SetAuthFor(handler); |
+ auth_supplied_waiter.Wait(); |
+ } |
+ |
+ if (n_handlers < 1) |
+ auth_needed_waiter.Wait(); |
+ } |
+ |
+ load_stop_waiter.Wait(); |
+ |
+ // The single realm test has only one realm, and thus only one login |
+ // prompt. |
+ EXPECT_EQ(1, n_handlers); |
+ EXPECT_LT(0, observer.auth_needed_count_); |
+ EXPECT_LT(0, observer.auth_supplied_count_); |
+ EXPECT_EQ(0, observer.auth_cancelled_count_); |
+ EXPECT_TRUE(test_server()->Stop()); |
+} |
+} // namespace |