• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
HostResolutionRequestRecorder()27   HostResolutionRequestRecorder()
28       : HostResolverProc(NULL),
29         is_waiting_for_hostname_(false) {
30   }
31 
Resolve(const std::string & host,net::AddressFamily address_family,net::HostResolverFlags host_resolver_flags,net::AddressList * addrlist,int * os_error)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 
HasHostBeenRequested(const std::string & hostname)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 
WaitUntilHostHasBeenRequested(const std::string & hostname)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:
~HostResolutionRequestRecorder()64   virtual ~HostResolutionRequestRecorder() {}
65 
AddToHistory(const std::string & hostname)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:
PredictorBrowserTest()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:
SetUpInProcessBrowserTestFixture()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 
TearDownInProcessBrowserTestFixture()111   virtual void TearDownInProcessBrowserTestFixture() OVERRIDE {
112     InProcessBrowserTest::TearDownInProcessBrowserTestFixture();
113     scoped_host_resolver_proc_.reset();
114   }
115 
LearnAboutInitialNavigation(const GURL & url)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 
LearnFromNavigation(const GURL & referring_url,const GURL & target_url)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 
PrepareFrameSubresources(const GURL & url)137   void PrepareFrameSubresources(const GURL& url) {
138     Predictor* predictor = browser()->profile()->GetNetworkPredictor();
139     predictor->PredictFrameSubresources(url, GURL());
140   }
141 
GetListFromPrefsAsString(const char * list_path,std::string * value_as_string) const142   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 
WaitUntilHostHasBeenRequested(const std::string & hostname)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 
IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,PRE_ShutdownStartupCycle)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 
IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,ShutdownStartupCycle)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