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 SetUp() OVERRIDE {
    106     net::ScopedDefaultHostResolverProc scoped_host_resolver_proc(
    107         host_resolution_request_recorder_.get());
    108     InProcessBrowserTest::SetUp();
    109   }
    110 
    111   void LearnAboutInitialNavigation(const GURL& url) {
    112     Predictor* predictor = browser()->profile()->GetNetworkPredictor();
    113     BrowserThread::PostTask(BrowserThread::IO,
    114                             FROM_HERE,
    115                             base::Bind(&Predictor::LearnAboutInitialNavigation,
    116                                        base::Unretained(predictor),
    117                                        url));
    118     content::RunAllPendingInMessageLoop(BrowserThread::IO);
    119   }
    120 
    121   void LearnFromNavigation(const GURL& referring_url, const GURL& target_url) {
    122     Predictor* predictor = browser()->profile()->GetNetworkPredictor();
    123     BrowserThread::PostTask(BrowserThread::IO,
    124                             FROM_HERE,
    125                             base::Bind(&Predictor::LearnFromNavigation,
    126                                        base::Unretained(predictor),
    127                                        referring_url,
    128                                        target_url));
    129     content::RunAllPendingInMessageLoop(BrowserThread::IO);
    130   }
    131 
    132   void PrepareFrameSubresources(const GURL& url) {
    133     Predictor* predictor = browser()->profile()->GetNetworkPredictor();
    134     predictor->PredictFrameSubresources(url, GURL());
    135   }
    136 
    137   void GetListFromPrefsAsString(const char* list_path,
    138                                 std::string* value_as_string) const {
    139     PrefService* prefs = browser()->profile()->GetPrefs();
    140     const base::ListValue* list_value = prefs->GetList(list_path);
    141     JSONStringValueSerializer serializer(value_as_string);
    142     serializer.Serialize(*list_value);
    143   }
    144 
    145   void WaitUntilHostHasBeenRequested(const std::string& hostname) {
    146     host_resolution_request_recorder_->WaitUntilHostHasBeenRequested(hostname);
    147   }
    148 
    149   const GURL startup_url_;
    150   const GURL referring_url_;
    151   const GURL target_url_;
    152 
    153  private:
    154   scoped_refptr<HostResolutionRequestRecorder>
    155       host_resolution_request_recorder_;
    156 };
    157 
    158 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, PRE_ShutdownStartupCycle) {
    159   // Prepare state that will be serialized on this shut-down and read on next
    160   // start-up.
    161   LearnAboutInitialNavigation(startup_url_);
    162   LearnFromNavigation(referring_url_, target_url_);
    163 }
    164 
    165 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, ShutdownStartupCycle) {
    166   // Make sure that the Preferences file is actually wiped of all DNS prefetch
    167   // related data after start-up.
    168   std::string cleared_startup_list;
    169   std::string cleared_referral_list;
    170   GetListFromPrefsAsString(prefs::kDnsPrefetchingStartupList,
    171                            &cleared_startup_list);
    172   GetListFromPrefsAsString(prefs::kDnsPrefetchingHostReferralList,
    173                            &cleared_referral_list);
    174 
    175   EXPECT_THAT(cleared_startup_list, Not(HasSubstr(startup_url_.host())));
    176   EXPECT_THAT(cleared_referral_list, Not(HasSubstr(referring_url_.host())));
    177   EXPECT_THAT(cleared_referral_list, Not(HasSubstr(target_url_.host())));
    178 
    179   // But also make sure this data has been first loaded into the Predictor, by
    180   // inspecting that the Predictor starts making the expected hostname requests.
    181   PrepareFrameSubresources(referring_url_);
    182   WaitUntilHostHasBeenRequested(startup_url_.host());
    183   WaitUntilHostHasBeenRequested(target_url_.host());
    184 }
    185 
    186 }  // namespace chrome_browser_net
    187 
    188