Passed
Push — master ( b05304...84ccec )
by Harry
02:04
created

PoolTest::testPriority()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
/**
4
 * This file is part of graze/parallel-process.
5
 *
6
 * Copyright © 2018 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\CallbackRun;
19
use Graze\ParallelProcess\Event\PoolRunEvent;
20
use Graze\ParallelProcess\Event\RunEvent;
21
use Graze\ParallelProcess\Pool;
22
use Graze\ParallelProcess\PoolInterface;
23
use Graze\ParallelProcess\ProcessRun;
24
use Graze\ParallelProcess\RunInterface;
25
use Graze\ParallelProcess\Test\TestCase;
26
use Mockery;
27
use Symfony\Component\Process\Process;
28
29
class PoolTest extends TestCase
30
{
31
    /** @var mixed */
32
    private $process;
33
34
    public function setUp()
35
    {
36
        parent::setUp();
37
38
        $this->process = Mockery::mock(Process::class)
39
                                ->allows(['stop' => null, 'isStarted' => false, 'isRunning' => false]);
40
    }
41
42
    public function testPoolIsARunInterface()
43
    {
44
        $pool = new Pool();
45
        $this->assertInstanceOf(RunInterface::class, $pool);
46
    }
47
48
    public function testPoolIsAPoolInterface()
49
    {
50
        $pool = new Pool();
51
        $this->assertInstanceOf(PoolInterface::class, $pool);
52
    }
53
54
    public function testPoolIsACollectionOfRuns()
55
    {
56
        $pool = new Pool();
57
        $this->assertInstanceOf(CollectionInterface::class, $pool);
58
59
        $this->assertSame($pool, $pool->add($this->process));
60
61
        $runs = $pool->getAll();
62
        $this->assertCount(1, $runs);
63
64
        $this->assertInstanceOf(ProcessRun::class, reset($runs));
65
    }
66
67
    public function testPoolInitialStateWithProcess()
68
    {
69
        $pool = new Pool();
70
        $pool->add($this->process);
71
72
        $this->assertFalse($pool->isSuccessful());
73
        $this->assertFalse($pool->isRunning());
74
        $this->assertFalse($pool->hasStarted());
75
    }
76
77
    public function testPoolConstructor()
78
    {
79
        $runs = [];
80
        for ($i = 0; $i < 2; $i++) {
81
            $runs[] = Mockery::mock(RunInterface::class)
82
                             ->allows(['isRunning' => false, 'hasStarted' => false, 'addListener' => true, 'getPriority' => 1.0]);
83
        }
84
85
        $pool = new Pool($runs);
86
87
        $this->assertEquals(2, $pool->count());
88
    }
89
90
    /**
91
     * @expectedException \InvalidArgumentException
92
     */
93
    public function testAddingNonRunInterfaceWillThrowException()
94
    {
95
        $nope = Mockery::mock();
96
        $pool = new Pool();
97
        $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

97
        $pool->add(/** @scrutinizer ignore-type */ $nope);
Loading history...
98
    }
99
100
    public function testPoolInitialStateWithNoRuns()
101
    {
102
        $pool = new Pool();
103
104
        $this->assertFalse($pool->isSuccessful(), 'should not be successful');
105
        $this->assertFalse($pool->isRunning(), 'should not be running');
106
        $this->assertFalse($pool->hasStarted(), 'should not be started');
107
    }
108
109
    public function testPoolAddingRun()
110
    {
111
        $pool = new Pool();
112
        $pool->add(new CallbackRun(function () {
113
            return true;
114
        }));
115
116
        $this->assertEquals(1, $pool->count());
117
    }
118
119
    public function testPoolAddingRunFiresAnEvent()
120
    {
121
        $run = new CallbackRun(function () {
122
            return true;
123
        });
124
125
        $hit = false;
126
127
        $pool = new Pool();
128
        $pool->addListener(
129
            PoolRunEvent::POOL_RUN_ADDED,
130
            function (PoolRunEvent $event) use ($pool, $run, &$hit) {
131
                $this->assertSame($pool, $event->getPool());
132
                $this->assertSame($run, $event->getRun());
133
                $hit = true;
134
            }
135
        );
136
137
        $pool->add($run);
138
139
        $this->assertEquals(1, $pool->count());
140
        $this->assertTrue($hit);
141
    }
