diff options
author | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-24 00:46:44 +0000 |
---|---|---|
committer | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-24 00:46:44 +0000 |
commit | 79ea4860d2a22403dbbdda865b2a360afbc3afbe (patch) | |
tree | a7a0b02aa35d620084adb6634c7b11769d415ac7 /content/browser | |
parent | 0651b818c7122d319954ff5bc30dff68ba8b9013 (diff) | |
download | chromium_src-79ea4860d2a22403dbbdda865b2a360afbc3afbe.zip chromium_src-79ea4860d2a22403dbbdda865b2a360afbc3afbe.tar.gz chromium_src-79ea4860d2a22403dbbdda865b2a360afbc3afbe.tar.bz2 |
Move files out of chrome\browser\renderer_host\test alongside their source. Most of them went to content\browser\renderer_host.
Review URL: http://codereview.chromium.org/6575009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@75824 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser')
13 files changed, 2164 insertions, 19 deletions
diff --git a/content/browser/renderer_host/render_process_host_browsertest.cc b/content/browser/renderer_host/render_process_host_browsertest.cc new file mode 100644 index 0000000..afe829c --- /dev/null +++ b/content/browser/renderer_host/render_process_host_browsertest.cc @@ -0,0 +1,263 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/command_line.h" +#include "chrome/browser/debugger/devtools_manager.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/url_constants.h" +#include "chrome/test/in_process_browser_test.h" +#include "chrome/test/ui_test_utils.h" +#include "content/browser/renderer_host/render_process_host.h" +#include "content/browser/renderer_host/render_view_host.h" +#include "content/browser/renderer_host/render_widget_host.h" +#include "content/browser/site_instance.h" +#include "content/browser/tab_contents/tab_contents.h" + +class RenderProcessHostTest : public InProcessBrowserTest { + public: + RenderProcessHostTest() { + EnableDOMAutomation(); + } + + int RenderProcessHostCount() { + RenderProcessHost::iterator hosts = RenderProcessHost::AllHostsIterator(); + int count = 0; + while (!hosts.IsAtEnd()) { + if (hosts.GetCurrentValue()->HasConnection()) + count++; + hosts.Advance(); + } + return count; + } + + RenderViewHost* FindFirstDevToolsHost() { + RenderProcessHost::iterator hosts = RenderProcessHost::AllHostsIterator(); + for (; !hosts.IsAtEnd(); hosts.Advance()) { + RenderProcessHost* render_process_host = hosts.GetCurrentValue(); + DCHECK(render_process_host); + if (!render_process_host->HasConnection()) + continue; + RenderProcessHost::listeners_iterator iter( + render_process_host->ListenersIterator()); + for (; !iter.IsAtEnd(); iter.Advance()) { + const RenderWidgetHost* widget = + static_cast<const RenderWidgetHost*>(iter.GetCurrentValue()); + DCHECK(widget); + if (!widget || !widget->IsRenderView()) + continue; + RenderViewHost* host = const_cast<RenderViewHost*>( + static_cast<const RenderViewHost*>(widget)); + RenderViewHostDelegate* host_delegate = host->delegate(); + GURL url = host_delegate->GetURL(); + if (url.SchemeIs(chrome::kChromeDevToolsScheme)) + return host; + } + } + return NULL; + } +}; + +IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, ProcessPerTab) { + // Set max renderers to 1 to force running out of processes. + RenderProcessHost::SetMaxRendererProcessCount(1); + + CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); + parsed_command_line.AppendSwitch(switches::kProcessPerTab); + + int tab_count = 1; + int host_count = 1; + + // Change the first tab to be the new tab page (TYPE_WEBUI). + GURL newtab(chrome::kChromeUINewTabURL); + ui_test_utils::NavigateToURL(browser(), newtab); + EXPECT_EQ(tab_count, browser()->tab_count()); + EXPECT_EQ(host_count, RenderProcessHostCount()); + + // Create a new TYPE_NORMAL tab. It should be in its own process. + GURL page1("data:text/html,hello world1"); + browser()->ShowSingletonTab(page1, false); + if (browser()->tab_count() == tab_count) + ui_test_utils::WaitForNewTab(browser()); + tab_count++; + host_count++; + EXPECT_EQ(tab_count, browser()->tab_count()); + EXPECT_EQ(host_count, RenderProcessHostCount()); + + // Create another TYPE_NORMAL tab. It should share the previous process. + GURL page2("data:text/html,hello world2"); + browser()->ShowSingletonTab(page2, false); + if (browser()->tab_count() == tab_count) + ui_test_utils::WaitForNewTab(browser()); + tab_count++; + EXPECT_EQ(tab_count, browser()->tab_count()); + EXPECT_EQ(host_count, RenderProcessHostCount()); + + // Create another new tab. It should share the process with the other WebUI. + browser()->NewTab(); + if (browser()->tab_count() == tab_count) + ui_test_utils::WaitForNewTab(browser()); + tab_count++; + EXPECT_EQ(tab_count, browser()->tab_count()); + EXPECT_EQ(host_count, RenderProcessHostCount()); + + // Create another new tab. It should share the process with the other WebUI. + browser()->NewTab(); + if (browser()->tab_count() == tab_count) + ui_test_utils::WaitForNewTab(browser()); + tab_count++; + EXPECT_EQ(tab_count, browser()->tab_count()); + EXPECT_EQ(host_count, RenderProcessHostCount()); +} + +// Ensure that DevTools opened to debug DevTools is launched in a separate +// process when --process-per-tab is set. See crbug.com/69873. +IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, DevToolsOnSelfInOwnProcessPPT) { + CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); + parsed_command_line.AppendSwitch(switches::kProcessPerTab); + + int tab_count = 1; + int host_count = 1; + + GURL page1("data:text/html,hello world1"); + browser()->ShowSingletonTab(page1, false); + if (browser()->tab_count() == tab_count) + ui_test_utils::WaitForNewTab(browser()); + tab_count++; + host_count++; + EXPECT_EQ(tab_count, browser()->tab_count()); + EXPECT_EQ(host_count, RenderProcessHostCount()); + + // DevTools start in docked mode (no new tab), in a separate process. + browser()->ToggleDevToolsWindow(DEVTOOLS_TOGGLE_ACTION_INSPECT); + host_count++; + EXPECT_EQ(tab_count, browser()->tab_count()); + EXPECT_EQ(host_count, RenderProcessHostCount()); + + RenderViewHost* devtools = FindFirstDevToolsHost(); + DCHECK(devtools); + + // DevTools start in a separate process. + DevToolsManager::GetInstance()->ToggleDevToolsWindow( + devtools, DEVTOOLS_TOGGLE_ACTION_INSPECT); + host_count++; + EXPECT_EQ(tab_count, browser()->tab_count()); + EXPECT_EQ(host_count, RenderProcessHostCount()); +} + +// Ensure that DevTools opened to debug DevTools is launched in a separate +// process. See crbug.com/69873. +IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, DevToolsOnSelfInOwnProcess) { + int tab_count = 1; + int host_count = 1; + + GURL page1("data:text/html,hello world1"); + browser()->ShowSingletonTab(page1, false); + if (browser()->tab_count() == tab_count) + ui_test_utils::WaitForNewTab(browser()); + tab_count++; + host_count++; + EXPECT_EQ(tab_count, browser()->tab_count()); + EXPECT_EQ(host_count, RenderProcessHostCount()); + + // DevTools start in docked mode (no new tab), in a separate process. + browser()->ToggleDevToolsWindow(DEVTOOLS_TOGGLE_ACTION_INSPECT); + host_count++; + EXPECT_EQ(tab_count, browser()->tab_count()); + EXPECT_EQ(host_count, RenderProcessHostCount()); + + RenderViewHost* devtools = FindFirstDevToolsHost(); + DCHECK(devtools); + + // DevTools start in a separate process. + DevToolsManager::GetInstance()->ToggleDevToolsWindow( + devtools, DEVTOOLS_TOGGLE_ACTION_INSPECT); + host_count++; + EXPECT_EQ(tab_count, browser()->tab_count()); + EXPECT_EQ(host_count, RenderProcessHostCount()); +} + +// When we hit the max number of renderers, verify that the way we do process +// sharing behaves correctly. In particular, this test is verifying that even +// when we hit the max process limit, that renderers of each type will wind up +// in a process of that type, even if that means creating a new process. +IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, ProcessOverflow) { + // Set max renderers to 1 to force running out of processes. + RenderProcessHost::SetMaxRendererProcessCount(1); + + int tab_count = 1; + int host_count = 1; + TabContents* tab1 = NULL; + TabContents* tab2 = NULL; + RenderProcessHost* rph1 = NULL; + RenderProcessHost* rph2 = NULL; + RenderProcessHost* rph3 = NULL; + + // Change the first tab to be the new tab page (TYPE_WEBUI). + GURL newtab(chrome::kChromeUINewTabURL); + ui_test_utils::NavigateToURL(browser(), newtab); + EXPECT_EQ(tab_count, browser()->tab_count()); + tab1 = browser()->GetTabContentsAt(tab_count - 1); + rph1 = tab1->GetRenderProcessHost(); + EXPECT_EQ(tab1->GetURL(), newtab); + EXPECT_EQ(host_count, RenderProcessHostCount()); + + // Create a new TYPE_NORMAL tab. It should be in its own process. + GURL page1("data:text/html,hello world1"); + browser()->ShowSingletonTab(page1, false); + if (browser()->tab_count() == tab_count) + ui_test_utils::WaitForNewTab(browser()); + tab_count++; + host_count++; + EXPECT_EQ(tab_count, browser()->tab_count()); + tab1 = browser()->GetTabContentsAt(tab_count - 1); + rph2 = tab1->GetRenderProcessHost(); + EXPECT_EQ(tab1->GetURL(), page1); + EXPECT_EQ(host_count, RenderProcessHostCount()); + EXPECT_NE(rph1, rph2); + + // Create another TYPE_NORMAL tab. It should share the previous process. + GURL page2("data:text/html,hello world2"); + browser()->ShowSingletonTab(page2, false); + if (browser()->tab_count() == tab_count) + ui_test_utils::WaitForNewTab(browser()); + tab_count++; + EXPECT_EQ(tab_count, browser()->tab_count()); + tab2 = browser()->GetTabContentsAt(tab_count - 1); + EXPECT_EQ(tab2->GetURL(), page2); + EXPECT_EQ(host_count, RenderProcessHostCount()); + EXPECT_EQ(tab2->GetRenderProcessHost(), rph2); + + // Create another TYPE_WEBUI tab. It should share the process with newtab. + // Note: intentionally create this tab after the TYPE_NORMAL tabs to exercise + // bug 43448 where extension and WebUI tabs could get combined into normal + // renderers. + GURL history(chrome::kChromeUIHistoryURL); + browser()->ShowSingletonTab(history, false); + if (browser()->tab_count() == tab_count) + ui_test_utils::WaitForNewTab(browser()); + tab_count++; + EXPECT_EQ(tab_count, browser()->tab_count()); + tab2 = browser()->GetTabContentsAt(tab_count - 1); + EXPECT_EQ(tab2->GetURL(), history); + EXPECT_EQ(host_count, RenderProcessHostCount()); + EXPECT_EQ(tab2->GetRenderProcessHost(), rph1); + + // Create a TYPE_EXTENSION tab. It should be in its own process. + // (the bookmark manager is implemented as an extension) + GURL bookmarks(chrome::kChromeUIBookmarksURL); + browser()->ShowSingletonTab(bookmarks, false); + if (browser()->tab_count() == tab_count) + ui_test_utils::WaitForNewTab(browser()); + tab_count++; + host_count++; + EXPECT_EQ(tab_count, browser()->tab_count()); + tab1 = browser()->GetTabContentsAt(tab_count - 1); + rph3 = tab1->GetRenderProcessHost(); + EXPECT_EQ(tab1->GetURL(), bookmarks); + EXPECT_EQ(host_count, RenderProcessHostCount()); + EXPECT_NE(rph1, rph3); + EXPECT_NE(rph2, rph3); +} diff --git a/content/browser/renderer_host/render_view_host_browsertest.cc b/content/browser/renderer_host/render_view_host_browsertest.cc new file mode 100644 index 0000000..6c4a771 --- /dev/null +++ b/content/browser/renderer_host/render_view_host_browsertest.cc @@ -0,0 +1,268 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/utf_string_conversions.h" +#include "base/time.h" +#include "base/values.h" +#include "chrome/browser/content_settings/host_content_settings_map.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/tab_contents/tab_specific_content_settings.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/common/render_messages_params.h" +#include "chrome/test/in_process_browser_test.h" +#include "chrome/test/ui_test_utils.h" +#include "content/browser/renderer_host/render_view_host.h" +#include "content/browser/tab_contents/tab_contents.h" +#include "content/browser/tab_contents/tab_contents_observer.h" +#include "net/base/host_port_pair.h" +#include "net/test/test_server.h" + +typedef std::pair<int, Value*> ExecuteDetailType; + +namespace { + +// NotificationObserver used to listen for EXECUTE_JAVASCRIPT_RESULT +// notifications. +class ExecuteNotificationObserver : public NotificationObserver { + public: + ExecuteNotificationObserver() : id_(0) {} + + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + id_ = (static_cast<Details<ExecuteDetailType > >(details))->first; + Value* value = (static_cast<Details<ExecuteDetailType > >(details))->second; + if (value) + value_.reset(value->DeepCopy()); + MessageLoopForUI::current()->Quit(); + } + + int id() const { return id_; } + + Value* value() const { return value_.get(); } + + private: + int id_; + scoped_ptr<Value> value_; + + DISALLOW_COPY_AND_ASSIGN(ExecuteNotificationObserver); +}; + +} // namespace + +class RenderViewHostTest : public InProcessBrowserTest { + public: + RenderViewHostTest() : last_execute_id_(0) {} + + void ExecuteJavascriptAndGetValue(const char* script, + ExecuteNotificationObserver* out_result) { + RenderViewHost* rvh = + browser()->GetSelectedTabContents()->render_view_host(); + ASSERT_TRUE(rvh); + int execute_id = rvh->ExecuteJavascriptInWebFrameNotifyResult( + string16(), + ASCIIToUTF16(script)); + EXPECT_NE(execute_id, last_execute_id_); + ExecuteNotificationObserver observer; + ui_test_utils::RegisterAndWait( + out_result, + NotificationType::EXECUTE_JAVASCRIPT_RESULT, + Source<RenderViewHost>(rvh)); + EXPECT_EQ(execute_id, out_result->id()); + ASSERT_TRUE(out_result->value()); + last_execute_id_ = execute_id; + } + + private: + int last_execute_id_; +}; + + +// Makes sure ExecuteJavascriptInWebFrameNotifyResult works. +IN_PROC_BROWSER_TEST_F(RenderViewHostTest, + ExecuteJavascriptInWebFrameNotifyResult) { + ASSERT_TRUE(test_server()->Start()); + GURL empty_url(test_server()->GetURL("files/empty.html")); + ui_test_utils::NavigateToURL(browser(), empty_url); + + // Execute the script 'true' and make sure we get back true. + { + ExecuteNotificationObserver observer; + ExecuteJavascriptAndGetValue("true;", &observer); + EXPECT_EQ(Value::TYPE_BOOLEAN, observer.value()->GetType()); + bool bool_value; + EXPECT_TRUE(observer.value()->GetAsBoolean(&bool_value)); + EXPECT_TRUE(bool_value); + } + + // Execute the script 'false' and make sure we get back false. + { + ExecuteNotificationObserver observer; + ExecuteJavascriptAndGetValue("false;", &observer); + EXPECT_EQ(Value::TYPE_BOOLEAN, observer.value()->GetType()); + bool bool_value; + EXPECT_TRUE(observer.value()->GetAsBoolean(&bool_value)); + EXPECT_FALSE(bool_value); + } + + // And now, for something completely different, try a number. + { + ExecuteNotificationObserver observer; + ExecuteJavascriptAndGetValue("42;", &observer); + EXPECT_EQ(Value::TYPE_INTEGER, observer.value()->GetType()); + int int_value; + EXPECT_TRUE(observer.value()->GetAsInteger(&int_value)); + EXPECT_EQ(42, int_value); + } + + // Try a floating point number. + { + ExecuteNotificationObserver observer; + ExecuteJavascriptAndGetValue("42.2;", &observer); + EXPECT_EQ(Value::TYPE_DOUBLE, observer.value()->GetType()); + double double_value; + EXPECT_TRUE(observer.value()->GetAsDouble(&double_value)); + EXPECT_EQ(42.2, double_value); + } + + // Let's check out string. + { + ExecuteNotificationObserver observer; + ExecuteJavascriptAndGetValue("\"something completely different\";", + &observer); + EXPECT_EQ(Value::TYPE_STRING, observer.value()->GetType()); + std::string string_value; + EXPECT_TRUE(observer.value()->GetAsString(&string_value)); + EXPECT_EQ(std::string("something completely different"), string_value); + } + + // Regular expressions might be fun. + { + ExecuteNotificationObserver observer; + ExecuteJavascriptAndGetValue("/finder.*foo/g;", &observer); + EXPECT_EQ(Value::TYPE_STRING, observer.value()->GetType()); + std::string string_value; + EXPECT_TRUE(observer.value()->GetAsString(&string_value)); + EXPECT_EQ(std::string("/finder.*foo/g"), string_value); + } + + // Let's test some date conversions. First up, epoch. Can't use 0 because + // that means uninitialized, so use the next best thing. + { + ExecuteNotificationObserver observer; + ExecuteJavascriptAndGetValue("new Date(1);", &observer); + EXPECT_EQ(Value::TYPE_DOUBLE, observer.value()->GetType()); + double date_seconds; + EXPECT_TRUE(observer.value()->GetAsDouble(&date_seconds)); + + base::Time time = base::Time::FromDoubleT(date_seconds); + + base::Time::Exploded time_exploded; + time.UTCExplode(&time_exploded); + EXPECT_EQ(1970, time_exploded.year); + EXPECT_EQ(1, time_exploded.month); + EXPECT_EQ(1, time_exploded.day_of_month); + EXPECT_EQ(0, time_exploded.hour); + EXPECT_EQ(0, time_exploded.minute); + EXPECT_EQ(0, time_exploded.second); + } + + // Test date with a real date input. + { + ExecuteNotificationObserver observer; + ExecuteJavascriptAndGetValue("new Date(Date.UTC(2006, 7, 16, 12, 0, 15));", + &observer); + EXPECT_EQ(Value::TYPE_DOUBLE, observer.value()->GetType()); + double date_seconds; + EXPECT_TRUE(observer.value()->GetAsDouble(&date_seconds)); + + base::Time time = base::Time::FromDoubleT(date_seconds); + + base::Time::Exploded time_exploded; + time.UTCExplode(&time_exploded); + EXPECT_EQ(2006, time_exploded.year); + // Subtle; 0 based in JS, 1 based in base::Time: + EXPECT_EQ(8, time_exploded.month); + EXPECT_EQ(16, time_exploded.day_of_month); + EXPECT_EQ(12, time_exploded.hour); + EXPECT_EQ(0, time_exploded.minute); + EXPECT_EQ(15, time_exploded.second); + } + + // And something more complicated - get an array back as a list. + { + ExecuteNotificationObserver observer; + ExecuteJavascriptAndGetValue("new Array(\"one\", 2, false);", &observer); + EXPECT_EQ(Value::TYPE_LIST, observer.value()->GetType()); + ListValue* list_value; + EXPECT_TRUE(observer.value()->GetAsList(&list_value)); + EXPECT_EQ(3U, list_value->GetSize()); + Value* value; + EXPECT_TRUE(list_value->Get(0, &value)); + EXPECT_EQ(Value::TYPE_STRING, value->GetType()); + EXPECT_TRUE(list_value->Get(1, &value)); + EXPECT_EQ(Value::TYPE_INTEGER, value->GetType()); + EXPECT_TRUE(list_value->Get(2, &value)); + EXPECT_EQ(Value::TYPE_BOOLEAN, value->GetType()); + } +} + +// Regression test for http://crbug.com/63649. +IN_PROC_BROWSER_TEST_F(RenderViewHostTest, RedirectLoopCookies) { + ASSERT_TRUE(test_server()->Start()); + + GURL test_url = test_server()->GetURL("files/redirect-loop.html"); + + browser()->profile()->GetHostContentSettingsMap()->SetDefaultContentSetting( + CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_BLOCK); + + ui_test_utils::NavigateToURL(browser(), test_url); + + TabContents* tab_contents = browser()->GetSelectedTabContents(); + ASSERT_EQ(UTF8ToUTF16(test_url.spec() + " failed to load"), + tab_contents->GetTitle()); + + EXPECT_TRUE(tab_contents->GetTabSpecificContentSettings()->IsContentBlocked( + CONTENT_SETTINGS_TYPE_COOKIES)); +} + +class RenderViewHostTestTabContentsObserver : public TabContentsObserver { + public: + explicit RenderViewHostTestTabContentsObserver(TabContents* tab_contents) + : TabContentsObserver(tab_contents), + navigation_count_(0) {} + virtual ~RenderViewHostTestTabContentsObserver() {} + + virtual void DidNavigateMainFramePostCommit( + const NavigationController::LoadCommittedDetails& details, + const ViewHostMsg_FrameNavigate_Params& params) { + observed_socket_address_ = params.socket_address; + ++navigation_count_; + } + + const net::HostPortPair& observed_socket_address() const { + return observed_socket_address_; + } + + int navigation_count() const { return navigation_count_; } + + private: + net::HostPortPair observed_socket_address_; + int navigation_count_; + + DISALLOW_COPY_AND_ASSIGN(RenderViewHostTestTabContentsObserver); +}; + +IN_PROC_BROWSER_TEST_F(RenderViewHostTest, FrameNavigateSocketAddress) { + ASSERT_TRUE(test_server()->Start()); + RenderViewHostTestTabContentsObserver observer( + browser()->GetSelectedTabContents()); + + GURL test_url = test_server()->GetURL("files/simple.html"); + ui_test_utils::NavigateToURL(browser(), test_url); + + EXPECT_EQ(test_server()->host_port_pair().ToString(), + observer.observed_socket_address().ToString()); + EXPECT_EQ(1, observer.navigation_count()); +} diff --git a/content/browser/renderer_host/render_view_host_manager_browsertest.cc b/content/browser/renderer_host/render_view_host_manager_browsertest.cc new file mode 100644 index 0000000..423ce64 --- /dev/null +++ b/content/browser/renderer_host/render_view_host_manager_browsertest.cc @@ -0,0 +1,277 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/file_util.h" +#include "base/path_service.h" +#include "base/ref_counted.h" +#include "chrome/browser/download/download_manager.h" +#include "chrome/browser/extensions/extension_error_reporter.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/notification_details.h" +#include "chrome/common/notification_observer.h" +#include "chrome/common/notification_registrar.h" +#include "chrome/common/notification_type.h" +#include "chrome/test/in_process_browser_test.h" +#include "chrome/test/ui_test_utils.h" +#include "content/browser/tab_contents/tab_contents.h" +#include "content/browser/site_instance.h" +#include "net/base/net_util.h" +#include "net/test/test_server.h" + +class RenderViewHostManagerTest : public InProcessBrowserTest { + public: + RenderViewHostManagerTest() { + EnableDOMAutomation(); + } + + static bool GetFilePathWithHostAndPortReplacement( + const std::string& original_file_path, + const net::HostPortPair& host_port_pair, + std::string* replacement_path) { + std::vector<net::TestServer::StringPair> replacement_text; + replacement_text.push_back( + make_pair("REPLACE_WITH_HOST_AND_PORT", host_port_pair.ToString())); + return net::TestServer::GetFilePathWithReplacements( + original_file_path, replacement_text, replacement_path); + } +}; + +// Test for crbug.com/24447. Following a cross-site link with rel=noreferrer +// and target=_blank should create a new SiteInstance. +IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, + SwapProcessWithRelNoreferrerAndTargetBlank) { + // Start two servers with different sites. + ASSERT_TRUE(test_server()->Start()); + net::TestServer https_server_( + net::TestServer::TYPE_HTTPS, + FilePath(FILE_PATH_LITERAL("chrome/test/data"))); + ASSERT_TRUE(https_server_.Start()); + + // Load a page with links that open in a new window. + std::string replacement_path; + ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( + "files/click-noreferrer-links.html", + https_server_.host_port_pair(), + &replacement_path)); + ui_test_utils::NavigateToURL(browser(), + test_server()->GetURL(replacement_path)); + + // Get the original SiteInstance for later comparison. + scoped_refptr<SiteInstance> orig_site_instance( + browser()->GetSelectedTabContents()->GetSiteInstance()); + EXPECT_TRUE(orig_site_instance != NULL); + + // Test clicking a rel=noreferrer + target=blank link. + bool success = false; + EXPECT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( + browser()->GetSelectedTabContents()->render_view_host(), L"", + L"window.domAutomationController.send(clickNoRefTargetBlankLink());", + &success)); + EXPECT_TRUE(success); + // Wait for the cross-site transition to finish. + ui_test_utils::WaitForLoadStop( + &(browser()->GetSelectedTabContents()->controller())); + + // Opens in new tab. + EXPECT_EQ(2, browser()->tab_count()); + EXPECT_EQ(1, browser()->selected_index()); + EXPECT_EQ(L"Title Of Awesomeness", + browser()->GetSelectedTabContents()->GetTitle()); + + // Should have a new SiteInstance. + scoped_refptr<SiteInstance> noref_blank_site_instance( + browser()->GetSelectedTabContents()->GetSiteInstance()); + EXPECT_NE(orig_site_instance, noref_blank_site_instance); +} + +// Test for crbug.com/24447. Following a cross-site link with just +// target=_blank should not create a new SiteInstance. +// Disabled, http://crbug.com/67532. +IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, + DISABLED_DontSwapProcessWithOnlyTargetBlank) { + // Start two servers with different sites. + ASSERT_TRUE(test_server()->Start()); + net::TestServer https_server_( + net::TestServer::TYPE_HTTPS, + FilePath(FILE_PATH_LITERAL("chrome/test/data"))); + ASSERT_TRUE(https_server_.Start()); + + // Load a page with links that open in a new window. + std::string replacement_path; + ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( + "files/click-noreferrer-links.html", + https_server_.host_port_pair(), + &replacement_path)); + ui_test_utils::NavigateToURL(browser(), + test_server()->GetURL(replacement_path)); + + // Get the original SiteInstance for later comparison. + scoped_refptr<SiteInstance> orig_site_instance( + browser()->GetSelectedTabContents()->GetSiteInstance()); + EXPECT_TRUE(orig_site_instance != NULL); + + // Test clicking a target=blank link. + bool success = false; + EXPECT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( + browser()->GetSelectedTabContents()->render_view_host(), L"", + L"window.domAutomationController.send(clickTargetBlankLink());", + &success)); + EXPECT_TRUE(success); + // Wait for the cross-site transition to finish. + ui_test_utils::WaitForLoadStop( + &(browser()->GetSelectedTabContents()->controller())); + + // Opens in new tab. + EXPECT_EQ(2, browser()->tab_count()); + EXPECT_EQ(1, browser()->selected_index()); + EXPECT_EQ(L"Title Of Awesomeness", + browser()->GetSelectedTabContents()->GetTitle()); + + // Should have the same SiteInstance. + scoped_refptr<SiteInstance> blank_site_instance( + browser()->GetSelectedTabContents()->GetSiteInstance()); + EXPECT_EQ(orig_site_instance, blank_site_instance); +} + +// Test for crbug.com/24447. Following a cross-site link with rel=noreferrer +// and no target=_blank should not create a new SiteInstance. +IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, + DontSwapProcessWithOnlyRelNoreferrer) { + // Start two servers with different sites. + ASSERT_TRUE(test_server()->Start()); + net::TestServer https_server_( + net::TestServer::TYPE_HTTPS, + FilePath(FILE_PATH_LITERAL("chrome/test/data"))); + ASSERT_TRUE(https_server_.Start()); + + // Load a page with links that open in a new window. + std::string replacement_path; + ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( + "files/click-noreferrer-links.html", + https_server_.host_port_pair(), + &replacement_path)); + ui_test_utils::NavigateToURL(browser(), + test_server()->GetURL(replacement_path)); + + // Get the original SiteInstance for later comparison. + scoped_refptr<SiteInstance> orig_site_instance( + browser()->GetSelectedTabContents()->GetSiteInstance()); + EXPECT_TRUE(orig_site_instance != NULL); + + // Test clicking a rel=noreferrer link. + bool success = false; + EXPECT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( + browser()->GetSelectedTabContents()->render_view_host(), L"", + L"window.domAutomationController.send(clickNoRefLink());", + &success)); + EXPECT_TRUE(success); + // Wait for the cross-site transition to finish. + ui_test_utils::WaitForLoadStop( + &(browser()->GetSelectedTabContents()->controller())); + + // Opens in same tab. + EXPECT_EQ(1, browser()->tab_count()); + EXPECT_EQ(0, browser()->selected_index()); + EXPECT_EQ(L"Title Of Awesomeness", + browser()->GetSelectedTabContents()->GetTitle()); + + // Should have the same SiteInstance. + scoped_refptr<SiteInstance> noref_site_instance( + browser()->GetSelectedTabContents()->GetSiteInstance()); + EXPECT_EQ(orig_site_instance, noref_site_instance); +} + +// Hangs flakily in Win, http://crbug.com/45040. +#if defined(OS_WIN) +#define MAYBE_ChromeURLAfterDownload DISABLED_ChromeURLAfterDownload +#else +#define MAYBE_ChromeURLAfterDownload ChromeURLAfterDownload +#endif // defined(OS_WIN) + +// Test for crbug.com/14505. This tests that chrome:// urls are still functional +// after download of a file while viewing another chrome://. +IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, + MAYBE_ChromeURLAfterDownload) { + GURL downloads_url("chrome://downloads"); + GURL extensions_url("chrome://extensions"); + FilePath zip_download; + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &zip_download)); + zip_download = zip_download.AppendASCII("zip").AppendASCII("test.zip"); + GURL zip_url = net::FilePathToFileURL(zip_download); + + ui_test_utils::NavigateToURL(browser(), downloads_url); + ui_test_utils::NavigateToURL(browser(), zip_url); + ui_test_utils::WaitForDownloadCount( + browser()->profile()->GetDownloadManager(), 1); + ui_test_utils::NavigateToURL(browser(), extensions_url); + + TabContents *contents = browser()->GetSelectedTabContents(); + ASSERT_TRUE(contents); + bool webui_responded = false; + EXPECT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( + contents->render_view_host(), + L"", + L"window.domAutomationController.send(window.webui_responded_);", + &webui_responded)); + EXPECT_TRUE(webui_responded); +} + +class BrowserClosedObserver : public NotificationObserver { + public: + explicit BrowserClosedObserver(Browser* browser) { + registrar_.Add(this, NotificationType::BROWSER_CLOSED, + Source<Browser>(browser)); + ui_test_utils::RunMessageLoop(); + } + + // NotificationObserver + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + switch (type.value) { + case NotificationType::BROWSER_CLOSED: + MessageLoopForUI::current()->Quit(); + break; + } + } + + private: + NotificationRegistrar registrar_; +}; + +// Test for crbug.com/12745. This tests that if a download is initiated from +// a chrome:// page that has registered and onunload handler, the browser +// will be able to close. +// TODO(rafaelw): The fix for 12745 has now also been reverted. Another fix +// must be found before this can be re-enabled. +IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, + DISABLED_BrowserCloseAfterDownload) { + GURL downloads_url("chrome://downloads"); + FilePath zip_download; + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &zip_download)); + zip_download = zip_download.AppendASCII("zip").AppendASCII("test.zip"); + ASSERT_TRUE(file_util::PathExists(zip_download)); + GURL zip_url = net::FilePathToFileURL(zip_download); + + ui_test_utils::NavigateToURL(browser(), downloads_url); + TabContents *contents = browser()->GetSelectedTabContents(); + ASSERT_TRUE(contents); + bool result = false; + EXPECT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( + contents->render_view_host(), + L"", + L"window.onunload = function() { var do_nothing = 0; }; " + L"window.domAutomationController.send(true);", + &result)); + EXPECT_TRUE(result); + ui_test_utils::NavigateToURL(browser(), zip_url); + + ui_test_utils::WaitForDownloadCount( + browser()->profile()->GetDownloadManager(), 1); + + browser()->CloseWindow(); + BrowserClosedObserver wait_for_close(browser()); +} diff --git a/content/browser/renderer_host/render_view_host_unittest.cc b/content/browser/renderer_host/render_view_host_unittest.cc new file mode 100644 index 0000000..83c52fd7 --- /dev/null +++ b/content/browser/renderer_host/render_view_host_unittest.cc @@ -0,0 +1,100 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/common/page_transition_types.h" +#include "chrome/common/render_messages.h" +#include "content/browser/renderer_host/test_render_view_host.h" +#include "content/browser/tab_contents/navigation_controller.h" +#include "content/browser/tab_contents/navigation_entry.h" +#include "content/browser/tab_contents/test_tab_contents.h" + +class RenderViewHostTest : public RenderViewHostTestHarness { +}; + +// All about URLs reported by the renderer should get rewritten to about:blank. +// See RenderViewHost::OnMsgNavigate for a discussion. +TEST_F(RenderViewHostTest, FilterAbout) { + rvh()->SendNavigate(1, GURL("about:cache")); + ASSERT_TRUE(controller().GetActiveEntry()); + EXPECT_EQ(GURL("about:blank"), controller().GetActiveEntry()->url()); +} + +// Create a full screen popup RenderWidgetHost and View. +TEST_F(RenderViewHostTest, CreateFullscreenWidget) { + int routing_id = process()->GetNextRoutingID(); + rvh()->CreateNewFullscreenWidget(routing_id); +} + +// Makes sure that RenderViewHost::is_waiting_for_unload_ack_ is false when +// reloading a page. If is_waiting_for_unload_ack_ is not false when reloading +// the tab may get closed out even though the user pressed the reload button. +TEST_F(RenderViewHostTest, ResetUnloadOnReload) { + const GURL url1("http://foo1"); + const GURL url2("http://foo2"); + + // This test is for a subtle timing bug. Here's the sequence that triggered + // the bug: + // . go to a page. + // . go to a new page, preferably one that takes a while to resolve, such + // as one on a site that doesn't exist. + // . After this step is_waiting_for_unload_ack_ has been set to true on + // the first RVH. + // . click stop before the page has been commited. + // . click reload. + // . is_waiting_for_unload_ack_ is still true, and the if the hang monitor + // fires the tab gets closed. + + NavigateAndCommit(url1); + controller().LoadURL(url2, GURL(), PageTransition::LINK); + // Simulate the ClosePage call which is normally sent by the net::URLRequest. + rvh()->ClosePage(true, 0, 0); + // Needed so that navigations are not suspended on the RVH. Normally handled + // by way of ViewHostMsg_ShouldClose_ACK. + contents()->render_manager()->ShouldClosePage(true, true); + contents()->Stop(); + controller().Reload(false); + EXPECT_FALSE(rvh()->is_waiting_for_unload_ack()); +} + +// The test that follow trigger DCHECKS in debug build. +#if defined(NDEBUG) + +// Test that when we fail to de-serialize a message, RenderViewHost calls the +// ReceivedBadMessage() handler. +TEST_F(RenderViewHostTest, BadMessageHandlerRenderViewHost) { + EXPECT_EQ(0, process()->bad_msg_count()); + // craft an incorrect ViewHostMsg_UpdateTargetURL message. The real one has + // two payload items but the one we construct has none. + IPC::Message message(0, ViewHostMsg_UpdateTargetURL::ID, + IPC::Message::PRIORITY_NORMAL); + rvh()->TestOnMessageReceived(message); + EXPECT_EQ(1, process()->bad_msg_count()); +} + +// Test that when we fail to de-serialize a message, RenderWidgetHost calls the +// ReceivedBadMessage() handler. +TEST_F(RenderViewHostTest, BadMessageHandlerRenderWidgetHost) { + EXPECT_EQ(0, process()->bad_msg_count()); + // craft an incorrect ViewHostMsg_UpdateRect message. The real one has + // one payload item but the one we construct has none. + IPC::Message message(0, ViewHostMsg_UpdateRect::ID, + IPC::Message::PRIORITY_NORMAL); + rvh()->TestOnMessageReceived(message); + EXPECT_EQ(1, process()->bad_msg_count()); +} + +// Test that OnMsgInputEventAck() detects bad messages. +TEST_F(RenderViewHostTest, BadMessageHandlerInputEventAck) { + EXPECT_EQ(0, process()->bad_msg_count()); + // ViewHostMsg_HandleInputEvent_ACK is defined taking 0 params but + // the code actually expects it to have at least one int para, this this + // bogus message will not fail at de-serialization but should fail in + // OnMsgInputEventAck() processing. + IPC::Message message(0, ViewHostMsg_HandleInputEvent_ACK::ID, + IPC::Message::PRIORITY_NORMAL); + rvh()->TestOnMessageReceived(message); + EXPECT_EQ(1, process()->bad_msg_count()); +} + +#endif // NDEBUG diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc index 546854e..162dd96 100644 --- a/content/browser/renderer_host/render_widget_host_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_unittest.cc @@ -7,13 +7,13 @@ #include "base/shared_memory.h" #include "base/timer.h" #include "build/build_config.h" -#include "chrome/browser/renderer_host/backing_store.h" -#include "chrome/browser/renderer_host/test/test_render_view_host.h" #include "chrome/common/notification_details.h" #include "chrome/common/notification_source.h" #include "chrome/common/render_messages.h" #include "chrome/common/render_messages_params.h" #include "chrome/test/testing_profile.h" +#include "content/browser/renderer_host/backing_store.h" +#include "content/browser/renderer_host/test_render_view_host.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/keycodes/keyboard_codes.h" #include "ui/gfx/canvas_skia.h" diff --git a/content/browser/renderer_host/test_backing_store.cc b/content/browser/renderer_host/test_backing_store.cc new file mode 100644 index 0000000..e0c2694 --- /dev/null +++ b/content/browser/renderer_host/test_backing_store.cc @@ -0,0 +1,30 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/renderer_host/test_backing_store.h" + +TestBackingStore::TestBackingStore(RenderWidgetHost* widget, + const gfx::Size& size) + : BackingStore(widget, size) { +} + +TestBackingStore::~TestBackingStore() { +} + +void TestBackingStore::PaintToBackingStore( + RenderProcessHost* process, + TransportDIB::Id bitmap, + const gfx::Rect& bitmap_rect, + const std::vector<gfx::Rect>& copy_rects) { +} + +bool TestBackingStore::CopyFromBackingStore(const gfx::Rect& rect, + skia::PlatformCanvas* output) { + return false; +} + +void TestBackingStore::ScrollBackingStore(int dx, int dy, + const gfx::Rect& clip_rect, + const gfx::Size& view_size) { +} diff --git a/content/browser/renderer_host/test_backing_store.h b/content/browser/renderer_host/test_backing_store.h new file mode 100644 index 0000000..83909dc --- /dev/null +++ b/content/browser/renderer_host/test_backing_store.h @@ -0,0 +1,31 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_RENDERER_HOST_TEST_TEST_BACKING_STORE_H_ +#define CONTENT_BROWSER_RENDERER_HOST_TEST_TEST_BACKING_STORE_H_ +#pragma once + +#include "base/basictypes.h" +#include "content/browser/renderer_host/backing_store.h" + +class TestBackingStore : public BackingStore { + public: + TestBackingStore(RenderWidgetHost* widget, const gfx::Size& size); + virtual ~TestBackingStore(); + + // BackingStore implementation. + virtual void PaintToBackingStore(RenderProcessHost* process, + TransportDIB::Id bitmap, + const gfx::Rect& bitmap_rect, + const std::vector<gfx::Rect>& copy_rects); + virtual bool CopyFromBackingStore(const gfx::Rect& rect, + skia::PlatformCanvas* output); + virtual void ScrollBackingStore(int dx, int dy, + const gfx::Rect& clip_rect, + const gfx::Size& view_size); + private: + DISALLOW_COPY_AND_ASSIGN(TestBackingStore); +}; + +#endif // CONTENT_BROWSER_RENDERER_HOST_TEST_TEST_BACKING_STORE_H_ diff --git a/content/browser/renderer_host/test_render_view_host.cc b/content/browser/renderer_host/test_render_view_host.cc new file mode 100644 index 0000000..918ddbd --- /dev/null +++ b/content/browser/renderer_host/test_render_view_host.cc @@ -0,0 +1,346 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/browser_url_handler.h" +#include "chrome/common/dom_storage_common.h" +#include "chrome/common/render_messages.h" +#include "chrome/common/render_messages_params.h" +#include "chrome/test/testing_profile.h" +#include "content/browser/renderer_host/test_backing_store.h" +#include "content/browser/renderer_host/test_render_view_host.h" +#include "content/browser/site_instance.h" +#include "content/browser/tab_contents/navigation_controller.h" +#include "content/browser/tab_contents/test_tab_contents.h" +#include "ui/gfx/rect.h" +#include "webkit/glue/webpreferences.h" +#include "webkit/glue/password_form.h" + +using webkit_glue::PasswordForm; + +void InitNavigateParams(ViewHostMsg_FrameNavigate_Params* params, + int page_id, + const GURL& url, + PageTransition::Type transition) { + params->page_id = page_id; + params->url = url; + params->referrer = GURL(); + params->transition = transition; + params->redirects = std::vector<GURL>(); + params->should_update_history = false; + params->searchable_form_url = GURL(); + params->searchable_form_encoding = std::string(); + params->password_form = PasswordForm(); + params->security_info = std::string(); + params->gesture = NavigationGestureUser; + params->was_within_same_page = false; + params->is_post = false; +} + +TestRenderViewHost::TestRenderViewHost(SiteInstance* instance, + RenderViewHostDelegate* delegate, + int routing_id) + : RenderViewHost(instance, delegate, routing_id, + kInvalidSessionStorageNamespaceId), + render_view_created_(false), + delete_counter_(NULL) { + // For normal RenderViewHosts, this is freed when |Shutdown()| is called. + // For TestRenderViewHost, the view is explicitly deleted in the destructor + // below, because TestRenderWidgetHostView::Destroy() doesn't |delete this|. + set_view(new TestRenderWidgetHostView(this)); +} + +TestRenderViewHost::~TestRenderViewHost() { + if (delete_counter_) + ++*delete_counter_; + + // Since this isn't a traditional view, we have to delete it. + delete view(); +} + +bool TestRenderViewHost::CreateRenderView(const string16& frame_name) { + DCHECK(!render_view_created_); + render_view_created_ = true; + process()->ViewCreated(); + return true; +} + +bool TestRenderViewHost::IsRenderViewLive() const { + return render_view_created_; +} + +bool TestRenderViewHost::TestOnMessageReceived(const IPC::Message& msg) { + return OnMessageReceived(msg); +} + +void TestRenderViewHost::SendNavigate(int page_id, const GURL& url) { + SendNavigateWithTransition(page_id, url, PageTransition::LINK); +} + +void TestRenderViewHost::SendNavigateWithTransition( + int page_id, const GURL& url, PageTransition::Type transition) { + ViewHostMsg_FrameNavigate_Params params; + + params.page_id = page_id; + params.url = url; + params.referrer = GURL(); + params.transition = transition; + params.redirects = std::vector<GURL>(); + params.should_update_history = true; + params.searchable_form_url = GURL(); + params.searchable_form_encoding = std::string(); + params.password_form = PasswordForm(); + params.security_info = std::string(); + params.gesture = NavigationGestureUser; + params.contents_mime_type = std::string(); + params.is_post = false; + params.is_content_filtered = false; + params.was_within_same_page = false; + params.http_status_code = 0; + params.socket_address.set_host("2001:db8::1"); + params.socket_address.set_port(80); + + ViewHostMsg_FrameNavigate msg(1, params); + OnMsgNavigate(msg); +} + +TestRenderWidgetHostView::TestRenderWidgetHostView(RenderWidgetHost* rwh) + : rwh_(rwh), + is_showing_(false) { +} + +TestRenderWidgetHostView::~TestRenderWidgetHostView() { +} + +RenderWidgetHost* TestRenderWidgetHostView::GetRenderWidgetHost() const { + return NULL; +} + +gfx::NativeView TestRenderWidgetHostView::GetNativeView() { + return NULL; +} + +bool TestRenderWidgetHostView::HasFocus() { + return true; +} + +void TestRenderWidgetHostView::Show() { + is_showing_ = true; +} + +void TestRenderWidgetHostView::Hide() { + is_showing_ = false; +} + +bool TestRenderWidgetHostView::IsShowing() { + return is_showing_; +} + +void TestRenderWidgetHostView::RenderViewGone(base::TerminationStatus status, + int error_code) { + delete this; +} + +gfx::Rect TestRenderWidgetHostView::GetViewBounds() const { + return gfx::Rect(); +} + +BackingStore* TestRenderWidgetHostView::AllocBackingStore( + const gfx::Size& size) { + return new TestBackingStore(rwh_, size); +} + +#if defined(OS_MACOSX) + +void TestRenderWidgetHostView::ShowPopupWithItems( + gfx::Rect bounds, + int item_height, + double item_font_size, + int selected_item, + const std::vector<WebMenuItem>& items, + bool right_aligned) { +} + +gfx::Rect TestRenderWidgetHostView::GetViewCocoaBounds() const { + return gfx::Rect(); +} + +gfx::Rect TestRenderWidgetHostView::GetRootWindowRect() { + return gfx::Rect(); +} + +void TestRenderWidgetHostView::SetActive(bool active) { + // <viettrungluu@gmail.com>: Do I need to do anything here? +} + +void TestRenderWidgetHostView::PluginFocusChanged(bool focused, + int plugin_id) { +} + +void TestRenderWidgetHostView::StartPluginIme() { +} + +bool TestRenderWidgetHostView::PostProcessEventForPluginIme( + const NativeWebKeyboardEvent& event) { + return false; +} + +gfx::PluginWindowHandle +TestRenderWidgetHostView::AllocateFakePluginWindowHandle( + bool opaque, + bool root) { + return NULL; +} + +void TestRenderWidgetHostView::DestroyFakePluginWindowHandle( + gfx::PluginWindowHandle window) { +} + +void TestRenderWidgetHostView::AcceleratedSurfaceSetIOSurface( + gfx::PluginWindowHandle window, + int32 width, + int32 height, + uint64 surface_id) { +} + +void TestRenderWidgetHostView::AcceleratedSurfaceSetTransportDIB( + gfx::PluginWindowHandle window, + int32 width, + int32 height, + TransportDIB::Handle transport_dib) { +} + +void TestRenderWidgetHostView::AcceleratedSurfaceBuffersSwapped( + gfx::PluginWindowHandle window, + uint64 surface_id, + int renderer_id, + int32 route_id, + int gpu_host_id, + uint64 swap_buffers_count) { +} + +void TestRenderWidgetHostView::GpuRenderingStateDidChange() { +} +#elif defined(OS_WIN) +void TestRenderWidgetHostView::WillWmDestroy() { +} + +void TestRenderWidgetHostView::ShowCompositorHostWindow(bool show) { +} +#endif + +gfx::PluginWindowHandle TestRenderWidgetHostView::AcquireCompositingSurface() { + return gfx::kNullPluginWindow; +} + +bool TestRenderWidgetHostView::ContainsNativeView( + gfx::NativeView native_view) const { + return false; +} + +TestRenderViewHostFactory::TestRenderViewHostFactory( + RenderProcessHostFactory* rph_factory) + : render_process_host_factory_(rph_factory) { + RenderViewHostFactory::RegisterFactory(this); +} + +TestRenderViewHostFactory::~TestRenderViewHostFactory() { + RenderViewHostFactory::UnregisterFactory(); +} + +void TestRenderViewHostFactory::set_render_process_host_factory( + RenderProcessHostFactory* rph_factory) { + render_process_host_factory_ = rph_factory; +} + +RenderViewHost* TestRenderViewHostFactory::CreateRenderViewHost( + SiteInstance* instance, + RenderViewHostDelegate* delegate, + int routing_id, + SessionStorageNamespace* session_storage) { + // See declaration of render_process_host_factory_ below. + instance->set_render_process_host_factory(render_process_host_factory_); + return new TestRenderViewHost(instance, delegate, routing_id); +} + +RenderViewHostTestHarness::RenderViewHostTestHarness() + : rph_factory_(), + rvh_factory_(&rph_factory_), + contents_(NULL) { +} + +RenderViewHostTestHarness::~RenderViewHostTestHarness() { +} + +NavigationController& RenderViewHostTestHarness::controller() { + return contents_->controller(); +} + +TestTabContents* RenderViewHostTestHarness::contents() { + return contents_.get(); +} + +TestRenderViewHost* RenderViewHostTestHarness::rvh() { + return static_cast<TestRenderViewHost*>(contents_->render_view_host()); +} + +TestRenderViewHost* RenderViewHostTestHarness::pending_rvh() { + return static_cast<TestRenderViewHost*>( + contents_->render_manager()->pending_render_view_host()); +} + +TestRenderViewHost* RenderViewHostTestHarness::active_rvh() { + return pending_rvh() ? pending_rvh() : rvh(); +} + +TestingProfile* RenderViewHostTestHarness::profile() { + return profile_.get(); +} + +MockRenderProcessHost* RenderViewHostTestHarness::process() { + if (pending_rvh()) + return static_cast<MockRenderProcessHost*>(pending_rvh()->process()); + return static_cast<MockRenderProcessHost*>(rvh()->process()); +} + +void RenderViewHostTestHarness::DeleteContents() { + contents_.reset(); +} + +TestTabContents* RenderViewHostTestHarness::CreateTestTabContents() { + // See comment above profile_ decl for why we check for NULL here. + if (!profile_.get()) + profile_.reset(new TestingProfile()); + + // This will be deleted when the TabContents goes away. + SiteInstance* instance = SiteInstance::CreateSiteInstance(profile_.get()); + + return new TestTabContents(profile_.get(), instance); +} + +void RenderViewHostTestHarness::NavigateAndCommit(const GURL& url) { + contents()->NavigateAndCommit(url); +} + +void RenderViewHostTestHarness::Reload() { + NavigationEntry* entry = controller().GetLastCommittedEntry(); + DCHECK(entry); + controller().Reload(false); + rvh()->SendNavigate(entry->page_id(), entry->url()); +} + +void RenderViewHostTestHarness::SetUp() { + contents_.reset(CreateTestTabContents()); +} + +void RenderViewHostTestHarness::TearDown() { + contents_.reset(); + + // Make sure that we flush any messages related to TabContents destruction + // before we destroy the profile. + MessageLoop::current()->RunAllPending(); + + // Release the profile on the UI thread. + message_loop_.DeleteSoon(FROM_HERE, profile_.release()); + message_loop_.RunAllPending(); +} diff --git a/content/browser/renderer_host/test_render_view_host.h b/content/browser/renderer_host/test_render_view_host.h new file mode 100644 index 0000000..8110e6b --- /dev/null +++ b/content/browser/renderer_host/test_render_view_host.h @@ -0,0 +1,301 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_RENDERER_HOST_TEST_TEST_RENDER_VIEW_HOST_H_ +#define CONTENT_BROWSER_RENDERER_HOST_TEST_TEST_RENDER_VIEW_HOST_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/gtest_prod_util.h" +#include "base/message_loop.h" +#include "build/build_config.h" +#include "chrome/common/page_transition_types.h" +#include "content/browser/renderer_host/mock_render_process_host.h" +#include "content/browser/renderer_host/render_view_host.h" +#include "content/browser/renderer_host/render_view_host_factory.h" +#include "content/browser/renderer_host/render_widget_host_view.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace gfx { +class Rect; +} + +class NavigationController; +class SiteInstance; +class TestingProfile; +class TestTabContents; +struct WebMenuItem; +struct ViewHostMsg_FrameNavigate_Params; + +// Utility function to initialize ViewHostMsg_NavigateParams_Params +// with given |page_id|, |url| and |transition_type|. +void InitNavigateParams(ViewHostMsg_FrameNavigate_Params* params, + int page_id, + const GURL& url, + PageTransition::Type transition_type); + +// This file provides a testing framework for mocking out the RenderProcessHost +// layer. It allows you to test RenderViewHost, TabContents, +// NavigationController, and other layers above that without running an actual +// renderer process. +// +// To use, derive your test base class from RenderViewHostTestHarness. + +// TestRenderViewHostView ------------------------------------------------------ + +// Subclass the RenderViewHost's view so that we can call Show(), etc., +// without having side-effects. +class TestRenderWidgetHostView : public RenderWidgetHostView { + public: + explicit TestRenderWidgetHostView(RenderWidgetHost* rwh); + virtual ~TestRenderWidgetHostView(); + + virtual void InitAsPopup(RenderWidgetHostView* parent_host_view, + const gfx::Rect& pos) {} + virtual void InitAsFullscreen() {} + virtual RenderWidgetHost* GetRenderWidgetHost() const; + virtual void DidBecomeSelected() {} + virtual void WasHidden() {} + virtual void SetSize(const gfx::Size& size) {} + virtual gfx::NativeView GetNativeView(); + virtual void MovePluginWindows( + const std::vector<webkit::npapi::WebPluginGeometry>& moves) {} +#if defined(OS_WIN) + virtual void ForwardMouseEventToRenderer(UINT message, + WPARAM wparam, + LPARAM lparam) {} +#endif + virtual void Focus() {} + virtual void Blur() {} + virtual bool HasFocus(); + virtual void AdvanceFocus(bool reverse) {} + virtual void Show(); + virtual void Hide(); + virtual bool IsShowing(); + virtual gfx::Rect GetViewBounds() const; + virtual void SetIsLoading(bool is_loading) {} + virtual void UpdateCursor(const WebCursor& cursor) {} + virtual void UpdateCursorIfOverSelf() {} + virtual void ImeUpdateTextInputState(WebKit::WebTextInputType state, + const gfx::Rect& caret_rect) {} + virtual void ImeCancelComposition() {} + virtual void DidUpdateBackingStore( + const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy, + const std::vector<gfx::Rect>& rects) {} + virtual void RenderViewGone(base::TerminationStatus status, + int error_code); + virtual void WillDestroyRenderWidget(RenderWidgetHost* rwh) { } + virtual void Destroy() {} + virtual void PrepareToDestroy() {} + virtual void SetTooltipText(const std::wstring& tooltip_text) {} + virtual BackingStore* AllocBackingStore(const gfx::Size& size); +#if defined(OS_MACOSX) + virtual void SetTakesFocusOnlyOnMouseDown(bool flag) {} + virtual void ShowPopupWithItems(gfx::Rect bounds, + int item_height, + double item_font_size, + int selected_item, + const std::vector<WebMenuItem>& items, + bool right_aligned); + virtual gfx::Rect GetViewCocoaBounds() const; + virtual gfx::Rect GetRootWindowRect(); + virtual void SetActive(bool active); + virtual void SetWindowVisibility(bool visible) {} + virtual void WindowFrameChanged() {} + virtual void PluginFocusChanged(bool focused, int plugin_id); + virtual void StartPluginIme(); + virtual bool PostProcessEventForPluginIme( + const NativeWebKeyboardEvent& event); + virtual gfx::PluginWindowHandle AllocateFakePluginWindowHandle( + bool opaque, + bool root); + virtual void DestroyFakePluginWindowHandle(gfx::PluginWindowHandle window); + virtual void AcceleratedSurfaceSetIOSurface(gfx::PluginWindowHandle window, + int32 width, + int32 height, + uint64 surface_id); + virtual void AcceleratedSurfaceSetTransportDIB( + gfx::PluginWindowHandle window, + int32 width, + int32 height, + TransportDIB::Handle transport_dib); + virtual void AcceleratedSurfaceBuffersSwapped( + gfx::PluginWindowHandle window, + uint64 surface_id, + int renderer_id, + int32 route_id, + int gpu_host_id, + uint64 swap_buffers_count); + virtual void GpuRenderingStateDidChange(); +#elif defined(OS_WIN) + virtual void WillWmDestroy(); + virtual void ShowCompositorHostWindow(bool show); +#endif + virtual void SetVisuallyDeemphasized(const SkColor* color, bool animate) { } + +#if defined(TOOLKIT_USES_GTK) + virtual void CreatePluginContainer(gfx::PluginWindowHandle id) { } + virtual void DestroyPluginContainer(gfx::PluginWindowHandle id) { } + virtual void AcceleratedCompositingActivated(bool activated) { } +#endif + + virtual gfx::PluginWindowHandle AcquireCompositingSurface(); + virtual void ReleaseCompositingSurface(gfx::PluginWindowHandle surface) { } + + virtual bool ContainsNativeView(gfx::NativeView native_view) const; + + bool is_showing() const { return is_showing_; } + + private: + RenderWidgetHost* rwh_; + bool is_showing_; +}; + +// TestRenderViewHost ---------------------------------------------------------- + +// TODO(brettw) this should use a TestTabContents which should be generalized +// from the TabContents test. We will probably also need that class' version of +// CreateRenderViewForRenderManager when more complicate tests start using this. +class TestRenderViewHost : public RenderViewHost { + public: + TestRenderViewHost(SiteInstance* instance, + RenderViewHostDelegate* delegate, + int routing_id); + virtual ~TestRenderViewHost(); + + // Testing functions --------------------------------------------------------- + + // Calls the RenderViewHosts' private OnMessageReceived function with the + // given message. + bool TestOnMessageReceived(const IPC::Message& msg); + + // Calls OnMsgNavigate on the RenderViewHost with the given information, + // setting the rest of the parameters in the message to the "typical" values. + // This is a helper function for simulating the most common types of loads. + void SendNavigate(int page_id, const GURL& url); + + // Calls OnMsgNavigate on the RenderViewHost with the given information, + // including a custom PageTransition::Type. Sets the rest of the parameters + // in the message to the "typical" values. + // This is a helper function for simulating the most common types of loads. + void SendNavigateWithTransition(int page_id, const GURL& url, + PageTransition::Type transition); + + // If set, *delete_counter is incremented when this object destructs. + void set_delete_counter(int* delete_counter) { + delete_counter_ = delete_counter; + } + + // Sets whether the RenderView currently exists or not. This controls the + // return value from IsRenderViewLive, which the rest of the system uses to + // check whether the RenderView has crashed or not. + void set_render_view_created(bool created) { + render_view_created_ = created; + } + + // Returns whether the RenderViewHost is currently waiting to hear the result + // of a before unload handler from the renderer. + bool is_waiting_for_beforeunload_ack() const { + return is_waiting_for_beforeunload_ack_; + } + + // RenderViewHost overrides -------------------------------------------------- + + virtual bool CreateRenderView(const string16& frame_name); + virtual bool IsRenderViewLive() const; + + private: + FRIEND_TEST_ALL_PREFIXES(RenderViewHostTest, FilterNavigate); + + // Tracks if the caller thinks if it created the RenderView. This is so we can + // respond to IsRenderViewLive appropriately. + bool render_view_created_; + + // See set_delete_counter() above. May be NULL. + int* delete_counter_; + + DISALLOW_COPY_AND_ASSIGN(TestRenderViewHost); +}; + +// TestRenderViewHostFactory --------------------------------------------------- + +// Manages creation of the RenderViewHosts using our special subclass. This +// automatically registers itself when it goes in scope, and unregisters itself +// when it goes out of scope. Since you can't have more than one factory +// registered at a time, you can only have one of these objects at a time. +class TestRenderViewHostFactory : public RenderViewHostFactory { + public: + explicit TestRenderViewHostFactory(RenderProcessHostFactory* rph_factory); + virtual ~TestRenderViewHostFactory(); + + virtual void set_render_process_host_factory( + RenderProcessHostFactory* rph_factory); + virtual RenderViewHost* CreateRenderViewHost( + SiteInstance* instance, + RenderViewHostDelegate* delegate, + int routing_id, + SessionStorageNamespace* session_storage); + + private: + // This is a bit of a hack. With the current design of the site instances / + // browsing instances, it's difficult to pass a RenderProcessHostFactory + // around properly. + // + // Instead, we set it right before we create a new RenderViewHost, which + // happens before the RenderProcessHost is created. This way, the instance + // has the correct factory and creates our special RenderProcessHosts. + RenderProcessHostFactory* render_process_host_factory_; + + DISALLOW_COPY_AND_ASSIGN(TestRenderViewHostFactory); +}; + +// RenderViewHostTestHarness --------------------------------------------------- + +class RenderViewHostTestHarness : public testing::Test { + public: + RenderViewHostTestHarness(); + virtual ~RenderViewHostTestHarness(); + + NavigationController& controller(); + TestTabContents* contents(); + TestRenderViewHost* rvh(); + TestRenderViewHost* pending_rvh(); + TestRenderViewHost* active_rvh(); + TestingProfile* profile(); + MockRenderProcessHost* process(); + + // Frees the current tab contents for tests that want to test destruction. + void DeleteContents(); + + // Creates a new TestTabContents. Ownership passes to the caller. + TestTabContents* CreateTestTabContents(); + + // Cover for |contents()->NavigateAndCommit(url)|. See + // TestTabContents::NavigateAndCommit for details. + void NavigateAndCommit(const GURL& url); + + // Simulates a reload of the current page. + void Reload(); + + protected: + // testing::Test + virtual void SetUp(); + virtual void TearDown(); + + // This profile will be created in SetUp if it has not already been created. + // This allows tests to override the profile if they so choose in their own + // SetUp function before calling the base class's (us) SetUp(). + scoped_ptr<TestingProfile> profile_; + + MessageLoopForUI message_loop_; + + MockRenderProcessHostFactory rph_factory_; + TestRenderViewHostFactory rvh_factory_; + + scoped_ptr<TestTabContents> contents_; + + DISALLOW_COPY_AND_ASSIGN(RenderViewHostTestHarness); +}; + +#endif // CONTENT_BROWSER_RENDERER_HOST_TEST_TEST_RENDER_VIEW_HOST_H_ diff --git a/content/browser/site_instance_unittest.cc b/content/browser/site_instance_unittest.cc new file mode 100644 index 0000000..cc3651f --- /dev/null +++ b/content/browser/site_instance_unittest.cc @@ -0,0 +1,529 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/stl_util-inl.h" +#include "base/string16.h" +#include "chrome/browser/renderer_host/browser_render_process_host.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/common/url_constants.h" +#include "chrome/common/render_messages.h" +#include "chrome/test/testing_profile.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "content/browser/browsing_instance.h" +#include "content/browser/child_process_security_policy.h" +#include "content/browser/renderer_host/render_view_host.h" +#include "content/browser/site_instance.h" +#include "content/browser/renderer_host/test_render_view_host.h" +#include "content/browser/tab_contents/navigation_entry.h" +#include "content/browser/tab_contents/tab_contents.h" + +class SiteInstanceTest : public testing::Test { + private: + MessageLoopForUI message_loop_; +}; + +namespace { + +class TestBrowsingInstance : public BrowsingInstance { + public: + TestBrowsingInstance(Profile* profile, int* deleteCounter) + : BrowsingInstance(profile), + use_process_per_site(false), + deleteCounter_(deleteCounter) { + } + + // Overrides BrowsingInstance::ShouldUseProcessPerSite so that we can test + // both alternatives without using command-line switches. + bool ShouldUseProcessPerSite(const GURL& url) { + return use_process_per_site; + } + + // Set by individual tests. + bool use_process_per_site; + + private: + ~TestBrowsingInstance() { + (*deleteCounter_)++; + } + + int* deleteCounter_; +}; + + +class TestSiteInstance : public SiteInstance { + public: + static TestSiteInstance* CreateTestSiteInstance(Profile* profile, + int* siteDeleteCounter, + int* browsingDeleteCounter) { + TestBrowsingInstance* browsing_instance = + new TestBrowsingInstance(profile, browsingDeleteCounter); + return new TestSiteInstance(browsing_instance, siteDeleteCounter); + } + + private: + TestSiteInstance(BrowsingInstance* browsing_instance, int* deleteCounter) + : SiteInstance(browsing_instance), deleteCounter_(deleteCounter) {} + ~TestSiteInstance() { + (*deleteCounter_)++; + } + + int* deleteCounter_; +}; + +} // namespace + +// Test to ensure no memory leaks for SiteInstance objects. +TEST_F(SiteInstanceTest, SiteInstanceDestructor) { + // The existence of these factories will cause TabContents to create our test + // one instead of the real one. + MockRenderProcessHostFactory rph_factory; + TestRenderViewHostFactory rvh_factory(&rph_factory); + int siteDeleteCounter = 0; + int browsingDeleteCounter = 0; + const GURL url("test:foo"); + + // Ensure that instances are deleted when their NavigationEntries are gone. + TestSiteInstance* instance = + TestSiteInstance::CreateTestSiteInstance(NULL, &siteDeleteCounter, + &browsingDeleteCounter); + EXPECT_EQ(0, siteDeleteCounter); + + NavigationEntry* e1 = new NavigationEntry(instance, 0, url, GURL(), + string16(), + PageTransition::LINK); + + // Redundantly setting e1's SiteInstance shouldn't affect the ref count. + e1->set_site_instance(instance); + EXPECT_EQ(0, siteDeleteCounter); + + // Add a second reference + NavigationEntry* e2 = new NavigationEntry(instance, 0, url, + GURL(), string16(), + PageTransition::LINK); + + // Now delete both entries and be sure the SiteInstance goes away. + delete e1; + EXPECT_EQ(0, siteDeleteCounter); + EXPECT_EQ(0, browsingDeleteCounter); + delete e2; + EXPECT_EQ(1, siteDeleteCounter); + // instance is now deleted + EXPECT_EQ(1, browsingDeleteCounter); + // browsing_instance is now deleted + + // Ensure that instances are deleted when their RenderViewHosts are gone. + scoped_ptr<TestingProfile> profile(new TestingProfile()); + instance = + TestSiteInstance::CreateTestSiteInstance(profile.get(), + &siteDeleteCounter, + &browsingDeleteCounter); + { + TabContents contents(profile.get(), instance, MSG_ROUTING_NONE, NULL, NULL); + EXPECT_EQ(1, siteDeleteCounter); + EXPECT_EQ(1, browsingDeleteCounter); + } + + // Make sure that we flush any messages related to the above TabContents + // destruction. + MessageLoop::current()->RunAllPending(); + + EXPECT_EQ(2, siteDeleteCounter); + EXPECT_EQ(2, browsingDeleteCounter); + // contents is now deleted, along with instance and browsing_instance +} + +// Test that NavigationEntries with SiteInstances can be cloned, but that their +// SiteInstances can be changed afterwards. Also tests that the ref counts are +// updated properly after the change. +TEST_F(SiteInstanceTest, CloneNavigationEntry) { + int siteDeleteCounter1 = 0; + int siteDeleteCounter2 = 0; + int browsingDeleteCounter = 0; + const GURL url("test:foo"); + + SiteInstance* instance1 = + TestSiteInstance::CreateTestSiteInstance(NULL, &siteDeleteCounter1, + &browsingDeleteCounter); + SiteInstance* instance2 = + TestSiteInstance::CreateTestSiteInstance(NULL, &siteDeleteCounter2, + &browsingDeleteCounter); + + NavigationEntry* e1 = new NavigationEntry(instance1, 0, url, GURL(), + string16(), + PageTransition::LINK); + // Clone the entry + NavigationEntry* e2 = new NavigationEntry(*e1); + + // Should be able to change the SiteInstance of the cloned entry. + e2->set_site_instance(instance2); + + // The first SiteInstance should go away after deleting e1, since e2 should + // no longer be referencing it. + delete e1; + EXPECT_EQ(1, siteDeleteCounter1); + EXPECT_EQ(0, siteDeleteCounter2); + + // The second SiteInstance should go away after deleting e2. + delete e2; + EXPECT_EQ(1, siteDeleteCounter1); + EXPECT_EQ(1, siteDeleteCounter2); + + // Both BrowsingInstances are also now deleted + EXPECT_EQ(2, browsingDeleteCounter); +} + +// Test to ensure UpdateMaxPageID is working properly. +TEST_F(SiteInstanceTest, UpdateMaxPageID) { + scoped_refptr<SiteInstance> instance(SiteInstance::CreateSiteInstance(NULL)); + EXPECT_EQ(-1, instance->max_page_id()); + + // Make sure max_page_id_ is monotonically increasing. + instance->UpdateMaxPageID(3); + instance->UpdateMaxPageID(1); + EXPECT_EQ(3, instance->max_page_id()); +} + +// Test to ensure GetProcess returns and creates processes correctly. +TEST_F(SiteInstanceTest, GetProcess) { + // Ensure that GetProcess returns a process. + scoped_ptr<TestingProfile> profile(new TestingProfile()); + scoped_ptr<RenderProcessHost> host1; + scoped_refptr<SiteInstance> instance( + SiteInstance::CreateSiteInstance(profile.get())); + host1.reset(instance->GetProcess()); + EXPECT_TRUE(host1.get() != NULL); + + // Ensure that GetProcess creates a new process. + scoped_refptr<SiteInstance> instance2( + SiteInstance::CreateSiteInstance(profile.get())); + scoped_ptr<RenderProcessHost> host2(instance2->GetProcess()); + EXPECT_TRUE(host2.get() != NULL); + EXPECT_NE(host1.get(), host2.get()); +} + +// Test to ensure SetSite and site() work properly. +TEST_F(SiteInstanceTest, SetSite) { + scoped_refptr<SiteInstance> instance(SiteInstance::CreateSiteInstance(NULL)); + EXPECT_FALSE(instance->has_site()); + EXPECT_TRUE(instance->site().is_empty()); + + instance->SetSite(GURL("http://www.google.com/index.html")); + EXPECT_EQ(GURL("http://google.com"), instance->site()); + + EXPECT_TRUE(instance->has_site()); +} + +// Test to ensure GetSiteForURL properly returns sites for URLs. +TEST_F(SiteInstanceTest, GetSiteForURL) { + // Pages are irrelevant. + GURL test_url = GURL("http://www.google.com/index.html"); + EXPECT_EQ(GURL("http://google.com"), + SiteInstance::GetSiteForURL(NULL, test_url)); + + // Ports are irrlevant. + test_url = GURL("https://www.google.com:8080"); + EXPECT_EQ(GURL("https://google.com"), + SiteInstance::GetSiteForURL(NULL, test_url)); + + // Javascript URLs have no site. + test_url = GURL("javascript:foo();"); + EXPECT_EQ(GURL(), SiteInstance::GetSiteForURL(NULL, test_url)); + + test_url = GURL("http://foo/a.html"); + EXPECT_EQ(GURL("http://foo"), SiteInstance::GetSiteForURL(NULL, test_url)); + + test_url = GURL("file:///C:/Downloads/"); + EXPECT_EQ(GURL(), SiteInstance::GetSiteForURL(NULL, test_url)); + + // TODO(creis): Do we want to special case file URLs to ensure they have + // either no site or a special "file://" site? We currently return + // "file://home/" as the site, which seems broken. + // test_url = GURL("file://home/"); + // EXPECT_EQ(GURL(), SiteInstance::GetSiteForURL(NULL, test_url)); +} + +// Test of distinguishing URLs from different sites. Most of this logic is +// tested in RegistryControlledDomainTest. This test focuses on URLs with +// different schemes or ports. +TEST_F(SiteInstanceTest, IsSameWebSite) { + GURL url_foo = GURL("http://foo/a.html"); + GURL url_foo2 = GURL("http://foo/b.html"); + GURL url_foo_https = GURL("https://foo/a.html"); + GURL url_foo_port = GURL("http://foo:8080/a.html"); + GURL url_javascript = GURL("javascript:alert(1);"); + GURL url_crash = GURL(chrome::kAboutCrashURL); + GURL url_hang = GURL(chrome::kAboutHangURL); + GURL url_shorthang = GURL(chrome::kAboutShorthangURL); + + // Same scheme and port -> same site. + EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_foo, url_foo2)); + + // Different scheme -> different site. + EXPECT_FALSE(SiteInstance::IsSameWebSite(NULL, url_foo, url_foo_https)); + + // Different port -> same site. + // (Changes to document.domain make renderer ignore the port.) + EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_foo, url_foo_port)); + + // JavaScript links should be considered same site for anything. + EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_javascript, url_foo)); + EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_javascript, url_foo_https)); + EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_javascript, url_foo_port)); + + // The crash/hang URLs should also be treated as same site. (Bug 1143809.) + EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_crash, url_foo)); + EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_hang, url_foo)); + EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_shorthang, url_foo)); +} + +// Test to ensure that there is only one SiteInstance per site in a given +// BrowsingInstance, when process-per-site is not in use. +TEST_F(SiteInstanceTest, OneSiteInstancePerSite) { + int deleteCounter = 0; + TestBrowsingInstance* browsing_instance = + new TestBrowsingInstance(NULL, &deleteCounter); + browsing_instance->use_process_per_site = false; + + const GURL url_a1("http://www.google.com/1.html"); + scoped_refptr<SiteInstance> site_instance_a1( + browsing_instance->GetSiteInstanceForURL(url_a1)); + EXPECT_TRUE(site_instance_a1.get() != NULL); + + // A separate site should create a separate SiteInstance. + const GURL url_b1("http://www.yahoo.com/"); + scoped_refptr<SiteInstance> site_instance_b1( + browsing_instance->GetSiteInstanceForURL(url_b1)); + EXPECT_NE(site_instance_a1.get(), site_instance_b1.get()); + + // Getting the new SiteInstance from the BrowsingInstance and from another + // SiteInstance in the BrowsingInstance should give the same result. + EXPECT_EQ(site_instance_b1.get(), + site_instance_a1->GetRelatedSiteInstance(url_b1)); + + // A second visit to the original site should return the same SiteInstance. + const GURL url_a2("http://www.google.com/2.html"); + EXPECT_EQ(site_instance_a1.get(), + browsing_instance->GetSiteInstanceForURL(url_a2)); + EXPECT_EQ(site_instance_a1.get(), + site_instance_a1->GetRelatedSiteInstance(url_a2)); + + // A visit to the original site in a new BrowsingInstance (same or different + // profile) should return a different SiteInstance. + TestBrowsingInstance* browsing_instance2 = + new TestBrowsingInstance(NULL, &deleteCounter); + browsing_instance2->use_process_per_site = false; + // Ensure the new SiteInstance is ref counted so that it gets deleted. + scoped_refptr<SiteInstance> site_instance_a2_2( + browsing_instance2->GetSiteInstanceForURL(url_a2)); + EXPECT_NE(site_instance_a1.get(), site_instance_a2_2.get()); + + // Should be able to see that we do have SiteInstances. + EXPECT_TRUE(browsing_instance->HasSiteInstance( + GURL("http://mail.google.com"))); + EXPECT_TRUE(browsing_instance2->HasSiteInstance( + GURL("http://mail.google.com"))); + EXPECT_TRUE(browsing_instance->HasSiteInstance( + GURL("http://mail.yahoo.com"))); + + // Should be able to see that we don't have SiteInstances. + EXPECT_FALSE(browsing_instance->HasSiteInstance( + GURL("https://www.google.com"))); + EXPECT_FALSE(browsing_instance2->HasSiteInstance( + GURL("http://www.yahoo.com"))); + + // browsing_instances will be deleted when their SiteInstances are deleted +} + +// Test to ensure that there is only one SiteInstance per site for an entire +// Profile, if process-per-site is in use. +TEST_F(SiteInstanceTest, OneSiteInstancePerSiteInProfile) { + int deleteCounter = 0; + TestBrowsingInstance* browsing_instance = + new TestBrowsingInstance(NULL, &deleteCounter); + browsing_instance->use_process_per_site = true; + + const GURL url_a1("http://www.google.com/1.html"); + scoped_refptr<SiteInstance> site_instance_a1( + browsing_instance->GetSiteInstanceForURL(url_a1)); + EXPECT_TRUE(site_instance_a1.get() != NULL); + + // A separate site should create a separate SiteInstance. + const GURL url_b1("http://www.yahoo.com/"); + scoped_refptr<SiteInstance> site_instance_b1( + browsing_instance->GetSiteInstanceForURL(url_b1)); + EXPECT_NE(site_instance_a1.get(), site_instance_b1.get()); + + // Getting the new SiteInstance from the BrowsingInstance and from another + // SiteInstance in the BrowsingInstance should give the same result. + EXPECT_EQ(site_instance_b1.get(), + site_instance_a1->GetRelatedSiteInstance(url_b1)); + + // A second visit to the original site should return the same SiteInstance. + const GURL url_a2("http://www.google.com/2.html"); + EXPECT_EQ(site_instance_a1.get(), + browsing_instance->GetSiteInstanceForURL(url_a2)); + EXPECT_EQ(site_instance_a1.get(), + site_instance_a1->GetRelatedSiteInstance(url_a2)); + + // A visit to the original site in a new BrowsingInstance (same profile) + // should also return the same SiteInstance. + // This BrowsingInstance doesn't get its own SiteInstance within the test, so + // it won't be deleted by its children. Thus, we'll keep a ref count to it + // to make sure it gets deleted. + scoped_refptr<TestBrowsingInstance> browsing_instance2( + new TestBrowsingInstance(NULL, &deleteCounter)); + browsing_instance2->use_process_per_site = true; + EXPECT_EQ(site_instance_a1.get(), + browsing_instance2->GetSiteInstanceForURL(url_a2)); + + // A visit to the original site in a new BrowsingInstance (different profile) + // should return a different SiteInstance. + scoped_ptr<TestingProfile> profile(new TestingProfile()); + TestBrowsingInstance* browsing_instance3 = + new TestBrowsingInstance(profile.get(), &deleteCounter); + browsing_instance3->use_process_per_site = true; + // Ensure the new SiteInstance is ref counted so that it gets deleted. + scoped_refptr<SiteInstance> site_instance_a2_3( + browsing_instance3->GetSiteInstanceForURL(url_a2)); + EXPECT_NE(site_instance_a1.get(), site_instance_a2_3.get()); + + // Should be able to see that we do have SiteInstances. + EXPECT_TRUE(browsing_instance->HasSiteInstance( + GURL("http://mail.google.com"))); // visited before + EXPECT_TRUE(browsing_instance2->HasSiteInstance( + GURL("http://mail.google.com"))); // visited before + EXPECT_TRUE(browsing_instance->HasSiteInstance( + GURL("http://mail.yahoo.com"))); // visited before + EXPECT_TRUE(browsing_instance2->HasSiteInstance( + GURL("http://www.yahoo.com"))); // different BI, but same profile + + // Should be able to see that we don't have SiteInstances. + EXPECT_FALSE(browsing_instance->HasSiteInstance( + GURL("https://www.google.com"))); // not visited before + EXPECT_FALSE(browsing_instance3->HasSiteInstance( + GURL("http://www.yahoo.com"))); // different BI, different profile + + // browsing_instances will be deleted when their SiteInstances are deleted +} + +static SiteInstance* CreateSiteInstance(RenderProcessHostFactory* factory, + const GURL& url) { + SiteInstance* instance = SiteInstance::CreateSiteInstanceForURL(NULL, url); + instance->set_render_process_host_factory(factory); + return instance; +} + +// Test to ensure that pages that require certain privileges are grouped +// in processes with similar pages. +TEST_F(SiteInstanceTest, ProcessSharingByType) { + MockRenderProcessHostFactory rph_factory; + ChildProcessSecurityPolicy* policy = + ChildProcessSecurityPolicy::GetInstance(); + + // Make a bunch of mock renderers so that we hit the limit. + std::vector<MockRenderProcessHost*> hosts; + for (size_t i = 0; i < chrome::kMaxRendererProcessCount; ++i) + hosts.push_back(new MockRenderProcessHost(NULL)); + + // Create some extension instances and make sure they share a process. + scoped_refptr<SiteInstance> extension1_instance( + CreateSiteInstance(&rph_factory, GURL("chrome-extension://foo/bar"))); + policy->GrantExtensionBindings(extension1_instance->GetProcess()->id()); + + scoped_refptr<SiteInstance> extension2_instance( + CreateSiteInstance(&rph_factory, GURL("chrome-extension://baz/bar"))); + + scoped_ptr<RenderProcessHost> extension_host( + extension1_instance->GetProcess()); + EXPECT_EQ(extension1_instance->GetProcess(), + extension2_instance->GetProcess()); + + // Create some WebUI instances and make sure they share a process. + scoped_refptr<SiteInstance> dom1_instance( + CreateSiteInstance(&rph_factory, GURL("chrome://newtab"))); + policy->GrantWebUIBindings(dom1_instance->GetProcess()->id()); + + scoped_refptr<SiteInstance> dom2_instance( + CreateSiteInstance(&rph_factory, GURL("chrome://history"))); + + scoped_ptr<RenderProcessHost> dom_host(dom1_instance->GetProcess()); + EXPECT_EQ(dom1_instance->GetProcess(), dom2_instance->GetProcess()); + + // Make sure none of differing privilege processes are mixed. + EXPECT_NE(extension1_instance->GetProcess(), dom1_instance->GetProcess()); + + for (size_t i = 0; i < chrome::kMaxRendererProcessCount; ++i) { + EXPECT_NE(extension1_instance->GetProcess(), hosts[i]); + EXPECT_NE(dom1_instance->GetProcess(), hosts[i]); + } + + STLDeleteContainerPointers(hosts.begin(), hosts.end()); +} + +// Test to ensure that profiles that derive from each other share site +// information. +TEST_F(SiteInstanceTest, GetSiteInstanceMap) { + int deleteCounter = 0; + + scoped_ptr<Profile> p1(new TestingProfile()); + scoped_ptr<Profile> p2(new TestingProfile()); + scoped_ptr<Profile> p3(new DerivedTestingProfile(p1.get())); + + // In this test, instances 1 and 2 will be deleted automatically when the + // SiteInstance objects they return are deleted. However, instance 3 never + // returns any SitesIntance objects in this test, so will not be automatically + // deleted. It must be deleted manually. + TestBrowsingInstance* instance1(new TestBrowsingInstance(p1.get(), + &deleteCounter)); + TestBrowsingInstance* instance2(new TestBrowsingInstance(p2.get(), + &deleteCounter)); + scoped_refptr<TestBrowsingInstance> instance3( + new TestBrowsingInstance(p3.get(), &deleteCounter)); + + instance1->use_process_per_site = true; + instance2->use_process_per_site = true; + instance3->use_process_per_site = true; + + // The same profile with the same site. + scoped_refptr<SiteInstance> s1a(instance1->GetSiteInstanceForURL( + GURL("chrome-extension://baz/bar"))); + scoped_refptr<SiteInstance> s1b(instance1->GetSiteInstanceForURL( + GURL("chrome-extension://baz/bar"))); + EXPECT_EQ(s1a, s1b); + + // The same profile with different sites. + scoped_refptr<SiteInstance> s2a(instance1->GetSiteInstanceForURL( + GURL("chrome-extension://baz/bar"))); + scoped_refptr<SiteInstance> s2b(instance1->GetSiteInstanceForURL( + GURL("chrome-extension://foo/boo"))); + EXPECT_NE(s2a, s2b); + + // The different profiles with the same site. + scoped_refptr<SiteInstance> s3a(instance1->GetSiteInstanceForURL( + GURL("chrome-extension://baz/bar"))); + scoped_refptr<SiteInstance> s3b(instance2->GetSiteInstanceForURL( + GURL("chrome-extension://baz/bar"))); + EXPECT_NE(s3a, s3b); + + // The different profiles with different sites. + scoped_refptr<SiteInstance> s4a(instance1->GetSiteInstanceForURL( + GURL("chrome-extension://baz/bar"))); + scoped_refptr<SiteInstance> s4b(instance2->GetSiteInstanceForURL( + GURL("chrome-extension://foo/boo"))); + EXPECT_NE(s4a, s4b); + + // The derived profiles with the same site. + scoped_refptr<SiteInstance> s5a(instance1->GetSiteInstanceForURL( + GURL("chrome-extension://baz/bar"))); + scoped_refptr<SiteInstance> s5b(instance3->GetSiteInstanceForURL( + GURL("chrome-extension://baz/bar"))); + EXPECT_EQ(s5a, s5b); + + // The derived profiles with the different sites. + scoped_refptr<SiteInstance> s6a(instance1->GetSiteInstanceForURL( + GURL("chrome-extension://baz/bar"))); + scoped_refptr<SiteInstance> s6b(instance3->GetSiteInstanceForURL( + GURL("chrome-extension://foo/boo"))); + EXPECT_NE(s6a, s6b); +} diff --git a/content/browser/tab_contents/navigation_controller_unittest.cc b/content/browser/tab_contents/navigation_controller_unittest.cc index 2691305..0d3b0c1 100644 --- a/content/browser/tab_contents/navigation_controller_unittest.cc +++ b/content/browser/tab_contents/navigation_controller_unittest.cc @@ -10,20 +10,20 @@ #include "base/utf_string_conversions.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/history/history.h" -#include "chrome/browser/renderer_host/site_instance.h" -#include "chrome/browser/renderer_host/test/test_render_view_host.h" #include "chrome/browser/sessions/session_service.h" #include "chrome/browser/sessions/session_service_test_helper.h" #include "chrome/browser/sessions/session_types.h" #include "chrome/browser/tab_contents/navigation_controller.h" -#include "chrome/browser/tab_contents/navigation_entry.h" -#include "chrome/browser/tab_contents/tab_contents.h" -#include "chrome/browser/tab_contents/tab_contents_delegate.h" -#include "chrome/browser/tab_contents/test_tab_contents.h" #include "chrome/common/notification_registrar.h" #include "chrome/common/render_messages.h" #include "chrome/common/render_messages_params.h" #include "chrome/test/test_notification_tracker.h" +#include "content/browser/renderer_host/test_render_view_host.h" +#include "content/browser/site_instance.h" +#include "content/browser/tab_contents/navigation_entry.h" +#include "content/browser/tab_contents/tab_contents.h" +#include "content/browser/tab_contents/tab_contents_delegate.h" +#include "content/browser/tab_contents/test_tab_contents.h" #include "chrome/test/testing_profile.h" #include "net/base/net_util.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/content/browser/tab_contents/render_view_host_manager_unittest.cc b/content/browser/tab_contents/render_view_host_manager_unittest.cc index a4b82d8..fc13f1b 100644 --- a/content/browser/tab_contents/render_view_host_manager_unittest.cc +++ b/content/browser/tab_contents/render_view_host_manager_unittest.cc @@ -4,12 +4,6 @@ #include "chrome/browser/browser_thread.h" #include "chrome/browser/browser_url_handler.h" -#include "chrome/browser/renderer_host/site_instance.h" -#include "chrome/browser/renderer_host/test/test_render_view_host.h" -#include "chrome/browser/tab_contents/navigation_controller.h" -#include "chrome/browser/tab_contents/navigation_entry.h" -#include "chrome/browser/tab_contents/render_view_host_manager.h" -#include "chrome/browser/tab_contents/test_tab_contents.h" #include "chrome/common/notification_details.h" #include "chrome/common/notification_source.h" #include "chrome/common/page_transition_types.h" @@ -18,6 +12,12 @@ #include "chrome/common/url_constants.h" #include "chrome/test/test_notification_tracker.h" #include "chrome/test/testing_profile.h" +#include "content/browser/renderer_host/test_render_view_host.h" +#include "content/browser/site_instance.h" +#include "content/browser/tab_contents/navigation_controller.h" +#include "content/browser/tab_contents/navigation_entry.h" +#include "content/browser/tab_contents/render_view_host_manager.h" +#include "content/browser/tab_contents/test_tab_contents.h" #include "ipc/ipc_message.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/content/browser/tab_contents/test_tab_contents.cc b/content/browser/tab_contents/test_tab_contents.cc index 69fc0cf..983f5c8 100644 --- a/content/browser/tab_contents/test_tab_contents.cc +++ b/content/browser/tab_contents/test_tab_contents.cc @@ -7,14 +7,14 @@ #include <utility> #include "chrome/browser/browser_url_handler.h" -#include "chrome/browser/renderer_host/mock_render_process_host.h" -#include "chrome/browser/renderer_host/render_view_host.h" -#include "chrome/browser/renderer_host/site_instance.h" -#include "chrome/browser/renderer_host/test/test_render_view_host.h" -#include "chrome/browser/tab_contents/infobar_delegate.h" #include "chrome/common/notification_details.h" #include "chrome/common/notification_source.h" #include "chrome/common/page_transition_types.h" +#include "content/browser/renderer_host/mock_render_process_host.h" +#include "content/browser/renderer_host/render_view_host.h" +#include "content/browser/renderer_host/test_render_view_host.h" +#include "content/browser/site_instance.h" +#include "content/browser/tab_contents/infobar_delegate.h" TestTabContents::TestTabContents(Profile* profile, SiteInstance* instance) : TabContents(profile, instance, MSG_ROUTING_NONE, NULL, NULL), |