summaryrefslogtreecommitdiffstats
path: root/chrome/test
diff options
context:
space:
mode:
authorsky@google.com <sky@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-01-30 00:40:43 +0000
committersky@google.com <sky@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-01-30 00:40:43 +0000
commitd4515eb94ad33ac2ab9bfd1094c8e1edd1eefa1b (patch)
treeadd4a98df5bcdbb3ca0e1f4471c77f453d52a1f4 /chrome/test
parent0815731ac884b41853725e51e26b0697449747b4 (diff)
downloadchromium_src-d4515eb94ad33ac2ab9bfd1094c8e1edd1eefa1b.zip
chromium_src-d4515eb94ad33ac2ab9bfd1094c8e1edd1eefa1b.tar.gz
chromium_src-d4515eb94ad33ac2ab9bfd1094c8e1edd1eefa1b.tar.bz2
Provides the ability to write a unit test that brings up a browser. As
a proof of concept I converted FindInPageControllerTest.FindInPageFrames over to this. See the description in InProcessBrowserTest for how it all works. BUG=none TEST=none Review URL: http://codereview.chromium.org/19644 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@8934 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/test')
-rw-r--r--chrome/test/in_process_browser_test.cc179
-rw-r--r--chrome/test/in_process_browser_test.h125
-rw-r--r--chrome/test/ui_test_utils.cc77
-rw-r--r--chrome/test/ui_test_utils.h30
-rw-r--r--chrome/test/unit/unittests.vcproj20
5 files changed, 431 insertions, 0 deletions
diff --git a/chrome/test/in_process_browser_test.cc b/chrome/test/in_process_browser_test.cc
new file mode 100644
index 0000000..581ddab
--- /dev/null
+++ b/chrome/test/in_process_browser_test.cc
@@ -0,0 +1,179 @@
+// Copyright (c) 2006-2008 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 "chrome/test/in_process_browser_test.h"
+
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_shutdown.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/views/frame/browser_view.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/main_function_params.h"
+#include "chrome/test/testing_browser_process.h"
+#include "chrome/test/ui_test_utils.h"
+#include "sandbox/src/sandbox_factory.h"
+#include "sandbox/src/dep.h"
+
+extern int BrowserMain(const MainFunctionParams&);
+
+const wchar_t kUnitTestShowWindows[] = L"show-windows";
+
+namespace {
+
+bool DieFileDie(const std::wstring& file, bool recurse) {
+ if (!file_util::PathExists(file))
+ return true;
+
+ // Sometimes Delete fails, so try a few more times.
+ for (int i = 0; i < 10; ++i) {
+ if (file_util::Delete(file, recurse))
+ return true;
+ PlatformThread::Sleep(100);
+ }
+ return false;
+}
+
+} // namespace
+
+InProcessBrowserTest::InProcessBrowserTest() : browser_(NULL) {
+}
+
+void InProcessBrowserTest::SetUp() {
+ // Cleanup the user data dir.
+ std::wstring user_data_dir;
+ PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
+ ASSERT_LT(10, static_cast<int>(user_data_dir.size())) <<
+ "The user data directory name passed into this test was too "
+ "short to delete safely. Please check the user-data-dir "
+ "argument and try again.";
+ ASSERT_TRUE(DieFileDie(user_data_dir, true));
+
+ // The unit test suite creates a testingbrowser, but we want the real thing.
+ // Delete the current one. We'll install the testing one in TearDown.
+ delete g_browser_process;
+
+ // Don't delete the resources when BrowserMain returns. Many ui classes
+ // cache SkBitmaps in a static field so that if we delete the resource
+ // bundle we'll crash.
+ browser_shutdown::delete_resources_on_shutdown = false;
+
+ CommandLine* command_line = CommandLine::ForCurrentProcessMutable();
+
+ // Hide windows on show.
+ if (!command_line->HasSwitch(kUnitTestShowWindows))
+ BrowserView::SetShowState(SW_HIDE);
+
+ command_line->AppendSwitchWithValue(switches::kUserDataDir, user_data_dir);
+
+ // For some reason the sandbox wasn't happy running in test mode. These
+ // tests aren't intended to test the sandbox, so we turn it off.
+ command_line->AppendSwitch(switches::kNoSandbox);
+
+ // Explicitly set the path of the exe used for the renderer, otherwise it'll
+ // try to use unit_test.exe.
+ std::wstring renderer_path;
+ PathService::Get(base::FILE_EXE, &renderer_path);
+ file_util::TrimFilename(&renderer_path);
+ file_util::AppendToPath(&renderer_path,
+ chrome::kBrowserProcessExecutableName);
+ command_line->AppendSwitchWithValue(switches::kRendererPath, renderer_path);
+
+ sandbox::SandboxInterfaceInfo sandbox_info = {0};
+ SandboxInitWrapper sandbox_wrapper;
+ MainFunctionParams params(*command_line, sandbox_wrapper);
+ params.ui_task =
+ NewRunnableMethod(this, &InProcessBrowserTest::RunTestOnMainThreadLoop);
+ BrowserMain(params);
+}
+
+void InProcessBrowserTest::TearDown() {
+ // Reinstall testing browser process.
+ delete g_browser_process;
+ g_browser_process = new TestingBrowserProcess();
+
+ browser_shutdown::delete_resources_on_shutdown = true;
+
+ BrowserView::SetShowState(-1);
+}
+
+void InProcessBrowserTest::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NOTIFY_BROWSER_CLOSED) {
+ DCHECK(Source<Browser>(source).ptr() == browser_);
+ browser_ = NULL;
+ } else {
+ NOTREACHED();
+ }
+}
+
+HTTPTestServer* InProcessBrowserTest::StartHTTPServer() {
+ // The HTTPServer must run on the IO thread.
+ DCHECK(!http_server_.get());
+ http_server_ = HTTPTestServer::CreateServer(
+ L"chrome/test/data",
+ g_browser_process->io_thread()->message_loop());
+ return http_server_.get();
+}
+
+// Creates a browser with a single tab (about:blank), waits for the tab to
+// finish loading and shows the browser.
+Browser* InProcessBrowserTest::CreateBrowser(Profile* profile) {
+ Browser* browser = Browser::Create(profile);
+
+ browser->AddTabWithURL(
+ GURL("about:blank"), GURL(), PageTransition::START_PAGE, true, NULL);
+
+ // Wait for the page to finish loading.
+ ui_test_utils::WaitForNavigation(
+ browser->GetSelectedTabContents()->controller());
+
+ browser->window()->Show();
+
+ return browser;
+}
+
+void InProcessBrowserTest::RunTestOnMainThreadLoop() {
+ // In the long term it would be great if we could use a TestingProfile
+ // here and only enable services you want tested, but that requires all
+ // consumers of Profile to handle NULL services.
+ FilePath user_data_dir;
+ PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ Profile* profile = profile_manager->GetDefaultProfile(user_data_dir);
+ if (!profile) {
+ // We should only be able to get here if the profile already exists and
+ // has been created.
+ NOTREACHED();
+ MessageLoopForUI::current()->Quit();
+ return;
+ }
+
+ profile->InitExtensions();
+
+ browser_ = CreateBrowser(profile);
+
+ registrar_.Add(this, NOTIFY_BROWSER_CLOSED, Source<Browser>(browser_));
+
+ RunTestOnMainThread();
+
+ if (browser_)
+ browser_->CloseAllTabs();
+
+ // Remove all registered notifications, otherwise by the time the
+ // destructor is run the NotificationService is dead.
+ registrar_.RemoveAll();
+
+ // Stop the HTTP server.
+ http_server_ = NULL;
+
+ MessageLoopForUI::current()->Quit();
+}
diff --git a/chrome/test/in_process_browser_test.h b/chrome/test/in_process_browser_test.h
new file mode 100644
index 0000000..fb8bd9d
--- /dev/null
+++ b/chrome/test/in_process_browser_test.h
@@ -0,0 +1,125 @@
+// Copyright (c) 2006-2008 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_IN_PROCESS_BROWSER_TEST_H_
+#define CHROME_TEST_IN_PROCESS_BROWSER_TEST_H_
+
+#include "chrome/app/scoped_ole_initializer.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_service.h"
+#include "net/url_request/url_request_unittest.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class Browser;
+class Profile;
+
+// Base class for tests wanting to bring up a browser in the unit test process.
+// Writing tests with InProcessBrowserTest is slightly different than that of
+// other tests. This is necessitated by InProcessBrowserTest running a message
+// loop. To use InProcessBrowserTest do the following:
+// . Use the macro IN_PROC_BROWSER_TEST_F to define your test.
+// . Your test method is invoked on the ui thread. If you need to block until
+// state changes you'll need to run the message loop from your test method.
+// For example, if you need to wait till a find bar has completely been shown
+// you'll need to invoke ui_test_utils::RunMessageLoop. When the message bar
+// is shown, invoke MessageLoop::current()->Quit() to return control back to
+// your test method.
+// . If you subclass and override SetUp, be sure and invoke
+// InProcessBrowserTest::SetUp.
+//
+// By default InProcessBrowserTest creates a single Browser (as returned from
+// the CreateBrowser method). You can obviously create more as needed.
+
+// Browsers created while InProcessBrowserTest is running are shown hidden. Use
+// the command line switch --show-windows to make them visible when debugging.
+//
+// InProcessBrowserTest disables the sandbox when running.
+//
+// See ui_test_utils for a handful of methods designed for use with this class.
+class InProcessBrowserTest : public testing::Test, public NotificationObserver {
+ public:
+ InProcessBrowserTest();
+
+ // We do this so we can be used in a Task.
+ void AddRef() {}
+ void Release() {}
+
+ // Configures everything for an in process browser test, then invokes
+ // BrowserMain. BrowserMain ends up invoking RunTestOnMainThreadLoop.
+ virtual void SetUp();
+
+ // Restores state configured in SetUp.
+ virtual void TearDown();
+
+ // Used to track when the browser_ is destroyed. Resets the |browser_| field
+ // to NULL.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ protected:
+ // Returns the browser created by CreateBrowser.
+ Browser* browser() const { return browser_; }
+
+ // Override this rather than TestBody.
+ virtual void RunTestOnMainThread() = 0;
+
+ // Starts an HTTP server.
+ HTTPTestServer* StartHTTPServer();
+
+ // Creates a browser with a single tab (about:blank), waits for the tab to
+ // finish loading and shows the browser.
+ //
+ // This is invoked from Setup.
+ virtual Browser* CreateBrowser(Profile* profile);
+
+ private:
+ // Invokes CreateBrowser to create a browser, then RunTestOnMainThread, and
+ // destroys the browser.
+ void RunTestOnMainThreadLoop();
+
+ // Browser created from CreateBrowser.
+ Browser* browser_;
+
+ // Used to track when the browser is deleted.
+ NotificationRegistrar registrar_;
+
+ // HTTPServer, created when StartHTTPServer is invoked.
+ scoped_refptr<HTTPTestServer> http_server_;
+
+ ScopedOleInitializer ole_initializer_;
+
+ DISALLOW_COPY_AND_ASSIGN(InProcessBrowserTest);
+};
+
+#define IN_PROC_BROWSER_TEST_(test_case_name, test_name, parent_class,\
+ parent_id)\
+class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\
+ public:\
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\
+ protected:\
+ virtual void RunTestOnMainThread();\
+ private:\
+ virtual void TestBody() {}\
+ static ::testing::TestInfo* const test_info_;\
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(\
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\
+};\
+\
+::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\
+ ::test_info_ =\
+ ::testing::internal::MakeAndRegisterTestInfo(\
+ #test_case_name, #test_name, "", "", \
+ (parent_id), \
+ parent_class::SetUpTestCase, \
+ parent_class::TearDownTestCase, \
+ new ::testing::internal::TestFactoryImpl<\
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\
+void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::RunTestOnMainThread()
+
+#define IN_PROC_BROWSER_TEST_F(test_fixture, test_name)\
+ IN_PROC_BROWSER_TEST_(test_fixture, test_name, test_fixture,\
+ ::testing::internal::GetTypeId<test_fixture>())
+
+#endif // CHROME_TEST_IN_PROCESS_BROWSER_TEST_H_
diff --git a/chrome/test/ui_test_utils.cc b/chrome/test/ui_test_utils.cc
new file mode 100644
index 0000000..07016f7
--- /dev/null
+++ b/chrome/test/ui_test_utils.cc
@@ -0,0 +1,77 @@
+// Copyright (c) 2006-2008 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 "chrome/test/ui_test_utils.h"
+
+#include "base/message_loop.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/tab_contents/navigation_controller.h"
+#include "chrome/browser/tab_contents/web_contents.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_service.h"
+#include "googleurl/src/gurl.h"
+
+namespace ui_test_utils {
+
+namespace {
+
+// Used to block until a navigation completes.
+class NavigationNotificationObserver : public NotificationObserver {
+ public:
+ explicit NavigationNotificationObserver(NavigationController* controller)
+ : navigation_started_(false) {
+ registrar_.Add(this, NOTIFY_NAV_ENTRY_COMMITTED,
+ Source<NavigationController>(controller));
+ registrar_.Add(this, NOTIFY_LOAD_START,
+ Source<NavigationController>(controller));
+ registrar_.Add(this, NOTIFY_LOAD_STOP,
+ Source<NavigationController>(controller));
+ RunMessageLoop();
+ }
+
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NOTIFY_NAV_ENTRY_COMMITTED || type == NOTIFY_LOAD_START) {
+ navigation_started_ = true;
+ } else if (type == NOTIFY_LOAD_STOP) {
+ if (navigation_started_) {
+ navigation_started_ = false;
+ MessageLoopForUI::current()->Quit();
+ }
+ }
+ }
+
+ private:
+ NotificationRegistrar registrar_;
+
+ // If true the navigation has started.
+ bool navigation_started_;
+
+ DISALLOW_COPY_AND_ASSIGN(NavigationNotificationObserver);
+};
+
+} // namespace
+
+void RunMessageLoop() {
+ MessageLoopForUI* loop = MessageLoopForUI::current();
+ bool did_allow_task_nesting = loop->NestableTasksAllowed();
+ loop->SetNestableTasksAllowed(true);
+ loop->Run(NULL);
+ loop->SetNestableTasksAllowed(did_allow_task_nesting);
+}
+
+void WaitForNavigation(NavigationController* controller) {
+ NavigationNotificationObserver observer(controller);
+}
+
+void NavigateToURL(Browser* browser, const GURL& url) {
+ NavigationController* controller =
+ browser->GetSelectedTabContents()->controller();
+ browser->OpenURLFromTab(browser->GetSelectedTabContents(), url, GURL(),
+ CURRENT_TAB, PageTransition::TYPED);
+ WaitForNavigation(controller);
+}
+
+} // namespace ui_test_utils
diff --git a/chrome/test/ui_test_utils.h b/chrome/test/ui_test_utils.h
new file mode 100644
index 0000000..f0433b0
--- /dev/null
+++ b/chrome/test/ui_test_utils.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2006-2008 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_UI_TEST_UTILS_H_
+#define CHROME_TEST_UI_TEST_UTILS_H_
+
+class Browser;
+class GURL;
+class NavigationController;
+
+// A collections of functions designed for use with InProcessBrowserTest.
+namespace ui_test_utils {
+
+// Turns on nestable tasks, runs the message loop, then resets nestable tasks
+// to what they were originally. Prefer this over MessageLoop::Run for in
+// process browser tests that need to block until a condition is met.
+void RunMessageLoop();
+
+// Waits for |controller| to complete a navigation. This blocks until
+// the navigation finishes.
+void WaitForNavigation(NavigationController* controller);
+
+// Navigates the selected tab of |browser| to |url|, blocking until the
+// navigation finishes.
+void NavigateToURL(Browser* browser, const GURL& url);
+
+}
+
+#endif // CHROME_TEST_UI_TEST_UTILS_H_
diff --git a/chrome/test/unit/unittests.vcproj b/chrome/test/unit/unittests.vcproj
index d5d5e95..eafd8c4 100644
--- a/chrome/test/unit/unittests.vcproj
+++ b/chrome/test/unit/unittests.vcproj
@@ -159,6 +159,14 @@
>
</File>
<File
+ RelativePath="..\in_process_browser_test.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\in_process_browser_test.h"
+ >
+ </File>
+ <File
RelativePath="..\..\common\ipc_test_sink.cc"
>
</File>
@@ -207,6 +215,14 @@
>
</File>
<File
+ RelativePath="..\ui_test_utils.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\ui_test_utils.h"
+ >
+ </File>
+ <File
RelativePath="..\..\..\net\url_request\url_request_test_job.cc"
>
</File>
@@ -367,6 +383,10 @@
Name="browser"
>
<File
+ RelativePath="..\..\browser\views\find_bar_win_unittest.cc"
+ >
+ </File>
+ <File
RelativePath="..\..\browser\autocomplete\autocomplete_unittest.cc"
>
</File>