diff options
author | marvin-borner@live.com | 2018-04-10 21:50:16 +0200 |
---|---|---|
committer | marvin-borner@live.com | 2018-04-10 21:54:48 +0200 |
commit | fc9401f04a3aca5abb22f87ebc210de8afe11d32 (patch) | |
tree | b0b310f3581764ec3955f4e496a05137a32951c3 /assets/php/vendor/react/event-loop/tests | |
parent | 286d643180672f20526f3dc3bd19d7b751e2fa97 (diff) |
Initial Commit
Diffstat (limited to 'assets/php/vendor/react/event-loop/tests')
17 files changed, 1313 insertions, 0 deletions
diff --git a/assets/php/vendor/react/event-loop/tests/AbstractLoopTest.php b/assets/php/vendor/react/event-loop/tests/AbstractLoopTest.php new file mode 100644 index 0000000..dbfc91e --- /dev/null +++ b/assets/php/vendor/react/event-loop/tests/AbstractLoopTest.php @@ -0,0 +1,621 @@ +<?php + +namespace React\Tests\EventLoop; + +abstract class AbstractLoopTest extends TestCase +{ + /** + * @var \React\EventLoop\LoopInterface + */ + protected $loop; + + private $tickTimeout; + + const PHP_DEFAULT_CHUNK_SIZE = 8192; + + public function setUp() + { + // It's a timeout, don't set it too low. Travis and other CI systems are slow. + $this->tickTimeout = 0.02; + $this->loop = $this->createLoop(); + } + + abstract public function createLoop(); + + public function createSocketPair() + { + $domain = (DIRECTORY_SEPARATOR === '\\') ? STREAM_PF_INET : STREAM_PF_UNIX; + $sockets = stream_socket_pair($domain, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP); + + foreach ($sockets as $socket) { + if (function_exists('stream_set_read_buffer')) { + stream_set_read_buffer($socket, 0); + } + } + + return $sockets; + } + + public function testAddReadStream() + { + list ($input, $output) = $this->createSocketPair(); + + $this->loop->addReadStream($input, $this->expectCallableExactly(2)); + + fwrite($output, "foo\n"); + $this->tickLoop($this->loop); + + fwrite($output, "bar\n"); + $this->tickLoop($this->loop); + } + + public function testAddReadStreamIgnoresSecondCallable() + { + list ($input, $output) = $this->createSocketPair(); + + $this->loop->addReadStream($input, $this->expectCallableExactly(2)); + $this->loop->addReadStream($input, $this->expectCallableNever()); + + fwrite($output, "foo\n"); + $this->tickLoop($this->loop); + + fwrite($output, "bar\n"); + $this->tickLoop($this->loop); + } + + public function testAddReadStreamReceivesDataFromStreamReference() + { + $this->received = ''; + $this->subAddReadStreamReceivesDataFromStreamReference(); + $this->assertEquals('', $this->received); + + $this->assertRunFasterThan($this->tickTimeout * 2); + $this->assertEquals('[hello]X', $this->received); + } + + /** + * Helper for above test. This happens in another helper method to verify + * the loop keeps track of assigned stream resources (refcount). + */ + private function subAddReadStreamReceivesDataFromStreamReference() + { + list ($input, $output) = $this->createSocketPair(); + + fwrite($input, 'hello'); + fclose($input); + + $loop = $this->loop; + $received =& $this->received; + $loop->addReadStream($output, function ($output) use ($loop, &$received) { + $chunk = fread($output, 1024); + if ($chunk === '') { + $received .= 'X'; + $loop->removeReadStream($output); + fclose($output); + } else { + $received .= '[' . $chunk . ']'; + } + }); + } + + public function testAddWriteStream() + { + list ($input) = $this->createSocketPair(); + + $this->loop->addWriteStream($input, $this->expectCallableExactly(2)); + $this->tickLoop($this->loop); + $this->tickLoop($this->loop); + } + + public function testAddWriteStreamIgnoresSecondCallable() + { + list ($input) = $this->createSocketPair(); + + $this->loop->addWriteStream($input, $this->expectCallableExactly(2)); + $this->loop->addWriteStream($input, $this->expectCallableNever()); + $this->tickLoop($this->loop); + $this->tickLoop($this->loop); + } + + public function testRemoveReadStreamInstantly() + { + list ($input, $output) = $this->createSocketPair(); + + $this->loop->addReadStream($input, $this->expectCallableNever()); + $this->loop->removeReadStream($input); + + fwrite($output, "bar\n"); + $this->tickLoop($this->loop); + } + + public function testRemoveReadStreamAfterReading() + { + list ($input, $output) = $this->createSocketPair(); + + $this->loop->addReadStream($input, $this->expectCallableOnce()); + + fwrite($output, "foo\n"); + $this->tickLoop($this->loop); + + $this->loop->removeReadStream($input); + + fwrite($output, "bar\n"); + $this->tickLoop($this->loop); + } + + public function testRemoveWriteStreamInstantly() + { + list ($input) = $this->createSocketPair(); + + $this->loop->addWriteStream($input, $this->expectCallableNever()); + $this->loop->removeWriteStream($input); + $this->tickLoop($this->loop); + } + + public function testRemoveWriteStreamAfterWriting() + { + list ($input) = $this->createSocketPair(); + + $this->loop->addWriteStream($input, $this->expectCallableOnce()); + $this->tickLoop($this->loop); + + $this->loop->removeWriteStream($input); + $this->tickLoop($this->loop); + } + + public function testRemoveStreamForReadOnly() + { + list ($input, $output) = $this->createSocketPair(); + + $this->loop->addReadStream($input, $this->expectCallableNever()); + $this->loop->addWriteStream($output, $this->expectCallableOnce()); + $this->loop->removeReadStream($input); + + fwrite($output, "foo\n"); + $this->tickLoop($this->loop); + } + + public function testRemoveStreamForWriteOnly() + { + list ($input, $output) = $this->createSocketPair(); + + fwrite($output, "foo\n"); + + $this->loop->addReadStream($input, $this->expectCallableOnce()); + $this->loop->addWriteStream($output, $this->expectCallableNever()); + $this->loop->removeWriteStream($output); + + $this->tickLoop($this->loop); + } + + public function testRemoveReadAndWriteStreamFromLoopOnceResourceClosesEndsLoop() + { + list($stream, $other) = $this->createSocketPair(); + stream_set_blocking($stream, false); + stream_set_blocking($other, false); + + // dummy writable handler + $this->loop->addWriteStream($stream, function () { }); + + // remove stream when the stream is readable (closes) + $loop = $this->loop; + $loop->addReadStream($stream, function ($stream) use ($loop) { + $loop->removeReadStream($stream); + $loop->removeWriteStream($stream); + fclose($stream); + }); + + // close other side + fclose($other); + + $this->assertRunFasterThan($this->tickTimeout); + } + + public function testRemoveReadAndWriteStreamFromLoopOnceResourceClosesOnEndOfFileEndsLoop() + { + list($stream, $other) = $this->createSocketPair(); + stream_set_blocking($stream, false); + stream_set_blocking($other, false); + + // dummy writable handler + $this->loop->addWriteStream($stream, function () { }); + + // remove stream when the stream is readable (closes) + $loop = $this->loop; + $loop->addReadStream($stream, function ($stream) use ($loop) { + $data = fread($stream, 1024); + if ($data !== '') { + return; + } + + $loop->removeReadStream($stream); + $loop->removeWriteStream($stream); + fclose($stream); + }); + + // send data and close stream + fwrite($other, str_repeat('.', static::PHP_DEFAULT_CHUNK_SIZE)); + $this->loop->addTimer(0.01, function () use ($other) { + fclose($other); + }); + + $this->assertRunFasterThan(0.1); + } + + public function testRemoveReadAndWriteStreamFromLoopWithClosingResourceEndsLoop() + { + // get only one part of the pair to ensure the other side will close immediately + list($stream) = $this->createSocketPair(); + stream_set_blocking($stream, false); + + // dummy writable handler + $this->loop->addWriteStream($stream, function () { }); + + // remove stream when the stream is readable (closes) + $loop = $this->loop; + $loop->addReadStream($stream, function ($stream) use ($loop) { + $loop->removeReadStream($stream); + $loop->removeWriteStream($stream); + fclose($stream); + }); + + $this->assertRunFasterThan($this->tickTimeout); + } + + public function testRemoveInvalid() + { + list ($stream) = $this->createSocketPair(); + + // remove a valid stream from the event loop that was never added in the first place + $this->loop->removeReadStream($stream); + $this->loop->removeWriteStream($stream); + + $this->assertTrue(true); + } + + /** @test */ + public function emptyRunShouldSimplyReturn() + { + $this->assertRunFasterThan($this->tickTimeout); + } + + /** @test */ + public function runShouldReturnWhenNoMoreFds() + { + list ($input, $output) = $this->createSocketPair(); + + $loop = $this->loop; + $this->loop->addReadStream($input, function ($stream) use ($loop) { + $loop->removeReadStream($stream); + }); + + fwrite($output, "foo\n"); + + $this->assertRunFasterThan($this->tickTimeout * 2); + } + + /** @test */ + public function stopShouldStopRunningLoop() + { + list ($input, $output) = $this->createSocketPair(); + + $loop = $this->loop; + $this->loop->addReadStream($input, function ($stream) use ($loop) { + $loop->stop(); + }); + + fwrite($output, "foo\n"); + + $this->assertRunFasterThan($this->tickTimeout * 2); + } + + public function testStopShouldPreventRunFromBlocking() + { + $that = $this; + $this->loop->addTimer( + 1, + function () use ($that) { + $that->fail('Timer was executed.'); + } + ); + + $loop = $this->loop; + $this->loop->futureTick( + function () use ($loop) { + $loop->stop(); + } + ); + + $this->assertRunFasterThan($this->tickTimeout * 2); + } + + public function testIgnoreRemovedCallback() + { + // two independent streams, both should be readable right away + list ($input1, $output1) = $this->createSocketPair(); + list ($input2, $output2) = $this->createSocketPair(); + + $called = false; + + $loop = $this->loop; + $loop->addReadStream($input1, function ($stream) use (& $called, $loop, $input2) { + // stream1 is readable, remove stream2 as well => this will invalidate its callback + $loop->removeReadStream($stream); + $loop->removeReadStream($input2); + + $called = true; + }); + + // this callback would have to be called as well, but the first stream already removed us + $that = $this; + $loop->addReadStream($input2, function () use (& $called, $that) { + if ($called) { + $that->fail('Callback 2 must not be called after callback 1 was called'); + } + }); + + fwrite($output1, "foo\n"); + fwrite($output2, "foo\n"); + + $loop->run(); + + $this->assertTrue($called); + } + + public function testFutureTickEventGeneratedByFutureTick() + { + $loop = $this->loop; + $this->loop->futureTick( + function () use ($loop) { + $loop->futureTick( + function () { + echo 'future-tick' . PHP_EOL; + } + ); + } + ); + + $this->expectOutputString('future-tick' . PHP_EOL); + + $this->loop->run(); + } + + public function testFutureTick() + { + $called = false; + + $callback = function () use (&$called) { + $called = true; + }; + + $this->loop->futureTick($callback); + + $this->assertFalse($called); + + $this->tickLoop($this->loop); + + $this->assertTrue($called); + } + + public function testFutureTickFiresBeforeIO() + { + list ($stream) = $this->createSocketPair(); + + $this->loop->addWriteStream( + $stream, + function () { + echo 'stream' . PHP_EOL; + } + ); + + $this->loop->futureTick( + function () { + echo 'future-tick' . PHP_EOL; + } + ); + + $this->expectOutputString('future-tick' . PHP_EOL . 'stream' . PHP_EOL); + + $this->tickLoop($this->loop); + } + + public function testRecursiveFutureTick() + { + list ($stream) = $this->createSocketPair(); + + $loop = $this->loop; + $this->loop->addWriteStream( + $stream, + function () use ($stream, $loop) { + echo 'stream' . PHP_EOL; + $loop->removeWriteStream($stream); + } + ); + + $this->loop->futureTick( + function () use ($loop) { + echo 'future-tick-1' . PHP_EOL; + $loop->futureTick( + function () { + echo 'future-tick-2' . PHP_EOL; + } + ); + } + ); + + $this->expectOutputString('future-tick-1' . PHP_EOL . 'stream' . PHP_EOL . 'future-tick-2' . PHP_EOL); + + $this->loop->run(); + } + + public function testRunWaitsForFutureTickEvents() + { + list ($stream) = $this->createSocketPair(); + + $loop = $this->loop; + $this->loop->addWriteStream( + $stream, + function () use ($stream, $loop) { + $loop->removeWriteStream($stream); + $loop->futureTick( + function () { + echo 'future-tick' . PHP_EOL; + } + ); + } + ); + + $this->expectOutputString('future-tick' . PHP_EOL); + + $this->loop->run(); + } + + public function testFutureTickEventGeneratedByTimer() + { + $loop = $this->loop; + $this->loop->addTimer( + 0.001, + function () use ($loop) { + $loop->futureTick( + function () { + echo 'future-tick' . PHP_EOL; + } + ); + } + ); + + $this->expectOutputString('future-tick' . PHP_EOL); + + $this->loop->run(); + } + + public function testRemoveSignalNotRegisteredIsNoOp() + { + $this->loop->removeSignal(SIGINT, function () { }); + $this->assertTrue(true); + } + + public function testSignal() + { + if (!function_exists('posix_kill') || !function_exists('posix_getpid')) { + $this->markTestSkipped('Signal test skipped because functions "posix_kill" and "posix_getpid" are missing.'); + } + + $called = false; + $calledShouldNot = true; + + $timer = $this->loop->addPeriodicTimer(1, function () {}); + + $this->loop->addSignal(SIGUSR2, $func2 = function () use (&$calledShouldNot) { + $calledShouldNot = false; + }); + + $loop = $this->loop; + $this->loop->addSignal(SIGUSR1, $func1 = function () use (&$func1, &$func2, &$called, $timer, $loop) { + $called = true; + $loop->removeSignal(SIGUSR1, $func1); + $loop->removeSignal(SIGUSR2, $func2); + $loop->cancelTimer($timer); + }); + + $this->loop->futureTick(function () { + posix_kill(posix_getpid(), SIGUSR1); + }); + + $this->loop->run(); + + $this->assertTrue($called); + $this->assertTrue($calledShouldNot); + } + + public function testSignalMultipleUsagesForTheSameListener() + { + $funcCallCount = 0; + $func = function () use (&$funcCallCount) { + $funcCallCount++; + }; + $this->loop->addTimer(1, function () {}); + + $this->loop->addSignal(SIGUSR1, $func); + $this->loop->addSignal(SIGUSR1, $func); + + $this->loop->addTimer(0.4, function () { + posix_kill(posix_getpid(), SIGUSR1); + }); + $loop = $this->loop; + $this->loop->addTimer(0.9, function () use (&$func, $loop) { + $loop->removeSignal(SIGUSR1, $func); + }); + + $this->loop->run(); + + $this->assertSame(1, $funcCallCount); + } + + public function testSignalsKeepTheLoopRunning() + { + $loop = $this->loop; + $function = function () {}; + $this->loop->addSignal(SIGUSR1, $function); + $this->loop->addTimer(1.5, function () use ($function, $loop) { + $loop->removeSignal(SIGUSR1, $function); + $loop->stop(); + }); + + $this->assertRunSlowerThan(1.5); + } + + public function testSignalsKeepTheLoopRunningAndRemovingItStopsTheLoop() + { + $loop = $this->loop; + $function = function () {}; + $this->loop->addSignal(SIGUSR1, $function); + $this->loop->addTimer(1.5, function () use ($function, $loop) { + $loop->removeSignal(SIGUSR1, $function); + }); + + $this->assertRunFasterThan(1.6); + } + + public function testTimerIntervalCanBeFarInFuture() + { + // get only one part of the pair to ensure the other side will close immediately + list($stream) = $this->createSocketPair(); + + // start a timer very far in the future + $timer = $this->loop->addTimer(PHP_INT_MAX, function () { }); + + // remove stream and timer when the stream is readable (closes) + $loop = $this->loop; + $this->loop->addReadStream($stream, function ($stream) use ($timer, $loop) { + $loop->removeReadStream($stream); + $loop->cancelTimer($timer); + }); + + $this->assertRunFasterThan($this->tickTimeout); + } + + private function assertRunSlowerThan($minInterval) + { + $start = microtime(true); + + $this->loop->run(); + + $end = microtime(true); + $interval = $end - $start; + + $this->assertLessThan($interval, $minInterval); + } + + private function assertRunFasterThan($maxInterval) + { + $start = microtime(true); + + $this->loop->run(); + + $end = microtime(true); + $interval = $end - $start; + + $this->assertLessThan($maxInterval, $interval); + } +} diff --git a/assets/php/vendor/react/event-loop/tests/CallableStub.php b/assets/php/vendor/react/event-loop/tests/CallableStub.php new file mode 100644 index 0000000..913d403 --- /dev/null +++ b/assets/php/vendor/react/event-loop/tests/CallableStub.php @@ -0,0 +1,10 @@ +<?php + +namespace React\Tests\EventLoop; + +class CallableStub +{ + public function __invoke() + { + } +} diff --git a/assets/php/vendor/react/event-loop/tests/ExtEvLoopTest.php b/assets/php/vendor/react/event-loop/tests/ExtEvLoopTest.php new file mode 100644 index 0000000..ab41c9f --- /dev/null +++ b/assets/php/vendor/react/event-loop/tests/ExtEvLoopTest.php @@ -0,0 +1,17 @@ +<?php + +namespace React\Tests\EventLoop; + +use React\EventLoop\ExtEvLoop; + +class ExtEvLoopTest extends AbstractLoopTest +{ + public function createLoop() + { + if (!class_exists('EvLoop')) { + $this->markTestSkipped('ExtEvLoop tests skipped because ext-ev extension is not installed.'); + } + + return new ExtEvLoop(); + } +} diff --git a/assets/php/vendor/react/event-loop/tests/ExtEventLoopTest.php b/assets/php/vendor/react/event-loop/tests/ExtEventLoopTest.php new file mode 100644 index 0000000..2f88d18 --- /dev/null +++ b/assets/php/vendor/react/event-loop/tests/ExtEventLoopTest.php @@ -0,0 +1,84 @@ +<?php + +namespace React\Tests\EventLoop; + +use React\EventLoop\ExtEventLoop; + +class ExtEventLoopTest extends AbstractLoopTest +{ + public function createLoop($readStreamCompatible = false) + { + if ('Linux' === PHP_OS && !extension_loaded('posix')) { + $this->markTestSkipped('libevent tests skipped on linux due to linux epoll issues.'); + } + + if (!extension_loaded('event')) { + $this->markTestSkipped('ext-event tests skipped because ext-event is not installed.'); + } + + return new ExtEventLoop(); + } + + public function createStream() + { + // Use a FIFO on linux to get around lack of support for disk-based file + // descriptors when using the EPOLL back-end. + if ('Linux' === PHP_OS) { + $this->fifoPath = tempnam(sys_get_temp_dir(), 'react-'); + + unlink($this->fifoPath); + + posix_mkfifo($this->fifoPath, 0600); + + $stream = fopen($this->fifoPath, 'r+'); + + // ext-event (as of 1.8.1) does not yet support in-memory temporary + // streams. Setting maxmemory:0 and performing a write forces PHP to + // back this temporary stream with a real file. + // + // This problem is mentioned at https://bugs.php.net/bug.php?id=64652&edit=3 + // but remains unresolved (despite that issue being closed). + } else { + $stream = fopen('php://temp/maxmemory:0', 'r+'); + + fwrite($stream, 'x'); + ftruncate($stream, 0); + } + + return $stream; + } + + public function writeToStream($stream, $content) + { + if ('Linux' !== PHP_OS) { + return parent::writeToStream($stream, $content); + } + + fwrite($stream, $content); + } + + /** + * @group epoll-readable-error + */ + public function testCanUseReadableStreamWithFeatureFds() + { + if (PHP_VERSION_ID > 70000) { + $this->markTestSkipped('Memory stream not supported'); + } + + $this->loop = $this->createLoop(true); + + $input = fopen('php://temp/maxmemory:0', 'r+'); + + fwrite($input, 'x'); + ftruncate($input, 0); + + $this->loop->addReadStream($input, $this->expectCallableExactly(2)); + + fwrite($input, "foo\n"); + $this->tickLoop($this->loop); + + fwrite($input, "bar\n"); + $this->tickLoop($this->loop); + } +} diff --git a/assets/php/vendor/react/event-loop/tests/ExtLibevLoopTest.php b/assets/php/vendor/react/event-loop/tests/ExtLibevLoopTest.php new file mode 100644 index 0000000..19a5e87 --- /dev/null +++ b/assets/php/vendor/react/event-loop/tests/ExtLibevLoopTest.php @@ -0,0 +1,22 @@ +<?php + +namespace React\Tests\EventLoop; + +use React\EventLoop\ExtLibevLoop; + +class ExtLibevLoopTest extends AbstractLoopTest +{ + public function createLoop() + { + if (!class_exists('libev\EventLoop')) { + $this->markTestSkipped('libev tests skipped because ext-libev is not installed.'); + } + + return new ExtLibevLoop(); + } + + public function testLibEvConstructor() + { + $loop = new ExtLibevLoop(); + } +} diff --git a/assets/php/vendor/react/event-loop/tests/ExtLibeventLoopTest.php b/assets/php/vendor/react/event-loop/tests/ExtLibeventLoopTest.php new file mode 100644 index 0000000..8497065 --- /dev/null +++ b/assets/php/vendor/react/event-loop/tests/ExtLibeventLoopTest.php @@ -0,0 +1,58 @@ +<?php + +namespace React\Tests\EventLoop; + +use React\EventLoop\ExtLibeventLoop; + +class ExtLibeventLoopTest extends AbstractLoopTest +{ + private $fifoPath; + + public function createLoop() + { + if ('Linux' === PHP_OS && !extension_loaded('posix')) { + $this->markTestSkipped('libevent tests skipped on linux due to linux epoll issues.'); + } + + if (!function_exists('event_base_new')) { + $this->markTestSkipped('libevent tests skipped because ext-libevent is not installed.'); + } + + return new ExtLibeventLoop(); + } + + public function tearDown() + { + if (file_exists($this->fifoPath)) { + unlink($this->fifoPath); + } + } + + public function createStream() + { + if ('Linux' !== PHP_OS) { + return parent::createStream(); + } + + $this->fifoPath = tempnam(sys_get_temp_dir(), 'react-'); + + unlink($this->fifoPath); + + // Use a FIFO on linux to get around lack of support for disk-based file + // descriptors when using the EPOLL back-end. + posix_mkfifo($this->fifoPath, 0600); + + $stream = fopen($this->fifoPath, 'r+'); + + return $stream; + } + + public function writeToStream($stream, $content) + { + if ('Linux' !== PHP_OS) { + return parent::writeToStream($stream, $content); + } + + fwrite($stream, $content); + } +} diff --git a/assets/php/vendor/react/event-loop/tests/SignalsHandlerTest.php b/assets/php/vendor/react/event-loop/tests/SignalsHandlerTest.php new file mode 100644 index 0000000..f8b7df3 --- /dev/null +++ b/assets/php/vendor/react/event-loop/tests/SignalsHandlerTest.php @@ -0,0 +1,55 @@ +<?php + +namespace React\Tests\EventLoop; + +use React\EventLoop\SignalsHandler; + +final class SignalsHandlerTest extends TestCase +{ + public function testEmittedEventsAndCallHandling() + { + $callCount = 0; + $func = function () use (&$callCount) { + $callCount++; + }; + $signals = new SignalsHandler(); + + $this->assertSame(0, $callCount); + + $signals->add(SIGUSR1, $func); + $this->assertSame(0, $callCount); + + $signals->add(SIGUSR1, $func); + $this->assertSame(0, $callCount); + + $signals->add(SIGUSR1, $func); + $this->assertSame(0, $callCount); + + $signals->call(SIGUSR1); + $this->assertSame(1, $callCount); + + $signals->add(SIGUSR2, $func); + $this->assertSame(1, $callCount); + + $signals->add(SIGUSR2, $func); + $this->assertSame(1, $callCount); + + $signals->call(SIGUSR2); + $this->assertSame(2, $callCount); + + $signals->remove(SIGUSR2, $func); + $this->assertSame(2, $callCount); + + $signals->remove(SIGUSR2, $func); + $this->assertSame(2, $callCount); + + $signals->call(SIGUSR2); + $this->assertSame(2, $callCount); + + $signals->remove(SIGUSR1, $func); + $this->assertSame(2, $callCount); + + $signals->call(SIGUSR1); + $this->assertSame(2, $callCount); + } +} diff --git a/assets/php/vendor/react/event-loop/tests/StreamSelectLoopTest.php b/assets/php/vendor/react/event-loop/tests/StreamSelectLoopTest.php new file mode 100644 index 0000000..bd19e1c --- /dev/null +++ b/assets/php/vendor/react/event-loop/tests/StreamSelectLoopTest.php @@ -0,0 +1,148 @@ +<?php + +namespace React\Tests\EventLoop; + +use React\EventLoop\LoopInterface; +use React\EventLoop\StreamSelectLoop; + +class StreamSelectLoopTest extends AbstractLoopTest +{ + protected function tearDown() + { + parent::tearDown(); + if (strncmp($this->getName(false), 'testSignal', 10) === 0 && extension_loaded('pcntl')) { + $this->resetSignalHandlers(); + } + } + + public function createLoop() + { + return new StreamSelectLoop(); + } + + public function testStreamSelectTimeoutEmulation() + { + $this->loop->addTimer( + 0.05, + $this->expectCallableOnce() + ); + + $start = microtime(true); + + $this->loop->run(); + + $end = microtime(true); + $interval = $end - $start; + + $this->assertGreaterThan(0.04, $interval); + } + + public function signalProvider() + { + return array( + array('SIGUSR1'), + array('SIGHUP'), + array('SIGTERM'), + ); + } + + /** + * Test signal interrupt when no stream is attached to the loop + * @dataProvider signalProvider + */ + public function testSignalInterruptNoStream($signal) + { + if (!extension_loaded('pcntl')) { + $this->markTestSkipped('"pcntl" extension is required to run this test.'); + } + + // dispatch signal handler every 10ms for 0.1s + $check = $this->loop->addPeriodicTimer(0.01, function() { + pcntl_signal_dispatch(); + }); + $loop = $this->loop; + $loop->addTimer(0.1, function () use ($check, $loop) { + $loop->cancelTimer($check); + }); + + $handled = false; + $this->assertTrue(pcntl_signal(constant($signal), function () use (&$handled) { + $handled = true; + })); + + // spawn external process to send signal to current process id + $this->forkSendSignal($signal); + + $this->loop->run(); + $this->assertTrue($handled); + } + + /** + * Test signal interrupt when a stream is attached to the loop + * @dataProvider signalProvider + */ + public function testSignalInterruptWithStream($signal) + { + if (!extension_loaded('pcntl')) { + $this->markTestSkipped('"pcntl" extension is required to run this test.'); + } + + // dispatch signal handler every 10ms + $this->loop->addPeriodicTimer(0.01, function() { + pcntl_signal_dispatch(); + }); + + // add stream to the loop + $loop = $this->loop; + list($writeStream, $readStream) = $this->createSocketPair(); + $loop->addReadStream($readStream, function ($stream) use ($loop) { + /** @var $loop LoopInterface */ + $read = fgets($stream); + if ($read === "end loop\n") { + $loop->stop(); + } + }); + $this->loop->addTimer(0.1, function() use ($writeStream) { + fwrite($writeStream, "end loop\n"); + }); + + $handled = false; + $this->assertTrue(pcntl_signal(constant($signal), function () use (&$handled) { + $handled = true; + })); + + // spawn external process to send signal to current process id + $this->forkSendSignal($signal); + + $this->loop->run(); + + $this->assertTrue($handled); + } + + /** + * reset all signal handlers to default + */ + protected function resetSignalHandlers() + { + foreach($this->signalProvider() as $signal) { + pcntl_signal(constant($signal[0]), SIG_DFL); + } + } + + /** + * fork child process to send signal to current process id + */ + protected function forkSendSignal($signal) + { + $currentPid = posix_getpid(); + $childPid = pcntl_fork(); + if ($childPid == -1) { + $this->fail("Failed to fork child process!"); + } else if ($childPid === 0) { + // this is executed in the child process + usleep(20000); + posix_kill($currentPid, constant($signal)); + die(); + } + } +} diff --git a/assets/php/vendor/react/event-loop/tests/TestCase.php b/assets/php/vendor/react/event-loop/tests/TestCase.php new file mode 100644 index 0000000..dbdd54c --- /dev/null +++ b/assets/php/vendor/react/event-loop/tests/TestCase.php @@ -0,0 +1,53 @@ +<?php + +namespace React\Tests\EventLoop; + +use PHPUnit\Framework\TestCase as BaseTestCase; +use React\EventLoop\LoopInterface; + +class TestCase extends BaseTestCase +{ + protected function expectCallableExactly($amount) + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->exactly($amount)) + ->method('__invoke'); + + return $mock; + } + + protected function expectCallableOnce() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke'); + + return $mock; + } + + protected function expectCallableNever() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->never()) + ->method('__invoke'); + + return $mock; + } + + protected function createCallableMock() + { + return $this->getMockBuilder('React\Tests\EventLoop\CallableStub')->getMock(); + } + + protected function tickLoop(LoopInterface $loop) + { + $loop->futureTick(function () use ($loop) { + $loop->stop(); + }); + + $loop->run(); + } +} diff --git a/assets/php/vendor/react/event-loop/tests/Timer/AbstractTimerTest.php b/assets/php/vendor/react/event-loop/tests/Timer/AbstractTimerTest.php new file mode 100644 index 0000000..294e683 --- /dev/null +++ b/assets/php/vendor/react/event-loop/tests/Timer/AbstractTimerTest.php @@ -0,0 +1,122 @@ +<?php + +namespace React\Tests\EventLoop\Timer; + +use React\EventLoop\LoopInterface; +use React\Tests\EventLoop\TestCase; + +abstract class AbstractTimerTest extends TestCase +{ + /** + * @return LoopInterface + */ + abstract public function createLoop(); + + public function testAddTimerReturnsNonPeriodicTimerInstance() + { + $loop = $this->createLoop(); + + $timer = $loop->addTimer(0.001, $this->expectCallableNever()); + + $this->assertInstanceOf('React\EventLoop\TimerInterface', $timer); + $this->assertFalse($timer->isPeriodic()); + } + + public function testAddTimerWillBeInvokedOnceAndBlocksLoopWhenRunning() + { + $loop = $this->createLoop(); + + $loop->addTimer(0.001, $this->expectCallableOnce()); + + $start = microtime(true); + $loop->run(); + $end = microtime(true); + + // make no strict assumptions about actual time interval. + // must be at least 0.001s (1ms) and should not take longer than 0.1s + $this->assertGreaterThanOrEqual(0.001, $end - $start); + $this->assertLessThan(0.1, $end - $start); + } + + public function testAddPeriodicTimerReturnsPeriodicTimerInstance() + { + $loop = $this->createLoop(); + + $periodic = $loop->addPeriodicTimer(0.1, $this->expectCallableNever()); + + $this->assertInstanceOf('React\EventLoop\TimerInterface', $periodic); + $this->assertTrue($periodic->isPeriodic()); + } + + public function testAddPeriodicTimerWillBeInvokedUntilItIsCancelled() + { + $loop = $this->createLoop(); + + $periodic = $loop->addPeriodicTimer(0.1, $this->expectCallableExactly(3)); + + // make no strict assumptions about actual time interval. + // leave some room to ensure this ticks exactly 3 times. + $loop->addTimer(0.399, function () use ($loop, $periodic) { + $loop->cancelTimer($periodic); + }); + + $loop->run(); + } + + public function testAddPeriodicTimerWillBeInvokedWithMaximumAccuracyUntilItIsCancelled() + { + $loop = $this->createLoop(); + + $i = 0; + $periodic = $loop->addPeriodicTimer(0.001, function () use (&$i) { + ++$i; + }); + + $loop->addTimer(0.02, function () use ($loop, $periodic) { + $loop->cancelTimer($periodic); + }); + + $loop->run(); + + // make no strict assumptions about number of invocations. + // we know it must be no more than 20 times and should at least be + // invoked twice for really slow loops + $this->assertLessThanOrEqual(20, $i); + $this->assertGreaterThan(2, $i); + } + + public function testAddPeriodicTimerCancelsItself() + { + $loop = $this->createLoop(); + + $i = 0; + $loop->addPeriodicTimer(0.001, function ($timer) use (&$i, $loop) { + $i++; + + if ($i === 5) { + $loop->cancelTimer($timer); + } + }); + + $start = microtime(true); + $loop->run(); + $end = microtime(true); + + $this->assertEquals(5, $i); + + // make no strict assumptions about time interval. + // 5 invocations must take at least 0.005s (5ms) and should not take + // longer than 0.1s for slower loops. + $this->assertGreaterThanOrEqual(0.005, $end - $start); + $this->assertLessThan(0.1, $end - $start); + } + + public function testMinimumIntervalOneMicrosecond() + { + $loop = $this->createLoop(); + + $timer = $loop->addTimer(0, function () {}); + + $this->assertEquals(0.000001, $timer->getInterval()); + } +} diff --git a/assets/php/vendor/react/event-loop/tests/Timer/ExtEvTimerTest.php b/assets/php/vendor/react/event-loop/tests/Timer/ExtEvTimerTest.php new file mode 100644 index 0000000..bfa9186 --- /dev/null +++ b/assets/php/vendor/react/event-loop/tests/Timer/ExtEvTimerTest.php @@ -0,0 +1,17 @@ +<?php + +namespace React\Tests\EventLoop\Timer; + +use React\EventLoop\ExtEvLoop; + +class ExtEvTimerTest extends AbstractTimerTest +{ + public function createLoop() + { + if (!class_exists('EvLoop')) { + $this->markTestSkipped('ExtEvLoop tests skipped because ext-ev extension is not installed.'); + } + + return new ExtEvLoop(); + } +} diff --git a/assets/php/vendor/react/event-loop/tests/Timer/ExtEventTimerTest.php b/assets/php/vendor/react/event-loop/tests/Timer/ExtEventTimerTest.php new file mode 100644 index 0000000..a7a6d00 --- /dev/null +++ b/assets/php/vendor/react/event-loop/tests/Timer/ExtEventTimerTest.php @@ -0,0 +1,17 @@ +<?php + +namespace React\Tests\EventLoop\Timer; + +use React\EventLoop\ExtEventLoop; + +class ExtEventTimerTest extends AbstractTimerTest +{ + public function createLoop() + { + if (!extension_loaded('event')) { + $this->markTestSkipped('ext-event tests skipped because ext-event is not installed.'); + } + + return new ExtEventLoop(); + } +} diff --git a/assets/php/vendor/react/event-loop/tests/Timer/ExtLibevTimerTest.php b/assets/php/vendor/react/event-loop/tests/Timer/ExtLibevTimerTest.php new file mode 100644 index 0000000..65e82be --- /dev/null +++ b/assets/php/vendor/react/event-loop/tests/Timer/ExtLibevTimerTest.php @@ -0,0 +1,17 @@ +<?php + +namespace React\Tests\EventLoop\Timer; + +use React\EventLoop\ExtLibevLoop; + +class ExtLibevTimerTest extends AbstractTimerTest +{ + public function createLoop() + { + if (!class_exists('libev\EventLoop')) { + $this->markTestSkipped('libev tests skipped because ext-libev is not installed.'); + } + + return new ExtLibevLoop(); + } +} diff --git a/assets/php/vendor/react/event-loop/tests/Timer/ExtLibeventTimerTest.php b/assets/php/vendor/react/event-loop/tests/Timer/ExtLibeventTimerTest.php new file mode 100644 index 0000000..9089b9a --- /dev/null +++ b/assets/php/vendor/react/event-loop/tests/Timer/ExtLibeventTimerTest.php @@ -0,0 +1,17 @@ +<?php + +namespace React\Tests\EventLoop\Timer; + +use React\EventLoop\ExtLibeventLoop; + +class ExtLibeventTimerTest extends AbstractTimerTest +{ + public function createLoop() + { + if (!function_exists('event_base_new')) { + $this->markTestSkipped('libevent tests skipped because ext-libevent is not installed.'); + } + + return new ExtLibeventLoop(); + } +} diff --git a/assets/php/vendor/react/event-loop/tests/Timer/StreamSelectTimerTest.php b/assets/php/vendor/react/event-loop/tests/Timer/StreamSelectTimerTest.php new file mode 100644 index 0000000..cfe1d7d --- /dev/null +++ b/assets/php/vendor/react/event-loop/tests/Timer/StreamSelectTimerTest.php @@ -0,0 +1,13 @@ +<?php + +namespace React\Tests\EventLoop\Timer; + +use React\EventLoop\StreamSelectLoop; + +class StreamSelectTimerTest extends AbstractTimerTest +{ + public function createLoop() + { + return new StreamSelectLoop(); + } +} diff --git a/assets/php/vendor/react/event-loop/tests/Timer/TimersTest.php b/assets/php/vendor/react/event-loop/tests/Timer/TimersTest.php new file mode 100644 index 0000000..b279478 --- /dev/null +++ b/assets/php/vendor/react/event-loop/tests/Timer/TimersTest.php @@ -0,0 +1,27 @@ +<?php + +namespace React\Tests\EventLoop\Timer; + +use React\Tests\EventLoop\TestCase; +use React\EventLoop\Timer\Timer; +use React\EventLoop\Timer\Timers; + +class TimersTest extends TestCase +{ + public function testBlockedTimer() + { + $timers = new Timers(); + $timers->tick(); + + // simulate a bunch of processing on stream events, + // part of which schedules a future timer... + sleep(1); + $timers->add(new Timer(0.5, function () { + $this->fail("Timer shouldn't be called"); + })); + + $timers->tick(); + + $this->assertTrue(true); + } +} diff --git a/assets/php/vendor/react/event-loop/tests/bootstrap.php b/assets/php/vendor/react/event-loop/tests/bootstrap.php new file mode 100644 index 0000000..ea7dd4c --- /dev/null +++ b/assets/php/vendor/react/event-loop/tests/bootstrap.php @@ -0,0 +1,15 @@ +<?php + +$loader = @include __DIR__ . '/../vendor/autoload.php'; +if (!$loader) { + $loader = require __DIR__ . '/../../../../vendor/autoload.php'; +} +$loader->addPsr4('React\\Tests\\EventLoop\\', __DIR__); + +if (!defined('SIGUSR1')) { + define('SIGUSR1', 1); +} + +if (!defined('SIGUSR2')) { + define('SIGUSR2', 2); +} |