init
This commit is contained in:
100
vendor/react/dns/tests/Query/CachedExecutorTest.php
vendored
Executable file
100
vendor/react/dns/tests/Query/CachedExecutorTest.php
vendored
Executable file
@@ -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();
|
||||
}
|
||||
}
|
||||
183
vendor/react/dns/tests/Query/CachingExecutorTest.php
vendored
Executable file
183
vendor/react/dns/tests/Query/CachingExecutorTest.php
vendored
Executable file
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Dns\Query;
|
||||
|
||||
use React\Dns\Model\Message;
|
||||
use React\Dns\Query\CachingExecutor;
|
||||
use React\Dns\Query\Query;
|
||||
use React\Promise\Promise;
|
||||
use React\Tests\Dns\TestCase;
|
||||
use React\Promise\Deferred;
|
||||
use React\Dns\Model\Record;
|
||||
|
||||
class CachingExecutorTest extends TestCase
|
||||
{
|
||||
public function testQueryWillReturnPendingPromiseWhenCacheIsPendingWithoutSendingQueryToFallbackExecutor()
|
||||
{
|
||||
$fallback = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
|
||||
$fallback->expects($this->never())->method('query');
|
||||
|
||||
$cache = $this->getMockBuilder('React\Cache\CacheInterface')->getMock();
|
||||
$cache->expects($this->once())->method('get')->with('reactphp.org:1:1')->willReturn(new Promise(function () { }));
|
||||
|
||||
$executor = new CachingExecutor($fallback, $cache);
|
||||
|
||||
$query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
|
||||
|
||||
$promise = $executor->query('8.8.8.8', $query);
|
||||
|
||||
$promise->then($this->expectCallableNever(), $this->expectCallableNever());
|
||||
}
|
||||
|
||||
public function testQueryWillReturnPendingPromiseWhenCacheReturnsMissAndWillSendSameQueryToFallbackExecutor()
|
||||
{
|
||||
$query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
|
||||
|
||||
$fallback = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
|
||||
$fallback->expects($this->once())->method('query')->with('8.8.8.8', $query)->willReturn(new Promise(function () { }));
|
||||
|
||||
$cache = $this->getMockBuilder('React\Cache\CacheInterface')->getMock();
|
||||
$cache->expects($this->once())->method('get')->willReturn(\React\Promise\resolve(null));
|
||||
|
||||
$executor = new CachingExecutor($fallback, $cache);
|
||||
|
||||
$promise = $executor->query('8.8.8.8', $query);
|
||||
|
||||
$promise->then($this->expectCallableNever(), $this->expectCallableNever());
|
||||
}
|
||||
|
||||
public function testQueryWillReturnResolvedPromiseWhenCacheReturnsHitWithoutSendingQueryToFallbackExecutor()
|
||||
{
|
||||
$fallback = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
|
||||
$fallback->expects($this->never())->method('query');
|
||||
|
||||
$message = new Message();
|
||||
$cache = $this->getMockBuilder('React\Cache\CacheInterface')->getMock();
|
||||
$cache->expects($this->once())->method('get')->with('reactphp.org:1:1')->willReturn(\React\Promise\resolve($message));
|
||||
|
||||
$executor = new CachingExecutor($fallback, $cache);
|
||||
|
||||
$query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
|
||||
|
||||
$promise = $executor->query('8.8.8.8', $query);
|
||||
|
||||
$promise->then($this->expectCallableOnceWith($message), $this->expectCallableNever());
|
||||
}
|
||||
|
||||
public function testQueryWillReturnResolvedPromiseWhenCacheReturnsMissAndFallbackExecutorResolvesAndSaveMessageToCacheWithMinimumTtlFromRecord()
|
||||
{
|
||||
$message = new Message();
|
||||
$message->answers[] = new Record('reactphp.org', Message::TYPE_A, Message::CLASS_IN, 3700, '127.0.0.1');
|
||||
$message->answers[] = new Record('reactphp.org', Message::TYPE_A, Message::CLASS_IN, 3600, '127.0.0.1');
|
||||
$fallback = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
|
||||
$fallback->expects($this->once())->method('query')->willReturn(\React\Promise\resolve($message));
|
||||
|
||||
$cache = $this->getMockBuilder('React\Cache\CacheInterface')->getMock();
|
||||
$cache->expects($this->once())->method('get')->with('reactphp.org:1:1')->willReturn(\React\Promise\resolve(null));
|
||||
$cache->expects($this->once())->method('set')->with('reactphp.org:1:1', $message, 3600);
|
||||
|
||||
$executor = new CachingExecutor($fallback, $cache);
|
||||
|
||||
$query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
|
||||
|
||||
$promise = $executor->query('8.8.8.8', $query);
|
||||
|
||||
$promise->then($this->expectCallableOnceWith($message), $this->expectCallableNever());
|
||||
}
|
||||
|
||||
public function testQueryWillReturnResolvedPromiseWhenCacheReturnsMissAndFallbackExecutorResolvesAndSaveMessageToCacheWithDefaultTtl()
|
||||
{
|
||||
$message = new Message();
|
||||
$fallback = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
|
||||
$fallback->expects($this->once())->method('query')->willReturn(\React\Promise\resolve($message));
|
||||
|
||||
$cache = $this->getMockBuilder('React\Cache\CacheInterface')->getMock();
|
||||
$cache->expects($this->once())->method('get')->with('reactphp.org:1:1')->willReturn(\React\Promise\resolve(null));
|
||||
$cache->expects($this->once())->method('set')->with('reactphp.org:1:1', $message, 60);
|
||||
|
||||
$executor = new CachingExecutor($fallback, $cache);
|
||||
|
||||
$query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
|
||||
|
||||
$promise = $executor->query('8.8.8.8', $query);
|
||||
|
||||
$promise->then($this->expectCallableOnceWith($message), $this->expectCallableNever());
|
||||
}
|
||||
|
||||
public function testQueryWillReturnResolvedPromiseWhenCacheReturnsMissAndFallbackExecutorResolvesWithTruncatedResponseButShouldNotSaveTruncatedMessageToCache()
|
||||
{
|
||||
$message = new Message();
|
||||
$message->header->set('tc', 1);
|
||||
$fallback = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
|
||||
$fallback->expects($this->once())->method('query')->willReturn(\React\Promise\resolve($message));
|
||||
|
||||
$cache = $this->getMockBuilder('React\Cache\CacheInterface')->getMock();
|
||||
$cache->expects($this->once())->method('get')->with('reactphp.org:1:1')->willReturn(\React\Promise\resolve(null));
|
||||
$cache->expects($this->never())->method('set');
|
||||
|
||||
$executor = new CachingExecutor($fallback, $cache);
|
||||
|
||||
$query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
|
||||
|
||||
$promise = $executor->query('8.8.8.8', $query);
|
||||
|
||||
$promise->then($this->expectCallableOnceWith($message), $this->expectCallableNever());
|
||||
}
|
||||
|
||||
public function testQueryWillReturnRejectedPromiseWhenCacheReturnsMissAndFallbackExecutorRejects()
|
||||
{
|
||||
$query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
|
||||
|
||||
$fallback = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
|
||||
$fallback->expects($this->once())->method('query')->willReturn(\React\Promise\reject(new \RuntimeException()));
|
||||
|
||||
$cache = $this->getMockBuilder('React\Cache\CacheInterface')->getMock();
|
||||
$cache->expects($this->once())->method('get')->willReturn(\React\Promise\resolve(null));
|
||||
|
||||
$executor = new CachingExecutor($fallback, $cache);
|
||||
|
||||
$promise = $executor->query('8.8.8.8', $query);
|
||||
|
||||
$promise->then($this->expectCallableNever(), $this->expectCallableOnceWith($this->isInstanceOf('RuntimeException')));
|
||||
}
|
||||
|
||||
public function testCancelQueryWillReturnRejectedPromiseAndCancelPendingPromiseFromCache()
|
||||
{
|
||||
$fallback = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
|
||||
$fallback->expects($this->never())->method('query');
|
||||
|
||||
$pending = new Promise(function () { }, $this->expectCallableOnce());
|
||||
$cache = $this->getMockBuilder('React\Cache\CacheInterface')->getMock();
|
||||
$cache->expects($this->once())->method('get')->with('reactphp.org:1:1')->willReturn($pending);
|
||||
|
||||
$executor = new CachingExecutor($fallback, $cache);
|
||||
|
||||
$query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
|
||||
|
||||
$promise = $executor->query('8.8.8.8', $query);
|
||||
$promise->cancel();
|
||||
|
||||
$promise->then($this->expectCallableNever(), $this->expectCallableOnceWith($this->isInstanceOf('RuntimeException')));
|
||||
}
|
||||
|
||||
public function testCancelQueryWillReturnRejectedPromiseAndCancelPendingPromiseFromFallbackExecutorWhenCacheReturnsMiss()
|
||||
{
|
||||
$pending = new Promise(function () { }, $this->expectCallableOnce());
|
||||
$fallback = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
|
||||
$fallback->expects($this->once())->method('query')->willReturn($pending);
|
||||
|
||||
$deferred = new Deferred();
|
||||
$cache = $this->getMockBuilder('React\Cache\CacheInterface')->getMock();
|
||||
$cache->expects($this->once())->method('get')->with('reactphp.org:1:1')->willReturn($deferred->promise());
|
||||
|
||||
$executor = new CachingExecutor($fallback, $cache);
|
||||
|
||||
$query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
|
||||
|
||||
$promise = $executor->query('8.8.8.8', $query);
|
||||
$deferred->resolve(null);
|
||||
$promise->cancel();
|
||||
|
||||
$promise->then($this->expectCallableNever(), $this->expectCallableOnceWith($this->isInstanceOf('RuntimeException')));
|
||||
}
|
||||
}
|
||||
233
vendor/react/dns/tests/Query/CoopExecutorTest.php
vendored
Executable file
233
vendor/react/dns/tests/Query/CoopExecutorTest.php
vendored
Executable file
@@ -0,0 +1,233 @@
|
||||
<?php
|
||||
|
||||
use React\Dns\Query\CoopExecutor;
|
||||
use React\Dns\Model\Message;
|
||||
use React\Dns\Query\Query;
|
||||
use React\Promise\Promise;
|
||||
use React\Tests\Dns\TestCase;
|
||||
use React\Promise\Deferred;
|
||||
|
||||
class CoopExecutorTest extends TestCase
|
||||
{
|
||||
public function testQueryOnceWillPassExactQueryToBaseExecutor()
|
||||
{
|
||||
$pending = new Promise(function () { });
|
||||
$query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
|
||||
$base = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
|
||||
$base->expects($this->once())->method('query')->with('8.8.8.8', $query)->willReturn($pending);
|
||||
$connector = new CoopExecutor($base);
|
||||
|
||||
$connector->query('8.8.8.8', $query);
|
||||
}
|
||||
|
||||
public function testQueryOnceWillResolveWhenBaseExecutorResolves()
|
||||
{
|
||||
$message = new Message();
|
||||
|
||||
$base = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
|
||||
$base->expects($this->once())->method('query')->willReturn(\React\Promise\resolve($message));
|
||||
$connector = new CoopExecutor($base);
|
||||
|
||||
$query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
|
||||
$promise = $connector->query('8.8.8.8', $query);
|
||||
|
||||
$this->assertInstanceOf('React\Promise\PromiseInterface', $promise);
|
||||
|
||||
$promise->then($this->expectCallableOnceWith($message));
|
||||
}
|
||||
|
||||
public function testQueryOnceWillRejectWhenBaseExecutorRejects()
|
||||
{
|
||||
$exception = new RuntimeException();
|
||||
|
||||
$base = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
|
||||
$base->expects($this->once())->method('query')->willReturn(\React\Promise\reject($exception));
|
||||
$connector = new CoopExecutor($base);
|
||||
|
||||
$query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
|
||||
$promise = $connector->query('8.8.8.8', $query);
|
||||
|
||||
$this->assertInstanceOf('React\Promise\PromiseInterface', $promise);
|
||||
|
||||
$promise->then(null, $this->expectCallableOnceWith($exception));
|
||||
}
|
||||
|
||||
public function testQueryTwoDifferentQueriesWillPassExactQueryToBaseExecutorTwice()
|
||||
{
|
||||
$pending = new Promise(function () { });
|
||||
$query1 = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
|
||||
$query2 = new Query('reactphp.org', Message::TYPE_AAAA, Message::CLASS_IN);
|
||||
$base = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
|
||||
$base->expects($this->exactly(2))->method('query')->withConsecutive(
|
||||
array('8.8.8.8', $query1),
|
||||
array('8.8.8.8', $query2)
|
||||
)->willReturn($pending);
|
||||
$connector = new CoopExecutor($base);
|
||||
|
||||
$connector->query('8.8.8.8', $query1);
|
||||
$connector->query('8.8.8.8', $query2);
|
||||
}
|
||||
|
||||
public function testQueryTwiceWillPassExactQueryToBaseExecutorOnceWhenQueryIsStillPending()
|
||||
{
|
||||
$pending = new Promise(function () { });
|
||||
$query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
|
||||
$base = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
|
||||
$base->expects($this->once())->method('query')->with('8.8.8.8', $query)->willReturn($pending);
|
||||
$connector = new CoopExecutor($base);
|
||||
|
||||
$connector->query('8.8.8.8', $query);
|
||||
$connector->query('8.8.8.8', $query);
|
||||
}
|
||||
|
||||
public function testQueryTwiceWillPassExactQueryToBaseExecutorTwiceWhenFirstQueryIsAlreadyResolved()
|
||||
{
|
||||
$deferred = new Deferred();
|
||||
$pending = new Promise(function () { });
|
||||
$query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
|
||||
$base = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
|
||||
$base->expects($this->exactly(2))->method('query')->with('8.8.8.8', $query)->willReturnOnConsecutiveCalls($deferred->promise(), $pending);
|
||||
|
||||
$connector = new CoopExecutor($base);
|
||||
|
||||
$connector->query('8.8.8.8', $query);
|
||||
|
||||
$deferred->resolve(new Message());
|
||||
|
||||
$connector->query('8.8.8.8', $query);
|
||||
}
|
||||
|
||||
public function testQueryTwiceWillPassExactQueryToBaseExecutorTwiceWhenFirstQueryIsAlreadyRejected()
|
||||
{
|
||||
$deferred = new Deferred();
|
||||
$pending = new Promise(function () { });
|
||||
$query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
|
||||
$base = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
|
||||
$base->expects($this->exactly(2))->method('query')->with('8.8.8.8', $query)->willReturnOnConsecutiveCalls($deferred->promise(), $pending);
|
||||
|
||||
$connector = new CoopExecutor($base);
|
||||
|
||||
$connector->query('8.8.8.8', $query);
|
||||
|
||||
$deferred->reject(new RuntimeException());
|
||||
|
||||
$connector->query('8.8.8.8', $query);
|
||||
}
|
||||
|
||||
public function testCancelQueryWillCancelPromiseFromBaseExecutorAndReject()
|
||||
{
|
||||
$promise = new Promise(function () { }, $this->expectCallableOnce());
|
||||
|
||||
$base = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
|
||||
$base->expects($this->once())->method('query')->willReturn($promise);
|
||||
$connector = new CoopExecutor($base);
|
||||
|
||||
$query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
|
||||
$promise = $connector->query('8.8.8.8', $query);
|
||||
|
||||
$promise->cancel();
|
||||
|
||||
$promise->then(null, $this->expectCallableOnce());
|
||||
}
|
||||
|
||||
public function testCancelOneQueryWhenOtherQueryIsStillPendingWillNotCancelPromiseFromBaseExecutorAndRejectCancelled()
|
||||
{
|
||||
$promise = new Promise(function () { }, $this->expectCallableNever());
|
||||
|
||||
$base = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
|
||||
$base->expects($this->once())->method('query')->willReturn($promise);
|
||||
$connector = new CoopExecutor($base);
|
||||
|
||||
$query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
|
||||
$promise1 = $connector->query('8.8.8.8', $query);
|
||||
$promise2 = $connector->query('8.8.8.8', $query);
|
||||
|
||||
$promise1->cancel();
|
||||
|
||||
$promise1->then(null, $this->expectCallableOnce());
|
||||
$promise2->then(null, $this->expectCallableNever());
|
||||
}
|
||||
|
||||
public function testCancelSecondQueryWhenFirstQueryIsStillPendingWillNotCancelPromiseFromBaseExecutorAndRejectCancelled()
|
||||
{
|
||||
$promise = new Promise(function () { }, $this->expectCallableNever());
|
||||
|
||||
$base = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
|
||||
$base->expects($this->once())->method('query')->willReturn($promise);
|
||||
$connector = new CoopExecutor($base);
|
||||
|
||||
$query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
|
||||
$promise1 = $connector->query('8.8.8.8', $query);
|
||||
$promise2 = $connector->query('8.8.8.8', $query);
|
||||
|
||||
$promise2->cancel();
|
||||
|
||||
$promise2->then(null, $this->expectCallableOnce());
|
||||
$promise1->then(null, $this->expectCallableNever());
|
||||
}
|
||||
|
||||
public function testCancelAllPendingQueriesWillCancelPromiseFromBaseExecutorAndRejectCancelled()
|
||||
{
|
||||
$promise = new Promise(function () { }, $this->expectCallableOnce());
|
||||
|
||||
$base = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
|
||||
$base->expects($this->once())->method('query')->willReturn($promise);
|
||||
$connector = new CoopExecutor($base);
|
||||
|
||||
$query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
|
||||
$promise1 = $connector->query('8.8.8.8', $query);
|
||||
$promise2 = $connector->query('8.8.8.8', $query);
|
||||
|
||||
$promise1->cancel();
|
||||
$promise2->cancel();
|
||||
|
||||
$promise1->then(null, $this->expectCallableOnce());
|
||||
$promise2->then(null, $this->expectCallableOnce());
|
||||
}
|
||||
|
||||
public function testQueryTwiceWillQueryBaseExecutorTwiceIfFirstQueryHasAlreadyBeenCancelledWhenSecondIsStarted()
|
||||
{
|
||||
$promise = new Promise(function () { }, $this->expectCallableOnce());
|
||||
$pending = new Promise(function () { });
|
||||
|
||||
$base = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
|
||||
$base->expects($this->exactly(2))->method('query')->willReturnOnConsecutiveCalls($promise, $pending);
|
||||
$connector = new CoopExecutor($base);
|
||||
|
||||
$query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
|
||||
|
||||
$promise1 = $connector->query('8.8.8.8', $query);
|
||||
$promise1->cancel();
|
||||
|
||||
$promise2 = $connector->query('8.8.8.8', $query);
|
||||
|
||||
$promise1->then(null, $this->expectCallableOnce());
|
||||
|
||||
$promise2->then(null, $this->expectCallableNever());
|
||||
}
|
||||
|
||||
public function testCancelQueryShouldNotCauseGarbageReferences()
|
||||
{
|
||||
if (class_exists('React\Promise\When')) {
|
||||
$this->markTestSkipped('Not supported on legacy Promise v1 API');
|
||||
}
|
||||
|
||||
$deferred = new Deferred(function () {
|
||||
throw new \RuntimeException();
|
||||
});
|
||||
|
||||
$base = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
|
||||
$base->expects($this->once())->method('query')->willReturn($deferred->promise());
|
||||
$connector = new CoopExecutor($base);
|
||||
|
||||
gc_collect_cycles();
|
||||
|
||||
$query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
|
||||
|
||||
$promise = $connector->query('8.8.8.8', $query);
|
||||
$promise->cancel();
|
||||
$promise = null;
|
||||
|
||||
$this->assertEquals(0, gc_collect_cycles());
|
||||
}
|
||||
}
|
||||
308
vendor/react/dns/tests/Query/ExecutorTest.php
vendored
Executable file
308
vendor/react/dns/tests/Query/ExecutorTest.php
vendored
Executable file
@@ -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();
|
||||
}
|
||||
}
|
||||
126
vendor/react/dns/tests/Query/HostsFileExecutorTest.php
vendored
Executable file
126
vendor/react/dns/tests/Query/HostsFileExecutorTest.php
vendored
Executable file
@@ -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));
|
||||
}
|
||||
}
|
||||
83
vendor/react/dns/tests/Query/RecordBagTest.php
vendored
Executable file
83
vendor/react/dns/tests/Query/RecordBagTest.php
vendored
Executable file
@@ -0,0 +1,83 @@
|
||||
<?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 setShouldAcceptMxRecord()
|
||||
{
|
||||
$currentTime = 1345656451;
|
||||
|
||||
$recordBag = new RecordBag();
|
||||
$recordBag->set($currentTime, new Record('igor.io', Message::TYPE_MX, Message::CLASS_IN, 3600, array('priority' => 10, 'target' => 'igor.io')));
|
||||
|
||||
$records = $recordBag->all();
|
||||
$this->assertCount(1, $records);
|
||||
$this->assertSame('igor.io', $records[0]->name);
|
||||
$this->assertSame(Message::TYPE_MX, $records[0]->type);
|
||||
$this->assertSame(Message::CLASS_IN, $records[0]->class);
|
||||
$this->assertSame(array('priority' => 10, 'target' => 'igor.io'), $records[0]->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
160
vendor/react/dns/tests/Query/RecordCacheTest.php
vendored
Executable file
160
vendor/react/dns/tests/Query/RecordCacheTest.php
vendored
Executable file
@@ -0,0 +1,160 @@
|
||||
<?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;
|
||||
use React\Promise\Promise;
|
||||
|
||||
class RecordCacheTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers React\Dns\Query\RecordCache
|
||||
* @test
|
||||
*/
|
||||
public function lookupOnCacheMissShouldReturnNull()
|
||||
{
|
||||
$query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451);
|
||||
|
||||
$base = $this->getMockBuilder('React\Cache\CacheInterface')->getMock();
|
||||
$base->expects($this->once())->method('get')->willReturn(\React\Promise\resolve(null));
|
||||
|
||||
$cache = new RecordCache($base);
|
||||
$promise = $cache->lookup($query);
|
||||
|
||||
$this->assertInstanceOf('React\Promise\RejectedPromise', $promise);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Dns\Query\RecordCache
|
||||
* @test
|
||||
*/
|
||||
public function storeRecordPendingCacheDoesNotSetCache()
|
||||
{
|
||||
$query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451);
|
||||
$pending = new Promise(function () { });
|
||||
|
||||
$base = $this->getMockBuilder('React\Cache\CacheInterface')->getMock();
|
||||
$base->expects($this->once())->method('get')->willReturn($pending);
|
||||
$base->expects($this->never())->method('set');
|
||||
|
||||
$cache = new RecordCache($base);
|
||||
$cache->storeRecord($query->currentTime, new Record('igor.io', Message::TYPE_A, Message::CLASS_IN, 3600, '178.79.169.131'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Dns\Query\RecordCache
|
||||
* @test
|
||||
*/
|
||||
public function storeRecordOnCacheMissSetsCache()
|
||||
{
|
||||
$query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451);
|
||||
|
||||
$base = $this->getMockBuilder('React\Cache\CacheInterface')->getMock();
|
||||
$base->expects($this->once())->method('get')->willReturn(\React\Promise\resolve(null));
|
||||
$base->expects($this->once())->method('set')->with($this->isType('string'), $this->isType('string'));
|
||||
|
||||
$cache = new RecordCache($base);
|
||||
$cache->storeRecord($query->currentTime, new Record('igor.io', Message::TYPE_A, Message::CLASS_IN, 3600, '178.79.169.131'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
350
vendor/react/dns/tests/Query/RetryExecutorTest.php
vendored
Executable file
350
vendor/react/dns/tests/Query/RetryExecutorTest.php
vendored
Executable file
@@ -0,0 +1,350 @@
|
||||
<?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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Dns\Query\RetryExecutor
|
||||
* @test
|
||||
*/
|
||||
public function queryShouldCancelSecondQueryOnCancel()
|
||||
{
|
||||
$deferred = new Deferred();
|
||||
$cancelled = 0;
|
||||
|
||||
$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->returnValue($deferred->promise()),
|
||||
$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());
|
||||
|
||||
// first query will time out after a while and this sends the next query
|
||||
$deferred->reject(new TimeoutException());
|
||||
|
||||
$this->assertEquals(0, $cancelled);
|
||||
$promise->cancel();
|
||||
$this->assertEquals(1, $cancelled);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Dns\Query\RetryExecutor
|
||||
* @test
|
||||
*/
|
||||
public function queryShouldNotCauseGarbageReferencesOnSuccess()
|
||||
{
|
||||
if (class_exists('React\Promise\When')) {
|
||||
$this->markTestSkipped('Not supported on legacy Promise v1 API');
|
||||
}
|
||||
|
||||
$executor = $this->createExecutorMock();
|
||||
$executor
|
||||
->expects($this->once())
|
||||
->method('query')
|
||||
->with('8.8.8.8', $this->isInstanceOf('React\Dns\Query\Query'))
|
||||
->willReturn(Promise\resolve($this->createStandardResponse()));
|
||||
|
||||
$retryExecutor = new RetryExecutor($executor, 0);
|
||||
|
||||
gc_collect_cycles();
|
||||
$query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451);
|
||||
$retryExecutor->query('8.8.8.8', $query);
|
||||
|
||||
$this->assertEquals(0, gc_collect_cycles());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Dns\Query\RetryExecutor
|
||||
* @test
|
||||
*/
|
||||
public function queryShouldNotCauseGarbageReferencesOnTimeoutErrors()
|
||||
{
|
||||
if (class_exists('React\Promise\When')) {
|
||||
$this->markTestSkipped('Not supported on legacy Promise v1 API');
|
||||
}
|
||||
|
||||
$executor = $this->createExecutorMock();
|
||||
$executor
|
||||
->expects($this->any())
|
||||
->method('query')
|
||||
->with('8.8.8.8', $this->isInstanceOf('React\Dns\Query\Query'))
|
||||
->willReturn(Promise\reject(new TimeoutException("timeout")));
|
||||
|
||||
$retryExecutor = new RetryExecutor($executor, 0);
|
||||
|
||||
gc_collect_cycles();
|
||||
$query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451);
|
||||
$retryExecutor->query('8.8.8.8', $query);
|
||||
|
||||
$this->assertEquals(0, gc_collect_cycles());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Dns\Query\RetryExecutor
|
||||
* @test
|
||||
*/
|
||||
public function queryShouldNotCauseGarbageReferencesOnCancellation()
|
||||
{
|
||||
if (class_exists('React\Promise\When')) {
|
||||
$this->markTestSkipped('Not supported on legacy Promise v1 API');
|
||||
}
|
||||
|
||||
$deferred = new Deferred(function () {
|
||||
throw new \RuntimeException();
|
||||
});
|
||||
|
||||
$executor = $this->createExecutorMock();
|
||||
$executor
|
||||
->expects($this->once())
|
||||
->method('query')
|
||||
->with('8.8.8.8', $this->isInstanceOf('React\Dns\Query\Query'))
|
||||
->willReturn($deferred->promise());
|
||||
|
||||
$retryExecutor = new RetryExecutor($executor, 0);
|
||||
|
||||
gc_collect_cycles();
|
||||
$query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451);
|
||||
$promise = $retryExecutor->query('8.8.8.8', $query);
|
||||
$promise->cancel();
|
||||
$promise = null;
|
||||
|
||||
$this->assertEquals(0, gc_collect_cycles());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Dns\Query\RetryExecutor
|
||||
* @test
|
||||
*/
|
||||
public function queryShouldNotCauseGarbageReferencesOnNonTimeoutErrors()
|
||||
{
|
||||
if (class_exists('React\Promise\When')) {
|
||||
$this->markTestSkipped('Not supported on legacy Promise v1 API');
|
||||
}
|
||||
|
||||
$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);
|
||||
}));
|
||||
|
||||
$retryExecutor = new RetryExecutor($executor, 2);
|
||||
|
||||
gc_collect_cycles();
|
||||
$query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451);
|
||||
$retryExecutor->query('8.8.8.8', $query);
|
||||
|
||||
$this->assertEquals(0, gc_collect_cycles());
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
115
vendor/react/dns/tests/Query/TimeoutExecutorTest.php
vendored
Executable file
115
vendor/react/dns/tests/Query/TimeoutExecutorTest.php
vendored
Executable file
@@ -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);
|
||||
}
|
||||
}
|
||||
215
vendor/react/dns/tests/Query/UdpTransportExecutorTest.php
vendored
Executable file
215
vendor/react/dns/tests/Query/UdpTransportExecutorTest.php
vendored
Executable file
@@ -0,0 +1,215 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Dns\Query;
|
||||
|
||||
use React\Dns\Model\Message;
|
||||
use React\Dns\Protocol\BinaryDumper;
|
||||
use React\Dns\Protocol\Parser;
|
||||
use React\Dns\Query\Query;
|
||||
use React\Dns\Query\UdpTransportExecutor;
|
||||
use React\EventLoop\Factory;
|
||||
use React\Tests\Dns\TestCase;
|
||||
|
||||
class UdpTransportExecutorTest extends TestCase
|
||||
{
|
||||
public function testQueryRejectsIfMessageExceedsUdpSize()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$loop->expects($this->never())->method('addReadStream');
|
||||
|
||||
$dumper = $this->getMockBuilder('React\Dns\Protocol\BinaryDumper')->getMock();
|
||||
$dumper->expects($this->once())->method('toBinary')->willReturn(str_repeat('.', 513));
|
||||
|
||||
$executor = new UdpTransportExecutor($loop, null, $dumper);
|
||||
|
||||
$query = new Query('google.com', Message::TYPE_A, Message::CLASS_IN);
|
||||
$promise = $executor->query('8.8.8.8:53', $query);
|
||||
|
||||
$this->assertInstanceOf('React\Promise\PromiseInterface', $promise);
|
||||
$promise->then(null, $this->expectCallableOnce());
|
||||
}
|
||||
|
||||
public function testQueryRejectsIfServerConnectionFails()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$loop->expects($this->never())->method('addReadStream');
|
||||
|
||||
$executor = new UdpTransportExecutor($loop);
|
||||
|
||||
$query = new Query('google.com', Message::TYPE_A, Message::CLASS_IN);
|
||||
$promise = $executor->query('///', $query);
|
||||
|
||||
$this->assertInstanceOf('React\Promise\PromiseInterface', $promise);
|
||||
$promise->then(null, $this->expectCallableOnce());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group internet
|
||||
*/
|
||||
public function testQueryRejectsOnCancellation()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$loop->expects($this->once())->method('addReadStream');
|
||||
$loop->expects($this->once())->method('removeReadStream');
|
||||
|
||||
$executor = new UdpTransportExecutor($loop);
|
||||
|
||||
$query = new Query('google.com', Message::TYPE_A, Message::CLASS_IN);
|
||||
$promise = $executor->query('8.8.8.8:53', $query);
|
||||
$promise->cancel();
|
||||
|
||||
$this->assertInstanceOf('React\Promise\PromiseInterface', $promise);
|
||||
$promise->then(null, $this->expectCallableOnce());
|
||||
}
|
||||
|
||||
public function testQueryKeepsPendingIfServerRejectsNetworkPacket()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$executor = new UdpTransportExecutor($loop);
|
||||
|
||||
$query = new Query('google.com', Message::TYPE_A, Message::CLASS_IN);
|
||||
|
||||
$wait = true;
|
||||
$promise = $executor->query('127.0.0.1:1', $query)->then(
|
||||
null,
|
||||
function ($e) use (&$wait) {
|
||||
$wait = false;
|
||||
throw $e;
|
||||
}
|
||||
);
|
||||
|
||||
\Clue\React\Block\sleep(0.2, $loop);
|
||||
$this->assertTrue($wait);
|
||||
}
|
||||
|
||||
public function testQueryKeepsPendingIfServerSendInvalidMessage()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = stream_socket_server('udp://127.0.0.1:0', $errno, $errstr, STREAM_SERVER_BIND);
|
||||
$loop->addReadStream($server, function ($server) {
|
||||
$data = stream_socket_recvfrom($server, 512, 0, $peer);
|
||||
stream_socket_sendto($server, 'invalid', 0, $peer);
|
||||
});
|
||||
|
||||
$address = stream_socket_get_name($server, false);
|
||||
$executor = new UdpTransportExecutor($loop);
|
||||
|
||||
$query = new Query('google.com', Message::TYPE_A, Message::CLASS_IN);
|
||||
|
||||
$wait = true;
|
||||
$promise = $executor->query($address, $query)->then(
|
||||
null,
|
||||
function ($e) use (&$wait) {
|
||||
$wait = false;
|
||||
throw $e;
|
||||
}
|
||||
);
|
||||
|
||||
\Clue\React\Block\sleep(0.2, $loop);
|
||||
$this->assertTrue($wait);
|
||||
}
|
||||
|
||||
public function testQueryKeepsPendingIfServerSendInvalidId()
|
||||
{
|
||||
$parser = new Parser();
|
||||
$dumper = new BinaryDumper();
|
||||
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = stream_socket_server('udp://127.0.0.1:0', $errno, $errstr, STREAM_SERVER_BIND);
|
||||
$loop->addReadStream($server, function ($server) use ($parser, $dumper) {
|
||||
$data = stream_socket_recvfrom($server, 512, 0, $peer);
|
||||
|
||||
$message = $parser->parseMessage($data);
|
||||
$message->header->set('id', 0);
|
||||
|
||||
stream_socket_sendto($server, $dumper->toBinary($message), 0, $peer);
|
||||
});
|
||||
|
||||
$address = stream_socket_get_name($server, false);
|
||||
$executor = new UdpTransportExecutor($loop, $parser, $dumper);
|
||||
|
||||
$query = new Query('google.com', Message::TYPE_A, Message::CLASS_IN);
|
||||
|
||||
$wait = true;
|
||||
$promise = $executor->query($address, $query)->then(
|
||||
null,
|
||||
function ($e) use (&$wait) {
|
||||
$wait = false;
|
||||
throw $e;
|
||||
}
|
||||
);
|
||||
|
||||
\Clue\React\Block\sleep(0.2, $loop);
|
||||
$this->assertTrue($wait);
|
||||
}
|
||||
|
||||
public function testQueryRejectsIfServerSendsTruncatedResponse()
|
||||
{
|
||||
$parser = new Parser();
|
||||
$dumper = new BinaryDumper();
|
||||
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = stream_socket_server('udp://127.0.0.1:0', $errno, $errstr, STREAM_SERVER_BIND);
|
||||
$loop->addReadStream($server, function ($server) use ($parser, $dumper) {
|
||||
$data = stream_socket_recvfrom($server, 512, 0, $peer);
|
||||
|
||||
$message = $parser->parseMessage($data);
|
||||
$message->header->set('tc', 1);
|
||||
|
||||
stream_socket_sendto($server, $dumper->toBinary($message), 0, $peer);
|
||||
});
|
||||
|
||||
$address = stream_socket_get_name($server, false);
|
||||
$executor = new UdpTransportExecutor($loop, $parser, $dumper);
|
||||
|
||||
$query = new Query('google.com', Message::TYPE_A, Message::CLASS_IN);
|
||||
|
||||
$wait = true;
|
||||
$promise = $executor->query($address, $query)->then(
|
||||
null,
|
||||
function ($e) use (&$wait) {
|
||||
$wait = false;
|
||||
throw $e;
|
||||
}
|
||||
);
|
||||
|
||||
// run loop for short period to ensure we detect connection ICMP rejection error
|
||||
\Clue\React\Block\sleep(0.01, $loop);
|
||||
if ($wait) {
|
||||
\Clue\React\Block\sleep(0.2, $loop);
|
||||
}
|
||||
|
||||
$this->assertFalse($wait);
|
||||
}
|
||||
|
||||
public function testQueryResolvesIfServerSendsValidResponse()
|
||||
{
|
||||
$parser = new Parser();
|
||||
$dumper = new BinaryDumper();
|
||||
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = stream_socket_server('udp://127.0.0.1:0', $errno, $errstr, STREAM_SERVER_BIND);
|
||||
$loop->addReadStream($server, function ($server) use ($parser, $dumper) {
|
||||
$data = stream_socket_recvfrom($server, 512, 0, $peer);
|
||||
|
||||
$message = $parser->parseMessage($data);
|
||||
|
||||
stream_socket_sendto($server, $dumper->toBinary($message), 0, $peer);
|
||||
});
|
||||
|
||||
$address = stream_socket_get_name($server, false);
|
||||
$executor = new UdpTransportExecutor($loop, $parser, $dumper);
|
||||
|
||||
$query = new Query('google.com', Message::TYPE_A, Message::CLASS_IN);
|
||||
|
||||
$promise = $executor->query($address, $query);
|
||||
$response = \Clue\React\Block\await($promise, $loop, 0.2);
|
||||
|
||||
$this->assertInstanceOf('React\Dns\Model\Message', $response);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user