Completed
Pull Request — master (#94)
by Alessandro
05:58
created

Runner::runProcess()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4.0218

Importance

Changes 0
Metric Value
dl 0
loc 17
ccs 8
cts 9
cp 0.8889
rs 9.2
c 0
b 0
f 0
cc 4
eloc 9
nc 3
nop 1
crap 4.0218
1
<?php
2
declare(strict_types=1);
3
4
namespace Paraunit\Runner;
5
6
use Paraunit\Filter\Filter;
7
use Paraunit\Lifecycle\EngineEvent;
8
use Paraunit\Lifecycle\ProcessEvent;
9
use Paraunit\Process\ProcessBuilderFactory;
10
use Paraunit\Process\SymfonyProcessWrapper;
11
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
12
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
13
14
/**
15
 * Class Runner
16
 * @package Paraunit\Runner
17
 */
18
class Runner implements EventSubscriberInterface
19
{
20
    /** @var  ProcessBuilderFactory */
21
    private $processBuilderFactory;
22
23
    /** @var EventDispatcherInterface */
24
    private $eventDispatcher;
25
26
    /** @var Filter */
27
    private $filter;
28
29
    /** @var PipelineCollection */
30
    private $pipelineCollection;
31
32
    /** @var \SplQueue */
33
    private $queuedProcesses;
34
35
    /** @var int */
36
    private $exitCode;
37
38
    /** @var bool */
39
    private $pushed;
40
41
    /**
42
     * @param EventDispatcherInterface $eventDispatcher
43
     * @param ProcessBuilderFactory $processFactory
44
     * @param Filter $filter
45
     * @param PipelineCollection $pipelineCollection
46
     */
47 32
    public function __construct(
48
        EventDispatcherInterface $eventDispatcher,
49
        ProcessBuilderFactory $processFactory,
50
        Filter $filter,
51
        PipelineCollection $pipelineCollection
52
    ) {
53 32
        $this->eventDispatcher = $eventDispatcher;
54 32
        $this->processBuilderFactory = $processFactory;
55 32
        $this->filter = $filter;
56 32
        $this->pipelineCollection = $pipelineCollection;
57 32
        $this->queuedProcesses = new \SplQueue();
58 32
        $this->exitCode = 0;
59
    }
60
61 55
    public static function getSubscribedEvents(): array
62
    {
63
        return [
64 55
            ProcessEvent::PROCESS_TERMINATED => 'pushToPipeline',
65 55
            ProcessEvent::PROCESS_PARSING_COMPLETED => 'onProcessParsingCompleted',
66
        ];
67
    }
68
69
    /**
70
     * @return int The final exit code: 0 if no failures, 10 otherwise
71
     */
72 16
    public function run(): int
73
    {
74 16
        $this->eventDispatcher->dispatch(EngineEvent::BEFORE_START);
75
76 16
        $this->createProcessQueue();
77
78 16
        $this->eventDispatcher->dispatch(EngineEvent::START);
79
80 16
        while ($this->pushToPipeline() || $this->pipelineCollection->checkRunningState() || $this->pushed) {
81 15
            usleep(100);
82
        }
83
84 16
        $this->eventDispatcher->dispatch(EngineEvent::END);
85
86 16
        return $this->exitCode;
87
    }
88
89
    /**
90
     * @param ProcessEvent $processEvent
91
     */
92 28
    public function onProcessParsingCompleted(ProcessEvent $processEvent)
93
    {
94 28
        $process = $processEvent->getProcess();
95
96 28
        if ($process->isToBeRetried()) {
97 5
            $process->reset();
98 5
            $process->increaseRetryCount();
99
100 5
            $this->queuedProcesses->enqueue($process);
101
102 5
            $this->eventDispatcher->dispatch(ProcessEvent::PROCESS_TO_BE_RETRIED, new ProcessEvent($process));
103 27
        } elseif ($process->getExitCode() !== 0) {
104 11
            $this->exitCode = 10;
105
        }
106
    }
107
108 16
    private function createProcessQueue()
109
    {
110 16
        foreach ($this->filter->filterTestFiles() as $file) {
111 15
            $processBuilder = $this->processBuilderFactory->create($file);
112 15
            $this->queuedProcesses->enqueue(new SymfonyProcessWrapper($processBuilder, $file));
113
        }
114
    }
115
116 16
    public function pushToPipeline(): bool
117
    {
118 16
        $this->pushed = false;
119 16
        while (! $this->queuedProcesses->isEmpty() && $this->pipelineCollection->hasEmptySlots()) {
120 15
            $this->pipelineCollection->push($this->queuedProcesses->dequeue());
121 15
            $this->pushed = true;
122
        }
123
124 16
        return $this->pushed;
125
    }
126
}
127