Commit 5429cf40 authored by davidben@chromium.org's avatar davidben@chromium.org

Re-enable prerender RemovingLink browser tests.

The tests have changed significantly since they were first disabled. Add a
WaitForStop or two for good measure, but leave them as-is for the most part.
They can be disabled again if they still flake. Merge their custom prerender
loader into the main one; it's mostly the same.

In addition, for better test coverage, add a new test which asserts on events
received when a <link rel=prerender> is added for an existing prerender after
that prerender has loaded. Significantly rework the prerender events logic
to allow the test framework to wait on an event being received in the loader.

BUG=167340, 128841

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@251495 0039d316-1c4b-4281-b951-d872f2087c98
parent b1400a4f
...@@ -1279,56 +1279,46 @@ class PrerenderBrowserTest : virtual public InProcessBrowserTest { ...@@ -1279,56 +1279,46 @@ class PrerenderBrowserTest : virtual public InProcessBrowserTest {
return prerender_link_manager; return prerender_link_manager;
} }
bool DidReceivePrerenderStartEventForLinkNumber(int index) const { int GetPrerenderEventCount(int index, const std::string& type) const {
bool received_prerender_started; int event_count;
std::string expression = base::StringPrintf( std::string expression = base::StringPrintf(
"window.domAutomationController.send(Boolean(" "window.domAutomationController.send("
"receivedPrerenderStartEvents[%d]))", index); " GetPrerenderEventCount(%d, '%s'))", index, type.c_str());
CHECK(content::ExecuteScriptAndExtractBool( CHECK(content::ExecuteScriptAndExtractInt(
GetActiveWebContents(), GetActiveWebContents(), expression, &event_count));
expression, return event_count;
&received_prerender_started));
return received_prerender_started;
} }
int GetPrerenderLoadEventCountForLinkNumber(int index) const { bool DidReceivePrerenderStartEventForLinkNumber(int index) const {
int load_event_count; return GetPrerenderEventCount(index, "webkitprerenderstart") > 0;
std::string expression = base::StringPrintf( }
"window.domAutomationController.send("
"receivedPrerenderLoadEvents[%d] || 0)", index);
CHECK(content::ExecuteScriptAndExtractInt( int GetPrerenderLoadEventCountForLinkNumber(int index) const {
GetActiveWebContents(), return GetPrerenderEventCount(index, "webkitprerenderload");
expression,
&load_event_count));
return load_event_count;
} }
int GetPrerenderDomContentLoadedEventCountForLinkNumber(int index) const { int GetPrerenderDomContentLoadedEventCountForLinkNumber(int index) const {
int dom_content_loaded_event_count; return GetPrerenderEventCount(index, "webkitprerenderdomcontentloaded");
std::string expression = base::StringPrintf(
"window.domAutomationController.send("
"receivedPrerenderDomContentLoadedEvents[%d] || 0)", index);
CHECK(content::ExecuteScriptAndExtractInt(
GetActiveWebContents(),
expression,
&dom_content_loaded_event_count));
return dom_content_loaded_event_count;
} }
bool DidReceivePrerenderStopEventForLinkNumber(int index) const { bool DidReceivePrerenderStopEventForLinkNumber(int index) const {
bool received_prerender_stopped; return GetPrerenderEventCount(index, "webkitprerenderstop") > 0;
}
void WaitForPrerenderEventCount(int index,
const std::string& type,
int count) const {
int dummy;
std::string expression = base::StringPrintf( std::string expression = base::StringPrintf(
"window.domAutomationController.send(Boolean(" "WaitForPrerenderEventCount(%d, '%s', %d,"
"receivedPrerenderStopEvents[%d]))", index); " window.domAutomationController.send.bind("
" window.domAutomationController, 0))",
index, type.c_str(), count);
CHECK(content::ExecuteScriptAndExtractBool( CHECK(content::ExecuteScriptAndExtractInt(
GetActiveWebContents(), GetActiveWebContents(), expression, &dummy));
expression, CHECK_EQ(0, dummy);
&received_prerender_stopped));
return received_prerender_stopped;
} }
bool HadPrerenderEventErrors() const { bool HadPrerenderEventErrors() const {
...@@ -1723,18 +1713,17 @@ IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderPageRemovesPending) { ...@@ -1723,18 +1713,17 @@ IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderPageRemovesPending) {
ASSERT_TRUE(IsEmptyPrerenderLinkManager()); ASSERT_TRUE(IsEmptyPrerenderLinkManager());
} }
// Flaky, http://crbug.com/167340. IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderPageRemovingLink) {
IN_PROC_BROWSER_TEST_F( scoped_ptr<TestPrerender> prerender =
PrerenderBrowserTest, DISABLED_PrerenderPageRemovingLink) { PrerenderTestURL("files/prerender/prerender_page.html",
set_loader_path("files/prerender/prerender_loader_removing_links.html"); FINAL_STATUS_CANCELLED, 1);
set_loader_query_and_fragment("?links_to_insert=1");
PrerenderTestURL("files/prerender/prerender_page.html",
FINAL_STATUS_CANCELLED, 1);
// No ChannelDestructionWatcher is needed here, since prerenders in the // No ChannelDestructionWatcher is needed here, since prerenders in the
// PrerenderLinkManager should be deleted by removing the links, rather than // PrerenderLinkManager should be deleted by removing the links, rather than
// shutting down the renderer process. // shutting down the renderer process.
RemoveLinkElement(0); RemoveLinkElement(0);
prerender->WaitForStop();
EXPECT_TRUE(DidReceivePrerenderStartEventForLinkNumber(0)); EXPECT_TRUE(DidReceivePrerenderStartEventForLinkNumber(0));
EXPECT_FALSE(DidReceivePrerenderStopEventForLinkNumber(0)); EXPECT_FALSE(DidReceivePrerenderStopEventForLinkNumber(0));
EXPECT_FALSE(HadPrerenderEventErrors()); EXPECT_FALSE(HadPrerenderEventErrors());
...@@ -1744,16 +1733,15 @@ IN_PROC_BROWSER_TEST_F( ...@@ -1744,16 +1733,15 @@ IN_PROC_BROWSER_TEST_F(
EXPECT_TRUE(IsEmptyPrerenderLinkManager()); EXPECT_TRUE(IsEmptyPrerenderLinkManager());
} }
// Flaky, http://crbug.com/167340.
IN_PROC_BROWSER_TEST_F( IN_PROC_BROWSER_TEST_F(
PrerenderBrowserTest, DISABLED_PrerenderPageRemovingLinkWithTwoLinks) { PrerenderBrowserTest, PrerenderPageRemovingLinkWithTwoLinks) {
GetPrerenderManager()->mutable_config().max_link_concurrency = 2; GetPrerenderManager()->mutable_config().max_link_concurrency = 2;
GetPrerenderManager()->mutable_config().max_link_concurrency_per_launcher = 2; GetPrerenderManager()->mutable_config().max_link_concurrency_per_launcher = 2;
set_loader_path("files/prerender/prerender_loader_removing_links.html");
set_loader_query_and_fragment("?links_to_insert=2"); set_loader_query_and_fragment("?links_to_insert=2");
PrerenderTestURL("files/prerender/prerender_page.html", scoped_ptr<TestPrerender> prerender =
FINAL_STATUS_CANCELLED, 1); PrerenderTestURL("files/prerender/prerender_page.html",
FINAL_STATUS_CANCELLED, 1);
EXPECT_TRUE(DidReceivePrerenderStartEventForLinkNumber(0)); EXPECT_TRUE(DidReceivePrerenderStartEventForLinkNumber(0));
EXPECT_FALSE(DidReceivePrerenderStopEventForLinkNumber(0)); EXPECT_FALSE(DidReceivePrerenderStopEventForLinkNumber(0));
EXPECT_TRUE(DidReceivePrerenderStartEventForLinkNumber(1)); EXPECT_TRUE(DidReceivePrerenderStartEventForLinkNumber(1));
...@@ -1761,6 +1749,40 @@ IN_PROC_BROWSER_TEST_F( ...@@ -1761,6 +1749,40 @@ IN_PROC_BROWSER_TEST_F(
RemoveLinkElement(0); RemoveLinkElement(0);
RemoveLinkElement(1); RemoveLinkElement(1);
prerender->WaitForStop();
EXPECT_TRUE(DidReceivePrerenderStartEventForLinkNumber(0));
EXPECT_FALSE(DidReceivePrerenderStopEventForLinkNumber(0));
EXPECT_TRUE(DidReceivePrerenderStartEventForLinkNumber(1));
EXPECT_FALSE(DidReceivePrerenderStopEventForLinkNumber(1));
EXPECT_FALSE(HadPrerenderEventErrors());
// IsEmptyPrerenderLinkManager() is not racy because the earlier DidReceive*
// calls did a thread/process hop to the renderer which insured pending
// renderer events have arrived.
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
}
IN_PROC_BROWSER_TEST_F(
PrerenderBrowserTest, PrerenderPageRemovingLinkWithTwoLinksOneLate) {
GetPrerenderManager()->mutable_config().max_link_concurrency = 2;
GetPrerenderManager()->mutable_config().max_link_concurrency_per_launcher = 2;
GURL url = test_server()->GetURL("files/prerender/prerender_page.html");
scoped_ptr<TestPrerender> prerender =
PrerenderTestURL(url, FINAL_STATUS_CANCELLED, 1);
// Add a second prerender for the same link. It reuses the prerender, so only
// the start event fires here.
AddPrerender(url, 1);
WaitForPrerenderEventCount(1, "webkitprerenderstart", 1);
EXPECT_TRUE(DidReceivePrerenderStartEventForLinkNumber(1));
EXPECT_EQ(0, GetPrerenderLoadEventCountForLinkNumber(1));
EXPECT_FALSE(DidReceivePrerenderStopEventForLinkNumber(1));
RemoveLinkElement(0);
RemoveLinkElement(1);
prerender->WaitForStop();
EXPECT_TRUE(DidReceivePrerenderStartEventForLinkNumber(0)); EXPECT_TRUE(DidReceivePrerenderStartEventForLinkNumber(0));
EXPECT_FALSE(DidReceivePrerenderStopEventForLinkNumber(0)); EXPECT_FALSE(DidReceivePrerenderStopEventForLinkNumber(0));
EXPECT_TRUE(DidReceivePrerenderStartEventForLinkNumber(1)); EXPECT_TRUE(DidReceivePrerenderStartEventForLinkNumber(1));
...@@ -1772,20 +1794,11 @@ IN_PROC_BROWSER_TEST_F( ...@@ -1772,20 +1794,11 @@ IN_PROC_BROWSER_TEST_F(
EXPECT_TRUE(IsEmptyPrerenderLinkManager()); EXPECT_TRUE(IsEmptyPrerenderLinkManager());
} }
#if defined(OS_WIN)
// TODO(gavinp): Fails on XP Rel - http://crbug.com/128841
#define MAYBE_PrerenderPageRemovingLinkWithTwoLinksRemovingOne \
DISABLED_PrerenderPageRemovingLinkWithTwoLinksRemovingOne
#else
#define MAYBE_PrerenderPageRemovingLinkWithTwoLinksRemovingOne \
PrerenderPageRemovingLinkWithTwoLinksRemovingOne
#endif // defined(OS_WIN)
IN_PROC_BROWSER_TEST_F( IN_PROC_BROWSER_TEST_F(
PrerenderBrowserTest, PrerenderBrowserTest,
MAYBE_PrerenderPageRemovingLinkWithTwoLinksRemovingOne) { PrerenderPageRemovingLinkWithTwoLinksRemovingOne) {
GetPrerenderManager()->mutable_config().max_link_concurrency = 2; GetPrerenderManager()->mutable_config().max_link_concurrency = 2;
GetPrerenderManager()->mutable_config().max_link_concurrency_per_launcher = 2; GetPrerenderManager()->mutable_config().max_link_concurrency_per_launcher = 2;
set_loader_path("files/prerender/prerender_loader_removing_links.html");
set_loader_query_and_fragment("?links_to_insert=2"); set_loader_query_and_fragment("?links_to_insert=2");
PrerenderTestURL("files/prerender/prerender_page.html", PrerenderTestURL("files/prerender/prerender_page.html",
FINAL_STATUS_USED, 1); FINAL_STATUS_USED, 1);
......
...@@ -10,66 +10,80 @@ ...@@ -10,66 +10,80 @@
// Currently only errors with the ordering of Prerender events are caught. // Currently only errors with the ordering of Prerender events are caught.
var hadPrerenderEventErrors = false; var hadPrerenderEventErrors = false;
var receivedPrerenderStartEvents = []; var receivedPrerenderEvents = {
var receivedPrerenderLoadEvents = []; 'webkitprerenderstart': [],
var receivedPrerenderDomContentLoadedEvents = []; 'webkitprerenderdomcontentloaded': [],
var receivedPrerenderStopEvents = []; 'webkitprerenderload': [],
'webkitprerenderstop': [],
function PrerenderStartHandler(index) { }
if (receivedPrerenderStartEvents[index] || // A list of callbacks to be called on every prerender event. Each callback
receivedPrerenderLoadEvents[index] || // returns true if it should never be called again, or false to remain in the
receivedPrerenderStopEvents[index]) { // list and be called on future events. These are used to implement
hadPrerenderEventErrors = true; // WaitForPrerenderEventCount.
return; var prerenderEventCallbacks = [];
function GetPrerenderEventCount(index, type) {
return receivedPrerenderEvents[type][index] || 0;
}
function PrerenderEventHandler(index, ev) {
// Check for errors.
if (ev.type == 'webkitprerenderstart') {
// No event may preceed start.
if (GetPrerenderEventCount(index, 'webkitprerenderstart') ||
GetPrerenderEventCount(index, 'webkitprerenderdomcontentloaded') ||
GetPrerenderEventCount(index, 'webkitprerenderload') ||
GetPrerenderEventCount(index, 'webkitprerenderstop')) {
hadPrerenderEventErrors = true;
}
} else {
// There may be multiple load or domcontentloaded events, but they must not
// come after start and must come before stop. And there may be at most one
// start. Note that stop may be delivered without any load events.
if (!GetPrerenderEventCount(index, 'webkitprerenderstart') ||
GetPrerenderEventCount(index, 'webkitprerenderstop')) {
hadPrerenderEventErrors = true;
}
} }
receivedPrerenderStartEvents[index] = true;
}
function PrerenderLoadHandler(index) { // Update count.
if (!receivedPrerenderStartEvents[index] || receivedPrerenderEvents[ev.type][index] =
receivedPrerenderStopEvents[index]) { (receivedPrerenderEvents[ev.type][index] || 0) + 1;
hadPrerenderEventErrors = true;
return;
}
if (!receivedPrerenderLoadEvents[index])
receivedPrerenderLoadEvents[index] = 0;
receivedPrerenderLoadEvents[index]++;
}
function PrerenderDomContentLoadedHandler(index) { // Run all callbacks. Remove the ones that are done.
if (!receivedPrerenderStartEvents[index] || prerenderEventCallbacks = prerenderEventCallbacks.filter(function(callback) {
receivedPrerenderStopEvents[index]) { return !callback();
hadPrerenderEventErrors = true; });
return;
}
if (!receivedPrerenderDomContentLoadedEvents[index])
receivedPrerenderDomContentLoadedEvents[index] = 0;
receivedPrerenderDomContentLoadedEvents[index]++;
} }
function PrerenderStopHandler(index) { // Calls |callback| when at least |count| instances of event |type| have been
if (!receivedPrerenderStartEvents[index] || // observed for prerender |index|.
receivedPrerenderStopEvents[index]) { function WaitForPrerenderEventCount(index, type, count, callback) {
hadPrerenderEventErrors = true; var checkCount = function() {
return; if (GetPrerenderEventCount(index, type) >= count) {
} callback();
receivedPrerenderStopEvents[index] = true; return true;
}
return false;
};
if (!checkCount())
prerenderEventCallbacks.push(checkCount);
} }
function AddEventHandlersToLinkElement(link, index) { function AddEventHandlersToLinkElement(link, index) {
link.addEventListener('webkitprerenderstart', link.addEventListener('webkitprerenderstart',
PrerenderStartHandler.bind(null, index), false); PrerenderEventHandler.bind(null, index), false);
link.addEventListener('webkitprerenderload',
PrerenderLoadHandler.bind(null, index), false);
link.addEventListener('webkitprerenderdomcontentloaded', link.addEventListener('webkitprerenderdomcontentloaded',
PrerenderDomContentLoadedHandler.bind(null, index), PrerenderEventHandler.bind(null, index), false);
false); link.addEventListener('webkitprerenderload',
PrerenderEventHandler.bind(null, index), false);
link.addEventListener('webkitprerenderstop', link.addEventListener('webkitprerenderstop',
PrerenderStopHandler.bind(null, index), false); PrerenderEventHandler.bind(null, index), false);
} }
function AddPrerender(url, index) { function AddPrerender(url, index) {
var link = document.createElement('link'); var link = document.createElement('link');
link.id = 'prerenderElement' + index;
link.rel = 'prerender'; link.rel = 'prerender';
link.href = url; link.href = url;
AddEventHandlersToLinkElement(link, index); AddEventHandlersToLinkElement(link, index);
...@@ -77,6 +91,19 @@ function AddPrerender(url, index) { ...@@ -77,6 +91,19 @@ function AddPrerender(url, index) {
return link; return link;
} }
function RemoveLinkElement(index) {
var link = document.getElementById('prerenderElement' + index);
link.parentElement.removeChild(link);
}
function ExtractGetParameterBadlyAndInsecurely(param, defaultValue) {
var re = RegExp('[&?]' + param + '=([^&?#]*)');
var result = re.exec(document.location);
if (result)
return result[1];
return defaultValue;
}
function AddAnchor(href, target) { function AddAnchor(href, target) {
var a = document.createElement('a'); var a = document.createElement('a');
a.href = href; a.href = href;
......
...@@ -5,7 +5,11 @@ ...@@ -5,7 +5,11 @@
</head> </head>
<body> <body>
<script> <script>
AddPrerender('REPLACE_WITH_PRERENDER_URL', 0); var numLinksToInsert =
ExtractGetParameterBadlyAndInsecurely('links_to_insert', 1);
for (var i = 0; i < numLinksToInsert; ++i) {
AddPrerender('REPLACE_WITH_PRERENDER_URL', i);
}
</script> </script>
</body> </body>
</html> </html>
<html>
<head>
<title>Preloader</title>
<script src="prerender_events_common.js"></script>
<script>
function ExtractGetParameterBadlyAndInsecurely(param, defaultValue) {
var re = RegExp('[&?]' + param + '=([^&?#]*)');
var result = re.exec(document.location);
if (result)
return result[1];
return defaultValue;
}
var numLinksToInsert =
ExtractGetParameterBadlyAndInsecurely('links_to_insert', 1);
function RemoveLinkElement(index) {
var link = document.getElementById('prerenderElement' + index);
link.parentElement.removeChild(link);
}
</script>
</head>
<body>
<script>
for (var i = 0; i < numLinksToInsert; ++i) {
var link = AddPrerender('REPLACE_WITH_PRERENDER_URL', i);
link.id = 'prerenderElement' + i;
}
</script>
</body>
</html>
...@@ -14,7 +14,7 @@ var pageWasPrerendered = false; ...@@ -14,7 +14,7 @@ var pageWasPrerendered = false;
function DidPrerenderPass() { function DidPrerenderPass() {
pageWasPrerendered = true; pageWasPrerendered = true;
return !receivedPrerenderStartEvents[0] && !receivedPrerenderStopEvents[0]; return !GetPrerenderEventCount(0, 'webkitprerenderstart');
} }
// Make sure DidPrerenderPass() was called first. Otherwise, the page was // Make sure DidPrerenderPass() was called first. Otherwise, the page was
......
...@@ -17,14 +17,14 @@ function DidPrerenderPass() { ...@@ -17,14 +17,14 @@ function DidPrerenderPass() {
var link = document.getElementById('thePrerender'); var link = document.getElementById('thePrerender');
if (link) if (link)
link.parentElement.removeChild(link) link.parentElement.removeChild(link)
return !receivedPrerenderStartEvents[0] && !receivedPrerenderStopEvents[0]; return !GetPrerenderEventCount(0, 'webkitprerenderstart');
} }
// Make sure DidPrerenderPass() was called first. Otherwise, the page was // Make sure DidPrerenderPass() was called first. Otherwise, the page was
// most likely reloaded instead of using the prerendered page. // most likely reloaded instead of using the prerendered page.
function DidDisplayPass() { function DidDisplayPass() {
return pageWasPrerendered && !receivedPrerenderStartEvents[0] && return pageWasPrerendered &&
!receivedPrerenderStopEvents[0]; !GetPrerenderEventCount(0, 'webkitprerenderstart');
} }
var link = document.getElementById('thePrerender'); var link = document.getElementById('thePrerender');
......
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