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

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: Rebase and Address comments. 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 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
49 49
50 base::FilePath extension_dir = temp_dir.AppendASCII("internal"); 50 base::FilePath extension_dir = temp_dir.AppendASCII("internal");
51 if (!zip::Unzip(extension_zip, extension_dir)) 51 if (!zip::Unzip(extension_zip, extension_dir))
52 return Status(kUnknownError, "failed to unzip automation extension"); 52 return Status(kUnknownError, "failed to unzip automation extension");
53 53
54 *automation_extension = extension_dir; 54 *automation_extension = extension_dir;
55 return Status(kOk); 55 return Status(kOk);
56 } 56 }
57 57
58 Status PrepareCommandLine(int port, 58 Status PrepareCommandLine(int port,
59 const base::FilePath& exe, 59 const Capabilities& capabilities,
60 const base::ListValue* args,
61 const base::ListValue* extensions,
62 const base::DictionaryValue* prefs,
63 const base::DictionaryValue* local_state,
64 CommandLine* prepared_command, 60 CommandLine* prepared_command,
65 base::ScopedTempDir* user_data_dir, 61 base::ScopedTempDir* user_data_dir,
66 base::ScopedTempDir* extension_dir) { 62 base::ScopedTempDir* extension_dir) {
67 base::FilePath program = exe; 63 CommandLine command = capabilities.command;
64 base::FilePath program = command.GetProgram();
68 if (program.empty()) { 65 if (program.empty()) {
69 if (!FindChrome(&program)) 66 if (!FindChrome(&program))
70 return Status(kUnknownError, "cannot find Chrome binary"); 67 return Status(kUnknownError, "cannot find Chrome binary");
68 command.SetProgram(program);
69 } else if (!file_util::PathExists(program)) {
70 return Status(kUnknownError,
71 base::StringPrintf("no chrome binary at %" PRFilePath,
72 program.value().c_str()));
71 } 73 }
72 LOG(INFO) << "Using chrome from " << program.value(); 74 LOG(INFO) << "Using chrome from " << program.value();
73 75
74 CommandLine command(program);
75 command.AppendSwitchASCII("remote-debugging-port", base::IntToString(port)); 76 command.AppendSwitchASCII("remote-debugging-port", base::IntToString(port));
76 command.AppendSwitch("no-first-run"); 77 command.AppendSwitch("no-first-run");
77 command.AppendSwitch("enable-logging"); 78 command.AppendSwitch("enable-logging");
78 command.AppendSwitchASCII("logging-level", "1"); 79 command.AppendSwitchASCII("logging-level", "1");
79 command.AppendArg("data:text/html;charset=utf-8,"); 80 command.AppendArg("data:text/html;charset=utf-8,");
80 81
81 if (args) {
82 Status status = internal::ProcessCommandLineArgs(args, &command);
83 if (status.IsError())
84 return status;
85 }
86
87 if (!command.HasSwitch("user-data-dir")) { 82 if (!command.HasSwitch("user-data-dir")) {
88 if (!user_data_dir->CreateUniqueTempDir()) 83 if (!user_data_dir->CreateUniqueTempDir())
89 return Status(kUnknownError, "cannot create temp dir for user data dir"); 84 return Status(kUnknownError, "cannot create temp dir for user data dir");
90 command.AppendSwitchPath("user-data-dir", user_data_dir->path()); 85 command.AppendSwitchPath("user-data-dir", user_data_dir->path());
91 Status status = internal::PrepareUserDataDir( 86 Status status = internal::PrepareUserDataDir(
92 user_data_dir->path(), prefs, local_state); 87 user_data_dir->path(), capabilities.prefs.get(),
88 capabilities.local_state.get());
93 if (status.IsError()) 89 if (status.IsError())
94 return status; 90 return status;
95 } 91 }
96 92
97 if (!extension_dir->CreateUniqueTempDir()) { 93 if (!extension_dir->CreateUniqueTempDir()) {
98 return Status(kUnknownError, 94 return Status(kUnknownError,
99 "cannot create temp dir for unpacking extensions"); 95 "cannot create temp dir for unpacking extensions");
100 } 96 }
101 Status status = internal::ProcessExtensions( 97 Status status = internal::ProcessExtensions(
102 extensions, extension_dir->path(), true, &command); 98 capabilities.extensions, extension_dir->path(), true, &command);
103 if (status.IsError()) 99 if (status.IsError())
104 return status; 100 return status;
105 101
106 *prepared_command = command; 102 *prepared_command = command;
107 return Status(kOk); 103 return Status(kOk);
108 } 104 }
109 105
110 Status ParseAndCheckVersion(const std::string& devtools_version, 106 Status ParseAndCheckVersion(const std::string& devtools_version,
111 std::string* version, 107 std::string* version,
112 int* build_no) { 108 int* build_no) {
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
174 client->GetWebViewsInfo(&views_info); 170 client->GetWebViewsInfo(&views_info);
175 if (views_info.GetSize()) { 171 if (views_info.GetSize()) {
176 *user_client = client.Pass(); 172 *user_client = client.Pass();
177 return Status(kOk); 173 return Status(kOk);
178 } 174 }
179 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100)); 175 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
180 } 176 }
181 return Status(kUnknownError, "unable to discover open pages"); 177 return Status(kUnknownError, "unable to discover open pages");
182 } 178 }
183 179
184 } // namespace
185
186 Status LaunchDesktopChrome(URLRequestContextGetter* context_getter, 180 Status LaunchDesktopChrome(URLRequestContextGetter* context_getter,
187 int port, 181 int port,
188 const SyncWebSocketFactory& socket_factory, 182 const SyncWebSocketFactory& socket_factory,
189 const base::FilePath& exe, 183 const Capabilities& capabilities,
190 const base::ListValue* args,
191 const base::ListValue* extensions,
192 const base::DictionaryValue* prefs,
193 const base::DictionaryValue* local_state,
194 const std::string& log_path,
195 scoped_ptr<Chrome>* chrome) { 184 scoped_ptr<Chrome>* chrome) {
196 CommandLine command(CommandLine::NO_PROGRAM); 185 CommandLine command(CommandLine::NO_PROGRAM);
197 base::ScopedTempDir user_data_dir; 186 base::ScopedTempDir user_data_dir;
198 base::ScopedTempDir extension_dir; 187 base::ScopedTempDir extension_dir;
199 PrepareCommandLine(port, exe, args, extensions, prefs, local_state, 188 PrepareCommandLine(port, capabilities,
200 &command, &user_data_dir, &extension_dir); 189 &command, &user_data_dir, &extension_dir);
201 base::LaunchOptions options; 190 base::LaunchOptions options;
202 191
203 #if !defined(OS_WIN) 192 #if !defined(OS_WIN)
204 base::EnvironmentVector environ; 193 base::EnvironmentVector environ;
205 if (!log_path.empty()) { 194 if (!capabilities.log_path.empty()) {
206 environ.push_back(base::EnvironmentVector::value_type("CHROME_LOG_FILE", 195 environ.push_back(
207 log_path)); 196 base::EnvironmentVector::value_type("CHROME_LOG_FILE",
197 capabilities.log_path));
208 options.environ = &environ; 198 options.environ = &environ;
209 } 199 }
210 #endif 200 #endif
211 201
212 base::ProcessHandle process; 202 base::ProcessHandle process;
213 if (!base::LaunchProcess(command, options, &process)) 203 if (!base::LaunchProcess(command, options, &process))
214 return Status(kUnknownError, "chrome failed to start"); 204 return Status(kUnknownError, "chrome failed to start");
215 205
216 scoped_ptr<DevToolsHttpClient> devtools_client; 206 scoped_ptr<DevToolsHttpClient> devtools_client;
217 std::string version; 207 std::string version;
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
256 } 246 }
257 chrome->reset(new ChromeDesktopImpl( 247 chrome->reset(new ChromeDesktopImpl(
258 devtools_client.Pass(), version, build_no, process, &user_data_dir, 248 devtools_client.Pass(), version, build_no, process, &user_data_dir,
259 &extension_dir)); 249 &extension_dir));
260 return Status(kOk); 250 return Status(kOk);
261 } 251 }
262 252
263 Status LaunchAndroidChrome(URLRequestContextGetter* context_getter, 253 Status LaunchAndroidChrome(URLRequestContextGetter* context_getter,
264 int port, 254 int port,
265 const SyncWebSocketFactory& socket_factory, 255 const SyncWebSocketFactory& socket_factory,
266 const std::string& package_name, 256 const Capabilities& capabilities,
267 scoped_ptr<Chrome>* chrome) { 257 scoped_ptr<Chrome>* chrome) {
268 // TODO(frankf): Figure out how this should be installed to 258 // TODO(frankf): Figure out how this should be installed to
269 // make this work for all platforms. 259 // make this work for all platforms.
270 base::FilePath adb_commands(FILE_PATH_LITERAL("adb_commands.py")); 260 base::FilePath adb_commands(FILE_PATH_LITERAL("adb_commands.py"));
271 CommandLine command(adb_commands); 261 CommandLine command(adb_commands);
272 command.AppendSwitchASCII("package", package_name); 262 command.AppendSwitchASCII("package", capabilities.android_package);
273 command.AppendSwitch("launch"); 263 command.AppendSwitch("launch");
274 command.AppendSwitchASCII("port", base::IntToString(port)); 264 command.AppendSwitchASCII("port", base::IntToString(port));
275 265
276 std::string output; 266 std::string output;
277 if (!base::GetAppOutput(command, &output)) { 267 if (!base::GetAppOutput(command, &output)) {
278 if (output.empty()) 268 if (output.empty())
279 return Status( 269 return Status(
280 kUnknownError, 270 kUnknownError,
281 "failed to run adb_commands.py. Make sure it is set in PATH."); 271 "failed to run adb_commands.py. Make sure it is set in PATH.");
282 else 272 else
283 return Status(kUnknownError, "android app failed to start.\n" + output); 273 return Status(kUnknownError, "android app failed to start.\n" + output);
284 } 274 }
285 275
286 scoped_ptr<DevToolsHttpClient> devtools_client; 276 scoped_ptr<DevToolsHttpClient> devtools_client;
287 std::string version; 277 std::string version;
288 int build_no; 278 int build_no;
289 Status status = WaitForDevToolsAndCheckVersion( 279 Status status = WaitForDevToolsAndCheckVersion(
290 port, context_getter, socket_factory, &devtools_client, &version, 280 port, context_getter, socket_factory, &devtools_client, &version,
291 &build_no); 281 &build_no);
292 if (status.IsError()) 282 if (status.IsError())
293 return status; 283 return status;
294 284
295 chrome->reset(new ChromeAndroidImpl( 285 chrome->reset(new ChromeAndroidImpl(
296 devtools_client.Pass(), version, build_no)); 286 devtools_client.Pass(), version, build_no));
297 return Status(kOk); 287 return Status(kOk);
298 } 288 }
299 289
290 } // namespace
291
292 Status LaunchChrome(URLRequestContextGetter* context_getter,
293 int port,
294 const SyncWebSocketFactory& socket_factory,
295 const Capabilities& capabilities,
296 scoped_ptr<Chrome>* chrome) {
297 if (capabilities.IsAndroid()) {
298 return LaunchAndroidChrome(
299 context_getter, port, socket_factory, capabilities, chrome);
300 } else {
301 return LaunchDesktopChrome(
302 context_getter, port, socket_factory, capabilities, chrome);
303 }
304 }
305
300 namespace internal { 306 namespace internal {
301 307
302 Status ProcessCommandLineArgs(const base::ListValue* args, 308 Status ProcessExtensions(const std::vector<std::string>& extensions,
303 CommandLine* command) {
304 for (size_t i = 0; i < args->GetSize(); ++i) {
305 std::string arg_string;
306 if (!args->GetString(i, &arg_string))
307 return Status(kUnknownError, "invalid chrome command line argument");
308 size_t separator_index = arg_string.find("=");
309 if (separator_index != std::string::npos) {
310 CommandLine::StringType arg_string_native;
311 if (!args->GetString(i, &arg_string_native))
312 return Status(kUnknownError, "invalid chrome command line argument");
313 command->AppendSwitchNative(
314 arg_string.substr(0, separator_index),
315 arg_string_native.substr(separator_index + 1));
316 } else {
317 command->AppendSwitch(arg_string);
318 }
319 }
320 return Status(kOk);
321 }
322
323 Status ProcessExtensions(const base::ListValue* extensions,
324 const base::FilePath& temp_dir, 309 const base::FilePath& temp_dir,
325 bool include_automation_extension, 310 bool include_automation_extension,
326 CommandLine* command) { 311 CommandLine* command) {
327 std::vector<base::FilePath::StringType> extension_paths; 312 std::vector<base::FilePath::StringType> extension_paths;
328 for (size_t i = 0; i < (extensions ? extensions->GetSize() : 0); ++i) { 313 size_t count = 0;
314 for (std::vector<std::string>::const_iterator it = extensions.begin();
315 it != extensions.end(); ++it) {
329 std::string extension_base64; 316 std::string extension_base64;
330 if (!extensions->GetString(i, &extension_base64)) {
331 return Status(kUnknownError,
332 "each extension must be a base64 encoded string");
333 }
334
335 // Decodes extension string. 317 // Decodes extension string.
336 // Some WebDriver client base64 encoders follow RFC 1521, which require that 318 // Some WebDriver client base64 encoders follow RFC 1521, which require that
337 // 'encoded lines be no more than 76 characters long'. Just remove any 319 // 'encoded lines be no more than 76 characters long'. Just remove any
338 // newlines. 320 // newlines.
339 RemoveChars(extension_base64, "\n", &extension_base64); 321 RemoveChars(*it, "\n", &extension_base64);
340 std::string decoded_extension; 322 std::string decoded_extension;
341 if (!base::Base64Decode(extension_base64, &decoded_extension)) 323 if (!base::Base64Decode(extension_base64, &decoded_extension))
342 return Status(kUnknownError, "failed to base64 decode extension"); 324 return Status(kUnknownError, "failed to base64 decode extension");
343 325
344 // Writes decoded extension into a temporary .crx file. 326 // Writes decoded extension into a temporary .crx file.
345 base::ScopedTempDir temp_crx_dir; 327 base::ScopedTempDir temp_crx_dir;
346 if (!temp_crx_dir.CreateUniqueTempDir()) 328 if (!temp_crx_dir.CreateUniqueTempDir())
347 return Status(kUnknownError, 329 return Status(kUnknownError,
348 "cannot create temp dir for writing extension CRX file"); 330 "cannot create temp dir for writing extension CRX file");
349 base::FilePath extension_crx = temp_crx_dir.path().AppendASCII("temp.crx"); 331 base::FilePath extension_crx = temp_crx_dir.path().AppendASCII("temp.crx");
350 int size = static_cast<int>(decoded_extension.length()); 332 int size = static_cast<int>(decoded_extension.length());
351 if (file_util::WriteFile(extension_crx, decoded_extension.c_str(), size) 333 if (file_util::WriteFile(extension_crx, decoded_extension.c_str(), size)
352 != size) 334 != size) {
353 return Status(kUnknownError, "failed to write extension file"); 335 return Status(kUnknownError, "failed to write extension file");
336 }
354 337
355 // Unzips the temporary .crx file. 338 // Unzips the temporary .crx file.
339 count++;
356 base::FilePath extension_dir = temp_dir.AppendASCII( 340 base::FilePath extension_dir = temp_dir.AppendASCII(
357 base::StringPrintf("extension%" PRIuS, i)); 341 base::StringPrintf("extension%" PRIuS, count));
358 if (!zip::Unzip(extension_crx, extension_dir)) 342 if (!zip::Unzip(extension_crx, extension_dir))
359 return Status(kUnknownError, "failed to unzip the extension CRX file"); 343 return Status(kUnknownError, "failed to unzip the extension CRX file");
360 extension_paths.push_back(extension_dir.value()); 344 extension_paths.push_back(extension_dir.value());
361 } 345 }
362 346
363 if (include_automation_extension) { 347 if (include_automation_extension) {
364 base::FilePath automation_extension; 348 base::FilePath automation_extension;
365 Status status = UnpackAutomationExtension(temp_dir, &automation_extension); 349 Status status = UnpackAutomationExtension(temp_dir, &automation_extension);
366 if (status.IsError()) 350 if (status.IsError())
367 return status; 351 return status;
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
427 // Write empty "First Run" file, otherwise Chrome will wipe the default 411 // Write empty "First Run" file, otherwise Chrome will wipe the default
428 // profile that was written. 412 // profile that was written.
429 if (file_util::WriteFile( 413 if (file_util::WriteFile(
430 user_data_dir.AppendASCII("First Run"), "", 0) != 0) { 414 user_data_dir.AppendASCII("First Run"), "", 0) != 0) {
431 return Status(kUnknownError, "failed to write first run file"); 415 return Status(kUnknownError, "failed to write first run file");
432 } 416 }
433 return Status(kOk); 417 return Status(kOk);
434 } 418 }
435 419
436 } // namespace internal 420 } // namespace internal
OLDNEW
« no previous file with comments | « chrome/test/chromedriver/chrome_launcher.h ('k') | chrome/test/chromedriver/chrome_launcher_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698