diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 65fe5d47..5da29cab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,10 +7,12 @@ on: jobs: PHPUnit: name: PHPUnit (PHP ${{ matrix.php }}) - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: matrix: php: + - 8.5 + - 8.4 - 8.3 - 8.2 - 8.1 @@ -39,13 +41,13 @@ jobs: PHPUnit-macOS: name: PHPUnit (macOS) - runs-on: macos-12 + runs-on: macos-14 continue-on-error: true steps: - uses: actions/checkout@v4 - uses: shivammathur/setup-php@v2 with: - php-version: 8.2 + php-version: 8.5 coverage: xdebug ini-file: development - run: composer install diff --git a/CHANGELOG.md b/CHANGELOG.md index a810eff4..3064849c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.14.0 (2025-11-18) + +* Feature: Improve PHP 8.5+ support by avoiding deprecated `setAccessible()` calls. + (#238 by @W0rma and #243 by @WyriHaximus) + +* Improve test suite, update test environment and increase query count in excessive TCP query tests. + (#239 and #240 by @WyriHaximus) + +## 1.13.0 (2024-06-13) + +* Feature: Improve PHP 8.4+ support by avoiding implicitly nullable type declarations. + (#224 by @WyriHaximus) + ## 1.12.0 (2023-11-29) * Feature: Full PHP 8.3 compatibility. diff --git a/README.md b/README.md index 3b3cf022..b6e8fe4c 100644 --- a/README.md +++ b/README.md @@ -410,7 +410,7 @@ This project follows [SemVer](https://semver.org/). This will install the latest supported version: ```bash -composer require react/dns:^1.12 +composer require react/dns:^1.14 ``` See also the [CHANGELOG](CHANGELOG.md) for details about version upgrades. diff --git a/composer.json b/composer.json index de22b26f..4fe5c0da 100644 --- a/composer.json +++ b/composer.json @@ -29,12 +29,12 @@ "php": ">=5.3.0", "react/cache": "^1.0 || ^0.6 || ^0.5", "react/event-loop": "^1.2", - "react/promise": "^3.0 || ^2.7 || ^1.2.1" + "react/promise": "^3.2 || ^2.7 || ^1.2.1" }, "require-dev": { "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", - "react/async": "^4 || ^3 || ^2", - "react/promise-timer": "^1.9" + "react/async": "^4.3 || ^3 || ^2", + "react/promise-timer": "^1.11" }, "autoload": { "psr-4": { diff --git a/src/Query/RetryExecutor.php b/src/Query/RetryExecutor.php index 880609b2..11c123b8 100644 --- a/src/Query/RetryExecutor.php +++ b/src/Query/RetryExecutor.php @@ -50,7 +50,9 @@ public function tryQuery(Query $query, $retries) // avoid garbage references by replacing all closures in call stack. // what a lovely piece of code! $r = new \ReflectionProperty('Exception', 'trace'); - $r->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $r->setAccessible(true); + } $trace = $r->getValue($e); // Exception trace arguments are not available on some PHP 7.4 installs diff --git a/src/Query/TcpTransportExecutor.php b/src/Query/TcpTransportExecutor.php index bfaedbae..669fd012 100644 --- a/src/Query/TcpTransportExecutor.php +++ b/src/Query/TcpTransportExecutor.php @@ -134,7 +134,7 @@ class TcpTransportExecutor implements ExecutorInterface * @param string $nameserver * @param ?LoopInterface $loop */ - public function __construct($nameserver, LoopInterface $loop = null) + public function __construct($nameserver, $loop = null) { if (\strpos($nameserver, '[') === false && \substr_count($nameserver, ':') >= 2 && \strpos($nameserver, '://') === false) { // several colons, but not enclosed in square brackets => enclose IPv6 address in square brackets @@ -146,6 +146,10 @@ public function __construct($nameserver, LoopInterface $loop = null) throw new \InvalidArgumentException('Invalid nameserver address given'); } + if ($loop !== null && !$loop instanceof LoopInterface) { // manual type check to support legacy PHP < 7.1 + throw new \InvalidArgumentException('Argument #2 ($loop) expected null|React\EventLoop\LoopInterface'); + } + $this->nameserver = 'tcp://' . $parts['host'] . ':' . (isset($parts['port']) ? $parts['port'] : 53); $this->loop = $loop ?: Loop::get(); $this->parser = new Parser(); diff --git a/src/Query/TimeoutExecutor.php b/src/Query/TimeoutExecutor.php index 06c51b15..b61fea6d 100644 --- a/src/Query/TimeoutExecutor.php +++ b/src/Query/TimeoutExecutor.php @@ -12,8 +12,17 @@ final class TimeoutExecutor implements ExecutorInterface private $loop; private $timeout; - public function __construct(ExecutorInterface $executor, $timeout, LoopInterface $loop = null) + /** + * @param ExecutorInterface $executor + * @param float $timeout + * @param ?LoopInterface $loop + */ + public function __construct(ExecutorInterface $executor, $timeout, $loop = null) { + if ($loop !== null && !$loop instanceof LoopInterface) { // manual type check to support legacy PHP < 7.1 + throw new \InvalidArgumentException('Argument #3 ($loop) expected null|React\EventLoop\LoopInterface'); + } + $this->executor = $executor; $this->loop = $loop ?: Loop::get(); $this->timeout = $timeout; diff --git a/src/Query/UdpTransportExecutor.php b/src/Query/UdpTransportExecutor.php index 30a3d705..a8cbfafa 100644 --- a/src/Query/UdpTransportExecutor.php +++ b/src/Query/UdpTransportExecutor.php @@ -98,7 +98,7 @@ final class UdpTransportExecutor implements ExecutorInterface * @param string $nameserver * @param ?LoopInterface $loop */ - public function __construct($nameserver, LoopInterface $loop = null) + public function __construct($nameserver, $loop = null) { if (\strpos($nameserver, '[') === false && \substr_count($nameserver, ':') >= 2 && \strpos($nameserver, '://') === false) { // several colons, but not enclosed in square brackets => enclose IPv6 address in square brackets @@ -110,6 +110,10 @@ public function __construct($nameserver, LoopInterface $loop = null) throw new \InvalidArgumentException('Invalid nameserver address given'); } + if ($loop !== null && !$loop instanceof LoopInterface) { // manual type check to support legacy PHP < 7.1 + throw new \InvalidArgumentException('Argument #2 ($loop) expected null|React\EventLoop\LoopInterface'); + } + $this->nameserver = 'udp://' . $parts['host'] . ':' . (isset($parts['port']) ? $parts['port'] : 53); $this->loop = $loop ?: Loop::get(); $this->parser = new Parser(); diff --git a/src/Resolver/Factory.php b/src/Resolver/Factory.php index 5fe608cb..52658951 100644 --- a/src/Resolver/Factory.php +++ b/src/Resolver/Factory.php @@ -36,8 +36,12 @@ final class Factory * @throws \InvalidArgumentException for invalid DNS server address * @throws \UnderflowException when given DNS Config object has an empty list of nameservers */ - public function create($config, LoopInterface $loop = null) + public function create($config, $loop = null) { + if ($loop !== null && !$loop instanceof LoopInterface) { // manual type check to support legacy PHP < 7.1 + throw new \InvalidArgumentException('Argument #2 ($loop) expected null|React\EventLoop\LoopInterface'); + } + $executor = $this->decorateHostsFileExecutor($this->createExecutor($config, $loop ?: Loop::get())); return new Resolver($executor); @@ -59,8 +63,16 @@ public function create($config, LoopInterface $loop = null) * @throws \InvalidArgumentException for invalid DNS server address * @throws \UnderflowException when given DNS Config object has an empty list of nameservers */ - public function createCached($config, LoopInterface $loop = null, CacheInterface $cache = null) + public function createCached($config, $loop = null, $cache = null) { + if ($loop !== null && !$loop instanceof LoopInterface) { // manual type check to support legacy PHP < 7.1 + throw new \InvalidArgumentException('Argument #2 ($loop) expected null|React\EventLoop\LoopInterface'); + } + + if ($cache !== null && !$cache instanceof CacheInterface) { // manual type check to support legacy PHP < 7.1 + throw new \InvalidArgumentException('Argument #3 ($cache) expected null|React\Cache\CacheInterface'); + } + // default to keeping maximum of 256 responses in cache unless explicitly given if (!($cache instanceof CacheInterface)) { $cache = new ArrayCache(256); diff --git a/tests/Query/TcpTransportExecutorTest.php b/tests/Query/TcpTransportExecutorTest.php index 33dddacd..3bdf3831 100644 --- a/tests/Query/TcpTransportExecutorTest.php +++ b/tests/Query/TcpTransportExecutorTest.php @@ -24,7 +24,9 @@ public function testCtorShouldAcceptNameserverAddresses($input, $expected) $executor = new TcpTransportExecutor($input, $loop); $ref = new \ReflectionProperty($executor, 'nameserver'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $value = $ref->getValue($executor); $this->assertEquals($expected, $value); @@ -65,7 +67,9 @@ public function testCtorWithoutLoopShouldAssignDefaultLoop() $executor = new TcpTransportExecutor('127.0.0.1'); $ref = new \ReflectionProperty($executor, 'loop'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $loop = $ref->getValue($executor); $this->assertInstanceOf('React\EventLoop\LoopInterface', $loop); @@ -127,7 +131,9 @@ public function testQueryRejectsIfServerConnectionFails() $executor = new TcpTransportExecutor('::1', $loop); $ref = new \ReflectionProperty($executor, 'nameserver'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue($executor, '///'); $query = new Query('google.com', Message::TYPE_A, Message::CLASS_IN); @@ -306,7 +312,9 @@ public function testQueryStaysPendingWhenClientCanNotSendExcessiveMessageInOneCh $promise->then($this->expectCallableNever(), $this->expectCallableNever()); $ref = new \ReflectionProperty($executor, 'writePending'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $writePending = $ref->getValue($executor); $this->assertTrue($writePending); @@ -336,7 +344,7 @@ public function testQueryStaysPendingWhenClientCanNotSendExcessiveMessageInOneCh $query = new Query('google' . str_repeat('.com', 100), Message::TYPE_A, Message::CLASS_IN); // send a bunch of queries and keep reference to last promise - for ($i = 0; $i < 2000; ++$i) { + for ($i = 0; $i < 20000; ++$i) { $promise = $executor->query($query); } @@ -348,7 +356,9 @@ public function testQueryStaysPendingWhenClientCanNotSendExcessiveMessageInOneCh $promise->then($this->expectCallableNever(), $this->expectCallableNever()); $ref = new \ReflectionProperty($executor, 'writePending'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $writePending = $ref->getValue($executor); $this->assertTrue($writePending); @@ -371,7 +381,7 @@ public function testQueryRejectsWhenClientKeepsSendingWhenServerClosesSocketWith // send a bunch of queries and keep reference to last promise $exception = null; - for ($i = 0; $i < 2000; ++$i) { + for ($i = 0; $i < 20000; ++$i) { $promise = $executor->query($query); $promise->then(null, function (\Exception $reason) use (&$exception) { $exception = $reason; @@ -389,7 +399,9 @@ public function testQueryRejectsWhenClientKeepsSendingWhenServerClosesSocketWith $executor->handleWritable(); $ref = new \ReflectionProperty($executor, 'writePending'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $writePending = $ref->getValue($executor); // We expect an EPIPE (Broken pipe) on second write. @@ -744,7 +756,9 @@ public function testQueryResolvesIfServerSendsBackResponseMessageAndWillStartIdl // use outgoing buffer as response message $ref = new \ReflectionProperty($executor, 'writeBuffer'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $data = $ref->getValue($executor); $client = stream_socket_accept($server); @@ -779,7 +793,9 @@ public function testQueryResolvesIfServerSendsBackResponseMessageAfterCancelling // use outgoing buffer as response message $ref = new \ReflectionProperty($executor, 'writeBuffer'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $data = $ref->getValue($executor); $client = stream_socket_accept($server); @@ -812,7 +828,9 @@ public function testQueryResolvesIfServerSendsBackResponseMessageAfterCancelling // use outgoing buffer as response message $ref = new \ReflectionProperty($executor, 'writeBuffer'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $data = $ref->getValue($executor); $client = stream_socket_accept($server); @@ -853,7 +871,9 @@ public function testTriggerIdleTimerAfterPreviousQueryResolvedWillCloseIdleSocke // use outgoing buffer as response message $ref = new \ReflectionProperty($executor, 'writeBuffer'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $data = $ref->getValue($executor); $client = stream_socket_accept($server); @@ -891,7 +911,9 @@ public function testClosingConnectionAfterPreviousQueryResolvedWillCancelIdleTim // use outgoing buffer as response message $ref = new \ReflectionProperty($executor, 'writeBuffer'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $data = $ref->getValue($executor); $client = stream_socket_accept($server); @@ -929,7 +951,9 @@ public function testQueryAgainAfterPreviousQueryResolvedWillReuseSocketAndCancel // use outgoing buffer as response message $ref = new \ReflectionProperty($executor, 'writeBuffer'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $data = $ref->getValue($executor); $client = stream_socket_accept($server); @@ -943,4 +967,11 @@ public function testQueryAgainAfterPreviousQueryResolvedWillReuseSocketAndCancel // trigger second query $executor->query($query); } + + /** @test */ + public function constructorThrowsExceptionForInvalidLoop() + { + $this->setExpectedException('InvalidArgumentException', 'Argument #2 ($loop) expected null|React\EventLoop\LoopInterface'); + new TcpTransportExecutor('tcp://127.0.0.1:53', 'loop'); + } } diff --git a/tests/Query/TimeoutExecutorTest.php b/tests/Query/TimeoutExecutorTest.php index b7857783..a0bc3abb 100644 --- a/tests/Query/TimeoutExecutorTest.php +++ b/tests/Query/TimeoutExecutorTest.php @@ -34,7 +34,9 @@ public function testCtorWithoutLoopShouldAssignDefaultLoop() $executor = new TimeoutExecutor($this->executor, 5.0); $ref = new \ReflectionProperty($executor, 'loop'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $loop = $ref->getValue($executor); $this->assertInstanceOf('React\EventLoop\LoopInterface', $loop); @@ -185,4 +187,11 @@ public function testRejectsPromiseAndCancelsPendingQueryWhenTimeoutTriggers() $this->assertInstanceOf('React\Dns\Query\TimeoutException', $exception); $this->assertEquals('DNS query for igor.io (A) timed out' , $exception->getMessage()); } + + /** @test */ + public function constructorThrowsExceptionForInvalidLoop() + { + $this->setExpectedException('InvalidArgumentException', 'Argument #3 ($loop) expected null|React\EventLoop\LoopInterface'); + new TimeoutExecutor($this->executor, 5.0, 'loop'); + } } diff --git a/tests/Query/UdpTransportExecutorTest.php b/tests/Query/UdpTransportExecutorTest.php index 3f04d9ad..4036b675 100644 --- a/tests/Query/UdpTransportExecutorTest.php +++ b/tests/Query/UdpTransportExecutorTest.php @@ -24,7 +24,9 @@ public function testCtorShouldAcceptNameserverAddresses($input, $expected) $executor = new UdpTransportExecutor($input, $loop); $ref = new \ReflectionProperty($executor, 'nameserver'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $value = $ref->getValue($executor); $this->assertEquals($expected, $value); @@ -65,7 +67,9 @@ public function testCtorWithoutLoopShouldAssignDefaultLoop() $executor = new UdpTransportExecutor('127.0.0.1'); $ref = new \ReflectionProperty($executor, 'loop'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $loop = $ref->getValue($executor); $this->assertInstanceOf('React\EventLoop\LoopInterface', $loop); @@ -132,7 +136,9 @@ public function testQueryRejectsIfServerConnectionFails() $executor = new UdpTransportExecutor('::1', $loop); $ref = new \ReflectionProperty($executor, 'nameserver'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue($executor, '///'); $query = new Query('google.com', Message::TYPE_A, Message::CLASS_IN); @@ -161,7 +167,9 @@ public function testQueryRejectsIfSendToServerFailsAfterConnectionWithoutCalling // increase hard-coded maximum packet size to allow sending excessive data $ref = new \ReflectionProperty($executor, 'maxPacketSize'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue($executor, PHP_INT_MAX); $error = null; @@ -375,4 +383,11 @@ public function testQueryResolvesIfServerSendsValidResponse() $this->assertInstanceOf('React\Dns\Model\Message', $response); } + + /** @test */ + public function constructorThrowsExceptionForInvalidLoop() + { + $this->setExpectedException('InvalidArgumentException', 'Argument #2 ($loop) expected null|React\EventLoop\LoopInterface'); + new UdpTransportExecutor('udp://127.0.0.1:53', 'loop'); + } } diff --git a/tests/Resolver/FactoryTest.php b/tests/Resolver/FactoryTest.php index af758b51..4a14df03 100644 --- a/tests/Resolver/FactoryTest.php +++ b/tests/Resolver/FactoryTest.php @@ -33,13 +33,17 @@ public function createWithoutSchemeShouldCreateResolverWithSelectiveUdpAndTcpExe $this->assertInstanceOf('React\Dns\Query\CoopExecutor', $coopExecutor); $ref = new \ReflectionProperty($coopExecutor, 'executor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $retryExecutor = $ref->getValue($coopExecutor); $this->assertInstanceOf('React\Dns\Query\RetryExecutor', $retryExecutor); $ref = new \ReflectionProperty($retryExecutor, 'executor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $selectiveExecutor = $ref->getValue($retryExecutor); $this->assertInstanceOf('React\Dns\Query\SelectiveTransportExecutor', $selectiveExecutor); @@ -47,13 +51,17 @@ public function createWithoutSchemeShouldCreateResolverWithSelectiveUdpAndTcpExe // udp below: $ref = new \ReflectionProperty($selectiveExecutor, 'datagramExecutor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $timeoutExecutor = $ref->getValue($selectiveExecutor); $this->assertInstanceOf('React\Dns\Query\TimeoutExecutor', $timeoutExecutor); $ref = new \ReflectionProperty($timeoutExecutor, 'executor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $udpExecutor = $ref->getValue($timeoutExecutor); $this->assertInstanceOf('React\Dns\Query\UdpTransportExecutor', $udpExecutor); @@ -61,13 +69,17 @@ public function createWithoutSchemeShouldCreateResolverWithSelectiveUdpAndTcpExe // tcp below: $ref = new \ReflectionProperty($selectiveExecutor, 'streamExecutor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $timeoutExecutor = $ref->getValue($selectiveExecutor); $this->assertInstanceOf('React\Dns\Query\TimeoutExecutor', $timeoutExecutor); $ref = new \ReflectionProperty($timeoutExecutor, 'executor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $tcpExecutor = $ref->getValue($timeoutExecutor); $this->assertInstanceOf('React\Dns\Query\TcpTransportExecutor', $tcpExecutor); @@ -88,19 +100,25 @@ public function createWithUdpSchemeShouldCreateResolverWithUdpExecutorStack() $this->assertInstanceOf('React\Dns\Query\CoopExecutor', $coopExecutor); $ref = new \ReflectionProperty($coopExecutor, 'executor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $retryExecutor = $ref->getValue($coopExecutor); $this->assertInstanceOf('React\Dns\Query\RetryExecutor', $retryExecutor); $ref = new \ReflectionProperty($retryExecutor, 'executor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $timeoutExecutor = $ref->getValue($retryExecutor); $this->assertInstanceOf('React\Dns\Query\TimeoutExecutor', $timeoutExecutor); $ref = new \ReflectionProperty($timeoutExecutor, 'executor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $udpExecutor = $ref->getValue($timeoutExecutor); $this->assertInstanceOf('React\Dns\Query\UdpTransportExecutor', $udpExecutor); @@ -121,19 +139,25 @@ public function createWithTcpSchemeShouldCreateResolverWithTcpExecutorStack() $this->assertInstanceOf('React\Dns\Query\CoopExecutor', $coopExecutor); $ref = new \ReflectionProperty($coopExecutor, 'executor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $retryExecutor = $ref->getValue($coopExecutor); $this->assertInstanceOf('React\Dns\Query\RetryExecutor', $retryExecutor); $ref = new \ReflectionProperty($retryExecutor, 'executor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $timeoutExecutor = $ref->getValue($retryExecutor); $this->assertInstanceOf('React\Dns\Query\TimeoutExecutor', $timeoutExecutor); $ref = new \ReflectionProperty($timeoutExecutor, 'executor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $tcpExecutor = $ref->getValue($timeoutExecutor); $this->assertInstanceOf('React\Dns\Query\TcpTransportExecutor', $tcpExecutor); @@ -157,19 +181,25 @@ public function createWithConfigWithTcpNameserverSchemeShouldCreateResolverWithT $this->assertInstanceOf('React\Dns\Query\CoopExecutor', $coopExecutor); $ref = new \ReflectionProperty($coopExecutor, 'executor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $retryExecutor = $ref->getValue($coopExecutor); $this->assertInstanceOf('React\Dns\Query\RetryExecutor', $retryExecutor); $ref = new \ReflectionProperty($retryExecutor, 'executor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $timeoutExecutor = $ref->getValue($retryExecutor); $this->assertInstanceOf('React\Dns\Query\TimeoutExecutor', $timeoutExecutor); $ref = new \ReflectionProperty($timeoutExecutor, 'executor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $tcpExecutor = $ref->getValue($timeoutExecutor); $this->assertInstanceOf('React\Dns\Query\TcpTransportExecutor', $tcpExecutor); @@ -194,49 +224,65 @@ public function createWithConfigWithTwoNameserversWithTcpSchemeShouldCreateResol $this->assertInstanceOf('React\Dns\Query\CoopExecutor', $coopExecutor); $ref = new \ReflectionProperty($coopExecutor, 'executor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $retryExecutor = $ref->getValue($coopExecutor); $this->assertInstanceOf('React\Dns\Query\RetryExecutor', $retryExecutor); $ref = new \ReflectionProperty($retryExecutor, 'executor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $fallbackExecutor = $ref->getValue($retryExecutor); $this->assertInstanceOf('React\Dns\Query\FallbackExecutor', $fallbackExecutor); $ref = new \ReflectionProperty($fallbackExecutor, 'executor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $timeoutExecutor = $ref->getValue($fallbackExecutor); $this->assertInstanceOf('React\Dns\Query\TimeoutExecutor', $timeoutExecutor); $ref = new \ReflectionProperty($timeoutExecutor, 'executor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $tcpExecutor = $ref->getValue($timeoutExecutor); $this->assertInstanceOf('React\Dns\Query\TcpTransportExecutor', $tcpExecutor); $ref = new \ReflectionProperty($tcpExecutor, 'nameserver'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $nameserver = $ref->getValue($tcpExecutor); $this->assertEquals('tcp://8.8.8.8:53', $nameserver); $ref = new \ReflectionProperty($fallbackExecutor, 'fallback'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $timeoutExecutor = $ref->getValue($fallbackExecutor); $this->assertInstanceOf('React\Dns\Query\TimeoutExecutor', $timeoutExecutor); $ref = new \ReflectionProperty($timeoutExecutor, 'executor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $tcpExecutor = $ref->getValue($timeoutExecutor); $this->assertInstanceOf('React\Dns\Query\TcpTransportExecutor', $tcpExecutor); $ref = new \ReflectionProperty($tcpExecutor, 'nameserver'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $nameserver = $ref->getValue($tcpExecutor); $this->assertEquals('tcp://1.1.1.1:53', $nameserver); @@ -262,73 +308,97 @@ public function createWithConfigWithThreeNameserversWithTcpSchemeShouldCreateRes $this->assertInstanceOf('React\Dns\Query\CoopExecutor', $coopExecutor); $ref = new \ReflectionProperty($coopExecutor, 'executor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $retryExecutor = $ref->getValue($coopExecutor); $this->assertInstanceOf('React\Dns\Query\RetryExecutor', $retryExecutor); $ref = new \ReflectionProperty($retryExecutor, 'executor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $fallbackExecutor = $ref->getValue($retryExecutor); $this->assertInstanceOf('React\Dns\Query\FallbackExecutor', $fallbackExecutor); $ref = new \ReflectionProperty($fallbackExecutor, 'executor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $timeoutExecutor = $ref->getValue($fallbackExecutor); $this->assertInstanceOf('React\Dns\Query\TimeoutExecutor', $timeoutExecutor); $ref = new \ReflectionProperty($timeoutExecutor, 'executor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $tcpExecutor = $ref->getValue($timeoutExecutor); $this->assertInstanceOf('React\Dns\Query\TcpTransportExecutor', $tcpExecutor); $ref = new \ReflectionProperty($tcpExecutor, 'nameserver'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $nameserver = $ref->getValue($tcpExecutor); $this->assertEquals('tcp://8.8.8.8:53', $nameserver); $ref = new \ReflectionProperty($fallbackExecutor, 'fallback'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $fallbackExecutor = $ref->getValue($fallbackExecutor); $this->assertInstanceOf('React\Dns\Query\FallbackExecutor', $fallbackExecutor); $ref = new \ReflectionProperty($fallbackExecutor, 'executor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $timeoutExecutor = $ref->getValue($fallbackExecutor); $this->assertInstanceOf('React\Dns\Query\TimeoutExecutor', $timeoutExecutor); $ref = new \ReflectionProperty($timeoutExecutor, 'executor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $tcpExecutor = $ref->getValue($timeoutExecutor); $this->assertInstanceOf('React\Dns\Query\TcpTransportExecutor', $tcpExecutor); $ref = new \ReflectionProperty($tcpExecutor, 'nameserver'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $nameserver = $ref->getValue($tcpExecutor); $this->assertEquals('tcp://1.1.1.1:53', $nameserver); $ref = new \ReflectionProperty($fallbackExecutor, 'fallback'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $timeoutExecutor = $ref->getValue($fallbackExecutor); $this->assertInstanceOf('React\Dns\Query\TimeoutExecutor', $timeoutExecutor); $ref = new \ReflectionProperty($timeoutExecutor, 'executor'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $tcpExecutor = $ref->getValue($timeoutExecutor); $this->assertInstanceOf('React\Dns\Query\TcpTransportExecutor', $tcpExecutor); $ref = new \ReflectionProperty($tcpExecutor, 'nameserver'); - $ref->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $nameserver = $ref->getValue($tcpExecutor); $this->assertEquals('tcp://9.9.9.9:53', $nameserver); @@ -399,6 +469,32 @@ public function createCachedShouldCreateResolverWithCachingExecutorWithCustomCac $this->assertSame($cache, $cacheProperty); } + /** @test */ + public function createThrowsExceptionForInvalidLoop() + { + $this->setExpectedException('InvalidArgumentException', 'Argument #2 ($loop) expected null|React\EventLoop\LoopInterface'); + $factory = new Factory(); + $factory->create('config', 'loop'); + } + + /** @test */ + public function createCachedThrowsExceptionForInvalidLoop() + { + $this->setExpectedException('InvalidArgumentException', 'Argument #2 ($loop) expected null|React\EventLoop\LoopInterface'); + $factory = new Factory(); + $factory->createCached('config', 'loop'); + } + + /** @test */ + public function createCachedThrowsExceptionForInvalidCache() + { + $loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock(); + + $this->setExpectedException('InvalidArgumentException', 'Argument #3 ($cache) expected null|React\Cache\CacheInterface'); + $factory = new Factory(); + $factory->createCached('config', $loop, 'cache'); + } + private function getResolverPrivateExecutor($resolver) { $executor = $this->getResolverPrivateMemberValue($resolver, 'executor'); @@ -406,7 +502,9 @@ private function getResolverPrivateExecutor($resolver) // extract underlying executor that may be wrapped in multiple layers of hosts file executors while ($executor instanceof HostsFileExecutor) { $reflector = new \ReflectionProperty('React\Dns\Query\HostsFileExecutor', 'fallback'); - $reflector->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $reflector->setAccessible(true); + } $executor = $reflector->getValue($executor); } @@ -417,14 +515,18 @@ private function getResolverPrivateExecutor($resolver) private function getResolverPrivateMemberValue($resolver, $field) { $reflector = new \ReflectionProperty('React\Dns\Resolver\Resolver', $field); - $reflector->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $reflector->setAccessible(true); + } return $reflector->getValue($resolver); } private function getCachingExecutorPrivateMemberValue($resolver, $field) { $reflector = new \ReflectionProperty('React\Dns\Query\CachingExecutor', $field); - $reflector->setAccessible(true); + if (\PHP_VERSION_ID < 80100) { + $reflector->setAccessible(true); + } return $reflector->getValue($resolver); } }