Completed
Pull Request — master (#34)
by Alessandro
03:03 queued 40s
created

Runner::markProcessCompleted()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 3.004

Importance

Changes 6
Bugs 0 Features 1
Metric Value
c 6
b 0
f 1
dl 0
loc 18
ccs 12
cts 13
cp 0.9231
rs 9.4285
cc 3
eloc 12
nc 3
nop 1
crap 3.004
1
<?php
2
3
namespace Paraunit\Runner;
4
5
use Paraunit\Configuration\PHPUnitConfigFile;
6
use Paraunit\Printer\DebugPrinter;
7
use Paraunit\Process\ParaunitProcessAbstract;
8
use Paraunit\Process\ParaunitProcessInterface;
9
use Paraunit\Process\ProcessFactory;
10
use Paraunit\Lifecycle\EngineEvent;
11
use Paraunit\Lifecycle\ProcessEvent;
12
use Symfony\Component\Console\Output\OutputInterface;
13
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
14
15
/**
16
 * Class Runner.
17
 */
18
class Runner
19
{
20
    /** @var int */
21
    protected $maxProcessNumber;
22
23
    /** @var ParaunitProcessAbstract[] */
24
    protected $processStack;
25
26
    /** @var ParaunitProcessAbstract[] */
27
    protected $processCompleted;
28
29
    /** @var ParaunitProcessAbstract[] */
30
    protected $processRunning;
31
32
    /** @var  ProcessFactory */
33
    protected $processFactory;
34
35
    /** @var EventDispatcherInterface */
36
    protected $eventDispatcher;
37
38
    /**
39
     * @param int $maxProcessNumber
40
     * @param EventDispatcherInterface $eventDispatcher
41
     * @param ProcessFactory $processFactory
42
     */
43 8
    public function __construct(
44
        $maxProcessNumber = 10,
45
        EventDispatcherInterface $eventDispatcher,
46
        ProcessFactory $processFactory
47
    )
48
    {
49 8
        $this->eventDispatcher = $eventDispatcher;
50 8
        $this->maxProcessNumber = $maxProcessNumber;
51 8
        $this->processFactory = $processFactory;
52
53 8
        $this->processStack = array();
54 8
        $this->processCompleted = array();
55 8
        $this->processRunning = array();
56 8
    }
57
58
    /**
59
     * @param                 $files
60
     * @param OutputInterface $outputInterface
61
     * @param PHPUnitConfigFile $phpunitConfigFile
62
     * @param bool $debug
63
     * @return int
64
     */
65 8
    public function run($files, OutputInterface $outputInterface, PHPUnitConfigFile $phpunitConfigFile, $debug = false)
66
    {
67 8
        $this->eventDispatcher->dispatch(EngineEvent::BEFORE_START, new EngineEvent($outputInterface));
68
69 8
        $this->processFactory->setConfigFile($phpunitConfigFile);
70 8
        $start = new \Datetime('now');
71 8
        $this->createProcessStackFromFiles($files);
72
73 8
        $this->eventDispatcher->dispatch(
74 8
            EngineEvent::START,
75 8
            new EngineEvent($outputInterface, array('start' => $start,))
76 8
        );
77
78 8
        while ( ! empty($this->processStack) || ! empty($this->processRunning)) {
79
80 8
            if ($process = $this->runProcess($debug)) {
81 8
                $this->eventDispatcher->dispatch(ProcessEvent::PROCESS_STARTED, new ProcessEvent($process));
82 8
            }
83
84 8
            foreach ($this->processRunning as $process) {
85
86 8
                if ($process->isTerminated()) {
87
88 8
                    $this->eventDispatcher->dispatch(
89 8
                        ProcessEvent::PROCESS_TERMINATED,
90 8
                        new ProcessEvent($process, array('output_interface' => $outputInterface,))
91 8
                    );
92
                    // Completed or back to the stack
93 8
                    $this->markProcessCompleted($process);
94 8
                }
95
96 8
                usleep(500);
97 8
            }
98 8
        }
99
100 8
        $end = new \Datetime('now');
101
102 8
        $this->eventDispatcher->dispatch(
103 8
            EngineEvent::END,
104 8
            new EngineEvent(
105 8
                $outputInterface,
106 8
                array('end' => $end, 'start' => $start, 'process_completed' => $this->processCompleted)
107 8
            )
108 8
        );
109
110 8
        return $this->getReturnCode();
111
    }
112
113
    /**
114
     * @return int
115
     */
116 8
    protected function getReturnCode()
117
    {
118 8
        foreach ($this->processCompleted as $process) {
119 8
            if ($process->getExitCode() != 0) {
120 6
                return 10;
121
            }
122 2
        }
123
124 2
        return 0;
125
    }
126
127
    /**
128
     * @param string[] $files
129
     */
130 8
    protected function createProcessStackFromFiles($files)
131
    {
132 8
        foreach ($files as $file) {
133 8
            $process = $this->processFactory->createProcess($file);
134 8
            $this->processStack[$process->getUniqueId()] = $process;
135 8
        }
136 8
    }
137
138
    /**
139
     * @param $debug
140
     *
141
     * @return ParaunitProcessAbstract
142
     */
143 8
    protected function runProcess($debug)
144
    {
145 8
        if ($this->maxProcessNumber > count($this->processRunning) && ! empty($this->processStack)) {
146
            /** @var ParaunitProcessInterface $process */
147 8
            $process = array_pop($this->processStack);
148 8
            $process->start();
149 8
            $this->processRunning[$process->getUniqueId()] = $process;
150
151 8
            if ($debug) {
152
                DebugPrinter::printDebugOutput($process, $this->processRunning);
153
            }
154
155 8
            return $process;
156
        }
157 8
    }
158
159
    /**
160
     * @param ParaunitProcessAbstract $process
161
     * @throws \Exception
162
     */
163 8
    protected function markProcessCompleted(ParaunitProcessAbstract $process)
164
    {
165 8
        $pHash = $process->getUniqueId();
166
167 8
        if (array_key_exists($pHash, $this->processRunning)) {
168 8
            unset($this->processRunning[$pHash]);
169 8
        } else {
170
            throw new \Exception('Trying to remove a non-existing process from running stack\! ID: ' . $pHash);
171
        }
172
173 8
        if ($process->isToBeRetried()) {
174 3
            $process->reset();
175 3
            $process->increaseRetryCount();
176 3
            $this->processStack[$pHash] = $process;
177 3
        } else {
178 8
            $this->processCompleted[$pHash] = $process;
179
        }
180 8
    }
181
}
182