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/dns/tests/Query | |
parent | 286d643180672f20526f3dc3bd19d7b751e2fa97 (diff) |
Initial Commit
Diffstat (limited to 'assets/php/vendor/react/dns/tests/Query')
7 files changed, 1033 insertions, 0 deletions
diff --git a/assets/php/vendor/react/dns/tests/Query/CachedExecutorTest.php b/assets/php/vendor/react/dns/tests/Query/CachedExecutorTest.php new file mode 100644 index 0000000..d08ed05 --- /dev/null +++ b/assets/php/vendor/react/dns/tests/Query/CachedExecutorTest.php @@ -0,0 +1,100 @@ +<?php + +namespace React\Tests\Dns\Query; + +use React\Tests\Dns\TestCase; +use React\Dns\Query\CachedExecutor; +use React\Dns\Query\Query; +use React\Dns\Model\Message; +use React\Dns\Model\Record; +use React\Promise; + +class CachedExecutorTest extends TestCase +{ + /** + * @covers React\Dns\Query\CachedExecutor + * @test + */ + public function queryShouldDelegateToDecoratedExecutor() + { + $executor = $this->createExecutorMock(); + $executor + ->expects($this->once()) + ->method('query') + ->with('8.8.8.8', $this->isInstanceOf('React\Dns\Query\Query')) + ->will($this->returnValue($this->createPromiseMock())); + + $cache = $this->getMockBuilder('React\Dns\Query\RecordCache') + ->disableOriginalConstructor() + ->getMock(); + $cache + ->expects($this->once()) + ->method('lookup') + ->will($this->returnValue(Promise\reject())); + $cachedExecutor = new CachedExecutor($executor, $cache); + + $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); + $cachedExecutor->query('8.8.8.8', $query); + } + + /** + * @covers React\Dns\Query\CachedExecutor + * @test + */ + public function callingQueryTwiceShouldUseCachedResult() + { + $cachedRecords = array(new Record('igor.io', Message::TYPE_A, Message::CLASS_IN)); + + $executor = $this->createExecutorMock(); + $executor + ->expects($this->once()) + ->method('query') + ->will($this->callQueryCallbackWithAddress('178.79.169.131')); + + $cache = $this->getMockBuilder('React\Dns\Query\RecordCache') + ->disableOriginalConstructor() + ->getMock(); + $cache + ->expects($this->at(0)) + ->method('lookup') + ->with($this->isInstanceOf('React\Dns\Query\Query')) + ->will($this->returnValue(Promise\reject())); + $cache + ->expects($this->at(1)) + ->method('storeResponseMessage') + ->with($this->isType('integer'), $this->isInstanceOf('React\Dns\Model\Message')); + $cache + ->expects($this->at(2)) + ->method('lookup') + ->with($this->isInstanceOf('React\Dns\Query\Query')) + ->will($this->returnValue(Promise\resolve($cachedRecords))); + + $cachedExecutor = new CachedExecutor($executor, $cache); + + $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); + $cachedExecutor->query('8.8.8.8', $query, function () {}, function () {}); + $cachedExecutor->query('8.8.8.8', $query, function () {}, function () {}); + } + + private function callQueryCallbackWithAddress($address) + { + return $this->returnCallback(function ($nameserver, $query) use ($address) { + $response = new Message(); + $response->header->set('qr', 1); + $response->questions[] = new Record($query->name, $query->type, $query->class); + $response->answers[] = new Record($query->name, $query->type, $query->class, 3600, $address); + + return Promise\resolve($response); + }); + } + + private function createExecutorMock() + { + return $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock(); + } + + private function createPromiseMock() + { + return $this->getMockBuilder('React\Promise\PromiseInterface')->getMock(); + } +} diff --git a/assets/php/vendor/react/dns/tests/Query/ExecutorTest.php b/assets/php/vendor/react/dns/tests/Query/ExecutorTest.php new file mode 100644 index 0000000..0d7ac1d --- /dev/null +++ b/assets/php/vendor/react/dns/tests/Query/ExecutorTest.php @@ -0,0 +1,308 @@ +<?php + +namespace React\Tests\Dns\Query; + +use Clue\React\Block; +use React\Dns\Query\Executor; +use React\Dns\Query\Query; +use React\Dns\Model\Message; +use React\Dns\Model\Record; +use React\Dns\Protocol\BinaryDumper; +use React\Tests\Dns\TestCase; + +class ExecutorTest extends TestCase +{ + private $loop; + private $parser; + private $dumper; + private $executor; + + public function setUp() + { + $this->loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock(); + $this->parser = $this->getMockBuilder('React\Dns\Protocol\Parser')->getMock(); + $this->dumper = new BinaryDumper(); + + $this->executor = new Executor($this->loop, $this->parser, $this->dumper); + } + + /** @test */ + public function queryShouldCreateUdpRequest() + { + $timer = $this->createTimerMock(); + $this->loop + ->expects($this->any()) + ->method('addTimer') + ->will($this->returnValue($timer)); + + $this->executor = $this->createExecutorMock(); + $this->executor + ->expects($this->once()) + ->method('createConnection') + ->with('8.8.8.8:53', 'udp') + ->will($this->returnNewConnectionMock(false)); + + $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); + $this->executor->query('8.8.8.8:53', $query); + } + + /** @test */ + public function resolveShouldRejectIfRequestIsLargerThan512Bytes() + { + $query = new Query(str_repeat('a', 512).'.igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); + $promise = $this->executor->query('8.8.8.8:53', $query); + + $this->setExpectedException('RuntimeException', 'DNS query for ' . $query->name . ' failed: Requested transport "tcp" not available, only UDP is supported in this version'); + Block\await($promise, $this->loop); + } + + /** @test */ + public function resolveShouldCloseConnectionWhenCancelled() + { + $conn = $this->createConnectionMock(false); + $conn->expects($this->once())->method('close'); + + $timer = $this->createTimerMock(); + $this->loop + ->expects($this->any()) + ->method('addTimer') + ->will($this->returnValue($timer)); + + $this->executor = $this->createExecutorMock(); + $this->executor + ->expects($this->once()) + ->method('createConnection') + ->with('8.8.8.8:53', 'udp') + ->will($this->returnValue($conn)); + + $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); + $promise = $this->executor->query('8.8.8.8:53', $query); + + $promise->cancel(); + + $this->setExpectedException('React\Dns\Query\CancellationException', 'DNS query for igor.io has been cancelled'); + Block\await($promise, $this->loop); + } + + /** @test */ + public function resolveShouldNotStartOrCancelTimerWhenCancelledWithTimeoutIsNull() + { + $this->loop + ->expects($this->never()) + ->method('addTimer'); + + $this->executor = new Executor($this->loop, $this->parser, $this->dumper, null); + + $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); + $promise = $this->executor->query('127.0.0.1:53', $query); + + $promise->cancel(); + + $this->setExpectedException('React\Dns\Query\CancellationException', 'DNS query for igor.io has been cancelled'); + Block\await($promise, $this->loop); + } + + /** @test */ + public function resolveShouldRejectIfResponseIsTruncated() + { + $timer = $this->createTimerMock(); + + $this->loop + ->expects($this->any()) + ->method('addTimer') + ->will($this->returnValue($timer)); + + $this->parser + ->expects($this->once()) + ->method('parseMessage') + ->will($this->returnTruncatedResponse()); + + $this->executor = $this->createExecutorMock(); + $this->executor + ->expects($this->once()) + ->method('createConnection') + ->with('8.8.8.8:53', 'udp') + ->will($this->returnNewConnectionMock()); + + $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); + $this->executor->query('8.8.8.8:53', $query); + } + + /** @test */ + public function resolveShouldFailIfUdpThrow() + { + $this->loop + ->expects($this->never()) + ->method('addTimer'); + + $this->parser + ->expects($this->never()) + ->method('parseMessage'); + + $this->executor = $this->createExecutorMock(); + $this->executor + ->expects($this->once()) + ->method('createConnection') + ->with('8.8.8.8:53', 'udp') + ->will($this->throwException(new \Exception('Nope'))); + + $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); + $promise = $this->executor->query('8.8.8.8:53', $query); + + $this->setExpectedException('RuntimeException', 'DNS query for igor.io failed: Nope'); + Block\await($promise, $this->loop); + } + + /** @test */ + public function resolveShouldCancelTimerWhenFullResponseIsReceived() + { + $conn = $this->createConnectionMock(); + + $this->parser + ->expects($this->once()) + ->method('parseMessage') + ->will($this->returnStandardResponse()); + + $this->executor = $this->createExecutorMock(); + $this->executor + ->expects($this->at(0)) + ->method('createConnection') + ->with('8.8.8.8:53', 'udp') + ->will($this->returnNewConnectionMock()); + + + $timer = $this->createTimerMock(); + + $this->loop + ->expects($this->once()) + ->method('addTimer') + ->with(5, $this->isInstanceOf('Closure')) + ->will($this->returnValue($timer)); + + $this->loop + ->expects($this->once()) + ->method('cancelTimer') + ->with($timer); + + $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); + $this->executor->query('8.8.8.8:53', $query); + } + + /** @test */ + public function resolveShouldCloseConnectionOnTimeout() + { + $this->executor = $this->createExecutorMock(); + $this->executor + ->expects($this->at(0)) + ->method('createConnection') + ->with('8.8.8.8:53', 'udp') + ->will($this->returnNewConnectionMock(false)); + + $timer = $this->createTimerMock(); + + $this->loop + ->expects($this->never()) + ->method('cancelTimer'); + + $this->loop + ->expects($this->once()) + ->method('addTimer') + ->with(5, $this->isInstanceOf('Closure')) + ->will($this->returnCallback(function ($time, $callback) use (&$timerCallback, $timer) { + $timerCallback = $callback; + return $timer; + })); + + $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); + $promise = $this->executor->query('8.8.8.8:53', $query); + + $this->assertNotNull($timerCallback); + $timerCallback(); + + $this->setExpectedException('React\Dns\Query\TimeoutException', 'DNS query for igor.io timed out'); + Block\await($promise, $this->loop); + } + + private function returnStandardResponse() + { + $that = $this; + $callback = function ($data) use ($that) { + $response = new Message(); + $that->convertMessageToStandardResponse($response); + return $response; + }; + + return $this->returnCallback($callback); + } + + private function returnTruncatedResponse() + { + $that = $this; + $callback = function ($data) use ($that) { + $response = new Message(); + $that->convertMessageToTruncatedResponse($response); + return $response; + }; + + return $this->returnCallback($callback); + } + + public function convertMessageToStandardResponse(Message $response) + { + $response->header->set('qr', 1); + $response->questions[] = new Record('igor.io', Message::TYPE_A, Message::CLASS_IN); + $response->answers[] = new Record('igor.io', Message::TYPE_A, Message::CLASS_IN, 3600, '178.79.169.131'); + $response->prepare(); + + return $response; + } + + public function convertMessageToTruncatedResponse(Message $response) + { + $this->convertMessageToStandardResponse($response); + $response->header->set('tc', 1); + $response->prepare(); + + return $response; + } + + private function returnNewConnectionMock($emitData = true) + { + $conn = $this->createConnectionMock($emitData); + + $callback = function () use ($conn) { + return $conn; + }; + + return $this->returnCallback($callback); + } + + private function createConnectionMock($emitData = true) + { + $conn = $this->getMockBuilder('React\Stream\DuplexStreamInterface')->getMock(); + $conn + ->expects($this->any()) + ->method('on') + ->with('data', $this->isInstanceOf('Closure')) + ->will($this->returnCallback(function ($name, $callback) use ($emitData) { + $emitData && $callback(null); + })); + + return $conn; + } + + private function createTimerMock() + { + return $this->getMockBuilder( + interface_exists('React\EventLoop\TimerInterface') ? 'React\EventLoop\TimerInterface' : 'React\EventLoop\Timer\TimerInterface' + )->getMock(); + } + + private function createExecutorMock() + { + return $this->getMockBuilder('React\Dns\Query\Executor') + ->setConstructorArgs(array($this->loop, $this->parser, $this->dumper)) + ->setMethods(array('createConnection')) + ->getMock(); + } +} diff --git a/assets/php/vendor/react/dns/tests/Query/HostsFileExecutorTest.php b/assets/php/vendor/react/dns/tests/Query/HostsFileExecutorTest.php new file mode 100644 index 0000000..70d877e --- /dev/null +++ b/assets/php/vendor/react/dns/tests/Query/HostsFileExecutorTest.php @@ -0,0 +1,126 @@ +<?php + +namespace React\Tests\Dns\Query; + +use React\Tests\Dns\TestCase; +use React\Dns\Query\HostsFileExecutor; +use React\Dns\Query\Query; +use React\Dns\Model\Message; + +class HostsFileExecutorTest extends TestCase +{ + private $hosts; + private $fallback; + private $executor; + + public function setUp() + { + $this->hosts = $this->getMockBuilder('React\Dns\Config\HostsFile')->disableOriginalConstructor()->getMock(); + $this->fallback = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock(); + $this->executor = new HostsFileExecutor($this->hosts, $this->fallback); + } + + public function testDoesNotTryToGetIpsForMxQuery() + { + $this->hosts->expects($this->never())->method('getIpsForHost'); + $this->fallback->expects($this->once())->method('query'); + + $this->executor->query('8.8.8.8', new Query('google.com', Message::TYPE_MX, Message::CLASS_IN, 0)); + } + + public function testFallsBackIfNoIpsWereFound() + { + $this->hosts->expects($this->once())->method('getIpsForHost')->willReturn(array()); + $this->fallback->expects($this->once())->method('query'); + + $this->executor->query('8.8.8.8', new Query('google.com', Message::TYPE_A, Message::CLASS_IN, 0)); + } + + public function testReturnsResponseMessageIfIpsWereFound() + { + $this->hosts->expects($this->once())->method('getIpsForHost')->willReturn(array('127.0.0.1')); + $this->fallback->expects($this->never())->method('query'); + + $ret = $this->executor->query('8.8.8.8', new Query('google.com', Message::TYPE_A, Message::CLASS_IN, 0)); + } + + public function testFallsBackIfNoIpv4Matches() + { + $this->hosts->expects($this->once())->method('getIpsForHost')->willReturn(array('::1')); + $this->fallback->expects($this->once())->method('query'); + + $ret = $this->executor->query('8.8.8.8', new Query('google.com', Message::TYPE_A, Message::CLASS_IN, 0)); + } + + public function testReturnsResponseMessageIfIpv6AddressesWereFound() + { + $this->hosts->expects($this->once())->method('getIpsForHost')->willReturn(array('::1')); + $this->fallback->expects($this->never())->method('query'); + + $ret = $this->executor->query('8.8.8.8', new Query('google.com', Message::TYPE_AAAA, Message::CLASS_IN, 0)); + } + + public function testFallsBackIfNoIpv6Matches() + { + $this->hosts->expects($this->once())->method('getIpsForHost')->willReturn(array('127.0.0.1')); + $this->fallback->expects($this->once())->method('query'); + + $ret = $this->executor->query('8.8.8.8', new Query('google.com', Message::TYPE_AAAA, Message::CLASS_IN, 0)); + } + + public function testDoesReturnReverseIpv4Lookup() + { + $this->hosts->expects($this->once())->method('getHostsForIp')->with('127.0.0.1')->willReturn(array('localhost')); + $this->fallback->expects($this->never())->method('query'); + + $this->executor->query('8.8.8.8', new Query('1.0.0.127.in-addr.arpa', Message::TYPE_PTR, Message::CLASS_IN, 0)); + } + + public function testFallsBackIfNoReverseIpv4Matches() + { + $this->hosts->expects($this->once())->method('getHostsForIp')->with('127.0.0.1')->willReturn(array()); + $this->fallback->expects($this->once())->method('query'); + + $this->executor->query('8.8.8.8', new Query('1.0.0.127.in-addr.arpa', Message::TYPE_PTR, Message::CLASS_IN, 0)); + } + + public function testDoesReturnReverseIpv6Lookup() + { + $this->hosts->expects($this->once())->method('getHostsForIp')->with('2a02:2e0:3fe:100::6')->willReturn(array('ip6-localhost')); + $this->fallback->expects($this->never())->method('query'); + + $this->executor->query('8.8.8.8', new Query('6.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.e.f.3.0.0.e.2.0.2.0.a.2.ip6.arpa', Message::TYPE_PTR, Message::CLASS_IN, 0)); + } + + public function testFallsBackForInvalidAddress() + { + $this->hosts->expects($this->never())->method('getHostsForIp'); + $this->fallback->expects($this->once())->method('query'); + + $this->executor->query('8.8.8.8', new Query('example.com', Message::TYPE_PTR, Message::CLASS_IN, 0)); + } + + public function testReverseFallsBackForInvalidIpv4Address() + { + $this->hosts->expects($this->never())->method('getHostsForIp'); + $this->fallback->expects($this->once())->method('query'); + + $this->executor->query('8.8.8.8', new Query('::1.in-addr.arpa', Message::TYPE_PTR, Message::CLASS_IN, 0)); + } + + public function testReverseFallsBackForInvalidLengthIpv6Address() + { + $this->hosts->expects($this->never())->method('getHostsForIp'); + $this->fallback->expects($this->once())->method('query'); + + $this->executor->query('8.8.8.8', new Query('abcd.ip6.arpa', Message::TYPE_PTR, Message::CLASS_IN, 0)); + } + + public function testReverseFallsBackForInvalidHexIpv6Address() + { + $this->hosts->expects($this->never())->method('getHostsForIp'); + $this->fallback->expects($this->once())->method('query'); + + $this->executor->query('8.8.8.8', new Query('zZz.ip6.arpa', Message::TYPE_PTR, Message::CLASS_IN, 0)); + } +} diff --git a/assets/php/vendor/react/dns/tests/Query/RecordBagTest.php b/assets/php/vendor/react/dns/tests/Query/RecordBagTest.php new file mode 100644 index 0000000..83b8934 --- /dev/null +++ b/assets/php/vendor/react/dns/tests/Query/RecordBagTest.php @@ -0,0 +1,64 @@ +<?php + +namespace React\Tests\Dns\Query; + +use PHPUnit\Framework\TestCase; +use React\Dns\Query\RecordBag; +use React\Dns\Model\Message; +use React\Dns\Model\Record; + +class RecordBagTest extends TestCase +{ + /** + * @covers React\Dns\Query\RecordBag + * @test + */ + public function emptyBagShouldBeEmpty() + { + $recordBag = new RecordBag(); + + $this->assertSame(array(), $recordBag->all()); + } + + /** + * @covers React\Dns\Query\RecordBag + * @test + */ + public function setShouldSetTheValue() + { + $currentTime = 1345656451; + + $recordBag = new RecordBag(); + $recordBag->set($currentTime, new Record('igor.io', Message::TYPE_A, Message::CLASS_IN, 3600)); + + $records = $recordBag->all(); + $this->assertCount(1, $records); + $this->assertSame('igor.io', $records[0]->name); + $this->assertSame(Message::TYPE_A, $records[0]->type); + $this->assertSame(Message::CLASS_IN, $records[0]->class); + } + + /** + * @covers React\Dns\Query\RecordBag + * @test + */ + public function setShouldSetManyValues() + { + $currentTime = 1345656451; + + $recordBag = new RecordBag(); + $recordBag->set($currentTime, new Record('igor.io', Message::TYPE_A, Message::CLASS_IN, 3600, '178.79.169.131')); + $recordBag->set($currentTime, new Record('igor.io', Message::TYPE_A, Message::CLASS_IN, 3600, '178.79.169.132')); + + $records = $recordBag->all(); + $this->assertCount(2, $records); + $this->assertSame('igor.io', $records[0]->name); + $this->assertSame(Message::TYPE_A, $records[0]->type); + $this->assertSame(Message::CLASS_IN, $records[0]->class); + $this->assertSame('178.79.169.131', $records[0]->data); + $this->assertSame('igor.io', $records[1]->name); + $this->assertSame(Message::TYPE_A, $records[1]->type); + $this->assertSame(Message::CLASS_IN, $records[1]->class); + $this->assertSame('178.79.169.132', $records[1]->data); + } +} diff --git a/assets/php/vendor/react/dns/tests/Query/RecordCacheTest.php b/assets/php/vendor/react/dns/tests/Query/RecordCacheTest.php new file mode 100644 index 0000000..399fbe8 --- /dev/null +++ b/assets/php/vendor/react/dns/tests/Query/RecordCacheTest.php @@ -0,0 +1,123 @@ +<?php + +namespace React\Tests\Dns\Query; + +use PHPUnit\Framework\TestCase; +use React\Cache\ArrayCache; +use React\Dns\Model\Message; +use React\Dns\Model\Record; +use React\Dns\Query\RecordCache; +use React\Dns\Query\Query; +use React\Promise\PromiseInterface; + +class RecordCacheTest extends TestCase +{ + /** + * @covers React\Dns\Query\RecordCache + * @test + */ + public function lookupOnEmptyCacheShouldReturnNull() + { + $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); + + $cache = new RecordCache(new ArrayCache()); + $promise = $cache->lookup($query); + + $this->assertInstanceOf('React\Promise\RejectedPromise', $promise); + } + + /** + * @covers React\Dns\Query\RecordCache + * @test + */ + public function storeRecordShouldMakeLookupSucceed() + { + $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); + + $cache = new RecordCache(new ArrayCache()); + $cache->storeRecord($query->currentTime, new Record('igor.io', Message::TYPE_A, Message::CLASS_IN, 3600, '178.79.169.131')); + $promise = $cache->lookup($query); + + $this->assertInstanceOf('React\Promise\FulfilledPromise', $promise); + $cachedRecords = $this->getPromiseValue($promise); + + $this->assertCount(1, $cachedRecords); + $this->assertSame('178.79.169.131', $cachedRecords[0]->data); + } + + /** + * @covers React\Dns\Query\RecordCache + * @test + */ + public function storeTwoRecordsShouldReturnBoth() + { + $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); + + $cache = new RecordCache(new ArrayCache()); + $cache->storeRecord($query->currentTime, new Record('igor.io', Message::TYPE_A, Message::CLASS_IN, 3600, '178.79.169.131')); + $cache->storeRecord($query->currentTime, new Record('igor.io', Message::TYPE_A, Message::CLASS_IN, 3600, '178.79.169.132')); + $promise = $cache->lookup($query); + + $this->assertInstanceOf('React\Promise\FulfilledPromise', $promise); + $cachedRecords = $this->getPromiseValue($promise); + + $this->assertCount(2, $cachedRecords); + $this->assertSame('178.79.169.131', $cachedRecords[0]->data); + $this->assertSame('178.79.169.132', $cachedRecords[1]->data); + } + + /** + * @covers React\Dns\Query\RecordCache + * @test + */ + public function storeResponseMessageShouldStoreAllAnswerValues() + { + $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); + + $response = new Message(); + $response->answers[] = new Record('igor.io', Message::TYPE_A, Message::CLASS_IN, 3600, '178.79.169.131'); + $response->answers[] = new Record('igor.io', Message::TYPE_A, Message::CLASS_IN, 3600, '178.79.169.132'); + $response->prepare(); + + $cache = new RecordCache(new ArrayCache()); + $cache->storeResponseMessage($query->currentTime, $response); + $promise = $cache->lookup($query); + + $this->assertInstanceOf('React\Promise\FulfilledPromise', $promise); + $cachedRecords = $this->getPromiseValue($promise); + + $this->assertCount(2, $cachedRecords); + $this->assertSame('178.79.169.131', $cachedRecords[0]->data); + $this->assertSame('178.79.169.132', $cachedRecords[1]->data); + } + + /** + * @covers React\Dns\Query\RecordCache + * @test + */ + public function expireShouldExpireDeadRecords() + { + $cachedTime = 1345656451; + $currentTime = $cachedTime + 3605; + + $cache = new RecordCache(new ArrayCache()); + $cache->storeRecord($cachedTime, new Record('igor.io', Message::TYPE_A, Message::CLASS_IN, 3600, '178.79.169.131')); + $cache->expire($currentTime); + + $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, $currentTime); + $promise = $cache->lookup($query); + + $this->assertInstanceOf('React\Promise\RejectedPromise', $promise); + } + + private function getPromiseValue(PromiseInterface $promise) + { + $capturedValue = null; + + $promise->then(function ($value) use (&$capturedValue) { + $capturedValue = $value; + }); + + return $capturedValue; + } +} diff --git a/assets/php/vendor/react/dns/tests/Query/RetryExecutorTest.php b/assets/php/vendor/react/dns/tests/Query/RetryExecutorTest.php new file mode 100644 index 0000000..8950f84 --- /dev/null +++ b/assets/php/vendor/react/dns/tests/Query/RetryExecutorTest.php @@ -0,0 +1,197 @@ +<?php + +namespace React\Tests\Dns\Query; + +use React\Tests\Dns\TestCase; +use React\Dns\Query\RetryExecutor; +use React\Dns\Query\Query; +use React\Dns\Model\Message; +use React\Dns\Query\TimeoutException; +use React\Dns\Model\Record; +use React\Promise; +use React\Promise\Deferred; +use React\Dns\Query\CancellationException; + +class RetryExecutorTest extends TestCase +{ + /** + * @covers React\Dns\Query\RetryExecutor + * @test + */ + public function queryShouldDelegateToDecoratedExecutor() + { + $executor = $this->createExecutorMock(); + $executor + ->expects($this->once()) + ->method('query') + ->with('8.8.8.8', $this->isInstanceOf('React\Dns\Query\Query')) + ->will($this->returnValue($this->expectPromiseOnce())); + + $retryExecutor = new RetryExecutor($executor, 2); + + $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); + $retryExecutor->query('8.8.8.8', $query); + } + + /** + * @covers React\Dns\Query\RetryExecutor + * @test + */ + public function queryShouldRetryQueryOnTimeout() + { + $response = $this->createStandardResponse(); + + $executor = $this->createExecutorMock(); + $executor + ->expects($this->exactly(2)) + ->method('query') + ->with('8.8.8.8', $this->isInstanceOf('React\Dns\Query\Query')) + ->will($this->onConsecutiveCalls( + $this->returnCallback(function ($domain, $query) { + return Promise\reject(new TimeoutException("timeout")); + }), + $this->returnCallback(function ($domain, $query) use ($response) { + return Promise\resolve($response); + }) + )); + + $callback = $this->createCallableMock(); + $callback + ->expects($this->once()) + ->method('__invoke') + ->with($this->isInstanceOf('React\Dns\Model\Message')); + + $errorback = $this->expectCallableNever(); + + $retryExecutor = new RetryExecutor($executor, 2); + + $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); + $retryExecutor->query('8.8.8.8', $query)->then($callback, $errorback); + } + + /** + * @covers React\Dns\Query\RetryExecutor + * @test + */ + public function queryShouldStopRetryingAfterSomeAttempts() + { + $executor = $this->createExecutorMock(); + $executor + ->expects($this->exactly(3)) + ->method('query') + ->with('8.8.8.8', $this->isInstanceOf('React\Dns\Query\Query')) + ->will($this->returnCallback(function ($domain, $query) { + return Promise\reject(new TimeoutException("timeout")); + })); + + $callback = $this->expectCallableNever(); + + $errorback = $this->createCallableMock(); + $errorback + ->expects($this->once()) + ->method('__invoke') + ->with($this->isInstanceOf('RuntimeException')); + + $retryExecutor = new RetryExecutor($executor, 2); + + $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); + $retryExecutor->query('8.8.8.8', $query)->then($callback, $errorback); + } + + /** + * @covers React\Dns\Query\RetryExecutor + * @test + */ + public function queryShouldForwardNonTimeoutErrors() + { + $executor = $this->createExecutorMock(); + $executor + ->expects($this->once()) + ->method('query') + ->with('8.8.8.8', $this->isInstanceOf('React\Dns\Query\Query')) + ->will($this->returnCallback(function ($domain, $query) { + return Promise\reject(new \Exception); + })); + + $callback = $this->expectCallableNever(); + + $errorback = $this->createCallableMock(); + $errorback + ->expects($this->once()) + ->method('__invoke') + ->with($this->isInstanceOf('Exception')); + + $retryExecutor = new RetryExecutor($executor, 2); + + $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); + $retryExecutor->query('8.8.8.8', $query)->then($callback, $errorback); + } + + /** + * @covers React\Dns\Query\RetryExecutor + * @test + */ + public function queryShouldCancelQueryOnCancel() + { + $cancelled = 0; + + $executor = $this->createExecutorMock(); + $executor + ->expects($this->once()) + ->method('query') + ->with('8.8.8.8', $this->isInstanceOf('React\Dns\Query\Query')) + ->will($this->returnCallback(function ($domain, $query) use (&$cancelled) { + $deferred = new Deferred(function ($resolve, $reject) use (&$cancelled) { + ++$cancelled; + $reject(new CancellationException('Cancelled')); + }); + + return $deferred->promise(); + }) + ); + + $retryExecutor = new RetryExecutor($executor, 2); + + $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); + $promise = $retryExecutor->query('8.8.8.8', $query); + + $promise->then($this->expectCallableNever(), $this->expectCallableOnce()); + + $this->assertEquals(0, $cancelled); + $promise->cancel(); + $this->assertEquals(1, $cancelled); + } + + protected function expectPromiseOnce($return = null) + { + $mock = $this->createPromiseMock(); + $mock + ->expects($this->once()) + ->method('then') + ->will($this->returnValue($return)); + + return $mock; + } + + protected function createExecutorMock() + { + return $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock(); + } + + protected function createPromiseMock() + { + return $this->getMockBuilder('React\Promise\PromiseInterface')->getMock(); + } + + protected function createStandardResponse() + { + $response = new Message(); + $response->header->set('qr', 1); + $response->questions[] = new Record('igor.io', Message::TYPE_A, Message::CLASS_IN); + $response->answers[] = new Record('igor.io', Message::TYPE_A, Message::CLASS_IN, 3600, '178.79.169.131'); + $response->prepare(); + + return $response; + } +} + diff --git a/assets/php/vendor/react/dns/tests/Query/TimeoutExecutorTest.php b/assets/php/vendor/react/dns/tests/Query/TimeoutExecutorTest.php new file mode 100644 index 0000000..0d37fb4 --- /dev/null +++ b/assets/php/vendor/react/dns/tests/Query/TimeoutExecutorTest.php @@ -0,0 +1,115 @@ +<?php + +namespace React\Tests\Dns\Query; + +use React\Dns\Query\TimeoutExecutor; +use React\Dns\Query\Query; +use React\Dns\Model\Message; +use React\Promise\Deferred; +use React\Dns\Query\CancellationException; +use React\Tests\Dns\TestCase; +use React\EventLoop\Factory; +use React\Promise; + +class TimeoutExecutorTest extends TestCase +{ + public function setUp() + { + $this->loop = Factory::create(); + + $this->wrapped = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock(); + + $this->executor = new TimeoutExecutor($this->wrapped, 5.0, $this->loop); + } + + public function testCancellingPromiseWillCancelWrapped() + { + $cancelled = 0; + + $this->wrapped + ->expects($this->once()) + ->method('query') + ->will($this->returnCallback(function ($domain, $query) use (&$cancelled) { + $deferred = new Deferred(function ($resolve, $reject) use (&$cancelled) { + ++$cancelled; + $reject(new CancellationException('Cancelled')); + }); + + return $deferred->promise(); + })); + + $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); + $promise = $this->executor->query('8.8.8.8:53', $query); + + $this->assertEquals(0, $cancelled); + $promise->cancel(); + $this->assertEquals(1, $cancelled); + + $promise->then($this->expectCallableNever(), $this->expectCallableOnce()); + } + + public function testResolvesPromiseWhenWrappedResolves() + { + $this->wrapped + ->expects($this->once()) + ->method('query') + ->willReturn(Promise\resolve('0.0.0.0')); + + $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); + $promise = $this->executor->query('8.8.8.8:53', $query); + + $promise->then($this->expectCallableOnce(), $this->expectCallableNever()); + } + + public function testRejectsPromiseWhenWrappedRejects() + { + $this->wrapped + ->expects($this->once()) + ->method('query') + ->willReturn(Promise\reject(new \RuntimeException())); + + $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); + $promise = $this->executor->query('8.8.8.8:53', $query); + + $promise->then($this->expectCallableNever(), $this->expectCallableOnceWith(new \RuntimeException())); + } + + public function testWrappedWillBeCancelledOnTimeout() + { + $this->executor = new TimeoutExecutor($this->wrapped, 0, $this->loop); + + $cancelled = 0; + + $this->wrapped + ->expects($this->once()) + ->method('query') + ->will($this->returnCallback(function ($domain, $query) use (&$cancelled) { + $deferred = new Deferred(function ($resolve, $reject) use (&$cancelled) { + ++$cancelled; + $reject(new CancellationException('Cancelled')); + }); + + return $deferred->promise(); + })); + + $callback = $this->expectCallableNever(); + + $errorback = $this->createCallableMock(); + $errorback + ->expects($this->once()) + ->method('__invoke') + ->with($this->logicalAnd( + $this->isInstanceOf('React\Dns\Query\TimeoutException'), + $this->attribute($this->equalTo('DNS query for igor.io timed out'), 'message') + )); + + $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); + $this->executor->query('8.8.8.8:53', $query)->then($callback, $errorback); + + $this->assertEquals(0, $cancelled); + + $this->loop->run(); + + $this->assertEquals(1, $cancelled); + } +} |