2016-05-24 10:37:25 +02:00
< ? php
2017-03-12 11:21:44 +01:00
namespace Amp\Test\Loop ;
2016-05-24 10:37:25 +02:00
2017-03-10 21:31:57 +01:00
use Amp\Loop\Driver ;
2017-03-14 17:50:24 +01:00
use Amp\Loop\InvalidWatcherError ;
2017-03-10 21:31:57 +01:00
use Amp\Loop\UnsupportedFeatureException ;
2017-03-12 11:21:44 +01:00
use PHPUnit\Framework\TestCase ;
2020-07-14 21:45:35 +02:00
use function Amp\getCurrentTime ;
2016-05-24 10:37:25 +02:00
2017-11-29 13:36:50 +01:00
if ( ! \defined ( " SIGUSR1 " )) {
\define ( " SIGUSR1 " , 30 );
2016-08-14 21:14:43 +02:00
}
2017-11-29 13:36:50 +01:00
if ( ! \defined ( " SIGUSR2 " )) {
\define ( " SIGUSR2 " , 31 );
2016-05-27 03:25:55 +02:00
}
2017-11-29 13:36:50 +01:00
if ( ! \defined ( " PHP_INT_MIN " )) {
\define ( " PHP_INT_MIN " , ~ PHP_INT_MAX );
2016-08-14 22:44:49 +02:00
}
2018-06-18 20:00:01 +02:00
abstract class DriverTest extends TestCase
{
2016-06-03 17:01:21 +02:00
/**
2017-04-24 15:39:08 +02:00
* The DriverFactory to run this test on .
2016-06-03 17:01:21 +02:00
*
2017-03-10 21:31:57 +01:00
* @ return callable
2016-06-03 17:01:21 +02:00
*/
2017-04-24 15:39:08 +02:00
abstract public function getFactory () : callable ;
2016-06-03 17:01:21 +02:00
/** @var Driver */
2020-10-03 15:38:31 +02:00
public Driver $loop ;
2016-06-03 17:01:21 +02:00
2020-09-26 19:34:39 +02:00
public function setUp () : void
2018-06-18 20:00:01 +02:00
{
2017-03-10 21:31:57 +01:00
$this -> loop = ( $this -> getFactory ())();
2017-03-12 22:09:19 +01:00
2016-06-03 17:01:21 +02:00
if ( ! $this -> loop instanceof Driver ) {
$this -> fail ( " Factory did not return a loop Driver " );
}
2017-03-12 22:09:19 +01:00
2017-11-29 13:36:50 +01:00
\gc_collect_cycles ();
2017-05-07 13:09:59 +02:00
}
2020-09-26 19:34:39 +02:00
public function tearDown () : void
2018-06-18 20:00:01 +02:00
{
2017-05-07 13:09:59 +02:00
unset ( $this -> loop );
2016-06-03 17:01:21 +02:00
}
2020-09-26 19:34:39 +02:00
protected function start ( $cb ) : void
2018-06-18 20:00:01 +02:00
{
2020-10-03 05:26:10 +02:00
$cb ( $this -> loop );
$this -> loop -> run ();
2016-06-03 17:01:21 +02:00
}
2020-09-26 19:34:39 +02:00
public function testCorrectTimeoutIfBlockingBeforeActivate () : void
2020-07-14 21:45:35 +02:00
{
$start = 0 ;
$invoked = 0 ;
2020-09-26 19:34:39 +02:00
$this -> start ( function ( Driver $loop ) use ( & $start , & $invoked ) : void {
2020-07-14 21:45:35 +02:00
$loop -> defer ( function () use ( $loop , & $start , & $invoked ) {
$start = getCurrentTime ();
$loop -> delay ( 1000 , function () use ( & $invoked ) {
$invoked = getCurrentTime ();
});
\usleep ( 500000 );
});
});
$this -> assertNotSame ( 0 , $start );
$this -> assertNotSame ( 0 , $invoked );
$this -> assertGreaterThanOrEqual ( 999 , $invoked - $start );
$this -> assertLessThan ( 1100 , $invoked - $start );
}
2020-09-26 19:34:39 +02:00
public function testCorrectTimeoutIfBlockingBeforeDelay () : void
2020-07-14 21:45:35 +02:00
{
$start = 0 ;
$invoked = 0 ;
2020-09-26 19:34:39 +02:00
$this -> start ( function ( Driver $loop ) use ( & $start , & $invoked ) : void {
2020-07-14 21:45:35 +02:00
$start = getCurrentTime ();
\usleep ( 500000 );
$loop -> delay ( 1000 , function () use ( & $invoked ) {
$invoked = getCurrentTime ();
});
});
$this -> assertNotSame ( 0 , $start );
$this -> assertNotSame ( 0 , $invoked );
$this -> assertGreaterThanOrEqual ( 1500 , $invoked - $start );
$this -> assertLessThan ( 1600 , $invoked - $start );
}
2020-09-26 19:34:39 +02:00
public function testLoopTerminatesWithOnlyUnreferencedWatchers () : void
2018-06-18 20:00:01 +02:00
{
2020-09-26 19:34:39 +02:00
$this -> start ( function ( Driver $loop ) use ( & $end ) : void {
$loop -> unreference ( $loop -> onReadable ( STDIN , function () : void {
2018-06-18 20:00:01 +02:00
}));
2020-09-26 19:34:39 +02:00
$w = $loop -> delay ( 10000000 , function () : void {
2018-06-18 20:00:01 +02:00
});
2020-09-26 19:34:39 +02:00
$loop -> defer ( function () use ( $loop , $w ) : void {
2018-06-18 20:00:01 +02:00
$loop -> cancel ( $w );
});
2017-07-09 09:28:32 +02:00
$end = true ;
});
$this -> assertTrue ( $end );
}
2017-03-12 17:33:46 +01:00
/** This MUST NOT have a "test" prefix, otherwise it's executed as test and marked as risky. */
2020-09-26 19:34:39 +02:00
public function checkForSignalCapability () : void
2018-06-18 20:00:01 +02:00
{
2016-06-03 17:01:21 +02:00
try {
2020-09-26 19:34:39 +02:00
$watcher = $this -> loop -> onSignal ( SIGUSR1 , function () : void {
2017-03-15 00:34:37 +01:00
});
2016-06-03 17:01:21 +02:00
$this -> loop -> cancel ( $watcher );
} catch ( UnsupportedFeatureException $e ) {
$this -> markTestSkipped ( " The loop is not capable of handling signals properly. Skipping. " );
}
}
2020-09-26 19:34:39 +02:00
public function testWatcherUnrefRerefRunResult () : void
2018-06-18 20:00:01 +02:00
{
2016-06-03 17:01:21 +02:00
$invoked = false ;
2020-09-26 19:34:39 +02:00
$this -> start ( function ( Driver $loop ) use ( & $invoked ) : void {
$watcher = $loop -> defer ( function () use ( & $invoked ) : void {
2016-06-03 17:01:21 +02:00
$invoked = true ;
});
$loop -> unreference ( $watcher );
2016-06-07 01:53:28 +02:00
$loop -> unreference ( $watcher );
2016-06-03 17:01:21 +02:00
$loop -> reference ( $watcher );
});
$this -> assertTrue ( $invoked );
}
2020-09-26 19:34:39 +02:00
public function testDeferWatcherUnrefRunResult () : void
2018-06-18 20:00:01 +02:00
{
2017-03-14 00:52:57 +01:00
$invoked = false ;
2020-09-26 19:34:39 +02:00
$this -> start ( function ( Driver $loop ) use ( & $invoked ) : void {
$watcher = $loop -> defer ( function () use ( & $invoked ) : void {
2017-03-14 00:52:57 +01:00
$invoked = true ;
2016-06-03 17:01:21 +02:00
});
$loop -> unreference ( $watcher );
});
2017-03-14 00:52:57 +01:00
$this -> assertFalse ( $invoked );
2016-06-03 17:01:21 +02:00
}
2020-09-26 19:34:39 +02:00
public function testOnceWatcherUnrefRunResult () : void
2018-06-18 20:00:01 +02:00
{
2016-06-03 17:01:21 +02:00
$invoked = false ;
2020-09-26 19:34:39 +02:00
$this -> start ( function ( Driver $loop ) use ( & $invoked ) : void {
$watcher = $loop -> delay ( 2000 , function () use ( & $invoked ) : void {
2016-06-03 17:01:21 +02:00
$invoked = true ;
});
$loop -> unreference ( $watcher );
$loop -> unreference ( $watcher );
});
$this -> assertFalse ( $invoked );
}
2020-09-26 19:34:39 +02:00
public function testRepeatWatcherUnrefRunResult () : void
2018-06-18 20:00:01 +02:00
{
2016-06-03 17:01:21 +02:00
$invoked = false ;
2020-09-26 19:34:39 +02:00
$this -> start ( function ( Driver $loop ) use ( & $invoked ) : void {
$watcher = $loop -> repeat ( 2000 , function () use ( & $invoked ) : void {
2016-06-03 17:01:21 +02:00
$invoked = true ;
});
$loop -> unreference ( $watcher );
});
$this -> assertFalse ( $invoked );
}
2020-09-26 19:34:39 +02:00
public function testOnReadableWatcherUnrefRunResult () : void
2018-06-18 20:00:01 +02:00
{
2017-03-14 00:52:57 +01:00
$invoked = false ;
2020-09-26 19:34:39 +02:00
$this -> start ( function ( Driver $loop ) use ( & $invoked ) : void {
$watcher = $loop -> onReadable ( STDIN , function () use ( & $invoked ) : void {
2017-03-14 00:52:57 +01:00
$invoked = true ;
2016-06-03 17:01:21 +02:00
});
$loop -> unreference ( $watcher );
});
2017-03-14 00:52:57 +01:00
$this -> assertFalse ( $invoked );
2016-06-03 17:01:21 +02:00
}
2020-09-26 19:34:39 +02:00
public function testOnWritableWatcherKeepAliveRunResult () : void
2018-06-18 20:00:01 +02:00
{
2017-03-14 00:52:57 +01:00
$invoked = false ;
2020-09-26 19:34:39 +02:00
$this -> start ( function ( Driver $loop ) use ( & $invoked ) : void {
$watcher = $loop -> onWritable ( STDOUT , function () use ( & $invoked ) : void {
2017-03-14 00:52:57 +01:00
$invoked = true ;
2016-06-03 17:01:21 +02:00
});
$loop -> unreference ( $watcher );
});
2017-03-14 00:52:57 +01:00
$this -> assertFalse ( $invoked );
2016-06-03 17:01:21 +02:00
}
2020-09-26 19:34:39 +02:00
public function testOnSignalWatcherKeepAliveRunResult () : void
2018-06-18 20:00:01 +02:00
{
2017-03-14 22:47:54 +01:00
$this -> checkForSignalCapability ();
$invoked = false ;
2020-09-26 19:34:39 +02:00
$this -> start ( function ( Driver $loop ) use ( & $invoked ) : void {
2017-03-10 21:31:57 +01:00
$watcher = $loop -> onSignal ( SIGUSR1 , function () {
2016-06-03 17:01:21 +02:00
// empty
});
2020-09-26 19:34:39 +02:00
$watcher = $loop -> delay ( 100 , function () use ( & $invoked , $loop , $watcher ) : void {
2017-03-14 22:47:54 +01:00
$invoked = true ;
$loop -> unreference ( $watcher );
});
2016-06-03 17:01:21 +02:00
$loop -> unreference ( $watcher );
});
2017-03-14 22:47:54 +01:00
$this -> assertTrue ( $invoked );
2016-06-03 17:01:21 +02:00
}
2020-09-26 19:34:39 +02:00
public function testUnreferencedDeferWatcherStillExecutes () : void
2018-06-18 20:00:01 +02:00
{
2017-01-08 17:56:59 +01:00
$invoked = false ;
2020-09-26 19:34:39 +02:00
$this -> start ( function ( Driver $loop ) use ( & $invoked ) : void {
$watcher = $loop -> defer ( function () use ( & $invoked ) : void {
2017-01-08 17:56:59 +01:00
$invoked = true ;
});
$loop -> unreference ( $watcher );
$loop -> defer ( function () {
// just to keep loop running
});
});
$this -> assertTrue ( $invoked );
}
2020-09-26 19:34:39 +02:00
public function testLoopDoesNotBlockOnNegativeTimerExpiration () : void
2018-06-18 20:00:01 +02:00
{
2017-01-08 17:56:59 +01:00
$invoked = false ;
2020-09-26 19:34:39 +02:00
$this -> start ( function ( Driver $loop ) use ( & $invoked ) : void {
$loop -> delay ( 1 , function () use ( & $invoked ) : void {
2017-01-08 17:56:59 +01:00
$invoked = true ;
});
2017-11-29 13:36:50 +01:00
\usleep ( 1000 * 10 );
2017-01-08 17:56:59 +01:00
});
$this -> assertTrue ( $invoked );
}
2020-09-26 19:34:39 +02:00
public function testDisabledDeferReenableInSubsequentTick () : void
2018-06-18 20:00:01 +02:00
{
2016-06-03 17:01:21 +02:00
$this -> expectOutputString ( " 123 " );
2017-03-10 21:31:57 +01:00
$this -> start ( function ( Driver $loop ) {
2020-09-26 19:34:39 +02:00
$watcherId = $loop -> defer ( function ( $watcherId ) : void {
2016-06-03 17:01:21 +02:00
echo 3 ;
});
$loop -> disable ( $watcherId );
2020-09-26 19:34:39 +02:00
$loop -> defer ( function () use ( $loop , $watcherId ) : void {
2016-06-03 17:01:21 +02:00
$loop -> enable ( $watcherId );
echo 2 ;
});
echo 1 ;
});
}
2020-09-26 19:34:39 +02:00
public function provideRegistrationArgs () : array
2018-06-18 20:00:01 +02:00
{
2016-06-03 17:01:21 +02:00
$args = [
2020-07-14 21:45:35 +02:00
[
" defer " ,
[
function () {
},
],
],
[
" delay " ,
[
5 ,
function () {
},
],
],
[
" repeat " ,
[
5 ,
function () {
},
],
],
[
" onWritable " ,
[
\STDOUT ,
function () {
},
],
],
[
" onReadable " ,
[
\STDIN ,
function () {
},
],
],
[
" onSignal " ,
[
\SIGUSR1 ,
function () {
},
],
],
2016-06-03 17:01:21 +02:00
];
return $args ;
}
2017-01-07 12:23:28 +01:00
2016-12-29 21:59:26 +01:00
/**
* @ requires PHP 7
* @ dataProvider provideRegistrationArgs
*/
2020-09-26 19:34:39 +02:00
public function testWeakTypes ( string $type , array $args ) : void
2018-06-18 20:00:01 +02:00
{
2016-12-29 18:16:36 +01:00
if ( $type == " onSignal " ) {
2017-03-12 17:33:46 +01:00
$this -> checkForSignalCapability ();
2016-12-29 18:16:36 +01:00
}
2020-09-26 19:34:39 +02:00
$this -> start ( function ( Driver $loop ) use ( $type , $args , & $invoked ) : void {
2016-12-29 17:45:12 +01:00
if ( $type == " onReadable " ) {
2020-07-14 21:45:35 +02:00
$ends = \stream_socket_pair (
\stripos ( PHP_OS , " win " ) === 0 ? STREAM_PF_INET : STREAM_PF_UNIX ,
STREAM_SOCK_STREAM ,
STREAM_IPPROTO_IP
);
2017-11-29 13:36:50 +01:00
\fwrite ( $ends [ 0 ], " trigger readability watcher " );
2016-12-29 17:45:12 +01:00
$args = [ $ends [ 1 ]];
} else {
2017-11-29 13:36:50 +01:00
\array_pop ( $args );
2016-12-29 17:45:12 +01:00
}
$expectedData = 20.75 ;
2017-11-29 13:36:50 +01:00
if ( \substr ( $type , 0 , 2 ) == " on " ) {
2020-09-26 19:34:39 +02:00
$args [] = function ( $watcherId , $arg , int $data ) use ( $loop , & $invoked , $expectedData ) : void {
2016-12-29 17:45:12 +01:00
$invoked = true ;
$this -> assertSame (( int ) $expectedData , $data );
$loop -> unreference ( $watcherId );
};
} else {
2020-09-26 19:34:39 +02:00
$args [] = function ( $watcherId , int $data ) use ( $loop , & $invoked , $expectedData , $type ) : void {
2016-12-29 17:45:12 +01:00
$invoked = true ;
$this -> assertSame (( int ) $expectedData , $data );
if ( $type == " repeat " ) {
$loop -> unreference ( $watcherId );
}
};
}
$args [] = $expectedData ;
2017-11-29 13:36:50 +01:00
\call_user_func_array ([ $loop , $type ], $args );
2016-12-29 17:45:12 +01:00
if ( $type == " onSignal " ) {
2020-10-10 15:54:50 +02:00
$loop -> delay ( 1 , function () {
2016-12-29 17:45:12 +01:00
\posix_kill ( \getmypid (), \SIGUSR1 );
});
}
});
$this -> assertTrue ( $invoked );
}
2016-06-07 01:53:28 +02:00
/** @dataProvider provideRegistrationArgs */
2020-09-26 19:34:39 +02:00
public function testDisableWithConsecutiveCancel ( string $type , array $args ) : void
2018-06-18 20:00:01 +02:00
{
2016-06-03 17:01:21 +02:00
if ( $type === " onSignal " ) {
2017-03-12 17:33:46 +01:00
$this -> checkForSignalCapability ();
2016-06-03 17:01:21 +02:00
}
2017-03-14 00:52:57 +01:00
$invoked = false ;
2020-09-26 19:34:39 +02:00
$this -> start ( function ( Driver $loop ) use ( & $invoked , $type , $args ) : void {
2016-06-03 17:01:21 +02:00
$func = [ $loop , $type ];
$watcherId = \call_user_func_array ( $func , $args );
$loop -> disable ( $watcherId );
2020-09-26 19:34:39 +02:00
$loop -> defer ( function () use ( & $invoked , $loop , $watcherId ) : void {
2016-06-03 17:01:21 +02:00
$loop -> cancel ( $watcherId );
2017-03-14 00:52:57 +01:00
$invoked = true ;
2016-06-03 17:01:21 +02:00
});
2017-03-14 00:52:57 +01:00
$this -> assertFalse ( $invoked );
2016-06-03 17:01:21 +02:00
});
2017-03-14 00:52:57 +01:00
$this -> assertTrue ( $invoked );
2016-06-03 17:01:21 +02:00
}
2016-06-07 01:53:28 +02:00
/** @dataProvider provideRegistrationArgs */
2020-09-26 19:34:39 +02:00
public function testWatcherReferenceInfo ( string $type , array $args ) : void
2018-06-18 20:00:01 +02:00
{
2016-06-03 17:01:21 +02:00
if ( $type === " onSignal " ) {
2017-03-12 17:33:46 +01:00
$this -> checkForSignalCapability ();
2016-06-03 17:01:21 +02:00
}
$loop = $this -> loop ;
$func = [ $loop , $type ];
2017-11-29 13:36:50 +01:00
if ( \substr ( $type , 0 , 2 ) === " on " ) {
$type = " on_ " . \lcfirst ( \substr ( $type , 2 ));
2016-06-03 17:01:21 +02:00
}
// being referenced is the default
$watcherId1 = \call_user_func_array ( $func , $args );
2016-12-28 19:48:34 +01:00
$info = $loop -> getInfo ();
2016-06-03 17:01:21 +02:00
$expected = [ " enabled " => 1 , " disabled " => 0 ];
$this -> assertSame ( $expected , $info [ $type ]);
$expected = [ " referenced " => 1 , " unreferenced " => 0 ];
2017-03-10 22:20:28 +01:00
$this -> assertSame ( $expected , $info [ " enabled_watchers " ]);
2016-06-03 17:01:21 +02:00
// explicitly reference() even though it's the default setting
$argsCopy = $args ;
$watcherId2 = \call_user_func_array ( $func , $argsCopy );
$loop -> reference ( $watcherId2 );
$loop -> reference ( $watcherId2 );
2016-12-28 19:48:34 +01:00
$info = $loop -> getInfo ();
2016-06-03 17:01:21 +02:00
$expected = [ " enabled " => 2 , " disabled " => 0 ];
$this -> assertSame ( $expected , $info [ $type ]);
$expected = [ " referenced " => 2 , " unreferenced " => 0 ];
2017-03-10 22:20:28 +01:00
$this -> assertSame ( $expected , $info [ " enabled_watchers " ]);
2016-06-03 17:01:21 +02:00
// disabling a referenced watcher should decrement the referenced count
$loop -> disable ( $watcherId2 );
$loop -> disable ( $watcherId2 );
$loop -> disable ( $watcherId2 );
2016-12-28 19:48:34 +01:00
$info = $loop -> getInfo ();
2016-06-03 17:01:21 +02:00
$expected = [ " referenced " => 1 , " unreferenced " => 0 ];
2017-03-10 22:20:28 +01:00
$this -> assertSame ( $expected , $info [ " enabled_watchers " ]);
2016-06-03 17:01:21 +02:00
// enabling a referenced watcher should increment the referenced count
$loop -> enable ( $watcherId2 );
$loop -> enable ( $watcherId2 );
2016-12-28 19:48:34 +01:00
$info = $loop -> getInfo ();
2016-06-03 17:01:21 +02:00
$expected = [ " referenced " => 2 , " unreferenced " => 0 ];
2017-03-10 22:20:28 +01:00
$this -> assertSame ( $expected , $info [ " enabled_watchers " ]);
2016-06-03 17:01:21 +02:00
// cancelling an referenced watcher should decrement the referenced count
$loop -> cancel ( $watcherId2 );
2016-12-28 19:48:34 +01:00
$info = $loop -> getInfo ();
2016-06-03 17:01:21 +02:00
$expected = [ " referenced " => 1 , " unreferenced " => 0 ];
2017-03-10 22:20:28 +01:00
$this -> assertSame ( $expected , $info [ " enabled_watchers " ]);
2016-06-03 17:01:21 +02:00
// unreference() should just increment unreferenced count
$watcherId2 = \call_user_func_array ( $func , $args );
$loop -> unreference ( $watcherId2 );
2016-12-28 19:48:34 +01:00
$info = $loop -> getInfo ();
2016-06-03 17:01:21 +02:00
$expected = [ " enabled " => 2 , " disabled " => 0 ];
$this -> assertSame ( $expected , $info [ $type ]);
$expected = [ " referenced " => 1 , " unreferenced " => 1 ];
2017-03-10 22:20:28 +01:00
$this -> assertSame ( $expected , $info [ " enabled_watchers " ]);
2016-06-03 17:01:21 +02:00
$loop -> cancel ( $watcherId1 );
$loop -> cancel ( $watcherId2 );
}
2016-06-07 01:53:28 +02:00
/** @dataProvider provideRegistrationArgs */
2020-09-26 19:34:39 +02:00
public function testWatcherRegistrationAndCancellationInfo ( string $type , array $args ) : void
2018-06-18 20:00:01 +02:00
{
2016-06-03 17:01:21 +02:00
if ( $type === " onSignal " ) {
2017-03-12 17:33:46 +01:00
$this -> checkForSignalCapability ();
2016-06-03 17:01:21 +02:00
}
$loop = $this -> loop ;
$func = [ $loop , $type ];
2017-11-29 13:36:50 +01:00
if ( \substr ( $type , 0 , 2 ) === " on " ) {
$type = " on_ " . \lcfirst ( \substr ( $type , 2 ));
2016-06-03 17:01:21 +02:00
}
$watcherId = \call_user_func_array ( $func , $args );
2020-09-26 19:34:39 +02:00
$this -> assertIsString ( $watcherId );
2016-12-28 19:48:34 +01:00
$info = $loop -> getInfo ();
2016-06-03 17:01:21 +02:00
$expected = [ " enabled " => 1 , " disabled " => 0 ];
$this -> assertSame ( $expected , $info [ $type ]);
// invoke enable() on active watcher to ensure it has no side-effects
$loop -> enable ( $watcherId );
2016-12-28 19:48:34 +01:00
$info = $loop -> getInfo ();
2016-06-03 17:01:21 +02:00
$expected = [ " enabled " => 1 , " disabled " => 0 ];
$this -> assertSame ( $expected , $info [ $type ]);
// invoke disable() twice to ensure it has no side-effects
$loop -> disable ( $watcherId );
$loop -> disable ( $watcherId );
2016-12-28 19:48:34 +01:00
$info = $loop -> getInfo ();
2016-06-03 17:01:21 +02:00
$expected = [ " enabled " => 0 , " disabled " => 1 ];
$this -> assertSame ( $expected , $info [ $type ]);
$loop -> cancel ( $watcherId );
2016-12-28 19:48:34 +01:00
$info = $loop -> getInfo ();
2016-06-03 17:01:21 +02:00
$expected = [ " enabled " => 0 , " disabled " => 0 ];
$this -> assertSame ( $expected , $info [ $type ]);
$watcherId = \call_user_func_array ( $func , $args );
2016-12-28 19:48:34 +01:00
$info = $loop -> getInfo ();
2016-06-03 17:01:21 +02:00
$expected = [ " enabled " => 1 , " disabled " => 0 ];
$this -> assertSame ( $expected , $info [ $type ]);
$loop -> disable ( $watcherId );
2016-12-28 19:48:34 +01:00
$info = $loop -> getInfo ();
2016-06-03 17:01:21 +02:00
$expected = [ " enabled " => 0 , " disabled " => 1 ];
$this -> assertSame ( $expected , $info [ $type ]);
$loop -> enable ( $watcherId );
2016-12-28 19:48:34 +01:00
$info = $loop -> getInfo ();
2016-06-03 17:01:21 +02:00
$expected = [ " enabled " => 1 , " disabled " => 0 ];
$this -> assertSame ( $expected , $info [ $type ]);
$loop -> cancel ( $watcherId );
2016-12-28 19:48:34 +01:00
$info = $loop -> getInfo ();
2016-06-03 17:01:21 +02:00
$expected = [ " enabled " => 0 , " disabled " => 0 ];
$this -> assertSame ( $expected , $info [ $type ]);
2016-08-30 22:39:47 +02:00
$loop -> disable ( $watcherId );
2016-12-28 19:48:34 +01:00
$info = $loop -> getInfo ();
2016-08-30 22:39:47 +02:00
$expected = [ " enabled " => 0 , " disabled " => 0 ];
$this -> assertSame ( $expected , $info [ $type ]);
2016-06-03 17:01:21 +02:00
}
2017-04-26 20:27:59 +02:00
/**
* @ dataProvider provideRegistrationArgs
* @ group memoryleak
*/
2020-09-26 19:34:39 +02:00
public function testNoMemoryLeak ( string $type , array $args ) : void
2018-06-18 20:00:01 +02:00
{
2017-03-10 21:31:57 +01:00
if ( $this -> getTestResultObject () -> getCollectCodeCoverageInformation ()) {
2016-12-29 17:45:12 +01:00
$this -> markTestSkipped ( " Cannot run this test with code coverage active [code coverage consumes memory which makes it impossible to rely on memory_get_usage()] " );
}
2016-08-15 15:08:09 +02:00
2016-06-07 19:45:15 +02:00
$runs = 2000 ;
2016-06-03 17:01:21 +02:00
if ( $type === " onSignal " ) {
2017-03-12 17:33:46 +01:00
$this -> checkForSignalCapability ();
2016-06-03 17:01:21 +02:00
}
2020-10-03 05:26:10 +02:00
$this -> start ( function ( Driver $loop ) use ( $type , $args , $runs ) {
2017-11-29 13:36:50 +01:00
$initialMem = \memory_get_usage ();
2020-10-03 05:26:10 +02:00
$cb = function ( $runs ) use ( $loop , $type , $args ) : void {
2016-06-03 17:01:21 +02:00
$func = [ $loop , $type ];
for ( $watchers = [], $i = 0 ; $i < $runs ; $i ++ ) {
$watchers [] = \call_user_func_array ( $func , $args );
}
foreach ( $watchers as $watcher ) {
$loop -> cancel ( $watcher );
}
for ( $watchers = [], $i = 0 ; $i < $runs ; $i ++ ) {
$watchers [] = \call_user_func_array ( $func , $args );
}
foreach ( $watchers as $watcher ) {
$loop -> disable ( $watcher );
$loop -> cancel ( $watcher );
}
for ( $watchers = [], $i = 0 ; $i < $runs ; $i ++ ) {
$watchers [] = \call_user_func_array ( $func , $args );
}
if ( $type === " repeat " ) {
2020-09-26 19:34:39 +02:00
$loop -> delay ( $msInterval = 7 , function () use ( $loop , $watchers ) : void {
2016-06-03 17:01:21 +02:00
foreach ( $watchers as $watcher ) {
$loop -> cancel ( $watcher );
}
});
} elseif ( $type !== " defer " && $type !== " delay " ) {
$loop -> defer ( function () use ( $loop , $watchers ) {
foreach ( $watchers as $watcher ) {
$loop -> cancel ( $watcher );
}
});
}
2020-10-03 05:26:10 +02:00
$loop -> run ();
2016-06-03 17:01:21 +02:00
if ( $type === " defer " ) {
2020-09-26 19:34:39 +02:00
$loop -> defer ( $fn = function ( $watcherId , $i ) use ( & $fn , $loop ) : void {
2016-06-03 17:01:21 +02:00
if ( $i ) {
$loop -> defer ( $fn , -- $i );
}
}, $runs );
2020-10-03 05:26:10 +02:00
$loop -> run ();
2016-06-03 17:01:21 +02:00
}
if ( $type === " delay " ) {
2020-09-26 19:34:39 +02:00
$loop -> delay ( $msDelay = 0 , $fn = function ( $watcherId , $i ) use ( & $fn , $loop ) : void {
2016-06-03 17:01:21 +02:00
if ( $i ) {
$loop -> delay ( $msDelay = 0 , $fn , -- $i );
}
}, $runs );
2020-10-03 05:26:10 +02:00
$loop -> run ();
2016-06-03 17:01:21 +02:00
}
if ( $type === " repeat " ) {
2020-09-26 19:34:39 +02:00
$loop -> repeat ( $msDelay = 0 , $fn = function ( $watcherId , $i ) use ( & $fn , $loop ) : void {
2016-06-03 17:01:21 +02:00
$loop -> cancel ( $watcherId );
if ( $i ) {
$loop -> repeat ( $msDelay = 0 , $fn , -- $i );
}
}, $runs );
2020-10-03 05:26:10 +02:00
$loop -> run ();
2016-06-03 17:01:21 +02:00
}
if ( $type === " onWritable " ) {
2020-09-26 19:34:39 +02:00
$loop -> defer ( function ( $watcherId , $runs ) use ( $loop ) : void {
$fn = function ( $watcherId , $socket , $i ) use ( & $fn , $loop ) : void {
2016-06-03 17:01:21 +02:00
$loop -> cancel ( $watcherId );
if ( $socket ) {
2017-11-29 13:36:50 +01:00
\fwrite ( $socket , " . " );
2016-06-03 17:01:21 +02:00
}
if ( $i ) {
// explicitly use *different* streams with *different* resource ids
2020-07-14 21:45:35 +02:00
$ends = \stream_socket_pair (
\stripos (
PHP_OS ,
" win "
) === 0 ? STREAM_PF_INET : STREAM_PF_UNIX ,
STREAM_SOCK_STREAM ,
STREAM_IPPROTO_IP
);
2016-06-03 17:01:21 +02:00
$loop -> onWritable ( $ends [ 0 ], $fn , -- $i );
2020-09-26 19:34:39 +02:00
$loop -> onReadable ( $ends [ 1 ], function ( $watcherId ) use ( $loop ) : void {
2016-06-03 17:01:21 +02:00
$loop -> cancel ( $watcherId );
});
}
};
$fn ( $watcherId , null , $runs );
}, $runs + 1 );
2020-10-03 05:26:10 +02:00
$loop -> run ();
2016-06-03 17:01:21 +02:00
}
if ( $type === " onSignal " ) {
2020-09-26 19:34:39 +02:00
$sendSignal = function () : void {
2016-06-07 20:21:10 +02:00
\posix_kill ( \getmypid (), \SIGUSR1 );
};
2020-09-26 19:34:39 +02:00
$loop -> onSignal ( \SIGUSR1 , $fn = function ( $watcherId , $signo , $i ) use ( & $fn , $loop , $sendSignal ) : void {
2016-06-03 17:01:21 +02:00
if ( $i ) {
2016-06-07 20:21:10 +02:00
$loop -> onSignal ( \SIGUSR1 , $fn , -- $i );
2020-10-10 15:54:50 +02:00
$loop -> delay ( 1 , $sendSignal );
2016-06-03 17:01:21 +02:00
}
2016-06-07 20:21:10 +02:00
$loop -> cancel ( $watcherId );
}, $runs );
2020-10-10 15:54:50 +02:00
$loop -> delay ( 1 , $sendSignal );
2020-10-03 05:26:10 +02:00
$loop -> run ();
2016-06-03 17:01:21 +02:00
}
};
2017-11-29 13:36:50 +01:00
$closureMem = \memory_get_usage () - $initialMem ;
2016-06-07 19:45:15 +02:00
$cb ( $runs ); /* just to set up eventual structures inside loop without counting towards memory comparison */
2017-11-29 13:36:50 +01:00
\gc_collect_cycles ();
$initialMem = \memory_get_usage () - $closureMem ;
2016-06-07 19:45:15 +02:00
$cb ( $runs );
2016-06-03 17:01:21 +02:00
unset ( $cb );
2017-11-29 13:36:50 +01:00
\gc_collect_cycles ();
$endMem = \memory_get_usage ();
2016-06-03 17:01:21 +02:00
/* this is allowing some memory usage due to runtime caches etc., but nothing actually leaking */
2016-06-07 19:45:15 +02:00
$this -> assertLessThan ( $runs * 4 , $endMem - $initialMem ); // * 4, as 4 is minimal sizeof(void *)
2016-06-03 17:01:21 +02:00
});
}
2017-03-25 19:52:17 +01:00
/**
* The first number of each tuple indicates the tick in which the watcher is supposed to execute , the second digit
* indicates the order within the tick .
*/
2020-09-26 19:34:39 +02:00
public function testExecutionOrderGuarantees () : void
2018-06-18 20:00:01 +02:00
{
2020-07-14 21:45:35 +02:00
$this -> expectOutputString ( " 01 02 03 04 " . \str_repeat ( " 05 " , 8 ) . " 10 11 12 " . \str_repeat (
" 13 " ,
4
) . " 20 " . \str_repeat ( " 21 " , 4 ) . " 30 40 41 " );
2020-09-26 19:34:39 +02:00
$this -> start ( function ( Driver $loop ) : void {
2017-05-02 21:42:45 +02:00
// Wrap in extra defer, so driver creation time doesn't count for timers, as timers are driver creation
// relative instead of last tick relative before first tick.
2020-09-26 19:34:39 +02:00
$loop -> defer ( function () use ( $loop ) : void {
$f = function () use ( $loop ) : callable {
2017-11-29 13:36:50 +01:00
$args = \func_get_args ();
2020-09-26 19:34:39 +02:00
return function ( $watcherId ) use ( $loop , & $args ) : void {
2017-05-02 21:42:45 +02:00
if ( ! $args ) {
$this -> fail ( " Watcher callback called too often " );
}
$loop -> cancel ( $watcherId );
2017-11-29 13:36:50 +01:00
echo \array_shift ( $args ) . \array_shift ( $args ), " " ;
2017-05-02 21:42:45 +02:00
};
2016-06-07 01:53:28 +02:00
};
2017-05-02 21:42:45 +02:00
$loop -> onWritable ( STDOUT , $f ( 0 , 5 ));
$writ1 = $loop -> onWritable ( STDOUT , $f ( 0 , 5 ));
$writ2 = $loop -> onWritable ( STDOUT , $f ( 0 , 5 ));
$loop -> delay ( $msDelay = 0 , $f ( 0 , 5 ));
$del1 = $loop -> delay ( $msDelay = 0 , $f ( 0 , 5 ));
$del2 = $loop -> delay ( $msDelay = 0 , $f ( 0 , 5 ));
$del3 = $loop -> delay ( $msDelay = 0 , $f ());
$del4 = $loop -> delay ( $msDelay = 0 , $f ( 1 , 3 ));
$del5 = $loop -> delay ( $msDelay = 0 , $f ( 2 , 0 ));
2020-09-26 19:34:39 +02:00
$loop -> defer ( function () use ( $loop , $del5 ) : void {
2017-05-02 21:42:45 +02:00
$loop -> disable ( $del5 );
});
$loop -> cancel ( $del3 );
$loop -> disable ( $del1 );
$loop -> disable ( $del2 );
$writ3 = $loop -> onWritable ( STDOUT , $f ());
$loop -> cancel ( $writ3 );
$loop -> disable ( $writ1 );
$loop -> disable ( $writ2 );
$loop -> enable ( $writ1 );
$writ4 = $loop -> onWritable ( STDOUT , $f ( 1 , 3 ));
$loop -> onWritable ( STDOUT , $f ( 0 , 5 ));
$loop -> enable ( $writ2 );
$loop -> disable ( $writ4 );
2020-09-26 19:34:39 +02:00
$loop -> defer ( function () use ( $loop , $writ4 , $f ) : void {
2017-05-02 21:42:45 +02:00
$loop -> enable ( $writ4 );
$loop -> onWritable ( STDOUT , $f ( 1 , 3 ));
});
2016-06-07 01:53:28 +02:00
2017-05-02 21:42:45 +02:00
$loop -> enable ( $del1 );
$loop -> delay ( $msDelay = 0 , $f ( 0 , 5 ));
$loop -> enable ( $del2 );
$loop -> disable ( $del4 );
2020-09-26 19:34:39 +02:00
$loop -> defer ( function () use ( $loop , $del4 , $f ) : void {
2017-05-02 21:42:45 +02:00
$loop -> enable ( $del4 );
$loop -> onWritable ( STDOUT , $f ( 1 , 3 ));
});
2017-01-07 12:23:28 +01:00
2017-05-02 21:42:45 +02:00
$loop -> delay ( $msDelay = 1000 , $f ( 4 , 1 ));
$loop -> delay ( $msDelay = 600 , $f ( 3 , 0 ));
$loop -> delay ( $msDelay = 500 , $f ( 2 , 1 ));
$loop -> repeat ( $msDelay = 500 , $f ( 2 , 1 ));
2017-05-03 22:21:57 +02:00
$rep1 = $loop -> repeat ( $msDelay = 250 , $f ( 2 , 1 ));
2017-05-02 21:42:45 +02:00
$loop -> disable ( $rep1 );
$loop -> delay ( $msDelay = 500 , $f ( 2 , 1 ));
$loop -> enable ( $rep1 );
$loop -> defer ( $f ( 0 , 1 ));
$def1 = $loop -> defer ( $f ( 0 , 3 ));
$def2 = $loop -> defer ( $f ( 1 , 1 ));
$def3 = $loop -> defer ( $f ());
$loop -> defer ( $f ( 0 , 2 ));
$loop -> disable ( $def1 );
$loop -> cancel ( $def3 );
$loop -> enable ( $def1 );
2020-09-26 19:34:39 +02:00
$loop -> defer ( function () use ( $loop , $def2 , $del5 , $f ) : void {
2017-05-02 21:42:45 +02:00
$tick = $f ( 0 , 4 );
$tick ( " invalid " );
$loop -> defer ( $f ( 1 , 0 ));
$loop -> enable ( $def2 );
$loop -> defer ( $f ( 1 , 2 ));
2020-09-26 19:34:39 +02:00
$loop -> defer ( function () use ( $loop , $del5 , $f ) : void {
2017-05-02 21:42:45 +02:00
$loop -> enable ( $del5 );
2020-09-26 19:34:39 +02:00
$loop -> defer ( function () use ( $loop , $f ) : void {
2017-11-29 13:36:50 +01:00
\usleep ( 700000 ); // to have $msDelay == 500 and $msDelay == 600 run at the same tick (but not $msDelay == 150)
2020-09-26 19:34:39 +02:00
$loop -> defer ( function () use ( $loop , $f ) : void {
2017-05-02 21:42:45 +02:00
$loop -> defer ( $f ( 4 , 0 ));
});
2016-06-26 17:12:33 +02:00
});
});
});
2017-05-02 21:42:45 +02:00
$loop -> disable ( $def2 );
2016-06-07 01:53:28 +02:00
});
});
}
2020-09-26 19:34:39 +02:00
public function testSignalExecutionOrder () : void
2018-06-18 20:00:01 +02:00
{
2017-03-14 22:47:54 +01:00
$this -> checkForSignalCapability ();
2016-06-07 01:53:28 +02:00
2016-10-26 15:39:07 +02:00
$this -> expectOutputString ( " 122222 " );
2020-10-03 05:26:10 +02:00
$this -> start ( function ( Driver $loop ) : void {
2017-03-10 21:31:57 +01:00
$f = function ( $i ) use ( $loop ) {
2020-09-26 19:34:39 +02:00
return function ( $watcherId ) use ( $loop , $i ) : void {
2016-06-07 01:53:28 +02:00
$loop -> cancel ( $watcherId );
echo $i ;
};
};
$loop -> defer ( $f ( 1 ));
$loop -> onSignal ( SIGUSR1 , $f ( 2 ));
2016-10-26 15:39:07 +02:00
$sig1 = $loop -> onSignal ( SIGUSR1 , $f ( 2 ));
$sig2 = $loop -> onSignal ( SIGUSR1 , $f ( 2 ));
2016-06-07 01:53:28 +02:00
$sig3 = $loop -> onSignal ( SIGUSR1 , $f ( " FAIL - MUST NOT BE CALLED " ));
$loop -> disable ( $sig1 );
2016-10-26 15:39:07 +02:00
$loop -> onSignal ( SIGUSR1 , $f ( 2 ));
2016-06-07 01:53:28 +02:00
$loop -> disable ( $sig2 );
$loop -> enable ( $sig1 );
$loop -> cancel ( $sig3 );
2016-10-26 15:39:07 +02:00
$loop -> onSignal ( SIGUSR1 , $f ( 2 ));
2020-10-03 05:26:10 +02:00
$loop -> defer ( function () use ( $loop , $sig2 ) : void {
2016-06-07 01:53:28 +02:00
$loop -> enable ( $sig2 );
2020-10-10 15:54:50 +02:00
$loop -> delay ( 1 , function () use ( $loop ) {
2016-06-07 19:31:49 +02:00
\posix_kill ( \getmypid (), \SIGUSR1 );
2020-10-03 05:26:10 +02:00
$loop -> delay ( $msDelay = 10 , function () use ( $loop ) : void {
$loop -> stop ();
2016-06-07 19:31:49 +02:00
});
2016-06-07 01:53:28 +02:00
});
});
});
}
2020-09-26 19:34:39 +02:00
public function testExceptionOnEnableNonexistentWatcher () : void
2018-06-18 20:00:01 +02:00
{
2020-09-26 19:34:39 +02:00
$this -> expectException ( InvalidWatcherError :: class );
2016-12-23 01:43:09 +01:00
try {
$this -> loop -> enable ( " nonexistentWatcher " );
2017-03-14 17:50:24 +01:00
} catch ( InvalidWatcherError $e ) {
2017-04-24 15:39:08 +02:00
$this -> assertSame ( " nonexistentWatcher " , $e -> getWatcherId ());
2016-12-23 01:43:09 +01:00
throw $e ;
}
2016-06-03 17:01:21 +02:00
}
2020-09-26 19:34:39 +02:00
public function testSuccessOnDisableNonexistentWatcher () : void
2018-06-18 20:00:01 +02:00
{
2016-06-03 17:01:21 +02:00
$this -> loop -> disable ( " nonexistentWatcher " );
2017-03-12 17:33:46 +01:00
// Otherwise risky, throwing fails the test
$this -> assertTrue ( true );
2016-06-03 17:01:21 +02:00
}
2020-09-26 19:34:39 +02:00
public function testSuccessOnCancelNonexistentWatcher () : void
2018-06-18 20:00:01 +02:00
{
2016-06-03 17:01:21 +02:00
$this -> loop -> cancel ( " nonexistentWatcher " );
2017-03-12 17:33:46 +01:00
// Otherwise risky, throwing fails the test
$this -> assertTrue ( true );
2016-06-03 17:01:21 +02:00
}
2020-09-26 19:34:39 +02:00
public function testExceptionOnReferenceNonexistentWatcher () : void
2018-06-18 20:00:01 +02:00
{
2020-09-26 19:34:39 +02:00
$this -> expectException ( InvalidWatcherError :: class );
2016-12-23 01:43:09 +01:00
try {
$this -> loop -> reference ( " nonexistentWatcher " );
2017-03-14 17:50:24 +01:00
} catch ( InvalidWatcherError $e ) {
2017-04-24 15:39:08 +02:00
$this -> assertSame ( " nonexistentWatcher " , $e -> getWatcherId ());
2016-12-23 01:43:09 +01:00
throw $e ;
}
2016-06-07 01:53:28 +02:00
}
2020-09-26 19:34:39 +02:00
public function testSuccessOnUnreferenceNonexistentWatcher () : void
2018-06-18 20:00:01 +02:00
{
2018-04-12 09:46:52 +02:00
$this -> loop -> unreference ( " nonexistentWatcher " );
// Otherwise risky, throwing fails the test
$this -> assertTrue ( true );
2016-06-07 01:53:28 +02:00
}
2020-09-26 19:34:39 +02:00
public function testWatcherInvalidityOnDefer () : void
2018-06-18 20:00:01 +02:00
{
2020-09-26 19:34:39 +02:00
$this -> expectException ( InvalidWatcherError :: class );
$this -> start ( function ( Driver $loop ) : void {
$loop -> defer ( function ( $watcher ) use ( $loop ) : void {
2016-08-30 22:39:47 +02:00
$loop -> enable ( $watcher );
2016-06-07 01:53:28 +02:00
});
});
}
2020-09-26 19:34:39 +02:00
public function testWatcherInvalidityOnDelay () : void
2018-06-18 20:00:01 +02:00
{
2020-09-26 19:34:39 +02:00
$this -> expectException ( InvalidWatcherError :: class );
$this -> start ( function ( Driver $loop ) : void {
$loop -> delay ( $msDelay = 0 , function ( $watcher ) use ( $loop ) : void {
2016-08-30 22:39:47 +02:00
$loop -> enable ( $watcher );
2016-06-07 01:53:28 +02:00
});
});
}
2020-09-26 19:34:39 +02:00
public function testEventsNotExecutedInSameTickAsEnabled () : void
2018-06-18 20:00:01 +02:00
{
2020-09-26 19:34:39 +02:00
$this -> start ( function ( Driver $loop ) : void {
$loop -> defer ( function () use ( $loop ) : void {
$loop -> defer ( function () use ( $loop , & $diswatchers , & $watchers ) : void {
$loop -> defer ( function () use ( $loop , $diswatchers ) : void {
2016-06-07 01:53:28 +02:00
foreach ( $diswatchers as $watcher ) {
$loop -> disable ( $watcher );
}
2020-09-26 19:34:39 +02:00
$loop -> defer ( function () use ( $loop , $diswatchers ) : void {
$loop -> defer ( function () use ( $loop , $diswatchers ) : void {
2016-06-07 01:53:28 +02:00
foreach ( $diswatchers as $watcher ) {
$loop -> cancel ( $watcher );
}
});
2016-06-07 19:25:59 +02:00
foreach ( $diswatchers as $watcher ) {
$loop -> enable ( $watcher );
}
2016-06-07 01:53:28 +02:00
});
});
2016-06-07 19:25:59 +02:00
foreach ( $watchers as $watcher ) {
$loop -> cancel ( $watcher );
}
foreach ( $diswatchers as $watcher ) {
$loop -> disable ( $watcher );
$loop -> enable ( $watcher );
}
2016-06-07 01:53:28 +02:00
});
2020-09-26 19:34:39 +02:00
$f = function () use ( $loop ) : array {
2016-06-07 01:53:28 +02:00
$watchers [] = $loop -> defer ([ $this , " fail " ]);
$watchers [] = $loop -> delay ( $msDelay = 0 , [ $this , " fail " ]);
$watchers [] = $loop -> repeat ( $msDelay = 0 , [ $this , " fail " ]);
$watchers [] = $loop -> onWritable ( STDIN , [ $this , " fail " ]);
return $watchers ;
};
$watchers = $f ();
$diswatchers = $f ();
});
});
2017-03-12 17:33:46 +01:00
// Otherwise risky, as we only rely on $this->fail()
$this -> assertTrue ( true );
2016-06-07 01:53:28 +02:00
}
2020-09-26 19:34:39 +02:00
public function testEnablingWatcherAllowsSubsequentInvocation () : void
2018-06-18 20:00:01 +02:00
{
2016-06-03 17:01:21 +02:00
$increment = 0 ;
2020-10-03 05:26:10 +02:00
$watcherId = $this -> loop -> defer ( function () use ( & $increment ) : void {
2016-06-03 17:01:21 +02:00
$increment ++ ;
});
2020-10-03 05:26:10 +02:00
$this -> loop -> disable ( $watcherId );
$this -> loop -> delay ( $msDelay = 5 , [ $this -> loop , " stop " ]);
$this -> loop -> run ();
2017-04-24 15:39:08 +02:00
$this -> assertSame ( 0 , $increment );
2020-10-03 05:26:10 +02:00
$this -> loop -> enable ( $watcherId );
$this -> loop -> delay ( $msDelay = 5 , [ $this -> loop , " stop " ]);
$this -> loop -> run ();
2017-04-24 15:39:08 +02:00
$this -> assertSame ( 1 , $increment );
2016-06-03 17:01:21 +02:00
}
2020-09-26 19:34:39 +02:00
public function testUnresolvedEventsAreReenabledOnRunFollowingPreviousStop () : void
2018-06-18 20:00:01 +02:00
{
2016-06-03 17:01:21 +02:00
$increment = 0 ;
2020-10-03 05:26:10 +02:00
$this -> start ( function ( Driver $loop ) use ( & $increment ) : void {
$loop -> defer ([ $loop , " stop " ]);
$loop -> run ();
2016-06-03 17:01:21 +02:00
2020-10-03 05:26:10 +02:00
$loop -> defer ( function () use ( & $increment , $loop ) : void {
$loop -> delay ( $msDelay = 100 , function () use ( $loop , & $increment ) : void {
2016-06-03 17:01:21 +02:00
$increment ++ ;
2020-10-03 05:26:10 +02:00
$loop -> stop ();
2016-06-03 17:01:21 +02:00
});
});
2017-04-24 15:39:08 +02:00
$this -> assertSame ( 0 , $increment );
2016-06-03 17:01:21 +02:00
\usleep ( 5000 );
});
2017-04-24 15:39:08 +02:00
$this -> assertSame ( 1 , $increment );
2016-06-03 17:01:21 +02:00
}
2020-09-26 19:34:39 +02:00
public function testTimerWatcherParameterOrder () : void
2018-06-18 20:00:01 +02:00
{
2020-10-03 05:26:10 +02:00
$this -> start ( function ( Driver $loop ) : void {
2016-06-03 17:01:21 +02:00
$counter = 0 ;
2020-10-03 05:26:10 +02:00
$loop -> defer ( function ( $watcherId ) use ( $loop , & $counter ) : void {
2020-09-26 19:34:39 +02:00
$this -> assertIsString ( $watcherId );
2016-06-03 17:01:21 +02:00
if ( ++ $counter === 3 ) {
2020-10-03 05:26:10 +02:00
$loop -> stop ();
2016-06-03 17:01:21 +02:00
}
});
2020-10-03 05:26:10 +02:00
$loop -> delay ( $msDelay = 5 , function ( $watcherId ) use ( $loop , & $counter ) : void {
2020-09-26 19:34:39 +02:00
$this -> assertIsString ( $watcherId );
2016-06-03 17:01:21 +02:00
if ( ++ $counter === 3 ) {
2020-10-03 05:26:10 +02:00
$loop -> stop ();
2016-06-03 17:01:21 +02:00
}
});
2020-10-03 05:26:10 +02:00
$loop -> repeat ( $msDelay = 5 , function ( $watcherId ) use ( $loop , & $counter ) : void {
2020-09-26 19:34:39 +02:00
$this -> assertIsString ( $watcherId );
2016-06-03 17:01:21 +02:00
$loop -> cancel ( $watcherId );
if ( ++ $counter === 3 ) {
2020-10-03 05:26:10 +02:00
$loop -> stop ();
2016-06-03 17:01:21 +02:00
}
});
});
}
2020-09-26 19:34:39 +02:00
public function testStreamWatcherParameterOrder () : void
2018-06-18 20:00:01 +02:00
{
2020-09-26 19:34:39 +02:00
$this -> start ( function ( Driver $loop ) use ( & $invoked ) : void {
2016-06-03 17:01:21 +02:00
$invoked = 0 ;
2020-09-26 19:34:39 +02:00
$loop -> onWritable ( STDOUT , function ( $watcherId , $stream ) use ( $loop , & $invoked ) : void {
$this -> assertIsString ( $watcherId );
2016-06-03 17:01:21 +02:00
$this -> assertSame ( STDOUT , $stream );
$invoked ++ ;
$loop -> cancel ( $watcherId );
});
});
$this -> assertSame ( 1 , $invoked );
}
2020-09-26 19:34:39 +02:00
public function testDisablingWatcherPreventsSubsequentInvocation () : void
2018-06-18 20:00:01 +02:00
{
2020-10-03 05:26:10 +02:00
$this -> start ( function ( Driver $loop ) : void {
2016-06-03 17:01:21 +02:00
$increment = 0 ;
2020-09-26 19:34:39 +02:00
$watcherId = $loop -> defer ( function () use ( & $increment ) : void {
2016-06-03 17:01:21 +02:00
$increment ++ ;
});
$loop -> disable ( $watcherId );
2020-10-03 05:26:10 +02:00
$loop -> delay ( $msDelay = 5 , [ $loop , " stop " ]);
2016-06-03 17:01:21 +02:00
2017-04-24 15:39:08 +02:00
$this -> assertSame ( 0 , $increment );
2016-06-03 17:01:21 +02:00
});
}
2020-09-26 19:34:39 +02:00
public function testImmediateExecution () : void
2018-06-18 20:00:01 +02:00
{
2016-06-03 17:01:21 +02:00
$loop = $this -> loop ;
$increment = 0 ;
2020-10-03 05:26:10 +02:00
$this -> start ( function ( Driver $loop ) use ( & $increment ) : void {
2020-09-26 19:34:39 +02:00
$loop -> defer ( function () use ( & $increment ) : void {
2016-06-03 17:01:21 +02:00
$increment ++ ;
});
2020-10-03 05:26:10 +02:00
$loop -> defer ([ $loop , " stop " ]);
2016-06-03 17:01:21 +02:00
});
2017-04-24 15:39:08 +02:00
$this -> assertSame ( 1 , $increment );
2016-06-03 17:01:21 +02:00
}
2020-09-26 19:34:39 +02:00
public function testImmediatelyCallbacksDoNotRecurseInSameTick () : void
2018-06-18 20:00:01 +02:00
{
2016-06-03 17:01:21 +02:00
$increment = 0 ;
2020-10-03 05:26:10 +02:00
$this -> start ( function ( Driver $loop ) use ( & $increment ) : void {
2016-06-03 17:01:21 +02:00
$loop -> defer ( function () use ( $loop , & $increment ) {
$increment ++ ;
$loop -> defer ( function () use ( & $increment ) {
$increment ++ ;
});
});
2020-10-03 05:26:10 +02:00
$loop -> defer ([ $loop , " stop " ]);
2016-06-03 17:01:21 +02:00
});
2017-04-24 15:39:08 +02:00
$this -> assertSame ( 1 , $increment );
2016-06-03 17:01:21 +02:00
}
2020-09-26 19:34:39 +02:00
public function testRunExecutesEventsUntilExplicitlyStopped () : void
2018-06-18 20:00:01 +02:00
{
2016-06-03 17:01:21 +02:00
$increment = 0 ;
2020-09-26 19:34:39 +02:00
$this -> start ( function ( Driver $loop ) use ( & $increment ) : void {
$loop -> repeat ( $msInterval = 5 , function ( $watcherId ) use ( $loop , & $increment ) : void {
2016-06-03 17:01:21 +02:00
$increment ++ ;
if ( $increment === 10 ) {
$loop -> cancel ( $watcherId );
}
});
});
2017-04-24 15:39:08 +02:00
$this -> assertSame ( 10 , $increment );
2016-06-03 17:01:21 +02:00
}
2020-09-26 19:34:39 +02:00
public function testLoopAllowsExceptionToBubbleUpDuringStart () : void
2018-06-18 20:00:01 +02:00
{
2020-09-26 19:34:39 +02:00
$this -> expectException ( \Exception :: class );
$this -> expectExceptionMessage ( " loop error " );
$this -> start ( function ( Driver $loop ) : void {
$loop -> defer ( function () : void {
2016-06-03 17:01:21 +02:00
throw new \Exception ( " loop error " );
});
});
2016-05-24 10:37:25 +02:00
}
2020-09-26 19:34:39 +02:00
public function testLoopAllowsExceptionToBubbleUpFromRepeatingAlarmDuringStart () : void
2018-06-18 20:00:01 +02:00
{
2020-09-26 19:34:39 +02:00
$this -> expectException ( \RuntimeException :: class );
$this -> expectExceptionMessage ( " test " );
$this -> start ( function ( Driver $loop ) : void {
$loop -> repeat ( $msInterval = 1 , function () : void {
2016-06-03 17:01:21 +02:00
throw new \RuntimeException ( " test " );
});
});
}
2016-05-24 10:37:25 +02:00
2020-09-26 19:34:39 +02:00
public function testErrorHandlerCapturesUncaughtException () : void
2018-06-18 20:00:01 +02:00
{
2016-06-03 17:01:21 +02:00
$msg = " " ;
2020-09-26 19:34:39 +02:00
$this -> loop -> setErrorHandler ( $f = function () : void {
2017-03-10 21:31:57 +01:00
});
2020-09-26 19:34:39 +02:00
$oldErrorHandler = $this -> loop -> setErrorHandler ( function ( \Exception $error ) use ( & $msg ) : void {
2016-06-03 17:01:21 +02:00
$msg = $error -> getMessage ();
});
2017-04-24 15:39:08 +02:00
$this -> assertSame ( $f , $oldErrorHandler );
2017-03-10 21:31:57 +01:00
$this -> start ( function ( Driver $loop ) {
$loop -> defer ( function () {
2016-06-03 17:01:21 +02:00
throw new \Exception ( " loop error " );
});
});
$this -> assertSame ( " loop error " , $msg );
}
2016-05-24 10:37:25 +02:00
2020-09-26 19:34:39 +02:00
public function testOnErrorFailure () : void
2018-06-18 20:00:01 +02:00
{
2020-09-26 19:34:39 +02:00
$this -> expectException ( \Exception :: class );
$this -> expectExceptionMessage ( " errorception " );
$this -> loop -> setErrorHandler ( function () : void {
2016-06-03 17:01:21 +02:00
throw new \Exception ( " errorception " );
});
2020-09-26 19:34:39 +02:00
$this -> start ( function ( Driver $loop ) : void {
2017-03-10 21:31:57 +01:00
$loop -> delay ( $msDelay = 5 , function () {
2016-06-03 17:01:21 +02:00
throw new \Exception ( " error " );
});
});
}
2016-05-24 10:37:25 +02:00
2020-09-26 19:34:39 +02:00
public function testLoopException () : void
2018-06-18 20:00:01 +02:00
{
2020-09-26 19:34:39 +02:00
$this -> expectException ( \RuntimeException :: class );
$this -> expectExceptionMessage ( " test " );
$this -> start ( function ( Driver $loop ) : void {
$loop -> defer ( function () use ( $loop ) : void {
2016-06-03 17:01:21 +02:00
// force next tick, outside of primary startup tick
2017-03-10 21:31:57 +01:00
$loop -> defer ( function () {
2016-06-03 17:01:21 +02:00
throw new \RuntimeException ( " test " );
});
});
});
}
2020-09-26 19:34:39 +02:00
public function testOnSignalWatcher () : void
2018-06-18 20:00:01 +02:00
{
2017-03-14 22:47:54 +01:00
$this -> checkForSignalCapability ();
2016-06-03 17:01:21 +02:00
$this -> expectOutputString ( " caught SIGUSR1 " );
2020-10-03 05:26:10 +02:00
$this -> start ( function ( Driver $loop ) : void {
$loop -> delay ( $msDelay = 1 , function () use ( $loop ) : void {
2016-06-03 17:01:21 +02:00
\posix_kill ( \getmypid (), \SIGUSR1 );
2020-10-03 05:26:10 +02:00
$loop -> delay ( $msDelay = 10 , [ $loop , " stop " ]);
2016-06-03 17:01:21 +02:00
});
2020-09-26 19:34:39 +02:00
$loop -> onSignal ( SIGUSR1 , function ( $watcherId ) use ( $loop ) : void {
2016-06-03 17:01:21 +02:00
$loop -> cancel ( $watcherId );
echo " caught SIGUSR1 " ;
});
});
}
2020-09-26 19:34:39 +02:00
public function testInitiallyDisabledOnSignalWatcher () : void
2018-06-18 20:00:01 +02:00
{
2017-03-14 22:47:54 +01:00
$this -> checkForSignalCapability ();
2016-06-03 17:01:21 +02:00
$this -> expectOutputString ( " caught SIGUSR1 " );
2020-10-03 05:26:10 +02:00
$this -> start ( function ( Driver $loop ) : void {
$stop = $loop -> delay ( $msDelay = 100 , function () use ( $loop ) : void {
2016-06-26 17:12:33 +02:00
echo " ERROR: manual stop " ;
2020-10-03 05:26:10 +02:00
$loop -> stop ();
2016-06-26 17:12:33 +02:00
});
2020-09-26 19:34:39 +02:00
$watcherId = $loop -> onSignal ( SIGUSR1 , function ( $watcherId ) use ( $loop , $stop ) : void {
2016-06-03 17:01:21 +02:00
echo " caught SIGUSR1 " ;
2016-06-26 17:12:33 +02:00
$loop -> disable ( $stop );
$loop -> disable ( $watcherId );
});
$loop -> disable ( $watcherId );
2020-09-26 19:34:39 +02:00
$loop -> delay ( $msDelay = 1 , function () use ( $loop , $watcherId ) : void {
2016-06-26 17:12:33 +02:00
$loop -> enable ( $watcherId );
2017-03-10 21:31:57 +01:00
$loop -> delay ( $msDelay = 1 , function () {
2016-08-14 21:14:43 +02:00
\posix_kill ( \getmypid (), SIGUSR1 );
2016-06-26 17:12:33 +02:00
});
});
});
}
2020-09-26 19:34:39 +02:00
public function testNestedLoopSignalDispatch () : void
2018-06-18 20:00:01 +02:00
{
2017-03-14 22:47:54 +01:00
$this -> checkForSignalCapability ();
2016-06-26 17:12:33 +02:00
2016-08-14 21:14:43 +02:00
$this -> expectOutputString ( " inner SIGUSR2 \n outer SIGUSR1 \n " );
2020-10-03 05:26:10 +02:00
$this -> start ( function ( Driver $loop ) : void {
$loop -> delay ( $msDelay = 300 , function () use ( $loop ) : void {
$loop -> stop ();
2016-06-26 17:12:33 +02:00
});
2020-10-03 05:26:10 +02:00
$loop -> onSignal ( SIGUSR1 , function () use ( $loop ) : void {
2016-06-26 17:12:33 +02:00
echo " outer SIGUSR1 \n " ;
2020-10-03 05:26:10 +02:00
$loop -> stop ();
2016-06-26 17:12:33 +02:00
});
2016-06-03 17:01:21 +02:00
2020-09-26 19:34:39 +02:00
$loop -> delay ( $msDelay = 1 , function () : void {
2017-03-10 22:20:28 +01:00
/** @var Driver $loop */
$loop = ( $this -> getFactory ())();
2020-10-03 05:26:10 +02:00
$stop = $loop -> delay ( $msDelay = 100 , function () use ( $loop ) : void {
2016-06-26 17:12:33 +02:00
echo " ERROR: manual stop " ;
2020-10-03 05:26:10 +02:00
$loop -> stop ();
2016-06-26 17:12:33 +02:00
});
2020-09-26 19:34:39 +02:00
$loop -> onSignal ( SIGUSR2 , function ( $watcherId ) use ( $loop , $stop ) : void {
2016-08-14 21:14:43 +02:00
echo " inner SIGUSR2 \n " ;
2016-06-26 17:12:33 +02:00
$loop -> cancel ( $stop );
$loop -> cancel ( $watcherId );
});
2020-09-26 19:34:39 +02:00
$loop -> delay ( $msDelay = 1 , function () : void {
2016-08-14 21:14:43 +02:00
\posix_kill ( \getmypid (), SIGUSR2 );
2016-06-03 17:01:21 +02:00
});
2020-10-03 05:26:10 +02:00
$loop -> run ();
2016-06-26 17:12:33 +02:00
});
2020-09-26 19:34:39 +02:00
$loop -> delay ( $msDelay = 20 , function () : void {
2016-06-26 17:12:33 +02:00
\posix_kill ( \getmypid (), \SIGUSR1 );
2016-06-03 17:01:21 +02:00
});
2016-05-24 10:37:25 +02:00
});
}
2020-09-26 19:34:39 +02:00
public function testCancelRemovesWatcher () : void
2018-06-18 20:00:01 +02:00
{
2017-03-12 17:33:46 +01:00
$invoked = false ;
2020-10-03 05:26:10 +02:00
$this -> start ( function ( Driver $loop ) use ( & $invoked ) : void {
2020-09-26 19:34:39 +02:00
$watcherId = $loop -> delay ( $msDelay = 10 , function () : void {
2016-06-03 17:01:21 +02:00
$this -> fail ( 'Watcher was not cancelled as expected' );
});
2020-09-26 19:34:39 +02:00
$loop -> defer ( function () use ( $loop , $watcherId , & $invoked ) : void {
2016-06-03 17:01:21 +02:00
$loop -> cancel ( $watcherId );
2017-03-12 17:33:46 +01:00
$invoked = true ;
2016-06-03 17:01:21 +02:00
});
2017-03-12 17:33:46 +01:00
2020-10-03 05:26:10 +02:00
$loop -> delay ( $msDelay = 5 , [ $loop , " stop " ]);
2016-06-03 17:01:21 +02:00
});
2017-03-12 17:33:46 +01:00
$this -> assertTrue ( $invoked );
2016-06-03 17:01:21 +02:00
}
2016-05-24 10:37:25 +02:00
2020-09-26 19:34:39 +02:00
public function testOnWritableWatcher () : void
2018-06-18 20:00:01 +02:00
{
2016-06-03 17:01:21 +02:00
$flag = false ;
2020-10-03 05:26:10 +02:00
$this -> start ( function ( Driver $loop ) use ( & $flag ) : void {
$loop -> onWritable ( STDOUT , function () use ( $loop , & $flag ) {
2016-06-03 17:01:21 +02:00
$flag = true ;
2020-10-03 05:26:10 +02:00
$loop -> stop ();
2016-06-03 17:01:21 +02:00
});
2020-10-03 05:26:10 +02:00
$loop -> delay ( $msDelay = 5 , [ $loop , " stop " ]);
2016-06-03 17:01:21 +02:00
});
$this -> assertTrue ( $flag );
}
2016-05-24 10:37:25 +02:00
2020-09-26 19:34:39 +02:00
public function testInitiallyDisabledWriteWatcher () : void
2018-06-18 20:00:01 +02:00
{
2016-06-03 17:01:21 +02:00
$increment = 0 ;
2020-10-03 05:26:10 +02:00
$this -> start ( function ( Driver $loop ) : void {
2020-09-26 19:34:39 +02:00
$watcherId = $loop -> onWritable ( STDOUT , function () use ( & $increment ) : void {
2016-06-03 17:01:21 +02:00
$increment ++ ;
});
$loop -> disable ( $watcherId );
2020-10-03 05:26:10 +02:00
$loop -> delay ( $msDelay = 5 , [ $loop , " stop " ]);
2016-06-03 17:01:21 +02:00
});
$this -> assertSame ( 0 , $increment );
}
2020-09-26 19:34:39 +02:00
public function testInitiallyDisabledWriteWatcherIsTriggeredOnceEnabled () : void
2018-06-18 20:00:01 +02:00
{
2016-06-03 17:01:21 +02:00
$this -> expectOutputString ( " 12 " );
2020-10-03 05:26:10 +02:00
$this -> start ( function ( Driver $loop ) : void {
$watcherId = $loop -> onWritable ( STDOUT , function () use ( $loop ) : void {
2016-06-03 17:01:21 +02:00
echo 2 ;
2020-10-03 05:26:10 +02:00
$loop -> stop ();
2016-06-03 17:01:21 +02:00
});
$loop -> disable ( $watcherId );
2020-09-26 19:34:39 +02:00
$loop -> defer ( function () use ( $loop , $watcherId ) : void {
2016-06-03 17:01:21 +02:00
$loop -> enable ( $watcherId );
echo 1 ;
});
});
}
2020-09-26 19:34:39 +02:00
public function testStreamWatcherDoesntSwallowExceptions () : void
2018-06-18 20:00:01 +02:00
{
2020-09-26 19:34:39 +02:00
$this -> expectException ( \RuntimeException :: class );
2020-10-03 05:26:10 +02:00
$this -> start ( function ( Driver $loop ) : void {
2016-06-03 17:01:21 +02:00
$loop -> onWritable ( STDOUT , function () {
throw new \RuntimeException ;
});
2020-10-03 05:26:10 +02:00
$loop -> delay ( $msDelay = 5 , [ $loop , " stop " ]);
2016-06-03 17:01:21 +02:00
});
}
2020-09-26 19:34:39 +02:00
public function testReactorRunsUntilNoWatchersRemain () : void
2018-06-18 20:00:01 +02:00
{
2016-06-03 17:01:21 +02:00
$var1 = $var2 = 0 ;
2020-09-26 19:34:39 +02:00
$this -> start ( function ( Driver $loop ) use ( & $var1 , & $var2 ) : void {
$loop -> repeat ( $msDelay = 1 , function ( $watcherId ) use ( $loop , & $var1 ) : void {
2016-06-03 17:01:21 +02:00
if ( ++ $var1 === 3 ) {
$loop -> cancel ( $watcherId );
}
});
2020-09-26 19:34:39 +02:00
$loop -> onWritable ( STDOUT , function ( $watcherId ) use ( $loop , & $var2 ) : void {
2016-06-03 17:01:21 +02:00
if ( ++ $var2 === 4 ) {
$loop -> cancel ( $watcherId );
}
});
});
$this -> assertSame ( 3 , $var1 );
$this -> assertSame ( 4 , $var2 );
}
2020-09-26 19:34:39 +02:00
public function testReactorRunsUntilNoWatchersRemainWhenStartedDeferred () : void
2018-06-18 20:00:01 +02:00
{
2016-06-03 17:01:21 +02:00
$var1 = $var2 = 0 ;
2020-09-26 19:34:39 +02:00
$this -> start ( function ( Driver $loop ) use ( & $var1 , & $var2 ) : void {
$loop -> defer ( function () use ( $loop , & $var1 , & $var2 ) : void {
$loop -> repeat ( $msDelay = 1 , function ( $watcherId ) use ( $loop , & $var1 ) : void {
2016-06-03 17:01:21 +02:00
if ( ++ $var1 === 3 ) {
$loop -> cancel ( $watcherId );
}
});
2020-09-26 19:34:39 +02:00
$loop -> onWritable ( STDOUT , function ( $watcherId ) use ( $loop , & $var2 ) : void {
2016-06-03 17:01:21 +02:00
if ( ++ $var2 === 4 ) {
$loop -> cancel ( $watcherId );
}
});
});
});
$this -> assertSame ( 3 , $var1 );
$this -> assertSame ( 4 , $var2 );
}
2020-09-26 19:34:39 +02:00
public function testOptionalCallbackDataPassedOnInvocation () : void
2018-06-18 20:00:01 +02:00
{
2016-06-03 17:01:21 +02:00
$callbackData = new \StdClass ;
2020-09-26 19:34:39 +02:00
$this -> start ( function ( Driver $loop ) use ( $callbackData ) : void {
$loop -> defer ( function ( $watcherId , $callbackData ) : void {
2016-06-03 17:01:21 +02:00
$callbackData -> defer = true ;
}, $callbackData );
2020-09-26 19:34:39 +02:00
$loop -> delay ( $msDelay = 1 , function ( $watcherId , $callbackData ) : void {
2016-06-03 17:01:21 +02:00
$callbackData -> delay = true ;
}, $callbackData );
2020-09-26 19:34:39 +02:00
$loop -> repeat ( $msDelay = 1 , function ( $watcherId , $callbackData ) use ( $loop ) : void {
2016-06-03 17:01:21 +02:00
$callbackData -> repeat = true ;
$loop -> cancel ( $watcherId );
}, $callbackData );
2020-09-26 19:34:39 +02:00
$loop -> onWritable ( STDERR , function ( $watcherId , $stream , $callbackData ) use ( $loop ) : void {
2016-06-03 17:01:21 +02:00
$callbackData -> onWritable = true ;
$loop -> cancel ( $watcherId );
}, $callbackData );
});
$this -> assertTrue ( $callbackData -> defer );
$this -> assertTrue ( $callbackData -> delay );
$this -> assertTrue ( $callbackData -> repeat );
$this -> assertTrue ( $callbackData -> onWritable );
}
2016-06-07 01:53:28 +02:00
2020-09-26 19:34:39 +02:00
public function testLoopStopPreventsTimerExecution () : void
2018-06-18 20:00:01 +02:00
{
2017-11-29 13:36:50 +01:00
$t = \microtime ( 1 );
2020-10-03 05:26:10 +02:00
$this -> start ( function ( Driver $loop ) : void {
2020-09-26 19:34:39 +02:00
$loop -> defer ( function () use ( $loop ) : void {
$loop -> delay ( $msDelay = 1000 , function () : void {
$this -> fail ( " Timer was executed despite stopped loop " );
});
2016-12-23 01:43:09 +01:00
});
2020-10-03 05:26:10 +02:00
$loop -> defer ([ $loop , " stop " ]);
2016-12-23 01:43:09 +01:00
});
2018-11-12 21:04:12 +01:00
$this -> assertGreaterThan ( \microtime ( 1 ), $t + 0.1 );
2016-12-23 01:43:09 +01:00
}
2020-09-26 19:34:39 +02:00
public function testDeferEnabledInNextTick () : void
2018-06-18 20:00:01 +02:00
{
2017-03-10 21:31:57 +01:00
$tick = function () {
2020-10-03 05:26:10 +02:00
$this -> loop -> defer ([ $this -> loop , " stop " ]);
$this -> loop -> run ();
2017-01-06 17:21:37 +01:00
};
$invoked = 0 ;
2020-09-26 19:34:39 +02:00
$watcher = $this -> loop -> onWritable ( STDOUT , function () use ( & $invoked ) : void {
2017-01-06 17:21:37 +01:00
$invoked ++ ;
});
$tick ();
$tick ();
$tick ();
2017-01-06 17:51:50 +01:00
$this -> loop -> disable ( $watcher );
$this -> loop -> enable ( $watcher );
2017-01-06 17:21:37 +01:00
$tick (); // disable + immediate enable after a tick should have no effect either
2017-04-24 15:39:08 +02:00
$this -> assertSame ( 4 , $invoked );
2017-01-06 17:21:37 +01:00
}
2016-08-14 21:14:43 +02:00
// getState and setState are final, but test it here again to be sure
2020-09-26 19:34:39 +02:00
public function testRegistry () : void
2018-06-18 20:00:01 +02:00
{
2016-08-14 21:14:43 +02:00
$this -> assertNull ( $this -> loop -> getState ( " foo " ));
$this -> loop -> setState ( " foo " , NAN );
2017-04-24 15:39:08 +02:00
$this -> assertNan ( $this -> loop -> getState ( " foo " ));
2016-08-14 21:14:43 +02:00
$this -> loop -> setState ( " foo " , " 1 " );
$this -> assertNull ( $this -> loop -> getState ( " bar " ));
$this -> loop -> setState ( " baz " , - INF );
2016-06-07 01:53:28 +02:00
// running must not affect state
2020-10-03 05:26:10 +02:00
$this -> loop -> defer ([ $this -> loop , " stop " ]);
$this -> loop -> run ();
2016-08-14 21:14:43 +02:00
$this -> assertSame ( - INF , $this -> loop -> getState ( " baz " ));
$this -> assertSame ( " 1 " , $this -> loop -> getState ( " foo " ));
2016-06-07 01:53:28 +02:00
}
/** @dataProvider provideRegistryValues */
2020-09-26 19:34:39 +02:00
public function testRegistryValues ( $val ) : void
2018-06-18 20:00:01 +02:00
{
2016-08-14 21:14:43 +02:00
$this -> loop -> setState ( " foo " , $val );
$this -> assertSame ( $val , $this -> loop -> getState ( " foo " ));
2016-06-07 01:53:28 +02:00
}
2016-05-24 10:37:25 +02:00
2020-09-26 19:34:39 +02:00
public function provideRegistryValues () : array
2018-06-18 20:00:01 +02:00
{
2016-06-07 01:53:28 +02:00
return [
[ " string " ],
[ 0 ],
[ PHP_INT_MIN ],
[ - 1.0 ],
[ true ],
[ false ],
[[]],
[ null ],
[ new \StdClass ],
];
2016-05-24 10:37:25 +02:00
}
2017-03-12 21:02:26 +01:00
2020-09-26 19:34:39 +02:00
public function testRethrowsFromCallbacks () : void
2018-06-18 20:00:01 +02:00
{
2017-03-15 07:32:43 +01:00
foreach ([ " onReadable " , " onWritable " , " defer " , " delay " , " repeat " , " onSignal " ] as $watcher ) {
2020-10-03 15:38:31 +02:00
if ( $watcher === " onSignal " ) {
$this -> checkForSignalCapability ();
}
2017-03-15 00:34:37 +01:00
2020-10-03 15:38:31 +02:00
try {
$args = [];
switch ( $watcher ) {
case " onSignal " :
$args [] = SIGUSR1 ;
break ;
case " onWritable " :
$args [] = STDOUT ;
break ;
case " onReadable " :
$ends = \stream_socket_pair (
\stripos ( PHP_OS , " win " ) === 0 ? STREAM_PF_INET : STREAM_PF_UNIX ,
STREAM_SOCK_STREAM ,
STREAM_IPPROTO_IP
);
\fwrite ( $ends [ 0 ], " trigger readability watcher " );
$args [] = $ends [ 1 ];
break ;
case " delay " :
case " repeat " :
$args [] = 5 ;
break ;
}
2017-03-15 00:34:37 +01:00
2020-10-03 15:38:31 +02:00
$args [] = function ( $watcherId ) {
$this -> loop -> cancel ( $watcherId );
throw new \Exception ( " rethrow test " );
};
2017-03-15 00:34:37 +01:00
2020-10-03 15:38:31 +02:00
\call_user_func_array ([ $this -> loop , $watcher ], $args );
2017-03-15 00:34:37 +01:00
2020-10-03 15:38:31 +02:00
if ( $watcher == " onSignal " ) {
$this -> loop -> delay ( 100 , function () {
\posix_kill ( \getmypid (), \SIGUSR1 );
});
}
2017-03-15 00:34:37 +01:00
2020-10-03 15:38:31 +02:00
$this -> loop -> run ();
2017-03-15 00:34:37 +01:00
2020-10-03 15:38:31 +02:00
$this -> fail ( " Didn't throw expected exception. " );
} catch ( \Exception $e ) {
$this -> assertSame ( " rethrow test " , $e -> getMessage ());
2017-03-15 00:34:37 +01:00
}
}
2017-03-12 21:02:26 +01:00
}
2017-04-19 18:16:37 +02:00
2020-09-26 19:34:39 +02:00
public function testMultipleWatchersOnSameDescriptor () : void
2018-06-18 20:00:01 +02:00
{
2020-07-14 21:45:35 +02:00
$sockets = \stream_socket_pair (
\stripos ( PHP_OS , " win " ) === 0 ? STREAM_PF_INET : STREAM_PF_UNIX ,
STREAM_SOCK_STREAM ,
STREAM_IPPROTO_IP
);
2017-04-21 17:02:10 +02:00
\fwrite ( $sockets [ 1 ], " testing " );
$invoked = 0 ;
2020-09-26 19:34:39 +02:00
$watcher1 = $this -> loop -> onReadable ( $sockets [ 0 ], function ( $watcher ) use ( & $invoked ) : void {
2017-04-21 17:02:10 +02:00
$invoked += 1 ;
$this -> loop -> disable ( $watcher );
});
2020-09-26 19:34:39 +02:00
$watcher2 = $this -> loop -> onReadable ( $sockets [ 0 ], function ( $watcher ) use ( & $invoked ) : void {
2017-04-21 17:02:10 +02:00
$invoked += 10 ;
$this -> loop -> disable ( $watcher );
});
2020-09-26 19:34:39 +02:00
$watcher3 = $this -> loop -> onWritable ( $sockets [ 0 ], function ( $watcher ) use ( & $invoked ) : void {
2017-04-21 17:02:10 +02:00
$invoked += 100 ;
$this -> loop -> disable ( $watcher );
});
2020-09-26 19:34:39 +02:00
$watcher4 = $this -> loop -> onWritable ( $sockets [ 0 ], function ( $watcher ) use ( & $invoked ) : void {
2017-04-21 17:02:10 +02:00
$invoked += 1000 ;
$this -> loop -> disable ( $watcher );
2017-04-21 19:18:40 +02:00
});
2020-09-26 19:34:39 +02:00
$this -> loop -> defer ( function () use ( $watcher1 , $watcher3 ) : void {
$this -> loop -> delay ( 200 , function () use ( $watcher1 , $watcher3 ) : void {
2017-05-02 21:51:52 +02:00
$this -> loop -> enable ( $watcher1 );
$this -> loop -> enable ( $watcher3 );
});
2017-04-21 17:02:10 +02:00
});
2020-10-03 05:26:10 +02:00
$this -> loop -> run ();
2017-04-21 17:02:10 +02:00
$this -> assertSame ( 1212 , $invoked );
2017-04-21 19:18:40 +02:00
$this -> loop -> enable ( $watcher1 );
$this -> loop -> enable ( $watcher3 );
$this -> loop -> delay ( 100 , function () use ( $watcher2 , $watcher4 ) {
$this -> loop -> enable ( $watcher2 );
$this -> loop -> enable ( $watcher4 );
});
2017-04-21 17:02:10 +02:00
2020-10-03 05:26:10 +02:00
$this -> loop -> run ();
2017-04-21 17:02:10 +02:00
$this -> assertSame ( 2323 , $invoked );
}
2020-09-26 19:34:39 +02:00
public function testTimerIntervalCountedWhenNotRunning () : void
2018-06-18 20:00:01 +02:00
{
2020-09-26 19:34:39 +02:00
$this -> loop -> delay ( 1000 , function () use ( & $start ) : void {
2017-04-20 16:59:46 +02:00
$this -> assertLessThan ( 0.5 , \microtime ( true ) - $start );
2017-04-19 18:16:37 +02:00
});
2020-07-14 21:45:35 +02:00
\usleep ( 600000 ); // 600ms instead of 500ms to allow for variations in timing.
$start = \microtime ( true );
2020-10-03 05:26:10 +02:00
$this -> loop -> run ();
2017-04-19 18:16:37 +02:00
}
2017-05-22 19:54:04 +02:00
2020-09-26 19:34:39 +02:00
public function testShortTimerDoesNotBlockOtherTimers () : void
2018-06-18 20:00:01 +02:00
{
2020-09-26 19:34:39 +02:00
$this -> loop -> repeat ( 0 , function () : void {
2017-05-22 19:54:04 +02:00
static $i = 0 ;
if ( ++ $i === 5 ) {
$this -> fail ( " Loop continues with repeat watcher " );
}
\usleep ( 2000 );
});
2020-10-03 05:26:10 +02:00
$this -> loop -> delay ( 2 , function () : void {
2017-05-22 19:54:04 +02:00
$this -> assertTrue ( true );
2020-10-03 05:26:10 +02:00
$this -> loop -> stop ();
2017-05-22 19:54:04 +02:00
});
2020-10-03 05:26:10 +02:00
$this -> loop -> run ();
2017-05-22 19:54:04 +02:00
}
2017-05-23 19:46:23 +02:00
2020-09-26 19:34:39 +02:00
public function testTwoShortRepeatTimersWorkAsExpected () : void
2018-06-18 20:00:01 +02:00
{
2020-10-03 05:26:10 +02:00
$this -> loop -> repeat ( 0 , function () use ( & $j ) : void {
2017-05-23 19:46:23 +02:00
static $i = 0 ;
if ( ++ $i === 5 ) {
2020-10-03 05:26:10 +02:00
$this -> loop -> stop ();
2017-05-23 19:46:23 +02:00
}
$j = $i ;
});
2020-10-03 05:26:10 +02:00
$this -> loop -> repeat ( 0 , function () use ( & $k ) : void {
2017-05-23 19:46:23 +02:00
static $i = 0 ;
if ( ++ $i === 5 ) {
2020-10-03 05:26:10 +02:00
$this -> loop -> stop ();
2017-05-23 19:46:23 +02:00
}
$k = $i ;
});
2020-10-03 05:26:10 +02:00
$this -> loop -> run ();
2017-05-23 19:46:23 +02:00
$this -> assertLessThan ( 2 , \abs ( $j - $k ));
$this -> assertNotSame ( 0 , $j );
}
2017-09-17 12:18:04 +02:00
2020-09-26 19:34:39 +02:00
public function testNow () : void
2018-01-06 03:32:57 +01:00
{
$now = $this -> loop -> now ();
2020-09-26 19:34:39 +02:00
$this -> loop -> delay ( 100 , function () use ( $now ) : void {
2018-01-06 03:32:57 +01:00
$now += 100 ;
$new = $this -> loop -> now ();
// Allow a few milliseconds of inaccuracy.
2018-12-11 11:31:37 +01:00
$this -> assertGreaterThanOrEqual ( $now - 1 , $new );
$this -> assertLessThanOrEqual ( $now + 10 , $new );
2018-01-06 03:32:57 +01:00
});
2020-10-03 05:26:10 +02:00
$this -> loop -> run ();
2018-01-06 03:32:57 +01:00
}
2016-05-24 10:37:25 +02:00
}