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