Passed
Pull Request — master (#15)
by Harry
02:27
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(/** @scrutinizer ignore-type */
88
            $nope
89
        );
90
    }
91
92
    public function testPoolInitialStateWithNoRuns()
93
    {
94
        $pool = new Pool();
95
96
        $this->assertFalse($pool->isSuccessful(), 'should not be successful');
97
        $this->assertFalse($pool->isRunning(), 'should not be running');
98
        $this->assertFalse($pool->hasStarted(), 'should not be started');
99
    }
100
101
    public function testPoolAddingRun()
102
    {
103
        $run = Mockery::mock(RunInterface::class);
104
        $run->allows(['hasStarted' => false, 'isRunning' => false]);
105
106
        $pool = new Pool();
107
        $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

107
        $pool->add(/** @scrutinizer ignore-type */ $run);
Loading history...
108
109
        $this->assertEquals(1, $pool->count());
110
    }
111
112
    public function testPoolAddingProcess()
113
    {
114
        $pool = new Pool();
115
        $pool->add($this->process);
116
117
        $this->assertEquals(1, $pool->count());
118
        $runs = $pool->getAll();
119
        $run = reset($runs);
120
121
        $this->assertEquals($this->process, $run->getProcess());
122
    }
123
124
    public function testSuccessfulRun()
125
    {
126
        $run = Mockery::mock(RunInterface::class);
127
        $run->shouldReceive('isRunning')
128
            ->andReturn(false);
129
        $run->shouldReceive('poll')
130
            ->andReturn(true, false);
131
        $run->shouldReceive('hasStarted')
132
            ->andReturn(true);
133
        $run->shouldReceive('isSuccessful')
134
            ->andReturn(true);
135
136
        $pool = new Pool([$run]);
137
138
        $run->shouldReceive('start');
139
        $pool->run(0);
140
141
        $this->assertTrue($pool->hasStarted());
142
        $this->assertFalse($pool->isRunning());
143
        $this->assertTrue($pool->isSuccessful());
144
    }
145
146
    /**
147
     * @expectedException \Graze\ParallelProcess\Exceptions\NotRunningException
148
     */
149
    public function testPoolUnableToAddRunningProcessWhenPoolHasNotStarted()
150
    {
151
        $run = Mockery::mock(RunInterface::class);
152
        $run->shouldReceive('isRunning')
153
            ->andReturn(true);
154
155
        $pool = new Pool();
156
157
        $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

157
        $pool->add(/** @scrutinizer ignore-type */ $run);
Loading history...
158
    }
159
160
    public function testPoolAbleToAddRunningProcessWhenPoolHasStarted()
161
    {
162
        $run = Mockery::mock(RunInterface::class)
163
                      ->allows(['isRunning' => false, 'hasStarted' => false, 'start' => null]);
164
        $pool = new Pool([$run]);
165
        $pool->start();
166
167
        $run2 = Mockery::mock(RunInterface::class)
168
                       ->allows(['isRunning' => true, 'start' => null]);
169
        $pool->add($run2);
170
171
        $this->assertEquals(2, $pool->count());
172
        $this->assertTrue($pool->isRunning());
173
    }
174
175
    public function testOnSuccessIsCalledOnSuccessfulProcess()
176
    {
177
        $process = Mockery::mock(Process::class);
178
        $process->shouldReceive('stop');
179
        $process->shouldReceive('isStarted')->andReturn(true);
180
        $process->shouldReceive('isRunning')->andReturn(false);
181
        $process->shouldReceive('start')->atLeast()->once();
182
        $process->shouldReceive('isSuccessful')->once()->andReturn(true);
183
184
        $hit = false;
185
186
        $pool = new Pool(
187
            [],
188
            function ($proc) use ($process, &$hit) {
189
                $this->assertSame($proc, $process);
190
                $hit = true;
191
            }
192
        );
193
194
        $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

194
        $pool->add(/** @scrutinizer ignore-type */ $process);
Loading history...
195
196
        $pool->run(0);
197
198
        $this->assertTrue($hit);
199
    }
200
201
    public function testOnFailureIsCalledForErroredProcess()
202
    {
203
        $process = Mockery::mock(Process::class);
204
        $process->shouldReceive('stop');
205
        $process->shouldReceive('isStarted')->andReturn(true);
206
        $process->shouldReceive('isRunning')->andReturn(false);
207
        $process->shouldReceive('start')->atLeast()->once();
208
        $process->shouldReceive('isSuccessful')->once()->andReturn(false);
209
210
        $hit = false;
211
212
        $pool = new Pool(
213
            [],
214
            null,
215
            function ($proc) use ($process, &$hit) {
216
                $this->assertEquals($proc, $process);
217
                $hit = true;
218
            }
219
        );
220
221
        $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

221
        $pool->add(/** @scrutinizer ignore-type */ $process);
Loading history...
222
223
        $pool->run(0);
224
225
        $this->assertTrue($hit);
226
    }
