Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(92)

Side by Side Diff: chrome/browser/prerender/prerender_nostate_prefetch_test.cc

Issue 2304953002: NoState Prefetch: nostate prefetch browser tests. (Closed)
Patch Set: All browser tests added and cleaned up for prefetch-specific issues. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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/command_line.h"
6 #include "base/strings/string_split.h"
7 #include "chrome/browser/prerender/prerender_manager.h"
8 #include "chrome/browser/prerender/prerender_manager_factory.h"
9 #include "chrome/browser/prerender/prerender_test_utils.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/task_manager/task_manager_browsertest_util.h"
12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/browser_commands.h"
14 #include "chrome/browser/ui/tabs/tab_strip_model.h"
15 #include "chrome/common/chrome_switches.h"
16 #include "chrome/grit/generated_resources.h"
17 #include "chrome/test/base/ui_test_utils.h"
18 #include "content/public/common/content_switches.h"
19 #include "content/public/common/url_constants.h"
20 #include "content/public/test/browser_test_utils.h"
21 #include "net/base/escape.h"
22 #include "net/dns/mock_host_resolver.h"
23 #include "net/test/embedded_test_server/request_handler_util.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 #include "ui/base/l10n/l10n_util.h"
26
27 using prerender::test_utils::CreateCountingInterceptorOnIO;
28 using prerender::test_utils::DestructionWaiter;
29 using prerender::test_utils::RequestCounter;
30 using prerender::test_utils::TestPrerender;
31 using prerender::test_utils::TestPrerenderContents;
32 using task_manager::browsertest_util::WaitForTaskManagerRows;
33 namespace prerender {
34
35 // The various uses of URLs in these tests (the test server, request capture,
36 // etc) are fussy about relative versus absolute paths. With the exception of
37 // kPrefetchLoaderPath, which is only used in PrerenderTestURLImpl, all other
38 // paths should be relative.
39 const char kPrefetchLoaderPath[] = "/prerender/prerender_prefetch_loader.html";
40 const char kPrefetchPage[] = "prerender/prerender_prefetch_page.html";
41 const char kPrefetchScript[] = "prerender/prerender_prefetch.js";
42 const char kPrefetchPage2[] = "prerender/prerender_prefetch_page2.html";
43 const char kPrefetchScript2[] = "prerender/prerender_prefetch2.js";
44 const char kPrefetchImagePage[] = "prerender/prerender_prefetch_image.html";
45 const char kPrefetchLoopPage[] = "prerender/prerender_prefetch_loop.html";
46
47 const char kPrefetchJpeg[] = "prerender/image.jpeg";
48 const char kPrefetchPng[] = "prerender/image.png";
49
50 const char kPageBool[] = "pageBool";
51 const char kScriptBool[] = "scriptBool";
52
53 class NoStatePrefetchBrowserTest
54 : public test_utils::PrerenderInProcessBrowserTest {
55 public:
56 NoStatePrefetchBrowserTest() {}
57
58 void SetUpCommandLine(base::CommandLine* command_line) override {
59 PrerenderInProcessBrowserTest::SetUpCommandLine(command_line);
60 command_line->AppendSwitchASCII(
61 switches::kPrerenderMode, switches::kPrerenderModeSwitchValuePrefetch);
62 }
63
64 // Set up a request counter for the path.
65 void CountRequestFor(const std::string& path, RequestCounter* counter) {
66 GURL::Replacements replacement;
67 replacement.SetPathStr(path);
68 const GURL url = src_server()->base_url().ReplaceComponents(replacement);
69 base::FilePath url_file =
70 ui_test_utils::GetTestFilePath(base::FilePath(), base::FilePath(path));
71 content::BrowserThread::PostTask(
72 content::BrowserThread::IO, FROM_HERE,
73 base::Bind(&CreateCountingInterceptorOnIO, url, url_file,
74 counter->AsWeakPtr()));
75 }
76
77 // Fetches a boolean value from javascript. Returns whether the fetch
78 // succeeded; the value of the variable is returned in value. If
79 // javascript_variable does not exist, this returns false and value is
80 // unchanged. The function checks that script execution works.
81 bool GetJavascriptBoolean(const std::string& javascript_variable,
82 content::WebContents* web_contents,
83 bool* value) {
84 // In order to detect unknown variables we need a three-valued return.
85 int result;
86 EXPECT_TRUE(content::ExecuteScriptAndExtractInt(
87 web_contents,
88 "try { if (" + javascript_variable + ") { " +
89 "window.domAutomationController.send(1) } else { " +
90 "window.domAutomationController.send(0); } } catch(err) {" +
91 "window.domAutomationController.send(2) }",
92 &result));
93 if (result == 2) {
94 // This means an exception was caught, usually because of a missing
95 // variable.
96 return false;
97 }
98 *value = (result == 1);
99 return true;
100 }
101
102 // As above, but just checks for a missing variable.
103 bool JavascriptVariableMissing(const std::string& javascript_variable,
104 content::WebContents* web_contents) {
105 bool unused;
106 return !GetJavascriptBoolean(javascript_variable, web_contents, &unused);
107 }
108
109 private:
110 ScopedVector<TestPrerender> PrerenderTestURLImpl(
droger 2016/09/20 10:57:19 Optional: I think ScopedVector is deprecated, use
mattcary 2016/09/21 08:45:10 I thought of that, but to tear it out would requir
111 const GURL& prerender_url,
112 const std::vector<FinalStatus>& expected_final_status_queue,
113 int expected_number_of_loads) override {
114 base::StringPairs replacement_text;
115 replacement_text.push_back(
116 make_pair("REPLACE_WITH_PREFETCH_URL", prerender_url.spec()));
117 std::string replacement_path;
118 net::test_server::GetFilePathWithReplacements(
119 kPrefetchLoaderPath, replacement_text, &replacement_path);
120 GURL loader_url = src_server()->GetURL(replacement_path);
121
122 ScopedVector<TestPrerender> prerenders = NavigateWithPrerenders(
droger 2016/09/20 10:57:19 Same comment about ScopedVector (optional).
mattcary 2016/09/21 08:45:10 Acknowledged.
123 loader_url, expected_final_status_queue, expected_number_of_loads);
124
125 TestPrerenderContents* prerender_contents = prerenders[0]->contents();
126 CHECK(prerender_contents);
127 // Check that the prerender contents final status is unchanged from its
128 // default value, meaning that the contents has not been destroyed.
129 EXPECT_EQ(FINAL_STATUS_MAX, prerender_contents->final_status());
130
131 EXPECT_EQ(expected_number_of_loads, prerenders[0]->number_of_loads());
132
133 return prerenders;
134 }
135 };
136
137 // Checks that when the prefetch page is loaded in full, javascript values are
138 // set as expected. This checks that our test system is working as expected.
139 IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, CheckJavascript) {
140 ui_test_utils::NavigateToURL(
141 current_browser(), src_server()->GetURL(MakeAbsolute(kPrefetchPage)));
142 content::WebContents* web_contents =
143 current_browser()->tab_strip_model()->GetActiveWebContents();
144
145 // Confirm we can get true and false values.
146 bool value = false;
147 EXPECT_TRUE(GetJavascriptBoolean(kPageBool, web_contents, &value));
148 EXPECT_TRUE(value);
149 value = true;
150 EXPECT_TRUE(GetJavascriptBoolean("pageAntiBool", web_contents, &value));
151 EXPECT_FALSE(value);
152
153 // Confirm a value from the script is plumbed through.
154 value = false;
155 EXPECT_TRUE(GetJavascriptBoolean(kScriptBool, web_contents, &value));
156 EXPECT_TRUE(value);
157
158 // Confirm that the expected happens when a value doesn't exist.
159 EXPECT_TRUE(JavascriptVariableMissing("iDontExist", web_contents));
160 }
161
162 // Checks that a page is correctly prerendered in the case of a
droger 2016/09/20 10:57:20 s/prerendered/prefetched/ ?
mattcary 2016/09/21 08:45:10 Done.
163 // <link rel=prerender> tag and then loaded into a tab in response to a
164 // navigation, when NoState Prefetch is enabled.
droger 2016/09/20 10:57:19 Maybe add something like: // Check that Javascript
mattcary 2016/09/21 08:45:10 Done.
165 IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, PrefetchSimple) {
166 RequestCounter script_counter;
167 CountRequestFor(kPrefetchScript, &script_counter);
168 RequestCounter main_counter;
169 CountRequestFor(kPrefetchPage, &main_counter);
170
171 std::unique_ptr<TestPrerender> test_prerender =
172 PrerenderTestURL(kPrefetchPage, FINAL_STATUS_APP_TERMINATING, 1);
173 main_counter.WaitForCount(1);
174 script_counter.WaitForCount(1);
175
176 content::WebContents* contents =
177 test_prerender->contents()->prerender_contents();
178 content::WebContents* active_contents =
179 current_browser()->tab_strip_model()->GetActiveWebContents();
180 EXPECT_TRUE(JavascriptVariableMissing(kPageBool, contents));
181 EXPECT_TRUE(JavascriptVariableMissing(kScriptBool, contents));
182 EXPECT_TRUE(JavascriptVariableMissing(kPageBool, active_contents));
183 EXPECT_TRUE(JavascriptVariableMissing(kScriptBool, active_contents));
184 histogram_tester().ExpectTotalCount("Prerender.PerceivedPLT", 1);
185 // TODO(mattcary): add prefetch-specific histograms when droger's cl lands.
droger 2016/09/20 10:57:20 That CL is landed now, but it's fine to leave this
mattcary 2016/09/21 08:45:10 Thanks. I can go ahead and add them, which histogr
droger 2016/09/21 10:01:52 In this particular test, Prerender.NoStatePrefet
186 }
187
188 // Test that we prefetch an img tag in body using our particular
189 // prerender_prefetch_image.html setup.
190 IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, PrefetchImage) {
191 RequestCounter image_counter;
192 CountRequestFor(kPrefetchJpeg, &image_counter);
193 base::StringPairs replacement_text;
194 replacement_text.push_back(
195 std::make_pair("REPLACE_WITH_IMAGE_URL", MakeAbsolute(kPrefetchJpeg)));
196 std::string main_page_path;
197 net::test_server::GetFilePathWithReplacements(
198 kPrefetchImagePage, replacement_text, &main_page_path);
199 // Note that we can't CountRequestFor the main page as we use the test server
200 // for handling the image url replacement.
201 PrerenderTestURL(main_page_path, FINAL_STATUS_APP_TERMINATING, 1);
202 image_counter.WaitForCount(1);
203 }
204
205 // Check cross-domain prefetching by looking at histograms.
206 IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, PrefetchCrossDomain) {
207 static const std::string secondary_domain = "www.foo.com";
208 host_resolver()->AddRule(secondary_domain, "127.0.0.1");
209 GURL cross_domain_url(base::StringPrintf(
210 "http://%s:%d/%s", secondary_domain.c_str(),
211 embedded_test_server()->host_port_pair().port(), kPrefetchPage));
212 PrerenderTestURL(cross_domain_url, FINAL_STATUS_APP_TERMINATING, 1);
213 histogram_tester().ExpectTotalCount("Prerender.PerceivedPLT", 1);
214 histogram_tester().ExpectTotalCount("Prerender.none_PerceivedPLT", 1);
215 histogram_tester().ExpectTotalCount(
216 "Prerender.webcross_PrerenderNotSwappedInPLT", 1);
217 }
218
219 // Check that we support simultaneous prefetch.
220 IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, PrefetchSimultaneous) {
221 RequestCounter first_main_counter;
222 CountRequestFor(kPrefetchPage, &first_main_counter);
223 RequestCounter second_main_counter;
224 CountRequestFor(kPrefetchPage2, &second_main_counter);
225 RequestCounter first_script_counter;
226 CountRequestFor(kPrefetchScript, &first_script_counter);
227 RequestCounter second_script_counter;
228 CountRequestFor(kPrefetchScript2, &second_script_counter);
229
230 // The first prerender is marked as canceled as when the second starts, it
231 // sees that the first has been abandoned (presumably because we detach
232 // immediately and so it dies quickly).
233 PrerenderTestURL(kPrefetchPage, FINAL_STATUS_CANCELLED, 1);
234 PrerenderTestURL(kPrefetchPage2, FINAL_STATUS_APP_TERMINATING, 1);
235 first_main_counter.WaitForCount(1);
236 second_main_counter.WaitForCount(1);
237 first_script_counter.WaitForCount(1);
238 second_script_counter.WaitForCount(1);
239 histogram_tester().ExpectTotalCount("Prerender.PerceivedPLT", 2);
240 histogram_tester().ExpectTotalCount("Prerender.none_PerceivedPLT", 2);
241 }
242
243 // Check that we correctly handle a prefetch to a nonexisting page.
244 IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, PrefetchNonexisting) {
245 PrerenderTestURL("nonexisting-page.html", FINAL_STATUS_APP_TERMINATING, 0);
246 // TODO(mattcary): we fire up a prerenderer before we discover that the main
247 // page doesn't exist, we still count this as a prerender. Also we don't fail
248 // the renderer (presumably because we've detached the resource, etc). Is this
249 // what we want?
250 histogram_tester().ExpectTotalCount("Prerender.PerceivedPLT", 1);
251 }
252
253 // Check that we follow a 301 redirect.
254 IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, Prefetch301Redirect) {
255 RequestCounter script_counter;
256 CountRequestFor(kPrefetchScript, &script_counter);
257 PrerenderTestURL(
258 "/server-redirect/?" +
259 net::EscapeQueryParamValue(MakeAbsolute(kPrefetchPage), false),
260 FINAL_STATUS_APP_TERMINATING, 1);
261 script_counter.WaitForCount(1);
262 }
263
264 // Check that we don't follow a client redirect.
265 IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, PrefetchClientRedirect) {
266 RequestCounter script_counter;
267 CountRequestFor(kPrefetchScript, &script_counter);
268 // We use a sentinel via a complete load kPrefetchPage2. Otherwise we end
269 // before script_counter would reliable see the load of kPrefetchScript, were
270 // it to happen.
271 RequestCounter sentinel_counter;
272 CountRequestFor(kPrefetchScript2, &sentinel_counter);
273 PrerenderTestURL(
274 "/client-redirect/?" +
275 net::EscapeQueryParamValue(MakeAbsolute(kPrefetchPage), false),
276 FINAL_STATUS_APP_TERMINATING, 1);
277 ui_test_utils::NavigateToURL(
278 current_browser(), src_server()->GetURL(MakeAbsolute(kPrefetchPage2)));
279 sentinel_counter.WaitForCount(1);
280 script_counter.WaitForCount(0);
281 }
282
283 IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, PrefetchHttps) {
284 UseHttpsSrcServer();
285 RequestCounter main_counter;
286 CountRequestFor(kPrefetchPage, &main_counter);
287 RequestCounter script_counter;
288 CountRequestFor(kPrefetchScript, &script_counter);
289 PrerenderTestURL(kPrefetchPage, FINAL_STATUS_APP_TERMINATING, 1);
290 main_counter.WaitForCount(1);
291 script_counter.WaitForCount(1);
292 }
293
294 // Check that if an SSL error happens we don't fetch.
295 IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, SSLError) {
296 // We only send the loaded page, not the loader, through SSL.
297 net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
298 https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_MISMATCHED_NAME);
299 https_server.ServeFilesFromSourceDirectory("chrome/test/data");
300 ASSERT_TRUE(https_server.Start());
301 std::unique_ptr<TestPrerender> prerender =
302 PrerenderTestURL(https_server.GetURL(MakeAbsolute(kPrefetchPage)),
303 FINAL_STATUS_SSL_ERROR, 0);
304 DestructionWaiter waiter(prerender->contents(), FINAL_STATUS_SSL_ERROR);
305 EXPECT_TRUE(waiter.WaitForDestroy());
306 }
307
308 // We should not have a problem if a subresource fails SSL.
309 IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, SSLSubresourceError) {
310 // First confirm that the image loads as expected.
311
312 // Note that we start a separate HTTPS server for the subresource;
313 // src_server() is non-HTTPS.
314 net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
315 https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_MISMATCHED_NAME);
316 https_server.ServeFilesFromSourceDirectory("chrome/test/data");
317 ASSERT_TRUE(https_server.Start());
318 GURL https_url = https_server.GetURL("/prerender/image.jpeg");
319 base::StringPairs replacement_text;
320 replacement_text.push_back(
321 std::make_pair("REPLACE_WITH_IMAGE_URL", https_url.spec()));
322 std::string main_page_path;
323 net::test_server::GetFilePathWithReplacements(
324 kPrefetchImagePage, replacement_text, &main_page_path);
325 RequestCounter script_counter;
326 CountRequestFor(kPrefetchScript, &script_counter);
327
328 std::unique_ptr<TestPrerender> prerender =
329 PrerenderTestURL(main_page_path, FINAL_STATUS_APP_TERMINATING, 1);
330 // Check that the presumed failure of the image load didn't affect the script
331 // fetch. This assumes waiting for the script load is enough to see any error
332 // from the image load.
333 script_counter.WaitForCount(1);
334 }
335
336 IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, Loop) {
337 RequestCounter script_counter;
338 CountRequestFor(kPrefetchScript, &script_counter);
339 RequestCounter main_counter;
340 CountRequestFor(kPrefetchLoopPage, &main_counter);
341
342 std::unique_ptr<TestPrerender> test_prerender =
343 PrerenderTestURL(kPrefetchLoopPage, FINAL_STATUS_APP_TERMINATING, 1);
344 main_counter.WaitForCount(1);
345 script_counter.WaitForCount(1);
346 }
347
348 #if defined(ENABLE_TASK_MANAGER)
349
350 IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest,
351 OpenTaskManagerBeforePrefetch) {
352 const base::string16 any_prerender = MatchTaskManagerPrerender("*");
353 const base::string16 any_tab = MatchTaskManagerTab("*");
354 const base::string16 original = MatchTaskManagerTab("Prefetch Loader");
355 // Presumably we don't see the title in the task manager as the page has not
356 // been fully parsed.
357 const base::string16 prerender =
358 MatchTaskManagerPrerender("*prerender_prefetch_page.html*");
359
360 // Show the task manager. This populates the model.
361 chrome::OpenTaskManager(current_browser());
362 ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, any_tab));
363 ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, any_prerender));
364
365 // Prerender a page in addition to the original tab.
366 PrerenderTestURL(kPrefetchPage, FINAL_STATUS_APP_TERMINATING, 1);
367
368 // A TaskManager entry should appear like "Prerender: Prerender Page"
369 // alongside the original tab entry. There should be just these two entries.
370 ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, prerender));
371 ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, original));
372 ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, any_prerender));
373 ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, any_tab));
374 }
375
376 #endif // defined(ENABLE_TASK_MANAGER)
377
378 IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, RendererCrash) {
379 std::unique_ptr<TestPrerender> prerender =
380 PrerenderTestURL(kPrefetchPage, FINAL_STATUS_RENDERER_CRASHED, 1);
381 prerender->contents()->prerender_contents()->GetController().LoadURL(
382 GURL(content::kChromeUICrashURL), content::Referrer(),
383 ui::PAGE_TRANSITION_TYPED, std::string());
384 prerender->WaitForStop();
385 }
386
387 // For the next two tests, there is nothing for the prefetch scanner to do. But
388 // we make sure we behave as expect.
389 IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, Png) {
390 RequestCounter counter;
391 CountRequestFor(kPrefetchPng, &counter);
392 PrerenderTestURL(kPrefetchPng, FINAL_STATUS_APP_TERMINATING, 1);
393 counter.WaitForCount(1);
394 }
395
396 IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, Jpeg) {
397 RequestCounter counter;
398 CountRequestFor(kPrefetchJpeg, &counter);
399 PrerenderTestURL(kPrefetchJpeg, FINAL_STATUS_APP_TERMINATING, 1);
400 counter.WaitForCount(1);
401 }
402
403 // We should not prefetch from malware sites.
404 IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest,
405 PrerenderSafeBrowsingTopLevel) {
406 GURL url = src_server()->GetURL(MakeAbsolute(kPrefetchPage));
407 GetFakeSafeBrowsingDatabaseManager()->SetThreatTypeForUrl(
408 url, safe_browsing::SB_THREAT_TYPE_URL_MALWARE);
409 // Prefetch resource are blocked, but the prerender is not killed in any
410 // special way.
411 // TODO(mattcary): do we care about detecting if the main resource is fetched
412 // and preload scanning has started?
413 std::unique_ptr<TestPrerender> prerender =
414 PrerenderTestURL(kPrefetchPage, FINAL_STATUS_APP_TERMINATING, 0);
415 }
416
417 // TODO(mattcary) more histograms when droger's change lands.
418
419 // histogram_tester()->GetTotalCountsForPrefix
droger 2016/09/20 10:57:20 Remove this line?
mattcary 2016/09/21 08:45:10 Opps, done.
420
421 } // namespace prerender
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698