summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/automation/automation_provider.cc63
-rw-r--r--chrome/browser/automation/automation_provider.h24
-rw-r--r--chrome/browser/automation/automation_provider_observers.cc2
-rw-r--r--chrome/browser/ui/browser_init.cc23
-rw-r--r--chrome/browser/ui/browser_init.h2
-rw-r--r--chrome/chrome_tests.gypi9
-rw-r--r--chrome/common/automation_constants.cc9
-rw-r--r--chrome/common/automation_constants.h10
-rw-r--r--chrome/test/automation/automation_proxy.cc14
-rw-r--r--chrome/test/automation/automation_proxy.h18
-rw-r--r--chrome/test/automation/automation_proxy_uitest.cc35
-rw-r--r--chrome/test/automation/automation_proxy_uitest.h7
-rw-r--r--chrome/test/automation/proxy_launcher.cc75
-rw-r--r--chrome/test/automation/proxy_launcher.h78
-rw-r--r--chrome/test/ui/named_interface_uitest.cc42
-rw-r--r--chrome/test/ui/ui_test.cc60
-rw-r--r--chrome/test/ui/ui_test.h27
-rw-r--r--chrome_frame/chrome_frame.gyp6
-rw-r--r--chrome_frame/chrome_frame_automation.cc11
-rw-r--r--chrome_frame/chrome_frame_automation.h1
-rw-r--r--chrome_frame/test/automation_client_mock.cc4
-rw-r--r--chrome_frame/test/net/test_automation_provider.cc2
-rw-r--r--ipc/ipc_channel.h4
-rw-r--r--ipc/ipc_channel_posix.cc16
24 files changed, 449 insertions, 93 deletions
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc
index ec48e7a..65dc5a3 100644
--- a/chrome/browser/automation/automation_provider.cc
+++ b/chrome/browser/automation/automation_provider.cc
@@ -113,7 +113,9 @@ using base::Time;
AutomationProvider::AutomationProvider(Profile* profile)
: profile_(profile),
- reply_message_(NULL) {
+ reply_message_(NULL),
+ is_connected_(false),
+ initial_loads_complete_(false) {
TRACE_EVENT_BEGIN("AutomationProvider::AutomationProvider", 0, "");
browser_tracker_.reset(new AutomationBrowserTracker(this));
@@ -149,23 +151,38 @@ AutomationProvider::~AutomationProvider() {
g_browser_process->ReleaseModule();
}
-void AutomationProvider::ConnectToChannel(const std::string& channel_id) {
- TRACE_EVENT_BEGIN("AutomationProvider::ConnectToChannel", 0, "");
+bool AutomationProvider::InitializeChannel(const std::string& channel_id) {
+ TRACE_EVENT_BEGIN("AutomationProvider::InitializeChannel", 0, "");
+
+ std::string effective_channel_id = channel_id;
+
+ // If the channel_id starts with kNamedInterfacePrefix, create a named IPC
+ // server and listen on it, else connect as client to an existing IPC server
+ bool use_named_interface =
+ channel_id.find(automation::kNamedInterfacePrefix) == 0;
+ if (use_named_interface) {
+ effective_channel_id = channel_id.substr(
+ strlen(automation::kNamedInterfacePrefix));
+ if (effective_channel_id.length() <= 0)
+ return false;
+ }
if (!automation_resource_message_filter_.get()) {
automation_resource_message_filter_ = new AutomationResourceMessageFilter;
}
- channel_.reset(
- new IPC::SyncChannel(channel_id, IPC::Channel::MODE_CLIENT, this,
- automation_resource_message_filter_,
- g_browser_process->io_thread()->message_loop(),
- true, g_browser_process->shutdown_event()));
+ channel_.reset(new IPC::SyncChannel(
+ effective_channel_id,
+ use_named_interface ? IPC::Channel::MODE_NAMED_SERVER
+ : IPC::Channel::MODE_CLIENT,
+ this,
+ automation_resource_message_filter_,
+ g_browser_process->io_thread()->message_loop(),
+ true, g_browser_process->shutdown_event()));
- // Send a hello message with our current automation protocol version.
- channel_->Send(new AutomationMsg_Hello(0, GetProtocolVersion().c_str()));
+ TRACE_EVENT_END("AutomationProvider::InitializeChannel", 0, "");
- TRACE_EVENT_END("AutomationProvider::ConnectToChannel", 0, "");
+ return true;
}
std::string AutomationProvider::GetProtocolVersion() {
@@ -174,11 +191,16 @@ std::string AutomationProvider::GetProtocolVersion() {
}
void AutomationProvider::SetExpectedTabCount(size_t expected_tabs) {
- if (expected_tabs == 0) {
- Send(new AutomationMsg_InitialLoadsComplete(0));
- } else {
+ if (expected_tabs == 0)
+ OnInitialLoadsComplete();
+ else
initial_load_observer_.reset(new InitialLoadObserver(expected_tabs, this));
- }
+}
+
+void AutomationProvider::OnInitialLoadsComplete() {
+ initial_loads_complete_ = true;
+ if (is_connected_)
+ Send(new AutomationMsg_InitialLoadsComplete(0));
}
NotificationObserver* AutomationProvider::AddNavigationStatusListener(
@@ -327,6 +349,17 @@ const Extension* AutomationProvider::GetDisabledExtension(
return NULL;
}
+void AutomationProvider::OnChannelConnected(int pid) {
+ is_connected_ = true;
+ LOG(INFO) << "Testing channel connected, sending hello message";
+
+ // Send a hello message with our current automation protocol version.
+ chrome::VersionInfo version_info;
+ channel_->Send(new AutomationMsg_Hello(0, version_info.Version()));
+ if (initial_loads_complete_)
+ Send(new AutomationMsg_InitialLoadsComplete(0));
+}
+
void AutomationProvider::OnMessageReceived(const IPC::Message& message) {
IPC_BEGIN_MESSAGE_MAP(AutomationProvider, message)
#if !defined(OS_MACOSX)
diff --git a/chrome/browser/automation/automation_provider.h b/chrome/browser/automation/automation_provider.h
index 0da77a1..c30fb97 100644
--- a/chrome/browser/automation/automation_provider.h
+++ b/chrome/browser/automation/automation_provider.h
@@ -17,6 +17,7 @@
#include <vector>
#include "base/basictypes.h"
+#include "base/compiler_specific.h"
#include "base/observer_list.h"
#include "base/scoped_ptr.h"
#include "base/string16.h"
@@ -82,15 +83,23 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>,
Profile* profile() const { return profile_; }
- // Establishes a connection to an automation client, if present.
- // An AutomationProxy should be established (probably in a different process)
- // before calling this.
- void ConnectToChannel(const std::string& channel_id);
+ // Initializes a channel for a connection to an AutomationProxy.
+ // If channel_id starts with kNamedInterfacePrefix, it will act
+ // as a server, create a named IPC socket with channel_id as its
+ // path, and will listen on the socket for incoming connections.
+ // If channel_id does not, it will act as a client and establish
+ // a connection on its primary IPC channel. See ipc/ipc_channel_posix.cc
+ // for more information about kPrimaryIPCChannel.
+ bool InitializeChannel(const std::string& channel_id) WARN_UNUSED_RESULT;
// Sets the number of tabs that we expect; when this number of tabs has
// loaded, an AutomationMsg_InitialLoadsComplete message is sent.
void SetExpectedTabCount(size_t expected_tabs);
+ // Called when the inital set of tabs has finished loading.
+ // Call SetExpectedTabCount(0) to set this to true immediately.
+ void OnInitialLoadsComplete();
+
// Add a listener for navigation status notification. Currently only
// navigation completion is observed; when the |number_of_navigations|
// complete, the completed_response object is sent; if the server requires
@@ -138,6 +147,7 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>,
// IPC implementations
virtual bool Send(IPC::Message* msg);
+ virtual void OnChannelConnected(int pid);
virtual void OnMessageReceived(const IPC::Message& msg);
virtual void OnChannelError();
@@ -406,6 +416,12 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>,
scoped_ptr<AutomationExtensionTracker> extension_tracker_;
PortContainerMap port_containers_;
+ // True iff connected to an AutomationProxy.
+ bool is_connected_;
+
+ // True iff browser finished loading initial set of tabs.
+ bool initial_loads_complete_;
+
DISALLOW_COPY_AND_ASSIGN(AutomationProvider);
};
diff --git a/chrome/browser/automation/automation_provider_observers.cc b/chrome/browser/automation/automation_provider_observers.cc
index 0bdb00d..779b6eb 100644
--- a/chrome/browser/automation/automation_provider_observers.cc
+++ b/chrome/browser/automation/automation_provider_observers.cc
@@ -140,7 +140,7 @@ DictionaryValue* InitialLoadObserver::GetTimingInformation() const {
void InitialLoadObserver::ConditionMet() {
registrar_.RemoveAll();
- automation_->Send(new AutomationMsg_InitialLoadsComplete(0));
+ automation_->OnInitialLoadsComplete();
}
NewTabUILoadObserver::NewTabUILoadObserver(AutomationProvider* automation)
diff --git a/chrome/browser/ui/browser_init.cc b/chrome/browser/ui/browser_init.cc
index d4b0d5d..e0a7ff5 100644
--- a/chrome/browser/ui/browser_init.cc
+++ b/chrome/browser/ui/browser_init.cc
@@ -973,10 +973,11 @@ bool BrowserInit::ProcessCmdLineImpl(const CommandLine& command_line,
expected_tab_count =
std::max(1, static_cast<int>(command_line.args().size()));
}
- CreateAutomationProvider<TestingAutomationProvider>(
+ if (!CreateAutomationProvider<TestingAutomationProvider>(
testing_channel_id,
profile,
- static_cast<size_t>(expected_tab_count));
+ static_cast<size_t>(expected_tab_count)))
+ return false;
}
}
@@ -993,11 +994,13 @@ bool BrowserInit::ProcessCmdLineImpl(const CommandLine& command_line,
silent_launch = true;
if (command_line.HasSwitch(switches::kChromeFrame)) {
- CreateAutomationProvider<ChromeFrameAutomationProvider>(
- automation_channel_id, profile, expected_tabs);
+ if (!CreateAutomationProvider<ChromeFrameAutomationProvider>(
+ automation_channel_id, profile, expected_tabs))
+ return false;
} else {
- CreateAutomationProvider<AutomationProvider>(automation_channel_id,
- profile, expected_tabs);
+ if (!CreateAutomationProvider<AutomationProvider>(
+ automation_channel_id, profile, expected_tabs))
+ return false;
}
}
@@ -1056,16 +1059,20 @@ bool BrowserInit::ProcessCmdLineImpl(const CommandLine& command_line,
}
template <class AutomationProviderClass>
-void BrowserInit::CreateAutomationProvider(const std::string& channel_id,
+bool BrowserInit::CreateAutomationProvider(const std::string& channel_id,
Profile* profile,
size_t expected_tabs) {
scoped_refptr<AutomationProviderClass> automation =
new AutomationProviderClass(profile);
- automation->ConnectToChannel(channel_id);
+
+ if (!automation->InitializeChannel(channel_id))
+ return false;
automation->SetExpectedTabCount(expected_tabs);
AutomationProviderList* list =
g_browser_process->InitAutomationProviderList();
DCHECK(list);
list->AddProvider(automation);
+
+ return true;
}
diff --git a/chrome/browser/ui/browser_init.h b/chrome/browser/ui/browser_init.h
index 07e99e9..746320c 100644
--- a/chrome/browser/ui/browser_init.h
+++ b/chrome/browser/ui/browser_init.h
@@ -53,7 +53,7 @@ class BrowserInit {
}
template <class AutomationProviderClass>
- static void CreateAutomationProvider(const std::string& channel_id,
+ static bool CreateAutomationProvider(const std::string& channel_id,
Profile* profile,
size_t expected_tabs);
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index bdd161a..03347f5 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -168,6 +168,8 @@
'sources': [
'test/automated_ui_tests/automated_ui_test_base.cc',
'test/automated_ui_tests/automated_ui_test_base.h',
+ 'test/automation/proxy_launcher.cc',
+ 'test/automation/proxy_launcher.h',
'test/testing_browser_process.h',
'test/ui/javascript_test_util.cc',
'test/ui/npapi_test_helper.cc',
@@ -515,6 +517,7 @@
'test/ui/dromaeo_benchmark_uitest.cc',
'test/ui/history_uitest.cc',
'test/ui/layout_plugin_uitest.cc',
+ 'test/ui/named_interface_uitest.cc',
'test/ui/npapi_uitest.cc',
'test/ui/omnibox_uitest.cc',
'test/ui/pepper_uitest.cc',
@@ -600,6 +603,10 @@
},
},
},
+ 'sources!': [
+ # TODO(dtu): port to windows http://crosbug.com/8515
+ 'test/ui/named_interface_uitest.cc',
+ ],
}, { # else: OS != "win"
'sources!': [
# TODO(port): http://crbug.com/45770
@@ -3109,6 +3116,8 @@
'-Wno-uninitialized',
],
'sources': [
+ 'test/automation/proxy_launcher.cc',
+ 'test/automation/proxy_launcher.h',
'test/pyautolib/pyautolib.cc',
'test/pyautolib/pyautolib.h',
'test/ui/ui_test.cc',
diff --git a/chrome/common/automation_constants.cc b/chrome/common/automation_constants.cc
index c253871..9480254 100644
--- a/chrome/common/automation_constants.cc
+++ b/chrome/common/automation_constants.cc
@@ -5,6 +5,7 @@
#include "chrome/common/automation_constants.h"
namespace automation {
+
// JSON value labels for proxy settings that are passed in via
// AutomationMsg_SetProxyConfig.
const char kJSONProxyAutoconfig[] = "proxy.autoconfig";
@@ -12,4 +13,10 @@ const char kJSONProxyNoProxy[] = "proxy.no_proxy";
const char kJSONProxyPacUrl[] = "proxy.pac_url";
const char kJSONProxyBypassList[] = "proxy.bypass_list";
const char kJSONProxyServer[] = "proxy.server";
-}
+
+// Named testing interface is used when you want to connect an
+// AutomationProxy to an already-running browser instance.
+const char kNamedInterfacePrefix[] = "NamedTestingInterface:";
+
+} // namespace automation
+
diff --git a/chrome/common/automation_constants.h b/chrome/common/automation_constants.h
index 13b120e..6579776 100644
--- a/chrome/common/automation_constants.h
+++ b/chrome/common/automation_constants.h
@@ -7,6 +7,7 @@
#pragma once
namespace automation {
+
// JSON value labels for proxy settings that are passed in via
// AutomationMsg_SetProxyConfig. These are here since they are used by both
// AutomationProvider and AutomationProxy.
@@ -16,9 +17,16 @@ extern const char kJSONProxyPacUrl[];
extern const char kJSONProxyBypassList[];
extern const char kJSONProxyServer[];
+// When passing the kTestingChannelID switch to the browser, prepend
+// this prefix to the channel id to enable the named testing interface.
+// Named testing interface is used when you want to connect an
+// AutomationProxy to an already-running browser instance.
+extern const char kNamedInterfacePrefix[];
+
// Amount of time to wait before querying the browser.
static const int kSleepTime = 250;
-}
+
+} // namespace automation
// Used by AutomationProxy, declared here so that other headers don't need
// to include automation_proxy.h.
diff --git a/chrome/test/automation/automation_proxy.cc b/chrome/test/automation/automation_proxy.cc
index fbdde25..a33f095 100644
--- a/chrome/test/automation/automation_proxy.cc
+++ b/chrome/test/automation/automation_proxy.cc
@@ -107,10 +107,8 @@ AutomationProxy::AutomationProxy(int command_execution_timeout_ms,
// least it is legal... ;-)
DCHECK_GE(command_execution_timeout_ms, 0);
listener_thread_id_ = PlatformThread::CurrentId();
- InitializeChannelID();
InitializeHandleTracker();
InitializeThread();
- InitializeChannel();
}
AutomationProxy::~AutomationProxy() {
@@ -122,7 +120,7 @@ AutomationProxy::~AutomationProxy() {
tracker_.reset();
}
-void AutomationProxy::InitializeChannelID() {
+std::string AutomationProxy::GenerateChannelID() {
// The channel counter keeps us out of trouble if we create and destroy
// several AutomationProxies sequentially over the course of a test run.
// (Creating the channel sometimes failed before when running a lot of
@@ -133,7 +131,7 @@ void AutomationProxy::InitializeChannelID() {
std::ostringstream buf;
buf << "ChromeTestingInterface:" << base::GetCurrentProcId() <<
"." << ++channel_counter;
- channel_id_ = buf.str();
+ return buf.str();
}
void AutomationProxy::InitializeThread() {
@@ -146,7 +144,8 @@ void AutomationProxy::InitializeThread() {
thread_.swap(thread);
}
-void AutomationProxy::InitializeChannel() {
+void AutomationProxy::InitializeChannel(const std::string& channel_id,
+ bool use_named_interface) {
DCHECK(shutdown_event_.get() != NULL);
// TODO(iyengar)
@@ -154,8 +153,9 @@ void AutomationProxy::InitializeChannel() {
// provider, where we use the shutdown event provided by the chrome browser
// process.
channel_.reset(new IPC::SyncChannel(
- channel_id_,
- IPC::Channel::MODE_SERVER,
+ channel_id,
+ use_named_interface ? IPC::Channel::MODE_NAMED_CLIENT
+ : IPC::Channel::MODE_SERVER,
this, // we are the listener
new AutomationMessageFilter(this),
thread_->message_loop(),
diff --git a/chrome/test/automation/automation_proxy.h b/chrome/test/automation/automation_proxy.h
index 853a6d3..7902ef0 100644
--- a/chrome/test/automation/automation_proxy.h
+++ b/chrome/test/automation/automation_proxy.h
@@ -61,6 +61,17 @@ class AutomationProxy : public IPC::Channel::Listener,
AutomationProxy(int command_execution_timeout_ms, bool disconnect_on_failure);
virtual ~AutomationProxy();
+ // Creates a previously unused channel id.
+ static std::string GenerateChannelID();
+
+ // Initializes a channel for a connection to an AutomationProvider.
+ // If use_named_interface is false, it will act as a client
+ // and connect to the named IPC socket with channel_id as its path.
+ // If use_named_interface is true, it will act as a server and
+ // use an anonymous socketpair instead.
+ void InitializeChannel(const std::string& channel_id,
+ bool use_named_interface);
+
// IPC callback
virtual void OnMessageReceived(const IPC::Message& msg);
virtual void OnChannelError();
@@ -208,10 +219,6 @@ class AutomationProxy : public IPC::Channel::Listener,
const std::string& password) WARN_UNUSED_RESULT;
#endif
- // Returns the ID of the automation IPC channel, so that it can be
- // passed to the app as a launch parameter.
- const std::string& channel_id() const { return channel_id_; }
-
#if defined(OS_POSIX)
base::file_handle_mapping_vector fds_to_map() const;
#endif
@@ -263,12 +270,9 @@ class AutomationProxy : public IPC::Channel::Listener,
protected:
template <class T> scoped_refptr<T> ProxyObjectFromHandle(int handle);
- void InitializeChannelID();
void InitializeThread();
- void InitializeChannel();
void InitializeHandleTracker();
- std::string channel_id_;
scoped_ptr<base::Thread> thread_;
scoped_ptr<IPC::SyncChannel> channel_;
scoped_ptr<AutomationHandleTracker> tracker_;
diff --git a/chrome/test/automation/automation_proxy_uitest.cc b/chrome/test/automation/automation_proxy_uitest.cc
index db6a18e4..f96de59 100644
--- a/chrome/test/automation/automation_proxy_uitest.cc
+++ b/chrome/test/automation/automation_proxy_uitest.cc
@@ -29,6 +29,7 @@
#include "chrome/test/automation/autocomplete_edit_proxy.h"
#include "chrome/test/automation/automation_proxy_uitest.h"
#include "chrome/test/automation/browser_proxy.h"
+#include "chrome/test/automation/proxy_launcher.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/automation/window_proxy.h"
#include "chrome/test/ui_test_utils.h"
@@ -47,6 +48,34 @@ using testing::CreateFunctor;
using testing::StrEq;
using testing::_;
+
+// Replace the default automation proxy with our mock client.
+class ExternalTabUITestMockLauncher : public ProxyLauncher {
+ public:
+ explicit ExternalTabUITestMockLauncher(ExternalTabUITestMockClient **mock)
+ : mock_(mock) {
+ channel_id_ = AutomationProxy::GenerateChannelID();
+ }
+
+ AutomationProxy* CreateAutomationProxy(int execution_timeout) {
+ *mock_ = new ExternalTabUITestMockClient(execution_timeout);
+ (*mock_)->InitializeChannel(channel_id_, false);
+ return *mock_;
+ }
+
+ void InitializeConnection(UITestBase* ui_test_base) const {
+ ui_test_base->LaunchBrowserAndServer();
+ }
+
+ std::string PrefixedChannelID() const {
+ return channel_id_;
+ }
+
+ private:
+ ExternalTabUITestMockClient **mock_;
+ std::string channel_id_; // Channel id of automation proxy.
+};
+
class AutomationProxyTest : public UITest {
protected:
AutomationProxyTest() {
@@ -841,9 +870,9 @@ template <typename T> T** ReceivePointer(scoped_refptr<T>& p) { // NOLINT
return reinterpret_cast<T**>(&p);
}
-AutomationProxy* ExternalTabUITest::CreateAutomationProxy(int exec_timeout) {
- mock_ = new ExternalTabUITestMockClient(exec_timeout);
- return mock_;
+// Replace the default automation proxy with our mock client.
+ProxyLauncher* ExternalTabUITest::CreateProxyLauncher() {
+ return new ExternalTabUITestMockLauncher(&mock_);
}
// Create with specifying a url
diff --git a/chrome/test/automation/automation_proxy_uitest.h b/chrome/test/automation/automation_proxy_uitest.h
index 55da8cc..4e6d095 100644
--- a/chrome/test/automation/automation_proxy_uitest.h
+++ b/chrome/test/automation/automation_proxy_uitest.h
@@ -112,16 +112,17 @@ class ExternalTabUITestMockClient : public AutomationProxy {
class ExternalTabUITest : public UITest {
public:
ExternalTabUITest() : UITest(MessageLoop::TYPE_UI) {}
- // Override UITest's CreateAutomationProxy to provide the unit test
+ // Override UITest's CreateProxyLauncher to provide the unit test
// with our special implementation of AutomationProxy.
- // This function is called from within UITest::LaunchBrowserAndServer.
- virtual AutomationProxy* CreateAutomationProxy(int execution_timeout);
+ // This function is called from within UITest::SetUp().
+ virtual ProxyLauncher* CreateProxyLauncher();
protected:
// Filtered Inet will override automation callbacks for network resources.
virtual bool ShouldFilterInet() {
return false;
}
ExternalTabUITestMockClient* mock_;
+ std::string channel_id_; // Channel id of automation proxy.
};
#endif // CHROME_TEST_AUTOMATION_AUTOMATION_PROXY_UITEST_H_
diff --git a/chrome/test/automation/proxy_launcher.cc b/chrome/test/automation/proxy_launcher.cc
new file mode 100644
index 0000000..2325958
--- /dev/null
+++ b/chrome/test/automation/proxy_launcher.cc
@@ -0,0 +1,75 @@
+// Copyright (c) 2010 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/automation/proxy_launcher.h"
+
+#include "chrome/common/automation_constants.h"
+#include "chrome/common/logging_chrome.h"
+#include "chrome/test/automation/automation_proxy.h"
+#include "chrome/test/ui/ui_test.h"
+
+// Default path of named testing interface.
+static const char kInterfacePath[] = "/var/tmp/ChromeTestingInterface";
+
+// NamedProxyLauncher functions
+
+NamedProxyLauncher::NamedProxyLauncher(bool launch_browser,
+ bool disconnect_on_failure)
+ : launch_browser_(launch_browser),
+ disconnect_on_failure_(disconnect_on_failure) {
+ channel_id_ = kInterfacePath;
+}
+
+AutomationProxy* NamedProxyLauncher::CreateAutomationProxy(
+ int execution_timeout) {
+ AutomationProxy* proxy = new AutomationProxy(execution_timeout,
+ disconnect_on_failure_);
+ proxy->InitializeChannel(channel_id_, true);
+ return proxy;
+}
+
+void NamedProxyLauncher::InitializeConnection(UITestBase* ui_test_base) const {
+ if (launch_browser_) {
+ // Set up IPC testing interface as a client.
+ ui_test_base->LaunchBrowser();
+
+ // Wait for browser to be ready for connections.
+ struct stat file_info;
+ while (stat(kInterfacePath, &file_info))
+ PlatformThread::Sleep(automation::kSleepTime);
+ }
+
+ ui_test_base->ConnectToRunningBrowser();
+}
+
+std::string NamedProxyLauncher::PrefixedChannelID() const {
+ std::string channel_id;
+ channel_id.append(automation::kNamedInterfacePrefix).append(channel_id_);
+ return channel_id;
+}
+
+// AnonymousProxyLauncher functions
+
+AnonymousProxyLauncher::AnonymousProxyLauncher(bool disconnect_on_failure)
+ : disconnect_on_failure_(disconnect_on_failure) {
+ channel_id_ = AutomationProxy::GenerateChannelID();
+}
+
+AutomationProxy* AnonymousProxyLauncher::CreateAutomationProxy(
+ int execution_timeout) {
+ AutomationProxy* proxy = new AutomationProxy(execution_timeout,
+ disconnect_on_failure_);
+ proxy->InitializeChannel(channel_id_, false);
+ return proxy;
+}
+
+void AnonymousProxyLauncher::InitializeConnection(
+ UITestBase* ui_test_base) const {
+ ui_test_base->LaunchBrowserAndServer();
+}
+
+std::string AnonymousProxyLauncher::PrefixedChannelID() const {
+ return channel_id_;
+}
+
diff --git a/chrome/test/automation/proxy_launcher.h b/chrome/test/automation/proxy_launcher.h
new file mode 100644
index 0000000..0f4d04d
--- /dev/null
+++ b/chrome/test/automation/proxy_launcher.h
@@ -0,0 +1,78 @@
+// Copyright (c) 2010 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_AUTOMATION_PROXY_LAUNCHER_H_
+#define CHROME_TEST_AUTOMATION_PROXY_LAUNCHER_H_
+
+#include <string>
+
+#include "base/basictypes.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.
+class ProxyLauncher {
+ public:
+ 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;
+
+ // 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;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ProxyLauncher);
+};
+
+// Uses an automation proxy that communicates over a named socket.
+// This is used if you want to connect an AutomationProxy
+// to a browser process that is already running.
+// The channel id of the proxy is a constant specified by kInterfacePath.
+class NamedProxyLauncher : public ProxyLauncher {
+ public:
+ // If launch_browser is true, launches Chrome with named interface enabled.
+ // Otherwise, there should be an existing instance the proxy can connect to.
+ NamedProxyLauncher(bool launch_browser, bool disconnect_on_failure);
+
+ virtual AutomationProxy* CreateAutomationProxy(int execution_timeout);
+ virtual void InitializeConnection(UITestBase* ui_test_base) const;
+ virtual std::string PrefixedChannelID() const;
+
+ protected:
+ std::string channel_id_; // Channel id of automation proxy.
+ bool launch_browser_; // True if we should launch the browser too.
+ bool disconnect_on_failure_; // True if we disconnect on IPC channel failure.
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NamedProxyLauncher);
+};
+
+// Uses an automation proxy that communicates over an anonymous socket.
+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 std::string PrefixedChannelID() const;
+
+ protected:
+ std::string channel_id_; // Channel id of automation proxy.
+ bool disconnect_on_failure_; // True if we disconnect on IPC channel failure.
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AnonymousProxyLauncher);
+};
+
+#endif // CHROME_TEST_AUTOMATION_PROXY_LAUNCHER_H_
+
diff --git a/chrome/test/ui/named_interface_uitest.cc b/chrome/test/ui/named_interface_uitest.cc
new file mode 100644
index 0000000..ee44820
--- /dev/null
+++ b/chrome/test/ui/named_interface_uitest.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2010 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/ui_test.h"
+
+#include "chrome/common/url_constants.h"
+#include "chrome/test/automation/proxy_launcher.h"
+
+// The named testing interface enables the use of a named socket for controlling
+// the browser. This eliminates the dependency that the browser must be forked
+// from the controlling process.
+namespace {
+
+class NamedInterfaceTest : public UITest {
+ public:
+ NamedInterfaceTest() {
+ show_window_ = true;
+ }
+
+ virtual ProxyLauncher *CreateProxyLauncher() {
+ return new NamedProxyLauncher(true, true);
+ }
+};
+
+// Basic sanity test for named testing interface which
+// launches a browser instance that uses a named socket, then
+// sends it some commands to open some tabs over that socket.
+TEST_F(NamedInterfaceTest, BasicNamedInterface) {
+ scoped_refptr<BrowserProxy> browser_proxy(
+ automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(browser_proxy.get());
+
+ for (int i = 0; i < 10; ++i)
+ ASSERT_TRUE(browser_proxy->AppendTab(GURL(chrome::kAboutBlankURL)));
+}
+
+// TODO(dtu): crosbug.com/8514: Write a test that makes sure you can disconnect,
+// then reconnect with a new connection and continue automation.
+
+} // namespace
+
diff --git a/chrome/test/ui/ui_test.cc b/chrome/test/ui/ui_test.cc
index 9fbb857..e6aff60 100644
--- a/chrome/test/ui/ui_test.cc
+++ b/chrome/test/ui/ui_test.cc
@@ -43,6 +43,7 @@
#include "chrome/test/automation/automation_proxy.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/javascript_execution_controller.h"
+#include "chrome/test/automation/proxy_launcher.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/automation/window_proxy.h"
#include "chrome/test/chrome_process_util.h"
@@ -140,7 +141,9 @@ void UITestBase::SetUp() {
JavaScriptExecutionController::set_timeout(
TestTimeouts::action_max_timeout_ms());
test_start_time_ = Time::NowFromSystemTime();
- LaunchBrowserAndServer();
+
+ launcher_.reset(CreateProxyLauncher());
+ launcher_->InitializeConnection(this);
}
void UITestBase::TearDown() {
@@ -175,24 +178,39 @@ void UITestBase::TearDown() {
// TODO(phajdan.jr): get rid of set_command_execution_timeout_ms.
void UITestBase::set_command_execution_timeout_ms(int timeout) {
- server_->set_command_execution_timeout_ms(timeout);
+ automation_proxy_->set_command_execution_timeout_ms(timeout);
VLOG(1) << "Automation command execution timeout set to " << timeout << " ms";
}
-AutomationProxy* UITestBase::CreateAutomationProxy(int execution_timeout) {
- return new AutomationProxy(execution_timeout, false);
+ProxyLauncher* UITestBase::CreateProxyLauncher() {
+ return new AnonymousProxyLauncher(false);
+}
+
+void UITestBase::LaunchBrowser() {
+ LaunchBrowser(launch_arguments_, clear_profile_);
}
void UITestBase::LaunchBrowserAndServer() {
- // Set up IPC testing interface server.
- server_.reset(CreateAutomationProxy(
- TestTimeouts::command_execution_timeout_ms()));
+ // Set up IPC testing interface as a server.
+ automation_proxy_.reset(launcher_->CreateAutomationProxy(
+ TestTimeouts::command_execution_timeout_ms()));
LaunchBrowser(launch_arguments_, clear_profile_);
- ASSERT_EQ(AUTOMATION_SUCCESS, server_->WaitForAppLaunch())
+ WaitForBrowserLaunch();
+}
+
+void UITestBase::ConnectToRunningBrowser() {
+ // Set up IPC testing interface as a client.
+ automation_proxy_.reset(launcher_->CreateAutomationProxy(
+ TestTimeouts::command_execution_timeout_ms()));
+ WaitForBrowserLaunch();
+}
+
+void UITestBase::WaitForBrowserLaunch() {
+ ASSERT_EQ(AUTOMATION_SUCCESS, automation_proxy_->WaitForAppLaunch())
<< "Error while awaiting automation ping from browser process";
if (wait_for_initial_loads_)
- ASSERT_TRUE(server_->WaitForInitialLoads());
+ ASSERT_TRUE(automation_proxy_->WaitForInitialLoads());
else
PlatformThread::Sleep(sleep_timeout_ms());
@@ -210,7 +228,7 @@ void UITestBase::CloseBrowserAndServer() {
AssertAppNotRunning(StringPrintf(
L"Unable to quit all browser processes. Original PID %d", process_id_));
- server_.reset(); // Shut down IPC testing interface.
+ automation_proxy_.reset(); // Shut down IPC testing interface.
}
void UITestBase::LaunchBrowser(const CommandLine& arguments,
@@ -567,7 +585,7 @@ FilePath UITestBase::GetDownloadDirectory() {
}
void UITestBase::CloseBrowserAsync(BrowserProxy* browser) const {
- ASSERT_TRUE(server_->Send(
+ ASSERT_TRUE(automation_proxy_->Send(
new AutomationMsg_CloseBrowserRequestAsync(0, browser->handle())));
}
@@ -579,7 +597,7 @@ bool UITestBase::CloseBrowser(BrowserProxy* browser,
bool result = true;
- bool succeeded = server_->Send(new AutomationMsg_CloseBrowser(
+ bool succeeded = automation_proxy_->Send(new AutomationMsg_CloseBrowser(
0, browser->handle(), &result, application_closed));
if (!succeeded)
@@ -694,10 +712,9 @@ void UITestBase::PrepareTestCommandline(CommandLine* command_line) {
if (dom_automation_enabled_)
command_line->AppendSwitch(switches::kDomAutomationController);
- if (include_testing_id_) {
+ if (include_testing_id_)
command_line->AppendSwitchASCII(switches::kTestingChannelID,
- server_->channel_id());
- }
+ launcher_->PrefixedChannelID());
if (!show_error_dialogs_ &&
!CommandLine::ForCurrentProcess()->HasSwitch(
@@ -786,10 +803,11 @@ bool UITestBase::LaunchBrowserHelper(const CommandLine& arguments,
<< browser_wrapper;
}
- bool started = base::LaunchApp(command_line.argv(),
- server_->fds_to_map(),
- wait,
- process);
+ 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;
@@ -867,11 +885,11 @@ void UITest::TearDown() {
PlatformTest::TearDown();
}
-AutomationProxy* UITest::CreateAutomationProxy(int execution_timeout) {
+ProxyLauncher* UITest::CreateProxyLauncher() {
// Make the AutomationProxy disconnect the channel on the first error,
// so that we avoid spending a lot of time in timeouts. The browser is likely
// hosed if we hit those errors.
- return new AutomationProxy(execution_timeout, true);
+ return new AnonymousProxyLauncher(true);
}
static CommandLine* CreatePythonCommandLine() {
diff --git a/chrome/test/ui/ui_test.h b/chrome/test/ui/ui_test.h
index ced9f34..3305cc5 100644
--- a/chrome/test/ui/ui_test.h
+++ b/chrome/test/ui/ui_test.h
@@ -38,6 +38,7 @@ class BrowserProxy;
class DictionaryValue;
class FilePath;
class GURL;
+class ProxyLauncher;
class ScopedTempDir;
class TabProxy;
@@ -68,14 +69,21 @@ class UITestBase {
public:
// ********* Utility functions *********
- // Launches the browser and IPC testing server.
+ // Launches the browser only.
+ void LaunchBrowser();
+
+ // Launches the browser and IPC testing connection in server mode.
void LaunchBrowserAndServer();
+ // Launches the IPC testing connection in client mode,
+ // which then attempts to connect to a browser.
+ void ConnectToRunningBrowser();
+
// Only for pyauto.
void set_command_execution_timeout_ms(int timeout);
- // Overridable so that derived classes can provide their own AutomationProxy.
- virtual AutomationProxy* CreateAutomationProxy(int execution_timeout);
+ // Overridable so that derived classes can provide their own ProxyLauncher.
+ virtual ProxyLauncher* CreateProxyLauncher();
// Closes the browser and IPC testing server.
void CloseBrowserAndServer();
@@ -102,7 +110,7 @@ class UITestBase {
// Terminates the browser, simulates end of session.
void TerminateBrowser();
- // Tells the browser to navigato to the givne URL in the active tab
+ // Tells the browser to navigate to the given URL in the active tab
// of the first app window.
// Does not wait for the navigation to complete to return.
void NavigateToURLAsync(const GURL& url);
@@ -361,8 +369,8 @@ class UITestBase {
protected:
AutomationProxy* automation() {
- EXPECT_TRUE(server_.get());
- return server_.get();
+ EXPECT_TRUE(automation_proxy_.get());
+ return automation_proxy_.get();
}
virtual bool ShouldFilterInet() {
@@ -412,6 +420,7 @@ class UITestBase {
// id on the command line? Default is
// true.
bool enable_file_cookies_; // Enable file cookies, default is true.
+ scoped_ptr<ProxyLauncher> launcher_; // Launches browser and AutomationProxy.
ProfileType profile_type_; // Are we using a profile with a
// complex theme?
FilePath websocket_pid_file_; // PID file for websocket server.
@@ -419,6 +428,8 @@ class UITestBase {
// the browser. Used in ShutdownTest.
private:
+ void WaitForBrowserLaunch();
+
bool LaunchBrowserHelper(const CommandLine& arguments,
bool wait,
base::ProcessHandle* process);
@@ -450,7 +461,7 @@ class UITestBase {
static std::string js_flags_; // Flags passed to the JS engine.
static std::string log_level_; // Logging level.
- scoped_ptr<AutomationProxy> server_;
+ scoped_ptr<AutomationProxy> automation_proxy_;
std::string ui_test_name_;
@@ -468,7 +479,7 @@ class UITest : public UITestBase, public PlatformTest {
virtual void SetUp();
virtual void TearDown();
- virtual AutomationProxy* CreateAutomationProxy(int execution_timeout);
+ virtual ProxyLauncher* CreateProxyLauncher();
// Synchronously launches local http server normally used to run LayoutTests.
void StartHttpServer(const FilePath& root_directory);
diff --git a/chrome_frame/chrome_frame.gyp b/chrome_frame/chrome_frame.gyp
index 39d5063..66d1dad 100644
--- a/chrome_frame/chrome_frame.gyp
+++ b/chrome_frame/chrome_frame.gyp
@@ -550,7 +550,10 @@
'test/win_event_receiver.h',
'chrome_tab.h',
'../base/test/test_file_util_win.cc',
+ '../chrome/test/automation/proxy_launcher.cc',
+ '../chrome/test/automation/proxy_launcher.h',
'../chrome/test/ui/ui_test.cc',
+ '../chrome/test/ui/ui_test.h',
'../chrome/test/ui/ui_test_suite.cc',
'../chrome/test/ui/ui_test_suite.h',
'../chrome/test/chrome_process_util.cc',
@@ -809,7 +812,8 @@
],
'process_outputs_as_sources': 0,
'message':
- 'Assembling <(RULE_INPUT_PATH) to <(INTERMEDIATE_DIR)\<(RULE_INPUT_ROOT).obj.',
+ 'Assembling <(RULE_INPUT_PATH) to ' \
+ '<(INTERMEDIATE_DIR)\<(RULE_INPUT_ROOT).obj.',
},
],
'msvs_settings': {
diff --git a/chrome_frame/chrome_frame_automation.cc b/chrome_frame/chrome_frame_automation.cc
index 7a49f18..94d30b8 100644
--- a/chrome_frame/chrome_frame_automation.cc
+++ b/chrome_frame/chrome_frame_automation.cc
@@ -144,10 +144,13 @@ class ChromeFrameAutomationProxyImpl::CFMsgDispatcher
};
ChromeFrameAutomationProxyImpl::ChromeFrameAutomationProxyImpl(
- AutomationProxyCacheEntry* entry, int launch_timeout)
+ AutomationProxyCacheEntry* entry,
+ std::string channel_id, int launch_timeout)
: AutomationProxy(launch_timeout, false), proxy_entry_(entry) {
TRACE_EVENT_BEGIN("chromeframe.automationproxy", this, "");
+ InitializeChannel(channel_id, false);
+
sync_ = new CFMsgDispatcher();
message_filter_ = new TabProxyNotificationMessageFilter(tracker_.get());
@@ -271,8 +274,10 @@ void AutomationProxyCacheEntry::CreateProxy(ChromeFrameLaunchParams* params,
// destruction notification.
// At same time we must destroy/stop the thread from another thread.
+ std::string channel_id = AutomationProxy::GenerateChannelID();
ChromeFrameAutomationProxyImpl* proxy =
- new ChromeFrameAutomationProxyImpl(this, params->launch_timeout());
+ new ChromeFrameAutomationProxyImpl(this, channel_id,
+ params->launch_timeout());
// Ensure that the automation proxy actually respects our choice on whether
// or not to check the version.
@@ -282,7 +287,7 @@ void AutomationProxyCacheEntry::CreateProxy(ChromeFrameLaunchParams* params,
scoped_ptr<CommandLine> command_line(
chrome_launcher::CreateLaunchCommandLine());
command_line->AppendSwitchASCII(switches::kAutomationClientChannelID,
- proxy->channel_id());
+ channel_id);
// Run Chrome in Chrome Frame mode. In practice, this modifies the paths
// and registry keys that Chrome looks in via the BrowserDistribution
diff --git a/chrome_frame/chrome_frame_automation.h b/chrome_frame/chrome_frame_automation.h
index cb1b282..5cf1304 100644
--- a/chrome_frame/chrome_frame_automation.h
+++ b/chrome_frame/chrome_frame_automation.h
@@ -92,6 +92,7 @@ class ChromeFrameAutomationProxyImpl
protected:
friend class AutomationProxyCacheEntry;
ChromeFrameAutomationProxyImpl(AutomationProxyCacheEntry* entry,
+ std::string channel_id,
int launch_timeout);
class CFMsgDispatcher;
diff --git a/chrome_frame/test/automation_client_mock.cc b/chrome_frame/test/automation_client_mock.cc
index 7e8f317..2cf981b 100644
--- a/chrome_frame/test/automation_client_mock.cc
+++ b/chrome_frame/test/automation_client_mock.cc
@@ -315,7 +315,8 @@ class TestChromeFrameAutomationProxyImpl
public:
TestChromeFrameAutomationProxyImpl()
// 1 is an unneeded timeout.
- : ChromeFrameAutomationProxyImpl(NULL, 1) {
+ : ChromeFrameAutomationProxyImpl(
+ NULL, AutomationProxy::GenerateChannelID(), 1) {
}
MOCK_METHOD3(
SendAsAsync,
@@ -469,4 +470,3 @@ TEST_F(CFACMockTest, NavigateTwiceAfterInitToSameUrl) {
EXPECT_CALL(mock_proxy_, ReleaseTabProxy(testing::Eq(tab_handle_))).Times(1);
client_->Uninitialize();
}
-
diff --git a/chrome_frame/test/net/test_automation_provider.cc b/chrome_frame/test/net/test_automation_provider.cc
index 5b8a9a6..d6a0676 100644
--- a/chrome_frame/test/net/test_automation_provider.cc
+++ b/chrome_frame/test/net/test_automation_provider.cc
@@ -119,7 +119,7 @@ TestAutomationProvider* TestAutomationProvider::NewAutomationProvider(
Profile* p, const std::string& channel,
TestAutomationProviderDelegate* delegate) {
TestAutomationProvider* automation = new TestAutomationProvider(p, delegate);
- automation->ConnectToChannel(channel);
+ automation->InitializeChannel(channel);
automation->SetExpectedTabCount(1);
return automation;
}
diff --git a/ipc/ipc_channel.h b/ipc/ipc_channel.h
index 2445e51..27b055c1 100644
--- a/ipc/ipc_channel.h
+++ b/ipc/ipc_channel.h
@@ -38,7 +38,9 @@ class Channel : public Message::Sender {
enum Mode {
MODE_NONE,
MODE_SERVER,
- MODE_CLIENT
+ MODE_CLIENT,
+ MODE_NAMED_SERVER,
+ MODE_NAMED_CLIENT
};
enum {
diff --git a/ipc/ipc_channel_posix.cc b/ipc/ipc_channel_posix.cc
index 86d1673..65a04e1 100644
--- a/ipc/ipc_channel_posix.cc
+++ b/ipc/ipc_channel_posix.cc
@@ -273,8 +273,9 @@ Channel::ChannelImpl::ChannelImpl(const std::string& channel_id, Mode mode,
: mode_(mode),
is_blocked_on_write_(false),
message_send_bytes_written_(0),
- uses_fifo_(CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kIPCUseFIFO)),
+ uses_fifo_(
+ CommandLine::ForCurrentProcess()->HasSwitch(switches::kIPCUseFIFO) ||
+ mode == MODE_NAMED_SERVER || mode == MODE_NAMED_CLIENT),
server_listen_pipe_(-1),
pipe_(-1),
client_pipe_(-1),
@@ -285,10 +286,15 @@ Channel::ChannelImpl::ChannelImpl(const std::string& channel_id, Mode mode,
listener_(listener),
waiting_connect_(true),
factory_(this) {
- if (!CreatePipe(channel_id, mode)) {
+ if (mode_ == MODE_NAMED_SERVER)
+ mode_ = MODE_SERVER;
+ if (mode_ == MODE_NAMED_CLIENT)
+ mode_ = MODE_CLIENT;
+
+ if (!CreatePipe(channel_id, mode_)) {
// The pipe may have been closed already.
PLOG(WARNING) << "Unable to create pipe named \"" << channel_id
- << "\" in " << (mode == MODE_SERVER ? "server" : "client")
+ << "\" in " << (mode_ == MODE_SERVER ? "server" : "client")
<< " mode";
}
}
@@ -346,7 +352,7 @@ bool Channel::ChannelImpl::CreatePipe(const std::string& channel_id,
// TODO(playmobil): We shouldn't need to create fifos on disk.
// TODO(playmobil): If we do, they should be in the user data directory.
// TODO(playmobil): Cleanup any stale fifos.
- pipe_name_ = "/var/tmp/chrome_" + channel_id;
+ pipe_name_ = channel_id;
if (mode == MODE_SERVER) {
if (!CreateServerFifo(pipe_name_, &server_listen_pipe_)) {
return false;