227
228
    public function testOnProgressIsCalledDuringProcessRun()
229
    {
230
        $process = Mockery::mock(Process::class);
231
        $process->shouldReceive('stop');
232
        $process->shouldReceive('isStarted')->andReturn(true);
233
        $process->shouldReceive('isRunning')->andReturn(false, false, true, false);
234
        $process->shouldReceive('start')->atLeast()->once();
235
        $process->shouldReceive('isSuccessful')->once()->andReturn(false);
236
237
        $hit = false;
238
239
        $pool = new Pool(
240
            [],
241
            null,
242
            null,
243
            function ($proc) use ($process, &$hit) {
244
                $this->assertEquals($proc, $process);
245
                $hit = true;
246
            }
247
        );
248
249
        $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

249
        $pool->add(/** @scrutinizer ignore-type */ $process);
Loading history...
250
251
        $pool->run(0);
252
253
        $this->assertTrue($hit);
254
    }
255
256
    public function testOnSuccessSetterIsCalledOnSuccessfulProcess()
257
    {
258
        $process = Mockery::mock(Process::class);
259
        $process->shouldReceive('stop');
260
        $process->shouldReceive('isStarted')->andReturn(true);
261
        $process->shouldReceive('isRunning')->andReturn(false);
262
        $process->shouldReceive('start')->atLeast()->once();
263
        $process->shouldReceive('isSuccessful')->once()->andReturn(true);
264
265
        $hit = false;
266
267
        $pool = new Pool();
268
        $this->assertSame(
269
            $pool,
270
            $pool->setOnSuccess(function ($proc) use ($process, &$hit) {
271
                $this->assertEquals($proc, $process);
272
                $hit = true;
273
            })
274
        );
275
276
        $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

276
        $pool->add(/** @scrutinizer ignore-type */ $process);
Loading history...
277
278
        $pool->run(0);
279
280
        $this->assertTrue($hit);
281
    }
282
283
    public function testOnFailureSetterIsCalledForErroredProcess()
284
    {
285
        $process = Mockery::mock(Process::class);
286
        $process->shouldReceive('stop');
287
        $process->shouldReceive('isStarted')->andReturn(true);
288
        $process->shouldReceive('isRunning')->andReturn(false);
289
        $process->shouldReceive('poll')->andReturn(false);
290
        $process->shouldReceive('start')->atLeast()->once();
291
        $process->shouldReceive('isSuccessful')->once()->andReturn(false);
292
293
        $hit = false;
294
295
        $pool = new Pool();
296
        $this->assertSame(
297
            $pool,
298
            $pool->setOnFailure(function ($proc) use ($process, &$hit) {
299
                $this->assertEquals($proc, $process);
300
                $hit = true;
301
            })
302
        );
303
304
        $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

304
        $pool->add(/** @scrutinizer ignore-type */ $process);
Loading history...
305
306
        $pool->run(0);
307
308
        $this->assertTrue($hit);
309
    }
310
311
    public function testOnProgressSetterIsCalledDuringProcessRun()
312
    {
313
        $process = Mockery::mock(Process::class);
314
        $process->shouldReceive('stop');
315
        $process->shouldReceive('isStarted')->andReturn(true);
316
        $process->shouldReceive('isRunning')->andReturn(false, false, true, false);
317
        $process->shouldReceive('start')->atLeast()->once();
318
        $process->shouldReceive('isSuccessful')->once()->andReturn(false);
319
320
        $hit = false;
321
322
        $pool = new Pool();
323
        $this->assertSame(
324
            $pool,
325
            $pool->setOnProgress(function ($proc) use ($process, &$hit) {
326
                $this->assertEquals($proc, $process);
327
                $hit = true;
328
            })
329
        );
330
331
        $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

331
        $pool->add(/** @scrutinizer ignore-type */ $process);
Loading history...
332
333
        $pool->run(0);
334
335
        $this->assertTrue($hit);
336
    }
337
338
    public function testOnStartSetterIsCalledDuringProcessRun()
339
    {
340
        $process = Mockery::mock(Process::class);
341
        $process->shouldReceive('stop');
342
        $process->shouldReceive('isStarted')->andReturn(true);
343
        $process->shouldReceive('isRunning')->andReturn(false, false, true, false);
344
        $process->shouldReceive('start')->atLeast()->once();
345
        $process->shouldReceive('isSuccessful')->once()->andReturn(false);
346
347
        $hit = false;
348
349
        $pool = new Pool();
350
        $this->assertSame(
351
            $pool,
352
            $pool->setOnStart(function ($proc) use ($process, &$hit) {
353
                $this->assertEquals($proc, $process);
354
                $hit = true;
355
            })
356
        );
357
358
        $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

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