15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/base_paths.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_writer.h"
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/automation_messages.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_switches.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/test/automation/automation_proxy.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/test/automation/tab_proxy.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/test/pyautolib/pyautolib.h"
207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PyUITestSuiteBase
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PyUITestSuiteBase::PyUITestSuiteBase(int argc, char** argv)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : UITestSuite(argc, argv) {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PyUITestSuiteBase::~PyUITestSuiteBase() {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pool_.Recycle();
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Shutdown();
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PyUITestSuiteBase::InitializeWithPath(const base::FilePath& browser_dir) {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetBrowserDirectory(browser_dir);
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UITestSuite::Initialize();
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PyUITestSuiteBase::SetCrSourceRoot(const base::FilePath& path) {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PathService::Override(base::DIR_SOURCE_ROOT, path);
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PyUITestBase
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PyUITestBase::PyUITestBase(bool clear_profile, std::wstring homepage)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : UITestBase() {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  set_clear_profile(clear_profile);
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  set_homepage(WideToASCII(homepage));
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We add this so that pyauto can execute javascript in the renderer and
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // read values back.
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dom_automation_enabled_ = true;
51a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  message_loop_ = GetSharedMessageLoop(base::MessageLoop::TYPE_DEFAULT);
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PyUITestBase::~PyUITestBase() {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static, refer .h for why it needs to be static
58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)base::MessageLoop* PyUITestBase::message_loop_ = NULL;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)base::MessageLoop* PyUITestBase::GetSharedMessageLoop(
62a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    base::MessageLoop::Type msg_loop_type) {
63a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (!message_loop_)  // Create a shared instance of MessageLoop
64a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    message_loop_ = new base::MessageLoop(msg_loop_type);
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return message_loop_;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PyUITestBase::Initialize(const base::FilePath& browser_dir) {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UITestBase::SetBrowserDirectory(browser_dir);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProxyLauncher* PyUITestBase::CreateProxyLauncher() {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (named_channel_id_.empty())
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return new AnonymousProxyLauncher(false);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return new NamedProxyLauncher(named_channel_id_, false, false);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PyUITestBase::SetUp() {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UITestBase::SetUp();
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PyUITestBase::TearDown() {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UITestBase::TearDown();
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PyUITestBase::SetLaunchSwitches() {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clear the homepage because some of the pyauto tests don't work correctly
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // if a URL argument is passed.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string homepage_original;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::swap(homepage_original, homepage_);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UITestBase::SetLaunchSwitches();
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // However, we *do* want the --homepage switch.
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::swap(homepage_original, homepage_);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  launch_arguments_.AppendSwitchASCII(switches::kHomePage, homepage_);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AutomationProxy* PyUITestBase::automation() const {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AutomationProxy* automation_proxy = UITestBase::automation();
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!automation_proxy) {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(FATAL) << "The automation proxy is NULL.";
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return automation_proxy;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string PyUITestBase::_SendJSONRequest(int window_index,
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           const std::string& request,
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           int timeout) {
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string response;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AutomationProxy* automation_sender = automation();
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeTicks time = base::TimeTicks::Now();
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!automation_sender) {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ErrorResponse("Automation proxy does not exist", request, false, &response);
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (!automation_sender->channel()) {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ErrorResponse("Chrome automation IPC channel was found already broken",
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  request, false, &response);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (!automation_sender->Send(
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new AutomationMsg_SendJSONRequest(window_index, request, &response,
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        &success),
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timeout)) {
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RequestFailureResponse(request, base::TimeTicks::Now() - time,
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           base::TimeDelta::FromMilliseconds(timeout),
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &response);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return response;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PyUITestBase::ErrorResponse(
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& error_string,
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& request,
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool is_timeout,
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string* response) {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::DictionaryValue error_dict;
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string error_msg = base::StringPrintf("%s for %s", error_string.c_str(),
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             request.c_str());
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LOG(ERROR) << "Error during automation: " << error_msg;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  error_dict.SetString("error", error_msg);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  error_dict.SetBoolean("is_interface_error", true);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  error_dict.SetBoolean("is_interface_timeout", is_timeout);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::JSONWriter::Write(&error_dict, response);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PyUITestBase::RequestFailureResponse(
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& request,
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::TimeDelta& duration,
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::TimeDelta& timeout,
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string* response) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(craigdh): Determine timeout directly from IPC's Send().
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (duration >= timeout) {
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ErrorResponse(
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::StringPrintf("Chrome automation timed out after %d seconds",
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           static_cast<int>(duration.InSeconds())),
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request, true, response);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(craigdh): Determine specific cause.
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ErrorResponse(
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "Chrome automation failed prior to timing out, did chrome crash?",
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request, false, response);
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
164