@@ -65,6 +65,40 @@ public function testConnectWillRejectWhenBothDnsLookupsReject()
6565 $ this ->assertEquals ('Connection to tcp://reactphp.org:80 failed during DNS lookup: DNS lookup error ' , $ exception ->getMessage ());
6666 }
6767
68+ public function testConnectWillRejectWhenBothDnsLookupsRejectWithDifferentMessages ()
69+ {
70+ $ loop = $ this ->getMockBuilder ('React\EventLoop\LoopInterface ' )->getMock ();
71+ $ loop ->expects ($ this ->never ())->method ('addTimer ' );
72+
73+ $ connector = $ this ->getMockBuilder ('React\Socket\ConnectorInterface ' )->getMock ();
74+ $ connector ->expects ($ this ->never ())->method ('connect ' );
75+
76+ $ resolver = $ this ->getMockBuilder ('React\Dns\Resolver\ResolverInterface ' )->getMock ();
77+ $ resolver ->expects ($ this ->exactly (2 ))->method ('resolveAll ' )->withConsecutive (
78+ array ('reactphp.org ' , Message::TYPE_AAAA ),
79+ array ('reactphp.org ' , Message::TYPE_A )
80+ )->willReturnOnConsecutiveCalls (
81+ \React \Promise \reject (new \RuntimeException ('DNS6 error ' )),
82+ \React \Promise \reject (new \RuntimeException ('DNS4 error ' ))
83+ );
84+
85+ $ uri = 'tcp://reactphp.org:80 ' ;
86+ $ host = 'reactphp.org ' ;
87+ $ parts = parse_url ($ uri );
88+
89+ $ builder = new HappyEyeBallsConnectionBuilder ($ loop , $ connector , $ resolver , $ uri , $ host , $ parts );
90+
91+ $ promise = $ builder ->connect ();
92+
93+ $ exception = null ;
94+ $ promise ->then (null , function ($ e ) use (&$ exception ) {
95+ $ exception = $ e ;
96+ });
97+
98+ $ this ->assertInstanceOf ('RuntimeException ' , $ exception );
99+ $ this ->assertEquals ('Connection to tcp://reactphp.org:80 failed during DNS lookup. Last error for IPv6: DNS6 error. Last error for IPv4: DNS4 error ' , $ exception ->getMessage ());
100+ }
101+
68102 public function testConnectWillStartDelayTimerWhenIpv4ResolvesAndIpv6IsPending ()
69103 {
70104 $ loop = $ this ->getMockBuilder ('React\EventLoop\LoopInterface ' )->getMock ();
@@ -364,7 +398,7 @@ public function testConnectWillStartAndCancelResolutionTimerAndStartAttemptTimer
364398 $ deferred ->resolve (array ('::1 ' ));
365399 }
366400
367- public function testConnectWillRejectWhenOnlyTcpConnectionRejectsAndCancelNextAttemptTimerImmediately ()
401+ public function testConnectWillRejectWhenOnlyTcp6ConnectionRejectsAndCancelNextAttemptTimerImmediately ()
368402 {
369403 $ timer = $ this ->getMockBuilder ('React\EventLoop\TimerInterface ' )->getMock ();
370404 $ loop = $ this ->getMockBuilder ('React\EventLoop\LoopInterface ' )->getMock ();
@@ -381,7 +415,81 @@ public function testConnectWillRejectWhenOnlyTcpConnectionRejectsAndCancelNextAt
381415 array ('reactphp.org ' , Message::TYPE_A )
382416 )->willReturnOnConsecutiveCalls (
383417 \React \Promise \resolve (array ('::1 ' )),
384- \React \Promise \reject (new \RuntimeException ('ignored ' ))
418+ \React \Promise \reject (new \RuntimeException ('DNS failed ' ))
419+ );
420+
421+ $ uri = 'tcp://reactphp.org:80 ' ;
422+ $ host = 'reactphp.org ' ;
423+ $ parts = parse_url ($ uri );
424+
425+ $ builder = new HappyEyeBallsConnectionBuilder ($ loop , $ connector , $ resolver , $ uri , $ host , $ parts );
426+
427+ $ promise = $ builder ->connect ();
428+ $ deferred ->reject (new \RuntimeException ('Connection refused ' ));
429+
430+ $ exception = null ;
431+ $ promise ->then (null , function ($ e ) use (&$ exception ) {
432+ $ exception = $ e ;
433+ });
434+
435+ $ this ->assertInstanceOf ('RuntimeException ' , $ exception );
436+ $ this ->assertEquals ('Connection to tcp://reactphp.org:80 failed: Last error for IPv6: Connection refused. Last error for IPv4: DNS failed ' , $ exception ->getMessage ());
437+ }
438+
439+ public function testConnectWillRejectWhenOnlyTcp4ConnectionRejectsAndWillNeverStartNextAttemptTimer ()
440+ {
441+ $ loop = $ this ->getMockBuilder ('React\EventLoop\LoopInterface ' )->getMock ();
442+ $ loop ->expects ($ this ->never ())->method ('addTimer ' );
443+
444+ $ deferred = new Deferred ();
445+ $ connector = $ this ->getMockBuilder ('React\Socket\ConnectorInterface ' )->getMock ();
446+ $ connector ->expects ($ this ->once ())->method ('connect ' )->with ('tcp://127.0.0.1:80?hostname=reactphp.org ' )->willReturn ($ deferred ->promise ());
447+
448+ $ resolver = $ this ->getMockBuilder ('React\Dns\Resolver\ResolverInterface ' )->getMock ();
449+ $ resolver ->expects ($ this ->exactly (2 ))->method ('resolveAll ' )->withConsecutive (
450+ array ('reactphp.org ' , Message::TYPE_AAAA ),
451+ array ('reactphp.org ' , Message::TYPE_A )
452+ )->willReturnOnConsecutiveCalls (
453+ \React \Promise \reject (new \RuntimeException ('DNS failed ' )),
454+ \React \Promise \resolve (array ('127.0.0.1 ' ))
455+ );
456+
457+ $ uri = 'tcp://reactphp.org:80 ' ;
458+ $ host = 'reactphp.org ' ;
459+ $ parts = parse_url ($ uri );
460+
461+ $ builder = new HappyEyeBallsConnectionBuilder ($ loop , $ connector , $ resolver , $ uri , $ host , $ parts );
462+
463+ $ promise = $ builder ->connect ();
464+ $ deferred ->reject (new \RuntimeException ('Connection refused ' ));
465+
466+ $ exception = null ;
467+ $ promise ->then (null , function ($ e ) use (&$ exception ) {
468+ $ exception = $ e ;
469+ });
470+
471+ $ this ->assertInstanceOf ('RuntimeException ' , $ exception );
472+ $ this ->assertEquals ('Connection to tcp://reactphp.org:80 failed: Last error for IPv6: DNS failed. Last error for IPv4: Connection refused ' , $ exception ->getMessage ());
473+ }
474+
475+ public function testConnectWillRejectWhenAllConnectionsRejectAndCancelNextAttemptTimerImmediately ()
476+ {
477+ $ timer = $ this ->getMockBuilder ('React\EventLoop\TimerInterface ' )->getMock ();
478+ $ loop = $ this ->getMockBuilder ('React\EventLoop\LoopInterface ' )->getMock ();
479+ $ loop ->expects ($ this ->once ())->method ('addTimer ' )->with (0.1 , $ this ->anything ())->willReturn ($ timer );
480+ $ loop ->expects ($ this ->once ())->method ('cancelTimer ' )->with ($ timer );
481+
482+ $ deferred = new Deferred ();
483+ $ connector = $ this ->getMockBuilder ('React\Socket\ConnectorInterface ' )->getMock ();
484+ $ connector ->expects ($ this ->exactly (2 ))->method ('connect ' )->willReturn ($ deferred ->promise ());
485+
486+ $ resolver = $ this ->getMockBuilder ('React\Dns\Resolver\ResolverInterface ' )->getMock ();
487+ $ resolver ->expects ($ this ->exactly (2 ))->method ('resolveAll ' )->withConsecutive (
488+ array ('reactphp.org ' , Message::TYPE_AAAA ),
489+ array ('reactphp.org ' , Message::TYPE_A )
490+ )->willReturnOnConsecutiveCalls (
491+ \React \Promise \resolve (array ('::1 ' )),
492+ \React \Promise \resolve (array ('127.0.0.1 ' ))
385493 );
386494
387495 $ uri = 'tcp://reactphp.org:80 ' ;
0 commit comments