<?php namespace React\Tests\Dns\Query; use PHPUnit\Framework\TestCase; use React\Cache\ArrayCache; use React\Dns\Model\Message; use React\Dns\Model\Record; use React\Dns\Query\RecordCache; use React\Dns\Query\Query; use React\Promise\PromiseInterface; use React\Promise\Promise; class RecordCacheTest extends TestCase { /** * @covers React\Dns\Query\RecordCache * @test */ public function lookupOnNewCacheMissShouldReturnNull() { $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); $base = $this->getMockBuilder('React\Cache\CacheInterface')->getMock(); $base->expects($this->once())->method('get')->willReturn(\React\Promise\resolve(null)); $cache = new RecordCache($base); $promise = $cache->lookup($query); $this->assertInstanceOf('React\Promise\RejectedPromise', $promise); } /** * @covers React\Dns\Query\RecordCache * @test */ public function lookupOnLegacyCacheMissShouldReturnNull() { $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); $base = $this->getMockBuilder('React\Cache\CacheInterface')->getMock(); $base->expects($this->once())->method('get')->willReturn(\React\Promise\reject()); $cache = new RecordCache($base); $promise = $cache->lookup($query); $this->assertInstanceOf('React\Promise\RejectedPromise', $promise); } /** * @covers React\Dns\Query\RecordCache * @test */ public function storeRecordPendingCacheDoesNotSetCache() { $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); $pending = new Promise(function () { }); $base = $this->getMockBuilder('React\Cache\CacheInterface')->getMock(); $base->expects($this->once())->method('get')->willReturn($pending); $base->expects($this->never())->method('set'); $cache = new RecordCache($base); $cache->storeRecord($query->currentTime, new Record('igor.io', Message::TYPE_A, Message::CLASS_IN, 3600, '178.79.169.131')); } /** * @covers React\Dns\Query\RecordCache * @test */ public function storeRecordOnNewCacheMissSetsCache() { $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); $base = $this->getMockBuilder('React\Cache\CacheInterface')->getMock(); $base->expects($this->once())->method('get')->willReturn(\React\Promise\resolve(null)); $base->expects($this->once())->method('set')->with($this->isType('string'), $this->isType('string')); $cache = new RecordCache($base); $cache->storeRecord($query->currentTime, new Record('igor.io', Message::TYPE_A, Message::CLASS_IN, 3600, '178.79.169.131')); } /** * @covers React\Dns\Query\RecordCache * @test */ public function storeRecordOnOldCacheMissSetsCache() { $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); $base = $this->getMockBuilder('React\Cache\CacheInterface')->getMock(); $base->expects($this->once())->method('get')->willReturn(\React\Promise\reject()); $base->expects($this->once())->method('set')->with($this->isType('string'), $this->isType('string')); $cache = new RecordCache($base); $cache->storeRecord($query->currentTime, new Record('igor.io', Message::TYPE_A, Message::CLASS_IN, 3600, '178.79.169.131')); } /** * @covers React\Dns\Query\RecordCache * @test */ public function storeRecordShouldMakeLookupSucceed() { $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); $cache = new RecordCache(new ArrayCache()); $cache->storeRecord($query->currentTime, new Record('igor.io', Message::TYPE_A, Message::CLASS_IN, 3600, '178.79.169.131')); $promise = $cache->lookup($query); $this->assertInstanceOf('React\Promise\FulfilledPromise', $promise); $cachedRecords = $this->getPromiseValue($promise); $this->assertCount(1, $cachedRecords); $this->assertSame('178.79.169.131', $cachedRecords[0]->data); } /** * @covers React\Dns\Query\RecordCache * @test */ public function storeTwoRecordsShouldReturnBoth() { $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); $cache = new RecordCache(new ArrayCache()); $cache->storeRecord($query->currentTime, new Record('igor.io', Message::TYPE_A, Message::CLASS_IN, 3600, '178.79.169.131')); $cache->storeRecord($query->currentTime, new Record('igor.io', Message::TYPE_A, Message::CLASS_IN, 3600, '178.79.169.132')); $promise = $cache->lookup($query); $this->assertInstanceOf('React\Promise\FulfilledPromise', $promise); $cachedRecords = $this->getPromiseValue($promise); $this->assertCount(2, $cachedRecords); $this->assertSame('178.79.169.131', $cachedRecords[0]->data); $this->assertSame('178.79.169.132', $cachedRecords[1]->data); } /** * @covers React\Dns\Query\RecordCache * @test */ public function storeResponseMessageShouldStoreAllAnswerValues() { $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, 1345656451); $response = new Message(); $response->answers[] = new Record('igor.io', Message::TYPE_A, Message::CLASS_IN, 3600, '178.79.169.131'); $response->answers[] = new Record('igor.io', Message::TYPE_A, Message::CLASS_IN, 3600, '178.79.169.132'); $response->prepare(); $cache = new RecordCache(new ArrayCache()); $cache->storeResponseMessage($query->currentTime, $response); $promise = $cache->lookup($query); $this->assertInstanceOf('React\Promise\FulfilledPromise', $promise); $cachedRecords = $this->getPromiseValue($promise); $this->assertCount(2, $cachedRecords); $this->assertSame('178.79.169.131', $cachedRecords[0]->data); $this->assertSame('178.79.169.132', $cachedRecords[1]->data); } /** * @covers React\Dns\Query\RecordCache * @test */ public function expireShouldExpireDeadRecords() { $cachedTime = 1345656451; $currentTime = $cachedTime + 3605; $cache = new RecordCache(new ArrayCache()); $cache->storeRecord($cachedTime, new Record('igor.io', Message::TYPE_A, Message::CLASS_IN, 3600, '178.79.169.131')); $cache->expire($currentTime); $query = new Query('igor.io', Message::TYPE_A, Message::CLASS_IN, $currentTime); $promise = $cache->lookup($query); $this->assertInstanceOf('React\Promise\RejectedPromise', $promise); } private function getPromiseValue(PromiseInterface $promise) { $capturedValue = null; $promise->then(function ($value) use (&$capturedValue) { $capturedValue = $value; }); return $capturedValue; } }