summaryrefslogtreecommitdiffstats
path: root/chrome/test/automation
diff options
context:
space:
mode:
authornirnimesh@chromium.org <nirnimesh@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-08 02:04:59 +0000
committernirnimesh@chromium.org <nirnimesh@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-08 02:04:59 +0000
commitc405290f60432b22e8e862377b4f00e6177b4451 (patch)
treea710eb4876a4ea9013715ba90a27139d5da835bc /chrome/test/automation
parent079443435c92b0294d63682c39a26df3391018c4 (diff)
downloadchromium_src-c405290f60432b22e8e862377b4f00e6177b4451.zip
chromium_src-c405290f60432b22e8e862377b4f00e6177b4451.tar.gz
chromium_src-c405290f60432b22e8e862377b4f00e6177b4451.tar.bz2
Moves everything related to launching and terminating the browser from UITestBase into ProxyLauncher.
The primary changes are in ui_test.* and proxy_launcher.*. The changes in the remaining files are mostly just changing namespaces from UITestBase:: to ProxyLauncher::. BUG=None. TEST=All tests should pass. No functionality change. Review URL: http://codereview.chromium.org/5967003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@70827 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/test/automation')
-rw-r--r--chrome/test/automation/automation_proxy_uitest.cc9
-rw-r--r--chrome/test/automation/automation_proxy_uitest.h2
-rw-r--r--chrome/test/automation/proxy_launcher.cc486
-rw-r--r--chrome/test/automation/proxy_launcher.h277
4 files changed, 751 insertions, 23 deletions
diff --git a/chrome/test/automation/automation_proxy_uitest.cc b/chrome/test/automation/automation_proxy_uitest.cc
index 465b610..ab65c43 100644
--- a/chrome/test/automation/automation_proxy_uitest.cc
+++ b/chrome/test/automation/automation_proxy_uitest.cc
@@ -63,8 +63,9 @@ class ExternalTabUITestMockLauncher : public ProxyLauncher {
return *mock_;
}
- void InitializeConnection(UITestBase* ui_test_base) const {
- ui_test_base->LaunchBrowserAndServer();
+ void InitializeConnection(const LaunchState& state,
+ bool wait_for_initial_loads) {
+ LaunchBrowserAndServer(state, wait_for_initial_loads);
}
std::string PrefixedChannelID() const {
@@ -885,6 +886,10 @@ template <typename T> T** ReceivePointer(scoped_refptr<T>& p) { // NOLINT
return reinterpret_cast<T**>(&p);
}
+ExternalTabUITest::ExternalTabUITest() : UITest(MessageLoop::TYPE_UI) {
+ launcher_.reset(CreateProxyLauncher());
+}
+
// Replace the default automation proxy with our mock client.
ProxyLauncher* ExternalTabUITest::CreateProxyLauncher() {
return new ExternalTabUITestMockLauncher(&mock_);
diff --git a/chrome/test/automation/automation_proxy_uitest.h b/chrome/test/automation/automation_proxy_uitest.h
index c08aa91..2ce19d4 100644
--- a/chrome/test/automation/automation_proxy_uitest.h
+++ b/chrome/test/automation/automation_proxy_uitest.h
@@ -109,7 +109,7 @@ class ExternalTabUITestMockClient : public AutomationProxy {
// Base your external tab UI tests on this.
class ExternalTabUITest : public UITest {
public:
- ExternalTabUITest() : UITest(MessageLoop::TYPE_UI) {}
+ ExternalTabUITest();
// Override UITest's CreateProxyLauncher to provide the unit test
// with our special implementation of AutomationProxy.
// This function is called from within UITest::SetUp().
diff --git a/chrome/test/automation/proxy_launcher.cc b/chrome/test/automation/proxy_launcher.cc
index 1d1583c..d30f212 100644
--- a/chrome/test/automation/proxy_launcher.cc
+++ b/chrome/test/automation/proxy_launcher.cc
@@ -4,14 +4,482 @@
#include "chrome/test/automation/proxy_launcher.h"
-#include "base/threading/platform_thread.h"
+#include "app/sql/connection.h"
+#include "base/file_util.h"
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
+#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/test/test_file_util.h"
+#include "base/test/test_timeouts.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h"
#include "chrome/common/automation_constants.h"
+#include "chrome/common/child_process_info.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/debug_flags.h"
#include "chrome/common/logging_chrome.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/test/chrome_process_util.h"
+#include "chrome/test/test_launcher_utils.h"
+#include "chrome/test/test_switches.h"
#include "chrome/test/automation/automation_proxy.h"
#include "chrome/test/ui/ui_test.h"
+namespace {
+
+// Passed as value of kTestType.
+const char kUITestType[] = "ui";
+
// Default path of named testing interface.
-static const char kInterfacePath[] = "/var/tmp/ChromeTestingInterface";
+const char kInterfacePath[] = "/var/tmp/ChromeTestingInterface";
+
+// Rewrite the preferences file to point to the proper image directory.
+void RewritePreferencesFile(const FilePath& user_data_dir) {
+ const FilePath pref_template_path(
+ user_data_dir.AppendASCII("Default").AppendASCII("PreferencesTemplate"));
+ const FilePath pref_path(
+ user_data_dir.AppendASCII("Default").AppendASCII("Preferences"));
+
+ // Read in preferences template.
+ std::string pref_string;
+ EXPECT_TRUE(file_util::ReadFileToString(pref_template_path, &pref_string));
+ string16 format_string = ASCIIToUTF16(pref_string);
+
+ // Make sure temp directory has the proper format for writing to prefs file.
+#if defined(OS_POSIX)
+ std::wstring user_data_dir_w(ASCIIToWide(user_data_dir.value()));
+#elif defined(OS_WIN)
+ std::wstring user_data_dir_w(user_data_dir.value());
+ // In Windows, the FilePath will write '\' for the path separators; change
+ // these to a separator that won't trigger escapes.
+ std::replace(user_data_dir_w.begin(),
+ user_data_dir_w.end(), '\\', '/');
+#endif
+
+ // Rewrite prefs file.
+ std::vector<string16> subst;
+ subst.push_back(WideToUTF16(user_data_dir_w));
+ const std::string prefs_string =
+ UTF16ToASCII(ReplaceStringPlaceholders(format_string, subst, NULL));
+ EXPECT_TRUE(file_util::WriteFile(pref_path, prefs_string.c_str(),
+ prefs_string.size()));
+ file_util::EvictFileFromSystemCache(pref_path);
+}
+
+// We want to have a current history database when we start the browser so
+// things like the NTP will have thumbnails. This method updates the dates
+// in the history to be more recent.
+void UpdateHistoryDates(const FilePath& user_data_dir) {
+ // Migrate the times in the segment_usage table to yesterday so we get
+ // actual thumbnails on the NTP.
+ sql::Connection db;
+ FilePath history =
+ user_data_dir.AppendASCII("Default").AppendASCII("History");
+ // Not all test profiles have a history file.
+ if (!file_util::PathExists(history))
+ return;
+
+ ASSERT_TRUE(db.Open(history));
+ base::Time yesterday = base::Time::Now() - base::TimeDelta::FromDays(1);
+ std::string yesterday_str = base::Int64ToString(yesterday.ToInternalValue());
+ std::string query = StringPrintf(
+ "UPDATE segment_usage "
+ "SET time_slot = %s "
+ "WHERE id IN (SELECT id FROM segment_usage WHERE time_slot > 0);",
+ yesterday_str.c_str());
+ ASSERT_TRUE(db.Execute(query.c_str()));
+ db.Close();
+ file_util::EvictFileFromSystemCache(history);
+}
+
+} // namespace
+
+// ProxyLauncher functions
+
+bool ProxyLauncher::in_process_renderer_ = false;
+bool ProxyLauncher::no_sandbox_ = false;
+bool ProxyLauncher::full_memory_dump_ = false;
+bool ProxyLauncher::safe_plugins_ = false;
+bool ProxyLauncher::show_error_dialogs_ = true;
+bool ProxyLauncher::dump_histograms_on_exit_ = false;
+bool ProxyLauncher::enable_dcheck_ = false;
+bool ProxyLauncher::silent_dump_on_dcheck_ = false;
+bool ProxyLauncher::disable_breakpad_ = false;
+std::string ProxyLauncher::js_flags_ = "";
+std::string ProxyLauncher::log_level_ = "";
+
+ProxyLauncher::ProxyLauncher()
+ : process_(base::kNullProcessHandle),
+ process_id_(-1) {}
+
+ProxyLauncher::~ProxyLauncher() {}
+
+void ProxyLauncher::WaitForBrowserLaunch(bool wait_for_initial_loads) {
+ ASSERT_EQ(AUTOMATION_SUCCESS, automation_proxy_->WaitForAppLaunch())
+ << "Error while awaiting automation ping from browser process";
+ if (wait_for_initial_loads)
+ ASSERT_TRUE(automation_proxy_->WaitForInitialLoads());
+ else
+ base::PlatformThread::Sleep(TestTimeouts::action_timeout_ms());
+
+ EXPECT_TRUE(automation()->SetFilteredInet(ShouldFilterInet()));
+}
+
+void ProxyLauncher::LaunchBrowserAndServer(const LaunchState& state,
+ bool wait_for_initial_loads) {
+ // Set up IPC testing interface as a server.
+ automation_proxy_.reset(CreateAutomationProxy(
+ TestTimeouts::command_execution_timeout_ms()));
+
+ LaunchBrowser(state);
+ WaitForBrowserLaunch(wait_for_initial_loads);
+}
+
+void ProxyLauncher::ConnectToRunningBrowser(bool wait_for_initial_loads) {
+ // Set up IPC testing interface as a client.
+ automation_proxy_.reset(CreateAutomationProxy(
+ TestTimeouts::command_execution_timeout_ms()));
+ WaitForBrowserLaunch(wait_for_initial_loads);
+}
+
+void ProxyLauncher::CloseBrowserAndServer(ShutdownType shutdown_type) {
+ QuitBrowser(shutdown_type);
+ CleanupAppProcesses();
+
+ // Suppress spammy failures that seem to be occurring when running
+ // the UI tests in single-process mode.
+ // TODO(jhughes): figure out why this is necessary at all, and fix it
+ if (!in_process_renderer_)
+ AssertAppNotRunning(
+ StringPrintf(L"Unable to quit all browser processes. Original PID %d",
+ &process_id_));
+
+ automation_proxy_.reset(); // Shut down IPC testing interface.
+}
+
+void ProxyLauncher::LaunchBrowser(const LaunchState& state) {
+ if (state.clear_profile || !temp_profile_dir_.IsValid()) {
+ temp_profile_dir_.Delete();
+ ASSERT_TRUE(temp_profile_dir_.CreateUniqueTempDir());
+
+ ASSERT_TRUE(test_launcher_utils::OverrideUserDataDir(user_data_dir()));
+ }
+
+ if (!state.template_user_data.empty()) {
+ // Recursively copy the template directory to the user_data_dir.
+ ASSERT_TRUE(file_util::CopyRecursiveDirNoCache(
+ state.template_user_data,
+ user_data_dir()));
+ // If we're using the complex theme data, we need to write the
+ // user_data_dir_ to our preferences file.
+ if (state.profile_type == COMPLEX_THEME) {
+ RewritePreferencesFile(user_data_dir());
+ }
+
+ // Update the history file to include recent dates.
+ UpdateHistoryDates(user_data_dir());
+ }
+
+ ASSERT_TRUE(LaunchBrowserHelper(state, false, &process_));
+ process_id_ = base::GetProcId(process_);
+}
+
+#if !defined(OS_MACOSX)
+bool ProxyLauncher::LaunchAnotherBrowserBlockUntilClosed(
+ const LaunchState& state) {
+ return LaunchBrowserHelper(state, true, NULL);
+}
+#endif
+
+void ProxyLauncher::QuitBrowser(ShutdownType shutdown_type) {
+ if (SESSION_ENDING == shutdown_type) {
+ TerminateBrowser();
+ return;
+ }
+
+ // There's nothing to do here if the browser is not running.
+ // WARNING: There is a race condition here where the browser may shut down
+ // after this check but before some later automation call. Your test should
+ // use WaitForBrowserProcessToQuit() if it intentionally
+ // causes the browser to shut down.
+ if (IsBrowserRunning()) {
+ base::TimeTicks quit_start = base::TimeTicks::Now();
+ EXPECT_TRUE(automation()->SetFilteredInet(false));
+
+ if (WINDOW_CLOSE == shutdown_type) {
+ int window_count = 0;
+ EXPECT_TRUE(automation()->GetBrowserWindowCount(&window_count));
+
+ // Synchronously close all but the last browser window. Closing them
+ // one-by-one may help with stability.
+ while (window_count > 1) {
+ scoped_refptr<BrowserProxy> browser_proxy =
+ automation()->GetBrowserWindow(0);
+ EXPECT_TRUE(browser_proxy.get());
+ if (browser_proxy.get()) {
+ EXPECT_TRUE(browser_proxy->RunCommand(IDC_CLOSE_WINDOW));
+ EXPECT_TRUE(automation()->GetBrowserWindowCount(&window_count));
+ } else {
+ break;
+ }
+ }
+
+ // Close the last window asynchronously, because the browser may
+ // shutdown faster than it will be able to send a synchronous response
+ // to our message.
+ scoped_refptr<BrowserProxy> browser_proxy =
+ automation()->GetBrowserWindow(0);
+ EXPECT_TRUE(browser_proxy.get());
+ if (browser_proxy.get()) {
+ EXPECT_TRUE(browser_proxy->ApplyAccelerator(IDC_CLOSE_WINDOW));
+ browser_proxy = NULL;
+ }
+ } else if (USER_QUIT == shutdown_type) {
+ scoped_refptr<BrowserProxy> browser_proxy =
+ automation()->GetBrowserWindow(0);
+ EXPECT_TRUE(browser_proxy.get());
+ if (browser_proxy.get()) {
+ EXPECT_TRUE(browser_proxy->RunCommandAsync(IDC_EXIT));
+ }
+ } else {
+ NOTREACHED() << "Invalid shutdown type " << shutdown_type;
+ }
+
+ // Now, drop the automation IPC channel so that the automation provider in
+ // the browser notices and drops its reference to the browser process.
+ automation()->Disconnect();
+
+ // Wait for the browser process to quit. It should quit once all tabs have
+ // been closed.
+ if (!WaitForBrowserProcessToQuit(
+ TestTimeouts::wait_for_terminate_timeout_ms())) {
+ // We need to force the browser to quit because it didn't quit fast
+ // enough. Take no chance and kill every chrome processes.
+ CleanupAppProcesses();
+ }
+ browser_quit_time_ = base::TimeTicks::Now() - quit_start;
+ }
+
+ // Don't forget to close the handle
+ base::CloseProcessHandle(process_);
+ process_ = base::kNullProcessHandle;
+ process_id_ = -1;
+}
+
+void ProxyLauncher::TerminateBrowser() {
+ if (IsBrowserRunning()) {
+ base::TimeTicks quit_start = base::TimeTicks::Now();
+ EXPECT_TRUE(automation()->SetFilteredInet(false));
+#if defined(OS_WIN)
+ scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(browser.get());
+ ASSERT_TRUE(browser->TerminateSession());
+#endif // defined(OS_WIN)
+
+ // Now, drop the automation IPC channel so that the automation provider in
+ // the browser notices and drops its reference to the browser process.
+ automation()->Disconnect();
+
+#if defined(OS_POSIX)
+ EXPECT_EQ(kill(process_, SIGTERM), 0);
+#endif // OS_POSIX
+
+ if (!WaitForBrowserProcessToQuit(
+ TestTimeouts::wait_for_terminate_timeout_ms())) {
+ // We need to force the browser to quit because it didn't quit fast
+ // enough. Take no chance and kill every chrome processes.
+ CleanupAppProcesses();
+ }
+ browser_quit_time_ = base::TimeTicks::Now() - quit_start;
+ }
+
+ // Don't forget to close the handle
+ base::CloseProcessHandle(process_);
+ process_ = base::kNullProcessHandle;
+ process_id_ = -1;
+}
+
+void ProxyLauncher::AssertAppNotRunning(const std::wstring& error_message) {
+ std::wstring final_error_message(error_message);
+
+ ChromeProcessList processes = GetRunningChromeProcesses(process_id_);
+ if (!processes.empty()) {
+ final_error_message += L" Leftover PIDs: [";
+ for (ChromeProcessList::const_iterator it = processes.begin();
+ it != processes.end(); ++it) {
+ final_error_message += StringPrintf(L" %d", *it);
+ }
+ final_error_message += L" ]";
+ }
+ ASSERT_TRUE(processes.empty()) << final_error_message;
+}
+
+void ProxyLauncher::CleanupAppProcesses() {
+ TerminateAllChromeProcesses(process_id_);
+}
+
+bool ProxyLauncher::WaitForBrowserProcessToQuit(int timeout) {
+#ifdef WAIT_FOR_DEBUGGER_ON_OPEN
+ timeout = 500000;
+#endif
+ return base::WaitForSingleProcess(process_, timeout);
+}
+
+bool ProxyLauncher::IsBrowserRunning() {
+ return CrashAwareSleep(0);
+}
+
+bool ProxyLauncher::CrashAwareSleep(int timeout_ms) {
+ return base::CrashAwareSleep(process_, timeout_ms);
+}
+
+void ProxyLauncher::PrepareTestCommandline(CommandLine* command_line,
+ bool include_testing_id) {
+ // Propagate commandline settings from test_launcher_utils.
+ test_launcher_utils::PrepareBrowserCommandLineForTests(command_line);
+
+ // Add any explicit command line flags passed to the process.
+ CommandLine::StringType extra_chrome_flags =
+ CommandLine::ForCurrentProcess()->GetSwitchValueNative(
+ switches::kExtraChromeFlags);
+ if (!extra_chrome_flags.empty()) {
+ // Split by spaces and append to command line
+ std::vector<CommandLine::StringType> flags;
+ base::SplitString(extra_chrome_flags, ' ', &flags);
+ for (size_t i = 0; i < flags.size(); ++i)
+ command_line->AppendArgNative(flags[i]);
+ }
+
+ // No default browser check, it would create an info-bar (if we are not the
+ // default browser) that could conflicts with some tests expectations.
+ command_line->AppendSwitch(switches::kNoDefaultBrowserCheck);
+
+ // This is a UI test.
+ command_line->AppendSwitchASCII(switches::kTestType, kUITestType);
+
+ // Tell the browser to use a temporary directory just for this test.
+ command_line->AppendSwitchPath(switches::kUserDataDir, user_data_dir());
+
+ if (include_testing_id)
+ command_line->AppendSwitchASCII(switches::kTestingChannelID,
+ PrefixedChannelID());
+
+ if (!show_error_dialogs_ &&
+ !CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableErrorDialogs)) {
+ command_line->AppendSwitch(switches::kNoErrorDialogs);
+ }
+ if (in_process_renderer_)
+ command_line->AppendSwitch(switches::kSingleProcess);
+ if (no_sandbox_)
+ command_line->AppendSwitch(switches::kNoSandbox);
+ if (full_memory_dump_)
+ command_line->AppendSwitch(switches::kFullMemoryCrashReport);
+ if (safe_plugins_)
+ command_line->AppendSwitch(switches::kSafePlugins);
+ if (enable_dcheck_)
+ command_line->AppendSwitch(switches::kEnableDCHECK);
+ if (silent_dump_on_dcheck_)
+ command_line->AppendSwitch(switches::kSilentDumpOnDCHECK);
+ if (disable_breakpad_)
+ command_line->AppendSwitch(switches::kDisableBreakpad);
+
+ if (!js_flags_.empty())
+ command_line->AppendSwitchASCII(switches::kJavaScriptFlags, js_flags_);
+ if (!log_level_.empty())
+ command_line->AppendSwitchASCII(switches::kLoggingLevel, log_level_);
+
+ command_line->AppendSwitch(switches::kMetricsRecordingOnly);
+
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableErrorDialogs))
+ command_line->AppendSwitch(switches::kEnableLogging);
+
+ if (dump_histograms_on_exit_)
+ command_line->AppendSwitch(switches::kDumpHistogramsOnExit);
+
+#ifdef WAIT_FOR_DEBUGGER_ON_OPEN
+ command_line->AppendSwitch(switches::kDebugOnStart);
+#endif
+
+ // The tests assume that file:// URIs can freely access other file:// URIs.
+ command_line->AppendSwitch(switches::kAllowFileAccessFromFiles);
+
+ // Disable TabCloseableStateWatcher for tests.
+ command_line->AppendSwitch(switches::kDisableTabCloseableStateWatcher);
+
+ // Allow file:// access on ChromeOS.
+ command_line->AppendSwitch(switches::kAllowFileAccess);
+}
+
+bool ProxyLauncher::LaunchBrowserHelper(const LaunchState& state, bool wait,
+ base::ProcessHandle* process) {
+ FilePath command = state.browser_directory.Append(
+ chrome::kBrowserProcessExecutablePath);
+
+ CommandLine command_line(command);
+
+ // Add command line arguments that should be applied to all UI tests.
+ PrepareTestCommandline(&command_line, state.include_testing_id);
+ DebugFlags::ProcessDebugFlags(
+ &command_line, ChildProcessInfo::UNKNOWN_PROCESS, false);
+ command_line.AppendArguments(state.arguments, false);
+
+ // TODO(phajdan.jr): Only run it for "main" browser launch.
+ browser_launch_time_ = base::TimeTicks::Now();
+
+#if defined(OS_WIN)
+ bool started = base::LaunchApp(command_line, wait,
+ !state.show_window, process);
+#elif defined(OS_POSIX)
+ // Sometimes one needs to run the browser under a special environment
+ // (e.g. valgrind) without also running the test harness (e.g. python)
+ // under the special environment. Provide a way to wrap the browser
+ // commandline with a special prefix to invoke the special environment.
+ const char* browser_wrapper = getenv("BROWSER_WRAPPER");
+ if (browser_wrapper) {
+ command_line.PrependWrapper(browser_wrapper);
+ VLOG(1) << "BROWSER_WRAPPER was set, prefixing command_line with "
+ << browser_wrapper;
+ }
+
+ base::file_handle_mapping_vector fds;
+ if (automation_proxy_.get())
+ fds = automation_proxy_->fds_to_map();
+
+ bool started = base::LaunchApp(command_line.argv(), fds, wait, process);
+#endif
+
+ return started;
+}
+
+AutomationProxy* ProxyLauncher::automation() const {
+ EXPECT_TRUE(automation_proxy_.get());
+ return automation_proxy_.get();
+}
+
+FilePath ProxyLauncher::user_data_dir() const {
+ EXPECT_TRUE(temp_profile_dir_.IsValid());
+ return temp_profile_dir_.path();
+}
+
+base::ProcessHandle ProxyLauncher::process() const {
+ return process_;
+}
+
+base::ProcessId ProxyLauncher::process_id() const {
+ return process_id_;
+}
+
+base::TimeTicks ProxyLauncher::browser_launch_time() const {
+ return browser_launch_time_;
+}
+
+base::TimeDelta ProxyLauncher::browser_quit_time() const {
+ return browser_quit_time_;
+}
// NamedProxyLauncher functions
@@ -30,10 +498,11 @@ AutomationProxy* NamedProxyLauncher::CreateAutomationProxy(
return proxy;
}
-void NamedProxyLauncher::InitializeConnection(UITestBase* ui_test_base) const {
+void NamedProxyLauncher::InitializeConnection(const LaunchState& state,
+ bool wait_for_initial_loads) {
if (launch_browser_) {
// Set up IPC testing interface as a client.
- ui_test_base->LaunchBrowser();
+ LaunchBrowser(state);
// Wait for browser to be ready for connections.
struct stat file_info;
@@ -41,7 +510,7 @@ void NamedProxyLauncher::InitializeConnection(UITestBase* ui_test_base) const {
base::PlatformThread::Sleep(automation::kSleepTime);
}
- ui_test_base->ConnectToRunningBrowser();
+ ConnectToRunningBrowser(wait_for_initial_loads);
}
std::string NamedProxyLauncher::PrefixedChannelID() const {
@@ -65,12 +534,11 @@ AutomationProxy* AnonymousProxyLauncher::CreateAutomationProxy(
return proxy;
}
-void AnonymousProxyLauncher::InitializeConnection(
- UITestBase* ui_test_base) const {
- ui_test_base->LaunchBrowserAndServer();
+void AnonymousProxyLauncher::InitializeConnection(const LaunchState& state,
+ bool wait_for_initial_loads) {
+ LaunchBrowserAndServer(state, wait_for_initial_loads);
}
std::string AnonymousProxyLauncher::PrefixedChannelID() const {
return channel_id_;
}
-
diff --git a/chrome/test/automation/proxy_launcher.h b/chrome/test/automation/proxy_launcher.h
index 0f4d04d..497d376 100644
--- a/chrome/test/automation/proxy_launcher.h
+++ b/chrome/test/automation/proxy_launcher.h
@@ -8,30 +8,284 @@
#include <string>
#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/process.h"
+#include "base/scoped_ptr.h"
+#include "base/scoped_temp_dir.h"
+#include "base/time.h"
class AutomationProxy;
-class UITestBase;
-// Subclass from this class to use a different implementation of AutomationProxy
-// or to use different channel IDs inside a class that derives from UITest.
+// Base class for all ProxyLauncher implementations. Contains functionality
+// fo launching, terminating, and connecting tests to browser processes. This
+// class determines which AutomationProxy implementation is used by a test.
+// Command line arguments passed to the browser are set in this class.
+//
+// Subclass from this class to use a different AutomationProxy
+// implementation or to override browser launching behavior.
class ProxyLauncher {
public:
- ProxyLauncher() {}
- virtual ~ProxyLauncher() {}
+ // Profile theme type choices.
+ enum ProfileType {
+ DEFAULT_THEME = 0,
+ COMPLEX_THEME = 1,
+ NATIVE_THEME = 2,
+ CUSTOM_FRAME = 3,
+ CUSTOM_FRAME_NATIVE_THEME = 4,
+ };
+
+ // Different ways to quit the browser.
+ enum ShutdownType {
+ WINDOW_CLOSE,
+ USER_QUIT,
+ SESSION_ENDING,
+ };
+
+ // POD containing state variables that determine how to launch browser.
+ typedef struct {
+ // If true the profile is cleared before launching.
+ bool clear_profile;
+
+ // If set, the profiles in this path are copied
+ // into the user data directory for the test.
+ FilePath& template_user_data;
+
+ // Profile theme type.
+ ProfileType profile_type;
+
+ // Path to the browser executable.
+ FilePath browser_directory;
+
+ // Command line arguments passed to the browser.
+ CommandLine& arguments;
+
+ // Should we supply the testing channel id on the command line?
+ bool include_testing_id;
+
+ // If true, the window is shown. Otherwise it is hidden.
+ bool show_window;
+ } LaunchState;
+
+ ProxyLauncher();
+
+ virtual ~ProxyLauncher();
// Creates an automation proxy.
virtual AutomationProxy* CreateAutomationProxy(
int execution_timeout) = 0;
- // Launches the browser if needed and establishes a connection
- // connection with it using the specified UITestBase.
- virtual void InitializeConnection(UITestBase* ui_test_base) const = 0;
+ // Launches the browser if needed and establishes a connection with it.
+ virtual void InitializeConnection(const LaunchState& state,
+ bool wait_for_initial_loads) = 0;
// Returns the automation proxy's channel with any prefixes prepended,
// for passing as a command line parameter over to the browser.
virtual std::string PrefixedChannelID() const = 0;
+ // Launches the browser and IPC testing connection in server mode.
+ void LaunchBrowserAndServer(const LaunchState& state,
+ bool wait_for_initial_loads);
+
+ // Launches the IPC testing connection in client mode,
+ // which then attempts to connect to a browser.
+ void ConnectToRunningBrowser(bool wait_for_initial_loads);
+
+ // Only for pyauto.
+ void set_command_execution_timeout_ms(int timeout);
+
+ // Closes the browser and IPC testing server.
+ void CloseBrowserAndServer(ShutdownType shutdown_type);
+
+ // Launches the browser with the given command line.
+ // TODO(phajdan.jr): Make LaunchBrowser private. Tests should use
+ // LaunchAnotherBrowserBlockUntilClosed.
+ void LaunchBrowser(const LaunchState& state);
+
+#if !defined(OS_MACOSX)
+ // This function is not defined on the Mac because the concept
+ // doesn't apply to Mac; you can't have N browser processes.
+
+ // Launches another browser process and waits for it to finish.
+ // Returns true on success.
+ bool LaunchAnotherBrowserBlockUntilClosed(const LaunchState& state);
+#endif
+
+ // Exits out of browser instance.
+ void QuitBrowser(ShutdownType shutdown_type);
+
+ // Terminates the browser, simulates end of session.
+ void TerminateBrowser();
+
+ // Check that no processes related to Chrome exist, displaying
+ // the given message if any do.
+ void AssertAppNotRunning(const std::wstring& error_message);
+
+ // Returns true when the browser process is running, independent if any
+ // renderer process exists or not. It will returns false if an user closed the
+ // window or if the browser process died by itself.
+ bool IsBrowserRunning();
+
+ // Returns true when timeout_ms milliseconds have elapsed.
+ // Returns false if the browser process died while waiting.
+ bool CrashAwareSleep(int timeout_ms);
+
+ // Wait for the browser process to shut down on its own (i.e. as a result of
+ // some action that your test has taken).
+ bool WaitForBrowserProcessToQuit(int timeout);
+
+ AutomationProxy* automation() const;
+
+ // Return the user data directory being used by the browser instance.
+ FilePath user_data_dir() const;
+
+ // Get the handle of browser process connected to the automation. This
+ // function only returns a reference to the handle so the caller does not
+ // own the handle returned.
+ base::ProcessHandle process() const;
+
+ // Return the process id of the browser process (-1 on error).
+ base::ProcessId process_id() const;
+
+ // Return the time when the browser was run.
+ base::TimeTicks browser_launch_time() const;
+
+ // Return how long the shutdown took.
+ base::TimeDelta browser_quit_time() const;
+
+ // Get/Set a flag to run the renderer in-process when running the tests.
+ static bool in_process_renderer() { return in_process_renderer_; }
+ static void set_in_process_renderer(bool value) {
+ in_process_renderer_ = value;
+ }
+
+ // Get/Set a flag to run the renderer outside the sandbox when running tests.
+ static bool no_sandbox() { return no_sandbox_; }
+ static void set_no_sandbox(bool value) {
+ no_sandbox_ = value;
+ }
+
+ // Get/Set a flag to run with DCHECKs enabled in release.
+ static bool enable_dcheck() { return enable_dcheck_; }
+ static void set_enable_dcheck(bool value) {
+ enable_dcheck_ = value;
+ }
+
+ // Get/Set a flag to dump the process memory without crashing on DCHECKs.
+ static bool silent_dump_on_dcheck() { return silent_dump_on_dcheck_; }
+ static void set_silent_dump_on_dcheck(bool value) {
+ silent_dump_on_dcheck_ = value;
+ }
+
+ // Get/Set a flag to disable breakpad handling.
+ static bool disable_breakpad() { return disable_breakpad_; }
+ static void set_disable_breakpad(bool value) {
+ disable_breakpad_ = value;
+ }
+
+ // Get/Set a flag to run the plugin processes inside the sandbox when running
+ // the tests
+ static bool safe_plugins() { return safe_plugins_; }
+ static void set_safe_plugins(bool value) {
+ safe_plugins_ = value;
+ }
+
+ static bool show_error_dialogs() { return show_error_dialogs_; }
+ static void set_show_error_dialogs(bool value) {
+ show_error_dialogs_ = value;
+ }
+
+ static bool full_memory_dump() { return full_memory_dump_; }
+ static void set_full_memory_dump(bool value) {
+ full_memory_dump_ = value;
+ }
+
+ static bool dump_histograms_on_exit() { return dump_histograms_on_exit_; }
+ static void set_dump_histograms_on_exit(bool value) {
+ dump_histograms_on_exit_ = value;
+ }
+
+ static const std::string& js_flags() { return js_flags_; }
+ static void set_js_flags(const std::string& value) {
+ js_flags_ = value;
+ }
+
+ static const std::string& log_level() { return log_level_; }
+ static void set_log_level(const std::string& value) {
+ log_level_ = value;
+ }
+
+ protected:
+ virtual bool ShouldFilterInet() {
+ return true;
+ }
+
private:
+ void WaitForBrowserLaunch(bool wait_for_initial_loads);
+
+ // Prepare command line that will be used to launch the child browser process.
+ void PrepareTestCommandline(CommandLine* command_line,
+ bool include_testing_id);
+
+ bool LaunchBrowserHelper(const LaunchState& state, bool wait,
+ base::ProcessHandle* process);
+
+ // Wait a certain amount of time for all the app processes to exit,
+ // forcibly killing them if they haven't exited by then.
+ // It has the side-effect of killing every browser window opened in your
+ // session, even those unrelated in the test.
+ void CleanupAppProcesses();
+
+ scoped_ptr<AutomationProxy> automation_proxy_;
+
+ // We use a temporary directory for profile to avoid issues with being
+ // unable to delete some files because they're in use, etc.
+ ScopedTempDir temp_profile_dir_;
+
+ // Handle to the first Chrome process.
+ base::ProcessHandle process_;
+
+ // PID of |process_| (for debugging).
+ base::ProcessId process_id_;
+
+ // Time when the browser was run.
+ base::TimeTicks browser_launch_time_;
+
+ // How long the shutdown took.
+ base::TimeDelta browser_quit_time_;
+
+ // True if we're in single process mode.
+ static bool in_process_renderer_;
+
+ // If true, runs the renderer outside the sandbox.
+ static bool no_sandbox_;
+
+ // If true, runs plugin processes inside the sandbox.
+ static bool safe_plugins_;
+
+ // If true, write full memory dump during crash.
+ static bool full_memory_dump_;
+
+ // If true, a user is paying attention to the test, so show error dialogs.
+ static bool show_error_dialogs_;
+
+ // Include histograms in log on exit.
+ static bool dump_histograms_on_exit_;
+
+ // Enable dchecks in release mode.
+ static bool enable_dcheck_;
+
+ // Dump process memory on dcheck without crashing.
+ static bool silent_dump_on_dcheck_;
+
+ // Disable breakpad on the browser.
+ static bool disable_breakpad_;
+
+ // Flags passed to the JS engine.
+ static std::string js_flags_;
+
+ // Logging level.
+ static std::string log_level_;
+
DISALLOW_COPY_AND_ASSIGN(ProxyLauncher);
};
@@ -46,7 +300,8 @@ class NamedProxyLauncher : public ProxyLauncher {
NamedProxyLauncher(bool launch_browser, bool disconnect_on_failure);
virtual AutomationProxy* CreateAutomationProxy(int execution_timeout);
- virtual void InitializeConnection(UITestBase* ui_test_base) const;
+ virtual void InitializeConnection(const LaunchState& state,
+ bool wait_for_initial_loads);
virtual std::string PrefixedChannelID() const;
protected:
@@ -63,7 +318,8 @@ class AnonymousProxyLauncher : public ProxyLauncher {
public:
explicit AnonymousProxyLauncher(bool disconnect_on_failure);
virtual AutomationProxy* CreateAutomationProxy(int execution_timeout);
- virtual void InitializeConnection(UITestBase* ui_test_base) const;
+ virtual void InitializeConnection(const LaunchState& state,
+ bool wait_for_initial_loads);
virtual std::string PrefixedChannelID() const;
protected:
@@ -75,4 +331,3 @@ class AnonymousProxyLauncher : public ProxyLauncher {
};
#endif // CHROME_TEST_AUTOMATION_PROXY_LAUNCHER_H_
-