DriverService.php 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. <?php
  2. // Copyright 2004-present Facebook. All Rights Reserved.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. namespace Facebook\WebDriver\Remote\Service;
  16. use Exception;
  17. use Facebook\WebDriver\Net\URLChecker;
  18. use Symfony\Component\Process\Process;
  19. use Symfony\Component\Process\ProcessBuilder;
  20. /**
  21. * Start local WebDriver service (when remote WebDriver server is not used).
  22. */
  23. class DriverService
  24. {
  25. /**
  26. * @var string
  27. */
  28. private $executable;
  29. /**
  30. * @var string
  31. */
  32. private $url;
  33. /**
  34. * @var array
  35. */
  36. private $args;
  37. /**
  38. * @var array
  39. */
  40. private $environment;
  41. /**
  42. * @var Process|null
  43. */
  44. private $process;
  45. /**
  46. * @param string $executable
  47. * @param int $port The given port the service should use.
  48. * @param array $args
  49. * @param array|null $environment Use the system environment if it is null
  50. */
  51. public function __construct($executable, $port, $args = [], $environment = null)
  52. {
  53. $this->executable = self::checkExecutable($executable);
  54. $this->url = sprintf('http://localhost:%d', $port);
  55. $this->args = $args;
  56. $this->environment = $environment ?: $_ENV;
  57. }
  58. /**
  59. * @return string
  60. */
  61. public function getURL()
  62. {
  63. return $this->url;
  64. }
  65. /**
  66. * @return DriverService
  67. */
  68. public function start()
  69. {
  70. if ($this->process !== null) {
  71. return $this;
  72. }
  73. $this->process = $this->createProcess();
  74. $this->process->start();
  75. $checker = new URLChecker();
  76. $checker->waitUntilAvailable(20 * 1000, $this->url . '/status');
  77. return $this;
  78. }
  79. /**
  80. * @return DriverService
  81. */
  82. public function stop()
  83. {
  84. if ($this->process === null) {
  85. return $this;
  86. }
  87. $this->process->stop();
  88. $this->process = null;
  89. $checker = new URLChecker();
  90. $checker->waitUntilUnavailable(3 * 1000, $this->url . '/shutdown');
  91. return $this;
  92. }
  93. /**
  94. * @return bool
  95. */
  96. public function isRunning()
  97. {
  98. if ($this->process === null) {
  99. return false;
  100. }
  101. return $this->process->isRunning();
  102. }
  103. /**
  104. * Check if the executable is executable.
  105. *
  106. * @param string $executable
  107. * @throws Exception
  108. * @return string
  109. */
  110. protected static function checkExecutable($executable)
  111. {
  112. if (!is_file($executable)) {
  113. throw new Exception("'$executable' is not a file.");
  114. }
  115. if (!is_executable($executable)) {
  116. throw new Exception("'$executable' is not executable.");
  117. }
  118. return $executable;
  119. }
  120. /**
  121. * @return Process
  122. */
  123. private function createProcess()
  124. {
  125. // BC: ProcessBuilder deprecated since Symfony 3.4 and removed in Symfony 4.0.
  126. if (class_exists(ProcessBuilder::class)
  127. && false === mb_strpos('@deprecated', (new \ReflectionClass(ProcessBuilder::class))->getDocComment())
  128. ) {
  129. $processBuilder = (new ProcessBuilder())
  130. ->setPrefix($this->executable)
  131. ->setArguments($this->args)
  132. ->addEnvironmentVariables($this->environment);
  133. return $processBuilder->getProcess();
  134. }
  135. // Safe to use since Symfony 3.3
  136. $commandLine = array_merge([$this->executable], $this->args);
  137. return new Process($commandLine, null, $this->environment);
  138. }
  139. }