| // 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/renderer/render_thread_impl.h" |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| #include <utility> |
| |
| #include "base/callback.h" |
| #include "base/command_line.h" |
| #include "base/location.h" |
| #include "base/memory/discardable_memory.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/thread_task_runner_handle.h" |
| #include "components/scheduler/renderer/renderer_scheduler.h" |
| #include "content/app/mojo/mojo_init.h" |
| #include "content/common/in_process_child_thread_params.h" |
| #include "content/common/resource_messages.h" |
| #include "content/common/websocket_messages.h" |
| #include "content/public/browser/content_browser_client.h" |
| #include "content/public/common/content_client.h" |
| #include "content/public/common/content_switches.h" |
| #include "content/public/renderer/content_renderer_client.h" |
| #include "content/renderer/render_process_impl.h" |
| #include "content/test/mock_render_process.h" |
| #include "content/test/render_thread_impl_browser_test_ipc_helper.h" |
| #include "gpu/GLES2/gl2extchromium.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| // IPC messages for testing ---------------------------------------------------- |
| |
| // TODO(mdempsky): Fix properly by moving into a separate |
| // browsertest_message_generator.cc file. |
| #undef IPC_IPC_MESSAGE_MACROS_H_ |
| #undef IPC_MESSAGE_EXTRA |
| #define IPC_MESSAGE_IMPL |
| #include "ipc/ipc_message_macros.h" |
| #include "ipc/ipc_message_templates_impl.h" |
| |
| #undef IPC_MESSAGE_START |
| #define IPC_MESSAGE_START TestMsgStart |
| IPC_MESSAGE_CONTROL0(TestMsg_QuitRunLoop) |
| |
| // ----------------------------------------------------------------------------- |
| |
| // These tests leak memory, this macro disables the test when under the |
| // LeakSanitizer. |
| #ifdef LEAK_SANITIZER |
| #define WILL_LEAK(NAME) DISABLED_##NAME |
| #else |
| #define WILL_LEAK(NAME) NAME |
| #endif |
| |
| namespace content { |
| namespace { |
| |
| // FIXME: It would be great if there was a reusable mock SingleThreadTaskRunner |
| class TestTaskCounter : public base::SingleThreadTaskRunner { |
| public: |
| TestTaskCounter() : count_(0) {} |
| |
| // SingleThreadTaskRunner implementation. |
| bool PostDelayedTask(const tracked_objects::Location&, |
| const base::Closure&, |
| base::TimeDelta) override { |
| base::AutoLock auto_lock(lock_); |
| count_++; |
| return true; |
| } |
| |
| bool PostNonNestableDelayedTask(const tracked_objects::Location&, |
| const base::Closure&, |
| base::TimeDelta) override { |
| base::AutoLock auto_lock(lock_); |
| count_++; |
| return true; |
| } |
| |
| bool RunsTasksOnCurrentThread() const override { return true; } |
| |
| int NumTasksPosted() const { |
| base::AutoLock auto_lock(lock_); |
| return count_; |
| } |
| |
| private: |
| ~TestTaskCounter() override {} |
| |
| mutable base::Lock lock_; |
| int count_; |
| }; |
| |
| #if defined(COMPILER_MSVC) |
| // See explanation for other RenderViewHostImpl which is the same issue. |
| #pragma warning(push) |
| #pragma warning(disable: 4250) |
| #endif |
| |
| class RenderThreadImplForTest : public RenderThreadImpl { |
| public: |
| RenderThreadImplForTest( |
| const InProcessChildThreadParams& params, |
| scoped_ptr<scheduler::RendererScheduler> scheduler, |
| scoped_refptr<base::SingleThreadTaskRunner>& test_task_counter) |
| : RenderThreadImpl(params, std::move(scheduler), test_task_counter) { |
| } |
| |
| ~RenderThreadImplForTest() override {} |
| |
| using ChildThreadImpl::OnMessageReceived; |
| |
| private: |
| }; |
| |
| #if defined(COMPILER_MSVC) |
| #pragma warning(pop) |
| #endif |
| |
| void QuitTask(base::MessageLoop* message_loop) { |
| message_loop->QuitWhenIdle(); |
| } |
| |
| class QuitOnTestMsgFilter : public IPC::MessageFilter { |
| public: |
| explicit QuitOnTestMsgFilter(base::MessageLoop* message_loop) |
| : message_loop_(message_loop) {} |
| |
| // IPC::MessageFilter overrides: |
| bool OnMessageReceived(const IPC::Message& message) override { |
| message_loop_->task_runner()->PostTask( |
| FROM_HERE, base::Bind(&QuitTask, message_loop_)); |
| return true; |
| } |
| |
| bool GetSupportedMessageClasses( |
| std::vector<uint32_t>* supported_message_classes) const override { |
| supported_message_classes->push_back(TestMsgStart); |
| return true; |
| } |
| |
| private: |
| ~QuitOnTestMsgFilter() override {} |
| |
| base::MessageLoop* message_loop_; |
| }; |
| |
| class RenderThreadImplBrowserTest : public testing::Test { |
| public: |
| void SetUp() override { |
| content_client_.reset(new ContentClient()); |
| content_browser_client_.reset(new ContentBrowserClient()); |
| content_renderer_client_.reset(new ContentRendererClient()); |
| SetContentClient(content_client_.get()); |
| SetBrowserClientForTesting(content_browser_client_.get()); |
| SetRendererClientForTesting(content_renderer_client_.get()); |
| |
| test_helper_.reset(new RenderThreadImplBrowserIPCTestHelper()); |
| |
| mock_process_.reset(new MockRenderProcess); |
| test_task_counter_ = make_scoped_refptr(new TestTaskCounter()); |
| |
| // RenderThreadImpl expects the browser to pass these flags. |
| base::CommandLine* cmd = base::CommandLine::ForCurrentProcess(); |
| base::CommandLine::StringVector old_argv = cmd->argv(); |
| |
| cmd->AppendSwitchASCII(switches::kNumRasterThreads, "1"); |
| std::string image_targets; |
| for (size_t format = 0; |
| format < static_cast<size_t>(gfx::BufferFormat::LAST) + 1; format++) { |
| if (!image_targets.empty()) |
| image_targets += ","; |
| image_targets += base::UintToString(GL_TEXTURE_2D); |
| } |
| cmd->AppendSwitchASCII(switches::kContentImageTextureTarget, image_targets); |
| |
| scoped_ptr<scheduler::RendererScheduler> renderer_scheduler = |
| scheduler::RendererScheduler::Create(); |
| InitializeMojo(); |
| scoped_refptr<base::SingleThreadTaskRunner> test_task_counter( |
| test_task_counter_.get()); |
| thread_ = new RenderThreadImplForTest( |
| InProcessChildThreadParams(test_helper_->GetChannelId(), |
| test_helper_->GetIOTaskRunner(), |
| test_helper_->GetMessagePipeHandle()), |
| std::move(renderer_scheduler), test_task_counter); |
| cmd->InitFromArgv(old_argv); |
| |
| test_msg_filter_ = make_scoped_refptr( |
| new QuitOnTestMsgFilter(test_helper_->GetMessageLoop())); |
| thread_->AddFilter(test_msg_filter_.get()); |
| } |
| |
| scoped_refptr<TestTaskCounter> test_task_counter_; |
| scoped_ptr<ContentClient> content_client_; |
| scoped_ptr<ContentBrowserClient> content_browser_client_; |
| scoped_ptr<ContentRendererClient> content_renderer_client_; |
| scoped_ptr<RenderThreadImplBrowserIPCTestHelper> test_helper_; |
| scoped_ptr<MockRenderProcess> mock_process_; |
| scoped_refptr<QuitOnTestMsgFilter> test_msg_filter_; |
| RenderThreadImplForTest* thread_; // Owned by mock_process_. |
| std::string channel_id_; |
| }; |
| |
| void CheckRenderThreadInputHandlerManager(RenderThreadImpl* thread) { |
| ASSERT_TRUE(thread->input_handler_manager()); |
| } |
| |
| // Check that InputHandlerManager outlives compositor thread because it uses |
| // raw pointers to post tasks. |
| // Disabled under LeakSanitizer due to memory leaks. http://crbug.com/348994 |
| TEST_F(RenderThreadImplBrowserTest, |
| WILL_LEAK(InputHandlerManagerDestroyedAfterCompositorThread)) { |
| ASSERT_TRUE(thread_->input_handler_manager()); |
| |
| thread_->compositor_task_runner()->PostTask( |
| FROM_HERE, base::Bind(&CheckRenderThreadInputHandlerManager, thread_)); |
| } |
| |
| // Disabled under LeakSanitizer due to memory leaks. |
| TEST_F(RenderThreadImplBrowserTest, |
| WILL_LEAK(ResourceDispatchIPCTasksGoThroughScheduler)) { |
| test_helper_->Sender()->Send(new ResourceHostMsg_FollowRedirect(0)); |
| test_helper_->Sender()->Send(new TestMsg_QuitRunLoop()); |
| |
| test_helper_->GetMessageLoop()->Run(); |
| EXPECT_EQ(1, test_task_counter_->NumTasksPosted()); |
| } |
| |
| // Disabled under LeakSanitizer due to memory leaks. |
| TEST_F(RenderThreadImplBrowserTest, |
| WILL_LEAK(NonResourceDispatchIPCTasksDontGoThroughScheduler)) { |
| // NOTE other than not being a resource message, the actual message is |
| // unimportant. |
| test_helper_->Sender()->Send(new WebSocketMsg_NotifyFailure(1, "")); |
| test_helper_->Sender()->Send(new TestMsg_QuitRunLoop()); |
| |
| test_helper_->GetMessageLoop()->Run(); |
| |
| EXPECT_EQ(0, test_task_counter_->NumTasksPosted()); |
| } |
| |
| } // namespace |
| } // namespace content |