Chromium Code Reviews| 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..61b2857e408f2356b517dc4eebc756d4aab81458 |
| --- /dev/null |
| +++ b/chrome/browser/ui/login/login_prompt_browsertest.cc |
| @@ -0,0 +1,329 @@ |
| +// Copyright (c) 2010 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 <set> |
| +#include <map> |
|
cbentzel
2010/12/17 22:02:55
Nit: <map> before <set>
asanka (google)
2010/12/20 17:44:08
Done.
|
| + |
| +#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" |
| + |
| +class LoginPromptBrowserTest : public InProcessBrowserTest { |
|
cbentzel
2010/12/17 22:02:55
Can these go in an anonymous namespace?
asanka (google)
2010/12/20 17:44:08
Done.
|
| + 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) { |
| + net::AuthChallengeInfo* challenge = handler->auth_info(); |
| + |
| + ASSERT_TRUE(challenge); |
| + std::map<std::wstring, AuthInfo>::iterator i = |
| + auth_map_.find(challenge->realm); |
| + EXPECT_NE(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), |
|
cbentzel
2010/12/17 22:02:55
Nit: probably move auth_supplied_count_ right unde
asanka (google)
2010/12/20 17:44:08
Done.
|
| + 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::set<LoginHandler*> handlers_; |
| + |
| + int auth_needed_count_; |
| + int auth_supplied_count_; |
| + int auth_cancelled_count_; |
| + |
| + 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) { |
| + EXPECT_TRUE(handlers_.find(handler) == handlers_.end()); |
| + handlers_.insert(handler); |
| +} |
| + |
| +void LoginPromptBrowserTestObserver::RemoveHandler(LoginHandler* handler) { |
| + std::set<LoginHandler*>::iterator i = handlers_.find(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; |
|
cbentzel
2010/12/17 22:02:55
Nit: I think it would be clearer if you indented t
asanka (google)
2010/12/20 17:44:08
Done.
|
| + |
| +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 (observer.auth_cancelled_count_ < kMultiRealmTestResourceCount) { |
| + 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 (observer.auth_cancelled_count_ < kMultiRealmTestResourceCount) |
| + auth_needed_waiter.Wait(); |
| + } |
| + |
| + load_stop_waiter.Wait(); |
| + |
| + EXPECT_EQ(kMultiRealmTestRealmCount, n_handlers); |
| + EXPECT_EQ(kMultiRealmTestResourceCount, observer.auth_needed_count_); |
| + EXPECT_EQ(0, observer.auth_supplied_count_); |
| + EXPECT_EQ(kMultiRealmTestResourceCount, observer.auth_cancelled_count_); |
| +} |
| + |
| +// 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 (observer.auth_supplied_count_ < kMultiRealmTestResourceCount) { |
| + 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 (observer.auth_supplied_count_ < kMultiRealmTestResourceCount) |
| + auth_needed_waiter.Wait(); |
| + } |
| + |
| + load_stop_waiter.Wait(); |
| + |
| + EXPECT_EQ(kMultiRealmTestRealmCount, n_handlers); |
| + EXPECT_EQ(kMultiRealmTestResourceCount, observer.auth_needed_count_); |
| + EXPECT_EQ(kMultiRealmTestResourceCount, observer.auth_supplied_count_); |
| + EXPECT_EQ(0, observer.auth_cancelled_count_); |
| +} |
| + |
| +// 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 (observer.auth_supplied_count_ < kSingleRealmTestResourceCount * 2) { |
| + 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 (observer.auth_supplied_count_ < kSingleRealmTestResourceCount) |
| + auth_needed_waiter.Wait(); |
| + } |
| + |
| + load_stop_waiter.Wait(); |
| + |
| + // auth_needed_count_ and auth_supplied_count_ are twice the number |
| + // of resources since the incorrect password attempt should have |
| + // resulted in a retry for the whole page. The single realm test |
| + // has only one realm, and thus only one login prompt. |
| + EXPECT_EQ(1, n_handlers); |
| + EXPECT_EQ(kSingleRealmTestResourceCount * 2, observer.auth_needed_count_); |
| + EXPECT_EQ(kSingleRealmTestResourceCount * 2, observer.auth_supplied_count_); |
| + EXPECT_EQ(0, observer.auth_cancelled_count_); |
| +} |