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.
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"
18 using content::BrowserThread
;
19 using testing::HasSubstr
;
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
{
27 HostResolutionRequestRecorder()
28 : HostResolverProc(NULL
),
29 is_waiting_for_hostname_(false) {
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(
40 base::Bind(&HostResolutionRequestRecorder::AddToHistory
,
41 base::Unretained(this),
43 return net::ERR_NAME_NOT_RESOLVED
;
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();
53 void WaitUntilHostHasBeenRequested(const std::string
& hostname
) {
54 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
55 DCHECK(!is_waiting_for_hostname_
);
56 if (HasHostBeenRequested(hostname
))
58 waiting_for_hostname_
= hostname
;
59 is_waiting_for_hostname_
= true;
60 content::RunMessageLoop();
64 virtual ~HostResolutionRequestRecorder() {}
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();
76 // The hostname which WaitUntilHostHasBeenRequested is currently waiting for
78 std::string waiting_for_hostname_
;
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_
;
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_
;
88 DISALLOW_COPY_AND_ASSIGN(HostResolutionRequestRecorder
);
93 namespace chrome_browser_net
{
95 class PredictorBrowserTest
: public InProcessBrowserTest
{
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
) {
105 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE
{
106 scoped_host_resolver_proc_
.reset(new net::ScopedDefaultHostResolverProc(
107 host_resolution_request_recorder_
.get()));
108 InProcessBrowserTest::SetUpInProcessBrowserTestFixture();
111 virtual void TearDownInProcessBrowserTestFixture() OVERRIDE
{
112 InProcessBrowserTest::TearDownInProcessBrowserTestFixture();
113 scoped_host_resolver_proc_
.reset();
116 void LearnAboutInitialNavigation(const GURL
& url
) {
117 Predictor
* predictor
= browser()->profile()->GetNetworkPredictor();
118 BrowserThread::PostTask(BrowserThread::IO
,
120 base::Bind(&Predictor::LearnAboutInitialNavigation
,
121 base::Unretained(predictor
),
123 content::RunAllPendingInMessageLoop(BrowserThread::IO
);
126 void LearnFromNavigation(const GURL
& referring_url
, const GURL
& target_url
) {
127 Predictor
* predictor
= browser()->profile()->GetNetworkPredictor();
128 BrowserThread::PostTask(BrowserThread::IO
,
130 base::Bind(&Predictor::LearnFromNavigation
,
131 base::Unretained(predictor
),
134 content::RunAllPendingInMessageLoop(BrowserThread::IO
);
137 void PrepareFrameSubresources(const GURL
& url
) {
138 Predictor
* predictor
= browser()->profile()->GetNetworkPredictor();
139 predictor
->PredictFrameSubresources(url
, GURL());
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
);
150 void WaitUntilHostHasBeenRequested(const std::string
& hostname
) {
151 host_resolution_request_recorder_
->WaitUntilHostHasBeenRequested(hostname
);
154 const GURL startup_url_
;
155 const GURL referring_url_
;
156 const GURL target_url_
;
159 scoped_refptr
<HostResolutionRequestRecorder
>
160 host_resolution_request_recorder_
;
161 scoped_ptr
<net::ScopedDefaultHostResolverProc
> scoped_host_resolver_proc_
;
164 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest
, PRE_ShutdownStartupCycle
) {
165 // Prepare state that will be serialized on this shut-down and read on next
167 LearnAboutInitialNavigation(startup_url_
);
168 LearnFromNavigation(referring_url_
, target_url_
);
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
);
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())));
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());
192 } // namespace chrome_browser_net