1 // Copyright 2013 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/command_line.h"
6 #include "base/prefs/pref_service.h"
7 #include "base/run_loop.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/profiles/profile.h"
10 #include "chrome/browser/ui/browser.h"
11 #include "chrome/browser/ui/tabs/tab_strip_model.h"
12 #include "chrome/common/chrome_switches.h"
13 #include "chrome/common/pref_names.h"
14 #include "chrome/common/prefetch_messages.h"
15 #include "chrome/test/base/in_process_browser_test.h"
16 #include "chrome/test/base/ui_test_utils.h"
17 #include "content/public/browser/render_frame_host.h"
18 #include "content/public/browser/web_contents.h"
19 #include "content/public/test/browser_test_utils.h"
20 #include "net/url_request/url_request_filter.h"
21 #include "net/url_request/url_request_job.h"
22
23 using content::BrowserThread;
24
25 namespace {
26
27 const char kPrefetchPage[] = "files/prerender/simple_prefetch.html";
28
29 class PrefetchBrowserTestBase : public InProcessBrowserTest {
30 public:
PrefetchBrowserTestBase(bool do_predictive_networking,bool do_prefetch_field_trial)31 explicit PrefetchBrowserTestBase(bool do_predictive_networking,
32 bool do_prefetch_field_trial)
33 : do_predictive_networking_(do_predictive_networking),
34 do_prefetch_field_trial_(do_prefetch_field_trial) {}
35
SetUpCommandLine(CommandLine * command_line)36 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
37 if (do_prefetch_field_trial_) {
38 command_line->AppendSwitchASCII(switches::kForceFieldTrials,
39 "Prefetch/ExperimentYes/");
40 } else {
41 command_line->AppendSwitchASCII(switches::kForceFieldTrials,
42 "Prefetch/ExperimentNo/");
43 }
44 }
45
SetUpOnMainThread()46 virtual void SetUpOnMainThread() OVERRIDE {
47 browser()->profile()->GetPrefs()->SetBoolean(
48 prefs::kNetworkPredictionEnabled, do_predictive_networking_);
49 }
50
RunPrefetchExperiment(bool expect_success,Browser * browser)51 bool RunPrefetchExperiment(bool expect_success, Browser* browser) {
52 CHECK(test_server()->Start());
53 GURL url = test_server()->GetURL(kPrefetchPage);
54
55 const base::string16 expected_title =
56 expect_success ? base::ASCIIToUTF16("link onload")
57 : base::ASCIIToUTF16("link onerror");
58 content::TitleWatcher title_watcher(
59 browser->tab_strip_model()->GetActiveWebContents(), expected_title);
60 ui_test_utils::NavigateToURL(browser, url);
61 return expected_title == title_watcher.WaitAndGetTitle();
62 }
63
64 private:
65 bool do_predictive_networking_;
66 bool do_prefetch_field_trial_;
67 };
68
69 class PrefetchBrowserTestPredictionOnExpOn : public PrefetchBrowserTestBase {
70 public:
PrefetchBrowserTestPredictionOnExpOn()71 PrefetchBrowserTestPredictionOnExpOn()
72 : PrefetchBrowserTestBase(true, true) {}
73 };
74
75 class PrefetchBrowserTestPredictionOnExpOff : public PrefetchBrowserTestBase {
76 public:
PrefetchBrowserTestPredictionOnExpOff()77 PrefetchBrowserTestPredictionOnExpOff()
78 : PrefetchBrowserTestBase(true, false) {}
79 };
80
81 class PrefetchBrowserTestPredictionOffExpOn : public PrefetchBrowserTestBase {
82 public:
PrefetchBrowserTestPredictionOffExpOn()83 PrefetchBrowserTestPredictionOffExpOn()
84 : PrefetchBrowserTestBase(false, true) {}
85 };
86
87 class PrefetchBrowserTestPredictionOffExpOff : public PrefetchBrowserTestBase {
88 public:
PrefetchBrowserTestPredictionOffExpOff()89 PrefetchBrowserTestPredictionOffExpOff()
90 : PrefetchBrowserTestBase(false, false) {}
91 };
92
93 // URLRequestJob (and associated handler) which hangs.
94 class HangingURLRequestJob : public net::URLRequestJob {
95 public:
HangingURLRequestJob(net::URLRequest * request,net::NetworkDelegate * network_delegate)96 HangingURLRequestJob(net::URLRequest* request,
97 net::NetworkDelegate* network_delegate)
98 : net::URLRequestJob(request, network_delegate) {}
99
100 // net::URLRequestJob implementation
Start()101 virtual void Start() OVERRIDE {}
102
103 private:
~HangingURLRequestJob()104 virtual ~HangingURLRequestJob() {}
105
106 DISALLOW_COPY_AND_ASSIGN(HangingURLRequestJob);
107 };
108
109 class HangingRequestInterceptor : public net::URLRequestInterceptor {
110 public:
HangingRequestInterceptor(const base::Closure & callback)111 explicit HangingRequestInterceptor(const base::Closure& callback)
112 : callback_(callback) {}
113
~HangingRequestInterceptor()114 virtual ~HangingRequestInterceptor() {}
115
MaybeInterceptRequest(net::URLRequest * request,net::NetworkDelegate * network_delegate) const116 virtual net::URLRequestJob* MaybeInterceptRequest(
117 net::URLRequest* request,
118 net::NetworkDelegate* network_delegate) const OVERRIDE {
119 if (!callback_.is_null())
120 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback_);
121 return new HangingURLRequestJob(request, network_delegate);
122 }
123
124 private:
125 base::Closure callback_;
126 };
127
CreateHangingRequestInterceptorOnIO(const GURL & url,base::Closure callback)128 void CreateHangingRequestInterceptorOnIO(const GURL& url,
129 base::Closure callback) {
130 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
131 scoped_ptr<net::URLRequestInterceptor> never_respond_handler(
132 new HangingRequestInterceptor(callback));
133 net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
134 url, never_respond_handler.Pass());
135 }
136
137 // Privacy option is on, experiment is on. Prefetch should succeed.
IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPredictionOnExpOn,PredOnExpOn)138 IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPredictionOnExpOn, PredOnExpOn) {
139 EXPECT_TRUE(RunPrefetchExperiment(true, browser()));
140 }
141
142 // Privacy option is on, experiment is off. Prefetch should be dropped.
IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPredictionOnExpOff,PredOnExpOff)143 IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPredictionOnExpOff, PredOnExpOff) {
144 EXPECT_TRUE(RunPrefetchExperiment(false, browser()));
145 }
146
147 // Privacy option is off, experiment is on. Prefetch should be dropped.
IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPredictionOffExpOn,PredOffExpOn)148 IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPredictionOffExpOn, PredOffExpOn) {
149 EXPECT_TRUE(RunPrefetchExperiment(false, browser()));
150 }
151
152 // Privacy option is off, experiment is off. Prefetch should be dropped.
IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPredictionOffExpOff,PredOffExpOff)153 IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPredictionOffExpOff, PredOffExpOff) {
154 EXPECT_TRUE(RunPrefetchExperiment(false, browser()));
155 }
156
157 // Bug 339909: When in incognito mode the browser crashed due to an
158 // uninitialized preference member. Verify that it no longer does.
IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPredictionOnExpOn,IncognitoTest)159 IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPredictionOnExpOn, IncognitoTest) {
160 Profile* incognito_profile = browser()->profile()->GetOffTheRecordProfile();
161 Browser* incognito_browser = new Browser(
162 Browser::CreateParams(incognito_profile, browser()->host_desktop_type()));
163
164 // Navigate just to have a tab in this window, otherwise there is no
165 // WebContents for the incognito browser.
166 ui_test_utils::OpenURLOffTheRecord(browser()->profile(), GURL("about:blank"));
167
168 EXPECT_TRUE(RunPrefetchExperiment(true, incognito_browser));
169 }
170
171 // This test will verify the following:
172 // - that prefetches from the browser are actually launched
173 // - if a prefetch is in progress, but the originating renderer is destroyed,
174 // that the pending prefetch request is cleaned up cleanly and does not
175 // result in a crash.
IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPredictionOnExpOn,PrefetchFromBrowser)176 IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPredictionOnExpOn,
177 PrefetchFromBrowser) {
178 const GURL kHangingUrl("http://hanging-url.com");
179 base::RunLoop loop_;
180 BrowserThread::PostTask(BrowserThread::IO,
181 FROM_HERE,
182 base::Bind(&CreateHangingRequestInterceptorOnIO,
183 kHangingUrl,
184 loop_.QuitClosure()));
185 ui_test_utils::NavigateToURL(browser(), GURL("about:blank"));
186 content::RenderFrameHost* rfh =
187 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame();
188 rfh->Send(new PrefetchMsg_Prefetch(rfh->GetRoutingID(), kHangingUrl));
189 loop_.Run();
190 }
191
192 } // namespace
193