Porting the browser tests to Unix.

The browser tests are an alternative to UI tests.
They provide a way to exercise the browser from within the test (without having the test and the browser running in different processes).
In order to ensure atexit hanlders are run after each tests and static initializers start fresh for each test, each test is run in a new process (on Linux and Mac). On Windows, a DLL containing the test is loaded/unloaded for each tests.

BUG=None
TEST=Run the browser tests. 

Review URL: http://codereview.chromium.org/115896

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@17781 0039d316-1c4b-4281-b951-d872f2087c98
Esse commit está contido em:
jcampan@chromium.org
2009-06-05 22:18:09 +00:00
commit 2b61de6382
17 arquivos alterados com 610 adições e 197 exclusões
-1
Ver Arquivo
@@ -169,7 +169,6 @@ bool CommandLine::IsSwitch(const StringType& parameter_string,
// static
void CommandLine::Init(int argc, const char* const* argv) {
DCHECK(current_process_commandline_ == NULL);
#if defined(OS_WIN)
current_process_commandline_ = new CommandLine;
current_process_commandline_->ParseFromString(::GetCommandLineW());
+28 -5
Ver Arquivo
@@ -16,19 +16,36 @@
#import <Carbon/Carbon.h>
#endif // OS_*
#include "base/string16.h"
// Macro usefull for writing cross-platform function pointers.
#if defined(OS_WIN) && !defined(CDECL)
#define CDECL __cdecl
#else
#define CDECL
#endif
class FilePath;
namespace base {
#if defined(OS_WIN)
typedef HMODULE NativeLibrary;
typedef char* NativeLibraryFunctionNameType;
#elif defined(OS_MACOSX)
typedef CFBundleRef NativeLibrary;
typedef CFStringRef NativeLibraryFunctionNameType;
enum NativeLibraryType {
BUNDLE,
DYNAMIC_LIB
};
struct NativeLibraryStruct {
NativeLibraryType type;
union {
CFBundleRef bundle;
void* dylib;
};
};
typedef NativeLibraryStruct* NativeLibrary;
#elif defined(OS_LINUX)
typedef void* NativeLibrary;
typedef const char* NativeLibraryFunctionNameType;
#endif // OS_*
// Loads a native library from disk. Release it with UnloadNativeLibrary when
@@ -40,7 +57,13 @@ void UnloadNativeLibrary(NativeLibrary library);
// Gets a function pointer from a native library.
void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
NativeLibraryFunctionNameType name);
const char* name);
// Returns the full platform specific name for a native library.
// For example:
// "mylib" returns "mylib.dll" on Windows, "libmylib.so" on Linux,
// "mylib.dylib" on Mac.
string16 GetNativeLibraryName(const string16& name);
} // namespace base
+7 -1
Ver Arquivo
@@ -8,6 +8,7 @@
#include "base/file_path.h"
#include "base/logging.h"
#include "base/string_util.h"
namespace base {
@@ -29,8 +30,13 @@ void UnloadNativeLibrary(NativeLibrary library) {
// static
void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
NativeLibraryFunctionNameType name) {
const char* name) {
return dlsym(library, name);
}
// static
string16 GetNativeLibraryName(const string16& name) {
return ASCIIToUTF16("lib") + name + ASCIIToUTF16(".so");
}
} // namespace base
+37 -4
Ver Arquivo
@@ -4,15 +4,28 @@
#include "base/native_library.h"
#include <dlfcn.h>
#import <Carbon/Carbon.h>
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/scoped_cftyperef.h"
#include "base/string_util.h"
namespace base {
// static
NativeLibrary LoadNativeLibrary(const FilePath& library_path) {
if (library_path.Extension() == "dylib" ||
!file_util::DirectoryExists(library_path)) {
void* dylib = dlopen(library_path.value().c_str(), RTLD_LAZY);
if (!dylib)
return NULL;
NativeLibrary native_lib = new NativeLibraryStruct();
native_lib->type = DYNAMIC_LIB;
native_lib->dylib = dylib;
return native_lib;
}
scoped_cftyperef<CFURLRef> url(CFURLCreateFromFileSystemRepresentation(
kCFAllocatorDefault,
(const UInt8*)library_path.value().c_str(),
@@ -20,19 +33,39 @@ NativeLibrary LoadNativeLibrary(const FilePath& library_path) {
true));
if (!url)
return NULL;
CFBundleRef bundle = CFBundleCreate(kCFAllocatorDefault, url.get());
if (!bundle)
return NULL;
return CFBundleCreate(kCFAllocatorDefault, url.get());
NativeLibrary native_lib = new NativeLibraryStruct();
native_lib->type = BUNDLE;
native_lib->bundle = bundle;
return native_lib;
}
// static
void UnloadNativeLibrary(NativeLibrary library) {
CFRelease(library);
if (library->type == BUNDLE)
CFRelease(library->bundle);
else
dlclose(library->dylib);
delete library;
}
// static
void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
NativeLibraryFunctionNameType name) {
return CFBundleGetFunctionPointerForName(library, name);
const char* name) {
if (library->type == BUNDLE)
return CFBundleGetFunctionPointerForName(library->bundle,
CFStringCreateWithCString(kCFAllocatorDefault, name,
kCFStringEncodingUTF8));
return dlsym(library->dylib, name);
}
// static
string16 GetNativeLibraryName(const string16& name) {
return name + ASCIIToUTF16(".dylib");
}
} // namespace base
+7 -1
Ver Arquivo
@@ -8,6 +8,7 @@
#include "base/file_path.h"
#include "base/path_service.h"
#include "base/string_util.h"
namespace base {
@@ -39,8 +40,13 @@ void UnloadNativeLibrary(NativeLibrary library) {
// static
void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
NativeLibraryFunctionNameType name) {
const char* name) {
return GetProcAddress(library, name);
}
// static
string16 GetNativeLibraryName(const string16& name) {
return name + ASCIIToUTF16(".dll");
}
} // namespace base
+18 -4
Ver Arquivo
@@ -73,6 +73,7 @@ class SSLUITest : public InProcessBrowserTest {
DISALLOW_COPY_AND_ASSIGN(SSLUITest);
};
#if defined(OS_WIN)
// Visits a regular page over http.
IN_PROC_BROWSER_TEST_F(SSLUITest, TestHTTP) {
scoped_refptr<HTTPTestServer> server = PlainServer();
@@ -280,7 +281,7 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, TestUnsafeContents) {
// opened (the iframe content opens one).
// Note: because of bug 1115868, no constrained window is opened right now.
// Once the bug is fixed, this will do the real check.
EXPECT_EQ(0, tab->constrained_window_count());
EXPECT_EQ(0, static_cast<int>(tab->constrained_window_count()));
int img_width;
EXPECT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractInt(
@@ -465,13 +466,13 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, TestCloseTabWithUnsafePopup) {
// It is probably overkill to add a notification for a popup-opening, let's
// just poll.
for (int i = 0; i < 10; i++) {
if (tab1->constrained_window_count() > 0)
if (static_cast<int>(tab1->constrained_window_count()) > 0)
break;
MessageLoop::current()->PostDelayedTask(FROM_HERE,
new MessageLoop::QuitTask(), 1000);
ui_test_utils::RunMessageLoop();
}
ASSERT_EQ(1, tab1->constrained_window_count());
ASSERT_EQ(1, static_cast<int>(tab1->constrained_window_count()));
// Let's add another tab to make sure the browser does not exit when we close
// the first tab.
@@ -699,7 +700,6 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, TestBadFrameNavigation) {
InterstitialPage* interstitial_page = tab->interstitial_page();
ASSERT_TRUE(interstitial_page);
interstitial_page->Proceed();
// Wait for the navigation to be done.
ui_test_utils::WaitForNavigation(&(tab->controller()));
// Navigate to a good frame.
@@ -761,6 +761,20 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, TestUnauthenticatedFrameNavigation) {
content_frame_xpath, is_frame_evil_js, &is_content_evil));
EXPECT_FALSE(is_content_evil);
}
#else
// TODO(port): enable the real tests.
IN_PROC_BROWSER_TEST_F(SSLUITest, PhonyTest1) {
EXPECT_TRUE(true);
}
IN_PROC_BROWSER_TEST_F(SSLUITest, PhonyTest2) {
EXPECT_TRUE(false);
}
IN_PROC_BROWSER_TEST_F(SSLUITest, PhonyTest3) {
EXPECT_TRUE(true);
}
#endif
// TODO(jcampan): more tests to do below.
+1 -1
Ver Arquivo
@@ -18,4 +18,4 @@ IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, OpenClose) {
IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, ShutdownWhileOpen) {
TaskManager::Open();
}
}
+185 -77
Ver Arquivo
@@ -3602,6 +3602,69 @@
},
],
}], # OS!="mac"
['OS!="win"',
{ 'targets': [
{
# Executable that runs each browser test in a new process.
'target_name': 'browser_tests',
'type': 'executable',
'dependencies': [
'app',
'browser',
'chrome_resources',
'debugger',
'test_support_common',
'../skia/skia.gyp:skia',
'../testing/gtest.gyp:gtest',
],
'include_dirs': [
'..',
],
'sources': [
'test/browser/run_all_unittests.cc',
'test/in_process_browser_test.cc',
'test/in_process_browser_test.h',
'test/browser/browser_test_launcher_out_of_proc.cc',
'test/browser/browser_test_runner.cc',
'test/browser/browser_test_runner.h',
'test/unit/chrome_test_suite.h',
'test/ui_test_utils.cc',
# Put your tests below.
# IMPORTANT NOTE: you must also put them in browser_tests_dll
'browser/ssl/ssl_browser_tests.cc',
'browser/child_process_security_policy_browser_test.cc',
# TODO(jcampan): make the task manager test compile on Mac.
# 'browser/task_manager_browsertest.cc',
'browser/renderer_host/web_cache_manager_browser_test.cc',
# Below is the list of Windows specific tests.
# 'browser/views/find_bar_win_browsertest.cc',
],
'conditions': [
['OS=="linux"', {
'dependencies': [
'../build/linux/system.gyp:gtk',
],
}],
['OS=="mac"', {
# The test fetches resources which means Mac need the app bundle to
# exist on disk so it can pull from it.
'dependencies': [
'app',
],
'sources': [
'app/breakpad_mac_stubs.mm',
'app/keystone_glue.h',
'app/keystone_glue.m',
],
# TODO(mark): We really want this for all non-static library targets,
# but when we tried to pull it up to the common.gypi level, it broke
# other things like the ui, startup, and page_cycler tests. *shrug*
'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-ObjC']},
}],
],
},
]
}],
['OS=="win"',
{ 'targets': [
{
@@ -3864,83 +3927,128 @@
'test/automation/window_proxy.h',
],
},
# TODO(sgk,bradnelson): re-enable once problems with
# LNK1104 errors for browser_tests.{ilk,pdb} have been fixed.
#{
# 'target_name': 'browser_tests',
# 'type': 'executable',
# 'msvs_guid': '9B87804D-2502-480B-95AE-5A572CE91809',
# 'msvs_existing_vcproj': 'test/browser/browser_tests_launcher.vcproj',
# 'dependencies': [
# 'installer/installer.gyp:installer_util',
# ],
# 'include_dirs': [
# '..',
# ],
# 'sources': [
# 'test/browser/browser_tests_launcher.cc',
# ],
#},
#{
# 'target_name': 'browser_tests_dll',
# 'type': 'shared_library',
# 'msvs_guid': 'D7589D0D-304E-4589-85A4-153B7D84B07F',
# 'msvs_existing_vcproj': 'test/browser/browser_tests_dll.vcproj',
# 'product_name': 'browser_tests',
# 'dependencies': [
# 'browser',
# 'chrome_resources',
# 'debugger',
# 'renderer',
# 'installer/installer.gyp:installer_util_strings',
# '../base/base.gyp:base',
# '../base/base.gyp:base_gfx',
# '../net/net.gyp:net',
# '../net/net.gyp:net_resources',
# '../skia/skia.gyp:skia',
# '../testing/gtest.gyp:gtest',
# '../webkit/webkit.gyp:glue',
# '../webkit/webkit.gyp:webkit_resources',
# ],
# 'include_dirs': [
# '..',
# 'third_party/wtl/include',
# ],
# 'sources': [
# '../webkit/glue/resources/aliasb.cur',
# '../webkit/glue/resources/cell.cur',
# '../webkit/glue/resources/col_resize.cur',
# '../webkit/glue/resources/copy.cur',
# '../webkit/glue/resources/row_resize.cur',
# '../webkit/glue/resources/vertical_text.cur',
# '../webkit/glue/resources/zoom_in.cur',
# '../webkit/glue/resources/zoom_out.cur',
# 'app/chrome_dll.rc',
# 'app/chrome_dll_resource.h',
# 'app/chrome_dll_version.rc.version',
# 'browser/child_process_security_policy_browser_test.cc',
# 'browser/renderer_host/web_cache_manager_browser_test.cc',
# 'browser/ssl/ssl_browser_tests.cc',
# 'browser/task_manager_browsertest.cc',
# 'browser/views/find_bar_win_browsertest.cc',
# 'test/browser/run_all_unittests.cc',
# 'test/data/resource.h',
# 'test/data/resource.rc',
# 'test/in_process_browser_test.cc',
# 'test/in_process_browser_test.h',
# 'test/ui_test_utils.cc',
# 'test/ui_test_utils.h',
# 'test/unit/chrome_test_suite.h',
# 'tools/build/win/precompiled_wtl.cc',
# 'tools/build/win/precompiled_wtl.h',
# ],
# 'configurations': {
# 'Debug': {
# 'msvs_precompiled_header': 'tools/build/win/precompiled_wtl.h',
# 'msvs_precompiled_source': 'tools/build/win/precompiled_wtl.cc',
# },
# },
#},
{
# Shared library used by the in-proc browser tests.
'target_name': 'browser_tests_dll',
'type': 'shared_library',
'product_name': 'browser_tests',
'msvs_guid': 'D7589D0D-304E-4589-85A4-153B7D84B07F',
'dependencies': [
'app',
'browser',
'chrome_resources',
'installer/installer.gyp:installer_util_strings',
'debugger',
'renderer',
'../skia/skia.gyp:skia',
'../testing/gtest.gyp:gtest',
],
'include_dirs': [
'..',
'third_party/wtl/include',
],
'configurations': {
'Debug': {
'msvs_precompiled_header': 'tools/build/win/precompiled_wtl.h',
'msvs_precompiled_source': 'tools/build/win/precompiled_wtl.cc',
'msvs_settings': {
'VCLinkerTool': {
'LinkIncremental': '1', # /INCREMENTAL:NO
},
},
},
},
'rules': [
{
'rule_name': 'win_version',
'extension': 'version',
'variables': {
'lastchange_path':
'<(SHARED_INTERMEDIATE_DIR)/build/LASTCHANGE',
'version_py': 'tools/build/version.py',
'version_path': 'VERSION',
'template_input_path': 'app/chrome_dll_version.rc.version',
'template_output_path': '<(grit_out_dir)/chrome_dll_version.rc',
},
'conditions': [
[ 'branding == "Chrome"', {
'variables': {
'branding_path': 'app/theme/google_chrome/BRANDING',
},
}, { # else branding!="Chrome"
'variables': {
'branding_path': 'app/theme/chromium/BRANDING',
},
}],
],
'inputs': [
'<(template_input_path)',
'<(version_path)',
'<(branding_path)',
'<(lastchange_path)',
],
'outputs': [
# Use a non-existant output so this action always runs and
# generates version information, e.g. to capture revision
# changes, which aren't captured by file dependencies.
'<(grit_out_dir)/chrome_dll_version.always',
# And this is the real output, so that the build system knows
# what action generates it.
'<(template_output_path)',
],
'action': [
'python',
'<(version_py)',
'-f', '<(version_path)',
'-f', '<(branding_path)',
'-f', '<(lastchange_path)',
'<(template_input_path)',
'<(template_output_path)',
],
'process_outputs_as_sources': 1,
'message': 'Generating version information in <(template_output_path)'
},
],
'sources': [
'test/browser/run_all_unittests.cc',
'test/in_process_browser_test.cc',
'test/in_process_browser_test.h',
'test/unit/chrome_test_suite.h',
'test/ui_test_utils.cc',
'app/chrome_dll.rc',
'app/chrome_dll_resource.h',
'app/chrome_dll_version.rc.version',
'tools/build/win/precompiled_wtl.h',
'tools/build/win/precompiled_wtl.cc',
'<(SHARED_INTERMEDIATE_DIR)/chrome/common_resources.rc',
# Put your tests below.
# IMPORTANT NOTE: you must also put them in browser_tests in
# the Mac/Linux section.
'browser/views/find_bar_win_browsertest.cc',
'browser/ssl/ssl_browser_tests.cc',
'browser/child_process_security_policy_browser_test.cc',
'browser/task_manager_browsertest.cc',
'browser/renderer_host/web_cache_manager_browser_test.cc'
],
},
{
# Executable that runs the browser tests in-process.
'target_name': 'browser_tests',
'type': 'executable',
'msvs_guid': '9B87804D-2502-480B-95AE-5A572CE91809',
'dependencies': [
'../base/base.gyp:base',
],
'include_dirs': [
'..',
],
'sources': [
'test/browser/browser_test_launcher_in_proc.cc',
'test/browser/browser_test_runner.cc',
'test/browser/browser_test_runner.h',
],
},
{
'target_name': 'crash_service',
'type': 'executable',
@@ -0,0 +1,124 @@
// 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 <string>
#include "base/command_line.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/native_library.h"
#include "base/process_util.h"
#include "base/string_util.h"
#include "chrome/test/browser/browser_test_runner.h"
// This version of the browser test launcher loads a dynamic library containing
// the tests and executes the them in that library. When the test has been run
// the library is unloaded, to ensure atexit handlers are run and static
// initializers will be run again for the next test.
namespace {
const wchar_t* const kBrowserTesLibBaseName = L"browser_tests";
const wchar_t* const kGTestListTestsFlag = L"gtest_list_tests";
class InProcBrowserTestRunner : public browser_tests::BrowserTestRunner {
public:
InProcBrowserTestRunner() : dynamic_lib_(NULL), run_test_proc_(NULL) {
}
~InProcBrowserTestRunner() {
if (!dynamic_lib_)
return;
base::UnloadNativeLibrary(dynamic_lib_);
LOG(INFO) << "Unloaded " <<
base::GetNativeLibraryName(kBrowserTesLibBaseName);
}
bool Init() {
FilePath lib_path;
if (!file_util::GetCurrentDirectory(&lib_path)) {
LOG(ERROR) << "Failed to retrieve curret directory.";
return false;
}
string16 lib_name = base::GetNativeLibraryName(kBrowserTesLibBaseName);
#if defined(OS_WIN)
lib_path = lib_path.Append(lib_name);
#else
lib_path = lib_path.Append(WideToUTF8(lib_name));
#endif
LOG(INFO) << "Loading '" << lib_path.value() << "'";
dynamic_lib_ = base::LoadNativeLibrary(lib_path);
if (!dynamic_lib_) {
LOG(ERROR) << "Failed to find " << lib_name;
return false;
}
run_test_proc_ = reinterpret_cast<RunTestProc>(
base::GetFunctionPointerFromNativeLibrary(dynamic_lib_, "RunTests"));
if (!run_test_proc_) {
LOG(ERROR) <<
"Failed to find RunTest function in " << lib_name;
return false;
}
return true;
}
// Returns true if the test succeeded, false if it failed.
bool RunTest(const std::string& test_name) {
std::string filter_flag = StringPrintf("--gtest_filter=%s",
test_name.c_str());
char* argv[2];
argv[0] = const_cast<char*>("");
argv[1] = const_cast<char*>(filter_flag.c_str());
return RunAsIs(2, argv) == 0;
}
// Calls-in to GTest with the arguments we were started with.
int RunAsIs(int argc, char** argv) {
return (run_test_proc_)(argc, argv);
}
private:
typedef int (CDECL *RunTestProc)(int, char**);
base::NativeLibrary dynamic_lib_;
RunTestProc run_test_proc_;
DISALLOW_COPY_AND_ASSIGN(InProcBrowserTestRunner);
};
class InProcBrowserTestRunnerFactory
: public browser_tests::BrowserTestRunnerFactory {
public:
InProcBrowserTestRunnerFactory() { }
virtual browser_tests::BrowserTestRunner* CreateBrowserTestRunner() const {
return new InProcBrowserTestRunner();
}
private:
DISALLOW_COPY_AND_ASSIGN(InProcBrowserTestRunnerFactory);
};
} // namespace
int main(int argc, char** argv) {
CommandLine::Init(argc, argv);
const CommandLine* command_line = CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(kGTestListTestsFlag)) {
InProcBrowserTestRunner test_runner;
if (!test_runner.Init())
return 1;
return test_runner.RunAsIs(argc, argv);
}
InProcBrowserTestRunnerFactory test_runner_factory;
return browser_tests::RunTests(test_runner_factory) ? 0 : 1;
}
@@ -0,0 +1,85 @@
// 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 <string>
#include "base/command_line.h"
#include "base/logging.h"
#include "base/process_util.h"
#include "chrome/test/browser/browser_test_runner.h"
#include "chrome/test/unit/chrome_test_suite.h"
// This version of the browser test launcher forks a new process for each test
// it runs.
namespace {
const wchar_t* const kGTestListTestsFlag = L"gtest_list_tests";
const wchar_t* const kChildProcessFlag = L"child";
class OutOfProcBrowserTestRunner : public browser_tests::BrowserTestRunner {
public:
OutOfProcBrowserTestRunner() {
}
virtual ~OutOfProcBrowserTestRunner() {
}
bool Init() {
return true;
}
// Returns true if the test succeeded, false if it failed.
bool RunTest(const std::string& test_name) {
const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
CommandLine new_cmd_line(cmd_line->argv());
new_cmd_line.AppendSwitchWithValue(L"gtest_filter", ASCIIToWide(test_name));
new_cmd_line.AppendSwitch(kChildProcessFlag);
base::ProcessHandle process_handle;
bool r = base::LaunchApp(new_cmd_line, false, false, &process_handle);
if (!r)
return false;
int exit_code = 0;
r = base::WaitForExitCode(process_handle, &exit_code);
if (!r)
return false;
return exit_code == 0;
}
private:
DISALLOW_COPY_AND_ASSIGN(OutOfProcBrowserTestRunner);
};
class OutOfProcBrowserTestRunnerFactory
: public browser_tests::BrowserTestRunnerFactory {
public:
OutOfProcBrowserTestRunnerFactory() { }
virtual browser_tests::BrowserTestRunner* CreateBrowserTestRunner() const {
return new OutOfProcBrowserTestRunner();
}
private:
DISALLOW_COPY_AND_ASSIGN(OutOfProcBrowserTestRunnerFactory);
};
} // namespace
int main(int argc, char** argv) {
CommandLine::Init(argc, argv);
const CommandLine* command_line = CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(kChildProcessFlag))
return ChromeTestSuite(argc, argv).Run();
if (command_line->HasSwitch(kGTestListTestsFlag))
return ChromeTestSuite(argc, argv).Run();
OutOfProcBrowserTestRunnerFactory test_runner_factory;
return browser_tests::RunTests(test_runner_factory) ? 0 : 1;
}
@@ -2,94 +2,40 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <windows.h>
#include "chrome/test/browser/browser_test_runner.h"
#include <vector>
#include "base/command_line.h"
#include "base/logging.h"
#include "base/process_util.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
namespace {
const wchar_t* const kBrowserTestDLLName = L"browser_tests.dll";
const wchar_t* const kGTestListTestsFlag = L"gtest_list_tests";
}
// TestEnvContext takes care of loading/unloading the DLL containing the tests.
class TestEnvContext {
public:
TestEnvContext()
: module_(NULL),
run_test_proc_(NULL) {
}
~TestEnvContext() {
if (!module_)
return;
BOOL r = ::FreeLibrary(module_);
DCHECK(r);
LOG(INFO) << "Unloaded " << kBrowserTestDLLName;
}
bool Init() {
module_ = ::LoadLibrary(kBrowserTestDLLName);
if (!module_) {
LOG(ERROR) << "Failed to find " << kBrowserTestDLLName;
return false;
}
run_test_proc_ = reinterpret_cast<RunTestProc>(
::GetProcAddress(module_, "RunTests"));
if (!run_test_proc_) {
LOG(ERROR) <<
"Failed to find RunTest function in " << kBrowserTestDLLName;
return false;
}
return true;
}
// Returns true if the test succeeded, false if it failed.
bool RunTest(const std::string& test_name) {
std::string filter_flag = StringPrintf("--gtest_filter=%s",
test_name.c_str());
char* argv[2];
argv[0] = "";
argv[1] = const_cast<char*>(filter_flag.c_str());
return RunAsIs(2, argv) == 0;
}
// Calls-in to GTest with the arguments we were started with.
int RunAsIs(int argc, char** argv) {
return (run_test_proc_)(argc, argv);
}
private:
typedef int (__cdecl *RunTestProc)(int, char**);
HMODULE module_;
RunTestProc run_test_proc_;
};
// Retrieves the list of tests to run.
// Simply uses the --gtest_list_tests option which honor the filter.
// Sadly there is no dry-run option (or willingness to get such an option) in
// GTest. So we'll have to process disabled and repeat options ourselves.
// Retrieves the list of tests to run by running gtest with the
// --gtest_list_tests flag in a forked process and parsing its output.
// |command_line| should contain the command line used to start the browser
// test launcher, it is expected that it does not contain the
// --gtest_list_tests flag already.
// Note: we cannot implement this in-process for InProcessBrowserTestRunner as
// GTest prints to the stdout and there are no good way of temporarily
// redirecting outputs.
bool GetTestList(const CommandLine& command_line,
std::vector<std::string>* test_list) {
DCHECK(!command_line.HasSwitch(kGTestListTestsFlag));
// Run ourselves with the --gtest_list_tests option and read the output.
std::wstring new_command_line = command_line.command_line_string() + L" --" +
kGTestListTestsFlag;
CommandLine new_command_line(command_line);
new_command_line.AppendSwitch(kGTestListTestsFlag);
std::string output;
if (!base::GetAppOutput(new_command_line, &output))
return false;
// Now let's parse the returned output.
// It looks like:
// The output looks like:
// TestCase.
// Test1
// Test2
@@ -117,40 +63,44 @@ bool GetTestList(const CommandLine& command_line,
return true;
}
int main(int argc, char** argv) {
CommandLine::Init(argc, argv);
} // namespace
namespace browser_tests {
BrowserTestRunner::BrowserTestRunner() {
}
BrowserTestRunner::~BrowserTestRunner() {
}
bool RunTests(const BrowserTestRunnerFactory& browser_test_runner_factory) {
const CommandLine* command_line = CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(kGTestListTestsFlag)) {
TestEnvContext test_context;
if (!test_context.Init())
return 1;
return test_context.RunAsIs(argc, argv);
}
DCHECK(!command_line->HasSwitch(kGTestListTestsFlag));
// First let's get the list of tests we need to run.
std::vector<std::string> test_list;
if (!GetTestList(*command_line, &test_list)) {
printf("Failed to retrieve the tests to run.\n");
return 0;
return false;
}
if (test_list.empty()) {
printf("No tests to run.\n");
return 0;
return false;
}
// Run the tests.
int test_run_count = 0;
std::vector<std::string> failed_tests;
for (std::vector<std::string>::const_iterator iter = test_list.begin();
iter != test_list.end(); ++iter) {
std::string test_name = *iter;
TestEnvContext test_context;
if (!test_context.Init())
return 1;
scoped_ptr<BrowserTestRunner> test_runner(
browser_test_runner_factory.CreateBrowserTestRunner());
if (!test_runner.get() || !test_runner->Init())
return false;
test_run_count++;
if (!test_context.RunTest(test_name.c_str())) {
if (!test_runner->RunTest(test_name.c_str())) {
if (std::find(failed_tests.begin(), failed_tests.end(), test_name) ==
failed_tests.end()) {
failed_tests.push_back(*iter);
@@ -159,10 +109,10 @@ int main(int argc, char** argv) {
}
printf("%d test%s run\n", test_run_count, test_run_count > 1 ? "s" : "");
printf("%d test%s failed\n", failed_tests.size(),
printf("%d test%s failed\n", static_cast<int>(failed_tests.size()),
failed_tests.size() > 1 ? "s" : "");
if (failed_tests.empty())
return 0;
return false;
printf("Failing tests:\n");
for (std::vector<std::string>::const_iterator iter = failed_tests.begin();
@@ -170,5 +120,7 @@ int main(int argc, char** argv) {
printf("%s\n", iter->c_str());
}
return 1;
return true;
}
} // namespace
+51
Ver Arquivo
@@ -0,0 +1,51 @@
// 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 CHROME_TEST_BROWSER_BROWSER_TEST_RUNNER_
#define CHROME_TEST_BROWSER_BROWSER_TEST_RUNNER_
#include <string>
#include <vector>
#include "base/basictypes.h"
namespace browser_tests {
class BrowserTestRunnerFactory;
// Runs the tests specified by the --gtest_filter flag specified in the command
// line that started this process.
// Returns true if all tests succeeded, false if there were no tests to run, or
// one or more tests failed, or if initialization failed.
// Results are printed to stdout.
bool RunTests(const BrowserTestRunnerFactory& browser_test_runner_factory);
// This class defines a way to run browser tests.
// There are 2 implementations, in-process and out-of-process.
class BrowserTestRunner {
public:
BrowserTestRunner();
virtual ~BrowserTestRunner();
// Called once before the BrowserTestRunner is used. Gives it an opportunity
// to perform any requried initialization. Should return true if the
// initialization was successful.
virtual bool Init() = 0;
// Runs the test named |test_name| and returns true if the test succeeded,
// false if it failed.
virtual bool RunTest(const std::string& test_name) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(BrowserTestRunner);
};
class BrowserTestRunnerFactory {
public:
virtual BrowserTestRunner* CreateBrowserTestRunner() const = 0;
};
} // namespace
#endif // CHROME_TEST_BROWSER_BROWSER_TEST_RUNNER_
+3 -2
Ver Arquivo
@@ -7,13 +7,14 @@
#if defined(OS_WIN)
#define DLLEXPORT __declspec(dllexport)
#elif
#else
#define DLLEXPORT
#define CDECL
#endif
// We use extern C for the prototype DLLEXPORT to avoid C++ name mangling.
extern "C" {
DLLEXPORT int __cdecl RunTests(int argc, char **argv) {
DLLEXPORT int CDECL RunTests(int argc, char **argv) {
return ChromeTestSuite(argc, argv).Run();
}
}
+7 -2
Ver Arquivo
@@ -11,10 +11,13 @@
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_shutdown.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#if defined(OS_WIN)
#include "chrome/browser/views/frame/browser_view.h"
#endif
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
@@ -22,7 +25,6 @@
#include "chrome/test/testing_browser_process.h"
#include "chrome/test/ui_test_utils.h"
#include "net/base/host_resolver_unittest.h"
#include "sandbox/src/sandbox_factory.h"
#include "sandbox/src/dep.h"
extern int BrowserMain(const MainFunctionParams&);
@@ -78,9 +80,11 @@ void InProcessBrowserTest::SetUp() {
SetUpCommandLine(command_line);
#if defined(OS_WIN)
// Hide windows on show.
if (!command_line->HasSwitch(kUnitTestShowWindows) && !show_window_)
BrowserView::SetShowState(SW_HIDE);
#endif
if (dom_automation_enabled_)
command_line->AppendSwitch(switches::kDomAutomationController);
@@ -111,7 +115,6 @@ void InProcessBrowserTest::SetUp() {
command_line->AppendSwitchWithValue(switches::kBrowserSubprocessPath,
subprocess_path);
sandbox::SandboxInterfaceInfo sandbox_info = {0};
SandboxInitWrapper sandbox_wrapper;
MainFunctionParams params(*command_line, sandbox_wrapper, NULL);
params.ui_task =
@@ -131,7 +134,9 @@ void InProcessBrowserTest::TearDown() {
browser_shutdown::delete_resources_on_shutdown = true;
#if defined(WIN)
BrowserView::SetShowState(-1);
#endif
*CommandLine::ForCurrentProcessMutable() = *original_command_line_;
RenderProcessHost::set_run_renderer_in_process(original_single_process_);
+7 -1
Ver Arquivo
@@ -14,9 +14,11 @@
#include "chrome/common/chrome_paths.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
#if defined (OS_WIN)
#include "views/widget/accelerator_handler.h"
#endif
#include "googleurl/src/gurl.h"
#include "net/base/net_util.h"
#include "views/widget/accelerator_handler.h"
namespace ui_test_utils {
@@ -101,8 +103,12 @@ void RunMessageLoop() {
MessageLoopForUI* loop = MessageLoopForUI::current();
bool did_allow_task_nesting = loop->NestableTasksAllowed();
loop->SetNestableTasksAllowed(true);
#if defined (OS_WIN)
views::AcceleratorHandler handler;
loop->Run(&handler);
#else
loop->Run();
#endif
loop->SetNestableTasksAllowed(did_allow_task_nesting);
}
+3 -12
Ver Arquivo
@@ -15,14 +15,6 @@
#include "webkit/glue/plugins/plugin_host.h"
#include "webkit/glue/plugins/plugin_list.h"
// A macro for converting string constants into appropriate
// NativeLibraryFunctionNameTypes.
#if defined(OS_MACOSX)
#define NATIVE_LIBRARY_FUNCTION_NAME(x) CFSTR(x)
#else
#define NATIVE_LIBRARY_FUNCTION_NAME(x) x
#endif // OS_*
namespace NPAPI
{
@@ -176,22 +168,21 @@ bool PluginLib::Load() {
entry_points_.np_initialize =
(NP_InitializeFunc)base::GetFunctionPointerFromNativeLibrary(library,
NATIVE_LIBRARY_FUNCTION_NAME("NP_Initialize"));
"NP_Initialize");
if (entry_points_.np_initialize == 0)
rv = false;
#if !defined(OS_LINUX)
entry_points_.np_getentrypoints =
(NP_GetEntryPointsFunc)base::GetFunctionPointerFromNativeLibrary(
library,
NATIVE_LIBRARY_FUNCTION_NAME("NP_GetEntryPoints"));
library, "NP_GetEntryPoints");
if (entry_points_.np_getentrypoints == 0)
rv = false;
#endif
entry_points_.np_shutdown =
(NP_ShutdownFunc)base::GetFunctionPointerFromNativeLibrary(library,
NATIVE_LIBRARY_FUNCTION_NAME("NP_Shutdown"));
"NP_Shutdown");
if (entry_points_.np_shutdown == 0)
rv = false;
} else {
+10 -1
Ver Arquivo
@@ -8,7 +8,9 @@
#include "webkit/glue/plugins/plugin_lib.h"
#include "base/native_library.h"
#include "base/scoped_cftyperef.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
#include "webkit/glue/plugins/plugin_list.h"
@@ -296,7 +298,14 @@ bool PluginLib::ReadWebPluginInfo(const FilePath &filename,
//
// Strictly speaking, only STR# 128 is required.
scoped_cftyperef<CFBundleRef> bundle(base::LoadNativeLibrary(filename));
// We are accessing the bundle contained in the NativeLibrary but not
// unloading it. We use a scoped_ptr to make sure the NativeLibraryStruct is
// not leaked.
scoped_ptr<base::NativeLibraryStruct> native_library(
base::LoadNativeLibrary(filename));
if (native_library->type != base::BUNDLE)
return false;
scoped_cftyperef<CFBundleRef> bundle(native_library->bundle);
if (!bundle)
return false;