@@ -15,6 +15,7 @@ class TimeoutExecutorTest extends TestCase
1515{
1616 private $ wrapped ;
1717 private $ executor ;
18+ private $ loop ;
1819
1920 /**
2021 * @before
@@ -23,7 +24,9 @@ public function setUpExecutor()
2324 {
2425 $ this ->wrapped = $ this ->getMockBuilder ('React\Dns\Query\ExecutorInterface ' )->getMock ();
2526
26- $ this ->executor = new TimeoutExecutor ($ this ->wrapped , 5.0 );
27+ $ this ->loop = $ this ->getMockBuilder ('React\EventLoop\LoopInterface ' )->getMock ();
28+
29+ $ this ->executor = new TimeoutExecutor ($ this ->wrapped , 5.0 , $ this ->loop );
2730 }
2831
2932 public function testCtorWithoutLoopShouldAssignDefaultLoop ()
@@ -39,6 +42,10 @@ public function testCtorWithoutLoopShouldAssignDefaultLoop()
3942
4043 public function testCancellingPromiseWillCancelWrapped ()
4144 {
45+ $ timer = $ this ->getMockBuilder ('React\EventLoop\TimerInterface ' )->getMock ();
46+ $ this ->loop ->expects ($ this ->once ())->method ('addTimer ' )->with (5.0 , $ this ->anything ())->willReturn ($ timer );
47+ $ this ->loop ->expects ($ this ->once ())->method ('cancelTimer ' )->with ($ timer );
48+
4249 $ cancelled = 0 ;
4350
4451 $ this ->wrapped
@@ -63,8 +70,11 @@ public function testCancellingPromiseWillCancelWrapped()
6370 $ promise ->then ($ this ->expectCallableNever (), $ this ->expectCallableOnce ());
6471 }
6572
66- public function testResolvesPromiseWhenWrappedResolves ()
73+ public function testResolvesPromiseWithoutStartingTimerWhenWrappedReturnsResolvedPromise ()
6774 {
75+ $ this ->loop ->expects ($ this ->never ())->method ('addTimer ' );
76+ $ this ->loop ->expects ($ this ->never ())->method ('cancelTimer ' );
77+
6878 $ this ->wrapped
6979 ->expects ($ this ->once ())
7080 ->method ('query ' )
@@ -76,8 +86,31 @@ public function testResolvesPromiseWhenWrappedResolves()
7686 $ promise ->then ($ this ->expectCallableOnce (), $ this ->expectCallableNever ());
7787 }
7888
79- public function testRejectsPromiseWhenWrappedRejects ()
89+ public function testResolvesPromiseAfterCancellingTimerWhenWrappedReturnsPendingPromiseThatResolves ()
90+ {
91+ $ timer = $ this ->getMockBuilder ('React\EventLoop\TimerInterface ' )->getMock ();
92+ $ this ->loop ->expects ($ this ->once ())->method ('addTimer ' )->with (5.0 , $ this ->anything ())->willReturn ($ timer );
93+ $ this ->loop ->expects ($ this ->once ())->method ('cancelTimer ' )->with ($ timer );
94+
95+ $ deferred = new Deferred ();
96+ $ this ->wrapped
97+ ->expects ($ this ->once ())
98+ ->method ('query ' )
99+ ->willReturn ($ deferred ->promise ());
100+
101+ $ query = new Query ('igor.io ' , Message::TYPE_A , Message::CLASS_IN );
102+ $ promise = $ this ->executor ->query ($ query );
103+
104+ $ deferred ->resolve ('0.0.0.0 ' );
105+
106+ $ promise ->then ($ this ->expectCallableOnce (), $ this ->expectCallableNever ());
107+ }
108+
109+ public function testRejectsPromiseWithoutStartingTimerWhenWrappedReturnsRejectedPromise ()
80110 {
111+ $ this ->loop ->expects ($ this ->never ())->method ('addTimer ' );
112+ $ this ->loop ->expects ($ this ->never ())->method ('cancelTimer ' );
113+
81114 $ this ->wrapped
82115 ->expects ($ this ->once ())
83116 ->method ('query ' )
@@ -89,9 +122,35 @@ public function testRejectsPromiseWhenWrappedRejects()
89122 $ promise ->then ($ this ->expectCallableNever (), $ this ->expectCallableOnceWith (new \RuntimeException ()));
90123 }
91124
92- public function testWrappedWillBeCancelledOnTimeout ()
125+ public function testRejectsPromiseAfterCancellingTimerWhenWrappedReturnsPendingPromiseThatRejects ()
126+ {
127+ $ timer = $ this ->getMockBuilder ('React\EventLoop\TimerInterface ' )->getMock ();
128+ $ this ->loop ->expects ($ this ->once ())->method ('addTimer ' )->with (5.0 , $ this ->anything ())->willReturn ($ timer );
129+ $ this ->loop ->expects ($ this ->once ())->method ('cancelTimer ' )->with ($ timer );
130+
131+ $ deferred = new Deferred ();
132+ $ this ->wrapped
133+ ->expects ($ this ->once ())
134+ ->method ('query ' )
135+ ->willReturn ($ deferred ->promise ());
136+
137+ $ query = new Query ('igor.io ' , Message::TYPE_A , Message::CLASS_IN );
138+ $ promise = $ this ->executor ->query ($ query );
139+
140+ $ deferred ->reject (new \RuntimeException ());
141+
142+ $ promise ->then ($ this ->expectCallableNever (), $ this ->expectCallableOnceWith (new \RuntimeException ()));
143+ }
144+
145+ public function testRejectsPromiseAndCancelsPendingQueryWhenTimeoutTriggers ()
93146 {
94- $ this ->executor = new TimeoutExecutor ($ this ->wrapped , 0 );
147+ $ timerCallback = null ;
148+ $ timer = $ this ->getMockBuilder ('React\EventLoop\TimerInterface ' )->getMock ();
149+ $ this ->loop ->expects ($ this ->once ())->method ('addTimer ' )->with (5.0 , $ this ->callback (function ($ callback ) use (&$ timerCallback ) {
150+ $ timerCallback = $ callback ;
151+ return true ;
152+ }))->willReturn ($ timer );
153+ $ this ->loop ->expects ($ this ->once ())->method ('cancelTimer ' )->with ($ timer );
95154
96155 $ cancelled = 0 ;
97156
@@ -112,14 +171,18 @@ public function testWrappedWillBeCancelledOnTimeout()
112171
113172 $ this ->assertEquals (0 , $ cancelled );
114173
115- try {
116- \React \Async \await (\React \Promise \Timer \sleep (0 ));
117- \React \Async \await ($ promise );
118- $ this ->fail ();
119- } catch (TimeoutException $ exception ) {
120- $ this ->assertEquals ('DNS query for igor.io (A) timed out ' , $ exception ->getMessage ());
121- }
174+ $ this ->assertNotNull ($ timerCallback );
175+ $ timerCallback ();
122176
123177 $ this ->assertEquals (1 , $ cancelled );
178+
179+ $ exception = null ;
180+ $ promise ->then (null , function ($ reason ) use (&$ exception ) {
181+ $ exception = $ reason ;
182+ });
183+
184+ assert ($ exception instanceof TimeoutException);
185+ $ this ->assertInstanceOf ('React\Dns\Query\TimeoutException ' , $ exception );
186+ $ this ->assertEquals ('DNS query for igor.io (A) timed out ' , $ exception ->getMessage ());
124187 }
125188}
0 commit comments