LoopTest.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. <?php
  2. namespace React\Tests\EventLoop;
  3. use React\EventLoop\Factory;
  4. use React\EventLoop\Loop;
  5. final class LoopTest extends TestCase
  6. {
  7. /**
  8. * @dataProvider numberOfTests
  9. */
  10. public function testFactoryCreateSetsEventLoopOnLoopAccessor()
  11. {
  12. $factoryLoop = Factory::create();
  13. $accessorLoop = Loop::get();
  14. self::assertSame($factoryLoop, $accessorLoop);
  15. }
  16. /**
  17. * @dataProvider numberOfTests
  18. */
  19. public function testCallingFactoryAfterCallingLoopGetYieldsADifferentInstanceOfTheEventLoop()
  20. {
  21. // Note that this behavior isn't wise and highly advised against. Always used Loop::get.
  22. $accessorLoop = Loop::get();
  23. $factoryLoop = Factory::create();
  24. self::assertNotSame($factoryLoop, $accessorLoop);
  25. }
  26. /**
  27. * @dataProvider numberOfTests
  28. */
  29. public function testCallingLoopGetShouldAlwaysReturnTheSameEventLoop()
  30. {
  31. self::assertSame(Loop::get(), Loop::get());
  32. }
  33. /**
  34. * Run several tests several times to ensure we reset the loop between tests and code is still behavior as expected.
  35. *
  36. * @return array<array>
  37. */
  38. public function numberOfTests()
  39. {
  40. return array(array(), array(), array());
  41. }
  42. public function testStaticAddReadStreamCallsAddReadStreamOnLoopInstance()
  43. {
  44. $stream = tmpfile();
  45. $listener = function () { };
  46. $loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
  47. $loop->expects($this->once())->method('addReadStream')->with($stream, $listener);
  48. Loop::set($loop);
  49. Loop::addReadStream($stream, $listener);
  50. }
  51. public function testStaticAddReadStreamWithNoDefaultLoopCallsAddReadStreamOnNewLoopInstance()
  52. {
  53. $ref = new \ReflectionProperty('React\EventLoop\Loop', 'instance');
  54. $ref->setAccessible(true);
  55. $ref->setValue(null, null);
  56. $stream = stream_socket_server('127.0.0.1:0');
  57. $listener = function () { };
  58. Loop::addReadStream($stream, $listener);
  59. $this->assertInstanceOf('React\EventLoop\LoopInterface', $ref->getValue());
  60. }
  61. public function testStaticAddWriteStreamCallsAddWriteStreamOnLoopInstance()
  62. {
  63. $stream = tmpfile();
  64. $listener = function () { };
  65. $loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
  66. $loop->expects($this->once())->method('addWriteStream')->with($stream, $listener);
  67. Loop::set($loop);
  68. Loop::addWriteStream($stream, $listener);
  69. }
  70. public function testStaticAddWriteStreamWithNoDefaultLoopCallsAddWriteStreamOnNewLoopInstance()
  71. {
  72. $ref = new \ReflectionProperty('React\EventLoop\Loop', 'instance');
  73. $ref->setAccessible(true);
  74. $ref->setValue(null, null);
  75. $stream = stream_socket_server('127.0.0.1:0');
  76. $listener = function () { };
  77. Loop::addWriteStream($stream, $listener);
  78. $this->assertInstanceOf('React\EventLoop\LoopInterface', $ref->getValue());
  79. }
  80. public function testStaticRemoveReadStreamCallsRemoveReadStreamOnLoopInstance()
  81. {
  82. $stream = tmpfile();
  83. $loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
  84. $loop->expects($this->once())->method('removeReadStream')->with($stream);
  85. Loop::set($loop);
  86. Loop::removeReadStream($stream);
  87. }
  88. public function testStaticRemoveReadStreamWithNoDefaultLoopIsNoOp()
  89. {
  90. $ref = new \ReflectionProperty('React\EventLoop\Loop', 'instance');
  91. $ref->setAccessible(true);
  92. $ref->setValue(null, null);
  93. $stream = tmpfile();
  94. Loop::removeReadStream($stream);
  95. $this->assertNull($ref->getValue());
  96. }
  97. public function testStaticRemoveWriteStreamCallsRemoveWriteStreamOnLoopInstance()
  98. {
  99. $stream = tmpfile();
  100. $loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
  101. $loop->expects($this->once())->method('removeWriteStream')->with($stream);
  102. Loop::set($loop);
  103. Loop::removeWriteStream($stream);
  104. }
  105. public function testStaticRemoveWriteStreamWithNoDefaultLoopIsNoOp()
  106. {
  107. $ref = new \ReflectionProperty('React\EventLoop\Loop', 'instance');
  108. $ref->setAccessible(true);
  109. $ref->setValue(null, null);
  110. $stream = tmpfile();
  111. Loop::removeWriteStream($stream);
  112. $this->assertNull($ref->getValue());
  113. }
  114. public function testStaticAddTimerCallsAddTimerOnLoopInstanceAndReturnsTimerInstance()
  115. {
  116. $interval = 1.0;
  117. $callback = function () { };
  118. $timer = $this->getMockBuilder('React\EventLoop\TimerInterface')->getMock();
  119. $loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
  120. $loop->expects($this->once())->method('addTimer')->with($interval, $callback)->willReturn($timer);
  121. Loop::set($loop);
  122. $ret = Loop::addTimer($interval, $callback);
  123. $this->assertSame($timer, $ret);
  124. }
  125. public function testStaticAddTimerWithNoDefaultLoopCallsAddTimerOnNewLoopInstance()
  126. {
  127. $ref = new \ReflectionProperty('React\EventLoop\Loop', 'instance');
  128. $ref->setAccessible(true);
  129. $ref->setValue(null, null);
  130. $interval = 1.0;
  131. $callback = function () { };
  132. $ret = Loop::addTimer($interval, $callback);
  133. $this->assertInstanceOf('React\EventLoop\TimerInterface', $ret);
  134. $this->assertInstanceOf('React\EventLoop\LoopInterface', $ref->getValue());
  135. }
  136. public function testStaticAddPeriodicTimerCallsAddPeriodicTimerOnLoopInstanceAndReturnsTimerInstance()
  137. {
  138. $interval = 1.0;
  139. $callback = function () { };
  140. $timer = $this->getMockBuilder('React\EventLoop\TimerInterface')->getMock();
  141. $loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
  142. $loop->expects($this->once())->method('addPeriodicTimer')->with($interval, $callback)->willReturn($timer);
  143. Loop::set($loop);
  144. $ret = Loop::addPeriodicTimer($interval, $callback);
  145. $this->assertSame($timer, $ret);
  146. }
  147. public function testStaticAddPeriodicTimerWithNoDefaultLoopCallsAddPeriodicTimerOnNewLoopInstance()
  148. {
  149. $ref = new \ReflectionProperty('React\EventLoop\Loop', 'instance');
  150. $ref->setAccessible(true);
  151. $ref->setValue(null, null);
  152. $interval = 1.0;
  153. $callback = function () { };
  154. $ret = Loop::addPeriodicTimer($interval, $callback);
  155. $this->assertInstanceOf('React\EventLoop\TimerInterface', $ret);
  156. $this->assertInstanceOf('React\EventLoop\LoopInterface', $ref->getValue());
  157. }
  158. public function testStaticCancelTimerCallsCancelTimerOnLoopInstance()
  159. {
  160. $timer = $this->getMockBuilder('React\EventLoop\TimerInterface')->getMock();
  161. $loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
  162. $loop->expects($this->once())->method('cancelTimer')->with($timer);
  163. Loop::set($loop);
  164. Loop::cancelTimer($timer);
  165. }
  166. public function testStaticCancelTimerWithNoDefaultLoopIsNoOp()
  167. {
  168. $ref = new \ReflectionProperty('React\EventLoop\Loop', 'instance');
  169. $ref->setAccessible(true);
  170. $ref->setValue(null, null);
  171. $timer = $this->getMockBuilder('React\EventLoop\TimerInterface')->getMock();
  172. Loop::cancelTimer($timer);
  173. $this->assertNull($ref->getValue());
  174. }
  175. public function testStaticFutureTickCallsFutureTickOnLoopInstance()
  176. {
  177. $listener = function () { };
  178. $loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
  179. $loop->expects($this->once())->method('futureTick')->with($listener);
  180. Loop::set($loop);
  181. Loop::futureTick($listener);
  182. }
  183. public function testStaticFutureTickWithNoDefaultLoopCallsFutureTickOnNewLoopInstance()
  184. {
  185. $ref = new \ReflectionProperty('React\EventLoop\Loop', 'instance');
  186. $ref->setAccessible(true);
  187. $ref->setValue(null, null);
  188. $listener = function () { };
  189. Loop::futureTick($listener);
  190. $this->assertInstanceOf('React\EventLoop\LoopInterface', $ref->getValue());
  191. }
  192. public function testStaticAddSignalCallsAddSignalOnLoopInstance()
  193. {
  194. $signal = 1;
  195. $listener = function () { };
  196. $loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
  197. $loop->expects($this->once())->method('addSignal')->with($signal, $listener);
  198. Loop::set($loop);
  199. Loop::addSignal($signal, $listener);
  200. }
  201. public function testStaticAddSignalWithNoDefaultLoopCallsAddSignalOnNewLoopInstance()
  202. {
  203. if (DIRECTORY_SEPARATOR === '\\') {
  204. $this->markTestSkipped('Not supported on Windows');
  205. }
  206. $ref = new \ReflectionProperty('React\EventLoop\Loop', 'instance');
  207. $ref->setAccessible(true);
  208. $ref->setValue(null, null);
  209. $signal = 1;
  210. $listener = function () { };
  211. try {
  212. Loop::addSignal($signal, $listener);
  213. } catch (\BadMethodCallException $e) {
  214. $this->markTestSkipped('Skipped: ' . $e->getMessage());
  215. }
  216. $this->assertInstanceOf('React\EventLoop\LoopInterface', $ref->getValue());
  217. }
  218. public function testStaticRemoveSignalCallsRemoveSignalOnLoopInstance()
  219. {
  220. $signal = 1;
  221. $listener = function () { };
  222. $loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
  223. $loop->expects($this->once())->method('removeSignal')->with($signal, $listener);
  224. Loop::set($loop);
  225. Loop::removeSignal($signal, $listener);
  226. }
  227. public function testStaticRemoveSignalWithNoDefaultLoopIsNoOp()
  228. {
  229. $ref = new \ReflectionProperty('React\EventLoop\Loop', 'instance');
  230. $ref->setAccessible(true);
  231. $ref->setValue(null, null);
  232. $signal = 1;
  233. $listener = function () { };
  234. Loop::removeSignal($signal, $listener);
  235. $this->assertNull($ref->getValue());
  236. }
  237. public function testStaticRunCallsRunOnLoopInstance()
  238. {
  239. $loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
  240. $loop->expects($this->once())->method('run')->with();
  241. Loop::set($loop);
  242. Loop::run();
  243. }
  244. public function testStaticRunWithNoDefaultLoopCallsRunsOnNewLoopInstance()
  245. {
  246. $ref = new \ReflectionProperty('React\EventLoop\Loop', 'instance');
  247. $ref->setAccessible(true);
  248. $ref->setValue(null, null);
  249. Loop::run();
  250. $this->assertInstanceOf('React\EventLoop\LoopInterface', $ref->getValue());
  251. }
  252. public function testStaticStopCallsStopOnLoopInstance()
  253. {
  254. $loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
  255. $loop->expects($this->once())->method('stop')->with();
  256. Loop::set($loop);
  257. Loop::stop();
  258. }
  259. public function testStaticStopCallWithNoDefaultLoopIsNoOp()
  260. {
  261. $ref = new \ReflectionProperty('React\EventLoop\Loop', 'instance');
  262. $ref->setAccessible(true);
  263. $ref->setValue(null, null);
  264. Loop::stop();
  265. $this->assertNull($ref->getValue());
  266. }
  267. /**
  268. * @after
  269. * @before
  270. */
  271. public function unsetLoopFromLoopAccessor()
  272. {
  273. $ref = new \ReflectionProperty('React\EventLoop\Loop', 'instance');
  274. $ref->setAccessible(true);
  275. $ref->setValue(null, null);
  276. }
  277. }