diff options
author | jcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-05 22:18:09 +0000 |
---|---|---|
committer | jcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-05 22:18:09 +0000 |
commit | 108c2a1d2780d49121e16b18a29580ef4d28c790 (patch) | |
tree | eca587b489c7c22924814f4475c4a56ec5bc5b8e | |
parent | 9e241cc8a7320c0a818da0ddac1bc3910fc1b60a (diff) | |
download | chromium_src-108c2a1d2780d49121e16b18a29580ef4d28c790.zip chromium_src-108c2a1d2780d49121e16b18a29580ef4d28c790.tar.gz chromium_src-108c2a1d2780d49121e16b18a29580ef4d28c790.tar.bz2 |
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
-rw-r--r-- | base/command_line.cc | 1 | ||||
-rw-r--r-- | base/native_library.h | 33 | ||||
-rw-r--r-- | base/native_library_linux.cc | 8 | ||||
-rw-r--r-- | base/native_library_mac.mm | 41 | ||||
-rw-r--r-- | base/native_library_win.cc | 8 | ||||
-rw-r--r-- | chrome/browser/ssl/ssl_browser_tests.cc | 22 | ||||
-rw-r--r-- | chrome/browser/task_manager_browsertest.cc | 2 | ||||
-rw-r--r-- | chrome/chrome.gyp | 262 | ||||
-rw-r--r-- | chrome/test/browser/browser_test_launcher_in_proc.cc | 124 | ||||
-rw-r--r-- | chrome/test/browser/browser_test_launcher_out_of_proc.cc | 85 | ||||
-rw-r--r-- | chrome/test/browser/browser_test_runner.cc (renamed from chrome/test/browser/browser_tests_launcher.cc) | 122 | ||||
-rw-r--r-- | chrome/test/browser/browser_test_runner.h | 51 | ||||
-rw-r--r-- | chrome/test/browser/run_all_unittests.cc | 5 | ||||
-rw-r--r-- | chrome/test/in_process_browser_test.cc | 9 | ||||
-rw-r--r-- | chrome/test/ui_test_utils.cc | 8 | ||||
-rw-r--r-- | webkit/glue/plugins/plugin_lib.cc | 15 | ||||
-rw-r--r-- | webkit/glue/plugins/plugin_lib_mac.mm | 11 |
17 files changed, 610 insertions, 197 deletions
diff --git a/base/command_line.cc b/base/command_line.cc index 8fb2dcc..a1f919a 100644 --- a/base/command_line.cc +++ b/base/command_line.cc @@ -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()); diff --git a/base/native_library.h b/base/native_library.h index ce85c23..6c835f2 100644 --- a/base/native_library.h +++ b/base/native_library.h @@ -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 diff --git a/base/native_library_linux.cc b/base/native_library_linux.cc index f103bba..39221c1 100644 --- a/base/native_library_linux.cc +++ b/base/native_library_linux.cc @@ -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 diff --git a/base/native_library_mac.mm b/base/native_library_mac.mm index f817a01..577f5ac 100644 --- a/base/native_library_mac.mm +++ b/base/native_library_mac.mm @@ -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 diff --git a/base/native_library_win.cc b/base/native_library_win.cc index cf477fe..459e2ff 100644 --- a/base/native_library_win.cc +++ b/base/native_library_win.cc @@ -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 diff --git a/chrome/browser/ssl/ssl_browser_tests.cc b/chrome/browser/ssl/ssl_browser_tests.cc index ca1d92d..0c36fd6 100644 --- a/chrome/browser/ssl/ssl_browser_tests.cc +++ b/chrome/browser/ssl/ssl_browser_tests.cc @@ -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. diff --git a/chrome/browser/task_manager_browsertest.cc b/chrome/browser/task_manager_browsertest.cc index c66ab2d..35aa462 100644 --- a/chrome/browser/task_manager_browsertest.cc +++ b/chrome/browser/task_manager_browsertest.cc @@ -18,4 +18,4 @@ IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, OpenClose) { IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, ShutdownWhileOpen) { TaskManager::Open(); -}
\ No newline at end of file +} diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 9834560..2823cd8 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -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', diff --git a/chrome/test/browser/browser_test_launcher_in_proc.cc b/chrome/test/browser/browser_test_launcher_in_proc.cc new file mode 100644 index 0000000..1d73788 --- /dev/null +++ b/chrome/test/browser/browser_test_launcher_in_proc.cc @@ -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; +} diff --git a/chrome/test/browser/browser_test_launcher_out_of_proc.cc b/chrome/test/browser/browser_test_launcher_out_of_proc.cc new file mode 100644 index 0000000..5fe3944 --- /dev/null +++ b/chrome/test/browser/browser_test_launcher_out_of_proc.cc @@ -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; +} diff --git a/chrome/test/browser/browser_tests_launcher.cc b/chrome/test/browser/browser_test_runner.cc index 34ec60c..fe633fe 100644 --- a/chrome/test/browser/browser_tests_launcher.cc +++ b/chrome/test/browser/browser_test_runner.cc @@ -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 diff --git a/chrome/test/browser/browser_test_runner.h b/chrome/test/browser/browser_test_runner.h new file mode 100644 index 0000000..cbc0ddf --- /dev/null +++ b/chrome/test/browser/browser_test_runner.h @@ -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_ diff --git a/chrome/test/browser/run_all_unittests.cc b/chrome/test/browser/run_all_unittests.cc index f8f7d57..e4eb431 100644 --- a/chrome/test/browser/run_all_unittests.cc +++ b/chrome/test/browser/run_all_unittests.cc @@ -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(); } } diff --git a/chrome/test/in_process_browser_test.cc b/chrome/test/in_process_browser_test.cc index c9642fe..8a4d69e 100644 --- a/chrome/test/in_process_browser_test.cc +++ b/chrome/test/in_process_browser_test.cc @@ -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_); diff --git a/chrome/test/ui_test_utils.cc b/chrome/test/ui_test_utils.cc index 1f252a0..7ef658a 100644 --- a/chrome/test/ui_test_utils.cc +++ b/chrome/test/ui_test_utils.cc @@ -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); } diff --git a/webkit/glue/plugins/plugin_lib.cc b/webkit/glue/plugins/plugin_lib.cc index c5b2d21..563e1a3 100644 --- a/webkit/glue/plugins/plugin_lib.cc +++ b/webkit/glue/plugins/plugin_lib.cc @@ -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 { diff --git a/webkit/glue/plugins/plugin_lib_mac.mm b/webkit/glue/plugins/plugin_lib_mac.mm index 04510a4..4137dd8 100644 --- a/webkit/glue/plugins/plugin_lib_mac.mm +++ b/webkit/glue/plugins/plugin_lib_mac.mm @@ -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; |