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