RunBefore.php 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. <?php
  2. namespace Codeception\Extension;
  3. use Codeception\Events;
  4. use Codeception\Exception\ExtensionException;
  5. use Codeception\Extension;
  6. use Symfony\Component\Process\Process;
  7. /**
  8. * Extension for execution of some processes before running tests.
  9. *
  10. * Processes can be independent and dependent.
  11. * Independent processes run independently of each other.
  12. * Dependent processes run sequentially one by one.
  13. *
  14. * Can be configured in suite config:
  15. *
  16. * ```yaml
  17. * # acceptance.suite.yml
  18. * extensions:
  19. * enabled:
  20. * - Codeception\Extension\RunBefore:
  21. * - independent_process_1
  22. * -
  23. * - dependent_process_1_1
  24. * - dependent_process_1_2
  25. * - independent_process_2
  26. * -
  27. * - dependent_process_2_1
  28. * - dependent_process_2_2
  29. * ```
  30. *
  31. * HINT: you can use different configurations per environment.
  32. */
  33. class RunBefore extends Extension
  34. {
  35. protected $config = [];
  36. protected static $events = [
  37. Events::SUITE_BEFORE => 'runBefore'
  38. ];
  39. /** @var array[] */
  40. private $processes = [];
  41. public function _initialize()
  42. {
  43. if (!class_exists('Symfony\Component\Process\Process')) {
  44. throw new ExtensionException($this, 'symfony/process package is required');
  45. }
  46. }
  47. public function runBefore()
  48. {
  49. $this->runProcesses();
  50. $this->processMonitoring();
  51. }
  52. private function runProcesses()
  53. {
  54. foreach ($this->config as $item) {
  55. if (is_array($item)) {
  56. $currentCommand = array_shift($item);
  57. $followingCommands = $item;
  58. } else {
  59. $currentCommand = $item;
  60. $followingCommands = [];
  61. }
  62. $process = $this->runProcess($currentCommand);
  63. $this->addProcessToMonitoring($process, $followingCommands);
  64. }
  65. }
  66. /**
  67. * @param string $command
  68. * @return Process
  69. */
  70. private function runProcess($command)
  71. {
  72. $this->output->debug('[RunBefore] Starting ' . $command);
  73. $process = new Process($command, $this->getRootDir());
  74. $process->start();
  75. return $process;
  76. }
  77. /**
  78. * @param string[] $followingCommands
  79. */
  80. private function addProcessToMonitoring(Process $process, array $followingCommands)
  81. {
  82. $this->processes[] = [
  83. 'instance' => $process,
  84. 'following' => $followingCommands
  85. ];
  86. }
  87. /**
  88. * @param int $index
  89. */
  90. private function removeProcessFromMonitoring($index)
  91. {
  92. unset($this->processes[$index]);
  93. }
  94. private function processMonitoring()
  95. {
  96. while (count($this->processes) !== 0) {
  97. $this->checkProcesses();
  98. sleep(1);
  99. }
  100. }
  101. private function checkProcesses()
  102. {
  103. foreach ($this->processes as $index => $process) {
  104. if (!$this->isRunning($process['instance'])) {
  105. $this->output->debug('[RunBefore] Completing ' . $process['instance']->getCommandLine());
  106. $this->runFollowingCommand($process['following']);
  107. $this->removeProcessFromMonitoring($index);
  108. }
  109. }
  110. }
  111. /**
  112. * @param string[] $followingCommands
  113. */
  114. private function runFollowingCommand(array $followingCommands)
  115. {
  116. if (count($followingCommands) > 0) {
  117. $process = $this->runProcess(array_shift($followingCommands));
  118. $this->addProcessToMonitoring($process, $followingCommands);
  119. }
  120. }
  121. private function isRunning(Process $process)
  122. {
  123. if ($process->isRunning()) {
  124. return true;
  125. }
  126. return false;
  127. }
  128. }