Home | History | Annotate | Download | only in net
      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 "base/json/json_string_value_serializer.h"
      6 #include "base/prefs/pref_service.h"
      7 #include "chrome/browser/net/predictor.h"
      8 #include "chrome/browser/profiles/profile.h"
      9 #include "chrome/browser/ui/browser.h"
     10 #include "chrome/common/pref_names.h"
     11 #include "chrome/test/base/in_process_browser_test.h"
     12 #include "chrome/test/base/ui_test_utils.h"
     13 #include "net/base/net_errors.h"
     14 #include "net/dns/host_resolver_proc.h"
     15 #include "net/dns/mock_host_resolver.h"
     16 #include "testing/gmock/include/gmock/gmock.h"
     17 
     18 using content::BrowserThread;
     19 using testing::HasSubstr;
     20 
     21 namespace {
     22 
     23 // Records a history of all hostnames for which resolving has been requested,
     24 // and immediately fails the resolution requests themselves.
     25 class HostResolutionRequestRecorder : public net::HostResolverProc {
     26  public:
     27   HostResolutionRequestRecorder()
     28       : HostResolverProc(NULL),
     29         is_waiting_for_hostname_(false) {
     30   }
     31 
     32   virtual int Resolve(const std::string& host,
     33                       net::AddressFamily address_family,
     34                       net::HostResolverFlags host_resolver_flags,
     35                       net::AddressList* addrlist,
     36                       int* os_error) OVERRIDE {
     37     BrowserThread::PostTask(
     38         BrowserThread::UI,
     39         FROM_HERE,
     40         base::Bind(&HostResolutionRequestRecorder::AddToHistory,
     41                    base::Unretained(this),
     42                    host));
     43     return net::ERR_NAME_NOT_RESOLVED;
     44   }
     45 
     46   bool HasHostBeenRequested(const std::string& hostname) {
     47     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     48     return std::find(requested_hostnames_.begin(),
     49                      requested_hostnames_.end(),
     50                      hostname) != requested_hostnames_.end();
     51   }
     52 
     53   void WaitUntilHostHasBeenRequested(const std::string& hostname) {
     54     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     55     DCHECK(!is_waiting_for_hostname_);
     56     if (HasHostBeenRequested(hostname))
     57       return;
     58     waiting_for_hostname_ = hostname;
     59     is_waiting_for_hostname_ = true;
     60     content::RunMessageLoop();
     61   }
     62 
     63  private:
     64   virtual ~HostResolutionRequestRecorder() {}
     65 
     66   void AddToHistory(const std::string& hostname) {
     67     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     68     requested_hostnames_.push_back(hostname);
     69     if (is_waiting_for_hostname_ && waiting_for_hostname_ == hostname) {
     70       is_waiting_for_hostname_ = false;
     71       waiting_for_hostname_.clear();
     72       base::MessageLoop::current()->Quit();
     73     }
     74   }
     75 
     76   // The hostname which WaitUntilHostHasBeenRequested is currently waiting for
     77   // to be requested.
     78   std::string waiting_for_hostname_;
     79 
     80   // Whether WaitUntilHostHasBeenRequested is waiting for a hostname to be
     81   // requested and thus is running a nested message loop.
     82   bool is_waiting_for_hostname_;
     83 
     84   // A list of hostnames for which resolution has already been requested. Only
     85   // to be accessed from the UI thread.
     86   std::vector<std::string> requested_hostnames_;
     87 
     88   DISALLOW_COPY_AND_ASSIGN(HostResolutionRequestRecorder);
     89 };
     90 
     91 }  // namespace
     92 
     93 namespace chrome_browser_net {
     94 
     95 class PredictorBrowserTest : public InProcessBrowserTest {
     96  public:
     97   PredictorBrowserTest()
     98       : startup_url_("http://host1:1"),
     99         referring_url_("http://host2:1"),
    100         target_url_("http://host3:1"),
    101         host_resolution_request_recorder_(new HostResolutionRequestRecorder) {
    102   }
    103 
    104  protected:
    105   virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
    106     scoped_host_resolver_proc_.reset(new net::ScopedDefaultHostResolverProc(
    107         host_resolution_request_recorder_.get()));
    108     InProcessBrowserTest::SetUpInProcessBrowserTestFixture();
    109   }
    110 
    111   virtual void TearDownInProcessBrowserTestFixture() OVERRIDE {
    112     InProcessBrowserTest::TearDownInProcessBrowserTestFixture();
    113     scoped_host_resolver_proc_.reset();
    114   }
    115 
    116   void LearnAboutInitialNavigation(const GURL& url) {
    117     Predictor* predictor = browser()->profile()->GetNetworkPredictor();
    118     BrowserThread::PostTask(BrowserThread::IO,
    119                             FROM_HERE,
    120                             base::Bind(&Predictor::LearnAboutInitialNavigation,
    121                                        base::Unretained(predictor),
    122                                        url));
    123     content::RunAllPendingInMessageLoop(BrowserThread::IO);
    124   }
    125 
    126   void LearnFromNavigation(const GURL& referring_url, const GURL& target_url) {
    127     Predictor* predictor = browser()->profile()->GetNetworkPredictor();
    128     BrowserThread::PostTask(BrowserThread::IO,
    129                             FROM_HERE,
    130                             base::Bind(&Predictor::LearnFromNavigation,
    131                                        base::Unretained(predictor),
    132                                        referring_url,
    133                                        target_url));
    134     content::RunAllPendingInMessageLoop(BrowserThread::IO);
    135   }
    136 
    137   void PrepareFrameSubresources(const GURL& url) {
    138     Predictor* predictor = browser()->profile()->GetNetworkPredictor();
    139     predictor->PredictFrameSubresources(url, GURL());
    140   }
    141 
    142   void GetListFromPrefsAsString(const char* list_path,
    143                                 std::string* value_as_string) const {
    144     PrefService* prefs = browser()->profile()->GetPrefs();
    145     const base::ListValue* list_value = prefs->GetList(list_path);
    146     JSONStringValueSerializer serializer(value_as_string);
    147     serializer.Serialize(*list_value);
    148   }
    149 
    150   void WaitUntilHostHasBeenRequested(const std::string& hostname) {
    151     host_resolution_request_recorder_->WaitUntilHostHasBeenRequested(hostname);
    152   }
    153 
    154   const GURL startup_url_;
    155   const GURL referring_url_;
    156   const GURL target_url_;
    157 
    158  private:
    159   scoped_refptr<HostResolutionRequestRecorder>
    160       host_resolution_request_recorder_;
    161   scoped_ptr<net::ScopedDefaultHostResolverProc> scoped_host_resolver_proc_;
    162 };
    163 
    164 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, PRE_ShutdownStartupCycle) {
    165   // Prepare state that will be serialized on this shut-down and read on next
    166   // start-up.
    167   LearnAboutInitialNavigation(startup_url_);
    168   LearnFromNavigation(referring_url_, target_url_);
    169 }
    170 
    171 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, ShutdownStartupCycle) {
    172   // Make sure that the Preferences file is actually wiped of all DNS prefetch
    173   // related data after start-up.
    174   std::string cleared_startup_list;
    175   std::string cleared_referral_list;
    176   GetListFromPrefsAsString(prefs::kDnsPrefetchingStartupList,
    177                            &cleared_startup_list);
    178   GetListFromPrefsAsString(prefs::kDnsPrefetchingHostReferralList,
    179                            &cleared_referral_list);
    180 
    181   EXPECT_THAT(cleared_startup_list, Not(HasSubstr(startup_url_.host())));
    182   EXPECT_THAT(cleared_referral_list, Not(HasSubstr(referring_url_.host())));
    183   EXPECT_THAT(cleared_referral_list, Not(HasSubstr(target_url_.host())));
    184 
    185   // But also make sure this data has been first loaded into the Predictor, by
    186   // inspecting that the Predictor starts making the expected hostname requests.
    187   PrepareFrameSubresources(referring_url_);
    188   WaitUntilHostHasBeenRequested(startup_url_.host());
    189   WaitUntilHostHasBeenRequested(target_url_.host());
    190 }
    191 
    192 }  // namespace chrome_browser_net
    193 
    194