Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(396)

Unified Diff: content/browser/renderer_host/render_process_host_impl_unittest.cc

Issue 16267002: Re-fix http://crbug.com/87176, and add a test. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Second round of creis comments Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/browser/renderer_host/render_process_host_impl.cc ('k') | content/content_tests.gypi » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/browser/renderer_host/render_process_host_impl_unittest.cc
diff --git a/content/browser/renderer_host/render_process_host_impl_unittest.cc b/content/browser/renderer_host/render_process_host_impl_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..f6e93e85144fe437947b0eba363252eabdb6e500
--- /dev/null
+++ b/content/browser/renderer_host/render_process_host_impl_unittest.cc
@@ -0,0 +1,256 @@
+// Copyright 2013 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/render_process_host_impl.h"
+
+#include "base/command_line.h"
+#include "base/process_util.h"
+#include "base/run_loop.h"
+#include "content/browser/child_process_launcher.h"
+#include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/site_instance_impl.h"
+#include "content/browser/storage_partition_impl.h"
+#include "content/browser/webui/web_ui_controller_factory_registry.h"
+#include "content/common/child_process_messages.h"
+#include "content/common/view_messages.h"
+#include "content/public/browser/render_process_host_factory.h"
+#include "content/public/common/sandboxed_process_launcher_delegate.h"
+#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_browser_thread.h"
+#include "content/test/test_content_browser_client.h"
+#include "content/test/test_render_view_host_factory.h"
+#include "content/test/test_web_contents.h"
+#include "ipc/ipc_switches.h"
+#include "ipc/ipc_test_sink.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+namespace {
+
+class FakeChildProcessLauncher;
+
+struct LaunchedChildProcess {
+ // Becomes NULL after the FakeChildProcessLauncher is destroyed.
+ FakeChildProcessLauncher* launcher_;
+ // Collects messages sent to the child process.
+ IPC::TestSink messages_;
+};
+
+class FakeChildProcessLauncher : public ChildProcessLauncher {
+ public:
+ FakeChildProcessLauncher(LaunchedChildProcess* info,
+ const IPC::ChannelHandle& channel,
+ Client* client)
+ : info_(info),
+ client_(client),
+ starting_(true),
+ termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION),
+ channel_(new IPC::ChannelProxy(
+ channel,
+ IPC::Channel::MODE_CLIENT,
+ &info->messages_,
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO))),
+ weak_this_factory_(this) {
+ info_->launcher_ = this;
+
+ // Automatically start the child process so the RenderProcessHostImpl sends
+ // messages to it. To mimic real child processes, don't start instantly.
+ base::MessageLoopProxy::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&FakeChildProcessLauncher::Start,
+ weak_this_factory_.GetWeakPtr()));
+ }
+
+ virtual ~FakeChildProcessLauncher() { info_->launcher_ = NULL; }
+
+ void Send(IPC::Message* msg) {
+ EXPECT_TRUE(channel_->Send(msg));
+ }
+
+ Client* client() const { return client_; }
+
+ // Implementation of ChildProcessLauncher.
+ virtual bool IsStarting() OVERRIDE { return starting_; }
+ virtual base::ProcessHandle GetHandle() OVERRIDE {
+ return base::Process::Current().handle();
+ }
+ virtual base::TerminationStatus GetChildTerminationStatus(bool known_dead,
+ int* exit_code)
+ OVERRIDE {
+ return termination_status_;
+ }
+ virtual void SetProcessBackgrounded(bool background) OVERRIDE {}
+ virtual void SetTerminateChildOnShutdown(bool terminate_on_shutdown)
+ OVERRIDE {}
+
+ private:
+ void Start() {
+ starting_ = false;
+ client_->OnProcessLaunched();
+ }
+
+ LaunchedChildProcess* info_;
+ Client* client_;
+ bool starting_;
+ base::TerminationStatus termination_status_;
+ scoped_ptr<IPC::ChannelProxy> channel_;
+ base::WeakPtrFactory<FakeChildProcessLauncher> weak_this_factory_;
+};
+
+scoped_ptr<ChildProcessLauncher> NewFakeChildProcessLauncher(
+ ScopedVector<LaunchedChildProcess>* child_processes,
+#if defined(OS_WIN)
+ SandboxedProcessLauncherDelegate* delegate,
+#elif defined(OS_POSIX)
+ bool use_zygote,
+ const base::EnvironmentVector& environ,
+ int ipcfd,
+#endif
+ CommandLine* cmd_line,
+ int child_process_id,
+ ChildProcessLauncher::Client* client) {
+#if defined(OS_WIN)
+ delete delegate;
+#endif
+ scoped_ptr<CommandLine> cmd_line_deleter(cmd_line);
+ child_processes->push_back(new LaunchedChildProcess());
+ std::string channel_id =
+ cmd_line->GetSwitchValueASCII(switches::kProcessChannelID);
+ return scoped_ptr<ChildProcessLauncher>(new FakeChildProcessLauncher(
+ child_processes->back(),
+ IPC::ChannelHandle(channel_id
+#if defined(OS_POSIX)
+ ,
+ base::FileDescriptor(ipcfd, false)
+#endif
+ ),
+ client));
+}
+
+class RPHIBrowserContext : public TestBrowserContext {
+ private:
+ virtual net::URLRequestContextGetter* GetRequestContextForRenderProcess(
+ int renderer_child_id) OVERRIDE {
+ return GetRequestContext();
+ }
+};
+
+class RPHIBrowserClient : public TestContentBrowserClient {
+ public:
+ RPHIBrowserClient()
+ : request_context_getter_(new net::TestURLRequestContextGetter(
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO))) {}
+
+ virtual net::URLRequestContextGetter* CreateRequestContext(
+ BrowserContext* browser_context,
+ ProtocolHandlerMap* protocol_handlers) OVERRIDE {
+ return request_context_getter_.get();
+ }
+
+ private:
+ scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
+};
+
+class FakeChildProcessRPHFactory : public RenderProcessHostFactory {
+ public:
+ FakeChildProcessRPHFactory(
+ ScopedVector<LaunchedChildProcess>* child_processes,
+ StoragePartitionImpl* storage_partition)
+ : child_processes_(child_processes),
+ storage_partition_(storage_partition) {
+ SiteInstanceImpl::set_render_process_host_factory(this);
+ }
+ virtual ~FakeChildProcessRPHFactory() {
+ SiteInstanceImpl::set_render_process_host_factory(NULL);
+ }
+
+ virtual RenderProcessHost* CreateRenderProcessHost(
+ BrowserContext* browser_context) const OVERRIDE {
+ RenderProcessHostImpl* host = new RenderProcessHostImpl(
+ browser_context, storage_partition_, false, false);
+ host->SetChildProcessLauncherFactory(
+ base::Bind(&NewFakeChildProcessLauncher, child_processes_));
+ return host;
+ }
+
+ private:
+ ScopedVector<LaunchedChildProcess>* child_processes_;
+ StoragePartitionImpl* storage_partition_;
+};
+
+class RenderProcessHostImplTest : public testing::Test {
+ public:
+ RenderProcessHostImplTest()
+ : ui_thread_(BrowserThread::UI, &message_loop_),
+ webkit_thread_(BrowserThread::WEBKIT_DEPRECATED, &message_loop_),
+ file_user_blocking_thread_(BrowserThread::FILE_USER_BLOCKING,
+ &message_loop_),
+ io_thread_(BrowserThread::IO, &message_loop_),
+ old_browser_client_(SetBrowserClientForTesting(&test_browser_client_)) {
+ }
+
+ virtual ~RenderProcessHostImplTest() {
+ base::RunLoop().RunUntilIdle();
+ SetBrowserClientForTesting(old_browser_client_);
+ }
+
+ protected:
+ ScopedVector<LaunchedChildProcess> child_processes_;
+ base::MessageLoopForIO message_loop_;
Jeffrey Yasskin 2013/06/05 22:53:20 I'll be able to replace this list of threads with
+ TestBrowserThread ui_thread_;
+ TestBrowserThread webkit_thread_;
+ TestBrowserThread file_user_blocking_thread_;
+ TestBrowserThread io_thread_;
+
+ RPHIBrowserContext browser_context_;
+ RPHIBrowserClient test_browser_client_;
+ ContentBrowserClient* old_browser_client_;
+ ResourceDispatcherHostImpl resource_dispatcher_host_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderProcessHostImplTest);
+};
+
+// http://crbug.com/87176
+TEST_F(RenderProcessHostImplTest,
+ RejectShutdownFromChildProcessWithOneActiveView) {
+ const GURL kUrl("http://example.com");
+
+ scoped_refptr<SiteInstance> site(
+ SiteInstance::CreateForURL(&browser_context_, kUrl));
+ FakeChildProcessRPHFactory rph_factory(
+ &child_processes_,
+ static_cast<StoragePartitionImpl*>(
+ TestBrowserContext::GetStoragePartition(&browser_context_,
+ site.get())));
+
+ WebContents::CreateParams params(&browser_context_, site.get());
+ scoped_ptr<WebContentsImpl> tab(
+ WebContentsImpl::CreateWithOpener(params, NULL));
+ tab->GetController().LoadURL(kUrl, Referrer(), PAGE_TRANSITION_TYPED, "");
+ base::RunLoop().RunUntilIdle();
+ ASSERT_EQ(1U, child_processes_.size());
+
+ child_processes_[0]->messages_.ClearMessages();
+
+ RenderProcessHostImpl* tab_process =
+ static_cast<RenderProcessHostImpl*>(tab->GetSiteInstance()->GetProcess());
+ EXPECT_EQ(1, tab_process->GetActiveViewCount());
+ EXPECT_EQ(child_processes_[0]->launcher_->client(), tab_process);
+
+ // Sometimes the renderer process's ShutdownRequest (corresponding to the
+ // ViewMsg_WasSwappedOut from a previous navigation) doesn't arrive until
+ // after the browser process decides to re-use the renderer for a new purpose.
+ // This test makes sure the browser doesn't let the renderer die in that case.
+ child_processes_[0]->launcher_->
+ Send(new ChildProcessHostMsg_ShutdownRequest());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(child_processes_[0]->messages_.GetFirstMessageMatching(
+ ChildProcessMsg_Shutdown::ID))
+ << "Host sent a message confirming that the renderer process should shut "
+ << "down even though it was still being used.";
+}
+
+} // namespace
+} // namespace content
« no previous file with comments | « content/browser/renderer_host/render_process_host_impl.cc ('k') | content/content_tests.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698