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

Side by Side Diff: chrome/browser/ui/login/login_prompt_browsertest.cc

Issue 5814005: Minimize login prompts (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Simplify cleanup of LoginPromptBrowserTestObserver Created 10 years 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2010 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 <map>
cbentzel 2010/12/17 22:02:55 Nit: <map> before <set>
asanka (google) 2010/12/20 17:44:08 Done.
7
8 #include "chrome/browser/browser_thread.h"
9 #include "chrome/browser/ui/browser.h"
10 #include "chrome/browser/ui/login/login_prompt.h"
11 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
12 #include "chrome/common/notification_service.h"
13 #include "chrome/test/in_process_browser_test.h"
14 #include "chrome/test/ui_test_utils.h"
15 #include "net/base/auth.h"
16
17 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.
18 public:
19 LoginPromptBrowserTest()
20 : bad_password_(L"incorrect"), bad_username_(L"nouser") {
21 set_show_window(true);
22
23 auth_map_[L"foo"] = AuthInfo(L"testuser", L"foopassword");
24 auth_map_[L"bar"] = AuthInfo(L"testuser", L"barpassword");
25 }
26
27 protected:
28 void SetAuthFor(LoginHandler* handler);
29
30 struct AuthInfo {
31 std::wstring username_;
32 std::wstring password_;
33
34 AuthInfo() {}
35
36 AuthInfo(const std::wstring username,
37 const std::wstring password)
38 : username_(username), password_(password) {}
39 };
40
41 std::map<std::wstring, AuthInfo> auth_map_;
42 std::wstring bad_password_;
43 std::wstring bad_username_;
44 };
45
46 void LoginPromptBrowserTest::SetAuthFor(LoginHandler* handler) {
47 net::AuthChallengeInfo* challenge = handler->auth_info();
48
49 ASSERT_TRUE(challenge);
50 std::map<std::wstring, AuthInfo>::iterator i =
51 auth_map_.find(challenge->realm);
52 EXPECT_NE(auth_map_.end(), i);
53 if (i != auth_map_.end()) {
54 const AuthInfo& info = i->second;
55 handler->SetAuth(info.username_, info.password_);
56 }
57 }
58
59 // Maintains a set of LoginHandlers that are currently active and
60 // keeps a count of the notifications that were observed.
61 class LoginPromptBrowserTestObserver : public NotificationObserver {
62 public:
63 LoginPromptBrowserTestObserver()
64 : 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.
65 auth_cancelled_count_(0) {}
66
67 virtual void Observe(NotificationType type,
68 const NotificationSource& source,
69 const NotificationDetails& details);
70
71 void AddHandler(LoginHandler* handler);
72
73 void RemoveHandler(LoginHandler* handler);
74
75 void Register(const NotificationSource& source);
76
77 std::set<LoginHandler*> handlers_;
78
79 int auth_needed_count_;
80 int auth_supplied_count_;
81 int auth_cancelled_count_;
82
83 NotificationRegistrar registrar_;
84
85 DISALLOW_COPY_AND_ASSIGN(LoginPromptBrowserTestObserver);
86 };
87
88 void LoginPromptBrowserTestObserver::Observe(
89 NotificationType type,
90 const NotificationSource& source,
91 const NotificationDetails& details) {
92 if (type == NotificationType::AUTH_NEEDED) {
93 LoginNotificationDetails* login_details =
94 Details<LoginNotificationDetails>(details).ptr();
95 AddHandler(login_details->handler());
96 auth_needed_count_++;
97 } else if (type == NotificationType::AUTH_SUPPLIED) {
98 AuthSuppliedLoginNotificationDetails* login_details =
99 Details<AuthSuppliedLoginNotificationDetails>(details).ptr();
100 RemoveHandler(login_details->handler());
101 auth_supplied_count_++;
102 } else if (type == NotificationType::AUTH_CANCELLED) {
103 LoginNotificationDetails* login_details =
104 Details<LoginNotificationDetails>(details).ptr();
105 RemoveHandler(login_details->handler());
106 auth_cancelled_count_++;
107 }
108 }
109
110 void LoginPromptBrowserTestObserver::AddHandler(LoginHandler* handler) {
111 EXPECT_TRUE(handlers_.find(handler) == handlers_.end());
112 handlers_.insert(handler);
113 }
114
115 void LoginPromptBrowserTestObserver::RemoveHandler(LoginHandler* handler) {
116 std::set<LoginHandler*>::iterator i = handlers_.find(handler);
117 EXPECT_TRUE(i != handlers_.end());
118 if (i != handlers_.end())
119 handlers_.erase(i);
120 }
121
122 void LoginPromptBrowserTestObserver::Register(
123 const NotificationSource& source) {
124 registrar_.Add(this, NotificationType::AUTH_NEEDED, source);
125 registrar_.Add(this, NotificationType::AUTH_SUPPLIED, source);
126 registrar_.Add(this, NotificationType::AUTH_CANCELLED, source);
127 }
128
129 template <NotificationType::Type T>
130 class WindowedNavigationObserver
131 : public ui_test_utils::WindowedNotificationObserver {
132 public:
133 explicit WindowedNavigationObserver(NavigationController* controller)
134 : ui_test_utils::WindowedNotificationObserver(
135 T, Source<NavigationController>(controller)) {}
136 };
137
138 typedef WindowedNavigationObserver<NotificationType::LOAD_STOP>
139 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.
140
141 typedef WindowedNavigationObserver<NotificationType::AUTH_NEEDED>
142 WindowedAuthNeededObserver;
143
144 typedef WindowedNavigationObserver<NotificationType::AUTH_CANCELLED>
145 WindowedAuthCancelledObserver;
146
147 typedef WindowedNavigationObserver<NotificationType::AUTH_SUPPLIED>
148 WindowedAuthSuppliedObserver;
149
150 const char* kMultiRealmTestPage = "files/login/multi_realm.html";
151 const int kMultiRealmTestRealmCount = 2;
152 const int kMultiRealmTestResourceCount = 4;
153
154 const char* kSingleRealmTestPage = "files/login/single_realm.html";
155 const int kSingleRealmTestResourceCount = 6;
156
157 // Test handling of resources that require authentication even though
158 // the page they are included on doesn't. In this case we should only
159 // present the minimal number of prompts necessary for successfully
160 // displaying the page. First we check whether cancelling works as
161 // expected.
162 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, MultipleRealmCancellation) {
163 ASSERT_TRUE(test_server()->Start());
164 GURL test_page = test_server()->GetURL(kMultiRealmTestPage);
165
166 TabContentsWrapper* contents =
167 browser()->GetSelectedTabContentsWrapper();
168 ASSERT_TRUE(contents);
169
170 NavigationController* controller = &contents->controller();
171 LoginPromptBrowserTestObserver observer;
172
173 observer.Register(Source<NavigationController>(controller));
174
175 WindowedLoadStopObserver load_stop_waiter(controller);
176
177 {
178 WindowedAuthNeededObserver auth_needed_waiter(controller);
179 browser()->OpenURL(test_page, GURL(), CURRENT_TAB, PageTransition::TYPED);
180 auth_needed_waiter.Wait();
181 }
182
183 int n_handlers = 0;
184
185 while (observer.auth_cancelled_count_ < kMultiRealmTestResourceCount) {
186 WindowedAuthNeededObserver auth_needed_waiter(controller);
187
188 while (!observer.handlers_.empty()) {
189 WindowedAuthCancelledObserver auth_cancelled_waiter(controller);
190 LoginHandler* handler = *observer.handlers_.begin();
191
192 ASSERT_TRUE(handler);
193 n_handlers++;
194 handler->CancelAuth();
195 auth_cancelled_waiter.Wait();
196 }
197
198 if (observer.auth_cancelled_count_ < kMultiRealmTestResourceCount)
199 auth_needed_waiter.Wait();
200 }
201
202 load_stop_waiter.Wait();
203
204 EXPECT_EQ(kMultiRealmTestRealmCount, n_handlers);
205 EXPECT_EQ(kMultiRealmTestResourceCount, observer.auth_needed_count_);
206 EXPECT_EQ(0, observer.auth_supplied_count_);
207 EXPECT_EQ(kMultiRealmTestResourceCount, observer.auth_cancelled_count_);
208 }
209
210 // Similar to the MultipleRealmCancellation test above, but tests
211 // whether supplying credentials work as exepcted.
212 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, MultipleRealmConfirmation) {
213 ASSERT_TRUE(test_server()->Start());
214 GURL test_page = test_server()->GetURL(kMultiRealmTestPage);
215
216 TabContentsWrapper* contents =
217 browser()->GetSelectedTabContentsWrapper();
218 ASSERT_TRUE(contents);
219
220 NavigationController* controller = &contents->controller();
221 LoginPromptBrowserTestObserver observer;
222
223 observer.Register(Source<NavigationController>(controller));
224
225 WindowedLoadStopObserver load_stop_waiter(controller);
226 int n_handlers = 0;
227
228 {
229 WindowedAuthNeededObserver auth_needed_waiter(controller);
230
231 browser()->OpenURL(test_page, GURL(), CURRENT_TAB, PageTransition::TYPED);
232 auth_needed_waiter.Wait();
233 }
234
235 while (observer.auth_supplied_count_ < kMultiRealmTestResourceCount) {
236 WindowedAuthNeededObserver auth_needed_waiter(controller);
237
238 while (!observer.handlers_.empty()) {
239 WindowedAuthSuppliedObserver auth_supplied_waiter(controller);
240 LoginHandler* handler = *observer.handlers_.begin();
241
242 ASSERT_TRUE(handler);
243 n_handlers++;
244 SetAuthFor(handler);
245 auth_supplied_waiter.Wait();
246 }
247
248 if (observer.auth_supplied_count_ < kMultiRealmTestResourceCount)
249 auth_needed_waiter.Wait();
250 }
251
252 load_stop_waiter.Wait();
253
254 EXPECT_EQ(kMultiRealmTestRealmCount, n_handlers);
255 EXPECT_EQ(kMultiRealmTestResourceCount, observer.auth_needed_count_);
256 EXPECT_EQ(kMultiRealmTestResourceCount, observer.auth_supplied_count_);
257 EXPECT_EQ(0, observer.auth_cancelled_count_);
258 }
259
260 // Testing for recovery from an incorrect password for the case where
261 // there are multiple authenticated resources.
262 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, IncorrectConfirmation) {
263 ASSERT_TRUE(test_server()->Start());
264 GURL test_page = test_server()->GetURL(kSingleRealmTestPage);
265
266 TabContentsWrapper* contents =
267 browser()->GetSelectedTabContentsWrapper();
268 ASSERT_TRUE(contents);
269
270 NavigationController* controller = &contents->controller();
271 LoginPromptBrowserTestObserver observer;
272
273 observer.Register(Source<NavigationController>(controller));
274
275 WindowedLoadStopObserver load_stop_waiter(controller);
276
277 {
278 WindowedAuthNeededObserver auth_needed_waiter(controller);
279 browser()->OpenURL(test_page, GURL(), CURRENT_TAB, PageTransition::TYPED);
280 auth_needed_waiter.Wait();
281 }
282
283 EXPECT_FALSE(observer.handlers_.empty());
284
285 if (!observer.handlers_.empty()) {
286 WindowedAuthNeededObserver auth_needed_waiter(controller);
287 WindowedAuthSuppliedObserver auth_supplied_waiter(controller);
288 LoginHandler* handler = *observer.handlers_.begin();
289
290 ASSERT_TRUE(handler);
291 handler->SetAuth(bad_username_, bad_password_);
292 auth_supplied_waiter.Wait();
293
294 // The request should be retried after the incorrect password is
295 // supplied. This should result in a new AUTH_NEEDED notification
296 // for the same realm.
297 auth_needed_waiter.Wait();
298 }
299
300 int n_handlers = 0;
301
302 while (observer.auth_supplied_count_ < kSingleRealmTestResourceCount * 2) {
303 WindowedAuthNeededObserver auth_needed_waiter(controller);
304
305 while (!observer.handlers_.empty()) {
306 WindowedAuthSuppliedObserver auth_supplied_waiter(controller);
307 LoginHandler* handler = *observer.handlers_.begin();
308
309 ASSERT_TRUE(handler);
310 n_handlers++;
311 SetAuthFor(handler);
312 auth_supplied_waiter.Wait();
313 }
314
315 if (observer.auth_supplied_count_ < kSingleRealmTestResourceCount)
316 auth_needed_waiter.Wait();
317 }
318
319 load_stop_waiter.Wait();
320
321 // auth_needed_count_ and auth_supplied_count_ are twice the number
322 // of resources since the incorrect password attempt should have
323 // resulted in a retry for the whole page. The single realm test
324 // has only one realm, and thus only one login prompt.
325 EXPECT_EQ(1, n_handlers);
326 EXPECT_EQ(kSingleRealmTestResourceCount * 2, observer.auth_needed_count_);
327 EXPECT_EQ(kSingleRealmTestResourceCount * 2, observer.auth_supplied_count_);
328 EXPECT_EQ(0, observer.auth_cancelled_count_);
329 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698