2016-12-30 02:16:04 +01:00
< ? php
2015-08-29 03:55:30 +02:00
2016-08-23 23:47:40 +02:00
namespace Amp\Parallel\Test\Worker ;
2016-08-18 18:04:48 +02:00
2017-03-16 23:03:59 +01:00
use Amp\Loop ;
2017-12-13 23:29:44 +01:00
use Amp\Parallel\Sync\SerializationException ;
2017-11-23 04:38:11 +01:00
use Amp\Parallel\Worker\Environment ;
use Amp\Parallel\Worker\Task ;
use Amp\Parallel\Worker\TaskError ;
2018-10-24 05:10:12 +02:00
use Amp\Parallel\Worker\TaskException ;
2018-06-07 21:11:45 +02:00
use Amp\Parallel\Worker\WorkerException ;
2017-03-22 05:19:15 +01:00
use Amp\PHPUnit\TestCase ;
2015-08-29 03:55:30 +02:00
2018-10-07 16:50:45 +02:00
class NonAutoloadableTask implements Task
{
public function run ( Environment $environment )
{
2017-11-23 04:38:11 +01:00
return 1 ;
}
}
2018-10-07 16:50:45 +02:00
abstract class AbstractWorkerTest extends TestCase
{
2015-08-29 03:55:30 +02:00
/**
2016-08-23 23:47:40 +02:00
* @ return \Amp\Parallel\Worker\Worker
2015-08-29 03:55:30 +02:00
*/
2015-12-12 06:31:50 +01:00
abstract protected function createWorker ();
2015-08-29 03:55:30 +02:00
2018-10-07 16:50:45 +02:00
public function testWorkerConstantDefined ()
{
2017-07-28 06:49:43 +02:00
Loop :: run ( function () {
$worker = $this -> createWorker ();
$this -> assertTrue ( yield $worker -> enqueue ( new ConstantTask ));
yield $worker -> shutdown ();
});
}
2018-10-07 16:50:45 +02:00
public function testIsRunning ()
{
2017-03-16 23:03:59 +01:00
Loop :: run ( function () {
2015-12-12 06:31:50 +01:00
$worker = $this -> createWorker ();
2018-10-08 18:24:46 +02:00
$this -> assertTrue ( $worker -> isRunning ());
2015-08-29 03:55:30 +02:00
2017-12-13 21:14:31 +01:00
$worker -> enqueue ( new TestTask ( 42 )); // Enqueue a task to start the worker.
2015-08-31 19:57:40 +02:00
$this -> assertTrue ( $worker -> isRunning ());
2015-08-29 03:55:30 +02:00
2016-08-19 00:36:58 +02:00
yield $worker -> shutdown ();
2015-08-31 19:57:40 +02:00
$this -> assertFalse ( $worker -> isRunning ());
2017-03-16 23:03:59 +01:00
});
2015-08-29 03:55:30 +02:00
}
2018-10-07 16:50:45 +02:00
public function testIsIdleOnStart ()
{
2017-03-16 23:03:59 +01:00
Loop :: run ( function () {
2015-12-12 06:31:50 +01:00
$worker = $this -> createWorker ();
2015-08-29 03:55:30 +02:00
2015-08-31 19:57:40 +02:00
$this -> assertTrue ( $worker -> isIdle ());
2015-08-29 03:55:30 +02:00
2016-08-19 00:36:58 +02:00
yield $worker -> shutdown ();
2017-03-16 23:03:59 +01:00
});
2015-08-29 03:55:30 +02:00
}
2018-10-07 17:14:27 +02:00
/**
* @ expectedException \Amp\Parallel\Context\StatusError
* @ expectedExceptionMessage The worker has been shut down
*/
public function testEnqueueShouldThrowStatusError ()
{
Loop :: run ( function () {
$worker = $this -> createWorker ();
$this -> assertTrue ( $worker -> isIdle ());
yield $worker -> shutdown ();
yield $worker -> enqueue ( new TestTask ( 42 ));
});
}
2018-10-07 16:50:45 +02:00
public function testEnqueue ()
{
2017-03-16 23:03:59 +01:00
Loop :: run ( function () {
2015-12-12 06:31:50 +01:00
$worker = $this -> createWorker ();
2015-08-29 03:55:30 +02:00
2016-08-19 00:36:58 +02:00
$returnValue = yield $worker -> enqueue ( new TestTask ( 42 ));
2015-08-29 03:55:30 +02:00
$this -> assertEquals ( 42 , $returnValue );
2016-08-19 00:36:58 +02:00
yield $worker -> shutdown ();
2017-03-16 23:03:59 +01:00
});
2015-08-29 03:55:30 +02:00
}
2018-10-07 16:50:45 +02:00
public function testEnqueueMultipleSynchronous ()
{
2017-03-16 23:03:59 +01:00
Loop :: run ( function () {
2015-12-12 06:31:50 +01:00
$worker = $this -> createWorker ();
2017-05-18 09:51:31 +02:00
2017-03-16 23:03:59 +01:00
$values = yield \Amp\Promise\all ([
2016-08-19 00:36:58 +02:00
$worker -> enqueue ( new TestTask ( 42 )),
$worker -> enqueue ( new TestTask ( 56 )),
$worker -> enqueue ( new TestTask ( 72 ))
2016-01-23 07:00:56 +01:00
]);
2015-12-12 01:15:15 +01:00
$this -> assertEquals ([ 42 , 56 , 72 ], $values );
2016-08-19 00:36:58 +02:00
yield $worker -> shutdown ();
2017-03-16 23:03:59 +01:00
});
2015-12-12 01:15:15 +01:00
}
2018-10-07 16:50:45 +02:00
public function testEnqueueMultipleAsynchronous ()
{
2017-12-06 01:37:33 +01:00
Loop :: run ( function () {
$worker = $this -> createWorker ();
$promises = [
$worker -> enqueue ( new TestTask ( 42 , 200 )),
$worker -> enqueue ( new TestTask ( 56 , 300 )),
$worker -> enqueue ( new TestTask ( 72 , 100 ))
];
2017-12-06 22:59:28 +01:00
$expected = [ 42 , 56 , 72 ];
2017-12-06 01:37:33 +01:00
foreach ( $promises as $promise ) {
$promise -> onResolve ( function ( $e , $v ) use ( & $expected ) {
$this -> assertSame ( \array_shift ( $expected ), $v );
});
}
2018-06-07 21:11:45 +02:00
yield $promises ; // Wait until all tasks have finished before invoking $worker->shutdown().
2017-12-06 01:37:33 +01:00
yield $worker -> shutdown ();
});
}
2018-10-07 16:50:45 +02:00
public function testEnqueueMultipleThenShutdown ()
{
2018-06-07 21:11:45 +02:00
Loop :: run ( function () {
$worker = $this -> createWorker ();
$promises = [
$worker -> enqueue ( new TestTask ( 42 , 200 )),
$worker -> enqueue ( new TestTask ( 56 , 300 )),
$worker -> enqueue ( new TestTask ( 72 , 100 ))
];
yield $worker -> shutdown ();
\array_shift ( $promises ); // First task will succeed.
foreach ( $promises as $promise ) {
$promise -> onResolve ( function ( $e , $v ) {
$this -> assertInstanceOf ( WorkerException :: class , $e );
});
}
});
}
2018-10-07 16:50:45 +02:00
public function testNotIdleOnEnqueue ()
{
2017-03-16 23:03:59 +01:00
Loop :: run ( function () {
2015-12-12 06:31:50 +01:00
$worker = $this -> createWorker ();
2015-08-29 03:55:30 +02:00
2016-08-19 00:36:58 +02:00
$coroutine = $worker -> enqueue ( new TestTask ( 42 ));
2015-08-29 03:55:30 +02:00
$this -> assertFalse ( $worker -> isIdle ());
yield $coroutine ;
2016-08-19 00:36:58 +02:00
yield $worker -> shutdown ();
2017-03-16 23:03:59 +01:00
});
2015-08-29 03:55:30 +02:00
}
2015-11-11 09:59:22 +01:00
2018-10-07 16:50:45 +02:00
public function testKill ()
{
2015-12-12 06:31:50 +01:00
$worker = $this -> createWorker ();
2017-12-13 21:14:31 +01:00
$worker -> enqueue ( new TestTask ( 42 ));
2015-11-11 09:59:22 +01:00
2017-03-22 05:33:05 +01:00
$this -> assertRunTimeLessThan ([ $worker , 'kill' ], 250 );
2015-11-11 09:59:22 +01:00
$this -> assertFalse ( $worker -> isRunning ());
}
2017-11-23 04:38:11 +01:00
2018-10-07 16:50:45 +02:00
public function testNonAutoloadableTask ()
{
2017-11-23 04:38:11 +01:00
Loop :: run ( function () {
$worker = $this -> createWorker ();
try {
yield $worker -> enqueue ( new NonAutoloadableTask );
$this -> fail ( " Tasks that cannot be autoloaded should throw an exception " );
} catch ( TaskError $exception ) {
$this -> assertSame ( " Error " , $exception -> getName ());
$this -> assertGreaterThan ( 0 , \strpos ( $exception -> getMessage (), \sprintf ( " Classes implementing %s " , Task :: class )));
}
yield $worker -> shutdown ();
});
}
2017-12-13 23:29:44 +01:00
2018-10-07 16:50:45 +02:00
public function testUnserializableTask ()
{
2017-12-13 23:29:44 +01:00
Loop :: run ( function () {
$worker = $this -> createWorker ();
try {
yield $worker -> enqueue ( new class implements Task { // Anonymous classes are not serializable.
2018-10-07 16:50:45 +02:00
public function run ( Environment $environment )
{
2017-12-13 23:29:44 +01:00
}
});
2018-10-24 05:10:12 +02:00
$this -> fail ( " Tasks that cannot be serialized should throw an exception " );
2017-12-13 23:29:44 +01:00
} catch ( SerializationException $exception ) {
$this -> assertSame ( 0 , \strpos ( $exception -> getMessage (), " The given data cannot be sent because it is not serializable " ));
}
yield $worker -> shutdown ();
});
}
2017-12-14 03:56:28 +01:00
2018-10-24 05:10:12 +02:00
public function testUnserializableResult ()
{
Loop :: run ( function () {
$worker = $this -> createWorker ();
try {
yield $worker -> enqueue ( new UnserializableResultTask );
$this -> fail ( " Tasks results that cannot be serialized should throw an exception " );
} catch ( TaskException $exception ) {
$this -> assertSame ( 0 , \strpos ( $exception -> getMessage (), " Uncaught Amp \ Parallel \ Sync \ SerializationException in worker " ));
}
yield $worker -> shutdown ();
});
}
public function testNonAutoloadableResult ()
{
Loop :: run ( function () {
$worker = $this -> createWorker ();
try {
yield $worker -> enqueue ( new NonAutoloadableResultTask );
$this -> fail ( " Tasks results that cannot be autoloaded should throw an exception " );
} catch ( \Error $exception ) {
$this -> assertSame ( 0 , \strpos ( $exception -> getMessage (), " Class instances returned from Amp \ Parallel \ Worker \T ask::run() must be autoloadable by the Composer autoloader " ));
}
yield $worker -> shutdown ();
});
}
2018-10-07 16:50:45 +02:00
public function testUnserializableTaskFollowedByValidTask ()
{
2017-12-14 03:56:28 +01:00
Loop :: run ( function () {
$worker = $this -> createWorker ();
$promise1 = $worker -> enqueue ( new class implements Task { // Anonymous classes are not serializable.
2018-10-07 16:50:45 +02:00
public function run ( Environment $environment )
{
2017-12-14 03:56:28 +01:00
}
});
$promise2 = $worker -> enqueue ( new TestTask ( 42 ));
$this -> assertSame ( 42 , yield $promise2 );
yield $worker -> shutdown ();
});
}
2015-08-29 03:55:30 +02:00
}