Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(769)

Side by Side Diff: chrome/test/chromedriver/chrome_launcher.cc

Issue 13185004: [chromedriver] Implement proxy capability. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Check unexpected capabilities failed java tests. Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/test/chromedriver/chrome_launcher.h" 5 #include "chrome/test/chromedriver/chrome_launcher.h"
6 6
7 #include "base/base64.h" 7 #include "base/base64.h"
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/file_util.h" 9 #include "base/file_util.h"
10 #include "base/files/file_path.h" 10 #include "base/files/file_path.h"
(...skipping 16 matching lines...) Expand all
27 #include "chrome/test/chromedriver/chrome/devtools_http_client.h" 27 #include "chrome/test/chromedriver/chrome/devtools_http_client.h"
28 #include "chrome/test/chromedriver/chrome/status.h" 28 #include "chrome/test/chromedriver/chrome/status.h"
29 #include "chrome/test/chromedriver/chrome/user_data_dir.h" 29 #include "chrome/test/chromedriver/chrome/user_data_dir.h"
30 #include "chrome/test/chromedriver/chrome/version.h" 30 #include "chrome/test/chromedriver/chrome/version.h"
31 #include "chrome/test/chromedriver/chrome/zip.h" 31 #include "chrome/test/chromedriver/chrome/zip.h"
32 #include "chrome/test/chromedriver/net/url_request_context_getter.h" 32 #include "chrome/test/chromedriver/net/url_request_context_getter.h"
33 33
34 namespace { 34 namespace {
35 35
36 Status PrepareCommandLine(int port, 36 Status PrepareCommandLine(int port,
37 const base::FilePath& exe, 37 const Capabilities& capabilities,
38 const base::ListValue* args,
39 const base::ListValue* extensions,
40 const base::DictionaryValue* prefs,
41 const base::DictionaryValue* local_state,
42 CommandLine* prepared_command, 38 CommandLine* prepared_command,
43 base::ScopedTempDir* user_data_dir, 39 base::ScopedTempDir* user_data_dir,
44 base::ScopedTempDir* extension_dir) { 40 base::ScopedTempDir* extension_dir) {
45 base::FilePath program = exe; 41 CommandLine command = capabilities.command;
42 base::FilePath program = command.GetProgram();
46 if (program.empty()) { 43 if (program.empty()) {
47 if (!FindChrome(&program)) 44 if (!FindChrome(&program))
48 return Status(kUnknownError, "cannot find Chrome binary"); 45 return Status(kUnknownError, "cannot find Chrome binary");
46 command.SetProgram(program);
49 } 47 }
50 LOG(INFO) << "Using chrome from " << program.value(); 48 LOG(INFO) << "Using chrome from " << program.value();
51 49
52 CommandLine command(program);
53 command.AppendSwitchASCII("remote-debugging-port", base::IntToString(port)); 50 command.AppendSwitchASCII("remote-debugging-port", base::IntToString(port));
54 command.AppendSwitch("no-first-run"); 51 command.AppendSwitch("no-first-run");
55 command.AppendSwitch("enable-logging"); 52 command.AppendSwitch("enable-logging");
56 command.AppendSwitchASCII("logging-level", "1"); 53 command.AppendSwitchASCII("logging-level", "1");
57 command.AppendArg("data:text/html;charset=utf-8,"); 54 command.AppendArg("data:text/html;charset=utf-8,");
58 55
59 if (args) {
60 Status status = internal::ProcessCommandLineArgs(args, &command);
61 if (status.IsError())
62 return status;
63 }
64
65 if (!command.HasSwitch("user-data-dir")) { 56 if (!command.HasSwitch("user-data-dir")) {
66 if (!user_data_dir->CreateUniqueTempDir()) 57 if (!user_data_dir->CreateUniqueTempDir())
67 return Status(kUnknownError, "cannot create temp dir for user data dir"); 58 return Status(kUnknownError, "cannot create temp dir for user data dir");
68 command.AppendSwitchPath("user-data-dir", user_data_dir->path()); 59 command.AppendSwitchPath("user-data-dir", user_data_dir->path());
69 Status status = internal::PrepareUserDataDir( 60 Status status = internal::PrepareUserDataDir(
70 user_data_dir->path(), prefs, local_state); 61 user_data_dir->path(), capabilities.prefs.get(),
62 capabilities.local_state.get());
71 if (status.IsError()) 63 if (status.IsError())
72 return status; 64 return status;
73 } 65 }
74 66
75 if (extensions) { 67 if (!capabilities.extensions.empty()) {
76 if (!extension_dir->CreateUniqueTempDir()) 68 if (!extension_dir->CreateUniqueTempDir())
77 return Status(kUnknownError, 69 return Status(kUnknownError,
78 "cannot create temp dir for unpacking extensions"); 70 "cannot create temp dir for unpacking extensions");
79 Status status = internal::ProcessExtensions( 71 Status status = internal::ProcessExtensions(
80 extensions, extension_dir->path(), &command); 72 capabilities.extensions, extension_dir->path(), &command);
81 if (status.IsError()) 73 if (status.IsError())
82 return status; 74 return status;
83 } 75 }
84 *prepared_command = command; 76 *prepared_command = command;
85 return Status(kOk); 77 return Status(kOk);
86 } 78 }
87 79
88 Status ParseAndCheckVersion(const std::string& devtools_version, 80 Status ParseAndCheckVersion(const std::string& devtools_version,
89 std::string* version, 81 std::string* version,
90 int* build_no) { 82 int* build_no) {
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 client->GetWebViewsInfo(&views_info); 144 client->GetWebViewsInfo(&views_info);
153 if (views_info.GetSize()) { 145 if (views_info.GetSize()) {
154 *user_client = client.Pass(); 146 *user_client = client.Pass();
155 return Status(kOk); 147 return Status(kOk);
156 } 148 }
157 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100)); 149 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
158 } 150 }
159 return Status(kUnknownError, "unable to discover open pages"); 151 return Status(kUnknownError, "unable to discover open pages");
160 } 152 }
161 153
162 } // namespace
163
164 Status LaunchDesktopChrome(URLRequestContextGetter* context_getter, 154 Status LaunchDesktopChrome(URLRequestContextGetter* context_getter,
165 int port, 155 int port,
166 const SyncWebSocketFactory& socket_factory, 156 const SyncWebSocketFactory& socket_factory,
167 const base::FilePath& exe, 157 const Capabilities& capabilities,
168 const base::ListValue* args,
169 const base::ListValue* extensions,
170 const base::DictionaryValue* prefs,
171 const base::DictionaryValue* local_state,
172 const std::string& log_path,
173 scoped_ptr<Chrome>* chrome) { 158 scoped_ptr<Chrome>* chrome) {
174 CommandLine command(CommandLine::NO_PROGRAM); 159 CommandLine command(CommandLine::NO_PROGRAM);
175 base::ScopedTempDir user_data_dir; 160 base::ScopedTempDir user_data_dir;
176 base::ScopedTempDir extension_dir; 161 base::ScopedTempDir extension_dir;
177 PrepareCommandLine(port, exe, args, extensions, prefs, local_state, 162 PrepareCommandLine(port, capabilities,
178 &command, &user_data_dir, &extension_dir); 163 &command, &user_data_dir, &extension_dir);
179 base::LaunchOptions options; 164 base::LaunchOptions options;
180 165
181 #if !defined(OS_WIN) 166 #if !defined(OS_WIN)
182 base::EnvironmentVector environ; 167 base::EnvironmentVector environ;
183 if (!log_path.empty()) { 168 if (!capabilities.log_path.empty()) {
184 environ.push_back(base::EnvironmentVector::value_type("CHROME_LOG_FILE", 169 environ.push_back(
185 log_path)); 170 base::EnvironmentVector::value_type("CHROME_LOG_FILE",
171 capabilities.log_path));
186 options.environ = &environ; 172 options.environ = &environ;
187 } 173 }
188 #endif 174 #endif
189 175
190 base::ProcessHandle process; 176 base::ProcessHandle process;
191 if (!base::LaunchProcess(command, options, &process)) 177 if (!base::LaunchProcess(command, options, &process))
192 return Status(kUnknownError, "chrome failed to start"); 178 return Status(kUnknownError, "chrome failed to start");
193 179
194 scoped_ptr<DevToolsHttpClient> devtools_client; 180 scoped_ptr<DevToolsHttpClient> devtools_client;
195 std::string version; 181 std::string version;
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
234 } 220 }
235 chrome->reset(new ChromeDesktopImpl( 221 chrome->reset(new ChromeDesktopImpl(
236 devtools_client.Pass(), version, build_no, process, &user_data_dir, 222 devtools_client.Pass(), version, build_no, process, &user_data_dir,
237 &extension_dir)); 223 &extension_dir));
238 return Status(kOk); 224 return Status(kOk);
239 } 225 }
240 226
241 Status LaunchAndroidChrome(URLRequestContextGetter* context_getter, 227 Status LaunchAndroidChrome(URLRequestContextGetter* context_getter,
242 int port, 228 int port,
243 const SyncWebSocketFactory& socket_factory, 229 const SyncWebSocketFactory& socket_factory,
244 const std::string& package_name, 230 const Capabilities& capabilities,
245 scoped_ptr<Chrome>* chrome) { 231 scoped_ptr<Chrome>* chrome) {
246 // TODO(frankf): Figure out how this should be installed to 232 // TODO(frankf): Figure out how this should be installed to
247 // make this work for all platforms. 233 // make this work for all platforms.
248 base::FilePath adb_commands(FILE_PATH_LITERAL("adb_commands.py")); 234 base::FilePath adb_commands(FILE_PATH_LITERAL("adb_commands.py"));
249 CommandLine command(adb_commands); 235 CommandLine command(adb_commands);
250 command.AppendSwitchASCII("package", package_name); 236 command.AppendSwitchASCII("package", capabilities.android_package);
251 command.AppendSwitch("launch"); 237 command.AppendSwitch("launch");
252 command.AppendSwitchASCII("port", base::IntToString(port)); 238 command.AppendSwitchASCII("port", base::IntToString(port));
253 239
254 std::string output; 240 std::string output;
255 if (!base::GetAppOutput(command, &output)) { 241 if (!base::GetAppOutput(command, &output)) {
256 if (output.empty()) 242 if (output.empty())
257 return Status( 243 return Status(
258 kUnknownError, 244 kUnknownError,
259 "failed to run adb_commands.py. Make sure it is set in PATH."); 245 "failed to run adb_commands.py. Make sure it is set in PATH.");
260 else 246 else
261 return Status(kUnknownError, "android app failed to start.\n" + output); 247 return Status(kUnknownError, "android app failed to start.\n" + output);
262 } 248 }
263 249
264 scoped_ptr<DevToolsHttpClient> devtools_client; 250 scoped_ptr<DevToolsHttpClient> devtools_client;
265 std::string version; 251 std::string version;
266 int build_no; 252 int build_no;
267 Status status = WaitForDevToolsAndCheckVersion( 253 Status status = WaitForDevToolsAndCheckVersion(
268 port, context_getter, socket_factory, &devtools_client, &version, 254 port, context_getter, socket_factory, &devtools_client, &version,
269 &build_no); 255 &build_no);
270 if (status.IsError()) 256 if (status.IsError())
271 return status; 257 return status;
272 258
273 chrome->reset(new ChromeAndroidImpl( 259 chrome->reset(new ChromeAndroidImpl(
274 devtools_client.Pass(), version, build_no)); 260 devtools_client.Pass(), version, build_no));
275 return Status(kOk); 261 return Status(kOk);
276 } 262 }
277 263
264 } // namespace
265
266 Status LaunchChrome(URLRequestContextGetter* context_getter,
267 int port,
268 const SyncWebSocketFactory& socket_factory,
269 const Capabilities& capabilities,
270 scoped_ptr<Chrome>* chrome) {
271 if (capabilities.IsAndroid()) {
272 return LaunchAndroidChrome(
273 context_getter, port, socket_factory, capabilities, chrome);
274 } else {
275 return LaunchDesktopChrome(
276 context_getter, port, socket_factory, capabilities, chrome);
277 }
278 }
279
278 namespace internal { 280 namespace internal {
279 281
280 Status ProcessCommandLineArgs(const base::ListValue* args, 282 Status ProcessExtensions(const std::vector<std::string>& extensions,
281 CommandLine* command) {
282 for (size_t i = 0; i < args->GetSize(); ++i) {
283 std::string arg_string;
284 if (!args->GetString(i, &arg_string))
285 return Status(kUnknownError, "invalid chrome command line argument");
286 size_t separator_index = arg_string.find("=");
287 if (separator_index != std::string::npos) {
288 CommandLine::StringType arg_string_native;
289 if (!args->GetString(i, &arg_string_native))
290 return Status(kUnknownError, "invalid chrome command line argument");
291 command->AppendSwitchNative(
292 arg_string.substr(0, separator_index),
293 arg_string_native.substr(separator_index + 1));
294 } else {
295 command->AppendSwitch(arg_string);
296 }
297 }
298 return Status(kOk);
299 }
300
301 Status ProcessExtensions(const base::ListValue* extensions,
302 const base::FilePath& temp_dir, 283 const base::FilePath& temp_dir,
303 CommandLine* command) { 284 CommandLine* command) {
304 std::vector<base::FilePath::StringType> extension_paths; 285 std::vector<base::FilePath::StringType> extension_paths;
305 for (size_t i = 0; i < extensions->GetSize(); ++i) { 286 size_t count = 0;
287 for (std::vector<std::string>::const_iterator it = extensions.begin();
288 it != extensions.end(); ++it) {
306 std::string extension_base64; 289 std::string extension_base64;
307 if (!extensions->GetString(i, &extension_base64)) {
308 return Status(kUnknownError,
309 "each extension must be a base64 encoded string");
310 }
311
312 // Decodes extension string. 290 // Decodes extension string.
313 // Some WebDriver client base64 encoders follow RFC 1521, which require that 291 // Some WebDriver client base64 encoders follow RFC 1521, which require that
314 // 'encoded lines be no more than 76 characters long'. Just remove any 292 // 'encoded lines be no more than 76 characters long'. Just remove any
315 // newlines. 293 // newlines.
316 RemoveChars(extension_base64, "\n", &extension_base64); 294 RemoveChars(*it, "\n", &extension_base64);
317 std::string decoded_extension; 295 std::string decoded_extension;
318 if (!base::Base64Decode(extension_base64, &decoded_extension)) 296 if (!base::Base64Decode(extension_base64, &decoded_extension))
319 return Status(kUnknownError, "failed to base64 decode extension"); 297 return Status(kUnknownError, "failed to base64 decode extension");
320 298
321 // Writes decoded extension into a temporary .crx file. 299 // Writes decoded extension into a temporary .crx file.
322 base::ScopedTempDir temp_crx_dir; 300 base::ScopedTempDir temp_crx_dir;
323 if (!temp_crx_dir.CreateUniqueTempDir()) 301 if (!temp_crx_dir.CreateUniqueTempDir())
324 return Status(kUnknownError, 302 return Status(kUnknownError,
325 "cannot create temp dir for writing extension CRX file"); 303 "cannot create temp dir for writing extension CRX file");
326 base::FilePath extension_crx = temp_crx_dir.path().AppendASCII("temp.crx"); 304 base::FilePath extension_crx = temp_crx_dir.path().AppendASCII("temp.crx");
327 int size = static_cast<int>(decoded_extension.length()); 305 int size = static_cast<int>(decoded_extension.length());
328 if (file_util::WriteFile(extension_crx, decoded_extension.c_str(), size) 306 if (file_util::WriteFile(extension_crx, decoded_extension.c_str(), size)
329 != size) 307 != size) {
330 return Status(kUnknownError, "failed to write extension file"); 308 return Status(kUnknownError, "failed to write extension file");
309 }
331 310
332 // Unzips the temporary .crx file. 311 // Unzips the temporary .crx file.
312 count++;
333 base::FilePath extension_dir = temp_dir.AppendASCII( 313 base::FilePath extension_dir = temp_dir.AppendASCII(
334 base::StringPrintf("extension%" PRIuS, i)); 314 base::StringPrintf("extension%" PRIuS, count));
335 if (!zip::Unzip(extension_crx, extension_dir)) 315 if (!zip::Unzip(extension_crx, extension_dir))
336 return Status(kUnknownError, "failed to unzip the extension CRX file"); 316 return Status(kUnknownError, "failed to unzip the extension CRX file");
337 extension_paths.push_back(extension_dir.value()); 317 extension_paths.push_back(extension_dir.value());
338 } 318 }
339 319
340 // Sets paths of unpacked extensions to the command line. 320 // Sets paths of unpacked extensions to the command line.
341 if (!extension_paths.empty()) { 321 if (!extension_paths.empty()) {
342 base::FilePath::StringType extension_paths_value = JoinString( 322 base::FilePath::StringType extension_paths_value = JoinString(
343 extension_paths, FILE_PATH_LITERAL(',')); 323 extension_paths, FILE_PATH_LITERAL(','));
344 command->AppendSwitchNative("load-extension", extension_paths_value); 324 command->AppendSwitchNative("load-extension", extension_paths_value);
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
398 // Write empty "First Run" file, otherwise Chrome will wipe the default 378 // Write empty "First Run" file, otherwise Chrome will wipe the default
399 // profile that was written. 379 // profile that was written.
400 if (file_util::WriteFile( 380 if (file_util::WriteFile(
401 user_data_dir.AppendASCII("First Run"), "", 0) != 0) { 381 user_data_dir.AppendASCII("First Run"), "", 0) != 0) {
402 return Status(kUnknownError, "failed to write first run file"); 382 return Status(kUnknownError, "failed to write first run file");
403 } 383 }
404 return Status(kOk); 384 return Status(kOk);
405 } 385 }
406 386
407 } // namespace internal 387 } // namespace internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698