// 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 "content/public/test/content_browser_test.h" #include "base/command_line.h" #include "base/location.h" #include "base/process/launch.h" #include "base/single_thread_task_runner.h" #include "base/strings/utf_string_conversions.h" #include "base/test/launcher/test_launcher.h" #include "base/thread_task_runner_handle.h" #include "build/build_config.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_process_host_observer.h" #include "content/public/browser/web_contents.h" #include "content/public/common/content_switches.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/content_browser_test_utils.h" #include "content/public/test/test_launcher.h" #include "content/public/test/test_utils.h" #include "content/shell/browser/shell.h" #include "content/shell/common/shell_switches.h" #include "testing/gtest/include/gtest/gtest.h" #if defined(OS_WIN) #include "base/win/windows_version.h" #endif namespace content { // Disabled on official builds because symbolization in sandboxes processes // opens up security holes. // On Android symbolization happens in one step after all the tests ran, so this // test doesn't work there. // TODO(mac): figure out why symbolization doesn't happen in the renderer. // http://crbug.com/521456 // TODO(win): send PDB files for component build. http://crbug.com/521459 #if !defined(OFFICIAL_BUILD) && !defined(OS_ANDROID) && !defined(OS_MACOSX) && \ !(defined(COMPONENT_BUILD) && defined(OS_WIN)) IN_PROC_BROWSER_TEST_F(ContentBrowserTest, MANUAL_ShouldntRun) { // Ensures that tests with MANUAL_ prefix don't run automatically. ASSERT_TRUE(false); } class CrashObserver : public RenderProcessHostObserver { public: CrashObserver(const base::Closure& quit_closure) : quit_closure_(quit_closure) {} void RenderProcessExited(RenderProcessHost* host, base::TerminationStatus status, int exit_code) override { ASSERT_TRUE(status == base::TERMINATION_STATUS_PROCESS_CRASHED || status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION); quit_closure_.Run(); } private: base::Closure quit_closure_; }; IN_PROC_BROWSER_TEST_F(ContentBrowserTest, MANUAL_RendererCrash) { scoped_refptr message_loop_runner = new MessageLoopRunner; CrashObserver crash_observer(message_loop_runner->QuitClosure()); shell()->web_contents()->GetRenderProcessHost()->AddObserver(&crash_observer); NavigateToURL(shell(), GURL("chrome:crash")); message_loop_runner->Run(); } // Tests that browser tests print the callstack when a child process crashes. IN_PROC_BROWSER_TEST_F(ContentBrowserTest, RendererCrashCallStack) { #if defined(OS_WIN) // Matches the same condition in RouteStdioToConsole, which makes this test // fail on XP. if (base::win::GetVersion() < base::win::VERSION_VISTA) return; #endif base::ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); base::CommandLine new_test = base::CommandLine(base::CommandLine::ForCurrentProcess()->GetProgram()); new_test.AppendSwitchASCII(base::kGTestFilterFlag, "ContentBrowserTest.MANUAL_RendererCrash"); new_test.AppendSwitch(kRunManualTestsFlag); new_test.AppendSwitch(kSingleProcessTestsFlag); // Per https://www.chromium.org/developers/testing/addresssanitizer, there are // ASAN bots that run without the sandbox which this test will pass for. The // other ones pipe the output to a symbolizer script. if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoSandbox)) { new_test.AppendSwitch(switches::kNoSandbox); } else { #if defined(ADDRESS_SANITIZER) LOG(INFO) << "Couldn't run ContentBrowserTest.RendererCrashCallStack since " << "sandbox is enabled and ASAN requires piping to an external " << "script."; return; #endif } std::string output; base::GetAppOutputAndError(new_test, &output); std::string crash_string = "content::RenderFrameImpl::PrepareRenderViewForNavigation"; if (output.find(crash_string) == std::string::npos) { GTEST_FAIL() << "Couldn't find\n" << crash_string << "\n in output\n " << output; } } IN_PROC_BROWSER_TEST_F(ContentBrowserTest, MANUAL_BrowserCrash) { CHECK(false); } // Tests that browser tests print the callstack on asserts. IN_PROC_BROWSER_TEST_F(ContentBrowserTest, BrowserCrashCallStack) { base::ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); base::CommandLine new_test = base::CommandLine(base::CommandLine::ForCurrentProcess()->GetProgram()); new_test.AppendSwitchASCII(base::kGTestFilterFlag, "ContentBrowserTest.MANUAL_BrowserCrash"); new_test.AppendSwitch(kRunManualTestsFlag); new_test.AppendSwitch(kSingleProcessTestsFlag); std::string output; base::GetAppOutputAndError(new_test, &output); std::string crash_string = "content::ContentBrowserTest_MANUAL_BrowserCrash_Test::RunTestOnMainThread"; if (output.find(crash_string) == std::string::npos) { GTEST_FAIL() << "Couldn't find\n" << crash_string << "\n in output\n " << output; } } #endif class ContentBrowserTestSanityTest : public ContentBrowserTest { public: void SetUpCommandLine(base::CommandLine* command_line) override { const testing::TestInfo* const test_info = testing::UnitTest::GetInstance()->current_test_info(); if (std::string(test_info->name()) == "SingleProcess") command_line->AppendSwitch(switches::kSingleProcess); } void Test() { GURL url = GetTestUrl(".", "simple_page.html"); base::string16 expected_title(base::ASCIIToUTF16("OK")); TitleWatcher title_watcher(shell()->web_contents(), expected_title); NavigateToURL(shell(), url); base::string16 title = title_watcher.WaitAndGetTitle(); EXPECT_EQ(expected_title, title); } }; IN_PROC_BROWSER_TEST_F(ContentBrowserTestSanityTest, Basic) { Test(); } IN_PROC_BROWSER_TEST_F(ContentBrowserTestSanityTest, SingleProcess) { Test(); } namespace { void CallbackChecker(bool* non_nested_task_ran) { *non_nested_task_ran = true; } } // namespace IN_PROC_BROWSER_TEST_F(ContentBrowserTest, NonNestableTask) { bool non_nested_task_ran = false; base::ThreadTaskRunnerHandle::Get()->PostNonNestableTask( FROM_HERE, base::Bind(&CallbackChecker, &non_nested_task_ran)); content::RunAllPendingInMessageLoop(); ASSERT_TRUE(non_nested_task_ran); } } // namespace content