Passed
Push — master ( c649ab...71b580 )
by Harry
02:19
created

testRunningRunAddingToAnInstantRunProcessCarriesOn()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 26
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 26
rs 8.8571
c 0
b 0
f 0
cc 1
eloc 18
nc 1
nop 0
1
<?php
2
3
/**
4
 * This file is part of graze/parallel-process.
5
 *
6
 * Copyright (c) 2017 Nature Delivered Ltd. <https://www.graze.com>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 *
11
 * @license https://github.com/graze/parallel-process/blob/master/LICENSE.md
12
 * @link    https://github.com/graze/parallel-process
13
 */
14
15
namespace Graze\ParallelProcess\Test\Unit;
16
17
use Graze\DataStructure\Collection\CollectionInterface;
18
use Graze\ParallelProcess\Pool;
19
use Graze\ParallelProcess\Run;
20
use Graze\ParallelProcess\RunInterface;
21
use Graze\ParallelProcess\Test\TestCase;
22
use Mockery;
23
use Symfony\Component\Process\Process;
24
25
class PoolTest extends TestCase
26
{
27
    /** @var mixed */
28
    private $process;
29
30
    public function setUp()
31
    {
32
        parent::setUp();
33
34
        $this->process = Mockery::mock(Process::class)
35
                                ->allows(['stop' => null, 'isStarted' => false, 'isRunning' => false]);
36
    }
37
38
    public function testPoolIsARunInterface()
39
    {
40
        $pool = new Pool();
41
        $this->assertInstanceOf(RunInterface::class, $pool);
42
    }
43
44
    public function testPoolIsACollectionOfRuns()
45
    {
46
        $pool = new Pool();
47
        $this->assertInstanceOf(CollectionInterface::class, $pool);
48
49
        $this->assertSame($pool, $pool->add($this->process));
50
51
        $runs = $pool->getAll();
52
        $this->assertCount(1, $runs);
53
54
        $this->assertInstanceOf(Run::class, reset($runs));
55
    }
56
57
    public function testPoolInitialStateWithProcess()
58
    {
59
        $pool = new Pool();
60
        $pool->add($this->process);
61
62
        $this->assertFalse($pool->isSuccessful());
63
        $this->assertFalse($pool->isRunning());
64
        $this->assertFalse($pool->hasStarted());
65
    }
66
67
    public function testPoolConstructor()
68
    {
69
        $runs = [];
70
        for ($i = 0; $i < 2; $i++) {
71
            $runs[] = Mockery::mock(RunInterface::class)
72
                             ->allows(['isRunning' => false, 'hasStarted' => false]);
73
        }
74
75
        $pool = new Pool($runs);
76
77
        $this->assertEquals(2, $pool->count());
78
    }
79
80
    /**
81
     * @expectedException \InvalidArgumentException
82
     */
83
    public function testAddingNonRunInterfaceWillThrowException()
84
    {
85
        $nope = Mockery::mock();
86
        $pool = new Pool();
87
        $pool->add($nope);
0 ignored issues
show
Bug introduced by
$nope of type Mockery\MockInterface is incompatible with the type Symfony\Component\Proces...lelProcess\RunInterface expected by parameter $item of Graze\ParallelProcess\Pool::add(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

87
        $pool->add(/** @scrutinizer ignore-type */ $nope);
Loading history...
88
    }
89
90
    public function testPoolInitialStateWithNoRuns()
91
    {
92
        $pool = new Pool();
93
94
        $this->assertFalse($pool->isSuccessful(), 'should not be successful');
95
        $this->assertFalse($pool->isRunning(), 'should not be running');
96
        $this->assertFalse($pool->hasStarted(), 'should not be started');
97
    }
98
99
    public function testPoolAddingRun()
100
    {
101
        $run = Mockery::mock(RunInterface::class);
102
        $run->allows(['hasStarted' => false, 'isRunning' => false]);
103
104
        $pool = new Pool();
105
        $pool->add($run);
0 ignored issues
show
Bug introduced by
$run of type Mockery\MockInterface is incompatible with the type Symfony\Component\Proces...lelProcess\RunInterface expected by parameter $item of Graze\ParallelProcess\Pool::add(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

105
        $pool->add(/** @scrutinizer ignore-type */ $run);
Loading history...
106
107
        $this->assertEquals(1, $pool->count());
108
    }
109
110
    public function testPoolAddingProcess()
111
    {
112
        $pool = new Pool();
113
        $pool->add($this->process);
114
115
        $this->assertEquals(1, $pool->count());
116
        $runs = $pool->getAll();
117
        $run = reset($runs);
118
119
        $this->assertEquals($this->process, $run->getProcess());
120
    }
121
122
    public function testSuccessfulRun()
123
    {
124
        $run = Mockery::mock(RunInterface::class);
125
        $run->shouldReceive('isRunning')
126
            ->andReturn(false);
127
        $run->shouldReceive('poll')
128
            ->andReturn(true, false);
129
        $run->shouldReceive('hasStarted')
130
            ->andReturn(true);
131
        $run->shouldReceive('isSuccessful')
132
            ->andReturn(true);
133
134
        $pool = new Pool([$run]);
135
136
        $run->shouldReceive('start');
137
        $pool->run(0);
138
139
        $this->assertTrue($pool->hasStarted());
140
        $this->assertFalse($pool->isRunning());
141
        $this->assertTrue($pool->isSuccessful());
142
    }
143
144
    /**
145
     * @expectedException \Graze\ParallelProcess\Exceptions\NotRunningException
146
     */
147
    public function testPoolUnableToAddRunningProcessWhenPoolHasNotStarted()
148
    {
149
        $run = Mockery::mock(RunInterface::class);
150
        $run->shouldReceive('isRunning')
151
            ->andReturn(true);
152
153
        $pool = new Pool();
154
155
        $pool->add($run);
0 ignored issues
show
Bug introduced by
$run of type Mockery\MockInterface is incompatible with the type Symfony\Component\Proces...lelProcess\RunInterface expected by parameter $item of Graze\ParallelProcess\Pool::add(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

155
        $pool->add(/** @scrutinizer ignore-type */ $run);
Loading history...
156
    }
157
158
    public function testPoolAbleToAddRunningProcessWhenPoolHasStarted()
159
    {
160
        $run = Mockery::mock(RunInterface::class)
161
                      ->allows(['isRunning' => false, 'hasStarted' => false, 'start' => null]);
162
        $pool = new Pool([$run]);
163
        $pool->start();
164
165
        $run2 = Mockery::mock(RunInterface::class)
166
                       ->allows(['isRunning' => true, 'start' => null]);
167
        $pool->add($run2);
168
169
        $this->assertEquals(2, $pool->count());
170
        $this->assertTrue($pool->isRunning());
171
    }
172
173
    public function testOnSuccessIsCalledOnSuccessfulProcess()
174
    {
175
        $process = Mockery::mock(Process::class);
176
        $process->shouldReceive('stop');
177
        $process->shouldReceive('isStarted')->andReturn(true);
178
        $process->shouldReceive('isRunning')->andReturn(false);
179
        $process->shouldReceive('start')->atLeast()->once();
180
        $process->shouldReceive('isSuccessful')->once()->andReturn(true);
181
182
        $hit = false;
183
184
        $pool = new Pool(
185
            [],
186
            function ($proc) use ($process, &$hit) {
187
                $this->assertSame($proc, $process);
188
                $hit = true;
189
            }
190
        );
191
192
        $pool->add($process);
0 ignored issues
show
Bug introduced by
$process of type Mockery\MockInterface is incompatible with the type Symfony\Component\Proces...lelProcess\RunInterface expected by parameter $item of Graze\ParallelProcess\Pool::add(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

192
        $pool->add(/** @scrutinizer ignore-type */ $process);
Loading history...
193
194
        $pool->run(0);
195
196
        $this->assertTrue($hit);
197
    }
198
199
    public function testOnFailureIsCalledForErroredProcess()
200
    {
201
        $process = Mockery::mock(Process::class);
202
        $process->shouldReceive('stop');
203
        $process->shouldReceive('isStarted')->andReturn(true);
204
        $process->shouldReceive('isRunning')->andReturn(false);
205
        $process->shouldReceive('start')->atLeast()->once();
206
        $process->shouldReceive('isSuccessful')->once()->andReturn(false);
207
208
        $hit = false;
209
210
        $pool = new Pool(
211
            [],
212
            null,
213
            function ($proc) use ($process, &$hit) {
214
                $this->assertEquals($proc, $process);
215
                $hit = true;
216
            }
217
        );
218
219
        $pool->add($process);
0 ignored issues
show
Bug introduced by
$process of type Mockery\MockInterface is incompatible with the type Symfony\Component\Proces...lelProcess\RunInterface expected by parameter $item of Graze\ParallelProcess\Pool::add(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

219
        $pool->add(/** @scrutinizer ignore-type */ $process);
Loading history...
220
221
        $pool->run(0);
222
223
        $this->assertTrue($hit);
224
    }
225
226
    public function testOnProgressIsCalledDuringProcessRun()
227
    {
228
        $process = Mockery::mock(Process::class);
229
        $process->shouldReceive('stop');
230
        $process->shouldReceive('isStarted')->andReturn(true);
231
        $process->shouldReceive('isRunning')->andReturn(false, false, true, false);
232
        $process->shouldReceive('start')->atLeast()->once();
233
        $process->shouldReceive('isSuccessful')->once()->andReturn(false);
234
235
        $hit = false;
236
237
        $pool = new Pool(
238
            [],
239
            null,
240
            null,
241
            function ($proc) use ($process, &$hit) {
242
                $this->assertEquals($proc, $process);
243
                $hit = true;
244
            }
245
        );
246
247
        $pool->add($process);
0 ignored issues
show
Bug introduced by
$process of type Mockery\MockInterface is incompatible with the type Symfony\Component\Proces...lelProcess\RunInterface expected by parameter $item of Graze\ParallelProcess\Pool::add(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

247
        $pool->add(/** @scrutinizer ignore-type */ $process);
Loading history...
248
249
        $pool->run(0);
250
251
        $this->assertTrue($hit);
252
    }
253
254
    public function testOnSuccessSetterIsCalledOnSuccessfulProcess()
255
    {
256
        $process = Mockery::mock(Process::class);
257
        $process->shouldReceive('stop');
258
        $process->shouldReceive('isStarted')->andReturn(true);
259
        $process->shouldReceive('isRunning')->andReturn(false);
260
        $process->shouldReceive('start')->atLeast()->once();
261
        $process->shouldReceive('isSuccessful')->once()->andReturn(true);
262
263
        $hit = false;
264
265
        $pool = new Pool();
266
        $this->assertSame(
267
            $pool,
268
            $pool->setOnSuccess(function ($proc) use ($process, &$hit) {
269
                $this->assertEquals($proc, $process);
270
                $hit = true;
271
            })
272
        );
273
274
        $pool->add($process);
0 ignored issues
show
Bug introduced by
$process of type Mockery\MockInterface is incompatible with the type Symfony\Component\Proces...lelProcess\RunInterface expected by parameter $item of Graze\ParallelProcess\Pool::add(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

274
        $pool->add(/** @scrutinizer ignore-type */ $process);
Loading history...
275
276
        $pool->run(0);
277
278
        $this->assertTrue($hit);
279
    }
280
281
    public function testOnFailureSetterIsCalledForErroredProcess()
282
    {
283
        $process = Mockery::mock(Process::class);
284
        $process->shouldReceive('stop');
285
        $process->shouldReceive('isStarted')->andReturn(true);
286
        $process->shouldReceive('isRunning')->andReturn(false);
287
        $process->shouldReceive('poll')->andReturn(false);
288
        $process->shouldReceive('start')->atLeast()->once();
289
        $process->shouldReceive('isSuccessful')->once()->andReturn(false);
290
291
        $hit = false;
292
293
        $pool = new Pool();
294
        $this->assertSame(
295
            $pool,
296
            $pool->setOnFailure(function ($proc) use ($process, &$hit) {
297
                $this->assertEquals($proc, $process);
298
                $hit = true;
299
            })
300
        );
301
302
        $pool->add($process);
0 ignored issues
show
Bug introduced by
$process of type Mockery\MockInterface is incompatible with the type Symfony\Component\Proces...lelProcess\RunInterface expected by parameter $item of Graze\ParallelProcess\Pool::add(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

302
        $pool->add(/** @scrutinizer ignore-type */ $process);
Loading history...
303
304
        $pool->run(0);
305
306
        $this->assertTrue($hit);
307
    }
308
309
    public function testOnProgressSetterIsCalledDuringProcessRun()
310
    {
311
        $process = Mockery::mock(Process::class);
312
        $process->shouldReceive('stop');
313
        $process->shouldReceive('isStarted')->andReturn(true);
314
        $process->shouldReceive('isRunning')->andReturn(false, false, true, false);
315
        $process->shouldReceive('start')->atLeast()->once();
316
        $process->shouldReceive('isSuccessful')->once()->andReturn(false);
317
318
        $hit = false;
319
320
        $pool = new Pool();
321
        $this->assertSame(
322
            $pool,
323
            $pool->setOnProgress(function ($proc) use ($process, &$hit) {
324
                $this->assertEquals($proc, $process);
325
                $hit = true;
326
            })
327
        );
328
329
        $pool->add($process);
0 ignored issues
show
Bug introduced by
$process of type Mockery\MockInterface is incompatible with the type Symfony\Component\Proces...lelProcess\RunInterface expected by parameter $item of Graze\ParallelProcess\Pool::add(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

329
        $pool->add(/** @scrutinizer ignore-type */ $process);
Loading history...
330
331
        $pool->run(0);
332
333
        $this->assertTrue($hit);
334
    }
335
336
    public function testOnStartSetterIsCalledDuringProcessRun()
337
    {
338
        $process = Mockery::mock(Process::class);
339
        $process->shouldReceive('stop');
340
        $process->shouldReceive('isStarted')->andReturn(true);
341
        $process->shouldReceive('isRunning')->andReturn(false, false, true, false);
342
        $process->shouldReceive('start')->atLeast()->once();
343
        $process->shouldReceive('isSuccessful')->once()->andReturn(false);
344
345
        $hit = false;
346
347
        $pool = new Pool();
348
        $this->assertSame(
349
            $pool,
350
            $pool->setOnStart(function ($proc) use ($process, &$hit) {
351
                $this->assertEquals($proc, $process);
352
                $hit = true;
353
            })
354
        );
355
356
        $pool->add($process);
0 ignored issues
show
Bug introduced by
$process of type Mockery\MockInterface is incompatible with the type Symfony\Component\Proces...lelProcess\RunInterface expected by parameter $item of Graze\ParallelProcess\Pool::add(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

356
        $pool->add(/** @scrutinizer ignore-type */ $process);
Loading history...
357
358
        $pool->run(0);
359
360
        $this->assertTrue($hit);
361
    }
362
363
    public function testPoolInstantRunStates()
364
    {
365
        $pool = new Pool();
366
367
        $this->assertFalse($pool->isRunInstantly());
368
        $this->assertSame($pool, $pool->setRunInstantly(true));
369
        $this->assertTrue($pool->isRunInstantly());
370
    }
371
372
    public function testPoolInitialStateWithInstantRun()
373
    {
374
        $run = Mockery::mock(RunInterface::class)
375
                      ->allows([
376
                          'start'        => null,
377
                          'isRunning'    => false,
378
                          'poll'         => false,
379
                          'hasStarted'   => true,
380
                          'isSuccessful' => true,
381
                      ]);
382
383
        $pool = new Pool([$run], null, null, null, null, Pool::NO_MAX, true);
384
385
        $this->assertTrue($pool->hasStarted());
386
        $this->assertTrue($pool->isRunning());
387
        $this->assertTrue($pool->isSuccessful());
388
        $this->assertTrue($pool->isRunInstantly());
389
390
        $pool->poll();
391
392
        $this->assertTrue($pool->hasStarted());
393
        $this->assertFalse($pool->isRunning());
394
        $this->assertTrue($pool->isSuccessful());
395
    }
396
397
    public function testPoolRunsRunWhenInstantRunIsOn()
398
    {
399
        $run = Mockery::mock(RunInterface::class);
0 ignored issues
show
Unused Code introduced by
The assignment to $run is dead and can be removed.
Loading history...
400
        $pool = new Pool();
401
        $pool->setRunInstantly(true);
402
403
        $run = Mockery::mock(RunInterface::class)
404
                      ->allows([
405
                          'start'        => null,
406
                          'isRunning'    => false,
407
                          'poll'         => false,
408
                          'hasStarted'   => true,
409
                          'isSuccessful' => true,
410
                      ]);
411
412
        $pool->add($run);
413
414
        $this->assertTrue($pool->hasStarted());
415
        $this->assertTrue($pool->isRunning());
416
        $this->assertTrue($pool->isSuccessful());
417
418
        $pool->poll();
419
420
        $this->assertTrue($pool->hasStarted());
421
        $this->assertFalse($pool->isRunning());
422
        $this->assertTrue($pool->isSuccessful());
423
    }
424
425
    public function testRunningRunAddingToAnInstantRunProcessCarriesOn()
426
    {
427
        $run = Mockery::mock(RunInterface::class);
0 ignored issues
show
Unused Code introduced by
The assignment to $run is dead and can be removed.
Loading history...
428
        $pool = new Pool();
429
        $pool->setRunInstantly(true);
430
431
        $run = Mockery::mock(RunInterface::class)
432
                      ->allows([
433
                          'start'        => null,
434
                          'isRunning'    => true,
435
                          'poll'         => false,
436
                          'hasStarted'   => true,
437
                          'isSuccessful' => true,
438
                      ]);
439
440
        $pool->add($run);
441
442
        $this->assertTrue($pool->hasStarted());
443
        $this->assertTrue($pool->isRunning());
444
        $this->assertTrue($pool->isSuccessful());
445
446
        $pool->poll();
447
448
        $this->assertTrue($pool->hasStarted());
449
        $this->assertFalse($pool->isRunning());
450
        $this->assertTrue($pool->isSuccessful());
451
    }
452
}
453