CachingExecutorTest.php 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. <?php
  2. namespace React\Tests\Dns\Query;
  3. use React\Dns\Model\Message;
  4. use React\Dns\Query\CachingExecutor;
  5. use React\Dns\Query\Query;
  6. use React\Promise\Promise;
  7. use React\Tests\Dns\TestCase;
  8. use React\Promise\Deferred;
  9. use React\Dns\Model\Record;
  10. class CachingExecutorTest extends TestCase
  11. {
  12. public function testQueryWillReturnPendingPromiseWhenCacheIsPendingWithoutSendingQueryToFallbackExecutor()
  13. {
  14. $fallback = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
  15. $fallback->expects($this->never())->method('query');
  16. $cache = $this->getMockBuilder('React\Cache\CacheInterface')->getMock();
  17. $cache->expects($this->once())->method('get')->with('reactphp.org:1:1')->willReturn(new Promise(function () { }));
  18. $executor = new CachingExecutor($fallback, $cache);
  19. $query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
  20. $promise = $executor->query($query);
  21. $promise->then($this->expectCallableNever(), $this->expectCallableNever());
  22. }
  23. public function testQueryWillReturnPendingPromiseWhenCacheReturnsMissAndWillSendSameQueryToFallbackExecutor()
  24. {
  25. $query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
  26. $fallback = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
  27. $fallback->expects($this->once())->method('query')->with($query)->willReturn(new Promise(function () { }));
  28. $cache = $this->getMockBuilder('React\Cache\CacheInterface')->getMock();
  29. $cache->expects($this->once())->method('get')->willReturn(\React\Promise\resolve(null));
  30. $executor = new CachingExecutor($fallback, $cache);
  31. $promise = $executor->query($query);
  32. $promise->then($this->expectCallableNever(), $this->expectCallableNever());
  33. }
  34. public function testQueryWillReturnResolvedPromiseWhenCacheReturnsHitWithoutSendingQueryToFallbackExecutor()
  35. {
  36. $fallback = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
  37. $fallback->expects($this->never())->method('query');
  38. $message = new Message();
  39. $cache = $this->getMockBuilder('React\Cache\CacheInterface')->getMock();
  40. $cache->expects($this->once())->method('get')->with('reactphp.org:1:1')->willReturn(\React\Promise\resolve($message));
  41. $executor = new CachingExecutor($fallback, $cache);
  42. $query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
  43. $promise = $executor->query($query);
  44. $promise->then($this->expectCallableOnceWith($message), $this->expectCallableNever());
  45. }
  46. public function testQueryWillReturnResolvedPromiseWhenCacheReturnsMissAndFallbackExecutorResolvesAndSaveMessageToCacheWithMinimumTtlFromRecord()
  47. {
  48. $message = new Message();
  49. $message->answers[] = new Record('reactphp.org', Message::TYPE_A, Message::CLASS_IN, 3700, '127.0.0.1');
  50. $message->answers[] = new Record('reactphp.org', Message::TYPE_A, Message::CLASS_IN, 3600, '127.0.0.1');
  51. $fallback = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
  52. $fallback->expects($this->once())->method('query')->willReturn(\React\Promise\resolve($message));
  53. $cache = $this->getMockBuilder('React\Cache\CacheInterface')->getMock();
  54. $cache->expects($this->once())->method('get')->with('reactphp.org:1:1')->willReturn(\React\Promise\resolve(null));
  55. $cache->expects($this->once())->method('set')->with('reactphp.org:1:1', $message, 3600);
  56. $executor = new CachingExecutor($fallback, $cache);
  57. $query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
  58. $promise = $executor->query($query);
  59. $promise->then($this->expectCallableOnceWith($message), $this->expectCallableNever());
  60. }
  61. public function testQueryWillReturnResolvedPromiseWhenCacheReturnsMissAndFallbackExecutorResolvesAndSaveMessageToCacheWithDefaultTtl()
  62. {
  63. $message = new Message();
  64. $fallback = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
  65. $fallback->expects($this->once())->method('query')->willReturn(\React\Promise\resolve($message));
  66. $cache = $this->getMockBuilder('React\Cache\CacheInterface')->getMock();
  67. $cache->expects($this->once())->method('get')->with('reactphp.org:1:1')->willReturn(\React\Promise\resolve(null));
  68. $cache->expects($this->once())->method('set')->with('reactphp.org:1:1', $message, 60);
  69. $executor = new CachingExecutor($fallback, $cache);
  70. $query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
  71. $promise = $executor->query($query);
  72. $promise->then($this->expectCallableOnceWith($message), $this->expectCallableNever());
  73. }
  74. public function testQueryWillReturnResolvedPromiseWhenCacheReturnsMissAndFallbackExecutorResolvesWithTruncatedResponseButShouldNotSaveTruncatedMessageToCache()
  75. {
  76. $message = new Message();
  77. $message->tc = true;
  78. $fallback = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
  79. $fallback->expects($this->once())->method('query')->willReturn(\React\Promise\resolve($message));
  80. $cache = $this->getMockBuilder('React\Cache\CacheInterface')->getMock();
  81. $cache->expects($this->once())->method('get')->with('reactphp.org:1:1')->willReturn(\React\Promise\resolve(null));
  82. $cache->expects($this->never())->method('set');
  83. $executor = new CachingExecutor($fallback, $cache);
  84. $query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
  85. $promise = $executor->query($query);
  86. $promise->then($this->expectCallableOnceWith($message), $this->expectCallableNever());
  87. }
  88. public function testQueryWillReturnRejectedPromiseWhenCacheReturnsMissAndFallbackExecutorRejects()
  89. {
  90. $query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
  91. $fallback = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
  92. $fallback->expects($this->once())->method('query')->willReturn(\React\Promise\reject($exception = new \RuntimeException()));
  93. $cache = $this->getMockBuilder('React\Cache\CacheInterface')->getMock();
  94. $cache->expects($this->once())->method('get')->willReturn(\React\Promise\resolve(null));
  95. $executor = new CachingExecutor($fallback, $cache);
  96. $promise = $executor->query($query);
  97. $promise->then($this->expectCallableNever(), $this->expectCallableOnceWith($exception));
  98. }
  99. public function testCancelQueryWillReturnRejectedPromiseAndCancelPendingPromiseFromCache()
  100. {
  101. $fallback = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
  102. $fallback->expects($this->never())->method('query');
  103. $pending = new Promise(function () { }, $this->expectCallableOnce());
  104. $cache = $this->getMockBuilder('React\Cache\CacheInterface')->getMock();
  105. $cache->expects($this->once())->method('get')->with('reactphp.org:1:1')->willReturn($pending);
  106. $executor = new CachingExecutor($fallback, $cache);
  107. $query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
  108. $promise = $executor->query($query);
  109. $promise->cancel();
  110. $exception = null;
  111. $promise->then(null, function ($reason) use (&$exception) {
  112. $exception = $reason;
  113. });
  114. /** @var \RuntimeException $exception */
  115. $this->assertInstanceOf('RuntimeException', $exception);
  116. $this->assertEquals('DNS query for reactphp.org (A) has been cancelled', $exception->getMessage());
  117. }
  118. public function testCancelQueryWillReturnRejectedPromiseAndCancelPendingPromiseFromFallbackExecutorWhenCacheReturnsMiss()
  119. {
  120. $pending = new Promise(function () { }, $this->expectCallableOnce());
  121. $fallback = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
  122. $fallback->expects($this->once())->method('query')->willReturn($pending);
  123. $deferred = new Deferred();
  124. $cache = $this->getMockBuilder('React\Cache\CacheInterface')->getMock();
  125. $cache->expects($this->once())->method('get')->with('reactphp.org:1:1')->willReturn($deferred->promise());
  126. $executor = new CachingExecutor($fallback, $cache);
  127. $query = new Query('reactphp.org', Message::TYPE_A, Message::CLASS_IN);
  128. $promise = $executor->query($query);
  129. $deferred->resolve(null);
  130. $promise->cancel();
  131. $exception = null;
  132. $promise->then(null, function ($reason) use (&$exception) {
  133. $exception = $reason;
  134. });
  135. /** @var \RuntimeException $exception */
  136. $this->assertInstanceOf('RuntimeException', $exception);
  137. $this->assertEquals('DNS query for reactphp.org (A) has been cancelled', $exception->getMessage());
  138. }
  139. }