Commit 35c15596 authored by davidben@chromium.org's avatar davidben@chromium.org

prerender: Add NavigationOrSwapObserver in browsertest.

Prerender browser tests are currently sensitive to prerenders occurring
synchronously. Already we require an ad-hoc content::RunMessageLoop() in
PrerenderPageNewTab because that one is asynchronous. Instead, introduce
a NavigationOrSwapObserver so NavigateToURL always waits for either the
swap or a normal navigation. This allows removing the
content::RunMessageLoop() call and is necessary for fixing beforeunload
handling.

Also split off DidDisplayPass and DidPrerenderPass into helper functions.

BUG=307592,304932
TEST=PrerenderBrowserTest.*

Review URL: https://codereview.chromium.org/102433010

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@243616 0039d316-1c4b-4281-b951-d872f2087c98
parent 18f49b50
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include "chrome/browser/ui/browser_navigator.h" #include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
#include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h" #include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension_constants.h" #include "chrome/common/extensions/extension_constants.h"
...@@ -62,6 +63,7 @@ ...@@ -62,6 +63,7 @@
#include "content/public/browser/render_view_host.h" #include "content/public/browser/render_view_host.h"
#include "content/public/browser/site_instance.h" #include "content/public/browser/site_instance.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/url_constants.h" #include "content/public/common/url_constants.h"
#include "content/public/test/browser_test_utils.h" #include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_navigation_observer.h" #include "content/public/test/test_navigation_observer.h"
...@@ -91,6 +93,7 @@ using content::Referrer; ...@@ -91,6 +93,7 @@ using content::Referrer;
using content::RenderViewHost; using content::RenderViewHost;
using content::RenderWidgetHost; using content::RenderWidgetHost;
using content::WebContents; using content::WebContents;
using content::WebContentsObserver;
// Prerender tests work as follows: // Prerender tests work as follows:
// //
...@@ -213,6 +216,49 @@ class ChannelDestructionWatcher { ...@@ -213,6 +216,49 @@ class ChannelDestructionWatcher {
DISALLOW_COPY_AND_ASSIGN(ChannelDestructionWatcher); DISALLOW_COPY_AND_ASSIGN(ChannelDestructionWatcher);
}; };
// A simple observer to wait on either a load or a swap of a WebContents.
class NavigationOrSwapObserver : public WebContentsObserver,
public TabStripModelObserver {
public:
// Waits for either a load or a swap of |tab_strip_model|'s active
// WebContents.
NavigationOrSwapObserver(TabStripModel* tab_strip_model,
WebContents* web_contents)
: WebContentsObserver(web_contents),
tab_strip_model_(tab_strip_model) {
CHECK_NE(TabStripModel::kNoTab,
tab_strip_model->GetIndexOfWebContents(web_contents));
tab_strip_model_->AddObserver(this);
}
virtual ~NavigationOrSwapObserver() {
tab_strip_model_->RemoveObserver(this);
}
void Wait() {
loop_.Run();
}
// WebContentsObserver implementation:
virtual void DidStopLoading(RenderViewHost* render_view_host) OVERRIDE {
loop_.Quit();
}
// TabStripModelObserver implementation:
virtual void TabReplacedAt(TabStripModel* tab_strip_model,
WebContents* old_contents,
WebContents* new_contents,
int index) OVERRIDE {
if (old_contents != web_contents())
return;
loop_.Quit();
}
private:
TabStripModel* tab_strip_model_;
base::RunLoop loop_;
};
// PrerenderContents that stops the UI message loop on DidStopLoading(). // PrerenderContents that stops the UI message loop on DidStopLoading().
class TestPrerenderContents : public PrerenderContents { class TestPrerenderContents : public PrerenderContents {
public: public:
...@@ -608,10 +654,10 @@ class RestorePrerenderMode { ...@@ -608,10 +654,10 @@ class RestorePrerenderMode {
PrerenderManager::PrerenderManagerMode prev_mode_; PrerenderManager::PrerenderManagerMode prev_mode_;
}; };
// URLRequestJob (and associated handler) which never starts. // URLRequestJob (and associated handler) which hangs.
class NeverStartURLRequestJob : public net::URLRequestJob { class HangingURLRequestJob : public net::URLRequestJob {
public: public:
NeverStartURLRequestJob(net::URLRequest* request, HangingURLRequestJob(net::URLRequest* request,
net::NetworkDelegate* network_delegate) net::NetworkDelegate* network_delegate)
: net::URLRequestJob(request, network_delegate) { : net::URLRequestJob(request, network_delegate) {
} }
...@@ -619,26 +665,40 @@ class NeverStartURLRequestJob : public net::URLRequestJob { ...@@ -619,26 +665,40 @@ class NeverStartURLRequestJob : public net::URLRequestJob {
virtual void Start() OVERRIDE {} virtual void Start() OVERRIDE {}
private: private:
virtual ~NeverStartURLRequestJob() {} virtual ~HangingURLRequestJob() {}
}; };
class NeverStartProtocolHandler class HangingFirstRequestProtocolHandler
: public net::URLRequestJobFactory::ProtocolHandler { : public net::URLRequestJobFactory::ProtocolHandler {
public: public:
NeverStartProtocolHandler() {} explicit HangingFirstRequestProtocolHandler(const base::FilePath& file)
virtual ~NeverStartProtocolHandler() {} : file_(file),
first_run_(true) {
}
virtual ~HangingFirstRequestProtocolHandler() {}
virtual net::URLRequestJob* MaybeCreateJob( virtual net::URLRequestJob* MaybeCreateJob(
net::URLRequest* request, net::URLRequest* request,
net::NetworkDelegate* network_delegate) const OVERRIDE { net::NetworkDelegate* network_delegate) const OVERRIDE {
return new NeverStartURLRequestJob(request, network_delegate); if (first_run_) {
first_run_ = false;
return new HangingURLRequestJob(request, network_delegate);
}
return new content::URLRequestMockHTTPJob(request, network_delegate, file_);
} }
private:
base::FilePath file_;
mutable bool first_run_;
}; };
void CreateNeverStartProtocolHandlerOnIO(const GURL& url) { // Makes |url| never respond on the first load, and then with the contents of
// |file| afterwards.
void CreateHangingFirstRequestProtocolHandlerOnIO(const GURL& url,
const base::FilePath& file) {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
scoped_ptr<net::URLRequestJobFactory::ProtocolHandler> never_respond_handler( scoped_ptr<net::URLRequestJobFactory::ProtocolHandler> never_respond_handler(
new NeverStartProtocolHandler()); new HangingFirstRequestProtocolHandler(file));
net::URLRequestFilter::GetInstance()->AddUrlProtocolHandler( net::URLRequestFilter::GetInstance()->AddUrlProtocolHandler(
url, never_respond_handler.Pass()); url, never_respond_handler.Pass());
} }
...@@ -842,9 +902,6 @@ class PrerenderBrowserTest : virtual public InProcessBrowserTest { ...@@ -842,9 +902,6 @@ class PrerenderBrowserTest : virtual public InProcessBrowserTest {
// due to session storage namespace mismatch. The merge is only kicked off // due to session storage namespace mismatch. The merge is only kicked off
// asynchronously. // asynchronously.
NavigateToDestURLWithDisposition(CURRENT_TAB, false); NavigateToDestURLWithDisposition(CURRENT_TAB, false);
// Run the message loop, waiting for the merge to complete, the swapin to
// be reattempted, and to eventually succeed.
content::RunMessageLoop();
} }
// Opens the url in a new tab, with no opener. // Opens the url in a new tab, with no opener.
...@@ -1156,6 +1213,26 @@ class PrerenderBrowserTest : virtual public InProcessBrowserTest { ...@@ -1156,6 +1213,26 @@ class PrerenderBrowserTest : virtual public InProcessBrowserTest {
GetPrerenderManager()->mutable_config().max_bytes = 1000 * 1024 * 1024; GetPrerenderManager()->mutable_config().max_bytes = 1000 * 1024 * 1024;
} }
bool DidPrerenderPass(WebContents* web_contents) const {
bool prerender_test_result = false;
if (!content::ExecuteScriptAndExtractBool(
web_contents,
"window.domAutomationController.send(DidPrerenderPass())",
&prerender_test_result))
return false;
return prerender_test_result;
}
bool DidDisplayPass(WebContents* web_contents) const {
bool display_test_result = false;
if (!content::ExecuteScriptAndExtractBool(
web_contents,
"window.domAutomationController.send(DidDisplayPass())",
&display_test_result))
return false;
return display_test_result;
}
protected: protected:
bool autostart_test_server_; bool autostart_test_server_;
...@@ -1242,12 +1319,7 @@ class PrerenderBrowserTest : virtual public InProcessBrowserTest { ...@@ -1242,12 +1319,7 @@ class PrerenderBrowserTest : virtual public InProcessBrowserTest {
prerender_contents->WaitForPrerenderToHaveReadyTitleIfRequired(); prerender_contents->WaitForPrerenderToHaveReadyTitleIfRequired();
// Check if page behaves as expected while in prerendered state. // Check if page behaves as expected while in prerendered state.
bool prerender_test_result = false; EXPECT_TRUE(DidPrerenderPass(prerender_contents->prerender_contents()));
ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
prerender_contents->GetRenderViewHostMutable(),
"window.domAutomationController.send(DidPrerenderPass())",
&prerender_test_result));
EXPECT_TRUE(prerender_test_result);
} }
// Test that the referring page received events. // Test that the referring page received events.
...@@ -1306,10 +1378,16 @@ class PrerenderBrowserTest : virtual public InProcessBrowserTest { ...@@ -1306,10 +1378,16 @@ class PrerenderBrowserTest : virtual public InProcessBrowserTest {
} }
} }
// Navigate to the prerendered URL, but don't run the message loop. Browser // Navigate and wait for either the load to finish normally or for a swap to
// issued navigations to prerendered pages will synchronously swap in the // occur.
// prerendered page. // TODO(davidben): The only handles CURRENT_TAB navigations, which is the
// only case tested or prerendered right now.
CHECK_EQ(CURRENT_TAB, params.disposition);
NavigationOrSwapObserver swap_observer(
current_browser()->tab_strip_model(),
current_browser()->tab_strip_model()->GetActiveWebContents());
WebContents* target_web_contents = current_browser()->OpenURL(params); WebContents* target_web_contents = current_browser()->OpenURL(params);
swap_observer.Wait();
if (web_contents && expect_swap_to_succeed) { if (web_contents && expect_swap_to_succeed) {
EXPECT_EQ(web_contents, target_web_contents); EXPECT_EQ(web_contents, target_web_contents);
...@@ -1317,12 +1395,7 @@ class PrerenderBrowserTest : virtual public InProcessBrowserTest { ...@@ -1317,12 +1395,7 @@ class PrerenderBrowserTest : virtual public InProcessBrowserTest {
if (page_load_observer.get()) if (page_load_observer.get())
page_load_observer->Wait(); page_load_observer->Wait();
bool display_test_result = false; EXPECT_TRUE(DidDisplayPass(web_contents));
ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
web_contents,
"window.domAutomationController.send(DidDisplayPass())",
&display_test_result));
EXPECT_TRUE(display_test_result);
} }
} }
} }
...@@ -1556,9 +1629,12 @@ IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, ...@@ -1556,9 +1629,12 @@ IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderNoCommitNoSwap) { IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderNoCommitNoSwap) {
// Navigate to a page that triggers a prerender for a URL that never commits. // Navigate to a page that triggers a prerender for a URL that never commits.
const GURL kNoCommitUrl("http://never-respond.example.com"); const GURL kNoCommitUrl("http://never-respond.example.com");
base::FilePath file(FILE_PATH_LITERAL(
"chrome/test/data/prerender/prerender_page.html"));
BrowserThread::PostTask( BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE, BrowserThread::IO, FROM_HERE,
base::Bind(&CreateNeverStartProtocolHandlerOnIO, kNoCommitUrl)); base::Bind(&CreateHangingFirstRequestProtocolHandlerOnIO,
kNoCommitUrl, file));
DisableJavascriptCalls(); DisableJavascriptCalls();
PrerenderTestURL(kNoCommitUrl, PrerenderTestURL(kNoCommitUrl,
FINAL_STATUS_NAVIGATION_UNCOMMITTED, FINAL_STATUS_NAVIGATION_UNCOMMITTED,
...@@ -1572,9 +1648,12 @@ IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderNoCommitNoSwap) { ...@@ -1572,9 +1648,12 @@ IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderNoCommitNoSwap) {
IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderNoCommitNoSwap2) { IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderNoCommitNoSwap2) {
// Navigate to a page that then navigates to a URL that never commits. // Navigate to a page that then navigates to a URL that never commits.
const GURL kNoCommitUrl("http://never-respond.example.com"); const GURL kNoCommitUrl("http://never-respond.example.com");
base::FilePath file(FILE_PATH_LITERAL(
"chrome/test/data/prerender/prerender_page.html"));
BrowserThread::PostTask( BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE, BrowserThread::IO, FROM_HERE,
base::Bind(&CreateNeverStartProtocolHandlerOnIO, kNoCommitUrl)); base::Bind(&CreateHangingFirstRequestProtocolHandlerOnIO,
kNoCommitUrl, file));
DisableJavascriptCalls(); DisableJavascriptCalls();
PrerenderTestURL(CreateClientRedirect(kNoCommitUrl.spec()), PrerenderTestURL(CreateClientRedirect(kNoCommitUrl.spec()),
FINAL_STATUS_APP_TERMINATING, 1); FINAL_STATUS_APP_TERMINATING, 1);
...@@ -1656,12 +1735,7 @@ IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderNaClPluginDisabled) { ...@@ -1656,12 +1735,7 @@ IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderNaClPluginDisabled) {
// loading. It would be great if we could avoid that. // loading. It would be great if we could avoid that.
WebContents* web_contents = WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents(); browser()->tab_strip_model()->GetActiveWebContents();
bool display_test_result = false; EXPECT_TRUE(DidDisplayPass(web_contents));
ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
web_contents,
"window.domAutomationController.send(DidDisplayPass())",
&display_test_result));
EXPECT_TRUE(display_test_result);
} }
// Checks that plugins in an iframe are not loaded while a page is // Checks that plugins in an iframe are not loaded while a page is
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment