From 1cde2832285e124f6d91f3451b7630f608589596 Mon Sep 17 00:00:00 2001 From: Beno!t POLASZEK Date: Sat, 24 Feb 2024 11:24:26 +0100 Subject: [PATCH 1/5] chore: bump PHP version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 09d8b71..8432423 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ } ], "require": { - "php": ">=5.3.8", + "php": ">=7.1", "react/event-loop": "^1.2", "evenement/evenement": "^3.0 || ^2.0 || ^1.0" }, From af0f2846f0b8ae8cae69bf87285555f1778d5a2e Mon Sep 17 00:00:00 2001 From: Beno!t POLASZEK Date: Fri, 23 Feb 2024 16:54:43 +0100 Subject: [PATCH 2/5] refactor: remove $loop occurrences in favor of singleton --- src/DuplexResourceStream.php | 13 +- src/ReadableResourceStream.php | 11 +- src/WritableResourceStream.php | 12 +- tests/DuplexResourceStreamIntegrationTest.php | 97 +++++++------- tests/DuplexResourceStreamTest.php | 123 +++++++++--------- tests/FunctionalInternetTest.php | 24 ++-- tests/ReadableResourceStreamTest.php | 80 +++++++----- tests/UtilTest.php | 4 +- tests/WritableResourceStreamTest.php | 95 ++++++++------ 9 files changed, 241 insertions(+), 218 deletions(-) diff --git a/src/DuplexResourceStream.php b/src/DuplexResourceStream.php index 4da2139..8cca5df 100644 --- a/src/DuplexResourceStream.php +++ b/src/DuplexResourceStream.php @@ -4,16 +4,12 @@ use Evenement\EventEmitter; use React\EventLoop\Loop; -use React\EventLoop\LoopInterface; use InvalidArgumentException; final class DuplexResourceStream extends EventEmitter implements DuplexStreamInterface { private $stream; - /** @var LoopInterface */ - private $loop; - /** * Controls the maximum buffer size in bytes to read at once from the stream. * @@ -38,7 +34,7 @@ final class DuplexResourceStream extends EventEmitter implements DuplexStreamInt private $closing = false; private $listening = false; - public function __construct($stream, LoopInterface $loop = null, $readChunkSize = null, WritableStreamInterface $buffer = null) + public function __construct($stream, $readChunkSize = null, WritableStreamInterface $buffer = null) { if (!\is_resource($stream) || \get_resource_type($stream) !== "stream") { throw new InvalidArgumentException('First parameter must be a valid stream resource'); @@ -69,11 +65,10 @@ public function __construct($stream, LoopInterface $loop = null, $readChunkSize } if ($buffer === null) { - $buffer = new WritableResourceStream($stream, $loop); + $buffer = new WritableResourceStream($stream); } $this->stream = $stream; - $this->loop = $loop ?: Loop::get(); $this->bufferSize = ($readChunkSize === null) ? 65536 : (int)$readChunkSize; $this->buffer = $buffer; @@ -105,7 +100,7 @@ public function isWritable() public function pause() { if ($this->listening) { - $this->loop->removeReadStream($this->stream); + Loop::get()->removeReadStream($this->stream); $this->listening = false; } } @@ -113,7 +108,7 @@ public function pause() public function resume() { if (!$this->listening && $this->readable) { - $this->loop->addReadStream($this->stream, array($this, 'handleData')); + Loop::get()->addReadStream($this->stream, array($this, 'handleData')); $this->listening = true; } } diff --git a/src/ReadableResourceStream.php b/src/ReadableResourceStream.php index 1b0b08c..1c06287 100644 --- a/src/ReadableResourceStream.php +++ b/src/ReadableResourceStream.php @@ -4,7 +4,6 @@ use Evenement\EventEmitter; use React\EventLoop\Loop; -use React\EventLoop\LoopInterface; use InvalidArgumentException; final class ReadableResourceStream extends EventEmitter implements ReadableStreamInterface @@ -14,9 +13,6 @@ final class ReadableResourceStream extends EventEmitter implements ReadableStrea */ private $stream; - /** @var LoopInterface */ - private $loop; - /** * Controls the maximum buffer size in bytes to read at once from the stream. * @@ -40,7 +36,7 @@ final class ReadableResourceStream extends EventEmitter implements ReadableStrea private $closed = false; private $listening = false; - public function __construct($stream, LoopInterface $loop = null, $readChunkSize = null) + public function __construct($stream, $readChunkSize = null) { if (!\is_resource($stream) || \get_resource_type($stream) !== "stream") { throw new InvalidArgumentException('First parameter must be a valid stream resource'); @@ -71,7 +67,6 @@ public function __construct($stream, LoopInterface $loop = null, $readChunkSize } $this->stream = $stream; - $this->loop = $loop ?: Loop::get(); $this->bufferSize = ($readChunkSize === null) ? 65536 : (int)$readChunkSize; $this->resume(); @@ -85,7 +80,7 @@ public function isReadable() public function pause() { if ($this->listening) { - $this->loop->removeReadStream($this->stream); + Loop::get()->removeReadStream($this->stream); $this->listening = false; } } @@ -93,7 +88,7 @@ public function pause() public function resume() { if (!$this->listening && !$this->closed) { - $this->loop->addReadStream($this->stream, array($this, 'handleData')); + Loop::get()->addReadStream($this->stream, array($this, 'handleData')); $this->listening = true; } } diff --git a/src/WritableResourceStream.php b/src/WritableResourceStream.php index 1af16b1..3d66528 100644 --- a/src/WritableResourceStream.php +++ b/src/WritableResourceStream.php @@ -10,9 +10,6 @@ final class WritableResourceStream extends EventEmitter implements WritableStrea { private $stream; - /** @var LoopInterface */ - private $loop; - /** * @var int */ @@ -28,7 +25,7 @@ final class WritableResourceStream extends EventEmitter implements WritableStrea private $closed = false; private $data = ''; - public function __construct($stream, LoopInterface $loop = null, $writeBufferSoftLimit = null, $writeChunkSize = null) + public function __construct($stream, $writeBufferSoftLimit = null, $writeChunkSize = null) { if (!\is_resource($stream) || \get_resource_type($stream) !== "stream") { throw new \InvalidArgumentException('First parameter must be a valid stream resource'); @@ -47,7 +44,6 @@ public function __construct($stream, LoopInterface $loop = null, $writeBufferSof } $this->stream = $stream; - $this->loop = $loop ?: Loop::get(); $this->softLimit = ($writeBufferSoftLimit === null) ? 65536 : (int)$writeBufferSoftLimit; $this->writeChunkSize = ($writeChunkSize === null) ? -1 : (int)$writeChunkSize; } @@ -68,7 +64,7 @@ public function write($data) if (!$this->listening && $this->data !== '') { $this->listening = true; - $this->loop->addWriteStream($this->stream, array($this, 'handleWrite')); + Loop::get()->addWriteStream($this->stream, array($this, 'handleWrite')); } return !isset($this->data[$this->softLimit - 1]); @@ -97,7 +93,7 @@ public function close() if ($this->listening) { $this->listening = false; - $this->loop->removeWriteStream($this->stream); + Loop::get()->removeWriteStream($this->stream); } $this->closed = true; @@ -155,7 +151,7 @@ public function handleWrite() if ($this->data === '') { // stop waiting for resource to be writable if ($this->listening) { - $this->loop->removeWriteStream($this->stream); + Loop::get()->removeWriteStream($this->stream); $this->listening = false; } diff --git a/tests/DuplexResourceStreamIntegrationTest.php b/tests/DuplexResourceStreamIntegrationTest.php index 7135e15..74da653 100644 --- a/tests/DuplexResourceStreamIntegrationTest.php +++ b/tests/DuplexResourceStreamIntegrationTest.php @@ -3,6 +3,7 @@ namespace React\Tests\Stream; use Clue\StreamFilter as Filter; +use React\EventLoop\Loop; use React\Stream\DuplexResourceStream; use React\Stream\ReadableResourceStream; use React\EventLoop\ExtEventLoop; @@ -23,7 +24,8 @@ function() { return true; }, function () { - return new StreamSelectLoop(); + Loop::set(new StreamSelectLoop()); + return Loop::get(); } ), array( @@ -31,7 +33,10 @@ function () { return function_exists('event_base_new'); }, function () { - return class_exists('React\EventLoop\ExtLibeventLoop') ? new ExtLibeventLoop() : new LibEventLoop(); + Loop::set( + class_exists('React\EventLoop\ExtLibeventLoop') ? new ExtLibeventLoop() : new LibEventLoop() + ); + return Loop::get(); } ), array( @@ -39,7 +44,10 @@ function () { return class_exists('libev\EventLoop'); }, function () { - return class_exists('React\EventLoop\ExtLibevLoop') ? new ExtLibevLoop() : new LibEvLoop(); + Loop::set( + class_exists('React\EventLoop\ExtLibeventLoop') ? new ExtLibeventLoop() : new LibEventLoop() + ); + return Loop::get(); } ), array( @@ -47,7 +55,8 @@ function () { return class_exists('EventBase') && class_exists('React\EventLoop\ExtEventLoop'); }, function () { - return new ExtEventLoop(); + Loop::set(new ExtEventLoop()); + return Loop::get(); } ) ); @@ -62,13 +71,13 @@ public function testBufferReadsLargeChunks($condition, $loopFactory) return $this->markTestSkipped('Loop implementation not available'); } - $loop = $loopFactory(); + $loopFactory(); list($sockA, $sockB) = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, 0); $bufferSize = 4096; - $streamA = new DuplexResourceStream($sockA, $loop, $bufferSize); - $streamB = new DuplexResourceStream($sockB, $loop, $bufferSize); + $streamA = new DuplexResourceStream($sockA, $bufferSize); + $streamB = new DuplexResourceStream($sockB, $bufferSize); $testString = str_repeat("*", $bufferSize + 1); @@ -79,9 +88,9 @@ public function testBufferReadsLargeChunks($condition, $loopFactory) $streamA->write($testString); - $this->loopTick($loop); - $this->loopTick($loop); - $this->loopTick($loop); + $this->loopTick(Loop::get()); + $this->loopTick(Loop::get()); + $this->loopTick(Loop::get()); $streamA->close(); $streamB->close(); @@ -98,12 +107,12 @@ public function testWriteLargeChunk($condition, $loopFactory) return $this->markTestSkipped('Loop implementation not available'); } - $loop = $loopFactory(); + $loopFactory(); list($sockA, $sockB) = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, 0); - $streamA = new DuplexResourceStream($sockA, $loop); - $streamB = new DuplexResourceStream($sockB, $loop); + $streamA = new DuplexResourceStream($sockA); + $streamB = new DuplexResourceStream($sockB); // limit seems to be 192 KiB $size = 256 * 1024; @@ -121,7 +130,7 @@ public function testWriteLargeChunk($condition, $loopFactory) $streamB->on('close', $this->expectCallableOnce()); $streamB->on('error', $this->expectCallableNever()); - $loop->run(); + Loop::get()->run(); $streamA->close(); $streamB->close(); @@ -138,12 +147,12 @@ public function testDoesNotEmitDataIfNothingHasBeenWritten($condition, $loopFact return $this->markTestSkipped('Loop implementation not available'); } - $loop = $loopFactory(); + $loopFactory(); list($sockA, $sockB) = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, 0); - $streamA = new DuplexResourceStream($sockA, $loop); - $streamB = new DuplexResourceStream($sockB, $loop); + $streamA = new DuplexResourceStream($sockA); + $streamB = new DuplexResourceStream($sockB); // end streamA without writing any data $streamA->end(); @@ -151,7 +160,7 @@ public function testDoesNotEmitDataIfNothingHasBeenWritten($condition, $loopFact // streamB should not emit any data $streamB->on('data', $this->expectCallableNever()); - $loop->run(); + Loop::get()->run(); $streamA->close(); $streamB->close(); @@ -166,12 +175,12 @@ public function testDoesNotWriteDataIfRemoteSideFromPairHasBeenClosed($condition return $this->markTestSkipped('Loop implementation not available'); } - $loop = $loopFactory(); + $loopFactory(); list($sockA, $sockB) = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, 0); - $streamA = new DuplexResourceStream($sockA, $loop); - $streamB = new DuplexResourceStream($sockB, $loop); + $streamA = new DuplexResourceStream($sockA); + $streamB = new DuplexResourceStream($sockB); // end streamA without writing any data $streamA->pause(); @@ -181,7 +190,7 @@ public function testDoesNotWriteDataIfRemoteSideFromPairHasBeenClosed($condition $streamB->on('data', $this->expectCallableNever()); $streamB->close(); - $loop->run(); + Loop::get()->run(); $streamA->close(); $streamB->close(); @@ -196,15 +205,15 @@ public function testDoesNotWriteDataIfServerSideHasBeenClosed($condition, $loopF return $this->markTestSkipped('Loop implementation not available'); } - $loop = $loopFactory(); + $loopFactory(); $server = stream_socket_server('tcp://127.0.0.1:0'); $client = stream_socket_client(stream_socket_get_name($server, false)); $peer = stream_socket_accept($server); - $streamA = new DuplexResourceStream($client, $loop); - $streamB = new DuplexResourceStream($peer, $loop); + $streamA = new DuplexResourceStream($client); + $streamB = new DuplexResourceStream($peer); // end streamA without writing any data $streamA->pause(); @@ -214,7 +223,7 @@ public function testDoesNotWriteDataIfServerSideHasBeenClosed($condition, $loopF $streamB->on('data', $this->expectCallableNever()); $streamB->close(); - $loop->run(); + Loop::get()->run(); $streamA->close(); $streamB->close(); @@ -229,15 +238,15 @@ public function testDoesNotWriteDataIfClientSideHasBeenClosed($condition, $loopF return $this->markTestSkipped('Loop implementation not available'); } - $loop = $loopFactory(); + $loopFactory(); $server = stream_socket_server('tcp://127.0.0.1:0'); $client = stream_socket_client(stream_socket_get_name($server, false)); $peer = stream_socket_accept($server); - $streamA = new DuplexResourceStream($peer, $loop); - $streamB = new DuplexResourceStream($client, $loop); + $streamA = new DuplexResourceStream($peer); + $streamB = new DuplexResourceStream($client); // end streamA without writing any data $streamA->pause(); @@ -247,7 +256,7 @@ public function testDoesNotWriteDataIfClientSideHasBeenClosed($condition, $loopF $streamB->on('data', $this->expectCallableNever()); $streamB->close(); - $loop->run(); + Loop::get()->run(); $streamA->close(); $streamB->close(); @@ -262,14 +271,14 @@ public function testReadsSingleChunkFromProcessPipe($condition, $loopFactory) return $this->markTestSkipped('Loop implementation not available'); } - $loop = $loopFactory(); + $loopFactory(); - $stream = new ReadableResourceStream(popen('echo test', 'r'), $loop); + $stream = new ReadableResourceStream(popen('echo test', 'r')); $stream->on('data', $this->expectCallableOnceWith("test\n")); $stream->on('end', $this->expectCallableOnce()); $stream->on('error', $this->expectCallableNever()); - $loop->run(); + Loop::get()->run(); } /** @@ -281,9 +290,9 @@ public function testReadsMultipleChunksFromProcessPipe($condition, $loopFactory) return $this->markTestSkipped('Loop implementation not available'); } - $loop = $loopFactory(); + $loopFactory(); - $stream = new ReadableResourceStream(popen('echo a;sleep 0.1;echo b;sleep 0.1;echo c', 'r'), $loop); + $stream = new ReadableResourceStream(popen('echo a;sleep 0.1;echo b;sleep 0.1;echo c', 'r')); $buffer = ''; $stream->on('data', function ($chunk) use (&$buffer) { @@ -293,7 +302,7 @@ public function testReadsMultipleChunksFromProcessPipe($condition, $loopFactory) $stream->on('end', $this->expectCallableOnce()); $stream->on('error', $this->expectCallableNever()); - $loop->run(); + Loop::get()->run(); $this->assertEquals("a\n" . "b\n" . "c\n", $buffer); } @@ -307,9 +316,9 @@ public function testReadsLongChunksFromProcessPipe($condition, $loopFactory) return $this->markTestSkipped('Loop implementation not available'); } - $loop = $loopFactory(); + $loopFactory(); - $stream = new ReadableResourceStream(popen('dd if=/dev/zero bs=12345 count=1234 2>&-', 'r'), $loop); + $stream = new ReadableResourceStream(popen('dd if=/dev/zero bs=12345 count=1234 2>&-', 'r')); $bytes = 0; $stream->on('data', function ($chunk) use (&$bytes) { @@ -319,7 +328,7 @@ public function testReadsLongChunksFromProcessPipe($condition, $loopFactory) $stream->on('end', $this->expectCallableOnce()); $stream->on('error', $this->expectCallableNever()); - $loop->run(); + Loop::get()->run(); $this->assertEquals(12345 * 1234, $bytes); } @@ -333,14 +342,14 @@ public function testReadsNothingFromProcessPipeWithNoOutput($condition, $loopFac return $this->markTestSkipped('Loop implementation not available'); } - $loop = $loopFactory(); + $loopFactory(); - $stream = new ReadableResourceStream(popen('true', 'r'), $loop); + $stream = new ReadableResourceStream(popen('true', 'r')); $stream->on('data', $this->expectCallableNever()); $stream->on('end', $this->expectCallableOnce()); $stream->on('error', $this->expectCallableNever()); - $loop->run(); + Loop::get()->run(); } /** @@ -364,9 +373,9 @@ public function testEmptyReadShouldntFcloseStream($condition, $loopFactory) return ''; }, STREAM_FILTER_READ); - $loop = $loopFactory(); + $loopFactory(); - $conn = new DuplexResourceStream($stream, $loop); + $conn = new DuplexResourceStream($stream); $conn->on('error', $this->expectCallableNever()); $conn->on('data', $this->expectCallableNever()); $conn->on('end', $this->expectCallableNever()); diff --git a/tests/DuplexResourceStreamTest.php b/tests/DuplexResourceStreamTest.php index e61f14b..ecd2ffd 100644 --- a/tests/DuplexResourceStreamTest.php +++ b/tests/DuplexResourceStreamTest.php @@ -2,6 +2,7 @@ namespace React\Tests\Stream; +use React\EventLoop\Loop; use React\Stream\DuplexResourceStream; use Clue\StreamFilter as Filter; use React\Stream\WritableResourceStream; @@ -15,22 +16,9 @@ class DuplexResourceStreamTest extends TestCase public function testConstructor() { $stream = fopen('php://temp', 'r+'); - $loop = $this->createLoopMock(); - - new DuplexResourceStream($stream, $loop); - } - - public function testConstructWithoutLoopAssignsLoopAutomatically() - { - $resource = fopen('php://temp', 'r+'); - - $stream = new DuplexResourceStream($resource); - - $ref = new \ReflectionProperty($stream, 'loop'); - $ref->setAccessible(true); - $loop = $ref->getValue($stream); + Loop::set($this->createLoopMock()); - $this->assertInstanceOf('React\EventLoop\LoopInterface', $loop); + new DuplexResourceStream($stream); } /** @@ -44,8 +32,8 @@ public function testConstructorWithExcessiveMode() $stream = @fopen($name, 'r+eANYTHING'); unlink($name); - $loop = $this->createLoopMock(); - $buffer = new DuplexResourceStream($stream, $loop); + Loop::set($this->createLoopMock()); + $buffer = new DuplexResourceStream($stream); $buffer->close(); } @@ -54,10 +42,10 @@ public function testConstructorWithExcessiveMode() */ public function testConstructorThrowsExceptionOnInvalidStream() { - $loop = $this->createLoopMock(); + Loop::set($this->createLoopMock()); $this->setExpectedException('InvalidArgumentException'); - new DuplexResourceStream('breakme', $loop); + new DuplexResourceStream('breakme'); } /** @@ -69,10 +57,10 @@ public function testConstructorThrowsExceptionOnWriteOnlyStream() $this->markTestSkipped('HHVM does not report fopen mode for STDOUT'); } - $loop = $this->createLoopMock(); + Loop::set($this->createLoopMock()); $this->setExpectedException('InvalidArgumentException'); - new DuplexResourceStream(STDOUT, $loop); + new DuplexResourceStream(STDOUT); } /** @@ -85,9 +73,9 @@ public function testConstructorThrowsExceptionOnWriteOnlyStreamWithExcessiveMode $stream = fopen($name, 'weANYTHING'); unlink($name); - $loop = $this->createLoopMock(); + Loop::set($this->createLoopMock()); $this->setExpectedException('InvalidArgumentException'); - new DuplexResourceStream($stream, $loop); + new DuplexResourceStream($stream); } /** @@ -100,10 +88,10 @@ public function testConstructorThrowsExceptionIfStreamDoesNotSupportNonBlocking( } $stream = fopen('blocking://test', 'r+'); - $loop = $this->createLoopMock(); + Loop::set($this->createLoopMock()); $this->setExpectedException('RunTimeException'); - new DuplexResourceStream($stream, $loop); + new DuplexResourceStream($stream); } /** @@ -113,11 +101,11 @@ public function testConstructorThrowsExceptionIfStreamDoesNotSupportNonBlocking( public function testConstructorAcceptsBuffer() { $stream = fopen('php://temp', 'r+'); - $loop = $this->createLoopMock(); + Loop::set($this->createLoopMock()); $buffer = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock(); - new DuplexResourceStream($stream, $loop, null, $buffer); + new DuplexResourceStream($stream, null, $buffer); } /** @@ -130,20 +118,20 @@ public function testConstructorThrowsExceptionIfStreamDoesNotSupportNonBlockingW } $stream = fopen('blocking://test', 'r+'); - $loop = $this->createLoopMock(); + Loop::set($this->createLoopMock()); $buffer = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock(); $this->setExpectedException('RunTimeException'); - new DuplexResourceStream($stream, $loop, null, $buffer); + new DuplexResourceStream($stream, null, $buffer); } public function testCloseShouldEmitCloseEvent() { $stream = fopen('php://temp', 'r+'); - $loop = $this->createLoopMock(); + Loop::set($this->createLoopMock()); - $conn = new DuplexResourceStream($stream, $loop); + $conn = new DuplexResourceStream($stream); $conn->on('close', $this->expectCallableOnce()); $conn->on('end', $this->expectCallableNever()); @@ -155,12 +143,12 @@ public function testCloseShouldEmitCloseEvent() public function testEndShouldEndBuffer() { $stream = fopen('php://temp', 'r+'); - $loop = $this->createLoopMock(); + Loop::set($this->createLoopMock()); $buffer = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock(); $buffer->expects($this->once())->method('end')->with('foo'); - $conn = new DuplexResourceStream($stream, $loop, null, $buffer); + $conn = new DuplexResourceStream($stream, null, $buffer); $conn->end('foo'); } @@ -168,12 +156,12 @@ public function testEndShouldEndBuffer() public function testEndAfterCloseIsNoOp() { $stream = fopen('php://temp', 'r+'); - $loop = $this->createLoopMock(); + Loop::set($this->createLoopMock()); $buffer = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock(); $buffer->expects($this->never())->method('end'); - $conn = new DuplexResourceStream($stream, $loop); + $conn = new DuplexResourceStream($stream); $conn->close(); $conn->end(); } @@ -185,11 +173,11 @@ public function testEndAfterCloseIsNoOp() public function testDataEvent() { $stream = fopen('php://temp', 'r+'); - $loop = $this->createLoopMock(); + Loop::set($this->createLoopMock()); $capturedData = null; - $conn = new DuplexResourceStream($stream, $loop); + $conn = new DuplexResourceStream($stream); $conn->on('data', function ($data) use (&$capturedData) { $capturedData = $data; }); @@ -208,11 +196,11 @@ public function testDataEvent() public function testDataEventDoesEmitOneChunkMatchingBufferSize() { $stream = fopen('php://temp', 'r+'); - $loop = $this->createLoopMock(); + Loop::set($this->createLoopMock()); $capturedData = null; - $conn = new DuplexResourceStream($stream, $loop, 4321); + $conn = new DuplexResourceStream($stream, 4321); $conn->on('data', function ($data) use (&$capturedData) { $capturedData = $data; }); @@ -233,11 +221,11 @@ public function testDataEventDoesEmitOneChunkMatchingBufferSize() public function testDataEventDoesEmitOneChunkUntilStreamEndsWhenBufferSizeIsInfinite() { $stream = fopen('php://temp', 'r+'); - $loop = $this->createLoopMock(); + Loop::set($this->createLoopMock()); $capturedData = null; - $conn = new DuplexResourceStream($stream, $loop, -1); + $conn = new DuplexResourceStream($stream, -1); $conn->on('data', function ($data) use (&$capturedData) { $capturedData = $data; @@ -258,9 +246,9 @@ public function testDataEventDoesEmitOneChunkUntilStreamEndsWhenBufferSizeIsInfi public function testEmptyStreamShouldNotEmitData() { $stream = fopen('php://temp', 'r+'); - $loop = $this->createLoopMock(); + Loop::set($this->createLoopMock()); - $conn = new DuplexResourceStream($stream, $loop); + $conn = new DuplexResourceStream($stream); $conn->on('data', $this->expectCallableNever()); $conn->handleData($stream); @@ -272,9 +260,9 @@ public function testEmptyStreamShouldNotEmitData() public function testWrite() { $stream = fopen('php://temp', 'r+'); - $loop = $this->createWriteableLoopMock(); + Loop::set($this->createWriteableLoopMock()); - $conn = new DuplexResourceStream($stream, $loop); + $conn = new DuplexResourceStream($stream); $conn->write("foo\n"); rewind($stream); @@ -289,9 +277,9 @@ public function testWrite() public function testEnd() { $stream = fopen('php://temp', 'r+'); - $loop = $this->createLoopMock(); + Loop::set($this->createLoopMock()); - $conn = new DuplexResourceStream($stream, $loop); + $conn = new DuplexResourceStream($stream); $conn->end(); $this->assertFalse(is_resource($stream)); @@ -306,10 +294,11 @@ public function testEndRemovesReadStreamFromLoop() { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); $loop->expects($this->once())->method('addReadStream')->with($stream); $loop->expects($this->once())->method('removeReadStream')->with($stream); - $conn = new DuplexResourceStream($stream, $loop); + $conn = new DuplexResourceStream($stream); $conn->end('bye'); } @@ -320,10 +309,11 @@ public function testPauseRemovesReadStreamFromLoop() { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); $loop->expects($this->once())->method('addReadStream')->with($stream); $loop->expects($this->once())->method('removeReadStream')->with($stream); - $conn = new DuplexResourceStream($stream, $loop); + $conn = new DuplexResourceStream($stream); $conn->pause(); $conn->pause(); } @@ -335,9 +325,10 @@ public function testResumeDoesAddStreamToLoopOnlyOnce() { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); $loop->expects($this->once())->method('addReadStream')->with($stream); - $conn = new DuplexResourceStream($stream, $loop); + $conn = new DuplexResourceStream($stream); $conn->resume(); $conn->resume(); } @@ -349,10 +340,11 @@ public function testCloseRemovesReadStreamFromLoop() { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); $loop->expects($this->once())->method('addReadStream')->with($stream); $loop->expects($this->once())->method('removeReadStream')->with($stream); - $conn = new DuplexResourceStream($stream, $loop); + $conn = new DuplexResourceStream($stream); $conn->close(); } @@ -363,10 +355,11 @@ public function testCloseAfterPauseRemovesReadStreamFromLoopOnlyOnce() { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); $loop->expects($this->once())->method('addReadStream')->with($stream); $loop->expects($this->once())->method('removeReadStream')->with($stream); - $conn = new DuplexResourceStream($stream, $loop); + $conn = new DuplexResourceStream($stream); $conn->pause(); $conn->close(); } @@ -378,9 +371,10 @@ public function testResumeAfterCloseDoesAddReadStreamToLoopOnlyOnce() { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); $loop->expects($this->once())->method('addReadStream')->with($stream); - $conn = new DuplexResourceStream($stream, $loop); + $conn = new DuplexResourceStream($stream); $conn->close(); $conn->resume(); } @@ -390,8 +384,9 @@ public function testEndedStreamsShouldNotWrite() $file = tempnam(sys_get_temp_dir(), 'reactphptest_'); $stream = fopen($file, 'r+'); $loop = $this->createWriteableLoopMock(); + Loop::set($loop); - $conn = new DuplexResourceStream($stream, $loop); + $conn = new DuplexResourceStream($stream); $conn->write("foo\n"); $conn->end(); @@ -408,8 +403,9 @@ public function testPipeShouldReturnDestination() { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); - $conn = new DuplexResourceStream($stream, $loop); + $conn = new DuplexResourceStream($stream); $dest = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock(); $this->assertSame($dest, $conn->pipe($dest)); @@ -418,10 +414,10 @@ public function testPipeShouldReturnDestination() public function testBufferEventsShouldBubbleUp() { $stream = fopen('php://temp', 'r+'); - $loop = $this->createLoopMock(); + Loop::set($this->createLoopMock()); - $buffer = new WritableResourceStream($stream, $loop); - $conn = new DuplexResourceStream($stream, $loop, null, $buffer); + $buffer = new WritableResourceStream($stream); + $conn = new DuplexResourceStream($stream, null, $buffer); $conn->on('drain', $this->expectCallableOnce()); $conn->on('error', $this->expectCallableOnce()); @@ -437,8 +433,9 @@ public function testClosingStreamInDataEventShouldNotTriggerError() { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); - $conn = new DuplexResourceStream($stream, $loop); + $conn = new DuplexResourceStream($stream); $conn->on('error', $this->expectCallableNever()); $conn->on('data', function ($data) use ($conn) { $conn->close(); @@ -462,11 +459,11 @@ public function testDataFiltered() return str_replace('a', '', $chunk); }, STREAM_FILTER_READ); - $loop = $this->createLoopMock(); + Loop::set($this->createLoopMock()); $capturedData = null; - $conn = new DuplexResourceStream($stream, $loop); + $conn = new DuplexResourceStream($stream); $conn->on('data', function ($data) use (&$capturedData) { $capturedData = $data; }); @@ -493,9 +490,9 @@ public function testDataErrorShouldEmitErrorAndClose() return $chunk; }, STREAM_FILTER_READ); - $loop = $this->createLoopMock(); + Loop::set($this->createLoopMock()); - $conn = new DuplexResourceStream($stream, $loop); + $conn = new DuplexResourceStream($stream); $conn->on('data', $this->expectCallableNever()); $conn->on('error', $this->expectCallableOnce()); $conn->on('close', $this->expectCallableOnce()); diff --git a/tests/FunctionalInternetTest.php b/tests/FunctionalInternetTest.php index 4f07537..71b864e 100644 --- a/tests/FunctionalInternetTest.php +++ b/tests/FunctionalInternetTest.php @@ -3,7 +3,9 @@ namespace React\Tests\Stream; use React\EventLoop\Factory; +use React\EventLoop\Loop; use React\EventLoop\LoopInterface; +use React\EventLoop\StreamSelectLoop; use React\Stream\DuplexResourceStream; use React\Stream\WritableResourceStream; @@ -12,13 +14,18 @@ */ class FunctionalInternetTest extends TestCase { + public static function setUpBeforeClass(): void + { + Loop::set(new StreamSelectLoop()); + } + public function testUploadKilobytePlain() { $size = 1000; $stream = stream_socket_client('tcp://httpbin.org:80'); - $loop = Factory::create(); - $stream = new DuplexResourceStream($stream, $loop); + $loop = Loop::get(); + $stream = new DuplexResourceStream($stream); $buffer = ''; $stream->on('data', function ($chunk) use (&$buffer) { @@ -39,8 +46,8 @@ public function testUploadBiggerBlockPlain() $size = 50 * 1000; $stream = stream_socket_client('tcp://httpbin.org:80'); - $loop = Factory::create(); - $stream = new DuplexResourceStream($stream, $loop); + $loop = Loop::get(); + $stream = new DuplexResourceStream($stream); $buffer = ''; $stream->on('data', function ($chunk) use (&$buffer) { @@ -61,8 +68,8 @@ public function testUploadKilobyteSecure() $size = 1000; $stream = stream_socket_client('ssl://httpbin.org:443'); - $loop = Factory::create(); - $stream = new DuplexResourceStream($stream, $loop); + $loop = Loop::get(); + $stream = new DuplexResourceStream($stream); $buffer = ''; $stream->on('data', function ($chunk) use (&$buffer) { @@ -92,12 +99,11 @@ public function testUploadBiggerBlockSecure() // We work around this by limiting the write chunk size to 8192 bytes // here to also support older PHP versions. // See https://github.com/reactphp/socket/issues/105 - $loop = Factory::create(); + $loop = Loop::get(); $stream = new DuplexResourceStream( $stream, - $loop, null, - new WritableResourceStream($stream, $loop, null, 8192) + new WritableResourceStream($stream, null, 8192) ); $buffer = ''; diff --git a/tests/ReadableResourceStreamTest.php b/tests/ReadableResourceStreamTest.php index f534488..6ce59d5 100644 --- a/tests/ReadableResourceStreamTest.php +++ b/tests/ReadableResourceStreamTest.php @@ -2,6 +2,7 @@ namespace React\Tests\Stream; +use React\EventLoop\Loop; use React\Stream\ReadableResourceStream; use Clue\StreamFilter as Filter; @@ -15,21 +16,9 @@ public function testConstructor() { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); - new ReadableResourceStream($stream, $loop); - } - - public function testConstructWithoutLoopAssignsLoopAutomatically() - { - $resource = fopen('php://temp', 'r+'); - - $stream = new ReadableResourceStream($resource); - - $ref = new \ReflectionProperty($stream, 'loop'); - $ref->setAccessible(true); - $loop = $ref->getValue($stream); - - $this->assertInstanceOf('React\EventLoop\LoopInterface', $loop); + new ReadableResourceStream($stream); } /** @@ -44,7 +33,8 @@ public function testConstructorWithExcessiveMode() unlink($name); $loop = $this->createLoopMock(); - $buffer = new ReadableResourceStream($stream, $loop); + Loop::set($loop); + $buffer = new ReadableResourceStream($stream); $buffer->close(); } @@ -54,9 +44,10 @@ public function testConstructorWithExcessiveMode() public function testConstructorThrowsExceptionOnInvalidStream() { $loop = $this->createLoopMock(); + Loop::set($loop); $this->setExpectedException('InvalidArgumentException'); - new ReadableResourceStream(false, $loop); + new ReadableResourceStream(false); } /** @@ -69,9 +60,10 @@ public function testConstructorThrowsExceptionOnWriteOnlyStream() } $loop = $this->createLoopMock(); + Loop::set($loop); $this->setExpectedException('InvalidArgumentException'); - new ReadableResourceStream(STDOUT, $loop); + new ReadableResourceStream(STDOUT); } /** @@ -85,8 +77,9 @@ public function testConstructorThrowsExceptionOnWriteOnlyStreamWithExcessiveMode unlink($name); $loop = $this->createLoopMock(); + Loop::set($loop); $this->setExpectedException('InvalidArgumentException'); - new ReadableResourceStream($stream, $loop); + new ReadableResourceStream($stream); } /** @@ -100,18 +93,18 @@ public function testConstructorThrowsExceptionIfStreamDoesNotSupportNonBlocking( $stream = fopen('blocking://test', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); $this->setExpectedException('RuntimeException'); - new ReadableResourceStream($stream, $loop); + new ReadableResourceStream($stream); } public function testCloseShouldEmitCloseEvent() { $stream = fopen('php://temp', 'r+'); - $loop = $this->createLoopMock(); - $conn = new ReadableResourceStream($stream, $loop); + $conn = new ReadableResourceStream($stream); $conn->on('close', $this->expectCallableOnce()); $conn->close(); @@ -123,8 +116,9 @@ public function testCloseTwiceShouldEmitCloseEventOnce() { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); - $conn = new ReadableResourceStream($stream, $loop); + $conn = new ReadableResourceStream($stream); $conn->on('close', $this->expectCallableOnce()); $conn->close(); @@ -139,10 +133,11 @@ public function testDataEvent() { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); $capturedData = null; - $conn = new ReadableResourceStream($stream, $loop); + $conn = new ReadableResourceStream($stream); $conn->on('data', function ($data) use (&$capturedData) { $capturedData = $data; }); @@ -162,10 +157,11 @@ public function testDataEventDoesEmitOneChunkMatchingBufferSize() { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); $capturedData = null; - $conn = new ReadableResourceStream($stream, $loop, 4321); + $conn = new ReadableResourceStream($stream, 4321); $conn->on('data', function ($data) use (&$capturedData) { $capturedData = $data; }); @@ -187,10 +183,11 @@ public function testDataEventDoesEmitOneChunkUntilStreamEndsWhenBufferSizeIsInfi { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); $capturedData = null; - $conn = new ReadableResourceStream($stream, $loop, -1); + $conn = new ReadableResourceStream($stream, -1); $conn->on('data', function ($data) use (&$capturedData) { $capturedData = $data; @@ -212,8 +209,9 @@ public function testEmptyStreamShouldNotEmitData() { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); - $conn = new ReadableResourceStream($stream, $loop); + $conn = new ReadableResourceStream($stream); $conn->on('data', $this->expectCallableNever()); $conn->handleData($stream); @@ -223,8 +221,9 @@ public function testPipeShouldReturnDestination() { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); - $conn = new ReadableResourceStream($stream, $loop); + $conn = new ReadableResourceStream($stream); $dest = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock(); $this->assertSame($dest, $conn->pipe($dest)); @@ -237,8 +236,9 @@ public function testClosingStreamInDataEventShouldNotTriggerError() { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); - $conn = new ReadableResourceStream($stream, $loop); + $conn = new ReadableResourceStream($stream); $conn->on('error', $this->expectCallableNever()); $conn->on('data', function ($data) use ($conn) { $conn->close(); @@ -259,8 +259,9 @@ public function testPauseRemovesReadStreamFromLoop() $loop = $this->createLoopMock(); $loop->expects($this->once())->method('addReadStream')->with($stream); $loop->expects($this->once())->method('removeReadStream')->with($stream); + Loop::set($loop); - $conn = new ReadableResourceStream($stream, $loop); + $conn = new ReadableResourceStream($stream); $conn->pause(); $conn->pause(); } @@ -273,8 +274,9 @@ public function testResumeDoesAddStreamToLoopOnlyOnce() $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); $loop->expects($this->once())->method('addReadStream')->with($stream); + Loop::set($loop); - $conn = new ReadableResourceStream($stream, $loop); + $conn = new ReadableResourceStream($stream); $conn->resume(); $conn->resume(); } @@ -288,8 +290,9 @@ public function testCloseRemovesReadStreamFromLoop() $loop = $this->createLoopMock(); $loop->expects($this->once())->method('addReadStream')->with($stream); $loop->expects($this->once())->method('removeReadStream')->with($stream); + Loop::set($loop); - $conn = new ReadableResourceStream($stream, $loop); + $conn = new ReadableResourceStream($stream); $conn->close(); } @@ -302,8 +305,9 @@ public function testCloseAfterPauseRemovesReadStreamFromLoopOnce() $loop = $this->createLoopMock(); $loop->expects($this->once())->method('addReadStream')->with($stream); $loop->expects($this->once())->method('removeReadStream')->with($stream); + Loop::set($loop); - $conn = new ReadableResourceStream($stream, $loop); + $conn = new ReadableResourceStream($stream); $conn->pause(); $conn->close(); } @@ -316,8 +320,9 @@ public function testResumeAfterCloseDoesAddReadStreamToLoopOnlyOnce() $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); $loop->expects($this->once())->method('addReadStream')->with($stream); + Loop::set($loop); - $conn = new ReadableResourceStream($stream, $loop); + $conn = new ReadableResourceStream($stream); $conn->close(); $conn->resume(); } @@ -335,10 +340,11 @@ public function testDataFiltered() }, STREAM_FILTER_READ); $loop = $this->createLoopMock(); + Loop::set($loop); $capturedData = null; - $conn = new ReadableResourceStream($stream, $loop); + $conn = new ReadableResourceStream($stream); $conn->on('data', function ($data) use (&$capturedData) { $capturedData = $data; }); @@ -366,8 +372,9 @@ public function testDataErrorShouldEmitErrorAndClose() }, STREAM_FILTER_READ); $loop = $this->createLoopMock(); + Loop::set($loop); - $conn = new ReadableResourceStream($stream, $loop); + $conn = new ReadableResourceStream($stream); $conn->on('data', $this->expectCallableNever()); $conn->on('error', $this->expectCallableOnce()); $conn->on('close', $this->expectCallableOnce()); @@ -385,8 +392,9 @@ public function testEmptyReadShouldntFcloseStream() { list($stream, $_) = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, 0); $loop = $this->createLoopMock(); + Loop::set($loop); - $conn = new ReadableResourceStream($stream, $loop); + $conn = new ReadableResourceStream($stream); $conn->on('error', $this->expectCallableNever()); $conn->on('data', $this->expectCallableNever()); $conn->on('end', $this->expectCallableNever()); diff --git a/tests/UtilTest.php b/tests/UtilTest.php index f12baad..f00aef9 100644 --- a/tests/UtilTest.php +++ b/tests/UtilTest.php @@ -2,6 +2,7 @@ namespace React\Tests\Stream; +use React\EventLoop\Loop; use React\Stream\WritableResourceStream; use React\Stream\Util; use React\Stream\CompositeStream; @@ -176,7 +177,8 @@ public function testPipeWithWritableResourceStream() $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); - $buffer = new WritableResourceStream($stream, $loop); + Loop::set($loop); + $buffer = new WritableResourceStream($stream); $readable->pipe($buffer); diff --git a/tests/WritableResourceStreamTest.php b/tests/WritableResourceStreamTest.php index 678db98..b0367d3 100644 --- a/tests/WritableResourceStreamTest.php +++ b/tests/WritableResourceStreamTest.php @@ -3,6 +3,7 @@ namespace React\Tests\Stream; use Clue\StreamFilter as Filter; +use React\EventLoop\Loop; use React\Stream\WritableResourceStream; class WritableResourceStreamTest extends TestCase @@ -15,21 +16,9 @@ public function testConstructor() { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); - new WritableResourceStream($stream, $loop); - } - - public function testConstructWithoutLoopAssignsLoopAutomatically() - { - $resource = fopen('php://temp', 'r+'); - - $stream = new WritableResourceStream($resource); - - $ref = new \ReflectionProperty($stream, 'loop'); - $ref->setAccessible(true); - $loop = $ref->getValue($stream); - - $this->assertInstanceOf('React\EventLoop\LoopInterface', $loop); + new WritableResourceStream($stream); } /** @@ -44,7 +33,8 @@ public function testConstructorWithExcessiveMode() unlink($name); $loop = $this->createLoopMock(); - $buffer = new WritableResourceStream($stream, $loop); + Loop::set($loop); + $buffer = new WritableResourceStream($stream); $buffer->close(); } @@ -55,9 +45,10 @@ public function testConstructorThrowsIfNotAValidStreamResource() { $stream = null; $loop = $this->createLoopMock(); + Loop::set($loop); $this->setExpectedException('InvalidArgumentException'); - new WritableResourceStream($stream, $loop); + new WritableResourceStream($stream); } /** @@ -67,9 +58,10 @@ public function testConstructorThrowsExceptionOnReadOnlyStream() { $stream = fopen('php://temp', 'r'); $loop = $this->createLoopMock(); + Loop::set($loop); $this->setExpectedException('InvalidArgumentException'); - new WritableResourceStream($stream, $loop); + new WritableResourceStream($stream); } /** @@ -83,8 +75,9 @@ public function testConstructorThrowsExceptionOnReadOnlyStreamWithExcessiveMode( unlink($name); $loop = $this->createLoopMock(); + Loop::set($loop); $this->setExpectedException('InvalidArgumentException'); - new WritableResourceStream($stream, $loop); + new WritableResourceStream($stream); } /** @@ -98,9 +91,10 @@ public function testConstructorThrowsExceptionIfStreamDoesNotSupportNonBlocking( $stream = fopen('blocking://test', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); $this->setExpectedException('RuntimeException'); - new WritableResourceStream($stream, $loop); + new WritableResourceStream($stream); } /** @@ -111,8 +105,9 @@ public function testWrite() { $stream = fopen('php://temp', 'r+'); $loop = $this->createWriteableLoopMock(); + Loop::set($loop); - $buffer = new WritableResourceStream($stream, $loop); + $buffer = new WritableResourceStream($stream); $buffer->on('error', $this->expectCallableNever()); $buffer->write("foobar\n"); @@ -128,8 +123,9 @@ public function testWriteWithDataDoesAddResourceToLoop() $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); $loop->expects($this->once())->method('addWriteStream')->with($this->equalTo($stream)); + Loop::set($loop); - $buffer = new WritableResourceStream($stream, $loop); + $buffer = new WritableResourceStream($stream); $buffer->write("foobar\n"); } @@ -143,8 +139,9 @@ public function testEmptyWriteDoesNotAddToLoop() $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); $loop->expects($this->never())->method('addWriteStream'); + Loop::set($loop); - $buffer = new WritableResourceStream($stream, $loop); + $buffer = new WritableResourceStream($stream); $buffer->write(""); $buffer->write(null); @@ -168,8 +165,9 @@ public function testWriteReturnsFalseWhenWritableResourceStreamIsFull() call_user_func($listener, $stream); } })); + Loop::set($loop); - $buffer = new WritableResourceStream($stream, $loop, 4); + $buffer = new WritableResourceStream($stream, 4); $buffer->on('error', $this->expectCallableNever()); $this->assertTrue($buffer->write("foo")); @@ -184,8 +182,9 @@ public function testWriteReturnsFalseWhenWritableResourceStreamIsExactlyFull() { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); - $buffer = new WritableResourceStream($stream, $loop, 3); + $buffer = new WritableResourceStream($stream, 3); $this->assertFalse($buffer->write("foo")); } @@ -199,8 +198,9 @@ public function testWriteDetectsWhenOtherSideIsClosed() list($a, $b) = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP); $loop = $this->createWriteableLoopMock(); + Loop::set($loop); - $buffer = new WritableResourceStream($a, $loop, 4); + $buffer = new WritableResourceStream($a, 4); $buffer->on('error', $this->expectCallableOnce()); fclose($b); @@ -216,8 +216,9 @@ public function testEmitsDrainAfterWriteWhichExceedsBuffer() { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); - $buffer = new WritableResourceStream($stream, $loop, 2); + $buffer = new WritableResourceStream($stream, 2); $buffer->on('error', $this->expectCallableNever()); $buffer->on('drain', $this->expectCallableOnce()); @@ -233,8 +234,9 @@ public function testWriteInDrain() { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); - $buffer = new WritableResourceStream($stream, $loop, 2); + $buffer = new WritableResourceStream($stream, 2); $buffer->on('error', $this->expectCallableNever()); $buffer->once('drain', function () use ($buffer) { @@ -257,8 +259,9 @@ public function testDrainAfterWrite() { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); - $buffer = new WritableResourceStream($stream, $loop, 2); + $buffer = new WritableResourceStream($stream, 2); $buffer->on('drain', $this->expectCallableOnce()); @@ -274,8 +277,9 @@ public function testDrainAfterWriteWillRemoveResourceFromLoopWithoutClosing() $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); $loop->expects($this->once())->method('removeWriteStream')->with($stream); + Loop::set($loop); - $buffer = new WritableResourceStream($stream, $loop, 2); + $buffer = new WritableResourceStream($stream, 2); $buffer->on('drain', $this->expectCallableOnce()); @@ -292,9 +296,10 @@ public function testClosingDuringDrainAfterWriteWillRemoveResourceFromLoopOnceAn { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); $loop->expects($this->once())->method('removeWriteStream')->with($stream); - $buffer = new WritableResourceStream($stream, $loop, 2); + $buffer = new WritableResourceStream($stream, 2); $buffer->on('drain', function () use ($buffer) { $buffer->close(); @@ -313,8 +318,9 @@ public function testEndWithoutDataClosesImmediatelyIfWritableResourceStreamIsEmp { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); - $buffer = new WritableResourceStream($stream, $loop); + $buffer = new WritableResourceStream($stream); $buffer->on('error', $this->expectCallableNever()); $buffer->on('close', $this->expectCallableOnce()); @@ -330,8 +336,9 @@ public function testEndWithoutDataDoesNotCloseIfWritableResourceStreamIsFull() { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); - $buffer = new WritableResourceStream($stream, $loop); + $buffer = new WritableResourceStream($stream); $buffer->on('error', $this->expectCallableNever()); $buffer->on('close', $this->expectCallableNever()); @@ -354,8 +361,9 @@ public function testEndWithDataClosesImmediatelyIfWritableResourceStreamFlushes( $stream = fopen('php://temp', 'r+'); $filterBuffer = ''; $loop = $this->createLoopMock(); + Loop::set($loop); - $buffer = new WritableResourceStream($stream, $loop); + $buffer = new WritableResourceStream($stream); $buffer->on('error', $this->expectCallableNever()); $buffer->on('close', $this->expectCallableOnce()); @@ -379,8 +387,9 @@ public function testEndWithDataDoesNotCloseImmediatelyIfWritableResourceStreamIs { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); - $buffer = new WritableResourceStream($stream, $loop); + $buffer = new WritableResourceStream($stream); $buffer->on('error', $this->expectCallableNever()); $buffer->on('close', $this->expectCallableNever()); @@ -402,8 +411,9 @@ public function testClose() { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); - $buffer = new WritableResourceStream($stream, $loop); + $buffer = new WritableResourceStream($stream); $buffer->on('error', $this->expectCallableNever()); $buffer->on('close', $this->expectCallableOnce()); @@ -421,7 +431,8 @@ public function testClosingAfterWriteRemovesStreamFromLoop() { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); - $buffer = new WritableResourceStream($stream, $loop); + Loop::set($loop); + $buffer = new WritableResourceStream($stream); $loop->expects($this->once())->method('removeWriteStream')->with($stream); @@ -436,7 +447,8 @@ public function testClosingWithoutWritingDoesNotRemoveStreamFromLoop() { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); - $buffer = new WritableResourceStream($stream, $loop); + Loop::set($loop); + $buffer = new WritableResourceStream($stream); $loop->expects($this->never())->method('removeWriteStream'); @@ -450,8 +462,9 @@ public function testDoubleCloseWillEmitOnlyOnce() { $stream = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); + Loop::set($loop); - $buffer = new WritableResourceStream($stream, $loop); + $buffer = new WritableResourceStream($stream); $buffer->on('close', $this->expectCallableOnce()); $buffer->close(); @@ -467,8 +480,9 @@ public function testWritingToClosedWritableResourceStreamShouldNotWriteToStream( $stream = fopen('php://temp', 'r+'); $filterBuffer = ''; $loop = $this->createLoopMock(); + Loop::set($loop); - $buffer = new WritableResourceStream($stream, $loop); + $buffer = new WritableResourceStream($stream); Filter\append($stream, function ($chunk) use (&$filterBuffer) { $filterBuffer .= $chunk; @@ -491,10 +505,11 @@ public function testWritingToClosedStream() list($a, $b) = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP); $loop = $this->createLoopMock(); + Loop::set($loop); $error = null; - $buffer = new WritableResourceStream($a, $loop); + $buffer = new WritableResourceStream($a); $buffer->on('error', function($message) use (&$error) { $error = $message; }); From 862761bf9ed4b77e5eaf4f364f6c20aa754e6409 Mon Sep 17 00:00:00 2001 From: Beno!t POLASZEK Date: Sat, 24 Feb 2024 11:38:12 +0100 Subject: [PATCH 3/5] ci: drop unsupported PHP versions until #175 gets merged --- .github/workflows/ci.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bc36a4d..ec47074 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,11 +19,6 @@ jobs: - 7.3 - 7.2 - 7.1 - - 7.0 - - 5.6 - - 5.5 - - 5.4 - - 5.3 steps: - uses: actions/checkout@v4 - uses: shivammathur/setup-php@v2 From 8e9116ea20e7f8323ec24fdd88dd858f27a0c452 Mon Sep 17 00:00:00 2001 From: Beno!t POLASZEK Date: Tue, 5 Mar 2024 10:12:29 +0100 Subject: [PATCH 4/5] chore: replace Loop::get() by static methods --- src/DuplexResourceStream.php | 4 ++-- src/ReadableResourceStream.php | 4 ++-- src/WritableResourceStream.php | 6 +++--- tests/DuplexResourceStreamIntegrationTest.php | 18 +++++++++--------- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/DuplexResourceStream.php b/src/DuplexResourceStream.php index 8cca5df..31fbddf 100644 --- a/src/DuplexResourceStream.php +++ b/src/DuplexResourceStream.php @@ -100,7 +100,7 @@ public function isWritable() public function pause() { if ($this->listening) { - Loop::get()->removeReadStream($this->stream); + Loop::removeReadStream($this->stream); $this->listening = false; } } @@ -108,7 +108,7 @@ public function pause() public function resume() { if (!$this->listening && $this->readable) { - Loop::get()->addReadStream($this->stream, array($this, 'handleData')); + Loop::addReadStream($this->stream, array($this, 'handleData')); $this->listening = true; } } diff --git a/src/ReadableResourceStream.php b/src/ReadableResourceStream.php index 1c06287..6467b1e 100644 --- a/src/ReadableResourceStream.php +++ b/src/ReadableResourceStream.php @@ -80,7 +80,7 @@ public function isReadable() public function pause() { if ($this->listening) { - Loop::get()->removeReadStream($this->stream); + Loop::removeReadStream($this->stream); $this->listening = false; } } @@ -88,7 +88,7 @@ public function pause() public function resume() { if (!$this->listening && !$this->closed) { - Loop::get()->addReadStream($this->stream, array($this, 'handleData')); + Loop::addReadStream($this->stream, array($this, 'handleData')); $this->listening = true; } } diff --git a/src/WritableResourceStream.php b/src/WritableResourceStream.php index 3d66528..d185d2b 100644 --- a/src/WritableResourceStream.php +++ b/src/WritableResourceStream.php @@ -64,7 +64,7 @@ public function write($data) if (!$this->listening && $this->data !== '') { $this->listening = true; - Loop::get()->addWriteStream($this->stream, array($this, 'handleWrite')); + Loop::addWriteStream($this->stream, array($this, 'handleWrite')); } return !isset($this->data[$this->softLimit - 1]); @@ -93,7 +93,7 @@ public function close() if ($this->listening) { $this->listening = false; - Loop::get()->removeWriteStream($this->stream); + Loop::removeWriteStream($this->stream); } $this->closed = true; @@ -151,7 +151,7 @@ public function handleWrite() if ($this->data === '') { // stop waiting for resource to be writable if ($this->listening) { - Loop::get()->removeWriteStream($this->stream); + Loop::removeWriteStream($this->stream); $this->listening = false; } diff --git a/tests/DuplexResourceStreamIntegrationTest.php b/tests/DuplexResourceStreamIntegrationTest.php index 74da653..9f0ad86 100644 --- a/tests/DuplexResourceStreamIntegrationTest.php +++ b/tests/DuplexResourceStreamIntegrationTest.php @@ -130,7 +130,7 @@ public function testWriteLargeChunk($condition, $loopFactory) $streamB->on('close', $this->expectCallableOnce()); $streamB->on('error', $this->expectCallableNever()); - Loop::get()->run(); + Loop::run(); $streamA->close(); $streamB->close(); @@ -160,7 +160,7 @@ public function testDoesNotEmitDataIfNothingHasBeenWritten($condition, $loopFact // streamB should not emit any data $streamB->on('data', $this->expectCallableNever()); - Loop::get()->run(); + Loop::run(); $streamA->close(); $streamB->close(); @@ -190,7 +190,7 @@ public function testDoesNotWriteDataIfRemoteSideFromPairHasBeenClosed($condition $streamB->on('data', $this->expectCallableNever()); $streamB->close(); - Loop::get()->run(); + Loop::run(); $streamA->close(); $streamB->close(); @@ -223,7 +223,7 @@ public function testDoesNotWriteDataIfServerSideHasBeenClosed($condition, $loopF $streamB->on('data', $this->expectCallableNever()); $streamB->close(); - Loop::get()->run(); + Loop::run(); $streamA->close(); $streamB->close(); @@ -256,7 +256,7 @@ public function testDoesNotWriteDataIfClientSideHasBeenClosed($condition, $loopF $streamB->on('data', $this->expectCallableNever()); $streamB->close(); - Loop::get()->run(); + Loop::run(); $streamA->close(); $streamB->close(); @@ -278,7 +278,7 @@ public function testReadsSingleChunkFromProcessPipe($condition, $loopFactory) $stream->on('end', $this->expectCallableOnce()); $stream->on('error', $this->expectCallableNever()); - Loop::get()->run(); + Loop::run(); } /** @@ -302,7 +302,7 @@ public function testReadsMultipleChunksFromProcessPipe($condition, $loopFactory) $stream->on('end', $this->expectCallableOnce()); $stream->on('error', $this->expectCallableNever()); - Loop::get()->run(); + Loop::run(); $this->assertEquals("a\n" . "b\n" . "c\n", $buffer); } @@ -328,7 +328,7 @@ public function testReadsLongChunksFromProcessPipe($condition, $loopFactory) $stream->on('end', $this->expectCallableOnce()); $stream->on('error', $this->expectCallableNever()); - Loop::get()->run(); + Loop::run(); $this->assertEquals(12345 * 1234, $bytes); } @@ -349,7 +349,7 @@ public function testReadsNothingFromProcessPipeWithNoOutput($condition, $loopFac $stream->on('end', $this->expectCallableOnce()); $stream->on('error', $this->expectCallableNever()); - Loop::get()->run(); + Loop::run(); } /** From 89e26faee88614f1e3043ac8fe053e9c2bb9b5d5 Mon Sep 17 00:00:00 2001 From: Beno!t POLASZEK Date: Tue, 5 Mar 2024 10:21:53 +0100 Subject: [PATCH 5/5] refactor: use a static property --- tests/DuplexResourceStreamIntegrationTest.php | 1 - tests/FunctionalInternetTest.php | 28 +++++++++---------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/tests/DuplexResourceStreamIntegrationTest.php b/tests/DuplexResourceStreamIntegrationTest.php index 9f0ad86..a1c643f 100644 --- a/tests/DuplexResourceStreamIntegrationTest.php +++ b/tests/DuplexResourceStreamIntegrationTest.php @@ -8,7 +8,6 @@ use React\Stream\ReadableResourceStream; use React\EventLoop\ExtEventLoop; use React\EventLoop\ExtLibeventLoop; -use React\EventLoop\ExtLibevLoop; use React\EventLoop\LoopInterface; use React\EventLoop\LibEventLoop; use React\EventLoop\LibEvLoop; diff --git a/tests/FunctionalInternetTest.php b/tests/FunctionalInternetTest.php index 71b864e..88ffbcd 100644 --- a/tests/FunctionalInternetTest.php +++ b/tests/FunctionalInternetTest.php @@ -14,9 +14,13 @@ */ class FunctionalInternetTest extends TestCase { + /** @var LoopInterface */ + private static $loop; + public static function setUpBeforeClass(): void { Loop::set(new StreamSelectLoop()); + self::$loop = Loop::get(); } public function testUploadKilobytePlain() @@ -24,7 +28,6 @@ public function testUploadKilobytePlain() $size = 1000; $stream = stream_socket_client('tcp://httpbin.org:80'); - $loop = Loop::get(); $stream = new DuplexResourceStream($stream); $buffer = ''; @@ -36,7 +39,7 @@ public function testUploadKilobytePlain() $stream->write("POST /post HTTP/1.0\r\nHost: httpbin.org\r\nContent-Length: $size\r\n\r\n" . str_repeat('.', $size)); - $this->awaitStreamClose($stream, $loop); + $this->awaitStreamClose($stream); $this->assertNotEquals('', $buffer); } @@ -46,7 +49,6 @@ public function testUploadBiggerBlockPlain() $size = 50 * 1000; $stream = stream_socket_client('tcp://httpbin.org:80'); - $loop = Loop::get(); $stream = new DuplexResourceStream($stream); $buffer = ''; @@ -58,7 +60,7 @@ public function testUploadBiggerBlockPlain() $stream->write("POST /post HTTP/1.0\r\nHost: httpbin.org\r\nContent-Length: $size\r\n\r\n" . str_repeat('.', $size)); - $this->awaitStreamClose($stream, $loop); + $this->awaitStreamClose($stream); $this->assertNotEquals('', $buffer); } @@ -68,7 +70,6 @@ public function testUploadKilobyteSecure() $size = 1000; $stream = stream_socket_client('ssl://httpbin.org:443'); - $loop = Loop::get(); $stream = new DuplexResourceStream($stream); $buffer = ''; @@ -80,7 +81,7 @@ public function testUploadKilobyteSecure() $stream->write("POST /post HTTP/1.0\r\nHost: httpbin.org\r\nContent-Length: $size\r\n\r\n" . str_repeat('.', $size)); - $this->awaitStreamClose($stream, $loop); + $this->awaitStreamClose($stream); $this->assertNotEquals('', $buffer); } @@ -99,7 +100,6 @@ public function testUploadBiggerBlockSecure() // We work around this by limiting the write chunk size to 8192 bytes // here to also support older PHP versions. // See https://github.com/reactphp/socket/issues/105 - $loop = Loop::get(); $stream = new DuplexResourceStream( $stream, null, @@ -115,23 +115,23 @@ public function testUploadBiggerBlockSecure() $stream->write("POST /post HTTP/1.0\r\nHost: httpbin.org\r\nContent-Length: $size\r\n\r\n" . str_repeat('.', $size)); - $this->awaitStreamClose($stream, $loop); + $this->awaitStreamClose($stream); $this->assertNotEquals('', $buffer); } - private function awaitStreamClose(DuplexResourceStream $stream, LoopInterface $loop, $timeout = 10.0) + private function awaitStreamClose(DuplexResourceStream $stream, float $timeout = 10.0) { - $stream->on('close', function () use ($loop) { - $loop->stop(); + $stream->on('close', function () { + self::$loop->stop(); }); $that = $this; - $loop->addTimer($timeout, function () use ($loop, $that) { - $loop->stop(); + self::$loop->addTimer($timeout, function () use ($that) { + self::$loop->stop(); $that->fail('Timed out while waiting for stream to close'); }); - $loop->run(); + self::$loop->run(); } }