diff --git a/PRedis.php b/PRedis.php index a36b058..55a0316 100644 --- a/PRedis.php +++ b/PRedis.php @@ -37,7 +37,9 @@ public function lpush($key, $value) public function brpop($key, $timeout) { try { - return $this->brpop($key, (int) $timeout / 1000); + if ($result = $this->redis->brpop($key, $timeout)) { + return $result[1]; + } } catch (PRedisServerException $e) { throw new ServerException('brpop command has failed', null, $e); } @@ -48,19 +50,33 @@ public function brpop($key, $timeout) */ public function rpop($key) { try { - return $this->rpop($key); + return $this->redis->rpop($key); } catch (PRedisServerException $e) { throw new ServerException('rpop command has failed', null, $e); } } + /** + * {@inheritdoc} + */ public function connect() { $this->redis->connect(); } + /** + * {@inheritdoc} + */ public function disconnect() { $this->redis->disconnect(); } + + /** + * {@inheritdoc} + */ + public function del($key) + { + $this->redis->del([$key]); + } } diff --git a/PhpRedis.php b/PhpRedis.php index 1c767ff..94a0d89 100644 --- a/PhpRedis.php +++ b/PhpRedis.php @@ -14,13 +14,10 @@ class PhpRedis implements Redis private $config; /** - * @param \Redis $redis * @param array $config */ - public function __construct(\Redis $redis, array $config) + public function __construct(array $config) { - $this->redis = $redis; - $this->config = array_replace([ 'host' => null, 'port' => null, @@ -59,6 +56,9 @@ public function rpop($key) return $this->redis->rPop($key); } + /** + * {@inheritdoc} + */ public function connect() { if (false == $this->redis) { @@ -84,10 +84,21 @@ public function connect() return $this->redis; } + /** + * {@inheritdoc} + */ public function disconnect() { if ($this->redis) { $this->redis->close(); } } + + /** + * {@inheritdoc} + */ + public function del($key) + { + $this->redis->del($key); + } } diff --git a/Redis.php b/Redis.php index 8e69466..f14edc8 100644 --- a/Redis.php +++ b/Redis.php @@ -29,4 +29,9 @@ public function rpop($key); public function connect(); public function disconnect(); + + /** + * @param string $key + */ + public function del($key); } diff --git a/RedisConnectionFactory.php b/RedisConnectionFactory.php index 37d2bf5..28af729 100644 --- a/RedisConnectionFactory.php +++ b/RedisConnectionFactory.php @@ -63,10 +63,7 @@ public function createContext() { if ($this->config['lazy']) { return new RedisContext(function () { - $redis = $this->createRedis(); - $redis->connect(); - - return $redis; + return $this->createRedis(); }); } @@ -78,12 +75,16 @@ public function createContext() */ private function createRedis() { - if ('phpredis' == $this->config['vendor'] && false == $this->redis) { - $this->redis = new PhpRedis(new \Redis(), $this->config); - } + if (false == $this->redis) { + if ('phpredis' == $this->config['vendor'] && false == $this->redis) { + $this->redis = new PhpRedis($this->config); + } + + if ('predis' == $this->config['vendor'] && false == $this->redis) { + $this->redis = new PRedis(new Client($this->config, ['exceptions' => true])); + } - if ('predis' == $this->config['vendor'] && false == $this->redis) { - $this->redis = new PRedis(new Client($this->config, ['exceptions' => true])); + $this->redis->connect(); } return $this->redis; diff --git a/RedisContext.php b/RedisContext.php index 370398d..6dab888 100644 --- a/RedisContext.php +++ b/RedisContext.php @@ -5,6 +5,8 @@ use Enqueue\Psr\InvalidDestinationException; use Enqueue\Psr\PsrContext; use Enqueue\Psr\PsrDestination; +use Enqueue\Psr\PsrQueue; +use Enqueue\Psr\PsrTopic; class RedisContext implements PsrContext { @@ -68,6 +70,26 @@ public function createQueue($queueName) return new RedisDestination($queueName); } + /** + * @param RedisDestination|PsrQueue $queue + */ + public function deleteQueue(PsrQueue $queue) + { + InvalidDestinationException::assertDestinationInstanceOf($queue, RedisDestination::class); + + $this->getRedis()->del($queue->getName()); + } + + /** + * @param RedisDestination|PsrTopic $topic + */ + public function deleteTopic(PsrTopic $topic) + { + InvalidDestinationException::assertDestinationInstanceOf($topic, RedisDestination::class); + + $this->getRedis()->del($topic->getName()); + } + /** * {@inheritdoc} */ @@ -102,7 +124,7 @@ public function createConsumer(PsrDestination $destination) public function close() { - $this->getRedis()->close(); + $this->getRedis()->disconnect(); } /** diff --git a/Tests/Functional/CommonUseCasesTrait.php b/Tests/Functional/CommonUseCasesTrait.php new file mode 100644 index 0000000..ac12adb --- /dev/null +++ b/Tests/Functional/CommonUseCasesTrait.php @@ -0,0 +1,127 @@ +getContext()->createQueue('enqueue.test_queue'); + + $startAt = microtime(true); + + $consumer = $this->getContext()->createConsumer($queue); + $message = $consumer->receive(2000); + + $endAt = microtime(true); + + $this->assertNull($message); + + $this->assertGreaterThan(1.5, $endAt - $startAt); + $this->assertLessThan(2.5, $endAt - $startAt); + } + + public function testReturnNullImmediatelyOnReceiveNoWait() + { + $queue = $this->getContext()->createQueue('enqueue.test_queue'); + + $startAt = microtime(true); + + $consumer = $this->getContext()->createConsumer($queue); + $message = $consumer->receiveNoWait(); + + $endAt = microtime(true); + + $this->assertNull($message); + + $this->assertLessThan(0.5, $endAt - $startAt); + } + + public function testProduceAndReceiveOneMessageSentDirectlyToQueue() + { + $queue = $this->getContext()->createQueue('enqueue.test_queue'); + + $message = $this->getContext()->createMessage( + __METHOD__, + ['FooProperty' => 'FooVal'], + ['BarHeader' => 'BarVal'] + ); + + $producer = $this->getContext()->createProducer(); + $producer->send($queue, $message); + + $consumer = $this->getContext()->createConsumer($queue); + $message = $consumer->receive(1000); + + $this->assertInstanceOf(RedisMessage::class, $message); + $consumer->acknowledge($message); + + $this->assertEquals(__METHOD__, $message->getBody()); + $this->assertEquals(['FooProperty' => 'FooVal'], $message->getProperties()); + $this->assertEquals(['BarHeader' => 'BarVal'], $message->getHeaders()); + } + + public function testProduceAndReceiveOneMessageSentDirectlyToTopic() + { + $topic = $this->getContext()->createTopic('enqueue.test_topic'); + + $message = $this->getContext()->createMessage(__METHOD__); + + $producer = $this->getContext()->createProducer(); + $producer->send($topic, $message); + + $consumer = $this->getContext()->createConsumer($topic); + $message = $consumer->receive(1000); + + $this->assertInstanceOf(RedisMessage::class, $message); + $consumer->acknowledge($message); + + $this->assertEquals(__METHOD__, $message->getBody()); + } + + public function testConsumerReceiveMessageWithZeroTimeout() + { + $topic = $this->getContext()->createTopic('enqueue.test_topic'); + + $consumer = $this->getContext()->createConsumer($topic); + + //guard + $this->assertNull($consumer->receive(1000)); + + $message = $this->getContext()->createMessage(__METHOD__); + + $producer = $this->getContext()->createProducer(); + $producer->send($topic, $message); + usleep(100); + $actualMessage = $consumer->receive(0); + + $this->assertInstanceOf(RedisMessage::class, $actualMessage); + $consumer->acknowledge($message); + + $this->assertEquals(__METHOD__, $message->getBody()); + } + + public function testShouldReceiveMessagesInExpectedOrder() + { + $queue = $this->getContext()->createQueue('enqueue.test_queue'); + + $producer = $this->getContext()->createProducer(); + $producer->send($queue, $this->getContext()->createMessage(1)); + $producer->send($queue, $this->getContext()->createMessage(2)); + $producer->send($queue, $this->getContext()->createMessage(3)); + + $consumer = $this->getContext()->createConsumer($queue); + + $this->assertSame(1, $consumer->receiveNoWait()->getBody()); + $this->assertSame(2, $consumer->receiveNoWait()->getBody()); + $this->assertSame(3, $consumer->receiveNoWait()->getBody()); + } + + /** + * @return RedisContext + */ + abstract protected function getContext(); +} diff --git a/Tests/Functional/PRedisCommonUseCasesTest.php b/Tests/Functional/PRedisCommonUseCasesTest.php new file mode 100644 index 0000000..8c95e47 --- /dev/null +++ b/Tests/Functional/PRedisCommonUseCasesTest.php @@ -0,0 +1,42 @@ +context = $this->buildPRedisContext(); + + $this->context->deleteQueue($this->context->createQueue('enqueue.test_queue')); + $this->context->deleteTopic($this->context->createTopic('enqueue.test_topic')); + } + + public function tearDown() + { + $this->context->close(); + } + + /** + * {@inheritdoc} + */ + protected function getContext() + { + return $this->context; + } +} diff --git a/Tests/Functional/PhpRedisCommonUseCasesTest.php b/Tests/Functional/PhpRedisCommonUseCasesTest.php new file mode 100644 index 0000000..2d5559d --- /dev/null +++ b/Tests/Functional/PhpRedisCommonUseCasesTest.php @@ -0,0 +1,42 @@ +context = $this->buildPhpRedisContext(); + + $this->context->deleteQueue($this->context->createQueue('enqueue.test_queue')); + $this->context->deleteTopic($this->context->createTopic('enqueue.test_topic')); + } + + public function tearDown() + { + $this->context->close(); + } + + /** + * {@inheritdoc} + */ + protected function getContext() + { + return $this->context; + } +} diff --git a/Tests/RedisConnectionFactoryTest.php b/Tests/RedisConnectionFactoryTest.php index 8a8b1f9..7a19de4 100644 --- a/Tests/RedisConnectionFactoryTest.php +++ b/Tests/RedisConnectionFactoryTest.php @@ -1,13 +1,14 @@ null, 'persisted' => false, 'lazy' => true, + 'vendor' => 'phpredis' ], 'config', $factory); } @@ -43,6 +45,7 @@ public function testCouldBeConstructedWithCustomConfiguration() 'retry_interval' => null, 'persisted' => false, 'lazy' => true, + 'vendor' => 'phpredis' ], 'config', $factory); } diff --git a/Tests/RedisConsumerTest.php b/Tests/RedisConsumerTest.php new file mode 100644 index 0000000..555206e --- /dev/null +++ b/Tests/RedisConsumerTest.php @@ -0,0 +1,202 @@ +assertClassImplements(PsrConsumer::class, RedisConsumer::class); + } + + public function testCouldBeConstructedWithContextAndDestinationAndPreFetchCountAsArguments() + { + new RedisConsumer($this->createContextMock(), new RedisDestination('aQueue')); + } + + public function testShouldReturnDestinationSetInConstructorOnGetQueue() + { + $destination = new RedisDestination('aQueue'); + + $consumer = new RedisConsumer($this->createContextMock(), $destination, 1); + + $this->assertSame($destination, $consumer->getQueue()); + } + + public function testShouldDoNothingOnAcknowledge() + { + $consumer = new RedisConsumer($this->createContextMock(), new RedisDestination('aQueue')); + + $consumer->acknowledge(new RedisMessage()); + } + + public function testShouldDoNothingOnReject() + { + $consumer = new RedisConsumer($this->createContextMock(), new RedisDestination('aQueue')); + + $consumer->reject(new RedisMessage()); + } + + public function testShouldSendSameMessageToDestinationOnReQueue() + { + $message = new RedisMessage(); + + $destination = new RedisDestination('aQueue'); + + $producerMock = $this->createProducerMock(); + $producerMock + ->expects($this->once()) + ->method('send') + ->with($this->identicalTo($destination), $this->identicalTo($message)) + ; + + $contextMock = $this->createContextMock(); + $contextMock + ->expects($this->once()) + ->method('createProducer') + ->willReturn($producerMock) + ; + + $consumer = new RedisConsumer($contextMock, $destination); + + $consumer->reject($message, true); + } + + public function testShouldCallRedisBRPopAndReturnNullIfNothingInQueueOnReceive() + { + $destination = new RedisDestination('aQueue'); + + $redisMock = $this->createRedisMock(); + $redisMock + ->expects($this->once()) + ->method('brpop') + ->with('aQueue', 2) + ->willReturn(null) + ; + + $contextMock = $this->createContextMock(); + $contextMock + ->expects($this->once()) + ->method('getRedis') + ->willReturn($redisMock) + ; + + $consumer = new RedisConsumer($contextMock, $destination); + + $this->assertNull($consumer->receive(2000)); + } + + public function testShouldCallRedisBRPopAndReturnMessageIfOneInQueueOnReceive() + { + $destination = new RedisDestination('aQueue'); + + $redisMock = $this->createRedisMock(); + $redisMock + ->expects($this->once()) + ->method('brpop') + ->with('aQueue', 2) + ->willReturn(json_encode(new RedisMessage('aBody'))) + ; + + $contextMock = $this->createContextMock(); + $contextMock + ->expects($this->once()) + ->method('getRedis') + ->willReturn($redisMock) + ; + + $consumer = new RedisConsumer($contextMock, $destination); + + $message = $consumer->receive(2000); + + $this->assertInstanceOf(RedisMessage::class, $message); + $this->assertSame('aBody', $message->getBody()); + } + + public function testShouldCallRedisRPopAndReturnNullIfNothingInQueueOnReceiveNoWait() + { + $destination = new RedisDestination('aQueue'); + + $redisMock = $this->createRedisMock(); + $redisMock + ->expects($this->once()) + ->method('rpop') + ->with('aQueue') + ->willReturn(null) + ; + + $contextMock = $this->createContextMock(); + $contextMock + ->expects($this->once()) + ->method('getRedis') + ->willReturn($redisMock) + ; + + $consumer = new RedisConsumer($contextMock, $destination); + + $this->assertNull($consumer->receiveNoWait()); + } + + public function testShouldCallRedisRPopAndReturnMessageIfOneInQueueOnReceiveNoWait() + { + $destination = new RedisDestination('aQueue'); + + $redisMock = $this->createRedisMock(); + $redisMock + ->expects($this->once()) + ->method('rpop') + ->with('aQueue') + ->willReturn(json_encode(new RedisMessage('aBody'))) + ; + + $contextMock = $this->createContextMock(); + $contextMock + ->expects($this->once()) + ->method('getRedis') + ->willReturn($redisMock) + ; + + $consumer = new RedisConsumer($contextMock, $destination); + + $message = $consumer->receiveNoWait(); + + $this->assertInstanceOf(RedisMessage::class, $message); + $this->assertSame('aBody', $message->getBody()); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|Redis + */ + private function createRedisMock() + { + return $this->createMock(Redis::class); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|RedisProducer + */ + private function createProducerMock() + { + return $this->createMock(RedisProducer::class); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|RedisContext + */ + private function createContextMock() + { + return $this->createMock(RedisContext::class); + } +} diff --git a/Tests/RedisContextTest.php b/Tests/RedisContextTest.php index 945ab31..dd6d02d 100644 --- a/Tests/RedisContextTest.php +++ b/Tests/RedisContextTest.php @@ -2,6 +2,7 @@ namespace Enqueue\Redis\Tests; +use Enqueue\Redis\Redis; use Enqueue\Redis\RedisConsumer; use Enqueue\Redis\RedisContext; use Enqueue\Redis\RedisDestination; @@ -11,9 +12,10 @@ use Enqueue\Psr\PsrContext; use Enqueue\Test\ClassExtensionTrait; use Enqueue\Transport\Null\NullQueue; -use Makasim\File\TempFile; +use Enqueue\Transport\Null\NullTopic; +use PHPUnit\Framework\TestCase; -class RedisContextTest extends \PHPUnit_Framework_TestCase +class RedisContextTest extends \PHPUnit\Framework\TestCase { use ClassExtensionTrait; @@ -22,223 +24,189 @@ public function testShouldImplementContextInterface() $this->assertClassImplements(PsrContext::class, RedisContext::class); } - public function testCouldBeConstructedWithExpectedArguments() + public function testCouldBeConstructedWithRedisAsFirstArgument() { new RedisContext($this->createRedisMock()); } -// public function testShouldAllowCreateEmptyMessage() -// { -// $context = new RedisContext($this->createRedisMock()); -// -// $message = $context->createMessage(); -// -// $this->assertInstanceOf(RedisMessage::class, $message); -// -// $this->assertSame('', $message->getBody()); -// $this->assertSame([], $message->getProperties()); -// $this->assertSame([], $message->getHeaders()); -// } -// -// public function testShouldAllowCreateCustomMessage() -// { -// $context = new RedisContext($this->createRedisMock()); -// -// $message = $context->createMessage('theBody', ['aProp' => 'aPropVal'], ['aHeader' => 'aHeaderVal']); -// -// $this->assertInstanceOf(RedisMessage::class, $message); -// -// $this->assertSame('theBody', $message->getBody()); -// $this->assertSame(['aProp' => 'aPropVal'], $message->getProperties()); -// $this->assertSame(['aHeader' => 'aHeaderVal'], $message->getHeaders()); -// } -// -// public function testShouldCreateQueue() -// { -// $tmpFile = new TempFile(sys_get_temp_dir().'/foo'); -// -// $context = new RedisContext($this->createRedisMock()); -// -// $queue = $context->createQueue($tmpFile->getFilename()); -// -// $this->assertInstanceOf(RedisDestination::class, $queue); -// $this->assertInstanceOf(\SplFileInfo::class, $queue->getFileInfo()); -// $this->assertSame((string) $tmpFile, (string) $queue->getFileInfo()); -// -// $this->assertSame($tmpFile->getFilename(), $queue->getTopicName()); -// } -// -// public function testShouldAllowCreateTopic() -// { -// $tmpFile = new TempFile(sys_get_temp_dir().'/foo'); -// -// $context = new RedisContext($this->createRedisMock()); -// -// $topic = $context->createTopic($tmpFile->getFilename()); -// -// $this->assertInstanceOf(RedisDestination::class, $topic); -// $this->assertInstanceOf(\SplFileInfo::class, $topic->getFileInfo()); -// $this->assertSame((string) $tmpFile, (string) $topic->getFileInfo()); -// -// $this->assertSame($tmpFile->getFilename(), $topic->getTopicName()); -// } -// -// public function testShouldAllowCreateTmpQueue() -// { -// $tmpFile = new TempFile(sys_get_temp_dir().'/foo'); -// -// $context = new RedisContext($this->createRedisMock()); -// -// $queue = $context->createTemporaryQueue(); -// -// $this->assertInstanceOf(RedisDestination::class, $queue); -// $this->assertInstanceOf(TempFile::class, $queue->getFileInfo()); -// $this->assertNotEmpty($queue->getQueueName()); -// } -// -// public function testShouldCreateProducer() -// { -// $tmpFile = new TempFile(sys_get_temp_dir().'/foo'); -// -// $context = new RedisContext($this->createRedisMock()); -// -// $producer = $context->createProducer(); -// -// $this->assertInstanceOf(RedisProducer::class, $producer); -// } -// -// public function testShouldThrowIfNotRedisDestinationGivenOnCreateConsumer() -// { -// $tmpFile = new TempFile(sys_get_temp_dir().'/foo'); -// -// $context = new RedisContext($this->createRedisMock()); -// -// $this->expectException(InvalidDestinationException::class); -// $this->expectExceptionMessage('The destination must be an instance of Enqueue\Redis\RedisDestination but got Enqueue\Transport\Null\NullQueue.'); -// $consumer = $context->createConsumer(new NullQueue('aQueue')); -// -// $this->assertInstanceOf(RedisConsumer::class, $consumer); -// } -// -// public function testShouldCreateConsumer() -// { -// $tmpFile = new TempFile(sys_get_temp_dir().'/foo'); -// -// $context = new RedisContext($this->createRedisMock()); -// -// $queue = $context->createQueue($tmpFile->getFilename()); -// -// $context->createConsumer($queue); -// } -// -// public function testShouldPropagatePreFetchCountToCreatedConsumer() -// { -// $tmpFile = new TempFile(sys_get_temp_dir().'/foo'); -// -// $context = new RedisContext($this->createRedisMock()); -// -// $queue = $context->createQueue($tmpFile->getFilename()); -// -// $consumer = $context->createConsumer($queue); -// -// // guard -// $this->assertInstanceOf(RedisConsumer::class, $consumer); -// -// $this->assertAttributeSame(123, 'preFetchCount', $consumer); -// } -// -// public function testShouldAllowGetPreFetchCountSetInConstructor() -// { -// $tmpFile = new TempFile(sys_get_temp_dir().'/foo'); -// -// $context = new RedisContext($this->createRedisMock()); -// -// $this->assertSame(123, $context->getPreFetchCount()); -// } -// -// public function testShouldAllowGetPreviouslySetPreFetchCount() -// { -// $tmpFile = new TempFile(sys_get_temp_dir().'/foo'); -// -// $context = new RedisContext($this->createRedisMock()); -// -// $context->setPreFetchCount(456); -// -// $this->assertSame(456, $context->getPreFetchCount()); -// } -// -// public function testShouldAllowPurgeMessagesFromQueue() -// { -// $tmpFile = new TempFile(sys_get_temp_dir().'/foo'); -// -// file_put_contents($tmpFile, 'foo'); -// -// $context = new RedisContext($this->createRedisMock()); -// -// $queue = $context->createQueue($tmpFile->getFilename()); -// -// $context->purge($queue); -// -// $this->assertEmpty(file_get_contents($tmpFile)); -// } -// -// public function testShouldReleaseAllLocksOnClose() -// { -// new TempFile(sys_get_temp_dir().'/foo'); -// new TempFile(sys_get_temp_dir().'/bar'); -// -// $context = new RedisContext($this->createRedisMock()); -// -// $fooQueue = $context->createQueue('foo'); -// $barQueue = $context->createTopic('bar'); -// -// $this->assertAttributeCount(0, 'lockHandlers', $context); -// -// $context->workWithFile($fooQueue, 'r+', function () { -// }); -// $context->workWithFile($barQueue, 'r+', function () { -// }); -// $context->workWithFile($fooQueue, 'c+', function () { -// }); -// $context->workWithFile($barQueue, 'c+', function () { -// }); -// -// $this->assertAttributeCount(2, 'lockHandlers', $context); -// -// $context->close(); -// -// $this->assertAttributeCount(0, 'lockHandlers', $context); -// } -// -// public function testShouldCreateFileOnFilesystemIfNotExistOnDeclareDestination() -// { -// $tmpFile = new TempFile(sys_get_temp_dir().'/'.uniqid()); -// -// $context = new RedisContext(sys_get_temp_dir(), 1, 0666); -// -// $queue = $context->createQueue($tmpFile->getFilename()); -// -// $this->assertFileNotExists((string) $tmpFile); -// -// $context->declareDestination($queue); -// -// $this->assertFileExists((string) $tmpFile); -// $this->assertTrue(is_readable($tmpFile)); -// $this->assertTrue(is_writable($tmpFile)); -// -// // do nothing if file already exists -// $context->declareDestination($queue); -// -// $this->assertFileExists((string) $tmpFile); -// -// unlink($tmpFile); -// } + public function testCouldBeConstructedWithRedisFactoryAsFirstArgument() + { + new RedisContext(function() { + return $this->createRedisMock(); + }); + } + + public function testThrowIfNeitherRedisNorFactoryGiven() + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('The $redis argument must be either Enqueue\Redis\Redis or callable that returns $s once called.'); + new RedisContext(new \stdClass()); + } + + public function testShouldAllowCreateEmptyMessage() + { + $context = new RedisContext($this->createRedisMock()); + + $message = $context->createMessage(); + + $this->assertInstanceOf(RedisMessage::class, $message); + + $this->assertSame('', $message->getBody()); + $this->assertSame([], $message->getProperties()); + $this->assertSame([], $message->getHeaders()); + } + + public function testShouldAllowCreateCustomMessage() + { + $context = new RedisContext($this->createRedisMock()); + + $message = $context->createMessage('theBody', ['aProp' => 'aPropVal'], ['aHeader' => 'aHeaderVal']); + + $this->assertInstanceOf(RedisMessage::class, $message); + + $this->assertSame('theBody', $message->getBody()); + $this->assertSame(['aProp' => 'aPropVal'], $message->getProperties()); + $this->assertSame(['aHeader' => 'aHeaderVal'], $message->getHeaders()); + } + + public function testShouldCreateQueue() + { + $context = new RedisContext($this->createRedisMock()); + + $queue = $context->createQueue('aQueue'); + + $this->assertInstanceOf(RedisDestination::class, $queue); + $this->assertSame('aQueue', $queue->getQueueName()); + } + + public function testShouldAllowCreateTopic() + { + $context = new RedisContext($this->createRedisMock()); + + $topic = $context->createTopic('aTopic'); + + $this->assertInstanceOf(RedisDestination::class, $topic); + $this->assertSame('aTopic', $topic->getTopicName()); + } + + public function testThrowNotImplementedOnCreateTmpQueueCall() + { + $context = new RedisContext($this->createRedisMock()); + + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('Not implemented'); + $context->createTemporaryQueue(); + } + + public function testShouldCreateProducer() + { + $context = new RedisContext($this->createRedisMock()); + + $producer = $context->createProducer(); + + $this->assertInstanceOf(RedisProducer::class, $producer); + } + + public function testShouldThrowIfNotRedisDestinationGivenOnCreateConsumer() + { + $context = new RedisContext($this->createRedisMock()); + + $this->expectException(InvalidDestinationException::class); + $this->expectExceptionMessage('The destination must be an instance of Enqueue\Redis\RedisDestination but got Enqueue\Transport\Null\NullQueue.'); + $consumer = $context->createConsumer(new NullQueue('aQueue')); + + $this->assertInstanceOf(RedisConsumer::class, $consumer); + } + + public function testShouldCreateConsumer() + { + $context = new RedisContext($this->createRedisMock()); + + $queue = $context->createQueue('aQueue'); + + $consumer = $context->createConsumer($queue); + + $this->assertInstanceOf(RedisConsumer::class, $consumer); + } + + public function testShouldCallRedisDisconnectOnClose() + { + $redisMock = $this->createRedisMock(); + $redisMock + ->expects($this->once()) + ->method('disconnect') + ; + + $context = new RedisContext($redisMock); + + $context->close(); + } + + public function testThrowIfNotRedisDestinationGivenOnDeleteQueue() + { + $redisMock = $this->createRedisMock(); + $redisMock + ->expects($this->never()) + ->method('del') + ; + + $context = new RedisContext($redisMock); + + $this->expectException(InvalidDestinationException::class); + $context->deleteQueue(new NullQueue('aQueue')); + } + + public function testShouldAllowDeleteQueue() + { + $redisMock = $this->createRedisMock(); + $redisMock + ->expects($this->once()) + ->method('del') + ->with('aQueueName') + ; + + $context = new RedisContext($redisMock); + + $queue = $context->createQueue('aQueueName'); + + $context->deleteQueue($queue); + } + + public function testThrowIfNotRedisDestinationGivenOnDeleteTopic() + { + $redisMock = $this->createRedisMock(); + $redisMock + ->expects($this->never()) + ->method('del') + ; + + $context = new RedisContext($redisMock); + + $this->expectException(InvalidDestinationException::class); + $context->deleteTopic(new NullTopic('aTopic')); + } + + public function testShouldAllowDeleteTopic() + { + $redisMock = $this->createRedisMock(); + $redisMock + ->expects($this->once()) + ->method('del') + ->with('aTopicName') + ; + + $context = new RedisContext($redisMock); + + $topic = $context->createTopic('aTopicName'); + + $context->deleteQueue($topic); + } /** - * @return \PHPUnit_Framework_MockObject_MockObject|\Redis + * @return \PHPUnit_Framework_MockObject_MockObject|Redis */ private function createRedisMock() { - return $this->createMock(\Redis::class); + return $this->createMock(Redis::class); } } diff --git a/Tests/RedisDestinationTest.php b/Tests/RedisDestinationTest.php index 0af02a6..8ee065f 100644 --- a/Tests/RedisDestinationTest.php +++ b/Tests/RedisDestinationTest.php @@ -6,8 +6,9 @@ use Enqueue\Psr\PsrTopic; use Enqueue\Redis\RedisDestination; use Enqueue\Test\ClassExtensionTrait; +use PHPUnit\Framework\TestCase; -class RedisDestinationTest extends \PHPUnit_Framework_TestCase +class RedisDestinationTest extends \PHPUnit\Framework\TestCase { use ClassExtensionTrait; diff --git a/Tests/RedisMessageTest.php b/Tests/RedisMessageTest.php index 0e775d0..d9bab0e 100644 --- a/Tests/RedisMessageTest.php +++ b/Tests/RedisMessageTest.php @@ -5,8 +5,9 @@ use Enqueue\Psr\PsrMessage; use Enqueue\Redis\RedisMessage; use Enqueue\Test\ClassExtensionTrait; +use PHPUnit\Framework\TestCase; -class RedisMessageTest extends \PHPUnit_Framework_TestCase +class RedisMessageTest extends \PHPUnit\Framework\TestCase { use ClassExtensionTrait; diff --git a/Tests/RedisProducerTest.php b/Tests/RedisProducerTest.php new file mode 100644 index 0000000..ef796b4 --- /dev/null +++ b/Tests/RedisProducerTest.php @@ -0,0 +1,73 @@ +assertClassImplements(PsrProducer::class, RedisProducer::class); + } + + public function testCouldBeConstructedWithRedisAsFirstArgument() + { + new RedisProducer($this->createRedisMock()); + } + + public function testThrowIfDestinationNotRedisDestinationOnSend() + { + $producer = new RedisProducer($this->createRedisMock()); + + $this->expectException(InvalidDestinationException::class); + $this->expectExceptionMessage('The destination must be an instance of Enqueue\Redis\RedisDestination but got Enqueue\Transport\Null\NullQueue.'); + $producer->send(new NullQueue('aQueue'), new RedisMessage()); + } + + public function testThrowIfMessageNotRedisMessageOnSend() + { + $producer = new RedisProducer($this->createRedisMock()); + + $this->expectException(InvalidMessageException::class); + $this->expectExceptionMessage('The message must be an instance of Enqueue\Redis\RedisMessage but it is Enqueue\Transport\Null\NullMessage.'); + $producer->send(new RedisDestination(TempFile::generate()), new NullMessage()); + } + + public function testShouldCallLPushOnSend() + { + $destination = new RedisDestination('aDestination'); + + $redisMock = $this->createRedisMock(); + $redisMock + ->expects($this->once()) + ->method('lpush') + ->with('aDestination', '{"body":null,"properties":[],"headers":[]}') + ; + + $producer = new RedisProducer($redisMock); + + $producer->send($destination, new RedisMessage()); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|Redis + */ + private function createRedisMock() + { + return $this->createMock(Redis::class); + } +}