Home | History | Annotate | Download | only in captive_portal
      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_service.h"
      6 
      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/test_timeouts.h"
     13 #include "chrome/browser/chrome_notification_types.h"
     14 #include "chrome/common/chrome_switches.h"
     15 #include "chrome/common/pref_names.h"
     16 #include "chrome/test/base/testing_profile.h"
     17 #include "chrome/test/base/ui_test_utils.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"
     26 
     27 using captive_portal::CaptivePortalDetectorTestBase;
     28 using captive_portal::CaptivePortalResult;
     29 
     30 namespace {
     31 
     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_));
     46   }
     47 
     48   CaptivePortalResult captive_portal_result() const {
     49     return captive_portal_result_;
     50   }
     51 
     52   int num_results_received() const { return num_results_received_; }
     53 
     54  private:
     55   virtual 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());
     60 
     61     CaptivePortalService::Results *results =
     62         content::Details<CaptivePortalService::Results>(details).ptr();
     63 
     64     EXPECT_EQ(captive_portal_result_, results->previous_result);
     65     EXPECT_EQ(captive_portal_service_->last_detection_result(),
     66               results->result);
     67 
     68     captive_portal_result_ = results->result;
     69     ++num_results_received_;
     70   }
     71 
     72   CaptivePortalResult captive_portal_result_;
     73   int num_results_received_;
     74 
     75   Profile* profile_;
     76   CaptivePortalService* captive_portal_service_;
     77 
     78   content::NotificationRegistrar registrar_;
     79 
     80   DISALLOW_COPY_AND_ASSIGN(CaptivePortalObserver);
     81 };
     82 
     83 }  // namespace
     84 
     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()) {
     91   }
     92 
     93   virtual ~CaptivePortalServiceTest() {
     94     CaptivePortalService::set_state_for_testing(
     95         old_captive_portal_testing_state_);
     96   }
     97 
     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);
    103 
    104     profile_.reset(new TestingProfile());
    105     service_.reset(new CaptivePortalService(profile_.get()));
    106     service_->set_time_ticks_for_testing(base::TimeTicks::Now());
    107 
    108     // Use no delays for most tests.
    109     set_initial_backoff_no_portal(base::TimeDelta());
    110     set_initial_backoff_portal(base::TimeDelta());
    111 
    112     set_detector(&service_->captive_portal_detector_);
    113     SetTime(base::Time::Now());
    114 
    115     // Disable jitter, so can check exact values.
    116     set_jitter_factor(0.0);
    117 
    118     // These values make checking exponential backoff easier.
    119     set_multiply_factor(2.0);
    120     set_maximum_backoff(base::TimeDelta::FromSeconds(1600));
    121 
    122     // This means backoff starts after the second "failure", which is the third
    123     // captive portal test in a row that ends up with the same result.  Since
    124     // the first request uses no delay, this means the delays will be in
    125     // the pattern 0, 0, 100, 200, 400, etc.  There are two zeros because the
    126     // first check never has a delay, and the first check to have a new result
    127     // is followed by no delay.
    128     set_num_errors_to_ignore(1);
    129 
    130     EnableCaptivePortalDetectionPreference(true);
    131   }
    132 
    133   // Sets the captive portal checking preference.
    134   void EnableCaptivePortalDetectionPreference(bool enabled) {
    135     profile()->GetPrefs()->SetBoolean(prefs::kAlternateErrorPagesEnabled,
    136                                       enabled);
    137   }
    138 
    139   // Triggers a captive portal check, then simulates the URL request
    140   // returning with the specified |net_error| and |status_code|.  If |net_error|
    141   // is not OK, |status_code| is ignored.  Expects the CaptivePortalService to
    142   // return |expected_result|.
    143   //
    144   // |expected_delay_secs| is the expected value of GetTimeUntilNextRequest().
    145   // The function makes sure the value is as expected, and then simulates
    146   // waiting for that period of time before running the test.
    147   //
    148   // If |response_headers| is non-NULL, the response will use it as headers
    149   // for the simulate URL request.  It must use single linefeeds as line breaks.
    150   void RunTest(CaptivePortalResult expected_result,
    151                int net_error,
    152                int status_code,
    153                int expected_delay_secs,
    154                const char* response_headers) {
    155     base::TimeDelta expected_delay =
    156         base::TimeDelta::FromSeconds(expected_delay_secs);
    157 
    158     ASSERT_EQ(CaptivePortalService::STATE_IDLE, service()->state());
    159     ASSERT_EQ(expected_delay, GetTimeUntilNextRequest());
    160 
    161     AdvanceTime(expected_delay);
    162     ASSERT_EQ(base::TimeDelta(), GetTimeUntilNextRequest());
    163 
    164     CaptivePortalObserver observer(profile(), service());
    165     service()->DetectCaptivePortal();
    166 
    167     EXPECT_EQ(CaptivePortalService::STATE_TIMER_RUNNING, service()->state());
    168     EXPECT_FALSE(FetchingURL());
    169     ASSERT_TRUE(TimerRunning());
    170 
    171     base::RunLoop().RunUntilIdle();
    172     EXPECT_EQ(CaptivePortalService::STATE_CHECKING_FOR_PORTAL,
    173               service()->state());
    174     ASSERT_TRUE(FetchingURL());
    175     EXPECT_FALSE(TimerRunning());
    176 
    177     CompleteURLFetch(net_error, status_code, response_headers);
    178 
    179     EXPECT_FALSE(FetchingURL());
    180     EXPECT_FALSE(TimerRunning());
    181     EXPECT_EQ(1, observer.num_results_received());
    182     EXPECT_EQ(expected_result, observer.captive_portal_result());
    183   }
    184 
    185   // Runs a test when the captive portal service is disabled.
    186   void RunDisabledTest(int expected_delay_secs) {
    187     base::TimeDelta expected_delay =
    188         base::TimeDelta::FromSeconds(expected_delay_secs);
    189 
    190     ASSERT_EQ(CaptivePortalService::STATE_IDLE, service()->state());
    191     ASSERT_EQ(expected_delay, GetTimeUntilNextRequest());
    192 
    193     AdvanceTime(expected_delay);
    194     ASSERT_EQ(base::TimeDelta(), GetTimeUntilNextRequest());
    195 
    196     CaptivePortalObserver observer(profile(), service());
    197     service()->DetectCaptivePortal();
    198 
    199     EXPECT_EQ(CaptivePortalService::STATE_TIMER_RUNNING, service()->state());
    200     EXPECT_FALSE(FetchingURL());
    201     ASSERT_TRUE(TimerRunning());
    202 
    203     base::RunLoop().RunUntilIdle();
    204     EXPECT_FALSE(FetchingURL());
    205     EXPECT_FALSE(TimerRunning());
    206     EXPECT_EQ(1, observer.num_results_received());
    207     EXPECT_EQ(captive_portal::RESULT_INTERNET_CONNECTED,
    208               observer.captive_portal_result());
    209   }
    210 
    211   // Tests exponential backoff.  Prior to calling, the relevant recheck settings
    212   // must be set to have a minimum time of 100 seconds, with 2 checks before
    213   // starting exponential backoff.
    214   void RunBackoffTest(CaptivePortalResult expected_result,
    215                       int net_error,
    216                       int status_code) {
    217     RunTest(expected_result, net_error, status_code, 0, NULL);
    218     RunTest(expected_result, net_error, status_code, 0, NULL);
    219     RunTest(expected_result, net_error, status_code, 100, NULL);
    220     RunTest(expected_result, net_error, status_code, 200, NULL);
    221     RunTest(expected_result, net_error, status_code, 400, NULL);
    222     RunTest(expected_result, net_error, status_code, 800, NULL);
    223     RunTest(expected_result, net_error, status_code, 1600, NULL);
    224     RunTest(expected_result, net_error, status_code, 1600, NULL);
    225   }
    226 
    227   // Changes test time for the service and service's captive portal
    228   // detector.
    229   void AdvanceTime(const base::TimeDelta& delta) {
    230     service()->advance_time_ticks_for_testing(delta);
    231     CaptivePortalDetectorTestBase::AdvanceTime(delta);
    232   }
    233 
    234   bool TimerRunning() {
    235     return service()->TimerRunning();
    236   }
    237 
    238   base::TimeDelta GetTimeUntilNextRequest() {
    239     return service()->backoff_entry_->GetTimeUntilRelease();
    240   }
    241 
    242   void set_initial_backoff_no_portal(
    243       base::TimeDelta initial_backoff_no_portal) {
    244     service()->recheck_policy().initial_backoff_no_portal_ms =
    245         initial_backoff_no_portal.InMilliseconds();
    246   }
    247 
    248   void set_initial_backoff_portal(base::TimeDelta initial_backoff_portal) {
    249     service()->recheck_policy().initial_backoff_portal_ms =
    250         initial_backoff_portal.InMilliseconds();
    251   }
    252 
    253   void set_maximum_backoff(base::TimeDelta maximum_backoff) {
    254     service()->recheck_policy().backoff_policy.maximum_backoff_ms =
    255         maximum_backoff.InMilliseconds();
    256   }
    257 
    258   void set_num_errors_to_ignore(int num_errors_to_ignore) {
    259     service()->recheck_policy().backoff_policy.num_errors_to_ignore =
    260         num_errors_to_ignore;
    261   }
    262 
    263   void set_multiply_factor(double multiply_factor) {
    264     service()->recheck_policy().backoff_policy.multiply_factor =
    265         multiply_factor;
    266   }
    267 
    268   void set_jitter_factor(double jitter_factor) {
    269     service()->recheck_policy().backoff_policy.jitter_factor = jitter_factor;
    270   }
    271 
    272   TestingProfile* profile() { return profile_.get(); }
    273 
    274   CaptivePortalService* service() { return service_.get(); }
    275 
    276  private:
    277   // Stores the initial CaptivePortalService::TestingState so it can be restored
    278   // after the test.
    279   const CaptivePortalService::TestingState old_captive_portal_testing_state_;
    280 
    281   content::TestBrowserThreadBundle thread_bundle_;
    282 
    283   // Note that the construction order of these matters.
    284   scoped_ptr<TestingProfile> profile_;
    285   scoped_ptr<CaptivePortalService> service_;
    286 };
    287 
    288 // Verify that an observer doesn't get messages from the wrong profile.
    289 TEST_F(CaptivePortalServiceTest, CaptivePortalTwoProfiles) {
    290   Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
    291   TestingProfile profile2;
    292   scoped_ptr<CaptivePortalService> service2(
    293       new CaptivePortalService(&profile2));
    294   CaptivePortalObserver observer2(&profile2, service2.get());
    295 
    296   RunTest(captive_portal::RESULT_INTERNET_CONNECTED, net::OK, 204, 0, NULL);
    297   EXPECT_EQ(0, observer2.num_results_received());
    298 }
    299 
    300 // Checks exponential backoff when the Internet is connected.
    301 TEST_F(CaptivePortalServiceTest, CaptivePortalRecheckInternetConnected) {
    302   Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
    303 
    304   // This value should have no effect on this test, until the end.
    305   set_initial_backoff_portal(base::TimeDelta::FromSeconds(1));
    306 
    307   set_initial_backoff_no_portal(base::TimeDelta::FromSeconds(100));
    308   RunBackoffTest(captive_portal::RESULT_INTERNET_CONNECTED, net::OK, 204);
    309 
    310   // Make sure that getting a new result resets the timer.
    311   RunTest(
    312       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL, net::OK, 200, 1600, NULL);
    313   RunTest(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL, net::OK, 200, 0, NULL);
    314   RunTest(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL, net::OK, 200, 1, NULL);
    315   RunTest(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL, net::OK, 200, 2, NULL);
    316 }
    317 
    318 // Checks exponential backoff when there's an HTTP error.
    319 TEST_F(CaptivePortalServiceTest, CaptivePortalRecheckError) {
    320   Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
    321 
    322   // This value should have no effect on this test.
    323   set_initial_backoff_portal(base::TimeDelta::FromDays(1));
    324 
    325   set_initial_backoff_no_portal(base::TimeDelta::FromSeconds(100));
    326   RunBackoffTest(captive_portal::RESULT_NO_RESPONSE, net::OK, 500);
    327 
    328   // Make sure that getting a new result resets the timer.
    329   RunTest(captive_portal::RESULT_INTERNET_CONNECTED, net::OK, 204, 1600, NULL);
    330   RunTest(captive_portal::RESULT_INTERNET_CONNECTED, net::OK, 204, 0, NULL);
    331   RunTest(captive_portal::RESULT_INTERNET_CONNECTED, net::OK, 204, 100, NULL);
    332 }
    333 
    334 // Checks exponential backoff when there's a captive portal.
    335 TEST_F(CaptivePortalServiceTest, CaptivePortalRecheckBehindPortal) {
    336   Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
    337 
    338   // This value should have no effect on this test, until the end.
    339   set_initial_backoff_no_portal(base::TimeDelta::FromSeconds(250));
    340 
    341   set_initial_backoff_portal(base::TimeDelta::FromSeconds(100));
    342   RunBackoffTest(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL, net::OK, 200);
    343 
    344   // Make sure that getting a new result resets the timer.
    345   RunTest(captive_portal::RESULT_INTERNET_CONNECTED, net::OK, 204, 1600, NULL);
    346   RunTest(captive_portal::RESULT_INTERNET_CONNECTED, net::OK, 204, 0, NULL);
    347   RunTest(captive_portal::RESULT_INTERNET_CONNECTED, net::OK, 204, 250, NULL);
    348 }
    349 
    350 // Check that everything works as expected when captive portal checking is
    351 // disabled, including throttling.  Then enables it again and runs another test.
    352 TEST_F(CaptivePortalServiceTest, CaptivePortalPrefDisabled) {
    353   Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
    354 
    355   // This value should have no effect on this test.
    356   set_initial_backoff_no_portal(base::TimeDelta::FromDays(1));
    357 
    358   set_initial_backoff_portal(base::TimeDelta::FromSeconds(100));
    359 
    360   EnableCaptivePortalDetectionPreference(false);
    361 
    362   RunDisabledTest(0);
    363   for (int i = 0; i < 6; ++i)
    364     RunDisabledTest(100);
    365 
    366   EnableCaptivePortalDetectionPreference(true);
    367 
    368   RunTest(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL, net::OK, 200, 0, NULL);
    369 }
    370 
    371 // Check that disabling the captive portal service while a check is running
    372 // works.
    373 TEST_F(CaptivePortalServiceTest, CaptivePortalPrefDisabledWhileRunning) {
    374   Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
    375   CaptivePortalObserver observer(profile(), service());
    376 
    377   // Needed to create the URLFetcher, even if it never returns any results.
    378   service()->DetectCaptivePortal();
    379 
    380   base::RunLoop().RunUntilIdle();
    381   EXPECT_TRUE(FetchingURL());
    382   EXPECT_FALSE(TimerRunning());
    383 
    384   EnableCaptivePortalDetectionPreference(false);
    385   EXPECT_FALSE(FetchingURL());
    386   EXPECT_TRUE(TimerRunning());
    387   EXPECT_EQ(0, observer.num_results_received());
    388 
    389   base::RunLoop().RunUntilIdle();
    390 
    391   EXPECT_FALSE(FetchingURL());
    392   EXPECT_FALSE(TimerRunning());
    393   EXPECT_EQ(1, observer.num_results_received());
    394 
    395   EXPECT_EQ(captive_portal::RESULT_INTERNET_CONNECTED,
    396             observer.captive_portal_result());
    397 }
    398 
    399 // Check that disabling the captive portal service while a check is pending
    400 // works.
    401 TEST_F(CaptivePortalServiceTest, CaptivePortalPrefDisabledWhilePending) {
    402   Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
    403   set_initial_backoff_no_portal(base::TimeDelta::FromDays(1));
    404 
    405   CaptivePortalObserver observer(profile(), service());
    406   service()->DetectCaptivePortal();
    407   EXPECT_FALSE(FetchingURL());
    408   EXPECT_TRUE(TimerRunning());
    409 
    410   EnableCaptivePortalDetectionPreference(false);
    411   EXPECT_FALSE(FetchingURL());
    412   EXPECT_TRUE(TimerRunning());
    413   EXPECT_EQ(0, observer.num_results_received());
    414 
    415   base::RunLoop().RunUntilIdle();
    416 
    417   EXPECT_FALSE(FetchingURL());
    418   EXPECT_FALSE(TimerRunning());
    419   EXPECT_EQ(1, observer.num_results_received());
    420 
    421   EXPECT_EQ(captive_portal::RESULT_INTERNET_CONNECTED,
    422             observer.captive_portal_result());
    423 }
    424 
    425 // Check that disabling the captive portal service while a check is pending
    426 // works.
    427 TEST_F(CaptivePortalServiceTest, CaptivePortalPrefEnabledWhilePending) {
    428   Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
    429 
    430   EnableCaptivePortalDetectionPreference(false);
    431   RunDisabledTest(0);
    432 
    433   CaptivePortalObserver observer(profile(), service());
    434   service()->DetectCaptivePortal();
    435   EXPECT_FALSE(FetchingURL());
    436   EXPECT_TRUE(TimerRunning());
    437 
    438   EnableCaptivePortalDetectionPreference(true);
    439   EXPECT_FALSE(FetchingURL());
    440   EXPECT_TRUE(TimerRunning());
    441 
    442   base::RunLoop().RunUntilIdle();
    443   ASSERT_TRUE(FetchingURL());
    444   EXPECT_FALSE(TimerRunning());
    445 
    446   CompleteURLFetch(net::OK, 200, NULL);
    447   EXPECT_FALSE(FetchingURL());
    448   EXPECT_FALSE(TimerRunning());
    449 
    450   EXPECT_EQ(1, observer.num_results_received());
    451   EXPECT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
    452             observer.captive_portal_result());
    453 }
    454 
    455 // Checks that disabling for browser tests works as expected.
    456 TEST_F(CaptivePortalServiceTest, CaptivePortalDisableForTests) {
    457   Initialize(CaptivePortalService::DISABLED_FOR_TESTING);
    458   RunDisabledTest(0);
    459 }
    460 
    461 // Checks that jitter gives us values in the correct range.
    462 TEST_F(CaptivePortalServiceTest, CaptivePortalJitter) {
    463   Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
    464   set_jitter_factor(0.3);
    465   set_initial_backoff_no_portal(base::TimeDelta::FromSeconds(100));
    466   RunTest(captive_portal::RESULT_INTERNET_CONNECTED, net::OK, 204, 0, NULL);
    467   RunTest(captive_portal::RESULT_INTERNET_CONNECTED, net::OK, 204, 0, NULL);
    468 
    469   for (int i = 0; i < 50; ++i) {
    470     int interval_sec = GetTimeUntilNextRequest().InSeconds();
    471     // Allow for roundoff, though shouldn't be necessary.
    472     EXPECT_LE(69, interval_sec);
    473     EXPECT_LE(interval_sec, 101);
    474   }
    475 }
    476 
    477 // Check a Retry-After header that contains a delay in seconds.
    478 TEST_F(CaptivePortalServiceTest, CaptivePortalRetryAfterSeconds) {
    479   Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
    480   set_initial_backoff_no_portal(base::TimeDelta::FromSeconds(100));
    481   const char* retry_after = "HTTP/1.1 503 OK\nRetry-After: 101\n\n";
    482 
    483   // Check that Retry-After headers work both on the first request to return a
    484   // result and on subsequent requests.
    485   RunTest(captive_portal::RESULT_NO_RESPONSE, net::OK, 503, 0, retry_after);
    486   RunTest(captive_portal::RESULT_NO_RESPONSE, net::OK, 503, 101, retry_after);
    487   RunTest(captive_portal::RESULT_INTERNET_CONNECTED, net::OK, 204, 101, NULL);
    488 
    489   // Make sure that there's no effect on the next captive portal check after
    490   // login.
    491   EXPECT_EQ(base::TimeDelta::FromSeconds(0), GetTimeUntilNextRequest());
    492 }
    493 
    494 // Check that the RecheckPolicy is still respected on 503 responses with
    495 // Retry-After headers.
    496 TEST_F(CaptivePortalServiceTest, CaptivePortalRetryAfterSecondsTooShort) {
    497   Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
    498   set_initial_backoff_no_portal(base::TimeDelta::FromSeconds(100));
    499   const char* retry_after = "HTTP/1.1 503 OK\nRetry-After: 99\n\n";
    500 
    501   RunTest(captive_portal::RESULT_NO_RESPONSE, net::OK, 503, 0, retry_after);
    502   // Normally would be no delay on the first check with a new result.
    503   RunTest(captive_portal::RESULT_NO_RESPONSE, net::OK, 503, 99, retry_after);
    504   EXPECT_EQ(base::TimeDelta::FromSeconds(100), GetTimeUntilNextRequest());
    505 }
    506 
    507 // Check a Retry-After header that contains a date.
    508 TEST_F(CaptivePortalServiceTest, CaptivePortalRetryAfterDate) {
    509   Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
    510   set_initial_backoff_no_portal(base::TimeDelta::FromSeconds(50));
    511 
    512   // base has a function to get a time in the right format from a string, but
    513   // not the other way around.
    514   base::Time start_time;
    515   ASSERT_TRUE(
    516       base::Time::FromString("Tue, 17 Apr 2012 18:02:00 GMT", &start_time));
    517   SetTime(start_time);
    518 
    519   RunTest(captive_portal::RESULT_NO_RESPONSE,
    520           net::OK,
    521           503,
    522           0,
    523           "HTTP/1.1 503 OK\nRetry-After: Tue, 17 Apr 2012 18:02:51 GMT\n\n");
    524   EXPECT_EQ(base::TimeDelta::FromSeconds(51), GetTimeUntilNextRequest());
    525 }
    526