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.
5 #include "chrome/browser/captive_portal/captive_portal_service.h"
7 #include "base/basictypes.h"
9 #include "base/command_line.h"
10 #include "base/message_loop.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/test/test_timeouts.h"
13 #include "chrome/browser/captive_portal/testing_utils.h"
14 #include "chrome/common/chrome_notification_types.h"
15 #include "chrome/common/chrome_switches.h"
16 #include "chrome/common/pref_names.h"
17 #include "chrome/test/base/testing_profile.h"
18 #include "chrome/test/base/ui_test_utils.h"
19 #include "content/public/browser/notification_details.h"
20 #include "content/public/browser/notification_observer.h"
21 #include "content/public/browser/notification_registrar.h"
22 #include "content/public/browser/notification_source.h"
23 #include "net/base/net_errors.h"
24 #include "testing/gtest/include/gtest/gtest.h"
26 namespace captive_portal
{
30 // A short amount of time that some tests wait for.
31 const int kShortTimeMs
= 10;
33 // An observer watches the CaptivePortalDetector. It tracks the last
34 // received result and the total number of received results.
35 class CaptivePortalObserver
: public content::NotificationObserver
{
37 CaptivePortalObserver(Profile
* profile
,
38 CaptivePortalService
* captive_portal_service
)
39 : captive_portal_result_(
40 captive_portal_service
->last_detection_result()),
41 num_results_received_(0),
43 captive_portal_service_(captive_portal_service
) {
45 chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT
,
46 content::Source
<Profile
>(profile_
));
49 Result
captive_portal_result() const { return captive_portal_result_
; }
51 int num_results_received() const { return num_results_received_
; }
54 virtual void Observe(int type
,
55 const content::NotificationSource
& source
,
56 const content::NotificationDetails
& details
) OVERRIDE
{
57 ASSERT_EQ(type
, chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT
);
58 ASSERT_EQ(profile_
, content::Source
<Profile
>(source
).ptr());
60 CaptivePortalService::Results
*results
=
61 content::Details
<CaptivePortalService::Results
>(details
).ptr();
63 EXPECT_EQ(captive_portal_result_
, results
->previous_result
);
64 EXPECT_EQ(captive_portal_service_
->last_detection_result(),
67 captive_portal_result_
= results
->result
;
68 ++num_results_received_
;
71 Result captive_portal_result_
;
72 int num_results_received_
;
75 CaptivePortalService
* captive_portal_service_
;
77 content::NotificationRegistrar registrar_
;
79 DISALLOW_COPY_AND_ASSIGN(CaptivePortalObserver
);
84 class CaptivePortalServiceTest
: public testing::Test
,
85 public CaptivePortalDetectorTestBase
{
87 CaptivePortalServiceTest()
88 : old_captive_portal_testing_state_(
89 CaptivePortalService::get_state_for_testing()) {
92 virtual ~CaptivePortalServiceTest() {
93 CaptivePortalService::set_state_for_testing(
94 old_captive_portal_testing_state_
);
97 // |enable_service| is whether or not the captive portal service itself
98 // should be disabled. This is different from enabling the captive portal
99 // detection preference.
100 void Initialize(CaptivePortalService::TestingState testing_state
) {
101 CaptivePortalService::set_state_for_testing(testing_state
);
103 profile_
.reset(new TestingProfile());
104 service_
.reset(new CaptivePortalService(profile_
.get()));
105 service_
->set_time_ticks_for_testing(base::TimeTicks::Now());
107 // Use no delays for most tests.
108 set_initial_backoff_no_portal(base::TimeDelta());
109 set_initial_backoff_portal(base::TimeDelta());
111 set_detector(&service_
->captive_portal_detector_
);
112 SetTime(base::Time::Now());
114 // Disable jitter, so can check exact values.
115 set_jitter_factor(0.0);
117 // These values make checking exponential backoff easier.
118 set_multiply_factor(2.0);
119 set_maximum_backoff(base::TimeDelta::FromSeconds(1600));
121 // This means backoff starts after the second "failure", which is the third
122 // captive portal test in a row that ends up with the same result. Since
123 // the first request uses no delay, this means the delays will be in
124 // the pattern 0, 0, 100, 200, 400, etc. There are two zeros because the
125 // first check never has a delay, and the first check to have a new result
126 // is followed by no delay.
127 set_num_errors_to_ignore(1);
129 EnableCaptivePortalDetectionPreference(true);
132 // Sets the captive portal checking preference.
133 void EnableCaptivePortalDetectionPreference(bool enabled
) {
134 profile()->GetPrefs()->SetBoolean(prefs::kAlternateErrorPagesEnabled
,
138 // Triggers a captive portal check, then simulates the URL request
139 // returning with the specified |net_error| and |status_code|. If |net_error|
140 // is not OK, |status_code| is ignored. Expects the CaptivePortalService to
141 // return |expected_result|.
143 // |expected_delay_secs| is the expected value of GetTimeUntilNextRequest().
144 // The function makes sure the value is as expected, and then simulates
145 // waiting for that period of time before running the test.
147 // If |response_headers| is non-NULL, the response will use it as headers
148 // for the simulate URL request. It must use single linefeeds as line breaks.
149 void RunTest(Result expected_result
,
152 int expected_delay_secs
,
153 const char* response_headers
) {
154 base::TimeDelta expected_delay
=
155 base::TimeDelta::FromSeconds(expected_delay_secs
);
157 ASSERT_EQ(CaptivePortalService::STATE_IDLE
, service()->state());
158 ASSERT_EQ(expected_delay
, GetTimeUntilNextRequest());
160 AdvanceTime(expected_delay
);
161 ASSERT_EQ(base::TimeDelta(), GetTimeUntilNextRequest());
163 CaptivePortalObserver
observer(profile(), service());
164 service()->DetectCaptivePortal();
166 EXPECT_EQ(CaptivePortalService::STATE_TIMER_RUNNING
, service()->state());
167 EXPECT_FALSE(FetchingURL());
168 ASSERT_TRUE(TimerRunning());
170 MessageLoop::current()->RunUntilIdle();
171 EXPECT_EQ(CaptivePortalService::STATE_CHECKING_FOR_PORTAL
,
173 ASSERT_TRUE(FetchingURL());
174 EXPECT_FALSE(TimerRunning());
176 CompleteURLFetch(net_error
, status_code
, response_headers
);
178 EXPECT_FALSE(FetchingURL());
179 EXPECT_FALSE(TimerRunning());
180 EXPECT_EQ(1, observer
.num_results_received());
181 EXPECT_EQ(expected_result
, observer
.captive_portal_result());
184 // Runs a test when the captive portal service is disabled.
185 void RunDisabledTest(int expected_delay_secs
) {
186 base::TimeDelta expected_delay
=
187 base::TimeDelta::FromSeconds(expected_delay_secs
);
189 ASSERT_EQ(CaptivePortalService::STATE_IDLE
, service()->state());
190 ASSERT_EQ(expected_delay
, GetTimeUntilNextRequest());
192 AdvanceTime(expected_delay
);
193 ASSERT_EQ(base::TimeDelta(), GetTimeUntilNextRequest());
195 CaptivePortalObserver
observer(profile(), service());
196 service()->DetectCaptivePortal();
198 EXPECT_EQ(CaptivePortalService::STATE_TIMER_RUNNING
, service()->state());
199 EXPECT_FALSE(FetchingURL());
200 ASSERT_TRUE(TimerRunning());
202 MessageLoop::current()->RunUntilIdle();
203 EXPECT_FALSE(FetchingURL());
204 EXPECT_FALSE(TimerRunning());
205 EXPECT_EQ(1, observer
.num_results_received());
206 EXPECT_EQ(RESULT_INTERNET_CONNECTED
, observer
.captive_portal_result());
209 // Tests exponential backoff. Prior to calling, the relevant recheck settings
210 // must be set to have a minimum time of 100 seconds, with 2 checks before
211 // starting exponential backoff.
212 void RunBackoffTest(Result expected_result
, int net_error
, int status_code
) {
213 RunTest(expected_result
, net_error
, status_code
, 0, NULL
);
214 RunTest(expected_result
, net_error
, status_code
, 0, NULL
);
215 RunTest(expected_result
, net_error
, status_code
, 100, NULL
);
216 RunTest(expected_result
, net_error
, status_code
, 200, NULL
);
217 RunTest(expected_result
, net_error
, status_code
, 400, NULL
);
218 RunTest(expected_result
, net_error
, status_code
, 800, NULL
);
219 RunTest(expected_result
, net_error
, status_code
, 1600, NULL
);
220 RunTest(expected_result
, net_error
, status_code
, 1600, NULL
);
223 // Changes test time for the service and service's captive portal
225 void AdvanceTime(const base::TimeDelta
& delta
) {
226 service()->advance_time_ticks_for_testing(delta
);
227 CaptivePortalDetectorTestBase::AdvanceTime(delta
);
230 bool TimerRunning() {
231 return service()->TimerRunning();
234 base::TimeDelta
GetTimeUntilNextRequest() {
235 return service()->backoff_entry_
->GetTimeUntilRelease();
238 void set_initial_backoff_no_portal(
239 base::TimeDelta initial_backoff_no_portal
) {
240 service()->recheck_policy().initial_backoff_no_portal_ms
=
241 initial_backoff_no_portal
.InMilliseconds();
244 void set_initial_backoff_portal(base::TimeDelta initial_backoff_portal
) {
245 service()->recheck_policy().initial_backoff_portal_ms
=
246 initial_backoff_portal
.InMilliseconds();
249 void set_maximum_backoff(base::TimeDelta maximum_backoff
) {
250 service()->recheck_policy().backoff_policy
.maximum_backoff_ms
=
251 maximum_backoff
.InMilliseconds();
254 void set_num_errors_to_ignore(int num_errors_to_ignore
) {
255 service()->recheck_policy().backoff_policy
.num_errors_to_ignore
=
256 num_errors_to_ignore
;
259 void set_multiply_factor(double multiply_factor
) {
260 service()->recheck_policy().backoff_policy
.multiply_factor
=
264 void set_jitter_factor(double jitter_factor
) {
265 service()->recheck_policy().backoff_policy
.jitter_factor
= jitter_factor
;
268 TestingProfile
* profile() { return profile_
.get(); }
270 CaptivePortalService
* service() { return service_
.get(); }
273 // Stores the initial CaptivePortalService::TestingState so it can be restored
275 const CaptivePortalService::TestingState old_captive_portal_testing_state_
;
277 MessageLoop message_loop_
;
279 // Note that the construction order of these matters.
280 scoped_ptr
<TestingProfile
> profile_
;
281 scoped_ptr
<CaptivePortalService
> service_
;
284 // Verify that an observer doesn't get messages from the wrong profile.
285 TEST_F(CaptivePortalServiceTest
, CaptivePortalTwoProfiles
) {
286 Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING
);
287 TestingProfile profile2
;
288 scoped_ptr
<CaptivePortalService
> service2(
289 new CaptivePortalService(&profile2
));
290 CaptivePortalObserver
observer2(&profile2
, service2
.get());
292 RunTest(RESULT_INTERNET_CONNECTED
, net::OK
, 204, 0, NULL
);
293 EXPECT_EQ(0, observer2
.num_results_received());
296 // Checks exponential backoff when the Internet is connected.
297 TEST_F(CaptivePortalServiceTest
, CaptivePortalRecheckInternetConnected
) {
298 Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING
);
300 // This value should have no effect on this test, until the end.
301 set_initial_backoff_portal(base::TimeDelta::FromSeconds(1));
303 set_initial_backoff_no_portal(base::TimeDelta::FromSeconds(100));
304 RunBackoffTest(RESULT_INTERNET_CONNECTED
, net::OK
, 204);
306 // Make sure that getting a new result resets the timer.
307 RunTest(RESULT_BEHIND_CAPTIVE_PORTAL
, net::OK
, 200, 1600, NULL
);
308 RunTest(RESULT_BEHIND_CAPTIVE_PORTAL
, net::OK
, 200, 0, NULL
);
309 RunTest(RESULT_BEHIND_CAPTIVE_PORTAL
, net::OK
, 200, 1, NULL
);
310 RunTest(RESULT_BEHIND_CAPTIVE_PORTAL
, net::OK
, 200, 2, NULL
);
313 // Checks exponential backoff when there's an HTTP error.
314 TEST_F(CaptivePortalServiceTest
, CaptivePortalRecheckError
) {
315 Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING
);
317 // This value should have no effect on this test.
318 set_initial_backoff_portal(base::TimeDelta::FromDays(1));
320 set_initial_backoff_no_portal(base::TimeDelta::FromSeconds(100));
321 RunBackoffTest(RESULT_NO_RESPONSE
, net::OK
, 500);
323 // Make sure that getting a new result resets the timer.
324 RunTest(RESULT_INTERNET_CONNECTED
, net::OK
, 204, 1600, NULL
);
325 RunTest(RESULT_INTERNET_CONNECTED
, net::OK
, 204, 0, NULL
);
326 RunTest(RESULT_INTERNET_CONNECTED
, net::OK
, 204, 100, NULL
);
329 // Checks exponential backoff when there's a captive portal.
330 TEST_F(CaptivePortalServiceTest
, CaptivePortalRecheckBehindPortal
) {
331 Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING
);
333 // This value should have no effect on this test, until the end.
334 set_initial_backoff_no_portal(base::TimeDelta::FromSeconds(250));
336 set_initial_backoff_portal(base::TimeDelta::FromSeconds(100));
337 RunBackoffTest(RESULT_BEHIND_CAPTIVE_PORTAL
, net::OK
, 200);
339 // Make sure that getting a new result resets the timer.
340 RunTest(RESULT_INTERNET_CONNECTED
, net::OK
, 204, 1600, NULL
);
341 RunTest(RESULT_INTERNET_CONNECTED
, net::OK
, 204, 0, NULL
);
342 RunTest(RESULT_INTERNET_CONNECTED
, net::OK
, 204, 250, NULL
);
345 // Check that everything works as expected when captive portal checking is
346 // disabled, including throttling. Then enables it again and runs another test.
347 TEST_F(CaptivePortalServiceTest
, CaptivePortalPrefDisabled
) {
348 Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING
);
350 // This value should have no effect on this test.
351 set_initial_backoff_no_portal(base::TimeDelta::FromDays(1));
353 set_initial_backoff_portal(base::TimeDelta::FromSeconds(100));
355 EnableCaptivePortalDetectionPreference(false);
358 for (int i
= 0; i
< 6; ++i
)
359 RunDisabledTest(100);
361 EnableCaptivePortalDetectionPreference(true);
363 RunTest(RESULT_BEHIND_CAPTIVE_PORTAL
, net::OK
, 200, 0, NULL
);
366 // Check that disabling the captive portal service while a check is running
368 TEST_F(CaptivePortalServiceTest
, CaptivePortalPrefDisabledWhileRunning
) {
369 Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING
);
370 CaptivePortalObserver
observer(profile(), service());
372 // Needed to create the URLFetcher, even if it never returns any results.
373 service()->DetectCaptivePortal();
375 MessageLoop::current()->RunUntilIdle();
376 EXPECT_TRUE(FetchingURL());
377 EXPECT_FALSE(TimerRunning());
379 EnableCaptivePortalDetectionPreference(false);
380 EXPECT_FALSE(FetchingURL());
381 EXPECT_TRUE(TimerRunning());
382 EXPECT_EQ(0, observer
.num_results_received());
384 MessageLoop::current()->RunUntilIdle();
386 EXPECT_FALSE(FetchingURL());
387 EXPECT_FALSE(TimerRunning());
388 EXPECT_EQ(1, observer
.num_results_received());
390 EXPECT_EQ(RESULT_INTERNET_CONNECTED
, observer
.captive_portal_result());
393 // Check that disabling the captive portal service while a check is pending
395 TEST_F(CaptivePortalServiceTest
, CaptivePortalPrefDisabledWhilePending
) {
396 Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING
);
397 set_initial_backoff_no_portal(base::TimeDelta::FromDays(1));
399 CaptivePortalObserver
observer(profile(), service());
400 service()->DetectCaptivePortal();
401 EXPECT_FALSE(FetchingURL());
402 EXPECT_TRUE(TimerRunning());
404 EnableCaptivePortalDetectionPreference(false);
405 EXPECT_FALSE(FetchingURL());
406 EXPECT_TRUE(TimerRunning());
407 EXPECT_EQ(0, observer
.num_results_received());
409 MessageLoop::current()->RunUntilIdle();
411 EXPECT_FALSE(FetchingURL());
412 EXPECT_FALSE(TimerRunning());
413 EXPECT_EQ(1, observer
.num_results_received());
415 EXPECT_EQ(RESULT_INTERNET_CONNECTED
, observer
.captive_portal_result());
418 // Check that disabling the captive portal service while a check is pending
420 TEST_F(CaptivePortalServiceTest
, CaptivePortalPrefEnabledWhilePending
) {
421 Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING
);
423 EnableCaptivePortalDetectionPreference(false);
426 CaptivePortalObserver
observer(profile(), service());
427 service()->DetectCaptivePortal();
428 EXPECT_FALSE(FetchingURL());
429 EXPECT_TRUE(TimerRunning());
431 EnableCaptivePortalDetectionPreference(true);
432 EXPECT_FALSE(FetchingURL());
433 EXPECT_TRUE(TimerRunning());
435 MessageLoop::current()->RunUntilIdle();
436 ASSERT_TRUE(FetchingURL());
437 EXPECT_FALSE(TimerRunning());
439 CompleteURLFetch(net::OK
, 200, NULL
);
440 EXPECT_FALSE(FetchingURL());
441 EXPECT_FALSE(TimerRunning());
443 EXPECT_EQ(1, observer
.num_results_received());
444 EXPECT_EQ(RESULT_BEHIND_CAPTIVE_PORTAL
, observer
.captive_portal_result());
447 // Checks that disabling for browser tests works as expected.
448 TEST_F(CaptivePortalServiceTest
, CaptivePortalDisableForTests
) {
449 Initialize(CaptivePortalService::DISABLED_FOR_TESTING
);
453 // Checks that jitter gives us values in the correct range.
454 TEST_F(CaptivePortalServiceTest
, CaptivePortalJitter
) {
455 Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING
);
456 set_jitter_factor(0.3);
457 set_initial_backoff_no_portal(base::TimeDelta::FromSeconds(100));
458 RunTest(RESULT_INTERNET_CONNECTED
, net::OK
, 204, 0, NULL
);
459 RunTest(RESULT_INTERNET_CONNECTED
, net::OK
, 204, 0, NULL
);
461 for (int i
= 0; i
< 50; ++i
) {
462 int interval_sec
= GetTimeUntilNextRequest().InSeconds();
463 // Allow for roundoff, though shouldn't be necessary.
464 EXPECT_LE(69, interval_sec
);
465 EXPECT_LE(interval_sec
, 101);
469 // Check a Retry-After header that contains a delay in seconds.
470 TEST_F(CaptivePortalServiceTest
, CaptivePortalRetryAfterSeconds
) {
471 Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING
);
472 set_initial_backoff_no_portal(base::TimeDelta::FromSeconds(100));
473 const char* retry_after
= "HTTP/1.1 503 OK\nRetry-After: 101\n\n";
475 // Check that Retry-After headers work both on the first request to return a
476 // result and on subsequent requests.
477 RunTest(RESULT_NO_RESPONSE
, net::OK
, 503, 0, retry_after
);
478 RunTest(RESULT_NO_RESPONSE
, net::OK
, 503, 101, retry_after
);
479 RunTest(RESULT_INTERNET_CONNECTED
, net::OK
, 204, 101, NULL
);
481 // Make sure that there's no effect on the next captive portal check after
483 EXPECT_EQ(base::TimeDelta::FromSeconds(0), GetTimeUntilNextRequest());
486 // Check that the RecheckPolicy is still respected on 503 responses with
487 // Retry-After headers.
488 TEST_F(CaptivePortalServiceTest
, CaptivePortalRetryAfterSecondsTooShort
) {
489 Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING
);
490 set_initial_backoff_no_portal(base::TimeDelta::FromSeconds(100));
491 const char* retry_after
= "HTTP/1.1 503 OK\nRetry-After: 99\n\n";
493 RunTest(RESULT_NO_RESPONSE
, net::OK
, 503, 0, retry_after
);
494 // Normally would be no delay on the first check with a new result.
495 RunTest(RESULT_NO_RESPONSE
, net::OK
, 503, 99, retry_after
);
496 EXPECT_EQ(base::TimeDelta::FromSeconds(100), GetTimeUntilNextRequest());
499 // Check a Retry-After header that contains a date.
500 TEST_F(CaptivePortalServiceTest
, CaptivePortalRetryAfterDate
) {
501 Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING
);
502 set_initial_backoff_no_portal(base::TimeDelta::FromSeconds(50));
504 // base has a function to get a time in the right format from a string, but
505 // not the other way around.
506 base::Time start_time
;
508 base::Time::FromString("Tue, 17 Apr 2012 18:02:00 GMT", &start_time
));
511 RunTest(RESULT_NO_RESPONSE
,
515 "HTTP/1.1 503 OK\nRetry-After: Tue, 17 Apr 2012 18:02:51 GMT\n\n");
516 EXPECT_EQ(base::TimeDelta::FromSeconds(51), GetTimeUntilNextRequest());
519 } // namespace captive_portal