Home | History | Annotate | Download | only in pyautolib
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/base_paths.h"
      6 #include "base/json/json_writer.h"
      7 #include "base/logging.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/path_service.h"
     10 #include "base/strings/string_number_conversions.h"
     11 #include "base/strings/string_util.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "base/time/time.h"
     14 #include "base/values.h"
     15 #include "chrome/common/automation_messages.h"
     16 #include "chrome/common/chrome_switches.h"
     17 #include "chrome/test/automation/automation_proxy.h"
     18 #include "chrome/test/automation/tab_proxy.h"
     19 #include "chrome/test/pyautolib/pyautolib.h"
     20 #include "url/gurl.h"
     21 
     22 // PyUITestSuiteBase
     23 PyUITestSuiteBase::PyUITestSuiteBase(int argc, char** argv)
     24     : UITestSuite(argc, argv) {
     25 }
     26 
     27 PyUITestSuiteBase::~PyUITestSuiteBase() {
     28 #if defined(OS_MACOSX)
     29   pool_.Recycle();
     30 #endif
     31   Shutdown();
     32 }
     33 
     34 void PyUITestSuiteBase::InitializeWithPath(const base::FilePath& browser_dir) {
     35   SetBrowserDirectory(browser_dir);
     36   UITestSuite::Initialize();
     37 }
     38 
     39 void PyUITestSuiteBase::SetCrSourceRoot(const base::FilePath& path) {
     40   PathService::Override(base::DIR_SOURCE_ROOT, path);
     41 }
     42 
     43 // PyUITestBase
     44 PyUITestBase::PyUITestBase(bool clear_profile, std::wstring homepage)
     45     : UITestBase() {
     46   set_clear_profile(clear_profile);
     47   set_homepage(WideToASCII(homepage));
     48   // We add this so that pyauto can execute javascript in the renderer and
     49   // read values back.
     50   dom_automation_enabled_ = true;
     51   message_loop_ = GetSharedMessageLoop(base::MessageLoop::TYPE_DEFAULT);
     52 }
     53 
     54 PyUITestBase::~PyUITestBase() {
     55 }
     56 
     57 // static, refer .h for why it needs to be static
     58 base::MessageLoop* PyUITestBase::message_loop_ = NULL;
     59 
     60 // static
     61 base::MessageLoop* PyUITestBase::GetSharedMessageLoop(
     62     base::MessageLoop::Type msg_loop_type) {
     63   if (!message_loop_)  // Create a shared instance of MessageLoop
     64     message_loop_ = new base::MessageLoop(msg_loop_type);
     65   return message_loop_;
     66 }
     67 
     68 void PyUITestBase::Initialize(const base::FilePath& browser_dir) {
     69   UITestBase::SetBrowserDirectory(browser_dir);
     70 }
     71 
     72 ProxyLauncher* PyUITestBase::CreateProxyLauncher() {
     73   if (named_channel_id_.empty())
     74     return new AnonymousProxyLauncher(false);
     75   return new NamedProxyLauncher(named_channel_id_, false, false);
     76 }
     77 
     78 void PyUITestBase::SetUp() {
     79   UITestBase::SetUp();
     80 }
     81 
     82 void PyUITestBase::TearDown() {
     83   UITestBase::TearDown();
     84 }
     85 
     86 void PyUITestBase::SetLaunchSwitches() {
     87   // Clear the homepage because some of the pyauto tests don't work correctly
     88   // if a URL argument is passed.
     89   std::string homepage_original;
     90   std::swap(homepage_original, homepage_);
     91 
     92   UITestBase::SetLaunchSwitches();
     93 
     94   // However, we *do* want the --homepage switch.
     95   std::swap(homepage_original, homepage_);
     96   launch_arguments_.AppendSwitchASCII(switches::kHomePage, homepage_);
     97 }
     98 
     99 AutomationProxy* PyUITestBase::automation() const {
    100   AutomationProxy* automation_proxy = UITestBase::automation();
    101   if (!automation_proxy) {
    102     LOG(FATAL) << "The automation proxy is NULL.";
    103   }
    104   return automation_proxy;
    105 }
    106 
    107 std::string PyUITestBase::_SendJSONRequest(int window_index,
    108                                            const std::string& request,
    109                                            int timeout) {
    110   std::string response;
    111   bool success;
    112   AutomationProxy* automation_sender = automation();
    113   base::TimeTicks time = base::TimeTicks::Now();
    114 
    115   if (!automation_sender) {
    116     ErrorResponse("Automation proxy does not exist", request, false, &response);
    117   } else if (!automation_sender->channel()) {
    118     ErrorResponse("Chrome automation IPC channel was found already broken",
    119                   request, false, &response);
    120   } else if (!automation_sender->Send(
    121       new AutomationMsg_SendJSONRequest(window_index, request, &response,
    122                                         &success),
    123       timeout)) {
    124     RequestFailureResponse(request, base::TimeTicks::Now() - time,
    125                            base::TimeDelta::FromMilliseconds(timeout),
    126                            &response);
    127   }
    128   return response;
    129 }
    130 
    131 void PyUITestBase::ErrorResponse(
    132     const std::string& error_string,
    133     const std::string& request,
    134     bool is_timeout,
    135     std::string* response) {
    136   base::DictionaryValue error_dict;
    137   std::string error_msg = base::StringPrintf("%s for %s", error_string.c_str(),
    138                                              request.c_str());
    139   LOG(ERROR) << "Error during automation: " << error_msg;
    140   error_dict.SetString("error", error_msg);
    141   error_dict.SetBoolean("is_interface_error", true);
    142   error_dict.SetBoolean("is_interface_timeout", is_timeout);
    143   base::JSONWriter::Write(&error_dict, response);
    144 }
    145 
    146 void PyUITestBase::RequestFailureResponse(
    147     const std::string& request,
    148     const base::TimeDelta& duration,
    149     const base::TimeDelta& timeout,
    150     std::string* response) {
    151   // TODO(craigdh): Determine timeout directly from IPC's Send().
    152   if (duration >= timeout) {
    153     ErrorResponse(
    154         base::StringPrintf("Chrome automation timed out after %d seconds",
    155                            static_cast<int>(duration.InSeconds())),
    156         request, true, response);
    157   } else {
    158     // TODO(craigdh): Determine specific cause.
    159     ErrorResponse(
    160         "Chrome automation failed prior to timing out, did chrome crash?",
    161         request, false, response);
    162   }
    163 }
    164