From 2f19420221a19f698ee9bc2d4a99f6d8868d4f3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Mon, 22 Jun 2020 16:49:39 +0200 Subject: [PATCH] Fix unneeded timeout timer when body closes and sender already rejected --- src/Io/Transaction.php | 6 ++++-- tests/Io/TransactionTest.php | 26 +++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/Io/Transaction.php b/src/Io/Transaction.php index 6ad8347..17b873c 100644 --- a/src/Io/Transaction.php +++ b/src/Io/Transaction.php @@ -105,8 +105,10 @@ function ($e) use ($deferred, $loop, &$timeout) { $body = $request->getBody(); if ($body instanceof ReadableStreamInterface && $body->isReadable()) { $that = $this; - $body->on('close', function () use ($that, $deferred, $timeout) { - $that->applyTimeout($deferred, $timeout); + $body->on('close', function () use ($that, $deferred, &$timeout) { + if ($timeout >= 0) { + $that->applyTimeout($deferred, $timeout); + } }); } else { $this->applyTimeout($deferred, $timeout); diff --git a/tests/Io/TransactionTest.php b/tests/Io/TransactionTest.php index 18ada59..03c0714 100644 --- a/tests/Io/TransactionTest.php +++ b/tests/Io/TransactionTest.php @@ -298,7 +298,7 @@ public function testTimeoutExplicitOptionWillStartTimeoutTimerWhenStreamingReque $this->assertInstanceOf('React\Promise\PromiseInterface', $promise); } - public function testTimeoutExplicitOptionWillStartTimeoutTimerWhenStreamingRequestBodyCloses() + public function testTimeoutExplicitOptionWillStartTimeoutTimerWhenStreamingRequestBodyClosesWhileSenderIsStillPending() { $messageFactory = new MessageFactory(); @@ -322,6 +322,30 @@ public function testTimeoutExplicitOptionWillStartTimeoutTimerWhenStreamingReque $this->assertInstanceOf('React\Promise\PromiseInterface', $promise); } + public function testTimeoutExplicitOptionWillNotStartTimeoutTimerWhenStreamingRequestBodyClosesAfterSenderRejects() + { + $messageFactory = new MessageFactory(); + + $loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock(); + $loop->expects($this->never())->method('addTimer'); + + $stream = new ThroughStream(); + $request = $messageFactory->request('POST', 'http://example.com', array(), $stream); + + $deferred = new Deferred(); + $sender = $this->getMockBuilder('Clue\React\Buzz\Io\Sender')->disableOriginalConstructor()->getMock(); + $sender->expects($this->once())->method('send')->with($this->equalTo($request))->willReturn($deferred->promise()); + + $transaction = new Transaction($sender, $messageFactory, $loop); + $transaction = $transaction->withOptions(array('timeout' => 2)); + $promise = $transaction->send($request); + + $deferred->reject(new \RuntimeException('Request failed')); + $stream->close(); + + $this->assertInstanceOf('React\Promise\PromiseInterface', $promise); + } + public function testTimeoutExplicitOptionWillRejectWhenTimerFiresAfterStreamingRequestBodyCloses() { $messageFactory = new MessageFactory();