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 <stddef.h> | 7 #include <stddef.h> |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <memory> |
10 #include <utility> | 11 #include <utility> |
11 #include <vector> | 12 #include <vector> |
12 | 13 |
13 #include "base/base64.h" | 14 #include "base/base64.h" |
14 #include "base/bind.h" | 15 #include "base/bind.h" |
15 #include "base/command_line.h" | 16 #include "base/command_line.h" |
16 #include "base/files/file_path.h" | 17 #include "base/files/file_path.h" |
17 #include "base/files/file_util.h" | 18 #include "base/files/file_util.h" |
18 #include "base/files/scoped_file.h" | 19 #include "base/files/scoped_file.h" |
19 #include "base/format_macros.h" | 20 #include "base/format_macros.h" |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
237 } | 238 } |
238 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50)); | 239 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50)); |
239 } | 240 } |
240 return Status(kUnknownError, "unable to discover open pages"); | 241 return Status(kUnknownError, "unable to discover open pages"); |
241 } | 242 } |
242 | 243 |
243 Status CreateBrowserwideDevToolsClientAndConnect( | 244 Status CreateBrowserwideDevToolsClientAndConnect( |
244 const NetAddress& address, | 245 const NetAddress& address, |
245 const PerfLoggingPrefs& perf_logging_prefs, | 246 const PerfLoggingPrefs& perf_logging_prefs, |
246 const SyncWebSocketFactory& socket_factory, | 247 const SyncWebSocketFactory& socket_factory, |
247 const ScopedVector<DevToolsEventListener>& devtools_event_listeners, | 248 const std::vector<std::unique_ptr<DevToolsEventListener>>& |
| 249 devtools_event_listeners, |
248 std::unique_ptr<DevToolsClient>* browser_client) { | 250 std::unique_ptr<DevToolsClient>* browser_client) { |
249 std::unique_ptr<DevToolsClient> client(new DevToolsClientImpl( | 251 std::unique_ptr<DevToolsClient> client(new DevToolsClientImpl( |
250 socket_factory, base::StringPrintf("ws://%s/devtools/browser/", | 252 socket_factory, base::StringPrintf("ws://%s/devtools/browser/", |
251 address.ToString().c_str()), | 253 address.ToString().c_str()), |
252 DevToolsClientImpl::kBrowserwideDevToolsClientId)); | 254 DevToolsClientImpl::kBrowserwideDevToolsClientId)); |
253 for (ScopedVector<DevToolsEventListener>::const_iterator it = | 255 for (const auto& listener : devtools_event_listeners) { |
254 devtools_event_listeners.begin(); | |
255 it != devtools_event_listeners.end(); | |
256 ++it) { | |
257 // Only add listeners that subscribe to the browser-wide |DevToolsClient|. | 256 // Only add listeners that subscribe to the browser-wide |DevToolsClient|. |
258 // Otherwise, listeners will think this client is associated with a webview, | 257 // Otherwise, listeners will think this client is associated with a webview, |
259 // and will send unrecognized commands to it. | 258 // and will send unrecognized commands to it. |
260 if ((*it)->subscribes_to_browser()) | 259 if (listener->subscribes_to_browser()) |
261 client->AddListener(*it); | 260 client->AddListener(listener.get()); |
262 } | 261 } |
263 // Provide the client regardless of whether it connects, so that Chrome always | 262 // Provide the client regardless of whether it connects, so that Chrome always |
264 // has a valid |devtools_websocket_client_|. If not connected, no listeners | 263 // has a valid |devtools_websocket_client_|. If not connected, no listeners |
265 // will be notified, and client will just return kDisconnected errors if used. | 264 // will be notified, and client will just return kDisconnected errors if used. |
266 *browser_client = std::move(client); | 265 *browser_client = std::move(client); |
267 // To avoid unnecessary overhead, only connect if tracing is enabled, since | 266 // To avoid unnecessary overhead, only connect if tracing is enabled, since |
268 // the browser-wide client is currently only used for tracing. | 267 // the browser-wide client is currently only used for tracing. |
269 if (!perf_logging_prefs.trace_categories.empty()) { | 268 if (!perf_logging_prefs.trace_categories.empty()) { |
270 Status status = (*browser_client)->ConnectIfNecessary(); | 269 Status status = (*browser_client)->ConnectIfNecessary(); |
271 if (status.IsError()) | 270 if (status.IsError()) |
272 return status; | 271 return status; |
273 } | 272 } |
274 return Status(kOk); | 273 return Status(kOk); |
275 } | 274 } |
276 | 275 |
277 Status LaunchRemoteChromeSession( | 276 Status LaunchRemoteChromeSession( |
278 URLRequestContextGetter* context_getter, | 277 URLRequestContextGetter* context_getter, |
279 const SyncWebSocketFactory& socket_factory, | 278 const SyncWebSocketFactory& socket_factory, |
280 const Capabilities& capabilities, | 279 const Capabilities& capabilities, |
281 ScopedVector<DevToolsEventListener>* devtools_event_listeners, | 280 std::vector<std::unique_ptr<DevToolsEventListener>> |
| 281 devtools_event_listeners, |
282 std::unique_ptr<Chrome>* chrome) { | 282 std::unique_ptr<Chrome>* chrome) { |
283 Status status(kOk); | 283 Status status(kOk); |
284 std::unique_ptr<DevToolsHttpClient> devtools_http_client; | 284 std::unique_ptr<DevToolsHttpClient> devtools_http_client; |
285 status = WaitForDevToolsAndCheckVersion( | 285 status = WaitForDevToolsAndCheckVersion( |
286 capabilities.debugger_address, context_getter, socket_factory, | 286 capabilities.debugger_address, context_getter, socket_factory, |
287 &capabilities, &devtools_http_client); | 287 &capabilities, &devtools_http_client); |
288 if (status.IsError()) { | 288 if (status.IsError()) { |
289 return Status(kUnknownError, "cannot connect to chrome at " + | 289 return Status(kUnknownError, "cannot connect to chrome at " + |
290 capabilities.debugger_address.ToString(), | 290 capabilities.debugger_address.ToString(), |
291 status); | 291 status); |
292 } | 292 } |
293 | 293 |
294 std::unique_ptr<DevToolsClient> devtools_websocket_client; | 294 std::unique_ptr<DevToolsClient> devtools_websocket_client; |
295 status = CreateBrowserwideDevToolsClientAndConnect( | 295 status = CreateBrowserwideDevToolsClientAndConnect( |
296 capabilities.debugger_address, capabilities.perf_logging_prefs, | 296 capabilities.debugger_address, capabilities.perf_logging_prefs, |
297 socket_factory, *devtools_event_listeners, &devtools_websocket_client); | 297 socket_factory, devtools_event_listeners, &devtools_websocket_client); |
298 if (status.IsError()) { | 298 if (status.IsError()) { |
299 LOG(WARNING) << "Browser-wide DevTools client failed to connect: " | 299 LOG(WARNING) << "Browser-wide DevTools client failed to connect: " |
300 << status.message(); | 300 << status.message(); |
301 } | 301 } |
302 | 302 |
303 chrome->reset(new ChromeRemoteImpl(std::move(devtools_http_client), | 303 chrome->reset(new ChromeRemoteImpl( |
304 std::move(devtools_websocket_client), | 304 std::move(devtools_http_client), std::move(devtools_websocket_client), |
305 *devtools_event_listeners, | 305 std::move(devtools_event_listeners), capabilities.page_load_strategy)); |
306 capabilities.page_load_strategy)); | |
307 return Status(kOk); | 306 return Status(kOk); |
308 } | 307 } |
309 | 308 |
310 Status LaunchDesktopChrome( | 309 Status LaunchDesktopChrome(URLRequestContextGetter* context_getter, |
311 URLRequestContextGetter* context_getter, | 310 uint16_t port, |
312 uint16_t port, | 311 std::unique_ptr<PortReservation> port_reservation, |
313 std::unique_ptr<PortReservation> port_reservation, | 312 const SyncWebSocketFactory& socket_factory, |
314 const SyncWebSocketFactory& socket_factory, | 313 const Capabilities& capabilities, |
315 const Capabilities& capabilities, | 314 std::vector<std::unique_ptr<DevToolsEventListener>> |
316 ScopedVector<DevToolsEventListener>* devtools_event_listeners, | 315 devtools_event_listeners, |
317 std::unique_ptr<Chrome>* chrome, | 316 std::unique_ptr<Chrome>* chrome, |
318 bool w3c_compliant) { | 317 bool w3c_compliant) { |
319 base::CommandLine command(base::CommandLine::NO_PROGRAM); | 318 base::CommandLine command(base::CommandLine::NO_PROGRAM); |
320 base::ScopedTempDir user_data_dir; | 319 base::ScopedTempDir user_data_dir; |
321 base::ScopedTempDir extension_dir; | 320 base::ScopedTempDir extension_dir; |
322 std::vector<std::string> extension_bg_pages; | 321 std::vector<std::string> extension_bg_pages; |
323 Status status = PrepareCommandLine(port, | 322 Status status = PrepareCommandLine(port, |
324 capabilities, | 323 capabilities, |
325 &command, | 324 &command, |
326 &user_data_dir, | 325 &user_data_dir, |
327 &extension_dir, | 326 &extension_dir, |
328 &extension_bg_pages); | 327 &extension_bg_pages); |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
425 if (base::GetTerminationStatus(process.Handle(), &exit_code) == | 424 if (base::GetTerminationStatus(process.Handle(), &exit_code) == |
426 base::TERMINATION_STATUS_STILL_RUNNING) | 425 base::TERMINATION_STATUS_STILL_RUNNING) |
427 return Status(kUnknownError, "cannot kill Chrome", status); | 426 return Status(kUnknownError, "cannot kill Chrome", status); |
428 } | 427 } |
429 return status; | 428 return status; |
430 } | 429 } |
431 | 430 |
432 std::unique_ptr<DevToolsClient> devtools_websocket_client; | 431 std::unique_ptr<DevToolsClient> devtools_websocket_client; |
433 status = CreateBrowserwideDevToolsClientAndConnect( | 432 status = CreateBrowserwideDevToolsClientAndConnect( |
434 NetAddress(port), capabilities.perf_logging_prefs, socket_factory, | 433 NetAddress(port), capabilities.perf_logging_prefs, socket_factory, |
435 *devtools_event_listeners, &devtools_websocket_client); | 434 devtools_event_listeners, &devtools_websocket_client); |
436 if (status.IsError()) { | 435 if (status.IsError()) { |
437 LOG(WARNING) << "Browser-wide DevTools client failed to connect: " | 436 LOG(WARNING) << "Browser-wide DevTools client failed to connect: " |
438 << status.message(); | 437 << status.message(); |
439 } | 438 } |
440 | 439 |
441 std::unique_ptr<ChromeDesktopImpl> chrome_desktop( | 440 std::unique_ptr<ChromeDesktopImpl> chrome_desktop(new ChromeDesktopImpl( |
442 new ChromeDesktopImpl(std::move(devtools_http_client), | 441 std::move(devtools_http_client), std::move(devtools_websocket_client), |
443 std::move(devtools_websocket_client), | 442 std::move(devtools_event_listeners), std::move(port_reservation), |
444 *devtools_event_listeners, | 443 capabilities.page_load_strategy, std::move(process), command, |
445 std::move(port_reservation), | 444 &user_data_dir, &extension_dir, capabilities.network_emulation_enabled)); |
446 capabilities.page_load_strategy, | |
447 std::move(process), | |
448 command, | |
449 &user_data_dir, | |
450 &extension_dir, | |
451 capabilities.network_emulation_enabled)); | |
452 for (size_t i = 0; i < extension_bg_pages.size(); ++i) { | 445 for (size_t i = 0; i < extension_bg_pages.size(); ++i) { |
453 VLOG(0) << "Waiting for extension bg page load: " << extension_bg_pages[i]; | 446 VLOG(0) << "Waiting for extension bg page load: " << extension_bg_pages[i]; |
454 std::unique_ptr<WebView> web_view; | 447 std::unique_ptr<WebView> web_view; |
455 Status status = chrome_desktop->WaitForPageToLoad( | 448 Status status = chrome_desktop->WaitForPageToLoad( |
456 extension_bg_pages[i], base::TimeDelta::FromSeconds(10), | 449 extension_bg_pages[i], base::TimeDelta::FromSeconds(10), |
457 &web_view, w3c_compliant); | 450 &web_view, w3c_compliant); |
458 if (status.IsError()) { | 451 if (status.IsError()) { |
459 return Status(kUnknownError, | 452 return Status(kUnknownError, |
460 "failed to wait for extension background page to load: " + | 453 "failed to wait for extension background page to load: " + |
461 extension_bg_pages[i], | 454 extension_bg_pages[i], |
462 status); | 455 status); |
463 } | 456 } |
464 } | 457 } |
465 *chrome = std::move(chrome_desktop); | 458 *chrome = std::move(chrome_desktop); |
466 return Status(kOk); | 459 return Status(kOk); |
467 } | 460 } |
468 | 461 |
469 Status LaunchAndroidChrome( | 462 Status LaunchAndroidChrome(URLRequestContextGetter* context_getter, |
470 URLRequestContextGetter* context_getter, | 463 uint16_t port, |
471 uint16_t port, | 464 std::unique_ptr<PortReservation> port_reservation, |
472 std::unique_ptr<PortReservation> port_reservation, | 465 const SyncWebSocketFactory& socket_factory, |
473 const SyncWebSocketFactory& socket_factory, | 466 const Capabilities& capabilities, |
474 const Capabilities& capabilities, | 467 std::vector<std::unique_ptr<DevToolsEventListener>> |
475 ScopedVector<DevToolsEventListener>* devtools_event_listeners, | 468 devtools_event_listeners, |
476 DeviceManager* device_manager, | 469 DeviceManager* device_manager, |
477 std::unique_ptr<Chrome>* chrome) { | 470 std::unique_ptr<Chrome>* chrome) { |
478 Status status(kOk); | 471 Status status(kOk); |
479 std::unique_ptr<Device> device; | 472 std::unique_ptr<Device> device; |
480 if (capabilities.android_device_serial.empty()) { | 473 if (capabilities.android_device_serial.empty()) { |
481 status = device_manager->AcquireDevice(&device); | 474 status = device_manager->AcquireDevice(&device); |
482 } else { | 475 } else { |
483 status = device_manager->AcquireSpecificDevice( | 476 status = device_manager->AcquireSpecificDevice( |
484 capabilities.android_device_serial, &device); | 477 capabilities.android_device_serial, &device); |
485 } | 478 } |
486 if (status.IsError()) | 479 if (status.IsError()) |
487 return status; | 480 return status; |
(...skipping 23 matching lines...) Expand all Loading... |
511 &capabilities, | 504 &capabilities, |
512 &devtools_http_client); | 505 &devtools_http_client); |
513 if (status.IsError()) { | 506 if (status.IsError()) { |
514 device->TearDown(); | 507 device->TearDown(); |
515 return status; | 508 return status; |
516 } | 509 } |
517 | 510 |
518 std::unique_ptr<DevToolsClient> devtools_websocket_client; | 511 std::unique_ptr<DevToolsClient> devtools_websocket_client; |
519 status = CreateBrowserwideDevToolsClientAndConnect( | 512 status = CreateBrowserwideDevToolsClientAndConnect( |
520 NetAddress(port), capabilities.perf_logging_prefs, socket_factory, | 513 NetAddress(port), capabilities.perf_logging_prefs, socket_factory, |
521 *devtools_event_listeners, &devtools_websocket_client); | 514 devtools_event_listeners, &devtools_websocket_client); |
522 if (status.IsError()) { | 515 if (status.IsError()) { |
523 LOG(WARNING) << "Browser-wide DevTools client failed to connect: " | 516 LOG(WARNING) << "Browser-wide DevTools client failed to connect: " |
524 << status.message(); | 517 << status.message(); |
525 } | 518 } |
526 | 519 |
527 chrome->reset(new ChromeAndroidImpl(std::move(devtools_http_client), | 520 chrome->reset(new ChromeAndroidImpl( |
528 std::move(devtools_websocket_client), | 521 std::move(devtools_http_client), std::move(devtools_websocket_client), |
529 *devtools_event_listeners, | 522 std::move(devtools_event_listeners), std::move(port_reservation), |
530 std::move(port_reservation), | 523 capabilities.page_load_strategy, std::move(device))); |
531 capabilities.page_load_strategy, | |
532 std::move(device))); | |
533 return Status(kOk); | 524 return Status(kOk); |
534 } | 525 } |
535 | 526 |
536 } // namespace | 527 } // namespace |
537 | 528 |
538 Status LaunchChrome( | 529 Status LaunchChrome(URLRequestContextGetter* context_getter, |
539 URLRequestContextGetter* context_getter, | 530 const SyncWebSocketFactory& socket_factory, |
540 const SyncWebSocketFactory& socket_factory, | 531 DeviceManager* device_manager, |
541 DeviceManager* device_manager, | 532 PortServer* port_server, |
542 PortServer* port_server, | 533 PortManager* port_manager, |
543 PortManager* port_manager, | 534 const Capabilities& capabilities, |
544 const Capabilities& capabilities, | 535 std::vector<std::unique_ptr<DevToolsEventListener>> |
545 ScopedVector<DevToolsEventListener>* devtools_event_listeners, | 536 devtools_event_listeners, |
546 std::unique_ptr<Chrome>* chrome, | 537 std::unique_ptr<Chrome>* chrome, |
547 bool w3c_compliant) { | 538 bool w3c_compliant) { |
548 if (capabilities.IsRemoteBrowser()) { | 539 if (capabilities.IsRemoteBrowser()) { |
549 return LaunchRemoteChromeSession( | 540 return LaunchRemoteChromeSession( |
550 context_getter, socket_factory, | 541 context_getter, socket_factory, capabilities, |
551 capabilities, devtools_event_listeners, chrome); | 542 std::move(devtools_event_listeners), chrome); |
552 } | 543 } |
553 | 544 |
554 uint16_t port = 0; | 545 uint16_t port = 0; |
555 std::unique_ptr<PortReservation> port_reservation; | 546 std::unique_ptr<PortReservation> port_reservation; |
556 Status port_status(kOk); | 547 Status port_status(kOk); |
557 | 548 |
558 if (capabilities.IsAndroid()) { | 549 if (capabilities.IsAndroid()) { |
559 if (port_server) | 550 if (port_server) |
560 port_status = port_server->ReservePort(&port, &port_reservation); | 551 port_status = port_server->ReservePort(&port, &port_reservation); |
561 else | 552 else |
562 port_status = port_manager->ReservePortFromPool(&port, &port_reservation); | 553 port_status = port_manager->ReservePortFromPool(&port, &port_reservation); |
563 if (port_status.IsError()) | 554 if (port_status.IsError()) |
564 return Status(kUnknownError, "cannot reserve port for Chrome", | 555 return Status(kUnknownError, "cannot reserve port for Chrome", |
565 port_status); | 556 port_status); |
566 return LaunchAndroidChrome( | 557 return LaunchAndroidChrome( |
567 context_getter, port, std::move(port_reservation), socket_factory, | 558 context_getter, port, std::move(port_reservation), socket_factory, |
568 capabilities, devtools_event_listeners, device_manager, chrome); | 559 capabilities, std::move(devtools_event_listeners), device_manager, |
| 560 chrome); |
569 } else { | 561 } else { |
570 if (port_server) | 562 if (port_server) |
571 port_status = port_server->ReservePort(&port, &port_reservation); | 563 port_status = port_server->ReservePort(&port, &port_reservation); |
572 else | 564 else |
573 port_status = port_manager->ReservePort(&port, &port_reservation); | 565 port_status = port_manager->ReservePort(&port, &port_reservation); |
574 if (port_status.IsError()) | 566 if (port_status.IsError()) |
575 return Status(kUnknownError, "cannot reserve port for Chrome", | 567 return Status(kUnknownError, "cannot reserve port for Chrome", |
576 port_status); | 568 port_status); |
577 return LaunchDesktopChrome(context_getter, port, | 569 return LaunchDesktopChrome( |
578 std::move(port_reservation), socket_factory, | 570 context_getter, port, std::move(port_reservation), socket_factory, |
579 capabilities, devtools_event_listeners, chrome, | 571 capabilities, std::move(devtools_event_listeners), chrome, |
580 w3c_compliant); | 572 w3c_compliant); |
581 } | 573 } |
582 } | 574 } |
583 | 575 |
584 namespace internal { | 576 namespace internal { |
585 | 577 |
586 void ConvertHexadecimalToIDAlphabet(std::string* id) { | 578 void ConvertHexadecimalToIDAlphabet(std::string* id) { |
587 for (size_t i = 0; i < id->size(); ++i) { | 579 for (size_t i = 0; i < id->size(); ++i) { |
588 int val; | 580 int val; |
589 if (base::HexStringToInt(base::StringPiece(id->begin() + i, | 581 if (base::HexStringToInt(base::StringPiece(id->begin() + i, |
590 id->begin() + i + 1), | 582 id->begin() + i + 1), |
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
881 // Write empty "First Run" file, otherwise Chrome will wipe the default | 873 // Write empty "First Run" file, otherwise Chrome will wipe the default |
882 // profile that was written. | 874 // profile that was written. |
883 if (base::WriteFile( | 875 if (base::WriteFile( |
884 user_data_dir.Append(chrome::kFirstRunSentinel), "", 0) != 0) { | 876 user_data_dir.Append(chrome::kFirstRunSentinel), "", 0) != 0) { |
885 return Status(kUnknownError, "failed to write first run file"); | 877 return Status(kUnknownError, "failed to write first run file"); |
886 } | 878 } |
887 return Status(kOk); | 879 return Status(kOk); |
888 } | 880 } |
889 | 881 |
890 } // namespace internal | 882 } // namespace internal |
OLD | NEW |