OLD | NEW |
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 <algorithm> | 7 #include <algorithm> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/base64.h" | 10 #include "base/base64.h" |
(...skipping 27 matching lines...) Expand all Loading... |
38 #include "chrome/test/chromedriver/chrome/version.h" | 38 #include "chrome/test/chromedriver/chrome/version.h" |
39 #include "chrome/test/chromedriver/chrome/web_view.h" | 39 #include "chrome/test/chromedriver/chrome/web_view.h" |
40 #include "chrome/test/chromedriver/chrome/zip.h" | 40 #include "chrome/test/chromedriver/chrome/zip.h" |
41 #include "chrome/test/chromedriver/net/net_util.h" | 41 #include "chrome/test/chromedriver/net/net_util.h" |
42 #include "chrome/test/chromedriver/net/url_request_context_getter.h" | 42 #include "chrome/test/chromedriver/net/url_request_context_getter.h" |
43 #include "crypto/sha2.h" | 43 #include "crypto/sha2.h" |
44 | 44 |
45 namespace { | 45 namespace { |
46 | 46 |
47 const char* kCommonSwitches[] = { | 47 const char* kCommonSwitches[] = { |
48 "ignore-certificate-errors", "metrics-recording-only"}; | 48 "ignore-certificate-errors", "metrics-recording-only"}; |
49 | 49 |
50 Status UnpackAutomationExtension(const base::FilePath& temp_dir, | 50 Status UnpackAutomationExtension(const base::FilePath& temp_dir, |
51 base::FilePath* automation_extension) { | 51 base::FilePath* automation_extension) { |
52 std::string decoded_extension; | 52 std::string decoded_extension; |
53 if (!base::Base64Decode(kAutomationExtension, &decoded_extension)) | 53 if (!base::Base64Decode(kAutomationExtension, &decoded_extension)) |
54 return Status(kUnknownError, "failed to base64decode automation extension"); | 54 return Status(kUnknownError, "failed to base64decode automation extension"); |
55 | 55 |
56 base::FilePath extension_zip = temp_dir.AppendASCII("internal.zip"); | 56 base::FilePath extension_zip = temp_dir.AppendASCII("internal.zip"); |
57 int size = static_cast<int>(decoded_extension.length()); | 57 int size = static_cast<int>(decoded_extension.length()); |
58 if (file_util::WriteFile(extension_zip, decoded_extension.c_str(), size) | 58 if (file_util::WriteFile(extension_zip, decoded_extension.c_str(), size) |
59 != size) { | 59 != size) { |
60 return Status(kUnknownError, "failed to write automation extension zip"); | 60 return Status(kUnknownError, "failed to write automation extension zip"); |
61 } | 61 } |
62 | 62 |
63 base::FilePath extension_dir = temp_dir.AppendASCII("internal"); | 63 base::FilePath extension_dir = temp_dir.AppendASCII("internal"); |
64 if (!zip::Unzip(extension_zip, extension_dir)) | 64 if (!zip::Unzip(extension_zip, extension_dir)) |
65 return Status(kUnknownError, "failed to unzip automation extension"); | 65 return Status(kUnknownError, "failed to unzip automation extension"); |
66 | 66 |
67 *automation_extension = extension_dir; | 67 *automation_extension = extension_dir; |
68 return Status(kOk); | 68 return Status(kOk); |
69 } | 69 } |
70 | 70 |
71 void AddSwitches(CommandLine* command, | |
72 const char* switches[], | |
73 size_t switch_count, | |
74 const std::set<std::string>& exclude_switches) { | |
75 for (size_t i = 0; i < switch_count; ++i) { | |
76 if (exclude_switches.find(switches[i]) == exclude_switches.end()) | |
77 command->AppendSwitch(switches[i]); | |
78 } | |
79 } | |
80 | |
81 Status PrepareCommandLine(int port, | 71 Status PrepareCommandLine(int port, |
82 const Capabilities& capabilities, | 72 const Capabilities& capabilities, |
83 CommandLine* prepared_command, | 73 CommandLine* prepared_command, |
84 base::ScopedTempDir* user_data_dir, | 74 base::ScopedTempDir* user_data_dir, |
85 base::ScopedTempDir* extension_dir, | 75 base::ScopedTempDir* extension_dir, |
86 std::vector<std::string>* extension_bg_pages) { | 76 std::vector<std::string>* extension_bg_pages) { |
87 CommandLine command = capabilities.command; | 77 base::FilePath program = capabilities.binary; |
88 base::FilePath program = command.GetProgram(); | |
89 if (program.empty()) { | 78 if (program.empty()) { |
90 if (!FindChrome(&program)) | 79 if (!FindChrome(&program)) |
91 return Status(kUnknownError, "cannot find Chrome binary"); | 80 return Status(kUnknownError, "cannot find Chrome binary"); |
92 command.SetProgram(program); | |
93 } else if (!base::PathExists(program)) { | 81 } else if (!base::PathExists(program)) { |
94 return Status(kUnknownError, | 82 return Status(kUnknownError, |
95 base::StringPrintf("no chrome binary at %" PRFilePath, | 83 base::StringPrintf("no chrome binary at %" PRFilePath, |
96 program.value().c_str())); | 84 program.value().c_str())); |
97 } | 85 } |
| 86 CommandLine command(program); |
| 87 Switches switches; |
98 | 88 |
99 const char* excludable_switches[] = { | 89 // TODO(chrisgao): Add "disable-sync" when chrome 30- is not supported. |
100 "disable-hang-monitor", | 90 // For chrome 30-, it leads to crash when opening chrome://settings. |
101 "disable-prompt-on-repost", | 91 for (size_t i = 0; i < arraysize(kCommonSwitches); ++i) |
102 "full-memory-crash-report", | 92 switches.SetSwitch(kCommonSwitches[i]); |
103 "no-first-run", | 93 switches.SetSwitch("disable-hang-monitor"); |
104 "disable-background-networking", | 94 switches.SetSwitch("disable-prompt-on-repost"); |
105 // TODO(chrisgao): Add "disable-sync" when chrome 30- is not supported. | 95 switches.SetSwitch("full-memory-crash-report"); |
106 // For chrome 30-, it leads to crash when opening chrome://settings. | 96 switches.SetSwitch("no-first-run"); |
107 "disable-web-resources", | 97 switches.SetSwitch("disable-background-networking"); |
108 "safebrowsing-disable-auto-update", | 98 switches.SetSwitch("disable-web-resources"); |
109 "safebrowsing-disable-download-protection", | 99 switches.SetSwitch("safebrowsing-disable-auto-update"); |
110 "disable-client-side-phishing-detection", | 100 switches.SetSwitch("safebrowsing-disable-download-protection"); |
111 "disable-component-update", | 101 switches.SetSwitch("disable-client-side-phishing-detection"); |
112 "disable-default-apps", | 102 switches.SetSwitch("disable-component-update"); |
113 }; | 103 switches.SetSwitch("disable-default-apps"); |
| 104 switches.SetSwitch("enable-logging"); |
| 105 switches.SetSwitch("logging-level", "1"); |
| 106 switches.SetSwitch("password-store", "basic"); |
| 107 switches.SetSwitch("use-mock-keychain"); |
| 108 switches.SetSwitch("remote-debugging-port", base::IntToString(port)); |
114 | 109 |
115 AddSwitches(&command, excludable_switches, arraysize(excludable_switches), | 110 for (std::set<std::string>::const_iterator iter = |
116 capabilities.exclude_switches); | 111 capabilities.exclude_switches.begin(); |
117 AddSwitches(&command, kCommonSwitches, arraysize(kCommonSwitches), | 112 iter != capabilities.exclude_switches.end(); |
118 capabilities.exclude_switches); | 113 ++iter) { |
| 114 switches.RemoveSwitch(*iter); |
| 115 } |
| 116 switches.SetFromSwitches(capabilities.switches); |
119 | 117 |
120 command.AppendSwitch("enable-logging"); | 118 if (!switches.HasSwitch("user-data-dir")) { |
121 command.AppendSwitchASCII("logging-level", "1"); | |
122 command.AppendSwitchASCII("password-store", "basic"); | |
123 command.AppendSwitch("use-mock-keychain"); | |
124 command.AppendSwitchASCII("remote-debugging-port", base::IntToString(port)); | |
125 | |
126 if (!command.HasSwitch("user-data-dir")) { | |
127 command.AppendArg("about:blank"); | 119 command.AppendArg("about:blank"); |
128 if (!user_data_dir->CreateUniqueTempDir()) | 120 if (!user_data_dir->CreateUniqueTempDir()) |
129 return Status(kUnknownError, "cannot create temp dir for user data dir"); | 121 return Status(kUnknownError, "cannot create temp dir for user data dir"); |
130 command.AppendSwitchPath("user-data-dir", user_data_dir->path()); | 122 switches.SetSwitch("user-data-dir", user_data_dir->path().value()); |
131 Status status = internal::PrepareUserDataDir( | 123 Status status = internal::PrepareUserDataDir( |
132 user_data_dir->path(), capabilities.prefs.get(), | 124 user_data_dir->path(), capabilities.prefs.get(), |
133 capabilities.local_state.get()); | 125 capabilities.local_state.get()); |
134 if (status.IsError()) | 126 if (status.IsError()) |
135 return status; | 127 return status; |
136 } | 128 } |
137 | 129 |
138 if (!extension_dir->CreateUniqueTempDir()) { | 130 if (!extension_dir->CreateUniqueTempDir()) { |
139 return Status(kUnknownError, | 131 return Status(kUnknownError, |
140 "cannot create temp dir for unpacking extensions"); | 132 "cannot create temp dir for unpacking extensions"); |
141 } | 133 } |
142 Status status = internal::ProcessExtensions(capabilities.extensions, | 134 Status status = internal::ProcessExtensions(capabilities.extensions, |
143 extension_dir->path(), | 135 extension_dir->path(), |
144 true, | 136 true, |
145 &command, | 137 &switches, |
146 extension_bg_pages); | 138 extension_bg_pages); |
147 if (status.IsError()) | 139 if (status.IsError()) |
148 return status; | 140 return status; |
149 | 141 switches.AppendToCommandLine(&command); |
150 *prepared_command = command; | 142 *prepared_command = command; |
151 return Status(kOk); | 143 return Status(kOk); |
152 } | 144 } |
153 | 145 |
154 Status WaitForDevToolsAndCheckVersion( | 146 Status WaitForDevToolsAndCheckVersion( |
155 const NetAddress& address, | 147 const NetAddress& address, |
156 URLRequestContextGetter* context_getter, | 148 URLRequestContextGetter* context_getter, |
157 const SyncWebSocketFactory& socket_factory, | 149 const SyncWebSocketFactory& socket_factory, |
158 Log* log, | 150 Log* log, |
159 scoped_ptr<DevToolsHttpClient>* user_client) { | 151 scoped_ptr<DevToolsHttpClient>* user_client) { |
(...skipping 23 matching lines...) Expand all Loading... |
183 Status LaunchExistingChromeSession( | 175 Status LaunchExistingChromeSession( |
184 URLRequestContextGetter* context_getter, | 176 URLRequestContextGetter* context_getter, |
185 const SyncWebSocketFactory& socket_factory, | 177 const SyncWebSocketFactory& socket_factory, |
186 Log* log, | 178 Log* log, |
187 const Capabilities& capabilities, | 179 const Capabilities& capabilities, |
188 ScopedVector<DevToolsEventListener>& devtools_event_listeners, | 180 ScopedVector<DevToolsEventListener>& devtools_event_listeners, |
189 scoped_ptr<Chrome>* chrome) { | 181 scoped_ptr<Chrome>* chrome) { |
190 Status status(kOk); | 182 Status status(kOk); |
191 scoped_ptr<DevToolsHttpClient> devtools_client; | 183 scoped_ptr<DevToolsHttpClient> devtools_client; |
192 status = WaitForDevToolsAndCheckVersion( | 184 status = WaitForDevToolsAndCheckVersion( |
193 capabilities.use_existing_browser, context_getter, socket_factory, log, | 185 capabilities.debugger_address, context_getter, socket_factory, log, |
194 &devtools_client); | 186 &devtools_client); |
195 if (status.IsError()) { | 187 if (status.IsError()) { |
196 return Status(kUnknownError, "cannot connect to chrome at " + | 188 return Status(kUnknownError, "cannot connect to chrome at " + |
197 capabilities.use_existing_browser.ToString(), | 189 capabilities.debugger_address.ToString(), |
198 status); | 190 status); |
199 } | 191 } |
200 chrome->reset(new ChromeExistingImpl(devtools_client.Pass(), | 192 chrome->reset(new ChromeExistingImpl(devtools_client.Pass(), |
201 devtools_event_listeners, | 193 devtools_event_listeners, |
202 log)); | 194 log)); |
203 return Status(kOk); | 195 return Status(kOk); |
204 } | 196 } |
205 | 197 |
206 Status LaunchDesktopChrome( | 198 Status LaunchDesktopChrome( |
207 URLRequestContextGetter* context_getter, | 199 URLRequestContextGetter* context_getter, |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
321 scoped_ptr<Device> device; | 313 scoped_ptr<Device> device; |
322 if (capabilities.android_device_serial.empty()) { | 314 if (capabilities.android_device_serial.empty()) { |
323 status = device_manager->AcquireDevice(&device); | 315 status = device_manager->AcquireDevice(&device); |
324 } else { | 316 } else { |
325 status = device_manager->AcquireSpecificDevice( | 317 status = device_manager->AcquireSpecificDevice( |
326 capabilities.android_device_serial, &device); | 318 capabilities.android_device_serial, &device); |
327 } | 319 } |
328 if (!status.IsOk()) | 320 if (!status.IsOk()) |
329 return status; | 321 return status; |
330 | 322 |
331 std::string args(capabilities.android_args); | 323 Switches switches(capabilities.switches); |
332 for (size_t i = 0; i < arraysize(kCommonSwitches); i++) | 324 for (size_t i = 0; i < arraysize(kCommonSwitches); ++i) |
333 args += "--" + std::string(kCommonSwitches[i]) + " "; | 325 switches.SetSwitch(kCommonSwitches[i]); |
334 args += "--disable-fre --enable-remote-debugging"; | 326 switches.SetSwitch("disable-fre"); |
335 | 327 switches.SetSwitch("enable-remote-debugging"); |
336 status = device->StartApp(capabilities.android_package, | 328 status = device->StartApp(capabilities.android_package, |
337 capabilities.android_activity, | 329 capabilities.android_activity, |
338 capabilities.android_process, | 330 capabilities.android_process, |
339 args, port); | 331 switches.ToString(), port); |
340 if (!status.IsOk()) { | 332 if (!status.IsOk()) { |
341 device->StopApp(); | 333 device->StopApp(); |
342 return status; | 334 return status; |
343 } | 335 } |
344 | 336 |
345 scoped_ptr<DevToolsHttpClient> devtools_client; | 337 scoped_ptr<DevToolsHttpClient> devtools_client; |
346 status = WaitForDevToolsAndCheckVersion(NetAddress(port), | 338 status = WaitForDevToolsAndCheckVersion(NetAddress(port), |
347 context_getter, | 339 context_getter, |
348 socket_factory, | 340 socket_factory, |
349 log, | 341 log, |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
493 Status status = GetExtensionBackgroundPage(manifest, id, &bg_page_tmp); | 485 Status status = GetExtensionBackgroundPage(manifest, id, &bg_page_tmp); |
494 if (status.IsError()) | 486 if (status.IsError()) |
495 return status; | 487 return status; |
496 | 488 |
497 *path = extension_dir; | 489 *path = extension_dir; |
498 if (bg_page_tmp.size()) | 490 if (bg_page_tmp.size()) |
499 *bg_page = bg_page_tmp; | 491 *bg_page = bg_page_tmp; |
500 return Status(kOk); | 492 return Status(kOk); |
501 } | 493 } |
502 | 494 |
| 495 void UpdateExtensionSwitch(Switches* switches, |
| 496 const char name[], |
| 497 const base::FilePath::StringType& extension) { |
| 498 base::FilePath::StringType value = switches->GetSwitchValueNative(name); |
| 499 if (value.length()) |
| 500 value += FILE_PATH_LITERAL(","); |
| 501 value += extension; |
| 502 switches->SetSwitch(name, value); |
| 503 } |
| 504 |
503 Status ProcessExtensions(const std::vector<std::string>& extensions, | 505 Status ProcessExtensions(const std::vector<std::string>& extensions, |
504 const base::FilePath& temp_dir, | 506 const base::FilePath& temp_dir, |
505 bool include_automation_extension, | 507 bool include_automation_extension, |
506 CommandLine* command, | 508 Switches* switches, |
507 std::vector<std::string>* bg_pages) { | 509 std::vector<std::string>* bg_pages) { |
508 std::vector<std::string> bg_pages_tmp; | 510 std::vector<std::string> bg_pages_tmp; |
509 std::vector<base::FilePath::StringType> extension_paths; | 511 std::vector<base::FilePath::StringType> extension_paths; |
510 for (size_t i = 0; i < extensions.size(); ++i) { | 512 for (size_t i = 0; i < extensions.size(); ++i) { |
511 base::FilePath path; | 513 base::FilePath path; |
512 std::string bg_page; | 514 std::string bg_page; |
513 Status status = ProcessExtension(extensions[i], temp_dir, &path, &bg_page); | 515 Status status = ProcessExtension(extensions[i], temp_dir, &path, &bg_page); |
514 if (status.IsError()) { | 516 if (status.IsError()) { |
515 return Status( | 517 return Status( |
516 kUnknownError, | 518 kUnknownError, |
517 base::StringPrintf("cannot process extension #%" PRIuS, i + 1), | 519 base::StringPrintf("cannot process extension #%" PRIuS, i + 1), |
518 status); | 520 status); |
519 } | 521 } |
520 extension_paths.push_back(path.value()); | 522 extension_paths.push_back(path.value()); |
521 if (bg_page.length()) | 523 if (bg_page.length()) |
522 bg_pages_tmp.push_back(bg_page); | 524 bg_pages_tmp.push_back(bg_page); |
523 } | 525 } |
524 | 526 |
525 if (include_automation_extension) { | 527 if (include_automation_extension) { |
526 base::FilePath automation_extension; | 528 base::FilePath automation_extension; |
527 Status status = UnpackAutomationExtension(temp_dir, &automation_extension); | 529 Status status = UnpackAutomationExtension(temp_dir, &automation_extension); |
528 if (status.IsError()) | 530 if (status.IsError()) |
529 return status; | 531 return status; |
530 if (command->HasSwitch("disable-extensions")) { | 532 if (switches->HasSwitch("disable-extensions")) { |
531 command->AppendSwitchNative("load-component-extension", | 533 UpdateExtensionSwitch(switches, "load-component-extension", |
532 automation_extension.value()); | 534 automation_extension.value()); |
533 } else { | 535 } else { |
534 extension_paths.push_back(automation_extension.value()); | 536 extension_paths.push_back(automation_extension.value()); |
535 } | 537 } |
536 } | 538 } |
537 | 539 |
538 if (extension_paths.size()) { | 540 if (extension_paths.size()) { |
539 base::FilePath::StringType extension_paths_value = JoinString( | 541 base::FilePath::StringType extension_paths_value = JoinString( |
540 extension_paths, FILE_PATH_LITERAL(',')); | 542 extension_paths, FILE_PATH_LITERAL(',')); |
541 command->AppendSwitchNative("load-extension", extension_paths_value); | 543 UpdateExtensionSwitch(switches, "load-extension", extension_paths_value); |
542 } | 544 } |
543 bg_pages->swap(bg_pages_tmp); | 545 bg_pages->swap(bg_pages_tmp); |
544 return Status(kOk); | 546 return Status(kOk); |
545 } | 547 } |
546 | 548 |
547 Status WritePrefsFile( | 549 Status WritePrefsFile( |
548 const std::string& template_string, | 550 const std::string& template_string, |
549 const base::DictionaryValue* custom_prefs, | 551 const base::DictionaryValue* custom_prefs, |
550 const base::FilePath& path) { | 552 const base::FilePath& path) { |
551 int code; | 553 int code; |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
599 // Write empty "First Run" file, otherwise Chrome will wipe the default | 601 // Write empty "First Run" file, otherwise Chrome will wipe the default |
600 // profile that was written. | 602 // profile that was written. |
601 if (file_util::WriteFile( | 603 if (file_util::WriteFile( |
602 user_data_dir.AppendASCII("First Run"), "", 0) != 0) { | 604 user_data_dir.AppendASCII("First Run"), "", 0) != 0) { |
603 return Status(kUnknownError, "failed to write first run file"); | 605 return Status(kUnknownError, "failed to write first run file"); |
604 } | 606 } |
605 return Status(kOk); | 607 return Status(kOk); |
606 } | 608 } |
607 | 609 |
608 } // namespace internal | 610 } // namespace internal |
OLD | NEW |