@@ -217,6 +217,80 @@ public function testConnectWillStartConnectingWithAttemptTimerButWithoutResoluti
217217 $ deferred ->reject (new \RuntimeException ());
218218 }
219219
220+ public function testConnectWillStartConnectingWithAttemptTimerWhenIpv6AndIpv4ResolvesAndWillStartNextConnectionAttemptWithoutAttemptTimerImmediatelyWhenFirstConnectionAttemptFails ()
221+ {
222+ $ timer = $ this ->getMockBuilder ('React\EventLoop\TimerInterface ' )->getMock ();
223+ $ loop = $ this ->getMockBuilder ('React\EventLoop\LoopInterface ' )->getMock ();
224+ $ loop ->expects ($ this ->once ())->method ('addTimer ' )->with (0.1 , $ this ->anything ())->willReturn ($ timer );
225+ $ loop ->expects ($ this ->once ())->method ('cancelTimer ' )->with ($ timer );
226+
227+ $ deferred = new Deferred ();
228+ $ connector = $ this ->getMockBuilder ('React\Socket\ConnectorInterface ' )->getMock ();
229+ $ connector ->expects ($ this ->exactly (2 ))->method ('connect ' )->withConsecutive (
230+ array ('tcp://[::1]:80?hostname=reactphp.org ' ),
231+ array ('tcp://127.0.0.1:80?hostname=reactphp.org ' )
232+ )->willReturnOnConsecutiveCalls (
233+ $ deferred ->promise (),
234+ new Promise (function () { })
235+ );
236+
237+ $ resolver = $ this ->getMockBuilder ('React\Dns\Resolver\ResolverInterface ' )->getMock ();
238+ $ resolver ->expects ($ this ->exactly (2 ))->method ('resolveAll ' )->withConsecutive (
239+ array ('reactphp.org ' , Message::TYPE_AAAA ),
240+ array ('reactphp.org ' , Message::TYPE_A )
241+ )->willReturnOnConsecutiveCalls (
242+ \React \Promise \resolve (array ('::1 ' )),
243+ \React \Promise \resolve (array ('127.0.0.1 ' ))
244+ );
245+
246+ $ uri = 'tcp://reactphp.org:80 ' ;
247+ $ host = 'reactphp.org ' ;
248+ $ parts = parse_url ($ uri );
249+
250+ $ builder = new HappyEyeBallsConnectionBuilder ($ loop , $ connector , $ resolver , $ uri , $ host , $ parts );
251+
252+ $ builder ->connect ();
253+
254+ $ deferred ->reject (new \RuntimeException ());
255+ }
256+
257+ public function testConnectWillStartConnectingWithAttemptTimerWhenOnlyIpv6ResolvesAndWillStartNextConnectionAttemptWithoutAttemptTimerImmediatelyWhenFirstConnectionAttemptFails ()
258+ {
259+ $ timer = $ this ->getMockBuilder ('React\EventLoop\TimerInterface ' )->getMock ();
260+ $ loop = $ this ->getMockBuilder ('React\EventLoop\LoopInterface ' )->getMock ();
261+ $ loop ->expects ($ this ->once ())->method ('addTimer ' )->with (0.1 , $ this ->anything ())->willReturn ($ timer );
262+ $ loop ->expects ($ this ->once ())->method ('cancelTimer ' )->with ($ timer );
263+
264+ $ deferred = new Deferred ();
265+ $ connector = $ this ->getMockBuilder ('React\Socket\ConnectorInterface ' )->getMock ();
266+ $ connector ->expects ($ this ->exactly (2 ))->method ('connect ' )->withConsecutive (
267+ array ('tcp://[::1]:80?hostname=reactphp.org ' ),
268+ array ('tcp://[::2]:80?hostname=reactphp.org ' )
269+ )->willReturnOnConsecutiveCalls (
270+ $ deferred ->promise (),
271+ new Promise (function () { })
272+ );
273+
274+ $ resolver = $ this ->getMockBuilder ('React\Dns\Resolver\ResolverInterface ' )->getMock ();
275+ $ resolver ->expects ($ this ->exactly (2 ))->method ('resolveAll ' )->withConsecutive (
276+ array ('reactphp.org ' , Message::TYPE_AAAA ),
277+ array ('reactphp.org ' , Message::TYPE_A )
278+ )->willReturnOnConsecutiveCalls (
279+ \React \Promise \resolve (array ('::1 ' , '::2 ' )),
280+ \React \Promise \reject (new \RuntimeException ())
281+ );
282+
283+ $ uri = 'tcp://reactphp.org:80 ' ;
284+ $ host = 'reactphp.org ' ;
285+ $ parts = parse_url ($ uri );
286+
287+ $ builder = new HappyEyeBallsConnectionBuilder ($ loop , $ connector , $ resolver , $ uri , $ host , $ parts );
288+
289+ $ builder ->connect ();
290+
291+ $ deferred ->reject (new \RuntimeException ());
292+ }
293+
220294 public function testConnectWillStartConnectingAndWillStartNextConnectionWithoutNewAttemptTimerWhenNextAttemptTimerFiresAfterIpv4Rejected ()
221295 {
222296 $ timer = null ;
0 commit comments