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 "components/captive_portal/captive_portal_detector.h"
      6 
      7 #include "base/basictypes.h"
      8 #include "base/bind.h"
      9 #include "base/memory/ref_counted.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "base/message_loop/message_loop.h"
     12 #include "base/run_loop.h"
     13 #include "base/time/time.h"
     14 #include "components/captive_portal/captive_portal_testing_utils.h"
     15 #include "net/base/net_errors.h"
     16 #include "net/url_request/url_request_test_util.h"
     17 #include "testing/gtest/include/gtest/gtest.h"
     18 #include "url/gurl.h"
     19 
     20 namespace captive_portal {
     21 
     22 namespace {
     23 
     24 class CaptivePortalClient {
     25  public:
     26   explicit CaptivePortalClient(CaptivePortalDetector* captive_portal_detector)
     27       : num_results_received_(0) {
     28   }
     29 
     30   void OnPortalDetectionCompleted(
     31       const CaptivePortalDetector::Results& results) {
     32     results_ = results;
     33     ++num_results_received_;
     34   }
     35 
     36   const CaptivePortalDetector::Results& captive_portal_results() const {
     37     return results_;
     38   }
     39 
     40   int num_results_received() const { return num_results_received_; }
     41 
     42  private:
     43   CaptivePortalDetector::Results results_;
     44   int num_results_received_;
     45 
     46   DISALLOW_COPY_AND_ASSIGN(CaptivePortalClient);
     47 };
     48 
     49 }  // namespace
     50 
     51 class CaptivePortalDetectorTest : public testing::Test,
     52                                   public CaptivePortalDetectorTestBase {
     53  public:
     54   CaptivePortalDetectorTest() {}
     55   virtual ~CaptivePortalDetectorTest() {}
     56 
     57   virtual void SetUp() OVERRIDE {
     58     CHECK(base::MessageLoopProxy::current().get());
     59     scoped_refptr<net::URLRequestContextGetter> request_context_getter(
     60         new net::TestURLRequestContextGetter(
     61             base::MessageLoopProxy::current()));
     62 
     63     detector_.reset(new CaptivePortalDetector(request_context_getter.get()));
     64     set_detector(detector_.get());
     65   }
     66 
     67   virtual void TearDown() OVERRIDE {
     68     detector_.reset();
     69   }
     70 
     71   void RunTest(const CaptivePortalDetector::Results& expected_results,
     72                int net_error,
     73                int status_code,
     74                const char* response_headers) {
     75     ASSERT_FALSE(FetchingURL());
     76 
     77     GURL url(CaptivePortalDetector::kDefaultURL);
     78     CaptivePortalClient client(detector());
     79 
     80     detector()->DetectCaptivePortal(url,
     81         base::Bind(&CaptivePortalClient::OnPortalDetectionCompleted,
     82                    base::Unretained(&client)));
     83 
     84     ASSERT_TRUE(FetchingURL());
     85     base::RunLoop().RunUntilIdle();
     86 
     87     CompleteURLFetch(net_error, status_code, response_headers);
     88 
     89     EXPECT_FALSE(FetchingURL());
     90     EXPECT_EQ(1, client.num_results_received());
     91     EXPECT_EQ(expected_results.result, client.captive_portal_results().result);
     92     EXPECT_EQ(expected_results.response_code,
     93               client.captive_portal_results().response_code);
     94     EXPECT_EQ(expected_results.retry_after_delta,
     95               client.captive_portal_results().retry_after_delta);
     96   }
     97 
     98   void RunCancelTest() {
     99     ASSERT_FALSE(FetchingURL());
    100 
    101     GURL url(CaptivePortalDetector::kDefaultURL);
    102     CaptivePortalClient client(detector());
    103 
    104     detector()->DetectCaptivePortal(url,
    105         base::Bind(&CaptivePortalClient::OnPortalDetectionCompleted,
    106                    base::Unretained(&client)));
    107 
    108     ASSERT_TRUE(FetchingURL());
    109     base::RunLoop().RunUntilIdle();
    110 
    111     detector()->Cancel();
    112 
    113     ASSERT_FALSE(FetchingURL());
    114     EXPECT_EQ(0, client.num_results_received());
    115   }
    116 
    117  private:
    118   base::MessageLoop message_loop_;
    119   scoped_ptr<CaptivePortalDetector> detector_;
    120 };
    121 
    122 // Test that the CaptivePortalDetector returns the expected result
    123 // codes in response to a variety of probe results.
    124 TEST_F(CaptivePortalDetectorTest, CaptivePortalResultCodes) {
    125   CaptivePortalDetector::Results results;
    126   results.result = captive_portal::RESULT_INTERNET_CONNECTED;
    127   results.response_code = 204;
    128 
    129   RunTest(results, net::OK, 204, NULL);
    130 
    131   // The server may return an HTTP error when it's acting up.
    132   results.result = captive_portal::RESULT_NO_RESPONSE;
    133   results.response_code = 500;
    134   RunTest(results, net::OK, 500, NULL);
    135 
    136   // Generic network error case.
    137   results.result = captive_portal::RESULT_NO_RESPONSE;
    138   results.response_code = net::URLFetcher::RESPONSE_CODE_INVALID;
    139   RunTest(results, net::ERR_TIMED_OUT, net::URLFetcher::RESPONSE_CODE_INVALID,
    140           NULL);
    141 
    142   // In the general captive portal case, the portal will return a page with a
    143   // 200 status.
    144   results.result = captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL;
    145   results.response_code = 200;
    146   RunTest(results, net::OK, 200, NULL);
    147 
    148   // Some captive portals return 511 instead, to advertise their captive
    149   // portal-ness.
    150   results.result = captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL;
    151   results.response_code = 511;
    152   RunTest(results, net::OK, 511, NULL);
    153 }
    154 
    155 // Check a Retry-After header that contains a delay in seconds.
    156 TEST_F(CaptivePortalDetectorTest, CaptivePortalRetryAfterSeconds) {
    157   const char* retry_after = "HTTP/1.1 503 OK\nRetry-After: 101\n\n";
    158   CaptivePortalDetector::Results results;
    159 
    160   // Check that Retry-After headers work both on the first request to return a
    161   // result and on subsequent requests.
    162   results.result = captive_portal::RESULT_NO_RESPONSE;
    163   results.response_code = 503;
    164   results.retry_after_delta = base::TimeDelta::FromSeconds(101);
    165   RunTest(results, net::OK, 503, retry_after);
    166 
    167   results.result = captive_portal::RESULT_INTERNET_CONNECTED;
    168   results.response_code = 204;
    169   results.retry_after_delta = base::TimeDelta();
    170   RunTest(results, net::OK, 204, NULL);
    171 }
    172 
    173 // Check a Retry-After header that contains a date.
    174 TEST_F(CaptivePortalDetectorTest, CaptivePortalRetryAfterDate) {
    175   const char* retry_after =
    176       "HTTP/1.1 503 OK\nRetry-After: Tue, 17 Apr 2012 18:02:51 GMT\n\n";
    177   CaptivePortalDetector::Results results;
    178 
    179   // base has a function to get a time in the right format from a string, but
    180   // not the other way around.
    181   base::Time start_time;
    182   ASSERT_TRUE(base::Time::FromString("Tue, 17 Apr 2012 18:02:00 GMT",
    183                                      &start_time));
    184   base::Time retry_after_time;
    185   ASSERT_TRUE(base::Time::FromString("Tue, 17 Apr 2012 18:02:51 GMT",
    186                                      &retry_after_time));
    187 
    188   SetTime(start_time);
    189 
    190   results.result = captive_portal::RESULT_NO_RESPONSE;
    191   results.response_code = 503;
    192   results.retry_after_delta = retry_after_time - start_time;
    193   RunTest(results, net::OK, 503, retry_after);
    194 }
    195 
    196 // Check invalid Retry-After headers are ignored.
    197 TEST_F(CaptivePortalDetectorTest, CaptivePortalRetryAfterInvalid) {
    198   const char* retry_after = "HTTP/1.1 503 OK\nRetry-After: Christmas\n\n";
    199   CaptivePortalDetector::Results results;
    200 
    201   results.result = captive_portal::RESULT_NO_RESPONSE;
    202   results.response_code = 503;
    203   RunTest(results, net::OK, 503, retry_after);
    204 }
    205 
    206 TEST_F(CaptivePortalDetectorTest, Cancel) {
    207   RunCancelTest();
    208   CaptivePortalDetector::Results results;
    209   results.result = captive_portal::RESULT_INTERNET_CONNECTED;
    210   results.response_code = 204;
    211   RunTest(results, net::OK, 204, NULL);
    212 }
    213 
    214 }  // namespace captive_portal
    215