From d64011a44b043303272d13d3d5b501017a5e0c94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Mon, 7 Mar 2016 14:26:37 +0100 Subject: [PATCH 1/2] Support Promise cancellation --- composer.json | 2 +- src/MulticastExecutor.php | 7 +++- tests/MulticastExecutorTest.php | 58 ++++++++++++++++++++++++++------- 3 files changed, 53 insertions(+), 14 deletions(-) diff --git a/composer.json b/composer.json index 0c415a6..6493eee 100644 --- a/composer.json +++ b/composer.json @@ -18,6 +18,6 @@ "clue/multicast-react": "~1.0|~0.2.0", "react/event-loop": "~0.4.0|~0.3.0", "react/dns": "~0.4.0|~0.3.0", - "react/promise": "~2.0|~1.0" + "react/promise": "~2.1|~1.2" } } diff --git a/src/MulticastExecutor.php b/src/MulticastExecutor.php index 6d085de..8422d54 100644 --- a/src/MulticastExecutor.php +++ b/src/MulticastExecutor.php @@ -72,7 +72,12 @@ public function doQuery($nameserver, $queryData, $name) $parser = $this->parser; $loop = $this->loop; - $deferred = new Deferred(); + $deferred = new Deferred(function ($_, $reject) use (&$conn, &$timer, $name) { + $conn->close(); + $timer->cancel(); + + $reject(new \RuntimeException(sprintf("DNS query for %s cancelled", $name))); + }); $timer = $this->loop->addTimer($this->timeout, function () use (&$conn, $name, $deferred) { $conn->close(); diff --git a/tests/MulticastExecutorTest.php b/tests/MulticastExecutorTest.php index 9f27926..2742dd0 100644 --- a/tests/MulticastExecutorTest.php +++ b/tests/MulticastExecutorTest.php @@ -3,29 +3,63 @@ use Clue\React\Mdns\MulticastExecutor; use Clue\React\Mdns\Factory; use React\Dns\Query\Query; + class MulticastExecutorTest extends TestCase { - public function testA() - { - $nameserver = Factory::DNS; + private $nameserver; + private $loop; + private $parser; + private $dumper; + private $sockets; - $loop = $this->getMock('React\EventLoop\LoopInterface'); - $parser = $this->getMock('React\Dns\Protocol\Parser'); - $dumper = $this->getMock('React\Dns\Protocol\BinaryDumper'); - $sockets = $this->getMockBuilder('Clue\React\Multicast\Factory')->disableOriginalConstructor()->getMock(); + public function setUp() + { + $this->nameserver = Factory::DNS; + $this->loop = $this->getMock('React\EventLoop\LoopInterface'); + $this->parser = $this->getMock('React\Dns\Protocol\Parser'); + $this->dumper = $this->getMock('React\Dns\Protocol\BinaryDumper'); + $this->sockets = $this->getMockBuilder('Clue\React\Multicast\Factory')->disableOriginalConstructor()->getMock(); + } - $executor = new MulticastExecutor($loop, $parser, $dumper, 5, $sockets); + public function testQueryWillReturnPromise() + { + $executor = new MulticastExecutor($this->loop, $this->parser, $this->dumper, 5, $this->sockets); $socket = $this->getMock('React\Datagram\SocketInterface'); - $dumper->expects($this->once())->method('toBinary')->will($this->returnValue('message')); - $sockets->expects($this->once())->method('createSender')->will($this->returnValue($socket)); + $this->dumper->expects($this->once())->method('toBinary')->will($this->returnValue('message')); + $this->sockets->expects($this->once())->method('createSender')->will($this->returnValue($socket)); - $socket->expects($this->once())->method('send')->with($this->equalTo('message'), $this->equalTo($nameserver)); + $socket->expects($this->once())->method('send')->with($this->equalTo('message'), $this->equalTo($this->nameserver)); $query = new Query('name', 'type', 'class', time()); - $ret = $executor->query($nameserver, $query); + $ret = $executor->query($this->nameserver, $query); $this->assertInstanceOf('React\Promise\PromiseInterface', $ret); } + + public function testCancellingPromiseWillCloseSocketAndReject() + { + $executor = new MulticastExecutor($this->loop, $this->parser, $this->dumper, 5, $this->sockets); + + $socket = $this->getMock('React\Datagram\SocketInterface'); + $socket->expects($this->once())->method('close'); + $socket->expects($this->once())->method('send')->with($this->equalTo('message'), $this->equalTo($this->nameserver)); + $this->sockets->expects($this->once())->method('createSender')->will($this->returnValue($socket)); + + $timer = $this->getMock('React\EventLoop\Timer\TimerInterface'); + $timer->expects($this->once())->method('cancel'); + $this->loop->expects($this->once())->method('addTimer')->willReturn($timer); + + $this->dumper->expects($this->once())->method('toBinary')->will($this->returnValue('message')); + + $query = new Query('name', 'type', 'class', time()); + + $ret = $executor->query($this->nameserver, $query); + $this->assertInstanceOf('React\Promise\CancellablePromiseInterface', $ret); + + $ret->cancel(); + + $ret->then($this->expectCallableNever(), $this->expectCallableOnceParameter('RuntimeException')); + } } From 28b6b8e84a2edfa09bcdbce5db9aac51399991f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Mon, 7 Mar 2016 16:36:57 +0100 Subject: [PATCH 2/2] Require fixed Promise v1.2.1 or up --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 6493eee..412260e 100644 --- a/composer.json +++ b/composer.json @@ -18,6 +18,6 @@ "clue/multicast-react": "~1.0|~0.2.0", "react/event-loop": "~0.4.0|~0.3.0", "react/dns": "~0.4.0|~0.3.0", - "react/promise": "~2.1|~1.2" + "react/promise": "^2.1 || ^1.2.1" } }