142
143
    public function testPoolAddingProcess()
144
    {
145
        $pool = new Pool();
146
        $pool->add($this->process);
147
148
        $this->assertEquals(1, $pool->count());
149
        $runs = $pool->getAll();
150
        $run = reset($runs);
151
152
        $this->assertEquals($this->process, $run->getProcess());
153
    }
154
155
    public function testPoolAddingProcessFiresAnEvent()
156
    {
157
        $pool = new Pool();
158
        $pool->addListener(
159
            PoolRunEvent::POOL_RUN_ADDED,
160
            function (PoolRunEvent $event) use ($pool, &$hit) {
161
                $this->assertSame($pool, $event->getPool());
162
                $run = $event->getRun();
163
                if ($run instanceof ProcessRun) {
164
                    $this->assertSame($this->process, $run->getProcess());
165
                }
166
                $hit = true;
167
            }
168
        );
169
170
        $pool->add($this->process);
171
172
        $this->assertEquals(1, $pool->count());
173
        $runs = $pool->getAll();
174
        $run = reset($runs);
175
176
        $this->assertEquals($this->process, $run->getProcess());
177
        $this->assertTrue($hit);
178
    }
179
180
    public function testAddingACompletedRunWillAddItToTheFinishedListAndStartThePool()
181
    {
182
        $run = new CallbackRun(function () {
183
            return true;
184
        });
185
        $run->start();
186
187
        $pool = new Pool();
188
        $hit = false;
189
        $pool->addListener(
190
            RunEvent::STARTED,
191
            function (RunEvent $event) use (&$hit, $pool) {
192
                $hit = true;
193
                $this->assertSame($pool, $event->getRun());
194
            }
195
        );
196
197
        $this->assertFalse($hit);
198
        $pool->add($run);
199
        $this->assertTrue($hit);
200
201
        $this->assertCount(1, $pool->getFinished());
202
        $this->assertFalse($pool->isRunning());
203
        $this->assertTrue($pool->hasStarted());
204
    }
205
206
    public function testSuccessfulRun()
207
    {
208
        $run = new CallbackRun(function () {
209
            return true;
210
        });
211
212
        $pool = new Pool([$run]);
213
        $pool->run(0);
214
215
        $this->assertTrue($pool->hasStarted());
216
        $this->assertFalse($pool->isRunning());
217
        $this->assertTrue($pool->isSuccessful());
218
    }
219
220
    public function testSuccessfulRunWithEvents()
221
    {
222
        $run = new CallbackRun(function () {
223
            return true;
224
        });
225
226
        $pool = new Pool([$run]);
227
228
        $startedHit = false;
229
        $completedHit = false;
230
231
        $pool->addListener(
232
            RunEvent::STARTED,
233
            function (RunEvent $event) use ($pool, &$startedHit) {
234
                $this->assertSame($pool, $event->getRun());
235
                $startedHit = true;
236
            }
237
        );
238
        $pool->addListener(
239
            RunEvent::COMPLETED,
240
            function (RunEvent $event) use ($pool, &$completedHit) {
241
                $this->assertSame($pool, $event->getRun());
242
                $completedHit = true;
243
            }
244
        );
245
246
        $pool->run(0);
247
248
        $this->assertTrue($pool->hasStarted());
249
        $this->assertFalse($pool->isRunning());
250
        $this->assertTrue($pool->isSuccessful());
251
252
        $this->assertTrue($startedHit);
253
        $this->assertTrue($completedHit);
254
    }
255
256
    public function testFailedRunWithEvents()
