1 | <?php |
||||
2 | /** |
||||
3 | * This file is part of graze/parallel-process. |
||||
4 | * |
||||
5 | * Copyright © 2018 Nature Delivered Ltd. <https://www.graze.com> |
||||
6 | * |
||||
7 | * For the full copyright and license information, please view the LICENSE |
||||
8 | * file that was distributed with this source code. |
||||
9 | * |
||||
10 | * @license https://github.com/graze/parallel-process/blob/master/LICENSE.md |
||||
11 | * @link https://github.com/graze/parallel-process |
||||
12 | */ |
||||
13 | |||||
14 | namespace Graze\ParallelProcess\Test\Unit; |
||||
15 | |||||
16 | use Graze\ParallelProcess\Event\RunEvent; |
||||
17 | use Graze\ParallelProcess\ProcessRun; |
||||
18 | use Graze\ParallelProcess\RunInterface; |
||||
19 | use Graze\ParallelProcess\Test\TestCase; |
||||
20 | use Mockery; |
||||
21 | use Symfony\Component\Process\Process; |
||||
22 | |||||
23 | class ProcessRunTest extends TestCase |
||||
24 | { |
||||
25 | public function testRunImplementsRunInterface() |
||||
26 | { |
||||
27 | $process = Mockery::mock(Process::class); |
||||
28 | $process->shouldReceive('stop'); |
||||
29 | $run = new ProcessRun($process); |
||||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||
30 | $this->assertInstanceOf(RunInterface::class, $run); |
||||
31 | } |
||||
32 | |||||
33 | public function testInitialState() |
||||
34 | { |
||||
35 | $process = Mockery::mock(Process::class); |
||||
36 | $process->shouldReceive('stop'); |
||||
37 | |||||
38 | $run = new ProcessRun($process); |
||||
0 ignored issues
–
show
$process of type Mockery\MockInterface is incompatible with the type Symfony\Component\Process\Process expected by parameter $process of Graze\ParallelProcess\ProcessRun::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
39 | |||||
40 | $this->assertSame($process, $run->getProcess()); |
||||
41 | |||||
42 | $process->shouldReceive('isRunning') |
||||
43 | ->andReturn(false); |
||||
44 | $process->shouldReceive('isStarted') |
||||
45 | ->andReturn(false); |
||||
46 | $process->shouldReceive('isSuccessful') |
||||
47 | ->andReturn(false); |
||||
48 | |||||
49 | $this->assertFalse($run->isRunning(), 'should not be running'); |
||||
50 | $this->assertFalse($run->hasStarted(), 'should not have started'); |
||||
51 | $this->assertFalse($run->isSuccessful(), 'should not be successful'); |
||||
52 | $this->assertTrue($run->isUpdateOnPoll(), 'update on poll should be on by deafult'); |
||||
53 | $this->assertTrue($run->isUpdateOnProcessOutput(), 'update on poll should be on by deafult'); |
||||
54 | $this->assertEquals([], $run->getExceptions(), 'no exceptions should be returned'); |
||||
55 | } |
||||
56 | |||||
57 | public function testUpdateOnPoll() |
||||
58 | { |
||||
59 | $process = Mockery::mock(Process::class); |
||||
60 | $process->shouldReceive('stop'); |
||||
61 | |||||
62 | $run = new ProcessRun($process); |
||||
0 ignored issues
–
show
$process of type Mockery\MockInterface is incompatible with the type Symfony\Component\Process\Process expected by parameter $process of Graze\ParallelProcess\ProcessRun::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
63 | |||||
64 | $this->assertTrue($run->isUpdateOnPoll()); |
||||
65 | $this->assertSame($run, $run->setUpdateOnPoll(false)); |
||||
66 | $this->assertFalse($run->isUpdateOnPoll()); |
||||
67 | } |
||||
68 | |||||
69 | public function testUpdateOnProcessOutput() |
||||
70 | { |
||||
71 | $process = Mockery::mock(Process::class); |
||||
72 | $process->shouldReceive('stop'); |
||||
73 | |||||
74 | $run = new ProcessRun($process); |
||||
0 ignored issues
–
show
$process of type Mockery\MockInterface is incompatible with the type Symfony\Component\Process\Process expected by parameter $process of Graze\ParallelProcess\ProcessRun::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
75 | |||||
76 | $this->assertTrue($run->isUpdateOnProcessOutput()); |
||||
77 | $this->assertSame($run, $run->setUpdateOnProcessOutput(false)); |
||||
78 | $this->assertFalse($run->isUpdateOnProcessOutput()); |
||||
79 | } |
||||
80 | |||||
81 | public function testProcessRunning() |
||||
82 | { |
||||
83 | $process = Mockery::mock(Process::class); |
||||
84 | $process->shouldReceive('stop'); |
||||
85 | |||||
86 | $run = new ProcessRun($process); |
||||
0 ignored issues
–
show
$process of type Mockery\MockInterface is incompatible with the type Symfony\Component\Process\Process expected by parameter $process of Graze\ParallelProcess\ProcessRun::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
87 | |||||
88 | $process->shouldReceive('isRunning') |
||||
89 | ->andReturn(true); // check |
||||
90 | $process->shouldReceive('start'); |
||||
91 | |||||
92 | $process->shouldReceive('isStarted') |
||||
93 | ->andReturn(false, true); // start, check |
||||
94 | |||||
95 | $run->start(); |
||||
96 | |||||
97 | $this->assertTrue($run->isRunning()); |
||||
98 | $this->assertTrue($run->hasStarted()); |
||||
99 | $this->assertFalse($run->isSuccessful()); |
||||
100 | } |
||||
101 | |||||
102 | public function testRun() |
||||
103 | { |
||||
104 | $process = Mockery::mock(Process::class); |
||||
105 | $process->shouldReceive('stop'); |
||||
106 | |||||
107 | $run = new ProcessRun($process); |
||||
0 ignored issues
–
show
$process of type Mockery\MockInterface is incompatible with the type Symfony\Component\Process\Process expected by parameter $process of Graze\ParallelProcess\ProcessRun::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
108 | |||||
109 | $process->shouldReceive('isRunning')->andReturn(true, false); |
||||
110 | $process->shouldReceive('start'); |
||||
111 | $process->shouldReceive('isStarted')->andReturn(false, true); |
||||
112 | |||||
113 | $run->start(); |
||||
114 | |||||
115 | $process->shouldReceive('isSuccessful')->andReturn(true); |
||||
116 | |||||
117 | $this->assertTrue($run->poll()); |
||||
118 | $this->assertFalse($run->poll()); |
||||
119 | $this->assertTrue($run->isSuccessful()); |
||||
120 | $this->assertTrue($run->hasStarted()); |
||||
121 | } |
||||
122 | |||||
123 | public function testOnStart() |
||||
124 | { |
||||
125 | $process = Mockery::mock(Process::class); |
||||
126 | $process->shouldReceive('stop'); |
||||
127 | |||||
128 | $hit = false; |
||||
129 | |||||
130 | $run = new ProcessRun($process); |
||||
0 ignored issues
–
show
$process of type Mockery\MockInterface is incompatible with the type Symfony\Component\Process\Process expected by parameter $process of Graze\ParallelProcess\ProcessRun::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
131 | $run->addListener( |
||||
132 | RunEvent::STARTED, |
||||
133 | function (RunEvent $event) use (&$run, &$hit) { |
||||
134 | $this->assertSame($event->getRun(), $run); |
||||
135 | $hit = true; |
||||
136 | } |
||||
137 | ); |
||||
138 | |||||
139 | $process->shouldReceive('start')->once(); |
||||
140 | $process->shouldReceive('isStarted')->andReturn(false, true); |
||||
141 | $process->shouldReceive('isRunning')->andReturn(false); |
||||
142 | $process->shouldReceive('isSuccessful')->once()->andReturn(true); |
||||
143 | |||||
144 | $run->start(); |
||||
145 | $this->assertFalse($run->poll()); |
||||
146 | } |
||||
147 | |||||
148 | public function testOnSuccess() |
||||
149 | { |
||||
150 | $process = Mockery::mock(Process::class); |
||||
151 | $process->shouldReceive('stop'); |
||||
152 | |||||
153 | $hit = false; |
||||
154 | |||||
155 | $run = new ProcessRun($process); |
||||
0 ignored issues
–
show
$process of type Mockery\MockInterface is incompatible with the type Symfony\Component\Process\Process expected by parameter $process of Graze\ParallelProcess\ProcessRun::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
156 | $run->addListener( |
||||
157 | RunEvent::COMPLETED, |
||||
158 | function (RunEvent $event) use (&$run, &$hit) { |
||||
159 | $this->assertSame($event->getRun(), $run); |
||||
160 | $hit = true; |
||||
161 | } |
||||
162 | ); |
||||
163 | |||||
164 | $process->shouldReceive('start')->once(); |
||||
165 | $process->shouldReceive('isStarted')->andReturn(false, true); |
||||
166 | $process->shouldReceive('isRunning')->andReturn(false); |
||||
167 | $process->shouldReceive('isSuccessful')->once()->andReturn(true); |
||||
168 | |||||
169 | $run->start(); |
||||
170 | $this->assertFalse($run->poll()); |
||||
171 | } |
||||
172 | |||||
173 | public function testOnFailure() |
||||
174 | { |
||||
175 | $process = Mockery::mock(Process::class); |
||||
176 | $process->shouldReceive('stop'); |
||||
177 | |||||
178 | $hit = false; |
||||
179 | |||||
180 | $run = new ProcessRun($process); |
||||
0 ignored issues
–
show
$process of type Mockery\MockInterface is incompatible with the type Symfony\Component\Process\Process expected by parameter $process of Graze\ParallelProcess\ProcessRun::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
181 | $run->addListener( |
||||
182 | RunEvent::FAILED, |
||||
183 | function (RunEvent $event) use (&$run, &$hit) { |
||||
184 | $this->assertSame($event->getRun(), $run); |
||||
185 | $hit = true; |
||||
186 | } |
||||
187 | ); |
||||
188 | |||||
189 | $process->shouldReceive('start')->once(); |
||||
190 | $process->shouldReceive('isStarted')->andReturn(false, true); |
||||
191 | $process->shouldReceive('isRunning')->andReturn(false); |
||||
192 | $process->shouldReceive('isSuccessful')->once()->andReturn(false); |
||||
193 | |||||
194 | $run->start(); |
||||
195 | $this->assertFalse($run->poll()); |
||||
196 | } |
||||
197 | |||||
198 | public function testOnProgress() |
||||
199 | { |
||||
200 | $process = Mockery::mock(Process::class); |
||||
201 | $process->shouldReceive('stop'); |
||||
202 | |||||
203 | $hit = false; |
||||
204 | |||||
205 | $run = new ProcessRun($process); |
||||
0 ignored issues
–
show
$process of type Mockery\MockInterface is incompatible with the type Symfony\Component\Process\Process expected by parameter $process of Graze\ParallelProcess\ProcessRun::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
206 | $run->addListener( |
||||
207 | RunEvent::UPDATED, |
||||
208 | function (RunEvent $event) use (&$run, &$hit) { |
||||
209 | $this->assertSame($event->getRun(), $run); |
||||
210 | $hit = true; |
||||
211 | } |
||||
212 | ); |
||||
213 | |||||
214 | $process->shouldReceive('start')->once(); |
||||
215 | $process->shouldReceive('isStarted')->andReturn(false, true); |
||||
216 | $process->shouldReceive('isRunning')->andReturn(true, false); |
||||
217 | $process->shouldReceive('isSuccessful')->once()->andReturn(true); |
||||
218 | |||||
219 | $run->start(); |
||||
220 | $this->assertTrue($run->poll()); |
||||
221 | $this->assertFalse($run->poll()); |
||||
222 | } |
||||
223 | |||||
224 | public function testStartingAfterStartedWillDoNothing() |
||||
225 | { |
||||
226 | $process = Mockery::mock(Process::class); |
||||
227 | $process->shouldReceive('stop'); |
||||
228 | |||||
229 | $run = new ProcessRun($process); |
||||
0 ignored issues
–
show
$process of type Mockery\MockInterface is incompatible with the type Symfony\Component\Process\Process expected by parameter $process of Graze\ParallelProcess\ProcessRun::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
230 | |||||
231 | $process->shouldReceive('isStarted') |
||||
232 | ->andReturn(true); |
||||
233 | |||||
234 | $this->assertSame($run, $run->start()); |
||||
235 | } |
||||
236 | |||||
237 | public function testEventsProvideDurationAndLastMessage() |
||||
238 | { |
||||
239 | $process = Mockery::mock(Process::class); |
||||
240 | $process->shouldReceive('stop'); |
||||
241 | |||||
242 | $process->shouldReceive('start') |
||||
243 | ->with( |
||||
244 | Mockery::on( |
||||
245 | function (callable $fn) { |
||||
246 | $this->assertNotNull($fn); |
||||
247 | $fn(Process::OUT, 'some text'); |
||||
248 | return true; |
||||
249 | } |
||||
250 | ) |
||||
251 | ) |
||||
252 | ->once(); |
||||
253 | |||||
254 | $run = new ProcessRun($process); |
||||
0 ignored issues
–
show
$process of type Mockery\MockInterface is incompatible with the type Symfony\Component\Process\Process expected by parameter $process of Graze\ParallelProcess\ProcessRun::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
255 | $run->addListener( |
||||
256 | RunEvent::UPDATED, |
||||
257 | function (RunEvent $event) use (&$run, &$hits) { |
||||
258 | $this->assertSame($event->getRun(), $run); |
||||
259 | $this->assertInternalType('float', $run->getDuration()); |
||||
0 ignored issues
–
show
The function
PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||
260 | $this->assertEquals('some text', $run->getLastMessage()); |
||||
261 | $this->assertEquals(Process::OUT, $run->getLastMessageType()); |
||||
262 | $hits++; |
||||
263 | } |
||||
264 | ); |
||||
265 | |||||
266 | $process->shouldReceive('isStarted')->andReturn(false, true); |
||||
267 | $process->shouldReceive('isRunning')->andReturn(false); |
||||
268 | $process->shouldReceive('isSuccessful')->once()->andReturn(true); |
||||
269 | |||||
270 | $run->start(); |
||||
271 | $this->assertFalse($run->poll()); |
||||
272 | } |
||||
273 | |||||
274 | public function testLastMessageHavingMultipleLinesReturnsOnePerLine() |
||||
275 | { |
||||
276 | $process = Mockery::mock(Process::class); |
||||
277 | $process->shouldReceive('stop'); |
||||
278 | |||||
279 | $process->shouldReceive('start') |
||||
280 | ->with( |
||||
281 | Mockery::on( |
||||
282 | function (callable $fn) { |
||||
283 | $this->assertNotNull($fn); |
||||
284 | $fn(Process::OUT, "line 1\n\nline 2"); |
||||
285 | return true; |
||||
286 | } |
||||
287 | ) |
||||
288 | ) |
||||
289 | ->once(); |
||||
290 | |||||
291 | $hits = 0; |
||||
292 | $run = new ProcessRun($process); |
||||
0 ignored issues
–
show
$process of type Mockery\MockInterface is incompatible with the type Symfony\Component\Process\Process expected by parameter $process of Graze\ParallelProcess\ProcessRun::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
293 | $run->addListener( |
||||
294 | RunEvent::UPDATED, |
||||
295 | function (RunEvent $event) use (&$run, &$hits) { |
||||
296 | $this->assertSame($event->getRun(), $run); |
||||
297 | $this->assertInternalType('float', $run->getDuration()); |
||||
0 ignored issues
–
show
The function
PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||
298 | $this->assertContains($run->getLastMessage(), ['line 1', 'line 2']); |
||||
299 | $this->assertEquals(Process::OUT, $run->getLastMessageType()); |
||||
300 | $hits++; |
||||
301 | } |
||||
302 | ); |
||||
303 | |||||
304 | $process->shouldReceive('isStarted')->andReturn(false, true); |
||||
305 | $process->shouldReceive('isRunning')->andReturn(false); |
||||
306 | $process->shouldReceive('isSuccessful')->once()->andReturn(true); |
||||
307 | |||||
308 | $run->start(); |
||||
309 | $this->assertFalse($run->poll()); |
||||
310 | $this->assertEquals(2, $hits); |
||||
311 | } |
||||
312 | |||||
313 | public function testUpdateOnPollOffDoesNotUpdateOnPoll() |
||||
314 | { |
||||
315 | $process = Mockery::mock(Process::class); |
||||
316 | $process->shouldReceive('stop'); |
||||
317 | |||||
318 | $process->shouldReceive('start')->once(); |
||||
319 | |||||
320 | $run = new ProcessRun($process); |
||||
0 ignored issues
–
show
$process of type Mockery\MockInterface is incompatible with the type Symfony\Component\Process\Process expected by parameter $process of Graze\ParallelProcess\ProcessRun::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
321 | $run->addListener( |
||||
322 | RunEvent::UPDATED, |
||||
323 | function () { |
||||
324 | $this->fail('onProgress should not be called'); |
||||
325 | } |
||||
326 | ); |
||||
327 | $run->setUpdateOnPoll(false); |
||||
328 | |||||
329 | $process->shouldReceive('isStarted')->andReturn(false, true); |
||||
330 | $process->shouldReceive('isRunning')->andReturn(true, false); |
||||
331 | $process->shouldReceive('isSuccessful')->once()->andReturn(true); |
||||
332 | |||||
333 | $run->start(); |
||||
334 | $this->assertTrue($run->poll()); |
||||
335 | $this->assertFalse($run->poll()); |
||||
336 | } |
||||
337 | |||||
338 | public function testUpdateOnOutputOffDoesNotCallUpdateOnOutput() |
||||
339 | { |
||||
340 | $process = Mockery::mock(Process::class); |
||||
341 | $process->shouldReceive('stop'); |
||||
342 | |||||
343 | $process->shouldReceive('start') |
||||
344 | ->with( |
||||
345 | Mockery::on( |
||||
346 | function (callable $fn) { |
||||
347 | $this->assertNotNull($fn); |
||||
348 | $fn(Process::STDOUT, 'some text'); |
||||
349 | return true; |
||||
350 | } |
||||
351 | ) |
||||
352 | ) |
||||
353 | ->once(); |
||||
354 | |||||
355 | $run = new ProcessRun($process); |
||||
0 ignored issues
–
show
$process of type Mockery\MockInterface is incompatible with the type Symfony\Component\Process\Process expected by parameter $process of Graze\ParallelProcess\ProcessRun::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
356 | $run->addListener( |
||||
357 | RunEvent::UPDATED, |
||||
358 | function () { |
||||
359 | $this->fail('onProgress should not be called'); |
||||
360 | } |
||||
361 | ); |
||||
362 | $run->setUpdateOnProcessOutput(false); |
||||
363 | |||||
364 | $process->shouldReceive('isStarted')->andReturn(false, true); |
||||
365 | $process->shouldReceive('isRunning')->andReturn(false); |
||||
366 | $process->shouldReceive('isSuccessful')->once()->andReturn(true); |
||||
367 | |||||
368 | $run->start(); |
||||
369 | $this->assertFalse($run->poll()); |
||||
370 | } |
||||
371 | |||||
372 | public function testGetPriority() |
||||
373 | { |
||||
374 | $process = Mockery::mock(Process::class); |
||||
375 | $process->allows(['stop' => null, 'isStarted' => false]); |
||||
376 | $run = new ProcessRun($process, [], 1.5); |
||||
0 ignored issues
–
show
$process of type Mockery\MockInterface is incompatible with the type Symfony\Component\Process\Process expected by parameter $process of Graze\ParallelProcess\ProcessRun::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
377 | |||||
378 | $this->assertEquals(1.5, $run->getPriority()); |
||||
379 | $this->assertSame($run, $run->setPriority(2)); |
||||
380 | $this->assertEquals(2, $run->getPriority()); |
||||
381 | } |
||||
382 | } |
||||
383 |