Index: content/browser/frame_host/render_frame_host_manager_unittest.cc |
diff --git a/content/browser/frame_host/render_frame_host_manager_unittest.cc b/content/browser/frame_host/render_frame_host_manager_unittest.cc |
index bac4f6df8215295e4fe88f03dc88fe333798b34d..cdda5f721713cc17db971c8440a7b3c55d5c7eb5 100644 |
--- a/content/browser/frame_host/render_frame_host_manager_unittest.cc |
+++ b/content/browser/frame_host/render_frame_host_manager_unittest.cc |
@@ -37,6 +37,7 @@ |
#include "content/public/test/mock_render_process_host.h" |
#include "content/public/test/test_notification_tracker.h" |
#include "content/public/test/test_utils.h" |
+#include "content/test/browser_side_navigation_test_utils.h" |
#include "content/test/test_content_browser_client.h" |
#include "content/test/test_content_client.h" |
#include "content/test/test_render_frame_host.h" |
@@ -54,7 +55,8 @@ class RenderFrameHostManagerTestWebUIControllerFactory |
: public WebUIControllerFactory { |
public: |
RenderFrameHostManagerTestWebUIControllerFactory() |
- : should_create_webui_(false) { |
+ : should_create_webui_(false), type_(1) { |
+ CHECK_NE(reinterpret_cast<WebUI::TypeID>(type_), WebUI::kNoWebUI); |
} |
~RenderFrameHostManagerTestWebUIControllerFactory() override {} |
@@ -62,6 +64,17 @@ class RenderFrameHostManagerTestWebUIControllerFactory |
should_create_webui_ = should_create_webui; |
} |
+ // This method allows simulating the expectation that a different WebUI |
+ // instance types would be created. This value will be returned in |
clamy
2015/10/22 16:51:40
nit: either "a different WebUI instance type" or "
carlosk
2015/10/26 10:33:23
Done.
|
+ // GetWebUIType, casted to WebUI::TypeID. |
+ // As WebUI::TypeID is a typedef to void pointer, factory implementations |
+ // return values that they know to be unique to their respective cases. So |
+ // values set here should be safe if kept very low (just above zero). |
+ void set_webui_type(uintptr_t type) { |
+ CHECK_NE(reinterpret_cast<WebUI::TypeID>(type), WebUI::kNoWebUI); |
+ type_ = type; |
+ } |
+ |
// WebUIFactory implementation. |
WebUIController* CreateWebUIControllerForURL(WebUI* web_ui, |
const GURL& url) const override { |
@@ -77,8 +90,7 @@ class RenderFrameHostManagerTestWebUIControllerFactory |
// If WebUI creation is enabled for the test and this is a WebUI URL, |
// returns a mock WebUI type. |
if (should_create_webui_ && HasWebUIScheme(url)) { |
- return const_cast<RenderFrameHostManagerTestWebUIControllerFactory*>( |
- this); |
+ return reinterpret_cast<WebUI::TypeID>(type_); |
} |
return WebUI::kNoWebUI; |
} |
@@ -95,6 +107,7 @@ class RenderFrameHostManagerTestWebUIControllerFactory |
private: |
bool should_create_webui_; |
+ uintptr_t type_; |
DISALLOW_COPY_AND_ASSIGN(RenderFrameHostManagerTestWebUIControllerFactory); |
}; |
@@ -272,6 +285,8 @@ class RenderFrameHostManagerTest : public RenderViewHostImplTestHarness { |
factory_.set_should_create_webui(should_create_webui); |
} |
+ void set_webui_type(int type) { factory_.set_webui_type(type); } |
+ |
void NavigateActiveAndCommit(const GURL& url) { |
// Note: we navigate the active RenderFrameHost because previous navigations |
// won't have committed yet, so NavigateAndCommit does the wrong thing |
@@ -409,6 +424,13 @@ class RenderFrameHostManagerTest : public RenderViewHostImplTestHarness { |
frame_entry->referrer(), *frame_entry, entry, |
FrameMsg_Navigate_Type::NORMAL, false, base::TimeTicks::Now(), |
static_cast<NavigationControllerImpl*>(&controller())); |
+ |
+ // Simulates request creation that triggers the 1st internal call to |
+ // GetFrameHostForNavigation. |
+ manager->DidCreateNavigationRequest(*navigation_request); |
+ |
+ // And also simulates the 2nd and final call to GetFrameHostForNavigation |
+ // that determines the final frame that will commit the navigation. |
TestRenderFrameHost* frame_host = static_cast<TestRenderFrameHost*>( |
manager->GetFrameHostForNavigation(*navigation_request)); |
CHECK(frame_host); |
@@ -1108,13 +1130,17 @@ TEST_F(RenderFrameHostManagerTest, WebUI) { |
// The Web UI is committed immediately because the RenderViewHost has not been |
// used yet. UpdateStateForNavigate() took the short cut path. |
+ EXPECT_TRUE(manager->web_ui()); |
if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
switches::kEnableBrowserSideNavigation)) { |
- EXPECT_FALSE(manager->speculative_web_ui()); |
+ // For PlzNavigate as GetFrameHostForNavigation is called twice in a row, a |
+ // speculative WebUI will exist because of the 2nd call but it should just |
+ // be the re-using of the current one that has been committed. |
+ EXPECT_TRUE(manager->speculative_web_ui()); |
+ EXPECT_EQ(manager->web_ui(), manager->speculative_web_ui()); |
} else { |
EXPECT_FALSE(manager->pending_web_ui()); |
} |
- EXPECT_TRUE(manager->web_ui()); |
// Commit. |
manager->DidNavigateFrame(host, true); |
@@ -2488,4 +2514,202 @@ TEST_F(RenderFrameHostManagerTest, TraverseComplexOpenerChain) { |
nodes_with_back_links.end()); |
} |
+// Creates a test class for PlzNavigate tests. |
+class RenderFrameHostManagerTestWithBrowserSideNavigation |
+ : public RenderFrameHostManagerTest { |
+ public: |
+ void SetUp() override { |
+ EnableBrowserSideNavigation(); |
+ RenderFrameHostManagerTest::SetUp(); |
+ } |
+}; |
+ |
+// PlzNavigate: Tests that the correct intermediary and final navigation states |
+// are reached when navigating from a dead renderer to a WebUI URL. |
clamy
2015/10/22 16:51:40
nit: s/a dead renderer/a renderer that is not live
carlosk
2015/10/26 10:33:23
Done.
|
+TEST_F(RenderFrameHostManagerTestWithBrowserSideNavigation, |
+ NavigateFromDeadRendererToWebUI) { |
+ set_should_create_webui(true); |
+ RenderViewHostChangedObserver change_observer(contents()); |
+ RenderFrameHostManager* manager = contents()->GetRenderManagerForTesting(); |
+ |
+ RenderFrameHostImpl* initial_host = manager->current_frame_host(); |
+ ASSERT_TRUE(initial_host); |
+ EXPECT_FALSE(initial_host->IsRenderFrameLive()); |
+ |
+ // Navigation request. |
+ const GURL kUrl("chrome://foo"); |
+ NavigationEntryImpl entry(NULL /* instance */, -1 /* page_id */, kUrl, |
+ Referrer(), base::string16() /* title */, |
+ ui::PAGE_TRANSITION_TYPED, |
+ false /* is_renderer_init */); |
+ FrameNavigationEntry* frame_entry = entry.root_node()->frame_entry.get(); |
+ scoped_ptr<NavigationRequest> navigation_request = |
+ NavigationRequest::CreateBrowserInitiated( |
+ contents()->GetFrameTree()->root(), frame_entry->url(), |
+ frame_entry->referrer(), *frame_entry, entry, |
+ FrameMsg_Navigate_Type::NORMAL, false, base::TimeTicks::Now(), |
+ static_cast<NavigationControllerImpl*>(&controller())); |
+ manager->DidCreateNavigationRequest(*navigation_request); |
+ |
+ // As the initial renderer was not be live, the new RenderFrameHost should |
clamy
2015/10/22 16:51:39
nit: remove be
carlosk
2015/10/26 10:33:23
Done.
|
+ // be made immediately active at request time. |
+ EXPECT_TRUE(change_observer.DidHostChange()); |
+ EXPECT_FALSE(GetPendingFrameHost(manager)); |
+ TestRenderFrameHost* host = |
+ static_cast<TestRenderFrameHost*>(manager->current_frame_host()); |
+ ASSERT_TRUE(host); |
+ EXPECT_NE(host, initial_host); |
+ EXPECT_TRUE(host->IsRenderFrameLive()); |
+ WebUIImpl* web_ui = host->web_ui(); |
+ EXPECT_TRUE(web_ui); |
+ EXPECT_FALSE(manager->speculative_web_ui()); |
+ |
+ // Prepare to commit, updates the navigating RenderFrameHost. |
clamy
2015/10/22 16:51:40
nit: update
carlosk
2015/10/26 10:33:23
Done.
|
+ EXPECT_EQ(host, manager->GetFrameHostForNavigation(*navigation_request)); |
+ host->set_pending_commit(true); |
clamy
2015/10/22 16:51:39
Now that we have the NavigationHandle, I think we
carlosk
2015/10/26 10:33:23
Acknowledged.
|
+ |
+ // No pending RenderFrameHost as the current one should be reused. |
+ EXPECT_FALSE(GetPendingFrameHost(manager)); |
+ |
+ // But there should be a pending WebUI set to re-use the current one. |
+ EXPECT_EQ(web_ui, host->web_ui()); |
+ EXPECT_EQ(web_ui, manager->speculative_web_ui()); |
+ EXPECT_EQ(web_ui, host->pending_web_ui()); |
+ |
+ // The RenderFrameHost committed. |
+ manager->DidNavigateFrame(host, true); |
+ EXPECT_FALSE(change_observer.DidHostChange()); |
+ EXPECT_EQ(host, manager->current_frame_host()); |
+ EXPECT_FALSE(GetPendingFrameHost(manager)); |
+ EXPECT_EQ(web_ui, host->web_ui()); |
+ EXPECT_FALSE(manager->speculative_web_ui()); |
+ EXPECT_FALSE(host->pending_web_ui()); |
+} |
+ |
+// PlzNavigate: Tests that the correct intermediary and final navigation states |
+// are reached when navigating same-site between two different WebUI types. |
+TEST_F(RenderFrameHostManagerTestWithBrowserSideNavigation, |
+ NavigateSameSiteBetweenWebUIs) { |
+ set_should_create_webui(true); |
+ set_webui_type(1); |
+ NavigateActiveAndCommit(GURL("chrome://foo")); |
+ |
+ RenderFrameHostManager* manager = contents()->GetRenderManagerForTesting(); |
+ TestRenderFrameHost* host = |
+ static_cast<TestRenderFrameHost*>(manager->current_frame_host()); |
+ EXPECT_TRUE(host->IsRenderFrameLive()); |
+ EXPECT_TRUE(host->web_ui()); |
+ |
+ RenderViewHostChangedObserver change_observer(contents()); |
+ set_webui_type(2); |
+ |
+ // Navigation request. |
+ const GURL kUrl("chrome://foo/bar"); |
+ NavigationEntryImpl entry(NULL /* instance */, -1 /* page_id */, kUrl, |
+ Referrer(), base::string16() /* title */, |
+ ui::PAGE_TRANSITION_TYPED, |
+ false /* is_renderer_init */); |
+ FrameNavigationEntry* frame_entry = entry.root_node()->frame_entry.get(); |
+ scoped_ptr<NavigationRequest> navigation_request = |
+ NavigationRequest::CreateBrowserInitiated( |
+ contents()->GetFrameTree()->root(), frame_entry->url(), |
+ frame_entry->referrer(), *frame_entry, entry, |
+ FrameMsg_Navigate_Type::NORMAL, false, base::TimeTicks::Now(), |
+ static_cast<NavigationControllerImpl*>(&controller())); |
+ manager->DidCreateNavigationRequest(*navigation_request); |
+ |
+ // Current WebUI should still be in place and a new one should be pending |
clamy
2015/10/22 16:51:39
nit: The current.... and there should be a pending
carlosk
2015/10/26 10:33:23
Done.
|
+ // from the current RenderFrameHost. |
+ EXPECT_FALSE(change_observer.DidHostChange()); |
+ EXPECT_FALSE(GetPendingFrameHost(manager)); |
+ EXPECT_TRUE(host->web_ui()); |
+ WebUIImpl* next_web_ui = manager->speculative_web_ui(); |
+ EXPECT_TRUE(next_web_ui); |
+ EXPECT_NE(next_web_ui, host->web_ui()); |
+ EXPECT_EQ(next_web_ui, host->pending_web_ui()); |
+ |
+ // Prepare to commit, updates the navigating RenderFrameHost. |
clamy
2015/10/22 16:51:39
nit: update
carlosk
2015/10/26 10:33:23
Done.
|
+ EXPECT_EQ(host, manager->GetFrameHostForNavigation(*navigation_request)); |
+ host->set_pending_commit(true); |
clamy
2015/10/22 16:51:39
Again, let's avoid using this boolean.
carlosk
2015/10/26 10:33:23
Acknowledged.
|
+ |
+ EXPECT_FALSE(GetPendingFrameHost(manager)); |
+ EXPECT_TRUE(host->web_ui()); |
+ EXPECT_NE(next_web_ui, host->web_ui()); |
+ EXPECT_EQ(next_web_ui, manager->speculative_web_ui()); |
+ EXPECT_EQ(next_web_ui, host->pending_web_ui()); |
+ |
+ // The RenderFrameHost committed. |
+ manager->DidNavigateFrame(host, true); |
+ EXPECT_FALSE(change_observer.DidHostChange()); |
+ EXPECT_EQ(next_web_ui, host->web_ui()); |
+ EXPECT_FALSE(manager->speculative_web_ui()); |
+ EXPECT_FALSE(host->pending_web_ui()); |
+} |
+ |
+// PlzNavigate: Tests that the correct intermediary and final navigation states |
+// are reached when navigating cross-site between two different WebUI types. |
+TEST_F(RenderFrameHostManagerTestWithBrowserSideNavigation, |
+ NavigateCrossSiteBetweenWebUIs) { |
+ // Cross-site navigations will always cause the change of the WebUI instance |
+ // but for consistency sake different types will be set for each navigation. |
+ set_should_create_webui(true); |
+ set_webui_type(1); |
+ NavigateActiveAndCommit(GURL("chrome://foo")); |
+ |
+ RenderFrameHostManager* manager = contents()->GetRenderManagerForTesting(); |
+ TestRenderFrameHost* host = |
+ static_cast<TestRenderFrameHost*>(manager->current_frame_host()); |
+ EXPECT_TRUE(host->IsRenderFrameLive()); |
+ EXPECT_TRUE(host->web_ui()); |
+ |
+ RenderViewHostChangedObserver change_observer(contents()); |
+ set_webui_type(2); |
+ |
+ // Navigation request. |
+ const GURL kUrl("chrome://bar"); |
+ NavigationEntryImpl entry(NULL /* instance */, -1 /* page_id */, kUrl, |
+ Referrer(), base::string16() /* title */, |
+ ui::PAGE_TRANSITION_TYPED, |
+ false /* is_renderer_init */); |
+ FrameNavigationEntry* frame_entry = entry.root_node()->frame_entry.get(); |
+ scoped_ptr<NavigationRequest> navigation_request = |
+ NavigationRequest::CreateBrowserInitiated( |
+ contents()->GetFrameTree()->root(), frame_entry->url(), |
+ frame_entry->referrer(), *frame_entry, entry, |
+ FrameMsg_Navigate_Type::NORMAL, false, base::TimeTicks::Now(), |
+ static_cast<NavigationControllerImpl*>(&controller())); |
+ manager->DidCreateNavigationRequest(*navigation_request); |
+ |
+ // Current WebUI should still be in place and a new one should be pending |
clamy
2015/10/22 16:51:39
nit: see the comment about this comment above.
carlosk
2015/10/26 10:33:23
I adapted this to follow the same format but they
|
+ // from the speculative RenderFrameHost. |
+ EXPECT_FALSE(change_observer.DidHostChange()); |
+ TestRenderFrameHost* speculative_host = |
+ static_cast<TestRenderFrameHost*>(GetPendingFrameHost(manager)); |
+ EXPECT_TRUE(speculative_host); |
+ EXPECT_TRUE(manager->current_frame_host()->web_ui()); |
+ WebUIImpl* next_web_ui = manager->speculative_web_ui(); |
+ EXPECT_TRUE(next_web_ui); |
+ EXPECT_NE(next_web_ui, manager->current_frame_host()->web_ui()); |
+ EXPECT_EQ(next_web_ui, speculative_host->web_ui()); |
+ |
+ // Prepare to commit, updates the navigating RenderFrameHost. |
clamy
2015/10/22 16:51:39
Nit: see comment above.
carlosk
2015/10/26 10:33:23
Done.
|
+ EXPECT_EQ(speculative_host, |
+ manager->GetFrameHostForNavigation(*navigation_request)); |
+ speculative_host->set_pending_commit(true); |
+ |
+ EXPECT_EQ(speculative_host, GetPendingFrameHost(manager)); |
+ EXPECT_TRUE(manager->current_frame_host()->web_ui()); |
+ EXPECT_NE(next_web_ui, manager->current_frame_host()->web_ui()); |
clamy
2015/10/22 16:51:39
I think we should also test that the current RFH d
carlosk
2015/10/26 10:33:23
Done.
|
+ EXPECT_EQ(next_web_ui, manager->speculative_web_ui()); |
+ EXPECT_EQ(next_web_ui, speculative_host->web_ui()); |
+ |
+ // The RenderFrameHost committed. |
+ manager->DidNavigateFrame(speculative_host, true); |
+ EXPECT_EQ(speculative_host, manager->current_frame_host()); |
+ EXPECT_TRUE(change_observer.DidHostChange()); |
+ EXPECT_EQ(next_web_ui, manager->current_frame_host()->web_ui()); |
+ EXPECT_FALSE(manager->speculative_web_ui()); |
+ EXPECT_FALSE(speculative_host->pending_web_ui()); |
+} |
+ |
} // namespace content |