Completed
Pull Request — master (#15)
by Harry
06:15
created

PoolTest::testPoolInitialStateWithInstantRun()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 23
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 23
rs 9.0856
c 0
b 0
f 0
cc 1
eloc 16
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
    public function testPoolInitialStateWithNoRuns()
92
    {
93
        $pool = new Pool();
94
95
        $this->assertFalse($pool->isSuccessful(), 'should not be successful');
96
        $this->assertFalse($pool->isRunning(), 'should not be running');
97
        $this->assertFalse($pool->hasStarted(), 'should not be started');
98
    }
99
100
    public function testPoolAddingRun()
101
    {
102
        $run = Mockery::mock(RunInterface::class);
103
        $run->allows(['hasStarted' => false, 'isRunning' => false]);
104
105
        $pool = new Pool();
106
        $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

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

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

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

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

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

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

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

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

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