| Index: chrome/test/automation/automation_proxy.cc
|
| ===================================================================
|
| --- chrome/test/automation/automation_proxy.cc (revision 261647)
|
| +++ chrome/test/automation/automation_proxy.cc (working copy)
|
| @@ -1,426 +0,0 @@
|
| -// Copyright (c) 2012 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/automation_proxy.h"
|
| -
|
| -#include <sstream>
|
| -
|
| -#include "base/basictypes.h"
|
| -#include "base/file_util.h"
|
| -#include "base/logging.h"
|
| -#include "base/memory/ref_counted.h"
|
| -#include "base/synchronization/waitable_event.h"
|
| -#include "base/threading/platform_thread.h"
|
| -#include "chrome/common/automation_constants.h"
|
| -#include "chrome/common/automation_messages.h"
|
| -#include "chrome/common/chrome_version_info.h"
|
| -#include "chrome/test/automation/browser_proxy.h"
|
| -#include "chrome/test/automation/tab_proxy.h"
|
| -#include "ipc/ipc_descriptors.h"
|
| -#if defined(OS_WIN)
|
| -// TODO(port): Enable when dialog_delegate is ported.
|
| -#include "ui/views/window/dialog_delegate.h"
|
| -#endif
|
| -
|
| -using base::TimeDelta;
|
| -using base::TimeTicks;
|
| -
|
| -namespace {
|
| -
|
| -const char kChannelErrorVersionString[] = "***CHANNEL_ERROR***";
|
| -
|
| -// This object allows messages received on the background thread to be
|
| -// properly triaged.
|
| -class AutomationMessageFilter : public IPC::ChannelProxy::MessageFilter {
|
| - public:
|
| - explicit AutomationMessageFilter(AutomationProxy* server) : server_(server) {}
|
| -
|
| - // Return true to indicate that the message was handled, or false to let
|
| - // the message be handled in the default way.
|
| - virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
|
| - bool handled = true;
|
| - IPC_BEGIN_MESSAGE_MAP(AutomationMessageFilter, message)
|
| - IPC_MESSAGE_HANDLER_GENERIC(AutomationMsg_Hello,
|
| - OnAutomationHello(message))
|
| - IPC_MESSAGE_HANDLER_GENERIC(
|
| - AutomationMsg_InitialLoadsComplete, server_->SignalInitialLoads())
|
| - IPC_MESSAGE_HANDLER(AutomationMsg_InitialNewTabUILoadComplete,
|
| - NewTabLoaded)
|
| - IPC_MESSAGE_HANDLER_GENERIC(
|
| - AutomationMsg_InvalidateHandle, server_->InvalidateHandle(message))
|
| - IPC_MESSAGE_UNHANDLED(handled = false)
|
| - IPC_END_MESSAGE_MAP()
|
| -
|
| - return handled;
|
| - }
|
| -
|
| - virtual void OnFilterAdded(IPC::Channel* channel) OVERRIDE {
|
| - server_->SetChannel(channel);
|
| - }
|
| -
|
| - virtual void OnFilterRemoved() OVERRIDE {
|
| - server_->ResetChannel();
|
| - }
|
| -
|
| - virtual void OnChannelError() OVERRIDE {
|
| - server_->SignalAppLaunch(kChannelErrorVersionString);
|
| - server_->SignalNewTabUITab(-1);
|
| - }
|
| -
|
| - private:
|
| - void NewTabLoaded(int load_time) {
|
| - server_->SignalNewTabUITab(load_time);
|
| - }
|
| -
|
| - void OnAutomationHello(const IPC::Message& hello_message) {
|
| - std::string server_version;
|
| - PickleIterator iter(hello_message);
|
| - if (!hello_message.ReadString(&iter, &server_version)) {
|
| - // We got an AutomationMsg_Hello from an old automation provider
|
| - // that doesn't send version info. Leave server_version as an empty
|
| - // string to signal a version mismatch.
|
| - LOG(ERROR) << "Pre-versioning protocol detected in automation provider.";
|
| - }
|
| -
|
| - server_->SignalAppLaunch(server_version);
|
| - }
|
| -
|
| - AutomationProxy* server_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(AutomationMessageFilter);
|
| -};
|
| -
|
| -} // anonymous namespace
|
| -
|
| -
|
| -AutomationProxy::AutomationProxy(base::TimeDelta action_timeout,
|
| - bool disconnect_on_failure)
|
| - : app_launched_(true, false),
|
| - initial_loads_complete_(true, false),
|
| - new_tab_ui_load_complete_(true, false),
|
| - shutdown_event_(new base::WaitableEvent(true, false)),
|
| - perform_version_check_(false),
|
| - disconnect_on_failure_(disconnect_on_failure),
|
| - channel_disconnected_on_failure_(false),
|
| - action_timeout_(action_timeout),
|
| - listener_thread_id_(0) {
|
| - // base::WaitableEvent::TimedWait() will choke if we give it a negative value.
|
| - // Zero also seems unreasonable, since we need to wait for IPC, but at
|
| - // least it is legal... ;-)
|
| - DCHECK_GE(action_timeout.InMilliseconds(), 0);
|
| - listener_thread_id_ = base::PlatformThread::CurrentId();
|
| - InitializeHandleTracker();
|
| - InitializeThread();
|
| -}
|
| -
|
| -AutomationProxy::~AutomationProxy() {
|
| - // Destruction order is important. Thread has to outlive the channel and
|
| - // tracker has to outlive the thread since we access the tracker inside
|
| - // AutomationMessageFilter::OnMessageReceived.
|
| - Disconnect();
|
| - thread_.reset();
|
| - tracker_.reset();
|
| -}
|
| -
|
| -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
|
| - // tests in sequence, and our theory is that sometimes the channel ID
|
| - // wasn't getting freed up in time for the next test.)
|
| - static int channel_counter = 0;
|
| -
|
| - std::ostringstream buf;
|
| - buf << "ChromeTestingInterface:" << base::GetCurrentProcId() <<
|
| - "." << ++channel_counter;
|
| - return buf.str();
|
| -}
|
| -
|
| -void AutomationProxy::InitializeThread() {
|
| - scoped_ptr<base::Thread> thread(
|
| - new base::Thread("AutomationProxy_BackgroundThread"));
|
| - base::Thread::Options options;
|
| - options.message_loop_type = base::MessageLoop::TYPE_IO;
|
| - bool thread_result = thread->StartWithOptions(options);
|
| - DCHECK(thread_result);
|
| - thread_.swap(thread);
|
| -}
|
| -
|
| -void AutomationProxy::InitializeChannel(const std::string& channel_id,
|
| - bool use_named_interface) {
|
| - DCHECK(shutdown_event_.get() != NULL);
|
| -
|
| - // TODO(iyengar)
|
| - // The shutdown event could be global on the same lines as the automation
|
| - // provider, where we use the shutdown event provided by the chrome browser
|
| - // process.
|
| - channel_.reset(new IPC::SyncChannel(this, // we are the listener
|
| - thread_->message_loop_proxy().get(),
|
| - shutdown_event_.get()));
|
| - channel_->AddFilter(new AutomationMessageFilter(this));
|
| -
|
| - // Create the pipe synchronously so that Chrome doesn't try to connect to an
|
| - // unready server. Note this is done after adding a message filter to
|
| - // guarantee that it doesn't miss any messages when we are the client.
|
| - // See crbug.com/102894.
|
| - channel_->Init(
|
| - channel_id,
|
| - use_named_interface ? IPC::Channel::MODE_NAMED_CLIENT
|
| - : IPC::Channel::MODE_SERVER,
|
| - true /* create_pipe_now */);
|
| -}
|
| -
|
| -void AutomationProxy::InitializeHandleTracker() {
|
| - tracker_.reset(new AutomationHandleTracker());
|
| -}
|
| -
|
| -AutomationLaunchResult AutomationProxy::WaitForAppLaunch() {
|
| - AutomationLaunchResult result = AUTOMATION_SUCCESS;
|
| - if (app_launched_.TimedWait(action_timeout_)) {
|
| - if (server_version_ == kChannelErrorVersionString) {
|
| - result = AUTOMATION_CHANNEL_ERROR;
|
| - } else if (perform_version_check_) {
|
| - // Obtain our own version number and compare it to what the automation
|
| - // provider sent.
|
| - chrome::VersionInfo version_info;
|
| - DCHECK(version_info.is_valid());
|
| -
|
| - // Note that we use a simple string comparison since we expect the version
|
| - // to be a punctuated numeric string. Consider using base/Version if we
|
| - // ever need something more complicated here.
|
| - if (server_version_ != version_info.Version()) {
|
| - result = AUTOMATION_VERSION_MISMATCH;
|
| - }
|
| - }
|
| - } else {
|
| - result = AUTOMATION_TIMEOUT;
|
| - }
|
| - return result;
|
| -}
|
| -
|
| -void AutomationProxy::SignalAppLaunch(const std::string& version_string) {
|
| - server_version_ = version_string;
|
| - app_launched_.Signal();
|
| -}
|
| -
|
| -bool AutomationProxy::WaitForProcessLauncherThreadToGoIdle() {
|
| - return Send(new AutomationMsg_WaitForProcessLauncherThreadToGoIdle());
|
| -}
|
| -
|
| -bool AutomationProxy::WaitForInitialLoads() {
|
| - return initial_loads_complete_.TimedWait(action_timeout_);
|
| -}
|
| -
|
| -bool AutomationProxy::WaitForInitialNewTabUILoad(int* load_time) {
|
| - if (new_tab_ui_load_complete_.TimedWait(action_timeout_)) {
|
| - *load_time = new_tab_ui_load_time_;
|
| - new_tab_ui_load_complete_.Reset();
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -void AutomationProxy::SignalInitialLoads() {
|
| - initial_loads_complete_.Signal();
|
| -}
|
| -
|
| -void AutomationProxy::SignalNewTabUITab(int load_time) {
|
| - new_tab_ui_load_time_ = load_time;
|
| - new_tab_ui_load_complete_.Signal();
|
| -}
|
| -
|
| -bool AutomationProxy::GetBrowserWindowCount(int* num_windows) {
|
| - if (!num_windows) {
|
| - NOTREACHED();
|
| - return false;
|
| - }
|
| -
|
| - return Send(new AutomationMsg_BrowserWindowCount(num_windows));
|
| -}
|
| -
|
| -bool AutomationProxy::GetNormalBrowserWindowCount(int* num_windows) {
|
| - if (!num_windows) {
|
| - NOTREACHED();
|
| - return false;
|
| - }
|
| -
|
| - return Send(new AutomationMsg_NormalBrowserWindowCount(num_windows));
|
| -}
|
| -
|
| -bool AutomationProxy::WaitForWindowCountToBecome(int count) {
|
| - bool wait_success = false;
|
| - if (!Send(new AutomationMsg_WaitForBrowserWindowCountToBecome(
|
| - count, &wait_success))) {
|
| - return false;
|
| - }
|
| - return wait_success;
|
| -}
|
| -
|
| -bool AutomationProxy::IsURLDisplayed(GURL url) {
|
| - int window_count;
|
| - if (!GetBrowserWindowCount(&window_count))
|
| - return false;
|
| -
|
| - for (int i = 0; i < window_count; i++) {
|
| - scoped_refptr<BrowserProxy> window = GetBrowserWindow(i);
|
| - if (!window.get())
|
| - break;
|
| -
|
| - int tab_count;
|
| - if (!window->GetTabCount(&tab_count))
|
| - continue;
|
| -
|
| - for (int j = 0; j < tab_count; j++) {
|
| - scoped_refptr<TabProxy> tab = window->GetTab(j);
|
| - if (!tab.get())
|
| - break;
|
| -
|
| - GURL tab_url;
|
| - if (!tab->GetCurrentURL(&tab_url))
|
| - continue;
|
| -
|
| - if (tab_url == url)
|
| - return true;
|
| - }
|
| - }
|
| -
|
| - return false;
|
| -}
|
| -
|
| -bool AutomationProxy::GetMetricEventDuration(const std::string& event_name,
|
| - int* duration_ms) {
|
| - return Send(new AutomationMsg_GetMetricEventDuration(event_name,
|
| - duration_ms));
|
| -}
|
| -
|
| -void AutomationProxy::Disconnect() {
|
| - DCHECK(shutdown_event_.get() != NULL);
|
| - shutdown_event_->Signal();
|
| - channel_.reset();
|
| -}
|
| -
|
| -bool AutomationProxy::OnMessageReceived(const IPC::Message& msg) {
|
| - // This won't get called unless AutomationProxy is run from
|
| - // inside a message loop.
|
| - NOTREACHED();
|
| - return false;
|
| -}
|
| -
|
| -void AutomationProxy::OnChannelError() {
|
| - LOG(ERROR) << "Channel error in AutomationProxy.";
|
| - if (disconnect_on_failure_)
|
| - Disconnect();
|
| -}
|
| -
|
| -scoped_refptr<BrowserProxy> AutomationProxy::GetBrowserWindow(
|
| - int window_index) {
|
| - int handle = 0;
|
| - if (!Send(new AutomationMsg_BrowserWindow(window_index, &handle)))
|
| - return NULL;
|
| -
|
| - return ProxyObjectFromHandle<BrowserProxy>(handle);
|
| -}
|
| -
|
| -IPC::SyncChannel* AutomationProxy::channel() {
|
| - return channel_.get();
|
| -}
|
| -
|
| -bool AutomationProxy::Send(IPC::Message* message) {
|
| - return Send(message,
|
| - static_cast<int>(action_timeout_.InMilliseconds()));
|
| -}
|
| -
|
| -bool AutomationProxy::Send(IPC::Message* message, int timeout_ms) {
|
| - if (!channel_.get()) {
|
| - LOG(ERROR) << "Automation channel has been closed; dropping message!";
|
| - delete message;
|
| - return false;
|
| - }
|
| -
|
| - bool success = channel_->SendWithTimeout(message, timeout_ms);
|
| -
|
| - if (!success && disconnect_on_failure_) {
|
| - // Send failed (possibly due to a timeout). Browser is likely in a weird
|
| - // state, and further IPC requests are extremely likely to fail (possibly
|
| - // timeout, which would make tests slower). Disconnect the channel now
|
| - // to avoid the slowness.
|
| - channel_disconnected_on_failure_ = true;
|
| - LOG(ERROR) << "Disconnecting channel after error!";
|
| - Disconnect();
|
| - }
|
| -
|
| - return success;
|
| -}
|
| -
|
| -void AutomationProxy::InvalidateHandle(const IPC::Message& message) {
|
| - PickleIterator iter(message);
|
| - int handle;
|
| -
|
| - if (message.ReadInt(&iter, &handle)) {
|
| - tracker_->InvalidateHandle(handle);
|
| - }
|
| -}
|
| -
|
| -bool AutomationProxy::OpenNewBrowserWindow(Browser::Type type, bool show) {
|
| - return Send(
|
| - new AutomationMsg_OpenNewBrowserWindowOfType(static_cast<int>(type),
|
| - show));
|
| -}
|
| -
|
| -template <class T> scoped_refptr<T> AutomationProxy::ProxyObjectFromHandle(
|
| - int handle) {
|
| - if (!handle)
|
| - return NULL;
|
| -
|
| - // Get AddRef-ed pointer to the object if handle is already seen.
|
| - T* p = static_cast<T*>(tracker_->GetResource(handle));
|
| - if (!p) {
|
| - p = new T(this, tracker_.get(), handle);
|
| - p->AddRef();
|
| - }
|
| -
|
| - // Since there is no scoped_refptr::attach.
|
| - scoped_refptr<T> result;
|
| - result.swap(&p);
|
| - return result;
|
| -}
|
| -
|
| -void AutomationProxy::SetChannel(IPC::Channel* channel) {
|
| - if (tracker_.get())
|
| - tracker_->put_channel(channel);
|
| -}
|
| -
|
| -void AutomationProxy::ResetChannel() {
|
| - if (tracker_.get())
|
| - tracker_->put_channel(NULL);
|
| -}
|
| -
|
| -bool AutomationProxy::BeginTracing(const std::string& category_patterns) {
|
| - bool result = false;
|
| - bool send_success = Send(new AutomationMsg_BeginTracing(category_patterns,
|
| - &result));
|
| - return send_success && result;
|
| -}
|
| -
|
| -bool AutomationProxy::EndTracing(std::string* json_trace_output) {
|
| - bool success = false;
|
| - base::FilePath path;
|
| - if (!Send(new AutomationMsg_EndTracing(&path, &success)) || !success)
|
| - return false;
|
| -
|
| - bool ok = base::ReadFileToString(path, json_trace_output);
|
| - DCHECK(ok);
|
| - base::DeleteFile(path, false);
|
| - return true;
|
| -}
|
| -
|
| -bool AutomationProxy::SendJSONRequest(const std::string& request,
|
| - int timeout_ms,
|
| - std::string* response) {
|
| - bool result = false;
|
| - if (!Send(new AutomationMsg_SendJSONRequest(-1, request, response, &result),
|
| - timeout_ms))
|
| - return false;
|
| - return result;
|
| -}
|
|
|