@@ -120,7 +120,75 @@ public function testQueryRejectsIfServerConnectionFails()
120120 $ promise = $ executor ->query ($ query );
121121
122122 $ this ->assertInstanceOf ('React\Promise\PromiseInterface ' , $ promise );
123- $ promise ->then (null , $ this ->expectCallableOnce ());
123+
124+ $ exception = null ;
125+ $ promise ->then (null , function ($ reason ) use (&$ exception ) {
126+ $ exception = $ reason ;
127+ });
128+
129+ // PHP (Failed to parse address "///") differs from HHVM (Name or service not known)
130+ $ this ->setExpectedException ('RuntimeException ' , 'Unable to connect to DNS server ' );
131+ throw $ exception ;
132+ }
133+
134+ public function testQueryRejectsIfSendToServerFailsAfterConnection ()
135+ {
136+ $ loop = $ this ->getMockBuilder ('React\EventLoop\LoopInterface ' )->getMock ();
137+ $ loop ->expects ($ this ->never ())->method ('addReadStream ' );
138+
139+ $ executor = new UdpTransportExecutor ('0.0.0.0 ' , $ loop );
140+
141+ // increase hard-coded maximum packet size to allow sending excessive data
142+ $ ref = new \ReflectionProperty ($ executor , 'maxPacketSize ' );
143+ $ ref ->setAccessible (true );
144+ $ ref ->setValue ($ executor , PHP_INT_MAX );
145+
146+ $ query = new Query (str_repeat ('a. ' , 100000 ) . '.example ' , Message::TYPE_A , Message::CLASS_IN );
147+ $ promise = $ executor ->query ($ query );
148+
149+ $ this ->assertInstanceOf ('React\Promise\PromiseInterface ' , $ promise );
150+
151+ $ exception = null ;
152+ $ promise ->then (null , function ($ reason ) use (&$ exception ) {
153+ $ exception = $ reason ;
154+ });
155+
156+ // ECONNREFUSED( Connection refused) on Linux, EMSGSIZE (Message too long) on macOS
157+ $ this ->setExpectedException ('RuntimeException ' , 'Unable to send query to DNS server ' );
158+ throw $ exception ;
159+ }
160+
161+ public function testQueryKeepsPendingIfReadFailsBecauseServerRefusesConnection ()
162+ {
163+ $ socket = null ;
164+ $ callback = null ;
165+ $ loop = $ this ->getMockBuilder ('React\EventLoop\LoopInterface ' )->getMock ();
166+ $ loop ->expects ($ this ->once ())->method ('addReadStream ' )->with ($ this ->callback (function ($ ref ) use (&$ socket ) {
167+ $ socket = $ ref ;
168+ return true ;
169+ }), $ this ->callback (function ($ ref ) use (&$ callback ) {
170+ $ callback = $ ref ;
171+ return true ;
172+ }));
173+
174+ $ executor = new UdpTransportExecutor ('0.0.0.0 ' , $ loop );
175+
176+ $ query = new Query ('reactphp.org ' , Message::TYPE_A , Message::CLASS_IN );
177+ $ promise = $ executor ->query ($ query );
178+
179+ $ this ->assertNotNull ($ socket );
180+ $ callback ($ socket );
181+
182+ $ this ->assertInstanceOf ('React\Promise\PromiseInterface ' , $ promise );
183+
184+ $ pending = true ;
185+ $ promise ->then (function () use (&$ pending ) {
186+ $ pending = false ;
187+ }, function () use (&$ pending ) {
188+ $ pending = false ;
189+ });
190+
191+ $ this ->assertTrue ($ pending );
124192 }
125193
126194 /**
@@ -142,27 +210,6 @@ public function testQueryRejectsOnCancellation()
142210 $ promise ->then (null , $ this ->expectCallableOnce ());
143211 }
144212
145- public function testQueryKeepsPendingIfServerRejectsNetworkPacket ()
146- {
147- $ loop = Factory::create ();
148-
149- $ executor = new UdpTransportExecutor ('127.0.0.1:1 ' , $ loop );
150-
151- $ query = new Query ('google.com ' , Message::TYPE_A , Message::CLASS_IN );
152-
153- $ wait = true ;
154- $ promise = $ executor ->query ($ query )->then (
155- null ,
156- function ($ e ) use (&$ wait ) {
157- $ wait = false ;
158- throw $ e ;
159- }
160- );
161-
162- \Clue \React \Block \sleep (0.2 , $ loop );
163- $ this ->assertTrue ($ wait );
164- }
165-
166213 public function testQueryKeepsPendingIfServerSendsInvalidMessage ()
167214 {
168215 $ loop = Factory::create ();
0 commit comments