257
    {
258
        $exception = new \RuntimeException('bwark');
259
        $run = new CallbackRun(function () use ($exception) {
260
            throw $exception;
261
        });
262
263
        $pool = new Pool([$run]);
264
265
        $failedHit = false;
266
267
        $pool->addListener(
268
            RunEvent::FAILED,
269
            function (RunEvent $event) use ($pool, &$failedHit) {
270
                $this->assertSame($pool, $event->getRun());
271
                $failedHit = true;
272
            }
273
        );
274
275
        $pool->run(0);
276
277
        $this->assertTrue($pool->hasStarted());
278
        $this->assertFalse($pool->isRunning());
279
        $this->assertFalse($pool->isSuccessful());
280
281
        $this->assertTrue($failedHit);
282
283
        $this->assertEquals([$exception], $pool->getExceptions());
284
    }
285
286
    public function testPoolAbleToAddRunningProcessWhenPoolHasStarted()
287
    {
288
        $process = Mockery::mock(Process::class);
289
        $process->shouldReceive('stop');
290
        $process->shouldReceive('isStarted')
291
                ->andReturn(false, false, false, true); // add to pool, check start, check start, started
292
        $process->shouldReceive('isRunning')->andReturn(false, true, false);
293
        $process->shouldReceive('start')->atLeast()->once();
294
295
        $pool = new Pool([$process]);
296
        $pool->start();
297
298
        $process2 = Mockery::mock(Process::class);
299
        $process2->shouldReceive('stop');
300
        $process2->shouldReceive('isStarted')->andReturn(true);
301
        $process2->shouldReceive('isRunning')->andReturn(true, false);
302
        $pool->add($process2);
0 ignored issues
show
Bug introduced by
$process2 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 */ $process2);
Loading history...
303
304
        $this->assertEquals(2, $pool->count());
305
        $this->assertTrue($pool->isRunning());
306
    }
307
308
    public function testOnProgressIsCalledDuringProcessRun()
309
    {
310
        $process = Mockery::mock(Process::class);
311
        $process->shouldReceive('stop');
312
        $process->shouldReceive('isStarted')->andReturn(false, false, false, true);
313
        $process->shouldReceive('isRunning')->andReturn(false, true, false);
314
        $process->shouldReceive('start')->atLeast()->once();
315
        $process->shouldReceive('isSuccessful')->once()->andReturn(true);
316
317
        $hit = false;
318
319
        $pool = new Pool();
320
        $pool->addListener(
321
            RunEvent::UPDATED,
322
            function (RunEvent $event) use ($pool, &$hit) {
323
                $run = $event->getRun();
324
                $this->assertEquals($pool, $run);
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
        $pool->run(0);
331
        $this->assertTrue($hit);
332
    }
333
334
    public function testFinished()
335
    {
336
        $run = new CallbackRun(function () {
337
            return true;
338
        });
339
340
        $pool = new Pool([$run]);
341
        $pool->run(0);
342
343
        $this->assertEquals([$run], $pool->getFinished());
344
    }
345
346
    public function testTags()
347
    {
348
        $pool = new Pool([], ['tag1', 'key' => 'value']);
349
350
        $this->assertSame(['tag1', 'key' => 'value'], $pool->getTags());
351
    }
352
353
    public function testProgress()
354
    {
355
        $run = new CallbackRun(function () {
356
            return true;
357
        });
358
359
        $pool = new Pool([$run]);
360
361
        $this->assertEquals([0, 1, 0], $pool->getProgress());
362
        $pool->run(0);
363
364
        $this->assertEquals([1, 1, 1], $pool->getProgress());
365
    }
366
367
    public function testDuration()
368
    {
369
        $run = new CallbackRun(function () {
370
            return true;
371
        });
372
373
        $pool = new Pool([$run]);
374
375
        $this->assertEquals(0, $pool->getDuration());
376
        $pool->start();
377
378
        $this->assertGreaterThan(0, $pool->getDuration());
379
        $pool->run(0);
380
    }
381
382
    public function testPriority()
383
    {
384
        $pool = new Pool();
385
        $this->assertEquals(1, $pool->getPriority());
386
        $this->assertSame($pool, $pool->setPriority(2));
387
        $this->assertEquals(2, $pool->getPriority());
388
    }
389
}
390