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

Side by Side Diff: chrome/browser/captive_portal/captive_portal_tab_helper_unittest.cc

Issue 10020051: Open a login tab on captive portal detection on SSL loads. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Add NULL CaptivePortalService check Created 8 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 | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/captive_portal/captive_portal_tab_helper.h"
6
7 #include "base/message_loop.h"
8 #include "chrome/browser/captive_portal/captive_portal_service.h"
9 #include "chrome/common/chrome_notification_types.h"
10 #include "content/public/browser/notification_service.h"
11 #include "net/base/net_errors.h"
12 #include "testing/gmock/include/gmock/gmock.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 namespace captive_portal {
16
17 // Used for testing CaptivePortalTabHelper in isolation from the observer.
18 // Exposes a number of private functions and mocks out others.
19 class TestCaptivePortalTabHelper : public CaptivePortalTabHelper {
20 public:
21 // |profile| will only be used as a notification source, so we don't need
22 // an actual TestingProfile.
23 explicit TestCaptivePortalTabHelper(Profile* profile)
24 : CaptivePortalTabHelper(profile, NULL) {
25 }
26
27 bool TimerRunning() {
28 return slow_ssl_load_timer_.IsRunning();
29 }
30
31 void SetState(State state) {
cbentzel 2012/04/18 15:57:23 Can you add a comment about why you need to alias
mmenke 2012/04/18 19:15:46 Done.
32 CaptivePortalTabHelper::SetState(state);
33 }
34
35 State state() {
36 return CaptivePortalTabHelper::state();
37 }
38
39 void set_slow_ssl_load_time(base::TimeDelta slow_ssl_load_time) {
40 EXPECT_FALSE(TimerRunning());
41 CaptivePortalTabHelper::set_slow_ssl_load_time(slow_ssl_load_time);
42 }
43
44 // CaptivePortalTabHelper:
45 virtual void OnLoadStart(bool is_ssl) OVERRIDE {
46 CaptivePortalTabHelper::OnLoadStart(is_ssl);
47 }
48
49 virtual void OnLoadCommitted(int net_error) OVERRIDE {
50 CaptivePortalTabHelper::OnLoadCommitted(net_error);
51 }
52
53 virtual void OnAbort() OVERRIDE {
54 CaptivePortalTabHelper::OnAbort();
55 }
56
57 virtual void OnStopLoading() OVERRIDE {
58 CaptivePortalTabHelper::OnStopLoading();
59 }
60
61 MOCK_METHOD0(ReloadTab, void());
62 MOCK_METHOD0(MaybeOpenCaptivePortalLoginTab, void());
63 MOCK_METHOD0(CheckForCaptivePortal, void());
cbentzel 2012/04/18 15:57:23 I've been hesitant about using gmock, but this is
mmenke 2012/04/18 19:15:46 I haven't used it in the past, but simonjam's used
64 };
65
66 class CaptivePortalTabHelperTest : public testing::Test {
67 public:
68 CaptivePortalTabHelperTest() : tab_helper_(fake_profile()) {
69 // Most tests don't run the message loop, so don't use a timer for them.
70 tab_helper_.set_slow_ssl_load_time(base::TimeDelta());
71 }
72
73 virtual ~CaptivePortalTabHelperTest() {
74 }
75
76 // testing::Test
77 virtual void TearDown() OVERRIDE {
78 EXPECT_FALSE(tab_helper().TimerRunning());
79 // Run any pending operations, so we fail if we unexpectedly call a
80 // mocked out function.
81 MessageLoop::current()->RunAllPending();
82 }
83
84 void SendNotification(Result previous_result, Result result) {
85 CaptivePortalService::Results results;
86 results.previous_result = previous_result;
87 results.result = result;
88 content::NotificationService::current()->Notify(
89 chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT,
90 content::Source<Profile>(fake_profile()),
91 content::Details<CaptivePortalService::Results>(&results));
92 }
93
94 TestCaptivePortalTabHelper& tab_helper() { return tab_helper_; }
95
96 // This Profile should only be used as a notification source, so we
97 // initialize it to a value that will crash if we dereference it
98 // unexpectedly.
99 Profile* fake_profile() { return reinterpret_cast<Profile*>(17); }
cbentzel 2012/04/18 15:57:23 That is a bit of an unusual pattern. Hope the memo
mmenke 2012/04/18 19:15:46 Because the profile shouldn't be dereferenced. If
cbentzel 2012/04/18 21:12:37 You may want to ask Qin about this. I agree that i
mmenke 2012/04/19 15:26:25 Qin's response: 1. for the good behavior, i.e. if
100
101 private:
102 MessageLoop message_loop_;
103
104 testing::StrictMock<TestCaptivePortalTabHelper> tab_helper_;
105 };
106
107 // Simulates a slow SSL load when the Internet is connected.
108 TEST_F(CaptivePortalTabHelperTest, InternetConnected) {
109 EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
110
111 tab_helper().OnLoadStart(true);
112 EXPECT_EQ(CaptivePortalTabHelper::STATE_TIMER_RUNNING, tab_helper().state());
113 EXPECT_TRUE(tab_helper().TimerRunning());
114
115 EXPECT_CALL(tab_helper(), CheckForCaptivePortal()).Times(1);
116 MessageLoop::current()->RunAllPending();
cbentzel 2012/04/18 15:57:23 Is there any potential for flakiness here, or is t
mmenke 2012/04/18 19:15:46 No. PostDelayedTask and PostTask are both interna
117 EXPECT_FALSE(tab_helper().TimerRunning());
118 EXPECT_EQ(CaptivePortalTabHelper::STATE_MAYBE_BROKEN_BY_PORTAL,
119 tab_helper().state());
120
121 SendNotification(RESULT_INTERNET_CONNECTED, RESULT_INTERNET_CONNECTED);
122
123 EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
124 EXPECT_FALSE(tab_helper().TimerRunning());
125
126 tab_helper().OnLoadCommitted(net::OK);
127 EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
128 }
129
130 // Simulates a slow SSL load when the Internet is connected. In this case,
131 // we get the timeout error before the timer triggers. Unlikely to happen
132 // in practice, but we should still support it.
133 TEST_F(CaptivePortalTabHelperTest, InternetConnectedTimeout) {
134 EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
135
136 tab_helper().OnLoadStart(true);
137 EXPECT_EQ(CaptivePortalTabHelper::STATE_TIMER_RUNNING, tab_helper().state());
138 EXPECT_TRUE(tab_helper().TimerRunning());
139
140 EXPECT_CALL(tab_helper(), CheckForCaptivePortal()).Times(1);
141 tab_helper().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
142 EXPECT_FALSE(tab_helper().TimerRunning());
143 EXPECT_EQ(CaptivePortalTabHelper::STATE_MAYBE_BROKEN_BY_PORTAL,
144 tab_helper().state());
145
146 SendNotification(RESULT_INTERNET_CONNECTED, RESULT_INTERNET_CONNECTED);
147
148 EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
149 }
150
151 // Simulates a slow SSL load when captive portal checks return no response.
152 TEST_F(CaptivePortalTabHelperTest, NoResponse) {
153 EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
154
155 tab_helper().OnLoadStart(true);
156 EXPECT_EQ(CaptivePortalTabHelper::STATE_TIMER_RUNNING, tab_helper().state());
157 EXPECT_TRUE(tab_helper().TimerRunning());
158
159 EXPECT_CALL(tab_helper(), CheckForCaptivePortal()).Times(1);
160 MessageLoop::current()->RunAllPending();
161 EXPECT_FALSE(tab_helper().TimerRunning());
162 EXPECT_EQ(CaptivePortalTabHelper::STATE_MAYBE_BROKEN_BY_PORTAL,
163 tab_helper().state());
164
165 SendNotification(RESULT_NO_RESPONSE, RESULT_NO_RESPONSE);
166
167 EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
168 EXPECT_FALSE(tab_helper().TimerRunning());
169
170 tab_helper().OnLoadCommitted(net::OK);
171 EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
172 }
173
174 // Simulates a slow HTTP load that eventually times out when behind a captive
175 // portal, and then times out.
176 TEST_F(CaptivePortalTabHelperTest, DoesNothingOnHttp) {
177 tab_helper().OnLoadStart(false);
178 EXPECT_FALSE(tab_helper().TimerRunning());
179 EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
180
181 SendNotification(RESULT_INTERNET_CONNECTED, RESULT_BEHIND_CAPTIVE_PORTAL);
182 EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
183 SendNotification(RESULT_BEHIND_CAPTIVE_PORTAL, RESULT_INTERNET_CONNECTED);
184 EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
185
186 tab_helper().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
187 EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
188 }
189
190 // Simulate the normal login process. The user logs in before the tab finishes
191 // loading the error page.
192 TEST_F(CaptivePortalTabHelperTest, Login) {
193 tab_helper().OnLoadStart(true);
194
195 EXPECT_CALL(tab_helper(), CheckForCaptivePortal()).Times(1);
196 MessageLoop::current()->RunAllPending();
197 EXPECT_FALSE(tab_helper().TimerRunning());
198 EXPECT_EQ(CaptivePortalTabHelper::STATE_MAYBE_BROKEN_BY_PORTAL,
199 tab_helper().state());
200
201 // The captive portal service tells us we're behind a captive portal.
202 // The tab helper should try and create a new login tab in response.
203 EXPECT_CALL(tab_helper(), MaybeOpenCaptivePortalLoginTab()).Times(1);
204 SendNotification(RESULT_INTERNET_CONNECTED, RESULT_BEHIND_CAPTIVE_PORTAL);
205 EXPECT_EQ(CaptivePortalTabHelper::STATE_BROKEN_BY_PORTAL,
206 tab_helper().state());
207 EXPECT_FALSE(tab_helper().TimerRunning());
208
209 // The user logs on from another tab, and a captive portal check is triggered.
210 SendNotification(RESULT_BEHIND_CAPTIVE_PORTAL, RESULT_INTERNET_CONNECTED);
211 EXPECT_EQ(CaptivePortalTabHelper::STATE_NEEDS_RELOAD, tab_helper().state());
212
213 // The error page commits, which should start an asynchronous reload.
214 tab_helper().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
215 EXPECT_EQ(CaptivePortalTabHelper::STATE_NEEDS_RELOAD, tab_helper().state());
216
217 EXPECT_CALL(tab_helper(), ReloadTab()).Times(1);
218 MessageLoop::current()->RunAllPending();
219 EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
220 }
221
222 // Simulate the normal login process. The user logs in after the tab finishes
223 // loading the error page.
224 TEST_F(CaptivePortalTabHelperTest, LoginLate) {
225 tab_helper().OnLoadStart(true);
226
227 EXPECT_CALL(tab_helper(), CheckForCaptivePortal()).Times(1);
228 MessageLoop::current()->RunAllPending();
229 EXPECT_FALSE(tab_helper().TimerRunning());
230 EXPECT_EQ(CaptivePortalTabHelper::STATE_MAYBE_BROKEN_BY_PORTAL,
231 tab_helper().state());
232
233 // The captive portal service tells us we're behind a captive portal.
234 // The tab helper should try and create a new login tab in response.
235 EXPECT_CALL(tab_helper(), MaybeOpenCaptivePortalLoginTab()).Times(1);
236 SendNotification(RESULT_INTERNET_CONNECTED, RESULT_BEHIND_CAPTIVE_PORTAL);
237 EXPECT_EQ(CaptivePortalTabHelper::STATE_BROKEN_BY_PORTAL,
238 tab_helper().state());
239 EXPECT_FALSE(tab_helper().TimerRunning());
240
241 // The error page commits.
242 tab_helper().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
243 EXPECT_EQ(CaptivePortalTabHelper::STATE_BROKEN_BY_PORTAL,
244 tab_helper().state());
245
246 // The user logs on from another tab, and a captive portal check is triggered.
247 EXPECT_CALL(tab_helper(), ReloadTab()).Times(1);
248 SendNotification(RESULT_BEHIND_CAPTIVE_PORTAL, RESULT_INTERNET_CONNECTED);
249 EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
250 }
251
252 // Simulate a login after the tab times out unexpectedly quickly.
253 TEST_F(CaptivePortalTabHelperTest, TimeoutFast) {
254 tab_helper().OnLoadStart(true);
255
256 // The error page commits, which should trigger a captive portal check,
257 // since the timer's still running.
258 EXPECT_CALL(tab_helper(), CheckForCaptivePortal()).Times(1);
259 tab_helper().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
260 EXPECT_EQ(CaptivePortalTabHelper::STATE_MAYBE_BROKEN_BY_PORTAL,
261 tab_helper().state());
262
263 // The captive portal service tells us we're behind a captive portal.
264 // The tab helper should try and create a new login tab in response.
265 EXPECT_CALL(tab_helper(), MaybeOpenCaptivePortalLoginTab()).Times(1);
266 SendNotification(RESULT_INTERNET_CONNECTED, RESULT_BEHIND_CAPTIVE_PORTAL);
267 EXPECT_EQ(CaptivePortalTabHelper::STATE_BROKEN_BY_PORTAL,
268 tab_helper().state());
269 EXPECT_FALSE(tab_helper().TimerRunning());
270
271 // The user logs on from another tab, and a captive portal check is triggered.
272 EXPECT_CALL(tab_helper(), ReloadTab()).Times(1);
273 SendNotification(RESULT_BEHIND_CAPTIVE_PORTAL, RESULT_INTERNET_CONNECTED);
274 EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
275 }
276
277 // Simulate the case that a user has already logged in by the time we get
278 // our first captive portal result.
279 TEST_F(CaptivePortalTabHelperTest, AlreadyLoggedIn) {
280 tab_helper().OnLoadStart(true);
281
282 EXPECT_CALL(tab_helper(), CheckForCaptivePortal()).Times(1);
283 MessageLoop::current()->RunAllPending();
284 EXPECT_FALSE(tab_helper().TimerRunning());
285 EXPECT_EQ(CaptivePortalTabHelper::STATE_MAYBE_BROKEN_BY_PORTAL,
286 tab_helper().state());
287
288 // The user has already logged in. Since the last result indicated we
289 // were behind a captive portal, we decide to reload the tab when we can.
290 SendNotification(RESULT_BEHIND_CAPTIVE_PORTAL, RESULT_INTERNET_CONNECTED);
291 EXPECT_EQ(CaptivePortalTabHelper::STATE_NEEDS_RELOAD, tab_helper().state());
292
293 // The error page commits, which should start an asynchronous reload.
294 tab_helper().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
295 EXPECT_EQ(CaptivePortalTabHelper::STATE_NEEDS_RELOAD, tab_helper().state());
296
297 EXPECT_CALL(tab_helper(), ReloadTab()).Times(1);
298 MessageLoop::current()->RunAllPending();
299 EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
300 }
301
302 // Simulate the case that a user has already logged in before the timer
303 // triggers.
304 TEST_F(CaptivePortalTabHelperTest, AlreadyLoggedInBeforeTimerTriggers) {
305 tab_helper().OnLoadStart(true);
306
307 EXPECT_CALL(tab_helper(), CheckForCaptivePortal()).Times(1);
308 MessageLoop::current()->RunAllPending();
309 EXPECT_FALSE(tab_helper().TimerRunning());
310 EXPECT_EQ(CaptivePortalTabHelper::STATE_MAYBE_BROKEN_BY_PORTAL,
311 tab_helper().state());
312
313 // The user has already logged in. Since the last result indicated we
314 // were behind a captive portal, we decide to reload the tab when we can.
315 SendNotification(RESULT_BEHIND_CAPTIVE_PORTAL, RESULT_INTERNET_CONNECTED);
316 EXPECT_EQ(CaptivePortalTabHelper::STATE_NEEDS_RELOAD, tab_helper().state());
317
318 // The error page commits, which should start an asynchronous reload.
319 tab_helper().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
320 EXPECT_EQ(CaptivePortalTabHelper::STATE_NEEDS_RELOAD, tab_helper().state());
321
322 EXPECT_CALL(tab_helper(), ReloadTab()).Times(1);
323 MessageLoop::current()->RunAllPending();
324 EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
325 }
326
327 // Simulate the user logging in while the timer is still running. May happen
cbentzel 2012/04/18 15:57:23 It doesn't look like there is a test for when the
mmenke 2012/04/18 19:15:46 Test added for that case.
328 // if the tab is reloaded just before logging in on another tab.
329 TEST_F(CaptivePortalTabHelperTest, LogInWhileTimerRunning) {
330 tab_helper().OnLoadStart(true);
331 EXPECT_EQ(CaptivePortalTabHelper::STATE_TIMER_RUNNING, tab_helper().state());
332 EXPECT_TRUE(tab_helper().TimerRunning());
333
334 // The user has already logged in.
335 SendNotification(RESULT_BEHIND_CAPTIVE_PORTAL, RESULT_INTERNET_CONNECTED);
336 EXPECT_EQ(CaptivePortalTabHelper::STATE_NEEDS_RELOAD, tab_helper().state());
337
338 // The error page commits, which should start an asynchronous reload.
339 tab_helper().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
340 EXPECT_EQ(CaptivePortalTabHelper::STATE_NEEDS_RELOAD, tab_helper().state());
341
342 EXPECT_CALL(tab_helper(), ReloadTab()).Times(1);
343 MessageLoop::current()->RunAllPending();
344 EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
345 }
346
347 // Same as above, but the original load completes instead of committing.
348 TEST_F(CaptivePortalTabHelperTest, LogInWhileTimerRunningNoError) {
349 tab_helper().OnLoadStart(true);
350 EXPECT_EQ(CaptivePortalTabHelper::STATE_TIMER_RUNNING, tab_helper().state());
351 EXPECT_TRUE(tab_helper().TimerRunning());
352
353 // The user has already logged in.
354 SendNotification(RESULT_BEHIND_CAPTIVE_PORTAL, RESULT_INTERNET_CONNECTED);
355 EXPECT_EQ(CaptivePortalTabHelper::STATE_NEEDS_RELOAD, tab_helper().state());
356
357 // The error page commits, which should start an asynchronous reload.
358 tab_helper().OnLoadCommitted(net::OK);
359 EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
360 }
361
362 // Simulate a normal page load in a login tab while behind a captive portal.
363 TEST_F(CaptivePortalTabHelperTest, LoginTabPageLoad) {
364 tab_helper().SetState(
365 CaptivePortalTabHelper::STATE_CAPTIVE_PORTAL_LOGIN_PAGE);
366 tab_helper().OnLoadStart(false);
367 EXPECT_EQ(CaptivePortalTabHelper::STATE_CAPTIVE_PORTAL_LOGIN_PAGE,
368 tab_helper().state());
369
370 tab_helper().OnLoadCommitted(net::OK);
371 EXPECT_EQ(CaptivePortalTabHelper::STATE_CAPTIVE_PORTAL_LOGIN_PAGE,
372 tab_helper().state());
373
374 EXPECT_CALL(tab_helper(), CheckForCaptivePortal()).Times(1);
375 tab_helper().OnStopLoading();
376 EXPECT_EQ(CaptivePortalTabHelper::STATE_CAPTIVE_PORTAL_LOGIN_PAGE,
377 tab_helper().state());
378
379 SendNotification(RESULT_BEHIND_CAPTIVE_PORTAL, RESULT_BEHIND_CAPTIVE_PORTAL);
380 EXPECT_EQ(CaptivePortalTabHelper::STATE_CAPTIVE_PORTAL_LOGIN_PAGE,
381 tab_helper().state());
382 }
383
384 // Simulate a logging on through a login tab via an HTTP page.
385 TEST_F(CaptivePortalTabHelperTest, LoginTabLogin) {
386 tab_helper().SetState(
387 CaptivePortalTabHelper::STATE_CAPTIVE_PORTAL_LOGIN_PAGE);
388 tab_helper().OnLoadStart(false);
389 EXPECT_EQ(CaptivePortalTabHelper::STATE_CAPTIVE_PORTAL_LOGIN_PAGE,
390 tab_helper().state());
391
392 tab_helper().OnLoadCommitted(net::OK);
393 EXPECT_EQ(CaptivePortalTabHelper::STATE_CAPTIVE_PORTAL_LOGIN_PAGE,
394 tab_helper().state());
395
396 EXPECT_CALL(tab_helper(), CheckForCaptivePortal()).Times(1);
397 tab_helper().OnStopLoading();
398 EXPECT_EQ(CaptivePortalTabHelper::STATE_CAPTIVE_PORTAL_LOGIN_PAGE,
399 tab_helper().state());
400
401 SendNotification(RESULT_BEHIND_CAPTIVE_PORTAL, RESULT_INTERNET_CONNECTED);
402 EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
403 }
404
405 // Simulate an SSL connection timout in a login tab while behind a captive
406 // portal.
407 TEST_F(CaptivePortalTabHelperTest, LoginTabTimeout) {
408 // Load starts.
409 tab_helper().SetState(
410 CaptivePortalTabHelper::STATE_CAPTIVE_PORTAL_LOGIN_PAGE);
411 tab_helper().OnLoadStart(true);
412 EXPECT_EQ(CaptivePortalTabHelper::STATE_CAPTIVE_PORTAL_LOGIN_PAGE,
413 tab_helper().state());
414 EXPECT_FALSE(tab_helper().TimerRunning());
415
416 // Page times out.
417 tab_helper().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
418 EXPECT_EQ(CaptivePortalTabHelper::STATE_CAPTIVE_PORTAL_LOGIN_PAGE,
419 tab_helper().state());
420 }
421
422 } // namespace captive_portal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698