1// Copyright (c) 2011 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/path_service.h"
7#include "base/string_util.h"
8#include "chrome/browser/prerender/prerender_contents.h"
9#include "chrome/browser/prerender/prerender_manager.h"
10#include "chrome/browser/profiles/profile.h"
11#include "chrome/browser/task_manager/task_manager.h"
12#include "chrome/browser/ui/browser.h"
13#include "chrome/browser/ui/browser_window.h"
14#include "chrome/common/chrome_paths.h"
15#include "chrome/common/chrome_switches.h"
16#include "chrome/test/in_process_browser_test.h"
17#include "chrome/test/ui_test_utils.h"
18#include "content/browser/tab_contents/tab_contents.h"
19#include "grit/generated_resources.h"
20#include "net/url_request/url_request_context.h"
21#include "net/url_request/url_request_context_getter.h"
22#include "ui/base/l10n/l10n_util.h"
23
24#include <deque>
25
26// Prerender tests work as follows:
27//
28// A page with a prefetch link to the test page is loaded.  Once prerendered,
29// its Javascript function DidPrerenderPass() is called, which returns true if
30// the page behaves as expected when prerendered.
31//
32// The prerendered page is then displayed on a tab.  The Javascript function
33// DidDisplayPass() is called, and returns true if the page behaved as it
34// should while being displayed.
35
36namespace prerender {
37
38namespace {
39
40std::string CreateClientRedirect(const std::string& dest_url) {
41  const char* const kClientRedirectBase = "client-redirect?";
42  return kClientRedirectBase + dest_url;
43}
44
45std::string CreateServerRedirect(const std::string& dest_url) {
46  const char* const kServerRedirectBase = "server-redirect?";
47  return kServerRedirectBase + dest_url;
48}
49
50// PrerenderContents that stops the UI message loop on DidStopLoading().
51class TestPrerenderContents : public PrerenderContents {
52 public:
53  TestPrerenderContents(
54      PrerenderManager* prerender_manager, Profile* profile, const GURL& url,
55      const std::vector<GURL>& alias_urls,
56      const GURL& referrer,
57      int number_of_loads,
58      FinalStatus expected_final_status)
59      : PrerenderContents(prerender_manager, profile, url, alias_urls,
60                          referrer),
61        number_of_loads_(0),
62        expected_number_of_loads_(number_of_loads),
63        expected_final_status_(expected_final_status) {
64  }
65
66  virtual ~TestPrerenderContents() {
67    EXPECT_EQ(expected_final_status_, final_status()) <<
68        " when testing URL " << prerender_url().path();
69    // In the event we are destroyed, say if the prerender was canceled, quit
70    // the UI message loop.
71    MessageLoopForUI::current()->Quit();
72  }
73
74  virtual void DidStopLoading() {
75    PrerenderContents::DidStopLoading();
76    ++number_of_loads_;
77    if (expected_final_status_ == FINAL_STATUS_USED &&
78        number_of_loads_ >= expected_number_of_loads_) {
79      MessageLoopForUI::current()->Quit();
80    }
81  }
82
83 private:
84  int number_of_loads_;
85  int expected_number_of_loads_;
86  FinalStatus expected_final_status_;
87};
88
89// PrerenderManager that uses TestPrerenderContents.
90class WaitForLoadPrerenderContentsFactory : public PrerenderContents::Factory {
91 public:
92  WaitForLoadPrerenderContentsFactory(
93      int number_of_loads,
94      const std::deque<FinalStatus>& expected_final_status_queue)
95      : number_of_loads_(number_of_loads) {
96    expected_final_status_queue_.resize(expected_final_status_queue.size());
97    std::copy(expected_final_status_queue.begin(),
98              expected_final_status_queue.end(),
99              expected_final_status_queue_.begin());
100    LOG(INFO) << "Factory created with queue length " <<
101                 expected_final_status_queue_.size();
102  }
103
104  virtual PrerenderContents* CreatePrerenderContents(
105      PrerenderManager* prerender_manager, Profile* profile, const GURL& url,
106      const std::vector<GURL>& alias_urls, const GURL& referrer) {
107    CHECK(!expected_final_status_queue_.empty()) <<
108          "Creating prerender contents for " << url.path() <<
109          " with no expected final status";
110    FinalStatus expected_final_status = expected_final_status_queue_.front();
111    expected_final_status_queue_.pop_front();
112    LOG(INFO) << "Creating prerender contents for " << url.path() <<
113                 " with expected final status " << expected_final_status;
114    LOG(INFO) << expected_final_status_queue_.size() << " left in the queue.";
115    return new TestPrerenderContents(prerender_manager, profile, url,
116                                     alias_urls, referrer,
117                                     number_of_loads_,
118                                     expected_final_status);
119  }
120
121 private:
122  int number_of_loads_;
123  std::deque<FinalStatus> expected_final_status_queue_;
124};
125
126}  // namespace
127
128class PrerenderBrowserTest : public InProcessBrowserTest {
129 public:
130  PrerenderBrowserTest()
131      : prc_factory_(NULL),
132        use_https_src_server_(false) {
133    EnableDOMAutomation();
134  }
135
136  virtual void SetUpCommandLine(CommandLine* command_line) {
137    command_line->AppendSwitchASCII(switches::kPrerender,
138                                    switches::kPrerenderSwitchValueEnabled);
139#if defined(OS_MACOSX)
140    // The plugins directory isn't read by default on the Mac, so it needs to be
141    // explicitly registered.
142    FilePath app_dir;
143    PathService::Get(chrome::DIR_APP, &app_dir);
144    command_line->AppendSwitchPath(
145        switches::kExtraPluginDir,
146        app_dir.Append(FILE_PATH_LITERAL("plugins")));
147#endif
148  }
149
150  // Overload for a single expected final status
151  void PrerenderTestURL(const std::string& html_file,
152                        FinalStatus expected_final_status,
153                        int total_navigations) {
154    std::deque<FinalStatus> expected_final_status_queue(1,
155                                                        expected_final_status);
156    PrerenderTestURLImpl(html_file,
157                         expected_final_status_queue,
158                         total_navigations);
159  }
160
161  void PrerenderTestURL(
162      const std::string& html_file,
163      const std::deque<FinalStatus>& expected_final_status_queue,
164      int total_navigations) {
165    PrerenderTestURLImpl(html_file,
166                         expected_final_status_queue,
167                         total_navigations);
168  }
169
170  void NavigateToDestURL() const {
171    ui_test_utils::NavigateToURL(browser(), dest_url_);
172
173    // Make sure the PrerenderContents found earlier was used or removed
174    EXPECT_TRUE(prerender_manager()->FindEntry(dest_url_) == NULL);
175
176    // Check if page behaved as expected when actually displayed.
177    bool display_test_result = false;
178    ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
179        browser()->GetSelectedTabContents()->render_view_host(), L"",
180        L"window.domAutomationController.send(DidDisplayPass())",
181        &display_test_result));
182    EXPECT_TRUE(display_test_result);
183  }
184
185  bool UrlIsInPrerenderManager(const std::string& html_file) {
186    GURL dest_url = test_server()->GetURL(html_file);
187    return (prerender_manager()->FindEntry(dest_url) != NULL);
188  }
189
190  bool UrlIsInPrerenderManager(const GURL& url) {
191    return (prerender_manager()->FindEntry(url) != NULL);
192  }
193
194  bool UrlIsPendingInPrerenderManager(const std::string& html_file) {
195    GURL dest_url = test_server()->GetURL(html_file);
196    return (prerender_manager()->FindPendingEntry(dest_url) != NULL);
197  }
198
199  void set_use_https_src(bool use_https_src_server) {
200    use_https_src_server_ = use_https_src_server;
201  }
202
203  TaskManagerModel* model() const {
204    return TaskManager::GetInstance()->model();
205  }
206
207  void set_dest_url(const GURL& dest_url) { dest_url_ = dest_url; }
208
209 private:
210  void PrerenderTestURLImpl(
211      const std::string& html_file,
212      const std::deque<FinalStatus>& expected_final_status_queue,
213      int total_navigations) {
214    ASSERT_TRUE(test_server()->Start());
215    dest_url_ = test_server()->GetURL(html_file);
216
217    std::vector<net::TestServer::StringPair> replacement_text;
218    replacement_text.push_back(
219        make_pair("REPLACE_WITH_PREFETCH_URL", dest_url_.spec()));
220    std::string replacement_path;
221    ASSERT_TRUE(net::TestServer::GetFilePathWithReplacements(
222        "files/prerender/prerender_loader.html",
223        replacement_text,
224        &replacement_path));
225
226    net::TestServer* src_server = test_server();
227    scoped_ptr<net::TestServer> https_src_server;
228    if (use_https_src_server_) {
229      https_src_server.reset(
230          new net::TestServer(net::TestServer::TYPE_HTTPS,
231                              FilePath(FILE_PATH_LITERAL("chrome/test/data"))));
232      ASSERT_TRUE(https_src_server->Start());
233      src_server = https_src_server.get();
234    }
235    GURL src_url = src_server->GetURL(replacement_path);
236
237    // This is needed to exit the event loop once the prerendered page has
238    // stopped loading or was cancelled.
239    ASSERT_TRUE(prerender_manager());
240    prerender_manager()->rate_limit_enabled_ = false;
241    ASSERT_TRUE(prc_factory_ == NULL);
242    prc_factory_ =
243        new WaitForLoadPrerenderContentsFactory(total_navigations,
244                                                expected_final_status_queue);
245    prerender_manager()->SetPrerenderContentsFactory(prc_factory_);
246    FinalStatus expected_final_status = expected_final_status_queue.front();
247
248    // ui_test_utils::NavigateToURL uses its own observer and message loop.
249    // Since the test needs to wait until the prerendered page has stopped
250    // loading, rathather than the page directly navigated to, need to
251    // handle browser navigation directly.
252    browser()->OpenURL(src_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
253
254    TestPrerenderContents* prerender_contents = NULL;
255    ui_test_utils::RunMessageLoop();
256
257    prerender_contents =
258        static_cast<TestPrerenderContents*>(
259            prerender_manager()->FindEntry(dest_url_));
260
261    switch (expected_final_status) {
262      case FINAL_STATUS_USED: {
263        ASSERT_TRUE(prerender_contents != NULL);
264
265        // Check if page behaves as expected while in prerendered state.
266        bool prerender_test_result = false;
267        ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
268            prerender_contents->render_view_host(), L"",
269            L"window.domAutomationController.send(DidPrerenderPass())",
270            &prerender_test_result));
271        EXPECT_TRUE(prerender_test_result);
272        break;
273      }
274      default:
275        // In the failure case, we should have removed dest_url_ from the
276        // prerender_manager.
277        EXPECT_TRUE(prerender_contents == NULL);
278        break;
279    }
280  }
281
282  PrerenderManager* prerender_manager() const {
283    Profile* profile = browser()->GetSelectedTabContents()->profile();
284    PrerenderManager* prerender_manager = profile->GetPrerenderManager();
285    return prerender_manager;
286  }
287
288  WaitForLoadPrerenderContentsFactory* prc_factory_;
289  GURL dest_url_;
290  bool use_https_src_server_;
291};
292
293// Checks that a page is correctly prerendered in the case of a
294// <link rel=prefetch> tag and then loaded into a tab in response to a
295// navigation.
296IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderPage) {
297  PrerenderTestURL("files/prerender/prerender_page.html", FINAL_STATUS_USED, 1);
298  NavigateToDestURL();
299}
300
301// Checks that the prerendering of a page is canceled correctly when a
302// Javascript alert is called.
303IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderAlertBeforeOnload) {
304  PrerenderTestURL("files/prerender/prerender_alert_before_onload.html",
305                   FINAL_STATUS_JAVASCRIPT_ALERT,
306                   1);
307}
308
309// Checks that the prerendering of a page is canceled correctly when a
310// Javascript alert is called.
311IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderAlertAfterOnload) {
312  PrerenderTestURL("files/prerender/prerender_alert_after_onload.html",
313                   FINAL_STATUS_JAVASCRIPT_ALERT,
314                   1);
315}
316
317// Checks that plugins are not loaded while a page is being preloaded, but
318// are loaded when the page is displayed.
319IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderDelayLoadPlugin) {
320  PrerenderTestURL("files/prerender/plugin_delay_load.html",
321                   FINAL_STATUS_USED,
322                   1);
323  NavigateToDestURL();
324}
325
326// Checks that plugins in an iframe are not loaded while a page is
327// being preloaded, but are loaded when the page is displayed.
328IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderIframeDelayLoadPlugin) {
329  PrerenderTestURL("files/prerender/prerender_iframe_plugin_delay_load.html",
330                   FINAL_STATUS_USED,
331                   1);
332  NavigateToDestURL();
333}
334
335// Renders a page that contains a prerender link to a page that contains an
336// iframe with a source that requires http authentication. This should not
337// prerender successfully.
338IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderHttpAuthentication) {
339  PrerenderTestURL("files/prerender/prerender_http_auth_container.html",
340                   FINAL_STATUS_AUTH_NEEDED,
341                   1);
342}
343
344// Checks that client-issued redirects work with prerendering.
345// This version navigates to the page which issues the redirection, rather
346// than the final destination page.
347IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
348                       PrerenderClientRedirectNavigateToFirst) {
349  PrerenderTestURL(
350      CreateClientRedirect("files/prerender/prerender_page.html"),
351      FINAL_STATUS_USED,
352      2);
353  NavigateToDestURL();
354}
355
356// Checks that client-issued redirects work with prerendering.
357// This version navigates to the final destination page, rather than the
358// page which does the redirection.
359IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
360                       PrerenderClientRedirectNavigateToSecond) {
361  PrerenderTestURL(
362      CreateClientRedirect("files/prerender/prerender_page.html"),
363      FINAL_STATUS_USED,
364      2);
365  set_dest_url(test_server()->GetURL("files/prerender/prerender_page.html"));
366  NavigateToDestURL();
367}
368
369// Checks that client-issued redirects to an https page will cancel prerenders.
370IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderClientRedirectToHttps) {
371  net::TestServer https_server(net::TestServer::TYPE_HTTPS,
372                               FilePath(FILE_PATH_LITERAL("chrome/test/data")));
373  ASSERT_TRUE(https_server.Start());
374  GURL https_url = https_server.GetURL("files/prerender/prerender_page.html");
375  PrerenderTestURL(CreateClientRedirect(https_url.spec()),
376                   FINAL_STATUS_HTTPS,
377                   1);
378}
379
380// Checks that client-issued redirects within an iframe in a prerendered
381// page will not count as an "alias" for the prerendered page.
382IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderClientRedirectInIframe) {
383  std::string redirect_path = CreateClientRedirect(
384      "/files/prerender/prerender_embedded_content.html");
385  std::vector<net::TestServer::StringPair> replacement_text;
386  replacement_text.push_back(
387      std::make_pair("REPLACE_WITH_URL", "/" + redirect_path));
388  std::string replacement_path;
389  ASSERT_TRUE(net::TestServer::GetFilePathWithReplacements(
390      "files/prerender/prerender_with_iframe.html",
391      replacement_text,
392      &replacement_path));
393  PrerenderTestURL(replacement_path, FINAL_STATUS_USED, 1);
394  EXPECT_FALSE(UrlIsInPrerenderManager(
395      "files/prerender/prerender_embedded_content.html"));
396  NavigateToDestURL();
397}
398
399// Checks that client-issued redirects within an iframe in a prerendered
400// page to an https page will not cancel the prerender, nor will it
401// count as an "alias" for the prerendered page.
402IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
403                       PrerenderClientRedirectToHttpsInIframe) {
404  net::TestServer https_server(net::TestServer::TYPE_HTTPS,
405                               FilePath(FILE_PATH_LITERAL("chrome/test/data")));
406  ASSERT_TRUE(https_server.Start());
407  GURL https_url = https_server.GetURL("files/prerender/prerender_page.html");
408  std::string redirect_path = CreateClientRedirect(https_url.spec());
409  std::vector<net::TestServer::StringPair> replacement_text;
410  replacement_text.push_back(
411      std::make_pair("REPLACE_WITH_URL", "/" + redirect_path));
412  std::string replacement_path;
413  ASSERT_TRUE(net::TestServer::GetFilePathWithReplacements(
414      "files/prerender/prerender_with_iframe.html",
415      replacement_text,
416      &replacement_path));
417  PrerenderTestURL(replacement_path, FINAL_STATUS_USED, 1);
418  EXPECT_FALSE(UrlIsInPrerenderManager(https_url));
419  NavigateToDestURL();
420}
421
422// Checks that server-issued redirects work with prerendering.
423// This version navigates to the page which issues the redirection, rather
424// than the final destination page.
425IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
426                       PrerenderServerRedirectNavigateToFirst) {
427  PrerenderTestURL(
428      CreateServerRedirect("files/prerender/prerender_page.html"),
429      FINAL_STATUS_USED,
430      1);
431  NavigateToDestURL();
432}
433
434// Checks that server-issued redirects work with prerendering.
435// This version navigates to the final destination page, rather than the
436// page which does the redirection.
437IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
438                       PrerenderServerRedirectNavigateToSecond) {
439  std::string redirect_path;
440  PrerenderTestURL(
441      CreateServerRedirect("files/prerender/prerender_page.html"),
442      FINAL_STATUS_USED,
443      1);
444  set_dest_url(test_server()->GetURL("files/prerender/prerender_page.html"));
445  NavigateToDestURL();
446}
447
448// TODO(cbentzel): Add server-redirect-to-https test. http://crbug.com/79182
449
450// Checks that server-issued redirects within an iframe in a prerendered
451// page will not count as an "alias" for the prerendered page.
452IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderServerRedirectInIframe) {
453  std::string redirect_path = CreateServerRedirect(
454      "/files/prerender/prerender_embedded_content.html");
455  std::vector<net::TestServer::StringPair> replacement_text;
456  replacement_text.push_back(
457      std::make_pair("REPLACE_WITH_URL", "/" + redirect_path));
458  std::string replacement_path;
459  ASSERT_TRUE(net::TestServer::GetFilePathWithReplacements(
460      "files/prerender/prerender_with_iframe.html",
461      replacement_text,
462      &replacement_path));
463  PrerenderTestURL(replacement_path, FINAL_STATUS_USED, 1);
464  EXPECT_FALSE(UrlIsInPrerenderManager(
465      "files/prerender/prerender_embedded_content.html"));
466  NavigateToDestURL();
467}
468
469// Checks that server-issued redirects within an iframe in a prerendered
470// page to an https page will not cancel the prerender, nor will it
471// count as an "alias" for the prerendered page.
472IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
473                       PrerenderServerRedirectToHttpsInIframe) {
474  net::TestServer https_server(net::TestServer::TYPE_HTTPS,
475                               FilePath(FILE_PATH_LITERAL("chrome/test/data")));
476  ASSERT_TRUE(https_server.Start());
477  GURL https_url = https_server.GetURL("files/prerender/prerender_page.html");
478  std::string redirect_path = CreateServerRedirect(https_url.spec());
479  std::vector<net::TestServer::StringPair> replacement_text;
480  replacement_text.push_back(
481      std::make_pair("REPLACE_WITH_URL", "/" + redirect_path));
482  std::string replacement_path;
483  ASSERT_TRUE(net::TestServer::GetFilePathWithReplacements(
484      "files/prerender/prerender_with_iframe.html",
485      replacement_text,
486      &replacement_path));
487  PrerenderTestURL(replacement_path, FINAL_STATUS_USED, 1);
488  EXPECT_FALSE(UrlIsInPrerenderManager(https_url));
489  NavigateToDestURL();
490}
491
492// Prerenders a page that contains an automatic download triggered through an
493// iframe. This should not prerender successfully.
494IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderDownloadIFrame) {
495  PrerenderTestURL("files/prerender/prerender_download_iframe.html",
496                   FINAL_STATUS_DOWNLOAD,
497                   1);
498}
499
500// Prerenders a page that contains an automatic download triggered through
501// Javascript changing the window.location. This should not prerender
502// successfully.
503IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderDownloadLocation) {
504  PrerenderTestURL(CreateClientRedirect("files/download-test1.lib"),
505                   FINAL_STATUS_DOWNLOAD,
506                   1);
507}
508
509// Prerenders a page that contains an automatic download triggered through a
510// client-issued redirect. This should not prerender successfully.
511IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderDownloadClientRedirect) {
512  PrerenderTestURL("files/prerender/prerender_download_refresh.html",
513                   FINAL_STATUS_DOWNLOAD,
514                   1);
515}
516
517// Checks that the referrer is set when prerendering.
518IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderReferrer) {
519  PrerenderTestURL("files/prerender/prerender_referrer.html",
520                   FINAL_STATUS_USED,
521                   1);
522  NavigateToDestURL();
523}
524
525// Checks that the referrer is not set when prerendering and the source page is
526// HTTPS.
527IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderNoSSLReferrer) {
528  set_use_https_src(true);
529  PrerenderTestURL("files/prerender/prerender_no_referrer.html",
530                   FINAL_STATUS_USED,
531                   1);
532  NavigateToDestURL();
533}
534
535// Checks that popups on a prerendered page cause cancellation.
536IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderPopup) {
537  PrerenderTestURL("files/prerender/prerender_popup.html",
538                   FINAL_STATUS_CREATE_NEW_WINDOW,
539                   1);
540}
541
542
543
544// Checks that renderers using excessive memory will be terminated.
545// Disabled, http://crbug.com/77870.
546IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
547                       DISABLED_PrerenderExcessiveMemory) {
548  PrerenderTestURL("files/prerender/prerender_excessive_memory.html",
549                   FINAL_STATUS_MEMORY_LIMIT_EXCEEDED,
550                   1);
551}
552
553// Checks that we don't prerender in an infinite loop.
554// Disabled, http://crbug.com/77870.
555IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, DISABLED_PrerenderInfiniteLoop) {
556  const char* const kHtmlFileA = "prerender_infinite_a.html";
557  const char* const kHtmlFileB = "prerender_infinite_b.html";
558
559  std::deque<FinalStatus> expected_final_status_queue;
560  expected_final_status_queue.push_back(FINAL_STATUS_USED);
561  expected_final_status_queue.push_back(FINAL_STATUS_APP_TERMINATING);
562
563  PrerenderTestURL(kHtmlFileA, expected_final_status_queue, 1);
564
565  // Next url should be in pending list but not an active entry.
566  EXPECT_FALSE(UrlIsInPrerenderManager(kHtmlFileB));
567  EXPECT_TRUE(UrlIsPendingInPrerenderManager(kHtmlFileB));
568
569  NavigateToDestURL();
570
571  // Make sure the PrerenderContents for the next url is now in the manager
572  // and not pending.
573  EXPECT_TRUE(UrlIsInPrerenderManager(kHtmlFileB));
574  EXPECT_FALSE(UrlIsPendingInPrerenderManager(kHtmlFileB));
575}
576
577// Checks that we don't prerender in an infinite loop and multiple links are
578// handled correctly.
579IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
580                       FLAKY_PrerenderInfiniteLoopMultiple) {
581  const char* const kHtmlFileA =
582      "files/prerender/prerender_infinite_a_multiple.html";
583  const char* const kHtmlFileB =
584      "files/prerender/prerender_infinite_b_multiple.html";
585  const char* const kHtmlFileC =
586      "files/prerender/prerender_infinite_c_multiple.html";
587
588  // We need to set the final status to expect here before starting any
589  // prerenders. We set them on a queue so whichever we see first is expected to
590  // be evicted, and the second should stick around until we exit.
591  std::deque<FinalStatus> expected_final_status_queue;
592  expected_final_status_queue.push_back(FINAL_STATUS_USED);
593  expected_final_status_queue.push_back(FINAL_STATUS_EVICTED);
594  expected_final_status_queue.push_back(FINAL_STATUS_APP_TERMINATING);
595
596  PrerenderTestURL(kHtmlFileA, expected_final_status_queue, 1);
597
598  // Next url should be in pending list but not an active entry.
599  EXPECT_FALSE(UrlIsInPrerenderManager(kHtmlFileB));
600  EXPECT_FALSE(UrlIsInPrerenderManager(kHtmlFileC));
601  EXPECT_TRUE(UrlIsPendingInPrerenderManager(kHtmlFileB));
602  EXPECT_TRUE(UrlIsPendingInPrerenderManager(kHtmlFileC));
603
604  NavigateToDestURL();
605
606  // Make sure the PrerenderContents for the next urls are now in the manager
607  // and not pending. One and only one of the URLs (the last seen) should be the
608  // active entry.
609  bool url_b_is_active_prerender = UrlIsInPrerenderManager(kHtmlFileB);
610  bool url_c_is_active_prerender = UrlIsInPrerenderManager(kHtmlFileC);
611  EXPECT_TRUE((url_b_is_active_prerender || url_c_is_active_prerender) &&
612              !(url_b_is_active_prerender && url_c_is_active_prerender));
613  EXPECT_FALSE(UrlIsPendingInPrerenderManager(kHtmlFileB));
614  EXPECT_FALSE(UrlIsPendingInPrerenderManager(kHtmlFileC));
615}
616
617IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, TaskManager) {
618  // Show the task manager. This populates the model.
619  browser()->window()->ShowTaskManager();
620
621  // Start with two resources.
622  EXPECT_EQ(2, model()->ResourceCount());
623  PrerenderTestURL("files/prerender/prerender_page.html", FINAL_STATUS_USED, 1);
624
625  // The prerender makes three.
626  EXPECT_EQ(3, model()->ResourceCount());
627
628  // It shouldn't have a TabContents associated with it.
629  ASSERT_TRUE(model()->GetResourceTabContents(1) == NULL);
630
631  // The prefix should be "Prerender:"
632  string16 prefix =
633      l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_PRERENDER_PREFIX,
634                                 string16());
635  ASSERT_TRUE(StartsWith(model()->GetResourceTitle(1), prefix, true));
636
637  NavigateToDestURL();
638
639  // Prerender task should be killed and removed from the Task Manager.
640  EXPECT_EQ(2, model()->ResourceCount());
641}
642
643// Checks that prerenderers will terminate when an audio tag is encountered.
644IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderHTML5Audio) {
645  PrerenderTestURL("files/prerender/prerender_html5_audio.html",
646                   FINAL_STATUS_HTML5_MEDIA,
647                   1);
648}
649
650// Checks that prerenderers will terminate when a video tag is encountered.
651IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderHTML5Video) {
652  PrerenderTestURL("files/prerender/prerender_html5_video.html",
653                   FINAL_STATUS_HTML5_MEDIA,
654                   1);
655}
656
657// Checks that prerenderers will terminate when a video tag is inserted via
658// javascript.
659IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderHTML5VideoJs) {
660  PrerenderTestURL("files/prerender/prerender_html5_video_script.html",
661                   FINAL_STATUS_HTML5_MEDIA,
662                   1);
663}
664
665}  // namespace prerender
666