ResolverTest.php 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. <?php
  2. namespace React\Tests\Dns\Resolver;
  3. use React\Dns\Resolver\Resolver;
  4. use React\Dns\Query\Query;
  5. use React\Dns\Model\Message;
  6. use React\Dns\Model\Record;
  7. use React\Promise;
  8. use React\Tests\Dns\TestCase;
  9. use React\Dns\RecordNotFoundException;
  10. class ResolverTest extends TestCase
  11. {
  12. /** @test */
  13. public function resolveShouldQueryARecords()
  14. {
  15. $executor = $this->createExecutorMock();
  16. $executor
  17. ->expects($this->once())
  18. ->method('query')
  19. ->with($this->isInstanceOf('React\Dns\Query\Query'))
  20. ->will($this->returnCallback(function ($query) {
  21. $response = new Message();
  22. $response->qr = true;
  23. $response->questions[] = new Query($query->name, $query->type, $query->class);
  24. $response->answers[] = new Record($query->name, $query->type, $query->class, 3600, '178.79.169.131');
  25. return Promise\resolve($response);
  26. }));
  27. $resolver = new Resolver($executor);
  28. $resolver->resolve('igor.io')->then($this->expectCallableOnceWith('178.79.169.131'));
  29. }
  30. /** @test */
  31. public function resolveAllShouldQueryGivenRecords()
  32. {
  33. $executor = $this->createExecutorMock();
  34. $executor
  35. ->expects($this->once())
  36. ->method('query')
  37. ->with($this->isInstanceOf('React\Dns\Query\Query'))
  38. ->will($this->returnCallback(function ($query) {
  39. $response = new Message();
  40. $response->qr = true;
  41. $response->questions[] = new Query($query->name, $query->type, $query->class);
  42. $response->answers[] = new Record($query->name, $query->type, $query->class, 3600, '::1');
  43. return Promise\resolve($response);
  44. }));
  45. $resolver = new Resolver($executor);
  46. $resolver->resolveAll('reactphp.org', Message::TYPE_AAAA)->then($this->expectCallableOnceWith(array('::1')));
  47. }
  48. /** @test */
  49. public function resolveAllShouldIgnoreRecordsWithOtherTypes()
  50. {
  51. $executor = $this->createExecutorMock();
  52. $executor
  53. ->expects($this->once())
  54. ->method('query')
  55. ->with($this->isInstanceOf('React\Dns\Query\Query'))
  56. ->will($this->returnCallback(function ($query) {
  57. $response = new Message();
  58. $response->qr = true;
  59. $response->questions[] = new Query($query->name, $query->type, $query->class);
  60. $response->answers[] = new Record($query->name, Message::TYPE_TXT, $query->class, 3600, array('ignored'));
  61. $response->answers[] = new Record($query->name, $query->type, $query->class, 3600, '::1');
  62. return Promise\resolve($response);
  63. }));
  64. $resolver = new Resolver($executor);
  65. $resolver->resolveAll('reactphp.org', Message::TYPE_AAAA)->then($this->expectCallableOnceWith(array('::1')));
  66. }
  67. /** @test */
  68. public function resolveAllShouldReturnMultipleValuesForAlias()
  69. {
  70. $executor = $this->createExecutorMock();
  71. $executor
  72. ->expects($this->once())
  73. ->method('query')
  74. ->with($this->isInstanceOf('React\Dns\Query\Query'))
  75. ->will($this->returnCallback(function ($query) {
  76. $response = new Message();
  77. $response->qr = true;
  78. $response->questions[] = new Query($query->name, $query->type, $query->class);
  79. $response->answers[] = new Record($query->name, Message::TYPE_CNAME, $query->class, 3600, 'example.com');
  80. $response->answers[] = new Record('example.com', $query->type, $query->class, 3600, '::1');
  81. $response->answers[] = new Record('example.com', $query->type, $query->class, 3600, '::2');
  82. return Promise\resolve($response);
  83. }));
  84. $resolver = new Resolver($executor);
  85. $resolver->resolveAll('reactphp.org', Message::TYPE_AAAA)->then(
  86. $this->expectCallableOnceWith($this->equalTo(array('::1', '::2')))
  87. );
  88. }
  89. /** @test */
  90. public function resolveShouldQueryARecordsAndIgnoreCase()
  91. {
  92. $executor = $this->createExecutorMock();
  93. $executor
  94. ->expects($this->once())
  95. ->method('query')
  96. ->with($this->isInstanceOf('React\Dns\Query\Query'))
  97. ->will($this->returnCallback(function ($query) {
  98. $response = new Message();
  99. $response->qr = true;
  100. $response->questions[] = new Query('Blog.wyrihaximus.net', $query->type, $query->class);
  101. $response->answers[] = new Record('Blog.wyrihaximus.net', $query->type, $query->class, 3600, '178.79.169.131');
  102. return Promise\resolve($response);
  103. }));
  104. $resolver = new Resolver($executor);
  105. $resolver->resolve('blog.wyrihaximus.net')->then($this->expectCallableOnceWith('178.79.169.131'));
  106. }
  107. /** @test */
  108. public function resolveShouldFilterByName()
  109. {
  110. $executor = $this->createExecutorMock();
  111. $executor
  112. ->expects($this->once())
  113. ->method('query')
  114. ->with($this->isInstanceOf('React\Dns\Query\Query'))
  115. ->will($this->returnCallback(function ($query) {
  116. $response = new Message();
  117. $response->qr = true;
  118. $response->questions[] = new Query($query->name, $query->type, $query->class);
  119. $response->answers[] = new Record('foo.bar', $query->type, $query->class, 3600, '178.79.169.131');
  120. return Promise\resolve($response);
  121. }));
  122. $errback = $this->expectCallableOnceWith($this->isInstanceOf('React\Dns\RecordNotFoundException'));
  123. $resolver = new Resolver($executor);
  124. $resolver->resolve('igor.io')->then($this->expectCallableNever(), $errback);
  125. }
  126. /**
  127. * @test
  128. */
  129. public function resolveWithNoAnswersShouldCallErrbackIfGiven()
  130. {
  131. $executor = $this->createExecutorMock();
  132. $executor
  133. ->expects($this->once())
  134. ->method('query')
  135. ->with($this->isInstanceOf('React\Dns\Query\Query'))
  136. ->will($this->returnCallback(function ($query) {
  137. $response = new Message();
  138. $response->qr = true;
  139. $response->questions[] = new Query($query->name, $query->type, $query->class);
  140. return Promise\resolve($response);
  141. }));
  142. $errback = $this->expectCallableOnceWith($this->callback(function ($param) {
  143. return ($param instanceof RecordNotFoundException && $param->getCode() === 0 && $param->getMessage() === 'DNS query for igor.io (A) did not return a valid answer (NOERROR / NODATA)');
  144. }));
  145. $resolver = new Resolver($executor);
  146. $resolver->resolve('igor.io')->then($this->expectCallableNever(), $errback);
  147. }
  148. public function provideRcodeErrors()
  149. {
  150. return array(
  151. array(
  152. Message::RCODE_FORMAT_ERROR,
  153. 'DNS query for example.com (A) returned an error response (Format Error)',
  154. ),
  155. array(
  156. Message::RCODE_SERVER_FAILURE,
  157. 'DNS query for example.com (A) returned an error response (Server Failure)',
  158. ),
  159. array(
  160. Message::RCODE_NAME_ERROR,
  161. 'DNS query for example.com (A) returned an error response (Non-Existent Domain / NXDOMAIN)'
  162. ),
  163. array(
  164. Message::RCODE_NOT_IMPLEMENTED,
  165. 'DNS query for example.com (A) returned an error response (Not Implemented)'
  166. ),
  167. array(
  168. Message::RCODE_REFUSED,
  169. 'DNS query for example.com (A) returned an error response (Refused)'
  170. ),
  171. array(
  172. 99,
  173. 'DNS query for example.com (A) returned an error response (Unknown error response code 99)'
  174. )
  175. );
  176. }
  177. /**
  178. * @test
  179. * @dataProvider provideRcodeErrors
  180. */
  181. public function resolveWithRcodeErrorShouldCallErrbackIfGiven($code, $expectedMessage)
  182. {
  183. $executor = $this->createExecutorMock();
  184. $executor
  185. ->expects($this->once())
  186. ->method('query')
  187. ->with($this->isInstanceOf('React\Dns\Query\Query'))
  188. ->will($this->returnCallback(function ($query) use ($code) {
  189. $response = new Message();
  190. $response->qr = true;
  191. $response->rcode = $code;
  192. $response->questions[] = new Query($query->name, $query->type, $query->class);
  193. return Promise\resolve($response);
  194. }));
  195. $errback = $this->expectCallableOnceWith($this->callback(function ($param) use ($code, $expectedMessage) {
  196. return ($param instanceof RecordNotFoundException && $param->getCode() === $code && $param->getMessage() === $expectedMessage);
  197. }));
  198. $resolver = new Resolver($executor);
  199. $resolver->resolve('example.com')->then($this->expectCallableNever(), $errback);
  200. }
  201. private function createExecutorMock()
  202. {
  203. return $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
  204. }
  205. }