Refactor net::BackoffEntry to not require subclassing
[chromium-blink-merge.git] / chrome / browser / captive_portal / captive_portal_service_unittest.cc
blob0d335486ac6e9f1a8cb07cb7f94faaefa2fe1aca
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"
8 #include "base/bind.h"
9 #include "base/command_line.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/run_loop.h"
12 #include "base/test/simple_test_tick_clock.h"
13 #include "base/test/test_timeouts.h"
14 #include "chrome/browser/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 "components/captive_portal/captive_portal_testing_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 "content/public/test/test_browser_thread_bundle.h"
24 #include "net/base/net_errors.h"
25 #include "testing/gtest/include/gtest/gtest.h"
27 using captive_portal::CaptivePortalDetectorTestBase;
28 using captive_portal::CaptivePortalResult;
30 namespace {
32 // An observer watches the CaptivePortalDetector. It tracks the last
33 // received result and the total number of received results.
34 class CaptivePortalObserver : public content::NotificationObserver {
35 public:
36 CaptivePortalObserver(Profile* profile,
37 CaptivePortalService* captive_portal_service)
38 : captive_portal_result_(
39 captive_portal_service->last_detection_result()),
40 num_results_received_(0),
41 profile_(profile),
42 captive_portal_service_(captive_portal_service) {
43 registrar_.Add(this,
44 chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT,
45 content::Source<Profile>(profile_));
48 CaptivePortalResult captive_portal_result() const {
49 return captive_portal_result_;
52 int num_results_received() const { return num_results_received_; }
54 private:
55 void Observe(int type,
56 const content::NotificationSource& source,
57 const content::NotificationDetails& details) override {
58 ASSERT_EQ(type, chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT);
59 ASSERT_EQ(profile_, content::Source<Profile>(source).ptr());
61 CaptivePortalService::Results *results =
62 content::Details<CaptivePortalService::Results>(details).ptr();
64 EXPECT_EQ(captive_portal_result_, results->previous_result);
65 EXPECT_EQ(captive_portal_service_->last_detection_result(),
66 results->result);
68 captive_portal_result_ = results->result;
69 ++num_results_received_;
72 CaptivePortalResult captive_portal_result_;
73 int num_results_received_;
75 Profile* profile_;
76 CaptivePortalService* captive_portal_service_;
78 content::NotificationRegistrar registrar_;
80 DISALLOW_COPY_AND_ASSIGN(CaptivePortalObserver);
83 } // namespace
85 class CaptivePortalServiceTest : public testing::Test,
86 public CaptivePortalDetectorTestBase {
87 public:
88 CaptivePortalServiceTest()
89 : old_captive_portal_testing_state_(
90 CaptivePortalService::get_state_for_testing()) {
93 ~CaptivePortalServiceTest() override {
94 CaptivePortalService::set_state_for_testing(
95 old_captive_portal_testing_state_);
98 // |enable_service| is whether or not the captive portal service itself
99 // should be disabled. This is different from enabling the captive portal
100 // detection preference.
101 void Initialize(CaptivePortalService::TestingState testing_state) {
102 CaptivePortalService::set_state_for_testing(testing_state);
104 profile_.reset(new TestingProfile());
105 tick_clock_.reset(new base::SimpleTestTickClock());
106 tick_clock_->Advance(base::TimeTicks::Now() - tick_clock_->NowTicks());
107 service_.reset(new CaptivePortalService(profile_.get(), tick_clock_.get()));
109 // Use no delays for most tests.
110 set_initial_backoff_no_portal(base::TimeDelta());
111 set_initial_backoff_portal(base::TimeDelta());
113 set_detector(&service_->captive_portal_detector_);
114 SetTime(base::Time::Now());
116 // Disable jitter, so can check exact values.
117 set_jitter_factor(0.0);
119 // These values make checking exponential backoff easier.
120 set_multiply_factor(2.0);
121 set_maximum_backoff(base::TimeDelta::FromSeconds(1600));
123 // This means backoff starts after the second "failure", which is the third
124 // captive portal test in a row that ends up with the same result. Since
125 // the first request uses no delay, this means the delays will be in
126 // the pattern 0, 0, 100, 200, 400, etc. There are two zeros because the
127 // first check never has a delay, and the first check to have a new result
128 // is followed by no delay.
129 set_num_errors_to_ignore(1);
131 EnableCaptivePortalDetectionPreference(true);
134 // Sets the captive portal checking preference.
135 void EnableCaptivePortalDetectionPreference(bool enabled) {
136 profile()->GetPrefs()->SetBoolean(prefs::kAlternateErrorPagesEnabled,
137 enabled);
140 // Triggers a captive portal check, then simulates the URL request
141 // returning with the specified |net_error| and |status_code|. If |net_error|
142 // is not OK, |status_code| is ignored. Expects the CaptivePortalService to
143 // return |expected_result|.
145 // |expected_delay_secs| is the expected value of GetTimeUntilNextRequest().
146 // The function makes sure the value is as expected, and then simulates
147 // waiting for that period of time before running the test.
149 // If |response_headers| is non-NULL, the response will use it as headers
150 // for the simulate URL request. It must use single linefeeds as line breaks.
151 void RunTest(CaptivePortalResult expected_result,
152 int net_error,
153 int status_code,
154 int expected_delay_secs,
155 const char* response_headers) {
156 base::TimeDelta expected_delay =
157 base::TimeDelta::FromSeconds(expected_delay_secs);
159 ASSERT_EQ(CaptivePortalService::STATE_IDLE, service()->state());
160 ASSERT_EQ(expected_delay, GetTimeUntilNextRequest());
162 AdvanceTime(expected_delay);
163 ASSERT_EQ(base::TimeDelta(), GetTimeUntilNextRequest());
165 CaptivePortalObserver observer(profile(), service());
166 service()->DetectCaptivePortal();
168 EXPECT_EQ(CaptivePortalService::STATE_TIMER_RUNNING, service()->state());
169 EXPECT_FALSE(FetchingURL());
170 ASSERT_TRUE(TimerRunning());
172 base::RunLoop().RunUntilIdle();
173 EXPECT_EQ(CaptivePortalService::STATE_CHECKING_FOR_PORTAL,
174 service()->state());
175 ASSERT_TRUE(FetchingURL());
176 EXPECT_FALSE(TimerRunning());
178 CompleteURLFetch(net_error, status_code, response_headers);
180 EXPECT_FALSE(FetchingURL());
181 EXPECT_FALSE(TimerRunning());
182 EXPECT_EQ(1, observer.num_results_received());
183 EXPECT_EQ(expected_result, observer.captive_portal_result());
186 // Runs a test when the captive portal service is disabled.
187 void RunDisabledTest(int expected_delay_secs) {
188 base::TimeDelta expected_delay =
189 base::TimeDelta::FromSeconds(expected_delay_secs);
191 ASSERT_EQ(CaptivePortalService::STATE_IDLE, service()->state());
192 ASSERT_EQ(expected_delay, GetTimeUntilNextRequest());
194 AdvanceTime(expected_delay);
195 ASSERT_EQ(base::TimeDelta(), GetTimeUntilNextRequest());
197 CaptivePortalObserver observer(profile(), service());
198 service()->DetectCaptivePortal();
200 EXPECT_EQ(CaptivePortalService::STATE_TIMER_RUNNING, service()->state());
201 EXPECT_FALSE(FetchingURL());
202 ASSERT_TRUE(TimerRunning());
204 base::RunLoop().RunUntilIdle();
205 EXPECT_FALSE(FetchingURL());
206 EXPECT_FALSE(TimerRunning());
207 EXPECT_EQ(1, observer.num_results_received());
208 EXPECT_EQ(captive_portal::RESULT_INTERNET_CONNECTED,
209 observer.captive_portal_result());
212 // Tests exponential backoff. Prior to calling, the relevant recheck settings
213 // must be set to have a minimum time of 100 seconds, with 2 checks before
214 // starting exponential backoff.
215 void RunBackoffTest(CaptivePortalResult expected_result,
216 int net_error,
217 int status_code) {
218 RunTest(expected_result, net_error, status_code, 0, NULL);
219 RunTest(expected_result, net_error, status_code, 0, NULL);
220 RunTest(expected_result, net_error, status_code, 100, NULL);
221 RunTest(expected_result, net_error, status_code, 200, NULL);
222 RunTest(expected_result, net_error, status_code, 400, NULL);
223 RunTest(expected_result, net_error, status_code, 800, NULL);
224 RunTest(expected_result, net_error, status_code, 1600, NULL);
225 RunTest(expected_result, net_error, status_code, 1600, NULL);
228 // Changes test time for the service and service's captive portal
229 // detector.
230 void AdvanceTime(const base::TimeDelta& delta) {
231 tick_clock_->Advance(delta);
232 CaptivePortalDetectorTestBase::AdvanceTime(delta);
235 bool TimerRunning() {
236 return service()->TimerRunning();
239 base::TimeDelta GetTimeUntilNextRequest() {
240 return service()->backoff_entry_->GetTimeUntilRelease();
243 void set_initial_backoff_no_portal(
244 base::TimeDelta initial_backoff_no_portal) {
245 service()->recheck_policy().initial_backoff_no_portal_ms =
246 initial_backoff_no_portal.InMilliseconds();
249 void set_initial_backoff_portal(base::TimeDelta initial_backoff_portal) {
250 service()->recheck_policy().initial_backoff_portal_ms =
251 initial_backoff_portal.InMilliseconds();
254 void set_maximum_backoff(base::TimeDelta maximum_backoff) {
255 service()->recheck_policy().backoff_policy.maximum_backoff_ms =
256 maximum_backoff.InMilliseconds();
259 void set_num_errors_to_ignore(int num_errors_to_ignore) {
260 service()->recheck_policy().backoff_policy.num_errors_to_ignore =
261 num_errors_to_ignore;
264 void set_multiply_factor(double multiply_factor) {
265 service()->recheck_policy().backoff_policy.multiply_factor =
266 multiply_factor;
269 void set_jitter_factor(double jitter_factor) {
270 service()->recheck_policy().backoff_policy.jitter_factor = jitter_factor;
273 TestingProfile* profile() { return profile_.get(); }
275 CaptivePortalService* service() { return service_.get(); }
277 private:
278 // Stores the initial CaptivePortalService::TestingState so it can be restored
279 // after the test.
280 const CaptivePortalService::TestingState old_captive_portal_testing_state_;
282 content::TestBrowserThreadBundle thread_bundle_;
284 // Note that the construction order of these matters.
285 scoped_ptr<TestingProfile> profile_;
286 scoped_ptr<base::SimpleTestTickClock> tick_clock_;
287 scoped_ptr<CaptivePortalService> service_;
290 // Verify that an observer doesn't get messages from the wrong profile.
291 TEST_F(CaptivePortalServiceTest, CaptivePortalTwoProfiles) {
292 Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
293 TestingProfile profile2;
294 scoped_ptr<CaptivePortalService> service2(
295 new CaptivePortalService(&profile2));
296 CaptivePortalObserver observer2(&profile2, service2.get());
298 RunTest(captive_portal::RESULT_INTERNET_CONNECTED, net::OK, 204, 0, NULL);
299 EXPECT_EQ(0, observer2.num_results_received());
302 // Checks exponential backoff when the Internet is connected.
303 TEST_F(CaptivePortalServiceTest, CaptivePortalRecheckInternetConnected) {
304 Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
306 // This value should have no effect on this test, until the end.
307 set_initial_backoff_portal(base::TimeDelta::FromSeconds(1));
309 set_initial_backoff_no_portal(base::TimeDelta::FromSeconds(100));
310 RunBackoffTest(captive_portal::RESULT_INTERNET_CONNECTED, net::OK, 204);
312 // Make sure that getting a new result resets the timer.
313 RunTest(
314 captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL, net::OK, 200, 1600, NULL);
315 RunTest(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL, net::OK, 200, 0, NULL);
316 RunTest(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL, net::OK, 200, 1, NULL);
317 RunTest(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL, net::OK, 200, 2, NULL);
320 // Checks exponential backoff when there's an HTTP error.
321 TEST_F(CaptivePortalServiceTest, CaptivePortalRecheckError) {
322 Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
324 // This value should have no effect on this test.
325 set_initial_backoff_portal(base::TimeDelta::FromDays(1));
327 set_initial_backoff_no_portal(base::TimeDelta::FromSeconds(100));
328 RunBackoffTest(captive_portal::RESULT_NO_RESPONSE, net::OK, 500);
330 // Make sure that getting a new result resets the timer.
331 RunTest(captive_portal::RESULT_INTERNET_CONNECTED, net::OK, 204, 1600, NULL);
332 RunTest(captive_portal::RESULT_INTERNET_CONNECTED, net::OK, 204, 0, NULL);
333 RunTest(captive_portal::RESULT_INTERNET_CONNECTED, net::OK, 204, 100, NULL);
336 // Checks exponential backoff when there's a captive portal.
337 TEST_F(CaptivePortalServiceTest, CaptivePortalRecheckBehindPortal) {
338 Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
340 // This value should have no effect on this test, until the end.
341 set_initial_backoff_no_portal(base::TimeDelta::FromSeconds(250));
343 set_initial_backoff_portal(base::TimeDelta::FromSeconds(100));
344 RunBackoffTest(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL, net::OK, 200);
346 // Make sure that getting a new result resets the timer.
347 RunTest(captive_portal::RESULT_INTERNET_CONNECTED, net::OK, 204, 1600, NULL);
348 RunTest(captive_portal::RESULT_INTERNET_CONNECTED, net::OK, 204, 0, NULL);
349 RunTest(captive_portal::RESULT_INTERNET_CONNECTED, net::OK, 204, 250, NULL);
352 // Check that everything works as expected when captive portal checking is
353 // disabled, including throttling. Then enables it again and runs another test.
354 TEST_F(CaptivePortalServiceTest, CaptivePortalPrefDisabled) {
355 Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
357 // This value should have no effect on this test.
358 set_initial_backoff_no_portal(base::TimeDelta::FromDays(1));
360 set_initial_backoff_portal(base::TimeDelta::FromSeconds(100));
362 EnableCaptivePortalDetectionPreference(false);
364 RunDisabledTest(0);
365 for (int i = 0; i < 6; ++i)
366 RunDisabledTest(100);
368 EnableCaptivePortalDetectionPreference(true);
370 RunTest(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL, net::OK, 200, 0, NULL);
373 // Check that disabling the captive portal service while a check is running
374 // works.
375 TEST_F(CaptivePortalServiceTest, CaptivePortalPrefDisabledWhileRunning) {
376 Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
377 CaptivePortalObserver observer(profile(), service());
379 // Needed to create the URLFetcher, even if it never returns any results.
380 service()->DetectCaptivePortal();
382 base::RunLoop().RunUntilIdle();
383 EXPECT_TRUE(FetchingURL());
384 EXPECT_FALSE(TimerRunning());
386 EnableCaptivePortalDetectionPreference(false);
387 EXPECT_FALSE(FetchingURL());
388 EXPECT_TRUE(TimerRunning());
389 EXPECT_EQ(0, observer.num_results_received());
391 base::RunLoop().RunUntilIdle();
393 EXPECT_FALSE(FetchingURL());
394 EXPECT_FALSE(TimerRunning());
395 EXPECT_EQ(1, observer.num_results_received());
397 EXPECT_EQ(captive_portal::RESULT_INTERNET_CONNECTED,
398 observer.captive_portal_result());
401 // Check that disabling the captive portal service while a check is pending
402 // works.
403 TEST_F(CaptivePortalServiceTest, CaptivePortalPrefDisabledWhilePending) {
404 Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
405 set_initial_backoff_no_portal(base::TimeDelta::FromDays(1));
407 CaptivePortalObserver observer(profile(), service());
408 service()->DetectCaptivePortal();
409 EXPECT_FALSE(FetchingURL());
410 EXPECT_TRUE(TimerRunning());
412 EnableCaptivePortalDetectionPreference(false);
413 EXPECT_FALSE(FetchingURL());
414 EXPECT_TRUE(TimerRunning());
415 EXPECT_EQ(0, observer.num_results_received());
417 base::RunLoop().RunUntilIdle();
419 EXPECT_FALSE(FetchingURL());
420 EXPECT_FALSE(TimerRunning());
421 EXPECT_EQ(1, observer.num_results_received());
423 EXPECT_EQ(captive_portal::RESULT_INTERNET_CONNECTED,
424 observer.captive_portal_result());
427 // Check that disabling the captive portal service while a check is pending
428 // works.
429 TEST_F(CaptivePortalServiceTest, CaptivePortalPrefEnabledWhilePending) {
430 Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
432 EnableCaptivePortalDetectionPreference(false);
433 RunDisabledTest(0);
435 CaptivePortalObserver observer(profile(), service());
436 service()->DetectCaptivePortal();
437 EXPECT_FALSE(FetchingURL());
438 EXPECT_TRUE(TimerRunning());
440 EnableCaptivePortalDetectionPreference(true);
441 EXPECT_FALSE(FetchingURL());
442 EXPECT_TRUE(TimerRunning());
444 base::RunLoop().RunUntilIdle();
445 ASSERT_TRUE(FetchingURL());
446 EXPECT_FALSE(TimerRunning());
448 CompleteURLFetch(net::OK, 200, NULL);
449 EXPECT_FALSE(FetchingURL());
450 EXPECT_FALSE(TimerRunning());
452 EXPECT_EQ(1, observer.num_results_received());
453 EXPECT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
454 observer.captive_portal_result());
457 // Checks that disabling for browser tests works as expected.
458 TEST_F(CaptivePortalServiceTest, CaptivePortalDisableForTests) {
459 Initialize(CaptivePortalService::DISABLED_FOR_TESTING);
460 RunDisabledTest(0);
463 // Checks that jitter gives us values in the correct range.
464 TEST_F(CaptivePortalServiceTest, CaptivePortalJitter) {
465 Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
466 set_jitter_factor(0.3);
467 set_initial_backoff_no_portal(base::TimeDelta::FromSeconds(100));
468 RunTest(captive_portal::RESULT_INTERNET_CONNECTED, net::OK, 204, 0, NULL);
469 RunTest(captive_portal::RESULT_INTERNET_CONNECTED, net::OK, 204, 0, NULL);
471 for (int i = 0; i < 50; ++i) {
472 int interval_sec = GetTimeUntilNextRequest().InSeconds();
473 // Allow for roundoff, though shouldn't be necessary.
474 EXPECT_LE(69, interval_sec);
475 EXPECT_LE(interval_sec, 101);
479 // Check a Retry-After header that contains a delay in seconds.
480 TEST_F(CaptivePortalServiceTest, CaptivePortalRetryAfterSeconds) {
481 Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
482 set_initial_backoff_no_portal(base::TimeDelta::FromSeconds(100));
483 const char* retry_after = "HTTP/1.1 503 OK\nRetry-After: 101\n\n";
485 // Check that Retry-After headers work both on the first request to return a
486 // result and on subsequent requests.
487 RunTest(captive_portal::RESULT_NO_RESPONSE, net::OK, 503, 0, retry_after);
488 RunTest(captive_portal::RESULT_NO_RESPONSE, net::OK, 503, 101, retry_after);
489 RunTest(captive_portal::RESULT_INTERNET_CONNECTED, net::OK, 204, 101, NULL);
491 // Make sure that there's no effect on the next captive portal check after
492 // login.
493 EXPECT_EQ(base::TimeDelta::FromSeconds(0), GetTimeUntilNextRequest());
496 // Check that the RecheckPolicy is still respected on 503 responses with
497 // Retry-After headers.
498 TEST_F(CaptivePortalServiceTest, CaptivePortalRetryAfterSecondsTooShort) {
499 Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
500 set_initial_backoff_no_portal(base::TimeDelta::FromSeconds(100));
501 const char* retry_after = "HTTP/1.1 503 OK\nRetry-After: 99\n\n";
503 RunTest(captive_portal::RESULT_NO_RESPONSE, net::OK, 503, 0, retry_after);
504 // Normally would be no delay on the first check with a new result.
505 RunTest(captive_portal::RESULT_NO_RESPONSE, net::OK, 503, 99, retry_after);
506 EXPECT_EQ(base::TimeDelta::FromSeconds(100), GetTimeUntilNextRequest());
509 // Check a Retry-After header that contains a date.
510 TEST_F(CaptivePortalServiceTest, CaptivePortalRetryAfterDate) {
511 Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
512 set_initial_backoff_no_portal(base::TimeDelta::FromSeconds(50));
514 // base has a function to get a time in the right format from a string, but
515 // not the other way around.
516 base::Time start_time;
517 ASSERT_TRUE(
518 base::Time::FromString("Tue, 17 Apr 2012 18:02:00 GMT", &start_time));
519 SetTime(start_time);
521 RunTest(captive_portal::RESULT_NO_RESPONSE,
522 net::OK,
523 503,
525 "HTTP/1.1 503 OK\nRetry-After: Tue, 17 Apr 2012 18:02:51 GMT\n\n");
526 EXPECT_EQ(base::TimeDelta::FromSeconds(51), GetTimeUntilNextRequest());