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