No messages were sent.
diff --git a/pkg/enqueue-bundle/Tests/Functional/App/AbstractAsyncListener.php b/pkg/enqueue-bundle/Tests/Functional/App/AbstractAsyncListener.php
new file mode 100644
index 000000000..acf7406e1
--- /dev/null
+++ b/pkg/enqueue-bundle/Tests/Functional/App/AbstractAsyncListener.php
@@ -0,0 +1,48 @@
+producer = $producer;
+ $this->registry = $registry;
+ }
+
+ /**
+ * @param Event|ContractEvent $event
+ * @param string $eventName
+ */
+ protected function onEventInternal($event, $eventName)
+ {
+ if (false == $this->isSyncMode($eventName)) {
+ $transformerName = $this->registry->getTransformerNameForEvent($eventName);
+
+ $interopMessage = $this->registry->getTransformer($transformerName)->toMessage($eventName, $event);
+ $message = new Message($interopMessage->getBody());
+ $message->setScope(Message::SCOPE_APP);
+ $message->setProperty('event_name', $eventName);
+ $message->setProperty('transformer_name', $transformerName);
+
+ $this->producer->sendCommand(Commands::DISPATCH_ASYNC_EVENTS, $message);
+ }
+ }
+}
diff --git a/pkg/enqueue-bundle/Tests/Functional/App/AppKernel.php b/pkg/enqueue-bundle/Tests/Functional/App/AppKernel.php
index 59ac38666..3cafeedda 100644
--- a/pkg/enqueue-bundle/Tests/Functional/App/AppKernel.php
+++ b/pkg/enqueue-bundle/Tests/Functional/App/AppKernel.php
@@ -7,61 +7,39 @@
class AppKernel extends Kernel
{
- /**
- * @return array
- */
- public function registerBundles()
+ public function registerBundles(): iterable
{
$bundles = [
new \Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new \Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
- new \Symfony\Bundle\MonologBundle\MonologBundle(),
new \Enqueue\Bundle\EnqueueBundle(),
];
return $bundles;
}
- /**
- * @return string
- */
- public function getCacheDir()
+ public function getCacheDir(): string
{
return sys_get_temp_dir().'/EnqueueBundle/cache';
}
- /**
- * @return string
- */
- public function getLogDir()
+ public function getLogDir(): string
{
return sys_get_temp_dir().'/EnqueueBundle/cache/logs';
}
- /**
- * @param \Symfony\Component\Config\Loader\LoaderInterface $loader
- */
public function registerContainerConfiguration(LoaderInterface $loader)
{
- $loader->load(__DIR__.'/config/config.yml');
- }
+ if (self::VERSION_ID < 60000) {
+ $loader->load(__DIR__.'/config/config-sf5.yml');
- protected function getKernelParameters()
- {
- $parameters = parent::getKernelParameters();
+ return;
+ }
- // it works in all Symfony version, 2.8, 3.x, 4.x
- $parameters['db.driver'] = getenv('DOCTRINE_DRIVER');
- $parameters['db.host'] = getenv('DOCTRINE_HOST');
- $parameters['db.port'] = getenv('DOCTRINE_PORT');
- $parameters['db.name'] = getenv('DOCTRINE_DB_NAME');
- $parameters['db.user'] = getenv('DOCTRINE_USER');
- $parameters['db.password'] = getenv('DOCTRINE_PASSWORD');
-
- return $parameters;
+ $loader->load(__DIR__.'/config/config.yml');
}
- protected function getContainerClass()
+ protected function getContainerClass(): string
{
return parent::getContainerClass().'BundleDefault';
}
diff --git a/pkg/enqueue-bundle/Tests/Functional/App/AsyncListener.php b/pkg/enqueue-bundle/Tests/Functional/App/AsyncListener.php
index b55525fc4..23ab4af79 100644
--- a/pkg/enqueue-bundle/Tests/Functional/App/AsyncListener.php
+++ b/pkg/enqueue-bundle/Tests/Functional/App/AsyncListener.php
@@ -2,49 +2,15 @@
namespace Enqueue\Bundle\Tests\Functional\App;
-use Enqueue\AsyncEventDispatcher\Registry;
-use Enqueue\Client\Message;
-use Enqueue\Client\ProducerInterface;
-use Symfony\Component\EventDispatcher\Event;
+use Symfony\Contracts\EventDispatcher\Event;
-class AsyncListener extends \Enqueue\AsyncEventDispatcher\AsyncListener
+class AsyncListener extends AbstractAsyncListener
{
/**
- * @var ProducerInterface
- */
- private $producer;
-
- /**
- * @var Registry
- */
- private $registry;
-
- /**
- * @param ProducerInterface $producer
- * @param Registry $registry
- */
- public function __construct(ProducerInterface $producer, Registry $registry)
- {
- $this->producer = $producer;
- $this->registry = $registry;
- }
-
- /**
- * @param Event $event
* @param string $eventName
*/
- public function onEvent(Event $event = null, $eventName)
+ public function onEvent(Event $event, $eventName)
{
- if (false == $this->isSyncMode($eventName)) {
- $transformerName = $this->registry->getTransformerNameForEvent($eventName);
-
- $psrMessage = $this->registry->getTransformer($transformerName)->toMessage($eventName, $event);
- $message = new Message($psrMessage->getBody());
- $message->setScope(Message::SCOPE_APP);
- $message->setProperty('event_name', $eventName);
- $message->setProperty('transformer_name', $transformerName);
-
- $this->producer->sendCommand('symfony_events', $message);
- }
+ $this->onEventInternal($event, $eventName);
}
}
diff --git a/pkg/enqueue-bundle/Tests/Functional/App/CustomAppKernel.php b/pkg/enqueue-bundle/Tests/Functional/App/CustomAppKernel.php
index 465196149..81d73796e 100644
--- a/pkg/enqueue-bundle/Tests/Functional/App/CustomAppKernel.php
+++ b/pkg/enqueue-bundle/Tests/Functional/App/CustomAppKernel.php
@@ -7,7 +7,7 @@
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpKernel\Kernel;
-use Symfony\Component\Routing\RouteCollectionBuilder;
+use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator;
class CustomAppKernel extends Kernel
{
@@ -16,19 +16,21 @@ class CustomAppKernel extends Kernel
private $enqueueConfigId;
private $enqueueConfig = [
- 'client' => [
- 'prefix' => 'enqueue',
- 'app_name' => '',
- 'router_topic' => 'test',
- 'router_queue' => 'test',
- 'default_processor_queue' => 'test',
+ 'default' => [
+ 'client' => [
+ 'prefix' => 'enqueue',
+ 'app_name' => '',
+ 'router_topic' => 'test',
+ 'router_queue' => 'test',
+ 'default_queue' => 'test',
+ ],
],
];
- public function setEnqueueConfig(array $config)
+ public function setEnqueueConfig(array $config): void
{
$this->enqueueConfig = array_replace_recursive($this->enqueueConfig, $config);
- $this->enqueueConfig['client']['app_name'] = str_replace('.', '', uniqid('app_name', true));
+ $this->enqueueConfig['default']['client']['app_name'] = str_replace('.', '', uniqid('app_name', true));
$this->enqueueConfigId = md5(json_encode($this->enqueueConfig));
$fs = new Filesystem();
@@ -36,56 +38,44 @@ public function setEnqueueConfig(array $config)
$fs->mkdir(sys_get_temp_dir().'/EnqueueBundleCustom/cache/'.$this->enqueueConfigId);
}
- /**
- * @return array
- */
- public function registerBundles()
+ public function registerBundles(): iterable
{
$bundles = [
new \Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new \Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
- new \Symfony\Bundle\MonologBundle\MonologBundle(),
new \Enqueue\Bundle\EnqueueBundle(),
];
return $bundles;
}
- /**
- * @return string
- */
- public function getCacheDir()
+ public function getCacheDir(): string
{
return sys_get_temp_dir().'/EnqueueBundleCustom/cache/'.$this->enqueueConfigId;
}
- /**
- * @return string
- */
- public function getLogDir()
+ public function getLogDir(): string
{
return sys_get_temp_dir().'/EnqueueBundleCustom/cache/logs/'.$this->enqueueConfigId;
}
- protected function getContainerClass()
+ protected function getContainerClass(): string
{
return parent::getContainerClass().'Custom'.$this->enqueueConfigId;
}
- /**
- * {@inheritdoc}
- */
protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader)
{
- $loader->load(__DIR__.'/config/custom-config.yml');
+ if (self::VERSION_ID < 60000) {
+ $loader->load(__DIR__.'/config/custom-config-sf5.yml');
+ } else {
+ $loader->load(__DIR__.'/config/custom-config.yml');
+ }
$c->loadFromExtension('enqueue', $this->enqueueConfig);
}
- /**
- * {@inheritdoc}
- */
- protected function configureRoutes(RouteCollectionBuilder $routes)
+ protected function configureRoutes(RoutingConfigurator $routes)
{
}
}
diff --git a/pkg/enqueue-bundle/Tests/Functional/App/SqsCustomConnectionFactoryFactory.php b/pkg/enqueue-bundle/Tests/Functional/App/SqsCustomConnectionFactoryFactory.php
new file mode 100644
index 000000000..6ed70cd65
--- /dev/null
+++ b/pkg/enqueue-bundle/Tests/Functional/App/SqsCustomConnectionFactoryFactory.php
@@ -0,0 +1,30 @@
+container = $container;
+ }
+
+ public function create($config): ConnectionFactory
+ {
+ if (false == isset($config['service'])) {
+ throw new \LogicException('The sqs client has to be set');
+ }
+
+ return new SqsConnectionFactory($this->container->get($config['service']));
+ }
+}
diff --git a/pkg/enqueue-bundle/Tests/Functional/App/TestAsyncEventTransformer.php b/pkg/enqueue-bundle/Tests/Functional/App/TestAsyncEventTransformer.php
index 975cd4214..0a83a04b6 100644
--- a/pkg/enqueue-bundle/Tests/Functional/App/TestAsyncEventTransformer.php
+++ b/pkg/enqueue-bundle/Tests/Functional/App/TestAsyncEventTransformer.php
@@ -4,29 +4,26 @@
use Enqueue\AsyncEventDispatcher\EventTransformer;
use Enqueue\Util\JSON;
-use Interop\Queue\PsrContext;
-use Interop\Queue\PsrMessage;
-use Symfony\Component\EventDispatcher\Event;
+use Interop\Queue\Context;
+use Interop\Queue\Message;
use Symfony\Component\EventDispatcher\GenericEvent;
+use Symfony\Contracts\EventDispatcher\Event;
class TestAsyncEventTransformer implements EventTransformer
{
/**
- * @var PsrContext
+ * @var Context
*/
private $context;
- /**
- * @param PsrContext $context
- */
- public function __construct(PsrContext $context)
+ public function __construct(Context $context)
{
$this->context = $context;
}
- public function toMessage($eventName, Event $event)
+ public function toMessage($eventName, ?Event $event = null)
{
- if (Event::class === get_class($event)) {
+ if (Event::class === $event::class) {
return $this->context->createMessage(json_encode(''));
}
@@ -41,7 +38,7 @@ public function toMessage($eventName, Event $event)
]));
}
- public function toEvent($eventName, PsrMessage $message)
+ public function toEvent($eventName, Message $message)
{
$data = JSON::decode($message->getBody());
diff --git a/pkg/enqueue-bundle/Tests/Functional/App/TestAsyncListener.php b/pkg/enqueue-bundle/Tests/Functional/App/TestAsyncListener.php
index aa4884bca..fd0ec1d91 100644
--- a/pkg/enqueue-bundle/Tests/Functional/App/TestAsyncListener.php
+++ b/pkg/enqueue-bundle/Tests/Functional/App/TestAsyncListener.php
@@ -2,14 +2,13 @@
namespace Enqueue\Bundle\Tests\Functional\App;
-use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class TestAsyncListener
{
public $calls = [];
- public function onEvent(Event $event, $eventName, EventDispatcherInterface $dispatcher)
+ public function onEvent($event, $eventName, EventDispatcherInterface $dispatcher)
{
$this->calls[] = func_get_args();
}
diff --git a/pkg/enqueue-bundle/Tests/Functional/App/TestAsyncSubscriber.php b/pkg/enqueue-bundle/Tests/Functional/App/TestAsyncSubscriber.php
index 2b45bed6e..cd3beb45b 100644
--- a/pkg/enqueue-bundle/Tests/Functional/App/TestAsyncSubscriber.php
+++ b/pkg/enqueue-bundle/Tests/Functional/App/TestAsyncSubscriber.php
@@ -2,7 +2,6 @@
namespace Enqueue\Bundle\Tests\Functional\App;
-use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
@@ -10,7 +9,7 @@ class TestAsyncSubscriber implements EventSubscriberInterface
{
public $calls = [];
- public function onEvent(Event $event, $eventName, EventDispatcherInterface $dispatcher)
+ public function onEvent($event, $eventName, EventDispatcherInterface $dispatcher)
{
$this->calls[] = func_get_args();
}
diff --git a/pkg/enqueue-bundle/Tests/Functional/App/TestCommandSubscriberProcessor.php b/pkg/enqueue-bundle/Tests/Functional/App/TestCommandSubscriberProcessor.php
index bc45336d6..480992ff1 100644
--- a/pkg/enqueue-bundle/Tests/Functional/App/TestCommandSubscriberProcessor.php
+++ b/pkg/enqueue-bundle/Tests/Functional/App/TestCommandSubscriberProcessor.php
@@ -4,15 +4,15 @@
use Enqueue\Client\CommandSubscriberInterface;
use Enqueue\Consumption\Result;
-use Interop\Queue\PsrContext;
-use Interop\Queue\PsrMessage;
-use Interop\Queue\PsrProcessor;
+use Interop\Queue\Context;
+use Interop\Queue\Message;
+use Interop\Queue\Processor;
-class TestCommandSubscriberProcessor implements PsrProcessor, CommandSubscriberInterface
+class TestCommandSubscriberProcessor implements Processor, CommandSubscriberInterface
{
public $calls = [];
- public function process(PsrMessage $message, PsrContext $context)
+ public function process(Message $message, Context $context)
{
$this->calls[] = $message;
@@ -23,6 +23,6 @@ public function process(PsrMessage $message, PsrContext $context)
public static function getSubscribedCommand()
{
- return 'test_command_subscriber';
+ return 'theCommand';
}
}
diff --git a/pkg/enqueue-bundle/Tests/Functional/App/TestExclusiveCommandSubscriberProcessor.php b/pkg/enqueue-bundle/Tests/Functional/App/TestExclusiveCommandSubscriberProcessor.php
index 8f0001b92..999ad1f24 100644
--- a/pkg/enqueue-bundle/Tests/Functional/App/TestExclusiveCommandSubscriberProcessor.php
+++ b/pkg/enqueue-bundle/Tests/Functional/App/TestExclusiveCommandSubscriberProcessor.php
@@ -4,15 +4,15 @@
use Enqueue\Client\CommandSubscriberInterface;
use Enqueue\Consumption\Result;
-use Interop\Queue\PsrContext;
-use Interop\Queue\PsrMessage;
-use Interop\Queue\PsrProcessor;
+use Interop\Queue\Context;
+use Interop\Queue\Message;
+use Interop\Queue\Processor;
-class TestExclusiveCommandSubscriberProcessor implements PsrProcessor, CommandSubscriberInterface
+class TestExclusiveCommandSubscriberProcessor implements Processor, CommandSubscriberInterface
{
public $calls = [];
- public function process(PsrMessage $message, PsrContext $context)
+ public function process(Message $message, Context $context)
{
$this->calls[] = $message;
@@ -22,9 +22,10 @@ public function process(PsrMessage $message, PsrContext $context)
public static function getSubscribedCommand()
{
return [
- 'processorName' => 'theExclusiveCommandName',
- 'queueName' => 'the_exclusive_command_queue',
- 'queueNameHardcoded' => true,
+ 'command' => 'theExclusiveCommandName',
+ 'processor' => 'theExclusiveCommandName',
+ 'queue' => 'the_exclusive_command_queue',
+ 'prefix_queue' => true,
'exclusive' => true,
];
}
diff --git a/pkg/enqueue-bundle/Tests/Functional/App/TestTopicSubscriberProcessor.php b/pkg/enqueue-bundle/Tests/Functional/App/TestTopicSubscriberProcessor.php
new file mode 100644
index 000000000..2b9f16ead
--- /dev/null
+++ b/pkg/enqueue-bundle/Tests/Functional/App/TestTopicSubscriberProcessor.php
@@ -0,0 +1,28 @@
+calls[] = $message;
+
+ return Result::reply(
+ $context->createMessage($message->getBody().'Reply')
+ );
+ }
+
+ public static function getSubscribedTopics()
+ {
+ return 'theTopic';
+ }
+}
diff --git a/pkg/enqueue-bundle/Tests/Functional/App/config/config-sf5.yml b/pkg/enqueue-bundle/Tests/Functional/App/config/config-sf5.yml
new file mode 100644
index 000000000..e202bb86f
--- /dev/null
+++ b/pkg/enqueue-bundle/Tests/Functional/App/config/config-sf5.yml
@@ -0,0 +1,129 @@
+parameters:
+ locale: 'en'
+ secret: 'ThisTokenIsNotSoSecretChangeIt'
+
+
+framework:
+ #esi: ~
+ #translator: { fallback: "%locale%" }
+ test: ~
+ assets: false
+ session:
+ # option incompatible with Symfony 6
+ storage_id: session.storage.mock_file
+ secret: '%secret%'
+ router: { resource: '%kernel.project_dir%/config/routing.yml' }
+ default_locale: '%locale%'
+
+doctrine:
+ dbal:
+ url: "%env(DOCTRINE_DSN)%"
+ driver: pdo_mysql
+ charset: UTF8
+
+enqueue:
+ default:
+ transport: 'null:'
+ client:
+ traceable_producer: true
+ job: true
+ async_events: true
+ async_commands:
+ enabled: true
+ timeout: 60
+ command_name: ~
+ queue_name: ~
+
+services:
+ test_enqueue.client.default.traceable_producer:
+ alias: 'enqueue.client.default.traceable_producer'
+ public: true
+
+ test_enqueue.transport.default.queue_consumer:
+ alias: 'enqueue.transport.default.queue_consumer'
+ public: true
+
+ test_enqueue.client.default.queue_consumer:
+ alias: 'enqueue.client.default.queue_consumer'
+ public: true
+
+ test_enqueue.transport.default.rpc_client:
+ alias: 'enqueue.transport.default.rpc_client'
+ public: true
+
+ test_enqueue.client.default.producer:
+ alias: 'enqueue.client.default.producer'
+ public: true
+
+ test_enqueue.client.default.spool_producer:
+ alias: 'enqueue.client.default.spool_producer'
+ public: true
+
+ test_Enqueue\Client\ProducerInterface:
+ alias: 'Enqueue\Client\ProducerInterface'
+ public: true
+
+ test_enqueue.client.default.driver:
+ alias: 'enqueue.client.default.driver'
+ public: true
+
+ test_enqueue.transport.default.context:
+ alias: 'enqueue.transport.default.context'
+ public: true
+
+ test_enqueue.client.consume_command:
+ alias: 'enqueue.client.consume_command'
+ public: true
+
+ test.enqueue.client.routes_command:
+ alias: 'enqueue.client.routes_command'
+ public: true
+
+ test.enqueue.events.async_processor:
+ alias: 'enqueue.events.async_processor'
+ public: true
+
+ test_async_listener:
+ class: 'Enqueue\Bundle\Tests\Functional\App\TestAsyncListener'
+ public: true
+ tags:
+ - { name: 'kernel.event_listener', async: true, event: 'test_async', method: 'onEvent', dispatcher: 'enqueue.events.event_dispatcher' }
+
+ test_command_subscriber_processor:
+ class: 'Enqueue\Bundle\Tests\Functional\App\TestCommandSubscriberProcessor'
+ public: true
+ tags:
+ - { name: 'enqueue.command_subscriber', client: 'default' }
+
+ test_topic_subscriber_processor:
+ class: 'Enqueue\Bundle\Tests\Functional\App\TestTopicSubscriberProcessor'
+ public: true
+ tags:
+ - { name: 'enqueue.topic_subscriber', client: 'default' }
+
+ test_exclusive_command_subscriber_processor:
+ class: 'Enqueue\Bundle\Tests\Functional\App\TestExclusiveCommandSubscriberProcessor'
+ public: true
+ tags:
+ - { name: 'enqueue.command_subscriber', client: 'default' }
+
+ test_async_subscriber:
+ class: 'Enqueue\Bundle\Tests\Functional\App\TestAsyncSubscriber'
+ public: true
+ tags:
+ - { name: 'kernel.event_subscriber', async: true, dispatcher: 'enqueue.events.event_dispatcher' }
+
+ test_async_event_transformer:
+ class: 'Enqueue\Bundle\Tests\Functional\App\TestAsyncEventTransformer'
+ public: true
+ arguments:
+ - '@enqueue.transport.default.context'
+ tags:
+ - {name: 'enqueue.event_transformer', eventName: 'test_async', transformerName: 'test_async' }
+ - {name: 'enqueue.event_transformer', eventName: 'test_async_subscriber', transformerName: 'test_async' }
+
+ # overwrite async listener with one based on client producer. so we can use traceable producer.
+ enqueue.events.async_listener:
+ class: 'Enqueue\Bundle\Tests\Functional\App\AsyncListener'
+ public: true
+ arguments: ['@enqueue.client.default.producer', '@enqueue.events.registry']
diff --git a/pkg/enqueue-bundle/Tests/Functional/App/config/config.yml b/pkg/enqueue-bundle/Tests/Functional/App/config/config.yml
index aa1d645ff..d3ca2a37f 100644
--- a/pkg/enqueue-bundle/Tests/Functional/App/config/config.yml
+++ b/pkg/enqueue-bundle/Tests/Functional/App/config/config.yml
@@ -8,63 +8,109 @@ framework:
#translator: { fallback: "%locale%" }
test: ~
assets: false
- templating: false
session:
- storage_id: session.storage.mock_file
+ storage_factory_id: session.storage.factory.mock_file
secret: '%secret%'
- router: { resource: '%kernel.root_dir%/config/routing.yml' }
+ router: { resource: '%kernel.project_dir%/config/routing.yml' }
default_locale: '%locale%'
-monolog:
- handlers:
- main:
- type: 'null'
- level: 'error'
-
doctrine:
dbal:
- driver: "%db.driver%"
- host: "%db.host%"
- port: "%db.port%"
- dbname: "%db.name%"
- user: "%db.user%"
- password: "%db.password%"
+ url: "%env(DOCTRINE_DSN)%"
+ driver: pdo_mysql
charset: UTF8
enqueue:
- transport:
- default: 'null'
- 'null': ~
- client:
- traceable_producer: true
- job: true
- async_events: true
-
+ default:
+ transport: 'null:'
+ client:
+ traceable_producer: true
+ job: true
+ async_events: true
+ async_commands:
+ enabled: true
+ timeout: 60
+ command_name: ~
+ queue_name: ~
services:
+ test_enqueue.client.default.traceable_producer:
+ alias: 'enqueue.client.default.traceable_producer'
+ public: true
+
+ test_enqueue.transport.default.queue_consumer:
+ alias: 'enqueue.transport.default.queue_consumer'
+ public: true
+
+ test_enqueue.client.default.queue_consumer:
+ alias: 'enqueue.client.default.queue_consumer'
+ public: true
+
+ test_enqueue.transport.default.rpc_client:
+ alias: 'enqueue.transport.default.rpc_client'
+ public: true
+
+ test_enqueue.client.default.producer:
+ alias: 'enqueue.client.default.producer'
+ public: true
+
+ test_enqueue.client.default.spool_producer:
+ alias: 'enqueue.client.default.spool_producer'
+ public: true
+
+ test_Enqueue\Client\ProducerInterface:
+ alias: 'Enqueue\Client\ProducerInterface'
+ public: true
+
+ test_enqueue.client.default.driver:
+ alias: 'enqueue.client.default.driver'
+ public: true
+
+ test_enqueue.transport.default.context:
+ alias: 'enqueue.transport.default.context'
+ public: true
+
+ test_enqueue.client.consume_command:
+ alias: 'enqueue.client.consume_command'
+ public: true
+
+ test.enqueue.client.routes_command:
+ alias: 'enqueue.client.routes_command'
+ public: true
+
+ test.enqueue.events.async_processor:
+ alias: 'enqueue.events.async_processor'
+ public: true
+
test_async_listener:
class: 'Enqueue\Bundle\Tests\Functional\App\TestAsyncListener'
public: true
tags:
- - { name: 'kernel.event_listener', async: true, event: 'test_async', method: 'onEvent' }
+ - { name: 'kernel.event_listener', async: true, event: 'test_async', method: 'onEvent', dispatcher: 'enqueue.events.event_dispatcher' }
test_command_subscriber_processor:
class: 'Enqueue\Bundle\Tests\Functional\App\TestCommandSubscriberProcessor'
public: true
tags:
- - { name: 'enqueue.client.processor' }
+ - { name: 'enqueue.command_subscriber', client: 'default' }
+
+ test_topic_subscriber_processor:
+ class: 'Enqueue\Bundle\Tests\Functional\App\TestTopicSubscriberProcessor'
+ public: true
+ tags:
+ - { name: 'enqueue.topic_subscriber', client: 'default' }
test_exclusive_command_subscriber_processor:
class: 'Enqueue\Bundle\Tests\Functional\App\TestExclusiveCommandSubscriberProcessor'
public: true
tags:
- - { name: 'enqueue.client.processor' }
+ - { name: 'enqueue.command_subscriber', client: 'default' }
test_async_subscriber:
class: 'Enqueue\Bundle\Tests\Functional\App\TestAsyncSubscriber'
public: true
tags:
- - { name: 'kernel.event_subscriber', async: true }
+ - { name: 'kernel.event_subscriber', async: true, dispatcher: 'enqueue.events.event_dispatcher' }
test_async_event_transformer:
class: 'Enqueue\Bundle\Tests\Functional\App\TestAsyncEventTransformer'
@@ -79,4 +125,4 @@ services:
enqueue.events.async_listener:
class: 'Enqueue\Bundle\Tests\Functional\App\AsyncListener'
public: true
- arguments: ['@Enqueue\Client\Producer', '@enqueue.events.registry']
\ No newline at end of file
+ arguments: ['@enqueue.client.default.producer', '@enqueue.events.registry']
diff --git a/pkg/enqueue-bundle/Tests/Functional/App/config/custom-config-sf5.yml b/pkg/enqueue-bundle/Tests/Functional/App/config/custom-config-sf5.yml
new file mode 100644
index 000000000..35192652e
--- /dev/null
+++ b/pkg/enqueue-bundle/Tests/Functional/App/config/custom-config-sf5.yml
@@ -0,0 +1,85 @@
+parameters:
+ locale: 'en'
+ secret: 'ThisTokenIsNotSoSecretChangeIt'
+
+framework:
+ #esi: ~
+ #translator: { fallback: "%locale%" }
+ test: ~
+ assets: false
+ session:
+ # the only option incompatible with Symfony 6
+ storage_id: session.storage.mock_file
+ secret: '%secret%'
+ router: { resource: '%kernel.project_dir%/config/routing.yml' }
+ default_locale: '%locale%'
+
+doctrine:
+ dbal:
+ connections:
+ custom:
+ url: "%env(DOCTRINE_DSN)%"
+ driver: pdo_mysql
+ charset: UTF8
+
+services:
+ test_enqueue.client.default.driver:
+ alias: 'enqueue.client.default.driver'
+ public: true
+
+ test_enqueue.client.default.producer:
+ alias: 'enqueue.client.default.producer'
+ public: true
+
+ test_enqueue.client.default.lazy_producer:
+ alias: 'enqueue.client.default.lazy_producer'
+ public: true
+
+ test_enqueue.transport.default.context:
+ alias: 'enqueue.transport.default.context'
+ public: true
+
+ test_enqueue.transport.consume_command:
+ alias: 'enqueue.transport.consume_command'
+ public: true
+
+ test_enqueue.client.consume_command:
+ alias: 'enqueue.client.consume_command'
+ public: true
+
+ test_enqueue.client.produce_command:
+ alias: 'enqueue.client.produce_command'
+ public: true
+
+ test_enqueue.client.setup_broker_command:
+ alias: 'enqueue.client.setup_broker_command'
+ public: true
+
+ test.message.processor:
+ class: 'Enqueue\Bundle\Tests\Functional\TestProcessor'
+ public: true
+ tags:
+ - { name: 'enqueue.topic_subscriber', client: 'default' }
+ - { name: 'enqueue.transport.processor', transport: 'default' }
+
+ test.message.command_processor:
+ class: 'Enqueue\Bundle\Tests\Functional\TestCommandProcessor'
+ public: true
+ tags:
+ - { name: 'enqueue.command_subscriber', client: 'default' }
+
+ test.sqs_client:
+ public: true
+ class: 'Aws\Sqs\SqsClient'
+ arguments:
+ -
+ endpoint: '%env(AWS_SQS_ENDPOINT)%'
+ region: '%env(AWS_SQS_REGION)%'
+ version: '%env(AWS_SQS_VERSION)%'
+ credentials:
+ key: '%env(AWS_SQS_KEY)%'
+ secret: '%env(AWS_SQS_SECRET)%'
+
+ test.sqs_custom_connection_factory_factory:
+ class: 'Enqueue\Bundle\Tests\Functional\App\SqsCustomConnectionFactoryFactory'
+ arguments: ['@service_container']
diff --git a/pkg/enqueue-bundle/Tests/Functional/App/config/custom-config.yml b/pkg/enqueue-bundle/Tests/Functional/App/config/custom-config.yml
index 5407f8496..d02f3002d 100644
--- a/pkg/enqueue-bundle/Tests/Functional/App/config/custom-config.yml
+++ b/pkg/enqueue-bundle/Tests/Functional/App/config/custom-config.yml
@@ -1,46 +1,75 @@
parameters:
locale: 'en'
secret: 'ThisTokenIsNotSoSecretChangeIt'
- env(AWS_SQS_REGION): 'us-east-1'
- env(AWS_SQS_VERSION): 'latest'
- env(AWS_SQS_KEY): 'key'
- env(AWS_SQS_SECRET): 'secret'
- env(AWS_SQS_ENDPOINT): 'http://localstack:4576/'
framework:
#esi: ~
#translator: { fallback: "%locale%" }
test: ~
assets: false
- templating: false
session:
- storage_id: session.storage.mock_file
+ storage_factory_id: session.storage.factory.mock_file
secret: '%secret%'
- router: { resource: '%kernel.root_dir%/config/routing.yml' }
+ router: { resource: '%kernel.project_dir%/config/routing.yml' }
default_locale: '%locale%'
-monolog:
- handlers:
- main:
- type: 'null'
- level: 'error'
+doctrine:
+ dbal:
+ connections:
+ custom:
+ url: "%env(DOCTRINE_DSN)%"
+ driver: pdo_mysql
+ charset: UTF8
services:
+ test_enqueue.client.default.driver:
+ alias: 'enqueue.client.default.driver'
+ public: true
+
+ test_enqueue.client.default.producer:
+ alias: 'enqueue.client.default.producer'
+ public: true
+
+ test_enqueue.client.default.lazy_producer:
+ alias: 'enqueue.client.default.lazy_producer'
+ public: true
+
+ test_enqueue.transport.default.context:
+ alias: 'enqueue.transport.default.context'
+ public: true
+
+ test_enqueue.transport.consume_command:
+ alias: 'enqueue.transport.consume_command'
+ public: true
+
+ test_enqueue.client.consume_command:
+ alias: 'enqueue.client.consume_command'
+ public: true
+
+ test_enqueue.client.produce_command:
+ alias: 'enqueue.client.produce_command'
+ public: true
+
+ test_enqueue.client.setup_broker_command:
+ alias: 'enqueue.client.setup_broker_command'
+ public: true
+
test.message.processor:
class: 'Enqueue\Bundle\Tests\Functional\TestProcessor'
public: true
tags:
- - { name: 'enqueue.client.processor' }
+ - { name: 'enqueue.topic_subscriber', client: 'default' }
+ - { name: 'enqueue.transport.processor', transport: 'default' }
test.message.command_processor:
class: 'Enqueue\Bundle\Tests\Functional\TestCommandProcessor'
public: true
tags:
- - { name: 'enqueue.client.processor' }
+ - { name: 'enqueue.command_subscriber', client: 'default' }
test.sqs_client:
public: true
- class: Aws\Sqs\SqsClient
+ class: 'Aws\Sqs\SqsClient'
arguments:
-
endpoint: '%env(AWS_SQS_ENDPOINT)%'
@@ -49,3 +78,7 @@ services:
credentials:
key: '%env(AWS_SQS_KEY)%'
secret: '%env(AWS_SQS_SECRET)%'
+
+ test.sqs_custom_connection_factory_factory:
+ class: 'Enqueue\Bundle\Tests\Functional\App\SqsCustomConnectionFactoryFactory'
+ arguments: ['@service_container']
diff --git a/pkg/enqueue-bundle/Tests/Functional/Client/ConsumeMessagesCommandTest.php b/pkg/enqueue-bundle/Tests/Functional/Client/ConsumeMessagesCommandTest.php
deleted file mode 100644
index 5af610971..000000000
--- a/pkg/enqueue-bundle/Tests/Functional/Client/ConsumeMessagesCommandTest.php
+++ /dev/null
@@ -1,19 +0,0 @@
-get(ConsumeMessagesCommand::class);
-
- $this->assertInstanceOf(ConsumeMessagesCommand::class, $command);
- }
-}
diff --git a/pkg/enqueue-bundle/Tests/Functional/Client/DriverTest.php b/pkg/enqueue-bundle/Tests/Functional/Client/DriverTest.php
deleted file mode 100644
index d4b290fb3..000000000
--- a/pkg/enqueue-bundle/Tests/Functional/Client/DriverTest.php
+++ /dev/null
@@ -1,19 +0,0 @@
-get('enqueue.client.driver');
-
- $this->assertInstanceOf(DriverInterface::class, $driver);
- }
-}
diff --git a/pkg/enqueue-bundle/Tests/Functional/Client/ProduceMessageCommandTest.php b/pkg/enqueue-bundle/Tests/Functional/Client/ProduceMessageCommandTest.php
deleted file mode 100644
index 0873705e7..000000000
--- a/pkg/enqueue-bundle/Tests/Functional/Client/ProduceMessageCommandTest.php
+++ /dev/null
@@ -1,19 +0,0 @@
-get(ProduceMessageCommand::class);
-
- $this->assertInstanceOf(ProduceMessageCommand::class, $command);
- }
-}
diff --git a/pkg/enqueue-bundle/Tests/Functional/Client/ProducerTest.php b/pkg/enqueue-bundle/Tests/Functional/Client/ProducerTest.php
index 388cfa2f8..29a96aa7d 100644
--- a/pkg/enqueue-bundle/Tests/Functional/Client/ProducerTest.php
+++ b/pkg/enqueue-bundle/Tests/Functional/Client/ProducerTest.php
@@ -3,11 +3,8 @@
namespace Enqueue\Bundle\Tests\Functional\Client;
use Enqueue\Bundle\Tests\Functional\WebTestCase;
-use Enqueue\Client\Config;
use Enqueue\Client\Message;
-use Enqueue\Client\Producer;
use Enqueue\Client\ProducerInterface;
-use Enqueue\Client\RouterProcessor;
use Enqueue\Client\TraceableProducer;
use Enqueue\Rpc\Promise;
@@ -16,39 +13,24 @@
*/
class ProducerTest extends WebTestCase
{
- public function setUp()
+ public function testCouldBeGetFromContainerByInterface()
{
- parent::setUp();
+ $producer = static::$container->get('test_'.ProducerInterface::class);
- static::$container->get(Producer::class)->clearTraces();
+ $this->assertInstanceOf(ProducerInterface::class, $producer);
}
- public function tearDown()
+ public function testCouldBeGetFromContainerByServiceId()
{
- static::$container->get(Producer::class)->clearTraces();
+ $producer = static::$container->get('test_enqueue.client.default.producer');
- parent::tearDown();
- }
-
- public function testCouldBeGetFromContainerAsService()
- {
- $messageProducer = static::$container->get(Producer::class);
-
- $this->assertInstanceOf(ProducerInterface::class, $messageProducer);
- }
-
- public function testCouldBeGetFromContainerAsShortenAlias()
- {
- $messageProducer = static::$container->get(Producer::class);
- $aliasMessageProducer = static::$container->get('enqueue.producer');
-
- $this->assertSame($messageProducer, $aliasMessageProducer);
+ $this->assertInstanceOf(ProducerInterface::class, $producer);
}
public function testShouldSendEvent()
{
/** @var ProducerInterface $producer */
- $producer = static::$container->get(Producer::class);
+ $producer = static::$container->get('test_enqueue.client.default.producer');
$producer->sendEvent('theTopic', 'theMessage');
@@ -61,13 +43,13 @@ public function testShouldSendEvent()
public function testShouldSendCommandWithoutNeedForReply()
{
/** @var ProducerInterface $producer */
- $producer = static::$container->get(Producer::class);
+ $producer = static::$container->get('test_enqueue.client.default.producer');
$result = $producer->sendCommand('theCommand', 'theMessage', false);
$this->assertNull($result);
- $traces = $this->getTraceableProducer()->getTopicTraces(Config::COMMAND_TOPIC);
+ $traces = $this->getTraceableProducer()->getCommandTraces('theCommand');
$this->assertCount(1, $traces);
$this->assertEquals('theMessage', $traces[0]['body']);
@@ -76,7 +58,7 @@ public function testShouldSendCommandWithoutNeedForReply()
public function testShouldSendMessageInstanceAsCommandWithoutNeedForReply()
{
/** @var ProducerInterface $producer */
- $producer = static::$container->get(Producer::class);
+ $producer = static::$container->get('test_enqueue.client.default.producer');
$message = new Message('theMessage');
@@ -84,25 +66,20 @@ public function testShouldSendMessageInstanceAsCommandWithoutNeedForReply()
$this->assertNull($result);
- $traces = $this->getTraceableProducer()->getTopicTraces(Config::COMMAND_TOPIC);
+ $traces = $this->getTraceableProducer()->getCommandTraces('theCommand');
$this->assertCount(1, $traces);
$this->assertEquals('theMessage', $traces[0]['body']);
$this->assertEquals([
- 'enqueue.topic_name' => Config::COMMAND_TOPIC,
- 'enqueue.processor_name' => RouterProcessor::class,
- 'enqueue.command_name' => 'theCommand',
- 'enqueue.processor_queue_name' => 'default',
- // compatibility with 0.9x
+ 'enqueue.processor' => 'test_command_subscriber_processor',
'enqueue.command' => 'theCommand',
- 'enqueue.topic' => '__command__',
], $traces[0]['properties']);
}
public function testShouldSendExclusiveCommandWithNeedForReply()
{
/** @var ProducerInterface $producer */
- $producer = static::$container->get(Producer::class);
+ $producer = static::$container->get('test_enqueue.client.default.producer');
$message = new Message('theMessage');
@@ -115,20 +92,15 @@ public function testShouldSendExclusiveCommandWithNeedForReply()
$this->assertCount(1, $traces);
$this->assertEquals('theMessage', $traces[0]['body']);
$this->assertEquals([
- 'enqueue.topic_name' => Config::COMMAND_TOPIC,
- 'enqueue.processor_name' => 'theExclusiveCommandName',
- 'enqueue.command_name' => 'theExclusiveCommandName',
- 'enqueue.processor_queue_name' => 'the_exclusive_command_queue',
- // compatibility with 0.9x
+ 'enqueue.processor' => 'theExclusiveCommandName',
'enqueue.command' => 'theExclusiveCommandName',
- 'enqueue.topic' => '__command__',
], $traces[0]['properties']);
}
public function testShouldSendMessageInstanceCommandWithNeedForReply()
{
/** @var ProducerInterface $producer */
- $producer = static::$container->get(Producer::class);
+ $producer = static::$container->get('test_enqueue.client.default.producer');
$message = new Message('theMessage');
@@ -141,21 +113,13 @@ public function testShouldSendMessageInstanceCommandWithNeedForReply()
$this->assertCount(1, $traces);
$this->assertEquals('theMessage', $traces[0]['body']);
$this->assertEquals([
- 'enqueue.topic_name' => Config::COMMAND_TOPIC,
- 'enqueue.processor_name' => RouterProcessor::class,
- 'enqueue.command_name' => 'theCommand',
- 'enqueue.processor_queue_name' => 'default',
- // compatibility with 0.9x
+ 'enqueue.processor' => 'test_command_subscriber_processor',
'enqueue.command' => 'theCommand',
- 'enqueue.topic' => '__command__',
], $traces[0]['properties']);
}
- /**
- * @return TraceableProducer|object
- */
- private function getTraceableProducer()
+ private function getTraceableProducer(): TraceableProducer
{
- return static::$container->get(Producer::class);
+ return static::$container->get('test_enqueue.client.default.traceable_producer');
}
}
diff --git a/pkg/enqueue-bundle/Tests/Functional/Client/SpoolProducerTest.php b/pkg/enqueue-bundle/Tests/Functional/Client/SpoolProducerTest.php
index c8a1eaa27..0bba43327 100644
--- a/pkg/enqueue-bundle/Tests/Functional/Client/SpoolProducerTest.php
+++ b/pkg/enqueue-bundle/Tests/Functional/Client/SpoolProducerTest.php
@@ -12,19 +12,8 @@ class SpoolProducerTest extends WebTestCase
{
public function testCouldBeGetFromContainerAsService()
{
- $producer = static::$container->get(SpoolProducer::class);
+ $producer = static::$container->get('test_enqueue.client.default.spool_producer');
$this->assertInstanceOf(SpoolProducer::class, $producer);
}
-
- /**
- * @group legacy
- */
- public function testCouldBeGetFromContainerAsShortenAlias()
- {
- $producer = static::$container->get('enqueue.client.spool_producer');
- $aliasProducer = static::$container->get('enqueue.spool_producer');
-
- $this->assertSame($producer, $aliasProducer);
- }
}
diff --git a/pkg/enqueue-bundle/Tests/Functional/ConsumeMessagesCommandTest.php b/pkg/enqueue-bundle/Tests/Functional/ConsumeMessagesCommandTest.php
deleted file mode 100644
index d9313c4c5..000000000
--- a/pkg/enqueue-bundle/Tests/Functional/ConsumeMessagesCommandTest.php
+++ /dev/null
@@ -1,18 +0,0 @@
-get(ConsumeMessagesCommand::class);
-
- $this->assertInstanceOf(ConsumeMessagesCommand::class, $command);
- }
-}
diff --git a/pkg/enqueue-bundle/Tests/Functional/ContextTest.php b/pkg/enqueue-bundle/Tests/Functional/ContextTest.php
index 44c141acd..87e2d95a0 100644
--- a/pkg/enqueue-bundle/Tests/Functional/ContextTest.php
+++ b/pkg/enqueue-bundle/Tests/Functional/ContextTest.php
@@ -2,7 +2,7 @@
namespace Enqueue\Bundle\Tests\Functional;
-use Interop\Queue\PsrContext;
+use Interop\Queue\Context;
/**
* @group functional
@@ -11,8 +11,8 @@ class ContextTest extends WebTestCase
{
public function testCouldBeGetFromContainerAsService()
{
- $connection = static::$container->get('enqueue.transport.context');
+ $connection = static::$container->get('test_enqueue.transport.default.context');
- $this->assertInstanceOf(PsrContext::class, $connection);
+ $this->assertInstanceOf(Context::class, $connection);
}
}
diff --git a/pkg/enqueue-bundle/Tests/Functional/Events/AsyncListenerTest.php b/pkg/enqueue-bundle/Tests/Functional/Events/AsyncListenerTest.php
index b9be84e02..7fb6fdd86 100644
--- a/pkg/enqueue-bundle/Tests/Functional/Events/AsyncListenerTest.php
+++ b/pkg/enqueue-bundle/Tests/Functional/Events/AsyncListenerTest.php
@@ -2,6 +2,8 @@
namespace Enqueue\Bundle\Tests\Functional\Events;
+use Enqueue\AsyncEventDispatcher\AsyncListener;
+use Enqueue\AsyncEventDispatcher\Commands;
use Enqueue\Bundle\Tests\Functional\App\TestAsyncListener;
use Enqueue\Bundle\Tests\Functional\WebTestCase;
use Enqueue\Client\TraceableProducer;
@@ -14,11 +16,16 @@
*/
class AsyncListenerTest extends WebTestCase
{
- protected function tearDown()
+ protected function setUp(): void
{
- parent::tearDown();
+ parent::setUp();
- static::$container = null;
+ /** @var AsyncListener $asyncListener */
+ $asyncListener = static::$container->get('enqueue.events.async_listener');
+
+ $asyncListener->resetSyncMode();
+ static::$container->get('test_async_subscriber')->calls = [];
+ static::$container->get('test_async_listener')->calls = [];
}
public function testShouldNotCallRealListenerIfMarkedAsAsync()
@@ -26,7 +33,7 @@ public function testShouldNotCallRealListenerIfMarkedAsAsync()
/** @var EventDispatcherInterface $dispatcher */
$dispatcher = static::$container->get('event_dispatcher');
- $dispatcher->dispatch('test_async', new GenericEvent('aSubject'));
+ $this->dispatch($dispatcher, new GenericEvent('aSubject'), 'test_async');
/** @var TestAsyncListener $listener */
$listener = static::$container->get('test_async_listener');
@@ -41,16 +48,16 @@ public function testShouldSendMessageToExpectedCommandInsteadOfCallingRealListen
$event = new GenericEvent('theSubject', ['fooArg' => 'fooVal']);
- $dispatcher->dispatch('test_async', $event);
+ $this->dispatch($dispatcher, $event, 'test_async');
/** @var TraceableProducer $producer */
- $producer = static::$container->get('enqueue.producer');
+ $producer = static::$container->get('test_enqueue.client.default.producer');
- $traces = $producer->getCommandTraces('symfony_events');
+ $traces = $producer->getCommandTraces(Commands::DISPATCH_ASYNC_EVENTS);
$this->assertCount(1, $traces);
- $this->assertEquals('symfony_events', $traces[0]['command']);
+ $this->assertEquals(Commands::DISPATCH_ASYNC_EVENTS, $traces[0]['command']);
$this->assertEquals('{"subject":"theSubject","arguments":{"fooArg":"fooVal"}}', $traces[0]['body']);
}
@@ -59,14 +66,14 @@ public function testShouldSendMessageForEveryDispatchCall()
/** @var EventDispatcherInterface $dispatcher */
$dispatcher = static::$container->get('event_dispatcher');
- $dispatcher->dispatch('test_async', new GenericEvent('theSubject', ['fooArg' => 'fooVal']));
- $dispatcher->dispatch('test_async', new GenericEvent('theSubject', ['fooArg' => 'fooVal']));
- $dispatcher->dispatch('test_async', new GenericEvent('theSubject', ['fooArg' => 'fooVal']));
+ $this->dispatch($dispatcher, new GenericEvent('theSubject', ['fooArg' => 'fooVal']), 'test_async');
+ $this->dispatch($dispatcher, new GenericEvent('theSubject', ['fooArg' => 'fooVal']), 'test_async');
+ $this->dispatch($dispatcher, new GenericEvent('theSubject', ['fooArg' => 'fooVal']), 'test_async');
/** @var TraceableProducer $producer */
- $producer = static::$container->get('enqueue.producer');
+ $producer = static::$container->get('test_enqueue.client.default.producer');
- $traces = $producer->getCommandTraces('symfony_events');
+ $traces = $producer->getCommandTraces(Commands::DISPATCH_ASYNC_EVENTS);
$this->assertCount(3, $traces);
}
@@ -76,17 +83,29 @@ public function testShouldSendMessageIfDispatchedFromInsideListener()
/** @var EventDispatcherInterface $dispatcher */
$dispatcher = static::$container->get('event_dispatcher');
- $dispatcher->addListener('foo', function (Event $event, $eventName, EventDispatcherInterface $dispatcher) {
- $dispatcher->dispatch('test_async', new GenericEvent('theSubject', ['fooArg' => 'fooVal']));
+ $eventName = 'an_event_'.uniqid();
+ $dispatcher->addListener($eventName, function ($event, $eventName, EventDispatcherInterface $dispatcher) {
+ $this->dispatch($dispatcher, new GenericEvent('theSubject', ['fooArg' => 'fooVal']), 'test_async');
});
- $dispatcher->dispatch('foo');
+ $this->dispatch($dispatcher, new GenericEvent(), $eventName);
/** @var TraceableProducer $producer */
- $producer = static::$container->get('enqueue.producer');
+ $producer = static::$container->get('test_enqueue.client.default.producer');
- $traces = $producer->getCommandTraces('symfony_events');
+ $traces = $producer->getCommandTraces(Commands::DISPATCH_ASYNC_EVENTS);
$this->assertCount(1, $traces);
}
+
+ private function dispatch(EventDispatcherInterface $dispatcher, $event, $eventName): void
+ {
+ if (!class_exists(Event::class)) {
+ // Symfony 5
+ $dispatcher->dispatch($event, $eventName);
+ } else {
+ // Symfony < 5
+ $dispatcher->dispatch($eventName, $event);
+ }
+ }
}
diff --git a/pkg/enqueue-bundle/Tests/Functional/Events/AsyncProcessorTest.php b/pkg/enqueue-bundle/Tests/Functional/Events/AsyncProcessorTest.php
index 4513069a2..d85567509 100644
--- a/pkg/enqueue-bundle/Tests/Functional/Events/AsyncProcessorTest.php
+++ b/pkg/enqueue-bundle/Tests/Functional/Events/AsyncProcessorTest.php
@@ -2,6 +2,7 @@
namespace Enqueue\Bundle\Tests\Functional\Events;
+use Enqueue\AsyncEventDispatcher\AsyncListener;
use Enqueue\AsyncEventDispatcher\AsyncProcessor;
use Enqueue\Bundle\Tests\Functional\App\TestAsyncListener;
use Enqueue\Bundle\Tests\Functional\App\TestAsyncSubscriber;
@@ -9,7 +10,7 @@
use Enqueue\Null\NullContext;
use Enqueue\Null\NullMessage;
use Enqueue\Util\JSON;
-use Interop\Queue\PsrProcessor;
+use Interop\Queue\Processor;
use Symfony\Component\EventDispatcher\GenericEvent;
/**
@@ -17,17 +18,22 @@
*/
class AsyncProcessorTest extends WebTestCase
{
- protected function tearDown()
+ protected function setUp(): void
{
- parent::tearDown();
+ parent::setUp();
- static::$container = null;
+ /** @var AsyncListener $asyncListener */
+ $asyncListener = static::$container->get('enqueue.events.async_listener');
+
+ $asyncListener->resetSyncMode();
+ static::$container->get('test_async_subscriber')->calls = [];
+ static::$container->get('test_async_listener')->calls = [];
}
public function testCouldBeGetFromContainerAsService()
{
/** @var AsyncProcessor $processor */
- $processor = static::$container->get('enqueue.events.async_processor');
+ $processor = static::$container->get('test.enqueue.events.async_processor');
$this->assertInstanceOf(AsyncProcessor::class, $processor);
}
@@ -35,28 +41,28 @@ public function testCouldBeGetFromContainerAsService()
public function testShouldRejectIfMessageDoesNotContainEventNameProperty()
{
/** @var AsyncProcessor $processor */
- $processor = static::$container->get('enqueue.events.async_processor');
+ $processor = static::$container->get('test.enqueue.events.async_processor');
$message = new NullMessage();
- $this->assertEquals(PsrProcessor::REJECT, $processor->process($message, new NullContext()));
+ $this->assertEquals(Processor::REJECT, $processor->process($message, new NullContext()));
}
public function testShouldRejectIfMessageDoesNotContainTransformerNameProperty()
{
/** @var AsyncProcessor $processor */
- $processor = static::$container->get('enqueue.events.async_processor');
+ $processor = static::$container->get('test.enqueue.events.async_processor');
$message = new NullMessage();
$message->setProperty('event_name', 'anEventName');
- $this->assertEquals(PsrProcessor::REJECT, $processor->process($message, new NullContext()));
+ $this->assertEquals(Processor::REJECT, $processor->process($message, new NullContext()));
}
public function testShouldCallRealListener()
{
/** @var AsyncProcessor $processor */
- $processor = static::$container->get('enqueue.events.async_processor');
+ $processor = static::$container->get('test.enqueue.events.async_processor');
$message = new NullMessage();
$message->setProperty('event_name', 'test_async');
@@ -66,7 +72,7 @@ public function testShouldCallRealListener()
'arguments' => ['fooArg' => 'fooVal'],
]));
- $this->assertEquals(PsrProcessor::ACK, $processor->process($message, new NullContext()));
+ $this->assertEquals(Processor::ACK, $processor->process($message, new NullContext()));
/** @var TestAsyncListener $listener */
$listener = static::$container->get('test_async_listener');
@@ -87,7 +93,7 @@ public function testShouldCallRealListener()
public function testShouldCallRealSubscriber()
{
/** @var AsyncProcessor $processor */
- $processor = static::$container->get('enqueue.events.async_processor');
+ $processor = static::$container->get('test.enqueue.events.async_processor');
$message = new NullMessage();
$message->setProperty('event_name', 'test_async_subscriber');
@@ -97,7 +103,7 @@ public function testShouldCallRealSubscriber()
'arguments' => ['fooArg' => 'fooVal'],
]));
- $this->assertEquals(PsrProcessor::ACK, $processor->process($message, new NullContext()));
+ $this->assertEquals(Processor::ACK, $processor->process($message, new NullContext()));
/** @var TestAsyncSubscriber $subscriber */
$subscriber = static::$container->get('test_async_subscriber');
diff --git a/pkg/enqueue-bundle/Tests/Functional/Events/AsyncSubscriberTest.php b/pkg/enqueue-bundle/Tests/Functional/Events/AsyncSubscriberTest.php
index c2e9dc0f6..4b145524a 100644
--- a/pkg/enqueue-bundle/Tests/Functional/Events/AsyncSubscriberTest.php
+++ b/pkg/enqueue-bundle/Tests/Functional/Events/AsyncSubscriberTest.php
@@ -2,7 +2,9 @@
namespace Enqueue\Bundle\Tests\Functional\Events;
-use Enqueue\Bundle\Tests\Functional\App\TestAsyncListener;
+use Enqueue\AsyncEventDispatcher\AsyncListener;
+use Enqueue\AsyncEventDispatcher\Commands;
+use Enqueue\Bundle\Tests\Functional\App\TestAsyncSubscriber;
use Enqueue\Bundle\Tests\Functional\WebTestCase;
use Enqueue\Client\TraceableProducer;
use Symfony\Component\EventDispatcher\Event;
@@ -14,11 +16,16 @@
*/
class AsyncSubscriberTest extends WebTestCase
{
- protected function tearDown()
+ protected function setUp(): void
{
- parent::tearDown();
+ parent::setUp();
- static::$container = null;
+ /** @var AsyncListener $asyncListener */
+ $asyncListener = static::$container->get('enqueue.events.async_listener');
+
+ $asyncListener->resetSyncMode();
+ static::$container->get('test_async_subscriber')->calls = [];
+ static::$container->get('test_async_listener')->calls = [];
}
public function testShouldNotCallRealSubscriberIfMarkedAsAsync()
@@ -26,9 +33,9 @@ public function testShouldNotCallRealSubscriberIfMarkedAsAsync()
/** @var EventDispatcherInterface $dispatcher */
$dispatcher = static::$container->get('event_dispatcher');
- $dispatcher->dispatch('test_async_subscriber', new GenericEvent('aSubject'));
+ $this->dispatch($dispatcher, new GenericEvent('aSubject'), 'test_async_subscriber');
- /** @var TestAsyncListener $listener */
+ /** @var TestAsyncSubscriber $listener */
$listener = static::$container->get('test_async_subscriber');
$this->assertEmpty($listener->calls);
@@ -41,16 +48,16 @@ public function testShouldSendMessageToExpectedTopicInsteadOfCallingRealSubscrib
$event = new GenericEvent('theSubject', ['fooArg' => 'fooVal']);
- $dispatcher->dispatch('test_async_subscriber', $event);
+ $this->dispatch($dispatcher, $event, 'test_async_subscriber');
/** @var TraceableProducer $producer */
- $producer = static::$container->get('enqueue.producer');
+ $producer = static::$container->get('test_enqueue.client.default.producer');
- $traces = $producer->getCommandTraces('symfony_events');
+ $traces = $producer->getCommandTraces(Commands::DISPATCH_ASYNC_EVENTS);
$this->assertCount(1, $traces);
- $this->assertEquals('symfony_events', $traces[0]['command']);
+ $this->assertEquals(Commands::DISPATCH_ASYNC_EVENTS, $traces[0]['command']);
$this->assertEquals('{"subject":"theSubject","arguments":{"fooArg":"fooVal"}}', $traces[0]['body']);
}
@@ -59,14 +66,14 @@ public function testShouldSendMessageForEveryDispatchCall()
/** @var EventDispatcherInterface $dispatcher */
$dispatcher = static::$container->get('event_dispatcher');
- $dispatcher->dispatch('test_async_subscriber', new GenericEvent('theSubject', ['fooArg' => 'fooVal']));
- $dispatcher->dispatch('test_async_subscriber', new GenericEvent('theSubject', ['fooArg' => 'fooVal']));
- $dispatcher->dispatch('test_async_subscriber', new GenericEvent('theSubject', ['fooArg' => 'fooVal']));
+ $this->dispatch($dispatcher, new GenericEvent('theSubject', ['fooArg' => 'fooVal']), 'test_async_subscriber');
+ $this->dispatch($dispatcher, new GenericEvent('theSubject', ['fooArg' => 'fooVal']), 'test_async_subscriber');
+ $this->dispatch($dispatcher, new GenericEvent('theSubject', ['fooArg' => 'fooVal']), 'test_async_subscriber');
/** @var TraceableProducer $producer */
- $producer = static::$container->get('enqueue.producer');
+ $producer = static::$container->get('test_enqueue.client.default.producer');
- $traces = $producer->getCommandTraces('symfony_events');
+ $traces = $producer->getCommandTraces(Commands::DISPATCH_ASYNC_EVENTS);
$this->assertCount(3, $traces);
}
@@ -76,17 +83,29 @@ public function testShouldSendMessageIfDispatchedFromInsideListener()
/** @var EventDispatcherInterface $dispatcher */
$dispatcher = static::$container->get('event_dispatcher');
- $dispatcher->addListener('foo', function (Event $event, $eventName, EventDispatcherInterface $dispatcher) {
- $dispatcher->dispatch('test_async_subscriber', new GenericEvent('theSubject', ['fooArg' => 'fooVal']));
+ $eventName = 'anEvent'.uniqid();
+ $dispatcher->addListener($eventName, function ($event, $eventName, EventDispatcherInterface $dispatcher) {
+ $this->dispatch($dispatcher, new GenericEvent('theSubject', ['fooArg' => 'fooVal']), 'test_async_subscriber');
});
- $dispatcher->dispatch('foo');
+ $this->dispatch($dispatcher, new GenericEvent(), $eventName);
/** @var TraceableProducer $producer */
- $producer = static::$container->get('enqueue.producer');
+ $producer = static::$container->get('test_enqueue.client.default.producer');
- $traces = $producer->getCommandTraces('symfony_events');
+ $traces = $producer->getCommandTraces(Commands::DISPATCH_ASYNC_EVENTS);
$this->assertCount(1, $traces);
}
+
+ private function dispatch(EventDispatcherInterface $dispatcher, $event, $eventName): void
+ {
+ if (!class_exists(Event::class)) {
+ // Symfony 5
+ $dispatcher->dispatch($event, $eventName);
+ } else {
+ // Symfony < 5
+ $dispatcher->dispatch($eventName, $event);
+ }
+ }
}
diff --git a/pkg/enqueue-bundle/Tests/Functional/LazyProducerTest.php b/pkg/enqueue-bundle/Tests/Functional/LazyProducerTest.php
new file mode 100644
index 000000000..18375aef3
--- /dev/null
+++ b/pkg/enqueue-bundle/Tests/Functional/LazyProducerTest.php
@@ -0,0 +1,64 @@
+customSetUp([
+ 'default' => [
+ 'transport' => [
+ 'dsn' => 'invalidDSN',
+ ],
+ ],
+ ]);
+
+ /** @var LazyProducer $producer */
+ $producer = static::$container->get('test_enqueue.client.default.lazy_producer');
+ $this->assertInstanceOf(LazyProducer::class, $producer);
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('The DSN is invalid.');
+ $producer->sendEvent('foo', 'foo');
+ }
+
+ public static function getKernelClass(): string
+ {
+ include_once __DIR__.'/App/CustomAppKernel.php';
+
+ return CustomAppKernel::class;
+ }
+
+ protected function customSetUp(array $enqueueConfig)
+ {
+ static::$class = null;
+
+ static::$client = static::createClient(['enqueue_config' => $enqueueConfig]);
+ static::$client->getKernel()->boot();
+ static::$kernel = static::$client->getKernel();
+ static::$container = static::$kernel->getContainer();
+ }
+
+ protected static function createKernel(array $options = []): CustomAppKernel
+ {
+ /** @var CustomAppKernel $kernel */
+ $kernel = parent::createKernel($options);
+
+ $kernel->setEnqueueConfig(isset($options['enqueue_config']) ? $options['enqueue_config'] : []);
+
+ return $kernel;
+ }
+}
diff --git a/pkg/enqueue-bundle/Tests/Functional/QueueConsumerTest.php b/pkg/enqueue-bundle/Tests/Functional/QueueConsumerTest.php
index 1c0b16a56..e05d1532d 100644
--- a/pkg/enqueue-bundle/Tests/Functional/QueueConsumerTest.php
+++ b/pkg/enqueue-bundle/Tests/Functional/QueueConsumerTest.php
@@ -11,8 +11,10 @@ class QueueConsumerTest extends WebTestCase
{
public function testCouldBeGetFromContainerAsService()
{
- $queueConsumer = static::$container->get(QueueConsumer::class);
+ $queueConsumer = static::$container->get('test_enqueue.client.default.queue_consumer');
+ $this->assertInstanceOf(QueueConsumer::class, $queueConsumer);
+ $queueConsumer = static::$container->get('test_enqueue.transport.default.queue_consumer');
$this->assertInstanceOf(QueueConsumer::class, $queueConsumer);
}
}
diff --git a/pkg/enqueue-bundle/Tests/Functional/QueueRegistryTest.php b/pkg/enqueue-bundle/Tests/Functional/QueueRegistryTest.php
deleted file mode 100644
index d608b8f05..000000000
--- a/pkg/enqueue-bundle/Tests/Functional/QueueRegistryTest.php
+++ /dev/null
@@ -1,18 +0,0 @@
-get(QueueMetaRegistry::class);
-
- $this->assertInstanceOf(QueueMetaRegistry::class, $connection);
- }
-}
diff --git a/pkg/enqueue-bundle/Tests/Functional/QueuesCommandTest.php b/pkg/enqueue-bundle/Tests/Functional/QueuesCommandTest.php
deleted file mode 100644
index 53a008656..000000000
--- a/pkg/enqueue-bundle/Tests/Functional/QueuesCommandTest.php
+++ /dev/null
@@ -1,55 +0,0 @@
-get(QueuesCommand::class);
-
- $this->assertInstanceOf(QueuesCommand::class, $command);
- }
-
- public function testShouldDisplayRegisteredQueues()
- {
- $command = static::$container->get(QueuesCommand::class);
-
- $tester = new CommandTester($command);
- $tester->execute([]);
-
- $display = $tester->getDisplay();
-
- $this->assertContains(' default ', $display);
- $this->assertContains('enqueue.app.default', $display);
-
- $displayId = RouterProcessor::class;
- if (30300 > Kernel::VERSION_ID) {
- // Symfony 3.2 and below make service identifiers lowercase, so we do the same.
- // To be removed when dropping support for Symfony < 3.3.
- $displayId = strtolower($displayId);
- }
-
- $this->assertContains($displayId, $display);
- }
-
- public function testShouldDisplayRegisteredCommand()
- {
- $command = static::$container->get(QueuesCommand::class);
-
- $tester = new CommandTester($command);
- $tester->execute([]);
-
- $display = $tester->getDisplay();
-
- $this->assertContains('test_command_subscriber', $display);
- }
-}
diff --git a/pkg/enqueue-bundle/Tests/Functional/RoutesCommandTest.php b/pkg/enqueue-bundle/Tests/Functional/RoutesCommandTest.php
new file mode 100644
index 000000000..66833b1ce
--- /dev/null
+++ b/pkg/enqueue-bundle/Tests/Functional/RoutesCommandTest.php
@@ -0,0 +1,51 @@
+get('test.enqueue.client.routes_command');
+
+ $this->assertInstanceOf(RoutesCommand::class, $command);
+ }
+
+ public function testShouldDisplayRegisteredTopics()
+ {
+ /** @var RoutesCommand $command */
+ $command = static::$container->get('test.enqueue.client.routes_command');
+
+ $tester = new CommandTester($command);
+ $tester->execute([]);
+
+ $this->assertSame(0, $tester->getStatusCode());
+ $this->assertStringContainsString('| topic', $tester->getDisplay());
+ $this->assertStringContainsString('| theTopic', $tester->getDisplay());
+ $this->assertStringContainsString('| default (prefixed)', $tester->getDisplay());
+ $this->assertStringContainsString('| test_topic_subscriber_processor', $tester->getDisplay());
+ $this->assertStringContainsString('| (hidden)', $tester->getDisplay());
+ }
+
+ public function testShouldDisplayCommands()
+ {
+ /** @var RoutesCommand $command */
+ $command = static::$container->get('test.enqueue.client.routes_command');
+
+ $tester = new CommandTester($command);
+ $tester->execute([]);
+
+ $this->assertSame(0, $tester->getStatusCode());
+ $this->assertStringContainsString('| command', $tester->getDisplay());
+ $this->assertStringContainsString('| theCommand', $tester->getDisplay());
+ $this->assertStringContainsString('| test_command_subscriber_processor', $tester->getDisplay());
+ $this->assertStringContainsString('| default (prefixed)', $tester->getDisplay());
+ $this->assertStringContainsString('| (hidden)', $tester->getDisplay());
+ }
+}
diff --git a/pkg/enqueue-bundle/Tests/Functional/RpcClientTest.php b/pkg/enqueue-bundle/Tests/Functional/RpcClientTest.php
index 1b60661a4..3d99bcc72 100644
--- a/pkg/enqueue-bundle/Tests/Functional/RpcClientTest.php
+++ b/pkg/enqueue-bundle/Tests/Functional/RpcClientTest.php
@@ -11,8 +11,8 @@ class RpcClientTest extends WebTestCase
{
public function testTransportRpcClientCouldBeGetFromContainerAsService()
{
- $connection = static::$container->get(RpcClient::class);
+ $rpcClient = static::$container->get('test_enqueue.transport.default.rpc_client');
- $this->assertInstanceOf(RpcClient::class, $connection);
+ $this->assertInstanceOf(RpcClient::class, $rpcClient);
}
}
diff --git a/pkg/enqueue-bundle/Tests/Functional/TestCommandProcessor.php b/pkg/enqueue-bundle/Tests/Functional/TestCommandProcessor.php
index be6438ae2..dfc2bb864 100644
--- a/pkg/enqueue-bundle/Tests/Functional/TestCommandProcessor.php
+++ b/pkg/enqueue-bundle/Tests/Functional/TestCommandProcessor.php
@@ -3,20 +3,20 @@
namespace Enqueue\Bundle\Tests\Functional;
use Enqueue\Client\CommandSubscriberInterface;
-use Interop\Queue\PsrContext;
-use Interop\Queue\PsrMessage;
-use Interop\Queue\PsrProcessor;
+use Interop\Queue\Context;
+use Interop\Queue\Message;
+use Interop\Queue\Processor;
-class TestCommandProcessor implements PsrProcessor, CommandSubscriberInterface
+class TestCommandProcessor implements Processor, CommandSubscriberInterface
{
- const COMMAND = 'test-command';
+ public const COMMAND = 'test-command';
/**
- * @var PsrMessage
+ * @var Message
*/
public $message;
- public function process(PsrMessage $message, PsrContext $context)
+ public function process(Message $message, Context $context)
{
$this->message = $message;
diff --git a/pkg/enqueue-bundle/Tests/Functional/TestProcessor.php b/pkg/enqueue-bundle/Tests/Functional/TestProcessor.php
index a0086bed6..9b54bdf2d 100644
--- a/pkg/enqueue-bundle/Tests/Functional/TestProcessor.php
+++ b/pkg/enqueue-bundle/Tests/Functional/TestProcessor.php
@@ -3,20 +3,20 @@
namespace Enqueue\Bundle\Tests\Functional;
use Enqueue\Client\TopicSubscriberInterface;
-use Interop\Queue\PsrContext;
-use Interop\Queue\PsrMessage;
-use Interop\Queue\PsrProcessor;
+use Interop\Queue\Context;
+use Interop\Queue\Message;
+use Interop\Queue\Processor;
-class TestProcessor implements PsrProcessor, TopicSubscriberInterface
+class TestProcessor implements Processor, TopicSubscriberInterface
{
- const TOPIC = 'test-topic';
+ public const TOPIC = 'test-topic';
/**
- * @var PsrMessage
+ * @var Message
*/
public $message;
- public function process(PsrMessage $message, PsrContext $context)
+ public function process(Message $message, Context $context)
{
$this->message = $message;
diff --git a/pkg/enqueue-bundle/Tests/Functional/TopicRegistryTest.php b/pkg/enqueue-bundle/Tests/Functional/TopicRegistryTest.php
deleted file mode 100644
index bd15aa7d5..000000000
--- a/pkg/enqueue-bundle/Tests/Functional/TopicRegistryTest.php
+++ /dev/null
@@ -1,18 +0,0 @@
-get(TopicMetaRegistry::class);
-
- $this->assertInstanceOf(TopicMetaRegistry::class, $connection);
- }
-}
diff --git a/pkg/enqueue-bundle/Tests/Functional/TopicsCommandTest.php b/pkg/enqueue-bundle/Tests/Functional/TopicsCommandTest.php
deleted file mode 100644
index f5c1595f1..000000000
--- a/pkg/enqueue-bundle/Tests/Functional/TopicsCommandTest.php
+++ /dev/null
@@ -1,56 +0,0 @@
-get(TopicsCommand::class);
-
- $this->assertInstanceOf(TopicsCommand::class, $command);
- }
-
- public function testShouldDisplayRegisteredTopics()
- {
- $command = static::$container->get(TopicsCommand::class);
-
- $tester = new CommandTester($command);
- $tester->execute([]);
-
- $display = $tester->getDisplay();
-
- $this->assertContains('__router__', $display);
-
- $displayId = RouterProcessor::class;
- if (30300 > Kernel::VERSION_ID) {
- // Symfony 3.2 and below make service identifiers lowercase, so we do the same.
- // To be removed when dropping support for Symfony < 3.3.
- $displayId = strtolower($displayId);
- }
-
- $this->assertContains($displayId, $display);
- }
-
- public function testShouldDisplayCommands()
- {
- $command = static::$container->get(TopicsCommand::class);
-
- $tester = new CommandTester($command);
- $tester->execute([]);
-
- $display = $tester->getDisplay();
-
- $this->assertContains(Config::COMMAND_TOPIC, $display);
- $this->assertContains('test_command_subscriber', $display);
- }
-}
diff --git a/pkg/enqueue-bundle/Tests/Functional/UseCasesTest.php b/pkg/enqueue-bundle/Tests/Functional/UseCasesTest.php
index 7e0bcfbde..7417412bd 100644
--- a/pkg/enqueue-bundle/Tests/Functional/UseCasesTest.php
+++ b/pkg/enqueue-bundle/Tests/Functional/UseCasesTest.php
@@ -4,39 +4,31 @@
use Enqueue\Bundle\Tests\Functional\App\CustomAppKernel;
use Enqueue\Client\DriverInterface;
-use Enqueue\Client\Producer;
use Enqueue\Client\ProducerInterface;
use Enqueue\Stomp\StompDestination;
-use Enqueue\Symfony\Client\ConsumeMessagesCommand;
-use Enqueue\Symfony\Consumption\ContainerAwareConsumeMessagesCommand;
-use Interop\Queue\PsrContext;
-use Interop\Queue\PsrMessage;
-use Interop\Queue\PsrQueue;
+use Interop\Queue\Context;
+use Interop\Queue\Exception\PurgeQueueNotSupportedException;
+use Interop\Queue\Message;
+use Interop\Queue\Queue;
use Symfony\Component\Console\Tester\CommandTester;
-use Symfony\Component\Filesystem\Filesystem;
-use Symfony\Component\HttpKernel\Kernel;
/**
* @group functional
*/
class UseCasesTest extends WebTestCase
{
- public function setUp()
+ private const RECEIVE_TIMEOUT = 500;
+
+ protected function setUp(): void
{
// do not call parent::setUp.
// parent::setUp();
}
- public function tearDown()
+ protected function tearDown(): void
{
- if ($this->getPsrContext()) {
- $this->getPsrContext()->close();
- }
-
- if (static::$kernel) {
- $fs = new Filesystem();
- $fs->remove(static::$kernel->getLogDir());
- $fs->remove(static::$kernel->getCacheDir());
+ if ($this->getContext()) {
+ $this->getContext()->close();
}
parent::tearDown();
@@ -52,32 +44,15 @@ public function provideEnqueueConfigs()
$certDir = $baseDir.'/var/rabbitmq_certificates';
$this->assertDirectoryExists($certDir);
- yield 'amqp' => [[
- 'transport' => [
- 'default' => 'amqp',
- 'amqp' => [
- 'driver' => 'ext',
- 'host' => getenv('RABBITMQ_HOST'),
- 'port' => getenv('RABBITMQ_AMQP__PORT'),
- 'user' => getenv('RABBITMQ_USER'),
- 'pass' => getenv('RABBITMQ_PASSWORD'),
- 'vhost' => getenv('RABBITMQ_VHOST'),
- 'lazy' => false,
- ],
- ],
- ]];
-
yield 'amqp_dsn' => [[
- 'transport' => [
- 'default' => 'amqp',
- 'amqp' => getenv('AMQP_DSN'),
+ 'default' => [
+ 'transport' => getenv('AMQP_DSN'),
],
]];
yield 'amqps_dsn' => [[
- 'transport' => [
- 'default' => 'amqp',
- 'amqp' => [
+ 'default' => [
+ 'transport' => [
'dsn' => getenv('AMQPS_DSN'),
'ssl_verify' => false,
'ssl_cacert' => $certDir.'/cacert.pem',
@@ -87,154 +62,102 @@ public function provideEnqueueConfigs()
],
]];
- yield 'default_amqp_as_dsn' => [[
- 'transport' => [
- 'default' => getenv('AMQP_DSN'),
+ yield 'dsn_as_env' => [[
+ 'default' => [
+ 'transport' => '%env(AMQP_DSN)%',
],
]];
- // Symfony 2.x does not such env syntax
- if (version_compare(Kernel::VERSION, '3.2', '>=')) {
- yield 'default_dsn_as_env' => [[
- 'transport' => [
- 'default' => '%env(AMQP_DSN)%',
- ],
- ]];
- }
-
- yield 'default_dbal_as_dsn' => [[
- 'transport' => [
- 'default' => getenv('DOCTRINE_DSN'),
+ yield 'dbal_dsn' => [[
+ 'default' => [
+ 'transport' => getenv('DOCTRINE_DSN'),
],
]];
yield 'rabbitmq_stomp' => [[
- 'transport' => [
- 'default' => 'rabbitmq_stomp',
- 'rabbitmq_stomp' => [
- 'host' => getenv('RABBITMQ_HOST'),
- 'port' => getenv('RABBITMQ_STOMP_PORT'),
- 'login' => getenv('RABBITMQ_USER'),
- 'password' => getenv('RABBITMQ_PASSWORD'),
- 'vhost' => getenv('RABBITMQ_VHOST'),
+ 'default' => [
+ 'transport' => [
+ 'dsn' => getenv('RABITMQ_STOMP_DSN'),
'lazy' => false,
'management_plugin_installed' => true,
],
],
]];
- yield 'predis' => [[
- 'transport' => [
- 'default' => 'redis',
- 'redis' => [
- 'host' => getenv('REDIS_HOST'),
- 'port' => (int) getenv('REDIS_PORT'),
- 'vendor' => 'predis',
+ yield 'predis_dsn' => [[
+ 'default' => [
+ 'transport' => [
+ 'dsn' => getenv('PREDIS_DSN'),
'lazy' => false,
],
],
]];
- yield 'phpredis' => [[
- 'transport' => [
- 'default' => 'redis',
- 'redis' => [
- 'host' => getenv('REDIS_HOST'),
- 'port' => (int) getenv('REDIS_PORT'),
- 'vendor' => 'phpredis',
+ yield 'phpredis_dsn' => [[
+ 'default' => [
+ 'transport' => [
+ 'dsn' => getenv('PHPREDIS_DSN'),
'lazy' => false,
],
],
]];
- yield 'fs' => [[
- 'transport' => [
- 'default' => 'fs',
- 'fs' => [
- 'path' => sys_get_temp_dir(),
- ],
- ],
- ]];
-
yield 'fs_dsn' => [[
- 'transport' => [
- 'default' => 'fs',
- 'fs' => 'file://'.sys_get_temp_dir(),
+ 'default' => [
+ 'transport' => 'file://'.sys_get_temp_dir(),
],
]];
- yield 'default_fs_as_dsn' => [[
- 'transport' => [
- 'default' => 'file://'.sys_get_temp_dir(),
+ yield 'sqs' => [[
+ 'default' => [
+ 'transport' => [
+ 'dsn' => getenv('SQS_DSN'),
+ ],
],
]];
- yield 'dbal' => [[
- 'transport' => [
- 'default' => 'dbal',
- 'dbal' => [
- 'connection' => [
- 'dbname' => getenv('DOCTRINE_DB_NAME'),
- 'user' => getenv('DOCTRINE_USER'),
- 'password' => getenv('DOCTRINE_PASSWORD'),
- 'host' => getenv('DOCTRINE_HOST'),
- 'port' => getenv('DOCTRINE_PORT'),
- 'driver' => getenv('DOCTRINE_DRIVER'),
- ],
+ yield 'sqs_client' => [[
+ 'default' => [
+ 'transport' => [
+ 'dsn' => 'sqs:',
+ 'service' => 'test.sqs_client',
+ 'factory_service' => 'test.sqs_custom_connection_factory_factory',
],
],
]];
- yield 'dbal_dsn' => [[
- 'transport' => [
- 'default' => 'dbal',
- 'dbal' => getenv('DOCTRINE_DSN'),
+ yield 'mongodb_dsn' => [[
+ 'default' => [
+ 'transport' => getenv('MONGO_DSN'),
],
]];
- // travis build does not have secret env vars if contribution is from outside.
- if (getenv('AWS_SQS_KEY')) {
- yield 'sqs' => [[
- 'transport' => [
- 'default' => 'sqs',
- 'sqs' => [
- 'key' => getenv('AWS_SQS_KEY'),
- 'secret' => getenv('AWS_SQS_SECRET'),
- 'region' => getenv('AWS_SQS_REGION'),
- 'endpoint' => getenv('AWS_SQS_ENDPOINT'),
- ],
- ],
- ]];
+ yield 'doctrine' => [[
+ 'default' => [
+ 'transport' => 'doctrine://custom',
+ ],
+ ]];
- yield 'sqs_client' => [[
+ yield 'snsqs' => [[
+ 'default' => [
'transport' => [
- 'default' => 'sqs',
- 'sqs' => [
- 'client' => 'test.sqs_client',
- ],
+ 'dsn' => getenv('SNSQS_DSN'),
],
- ]];
- }
-
- yield 'mongodb_dsn' => [[
- 'transport' => [
- 'default' => 'mongodb',
- 'mongodb' => getenv('MONGO_DSN'),
],
]];
-// yield 'gps' => [[
-// 'transport' => [
-// 'default' => 'gps',
-// 'gps' => [],
-// ],
-// ]];
+ //
+ // yield 'gps' => [[
+ // 'transport' => [
+ // 'dsn' => getenv('GPS_DSN'),
+ // ],
+ // ]];
}
/**
* @dataProvider provideEnqueueConfigs
*/
- public function testProducerSendsMessage(array $enqueueConfig)
+ public function testProducerSendsEventMessage(array $enqueueConfig)
{
$this->customSetUp($enqueueConfig);
@@ -242,10 +165,10 @@ public function testProducerSendsMessage(array $enqueueConfig)
$this->getMessageProducer()->sendEvent(TestProcessor::TOPIC, $expectedBody);
- $consumer = $this->getPsrContext()->createConsumer($this->getTestQueue());
+ $consumer = $this->getContext()->createConsumer($this->getTestQueue());
- $message = $consumer->receive(100);
- $this->assertInstanceOf(PsrMessage::class, $message);
+ $message = $consumer->receive(self::RECEIVE_TIMEOUT);
+ $this->assertInstanceOf(Message::class, $message);
$consumer->acknowledge($message);
$this->assertSame($expectedBody, $message->getBody());
@@ -262,24 +185,95 @@ public function testProducerSendsCommandMessage(array $enqueueConfig)
$this->getMessageProducer()->sendCommand(TestCommandProcessor::COMMAND, $expectedBody);
- $consumer = $this->getPsrContext()->createConsumer($this->getTestQueue());
+ $consumer = $this->getContext()->createConsumer($this->getTestQueue());
- $message = $consumer->receive(100);
- $this->assertInstanceOf(PsrMessage::class, $message);
+ $message = $consumer->receive(self::RECEIVE_TIMEOUT);
+ $this->assertInstanceOf(Message::class, $message);
$consumer->acknowledge($message);
- $this->assertInstanceOf(PsrMessage::class, $message);
+ $this->assertInstanceOf(Message::class, $message);
$this->assertSame($expectedBody, $message->getBody());
}
- /**
- * @dataProvider provideEnqueueConfigs
- */
- public function testClientConsumeCommandMessagesFromExplicitlySetQueue(array $enqueueConfig)
+ public function testProducerSendsEventMessageViaProduceCommand()
{
- $this->customSetUp($enqueueConfig);
+ $this->customSetUp([
+ 'default' => [
+ 'transport' => getenv('AMQP_DSN'),
+ ],
+ ]);
+
+ $expectedBody = __METHOD__.time();
+
+ $command = static::$container->get('test_enqueue.client.produce_command');
+ $tester = new CommandTester($command);
+ $tester->execute([
+ 'message' => $expectedBody,
+ '--topic' => TestProcessor::TOPIC,
+ '--client' => 'default',
+ ]);
+
+ $consumer = $this->getContext()->createConsumer($this->getTestQueue());
+
+ $message = $consumer->receive(self::RECEIVE_TIMEOUT);
+ $this->assertInstanceOf(Message::class, $message);
+ $consumer->acknowledge($message);
- $command = static::$container->get(ConsumeMessagesCommand::class);
+ $this->assertSame($expectedBody, $message->getBody());
+ }
+
+ public function testProducerSendsCommandMessageViaProduceCommand()
+ {
+ $this->customSetUp([
+ 'default' => [
+ 'transport' => getenv('AMQP_DSN'),
+ ],
+ ]);
+
+ $expectedBody = __METHOD__.time();
+
+ $command = static::$container->get('test_enqueue.client.produce_command');
+ $tester = new CommandTester($command);
+ $tester->execute([
+ 'message' => $expectedBody,
+ '--command' => TestCommandProcessor::COMMAND,
+ '--client' => 'default',
+ ]);
+
+ $consumer = $this->getContext()->createConsumer($this->getTestQueue());
+
+ $message = $consumer->receive(self::RECEIVE_TIMEOUT);
+ $this->assertInstanceOf(Message::class, $message);
+ $consumer->acknowledge($message);
+
+ $this->assertInstanceOf(Message::class, $message);
+ $this->assertSame($expectedBody, $message->getBody());
+ }
+
+ public function testShouldSetupBroker()
+ {
+ $this->customSetUp([
+ 'default' => [
+ 'transport' => 'file://'.sys_get_temp_dir(),
+ ],
+ ]);
+
+ $command = static::$container->get('test_enqueue.client.setup_broker_command');
+ $tester = new CommandTester($command);
+ $tester->execute([]);
+
+ $this->assertSame("Broker set up\n", $tester->getDisplay());
+ }
+
+ public function testClientConsumeCommandMessagesFromExplicitlySetQueue()
+ {
+ $this->customSetUp([
+ 'default' => [
+ 'transport' => getenv('AMQP_DSN'),
+ ],
+ ]);
+
+ $command = static::$container->get('test_enqueue.client.consume_command');
$processor = static::$container->get('test.message.command_processor');
$expectedBody = __METHOD__.time();
@@ -289,24 +283,26 @@ public function testClientConsumeCommandMessagesFromExplicitlySetQueue(array $en
$tester = new CommandTester($command);
$tester->execute([
'--message-limit' => 2,
- '--time-limit' => 'now +10 seconds',
+ '--receive-timeout' => 100,
+ '--time-limit' => 'now + 2 seconds',
'client-queue-names' => ['test'],
]);
- $this->assertInstanceOf(PsrMessage::class, $processor->message);
+ $this->assertInstanceOf(Message::class, $processor->message);
$this->assertEquals($expectedBody, $processor->message->getBody());
}
- /**
- * @dataProvider provideEnqueueConfigs
- */
- public function testClientConsumeMessagesFromExplicitlySetQueue(array $enqueueConfig)
+ public function testClientConsumeMessagesFromExplicitlySetQueue()
{
- $this->customSetUp($enqueueConfig);
+ $this->customSetUp([
+ 'default' => [
+ 'transport' => getenv('AMQP_DSN'),
+ ],
+ ]);
$expectedBody = __METHOD__.time();
- $command = static::$container->get(ConsumeMessagesCommand::class);
+ $command = static::$container->get('test_enqueue.client.consume_command');
$processor = static::$container->get('test.message.processor');
$this->getMessageProducer()->sendEvent(TestProcessor::TOPIC, $expectedBody);
@@ -314,20 +310,22 @@ public function testClientConsumeMessagesFromExplicitlySetQueue(array $enqueueCo
$tester = new CommandTester($command);
$tester->execute([
'--message-limit' => 2,
- '--time-limit' => 'now +10 seconds',
+ '--receive-timeout' => 100,
+ '--time-limit' => 'now + 2 seconds',
'client-queue-names' => ['test'],
]);
- $this->assertInstanceOf(PsrMessage::class, $processor->message);
+ $this->assertInstanceOf(Message::class, $processor->message);
$this->assertEquals($expectedBody, $processor->message->getBody());
}
- /**
- * @dataProvider provideEnqueueConfigs
- */
- public function testTransportConsumeMessagesCommandShouldConsumeMessage(array $enqueueConfig)
+ public function testTransportConsumeCommandShouldConsumeOneMessage()
{
- $this->customSetUp($enqueueConfig);
+ $this->customSetUp([
+ 'default' => [
+ 'transport' => getenv('AMQP_DSN'),
+ ],
+ ]);
if ($this->getTestQueue() instanceof StompDestination) {
$this->markTestSkipped('The test fails with the exception Stomp\Exception\ErrorFrameException: Error "precondition_failed". '.
@@ -337,8 +335,7 @@ public function testTransportConsumeMessagesCommandShouldConsumeMessage(array $e
$expectedBody = __METHOD__.time();
- $command = static::$container->get(ContainerAwareConsumeMessagesCommand::class);
- $command->setContainer(static::$container);
+ $command = static::$container->get('test_enqueue.transport.consume_command');
$processor = static::$container->get('test.message.processor');
$this->getMessageProducer()->sendEvent(TestProcessor::TOPIC, $expectedBody);
@@ -346,20 +343,17 @@ public function testTransportConsumeMessagesCommandShouldConsumeMessage(array $e
$tester = new CommandTester($command);
$tester->execute([
'--message-limit' => 1,
- '--time-limit' => '+10sec',
+ '--time-limit' => '+2sec',
'--receive-timeout' => 1000,
- '--queue' => [$this->getTestQueue()->getQueueName()],
- 'processor-service' => 'test.message.processor',
+ 'processor' => 'test.message.processor',
+ 'queues' => [$this->getTestQueue()->getQueueName()],
]);
- $this->assertInstanceOf(PsrMessage::class, $processor->message);
+ $this->assertInstanceOf(Message::class, $processor->message);
$this->assertEquals($expectedBody, $processor->message->getBody());
}
- /**
- * @return string
- */
- public static function getKernelClass()
+ public static function getKernelClass(): string
{
include_once __DIR__.'/App/CustomAppKernel.php';
@@ -370,41 +364,35 @@ protected function customSetUp(array $enqueueConfig)
{
static::$class = null;
- $this->client = static::createClient(['enqueue_config' => $enqueueConfig]);
- $this->client->getKernel()->boot();
- static::$kernel = $this->client->getKernel();
+ static::$client = static::createClient(['enqueue_config' => $enqueueConfig]);
+ static::$client->getKernel()->boot();
+ static::$kernel = static::$client->getKernel();
static::$container = static::$kernel->getContainer();
/** @var DriverInterface $driver */
- $driver = static::$container->get('enqueue.client.driver');
- $context = $this->getPsrContext();
+ $driver = static::$container->get('test_enqueue.client.default.driver');
+ $context = $this->getContext();
$driver->setupBroker();
try {
- if (method_exists($context, 'purgeQueue')) {
- $queue = $this->getTestQueue();
- $context->purgeQueue($queue);
- }
- } catch (\Exception $e) {
+ $context->purgeQueue($this->getTestQueue());
+ } catch (PurgeQueueNotSupportedException $e) {
}
}
/**
- * @return PsrQueue
+ * @return Queue
*/
protected function getTestQueue()
{
/** @var DriverInterface $driver */
- $driver = static::$container->get('enqueue.client.driver');
+ $driver = static::$container->get('test_enqueue.client.default.driver');
return $driver->createQueue('test');
}
- /**
- * {@inheritdoc}
- */
- protected static function createKernel(array $options = [])
+ protected static function createKernel(array $options = []): CustomAppKernel
{
/** @var CustomAppKernel $kernel */
$kernel = parent::createKernel($options);
@@ -414,19 +402,13 @@ protected static function createKernel(array $options = [])
return $kernel;
}
- /**
- * @return ProducerInterface|object
- */
- private function getMessageProducer()
+ private function getMessageProducer(): ProducerInterface
{
- return static::$container->get(Producer::class);
+ return static::$container->get('test_enqueue.client.default.producer');
}
- /**
- * @return PsrContext|object
- */
- private function getPsrContext()
+ private function getContext(): Context
{
- return static::$container->get('enqueue.transport.context');
+ return static::$container->get('test_enqueue.transport.default.context');
}
}
diff --git a/pkg/enqueue-bundle/Tests/Functional/WebTestCase.php b/pkg/enqueue-bundle/Tests/Functional/WebTestCase.php
index 4b254ccd9..6a348a9f3 100644
--- a/pkg/enqueue-bundle/Tests/Functional/WebTestCase.php
+++ b/pkg/enqueue-bundle/Tests/Functional/WebTestCase.php
@@ -3,6 +3,7 @@
namespace Enqueue\Bundle\Tests\Functional;
use Enqueue\Bundle\Tests\Functional\App\AppKernel;
+use Enqueue\Client\TraceableProducer;
use Symfony\Bundle\FrameworkBundle\Client;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase as BaseWebTestCase;
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -12,30 +13,33 @@ abstract class WebTestCase extends BaseWebTestCase
/**
* @var Client
*/
- protected $client;
+ protected static $client;
/**
* @var ContainerInterface
*/
protected static $container;
- protected function setUp()
+ protected function setUp(): void
{
parent::setUp();
static::$class = null;
+ static::$client = static::createClient();
+ static::$container = static::$kernel->getContainer();
- $this->client = static::createClient();
+ /** @var TraceableProducer $producer */
+ $producer = static::$container->get('test_enqueue.client.default.traceable_producer');
+ $producer->clearTraces();
+ }
- if (false == static::$container) {
- static::$container = static::$kernel->getContainer();
- }
+ protected function tearDown(): void
+ {
+ static::ensureKernelShutdown();
+ static::$client = null;
}
- /**
- * @return string
- */
- public static function getKernelClass()
+ public static function getKernelClass(): string
{
include_once __DIR__.'/App/AppKernel.php';
diff --git a/pkg/enqueue-bundle/Tests/Unit/Consumption/Extension/DoctrineClearIdentityMapExtensionTest.php b/pkg/enqueue-bundle/Tests/Unit/Consumption/Extension/DoctrineClearIdentityMapExtensionTest.php
index 08403bf16..7c5c2dd5d 100644
--- a/pkg/enqueue-bundle/Tests/Unit/Consumption/Extension/DoctrineClearIdentityMapExtensionTest.php
+++ b/pkg/enqueue-bundle/Tests/Unit/Consumption/Extension/DoctrineClearIdentityMapExtensionTest.php
@@ -2,23 +2,20 @@
namespace Enqueue\Bundle\Tests\Unit\Consumption\Extension;
-use Doctrine\Common\Persistence\ObjectManager;
+use Doctrine\Persistence\ManagerRegistry;
+use Doctrine\Persistence\ObjectManager;
use Enqueue\Bundle\Consumption\Extension\DoctrineClearIdentityMapExtension;
-use Enqueue\Consumption\Context;
-use Interop\Queue\PsrConsumer;
-use Interop\Queue\PsrContext;
-use Interop\Queue\PsrProcessor;
+use Enqueue\Consumption\Context\MessageReceived;
+use Interop\Queue\Consumer;
+use Interop\Queue\Context as InteropContext;
+use Interop\Queue\Message;
+use Interop\Queue\Processor;
+use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
-use Symfony\Bridge\Doctrine\RegistryInterface;
class DoctrineClearIdentityMapExtensionTest extends TestCase
{
- public function testCouldBeConstructedWithRequiredArguments()
- {
- new DoctrineClearIdentityMapExtension($this->createRegistryMock());
- }
-
public function testShouldClearIdentityMap()
{
$manager = $this->createManagerMock();
@@ -31,10 +28,10 @@ public function testShouldClearIdentityMap()
$registry
->expects($this->once())
->method('getManagers')
- ->will($this->returnValue(['manager-name' => $manager]))
+ ->willReturn(['manager-name' => $manager])
;
- $context = $this->createPsrContext();
+ $context = $this->createContext();
$context->getLogger()
->expects($this->once())
->method('debug')
@@ -42,34 +39,33 @@ public function testShouldClearIdentityMap()
;
$extension = new DoctrineClearIdentityMapExtension($registry);
- $extension->onPreReceived($context);
+ $extension->onMessageReceived($context);
}
- /**
- * @return Context
- */
- protected function createPsrContext()
+ protected function createContext(): MessageReceived
{
- $context = new Context($this->createMock(PsrContext::class));
- $context->setLogger($this->createMock(LoggerInterface::class));
- $context->setPsrConsumer($this->createMock(PsrConsumer::class));
- $context->setPsrProcessor($this->createMock(PsrProcessor::class));
-
- return $context;
+ return new MessageReceived(
+ $this->createMock(InteropContext::class),
+ $this->createMock(Consumer::class),
+ $this->createMock(Message::class),
+ $this->createMock(Processor::class),
+ 1,
+ $this->createMock(LoggerInterface::class)
+ );
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|RegistryInterface
+ * @return MockObject|ManagerRegistry
*/
- protected function createRegistryMock()
+ protected function createRegistryMock(): ManagerRegistry
{
- return $this->createMock(RegistryInterface::class);
+ return $this->createMock(ManagerRegistry::class);
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|ObjectManager
+ * @return MockObject|ObjectManager
*/
- protected function createManagerMock()
+ protected function createManagerMock(): ObjectManager
{
return $this->createMock(ObjectManager::class);
}
diff --git a/pkg/enqueue-bundle/Tests/Unit/Consumption/Extension/DoctrineClosedEntityManagerExtensionTest.php b/pkg/enqueue-bundle/Tests/Unit/Consumption/Extension/DoctrineClosedEntityManagerExtensionTest.php
new file mode 100644
index 000000000..8e7120325
--- /dev/null
+++ b/pkg/enqueue-bundle/Tests/Unit/Consumption/Extension/DoctrineClosedEntityManagerExtensionTest.php
@@ -0,0 +1,223 @@
+createManagerMock(true);
+
+ $registry = $this->createRegistryMock([
+ 'manager' => $manager,
+ ]);
+
+ $message = new PreConsume(
+ $this->createMock(InteropContext::class),
+ $this->createMock(SubscriptionConsumer::class),
+ $this->createMock(LoggerInterface::class),
+ 1,
+ 2,
+ 3
+ );
+
+ self::assertFalse($message->isExecutionInterrupted());
+
+ $extension = new DoctrineClosedEntityManagerExtension($registry);
+ $extension->onPreConsume($message);
+
+ self::assertFalse($message->isExecutionInterrupted());
+ }
+
+ public function testOnPreConsumeShouldInterruptExecutionIfAManagerIsClosed()
+ {
+ $manager1 = $this->createManagerMock(true);
+ $manager2 = $this->createManagerMock(false);
+
+ $registry = $this->createRegistryMock([
+ 'manager1' => $manager1,
+ 'manager2' => $manager2,
+ ]);
+
+ $message = new PreConsume(
+ $this->createMock(InteropContext::class),
+ $this->createMock(SubscriptionConsumer::class),
+ $this->createMock(LoggerInterface::class),
+ 1,
+ 2,
+ 3
+ );
+ $message->getLogger()
+ ->expects($this->once())
+ ->method('debug')
+ ->with('[DoctrineClosedEntityManagerExtension] Interrupt execution as entity manager "manager2" has been closed')
+ ;
+
+ self::assertFalse($message->isExecutionInterrupted());
+
+ $extension = new DoctrineClosedEntityManagerExtension($registry);
+ $extension->onPreConsume($message);
+
+ self::assertTrue($message->isExecutionInterrupted());
+ }
+
+ public function testOnPostConsumeShouldNotInterruptExecution()
+ {
+ $manager = $this->createManagerMock(true);
+
+ $registry = $this->createRegistryMock([
+ 'manager' => $manager,
+ ]);
+
+ $message = new PostConsume(
+ $this->createMock(InteropContext::class),
+ $this->createMock(SubscriptionConsumer::class),
+ 1,
+ 1,
+ 1,
+ $this->createMock(LoggerInterface::class)
+ );
+
+ self::assertFalse($message->isExecutionInterrupted());
+
+ $extension = new DoctrineClosedEntityManagerExtension($registry);
+ $extension->onPostConsume($message);
+
+ self::assertFalse($message->isExecutionInterrupted());
+ }
+
+ public function testOnPostConsumeShouldInterruptExecutionIfAManagerIsClosed()
+ {
+ $manager1 = $this->createManagerMock(true);
+ $manager2 = $this->createManagerMock(false);
+
+ $registry = $this->createRegistryMock([
+ 'manager1' => $manager1,
+ 'manager2' => $manager2,
+ ]);
+
+ $message = new PostConsume(
+ $this->createMock(InteropContext::class),
+ $this->createMock(SubscriptionConsumer::class),
+ 1,
+ 1,
+ 1,
+ $this->createMock(LoggerInterface::class)
+ );
+ $message->getLogger()
+ ->expects($this->once())
+ ->method('debug')
+ ->with('[DoctrineClosedEntityManagerExtension] Interrupt execution as entity manager "manager2" has been closed')
+ ;
+
+ self::assertFalse($message->isExecutionInterrupted());
+
+ $extension = new DoctrineClosedEntityManagerExtension($registry);
+ $extension->onPostConsume($message);
+
+ self::assertTrue($message->isExecutionInterrupted());
+ }
+
+ public function testOnPostReceivedShouldNotInterruptExecution()
+ {
+ $manager = $this->createManagerMock(true);
+
+ $registry = $this->createRegistryMock([
+ 'manager' => $manager,
+ ]);
+
+ $message = new PostMessageReceived(
+ $this->createMock(InteropContext::class),
+ $this->createMock(Consumer::class),
+ $this->createMock(Message::class),
+ 'aResult',
+ 1,
+ $this->createMock(LoggerInterface::class)
+ );
+
+ self::assertFalse($message->isExecutionInterrupted());
+
+ $extension = new DoctrineClosedEntityManagerExtension($registry);
+ $extension->onPostMessageReceived($message);
+
+ self::assertFalse($message->isExecutionInterrupted());
+ }
+
+ public function testOnPostReceivedShouldInterruptExecutionIfAManagerIsClosed()
+ {
+ $manager1 = $this->createManagerMock(true);
+ $manager2 = $this->createManagerMock(false);
+
+ $registry = $this->createRegistryMock([
+ 'manager1' => $manager1,
+ 'manager2' => $manager2,
+ ]);
+
+ $message = new PostMessageReceived(
+ $this->createMock(InteropContext::class),
+ $this->createMock(Consumer::class),
+ $this->createMock(Message::class),
+ 'aResult',
+ 1,
+ $this->createMock(LoggerInterface::class)
+ );
+ $message->getLogger()
+ ->expects($this->once())
+ ->method('debug')
+ ->with('[DoctrineClosedEntityManagerExtension] Interrupt execution as entity manager "manager2" has been closed')
+ ;
+
+ self::assertFalse($message->isExecutionInterrupted());
+
+ $extension = new DoctrineClosedEntityManagerExtension($registry);
+ $extension->onPostMessageReceived($message);
+
+ self::assertTrue($message->isExecutionInterrupted());
+ }
+
+ /**
+ * @return MockObject|ManagerRegistry
+ */
+ protected function createRegistryMock(array $managers): ManagerRegistry
+ {
+ $mock = $this->createMock(ManagerRegistry::class);
+
+ $mock
+ ->expects($this->once())
+ ->method('getManagers')
+ ->willReturn($managers)
+ ;
+
+ return $mock;
+ }
+
+ /**
+ * @return MockObject|EntityManagerInterface
+ */
+ protected function createManagerMock(bool $open): EntityManagerInterface
+ {
+ $mock = $this->createMock(EntityManagerInterface::class);
+
+ $mock
+ ->expects($this->once())
+ ->method('isOpen')
+ ->willReturn($open)
+ ;
+
+ return $mock;
+ }
+}
diff --git a/pkg/enqueue-bundle/Tests/Unit/Consumption/Extension/DoctrinePingConnectionExtensionTest.php b/pkg/enqueue-bundle/Tests/Unit/Consumption/Extension/DoctrinePingConnectionExtensionTest.php
index acc23bc4e..36df82e52 100644
--- a/pkg/enqueue-bundle/Tests/Unit/Consumption/Extension/DoctrinePingConnectionExtensionTest.php
+++ b/pkg/enqueue-bundle/Tests/Unit/Consumption/Extension/DoctrinePingConnectionExtensionTest.php
@@ -3,34 +3,39 @@
namespace Enqueue\Bundle\Tests\Unit\Consumption\Extension;
use Doctrine\DBAL\Connection;
+use Doctrine\DBAL\Platforms\AbstractPlatform;
+use Doctrine\Persistence\ManagerRegistry;
use Enqueue\Bundle\Consumption\Extension\DoctrinePingConnectionExtension;
-use Enqueue\Consumption\Context;
-use Interop\Queue\PsrConsumer;
-use Interop\Queue\PsrContext;
-use Interop\Queue\PsrProcessor;
+use Enqueue\Consumption\Context\MessageReceived;
+use Enqueue\Test\TestLogger;
+use Interop\Queue\Consumer;
+use Interop\Queue\Context as InteropContext;
+use Interop\Queue\Message;
+use Interop\Queue\Processor;
+use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
-use Psr\Log\LoggerInterface;
-use Symfony\Bridge\Doctrine\RegistryInterface;
class DoctrinePingConnectionExtensionTest extends TestCase
{
- public function testCouldBeConstructedWithRequiredAttributes()
- {
- new DoctrinePingConnectionExtension($this->createRegistryMock());
- }
-
public function testShouldNotReconnectIfConnectionIsOK()
{
$connection = $this->createConnectionMock();
$connection
->expects($this->once())
->method('isConnected')
- ->will($this->returnValue(true))
+ ->willReturn(true)
;
+
+ $abstractPlatform = $this->createMock(AbstractPlatform::class);
+ $abstractPlatform->expects($this->once())
+ ->method('getDummySelectSQL')
+ ->willReturn('dummy')
+ ;
+
$connection
->expects($this->once())
- ->method('ping')
- ->will($this->returnValue(true))
+ ->method('getDatabasePlatform')
+ ->willReturn($abstractPlatform)
;
$connection
->expects($this->never())
@@ -41,21 +46,21 @@ public function testShouldNotReconnectIfConnectionIsOK()
->method('connect')
;
- $context = $this->createPsrContext();
- $context->getLogger()
- ->expects($this->never())
- ->method('debug')
- ;
+ $context = $this->createContext();
$registry = $this->createRegistryMock();
$registry
- ->expects($this->once())
+ ->expects(self::once())
->method('getConnections')
- ->will($this->returnValue([$connection]))
+ ->willReturn([$connection])
;
$extension = new DoctrinePingConnectionExtension($registry);
- $extension->onPreReceived($context);
+ $extension->onMessageReceived($context);
+
+ /** @var TestLogger $logger */
+ $logger = $context->getLogger();
+ self::assertFalse($logger->hasDebugRecords());
}
public function testShouldDoesReconnectIfConnectionFailed()
@@ -64,12 +69,13 @@ public function testShouldDoesReconnectIfConnectionFailed()
$connection
->expects($this->once())
->method('isConnected')
- ->will($this->returnValue(true))
+ ->willReturn(true)
;
+
$connection
->expects($this->once())
- ->method('ping')
- ->will($this->returnValue(false))
+ ->method('getDatabasePlatform')
+ ->willThrowException(new \Exception())
;
$connection
->expects($this->once())
@@ -80,27 +86,30 @@ public function testShouldDoesReconnectIfConnectionFailed()
->method('connect')
;
- $context = $this->createPsrContext();
- $context->getLogger()
- ->expects($this->at(0))
- ->method('debug')
- ->with('[DoctrinePingConnectionExtension] Connection is not active trying to reconnect.')
- ;
- $context->getLogger()
- ->expects($this->at(1))
- ->method('debug')
- ->with('[DoctrinePingConnectionExtension] Connection is active now.')
- ;
+ $context = $this->createContext();
$registry = $this->createRegistryMock();
$registry
->expects($this->once())
->method('getConnections')
- ->will($this->returnValue([$connection]))
+ ->willReturn([$connection])
;
$extension = new DoctrinePingConnectionExtension($registry);
- $extension->onPreReceived($context);
+ $extension->onMessageReceived($context);
+
+ /** @var TestLogger $logger */
+ $logger = $context->getLogger();
+ self::assertTrue(
+ $logger->hasDebugThatContains(
+ '[DoctrinePingConnectionExtension] Connection is not active trying to reconnect.'
+ )
+ );
+ self::assertTrue(
+ $logger->hasDebugThatContains(
+ '[DoctrinePingConnectionExtension] Connection is active now.'
+ )
+ );
}
public function testShouldSkipIfConnectionWasNotOpened()
@@ -109,11 +118,11 @@ public function testShouldSkipIfConnectionWasNotOpened()
$connection1
->expects($this->once())
->method('isConnected')
- ->will($this->returnValue(false))
+ ->willReturn(false)
;
$connection1
->expects($this->never())
- ->method('ping')
+ ->method('getDatabasePlatform')
;
// 2nd connection was opened in the past
@@ -121,56 +130,61 @@ public function testShouldSkipIfConnectionWasNotOpened()
$connection2
->expects($this->once())
->method('isConnected')
- ->will($this->returnValue(true))
+ ->willReturn(true)
+ ;
+ $abstractPlatform = $this->createMock(AbstractPlatform::class);
+ $abstractPlatform->expects($this->once())
+ ->method('getDummySelectSQL')
+ ->willReturn('dummy')
;
+
$connection2
->expects($this->once())
- ->method('ping')
- ->will($this->returnValue(true))
+ ->method('getDatabasePlatform')
+ ->willReturn($abstractPlatform)
;
- $context = $this->createPsrContext();
- $context->getLogger()
- ->expects($this->never())
- ->method('debug')
- ;
+ $context = $this->createContext();
$registry = $this->createRegistryMock();
$registry
->expects($this->once())
->method('getConnections')
- ->will($this->returnValue([$connection1, $connection2]))
+ ->willReturn([$connection1, $connection2])
;
$extension = new DoctrinePingConnectionExtension($registry);
- $extension->onPreReceived($context);
+ $extension->onMessageReceived($context);
+
+ /** @var TestLogger $logger */
+ $logger = $context->getLogger();
+ $this->assertFalse($logger->hasDebugRecords());
}
- /**
- * @return Context
- */
- protected function createPsrContext()
+ protected function createContext(): MessageReceived
{
- $context = new Context($this->createMock(PsrContext::class));
- $context->setLogger($this->createMock(LoggerInterface::class));
- $context->setPsrConsumer($this->createMock(PsrConsumer::class));
- $context->setPsrProcessor($this->createMock(PsrProcessor::class));
-
- return $context;
+ return new MessageReceived(
+ $this->createMock(InteropContext::class),
+ $this->createMock(Consumer::class),
+ $this->createMock(Message::class),
+ $this->createMock(Processor::class),
+ 1,
+ new TestLogger()
+ );
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|RegistryInterface
+ * @return MockObject|ManagerRegistry
*/
protected function createRegistryMock()
{
- return $this->createMock(RegistryInterface::class);
+ return $this->createMock(ManagerRegistry::class);
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|Connection
+ * @return MockObject|Connection
*/
- protected function createConnectionMock()
+ protected function createConnectionMock(): Connection
{
return $this->createMock(Connection::class);
}
diff --git a/pkg/enqueue-bundle/Tests/Unit/Consumption/Extension/ResetServicesExtensionTest.php b/pkg/enqueue-bundle/Tests/Unit/Consumption/Extension/ResetServicesExtensionTest.php
new file mode 100644
index 000000000..63282a255
--- /dev/null
+++ b/pkg/enqueue-bundle/Tests/Unit/Consumption/Extension/ResetServicesExtensionTest.php
@@ -0,0 +1,57 @@
+createResetterMock();
+ $resetter
+ ->expects($this->once())
+ ->method('reset')
+ ;
+
+ $context = $this->createContext();
+ $context->getLogger()
+ ->expects($this->once())
+ ->method('debug')
+ ->with('[ResetServicesExtension] Resetting services.')
+ ;
+
+ $extension = new ResetServicesExtension($resetter);
+ $extension->onPostMessageReceived($context);
+ }
+
+ protected function createContext(): PostMessageReceived
+ {
+ return new PostMessageReceived(
+ $this->createMock(InteropContext::class),
+ $this->createMock(Consumer::class),
+ $this->createMock(Message::class),
+ $this->createMock(Processor::class),
+ 1,
+ $this->createMock(LoggerInterface::class)
+ );
+ }
+
+ /**
+ * @return MockObject|ManagerRegistry
+ */
+ protected function createResetterMock(): ServicesResetter
+ {
+ return $this->createMock(ServicesResetter::class);
+ }
+}
diff --git a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/AddTopicMetaPassTest.php b/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/AddTopicMetaPassTest.php
deleted file mode 100644
index 94537fd89..000000000
--- a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/AddTopicMetaPassTest.php
+++ /dev/null
@@ -1,76 +0,0 @@
-assertClassImplements(CompilerPassInterface::class, AddTopicMetaPass::class);
- }
-
- public function testCouldBeConstructedWithoutAntArguments()
- {
- new AddTopicMetaPass();
- }
-
- public function testCouldBeConstructedByCreateFactoryMethod()
- {
- $pass = AddTopicMetaPass::create();
-
- $this->assertInstanceOf(AddTopicMetaPass::class, $pass);
- }
-
- public function testShouldReturnSelfOnAdd()
- {
- $pass = AddTopicMetaPass::create();
-
- $this->assertSame($pass, $pass->add('aTopic'));
- }
-
- public function testShouldDoNothingIfContainerDoesNotHaveRegistryService()
- {
- $container = new ContainerBuilder();
-
- $pass = AddTopicMetaPass::create()
- ->add('fooTopic')
- ->add('barTopic')
- ;
-
- $pass->process($container);
- }
-
- public function testShouldAddTopicsInRegistryKeepingPreviouslyAdded()
- {
- $container = new ContainerBuilder();
-
- $registry = new Definition(null, [[
- 'bazTopic' => [],
- ]]);
- $container->setDefinition(TopicMetaRegistry::class, $registry);
-
- $pass = AddTopicMetaPass::create()
- ->add('fooTopic')
- ->add('barTopic')
- ;
- $pass->process($container);
-
- $expectedTopics = [
- 'bazTopic' => [],
- 'fooTopic' => [],
- 'barTopic' => [],
- ];
-
- $this->assertSame($expectedTopics, $registry->getArgument(0));
- }
-}
diff --git a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/BuildClientExtensionsPassTest.php b/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/BuildClientExtensionsPassTest.php
deleted file mode 100644
index e98184b84..000000000
--- a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/BuildClientExtensionsPassTest.php
+++ /dev/null
@@ -1,129 +0,0 @@
-assertClassImplements(CompilerPassInterface::class, BuildClientExtensionsPass::class);
- }
-
- public function testCouldBeConstructedWithoutAnyArguments()
- {
- new BuildClientExtensionsPass();
- }
-
- public function testShouldReplaceFirstArgumentOfExtensionsServiceConstructorWithTagsExtensions()
- {
- $container = new ContainerBuilder();
-
- $extensions = new Definition();
- $extensions->addArgument([]);
- $container->setDefinition('enqueue.client.extensions', $extensions);
-
- $extension = new Definition();
- $extension->addTag('enqueue.client.extension');
- $container->setDefinition('foo_extension', $extension);
-
- $extension = new Definition();
- $extension->addTag('enqueue.client.extension');
- $container->setDefinition('bar_extension', $extension);
-
- $pass = new BuildClientExtensionsPass();
- $pass->process($container);
-
- $this->assertEquals(
- [new Reference('foo_extension'), new Reference('bar_extension')],
- $extensions->getArgument(0)
- );
- }
-
- public function testShouldOrderExtensionsByPriority()
- {
- $container = new ContainerBuilder();
-
- $extensions = new Definition();
- $extensions->addArgument([]);
- $container->setDefinition('enqueue.client.extensions', $extensions);
-
- $extension = new Definition();
- $extension->addTag('enqueue.client.extension', ['priority' => 6]);
- $container->setDefinition('foo_extension', $extension);
-
- $extension = new Definition();
- $extension->addTag('enqueue.client.extension', ['priority' => -5]);
- $container->setDefinition('bar_extension', $extension);
-
- $extension = new Definition();
- $extension->addTag('enqueue.client.extension', ['priority' => 2]);
- $container->setDefinition('baz_extension', $extension);
-
- $pass = new BuildClientExtensionsPass();
- $pass->process($container);
-
- $orderedExtensions = $extensions->getArgument(0);
-
- $this->assertEquals(new Reference('foo_extension'), $orderedExtensions[0]);
- $this->assertEquals(new Reference('baz_extension'), $orderedExtensions[1]);
- $this->assertEquals(new Reference('bar_extension'), $orderedExtensions[2]);
- }
-
- public function testShouldAssumePriorityZeroIfPriorityIsNotSet()
- {
- $container = new ContainerBuilder();
-
- $extensions = new Definition();
- $extensions->addArgument([]);
- $container->setDefinition('enqueue.client.extensions', $extensions);
-
- $extension = new Definition();
- $extension->addTag('enqueue.client.extension');
- $container->setDefinition('foo_extension', $extension);
-
- $extension = new Definition();
- $extension->addTag('enqueue.client.extension', ['priority' => 1]);
- $container->setDefinition('bar_extension', $extension);
-
- $extension = new Definition();
- $extension->addTag('enqueue.client.extension', ['priority' => -1]);
- $container->setDefinition('baz_extension', $extension);
-
- $pass = new BuildClientExtensionsPass();
- $pass->process($container);
-
- $orderedExtensions = $extensions->getArgument(0);
-
- $this->assertEquals(new Reference('bar_extension'), $orderedExtensions[0]);
- $this->assertEquals(new Reference('foo_extension'), $orderedExtensions[1]);
- $this->assertEquals(new Reference('baz_extension'), $orderedExtensions[2]);
- }
-
- public function testShouldDoesNothingIfClientExtensionServiceIsNotDefined()
- {
- $container = $this->createMock(ContainerBuilder::class);
- $container
- ->expects($this->once())
- ->method('hasDefinition')
- ->with('enqueue.client.extensions')
- ->willReturn(false)
- ;
- $container
- ->expects($this->never())
- ->method('findTaggedServiceIds')
- ;
-
- $pass = new BuildClientExtensionsPass();
- $pass->process($container);
- }
-}
diff --git a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/BuildClientRoutingPassTest.php b/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/BuildClientRoutingPassTest.php
deleted file mode 100644
index f1b678570..000000000
--- a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/BuildClientRoutingPassTest.php
+++ /dev/null
@@ -1,318 +0,0 @@
-createContainerBuilder();
-
- $processor = new Definition(\stdClass::class);
- $processor->addTag('enqueue.client.processor', [
- 'topicName' => 'topic',
- 'processorName' => 'processor',
- 'queueName' => 'queue',
- ]);
- $container->setDefinition('processor', $processor);
-
- $router = new Definition();
- $router->setArguments([null, null, null]);
- $container->setDefinition(RouterProcessor::class, $router);
-
- $pass = new BuildClientRoutingPass();
- $pass->process($container);
-
- $expectedRoutes = [
- 'topic' => [
- ['processor', 'queue'],
- ],
- ];
-
- $this->assertEquals($expectedRoutes, $router->getArgument(1));
- }
-
- public function testThrowIfProcessorClassNameCouldNotBeFound()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition('notExistingClass');
- $processor->addTag('enqueue.client.processor', [
- 'processorName' => 'processor',
- ]);
- $container->setDefinition('processor', $processor);
-
- $router = new Definition();
- $router->setArguments([null, []]);
- $container->setDefinition(RouterProcessor::class, $router);
-
- $pass = new BuildClientRoutingPass();
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('The class "notExistingClass" could not be found.');
- $pass->process($container);
- }
-
- public function testShouldThrowExceptionIfTopicNameIsNotSet()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(\stdClass::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor', $processor);
-
- $router = new Definition();
- $router->setArguments([null, null, null]);
- $container->setDefinition(RouterProcessor::class, $router);
-
- $pass = new BuildClientRoutingPass();
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('Topic name is not set on message processor tag but it is required.');
- $pass->process($container);
- }
-
- public function testShouldSetServiceIdAdProcessorIdIfIsNotSetInTag()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(\stdClass::class);
- $processor->addTag('enqueue.client.processor', [
- 'topicName' => 'topic',
- 'queueName' => 'queue',
- ]);
- $container->setDefinition('processor-service-id', $processor);
-
- $router = new Definition();
- $router->setArguments([null, null, null]);
- $container->setDefinition(RouterProcessor::class, $router);
-
- $pass = new BuildClientRoutingPass();
- $pass->process($container);
-
- $expectedRoutes = [
- 'topic' => [
- ['processor-service-id', 'queue'],
- ],
- ];
-
- $this->assertEquals($expectedRoutes, $router->getArgument(1));
- }
-
- public function testShouldSetDefaultQueueIfNotSetInTag()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(\stdClass::class);
- $processor->addTag('enqueue.client.processor', [
- 'topicName' => 'topic',
- ]);
- $container->setDefinition('processor-service-id', $processor);
-
- $router = new Definition();
- $router->setArguments([null, null, null]);
- $container->setDefinition(RouterProcessor::class, $router);
-
- $pass = new BuildClientRoutingPass();
- $pass->process($container);
-
- $expectedRoutes = [
- 'topic' => [
- ['processor-service-id', 'aDefaultQueueName'],
- ],
- ];
-
- $this->assertEquals($expectedRoutes, $router->getArgument(1));
- }
-
- public function testShouldBuildRouteFromSubscriberIfOnlyTopicNameSpecified()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(OnlyTopicNameTopicSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-service-id', $processor);
-
- $router = new Definition();
- $router->setArguments([null, null, null]);
- $container->setDefinition(RouterProcessor::class, $router);
-
- $pass = new BuildClientRoutingPass();
- $pass->process($container);
-
- $expectedRoutes = [
- 'topic-subscriber-name' => [
- ['processor-service-id', 'aDefaultQueueName'],
- ],
- ];
-
- $this->assertEquals($expectedRoutes, $router->getArgument(1));
- }
-
- public function testShouldBuildRouteFromSubscriberIfProcessorNameSpecified()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(ProcessorNameTopicSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-service-id', $processor);
-
- $router = new Definition();
- $router->setArguments([null, null, null]);
- $container->setDefinition(RouterProcessor::class, $router);
-
- $pass = new BuildClientRoutingPass();
- $pass->process($container);
-
- $expectedRoutes = [
- 'topic-subscriber-name' => [
- ['subscriber-processor-name', 'aDefaultQueueName'],
- ],
- ];
-
- $this->assertEquals($expectedRoutes, $router->getArgument(1));
- }
-
- public function testShouldBuildRouteFromSubscriberIfQueueNameSpecified()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(QueueNameTopicSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-service-id', $processor);
-
- $router = new Definition();
- $router->setArguments([null, null, null]);
- $container->setDefinition(RouterProcessor::class, $router);
-
- $pass = new BuildClientRoutingPass();
- $pass->process($container);
-
- $expectedRoutes = [
- 'topic-subscriber-name' => [
- ['processor-service-id', 'subscriber-queue-name'],
- ],
- ];
-
- $this->assertEquals($expectedRoutes, $router->getArgument(1));
- }
-
- public function testShouldBuildRouteFromWithoutProcessorNameTopicSubscriber()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(WithoutProcessorNameTopicSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-service-id', $processor);
-
- $router = new Definition();
- $router->setArguments([null, null, null]);
- $container->setDefinition(RouterProcessor::class, $router);
-
- $pass = new BuildClientRoutingPass();
- $pass->process($container);
-
- $expectedRoutes = [
- 'without-processor-name' => [
- ['processor-service-id', 'a_queue_name'],
- ],
- ];
-
- $this->assertEquals($expectedRoutes, $router->getArgument(1));
- }
-
- public function testShouldThrowExceptionWhenTopicSubscriberConfigurationIsInvalid()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(InvalidTopicSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-service-id', $processor);
-
- $router = new Definition();
- $router->setArguments(['', '']);
- $container->setDefinition(RouterProcessor::class, $router);
-
- $pass = new BuildClientRoutingPass();
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('Topic subscriber configuration is invalid');
-
- $pass->process($container);
- }
-
- public function testShouldBuildRouteFromCommandSubscriberIfOnlyCommandNameSpecified()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(OnlyCommandNameSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-service-id', $processor);
-
- $router = new Definition();
- $router->setArguments([null, null, null]);
- $container->setDefinition(RouterProcessor::class, $router);
-
- $pass = new BuildClientRoutingPass();
- $pass->process($container);
-
- $expectedRoutes = [
- 'the-command-name' => 'aDefaultQueueName',
- ];
-
- $this->assertEquals([], $router->getArgument(1));
- $this->assertEquals($expectedRoutes, $router->getArgument(2));
- }
-
- public function testShouldBuildRouteFromCommandSubscriberIfProcessorNameSpecified()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(ProcessorNameCommandSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-service-id', $processor);
-
- $router = new Definition();
- $router->setArguments([null, null, null]);
- $container->setDefinition(RouterProcessor::class, $router);
-
- $pass = new BuildClientRoutingPass();
- $pass->process($container);
-
- $expectedRoutes = [
- 'the-command-name' => 'the-command-queue-name',
- ];
-
- $this->assertEquals([], $router->getArgument(1));
- $this->assertEquals($expectedRoutes, $router->getArgument(2));
- }
-
- /**
- * @return ContainerBuilder
- */
- private function createContainerBuilder()
- {
- $container = new ContainerBuilder();
- $container->setParameter('enqueue.client.default_queue_name', 'aDefaultQueueName');
-
- return $container;
- }
-}
diff --git a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/BuildConsumptionExtensionsPassTest.php b/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/BuildConsumptionExtensionsPassTest.php
deleted file mode 100644
index a7614bc96..000000000
--- a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/BuildConsumptionExtensionsPassTest.php
+++ /dev/null
@@ -1,111 +0,0 @@
-assertClassImplements(CompilerPassInterface::class, BuildConsumptionExtensionsPass::class);
- }
-
- public function testCouldBeConstructedWithoutAnyArguments()
- {
- new BuildConsumptionExtensionsPass();
- }
-
- public function testShouldReplaceFirstArgumentOfExtensionsServiceConstructorWithTagsExtensions()
- {
- $container = new ContainerBuilder();
-
- $extensions = new Definition();
- $extensions->addArgument([]);
- $container->setDefinition('enqueue.consumption.extensions', $extensions);
-
- $extension = new Definition();
- $extension->addTag('enqueue.consumption.extension');
- $container->setDefinition('foo_extension', $extension);
-
- $extension = new Definition();
- $extension->addTag('enqueue.consumption.extension');
- $container->setDefinition('bar_extension', $extension);
-
- $pass = new BuildConsumptionExtensionsPass();
- $pass->process($container);
-
- $this->assertEquals(
- [new Reference('foo_extension'), new Reference('bar_extension')],
- $extensions->getArgument(0)
- );
- }
-
- public function testShouldOrderExtensionsByPriority()
- {
- $container = new ContainerBuilder();
-
- $extensions = new Definition();
- $extensions->addArgument([]);
- $container->setDefinition('enqueue.consumption.extensions', $extensions);
-
- $extension = new Definition();
- $extension->addTag('enqueue.consumption.extension', ['priority' => 6]);
- $container->setDefinition('foo_extension', $extension);
-
- $extension = new Definition();
- $extension->addTag('enqueue.consumption.extension', ['priority' => -5]);
- $container->setDefinition('bar_extension', $extension);
-
- $extension = new Definition();
- $extension->addTag('enqueue.consumption.extension', ['priority' => 2]);
- $container->setDefinition('baz_extension', $extension);
-
- $pass = new BuildConsumptionExtensionsPass();
- $pass->process($container);
-
- $orderedExtensions = $extensions->getArgument(0);
-
- $this->assertEquals(new Reference('foo_extension'), $orderedExtensions[0]);
- $this->assertEquals(new Reference('baz_extension'), $orderedExtensions[1]);
- $this->assertEquals(new Reference('bar_extension'), $orderedExtensions[2]);
- }
-
- public function testShouldAssumePriorityZeroIfPriorityIsNotSet()
- {
- $container = new ContainerBuilder();
-
- $extensions = new Definition();
- $extensions->addArgument([]);
- $container->setDefinition('enqueue.consumption.extensions', $extensions);
-
- $extension = new Definition();
- $extension->addTag('enqueue.consumption.extension');
- $container->setDefinition('foo_extension', $extension);
-
- $extension = new Definition();
- $extension->addTag('enqueue.consumption.extension', ['priority' => 1]);
- $container->setDefinition('bar_extension', $extension);
-
- $extension = new Definition();
- $extension->addTag('enqueue.consumption.extension', ['priority' => -1]);
- $container->setDefinition('baz_extension', $extension);
-
- $pass = new BuildConsumptionExtensionsPass();
- $pass->process($container);
-
- $orderedExtensions = $extensions->getArgument(0);
-
- $this->assertEquals(new Reference('bar_extension'), $orderedExtensions[0]);
- $this->assertEquals(new Reference('foo_extension'), $orderedExtensions[1]);
- $this->assertEquals(new Reference('baz_extension'), $orderedExtensions[2]);
- }
-}
diff --git a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/BuildExclusiveCommandsExtensionPassTest.php b/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/BuildExclusiveCommandsExtensionPassTest.php
deleted file mode 100644
index 395078ac2..000000000
--- a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/BuildExclusiveCommandsExtensionPassTest.php
+++ /dev/null
@@ -1,105 +0,0 @@
-assertClassImplements(CompilerPassInterface::class, BuildExclusiveCommandsExtensionPass::class);
- }
-
- public function testCouldBeConstructedWithoutAnyArguments()
- {
- new BuildExclusiveCommandsExtensionPass();
- }
-
- public function testShouldDoNothingIfExclusiveCommandExtensionServiceNotRegistered()
- {
- $container = new ContainerBuilder();
-
- $pass = new BuildExclusiveCommandsExtensionPass();
- $pass->process($container);
- }
-
- public function testShouldReplaceFirstArgumentOfExclusiveCommandExtensionServiceConstructorWithExpectedMap()
- {
- $container = new ContainerBuilder();
- $container->setParameter('enqueue.client.default_queue_name', 'default');
- $container->register('enqueue.client.exclusive_command_extension', ExclusiveCommandExtension::class)
- ->addArgument([])
- ;
-
- $processor = new Definition(ExclusiveCommandSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-id', $processor);
-
- $pass = new BuildExclusiveCommandsExtensionPass();
-
- $pass->process($container);
-
- $this->assertEquals([
- 'the-queue-name' => 'the-exclusive-command-name',
- ], $container->getDefinition('enqueue.client.exclusive_command_extension')->getArgument(0));
- }
-
- public function testShouldReplaceFirstArgumentOfExclusiveCommandConfiguredAsTagAttribute()
- {
- $container = new ContainerBuilder();
- $container->setParameter('enqueue.client.default_queue_name', 'default');
- $container->register('enqueue.client.exclusive_command_extension', ExclusiveCommandExtension::class)
- ->addArgument([])
- ;
-
- $processor = new Definition($this->getMockClass(PsrProcessor::class));
- $processor->addTag('enqueue.client.processor', [
- 'topicName' => Config::COMMAND_TOPIC,
- 'processorName' => 'the-exclusive-command-name',
- 'queueName' => 'the-queue-name',
- 'queueNameHardcoded' => true,
- 'exclusive' => true,
- ]);
- $container->setDefinition('processor-id', $processor);
-
- $pass = new BuildExclusiveCommandsExtensionPass();
-
- $pass->process($container);
-
- $this->assertEquals([
- 'the-queue-name' => 'the-exclusive-command-name',
- ], $container->getDefinition('enqueue.client.exclusive_command_extension')->getArgument(0));
- }
-
- public function testShouldThrowIfExclusiveSetTrueButQueueNameIsNotHardcoded()
- {
- $container = new ContainerBuilder();
- $container->setParameter('enqueue.client.default_queue_name', 'default');
- $container->register('enqueue.client.exclusive_command_extension', ExclusiveCommandExtension::class)
- ->addArgument([])
- ;
-
- $processor = new Definition(ExclusiveButQueueNameHardCodedCommandSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-id', $processor);
-
- $pass = new BuildExclusiveCommandsExtensionPass();
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('The exclusive command could be used only with queueNameHardcoded attribute set to true.');
- $pass->process($container);
- }
-}
diff --git a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/BuildProcessorRegistryPassTest.php b/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/BuildProcessorRegistryPassTest.php
deleted file mode 100644
index 9c7a00cdd..000000000
--- a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/BuildProcessorRegistryPassTest.php
+++ /dev/null
@@ -1,293 +0,0 @@
-createContainerBuilder();
-
- $processor = new Definition(\stdClass::class);
- $processor->addTag('enqueue.client.processor', [
- 'topicName' => 'topic',
- 'processorName' => 'processor-name',
- ]);
- $container->setDefinition('processor-id', $processor);
-
- $processorRegistry = new Definition();
- $processorRegistry->setArguments([]);
- $container->setDefinition('enqueue.client.processor_registry', $processorRegistry);
-
- $pass = new BuildProcessorRegistryPass();
- $pass->process($container);
-
- $expectedValue = [
- 'processor-name' => 'processor-id',
- ];
-
- $this->assertEquals($expectedValue, $processorRegistry->getArgument(0));
- }
-
- public function testThrowIfProcessorClassNameCouldNotBeFound()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition('notExistingClass');
- $processor->addTag('enqueue.client.processor', [
- 'processorName' => 'processor',
- ]);
- $container->setDefinition('processor', $processor);
-
- $processorRegistry = new Definition();
- $processorRegistry->setArguments([]);
- $container->setDefinition('enqueue.client.processor_registry', $processorRegistry);
-
- $pass = new BuildProcessorRegistryPass();
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('The class "notExistingClass" could not be found.');
- $pass->process($container);
- }
-
- public function testShouldThrowExceptionIfTopicNameIsNotSet()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(\stdClass::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor', $processor);
-
- $processorRegistry = new Definition();
- $processorRegistry->setArguments([]);
- $container->setDefinition('enqueue.client.processor_registry', $processorRegistry);
-
- $pass = new BuildProcessorRegistryPass();
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('Topic name is not set on message processor tag but it is required.');
- $pass->process($container);
- }
-
- public function testShouldSetServiceIdAdProcessorIdIfIsNotSetInTag()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(\stdClass::class);
- $processor->addTag('enqueue.client.processor', [
- 'topicName' => 'topic',
- ]);
- $container->setDefinition('processor-id', $processor);
-
- $processorRegistry = new Definition();
- $processorRegistry->setArguments([]);
- $container->setDefinition('enqueue.client.processor_registry', $processorRegistry);
-
- $pass = new BuildProcessorRegistryPass();
- $pass->process($container);
-
- $expectedValue = [
- 'processor-id' => 'processor-id',
- ];
-
- $this->assertEquals($expectedValue, $processorRegistry->getArgument(0));
- }
-
- public function testShouldBuildRouteFromSubscriberIfOnlyTopicNameSpecified()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(OnlyTopicNameTopicSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-id', $processor);
-
- $processorRegistry = new Definition();
- $processorRegistry->setArguments([]);
- $container->setDefinition('enqueue.client.processor_registry', $processorRegistry);
-
- $pass = new BuildProcessorRegistryPass();
- $pass->process($container);
-
- $expectedValue = [
- 'processor-id' => 'processor-id',
- ];
-
- $this->assertEquals($expectedValue, $processorRegistry->getArgument(0));
- }
-
- public function testShouldBuildRouteFromWithoutProcessorNameTopicSubscriber()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(WithoutProcessorNameTopicSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-id', $processor);
-
- $processorRegistry = new Definition();
- $processorRegistry->setArguments([]);
- $container->setDefinition('enqueue.client.processor_registry', $processorRegistry);
-
- $pass = new BuildProcessorRegistryPass();
- $pass->process($container);
-
- $expectedValue = [
- 'processor-id' => 'processor-id',
- ];
-
- $this->assertEquals($expectedValue, $processorRegistry->getArgument(0));
- }
-
- public function testShouldBuildRouteFromSubscriberIfProcessorNameSpecified()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(ProcessorNameTopicSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-id', $processor);
-
- $processorRegistry = new Definition();
- $processorRegistry->setArguments([]);
- $container->setDefinition('enqueue.client.processor_registry', $processorRegistry);
-
- $pass = new BuildProcessorRegistryPass();
- $pass->process($container);
-
- $expectedValue = [
- 'subscriber-processor-name' => 'processor-id',
- ];
-
- $this->assertEquals($expectedValue, $processorRegistry->getArgument(0));
- }
-
- public function testShouldThrowExceptionWhenTopicSubscriberConfigurationIsInvalid()
- {
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('Topic subscriber configuration is invalid');
-
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(InvalidTopicSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-id', $processor);
-
- $processorRegistry = new Definition();
- $processorRegistry->setArguments([]);
- $container->setDefinition('enqueue.client.processor_registry', $processorRegistry);
-
- $pass = new BuildProcessorRegistryPass();
- $pass->process($container);
- }
-
- public function testShouldBuildRouteFromOnlyNameCommandSubscriber()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(OnlyCommandNameSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-id', $processor);
-
- $processorRegistry = new Definition();
- $processorRegistry->setArguments([]);
- $container->setDefinition('enqueue.client.processor_registry', $processorRegistry);
-
- $pass = new BuildProcessorRegistryPass();
- $pass->process($container);
-
- $expectedValue = [
- 'the-command-name' => 'processor-id',
- ];
-
- $this->assertEquals($expectedValue, $processorRegistry->getArgument(0));
- }
-
- public function testShouldBuildRouteFromProcessorNameCommandSubscriber()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(ProcessorNameCommandSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-id', $processor);
-
- $processorRegistry = new Definition();
- $processorRegistry->setArguments([]);
- $container->setDefinition('enqueue.client.processor_registry', $processorRegistry);
-
- $pass = new BuildProcessorRegistryPass();
- $pass->process($container);
-
- $expectedValue = [
- 'the-command-name' => 'processor-id',
- ];
-
- $this->assertEquals($expectedValue, $processorRegistry->getArgument(0));
- }
-
- public function testShouldThrowExceptionWhenProcessorNameEmpty()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(EmptyCommandSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-id', $processor);
-
- $processorRegistry = new Definition();
- $processorRegistry->setArguments([]);
- $container->setDefinition('enqueue.client.processor_registry', $processorRegistry);
-
- $pass = new BuildProcessorRegistryPass();
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('The processor name (it is also the command name) must not be empty.');
-
- $pass->process($container);
- }
-
- public function testShouldThrowExceptionWhenCommandSubscriberConfigurationIsInvalid()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(InvalidCommandSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-id', $processor);
-
- $processorRegistry = new Definition();
- $processorRegistry->setArguments([]);
- $container->setDefinition('enqueue.client.processor_registry', $processorRegistry);
-
- $pass = new BuildProcessorRegistryPass();
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('Command subscriber configuration is invalid. "12345"');
-
- $pass->process($container);
- }
-
- /**
- * @return ContainerBuilder
- */
- private function createContainerBuilder()
- {
- $container = new ContainerBuilder();
- $container->setParameter('enqueue.client.default_queue_name', 'aDefaultQueueName');
-
- return $container;
- }
-}
diff --git a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/BuildQueueMetaRegistryPassTest.php b/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/BuildQueueMetaRegistryPassTest.php
deleted file mode 100644
index 46c315a78..000000000
--- a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/BuildQueueMetaRegistryPassTest.php
+++ /dev/null
@@ -1,252 +0,0 @@
-createContainerBuilder();
-
- $processor = new Definition(\stdClass::class);
- $processor->addTag('enqueue.client.processor', [
- 'processorName' => 'processor',
- ]);
- $container->setDefinition('processor', $processor);
-
- $pass = new BuildQueueMetaRegistryPass();
- $pass->process($container);
- }
-
- public function testThrowIfProcessorClassNameCouldNotBeFound()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition('notExistingClass');
- $processor->addTag('enqueue.client.processor', [
- 'processorName' => 'processor',
- ]);
- $container->setDefinition('processor', $processor);
-
- $registry = new Definition();
- $registry->setArguments([null, []]);
- $container->setDefinition(QueueMetaRegistry::class, $registry);
-
- $pass = new BuildQueueMetaRegistryPass();
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('The class "notExistingClass" could not be found.');
- $pass->process($container);
- }
-
- public function testShouldBuildQueueMetaRegistry()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(\stdClass::class);
- $processor->addTag('enqueue.client.processor', [
- 'processorName' => 'theProcessorName',
- 'topicName' => 'aTopicName',
- ]);
- $container->setDefinition('processor', $processor);
-
- $registry = new Definition();
- $registry->setArguments([null, []]);
- $container->setDefinition(QueueMetaRegistry::class, $registry);
-
- $pass = new BuildQueueMetaRegistryPass();
- $pass->process($container);
-
- $expectedQueues = [
- 'aDefaultQueueName' => ['processors' => ['theProcessorName']],
- ];
-
- $this->assertEquals($expectedQueues, $registry->getArgument(1));
- }
-
- public function testShouldSetServiceIdAdProcessorIdIfIsNotSetInTag()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(\stdClass::class);
- $processor->addTag('enqueue.client.processor', [
- 'topicName' => 'aTopicName',
- ]);
- $container->setDefinition('processor-service-id', $processor);
-
- $registry = new Definition();
- $registry->setArguments([null, []]);
- $container->setDefinition(QueueMetaRegistry::class, $registry);
-
- $pass = new BuildQueueMetaRegistryPass();
- $pass->process($container);
-
- $expectedQueues = [
- 'aDefaultQueueName' => ['processors' => ['processor-service-id']],
- ];
-
- $this->assertEquals($expectedQueues, $registry->getArgument(1));
- }
-
- public function testShouldSetQueueIfSetInTag()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(\stdClass::class);
- $processor->addTag('enqueue.client.processor', [
- 'queueName' => 'theClientQueueName',
- 'topicName' => 'aTopicName',
- ]);
- $container->setDefinition('processor-service-id', $processor);
-
- $registry = new Definition();
- $registry->setArguments([null, []]);
- $container->setDefinition(QueueMetaRegistry::class, $registry);
-
- $pass = new BuildQueueMetaRegistryPass();
- $pass->process($container);
-
- $expectedQueues = [
- 'theClientQueueName' => ['processors' => ['processor-service-id']],
- ];
-
- $this->assertEquals($expectedQueues, $registry->getArgument(1));
- }
-
- public function testShouldBuildQueueFromSubscriberIfOnlyTopicNameSpecified()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(OnlyTopicNameTopicSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-service-id', $processor);
-
- $registry = new Definition();
- $registry->setArguments([null, []]);
- $container->setDefinition(QueueMetaRegistry::class, $registry);
-
- $pass = new BuildQueueMetaRegistryPass();
- $pass->process($container);
-
- $expectedQueues = [
- 'aDefaultQueueName' => ['processors' => ['processor-service-id']],
- ];
-
- $this->assertEquals($expectedQueues, $registry->getArgument(1));
- }
-
- public function testShouldBuildQueueFromSubscriberIfProcessorNameSpecified()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(ProcessorNameTopicSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-service-id', $processor);
-
- $registry = new Definition();
- $registry->setArguments([null, []]);
- $container->setDefinition(QueueMetaRegistry::class, $registry);
-
- $pass = new BuildQueueMetaRegistryPass();
- $pass->process($container);
-
- $expectedQueues = [
- 'aDefaultQueueName' => ['processors' => ['subscriber-processor-name']],
- ];
-
- $this->assertEquals($expectedQueues, $registry->getArgument(1));
- }
-
- public function testShouldBuildQueueFromSubscriberIfQueueNameSpecified()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(QueueNameTopicSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-service-id', $processor);
-
- $registry = new Definition();
- $registry->setArguments([null, []]);
- $container->setDefinition(QueueMetaRegistry::class, $registry);
-
- $pass = new BuildQueueMetaRegistryPass();
- $pass->process($container);
-
- $expectedQueues = [
- 'subscriber-queue-name' => ['processors' => ['processor-service-id']],
- ];
-
- $this->assertEquals($expectedQueues, $registry->getArgument(1));
- }
-
- public function testShouldBuildQueueFromCommandSubscriber()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(ProcessorNameCommandSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-service-id', $processor);
-
- $registry = new Definition();
- $registry->setArguments([null, []]);
- $container->setDefinition(QueueMetaRegistry::class, $registry);
-
- $pass = new BuildQueueMetaRegistryPass();
- $pass->process($container);
-
- $expectedQueues = [
- 'the-command-queue-name' => ['processors' => ['the-command-name']],
- ];
-
- $this->assertEquals($expectedQueues, $registry->getArgument(1));
- }
-
- public function testShouldBuildQueueFromOnlyCommandNameSubscriber()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(OnlyCommandNameSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-service-id', $processor);
-
- $registry = new Definition();
- $registry->setArguments([null, []]);
- $container->setDefinition(QueueMetaRegistry::class, $registry);
-
- $pass = new BuildQueueMetaRegistryPass();
- $pass->process($container);
-
- $expectedQueues = [
- 'aDefaultQueueName' => ['processors' => ['the-command-name']],
- ];
-
- $this->assertEquals($expectedQueues, $registry->getArgument(1));
- }
-
- /**
- * @return ContainerBuilder
- */
- private function createContainerBuilder()
- {
- $container = new ContainerBuilder();
- $container->setParameter('enqueue.client.default_queue_name', 'aDefaultQueueName');
-
- return $container;
- }
-}
diff --git a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/BuildTopicMetaSubscribersPassTest.php b/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/BuildTopicMetaSubscribersPassTest.php
deleted file mode 100644
index 7e166b06d..000000000
--- a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/BuildTopicMetaSubscribersPassTest.php
+++ /dev/null
@@ -1,364 +0,0 @@
-createContainerBuilder();
-
- $processor = new Definition(\stdClass::class);
- $processor->addTag('enqueue.client.processor', [
- 'topicName' => 'topic',
- 'processorName' => 'processor-name',
- ]);
- $container->setDefinition('processor-id', $processor);
-
- $topicMetaRegistry = new Definition();
- $topicMetaRegistry->setArguments([[]]);
- $container->setDefinition(TopicMetaRegistry::class, $topicMetaRegistry);
-
- $pass = new BuildTopicMetaSubscribersPass();
- $pass->process($container);
-
- $expectedValue = [
- 'topic' => ['processors' => ['processor-name']],
- ];
-
- $this->assertEquals($expectedValue, $topicMetaRegistry->getArgument(0));
- }
-
- public function testThrowIfProcessorClassNameCouldNotBeFound()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition('notExistingClass');
- $processor->addTag('enqueue.client.processor', [
- 'processorName' => 'processor',
- ]);
- $container->setDefinition('processor', $processor);
-
- $topicMetaRegistry = new Definition();
- $topicMetaRegistry->setArguments([[]]);
- $container->setDefinition(TopicMetaRegistry::class, $topicMetaRegistry);
-
- $pass = new BuildTopicMetaSubscribersPass();
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('The class "notExistingClass" could not be found.');
- $pass->process($container);
- }
-
- public function testShouldBuildTopicMetaSubscribersForOneTagAndSameMetaInRegistry()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(\stdClass::class);
- $processor->addTag('enqueue.client.processor', [
- 'topicName' => 'topic',
- 'processorName' => 'barProcessorName',
- ]);
- $container->setDefinition('processor-id', $processor);
-
- $topicMetaRegistry = new Definition();
- $topicMetaRegistry->setArguments([[
- 'topic' => ['description' => 'aDescription', 'processors' => ['fooProcessorName']],
- ]]);
- $container->setDefinition(TopicMetaRegistry::class, $topicMetaRegistry);
-
- $pass = new BuildTopicMetaSubscribersPass();
- $pass->process($container);
-
- $expectedValue = [
- 'topic' => [
- 'description' => 'aDescription',
- 'processors' => ['fooProcessorName', 'barProcessorName'],
- ],
- ];
-
- $this->assertEquals($expectedValue, $topicMetaRegistry->getArgument(0));
- }
-
- public function testShouldBuildTopicMetaSubscribersForOneTagAndSameMetaInPlusAnotherRegistry()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(\stdClass::class);
- $processor->addTag('enqueue.client.processor', [
- 'topicName' => 'fooTopic',
- 'processorName' => 'barProcessorName',
- ]);
- $container->setDefinition('processor-id', $processor);
-
- $topicMetaRegistry = new Definition();
- $topicMetaRegistry->setArguments([[
- 'fooTopic' => ['description' => 'aDescription', 'processors' => ['fooProcessorName']],
- 'barTopic' => ['description' => 'aBarDescription'],
- ]]);
- $container->setDefinition(TopicMetaRegistry::class, $topicMetaRegistry);
-
- $pass = new BuildTopicMetaSubscribersPass();
- $pass->process($container);
-
- $expectedValue = [
- 'fooTopic' => [
- 'description' => 'aDescription',
- 'processors' => ['fooProcessorName', 'barProcessorName'],
- ],
- 'barTopic' => ['description' => 'aBarDescription'],
- ];
-
- $this->assertEquals($expectedValue, $topicMetaRegistry->getArgument(0));
- }
-
- public function testShouldBuildTopicMetaSubscribersForTwoTagAndEmptyRegistry()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(\stdClass::class);
- $processor->addTag('enqueue.client.processor', [
- 'topicName' => 'fooTopic',
- 'processorName' => 'fooProcessorName',
- ]);
- $container->setDefinition('processor-id', $processor);
-
- $processor = new Definition(\stdClass::class);
- $processor->addTag('enqueue.client.processor', [
- 'topicName' => 'fooTopic',
- 'processorName' => 'barProcessorName',
- ]);
- $container->setDefinition('another-processor-id', $processor);
-
- $topicMetaRegistry = new Definition();
- $topicMetaRegistry->setArguments([[]]);
- $container->setDefinition(TopicMetaRegistry::class, $topicMetaRegistry);
-
- $pass = new BuildTopicMetaSubscribersPass();
- $pass->process($container);
-
- $expectedValue = [
- 'fooTopic' => [
- 'processors' => ['fooProcessorName', 'barProcessorName'],
- ],
- ];
-
- $this->assertEquals($expectedValue, $topicMetaRegistry->getArgument(0));
- }
-
- public function testShouldBuildTopicMetaSubscribersForTwoTagSameMetaRegistry()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(\stdClass::class);
- $processor->addTag('enqueue.client.processor', [
- 'topicName' => 'fooTopic',
- 'processorName' => 'fooProcessorName',
- ]);
- $container->setDefinition('processor-id', $processor);
-
- $processor = new Definition(\stdClass::class);
- $processor->addTag('enqueue.client.processor', [
- 'topicName' => 'fooTopic',
- 'processorName' => 'barProcessorName',
- ]);
- $container->setDefinition('another-processor-id', $processor);
-
- $topicMetaRegistry = new Definition();
- $topicMetaRegistry->setArguments([[
- 'fooTopic' => ['description' => 'aDescription', 'processors' => ['bazProcessorName']],
- ]]);
- $container->setDefinition(TopicMetaRegistry::class, $topicMetaRegistry);
-
- $pass = new BuildTopicMetaSubscribersPass();
- $pass->process($container);
-
- $expectedValue = [
- 'fooTopic' => [
- 'description' => 'aDescription',
- 'processors' => ['bazProcessorName', 'fooProcessorName', 'barProcessorName'],
- ],
- ];
-
- $this->assertEquals($expectedValue, $topicMetaRegistry->getArgument(0));
- }
-
- public function testThrowIfTopicNameNotSetOnTagAsAttribute()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(\stdClass::class);
- $processor->addTag('enqueue.client.processor', []);
- $container->setDefinition('processor', $processor);
-
- $topicMetaRegistry = new Definition();
- $topicMetaRegistry->setArguments([[]]);
- $container->setDefinition(TopicMetaRegistry::class, $topicMetaRegistry);
-
- $pass = new BuildTopicMetaSubscribersPass();
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('Topic name is not set on message processor tag but it is required.');
- $pass->process($container);
- }
-
- public function testShouldSetServiceIdAdProcessorIdIfIsNotSetInTag()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(\stdClass::class);
- $processor->addTag('enqueue.client.processor', [
- 'topicName' => 'topic',
- ]);
- $container->setDefinition('processor-id', $processor);
-
- $topicMetaRegistry = new Definition();
- $topicMetaRegistry->setArguments([[]]);
- $container->setDefinition(TopicMetaRegistry::class, $topicMetaRegistry);
-
- $pass = new BuildTopicMetaSubscribersPass();
- $pass->process($container);
-
- $expectedValue = [
- 'topic' => ['processors' => ['processor-id']],
- ];
-
- $this->assertEquals($expectedValue, $topicMetaRegistry->getArgument(0));
- }
-
- public function testShouldBuildMetaFromSubscriberIfOnlyTopicNameSpecified()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(OnlyTopicNameTopicSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-id', $processor);
-
- $topicMetaRegistry = new Definition();
- $topicMetaRegistry->setArguments([[]]);
- $container->setDefinition(TopicMetaRegistry::class, $topicMetaRegistry);
-
- $pass = new BuildTopicMetaSubscribersPass();
- $pass->process($container);
-
- $expectedValue = [
- 'topic-subscriber-name' => ['processors' => ['processor-id']],
- ];
-
- $this->assertEquals($expectedValue, $topicMetaRegistry->getArgument(0));
- }
-
- public function testShouldBuildMetaFromSubscriberIfProcessorNameSpecified()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(ProcessorNameTopicSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-id', $processor);
-
- $topicMetaRegistry = new Definition();
- $topicMetaRegistry->setArguments([[]]);
- $container->setDefinition(TopicMetaRegistry::class, $topicMetaRegistry);
-
- $pass = new BuildTopicMetaSubscribersPass();
- $pass->process($container);
-
- $expectedValue = [
- 'topic-subscriber-name' => ['processors' => ['subscriber-processor-name']],
- ];
-
- $this->assertEquals($expectedValue, $topicMetaRegistry->getArgument(0));
- }
-
- public function testShouldThrowExceptionWhenTopicSubscriberConfigurationIsInvalid()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(InvalidTopicSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-id', $processor);
-
- $topicMetaRegistry = new Definition();
- $topicMetaRegistry->setArguments([[]]);
- $container->setDefinition(TopicMetaRegistry::class, $topicMetaRegistry);
-
- $pass = new BuildTopicMetaSubscribersPass();
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('Topic subscriber configuration is invalid');
-
- $pass->process($container);
- }
-
- public function testShouldBuildMetaFromCommandSubscriberIfOnlyCommandNameSpecified()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(OnlyCommandNameSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-id', $processor);
-
- $topicMetaRegistry = new Definition();
- $topicMetaRegistry->setArguments([[]]);
- $container->setDefinition(TopicMetaRegistry::class, $topicMetaRegistry);
-
- $pass = new BuildTopicMetaSubscribersPass();
- $pass->process($container);
-
- $expectedValue = [
- Config::COMMAND_TOPIC => ['processors' => ['the-command-name']],
- ];
-
- $this->assertEquals($expectedValue, $topicMetaRegistry->getArgument(0));
- }
-
- public function testShouldBuildMetaFromCommandSubscriberIfProcessorNameSpecified()
- {
- $container = $this->createContainerBuilder();
-
- $processor = new Definition(ProcessorNameCommandSubscriber::class);
- $processor->addTag('enqueue.client.processor');
- $container->setDefinition('processor-id', $processor);
-
- $topicMetaRegistry = new Definition();
- $topicMetaRegistry->setArguments([[]]);
- $container->setDefinition(TopicMetaRegistry::class, $topicMetaRegistry);
-
- $pass = new BuildTopicMetaSubscribersPass();
- $pass->process($container);
-
- $expectedValue = [
- Config::COMMAND_TOPIC => ['processors' => ['the-command-name']],
- ];
-
- $this->assertEquals($expectedValue, $topicMetaRegistry->getArgument(0));
- }
-
- /**
- * @return ContainerBuilder
- */
- private function createContainerBuilder()
- {
- $container = new ContainerBuilder();
- $container->setParameter('enqueue.client.default_queue_name', 'aDefaultQueueName');
-
- return $container;
- }
-}
diff --git a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/Mock/EmptyCommandSubscriber.php b/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/Mock/EmptyCommandSubscriber.php
deleted file mode 100644
index 27fb16138..000000000
--- a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/Mock/EmptyCommandSubscriber.php
+++ /dev/null
@@ -1,13 +0,0 @@
- 'the-exclusive-command-name',
- 'queueName' => 'the-queue-name',
- 'queueNameHardCoded' => false,
- 'exclusive' => true,
- ];
- }
-}
diff --git a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/Mock/ExclusiveCommandSubscriber.php b/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/Mock/ExclusiveCommandSubscriber.php
deleted file mode 100644
index 742758a81..000000000
--- a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/Mock/ExclusiveCommandSubscriber.php
+++ /dev/null
@@ -1,18 +0,0 @@
- 'the-exclusive-command-name',
- 'queueName' => 'the-queue-name',
- 'queueNameHardcoded' => true,
- 'exclusive' => true,
- ];
- }
-}
diff --git a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/Mock/InvalidCommandSubscriber.php b/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/Mock/InvalidCommandSubscriber.php
deleted file mode 100644
index 44b32a4de..000000000
--- a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/Mock/InvalidCommandSubscriber.php
+++ /dev/null
@@ -1,13 +0,0 @@
- 'the-command-name',
- 'queueName' => 'the-command-queue-name',
- ];
- }
-}
diff --git a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/Mock/ProcessorNameTopicSubscriber.php b/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/Mock/ProcessorNameTopicSubscriber.php
deleted file mode 100644
index 9574ee4e4..000000000
--- a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/Mock/ProcessorNameTopicSubscriber.php
+++ /dev/null
@@ -1,17 +0,0 @@
- [
- 'processorName' => 'subscriber-processor-name',
- ],
- ];
- }
-}
diff --git a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/Mock/QueueNameTopicSubscriber.php b/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/Mock/QueueNameTopicSubscriber.php
deleted file mode 100644
index 6ed163d13..000000000
--- a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/Mock/QueueNameTopicSubscriber.php
+++ /dev/null
@@ -1,17 +0,0 @@
- [
- 'queueName' => 'subscriber-queue-name',
- ],
- ];
- }
-}
diff --git a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/Mock/WithoutProcessorNameTopicSubscriber.php b/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/Mock/WithoutProcessorNameTopicSubscriber.php
deleted file mode 100644
index fa30d9f78..000000000
--- a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/Compiler/Mock/WithoutProcessorNameTopicSubscriber.php
+++ /dev/null
@@ -1,18 +0,0 @@
- [
- 'queueName' => 'a_queue_name',
- 'queueNameHardcoded' => true,
- ],
- ];
- }
-}
diff --git a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/ConfigurationTest.php b/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/ConfigurationTest.php
index 05f4b5d38..5330cde82 100644
--- a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/ConfigurationTest.php
+++ b/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/ConfigurationTest.php
@@ -2,15 +2,13 @@
namespace Enqueue\Bundle\Tests\Unit\DependencyInjection;
+use DMS\PHPUnitExtensions\ArraySubset\Assert;
use Enqueue\Bundle\DependencyInjection\Configuration;
-use Enqueue\Bundle\Tests\Unit\Mocks\FooTransportFactory;
-use Enqueue\Client\RouterProcessor;
-use Enqueue\Null\Symfony\NullTransportFactory;
-use Enqueue\Symfony\DefaultTransportFactory;
use Enqueue\Test\ClassExtensionTrait;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
+use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
use Symfony\Component\Config\Definition\Processor;
class ConfigurationTest extends TestCase
@@ -22,444 +20,643 @@ public function testShouldImplementConfigurationInterface()
$this->assertClassImplements(ConfigurationInterface::class, Configuration::class);
}
- public function testCouldBeConstructedWithFactoriesAsFirstArgument()
+ public function testShouldBeFinal()
{
- new Configuration([], true);
+ $this->assertClassFinal(Configuration::class);
}
- public function testThrowIfTransportNotConfigured()
+ public function testShouldProcessSeveralTransports()
{
- $this->expectException(InvalidConfigurationException::class);
- $this->expectExceptionMessage('The child node "transport" at path "enqueue" must be configured.');
+ $configuration = new Configuration(true);
- $configuration = new Configuration([], true);
+ $processor = new Processor();
+ $config = $processor->processConfiguration($configuration, [[
+ 'default' => [
+ 'transport' => 'default:',
+ ],
+ 'foo' => [
+ 'transport' => 'foo:',
+ ],
+ ]]);
+
+ $this->assertConfigEquals([
+ 'default' => [
+ 'transport' => [
+ 'dsn' => 'default:',
+ ],
+ ],
+ 'foo' => [
+ 'transport' => [
+ 'dsn' => 'foo:',
+ ],
+ ],
+ ], $config);
+ }
+
+ public function testTransportFactoryShouldValidateEachTransportAccordingToItsRules()
+ {
+ $configuration = new Configuration(true);
$processor = new Processor();
- $processor->processConfiguration($configuration, [[]]);
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Both options factory_class and factory_service are set. Please choose one.');
+ $processor->processConfiguration($configuration, [
+ [
+ 'default' => [
+ 'transport' => [
+ 'factory_class' => 'aClass',
+ 'factory_service' => 'aService',
+ ],
+ ],
+ ],
+ ]);
}
- public function testShouldInjectFooTransportFactoryConfig()
+ public function testShouldSetDefaultConfigurationForClient()
{
- $configuration = new Configuration([new FooTransportFactory()], true);
+ $configuration = new Configuration(true);
$processor = new Processor();
+ $config = $processor->processConfiguration($configuration, [[
+ 'default' => [
+ 'transport' => 'null:',
+ 'client' => null,
+ ],
+ ]]);
+
+ $this->assertConfigEquals([
+ 'default' => [
+ 'client' => [
+ 'prefix' => 'enqueue',
+ 'app_name' => 'app',
+ 'router_processor' => null,
+ 'router_topic' => 'default',
+ 'router_queue' => 'default',
+ 'default_queue' => 'default',
+ 'traceable_producer' => true,
+ 'redelivered_delay_time' => 0,
+ ],
+ ],
+ ], $config);
+ }
+
+ public function testThrowIfClientDriverOptionsIsNotArray()
+ {
+ $configuration = new Configuration(true);
+
+ $processor = new Processor();
+
+ $this->expectException(InvalidTypeException::class);
+ // Exception messages vary slightly between versions
+ $this->expectExceptionMessageMatches(
+ '/Invalid type for path "enqueue\.default\.client\.driver_options"\. Expected "?array"?, but got "?string"?/'
+ );
+
$processor->processConfiguration($configuration, [[
- 'transport' => [
- 'foo' => [
- 'foo_param' => 'aParam',
+ 'default' => [
+ 'transport' => 'null:',
+ 'client' => [
+ 'driver_options' => 'invalidOption',
+ ],
+ ],
+ ]]);
+ }
+
+ public function testShouldConfigureClientDriverOptions()
+ {
+ $configuration = new Configuration(true);
+
+ $processor = new Processor();
+ $config = $processor->processConfiguration($configuration, [[
+ 'default' => [
+ 'transport' => 'null:',
+ 'client' => [
+ 'driver_options' => [
+ 'foo' => 'fooVal',
+ ],
],
],
]]);
+
+ $this->assertConfigEquals([
+ 'default' => [
+ 'client' => [
+ 'prefix' => 'enqueue',
+ 'app_name' => 'app',
+ 'router_processor' => null,
+ 'router_topic' => 'default',
+ 'router_queue' => 'default',
+ 'default_queue' => 'default',
+ 'traceable_producer' => true,
+ 'driver_options' => [
+ 'foo' => 'fooVal',
+ ],
+ ],
+ ],
+ ], $config);
}
- public function testThrowExceptionIfFooTransportConfigInvalid()
+ public function testThrowExceptionIfRouterTopicIsEmpty()
{
- $configuration = new Configuration([new FooTransportFactory()], true);
+ $this->expectException(InvalidConfigurationException::class);
+ $this->expectExceptionMessage('The path "enqueue.default.client.router_topic" cannot contain an empty value, but got "".');
+
+ $configuration = new Configuration(true);
$processor = new Processor();
+ $processor->processConfiguration($configuration, [[
+ 'default' => [
+ 'transport' => ['dsn' => 'null:'],
+ 'client' => [
+ 'router_topic' => '',
+ ],
+ ],
+ ]]);
+ }
+ public function testThrowExceptionIfRouterQueueIsEmpty()
+ {
$this->expectException(InvalidConfigurationException::class);
- $this->expectExceptionMessage('The path "enqueue.transport.foo.foo_param" cannot contain an empty value, but got null.');
+ $this->expectExceptionMessage('The path "enqueue.default.client.router_queue" cannot contain an empty value, but got "".');
+ $configuration = new Configuration(true);
+
+ $processor = new Processor();
$processor->processConfiguration($configuration, [[
- 'transport' => [
- 'foo' => [
- 'foo_param' => null,
+ 'default' => [
+ 'transport' => ['dsn' => 'null:'],
+ 'client' => [
+ 'router_queue' => '',
],
],
]]);
}
- public function testShouldAllowConfigureDefaultTransport()
+ public function testShouldThrowExceptionIfDefaultProcessorQueueIsEmpty()
{
- $configuration = new Configuration([new DefaultTransportFactory()], true);
+ $configuration = new Configuration(true);
$processor = new Processor();
+
+ $this->expectException(InvalidConfigurationException::class);
+ $this->expectExceptionMessage('The path "enqueue.default.client.default_queue" cannot contain an empty value, but got "".');
$processor->processConfiguration($configuration, [[
- 'transport' => [
- 'default' => ['alias' => 'foo'],
+ 'default' => [
+ 'transport' => ['dsn' => 'null:'],
+ 'client' => [
+ 'default_queue' => '',
+ ],
],
]]);
}
- public function testShouldAllowConfigureNullTransport()
+ public function testJobShouldBeDisabledByDefault()
{
- $configuration = new Configuration([new NullTransportFactory()], true);
+ $configuration = new Configuration(true);
$processor = new Processor();
$config = $processor->processConfiguration($configuration, [[
- 'transport' => [
- 'null' => true,
+ 'default' => [
+ 'transport' => [],
],
]]);
- $this->assertArraySubset([
- 'transport' => [
- 'null' => [],
+ Assert::assertArraySubset([
+ 'default' => [
+ 'job' => [
+ 'enabled' => false,
+ ],
],
], $config);
}
- public function testShouldAllowConfigureSeveralTransportsSameTime()
+ public function testCouldEnableJob()
{
- $configuration = new Configuration([
- new NullTransportFactory(),
- new DefaultTransportFactory(),
- new FooTransportFactory(),
- ], true);
+ $configuration = new Configuration(true);
$processor = new Processor();
$config = $processor->processConfiguration($configuration, [[
- 'transport' => [
- 'default' => 'foo',
- 'null' => true,
- 'foo' => ['foo_param' => 'aParam'],
+ 'default' => [
+ 'transport' => [],
+ 'job' => true,
],
]]);
- $this->assertArraySubset([
- 'transport' => [
- 'default' => ['alias' => 'foo'],
- 'null' => [],
- 'foo' => ['foo_param' => 'aParam'],
+ Assert::assertArraySubset([
+ 'default' => [
+ 'job' => true,
],
], $config);
}
- public function testShouldSetDefaultConfigurationForClient()
+ public function testDoctrinePingConnectionExtensionShouldBeDisabledByDefault()
{
- $configuration = new Configuration([new DefaultTransportFactory()], true);
+ $configuration = new Configuration(true);
$processor = new Processor();
$config = $processor->processConfiguration($configuration, [[
- 'transport' => [
- 'default' => ['alias' => 'foo'],
+ 'default' => [
+ 'transport' => null,
],
- 'client' => null,
]]);
- $this->assertArraySubset([
- 'transport' => [
- 'default' => ['alias' => 'foo'],
- ],
- 'client' => [
- 'prefix' => 'enqueue',
- 'app_name' => 'app',
- 'router_processor' => RouterProcessor::class,
- 'router_topic' => 'default',
- 'router_queue' => 'default',
- 'default_processor_queue' => 'default',
- 'traceable_producer' => true,
- 'redelivered_delay_time' => 0,
+ Assert::assertArraySubset([
+ 'default' => [
+ 'extensions' => [
+ 'doctrine_ping_connection_extension' => false,
+ ],
],
], $config);
}
- public function testThrowExceptionIfRouterTopicIsEmpty()
+ public function testDoctrinePingConnectionExtensionCouldBeEnabled()
{
- $this->expectException(InvalidConfigurationException::class);
- $this->expectExceptionMessage('The path "enqueue.client.router_topic" cannot contain an empty value, but got "".');
-
- $configuration = new Configuration([new DefaultTransportFactory()], true);
+ $configuration = new Configuration(true);
$processor = new Processor();
- $processor->processConfiguration($configuration, [[
- 'transport' => [
- 'default' => ['alias' => 'foo'],
- ],
- 'client' => [
- 'router_topic' => '',
+ $config = $processor->processConfiguration($configuration, [[
+ 'default' => [
+ 'transport' => null,
+ 'extensions' => [
+ 'doctrine_ping_connection_extension' => true,
+ ],
],
]]);
+
+ Assert::assertArraySubset([
+ 'default' => [
+ 'extensions' => [
+ 'doctrine_ping_connection_extension' => true,
+ ],
+ ],
+ ], $config);
}
- public function testThrowExceptionIfRouterQueueIsEmpty()
+ public function testDoctrineClearIdentityMapExtensionShouldBeDisabledByDefault()
{
- $this->expectException(InvalidConfigurationException::class);
- $this->expectExceptionMessage('The path "enqueue.client.router_queue" cannot contain an empty value, but got "".');
-
- $configuration = new Configuration([new DefaultTransportFactory()], true);
+ $configuration = new Configuration(true);
$processor = new Processor();
- $processor->processConfiguration($configuration, [[
- 'transport' => [
- 'default' => ['alias' => 'foo'],
- ],
- 'client' => [
- 'router_queue' => '',
+ $config = $processor->processConfiguration($configuration, [[
+ 'default' => [
+ 'transport' => null,
],
]]);
+
+ Assert::assertArraySubset([
+ 'default' => [
+ 'extensions' => [
+ 'doctrine_clear_identity_map_extension' => false,
+ ],
+ ],
+ ], $config);
}
- public function testShouldThrowExceptionIfDefaultProcessorQueueIsEmpty()
+ public function testDoctrineClearIdentityMapExtensionCouldBeEnabled()
{
- $configuration = new Configuration([new DefaultTransportFactory()], true);
+ $configuration = new Configuration(true);
$processor = new Processor();
-
- $this->expectException(InvalidConfigurationException::class);
- $this->expectExceptionMessage('The path "enqueue.client.default_processor_queue" cannot contain an empty value, but got "".');
- $processor->processConfiguration($configuration, [[
- 'transport' => [
- 'default' => ['alias' => 'foo'],
- ],
- 'client' => [
- 'default_processor_queue' => '',
+ $config = $processor->processConfiguration($configuration, [[
+ 'default' => [
+ 'transport' => [],
+ 'extensions' => [
+ 'doctrine_clear_identity_map_extension' => true,
+ ],
],
]]);
+
+ Assert::assertArraySubset([
+ 'default' => [
+ 'extensions' => [
+ 'doctrine_clear_identity_map_extension' => true,
+ ],
+ ],
+ ], $config);
}
- public function testJobShouldBeDisabledByDefault()
+ public function testDoctrineOdmClearIdentityMapExtensionShouldBeDisabledByDefault()
{
- $configuration = new Configuration([], true);
+ $configuration = new Configuration(true);
$processor = new Processor();
$config = $processor->processConfiguration($configuration, [[
- 'transport' => [],
+ 'default' => [
+ 'transport' => null,
+ ],
]]);
- $this->assertArraySubset([
- 'job' => false,
+ Assert::assertArraySubset([
+ 'default' => [
+ 'extensions' => [
+ 'doctrine_odm_clear_identity_map_extension' => false,
+ ],
+ ],
], $config);
}
- public function testCouldEnableJob()
+ public function testDoctrineOdmClearIdentityMapExtensionCouldBeEnabled()
{
- $configuration = new Configuration([], true);
+ $configuration = new Configuration(true);
$processor = new Processor();
$config = $processor->processConfiguration($configuration, [[
- 'transport' => [],
- 'job' => true,
+ 'default' => [
+ 'transport' => [],
+ 'extensions' => [
+ 'doctrine_odm_clear_identity_map_extension' => true,
+ ],
+ ],
]]);
- $this->assertArraySubset([
- 'job' => true,
+ Assert::assertArraySubset([
+ 'default' => [
+ 'extensions' => [
+ 'doctrine_odm_clear_identity_map_extension' => true,
+ ],
+ ],
], $config);
}
- public function testDoctrinePingConnectionExtensionShouldBeDisabledByDefault()
+ public function testDoctrineClosedEntityManagerExtensionShouldBeDisabledByDefault()
{
- $configuration = new Configuration([], true);
+ $configuration = new Configuration(true);
$processor = new Processor();
$config = $processor->processConfiguration($configuration, [[
- 'transport' => [],
+ 'default' => [
+ 'transport' => null,
+ ],
]]);
- $this->assertArraySubset([
- 'extensions' => [
- 'doctrine_ping_connection_extension' => false,
+ Assert::assertArraySubset([
+ 'default' => [
+ 'extensions' => [
+ 'doctrine_closed_entity_manager_extension' => false,
+ ],
],
], $config);
}
- public function testDoctrinePingConnectionExtensionCouldBeEnabled()
+ public function testDoctrineClosedEntityManagerExtensionCouldBeEnabled()
{
- $configuration = new Configuration([], true);
+ $configuration = new Configuration(true);
$processor = new Processor();
$config = $processor->processConfiguration($configuration, [[
- 'transport' => [],
- 'extensions' => [
- 'doctrine_ping_connection_extension' => true,
+ 'default' => [
+ 'transport' => null,
+ 'extensions' => [
+ 'doctrine_closed_entity_manager_extension' => true,
+ ],
],
]]);
- $this->assertArraySubset([
- 'extensions' => [
- 'doctrine_ping_connection_extension' => true,
+ Assert::assertArraySubset([
+ 'default' => [
+ 'extensions' => [
+ 'doctrine_closed_entity_manager_extension' => true,
+ ],
],
], $config);
}
- public function testDoctrineClearIdentityMapExtensionShouldBeDisabledByDefault()
+ public function testResetServicesExtensionShouldBeDisabledByDefault()
{
- $configuration = new Configuration([], true);
+ $configuration = new Configuration(true);
$processor = new Processor();
$config = $processor->processConfiguration($configuration, [[
- 'transport' => [],
+ 'default' => [
+ 'transport' => null,
+ ],
]]);
- $this->assertArraySubset([
- 'extensions' => [
- 'doctrine_clear_identity_map_extension' => false,
+ Assert::assertArraySubset([
+ 'default' => [
+ 'extensions' => [
+ 'reset_services_extension' => false,
+ ],
],
], $config);
}
- public function testDoctrineClearIdentityMapExtensionCouldBeEnabled()
+ public function testResetServicesExtensionCouldBeEnabled()
{
- $configuration = new Configuration([], true);
+ $configuration = new Configuration(true);
$processor = new Processor();
$config = $processor->processConfiguration($configuration, [[
- 'transport' => [],
- 'extensions' => [
- 'doctrine_clear_identity_map_extension' => true,
+ 'default' => [
+ 'transport' => [],
+ 'extensions' => [
+ 'reset_services_extension' => true,
+ ],
],
]]);
- $this->assertArraySubset([
- 'extensions' => [
- 'doctrine_clear_identity_map_extension' => true,
+ Assert::assertArraySubset([
+ 'default' => [
+ 'extensions' => [
+ 'reset_services_extension' => true,
+ ],
],
], $config);
}
- public function testSignalExtensionShouldBeEnabledByDefault()
+ public function testSignalExtensionShouldBeEnabledIfPcntlExtensionIsLoaded()
{
- $configuration = new Configuration([], true);
+ $isLoaded = function_exists('pcntl_signal_dispatch');
+
+ $configuration = new Configuration(true);
$processor = new Processor();
$config = $processor->processConfiguration($configuration, [[
- 'transport' => [],
+ 'default' => [
+ 'transport' => [],
+ ],
]]);
- $this->assertArraySubset([
- 'extensions' => [
- 'signal_extension' => true,
+ Assert::assertArraySubset([
+ 'default' => [
+ 'extensions' => [
+ 'signal_extension' => $isLoaded,
+ ],
],
], $config);
}
public function testSignalExtensionCouldBeDisabled()
{
- $configuration = new Configuration([], true);
+ $configuration = new Configuration(true);
$processor = new Processor();
$config = $processor->processConfiguration($configuration, [[
- 'transport' => [],
- 'extensions' => [
- 'signal_extension' => false,
+ 'default' => [
+ 'transport' => [],
+ 'extensions' => [
+ 'signal_extension' => false,
+ ],
],
]]);
- $this->assertArraySubset([
- 'extensions' => [
- 'signal_extension' => false,
+ Assert::assertArraySubset([
+ 'default' => [
+ 'extensions' => [
+ 'signal_extension' => false,
+ ],
],
], $config);
}
public function testReplyExtensionShouldBeEnabledByDefault()
{
- $configuration = new Configuration([], true);
+ $configuration = new Configuration(true);
$processor = new Processor();
$config = $processor->processConfiguration($configuration, [[
- 'transport' => [],
+ 'default' => [
+ 'transport' => [],
+ ],
]]);
- $this->assertArraySubset([
- 'extensions' => [
- 'reply_extension' => true,
+ Assert::assertArraySubset([
+ 'default' => [
+ 'extensions' => [
+ 'reply_extension' => true,
+ ],
],
], $config);
}
public function testReplyExtensionCouldBeDisabled()
{
- $configuration = new Configuration([], true);
+ $configuration = new Configuration(true);
$processor = new Processor();
$config = $processor->processConfiguration($configuration, [[
- 'transport' => [],
- 'extensions' => [
- 'reply_extension' => false,
+ 'default' => [
+ 'transport' => [],
+ 'extensions' => [
+ 'reply_extension' => false,
+ ],
],
]]);
- $this->assertArraySubset([
- 'extensions' => [
- 'reply_extension' => false,
+ Assert::assertArraySubset([
+ 'default' => [
+ 'extensions' => [
+ 'reply_extension' => false,
+ ],
],
], $config);
}
public function testShouldDisableAsyncEventsByDefault()
{
- $configuration = new Configuration([], true);
+ $configuration = new Configuration(true);
$processor = new Processor();
$config = $processor->processConfiguration($configuration, [[
- 'transport' => [],
+ 'default' => [
+ 'transport' => [],
+ ],
]]);
- $this->assertArraySubset([
- 'async_events' => [
- 'enabled' => false,
+ Assert::assertArraySubset([
+ 'default' => [
+ 'async_events' => [
+ 'enabled' => false,
+ ],
],
], $config);
}
public function testShouldAllowEnableAsyncEvents()
{
- $configuration = new Configuration([], true);
+ $configuration = new Configuration(true);
$processor = new Processor();
$config = $processor->processConfiguration($configuration, [[
- 'transport' => [],
- 'async_events' => true,
+ 'default' => [
+ 'transport' => [],
+ 'async_events' => true,
+ ],
]]);
- $this->assertArraySubset([
- 'async_events' => [
- 'enabled' => true,
+ Assert::assertArraySubset([
+ 'default' => [
+ 'async_events' => [
+ 'enabled' => true,
+ ],
],
], $config);
$config = $processor->processConfiguration($configuration, [[
- 'transport' => [],
- 'async_events' => [
- 'enabled' => true,
+ 'default' => [
+ 'transport' => [],
+ 'async_events' => [
+ 'enabled' => true,
+ ],
],
]]);
- $this->assertArraySubset([
- 'async_events' => [
- 'enabled' => true,
+ Assert::assertArraySubset([
+ 'default' => [
+ 'async_events' => [
+ 'enabled' => true,
+ ],
],
], $config);
}
public function testShouldSetDefaultConfigurationForConsumption()
{
- $configuration = new Configuration([], true);
+ $configuration = new Configuration(true);
$processor = new Processor();
$config = $processor->processConfiguration($configuration, [[
- 'transport' => [],
+ 'default' => [
+ 'transport' => [],
+ ],
]]);
- $this->assertArraySubset([
- 'consumption' => [
- 'idle_timeout' => 0,
- 'receive_timeout' => 100,
+ Assert::assertArraySubset([
+ 'default' => [
+ 'consumption' => [
+ 'receive_timeout' => 10000,
+ ],
],
], $config);
}
public function testShouldAllowConfigureConsumption()
{
- $configuration = new Configuration([], true);
+ $configuration = new Configuration(true);
$processor = new Processor();
$config = $processor->processConfiguration($configuration, [[
- 'transport' => [],
- 'consumption' => [
- 'idle_timeout' => 123,
- 'receive_timeout' => 456,
+ 'default' => [
+ 'transport' => [],
+ 'consumption' => [
+ 'receive_timeout' => 456,
+ ],
],
]]);
- $this->assertArraySubset([
- 'consumption' => [
- 'idle_timeout' => 123,
- 'receive_timeout' => 456,
+ Assert::assertArraySubset([
+ 'default' => [
+ 'consumption' => [
+ 'receive_timeout' => 456,
+ ],
],
], $config);
}
+
+ private function assertConfigEquals(array $expected, array $actual): void
+ {
+ Assert::assertArraySubset($expected, $actual, false, var_export($actual, true));
+ }
}
diff --git a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/EnqueueExtensionTest.php b/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/EnqueueExtensionTest.php
index 4a59dc35b..6358bd24d 100644
--- a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/EnqueueExtensionTest.php
+++ b/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/EnqueueExtensionTest.php
@@ -4,27 +4,17 @@
use Enqueue\Bundle\DependencyInjection\Configuration;
use Enqueue\Bundle\DependencyInjection\EnqueueExtension;
-use Enqueue\Bundle\Tests\Unit\Mocks\FooTransportFactory;
-use Enqueue\Bundle\Tests\Unit\Mocks\TransportFactoryWithoutDriverFactory;
use Enqueue\Client\CommandSubscriberInterface;
use Enqueue\Client\Producer;
use Enqueue\Client\ProducerInterface;
use Enqueue\Client\TopicSubscriberInterface;
use Enqueue\Client\TraceableProducer;
-use Enqueue\Consumption\QueueConsumer;
use Enqueue\JobQueue\JobRunner;
-use Enqueue\Null\NullContext;
-use Enqueue\Null\Symfony\NullTransportFactory;
-use Enqueue\Symfony\DefaultTransportFactory;
-use Enqueue\Symfony\MissingTransportFactory;
-use Enqueue\Symfony\TransportFactoryInterface;
use Enqueue\Test\ClassExtensionTrait;
use PHPUnit\Framework\TestCase;
-use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Reference;
-use Symfony\Component\HttpKernel\DependencyInjection\Extension;
-use Symfony\Component\HttpKernel\Kernel;
class EnqueueExtensionTest extends TestCase
{
@@ -32,144 +22,61 @@ class EnqueueExtensionTest extends TestCase
public function testShouldImplementConfigurationInterface()
{
- self::assertClassExtends(Extension::class, EnqueueExtension::class);
+ $this->assertClassExtends(Extension::class, EnqueueExtension::class);
}
- public function testCouldBeConstructedWithoutAnyArguments()
+ public function testShouldBeFinal()
{
- new EnqueueExtension();
+ $this->assertClassFinal(EnqueueExtension::class);
}
- public function testShouldRegisterDefaultAndNullTransportFactoriesInConstructor()
- {
- $extension = new EnqueueExtension();
-
- /** @var TransportFactoryInterface[] $factories */
- $factories = $this->readAttribute($extension, 'factories');
-
- $this->assertInternalType('array', $factories);
- $this->assertCount(2, $factories);
-
- $this->assertArrayHasKey('default', $factories);
- $this->assertInstanceOf(DefaultTransportFactory::class, $factories['default']);
- $this->assertEquals('default', $factories['default']->getName());
-
- $this->assertArrayHasKey('null', $factories);
- $this->assertInstanceOf(NullTransportFactory::class, $factories['null']);
- $this->assertEquals('null', $factories['null']->getName());
- }
-
- public function testThrowIfTransportFactoryNameEmpty()
- {
- $extension = new EnqueueExtension();
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('Transport factory name cannot be empty');
-
- $extension->addTransportFactory(new FooTransportFactory(null));
- }
-
- public function testThrowIfTransportFactoryWithSameNameAlreadyAdded()
- {
- $extension = new EnqueueExtension();
-
- $extension->addTransportFactory(new FooTransportFactory('foo'));
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('Transport factory with such name already added. Name foo');
-
- $extension->addTransportFactory(new FooTransportFactory('foo'));
- }
-
- public function testShouldEnabledNullTransportAndSetItAsDefault()
+ public function testShouldRegisterConnectionFactory()
{
$container = $this->getContainerBuilder(true);
$extension = new EnqueueExtension();
$extension->load([[
- 'transport' => [
- 'default' => 'null',
- 'null' => true,
+ 'default' => [
+ 'transport' => null,
],
]], $container);
- self::assertTrue($container->hasAlias('enqueue.transport.default.context'));
- self::assertEquals('enqueue.transport.null.context', (string) $container->getAlias('enqueue.transport.default.context'));
-
- self::assertTrue($container->hasDefinition('enqueue.transport.null.context'));
- $context = $container->getDefinition('enqueue.transport.null.context');
- self::assertEquals(NullContext::class, $context->getClass());
- }
-
- public function testShouldUseNullTransportAsDefaultWhenExplicitlyConfigured()
- {
- $container = $this->getContainerBuilder(true);
-
- $extension = new EnqueueExtension();
-
- $extension->load([[
- 'transport' => [
- 'default' => 'null',
- 'null' => true,
- ],
- ]], $container);
-
- self::assertEquals(
- 'enqueue.transport.default.context',
- (string) $container->getAlias('enqueue.transport.context')
- );
- self::assertEquals(
- 'enqueue.transport.null.context',
- (string) $container->getAlias('enqueue.transport.default.context')
- );
+ self::assertTrue($container->hasDefinition('enqueue.transport.default.connection_factory'));
+ self::assertNotEmpty($container->getDefinition('enqueue.transport.default.connection_factory')->getFactory());
}
- public function testShouldConfigureFooTransport()
+ public function testShouldRegisterContext()
{
$container = $this->getContainerBuilder(true);
$extension = new EnqueueExtension();
- $extension->addTransportFactory(new FooTransportFactory());
$extension->load([[
- 'transport' => [
- 'default' => 'foo',
- 'foo' => ['foo_param' => 'aParam'],
+ 'default' => [
+ 'transport' => null,
],
]], $container);
- self::assertTrue($container->hasDefinition('foo.connection_factory'));
- self::assertTrue($container->hasDefinition('foo.context'));
- self::assertFalse($container->hasDefinition('foo.driver'));
-
- $context = $container->getDefinition('foo.context');
- self::assertEquals(\stdClass::class, $context->getClass());
- self::assertEquals([['foo_param' => 'aParam']], $context->getArguments());
+ self::assertTrue($container->hasDefinition('enqueue.transport.default.context'));
+ self::assertNotEmpty($container->getDefinition('enqueue.transport.default.context')->getFactory());
}
- public function testShouldUseFooTransportAsDefault()
+ public function testShouldRegisterClientDriver()
{
$container = $this->getContainerBuilder(true);
$extension = new EnqueueExtension();
- $extension->addTransportFactory(new FooTransportFactory());
$extension->load([[
- 'transport' => [
- 'default' => 'foo',
- 'foo' => ['foo_param' => 'aParam'],
+ 'default' => [
+ 'transport' => null,
+ 'client' => true,
],
]], $container);
- self::assertEquals(
- 'enqueue.transport.default.context',
- (string) $container->getAlias('enqueue.transport.context')
- );
- self::assertEquals(
- 'enqueue.transport.foo.context',
- (string) $container->getAlias('enqueue.transport.default.context')
- );
+ self::assertTrue($container->hasDefinition('enqueue.client.default.driver'));
+ self::assertNotEmpty($container->getDefinition('enqueue.client.default.driver')->getFactory());
}
public function testShouldLoadClientServicesWhenEnabled()
@@ -177,62 +84,33 @@ public function testShouldLoadClientServicesWhenEnabled()
$container = $this->getContainerBuilder(true);
$extension = new EnqueueExtension();
- $extension->addTransportFactory(new FooTransportFactory());
$extension->load([[
- 'client' => null,
- 'transport' => [
- 'default' => 'foo',
- 'foo' => [
- 'foo_param' => true,
- ],
+ 'default' => [
+ 'client' => null,
+ 'transport' => 'null:',
],
]], $container);
- self::assertTrue($container->hasDefinition('foo.driver'));
- self::assertTrue($container->hasDefinition('enqueue.client.config'));
- self::assertTrue($container->hasDefinition(Producer::class));
+ self::assertTrue($container->hasDefinition('enqueue.client.default.driver'));
+ self::assertTrue($container->hasDefinition('enqueue.client.default.config'));
self::assertTrue($container->hasAlias(ProducerInterface::class));
}
- public function testShouldNotCreateDriverIfFactoryDoesNotImplementDriverFactoryInterface()
- {
- $container = $this->getContainerBuilder(true);
-
- $extension = new EnqueueExtension();
- $extension->addTransportFactory(new TransportFactoryWithoutDriverFactory());
-
- $extension->load([[
- 'client' => null,
- 'transport' => [
- 'default' => 'without_driver',
- 'without_driver' => [],
- ],
- ]], $container);
-
- self::assertTrue($container->hasDefinition('without_driver.context'));
- self::assertTrue($container->hasDefinition('without_driver.connection_factory'));
- self::assertFalse($container->hasDefinition('without_driver.driver'));
- }
-
public function testShouldUseProducerByDefault()
{
$container = $this->getContainerBuilder(false);
$extension = new EnqueueExtension();
- $extension->addTransportFactory(new FooTransportFactory());
$extension->load([[
- 'client' => null,
- 'transport' => [
- 'default' => 'foo',
- 'foo' => [
- 'foo_param' => true,
- ],
+ 'default' => [
+ 'client' => null,
+ 'transport' => 'null',
],
]], $container);
- $producer = $container->getDefinition(Producer::class);
+ $producer = $container->getDefinition('enqueue.client.default.producer');
self::assertEquals(Producer::class, $producer->getClass());
}
@@ -241,21 +119,17 @@ public function testShouldUseMessageProducerIfTraceableProducerOptionSetToFalseE
$container = $this->getContainerBuilder(false);
$extension = new EnqueueExtension();
- $extension->addTransportFactory(new FooTransportFactory());
$extension->load([[
- 'client' => [
- 'traceable_producer' => false,
- ],
- 'transport' => [
- 'default' => 'foo',
- 'foo' => [
- 'foo_param' => true,
+ 'default' => [
+ 'client' => [
+ 'traceable_producer' => false,
],
+ 'transport' => 'null:',
],
]], $container);
- $producer = $container->getDefinition(Producer::class);
+ $producer = $container->getDefinition('enqueue.client.default.producer');
self::assertEquals(Producer::class, $producer->getClass());
}
@@ -264,32 +138,24 @@ public function testShouldUseTraceableMessageProducerIfDebugEnabled()
$container = $this->getContainerBuilder(true);
$extension = new EnqueueExtension();
- $extension->addTransportFactory(new FooTransportFactory());
$extension->load([[
- 'transport' => [
- 'default' => 'foo',
- 'foo' => [
- 'foo_param' => true,
- ],
+ 'default' => [
+ 'transport' => 'null:',
+ 'client' => null,
],
- 'client' => null,
]], $container);
- $producer = $container->getDefinition(TraceableProducer::class);
+ $producer = $container->getDefinition('enqueue.client.default.traceable_producer');
self::assertEquals(TraceableProducer::class, $producer->getClass());
self::assertEquals(
- [Producer::class, null, 0],
+ ['enqueue.client.default.producer', null, 0],
$producer->getDecoratedService()
);
self::assertInstanceOf(Reference::class, $producer->getArgument(0));
- $innerServiceName = sprintf('%s.inner', TraceableProducer::class);
- if (30300 > Kernel::VERSION_ID) {
- // Symfony 3.2 and below make service identifiers lowercase, so we do the same.
- $innerServiceName = strtolower($innerServiceName);
- }
+ $innerServiceName = 'enqueue.client.default.traceable_producer.inner';
self::assertEquals(
$innerServiceName,
@@ -302,18 +168,14 @@ public function testShouldNotUseTraceableMessageProducerIfDebugDisabledAndNotSet
$container = $this->getContainerBuilder(false);
$extension = new EnqueueExtension();
- $extension->addTransportFactory(new FooTransportFactory());
$extension->load([[
- 'transport' => [
- 'default' => 'foo',
- 'foo' => [
- 'foo_param' => true,
- ],
+ 'default' => [
+ 'transport' => 'null:',
],
]], $container);
- $this->assertFalse($container->hasDefinition(TraceableProducer::class));
+ $this->assertFalse($container->hasDefinition('enqueue.client.default.traceable_producer'));
}
public function testShouldUseTraceableMessageProducerIfDebugDisabledButTraceableProducerOptionSetToTrueExplicitly()
@@ -321,34 +183,26 @@ public function testShouldUseTraceableMessageProducerIfDebugDisabledButTraceable
$container = $this->getContainerBuilder(false);
$extension = new EnqueueExtension();
- $extension->addTransportFactory(new FooTransportFactory());
$extension->load([[
- 'client' => [
- 'traceable_producer' => true,
- ],
- 'transport' => [
- 'default' => 'foo',
- 'foo' => [
- 'foo_param' => true,
+ 'default' => [
+ 'client' => [
+ 'traceable_producer' => true,
],
+ 'transport' => 'null:',
],
]], $container);
- $producer = $container->getDefinition(TraceableProducer::class);
+ $producer = $container->getDefinition('enqueue.client.default.traceable_producer');
self::assertEquals(TraceableProducer::class, $producer->getClass());
self::assertEquals(
- [Producer::class, null, 0],
+ ['enqueue.client.default.producer', null, 0],
$producer->getDecoratedService()
);
self::assertInstanceOf(Reference::class, $producer->getArgument(0));
- $innerServiceName = sprintf('%s.inner', TraceableProducer::class);
- if (30300 > Kernel::VERSION_ID) {
- // Symfony 3.2 and below make service identifiers lowercase, so we do the same.
- $innerServiceName = strtolower($innerServiceName);
- }
+ $innerServiceName = 'enqueue.client.default.traceable_producer.inner';
self::assertEquals(
$innerServiceName,
@@ -361,21 +215,17 @@ public function testShouldLoadDelayRedeliveredMessageExtensionIfRedeliveredDelay
$container = $this->getContainerBuilder(true);
$extension = new EnqueueExtension();
- $extension->addTransportFactory(new FooTransportFactory());
$extension->load([[
- 'transport' => [
- 'default' => 'foo',
- 'foo' => [
- 'foo_param' => true,
+ 'default' => [
+ 'transport' => 'null:',
+ 'client' => [
+ 'redelivered_delay_time' => 12345,
],
],
- 'client' => [
- 'redelivered_delay_time' => 12345,
- ],
]], $container);
- $extension = $container->getDefinition('enqueue.client.delay_redelivered_message_extension');
+ $extension = $container->getDefinition('enqueue.client.default.delay_redelivered_message_extension');
self::assertEquals(12345, $extension->getArgument(1));
}
@@ -385,21 +235,17 @@ public function testShouldNotLoadDelayRedeliveredMessageExtensionIfRedeliveredDe
$container = $this->getContainerBuilder(true);
$extension = new EnqueueExtension();
- $extension->addTransportFactory(new FooTransportFactory());
$extension->load([[
- 'transport' => [
- 'default' => 'foo',
- 'foo' => [
- 'foo_param' => true,
+ 'default' => [
+ 'transport' => 'null:',
+ 'client' => [
+ 'redelivered_delay_time' => 0,
],
],
- 'client' => [
- 'redelivered_delay_time' => 0,
- ],
]], $container);
- $this->assertFalse($container->hasDefinition('enqueue.client.delay_redelivered_message_extension'));
+ $this->assertFalse($container->hasDefinition('enqueue.client.default.delay_redelivered_message_extension'));
}
public function testShouldLoadJobServicesIfEnabled()
@@ -409,13 +255,33 @@ public function testShouldLoadJobServicesIfEnabled()
$extension = new EnqueueExtension();
$extension->load([[
- 'transport' => [],
- 'job' => true,
+ 'default' => [
+ 'transport' => [],
+ 'client' => null,
+ 'job' => true,
+ ],
]], $container);
self::assertTrue($container->hasDefinition(JobRunner::class));
}
+ public function testShouldThrowExceptionIfClientIsNotEnabledOnJobLoad()
+ {
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Client is required for job-queue.');
+
+ $container = $this->getContainerBuilder(true);
+
+ $extension = new EnqueueExtension();
+
+ $extension->load([[
+ 'default' => [
+ 'transport' => [],
+ 'job' => true,
+ ],
+ ]], $container);
+ }
+
public function testShouldNotLoadJobServicesIfDisabled()
{
$container = $this->getContainerBuilder(true);
@@ -423,8 +289,10 @@ public function testShouldNotLoadJobServicesIfDisabled()
$extension = new EnqueueExtension();
$extension->load([[
- 'transport' => [],
- 'job' => false,
+ 'default' => [
+ 'transport' => [],
+ 'job' => false,
+ ],
]], $container);
self::assertFalse($container->hasDefinition(JobRunner::class));
@@ -446,9 +314,11 @@ public function testShouldLoadDoctrinePingConnectionExtensionServiceIfEnabled()
$extension = new EnqueueExtension();
$extension->load([[
- 'transport' => [],
- 'extensions' => [
- 'doctrine_ping_connection_extension' => true,
+ 'default' => [
+ 'transport' => [],
+ 'extensions' => [
+ 'doctrine_ping_connection_extension' => true,
+ ],
],
]], $container);
@@ -462,9 +332,11 @@ public function testShouldNotLoadDoctrinePingConnectionExtensionServiceIfDisable
$extension = new EnqueueExtension();
$extension->load([[
- 'transport' => [],
- 'extensions' => [
- 'doctrine_ping_connection_extension' => false,
+ 'default' => [
+ 'transport' => [],
+ 'extensions' => [
+ 'doctrine_ping_connection_extension' => false,
+ ],
],
]], $container);
@@ -478,9 +350,11 @@ public function testShouldLoadDoctrineClearIdentityMapExtensionServiceIfEnabled(
$extension = new EnqueueExtension();
$extension->load([[
- 'transport' => [],
- 'extensions' => [
- 'doctrine_clear_identity_map_extension' => true,
+ 'default' => [
+ 'transport' => [],
+ 'extensions' => [
+ 'doctrine_clear_identity_map_extension' => true,
+ ],
],
]], $container);
@@ -494,15 +368,125 @@ public function testShouldNotLoadDoctrineClearIdentityMapExtensionServiceIfDisab
$extension = new EnqueueExtension();
$extension->load([[
- 'transport' => [],
- 'extensions' => [
- 'doctrine_clear_identity_map_extension' => false,
+ 'default' => [
+ 'transport' => [],
+ 'extensions' => [
+ 'doctrine_clear_identity_map_extension' => false,
+ ],
],
]], $container);
self::assertFalse($container->hasDefinition('enqueue.consumption.doctrine_clear_identity_map_extension'));
}
+ public function testShouldLoadDoctrineOdmClearIdentityMapExtensionServiceIfEnabled()
+ {
+ $container = $this->getContainerBuilder(true);
+
+ $extension = new EnqueueExtension();
+
+ $extension->load([[
+ 'default' => [
+ 'transport' => [],
+ 'extensions' => [
+ 'doctrine_odm_clear_identity_map_extension' => true,
+ ],
+ ],
+ ]], $container);
+
+ self::assertTrue($container->hasDefinition('enqueue.consumption.doctrine_odm_clear_identity_map_extension'));
+ }
+
+ public function testShouldNotLoadDoctrineOdmClearIdentityMapExtensionServiceIfDisabled()
+ {
+ $container = $this->getContainerBuilder(true);
+
+ $extension = new EnqueueExtension();
+
+ $extension->load([[
+ 'default' => [
+ 'transport' => [],
+ 'extensions' => [
+ 'doctrine_odm_clear_identity_map_extension' => false,
+ ],
+ ],
+ ]], $container);
+
+ self::assertFalse($container->hasDefinition('enqueue.consumption.doctrine_odm_clear_identity_map_extension'));
+ }
+
+ public function testShouldLoadDoctrineClosedEntityManagerExtensionServiceIfEnabled()
+ {
+ $container = $this->getContainerBuilder(true);
+
+ $extension = new EnqueueExtension();
+
+ $extension->load([[
+ 'default' => [
+ 'transport' => [],
+ 'extensions' => [
+ 'doctrine_closed_entity_manager_extension' => true,
+ ],
+ ],
+ ]], $container);
+
+ self::assertTrue($container->hasDefinition('enqueue.consumption.doctrine_closed_entity_manager_extension'));
+ }
+
+ public function testShouldNotLoadDoctrineClosedEntityManagerExtensionServiceIfDisabled()
+ {
+ $container = $this->getContainerBuilder(true);
+
+ $extension = new EnqueueExtension();
+
+ $extension->load([[
+ 'default' => [
+ 'transport' => [],
+ 'extensions' => [
+ 'doctrine_closed_entity_manager_extension' => false,
+ ],
+ ],
+ ]], $container);
+
+ self::assertFalse($container->hasDefinition('enqueue.consumption.doctrine_closed_entity_manager_extension'));
+ }
+
+ public function testShouldLoadResetServicesExtensionServiceIfEnabled()
+ {
+ $container = $this->getContainerBuilder(true);
+
+ $extension = new EnqueueExtension();
+
+ $extension->load([[
+ 'default' => [
+ 'transport' => [],
+ 'extensions' => [
+ 'reset_services_extension' => true,
+ ],
+ ],
+ ]], $container);
+
+ self::assertTrue($container->hasDefinition('enqueue.consumption.reset_services_extension'));
+ }
+
+ public function testShouldNotLoadResetServicesExtensionServiceIfDisabled()
+ {
+ $container = $this->getContainerBuilder(true);
+
+ $extension = new EnqueueExtension();
+
+ $extension->load([[
+ 'default' => [
+ 'transport' => [],
+ 'extensions' => [
+ 'reset_services_extension' => false,
+ ],
+ ],
+ ]], $container);
+
+ self::assertFalse($container->hasDefinition('enqueue.consumption.reset_services_extension'));
+ }
+
public function testShouldLoadSignalExtensionServiceIfEnabled()
{
$container = $this->getContainerBuilder(true);
@@ -510,9 +494,11 @@ public function testShouldLoadSignalExtensionServiceIfEnabled()
$extension = new EnqueueExtension();
$extension->load([[
- 'transport' => [],
- 'extensions' => [
- 'signal_extension' => true,
+ 'default' => [
+ 'transport' => [],
+ 'extensions' => [
+ 'signal_extension' => true,
+ ],
],
]], $container);
@@ -526,9 +512,11 @@ public function testShouldNotLoadSignalExtensionServiceIfDisabled()
$extension = new EnqueueExtension();
$extension->load([[
- 'transport' => [],
- 'extensions' => [
- 'signal_extension' => false,
+ 'default' => [
+ 'transport' => [],
+ 'extensions' => [
+ 'signal_extension' => false,
+ ],
],
]], $container);
@@ -542,9 +530,11 @@ public function testShouldLoadReplyExtensionServiceIfEnabled()
$extension = new EnqueueExtension();
$extension->load([[
- 'transport' => [],
- 'extensions' => [
- 'reply_extension' => true,
+ 'default' => [
+ 'transport' => [],
+ 'extensions' => [
+ 'reply_extension' => true,
+ ],
],
]], $container);
@@ -558,9 +548,11 @@ public function testShouldNotLoadReplyExtensionServiceIfDisabled()
$extension = new EnqueueExtension();
$extension->load([[
- 'transport' => [],
- 'extensions' => [
- 'reply_extension' => false,
+ 'default' => [
+ 'transport' => [],
+ 'extensions' => [
+ 'reply_extension' => false,
+ ],
],
]], $container);
@@ -601,62 +593,92 @@ public function testShouldConfigureQueueConsumer()
$extension = new EnqueueExtension();
$extension->load([[
- 'client' => [],
- 'transport' => [
- ],
- 'consumption' => [
- 'idle_timeout' => 123,
- 'receive_timeout' => 456,
+ 'default' => [
+ 'client' => [],
+ 'transport' => [
+ ],
+ 'consumption' => [
+ 'receive_timeout' => 456,
+ ],
],
]], $container);
- $def = $container->getDefinition(QueueConsumer::class);
- $this->assertSame(123, $def->getArgument(2));
- $this->assertSame(456, $def->getArgument(3));
+ $def = $container->getDefinition('enqueue.transport.default.queue_consumer');
+ $this->assertSame('%enqueue.transport.default.receive_timeout%', $def->getArgument(4));
+
+ $this->assertSame(456, $container->getParameter('enqueue.transport.default.receive_timeout'));
- $def = $container->getDefinition('enqueue.client.queue_consumer');
- $this->assertSame(123, $def->getArgument(2));
- $this->assertSame(456, $def->getArgument(3));
+ $def = $container->getDefinition('enqueue.client.default.queue_consumer');
+ $this->assertSame(456, $def->getArgument(4));
}
- public function testShouldThrowIfPackageShouldBeInstalledToUseTransport()
+ public function testShouldSetPropertyWithAllConfiguredTransports()
{
$container = $this->getContainerBuilder(true);
$extension = new EnqueueExtension();
- $extension->addTransportFactory(new MissingTransportFactory('need_package', ['a_package', 'another_package']));
+ $extension->load([[
+ 'default' => [
+ 'transport' => 'default:',
+ 'client' => [],
+ ],
+ 'foo' => [
+ 'transport' => 'foo:',
+ 'client' => [],
+ ],
+ 'bar' => [
+ 'transport' => 'bar:',
+ 'client' => [],
+ ],
+ ]], $container);
- $this->expectException(InvalidConfigurationException::class);
- $this->expectExceptionMessage('In order to use the transport "need_package" install');
+ $this->assertTrue($container->hasParameter('enqueue.transports'));
+ $this->assertEquals(['default', 'foo', 'bar'], $container->getParameter('enqueue.transports'));
+ }
+
+ public function testShouldSetPropertyWithAllConfiguredClients()
+ {
+ $container = $this->getContainerBuilder(true);
+
+ $extension = new EnqueueExtension();
$extension->load([[
- 'transport' => [
- 'need_package' => true,
+ 'default' => [
+ 'transport' => 'default:',
+ 'client' => [],
+ ],
+ 'foo' => [
+ 'transport' => 'foo:',
+ ],
+ 'bar' => [
+ 'transport' => 'bar:',
+ 'client' => [],
],
]], $container);
+
+ $this->assertTrue($container->hasParameter('enqueue.clients'));
+ $this->assertEquals(['default', 'bar'], $container->getParameter('enqueue.clients'));
}
public function testShouldLoadProcessAutoconfigureChildDefinition()
{
- if (30300 >= Kernel::VERSION_ID) {
- $this->markTestSkipped('The autoconfigure feature is available since Symfony 3.3 version');
- }
-
$container = $this->getContainerBuilder(true);
$extension = new EnqueueExtension();
$extension->load([[
- 'client' => [],
- 'transport' => [],
+ 'default' => [
+ 'client' => [],
+ 'transport' => [],
+ ],
]], $container);
$autoconfigured = $container->getAutoconfiguredInstanceof();
self::assertArrayHasKey(CommandSubscriberInterface::class, $autoconfigured);
- self::assertTrue($autoconfigured[CommandSubscriberInterface::class]->hasTag('enqueue.client.processor'));
+ self::assertTrue($autoconfigured[CommandSubscriberInterface::class]->hasTag('enqueue.command_subscriber'));
self::assertTrue($autoconfigured[CommandSubscriberInterface::class]->isPublic());
self::assertArrayHasKey(TopicSubscriberInterface::class, $autoconfigured);
- self::assertTrue($autoconfigured[TopicSubscriberInterface::class]->hasTag('enqueue.client.processor'));
+ self::assertTrue($autoconfigured[TopicSubscriberInterface::class]->hasTag('enqueue.topic_subscriber'));
self::assertTrue($autoconfigured[TopicSubscriberInterface::class]->isPublic());
}
diff --git a/pkg/enqueue-bundle/Tests/Unit/EnqueueBundleTest.php b/pkg/enqueue-bundle/Tests/Unit/EnqueueBundleTest.php
index 270c4d315..7d5b0232b 100644
--- a/pkg/enqueue-bundle/Tests/Unit/EnqueueBundleTest.php
+++ b/pkg/enqueue-bundle/Tests/Unit/EnqueueBundleTest.php
@@ -2,27 +2,9 @@
namespace Enqueue\Bundle\Tests\Unit;
-use Enqueue\Bundle\DependencyInjection\Compiler\BuildClientExtensionsPass;
-use Enqueue\Bundle\DependencyInjection\Compiler\BuildClientRoutingPass;
-use Enqueue\Bundle\DependencyInjection\Compiler\BuildConsumptionExtensionsPass;
-use Enqueue\Bundle\DependencyInjection\Compiler\BuildExclusiveCommandsExtensionPass;
-use Enqueue\Bundle\DependencyInjection\Compiler\BuildProcessorRegistryPass;
-use Enqueue\Bundle\DependencyInjection\Compiler\BuildQueueMetaRegistryPass;
-use Enqueue\Bundle\DependencyInjection\Compiler\BuildTopicMetaSubscribersPass;
-use Enqueue\Bundle\DependencyInjection\EnqueueExtension;
use Enqueue\Bundle\EnqueueBundle;
-use Enqueue\Dbal\Symfony\DbalTransportFactory;
-use Enqueue\Fs\Symfony\FsTransportFactory;
-use Enqueue\Gps\Symfony\GpsTransportFactory;
-use Enqueue\Redis\Symfony\RedisTransportFactory;
-use Enqueue\Sqs\Symfony\SqsTransportFactory;
-use Enqueue\Stomp\Symfony\RabbitMqStompTransportFactory;
-use Enqueue\Stomp\Symfony\StompTransportFactory;
-use Enqueue\Symfony\AmqpTransportFactory;
-use Enqueue\Symfony\RabbitMqAmqpTransportFactory;
use Enqueue\Test\ClassExtensionTrait;
use PHPUnit\Framework\TestCase;
-use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class EnqueueBundleTest extends TestCase
@@ -33,214 +15,4 @@ public function testShouldExtendBundleClass()
{
$this->assertClassExtends(Bundle::class, EnqueueBundle::class);
}
-
- public function testCouldBeConstructedWithoutAnyArguments()
- {
- new EnqueueBundle();
- }
-
- public function testShouldRegisterExpectedCompilerPasses()
- {
- $extensionMock = $this->createMock(EnqueueExtension::class);
-
- $container = $this->createMock(ContainerBuilder::class);
- $container
- ->expects($this->at(0))
- ->method('addCompilerPass')
- ->with($this->isInstanceOf(BuildConsumptionExtensionsPass::class))
- ;
- $container
- ->expects($this->at(1))
- ->method('addCompilerPass')
- ->with($this->isInstanceOf(BuildClientRoutingPass::class))
- ;
- $container
- ->expects($this->at(2))
- ->method('addCompilerPass')
- ->with($this->isInstanceOf(BuildProcessorRegistryPass::class))
- ;
- $container
- ->expects($this->at(3))
- ->method('addCompilerPass')
- ->with($this->isInstanceOf(BuildTopicMetaSubscribersPass::class))
- ;
- $container
- ->expects($this->at(4))
- ->method('addCompilerPass')
- ->with($this->isInstanceOf(BuildQueueMetaRegistryPass::class))
- ;
- $container
- ->expects($this->at(5))
- ->method('addCompilerPass')
- ->with($this->isInstanceOf(BuildClientExtensionsPass::class))
- ;
- $container
- ->expects($this->at(6))
- ->method('addCompilerPass')
- ->with($this->isInstanceOf(BuildExclusiveCommandsExtensionPass::class))
- ;
- $container
- ->expects($this->at(7))
- ->method('getExtension')
- ->willReturn($extensionMock)
- ;
-
- $bundle = new EnqueueBundle();
- $bundle->build($container);
- }
-
- public function testShouldRegisterStompAndRabbitMqStompTransportFactories()
- {
- $extensionMock = $this->createEnqueueExtensionMock();
-
- $container = new ContainerBuilder();
- $container->registerExtension($extensionMock);
-
- $extensionMock
- ->expects($this->at(0))
- ->method('setTransportFactory')
- ->with($this->isInstanceOf(StompTransportFactory::class))
- ;
- $extensionMock
- ->expects($this->at(1))
- ->method('setTransportFactory')
- ->with($this->isInstanceOf(RabbitMqStompTransportFactory::class))
- ;
-
- $bundle = new EnqueueBundle();
- $bundle->build($container);
- }
-
- public function testShouldRegisterAmqpAndRabbitMqAmqpTransportFactories()
- {
- $extensionMock = $this->createEnqueueExtensionMock();
-
- $container = new ContainerBuilder();
- $container->registerExtension($extensionMock);
-
- $extensionMock
- ->expects($this->at(2))
- ->method('setTransportFactory')
- ->with($this->isInstanceOf(AmqpTransportFactory::class))
- ->willReturnCallback(function (AmqpTransportFactory $factory) {
- $this->assertSame('amqp', $factory->getName());
- })
- ;
- $extensionMock
- ->expects($this->at(3))
- ->method('setTransportFactory')
- ->with($this->isInstanceOf(RabbitMqAmqpTransportFactory::class))
- ->willReturnCallback(function (RabbitMqAmqpTransportFactory $factory) {
- $this->assertSame('rabbitmq_amqp', $factory->getName());
- })
- ;
-
- $bundle = new EnqueueBundle();
- $bundle->build($container);
- }
-
- public function testShouldRegisterFSTransportFactory()
- {
- $extensionMock = $this->createEnqueueExtensionMock();
-
- $container = new ContainerBuilder();
- $container->registerExtension($extensionMock);
-
- $extensionMock
- ->expects($this->at(4))
- ->method('setTransportFactory')
- ->with($this->isInstanceOf(FsTransportFactory::class))
- ;
-
- $bundle = new EnqueueBundle();
- $bundle->build($container);
- }
-
- public function testShouldRegisterRedisTransportFactory()
- {
- $extensionMock = $this->createEnqueueExtensionMock();
-
- $container = new ContainerBuilder();
- $container->registerExtension($extensionMock);
-
- $extensionMock
- ->expects($this->at(5))
- ->method('setTransportFactory')
- ->with($this->isInstanceOf(RedisTransportFactory::class))
- ;
-
- $bundle = new EnqueueBundle();
- $bundle->build($container);
- }
-
- public function testShouldRegisterDbalTransportFactory()
- {
- $extensionMock = $this->createEnqueueExtensionMock();
-
- $container = new ContainerBuilder();
- $container->registerExtension($extensionMock);
-
- $extensionMock
- ->expects($this->at(6))
- ->method('setTransportFactory')
- ->with($this->isInstanceOf(DbalTransportFactory::class))
- ;
-
- $bundle = new EnqueueBundle();
- $bundle->build($container);
- }
-
- public function testShouldRegisterSqsTransportFactory()
- {
- $extensionMock = $this->createEnqueueExtensionMock();
-
- $container = new ContainerBuilder();
- $container->registerExtension($extensionMock);
-
- $extensionMock
- ->expects($this->at(7))
- ->method('setTransportFactory')
- ->with($this->isInstanceOf(SqsTransportFactory::class))
- ;
-
- $bundle = new EnqueueBundle();
- $bundle->build($container);
- }
-
- public function testShouldRegisterGpsTransportFactory()
- {
- $extensionMock = $this->createEnqueueExtensionMock();
-
- $container = new ContainerBuilder();
- $container->registerExtension($extensionMock);
-
- $extensionMock
- ->expects($this->at(8))
- ->method('setTransportFactory')
- ->with($this->isInstanceOf(GpsTransportFactory::class))
- ;
-
- $bundle = new EnqueueBundle();
- $bundle->build($container);
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject|EnqueueExtension
- */
- private function createEnqueueExtensionMock()
- {
- $extensionMock = $this->createMock(EnqueueExtension::class);
- $extensionMock
- ->expects($this->once())
- ->method('getAlias')
- ->willReturn('enqueue')
- ;
- $extensionMock
- ->expects($this->once())
- ->method('getNamespace')
- ->willReturn(false)
- ;
-
- return $extensionMock;
- }
}
diff --git a/pkg/enqueue-bundle/Tests/Unit/Mocks/FooTransportFactory.php b/pkg/enqueue-bundle/Tests/Unit/Mocks/FooTransportFactory.php
deleted file mode 100644
index 5507d193d..000000000
--- a/pkg/enqueue-bundle/Tests/Unit/Mocks/FooTransportFactory.php
+++ /dev/null
@@ -1,83 +0,0 @@
-name = $name;
- }
-
- /**
- * {@inheritdoc}
- */
- public function addConfiguration(ArrayNodeDefinition $builder)
- {
- $builder
- ->children()
- ->scalarNode('foo_param')->isRequired()->cannotBeEmpty()->end()
- ;
- }
-
- /**
- * {@inheritdoc}
- */
- public function createConnectionFactory(ContainerBuilder $container, array $config)
- {
- $factoryId = 'foo.connection_factory';
-
- $container->setDefinition($factoryId, new Definition(\stdClass::class, [$config]));
-
- return $factoryId;
- }
-
- /**
- * {@inheritdoc}
- */
- public function createContext(ContainerBuilder $container, array $config)
- {
- $contextId = 'foo.context';
-
- $context = new Definition(\stdClass::class, [$config]);
- $context->setPublic(true);
-
- $container->setDefinition($contextId, $context);
-
- return $contextId;
- }
-
- public function createDriver(ContainerBuilder $container, array $config)
- {
- $driverId = 'foo.driver';
-
- $driver = new Definition(\stdClass::class, [$config]);
- $driver->setPublic(true);
-
- $container->setDefinition($driverId, $driver);
-
- return $driverId;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return $this->name;
- }
-}
diff --git a/pkg/enqueue-bundle/Tests/Unit/Mocks/TransportFactoryWithoutDriverFactory.php b/pkg/enqueue-bundle/Tests/Unit/Mocks/TransportFactoryWithoutDriverFactory.php
deleted file mode 100644
index f3a003201..000000000
--- a/pkg/enqueue-bundle/Tests/Unit/Mocks/TransportFactoryWithoutDriverFactory.php
+++ /dev/null
@@ -1,71 +0,0 @@
-name = $name;
- }
-
- /**
- * {@inheritdoc}
- */
- public function addConfiguration(ArrayNodeDefinition $builder)
- {
- }
-
- /**
- * {@inheritdoc}
- */
- public function createConnectionFactory(ContainerBuilder $container, array $config)
- {
- $factoryId = 'without_driver.connection_factory';
-
- $container->setDefinition($factoryId, new Definition(\stdClass::class, [$config]));
-
- return $factoryId;
- }
-
- /**
- * {@inheritdoc}
- */
- public function createContext(ContainerBuilder $container, array $config)
- {
- $contextId = 'without_driver.context';
-
- $context = new Definition(\stdClass::class, [$config]);
- $context->setPublic(true);
-
- $container->setDefinition($contextId, $context);
-
- return $contextId;
- }
-
- public function createDriver(ContainerBuilder $container, array $config)
- {
- throw new \LogicException('It should not be called. The method will be removed');
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return $this->name;
- }
-}
diff --git a/pkg/enqueue-bundle/Tests/Unit/Profiler/MessageQueueCollectorTest.php b/pkg/enqueue-bundle/Tests/Unit/Profiler/MessageQueueCollectorTest.php
index 62f7d6c1c..d6d638d75 100644
--- a/pkg/enqueue-bundle/Tests/Unit/Profiler/MessageQueueCollectorTest.php
+++ b/pkg/enqueue-bundle/Tests/Unit/Profiler/MessageQueueCollectorTest.php
@@ -2,11 +2,13 @@
namespace Enqueue\Bundle\Tests\Unit\Profiler;
+use DMS\PHPUnitExtensions\ArraySubset\Assert;
use Enqueue\Bundle\Profiler\MessageQueueCollector;
use Enqueue\Client\MessagePriority;
use Enqueue\Client\ProducerInterface;
use Enqueue\Client\TraceableProducer;
use Enqueue\Test\ClassExtensionTrait;
+use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
@@ -21,59 +23,105 @@ public function testShouldExtendDataCollectorClass()
$this->assertClassExtends(DataCollector::class, MessageQueueCollector::class);
}
- public function testCouldBeConstructedWithMessageProducerAsFirstArgument()
- {
- new MessageQueueCollector($this->createProducerMock());
- }
-
public function testShouldReturnExpectedName()
{
- $collector = new MessageQueueCollector($this->createProducerMock());
+ $collector = new MessageQueueCollector();
$this->assertEquals('enqueue.message_queue', $collector->getName());
}
public function testShouldReturnEmptySentMessageArrayIfNotTraceableProducer()
{
- $collector = new MessageQueueCollector($this->createProducerMock());
+ $collector = new MessageQueueCollector();
+ $collector->addProducer('default', $this->createProducerMock());
$collector->collect(new Request(), new Response());
$this->assertSame([], $collector->getSentMessages());
}
- public function testShouldReturnSentMessageArrayTakenFromTraceableProducer()
+ public function testShouldReturnSentMessageArrayTakenFromTraceableProducers()
{
- $producerMock = $this->createTraceableProducerMock();
- $producerMock
- ->expects($this->once())
- ->method('getTraces')
- ->willReturn([['foo'], ['bar']]);
+ $producer1 = new TraceableProducer($this->createProducerMock());
+ $producer1->sendEvent('fooTopic1', 'fooMessage');
+ $producer1->sendCommand('barCommand1', 'barMessage');
+
+ $producer2 = new TraceableProducer($this->createProducerMock());
+ $producer2->sendEvent('fooTopic2', 'fooMessage');
- $collector = new MessageQueueCollector($producerMock);
+ $collector = new MessageQueueCollector();
+ $collector->addProducer('foo', $producer1);
+ $collector->addProducer('bar', $producer2);
$collector->collect(new Request(), new Response());
- $this->assertSame([['foo'], ['bar']], $collector->getSentMessages());
+ Assert::assertArraySubset(
+ [
+ 'foo' => [
+ [
+ 'topic' => 'fooTopic1',
+ 'command' => null,
+ 'body' => 'fooMessage',
+ 'headers' => [],
+ 'properties' => [],
+ 'priority' => null,
+ 'expire' => null,
+ 'delay' => null,
+ 'timestamp' => null,
+ 'contentType' => null,
+ 'messageId' => null,
+ ],
+ [
+ 'topic' => null,
+ 'command' => 'barCommand1',
+ 'body' => 'barMessage',
+ 'headers' => [],
+ 'properties' => [],
+ 'priority' => null,
+ 'expire' => null,
+ 'delay' => null,
+ 'timestamp' => null,
+ 'contentType' => null,
+ 'messageId' => null,
+ ],
+ ],
+ 'bar' => [
+ [
+ 'topic' => 'fooTopic2',
+ 'command' => null,
+ 'body' => 'fooMessage',
+ 'headers' => [],
+ 'properties' => [],
+ 'priority' => null,
+ 'expire' => null,
+ 'delay' => null,
+ 'timestamp' => null,
+ 'contentType' => null,
+ 'messageId' => null,
+ ],
+ ],
+ ],
+ $collector->getSentMessages()
+ );
}
public function testShouldPrettyPrintKnownPriority()
{
- $collector = new MessageQueueCollector($this->createProducerMock());
+ $collector = new MessageQueueCollector();
$this->assertEquals('normal', $collector->prettyPrintPriority(MessagePriority::NORMAL));
}
public function testShouldPrettyPrintUnknownPriority()
{
- $collector = new MessageQueueCollector($this->createProducerMock());
+ $collector = new MessageQueueCollector();
$this->assertEquals('unknownPriority', $collector->prettyPrintPriority('unknownPriority'));
}
public function testShouldEnsureStringKeepStringSame()
{
- $collector = new MessageQueueCollector($this->createProducerMock());
+ $collector = new MessageQueueCollector();
$this->assertEquals('foo', $collector->ensureString('foo'));
$this->assertEquals('bar baz', $collector->ensureString('bar baz'));
@@ -81,13 +129,13 @@ public function testShouldEnsureStringKeepStringSame()
public function testShouldEnsureStringEncodeArrayToJson()
{
- $collector = new MessageQueueCollector($this->createProducerMock());
+ $collector = new MessageQueueCollector();
$this->assertEquals('["foo","bar"]', $collector->ensureString(['foo', 'bar']));
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|ProducerInterface
+ * @return MockObject|ProducerInterface
*/
protected function createProducerMock()
{
@@ -95,7 +143,7 @@ protected function createProducerMock()
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|TraceableProducer
+ * @return MockObject|TraceableProducer
*/
protected function createTraceableProducerMock()
{
diff --git a/pkg/enqueue-bundle/Tests/fix_composer_json.php b/pkg/enqueue-bundle/Tests/fix_composer_json.php
index fc430e276..5c80237ea 100644
--- a/pkg/enqueue-bundle/Tests/fix_composer_json.php
+++ b/pkg/enqueue-bundle/Tests/fix_composer_json.php
@@ -4,6 +4,7 @@
$composerJson = json_decode(file_get_contents(__DIR__.'/../composer.json'), true);
-$composerJson['config']['platform']['ext-amqp'] = '1.7';
+$composerJson['config']['platform']['ext-amqp'] = '1.9.3';
+$composerJson['config']['platform']['ext-mongo'] = '1.6.14';
-file_put_contents(__DIR__.'/../composer.json', json_encode($composerJson, JSON_PRETTY_PRINT));
+file_put_contents(__DIR__.'/../composer.json', json_encode($composerJson, \JSON_PRETTY_PRINT));
diff --git a/pkg/enqueue-bundle/composer.json b/pkg/enqueue-bundle/composer.json
index 8890feb0c..99d237bf6 100644
--- a/pkg/enqueue-bundle/composer.json
+++ b/pkg/enqueue-bundle/composer.json
@@ -6,11 +6,12 @@
"homepage": "https://enqueue.forma-pro.com/",
"license": "MIT",
"require": {
- "php": ">=5.6",
- "symfony/framework-bundle": "^2.8|^3|^4",
- "enqueue/enqueue": "^0.8.35@dev",
- "enqueue/null": "^0.8@dev",
- "enqueue/async-event-dispatcher": "^0.8@dev"
+ "php": "^8.1",
+ "symfony/framework-bundle": "^6.2|^7.0",
+ "queue-interop/amqp-interop": "^0.8.2",
+ "queue-interop/queue-interop": "^0.8",
+ "enqueue/enqueue": "^0.10",
+ "enqueue/null": "^0.10"
},
"support": {
"email": "opensource@forma-pro.com",
@@ -20,23 +21,32 @@
"docs": "https://github.com/php-enqueue/enqueue-dev/blob/master/docs/index.md"
},
"require-dev": {
- "phpunit/phpunit": "~5.5",
- "enqueue/stomp": "^0.8@dev",
- "enqueue/amqp-ext": "^0.8@dev",
- "php-amqplib/php-amqplib": "^2.7@dev",
- "enqueue/amqp-lib": "^0.8@dev",
- "enqueue/amqp-bunny": "^0.8@dev",
- "enqueue/job-queue": "^0.8@dev",
- "enqueue/fs": "^0.8@dev",
- "enqueue/redis": "^0.8@dev",
- "enqueue/dbal": "^0.8@dev",
- "enqueue/sqs": "^0.8@dev",
- "enqueue/gps": "^0.8@dev",
- "enqueue/test": "^0.8@dev",
- "doctrine/doctrine-bundle": "~1.2",
- "symfony/monolog-bundle": "^2.8|^3|^4",
- "symfony/browser-kit": "^2.8|^3|^4",
- "symfony/expression-language": "^2.8|^3|^4"
+ "phpunit/phpunit": "^9.5",
+ "enqueue/stomp": "0.10.x-dev",
+ "enqueue/amqp-ext": "0.10.x-dev",
+ "enqueue/amqp-lib": "0.10.x-dev",
+ "enqueue/amqp-bunny": "0.10.x-dev",
+ "enqueue/job-queue": "0.10.x-dev",
+ "enqueue/fs": "0.10.x-dev",
+ "enqueue/redis": "0.10.x-dev",
+ "enqueue/dbal": "0.10.x-dev",
+ "enqueue/sqs": "0.10.x-dev",
+ "enqueue/gps": "0.10.x-dev",
+ "enqueue/test": "0.10.x-dev",
+ "enqueue/async-event-dispatcher": "0.10.x-dev",
+ "enqueue/async-command": "0.10.x-dev",
+ "php-amqplib/php-amqplib": "^3.0",
+ "doctrine/doctrine-bundle": "^2.3.2",
+ "doctrine/mongodb-odm-bundle": "^3.5|^4.3|^5.0",
+ "alcaeus/mongo-php-adapter": "^1.0",
+ "symfony/browser-kit": "^6.2|^7.0",
+ "symfony/expression-language": "^6.2|^7.0",
+ "symfony/validator": "^6.2|^7.0",
+ "symfony/yaml": "^6.2|^7.0"
+ },
+ "suggest": {
+ "enqueue/async-command": "If want to run Symfony command via message queue",
+ "enqueue/async-event-dispatcher": "If you want dispatch and process events asynchronously"
},
"autoload": {
"psr-4": { "Enqueue\\Bundle\\": "" },
@@ -46,7 +56,12 @@
},
"extra": {
"branch-alias": {
- "dev-master": "0.8.x-dev"
+ "dev-master": "0.10.x-dev"
}
+ },
+ "config": {
+ "allow-plugins": {
+ "php-http/discovery": true
+ }
}
}
diff --git a/pkg/enqueue-bundle/phpunit.xml.dist b/pkg/enqueue-bundle/phpunit.xml.dist
index ac0770ea9..974d2c3f5 100644
--- a/pkg/enqueue-bundle/phpunit.xml.dist
+++ b/pkg/enqueue-bundle/phpunit.xml.dist
@@ -1,16 +1,11 @@
-
+
diff --git a/pkg/enqueue/.github/workflows/ci.yml b/pkg/enqueue/.github/workflows/ci.yml
new file mode 100644
index 000000000..28a46e908
--- /dev/null
+++ b/pkg/enqueue/.github/workflows/ci.yml
@@ -0,0 +1,30 @@
+name: CI
+on:
+ pull_request:
+ push:
+ branches:
+ - master
+jobs:
+ tests:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ php: ['7.4', '8.0', '8.1', '8.2']
+
+ name: PHP ${{ matrix.php }} tests
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php }}
+ coverage: none
+ extensions: mongodb
+
+ - run: php Tests/fix_composer_json.php
+
+ - uses: "ramsey/composer-install@v1"
+
+ - run: vendor/bin/phpunit --exclude-group=functional
diff --git a/pkg/enqueue/.travis.yml b/pkg/enqueue/.travis.yml
deleted file mode 100644
index 2c830d0a6..000000000
--- a/pkg/enqueue/.travis.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-sudo: false
-
-git:
- depth: 10
-
-language: php
-
-php:
- - '7.1'
-
-services:
- - mongodb
-
-before_install:
- - echo "extension = mongodb.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
-
-cache:
- directories:
- - $HOME/.composer/cache
-
-install:
- - php Tests/fix_composer_json.php
- - composer self-update
- - composer install
-
-script:
- - vendor/bin/phpunit --exclude-group=functional
diff --git a/pkg/enqueue/Client/ArrayProcessorRegistry.php b/pkg/enqueue/ArrayProcessorRegistry.php
similarity index 55%
rename from pkg/enqueue/Client/ArrayProcessorRegistry.php
rename to pkg/enqueue/ArrayProcessorRegistry.php
index d6cb300d0..592908c51 100644
--- a/pkg/enqueue/Client/ArrayProcessorRegistry.php
+++ b/pkg/enqueue/ArrayProcessorRegistry.php
@@ -1,37 +1,33 @@
processors = $processors;
+ $this->processors = [];
+ array_walk($processors, function (Processor $processor, string $key) {
+ $this->processors[$key] = $processor;
+ });
}
- /**
- * @param string $name
- * @param PsrProcessor $processor
- */
- public function add($name, PsrProcessor $processor)
+ public function add(string $name, Processor $processor): void
{
$this->processors[$name] = $processor;
}
- /**
- * {@inheritdoc}
- */
- public function get($processorName)
+ public function get(string $processorName): Processor
{
if (false == isset($this->processors[$processorName])) {
throw new \LogicException(sprintf('Processor was not found. processorName: "%s"', $processorName));
diff --git a/pkg/enqueue/Client/Amqp/AmqpDriver.php b/pkg/enqueue/Client/Amqp/AmqpDriver.php
deleted file mode 100644
index e8b5871d3..000000000
--- a/pkg/enqueue/Client/Amqp/AmqpDriver.php
+++ /dev/null
@@ -1,205 +0,0 @@
-context = $context;
- $this->config = $config;
- $this->queueMetaRegistry = $queueMetaRegistry;
- }
-
- /**
- * {@inheritdoc}
- */
- public function sendToRouter(Message $message)
- {
- if (false == $message->getProperty(Config::PARAMETER_TOPIC_NAME)) {
- throw new \LogicException('Topic name parameter is required but is not set');
- }
-
- $topic = $this->createRouterTopic();
- $transportMessage = $this->createTransportMessage($message);
-
- $this->context->createProducer()->send($topic, $transportMessage);
- }
-
- /**
- * {@inheritdoc}
- */
- public function sendToProcessor(Message $message)
- {
- if (false == $message->getProperty(Config::PARAMETER_PROCESSOR_NAME)) {
- throw new \LogicException('Processor name parameter is required but is not set');
- }
-
- if (false == $queueName = $message->getProperty(Config::PARAMETER_PROCESSOR_QUEUE_NAME)) {
- throw new \LogicException('Queue name parameter is required but is not set');
- }
-
- $transportMessage = $this->createTransportMessage($message);
- $destination = $this->createQueue($queueName);
-
- $this->context->createProducer()->send($destination, $transportMessage);
- }
-
- /**
- * {@inheritdoc}
- */
- public function setupBroker(LoggerInterface $logger = null)
- {
- $logger = $logger ?: new NullLogger();
- $log = function ($text, ...$args) use ($logger) {
- $logger->debug(sprintf('[AmqpDriver] '.$text, ...$args));
- };
-
- // setup router
- $routerTopic = $this->createRouterTopic();
- $routerQueue = $this->createQueue($this->config->getRouterQueueName());
-
- $log('Declare router exchange: %s', $routerTopic->getTopicName());
- $this->context->declareTopic($routerTopic);
- $log('Declare router queue: %s', $routerQueue->getQueueName());
- $this->context->declareQueue($routerQueue);
- $log('Bind router queue to exchange: %s -> %s', $routerQueue->getQueueName(), $routerTopic->getTopicName());
- $this->context->bind(new AmqpBind($routerTopic, $routerQueue, $routerQueue->getQueueName()));
-
- // setup queues
- foreach ($this->queueMetaRegistry->getQueuesMeta() as $meta) {
- $queue = $this->createQueue($meta->getClientName());
-
- $log('Declare processor queue: %s', $queue->getQueueName());
- $this->context->declareQueue($queue);
- }
- }
-
- /**
- * {@inheritdoc}
- *
- * @return AmqpQueue
- */
- public function createQueue($queueName)
- {
- $transportName = $this->queueMetaRegistry->getQueueMeta($queueName)->getTransportName();
-
- $queue = $this->context->createQueue($transportName);
- $queue->addFlag(AmqpQueue::FLAG_DURABLE);
-
- return $queue;
- }
-
- /**
- * {@inheritdoc}
- *
- * @return AmqpMessage
- */
- public function createTransportMessage(Message $message)
- {
- $headers = $message->getHeaders();
- $properties = $message->getProperties();
-
- $transportMessage = $this->context->createMessage();
- $transportMessage->setBody($message->getBody());
- $transportMessage->setHeaders($headers);
- $transportMessage->setProperties($properties);
- $transportMessage->setMessageId($message->getMessageId());
- $transportMessage->setTimestamp($message->getTimestamp());
- $transportMessage->setReplyTo($message->getReplyTo());
- $transportMessage->setCorrelationId($message->getCorrelationId());
- $transportMessage->setContentType($message->getContentType());
- $transportMessage->setDeliveryMode(AmqpMessage::DELIVERY_MODE_PERSISTENT);
-
- if ($message->getExpire()) {
- $transportMessage->setExpiration((string) ($message->getExpire() * 1000));
- }
-
- return $transportMessage;
- }
-
- /**
- * @param AmqpMessage $message
- *
- * {@inheritdoc}
- */
- public function createClientMessage(PsrMessage $message)
- {
- $clientMessage = new Message();
-
- $clientMessage->setBody($message->getBody());
- $clientMessage->setHeaders($message->getHeaders());
- $clientMessage->setProperties($message->getProperties());
- $clientMessage->setContentType($message->getContentType());
-
- if ($expiration = $message->getExpiration()) {
- if (false == is_numeric($expiration)) {
- throw new \LogicException(sprintf('expiration header is not numeric. "%s"', $expiration));
- }
-
- $clientMessage->setExpire((int) ((int) $expiration) / 1000);
- }
-
- $clientMessage->setMessageId($message->getMessageId());
- $clientMessage->setTimestamp($message->getTimestamp());
- $clientMessage->setReplyTo($message->getReplyTo());
- $clientMessage->setCorrelationId($message->getCorrelationId());
-
- return $clientMessage;
- }
-
- /**
- * @return Config
- */
- public function getConfig()
- {
- return $this->config;
- }
-
- /**
- * @return AmqpTopic
- */
- private function createRouterTopic()
- {
- $topic = $this->context->createTopic(
- $this->config->createTransportRouterTopicName($this->config->getRouterTopicName())
- );
- $topic->setType(AmqpTopic::TYPE_FANOUT);
- $topic->addFlag(AmqpTopic::FLAG_DURABLE);
-
- return $topic;
- }
-}
diff --git a/pkg/enqueue/Client/Amqp/RabbitMqDriver.php b/pkg/enqueue/Client/Amqp/RabbitMqDriver.php
deleted file mode 100644
index 518b90056..000000000
--- a/pkg/enqueue/Client/Amqp/RabbitMqDriver.php
+++ /dev/null
@@ -1,154 +0,0 @@
-config = $config;
- $this->context = $context;
- $this->queueMetaRegistry = $queueMetaRegistry;
-
- $this->priorityMap = [
- MessagePriority::VERY_LOW => 0,
- MessagePriority::LOW => 1,
- MessagePriority::NORMAL => 2,
- MessagePriority::HIGH => 3,
- MessagePriority::VERY_HIGH => 4,
- ];
- }
-
- /**
- * {@inheritdoc}
- */
- public function sendToProcessor(Message $message)
- {
- if (false == $message->getProperty(Config::PARAMETER_PROCESSOR_NAME)) {
- throw new \LogicException('Processor name parameter is required but is not set');
- }
-
- if (false == $queueName = $message->getProperty(Config::PARAMETER_PROCESSOR_QUEUE_NAME)) {
- throw new \LogicException('Queue name parameter is required but is not set');
- }
-
- $transportMessage = $this->createTransportMessage($message);
- $destination = $this->createQueue($queueName);
- $producer = $this->context->createProducer();
-
- if ($message->getDelay()) {
- $producer->setDeliveryDelay($message->getDelay() * 1000);
- }
-
- $producer->send($destination, $transportMessage);
- }
-
- /**
- * {@inheritdoc}
- *
- * @return AmqpQueue
- */
- public function createQueue($queueName)
- {
- $queue = parent::createQueue($queueName);
- $queue->setArguments(['x-max-priority' => 4]);
-
- return $queue;
- }
-
- /**
- * {@inheritdoc}
- *
- * @return AmqpMessage
- */
- public function createTransportMessage(Message $message)
- {
- $transportMessage = parent::createTransportMessage($message);
-
- if ($priority = $message->getPriority()) {
- if (false == array_key_exists($priority, $this->priorityMap)) {
- throw new \InvalidArgumentException(sprintf(
- 'Given priority could not be converted to client\'s one. Got: %s',
- $priority
- ));
- }
-
- $transportMessage->setPriority($this->priorityMap[$priority]);
- }
-
- if ($message->getDelay()) {
- if (false == $this->config->getTransportOption('delay_strategy', false)) {
- throw new LogicException('The message delaying is not supported. In order to use delay feature install RabbitMQ delay strategy.');
- }
-
- $transportMessage->setProperty('enqueue-delay', $message->getDelay() * 1000);
- }
-
- return $transportMessage;
- }
-
- /**
- * @param AmqpMessage $message
- *
- * {@inheritdoc}
- */
- public function createClientMessage(PsrMessage $message)
- {
- $clientMessage = parent::createClientMessage($message);
-
- if ($priority = $message->getPriority()) {
- if (false === $clientPriority = array_search($priority, $this->priorityMap, true)) {
- throw new \LogicException(sprintf('Cant convert transport priority to client: "%s"', $priority));
- }
-
- $clientMessage->setPriority($clientPriority);
- }
-
- if ($delay = $message->getProperty('enqueue-delay')) {
- if (false == is_numeric($delay)) {
- throw new \LogicException(sprintf('"enqueue-delay" header is not numeric. "%s"', $delay));
- }
-
- $clientMessage->setDelay((int) ((int) $delay) / 1000);
- }
-
- return $clientMessage;
- }
-}
diff --git a/pkg/enqueue/Client/ChainExtension.php b/pkg/enqueue/Client/ChainExtension.php
index c202e98e0..655b75f6a 100644
--- a/pkg/enqueue/Client/ChainExtension.php
+++ b/pkg/enqueue/Client/ChainExtension.php
@@ -2,38 +2,101 @@
namespace Enqueue\Client;
-class ChainExtension implements ExtensionInterface
+final class ChainExtension implements ExtensionInterface
{
/**
- * @var ExtensionInterface[]
+ * @var PreSendEventExtensionInterface[]
*/
- private $extensions;
+ private $preSendEventExtensions;
/**
- * @param ExtensionInterface[] $extensions
+ * @var PreSendCommandExtensionInterface[]
*/
+ private $preSendCommandExtensions;
+
+ /**
+ * @var DriverPreSendExtensionInterface[]
+ */
+ private $driverPreSendExtensions;
+
+ /**
+ * @var PostSendExtensionInterface[]
+ */
+ private $postSendExtensions;
+
public function __construct(array $extensions)
{
- $this->extensions = $extensions;
+ $this->preSendEventExtensions = [];
+ $this->preSendCommandExtensions = [];
+ $this->driverPreSendExtensions = [];
+ $this->postSendExtensions = [];
+
+ array_walk($extensions, function ($extension) {
+ if ($extension instanceof ExtensionInterface) {
+ $this->preSendEventExtensions[] = $extension;
+ $this->preSendCommandExtensions[] = $extension;
+ $this->driverPreSendExtensions[] = $extension;
+ $this->postSendExtensions[] = $extension;
+
+ return;
+ }
+
+ $extensionValid = false;
+ if ($extension instanceof PreSendEventExtensionInterface) {
+ $this->preSendEventExtensions[] = $extension;
+
+ $extensionValid = true;
+ }
+
+ if ($extension instanceof PreSendCommandExtensionInterface) {
+ $this->preSendCommandExtensions[] = $extension;
+
+ $extensionValid = true;
+ }
+
+ if ($extension instanceof DriverPreSendExtensionInterface) {
+ $this->driverPreSendExtensions[] = $extension;
+
+ $extensionValid = true;
+ }
+
+ if ($extension instanceof PostSendExtensionInterface) {
+ $this->postSendExtensions[] = $extension;
+
+ $extensionValid = true;
+ }
+
+ if (false == $extensionValid) {
+ throw new \LogicException(sprintf('Invalid extension given %s', $extension::class));
+ }
+ });
+ }
+
+ public function onPreSendEvent(PreSend $context): void
+ {
+ foreach ($this->preSendEventExtensions as $extension) {
+ $extension->onPreSendEvent($context);
+ }
}
- /**
- * {@inheritdoc}
- */
- public function onPreSend($topic, Message $message)
+ public function onPreSendCommand(PreSend $context): void
{
- foreach ($this->extensions as $extension) {
- $extension->onPreSend($topic, $message);
+ foreach ($this->preSendCommandExtensions as $extension) {
+ $extension->onPreSendCommand($context);
}
}
- /**
- * {@inheritdoc}
- */
- public function onPostSend($topic, Message $message)
+ public function onDriverPreSend(DriverPreSend $context): void
+ {
+ foreach ($this->driverPreSendExtensions as $extension) {
+ $extension->onDriverPreSend($context);
+ }
+ }
+
+ public function onPostSend(PostSend $context): void
{
- foreach ($this->extensions as $extension) {
- $extension->onPostSend($topic, $message);
+ foreach ($this->postSendExtensions as $extension) {
+ $extension->onPostSend($context);
}
}
}
diff --git a/pkg/enqueue/Client/CommandSubscriberInterface.php b/pkg/enqueue/Client/CommandSubscriberInterface.php
index 99f6b274b..d7b06daaf 100644
--- a/pkg/enqueue/Client/CommandSubscriberInterface.php
+++ b/pkg/enqueue/Client/CommandSubscriberInterface.php
@@ -2,6 +2,15 @@
namespace Enqueue\Client;
+/**
+ * @phpstan-type CommandConfig = array{
+ * command: string,
+ * processor?: string,
+ * queue?: string,
+ * prefix_queue?: bool,
+ * exclusive?: bool,
+ * }
+ */
interface CommandSubscriberInterface
{
/**
@@ -12,17 +21,40 @@ interface CommandSubscriberInterface
* or
*
* [
- * 'processorName' => 'aCommandName',
- * 'queueName' => 'a_client_queue_name',
- * 'queueNameHardcoded' => true,
+ * 'command' => 'aSubscribedCommand',
+ * 'processor' => 'aProcessorName',
+ * 'queue' => 'a_client_queue_name',
+ * 'prefix_queue' => true,
* 'exclusive' => true,
* ]
*
- * queueName, exclusive and queueNameHardcoded are optional.
+ * or
+ *
+ * [
+ * [
+ * 'command' => 'aSubscribedCommand',
+ * 'processor' => 'aProcessorName',
+ * 'queue' => 'a_client_queue_name',
+ * 'prefix_queue' => true,
+ * 'exclusive' => true,
+ * ],
+ * [
+ * 'command' => 'aSubscribedCommand',
+ * 'processor' => 'aProcessorName',
+ * 'queue' => 'a_client_queue_name',
+ * 'prefix_queue' => true,
+ * 'exclusive' => true,
+ * ]
+ * ]
+ *
+ * queue, processor, prefix_queue, and exclusive are optional.
+ * It is possible to pass other options, they could be accessible on a route instance through options.
*
- * Note: If you set queueNameHardcoded to true then the queueName is used as is and therefor the driver is not used to create a transport queue name.
+ * Note: If you set "prefix_queue" to true then the "queue" is used as is and therefor the driver is not used to create a transport queue name.
*
* @return string|array
+ *
+ * @phpstan-return string|CommandConfig|array
*/
public static function getSubscribedCommand();
}
diff --git a/pkg/enqueue/Client/Config.php b/pkg/enqueue/Client/Config.php
index d5d8b072a..8210dff68 100644
--- a/pkg/enqueue/Client/Config.php
+++ b/pkg/enqueue/Client/Config.php
@@ -4,12 +4,13 @@
class Config
{
- const PARAMETER_TOPIC_NAME = 'enqueue.topic_name';
- const PARAMETER_COMMAND_NAME = 'enqueue.command_name';
- const PARAMETER_PROCESSOR_NAME = 'enqueue.processor_name';
- const PARAMETER_PROCESSOR_QUEUE_NAME = 'enqueue.processor_queue_name';
- const DEFAULT_PROCESSOR_QUEUE_NAME = 'default';
- const COMMAND_TOPIC = '__command__';
+ public const TOPIC = 'enqueue.topic';
+ public const COMMAND = 'enqueue.command';
+ public const PROCESSOR = 'enqueue.processor';
+ public const EXPIRE = 'enqueue.expire';
+ public const PRIORITY = 'enqueue.priority';
+ public const DELAY = 'enqueue.delay';
+ public const CONTENT_TYPE = 'enqueue.content_type';
/**
* @var string
@@ -19,27 +20,32 @@ class Config
/**
* @var string
*/
- private $appName;
+ private $separator;
/**
* @var string
*/
- private $routerTopicName;
+ private $app;
/**
* @var string
*/
- private $routerQueueName;
+ private $routerTopic;
/**
* @var string
*/
- private $defaultProcessorQueueName;
+ private $routerQueue;
/**
* @var string
*/
- private $routerProcessorName;
+ private $defaultQueue;
+
+ /**
+ * @var string
+ */
+ private $routerProcessor;
/**
* @var array
@@ -47,116 +53,126 @@ class Config
private $transportConfig;
/**
- * @param string $prefix
- * @param string $appName
- * @param string $routerTopicName
- * @param string $routerQueueName
- * @param string $defaultProcessorQueueName
- * @param string $routerProcessorName
- * @param array $transportConfig
+ * @var array
*/
- public function __construct($prefix, $appName, $routerTopicName, $routerQueueName, $defaultProcessorQueueName, $routerProcessorName, array $transportConfig = [])
- {
- $this->prefix = $prefix;
- $this->appName = $appName;
- $this->routerTopicName = $routerTopicName;
- $this->routerQueueName = $routerQueueName;
- $this->defaultProcessorQueueName = $defaultProcessorQueueName;
- $this->routerProcessorName = $routerProcessorName;
+ private $driverConfig;
+
+ public function __construct(
+ string $prefix,
+ string $separator,
+ string $app,
+ string $routerTopic,
+ string $routerQueue,
+ string $defaultQueue,
+ string $routerProcessor,
+ array $transportConfig,
+ array $driverConfig,
+ ) {
+ $this->prefix = trim($prefix);
+ $this->app = trim($app);
+
+ $this->routerTopic = trim($routerTopic);
+ if (empty($this->routerTopic)) {
+ throw new \InvalidArgumentException('Router topic is empty.');
+ }
+
+ $this->routerQueue = trim($routerQueue);
+ if (empty($this->routerQueue)) {
+ throw new \InvalidArgumentException('Router queue is empty.');
+ }
+
+ $this->defaultQueue = trim($defaultQueue);
+ if (empty($this->defaultQueue)) {
+ throw new \InvalidArgumentException('Default processor queue name is empty.');
+ }
+
+ $this->routerProcessor = trim($routerProcessor);
+ if (empty($this->routerProcessor)) {
+ throw new \InvalidArgumentException('Router processor name is empty.');
+ }
+
$this->transportConfig = $transportConfig;
+ $this->driverConfig = $driverConfig;
+
+ $this->separator = $separator;
}
- /**
- * @return string
- */
- public function getRouterTopicName()
+ public function getPrefix(): string
{
- return $this->routerTopicName;
+ return $this->prefix;
}
- /**
- * @return string
- */
- public function getRouterQueueName()
+ public function getSeparator(): string
{
- return $this->routerQueueName;
+ return $this->separator;
}
- /**
- * @return string
- */
- public function getDefaultProcessorQueueName()
+ public function getApp(): string
{
- return $this->defaultProcessorQueueName;
+ return $this->app;
}
- /**
- * @return string
- */
- public function getRouterProcessorName()
+ public function getRouterTopic(): string
{
- return $this->routerProcessorName;
+ return $this->routerTopic;
}
- /**
- * @param string $name
- *
- * @return string
- */
- public function createTransportRouterTopicName($name)
+ public function getRouterQueue(): string
{
- return strtolower(implode('.', array_filter([trim($this->prefix), trim($name)])));
+ return $this->routerQueue;
}
- /**
- * @param string $name
- *
- * @return string
- */
- public function createTransportQueueName($name)
+ public function getDefaultQueue(): string
{
- return strtolower(implode('.', array_filter([trim($this->prefix), trim($this->appName), trim($name)])));
+ return $this->defaultQueue;
}
- /**
- * @param string $name
- * @param mixed|null $default
- *
- * @return array
- */
- public function getTransportOption($name, $default = null)
+ public function getRouterProcessor(): string
+ {
+ return $this->routerProcessor;
+ }
+
+ public function getTransportOption(string $name, $default = null)
{
return array_key_exists($name, $this->transportConfig) ? $this->transportConfig[$name] : $default;
}
- /**
- * @param string|null $prefix
- * @param string|null $appName
- * @param string|null $routerTopicName
- * @param string|null $routerQueueName
- * @param string|null $defaultProcessorQueueName
- * @param string|null $routerProcessorName
- * @param array $transportConfig
- *
- * @return static
- */
+ public function getTransportOptions(): array
+ {
+ return $this->transportConfig;
+ }
+
+ public function getDriverOption(string $name, $default = null)
+ {
+ return array_key_exists($name, $this->driverConfig) ? $this->driverConfig[$name] : $default;
+ }
+
+ public function getDriverOptions(): array
+ {
+ return $this->driverConfig;
+ }
+
public static function create(
- $prefix = null,
- $appName = null,
- $routerTopicName = null,
- $routerQueueName = null,
- $defaultProcessorQueueName = null,
- $routerProcessorName = null,
- array $transportConfig = []
- ) {
- return new static(
+ ?string $prefix = null,
+ ?string $separator = null,
+ ?string $app = null,
+ ?string $routerTopic = null,
+ ?string $routerQueue = null,
+ ?string $defaultQueue = null,
+ ?string $routerProcessor = null,
+ array $transportConfig = [],
+ array $driverConfig = [],
+ ): self {
+ return new self(
$prefix ?: '',
- $appName ?: '',
- $routerTopicName ?: 'router',
- $routerQueueName ?: 'default',
- $defaultProcessorQueueName ?: 'default',
- $routerProcessorName ?: 'router',
- $transportConfig
+ $separator ?: '.',
+ $app ?: '',
+ $routerTopic ?: 'router',
+ $routerQueue ?: 'default',
+ $defaultQueue ?: 'default',
+ $routerProcessor ?: 'router',
+ $transportConfig,
+ $driverConfig
);
}
}
diff --git a/pkg/enqueue/Client/ConsumptionExtension/DelayRedeliveredMessageExtension.php b/pkg/enqueue/Client/ConsumptionExtension/DelayRedeliveredMessageExtension.php
index 98fa483fa..475e2cf5b 100644
--- a/pkg/enqueue/Client/ConsumptionExtension/DelayRedeliveredMessageExtension.php
+++ b/pkg/enqueue/Client/ConsumptionExtension/DelayRedeliveredMessageExtension.php
@@ -3,16 +3,13 @@
namespace Enqueue\Client\ConsumptionExtension;
use Enqueue\Client\DriverInterface;
-use Enqueue\Consumption\Context;
-use Enqueue\Consumption\EmptyExtensionTrait;
-use Enqueue\Consumption\ExtensionInterface;
+use Enqueue\Consumption\Context\MessageReceived;
+use Enqueue\Consumption\MessageReceivedExtensionInterface;
use Enqueue\Consumption\Result;
-class DelayRedeliveredMessageExtension implements ExtensionInterface
+class DelayRedeliveredMessageExtension implements MessageReceivedExtensionInterface
{
- use EmptyExtensionTrait;
-
- const PROPERTY_REDELIVER_COUNT = 'enqueue.redelivery_count';
+ public const PROPERTY_REDELIVER_COUNT = 'enqueue.redelivery_count';
/**
* @var DriverInterface
@@ -27,8 +24,7 @@ class DelayRedeliveredMessageExtension implements ExtensionInterface
private $delay;
/**
- * @param DriverInterface $driver
- * @param int $delay The number of seconds the message should be delayed
+ * @param int $delay The number of seconds the message should be delayed
*/
public function __construct(DriverInterface $driver, $delay)
{
@@ -36,12 +32,9 @@ public function __construct(DriverInterface $driver, $delay)
$this->delay = $delay;
}
- /**
- * {@inheritdoc}
- */
- public function onPreReceived(Context $context)
+ public function onMessageReceived(MessageReceived $context): void
{
- $message = $context->getPsrMessage();
+ $message = $context->getMessage();
if (false == $message->isRedelivered()) {
return;
}
diff --git a/pkg/enqueue/Client/ConsumptionExtension/ExclusiveCommandExtension.php b/pkg/enqueue/Client/ConsumptionExtension/ExclusiveCommandExtension.php
index a9afde004..7ab88ae0f 100644
--- a/pkg/enqueue/Client/ConsumptionExtension/ExclusiveCommandExtension.php
+++ b/pkg/enqueue/Client/ConsumptionExtension/ExclusiveCommandExtension.php
@@ -3,83 +3,75 @@
namespace Enqueue\Client\ConsumptionExtension;
use Enqueue\Client\Config;
-use Enqueue\Client\ExtensionInterface as ClientExtensionInterface;
-use Enqueue\Client\Message;
-use Enqueue\Consumption\Context;
-use Enqueue\Consumption\EmptyExtensionTrait;
-use Enqueue\Consumption\ExtensionInterface as ConsumptionExtensionInterface;
+use Enqueue\Client\DriverInterface;
+use Enqueue\Client\Route;
+use Enqueue\Consumption\Context\MessageReceived;
+use Enqueue\Consumption\MessageReceivedExtensionInterface;
-class ExclusiveCommandExtension implements ConsumptionExtensionInterface, ClientExtensionInterface
+final class ExclusiveCommandExtension implements MessageReceivedExtensionInterface
{
- use EmptyExtensionTrait;
-
/**
- * @var string[]
+ * @var DriverInterface
*/
- private $queueNameToProcessorNameMap;
+ private $driver;
/**
- * @var string[]
+ * @var Route[]
*/
- private $processorNameToQueueNameMap;
+ private $queueToRouteMap;
- /**
- * @param string[] $queueNameToProcessorNameMap
- */
- public function __construct(array $queueNameToProcessorNameMap)
+ public function __construct(DriverInterface $driver)
{
- $this->queueNameToProcessorNameMap = $queueNameToProcessorNameMap;
- $this->processorNameToQueueNameMap = array_flip($queueNameToProcessorNameMap);
+ $this->driver = $driver;
}
- public function onPreReceived(Context $context)
+ public function onMessageReceived(MessageReceived $context): void
{
- $message = $context->getPsrMessage();
- $queue = $context->getPsrQueue();
-
- if ($message->getProperty(Config::PARAMETER_TOPIC_NAME)) {
+ $message = $context->getMessage();
+ if ($message->getProperty(Config::TOPIC)) {
return;
}
- if ($message->getProperty(Config::PARAMETER_PROCESSOR_QUEUE_NAME)) {
+ if ($message->getProperty(Config::COMMAND)) {
return;
}
- if ($message->getProperty(Config::PARAMETER_PROCESSOR_NAME)) {
+ if ($message->getProperty(Config::PROCESSOR)) {
return;
}
- if ($message->getProperty(Config::PARAMETER_COMMAND_NAME)) {
- return;
+
+ if (null === $this->queueToRouteMap) {
+ $this->queueToRouteMap = $this->buildMap();
}
- if (array_key_exists($queue->getQueueName(), $this->queueNameToProcessorNameMap)) {
+ $queue = $context->getConsumer()->getQueue();
+ if (array_key_exists($queue->getQueueName(), $this->queueToRouteMap)) {
$context->getLogger()->debug('[ExclusiveCommandExtension] This is a exclusive command queue and client\'s properties are not set. Setting them');
- $message->setProperty(Config::PARAMETER_TOPIC_NAME, Config::COMMAND_TOPIC);
- $message->setProperty(Config::PARAMETER_PROCESSOR_QUEUE_NAME, $queue->getQueueName());
- $message->setProperty(Config::PARAMETER_PROCESSOR_NAME, $this->queueNameToProcessorNameMap[$queue->getQueueName()]);
- $message->setProperty(Config::PARAMETER_COMMAND_NAME, $this->queueNameToProcessorNameMap[$queue->getQueueName()]);
+ $route = $this->queueToRouteMap[$queue->getQueueName()];
+ $message->setProperty(Config::PROCESSOR, $route->getProcessor());
+ $message->setProperty(Config::COMMAND, $route->getSource());
}
}
- /**
- * {@inheritdoc}
- */
- public function onPreSend($topic, Message $message)
+ private function buildMap(): array
{
- if (Config::COMMAND_TOPIC != $topic) {
- return;
- }
+ $map = [];
+ foreach ($this->driver->getRouteCollection()->all() as $route) {
+ if (false == $route->isCommand()) {
+ continue;
+ }
+
+ if (false == $route->isProcessorExclusive()) {
+ continue;
+ }
+
+ $queueName = $this->driver->createRouteQueue($route)->getQueueName();
+ if (array_key_exists($queueName, $map)) {
+ throw new \LogicException('The queue name has been already bound by another exclusive command processor');
+ }
- $commandName = $message->getProperty(Config::PARAMETER_COMMAND_NAME);
- if (array_key_exists($commandName, $this->processorNameToQueueNameMap)) {
- $message->setProperty(Config::PARAMETER_PROCESSOR_NAME, $commandName);
- $message->setProperty(Config::PARAMETER_PROCESSOR_QUEUE_NAME, $this->processorNameToQueueNameMap[$commandName]);
+ $map[$queueName] = $route;
}
- }
- /**
- * {@inheritdoc}
- */
- public function onPostSend($topic, Message $message)
- {
+ return $map;
}
}
diff --git a/pkg/enqueue/Client/ConsumptionExtension/FlushSpoolProducerExtension.php b/pkg/enqueue/Client/ConsumptionExtension/FlushSpoolProducerExtension.php
index efb6848b8..6682cad8e 100644
--- a/pkg/enqueue/Client/ConsumptionExtension/FlushSpoolProducerExtension.php
+++ b/pkg/enqueue/Client/ConsumptionExtension/FlushSpoolProducerExtension.php
@@ -3,36 +3,29 @@
namespace Enqueue\Client\ConsumptionExtension;
use Enqueue\Client\SpoolProducer;
-use Enqueue\Consumption\Context;
-use Enqueue\Consumption\EmptyExtensionTrait;
-use Enqueue\Consumption\ExtensionInterface;
+use Enqueue\Consumption\Context\End;
+use Enqueue\Consumption\Context\PostMessageReceived;
+use Enqueue\Consumption\EndExtensionInterface;
+use Enqueue\Consumption\PostMessageReceivedExtensionInterface;
-class FlushSpoolProducerExtension implements ExtensionInterface
+class FlushSpoolProducerExtension implements PostMessageReceivedExtensionInterface, EndExtensionInterface
{
- use EmptyExtensionTrait;
-
/**
* @var SpoolProducer
*/
private $producer;
- /**
- * @param SpoolProducer $producer
- */
public function __construct(SpoolProducer $producer)
{
$this->producer = $producer;
}
- /**
- * {@inheritdoc}
- */
- public function onPostReceived(Context $context)
+ public function onPostMessageReceived(PostMessageReceived $context): void
{
$this->producer->flush();
}
- public function onInterrupted(Context $context)
+ public function onEnd(End $context): void
{
$this->producer->flush();
}
diff --git a/pkg/enqueue/Client/ConsumptionExtension/LogExtension.php b/pkg/enqueue/Client/ConsumptionExtension/LogExtension.php
new file mode 100644
index 000000000..693be2035
--- /dev/null
+++ b/pkg/enqueue/Client/ConsumptionExtension/LogExtension.php
@@ -0,0 +1,69 @@
+getResult();
+ $message = $context->getMessage();
+
+ $logLevel = Result::REJECT == ((string) $result) ? LogLevel::ERROR : LogLevel::INFO;
+
+ if ($command = $message->getProperty(Config::COMMAND)) {
+ $reason = '';
+ $logMessage = "[client] Processed {command}\t{body}\t{result}";
+ if ($result instanceof Result && $result->getReason()) {
+ $reason = $result->getReason();
+
+ $logMessage .= ' {reason}';
+ }
+
+ $context->getLogger()->log($logLevel, $logMessage, [
+ 'result' => str_replace('enqueue.', '', $result),
+ 'reason' => $reason,
+ 'command' => $command,
+ 'queueName' => $context->getConsumer()->getQueue()->getQueueName(),
+ 'body' => Stringify::that($message->getBody()),
+ 'properties' => Stringify::that($message->getProperties()),
+ 'headers' => Stringify::that($message->getHeaders()),
+ ]);
+
+ return;
+ }
+
+ $topic = $message->getProperty(Config::TOPIC);
+ $processor = $message->getProperty(Config::PROCESSOR);
+ if ($topic && $processor) {
+ $reason = '';
+ $logMessage = "[client] Processed {topic} -> {processor}\t{body}\t{result}";
+ if ($result instanceof Result && $result->getReason()) {
+ $reason = $result->getReason();
+
+ $logMessage .= ' {reason}';
+ }
+
+ $context->getLogger()->log($logLevel, $logMessage, [
+ 'result' => str_replace('enqueue.', '', $result),
+ 'reason' => $reason,
+ 'topic' => $topic,
+ 'processor' => $processor,
+ 'queueName' => $context->getConsumer()->getQueue()->getQueueName(),
+ 'body' => Stringify::that($message->getBody()),
+ 'properties' => Stringify::that($message->getProperties()),
+ 'headers' => Stringify::that($message->getHeaders()),
+ ]);
+
+ return;
+ }
+
+ parent::onPostMessageReceived($context);
+ }
+}
diff --git a/pkg/enqueue/Client/ConsumptionExtension/SetRouterPropertiesExtension.php b/pkg/enqueue/Client/ConsumptionExtension/SetRouterPropertiesExtension.php
index d294a9d87..0d2278349 100644
--- a/pkg/enqueue/Client/ConsumptionExtension/SetRouterPropertiesExtension.php
+++ b/pkg/enqueue/Client/ConsumptionExtension/SetRouterPropertiesExtension.php
@@ -4,45 +4,43 @@
use Enqueue\Client\Config;
use Enqueue\Client\DriverInterface;
-use Enqueue\Consumption\Context;
-use Enqueue\Consumption\EmptyExtensionTrait;
-use Enqueue\Consumption\ExtensionInterface;
+use Enqueue\Consumption\Context\MessageReceived;
+use Enqueue\Consumption\MessageReceivedExtensionInterface;
-class SetRouterPropertiesExtension implements ExtensionInterface
+class SetRouterPropertiesExtension implements MessageReceivedExtensionInterface
{
- use EmptyExtensionTrait;
-
/**
* @var DriverInterface
*/
private $driver;
- /**
- * @param DriverInterface $driver
- */
public function __construct(DriverInterface $driver)
{
$this->driver = $driver;
}
- /**
- * {@inheritdoc}
- */
- public function onPreReceived(Context $context)
+ public function onMessageReceived(MessageReceived $context): void
{
- $message = $context->getPsrMessage();
- if ($message->getProperty(Config::PARAMETER_PROCESSOR_NAME)) {
+ $message = $context->getMessage();
+ if (false == $message->getProperty(Config::TOPIC)) {
+ return;
+ }
+ if ($message->getProperty(Config::PROCESSOR)) {
return;
}
$config = $this->driver->getConfig();
- $queue = $this->driver->createQueue($config->getRouterQueueName());
- if ($context->getPsrQueue()->getQueueName() != $queue->getQueueName()) {
+ $queue = $this->driver->createQueue($config->getRouterQueue());
+ if ($context->getConsumer()->getQueue()->getQueueName() != $queue->getQueueName()) {
return;
}
// RouterProcessor is our default message processor when that header is not set
- $message->setProperty(Config::PARAMETER_PROCESSOR_NAME, $config->getRouterProcessorName());
- $message->setProperty(Config::PARAMETER_PROCESSOR_QUEUE_NAME, $config->getRouterQueueName());
+ $message->setProperty(Config::PROCESSOR, $config->getRouterProcessor());
+
+ $context->getLogger()->debug(
+ '[SetRouterPropertiesExtension] '.
+ sprintf('Set router processor "%s"', $config->getRouterProcessor())
+ );
}
}
diff --git a/pkg/enqueue/Client/ConsumptionExtension/SetupBrokerExtension.php b/pkg/enqueue/Client/ConsumptionExtension/SetupBrokerExtension.php
index 8b6aecbc1..44d610fb9 100644
--- a/pkg/enqueue/Client/ConsumptionExtension/SetupBrokerExtension.php
+++ b/pkg/enqueue/Client/ConsumptionExtension/SetupBrokerExtension.php
@@ -3,14 +3,11 @@
namespace Enqueue\Client\ConsumptionExtension;
use Enqueue\Client\DriverInterface;
-use Enqueue\Consumption\Context;
-use Enqueue\Consumption\EmptyExtensionTrait;
-use Enqueue\Consumption\ExtensionInterface;
+use Enqueue\Consumption\Context\Start;
+use Enqueue\Consumption\StartExtensionInterface;
-class SetupBrokerExtension implements ExtensionInterface
+class SetupBrokerExtension implements StartExtensionInterface
{
- use EmptyExtensionTrait;
-
/**
* @var DriverInterface
*/
@@ -21,19 +18,13 @@ class SetupBrokerExtension implements ExtensionInterface
*/
private $isDone;
- /**
- * @param DriverInterface $driver
- */
public function __construct(DriverInterface $driver)
{
$this->driver = $driver;
$this->isDone = false;
}
- /**
- * {@inheritdoc}
- */
- public function onStart(Context $context)
+ public function onStart(Start $context): void
{
if (false == $this->isDone) {
$this->isDone = true;
diff --git a/pkg/enqueue/Client/DelegateProcessor.php b/pkg/enqueue/Client/DelegateProcessor.php
index 6cb8f9866..7582c52dc 100644
--- a/pkg/enqueue/Client/DelegateProcessor.php
+++ b/pkg/enqueue/Client/DelegateProcessor.php
@@ -2,36 +2,31 @@
namespace Enqueue\Client;
-use Interop\Queue\PsrContext;
-use Interop\Queue\PsrMessage;
-use Interop\Queue\PsrProcessor;
+use Enqueue\ProcessorRegistryInterface;
+use Interop\Queue\Context;
+use Interop\Queue\Message as InteropMessage;
+use Interop\Queue\Processor;
-class DelegateProcessor implements PsrProcessor
+class DelegateProcessor implements Processor
{
/**
* @var ProcessorRegistryInterface
*/
private $registry;
- /**
- * @param ProcessorRegistryInterface $registry
- */
public function __construct(ProcessorRegistryInterface $registry)
{
$this->registry = $registry;
}
/**
- * {@inheritdoc}
+ * @return string|object
*/
- public function process(PsrMessage $message, PsrContext $context)
+ public function process(InteropMessage $message, Context $context)
{
- $processorName = $message->getProperty(Config::PARAMETER_PROCESSOR_NAME);
+ $processorName = $message->getProperty(Config::PROCESSOR);
if (false == $processorName) {
- throw new \LogicException(sprintf(
- 'Got message without required parameter: "%s"',
- Config::PARAMETER_PROCESSOR_NAME
- ));
+ throw new \LogicException(sprintf('Got message without required parameter: "%s"', Config::PROCESSOR));
}
return $this->registry->get($processorName)->process($message, $context);
diff --git a/pkg/enqueue/Client/Driver/AmqpDriver.php b/pkg/enqueue/Client/Driver/AmqpDriver.php
new file mode 100644
index 000000000..1def3fb23
--- /dev/null
+++ b/pkg/enqueue/Client/Driver/AmqpDriver.php
@@ -0,0 +1,132 @@
+setDeliveryMode(AmqpMessage::DELIVERY_MODE_PERSISTENT);
+ $transportMessage->setContentType($clientMessage->getContentType());
+
+ if ($clientMessage->getExpire()) {
+ $transportMessage->setExpiration($clientMessage->getExpire() * 1000);
+ }
+
+ $priorityMap = $this->getPriorityMap();
+ if ($priority = $clientMessage->getPriority()) {
+ if (false == array_key_exists($priority, $priorityMap)) {
+ throw new \InvalidArgumentException(sprintf('Cant convert client priority "%s" to transport one. Could be one of "%s"', $priority, implode('", "', array_keys($priorityMap))));
+ }
+
+ $transportMessage->setPriority($priorityMap[$priority]);
+ }
+
+ return $transportMessage;
+ }
+
+ public function setupBroker(?LoggerInterface $logger = null): void
+ {
+ $logger = $logger ?: new NullLogger();
+ $log = function ($text, ...$args) use ($logger) {
+ $logger->debug(sprintf('[AmqpDriver] '.$text, ...$args));
+ };
+
+ // setup router
+ $routerTopic = $this->createRouterTopic();
+ $log('Declare router exchange: %s', $routerTopic->getTopicName());
+ $this->getContext()->declareTopic($routerTopic);
+
+ $routerQueue = $this->createQueue($this->getConfig()->getRouterQueue());
+ $log('Declare router queue: %s', $routerQueue->getQueueName());
+ $this->getContext()->declareQueue($routerQueue);
+
+ $log('Bind router queue to exchange: %s -> %s', $routerQueue->getQueueName(), $routerTopic->getTopicName());
+ $this->getContext()->bind(new AmqpBind($routerTopic, $routerQueue, $routerQueue->getQueueName()));
+
+ // setup queues
+ $declaredQueues = [];
+ foreach ($this->getRouteCollection()->all() as $route) {
+ /** @var AmqpQueue $queue */
+ $queue = $this->createRouteQueue($route);
+ if (array_key_exists($queue->getQueueName(), $declaredQueues)) {
+ continue;
+ }
+
+ $log('Declare processor queue: %s', $queue->getQueueName());
+ $this->getContext()->declareQueue($queue);
+
+ $declaredQueues[$queue->getQueueName()] = true;
+ }
+ }
+
+ /**
+ * @return AmqpTopic
+ */
+ protected function createRouterTopic(): Destination
+ {
+ $topic = $this->doCreateTopic(
+ $this->createTransportRouterTopicName($this->getConfig()->getRouterTopic(), true)
+ );
+ $topic->setType(AmqpTopic::TYPE_FANOUT);
+ $topic->addFlag(AmqpTopic::FLAG_DURABLE);
+
+ return $topic;
+ }
+
+ /**
+ * @return AmqpQueue
+ */
+ protected function doCreateQueue(string $transportQueueName): InteropQueue
+ {
+ /** @var AmqpQueue $queue */
+ $queue = parent::doCreateQueue($transportQueueName);
+ $queue->addFlag(AmqpQueue::FLAG_DURABLE);
+
+ return $queue;
+ }
+
+ /**
+ * @param AmqpProducer $producer
+ * @param AmqpTopic $topic
+ * @param AmqpMessage $transportMessage
+ */
+ protected function doSendToRouter(InteropProducer $producer, Destination $topic, InteropMessage $transportMessage): void
+ {
+ // We should not handle priority, expiration, and delay at this stage.
+ // The router will take care of it while re-sending the message to the final destinations.
+ $transportMessage->setPriority(null);
+ $transportMessage->setExpiration(null);
+
+ $producer->send($topic, $transportMessage);
+ }
+}
diff --git a/pkg/enqueue/Client/Driver/DbalDriver.php b/pkg/enqueue/Client/Driver/DbalDriver.php
new file mode 100644
index 000000000..34875eff7
--- /dev/null
+++ b/pkg/enqueue/Client/Driver/DbalDriver.php
@@ -0,0 +1,29 @@
+debug(sprintf('[DbalDriver] '.$text, ...$args));
+ };
+
+ $log('Creating database table: "%s"', $this->getContext()->getTableName());
+ $this->getContext()->createDataBaseTable();
+ }
+}
diff --git a/pkg/enqueue/Client/Driver/FsDriver.php b/pkg/enqueue/Client/Driver/FsDriver.php
new file mode 100644
index 000000000..f578b172d
--- /dev/null
+++ b/pkg/enqueue/Client/Driver/FsDriver.php
@@ -0,0 +1,49 @@
+debug(sprintf('[FsDriver] '.$text, ...$args));
+ };
+
+ // setup router
+ $routerQueue = $this->createQueue($this->getConfig()->getRouterQueue());
+
+ $log('Declare router queue "%s" file: %s', $routerQueue->getQueueName(), $routerQueue->getFileInfo());
+ $this->getContext()->declareDestination($routerQueue);
+
+ // setup queues
+ $declaredQueues = [];
+ foreach ($this->getRouteCollection()->all() as $route) {
+ /** @var FsDestination $queue */
+ $queue = $this->createRouteQueue($route);
+ if (array_key_exists($queue->getQueueName(), $declaredQueues)) {
+ continue;
+ }
+
+ $log('Declare processor queue "%s" file: %s', $queue->getQueueName(), $queue->getFileInfo());
+ $this->getContext()->declareDestination($queue);
+
+ $declaredQueues[$queue->getQueueName()] = true;
+ }
+ }
+}
diff --git a/pkg/enqueue/Client/Driver/GenericDriver.php b/pkg/enqueue/Client/Driver/GenericDriver.php
new file mode 100644
index 000000000..d509677df
--- /dev/null
+++ b/pkg/enqueue/Client/Driver/GenericDriver.php
@@ -0,0 +1,278 @@
+context = $context;
+ $this->config = $config;
+ $this->routeCollection = $routeCollection;
+ }
+
+ public function sendToRouter(Message $message): DriverSendResult
+ {
+ if ($message->getProperty(Config::COMMAND)) {
+ throw new \LogicException('Command must not be send to router but go directly to its processor.');
+ }
+ if (false == $message->getProperty(Config::TOPIC)) {
+ throw new \LogicException('Topic name parameter is required but is not set');
+ }
+
+ $topic = $this->createRouterTopic();
+ $transportMessage = $this->createTransportMessage($message);
+ $producer = $this->getContext()->createProducer();
+
+ $this->doSendToRouter($producer, $topic, $transportMessage);
+
+ return new DriverSendResult($topic, $transportMessage);
+ }
+
+ public function sendToProcessor(Message $message): DriverSendResult
+ {
+ $topic = $message->getProperty(Config::TOPIC);
+ $command = $message->getProperty(Config::COMMAND);
+
+ /** @var InteropQueue $queue */
+ $queue = null;
+ $routerProcessor = $this->config->getRouterProcessor();
+ $processor = $message->getProperty(Config::PROCESSOR);
+ if ($topic && $processor && $processor !== $routerProcessor) {
+ $route = $this->routeCollection->topicAndProcessor($topic, $processor);
+ if (false == $route) {
+ throw new \LogicException(sprintf('There is no route for topic "%s" and processor "%s"', $topic, $processor));
+ }
+
+ $message->setProperty(Config::PROCESSOR, $route->getProcessor());
+ $queue = $this->createRouteQueue($route);
+ } elseif ($topic && (false == $processor || $processor === $routerProcessor)) {
+ $message->setProperty(Config::PROCESSOR, $routerProcessor);
+
+ $queue = $this->createQueue($this->config->getRouterQueue());
+ } elseif ($command) {
+ $route = $this->routeCollection->command($command);
+ if (false == $route) {
+ throw new \LogicException(sprintf('There is no route for command "%s".', $command));
+ }
+
+ $message->setProperty(Config::PROCESSOR, $route->getProcessor());
+ $queue = $this->createRouteQueue($route);
+ } else {
+ throw new \LogicException('Either topic or command parameter must be set.');
+ }
+
+ $transportMessage = $this->createTransportMessage($message);
+
+ $producer = $this->context->createProducer();
+
+ if (null !== $delay = $transportMessage->getProperty(Config::DELAY)) {
+ $producer->setDeliveryDelay($delay * 1000);
+ }
+
+ if (null !== $expire = $transportMessage->getProperty(Config::EXPIRE)) {
+ $producer->setTimeToLive($expire * 1000);
+ }
+
+ if (null !== $priority = $transportMessage->getProperty(Config::PRIORITY)) {
+ $priorityMap = $this->getPriorityMap();
+
+ $producer->setPriority($priorityMap[$priority]);
+ }
+
+ $this->doSendToProcessor($producer, $queue, $transportMessage);
+
+ return new DriverSendResult($queue, $transportMessage);
+ }
+
+ public function setupBroker(?LoggerInterface $logger = null): void
+ {
+ }
+
+ public function createQueue(string $clientQueueName, bool $prefix = true): InteropQueue
+ {
+ $transportName = $this->createTransportQueueName($clientQueueName, $prefix);
+
+ return $this->doCreateQueue($transportName);
+ }
+
+ public function createRouteQueue(Route $route): InteropQueue
+ {
+ $transportName = $this->createTransportQueueName(
+ $route->getQueue() ?: $this->config->getDefaultQueue(),
+ $route->isPrefixQueue()
+ );
+
+ return $this->doCreateQueue($transportName);
+ }
+
+ public function createTransportMessage(Message $clientMessage): InteropMessage
+ {
+ $headers = $clientMessage->getHeaders();
+ $properties = $clientMessage->getProperties();
+
+ $transportMessage = $this->context->createMessage();
+ $transportMessage->setBody($clientMessage->getBody());
+ $transportMessage->setHeaders($headers);
+ $transportMessage->setProperties($properties);
+ $transportMessage->setMessageId($clientMessage->getMessageId());
+ $transportMessage->setTimestamp($clientMessage->getTimestamp());
+ $transportMessage->setReplyTo($clientMessage->getReplyTo());
+ $transportMessage->setCorrelationId($clientMessage->getCorrelationId());
+
+ if ($contentType = $clientMessage->getContentType()) {
+ $transportMessage->setProperty(Config::CONTENT_TYPE, $contentType);
+ }
+
+ if ($priority = $clientMessage->getPriority()) {
+ $transportMessage->setProperty(Config::PRIORITY, $priority);
+ }
+
+ if ($expire = $clientMessage->getExpire()) {
+ $transportMessage->setProperty(Config::EXPIRE, $expire);
+ }
+
+ if ($delay = $clientMessage->getDelay()) {
+ $transportMessage->setProperty(Config::DELAY, $delay);
+ }
+
+ return $transportMessage;
+ }
+
+ public function createClientMessage(InteropMessage $transportMessage): Message
+ {
+ $clientMessage = new Message();
+
+ $clientMessage->setBody($transportMessage->getBody());
+ $clientMessage->setHeaders($transportMessage->getHeaders());
+ $clientMessage->setProperties($transportMessage->getProperties());
+ $clientMessage->setMessageId($transportMessage->getMessageId());
+ $clientMessage->setTimestamp($transportMessage->getTimestamp());
+ $clientMessage->setReplyTo($transportMessage->getReplyTo());
+ $clientMessage->setCorrelationId($transportMessage->getCorrelationId());
+
+ if ($contentType = $transportMessage->getProperty(Config::CONTENT_TYPE)) {
+ $clientMessage->setContentType($contentType);
+ }
+
+ if ($priority = $transportMessage->getProperty(Config::PRIORITY)) {
+ $clientMessage->setPriority($priority);
+ }
+
+ if ($delay = $transportMessage->getProperty(Config::DELAY)) {
+ $clientMessage->setDelay((int) $delay);
+ }
+
+ if ($expire = $transportMessage->getProperty(Config::EXPIRE)) {
+ $clientMessage->setExpire((int) $expire);
+ }
+
+ return $clientMessage;
+ }
+
+ public function getConfig(): Config
+ {
+ return $this->config;
+ }
+
+ public function getContext(): Context
+ {
+ return $this->context;
+ }
+
+ public function getRouteCollection(): RouteCollection
+ {
+ return $this->routeCollection;
+ }
+
+ protected function doSendToRouter(InteropProducer $producer, Destination $topic, InteropMessage $transportMessage): void
+ {
+ $producer->send($topic, $transportMessage);
+ }
+
+ protected function doSendToProcessor(InteropProducer $producer, InteropQueue $queue, InteropMessage $transportMessage): void
+ {
+ $producer->send($queue, $transportMessage);
+ }
+
+ protected function createRouterTopic(): Destination
+ {
+ return $this->createQueue($this->getConfig()->getRouterQueue());
+ }
+
+ protected function createTransportRouterTopicName(string $name, bool $prefix): string
+ {
+ $clientPrefix = $prefix ? $this->config->getPrefix() : '';
+
+ return strtolower(implode($this->config->getSeparator(), array_filter([$clientPrefix, $name])));
+ }
+
+ protected function createTransportQueueName(string $name, bool $prefix): string
+ {
+ $clientPrefix = $prefix ? $this->config->getPrefix() : '';
+ $clientAppName = $prefix ? $this->config->getApp() : '';
+
+ return strtolower(implode($this->config->getSeparator(), array_filter([$clientPrefix, $clientAppName, $name])));
+ }
+
+ protected function doCreateQueue(string $transportQueueName): InteropQueue
+ {
+ return $this->context->createQueue($transportQueueName);
+ }
+
+ protected function doCreateTopic(string $transportTopicName): InteropTopic
+ {
+ return $this->context->createTopic($transportTopicName);
+ }
+
+ /**
+ * [client message priority => transport message priority].
+ *
+ * @return int[]
+ */
+ protected function getPriorityMap(): array
+ {
+ return [
+ MessagePriority::VERY_LOW => 0,
+ MessagePriority::LOW => 1,
+ MessagePriority::NORMAL => 2,
+ MessagePriority::HIGH => 3,
+ MessagePriority::VERY_HIGH => 4,
+ ];
+ }
+}
diff --git a/pkg/enqueue/Client/Driver/GpsDriver.php b/pkg/enqueue/Client/Driver/GpsDriver.php
new file mode 100644
index 000000000..32d14f721
--- /dev/null
+++ b/pkg/enqueue/Client/Driver/GpsDriver.php
@@ -0,0 +1,64 @@
+debug(sprintf('[GpsDriver] '.$text, ...$args));
+ };
+
+ // setup router
+ $routerTopic = $this->createRouterTopic();
+ $routerQueue = $this->createQueue($this->getConfig()->getRouterQueue());
+
+ $log('Subscribe router topic to queue: %s -> %s', $routerTopic->getTopicName(), $routerQueue->getQueueName());
+ $this->getContext()->subscribe($routerTopic, $routerQueue);
+
+ // setup queues
+ $declaredQueues = [];
+ foreach ($this->getRouteCollection()->all() as $route) {
+ /** @var GpsQueue $queue */
+ $queue = $this->createRouteQueue($route);
+ if (array_key_exists($queue->getQueueName(), $declaredQueues)) {
+ continue;
+ }
+
+ $topic = $this->getContext()->createTopic($queue->getQueueName());
+
+ $log('Subscribe processor topic to queue: %s -> %s', $topic->getTopicName(), $queue->getQueueName());
+ $this->getContext()->subscribe($topic, $queue);
+
+ $declaredQueues[$queue->getQueueName()] = true;
+ }
+ }
+
+ /**
+ * @return GpsTopic
+ */
+ protected function createRouterTopic(): Destination
+ {
+ return $this->doCreateTopic(
+ $this->createTransportRouterTopicName($this->getConfig()->getRouterTopic(), true)
+ );
+ }
+}
diff --git a/pkg/enqueue/Client/Driver/MongodbDriver.php b/pkg/enqueue/Client/Driver/MongodbDriver.php
new file mode 100644
index 000000000..1c9cff4bc
--- /dev/null
+++ b/pkg/enqueue/Client/Driver/MongodbDriver.php
@@ -0,0 +1,30 @@
+debug(sprintf('[MongodbDriver] '.$text, ...$args));
+ };
+
+ $contextConfig = $this->getContext()->getConfig();
+ $log('Creating database and collection: "%s" "%s"', $contextConfig['dbname'], $contextConfig['collection_name']);
+ $this->getContext()->createCollection();
+ }
+}
diff --git a/pkg/enqueue/Client/Driver/RabbitMqDriver.php b/pkg/enqueue/Client/Driver/RabbitMqDriver.php
new file mode 100644
index 000000000..f215d555e
--- /dev/null
+++ b/pkg/enqueue/Client/Driver/RabbitMqDriver.php
@@ -0,0 +1,20 @@
+setArguments(['x-max-priority' => 4]);
+
+ return $queue;
+ }
+}
diff --git a/pkg/enqueue/Client/Driver/RabbitMqStompDriver.php b/pkg/enqueue/Client/Driver/RabbitMqStompDriver.php
new file mode 100644
index 000000000..7af2db850
--- /dev/null
+++ b/pkg/enqueue/Client/Driver/RabbitMqStompDriver.php
@@ -0,0 +1,191 @@
+management = $management;
+ }
+
+ /**
+ * @return StompMessage
+ */
+ public function createTransportMessage(Message $message): InteropMessage
+ {
+ $transportMessage = parent::createTransportMessage($message);
+
+ if ($message->getExpire()) {
+ $transportMessage->setHeader('expiration', (string) ($message->getExpire() * 1000));
+ }
+
+ if ($priority = $message->getPriority()) {
+ $priorityMap = $this->getPriorityMap();
+
+ if (false == array_key_exists($priority, $priorityMap)) {
+ throw new \LogicException(sprintf('Cant convert client priority to transport: "%s"', $priority));
+ }
+
+ $transportMessage->setHeader('priority', $priorityMap[$priority]);
+ }
+
+ if ($message->getDelay()) {
+ if (false == $this->getConfig()->getTransportOption('delay_plugin_installed', false)) {
+ throw new \LogicException('The message delaying is not supported. In order to use delay feature install RabbitMQ delay plugin.');
+ }
+
+ $transportMessage->setHeader('x-delay', (string) ($message->getDelay() * 1000));
+ }
+
+ return $transportMessage;
+ }
+
+ public function setupBroker(?LoggerInterface $logger = null): void
+ {
+ $logger = $logger ?: new NullLogger();
+ $log = function ($text, ...$args) use ($logger) {
+ $logger->debug(sprintf('[RabbitMqStompDriver] '.$text, ...$args));
+ };
+
+ if (false == $this->getConfig()->getTransportOption('management_plugin_installed', false)) {
+ $log('Could not setup broker. The option `management_plugin_installed` is not enabled. Please enable that option and install rabbit management plugin');
+
+ return;
+ }
+
+ // setup router
+ $routerExchange = $this->createTransportRouterTopicName($this->getConfig()->getRouterTopic(), true);
+ $log('Declare router exchange: %s', $routerExchange);
+ $this->management->declareExchange($routerExchange, [
+ 'type' => 'fanout',
+ 'durable' => true,
+ 'auto_delete' => false,
+ ]);
+
+ $routerQueue = $this->createTransportQueueName($this->getConfig()->getRouterQueue(), true);
+ $log('Declare router queue: %s', $routerQueue);
+ $this->management->declareQueue($routerQueue, [
+ 'auto_delete' => false,
+ 'durable' => true,
+ 'arguments' => [
+ 'x-max-priority' => 4,
+ ],
+ ]);
+
+ $log('Bind router queue to exchange: %s -> %s', $routerQueue, $routerExchange);
+ $this->management->bind($routerExchange, $routerQueue, $routerQueue);
+
+ // setup queues
+ foreach ($this->getRouteCollection()->all() as $route) {
+ $queue = $this->createRouteQueue($route);
+
+ $log('Declare processor queue: %s', $queue->getStompName());
+ $this->management->declareQueue($queue->getStompName(), [
+ 'auto_delete' => false,
+ 'durable' => true,
+ 'arguments' => [
+ 'x-max-priority' => 4,
+ ],
+ ]);
+ }
+
+ // setup delay exchanges
+ if ($this->getConfig()->getTransportOption('delay_plugin_installed', false)) {
+ foreach ($this->getRouteCollection()->all() as $route) {
+ $queue = $this->createRouteQueue($route);
+ $delayExchange = $queue->getStompName().'.delayed';
+
+ $log('Declare delay exchange: %s', $delayExchange);
+ $this->management->declareExchange($delayExchange, [
+ 'type' => 'x-delayed-message',
+ 'durable' => true,
+ 'auto_delete' => false,
+ 'arguments' => [
+ 'x-delayed-type' => 'direct',
+ ],
+ ]);
+
+ $log('Bind processor queue to delay exchange: %s -> %s', $queue->getStompName(), $delayExchange);
+ $this->management->bind($delayExchange, $queue->getStompName(), $queue->getStompName());
+ }
+ } else {
+ $log('Delay exchange and bindings are not setup. if you\'d like to use delays please install delay rabbitmq plugin and set delay_plugin_installed option to true');
+ }
+ }
+
+ /**
+ * @return StompDestination
+ */
+ protected function doCreateQueue(string $transportQueueName): InteropQueue
+ {
+ $queue = parent::doCreateQueue($transportQueueName);
+ $queue->setHeader('x-max-priority', 4);
+
+ return $queue;
+ }
+
+ /**
+ * @param StompProducer $producer
+ * @param StompDestination $topic
+ * @param StompMessage $transportMessage
+ */
+ protected function doSendToRouter(InteropProducer $producer, Destination $topic, InteropMessage $transportMessage): void
+ {
+ // We should not handle priority, expiration, and delay at this stage.
+ // The router will take care of it while re-sending the message to the final destinations.
+ $transportMessage->setHeader('expiration', null);
+ $transportMessage->setHeader('priority', null);
+ $transportMessage->setHeader('x-delay', null);
+
+ $producer->send($topic, $transportMessage);
+ }
+
+ /**
+ * @param StompProducer $producer
+ * @param StompDestination $destination
+ * @param StompMessage $transportMessage
+ */
+ protected function doSendToProcessor(InteropProducer $producer, InteropQueue $destination, InteropMessage $transportMessage): void
+ {
+ if ($delay = $transportMessage->getProperty(Config::DELAY)) {
+ $producer->setDeliveryDelay(null);
+ $destination = $this->createDelayedTopic($destination);
+ }
+
+ $producer->send($destination, $transportMessage);
+ }
+
+ private function createDelayedTopic(StompDestination $queue): StompDestination
+ {
+ // in order to use delay feature make sure the rabbitmq_delayed_message_exchange plugin is installed.
+ $destination = $this->getContext()->createTopic($queue->getStompName().'.delayed');
+ $destination->setType(StompDestination::TYPE_EXCHANGE);
+ $destination->setDurable(true);
+ $destination->setAutoDelete(false);
+ $destination->setRoutingKey($queue->getStompName());
+
+ return $destination;
+ }
+}
diff --git a/pkg/enqueue/Client/Driver/RdKafkaDriver.php b/pkg/enqueue/Client/Driver/RdKafkaDriver.php
new file mode 100644
index 000000000..2609e3f91
--- /dev/null
+++ b/pkg/enqueue/Client/Driver/RdKafkaDriver.php
@@ -0,0 +1,48 @@
+debug('[RdKafkaDriver] setup broker');
+ $log = function ($text, ...$args) use ($logger) {
+ $logger->debug(sprintf('[RdKafkaDriver] '.$text, ...$args));
+ };
+
+ // setup router
+ $routerQueue = $this->createQueue($this->getConfig()->getRouterQueue());
+ $log('Create router queue: %s', $routerQueue->getQueueName());
+ $this->getContext()->createConsumer($routerQueue);
+
+ // setup queues
+ $declaredQueues = [];
+ foreach ($this->getRouteCollection()->all() as $route) {
+ /** @var RdKafkaTopic $queue */
+ $queue = $this->createRouteQueue($route);
+ if (array_key_exists($queue->getQueueName(), $declaredQueues)) {
+ continue;
+ }
+
+ $log('Create processor queue: %s', $queue->getQueueName());
+ $this->getContext()->createConsumer($queue);
+ }
+ }
+}
diff --git a/pkg/enqueue/Client/Driver/RedisDriver.php b/pkg/enqueue/Client/Driver/RedisDriver.php
new file mode 100644
index 000000000..493cb7c96
--- /dev/null
+++ b/pkg/enqueue/Client/Driver/RedisDriver.php
@@ -0,0 +1,20 @@
+debug(sprintf('[SqsQsDriver] '.$text, ...$args));
+ };
+
+ // setup router
+ $routerTopic = $this->createRouterTopic();
+ $log('Declare router topic: %s', $routerTopic->getTopicName());
+ $this->getContext()->declareTopic($routerTopic);
+
+ $routerQueue = $this->createQueue($this->getConfig()->getRouterQueue());
+ $log('Declare router queue: %s', $routerQueue->getQueueName());
+ $this->getContext()->declareQueue($routerQueue);
+
+ $log('Bind router queue to topic: %s -> %s', $routerQueue->getQueueName(), $routerTopic->getTopicName());
+ $this->getContext()->bind($routerTopic, $routerQueue);
+
+ // setup queues
+ $declaredQueues = [];
+ $declaredTopics = [];
+ foreach ($this->getRouteCollection()->all() as $route) {
+ $queue = $this->createRouteQueue($route);
+ if (false === array_key_exists($queue->getQueueName(), $declaredQueues)) {
+ $log('Declare processor queue: %s', $queue->getQueueName());
+ $this->getContext()->declareQueue($queue);
+
+ $declaredQueues[$queue->getQueueName()] = true;
+ }
+
+ if ($route->isCommand()) {
+ continue;
+ }
+
+ $topic = $this->doCreateTopic($this->createTransportQueueName($route->getSource(), true));
+ if (false === array_key_exists($topic->getTopicName(), $declaredTopics)) {
+ $log('Declare processor topic: %s', $topic->getTopicName());
+ $this->getContext()->declareTopic($topic);
+
+ $declaredTopics[$topic->getTopicName()] = true;
+ }
+
+ $log('Bind processor queue to topic: %s -> %s', $queue->getQueueName(), $topic->getTopicName());
+ $this->getContext()->bind($topic, $queue);
+ }
+ }
+
+ protected function createRouterTopic(): Destination
+ {
+ return $this->doCreateTopic(
+ $this->createTransportRouterTopicName($this->getConfig()->getRouterTopic(), true)
+ );
+ }
+
+ protected function createTransportRouterTopicName(string $name, bool $prefix): string
+ {
+ $name = parent::createTransportRouterTopicName($name, $prefix);
+
+ return str_replace('.', '_dot_', $name);
+ }
+
+ protected function createTransportQueueName(string $name, bool $prefix): string
+ {
+ $name = parent::createTransportQueueName($name, $prefix);
+
+ return str_replace('.', '_dot_', $name);
+ }
+}
diff --git a/pkg/enqueue/Client/Driver/SqsDriver.php b/pkg/enqueue/Client/Driver/SqsDriver.php
new file mode 100644
index 000000000..49b696aae
--- /dev/null
+++ b/pkg/enqueue/Client/Driver/SqsDriver.php
@@ -0,0 +1,62 @@
+debug(sprintf('[SqsDriver] '.$text, ...$args));
+ };
+
+ // setup router
+ $routerQueue = $this->createQueue($this->getConfig()->getRouterQueue());
+ $log('Declare router queue: %s', $routerQueue->getQueueName());
+ $this->getContext()->declareQueue($routerQueue);
+
+ // setup queues
+ $declaredQueues = [];
+ foreach ($this->getRouteCollection()->all() as $route) {
+ /** @var SqsDestination $queue */
+ $queue = $this->createRouteQueue($route);
+ if (array_key_exists($queue->getQueueName(), $declaredQueues)) {
+ continue;
+ }
+
+ $log('Declare processor queue: %s', $queue->getQueueName());
+ $this->getContext()->declareQueue($queue);
+
+ $declaredQueues[$queue->getQueueName()] = true;
+ }
+ }
+
+ protected function createTransportRouterTopicName(string $name, bool $prefix): string
+ {
+ $name = parent::createTransportRouterTopicName($name, $prefix);
+
+ return str_replace('.', '_dot_', $name);
+ }
+
+ protected function createTransportQueueName(string $name, bool $prefix): string
+ {
+ $name = parent::createTransportQueueName($name, $prefix);
+
+ return str_replace('.', '_dot_', $name);
+ }
+}
diff --git a/pkg/enqueue/Client/Driver/StompDriver.php b/pkg/enqueue/Client/Driver/StompDriver.php
new file mode 100644
index 000000000..811ad76e7
--- /dev/null
+++ b/pkg/enqueue/Client/Driver/StompDriver.php
@@ -0,0 +1,71 @@
+debug('[StompDriver] Stomp protocol does not support broker configuration');
+ }
+
+ /**
+ * @return StompMessage
+ */
+ public function createTransportMessage(Message $message): InteropMessage
+ {
+ /** @var StompMessage $transportMessage */
+ $transportMessage = parent::createTransportMessage($message);
+ $transportMessage->setPersistent(true);
+
+ return $transportMessage;
+ }
+
+ /**
+ * @return StompDestination
+ */
+ protected function doCreateQueue(string $transportQueueName): InteropQueue
+ {
+ /** @var StompDestination $queue */
+ $queue = parent::doCreateQueue($transportQueueName);
+ $queue->setDurable(true);
+ $queue->setAutoDelete(false);
+ $queue->setExclusive(false);
+
+ return $queue;
+ }
+
+ /**
+ * @return StompDestination
+ */
+ protected function createRouterTopic(): Destination
+ {
+ /** @var StompDestination $topic */
+ $topic = $this->doCreateTopic(
+ $this->createTransportRouterTopicName($this->getConfig()->getRouterTopic(), true)
+ );
+ $topic->setDurable(true);
+ $topic->setAutoDelete(false);
+
+ return $topic;
+ }
+}
diff --git a/pkg/enqueue/Client/Driver/StompManagementClient.php b/pkg/enqueue/Client/Driver/StompManagementClient.php
new file mode 100644
index 000000000..0d64450dd
--- /dev/null
+++ b/pkg/enqueue/Client/Driver/StompManagementClient.php
@@ -0,0 +1,44 @@
+client = $client;
+ $this->vhost = $vhost;
+ }
+
+ public static function create(string $vhost = '/', string $host = 'localhost', int $port = 15672, string $login = 'guest', string $password = 'guest'): self
+ {
+ return new self(new Client(null, 'http://'.$host.':'.$port, $login, $password), $vhost);
+ }
+
+ public function declareQueue(string $name, array $options)
+ {
+ return $this->client->queues()->create($this->vhost, $name, $options);
+ }
+
+ public function declareExchange(string $name, array $options)
+ {
+ return $this->client->exchanges()->create($this->vhost, $name, $options);
+ }
+
+ public function bind(string $exchange, string $queue, ?string $routingKey = null, $arguments = null)
+ {
+ return $this->client->bindings()->create($this->vhost, $exchange, $queue, $routingKey, $arguments);
+ }
+}
diff --git a/pkg/enqueue/Client/DriverFactory.php b/pkg/enqueue/Client/DriverFactory.php
new file mode 100644
index 000000000..1d383ac86
--- /dev/null
+++ b/pkg/enqueue/Client/DriverFactory.php
@@ -0,0 +1,91 @@
+getTransportOption('dsn');
+
+ if (empty($dsn)) {
+ throw new \LogicException('This driver factory relies on dsn option from transport config. The option is empty or not set.');
+ }
+
+ $dsn = Dsn::parseFirst($dsn);
+
+ if ($driverInfo = $this->findDriverInfo($dsn, Resources::getAvailableDrivers())) {
+ $driverClass = $driverInfo['driverClass'];
+
+ if (RabbitMqStompDriver::class === $driverClass) {
+ return $this->createRabbitMqStompDriver($factory, $dsn, $config, $collection);
+ }
+
+ return new $driverClass($factory->createContext(), $config, $collection);
+ }
+
+ $knownDrivers = Resources::getKnownDrivers();
+ if ($driverInfo = $this->findDriverInfo($dsn, $knownDrivers)) {
+ throw new \LogicException(sprintf('To use given scheme "%s" a package has to be installed. Run "composer req %s" to add it.', $dsn->getScheme(), implode(' ', $driverInfo['packages'])));
+ }
+
+ throw new \LogicException(sprintf('A given scheme "%s" is not supported. Maybe it is a custom driver, make sure you registered it with "%s::addDriver".', $dsn->getScheme(), Resources::class));
+ }
+
+ private function findDriverInfo(Dsn $dsn, array $factories): ?array
+ {
+ $protocol = $dsn->getSchemeProtocol();
+
+ if ($dsn->getSchemeExtensions()) {
+ foreach ($factories as $info) {
+ if (empty($info['requiredSchemeExtensions'])) {
+ continue;
+ }
+
+ if (false == in_array($protocol, $info['schemes'], true)) {
+ continue;
+ }
+
+ $diff = array_diff($dsn->getSchemeExtensions(), $info['requiredSchemeExtensions']);
+ if (empty($diff)) {
+ return $info;
+ }
+ }
+ }
+
+ foreach ($factories as $driverClass => $info) {
+ if (false == empty($info['requiredSchemeExtensions'])) {
+ continue;
+ }
+
+ if (false == in_array($protocol, $info['schemes'], true)) {
+ continue;
+ }
+
+ return $info;
+ }
+
+ return null;
+ }
+
+ private function createRabbitMqStompDriver(ConnectionFactory $factory, Dsn $dsn, Config $config, RouteCollection $collection): RabbitMqStompDriver
+ {
+ $defaultManagementHost = $dsn->getHost() ?: $config->getTransportOption('host', 'localhost');
+ $managementVast = ltrim($dsn->getPath(), '/') ?: $config->getTransportOption('vhost', '/');
+
+ $managementClient = StompManagementClient::create(
+ urldecode($managementVast),
+ $config->getDriverOption('rabbitmq_management_host', $defaultManagementHost),
+ $config->getDriverOption('rabbitmq_management_port', 15672),
+ (string) $dsn->getUser() ?: $config->getTransportOption('user', 'guest'),
+ (string) $dsn->getPassword() ?: $config->getTransportOption('pass', 'guest')
+ );
+
+ return new RabbitMqStompDriver($factory->createContext(), $config, $collection, $managementClient);
+ }
+}
diff --git a/pkg/enqueue/Client/DriverFactoryInterface.php b/pkg/enqueue/Client/DriverFactoryInterface.php
new file mode 100644
index 000000000..698ad05a4
--- /dev/null
+++ b/pkg/enqueue/Client/DriverFactoryInterface.php
@@ -0,0 +1,10 @@
+message = $message;
+ $this->producer = $producer;
+ $this->driver = $driver;
+ }
+
+ public function getMessage(): Message
+ {
+ return $this->message;
+ }
+
+ public function getProducer(): ProducerInterface
+ {
+ return $this->producer;
+ }
+
+ public function getDriver(): DriverInterface
+ {
+ return $this->driver;
+ }
+
+ public function isEvent(): bool
+ {
+ return (bool) $this->message->getProperty(Config::TOPIC);
+ }
+
+ public function isCommand(): bool
+ {
+ return (bool) $this->message->getProperty(Config::COMMAND);
+ }
+
+ public function getCommand(): string
+ {
+ return $this->message->getProperty(Config::COMMAND);
+ }
+
+ public function getTopic(): string
+ {
+ return $this->message->getProperty(Config::TOPIC);
+ }
+}
diff --git a/pkg/enqueue/Client/DriverPreSendExtensionInterface.php b/pkg/enqueue/Client/DriverPreSendExtensionInterface.php
new file mode 100644
index 000000000..fd95c9328
--- /dev/null
+++ b/pkg/enqueue/Client/DriverPreSendExtensionInterface.php
@@ -0,0 +1,8 @@
+transportDestination = $transportDestination;
+ $this->transportMessage = $transportMessage;
+ }
+
+ public function getTransportDestination(): Destination
+ {
+ return $this->transportDestination;
+ }
+
+ public function getTransportMessage(): TransportMessage
+ {
+ return $this->transportMessage;
+ }
+}
diff --git a/pkg/enqueue/Client/Extension/PrepareBodyExtension.php b/pkg/enqueue/Client/Extension/PrepareBodyExtension.php
new file mode 100644
index 000000000..e7924548c
--- /dev/null
+++ b/pkg/enqueue/Client/Extension/PrepareBodyExtension.php
@@ -0,0 +1,51 @@
+prepareBody($context->getMessage());
+ }
+
+ public function onPreSendCommand(PreSend $context): void
+ {
+ $this->prepareBody($context->getMessage());
+ }
+
+ private function prepareBody(Message $message): void
+ {
+ $body = $message->getBody();
+ $contentType = $message->getContentType();
+
+ if (is_scalar($body) || null === $body) {
+ $contentType = $contentType ?: 'text/plain';
+ $body = (string) $body;
+ } elseif (is_array($body)) {
+ // only array of scalars is allowed.
+ array_walk_recursive($body, function ($value) {
+ if (!is_scalar($value) && null !== $value) {
+ throw new \LogicException(sprintf('The message\'s body must be an array of scalars. Found not scalar in the array: %s', is_object($value) ? $value::class : gettype($value)));
+ }
+ });
+
+ $contentType = $contentType ?: 'application/json';
+ $body = JSON::encode($body);
+ } elseif ($body instanceof \JsonSerializable) {
+ $contentType = $contentType ?: 'application/json';
+ $body = JSON::encode($body);
+ } else {
+ throw new \InvalidArgumentException(sprintf('The message\'s body must be either null, scalar, array or object (implements \JsonSerializable). Got: %s', is_object($body) ? $body::class : gettype($body)));
+ }
+
+ $message->setContentType($contentType);
+ $message->setBody($body);
+ }
+}
diff --git a/pkg/enqueue/Client/ExtensionInterface.php b/pkg/enqueue/Client/ExtensionInterface.php
index 4f9fd66ea..596b1b9af 100644
--- a/pkg/enqueue/Client/ExtensionInterface.php
+++ b/pkg/enqueue/Client/ExtensionInterface.php
@@ -2,21 +2,6 @@
namespace Enqueue\Client;
-interface ExtensionInterface
+interface ExtensionInterface extends PreSendEventExtensionInterface, PreSendCommandExtensionInterface, DriverPreSendExtensionInterface, PostSendExtensionInterface
{
- /**
- * @param string $topic
- * @param Message $message
- *
- * @return
- */
- public function onPreSend($topic, Message $message);
-
- /**
- * @param string $topic
- * @param Message $message
- *
- * @return
- */
- public function onPostSend($topic, Message $message);
}
diff --git a/pkg/enqueue/Client/Message.php b/pkg/enqueue/Client/Message.php
index d58371b38..7e51ea10d 100644
--- a/pkg/enqueue/Client/Message.php
+++ b/pkg/enqueue/Client/Message.php
@@ -7,12 +7,12 @@ class Message
/**
* @const string
*/
- const SCOPE_MESSAGE_BUS = 'enqueue.scope.message_bus';
+ public const SCOPE_MESSAGE_BUS = 'enqueue.scope.message_bus';
/**
* @const string
*/
- const SCOPE_APP = 'enqueue.scope.app';
+ public const SCOPE_APP = 'enqueue.scope.app';
/**
* @var string|null
@@ -88,7 +88,7 @@ public function __construct($body = '', array $properties = [], array $headers =
}
/**
- * @return null|string
+ * @return string|null
*/
public function getBody()
{
@@ -96,7 +96,7 @@ public function getBody()
}
/**
- * @param null|string|int|float|array|\JsonSerializable $body
+ * @param string|int|float|array|\JsonSerializable|null $body
*/
public function setBody($body)
{
@@ -205,18 +205,12 @@ public function setDelay($delay)
$this->delay = $delay;
}
- /**
- * @param string $scope
- */
- public function setScope($scope)
+ public function setScope(string $scope): void
{
$this->scope = $scope;
}
- /**
- * @return string
- */
- public function getScope()
+ public function getScope(): string
{
return $this->scope;
}
@@ -262,10 +256,8 @@ public function getHeaders()
}
/**
- * @param string $name
- * @param mixed $default
- *
- * @return mixed
+ * @param string $name
+ * @param mixed|null $default
*/
public function getHeader($name, $default = null)
{
@@ -274,16 +266,12 @@ public function getHeader($name, $default = null)
/**
* @param string $name
- * @param mixed $value
*/
public function setHeader($name, $value)
{
$this->headers[$name] = $value;
}
- /**
- * @param array $headers
- */
public function setHeaders(array $headers)
{
$this->headers = $headers;
@@ -297,19 +285,14 @@ public function getProperties()
return $this->properties;
}
- /**
- * @param array $properties
- */
public function setProperties(array $properties)
{
$this->properties = $properties;
}
/**
- * @param string $name
- * @param mixed $default
- *
- * @return mixed
+ * @param string $name
+ * @param mixed|null $default
*/
public function getProperty($name, $default = null)
{
@@ -318,7 +301,6 @@ public function getProperty($name, $default = null)
/**
* @param string $name
- * @param mixed $value
*/
public function setProperty($name, $value)
{
diff --git a/pkg/enqueue/Client/MessagePriority.php b/pkg/enqueue/Client/MessagePriority.php
index efa658c14..e14be9a7d 100644
--- a/pkg/enqueue/Client/MessagePriority.php
+++ b/pkg/enqueue/Client/MessagePriority.php
@@ -4,9 +4,9 @@
class MessagePriority
{
- const VERY_LOW = 'enqueue.message_queue.client.very_low_message_priority';
- const LOW = 'enqueue.message_queue.client.low_message_priority';
- const NORMAL = 'enqueue.message_queue.client.normal_message_priority';
- const HIGH = 'enqueue.message_queue.client.high_message_priority';
- const VERY_HIGH = 'enqueue.message_queue.client.very_high_message_priority';
+ public const VERY_LOW = 'enqueue.message_queue.client.very_low_message_priority';
+ public const LOW = 'enqueue.message_queue.client.low_message_priority';
+ public const NORMAL = 'enqueue.message_queue.client.normal_message_priority';
+ public const HIGH = 'enqueue.message_queue.client.high_message_priority';
+ public const VERY_HIGH = 'enqueue.message_queue.client.very_high_message_priority';
}
diff --git a/pkg/enqueue/Client/Meta/QueueMeta.php b/pkg/enqueue/Client/Meta/QueueMeta.php
deleted file mode 100644
index bee32bd81..000000000
--- a/pkg/enqueue/Client/Meta/QueueMeta.php
+++ /dev/null
@@ -1,57 +0,0 @@
-clientName = $clientName;
- $this->transportName = $transportName;
- $this->processors = $processors;
- }
-
- /**
- * @return string
- */
- public function getClientName()
- {
- return $this->clientName;
- }
-
- /**
- * @return string
- */
- public function getTransportName()
- {
- return $this->transportName;
- }
-
- /**
- * @return string[]
- */
- public function getProcessors()
- {
- return $this->processors;
- }
-}
diff --git a/pkg/enqueue/Client/Meta/QueueMetaRegistry.php b/pkg/enqueue/Client/Meta/QueueMetaRegistry.php
deleted file mode 100644
index 29c2d69a3..000000000
--- a/pkg/enqueue/Client/Meta/QueueMetaRegistry.php
+++ /dev/null
@@ -1,95 +0,0 @@
- [
- * 'transportName' => 'aTransportQueueName',
- * 'processors' => ['aFooProcessorName', 'aBarProcessorName'],
- * ]
- * ].
- *
- *
- * @param Config $config
- * @param array $meta
- */
- public function __construct(Config $config, array $meta)
- {
- $this->config = $config;
- $this->meta = $meta;
- }
-
- /**
- * @param string $queueName
- * @param string|null $transportName
- */
- public function add($queueName, $transportName = null)
- {
- $this->meta[$queueName] = [
- 'transportName' => $transportName,
- 'processors' => [],
- ];
- }
-
- /**
- * @param string $queueName
- * @param string $processorName
- */
- public function addProcessor($queueName, $processorName)
- {
- if (false == array_key_exists($queueName, $this->meta)) {
- $this->add($queueName);
- }
-
- $this->meta[$queueName]['processors'][] = $processorName;
- }
-
- /**
- * @param string $queueName
- *
- * @return QueueMeta
- */
- public function getQueueMeta($queueName)
- {
- if (false == array_key_exists($queueName, $this->meta)) {
- throw new \InvalidArgumentException(sprintf(
- 'The queue meta not found. Requested name `%s`',
- $queueName
- ));
- }
-
- $transportName = $this->config->createTransportQueueName($queueName);
-
- $meta = array_replace([
- 'processors' => [],
- 'transportName' => $transportName,
- ], array_filter($this->meta[$queueName]));
-
- return new QueueMeta($queueName, $meta['transportName'], $meta['processors']);
- }
-
- /**
- * @return \Generator|QueueMeta[]
- */
- public function getQueuesMeta()
- {
- foreach (array_keys($this->meta) as $queueName) {
- yield $this->getQueueMeta($queueName);
- }
- }
-}
diff --git a/pkg/enqueue/Client/Meta/TopicMeta.php b/pkg/enqueue/Client/Meta/TopicMeta.php
deleted file mode 100644
index abb0e33ed..000000000
--- a/pkg/enqueue/Client/Meta/TopicMeta.php
+++ /dev/null
@@ -1,57 +0,0 @@
-name = $name;
- $this->description = $description;
- $this->processors = $processors;
- }
-
- /**
- * @return string
- */
- public function getName()
- {
- return $this->name;
- }
-
- /**
- * @return string
- */
- public function getDescription()
- {
- return $this->description;
- }
-
- /**
- * @return string[]
- */
- public function getProcessors()
- {
- return $this->processors;
- }
-}
diff --git a/pkg/enqueue/Client/Meta/TopicMetaRegistry.php b/pkg/enqueue/Client/Meta/TopicMetaRegistry.php
deleted file mode 100644
index efceb9a11..000000000
--- a/pkg/enqueue/Client/Meta/TopicMetaRegistry.php
+++ /dev/null
@@ -1,80 +0,0 @@
- [
- * 'description' => 'A desc',
- * 'processors' => ['aProcessorNameFoo', 'aProcessorNameBar],
- * ],
- * ].
- *
- * @param array $meta
- */
- public function __construct(array $meta)
- {
- $this->meta = $meta;
- }
-
- /**
- * @param string $topicName
- * @param string $description
- */
- public function add($topicName, $description = null)
- {
- $this->meta[$topicName] = [
- 'description' => $description,
- 'processors' => [],
- ];
- }
-
- /**
- * @param string $topicName
- * @param string $processorName
- */
- public function addProcessor($topicName, $processorName)
- {
- if (false == array_key_exists($topicName, $this->meta)) {
- $this->add($topicName);
- }
-
- $this->meta[$topicName]['processors'][] = $processorName;
- }
-
- /**
- * @param string $topicName
- *
- * @return TopicMeta
- */
- public function getTopicMeta($topicName)
- {
- if (false == array_key_exists($topicName, $this->meta)) {
- throw new \InvalidArgumentException(sprintf('The topic meta not found. Requested name `%s`', $topicName));
- }
-
- $topic = array_replace([
- 'description' => '',
- 'processors' => [],
- ], $this->meta[$topicName]);
-
- return new TopicMeta($topicName, $topic['description'], $topic['processors']);
- }
-
- /**
- * @return \Generator|TopicMeta[]
- */
- public function getTopicsMeta()
- {
- foreach (array_keys($this->meta) as $topicName) {
- yield $this->getTopicMeta($topicName);
- }
- }
-}
diff --git a/pkg/enqueue/Client/PostSend.php b/pkg/enqueue/Client/PostSend.php
new file mode 100644
index 000000000..5d9526ea4
--- /dev/null
+++ b/pkg/enqueue/Client/PostSend.php
@@ -0,0 +1,78 @@
+message = $message;
+ $this->producer = $producer;
+ $this->driver = $driver;
+ $this->transportDestination = $transportDestination;
+ $this->transportMessage = $transportMessage;
+ }
+
+ public function getMessage(): Message
+ {
+ return $this->message;
+ }
+
+ public function getProducer(): ProducerInterface
+ {
+ return $this->producer;
+ }
+
+ public function getDriver(): DriverInterface
+ {
+ return $this->driver;
+ }
+
+ public function getTransportDestination(): Destination
+ {
+ return $this->transportDestination;
+ }
+
+ public function getTransportMessage(): TransportMessage
+ {
+ return $this->transportMessage;
+ }
+
+ public function isEvent(): bool
+ {
+ return (bool) $this->message->getProperty(Config::TOPIC);
+ }
+
+ public function isCommand(): bool
+ {
+ return (bool) $this->message->getProperty(Config::COMMAND);
+ }
+
+ public function getCommand(): string
+ {
+ return $this->message->getProperty(Config::COMMAND);
+ }
+
+ public function getTopic(): string
+ {
+ return $this->message->getProperty(Config::TOPIC);
+ }
+}
diff --git a/pkg/enqueue/Client/PostSendExtensionInterface.php b/pkg/enqueue/Client/PostSendExtensionInterface.php
new file mode 100644
index 000000000..dd3ca8b71
--- /dev/null
+++ b/pkg/enqueue/Client/PostSendExtensionInterface.php
@@ -0,0 +1,8 @@
+message = $message;
+ $this->commandOrTopic = $commandOrTopic;
+ $this->producer = $producer;
+ $this->driver = $driver;
+
+ $this->originalMessage = clone $message;
+ }
+
+ public function getCommand(): string
+ {
+ return $this->commandOrTopic;
+ }
+
+ public function getTopic(): string
+ {
+ return $this->commandOrTopic;
+ }
+
+ public function changeCommand(string $newCommand): void
+ {
+ $this->commandOrTopic = $newCommand;
+ }
+
+ public function changeTopic(string $newTopic): void
+ {
+ $this->commandOrTopic = $newTopic;
+ }
+
+ public function changeBody($body, ?string $contentType = null): void
+ {
+ $this->message->setBody($body);
+
+ if (null !== $contentType) {
+ $this->message->setContentType($contentType);
+ }
+ }
+
+ public function getMessage(): Message
+ {
+ return $this->message;
+ }
+
+ public function getOriginalMessage(): Message
+ {
+ return $this->originalMessage;
+ }
+
+ public function getProducer(): ProducerInterface
+ {
+ return $this->producer;
+ }
+
+ public function getDriver(): DriverInterface
+ {
+ return $this->driver;
+ }
+}
diff --git a/pkg/enqueue/Client/PreSendCommandExtensionInterface.php b/pkg/enqueue/Client/PreSendCommandExtensionInterface.php
new file mode 100644
index 000000000..cefec097f
--- /dev/null
+++ b/pkg/enqueue/Client/PreSendCommandExtensionInterface.php
@@ -0,0 +1,11 @@
+driver = $driver;
$this->rpcFactory = $rpcFactory;
- $this->extension = $extension ?: new ChainExtension([]);
+
+ $this->extension = $extension ?
+ new ChainExtension([$extension, new PrepareBodyExtension()]) :
+ new ChainExtension([new PrepareBodyExtension()])
+ ;
}
- /**
- * {@inheritdoc}
- */
- public function sendEvent($topic, $message)
+ public function sendEvent(string $topic, $message): void
{
if (false == $message instanceof Message) {
- $body = $message;
- $message = new Message();
- $message->setBody($body);
- }
-
- $this->prepareBody($message);
-
- $message->setProperty(Config::PARAMETER_TOPIC_NAME, $topic);
- $message->setProperty(self::TOPIC_09X, $topic);
-
- if (!$message->getMessageId()) {
- $message->setMessageId(UUID::generate());
- }
-
- if (!$message->getTimestamp()) {
- $message->setTimestamp(time());
- }
-
- if (!$message->getPriority()) {
- $message->setPriority(MessagePriority::NORMAL);
+ $message = new Message($message);
}
- if (Message::SCOPE_MESSAGE_BUS == $message->getScope()) {
- if ($message->getProperty(Config::PARAMETER_PROCESSOR_QUEUE_NAME)) {
- throw new \LogicException(sprintf('The %s property must not be set for messages that are sent to message bus.', Config::PARAMETER_PROCESSOR_QUEUE_NAME));
- }
- if ($message->getProperty(Config::PARAMETER_PROCESSOR_NAME)) {
- throw new \LogicException(sprintf('The %s property must not be set for messages that are sent to message bus.', Config::PARAMETER_PROCESSOR_NAME));
- }
+ $preSend = new PreSend($topic, $message, $this, $this->driver);
+ $this->extension->onPreSendEvent($preSend);
- $this->extension->onPreSend($topic, $message);
- $this->driver->sendToRouter($message);
- $this->extension->onPostSend($topic, $message);
- } elseif (Message::SCOPE_APP == $message->getScope()) {
- if (false == $message->getProperty(Config::PARAMETER_PROCESSOR_NAME)) {
- $message->setProperty(Config::PARAMETER_PROCESSOR_NAME, $this->driver->getConfig()->getRouterProcessorName());
- }
- if (false == $message->getProperty(Config::PARAMETER_PROCESSOR_QUEUE_NAME)) {
- $message->setProperty(Config::PARAMETER_PROCESSOR_QUEUE_NAME, $this->driver->getConfig()->getRouterQueueName());
- }
+ $message = $preSend->getMessage();
+ $message->setProperty(Config::TOPIC, $preSend->getTopic());
- $this->extension->onPreSend($topic, $message);
- $this->driver->sendToProcessor($message);
- $this->extension->onPostSend($topic, $message);
- } else {
- throw new \LogicException(sprintf('The message scope "%s" is not supported.', $message->getScope()));
- }
+ $this->doSend($message);
}
- /**
- * {@inheritdoc}
- */
- public function sendCommand($command, $message, $needReply = false)
+ public function sendCommand(string $command, $message, bool $needReply = false): ?Promise
{
if (false == $message instanceof Message) {
$message = new Message($message);
}
+ $preSend = new PreSend($command, $message, $this, $this->driver);
+ $this->extension->onPreSendCommand($preSend);
+
+ $command = $preSend->getCommand();
+ $message = $preSend->getMessage();
+
$deleteReplyQueue = false;
$replyTo = $message->getReplyTo();
@@ -124,12 +79,10 @@ public function sendCommand($command, $message, $needReply = false)
}
}
- $message->setProperty(Config::PARAMETER_TOPIC_NAME, Config::COMMAND_TOPIC);
- $message->setProperty(Config::PARAMETER_COMMAND_NAME, $command);
- $message->setProperty(self::COMMAND_09X, $command);
+ $message->setProperty(Config::COMMAND, $command);
$message->setScope(Message::SCOPE_APP);
- $this->sendEvent(Config::COMMAND_TOPIC, $message);
+ $this->doSend($message);
if ($needReply) {
$promise = $this->rpcFactory->createPromise($replyTo, $message->getCorrelationId(), 60000);
@@ -137,59 +90,38 @@ public function sendCommand($command, $message, $needReply = false)
return $promise;
}
- }
- /**
- * {@inheritdoc}
- */
- public function send($topic, $message)
- {
- $this->sendEvent($topic, $message);
+ return null;
}
- /**
- * @param Message $message
- */
- private function prepareBody(Message $message)
+ private function doSend(Message $message): void
{
- $body = $message->getBody();
- $contentType = $message->getContentType();
-
- if (is_scalar($body) || null === $body) {
- $contentType = $contentType ?: 'text/plain';
- $body = (string) $body;
- } elseif (is_array($body)) {
- if ($contentType && 'application/json' !== $contentType) {
- throw new \LogicException(sprintf('Content type "application/json" only allowed when body is array'));
- }
+ if (false === is_string($message->getBody())) {
+ throw new \LogicException(sprintf('The message body must be string at this stage, got "%s". Make sure you passed string as message or there is an extension that converts custom input to string.', is_object($message->getBody()) ? get_class($message->getBody()) : gettype($message->getBody())));
+ }
- // only array of scalars is allowed.
- array_walk_recursive($body, function ($value) {
- if (!is_scalar($value) && null !== $value) {
- throw new \LogicException(sprintf(
- 'The message\'s body must be an array of scalars. Found not scalar in the array: %s',
- is_object($value) ? get_class($value) : gettype($value)
- ));
- }
- });
-
- $contentType = 'application/json';
- $body = JSON::encode($body);
- } elseif ($body instanceof \JsonSerializable) {
- if ($contentType && 'application/json' !== $contentType) {
- throw new \LogicException(sprintf('Content type "application/json" only allowed when body is array'));
- }
+ if ($message->getProperty(Config::PROCESSOR)) {
+ throw new \LogicException(sprintf('The %s property must not be set.', Config::PROCESSOR));
+ }
+
+ if (!$message->getMessageId()) {
+ $message->setMessageId(UUID::generate());
+ }
+
+ if (!$message->getTimestamp()) {
+ $message->setTimestamp(time());
+ }
+
+ $this->extension->onDriverPreSend(new DriverPreSend($message, $this, $this->driver));
- $contentType = 'application/json';
- $body = JSON::encode($body);
+ if (Message::SCOPE_MESSAGE_BUS == $message->getScope()) {
+ $result = $this->driver->sendToRouter($message);
+ } elseif (Message::SCOPE_APP == $message->getScope()) {
+ $result = $this->driver->sendToProcessor($message);
} else {
- throw new \InvalidArgumentException(sprintf(
- 'The message\'s body must be either null, scalar, array or object (implements \JsonSerializable). Got: %s',
- is_object($body) ? get_class($body) : gettype($body)
- ));
+ throw new \LogicException(sprintf('The message scope "%s" is not supported.', $message->getScope()));
}
- $message->setContentType($contentType);
- $message->setBody($body);
+ $this->extension->onPostSend(new PostSend($message, $this, $this->driver, $result->getTransportDestination(), $result->getTransportMessage()));
}
}
diff --git a/pkg/enqueue/Client/ProducerInterface.php b/pkg/enqueue/Client/ProducerInterface.php
index 2fc829eb2..3c884808a 100644
--- a/pkg/enqueue/Client/ProducerInterface.php
+++ b/pkg/enqueue/Client/ProducerInterface.php
@@ -7,17 +7,21 @@
interface ProducerInterface
{
/**
- * @param string $topic
+ * The message could be pretty much everything as long as you have a client extension that transforms a body to string on onPreSendEvent.
+ *
* @param string|array|Message $message
+ *
+ * @throws \Exception
*/
- public function sendEvent($topic, $message);
+ public function sendEvent(string $topic, $message): void;
/**
- * @param string $command
+ * The message could be pretty much everything as long as you have a client extension that transforms a body to string on onPreSendCommand.
+ * The promise is returned if needReply argument is true.
+ *
* @param string|array|Message $message
- * @param bool $needReply
*
- * @return Promise|null the promise is returned if needReply argument is true
+ * @throws \Exception
*/
- public function sendCommand($command, $message, $needReply = false);
+ public function sendCommand(string $command, $message, bool $needReply = false): ?Promise;
}
diff --git a/pkg/enqueue/Client/Resources.php b/pkg/enqueue/Client/Resources.php
new file mode 100644
index 000000000..a5cc6847c
--- /dev/null
+++ b/pkg/enqueue/Client/Resources.php
@@ -0,0 +1,194 @@
+ [
+ * schemes => [schemes strings],
+ * package => package name,
+ * ].
+ *
+ * @var array
+ */
+ private static $knownDrivers;
+
+ private function __construct()
+ {
+ }
+
+ public static function getAvailableDrivers(): array
+ {
+ $map = self::getKnownDrivers();
+
+ $availableMap = [];
+ foreach ($map as $item) {
+ if (class_exists($item['driverClass'])) {
+ $availableMap[] = $item;
+ }
+ }
+
+ return $availableMap;
+ }
+
+ public static function getKnownDrivers(): array
+ {
+ if (null === self::$knownDrivers) {
+ $map = [];
+
+ $map[] = [
+ 'schemes' => ['amqp', 'amqps'],
+ 'driverClass' => AmqpDriver::class,
+ 'requiredSchemeExtensions' => [],
+ 'packages' => ['enqueue/enqueue', 'enqueue/amqp-bunny'],
+ ];
+ $map[] = [
+ 'schemes' => ['amqp', 'amqps'],
+ 'driverClass' => RabbitMqDriver::class,
+ 'requiredSchemeExtensions' => ['rabbitmq'],
+ 'packages' => ['enqueue/enqueue', 'enqueue/amqp-bunny'],
+ ];
+ $map[] = [
+ 'schemes' => ['file'],
+ 'driverClass' => FsDriver::class,
+ 'requiredSchemeExtensions' => [],
+ 'packages' => ['enqueue/enqueue', 'enqueue/fs'],
+ ];
+ $map[] = [
+ 'schemes' => ['null'],
+ 'driverClass' => GenericDriver::class,
+ 'requiredSchemeExtensions' => [],
+ 'packages' => ['enqueue/enqueue', 'enqueue/null'],
+ ];
+ $map[] = [
+ 'schemes' => ['gps'],
+ 'driverClass' => GpsDriver::class,
+ 'requiredSchemeExtensions' => [],
+ 'packages' => ['enqueue/enqueue', 'enqueue/gps'],
+ ];
+ $map[] = [
+ 'schemes' => ['redis', 'rediss'],
+ 'driverClass' => RedisDriver::class,
+ 'requiredSchemeExtensions' => [],
+ 'packages' => ['enqueue/enqueue', 'enqueue/redis'],
+ ];
+ $map[] = [
+ 'schemes' => ['sqs'],
+ 'driverClass' => SqsDriver::class,
+ 'requiredSchemeExtensions' => [],
+ 'packages' => ['enqueue/enqueue', 'enqueue/sqs'],
+ ];
+ $map[] = [
+ 'schemes' => ['sns'],
+ 'driverClass' => GenericDriver::class,
+ 'requiredSchemeExtensions' => [],
+ 'packages' => ['enqueue/enqueue', 'enqueue/sns'],
+ ];
+ $map[] = [
+ 'schemes' => ['snsqs'],
+ 'driverClass' => SnsQsDriver::class,
+ 'requiredSchemeExtensions' => [],
+ 'packages' => ['enqueue/enqueue', 'enqueue/sqs', 'enqueue/sns', 'enqueue/snsqs'],
+ ];
+ $map[] = [
+ 'schemes' => ['stomp'],
+ 'driverClass' => StompDriver::class,
+ 'requiredSchemeExtensions' => [],
+ 'packages' => ['enqueue/enqueue', 'enqueue/stomp'],
+ ];
+ $map[] = [
+ 'schemes' => ['stomp'],
+ 'driverClass' => RabbitMqStompDriver::class,
+ 'requiredSchemeExtensions' => ['rabbitmq'],
+ 'packages' => ['enqueue/enqueue', 'enqueue/stomp'],
+ ];
+ $map[] = [
+ 'schemes' => ['kafka', 'rdkafka'],
+ 'driverClass' => RdKafkaDriver::class,
+ 'requiredSchemeExtensions' => [],
+ 'packages' => ['enqueue/enqueue', 'enqueue/rdkafka'],
+ ];
+ $map[] = [
+ 'schemes' => ['mongodb'],
+ 'driverClass' => MongodbDriver::class,
+ 'requiredSchemeExtensions' => [],
+ 'packages' => ['enqueue/enqueue', 'enqueue/mongodb'],
+ ];
+ $map[] = [
+ 'schemes' => [
+ 'db2',
+ 'ibm-db2',
+ 'mssql',
+ 'sqlsrv',
+ 'mysql',
+ 'mysql2',
+ 'mysql',
+ 'pgsql',
+ 'postgres',
+ 'pgsql',
+ 'sqlite',
+ 'sqlite3',
+ 'sqlite',
+ ],
+ 'driverClass' => DbalDriver::class,
+ 'requiredSchemeExtensions' => [],
+ 'package' => ['enqueue/enqueue', 'enqueue/dbal'],
+ ];
+ $map[] = [
+ 'schemes' => ['gearman'],
+ 'driverClass' => GenericDriver::class,
+ 'requiredSchemeExtensions' => [],
+ 'package' => ['enqueue/enqueue', 'enqueue/gearman'],
+ ];
+ $map[] = [
+ 'schemes' => ['beanstalk'],
+ 'driverClass' => GenericDriver::class,
+ 'requiredSchemeExtensions' => [],
+ 'package' => ['enqueue/enqueue', 'enqueue/pheanstalk'],
+ ];
+
+ self::$knownDrivers = $map;
+ }
+
+ return self::$knownDrivers;
+ }
+
+ public static function addDriver(string $driverClass, array $schemes, array $requiredExtensions, array $packages): void
+ {
+ if (class_exists($driverClass)) {
+ if (false == (new \ReflectionClass($driverClass))->implementsInterface(DriverInterface::class)) {
+ throw new \InvalidArgumentException(sprintf('The driver class "%s" must implement "%s" interface.', $driverClass, DriverInterface::class));
+ }
+ }
+
+ if (empty($schemes)) {
+ throw new \InvalidArgumentException('Schemes could not be empty.');
+ }
+ if (empty($packages)) {
+ throw new \InvalidArgumentException('Packages could not be empty.');
+ }
+
+ self::getKnownDrivers();
+ self::$knownDrivers[] = [
+ 'schemes' => $schemes,
+ 'driverClass' => $driverClass,
+ 'requiredSchemeExtensions' => $requiredExtensions,
+ 'packages' => $packages,
+ ];
+ }
+}
diff --git a/pkg/enqueue/Client/Route.php b/pkg/enqueue/Client/Route.php
new file mode 100644
index 000000000..8b9e31e36
--- /dev/null
+++ b/pkg/enqueue/Client/Route.php
@@ -0,0 +1,114 @@
+source = $source;
+ $this->sourceType = $sourceType;
+ $this->processor = $processor;
+ $this->options = $options;
+ }
+
+ public function getSource(): string
+ {
+ return $this->source;
+ }
+
+ public function isCommand(): bool
+ {
+ return self::COMMAND === $this->sourceType;
+ }
+
+ public function isTopic(): bool
+ {
+ return self::TOPIC === $this->sourceType;
+ }
+
+ public function getProcessor(): string
+ {
+ return $this->processor;
+ }
+
+ public function isProcessorExclusive(): bool
+ {
+ return (bool) $this->getOption('exclusive', false);
+ }
+
+ public function isProcessorExternal(): bool
+ {
+ return (bool) $this->getOption('external', false);
+ }
+
+ public function getQueue(): ?string
+ {
+ return $this->getOption('queue');
+ }
+
+ public function isPrefixQueue(): bool
+ {
+ return (bool) $this->getOption('prefix_queue', true);
+ }
+
+ public function getOptions(): array
+ {
+ return $this->options;
+ }
+
+ public function getOption(string $name, $default = null)
+ {
+ return array_key_exists($name, $this->options) ? $this->options[$name] : $default;
+ }
+
+ public function toArray(): array
+ {
+ return array_replace($this->options, [
+ 'source' => $this->source,
+ 'source_type' => $this->sourceType,
+ 'processor' => $this->processor,
+ ]);
+ }
+
+ public static function fromArray(array $route): self
+ {
+ list(
+ 'source' => $source,
+ 'source_type' => $sourceType,
+ 'processor' => $processor) = $route;
+
+ unset($route['source'], $route['source_type'], $route['processor']);
+ $options = $route;
+
+ return new self($source, $sourceType, $processor, $options);
+ }
+}
diff --git a/pkg/enqueue/Client/RouteCollection.php b/pkg/enqueue/Client/RouteCollection.php
new file mode 100644
index 000000000..76bcbe451
--- /dev/null
+++ b/pkg/enqueue/Client/RouteCollection.php
@@ -0,0 +1,114 @@
+routes = $routes;
+ }
+
+ public function add(Route $route): void
+ {
+ $this->routes[] = $route;
+ $this->topicRoutes = null;
+ $this->commandRoutes = null;
+ }
+
+ /**
+ * @return Route[]
+ */
+ public function all(): array
+ {
+ return $this->routes;
+ }
+
+ /**
+ * @return Route[]
+ */
+ public function command(string $command): ?Route
+ {
+ if (null === $this->commandRoutes) {
+ $commandRoutes = [];
+ foreach ($this->routes as $route) {
+ if ($route->isCommand()) {
+ $commandRoutes[$route->getSource()] = $route;
+ }
+ }
+
+ $this->commandRoutes = $commandRoutes;
+ }
+
+ return array_key_exists($command, $this->commandRoutes) ? $this->commandRoutes[$command] : null;
+ }
+
+ /**
+ * @return Route[]
+ */
+ public function topic(string $topic): array
+ {
+ if (null === $this->topicRoutes) {
+ $topicRoutes = [];
+ foreach ($this->routes as $route) {
+ if ($route->isTopic()) {
+ $topicRoutes[$route->getSource()][$route->getProcessor()] = $route;
+ }
+ }
+
+ $this->topicRoutes = $topicRoutes;
+ }
+
+ return array_key_exists($topic, $this->topicRoutes) ? $this->topicRoutes[$topic] : [];
+ }
+
+ public function topicAndProcessor(string $topic, string $processor): ?Route
+ {
+ $routes = $this->topic($topic);
+ foreach ($routes as $route) {
+ if ($route->getProcessor() === $processor) {
+ return $route;
+ }
+ }
+
+ return null;
+ }
+
+ public function toArray(): array
+ {
+ $rawRoutes = [];
+ foreach ($this->routes as $route) {
+ $rawRoutes[] = $route->toArray();
+ }
+
+ return $rawRoutes;
+ }
+
+ public static function fromArray(array $rawRoutes): self
+ {
+ $routes = [];
+ foreach ($rawRoutes as $rawRoute) {
+ $routes[] = Route::fromArray($rawRoute);
+ }
+
+ return new self($routes);
+ }
+}
diff --git a/pkg/enqueue/Client/RouterProcessor.php b/pkg/enqueue/Client/RouterProcessor.php
index 35efe1b02..c441ceb8b 100644
--- a/pkg/enqueue/Client/RouterProcessor.php
+++ b/pkg/enqueue/Client/RouterProcessor.php
@@ -3,119 +3,62 @@
namespace Enqueue\Client;
use Enqueue\Consumption\Result;
-use Interop\Queue\PsrContext;
-use Interop\Queue\PsrMessage;
-use Interop\Queue\PsrProcessor;
+use Interop\Queue\Context;
+use Interop\Queue\Message as InteropMessage;
+use Interop\Queue\Processor;
-class RouterProcessor implements PsrProcessor
+final class RouterProcessor implements Processor
{
/**
- * @var DriverInterface
- */
- private $driver;
-
- /**
- * @var array
+ * compatibility with 0.8x.
*/
- private $eventRoutes;
+ private const COMMAND_TOPIC_08X = '__command__';
/**
- * @var array
+ * @var DriverInterface
*/
- private $commandRoutes;
+ private $driver;
- /**
- * @param DriverInterface $driver
- * @param array $eventRoutes
- * @param array $commandRoutes
- */
- public function __construct(DriverInterface $driver, array $eventRoutes = [], array $commandRoutes = [])
+ public function __construct(DriverInterface $driver)
{
$this->driver = $driver;
-
- $this->eventRoutes = $eventRoutes;
- $this->commandRoutes = $commandRoutes;
}
- /**
- * @param string $topicName
- * @param string $queueName
- * @param string $processorName
- */
- public function add($topicName, $queueName, $processorName)
+ public function process(InteropMessage $message, Context $context): Result
{
- if (Config::COMMAND_TOPIC === $topicName) {
- $this->commandRoutes[$processorName] = $queueName;
- } else {
- $this->eventRoutes[$topicName][] = [$processorName, $queueName];
+ // compatibility with 0.8x
+ if (self::COMMAND_TOPIC_08X === $message->getProperty(Config::TOPIC)) {
+ $clientMessage = $this->driver->createClientMessage($message);
+ $clientMessage->setProperty(Config::TOPIC, null);
+
+ $this->driver->sendToProcessor($clientMessage);
+
+ return Result::ack('Legacy 0.8x message routed to processor');
}
- }
+ // compatibility with 0.8x
- /**
- * {@inheritdoc}
- */
- public function process(PsrMessage $message, PsrContext $context)
- {
- $topicName = $message->getProperty(Config::PARAMETER_TOPIC_NAME);
- if (false == $topicName) {
+ if ($message->getProperty(Config::COMMAND)) {
return Result::reject(sprintf(
- 'Got message without required parameter: "%s"',
- Config::PARAMETER_TOPIC_NAME
+ 'Unexpected command "%s" got. Command must not go to the router.',
+ $message->getProperty(Config::COMMAND)
));
}
- if (Config::COMMAND_TOPIC === $topicName) {
- return $this->routeCommand($message);
+ $topic = $message->getProperty(Config::TOPIC);
+ if (false == $topic) {
+ return Result::reject(sprintf('Topic property "%s" is required but not set or empty.', Config::TOPIC));
}
- return $this->routeEvent($message);
- }
-
- /**
- * @param PsrMessage $message
- *
- * @return string|Result
- */
- private function routeEvent(PsrMessage $message)
- {
- $topicName = $message->getProperty(Config::PARAMETER_TOPIC_NAME);
-
- if (array_key_exists($topicName, $this->eventRoutes)) {
- foreach ($this->eventRoutes[$topicName] as $route) {
- $processorMessage = clone $message;
- $processorMessage->setProperty(Config::PARAMETER_PROCESSOR_NAME, $route[0]);
- $processorMessage->setProperty(Config::PARAMETER_PROCESSOR_QUEUE_NAME, $route[1]);
-
- $this->driver->sendToProcessor($this->driver->createClientMessage($processorMessage));
- }
- }
-
- return self::ACK;
- }
-
- /**
- * @param PsrMessage $message
- *
- * @return string|Result
- */
- private function routeCommand(PsrMessage $message)
- {
- $commandName = $message->getProperty(Config::PARAMETER_COMMAND_NAME);
- if (false == $commandName) {
- return Result::reject(sprintf(
- 'Got message without required parameter: "%s"',
- Config::PARAMETER_COMMAND_NAME
- ));
- }
+ $count = 0;
+ foreach ($this->driver->getRouteCollection()->topic($topic) as $route) {
+ $clientMessage = $this->driver->createClientMessage($message);
+ $clientMessage->setProperty(Config::PROCESSOR, $route->getProcessor());
- if (isset($this->commandRoutes[$commandName])) {
- $processorMessage = clone $message;
- $processorMessage->setProperty(Config::PARAMETER_PROCESSOR_QUEUE_NAME, $this->commandRoutes[$commandName]);
- $processorMessage->setProperty(Config::PARAMETER_PROCESSOR_NAME, $commandName);
+ $this->driver->sendToProcessor($clientMessage);
- $this->driver->sendToProcessor($this->driver->createClientMessage($processorMessage));
+ ++$count;
}
- return self::ACK;
+ return Result::ack(sprintf('Routed to "%d" event subscribers', $count));
}
}
diff --git a/pkg/enqueue/Client/SpoolProducer.php b/pkg/enqueue/Client/SpoolProducer.php
index c5388770f..8ad0940f5 100644
--- a/pkg/enqueue/Client/SpoolProducer.php
+++ b/pkg/enqueue/Client/SpoolProducer.php
@@ -2,6 +2,8 @@
namespace Enqueue\Client;
+use Enqueue\Rpc\Promise;
+
class SpoolProducer implements ProducerInterface
{
/**
@@ -19,9 +21,6 @@ class SpoolProducer implements ProducerInterface
*/
private $commands;
- /**
- * @param ProducerInterface $realProducer
- */
public function __construct(ProducerInterface $realProducer)
{
$this->realProducer = $realProducer;
@@ -30,38 +29,26 @@ public function __construct(ProducerInterface $realProducer)
$this->commands = new \SplQueue();
}
- /**
- * {@inheritdoc}
- */
- public function sendCommand($command, $message, $needReply = false)
+ public function sendCommand(string $command, $message, bool $needReply = false): ?Promise
{
if ($needReply) {
return $this->realProducer->sendCommand($command, $message, $needReply);
}
$this->commands->enqueue([$command, $message]);
- }
- /**
- * {@inheritdoc}
- */
- public function sendEvent($topic, $message)
- {
- $this->events->enqueue([$topic, $message]);
+ return null;
}
- /**
- * {@inheritdoc}
- */
- public function send($topic, $message)
+ public function sendEvent(string $topic, $message): void
{
- $this->sendEvent($topic, $message);
+ $this->events->enqueue([$topic, $message]);
}
/**
* When it is called it sends all previously queued messages.
*/
- public function flush()
+ public function flush(): void
{
while (false == $this->events->isEmpty()) {
list($topic, $message) = $this->events->dequeue();
diff --git a/pkg/enqueue/Client/TopicSubscriberInterface.php b/pkg/enqueue/Client/TopicSubscriberInterface.php
index bdaa43f61..849a7827f 100644
--- a/pkg/enqueue/Client/TopicSubscriberInterface.php
+++ b/pkg/enqueue/Client/TopicSubscriberInterface.php
@@ -7,21 +7,35 @@ interface TopicSubscriberInterface
/**
* The result maybe either:.
*
- * ['aTopicName']
+ * 'aTopicName'
*
* or
*
- * ['aTopicName' => [
- * 'processorName' => 'processor',
- * 'queueName' => 'a_client_queue_name',
- * 'queueNameHardcoded' => true,
- * ]]
+ * ['aTopicName', 'anotherTopicName']
*
- * processorName, queueName and queueNameHardcoded are optional.
+ * or
+ *
+ * [
+ * [
+ * 'topic' => 'aTopicName',
+ * 'processor' => 'fooProcessor',
+ * 'queue' => 'a_client_queue_name',
+ *
+ * 'aCustomOption' => 'aVal',
+ * ],
+ * [
+ * 'topic' => 'anotherTopicName',
+ * 'processor' => 'barProcessor',
+ * 'queue' => 'a_client_queue_name',
+ *
+ * 'aCustomOption' => 'aVal',
+ * ],
+ * ]
*
- * Note: If you set queueNameHardcoded to true then the queueName is used as is and therefor the driver is not used to create a transport queue name.
+ * Note: If you set prefix_queue to true then the queue is used as is and therefor the driver is not used to prepare a transport queue name.
+ * It is possible to pass other options, they could be accessible on a route instance through options.
*
- * @return array
+ * @return string|array
*/
public static function getSubscribedTopics();
}
diff --git a/pkg/enqueue/Client/TraceableProducer.php b/pkg/enqueue/Client/TraceableProducer.php
index cd55a91d6..b0bd613c3 100644
--- a/pkg/enqueue/Client/TraceableProducer.php
+++ b/pkg/enqueue/Client/TraceableProducer.php
@@ -2,61 +2,42 @@
namespace Enqueue\Client;
-class TraceableProducer implements ProducerInterface
+use Enqueue\Rpc\Promise;
+
+final class TraceableProducer implements ProducerInterface
{
/**
* @var array
*/
- protected $traces = [];
+ private $traces = [];
+
/**
* @var ProducerInterface
*/
private $producer;
- /**
- * @param ProducerInterface $producer
- */
public function __construct(ProducerInterface $producer)
{
$this->producer = $producer;
}
- /**
- * {@inheritdoc}
- */
- public function sendEvent($topic, $message)
+ public function sendEvent(string $topic, $message): void
{
$this->producer->sendEvent($topic, $message);
$this->collectTrace($topic, null, $message);
}
- /**
- * {@inheritdoc}
- */
- public function sendCommand($command, $message, $needReply = false)
+ public function sendCommand(string $command, $message, bool $needReply = false): ?Promise
{
$result = $this->producer->sendCommand($command, $message, $needReply);
- $this->collectTrace(Config::COMMAND_TOPIC, $command, $message);
+ $this->collectTrace(null, $command, $message);
return $result;
}
- /**
- * {@inheritdoc}
- */
- public function send($topic, $message)
- {
- $this->sendEvent($topic, $message);
- }
-
- /**
- * @param string $topic
- *
- * @return array
- */
- public function getTopicTraces($topic)
+ public function getTopicTraces(string $topic): array
{
$topicTraces = [];
foreach ($this->traces as $trace) {
@@ -68,12 +49,7 @@ public function getTopicTraces($topic)
return $topicTraces;
}
- /**
- * @param string $command
- *
- * @return array
- */
- public function getCommandTraces($command)
+ public function getCommandTraces(string $command): array
{
$commandTraces = [];
foreach ($this->traces as $trace) {
@@ -85,25 +61,17 @@ public function getCommandTraces($command)
return $commandTraces;
}
- /**
- * @return array
- */
- public function getTraces()
+ public function getTraces(): array
{
return $this->traces;
}
- public function clearTraces()
+ public function clearTraces(): void
{
$this->traces = [];
}
- /**
- * @param string|null $topic
- * @param string|null $command
- * @param mixed $message
- */
- private function collectTrace($topic, $command, $message)
+ private function collectTrace(?string $topic, ?string $command, $message): void
{
$trace = [
'topic' => $topic,
@@ -117,7 +85,9 @@ private function collectTrace($topic, $command, $message)
'timestamp' => null,
'contentType' => null,
'messageId' => null,
+ 'sentAt' => (new \DateTime())->format('Y-m-d H:i:s.u'),
];
+
if ($message instanceof Message) {
$trace['body'] = $message->getBody();
$trace['headers'] = $message->getHeaders();
diff --git a/pkg/enqueue/ConnectionFactoryFactory.php b/pkg/enqueue/ConnectionFactoryFactory.php
new file mode 100644
index 000000000..d23518c1b
--- /dev/null
+++ b/pkg/enqueue/ConnectionFactoryFactory.php
@@ -0,0 +1,69 @@
+ $config];
+ }
+
+ if (false == is_array($config)) {
+ throw new \InvalidArgumentException('The config must be either array or DSN string.');
+ }
+
+ if (false == array_key_exists('dsn', $config)) {
+ throw new \InvalidArgumentException('The config must have dsn key set.');
+ }
+
+ $dsn = Dsn::parseFirst($config['dsn']);
+
+ if ($factoryClass = $this->findFactoryClass($dsn, Resources::getAvailableConnections())) {
+ return new $factoryClass(1 === count($config) ? $config['dsn'] : $config);
+ }
+
+ $knownConnections = Resources::getKnownConnections();
+ if ($factoryClass = $this->findFactoryClass($dsn, $knownConnections)) {
+ throw new \LogicException(sprintf('To use given scheme "%s" a package has to be installed. Run "composer req %s" to add it.', $dsn->getScheme(), $knownConnections[$factoryClass]['package']));
+ }
+
+ throw new \LogicException(sprintf('A given scheme "%s" is not supported. Maybe it is a custom connection, make sure you registered it with "%s::addConnection".', $dsn->getScheme(), Resources::class));
+ }
+
+ private function findFactoryClass(Dsn $dsn, array $factories): ?string
+ {
+ $protocol = $dsn->getSchemeProtocol();
+
+ if ($dsn->getSchemeExtensions()) {
+ foreach ($factories as $connectionClass => $info) {
+ if (empty($info['supportedSchemeExtensions'])) {
+ continue;
+ }
+
+ if (false == in_array($protocol, $info['schemes'], true)) {
+ continue;
+ }
+
+ $diff = array_diff($info['supportedSchemeExtensions'], $dsn->getSchemeExtensions());
+ if (empty($diff)) {
+ return $connectionClass;
+ }
+ }
+ }
+
+ foreach ($factories as $driverClass => $info) {
+ if (false == in_array($protocol, $info['schemes'], true)) {
+ continue;
+ }
+
+ return $driverClass;
+ }
+
+ return null;
+ }
+}
diff --git a/pkg/enqueue/ConnectionFactoryFactoryInterface.php b/pkg/enqueue/ConnectionFactoryFactoryInterface.php
new file mode 100644
index 000000000..f4ca4a6d3
--- /dev/null
+++ b/pkg/enqueue/ConnectionFactoryFactoryInterface.php
@@ -0,0 +1,21 @@
+queue = $queue;
+ $this->processor = $processor;
+ }
+
+ public function getQueue(): Queue
+ {
+ return $this->queue;
+ }
+
+ public function getProcessor(): Processor
+ {
+ return $this->processor;
+ }
+}
diff --git a/pkg/enqueue/Consumption/CallbackProcessor.php b/pkg/enqueue/Consumption/CallbackProcessor.php
index b002235ba..d15978fcb 100644
--- a/pkg/enqueue/Consumption/CallbackProcessor.php
+++ b/pkg/enqueue/Consumption/CallbackProcessor.php
@@ -2,29 +2,23 @@
namespace Enqueue\Consumption;
-use Interop\Queue\PsrContext;
-use Interop\Queue\PsrMessage;
-use Interop\Queue\PsrProcessor;
+use Interop\Queue\Context;
+use Interop\Queue\Message as InteropMessage;
+use Interop\Queue\Processor;
-class CallbackProcessor implements PsrProcessor
+class CallbackProcessor implements Processor
{
/**
* @var callable
*/
private $callback;
- /**
- * @param callable $callback
- */
public function __construct(callable $callback)
{
$this->callback = $callback;
}
- /**
- * {@inheritdoc}
- */
- public function process(PsrMessage $message, PsrContext $context)
+ public function process(InteropMessage $message, Context $context)
{
return call_user_func($this->callback, $message, $context);
}
diff --git a/pkg/enqueue/Consumption/ChainExtension.php b/pkg/enqueue/Consumption/ChainExtension.php
index d7a24adc7..83b4eba3a 100644
--- a/pkg/enqueue/Consumption/ChainExtension.php
+++ b/pkg/enqueue/Consumption/ChainExtension.php
@@ -2,90 +2,193 @@
namespace Enqueue\Consumption;
+use Enqueue\Consumption\Context\End;
+use Enqueue\Consumption\Context\InitLogger;
+use Enqueue\Consumption\Context\MessageReceived;
+use Enqueue\Consumption\Context\MessageResult;
+use Enqueue\Consumption\Context\PostConsume;
+use Enqueue\Consumption\Context\PostMessageReceived;
+use Enqueue\Consumption\Context\PreConsume;
+use Enqueue\Consumption\Context\PreSubscribe;
+use Enqueue\Consumption\Context\ProcessorException;
+use Enqueue\Consumption\Context\Start;
+
class ChainExtension implements ExtensionInterface
{
- use EmptyExtensionTrait;
-
- /**
- * @var ExtensionInterface[]
- */
- private $extensions;
+ private $startExtensions;
+ private $initLoggerExtensions;
+ private $preSubscribeExtensions;
+ private $preConsumeExtensions;
+ private $messageReceivedExtensions;
+ private $messageResultExtensions;
+ private $postMessageReceivedExtensions;
+ private $processorExceptionExtensions;
+ private $postConsumeExtensions;
+ private $endExtensions;
- /**
- * @param ExtensionInterface[] $extensions
- */
public function __construct(array $extensions)
{
- $this->extensions = $extensions;
+ $this->startExtensions = [];
+ $this->initLoggerExtensions = [];
+ $this->preSubscribeExtensions = [];
+ $this->preConsumeExtensions = [];
+ $this->messageReceivedExtensions = [];
+ $this->messageResultExtensions = [];
+ $this->postMessageReceivedExtensions = [];
+ $this->processorExceptionExtensions = [];
+ $this->postConsumeExtensions = [];
+ $this->endExtensions = [];
+
+ array_walk($extensions, function ($extension) {
+ if ($extension instanceof ExtensionInterface) {
+ $this->startExtensions[] = $extension;
+ $this->initLoggerExtensions[] = $extension;
+ $this->preSubscribeExtensions[] = $extension;
+ $this->preConsumeExtensions[] = $extension;
+ $this->messageReceivedExtensions[] = $extension;
+ $this->messageResultExtensions[] = $extension;
+ $this->postMessageReceivedExtensions[] = $extension;
+ $this->processorExceptionExtensions[] = $extension;
+ $this->postConsumeExtensions[] = $extension;
+ $this->endExtensions[] = $extension;
+
+ return;
+ }
+
+ $extensionValid = false;
+ if ($extension instanceof StartExtensionInterface) {
+ $this->startExtensions[] = $extension;
+
+ $extensionValid = true;
+ }
+
+ if ($extension instanceof InitLoggerExtensionInterface) {
+ $this->initLoggerExtensions[] = $extension;
+
+ $extensionValid = true;
+ }
+
+ if ($extension instanceof PreSubscribeExtensionInterface) {
+ $this->preSubscribeExtensions[] = $extension;
+
+ $extensionValid = true;
+ }
+
+ if ($extension instanceof PreConsumeExtensionInterface) {
+ $this->preConsumeExtensions[] = $extension;
+
+ $extensionValid = true;
+ }
+
+ if ($extension instanceof MessageReceivedExtensionInterface) {
+ $this->messageReceivedExtensions[] = $extension;
+
+ $extensionValid = true;
+ }
+
+ if ($extension instanceof MessageResultExtensionInterface) {
+ $this->messageResultExtensions[] = $extension;
+
+ $extensionValid = true;
+ }
+
+ if ($extension instanceof ProcessorExceptionExtensionInterface) {
+ $this->processorExceptionExtensions[] = $extension;
+
+ $extensionValid = true;
+ }
+
+ if ($extension instanceof PostMessageReceivedExtensionInterface) {
+ $this->postMessageReceivedExtensions[] = $extension;
+
+ $extensionValid = true;
+ }
+
+ if ($extension instanceof PostConsumeExtensionInterface) {
+ $this->postConsumeExtensions[] = $extension;
+
+ $extensionValid = true;
+ }
+
+ if ($extension instanceof EndExtensionInterface) {
+ $this->endExtensions[] = $extension;
+
+ $extensionValid = true;
+ }
+
+ if (false == $extensionValid) {
+ throw new \LogicException(sprintf('Invalid extension given %s', $extension::class));
+ }
+ });
+ }
+
+ public function onInitLogger(InitLogger $context): void
+ {
+ foreach ($this->initLoggerExtensions as $extension) {
+ $extension->onInitLogger($context);
+ }
}
- /**
- * @param Context $context
- */
- public function onStart(Context $context)
+ public function onStart(Start $context): void
{
- foreach ($this->extensions as $extension) {
+ foreach ($this->startExtensions as $extension) {
$extension->onStart($context);
}
}
- /**
- * @param Context $context
- */
- public function onBeforeReceive(Context $context)
+ public function onPreSubscribe(PreSubscribe $context): void
+ {
+ foreach ($this->preSubscribeExtensions as $extension) {
+ $extension->onPreSubscribe($context);
+ }
+ }
+
+ public function onPreConsume(PreConsume $context): void
{
- foreach ($this->extensions as $extension) {
- $extension->onBeforeReceive($context);
+ foreach ($this->preConsumeExtensions as $extension) {
+ $extension->onPreConsume($context);
}
}
- /**
- * @param Context $context
- */
- public function onPreReceived(Context $context)
+ public function onMessageReceived(MessageReceived $context): void
{
- foreach ($this->extensions as $extension) {
- $extension->onPreReceived($context);
+ foreach ($this->messageReceivedExtensions as $extension) {
+ $extension->onMessageReceived($context);
}
}
- /**
- * @param Context $context
- */
- public function onResult(Context $context)
+ public function onResult(MessageResult $context): void
{
- foreach ($this->extensions as $extension) {
+ foreach ($this->messageResultExtensions as $extension) {
$extension->onResult($context);
}
}
- /**
- * @param Context $context
- */
- public function onPostReceived(Context $context)
+ public function onProcessorException(ProcessorException $context): void
+ {
+ foreach ($this->processorExceptionExtensions as $extension) {
+ $extension->onProcessorException($context);
+ }
+ }
+
+ public function onPostMessageReceived(PostMessageReceived $context): void
{
- foreach ($this->extensions as $extension) {
- $extension->onPostReceived($context);
+ foreach ($this->postMessageReceivedExtensions as $extension) {
+ $extension->onPostMessageReceived($context);
}
}
- /**
- * @param Context $context
- */
- public function onIdle(Context $context)
+ public function onPostConsume(PostConsume $context): void
{
- foreach ($this->extensions as $extension) {
- $extension->onIdle($context);
+ foreach ($this->postConsumeExtensions as $extension) {
+ $extension->onPostConsume($context);
}
}
- /**
- * @param Context $context
- */
- public function onInterrupted(Context $context)
+ public function onEnd(End $context): void
{
- foreach ($this->extensions as $extension) {
- $extension->onInterrupted($context);
+ foreach ($this->endExtensions as $extension) {
+ $extension->onEnd($context);
}
}
}
diff --git a/pkg/enqueue/Consumption/Context.php b/pkg/enqueue/Consumption/Context.php
deleted file mode 100644
index 09332b9b3..000000000
--- a/pkg/enqueue/Consumption/Context.php
+++ /dev/null
@@ -1,233 +0,0 @@
-psrContext = $psrContext;
-
- $this->executionInterrupted = false;
- }
-
- /**
- * @return PsrMessage
- */
- public function getPsrMessage()
- {
- return $this->psrMessage;
- }
-
- /**
- * @param PsrMessage $psrMessage
- */
- public function setPsrMessage(PsrMessage $psrMessage)
- {
- if ($this->psrMessage) {
- throw new IllegalContextModificationException('The message could be set once');
- }
-
- $this->psrMessage = $psrMessage;
- }
-
- /**
- * @return PsrContext
- */
- public function getPsrContext()
- {
- return $this->psrContext;
- }
-
- /**
- * @return PsrConsumer
- */
- public function getPsrConsumer()
- {
- return $this->psrConsumer;
- }
-
- /**
- * @param PsrConsumer $psrConsumer
- */
- public function setPsrConsumer(PsrConsumer $psrConsumer)
- {
- if ($this->psrConsumer) {
- throw new IllegalContextModificationException('The message consumer could be set once');
- }
-
- $this->psrConsumer = $psrConsumer;
- }
-
- /**
- * @return PsrProcessor
- */
- public function getPsrProcessor()
- {
- return $this->psrProcessor;
- }
-
- /**
- * @param PsrProcessor $psrProcessor
- */
- public function setPsrProcessor(PsrProcessor $psrProcessor)
- {
- if ($this->psrProcessor) {
- throw new IllegalContextModificationException('The message processor could be set once');
- }
-
- $this->psrProcessor = $psrProcessor;
- }
-
- /**
- * @return \Exception
- */
- public function getException()
- {
- return $this->exception;
- }
-
- /**
- * @param \Exception $exception
- */
- public function setException(\Exception $exception)
- {
- $this->exception = $exception;
- }
-
- /**
- * @return Result|string
- */
- public function getResult()
- {
- return $this->result;
- }
-
- /**
- * @param Result|string $result
- */
- public function setResult($result)
- {
- if ($this->result) {
- throw new IllegalContextModificationException('The result modification is not allowed');
- }
-
- $this->result = $result;
- }
-
- /**
- * @return bool
- */
- public function isExecutionInterrupted()
- {
- return $this->executionInterrupted;
- }
-
- /**
- * @param bool $executionInterrupted
- */
- public function setExecutionInterrupted($executionInterrupted)
- {
- if (false == $executionInterrupted && $this->executionInterrupted) {
- throw new IllegalContextModificationException('The execution once interrupted could not be roll backed');
- }
-
- $this->executionInterrupted = $executionInterrupted;
- }
-
- /**
- * @return LoggerInterface
- */
- public function getLogger()
- {
- return $this->logger;
- }
-
- /**
- * @param LoggerInterface $logger
- */
- public function setLogger(LoggerInterface $logger)
- {
- if ($this->logger) {
- throw new IllegalContextModificationException('The logger modification is not allowed');
- }
-
- $this->logger = $logger;
- }
-
- /**
- * @return PsrQueue
- */
- public function getPsrQueue()
- {
- return $this->psrQueue;
- }
-
- /**
- * @param PsrQueue $psrQueue
- */
- public function setPsrQueue(PsrQueue $psrQueue)
- {
- if ($this->psrQueue) {
- throw new IllegalContextModificationException('The queue modification is not allowed');
- }
-
- $this->psrQueue = $psrQueue;
- }
-}
diff --git a/pkg/enqueue/Consumption/Context/End.php b/pkg/enqueue/Consumption/Context/End.php
new file mode 100644
index 000000000..07853b3d3
--- /dev/null
+++ b/pkg/enqueue/Consumption/Context/End.php
@@ -0,0 +1,79 @@
+context = $context;
+ $this->logger = $logger;
+ $this->startTime = $startTime;
+ $this->endTime = $endTime;
+ $this->exitStatus = $exitStatus;
+ }
+
+ public function getContext(): Context
+ {
+ return $this->context;
+ }
+
+ public function getLogger(): LoggerInterface
+ {
+ return $this->logger;
+ }
+
+ /**
+ * In milliseconds.
+ */
+ public function getStartTime(): int
+ {
+ return $this->startTime;
+ }
+
+ /**
+ * In milliseconds.
+ */
+ public function getEndTime(): int
+ {
+ return $this->startTime;
+ }
+
+ public function getExitStatus(): ?int
+ {
+ return $this->exitStatus;
+ }
+}
diff --git a/pkg/enqueue/Consumption/Context/InitLogger.php b/pkg/enqueue/Consumption/Context/InitLogger.php
new file mode 100644
index 000000000..c48057268
--- /dev/null
+++ b/pkg/enqueue/Consumption/Context/InitLogger.php
@@ -0,0 +1,28 @@
+logger = $logger;
+ }
+
+ public function getLogger(): LoggerInterface
+ {
+ return $this->logger;
+ }
+
+ public function changeLogger(LoggerInterface $logger): void
+ {
+ $this->logger = $logger;
+ }
+}
diff --git a/pkg/enqueue/Consumption/Context/MessageReceived.php b/pkg/enqueue/Consumption/Context/MessageReceived.php
new file mode 100644
index 000000000..35abf1ca8
--- /dev/null
+++ b/pkg/enqueue/Consumption/Context/MessageReceived.php
@@ -0,0 +1,109 @@
+context = $context;
+ $this->consumer = $consumer;
+ $this->message = $message;
+ $this->processor = $processor;
+ $this->receivedAt = $receivedAt;
+ $this->logger = $logger;
+ }
+
+ public function getContext(): Context
+ {
+ return $this->context;
+ }
+
+ public function getConsumer(): Consumer
+ {
+ return $this->consumer;
+ }
+
+ public function getMessage(): Message
+ {
+ return $this->message;
+ }
+
+ public function getProcessor(): Processor
+ {
+ return $this->processor;
+ }
+
+ public function changeProcessor(Processor $processor): void
+ {
+ $this->processor = $processor;
+ }
+
+ public function getLogger(): LoggerInterface
+ {
+ return $this->logger;
+ }
+
+ public function getReceivedAt(): int
+ {
+ return $this->receivedAt;
+ }
+
+ public function getResult(): ?Result
+ {
+ return $this->result;
+ }
+
+ public function setResult(Result $result): void
+ {
+ $this->result = $result;
+ }
+}
diff --git a/pkg/enqueue/Consumption/Context/MessageResult.php b/pkg/enqueue/Consumption/Context/MessageResult.php
new file mode 100644
index 000000000..4fa8f7de0
--- /dev/null
+++ b/pkg/enqueue/Consumption/Context/MessageResult.php
@@ -0,0 +1,93 @@
+context = $context;
+ $this->consumer = $consumer;
+ $this->message = $message;
+ $this->logger = $logger;
+ $this->result = $result;
+ $this->receivedAt = $receivedAt;
+ }
+
+ public function getContext(): Context
+ {
+ return $this->context;
+ }
+
+ public function getConsumer(): Consumer
+ {
+ return $this->consumer;
+ }
+
+ public function getMessage(): Message
+ {
+ return $this->message;
+ }
+
+ public function getLogger(): LoggerInterface
+ {
+ return $this->logger;
+ }
+
+ public function getReceivedAt(): int
+ {
+ return $this->receivedAt;
+ }
+
+ /**
+ * @return Result|object|string|null
+ */
+ public function getResult()
+ {
+ return $this->result;
+ }
+
+ /**
+ * @param Result|string|object|null $result
+ */
+ public function changeResult($result): void
+ {
+ $this->result = $result;
+ }
+}
diff --git a/pkg/enqueue/Consumption/Context/PostConsume.php b/pkg/enqueue/Consumption/Context/PostConsume.php
new file mode 100644
index 000000000..a6f1d8375
--- /dev/null
+++ b/pkg/enqueue/Consumption/Context/PostConsume.php
@@ -0,0 +1,108 @@
+context = $context;
+ $this->subscriptionConsumer = $subscriptionConsumer;
+ $this->receivedMessagesCount = $receivedMessagesCount;
+ $this->cycle = $cycle;
+ $this->startTime = $startTime;
+ $this->logger = $logger;
+
+ $this->executionInterrupted = false;
+ }
+
+ public function getContext(): Context
+ {
+ return $this->context;
+ }
+
+ public function getSubscriptionConsumer(): SubscriptionConsumer
+ {
+ return $this->subscriptionConsumer;
+ }
+
+ public function getReceivedMessagesCount(): int
+ {
+ return $this->receivedMessagesCount;
+ }
+
+ public function getCycle(): int
+ {
+ return $this->cycle;
+ }
+
+ public function getStartTime(): int
+ {
+ return $this->startTime;
+ }
+
+ public function getLogger(): LoggerInterface
+ {
+ return $this->logger;
+ }
+
+ public function getExitStatus(): ?int
+ {
+ return $this->exitStatus;
+ }
+
+ public function isExecutionInterrupted(): bool
+ {
+ return $this->executionInterrupted;
+ }
+
+ public function interruptExecution(?int $exitStatus = null): void
+ {
+ $this->exitStatus = $exitStatus;
+ $this->executionInterrupted = true;
+ }
+}
diff --git a/pkg/enqueue/Consumption/Context/PostMessageReceived.php b/pkg/enqueue/Consumption/Context/PostMessageReceived.php
new file mode 100644
index 000000000..23df2c849
--- /dev/null
+++ b/pkg/enqueue/Consumption/Context/PostMessageReceived.php
@@ -0,0 +1,119 @@
+context = $context;
+ $this->consumer = $consumer;
+ $this->message = $message;
+ $this->result = $result;
+ $this->receivedAt = $receivedAt;
+ $this->logger = $logger;
+
+ $this->executionInterrupted = false;
+ }
+
+ public function getContext(): Context
+ {
+ return $this->context;
+ }
+
+ public function getConsumer(): Consumer
+ {
+ return $this->consumer;
+ }
+
+ public function getMessage(): Message
+ {
+ return $this->message;
+ }
+
+ public function getLogger(): LoggerInterface
+ {
+ return $this->logger;
+ }
+
+ public function getReceivedAt(): int
+ {
+ return $this->receivedAt;
+ }
+
+ /**
+ * @return Result|object|string|null
+ */
+ public function getResult()
+ {
+ return $this->result;
+ }
+
+ public function getExitStatus(): ?int
+ {
+ return $this->exitStatus;
+ }
+
+ public function isExecutionInterrupted(): bool
+ {
+ return $this->executionInterrupted;
+ }
+
+ public function interruptExecution(?int $exitStatus = null): void
+ {
+ $this->exitStatus = $exitStatus;
+ $this->executionInterrupted = true;
+ }
+}
diff --git a/pkg/enqueue/Consumption/Context/PreConsume.php b/pkg/enqueue/Consumption/Context/PreConsume.php
new file mode 100644
index 000000000..77cc7d030
--- /dev/null
+++ b/pkg/enqueue/Consumption/Context/PreConsume.php
@@ -0,0 +1,108 @@
+context = $context;
+ $this->subscriptionConsumer = $subscriptionConsumer;
+ $this->logger = $logger;
+ $this->cycle = $cycle;
+ $this->receiveTimeout = $receiveTimeout;
+ $this->startTime = $startTime;
+
+ $this->executionInterrupted = false;
+ }
+
+ public function getContext(): Context
+ {
+ return $this->context;
+ }
+
+ public function getSubscriptionConsumer(): SubscriptionConsumer
+ {
+ return $this->subscriptionConsumer;
+ }
+
+ public function getLogger(): LoggerInterface
+ {
+ return $this->logger;
+ }
+
+ public function getCycle(): int
+ {
+ return $this->cycle;
+ }
+
+ public function getReceiveTimeout(): int
+ {
+ return $this->receiveTimeout;
+ }
+
+ public function getStartTime(): int
+ {
+ return $this->startTime;
+ }
+
+ public function getExitStatus(): ?int
+ {
+ return $this->exitStatus;
+ }
+
+ public function isExecutionInterrupted(): bool
+ {
+ return $this->executionInterrupted;
+ }
+
+ public function interruptExecution(?int $exitStatus = null): void
+ {
+ $this->exitStatus = $exitStatus;
+ $this->executionInterrupted = true;
+ }
+}
diff --git a/pkg/enqueue/Consumption/Context/PreSubscribe.php b/pkg/enqueue/Consumption/Context/PreSubscribe.php
new file mode 100644
index 000000000..dbc74bb69
--- /dev/null
+++ b/pkg/enqueue/Consumption/Context/PreSubscribe.php
@@ -0,0 +1,59 @@
+context = $context;
+ $this->processor = $processor;
+ $this->consumer = $consumer;
+ $this->logger = $logger;
+ }
+
+ public function getContext(): Context
+ {
+ return $this->context;
+ }
+
+ public function getProcessor(): Processor
+ {
+ return $this->processor;
+ }
+
+ public function getConsumer(): Consumer
+ {
+ return $this->consumer;
+ }
+
+ public function getLogger(): LoggerInterface
+ {
+ return $this->logger;
+ }
+}
diff --git a/pkg/enqueue/Consumption/Context/ProcessorException.php b/pkg/enqueue/Consumption/Context/ProcessorException.php
new file mode 100644
index 000000000..329b13d93
--- /dev/null
+++ b/pkg/enqueue/Consumption/Context/ProcessorException.php
@@ -0,0 +1,96 @@
+context = $context;
+ $this->consumer = $consumer;
+ $this->message = $message;
+ $this->exception = $exception;
+ $this->logger = $logger;
+ $this->receivedAt = $receivedAt;
+ }
+
+ public function getContext(): Context
+ {
+ return $this->context;
+ }
+
+ public function getConsumer(): Consumer
+ {
+ return $this->consumer;
+ }
+
+ public function getMessage(): Message
+ {
+ return $this->message;
+ }
+
+ public function getException(): \Throwable
+ {
+ return $this->exception;
+ }
+
+ public function getLogger(): LoggerInterface
+ {
+ return $this->logger;
+ }
+
+ public function getReceivedAt(): int
+ {
+ return $this->receivedAt;
+ }
+
+ public function getResult(): ?Result
+ {
+ return $this->result;
+ }
+
+ public function setResult(Result $result): void
+ {
+ $this->result = $result;
+ }
+}
diff --git a/pkg/enqueue/Consumption/Context/Start.php b/pkg/enqueue/Consumption/Context/Start.php
new file mode 100644
index 000000000..84db29c44
--- /dev/null
+++ b/pkg/enqueue/Consumption/Context/Start.php
@@ -0,0 +1,128 @@
+context = $context;
+ $this->logger = $logger;
+ $this->processors = $processors;
+ $this->receiveTimeout = $receiveTimeout;
+ $this->startTime = $startTime;
+
+ $this->executionInterrupted = false;
+ }
+
+ public function getContext(): Context
+ {
+ return $this->context;
+ }
+
+ public function getLogger(): LoggerInterface
+ {
+ return $this->logger;
+ }
+
+ /**
+ * In milliseconds.
+ */
+ public function getReceiveTimeout(): int
+ {
+ return $this->receiveTimeout;
+ }
+
+ /**
+ * In milliseconds.
+ */
+ public function changeReceiveTimeout(int $timeout): void
+ {
+ $this->receiveTimeout = $timeout;
+ }
+
+ /**
+ * In milliseconds.
+ */
+ public function getStartTime(): int
+ {
+ return $this->startTime;
+ }
+
+ /**
+ * @return BoundProcessor[]
+ */
+ public function getBoundProcessors(): array
+ {
+ return $this->processors;
+ }
+
+ /**
+ * @param BoundProcessor[] $processors
+ */
+ public function changeBoundProcessors(array $processors): void
+ {
+ $this->processors = [];
+ array_walk($processors, function (BoundProcessor $processor) {
+ $this->processors[] = $processor;
+ });
+ }
+
+ public function getExitStatus(): ?int
+ {
+ return $this->exitStatus;
+ }
+
+ public function isExecutionInterrupted(): bool
+ {
+ return $this->executionInterrupted;
+ }
+
+ public function interruptExecution(?int $exitStatus = null): void
+ {
+ $this->exitStatus = $exitStatus;
+ $this->executionInterrupted = true;
+ }
+}
diff --git a/pkg/enqueue/Consumption/EmptyExtensionTrait.php b/pkg/enqueue/Consumption/EmptyExtensionTrait.php
deleted file mode 100644
index 0f6b849c4..000000000
--- a/pkg/enqueue/Consumption/EmptyExtensionTrait.php
+++ /dev/null
@@ -1,55 +0,0 @@
-exitStatus = $context->getExitStatus();
+ }
+
+ public function getExitStatus(): ?int
+ {
+ return $this->exitStatus;
+ }
+}
diff --git a/pkg/enqueue/Consumption/Extension/LimitConsumedMessagesExtension.php b/pkg/enqueue/Consumption/Extension/LimitConsumedMessagesExtension.php
index ef6ec527e..0dc6feceb 100644
--- a/pkg/enqueue/Consumption/Extension/LimitConsumedMessagesExtension.php
+++ b/pkg/enqueue/Consumption/Extension/LimitConsumedMessagesExtension.php
@@ -2,14 +2,14 @@
namespace Enqueue\Consumption\Extension;
-use Enqueue\Consumption\Context;
-use Enqueue\Consumption\EmptyExtensionTrait;
-use Enqueue\Consumption\ExtensionInterface;
+use Enqueue\Consumption\Context\PostMessageReceived;
+use Enqueue\Consumption\Context\PreConsume;
+use Enqueue\Consumption\PostMessageReceivedExtensionInterface;
+use Enqueue\Consumption\PreConsumeExtensionInterface;
+use Psr\Log\LoggerInterface;
-class LimitConsumedMessagesExtension implements ExtensionInterface
+class LimitConsumedMessagesExtension implements PreConsumeExtensionInterface, PostMessageReceivedExtensionInterface
{
- use EmptyExtensionTrait;
-
/**
* @var int
*/
@@ -20,54 +20,41 @@ class LimitConsumedMessagesExtension implements ExtensionInterface
*/
protected $messageConsumed;
- /**
- * @param int $messageLimit
- */
- public function __construct($messageLimit)
+ public function __construct(int $messageLimit)
{
- if (false == is_int($messageLimit)) {
- throw new \InvalidArgumentException(sprintf(
- 'Expected message limit is int but got: "%s"',
- is_object($messageLimit) ? get_class($messageLimit) : gettype($messageLimit)
- ));
- }
-
$this->messageLimit = $messageLimit;
$this->messageConsumed = 0;
}
- /**
- * {@inheritdoc}
- */
- public function onBeforeReceive(Context $context)
+ public function onPreConsume(PreConsume $context): void
{
// this is added here to handle an edge case. when a user sets zero as limit.
- $this->checkMessageLimit($context);
+ if ($this->shouldBeStopped($context->getLogger())) {
+ $context->interruptExecution();
+ }
}
- /**
- * {@inheritdoc}
- */
- public function onPostReceived(Context $context)
+ public function onPostMessageReceived(PostMessageReceived $context): void
{
++$this->messageConsumed;
- $this->checkMessageLimit($context);
+ if ($this->shouldBeStopped($context->getLogger())) {
+ $context->interruptExecution();
+ }
}
- /**
- * @param Context $context
- */
- protected function checkMessageLimit(Context $context)
+ protected function shouldBeStopped(LoggerInterface $logger): bool
{
if ($this->messageConsumed >= $this->messageLimit) {
- $context->getLogger()->debug(sprintf(
+ $logger->debug(sprintf(
'[LimitConsumedMessagesExtension] Message consumption is interrupted since the message limit reached.'.
' limit: "%s"',
$this->messageLimit
));
- $context->setExecutionInterrupted(true);
+ return true;
}
+
+ return false;
}
}
diff --git a/pkg/enqueue/Consumption/Extension/LimitConsumerMemoryExtension.php b/pkg/enqueue/Consumption/Extension/LimitConsumerMemoryExtension.php
index c03686f33..7edbf232c 100644
--- a/pkg/enqueue/Consumption/Extension/LimitConsumerMemoryExtension.php
+++ b/pkg/enqueue/Consumption/Extension/LimitConsumerMemoryExtension.php
@@ -2,14 +2,16 @@
namespace Enqueue\Consumption\Extension;
-use Enqueue\Consumption\Context;
-use Enqueue\Consumption\EmptyExtensionTrait;
-use Enqueue\Consumption\ExtensionInterface;
+use Enqueue\Consumption\Context\PostConsume;
+use Enqueue\Consumption\Context\PostMessageReceived;
+use Enqueue\Consumption\Context\PreConsume;
+use Enqueue\Consumption\PostConsumeExtensionInterface;
+use Enqueue\Consumption\PostMessageReceivedExtensionInterface;
+use Enqueue\Consumption\PreConsumeExtensionInterface;
+use Psr\Log\LoggerInterface;
-class LimitConsumerMemoryExtension implements ExtensionInterface
+class LimitConsumerMemoryExtension implements PreConsumeExtensionInterface, PostMessageReceivedExtensionInterface, PostConsumeExtensionInterface
{
- use EmptyExtensionTrait;
-
/**
* @var int
*/
@@ -21,53 +23,46 @@ class LimitConsumerMemoryExtension implements ExtensionInterface
public function __construct($memoryLimit)
{
if (false == is_int($memoryLimit)) {
- throw new \InvalidArgumentException(sprintf(
- 'Expected memory limit is int but got: "%s"',
- is_object($memoryLimit) ? get_class($memoryLimit) : gettype($memoryLimit)
- ));
+ throw new \InvalidArgumentException(sprintf('Expected memory limit is int but got: "%s"', is_object($memoryLimit) ? $memoryLimit::class : gettype($memoryLimit)));
}
$this->memoryLimit = $memoryLimit * 1024 * 1024;
}
- /**
- * {@inheritdoc}
- */
- public function onBeforeReceive(Context $context)
+ public function onPreConsume(PreConsume $context): void
{
- $this->checkMemory($context);
+ if ($this->shouldBeStopped($context->getLogger())) {
+ $context->interruptExecution();
+ }
}
- /**
- * {@inheritdoc}
- */
- public function onPostReceived(Context $context)
+ public function onPostMessageReceived(PostMessageReceived $context): void
{
- $this->checkMemory($context);
+ if ($this->shouldBeStopped($context->getLogger())) {
+ $context->interruptExecution();
+ }
}
- /**
- * {@inheritdoc}
- */
- public function onIdle(Context $context)
+ public function onPostConsume(PostConsume $context): void
{
- $this->checkMemory($context);
+ if ($this->shouldBeStopped($context->getLogger())) {
+ $context->interruptExecution();
+ }
}
- /**
- * @param Context $context
- */
- protected function checkMemory(Context $context)
+ protected function shouldBeStopped(LoggerInterface $logger): bool
{
$memoryUsage = memory_get_usage(true);
if ($memoryUsage >= $this->memoryLimit) {
- $context->getLogger()->debug(sprintf(
+ $logger->debug(sprintf(
'[LimitConsumerMemoryExtension] Interrupt execution as memory limit reached. limit: "%s", used: "%s"',
$this->memoryLimit,
$memoryUsage
));
- $context->setExecutionInterrupted(true);
+ return true;
}
+
+ return false;
}
}
diff --git a/pkg/enqueue/Consumption/Extension/LimitConsumptionTimeExtension.php b/pkg/enqueue/Consumption/Extension/LimitConsumptionTimeExtension.php
index 65221f5c0..1953aa2e6 100644
--- a/pkg/enqueue/Consumption/Extension/LimitConsumptionTimeExtension.php
+++ b/pkg/enqueue/Consumption/Extension/LimitConsumptionTimeExtension.php
@@ -2,66 +2,61 @@
namespace Enqueue\Consumption\Extension;
-use Enqueue\Consumption\Context;
-use Enqueue\Consumption\EmptyExtensionTrait;
-use Enqueue\Consumption\ExtensionInterface;
-
-class LimitConsumptionTimeExtension implements ExtensionInterface
+use Enqueue\Consumption\Context\PostConsume;
+use Enqueue\Consumption\Context\PostMessageReceived;
+use Enqueue\Consumption\Context\PreConsume;
+use Enqueue\Consumption\PostConsumeExtensionInterface;
+use Enqueue\Consumption\PostMessageReceivedExtensionInterface;
+use Enqueue\Consumption\PreConsumeExtensionInterface;
+use Psr\Log\LoggerInterface;
+
+class LimitConsumptionTimeExtension implements PreConsumeExtensionInterface, PostConsumeExtensionInterface, PostMessageReceivedExtensionInterface
{
- use EmptyExtensionTrait;
-
/**
* @var \DateTime
*/
protected $timeLimit;
- /**
- * @param \DateTime $timeLimit
- */
public function __construct(\DateTime $timeLimit)
{
$this->timeLimit = $timeLimit;
}
- /**
- * {@inheritdoc}
- */
- public function onBeforeReceive(Context $context)
+ public function onPreConsume(PreConsume $context): void
{
- $this->checkTime($context);
+ if ($this->shouldBeStopped($context->getLogger())) {
+ $context->interruptExecution();
+ }
}
- /**
- * {@inheritdoc}
- */
- public function onIdle(Context $context)
+ public function onPostConsume(PostConsume $context): void
{
- $this->checkTime($context);
+ if ($this->shouldBeStopped($context->getLogger())) {
+ $context->interruptExecution();
+ }
}
- /**
- * {@inheritdoc}
- */
- public function onPostReceived(Context $context)
+ public function onPostMessageReceived(PostMessageReceived $context): void
{
- $this->checkTime($context);
+ if ($this->shouldBeStopped($context->getLogger())) {
+ $context->interruptExecution();
+ }
}
- /**
- * @param Context $context
- */
- protected function checkTime(Context $context)
+ protected function shouldBeStopped(LoggerInterface $logger): bool
{
$now = new \DateTime();
if ($now >= $this->timeLimit) {
- $context->getLogger()->debug(sprintf(
+ $logger->debug(sprintf(
'[LimitConsumptionTimeExtension] Execution interrupted as limit time has passed.'.
' now: "%s", time-limit: "%s"',
- $now->format(DATE_ISO8601),
- $this->timeLimit->format(DATE_ISO8601)
+ $now->format(\DATE_ISO8601),
+ $this->timeLimit->format(\DATE_ISO8601)
));
- $context->setExecutionInterrupted(true);
+ return true;
}
+
+ return false;
}
}
diff --git a/pkg/enqueue/Consumption/Extension/LogExtension.php b/pkg/enqueue/Consumption/Extension/LogExtension.php
new file mode 100644
index 000000000..14383c4d1
--- /dev/null
+++ b/pkg/enqueue/Consumption/Extension/LogExtension.php
@@ -0,0 +1,67 @@
+getLogger()->debug('Consumption has started');
+ }
+
+ public function onEnd(End $context): void
+ {
+ $context->getLogger()->debug('Consumption has ended');
+ }
+
+ public function onMessageReceived(MessageReceived $context): void
+ {
+ $message = $context->getMessage();
+
+ $context->getLogger()->debug("Received from {queueName}\t{body}", [
+ 'queueName' => $context->getConsumer()->getQueue()->getQueueName(),
+ 'redelivered' => $message->isRedelivered(),
+ 'body' => Stringify::that($message->getBody()),
+ 'properties' => Stringify::that($message->getProperties()),
+ 'headers' => Stringify::that($message->getHeaders()),
+ ]);
+ }
+
+ public function onPostMessageReceived(PostMessageReceived $context): void
+ {
+ $message = $context->getMessage();
+ $queue = $context->getConsumer()->getQueue();
+ $result = $context->getResult();
+
+ $reason = '';
+ $logMessage = "Processed from {queueName}\t{body}\t{result}";
+ if ($result instanceof Result && $result->getReason()) {
+ $reason = $result->getReason();
+ $logMessage .= ' {reason}';
+ }
+ $logContext = [
+ 'result' => str_replace('enqueue.', '', $result),
+ 'reason' => $reason,
+ 'queueName' => $queue->getQueueName(),
+ 'body' => Stringify::that($message->getBody()),
+ 'properties' => Stringify::that($message->getProperties()),
+ 'headers' => Stringify::that($message->getHeaders()),
+ ];
+
+ $logLevel = Result::REJECT == ((string) $result) ? LogLevel::ERROR : LogLevel::INFO;
+
+ $context->getLogger()->log($logLevel, $logMessage, $logContext);
+ }
+}
diff --git a/pkg/enqueue/Consumption/Extension/LoggerExtension.php b/pkg/enqueue/Consumption/Extension/LoggerExtension.php
index 0779c9033..90e92be8a 100644
--- a/pkg/enqueue/Consumption/Extension/LoggerExtension.php
+++ b/pkg/enqueue/Consumption/Extension/LoggerExtension.php
@@ -2,89 +2,30 @@
namespace Enqueue\Consumption\Extension;
-use Enqueue\Consumption\Context;
-use Enqueue\Consumption\EmptyExtensionTrait;
-use Enqueue\Consumption\ExtensionInterface;
-use Enqueue\Consumption\Result;
-use Interop\Queue\PsrMessage;
+use Enqueue\Consumption\Context\InitLogger;
+use Enqueue\Consumption\InitLoggerExtensionInterface;
use Psr\Log\LoggerInterface;
-class LoggerExtension implements ExtensionInterface
+class LoggerExtension implements InitLoggerExtensionInterface
{
- use EmptyExtensionTrait;
-
/**
* @var LoggerInterface
*/
private $logger;
- /**
- * @param LoggerInterface $logger
- */
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
- /**
- * {@inheritdoc}
- */
- public function onStart(Context $context)
+ public function onInitLogger(InitLogger $context): void
{
- if ($context->getLogger()) {
- $context->getLogger()->debug(sprintf(
- 'Skip setting context\'s logger "%s". Another one "%s" has already been set.',
- get_class($this->logger),
- get_class($context->getLogger())
- ));
- } else {
- $context->setLogger($this->logger);
- $this->logger->debug(sprintf('Set context\'s logger "%s"', get_class($this->logger)));
- }
- }
+ $previousLogger = $context->getLogger();
- /**
- * {@inheritdoc}
- */
- public function onPostReceived(Context $context)
- {
- if (false == $context->getResult() instanceof Result) {
- return;
- }
-
- /** @var $result Result */
- $result = $context->getResult();
-
- switch ($result->getStatus()) {
- case Result::REJECT:
- case Result::REQUEUE:
- if ($result->getReason()) {
- $this->logger->error($result->getReason(), $this->messageToLogContext($context->getPsrMessage()));
- }
+ if ($previousLogger !== $this->logger) {
+ $context->changeLogger($this->logger);
- break;
- case Result::ACK:
- if ($result->getReason()) {
- $this->logger->info($result->getReason(), $this->messageToLogContext($context->getPsrMessage()));
- }
-
- break;
- default:
- throw new \LogicException(sprintf('Got unexpected message result. "%s"', $result->getStatus()));
+ $this->logger->debug(sprintf('Change logger from "%s" to "%s"', $previousLogger::class, get_class($this->logger)));
}
}
-
- /**
- * @param PsrMessage $message
- *
- * @return array
- */
- private function messageToLogContext(PsrMessage $message)
- {
- return [
- 'body' => $message->getBody(),
- 'headers' => $message->getHeaders(),
- 'properties' => $message->getProperties(),
- ];
- }
}
diff --git a/pkg/enqueue/Consumption/Extension/NicenessExtension.php b/pkg/enqueue/Consumption/Extension/NicenessExtension.php
index 01a5383a2..436a8ec0f 100644
--- a/pkg/enqueue/Consumption/Extension/NicenessExtension.php
+++ b/pkg/enqueue/Consumption/Extension/NicenessExtension.php
@@ -2,14 +2,11 @@
namespace Enqueue\Consumption\Extension;
-use Enqueue\Consumption\Context;
-use Enqueue\Consumption\EmptyExtensionTrait;
-use Enqueue\Consumption\ExtensionInterface;
+use Enqueue\Consumption\Context\Start;
+use Enqueue\Consumption\StartExtensionInterface;
-class NicenessExtension implements ExtensionInterface
+class NicenessExtension implements StartExtensionInterface
{
- use EmptyExtensionTrait;
-
/**
* @var int
*/
@@ -23,27 +20,18 @@ class NicenessExtension implements ExtensionInterface
public function __construct($niceness)
{
if (false === is_int($niceness)) {
- throw new \InvalidArgumentException(sprintf(
- 'Expected niceness value is int but got: "%s"',
- is_object($niceness) ? get_class($niceness) : gettype($niceness)
- ));
+ throw new \InvalidArgumentException(sprintf('Expected niceness value is int but got: "%s"', is_object($niceness) ? $niceness::class : gettype($niceness)));
}
$this->niceness = $niceness;
}
- /**
- * {@inheritdoc}
- */
- public function onStart(Context $context)
+ public function onStart(Start $context): void
{
if (0 !== $this->niceness) {
$changed = @proc_nice($this->niceness);
if (!$changed) {
- throw new \InvalidArgumentException(sprintf(
- 'Cannot change process niceness, got warning: "%s"',
- error_get_last()['message']
- ));
+ throw new \InvalidArgumentException(sprintf('Cannot change process niceness, got warning: "%s"', error_get_last()['message']));
}
}
}
diff --git a/pkg/enqueue/Consumption/Extension/ReplyExtension.php b/pkg/enqueue/Consumption/Extension/ReplyExtension.php
index 0d7a76eeb..c1ac19bd7 100644
--- a/pkg/enqueue/Consumption/Extension/ReplyExtension.php
+++ b/pkg/enqueue/Consumption/Extension/ReplyExtension.php
@@ -2,21 +2,15 @@
namespace Enqueue\Consumption\Extension;
-use Enqueue\Consumption\Context;
-use Enqueue\Consumption\EmptyExtensionTrait;
-use Enqueue\Consumption\ExtensionInterface;
+use Enqueue\Consumption\Context\PostMessageReceived;
+use Enqueue\Consumption\PostMessageReceivedExtensionInterface;
use Enqueue\Consumption\Result;
-class ReplyExtension implements ExtensionInterface
+class ReplyExtension implements PostMessageReceivedExtensionInterface
{
- use EmptyExtensionTrait;
-
- /**
- * {@inheritdoc}
- */
- public function onPostReceived(Context $context)
+ public function onPostMessageReceived(PostMessageReceived $context): void
{
- $replyTo = $context->getPsrMessage()->getReplyTo();
+ $replyTo = $context->getMessage()->getReplyTo();
if (false == $replyTo) {
return;
}
@@ -31,13 +25,13 @@ public function onPostReceived(Context $context)
return;
}
- $correlationId = $context->getPsrMessage()->getCorrelationId();
+ $correlationId = $context->getMessage()->getCorrelationId();
$replyMessage = clone $result->getReply();
$replyMessage->setCorrelationId($correlationId);
- $replyQueue = $context->getPsrContext()->createQueue($replyTo);
+ $replyQueue = $context->getContext()->createQueue($replyTo);
$context->getLogger()->debug(sprintf('[ReplyExtension] Send reply to "%s"', $replyTo));
- $context->getPsrContext()->createProducer()->send($replyQueue, $replyMessage);
+ $context->getContext()->createProducer()->send($replyQueue, $replyMessage);
}
}
diff --git a/pkg/enqueue/Consumption/Extension/SignalExtension.php b/pkg/enqueue/Consumption/Extension/SignalExtension.php
index a8b53e8b8..8ea5307d5 100644
--- a/pkg/enqueue/Consumption/Extension/SignalExtension.php
+++ b/pkg/enqueue/Consumption/Extension/SignalExtension.php
@@ -2,16 +2,19 @@
namespace Enqueue\Consumption\Extension;
-use Enqueue\Consumption\Context;
-use Enqueue\Consumption\EmptyExtensionTrait;
+use Enqueue\Consumption\Context\PostConsume;
+use Enqueue\Consumption\Context\PostMessageReceived;
+use Enqueue\Consumption\Context\PreConsume;
+use Enqueue\Consumption\Context\Start;
use Enqueue\Consumption\Exception\LogicException;
-use Enqueue\Consumption\ExtensionInterface;
+use Enqueue\Consumption\PostConsumeExtensionInterface;
+use Enqueue\Consumption\PostMessageReceivedExtensionInterface;
+use Enqueue\Consumption\PreConsumeExtensionInterface;
+use Enqueue\Consumption\StartExtensionInterface;
use Psr\Log\LoggerInterface;
-class SignalExtension implements ExtensionInterface
+class SignalExtension implements StartExtensionInterface, PreConsumeExtensionInterface, PostMessageReceivedExtensionInterface, PostConsumeExtensionInterface
{
- use EmptyExtensionTrait;
-
/**
* @var bool
*/
@@ -22,95 +25,55 @@ class SignalExtension implements ExtensionInterface
*/
protected $logger;
- /**
- * {@inheritdoc}
- */
- public function onStart(Context $context)
+ public function onStart(Start $context): void
{
if (false == extension_loaded('pcntl')) {
throw new LogicException('The pcntl extension is required in order to catch signals.');
}
- if (function_exists('pcntl_async_signals')) {
- pcntl_async_signals(true);
- }
+ pcntl_async_signals(true);
- pcntl_signal(SIGTERM, [$this, 'handleSignal']);
- pcntl_signal(SIGQUIT, [$this, 'handleSignal']);
- pcntl_signal(SIGINT, [$this, 'handleSignal']);
+ pcntl_signal(\SIGTERM, [$this, 'handleSignal']);
+ pcntl_signal(\SIGQUIT, [$this, 'handleSignal']);
+ pcntl_signal(\SIGINT, [$this, 'handleSignal']);
+ $this->logger = $context->getLogger();
$this->interruptConsumption = false;
}
- /**
- * @param Context $context
- */
- public function onBeforeReceive(Context $context)
+ public function onPreConsume(PreConsume $context): void
{
$this->logger = $context->getLogger();
- $this->dispatchSignal();
-
- $this->interruptExecutionIfNeeded($context);
- }
-
- /**
- * {@inheritdoc}
- */
- public function onPreReceived(Context $context)
- {
- $this->interruptExecutionIfNeeded($context);
- }
-
- /**
- * {@inheritdoc}
- */
- public function onPostReceived(Context $context)
- {
- $this->dispatchSignal();
-
- $this->interruptExecutionIfNeeded($context);
+ if ($this->shouldBeStopped($context->getLogger())) {
+ $context->interruptExecution();
+ }
}
- /**
- * {@inheritdoc}
- */
- public function onIdle(Context $context)
+ public function onPostMessageReceived(PostMessageReceived $context): void
{
- $this->dispatchSignal();
-
- $this->interruptExecutionIfNeeded($context);
+ if ($this->shouldBeStopped($context->getLogger())) {
+ $context->interruptExecution();
+ }
}
- /**
- * @param Context $context
- */
- public function interruptExecutionIfNeeded(Context $context)
+ public function onPostConsume(PostConsume $context): void
{
- if (false == $context->isExecutionInterrupted() && $this->interruptConsumption) {
- if ($this->logger) {
- $this->logger->debug('[SignalExtension] Interrupt execution');
- }
-
- $context->setExecutionInterrupted($this->interruptConsumption);
-
- $this->interruptConsumption = false;
+ if ($this->shouldBeStopped($context->getLogger())) {
+ $context->interruptExecution();
}
}
- /**
- * @param int $signal
- */
- public function handleSignal($signal)
+ public function handleSignal(int $signal): void
{
if ($this->logger) {
$this->logger->debug(sprintf('[SignalExtension] Caught signal: %s', $signal));
}
switch ($signal) {
- case SIGTERM: // 15 : supervisor default stop
- case SIGQUIT: // 3 : kill -s QUIT
- case SIGINT: // 2 : ctrl+c
+ case \SIGTERM: // 15 : supervisor default stop
+ case \SIGQUIT: // 3 : kill -s QUIT
+ case \SIGINT: // 2 : ctrl+c
if ($this->logger) {
$this->logger->debug('[SignalExtension] Interrupt consumption');
}
@@ -122,10 +85,16 @@ public function handleSignal($signal)
}
}
- private function dispatchSignal()
+ private function shouldBeStopped(LoggerInterface $logger): bool
{
- if (false == function_exists('pcntl_async_signals')) {
- pcntl_signal_dispatch();
+ if ($this->interruptConsumption) {
+ $logger->debug('[SignalExtension] Interrupt execution');
+
+ $this->interruptConsumption = false;
+
+ return true;
}
+
+ return false;
}
}
diff --git a/pkg/enqueue/Consumption/ExtensionInterface.php b/pkg/enqueue/Consumption/ExtensionInterface.php
index 2a5d7bb72..326a98f0d 100644
--- a/pkg/enqueue/Consumption/ExtensionInterface.php
+++ b/pkg/enqueue/Consumption/ExtensionInterface.php
@@ -2,65 +2,6 @@
namespace Enqueue\Consumption;
-interface ExtensionInterface
+interface ExtensionInterface extends StartExtensionInterface, PreSubscribeExtensionInterface, PreConsumeExtensionInterface, MessageReceivedExtensionInterface, PostMessageReceivedExtensionInterface, MessageResultExtensionInterface, ProcessorExceptionExtensionInterface, PostConsumeExtensionInterface, EndExtensionInterface, InitLoggerExtensionInterface
{
- /**
- * Executed only once at the very begining of the consumption.
- * At this stage the context does not contain processor, consumer and queue.
- *
- * @param Context $context
- */
- public function onStart(Context $context);
-
- /**
- * Executed at every new cycle before we asked a broker for a new message.
- * At this stage the context already contains processor, consumer and queue.
- * The consumption could be interrupted at this step.
- *
- * @param Context $context
- */
- public function onBeforeReceive(Context $context);
-
- /**
- * Executed when a new message is received from a broker but before it was passed to processor
- * The context contains a message.
- * The extension may set a status. If the status is set the exception is thrown
- * The consumption could be interrupted at this step but it exits after the message is processed.
- *
- * @param Context $context
- */
- public function onPreReceived(Context $context);
-
- /**
- * Executed when a message is processed by a processor or a result was set in onPreReceived method.
- * BUT before the message status was sent to the broker
- * The consumption could be interrupted at this step but it exits after the message is processed.
- *
- * @param Context $context
- */
- public function onResult(Context $context);
-
- /**
- * Executed when a message is processed by a processor.
- * The context contains a status, which could not be changed.
- * The consumption could be interrupted at this step but it exits after the message is processed.
- *
- * @param Context $context
- */
- public function onPostReceived(Context $context);
-
- /**
- * Called each time at the end of the cycle if nothing was done.
- *
- * @param Context $context
- */
- public function onIdle(Context $context);
-
- /**
- * Called when the consumption was interrupted by an extension or exception
- * In case of exception it will be present in the context.
- *
- * @param Context $context
- */
- public function onInterrupted(Context $context);
}
diff --git a/pkg/enqueue/Consumption/FallbackSubscriptionConsumer.php b/pkg/enqueue/Consumption/FallbackSubscriptionConsumer.php
index f4176a696..15e2f273b 100644
--- a/pkg/enqueue/Consumption/FallbackSubscriptionConsumer.php
+++ b/pkg/enqueue/Consumption/FallbackSubscriptionConsumer.php
@@ -2,13 +2,13 @@
namespace Enqueue\Consumption;
-use Interop\Queue\PsrConsumer;
-use Interop\Queue\PsrSubscriptionConsumer;
+use Interop\Queue\Consumer;
+use Interop\Queue\SubscriptionConsumer;
-final class FallbackSubscriptionConsumer implements PsrSubscriptionConsumer
+final class FallbackSubscriptionConsumer implements SubscriptionConsumer
{
/**
- * an item contains an array: [PsrConsumer $consumer, callable $callback];.
+ * an item contains an array: [Consumer $consumer, callable $callback];.
* an item key is a queue name.
*
* @var array
@@ -16,7 +16,7 @@ final class FallbackSubscriptionConsumer implements PsrSubscriptionConsumer
private $subscribers;
/**
- * @var int|float the time in milliseconds the consumer waits if no message has been received
+ * @var int
*/
private $idleTime = 0;
@@ -25,32 +25,29 @@ public function __construct()
$this->subscribers = [];
}
- /**
- * {@inheritdoc}
- */
- public function consume($timeout = 0)
+ public function consume(int $timeoutMs = 0): void
{
- if (empty($this->subscribers)) {
+ if (!$subscriberCount = \count($this->subscribers)) {
throw new \LogicException('No subscribers');
}
- $timeout /= 1000;
+ $timeout = $timeoutMs / 1000;
$endAt = microtime(true) + $timeout;
while (true) {
/**
* @var string
- * @var PsrConsumer $consumer
- * @var callable $processor
+ * @var Consumer $consumer
+ * @var callable $processor
*/
foreach ($this->subscribers as $queueName => list($consumer, $callback)) {
- $message = $consumer->receiveNoWait();
+ $message = 1 === $subscriberCount ? $consumer->receive($timeoutMs) : $consumer->receiveNoWait();
if ($message) {
if (false === call_user_func($callback, $message, $consumer)) {
return;
}
- } else {
+ } elseif (1 !== $subscriberCount) {
if ($timeout && microtime(true) >= $endAt) {
return;
}
@@ -65,10 +62,7 @@ public function consume($timeout = 0)
}
}
- /**
- * {@inheritdoc}
- */
- public function subscribe(PsrConsumer $consumer, callable $callback)
+ public function subscribe(Consumer $consumer, callable $callback): void
{
$queueName = $consumer->getQueue()->getQueueName();
if (array_key_exists($queueName, $this->subscribers)) {
@@ -82,10 +76,7 @@ public function subscribe(PsrConsumer $consumer, callable $callback)
$this->subscribers[$queueName] = [$consumer, $callback];
}
- /**
- * {@inheritdoc}
- */
- public function unsubscribe(PsrConsumer $consumer)
+ public function unsubscribe(Consumer $consumer): void
{
if (false == array_key_exists($consumer->getQueue()->getQueueName(), $this->subscribers)) {
return;
@@ -98,26 +89,20 @@ public function unsubscribe(PsrConsumer $consumer)
unset($this->subscribers[$consumer->getQueue()->getQueueName()]);
}
- /**
- * {@inheritdoc}
- */
- public function unsubscribeAll()
+ public function unsubscribeAll(): void
{
$this->subscribers = [];
}
- /**
- * @return float|int
- */
- public function getIdleTime()
+ public function getIdleTime(): int
{
return $this->idleTime;
}
/**
- * @param float|int $idleTime
+ * The time in milliseconds the consumer waits if no message has been received.
*/
- public function setIdleTime($idleTime)
+ public function setIdleTime(int $idleTime): void
{
$this->idleTime = $idleTime;
}
diff --git a/pkg/enqueue/Consumption/InitLoggerExtensionInterface.php b/pkg/enqueue/Consumption/InitLoggerExtensionInterface.php
new file mode 100644
index 000000000..936e32d6e
--- /dev/null
+++ b/pkg/enqueue/Consumption/InitLoggerExtensionInterface.php
@@ -0,0 +1,14 @@
+psrContext = $psrContext;
- $this->staticExtension = $extension ?: new ChainExtension([]);
- $this->idleTimeout = $idleTimeout;
+ $this->interopContext = $interopContext;
$this->receiveTimeout = $receiveTimeout;
- $this->boundProcessors = [];
- $this->logger = new NullLogger();
-
- $this->enableSubscriptionConsumer = false;
- }
+ $this->staticExtension = $extension ?: new ChainExtension([]);
+ $this->logger = $logger ?: new NullLogger();
- /**
- * @param int $timeout
- */
- public function setIdleTimeout($timeout)
- {
- $this->idleTimeout = (int) $timeout;
- }
+ $this->boundProcessors = [];
+ array_walk($boundProcessors, function (BoundProcessor $processor) {
+ $this->boundProcessors[] = $processor;
+ });
- /**
- * @return int
- */
- public function getIdleTimeout()
- {
- return $this->idleTimeout;
+ $this->fallbackSubscriptionConsumer = new FallbackSubscriptionConsumer();
}
- /**
- * @param int $timeout
- */
- public function setReceiveTimeout($timeout)
+ public function setReceiveTimeout(int $timeout): void
{
- $this->receiveTimeout = (int) $timeout;
+ $this->receiveTimeout = $timeout;
}
- /**
- * @return int
- */
- public function getReceiveTimeout()
+ public function getReceiveTimeout(): int
{
return $this->receiveTimeout;
}
- /**
- * @return PsrContext
- */
- public function getPsrContext()
+ public function getContext(): InteropContext
{
- return $this->psrContext;
+ return $this->interopContext;
}
- /**
- * @param PsrQueue|string $queue
- * @param PsrProcessor|callable $processor
- *
- * @return QueueConsumer
- */
- public function bind($queue, $processor)
+ public function bind($queue, Processor $processor): QueueConsumerInterface
{
if (is_string($queue)) {
- $queue = $this->psrContext->createQueue($queue);
- }
- if (is_callable($processor)) {
- $processor = new CallbackProcessor($processor);
+ $queue = $this->interopContext->createQueue($queue);
}
- InvalidArgumentException::assertInstanceOf($queue, PsrQueue::class);
- InvalidArgumentException::assertInstanceOf($processor, PsrProcessor::class);
+ InvalidArgumentException::assertInstanceOf($queue, InteropQueue::class);
if (empty($queue->getQueueName())) {
throw new LogicException('The queue name must be not empty.');
@@ -154,326 +112,221 @@ public function bind($queue, $processor)
throw new LogicException(sprintf('The queue was already bound. Queue: %s', $queue->getQueueName()));
}
- $this->boundProcessors[$queue->getQueueName()] = [$queue, $processor];
+ $this->boundProcessors[$queue->getQueueName()] = new BoundProcessor($queue, $processor);
return $this;
}
- /**
- * Runtime extension - is an extension or a collection of extensions which could be set on runtime.
- * Here's a good example: @see LimitsExtensionsCommandTrait.
- *
- * @param ExtensionInterface|ChainExtension|null $runtimeExtension
- *
- * @throws \Exception
- */
- public function consume(ExtensionInterface $runtimeExtension = null)
+ public function bindCallback($queue, callable $processor): QueueConsumerInterface
{
- if (empty($this->boundProcessors)) {
- throw new \LogicException('There is nothing to consume. It is required to bind something before calling consume method.');
- }
-
- /** @var PsrConsumer[] $consumers */
- $consumers = [];
- /** @var PsrQueue $queue */
- foreach ($this->boundProcessors as list($queue, $processor)) {
- $consumers[$queue->getQueueName()] = $this->psrContext->createConsumer($queue);
- }
+ return $this->bind($queue, new CallbackProcessor($processor));
+ }
- $this->extension = $runtimeExtension ?
+ public function consume(?ExtensionInterface $runtimeExtension = null): void
+ {
+ $extension = $runtimeExtension ?
new ChainExtension([$this->staticExtension, $runtimeExtension]) :
$this->staticExtension
;
- $context = new Context($this->psrContext);
- $this->extension->onStart($context);
+ $initLogger = new InitLogger($this->logger);
+ $extension->onInitLogger($initLogger);
- if ($context->getLogger()) {
- $this->logger = $context->getLogger();
- } else {
- $this->logger = new NullLogger();
- $context->setLogger($this->logger);
- }
+ $this->logger = $initLogger->getLogger();
- $this->logger->info('Start consuming');
+ $startTime = (int) (microtime(true) * 1000);
- $subscriptionConsumer = null;
- if ($this->enableSubscriptionConsumer) {
- $subscriptionConsumer = new FallbackSubscriptionConsumer();
- if ($context instanceof PsrSubscriptionConsumerAwareContext) {
- $subscriptionConsumer = $context->createSubscriptionConsumer();
- }
+ $start = new Start(
+ $this->interopContext,
+ $this->logger,
+ $this->boundProcessors,
+ $this->receiveTimeout,
+ $startTime
+ );
- $callback = function (PsrMessage $message, PsrConsumer $consumer) use (&$context) {
- $currentProcessor = null;
+ $extension->onStart($start);
- /** @var PsrQueue $queue */
- foreach ($this->boundProcessors as list($queue, $processor)) {
- if ($queue->getQueueName() === $consumer->getQueue()->getQueueName()) {
- $currentProcessor = $processor;
- }
- }
+ if ($start->isExecutionInterrupted()) {
+ $this->onEnd($extension, $startTime, $start->getExitStatus());
- if (false == $currentProcessor) {
- throw new \LogicException(sprintf('The processor for the queue "%s" could not be found.', $consumer->getQueue()->getQueueName()));
- }
+ return;
+ }
- $context = new Context($this->psrContext);
- $context->setLogger($this->logger);
- $context->setPsrQueue($consumer->getQueue());
- $context->setPsrConsumer($consumer);
- $context->setPsrProcessor($currentProcessor);
- $context->setPsrMessage($message);
+ $this->logger = $start->getLogger();
+ $this->receiveTimeout = $start->getReceiveTimeout();
+ $this->boundProcessors = $start->getBoundProcessors();
- $this->doConsume($this->extension, $context);
+ if (empty($this->boundProcessors)) {
+ throw new \LogicException('There is nothing to consume. It is required to bind something before calling consume method.');
+ }
- return true;
- };
+ /** @var Consumer[] $consumers */
+ $consumers = [];
+ foreach ($this->boundProcessors as $queueName => $boundProcessor) {
+ $queue = $boundProcessor->getQueue();
- foreach ($consumers as $consumer) {
- /* @var AmqpConsumer $consumer */
+ $consumers[$queue->getQueueName()] = $this->interopContext->createConsumer($queue);
+ }
- $subscriptionConsumer->subscribe($consumer, $callback);
+ try {
+ $subscriptionConsumer = $this->interopContext->createSubscriptionConsumer();
+ } catch (SubscriptionConsumerNotSupportedException $e) {
+ $subscriptionConsumer = $this->fallbackSubscriptionConsumer;
+ }
+
+ $receivedMessagesCount = 0;
+ $interruptExecution = false;
+
+ $callback = function (InteropMessage $message, Consumer $consumer) use (&$receivedMessagesCount, &$interruptExecution, $extension) {
+ ++$receivedMessagesCount;
+
+ $receivedAt = (int) (microtime(true) * 1000);
+ $queue = $consumer->getQueue();
+ if (false == array_key_exists($queue->getQueueName(), $this->boundProcessors)) {
+ throw new \LogicException(sprintf('The processor for the queue "%s" could not be found.', $queue->getQueueName()));
}
- } elseif ($this->psrContext instanceof AmqpContext) {
- $callback = function (AmqpMessage $message, AmqpConsumer $consumer) use (&$context) {
- $currentProcessor = null;
-
- /** @var PsrQueue $queue */
- foreach ($this->boundProcessors as list($queue, $processor)) {
- if ($queue->getQueueName() === $consumer->getQueue()->getQueueName()) {
- $currentProcessor = $processor;
- }
- }
- if (false == $currentProcessor) {
- throw new \LogicException(sprintf('The processor for the queue "%s" could not be found.', $consumer->getQueue()->getQueueName()));
- }
+ $processor = $this->boundProcessors[$queue->getQueueName()]->getProcessor();
- $context = new Context($this->psrContext);
- $context->setLogger($this->logger);
- $context->setPsrQueue($consumer->getQueue());
- $context->setPsrConsumer($consumer);
- $context->setPsrProcessor($currentProcessor);
- $context->setPsrMessage($message);
+ $messageReceived = new MessageReceived($this->interopContext, $consumer, $message, $processor, $receivedAt, $this->logger);
+ $extension->onMessageReceived($messageReceived);
+ $result = $messageReceived->getResult();
+ $processor = $messageReceived->getProcessor();
+ if (null === $result) {
+ try {
+ $result = $processor->process($message, $this->interopContext);
+ } catch (\Exception|\Throwable $e) {
+ $result = $this->onProcessorException($extension, $consumer, $message, $e, $receivedAt);
+ }
+ }
- $this->doConsume($this->extension, $context);
+ $messageResult = new MessageResult($this->interopContext, $consumer, $message, $result, $receivedAt, $this->logger);
+ $extension->onResult($messageResult);
+ $result = $messageResult->getResult();
+
+ switch ($result) {
+ case Result::ACK:
+ $consumer->acknowledge($message);
+ break;
+ case Result::REJECT:
+ $consumer->reject($message, false);
+ break;
+ case Result::REQUEUE:
+ $consumer->reject($message, true);
+ break;
+ case Result::ALREADY_ACKNOWLEDGED:
+ break;
+ default:
+ throw new \LogicException(sprintf('Status is not supported: %s', $result));
+ }
- return true;
- };
+ $postMessageReceived = new PostMessageReceived($this->interopContext, $consumer, $message, $result, $receivedAt, $this->logger);
+ $extension->onPostMessageReceived($postMessageReceived);
- foreach ($consumers as $consumer) {
- /* @var AmqpConsumer $consumer */
+ if ($postMessageReceived->isExecutionInterrupted()) {
+ $interruptExecution = true;
- $this->psrContext->subscribe($consumer, $callback);
+ return false;
}
- }
- while (true) {
- try {
- if ($this->enableSubscriptionConsumer) {
- $this->extension->onBeforeReceive($context);
-
- if ($context->isExecutionInterrupted()) {
- throw new ConsumptionInterruptedException();
- }
-
- $subscriptionConsumer->consume($this->receiveTimeout);
-
- usleep($this->idleTimeout * 1000);
- $this->extension->onIdle($context);
- } elseif ($this->psrContext instanceof AmqpContext) {
- $this->extension->onBeforeReceive($context);
-
- if ($context->isExecutionInterrupted()) {
- throw new ConsumptionInterruptedException();
- }
-
- $this->psrContext->consume($this->receiveTimeout);
-
- usleep($this->idleTimeout * 1000);
- $this->extension->onIdle($context);
- } else {
- /** @var PsrQueue $queue */
- foreach ($this->boundProcessors as list($queue, $processor)) {
- $consumer = $consumers[$queue->getQueueName()];
-
- $context = new Context($this->psrContext);
- $context->setLogger($this->logger);
- $context->setPsrQueue($queue);
- $context->setPsrConsumer($consumer);
- $context->setPsrProcessor($processor);
-
- $this->doConsume($this->extension, $context);
- }
- }
- } catch (ConsumptionInterruptedException $e) {
- $this->logger->info(sprintf('Consuming interrupted'));
+ return true;
+ };
- if ($this->enableSubscriptionConsumer) {
- foreach ($consumers as $consumer) {
- /* @var PsrConsumer $consumer */
+ foreach ($consumers as $queueName => $consumer) {
+ /* @var Consumer $consumer */
- $subscriptionConsumer->unsubscribe($consumer);
- }
- } elseif ($this->psrContext instanceof AmqpContext) {
- foreach ($consumers as $consumer) {
- /* @var AmqpConsumer $consumer */
+ $preSubscribe = new PreSubscribe(
+ $this->interopContext,
+ $this->boundProcessors[$queueName]->getProcessor(),
+ $consumer,
+ $this->logger
+ );
- $this->psrContext->unsubscribe($consumer);
- }
- }
+ $extension->onPreSubscribe($preSubscribe);
- $context->setExecutionInterrupted(true);
+ $subscriptionConsumer->subscribe($consumer, $callback);
+ }
+
+ $cycle = 1;
+ while (true) {
+ $receivedMessagesCount = 0;
+ $interruptExecution = false;
+
+ $preConsume = new PreConsume($this->interopContext, $subscriptionConsumer, $this->logger, $cycle, $this->receiveTimeout, $startTime);
+ $extension->onPreConsume($preConsume);
- $this->extension->onInterrupted($context);
+ if ($preConsume->isExecutionInterrupted()) {
+ $this->onEnd($extension, $startTime, $preConsume->getExitStatus(), $subscriptionConsumer);
return;
- } catch (\Exception $exception) {
- $context->setExecutionInterrupted(true);
- $context->setException($exception);
+ }
- try {
- $this->onInterruptionByException($this->extension, $context);
- } catch (\Exception $e) {
- // for some reason finally does not work here on php5.5
+ $subscriptionConsumer->consume($this->receiveTimeout);
- throw $e;
- }
+ $postConsume = new PostConsume($this->interopContext, $subscriptionConsumer, $receivedMessagesCount, $cycle, $startTime, $this->logger);
+ $extension->onPostConsume($postConsume);
+
+ if ($interruptExecution || $postConsume->isExecutionInterrupted()) {
+ $this->onEnd($extension, $startTime, $postConsume->getExitStatus(), $subscriptionConsumer);
+
+ return;
}
+
+ ++$cycle;
}
}
/**
- * @param bool $enableSubscriptionConsumer
- * @throws \Enqueue\Consumption\Exception\InvalidArgumentException
+ * @internal
*/
- public function enableSubscriptionConsumer($enableSubscriptionConsumer)
+ public function setFallbackSubscriptionConsumer(SubscriptionConsumer $fallbackSubscriptionConsumer): void
{
- if (!is_bool($enableSubscriptionConsumer)) {
- throw new InvalidArgumentException(
- sprintf(
- 'The argument must be a boolean but got %s.',
- is_object($enableSubscriptionConsumer) ? get_class($enableSubscriptionConsumer) : gettype($enableSubscriptionConsumer)
- )
- );
- }
-
- $this->enableSubscriptionConsumer = $enableSubscriptionConsumer;
+ $this->fallbackSubscriptionConsumer = $fallbackSubscriptionConsumer;
}
- /**
- * @param ExtensionInterface $extension
- * @param Context $context
- *
- * @throws ConsumptionInterruptedException
- *
- * @return bool
- */
- protected function doConsume(ExtensionInterface $extension, Context $context)
+ private function onEnd(ExtensionInterface $extension, int $startTime, ?int $exitStatus = null, ?SubscriptionConsumer $subscriptionConsumer = null): void
{
- $processor = $context->getPsrProcessor();
- $consumer = $context->getPsrConsumer();
- $this->logger = $context->getLogger();
-
- if ($context->isExecutionInterrupted()) {
- throw new ConsumptionInterruptedException();
- }
-
- $message = $context->getPsrMessage();
- if (false == $message) {
- $this->extension->onBeforeReceive($context);
+ $endTime = (int) (microtime(true) * 1000);
- if ($message = $consumer->receive($this->receiveTimeout)) {
- $context->setPsrMessage($message);
- }
- }
+ $endContext = new End($this->interopContext, $startTime, $endTime, $this->logger, $exitStatus);
+ $extension->onEnd($endContext);
- if ($message) {
- $this->processMessage($consumer, $processor, $message, $context);
- } else {
- usleep($this->idleTimeout * 1000);
- $this->extension->onIdle($context);
- }
-
- if ($context->isExecutionInterrupted()) {
- throw new ConsumptionInterruptedException();
+ if ($subscriptionConsumer) {
+ $subscriptionConsumer->unsubscribeAll();
}
}
/**
- * @param ExtensionInterface $extension
- * @param Context $context
+ * The logic is similar to one in Symfony's ExceptionListener::onKernelException().
*
- * @throws \Exception
+ * https://github.com/symfony/symfony/blob/cbe289517470eeea27162fd2d523eb29c95f775f/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php#L77
*/
- protected function onInterruptionByException(ExtensionInterface $extension, Context $context)
+ private function onProcessorException(ExtensionInterface $extension, Consumer $consumer, Message $message, \Throwable $exception, int $receivedAt)
{
- $this->logger = $context->getLogger();
- $this->logger->error(sprintf('Consuming interrupted by exception'));
-
- $exception = $context->getException();
+ $processorException = new ProcessorException($this->interopContext, $consumer, $message, $exception, $receivedAt, $this->logger);
try {
- $this->extension->onInterrupted($context);
+ $extension->onProcessorException($processorException);
+
+ $result = $processorException->getResult();
+ if (null === $result) {
+ throw $exception;
+ }
+
+ return $result;
} catch (\Exception $e) {
- // logic is similar to one in Symfony's ExceptionListener::onKernelException
- $this->logger->error(sprintf(
- 'Exception thrown when handling an exception (%s: %s at %s line %s)',
- get_class($e),
- $e->getMessage(),
- $e->getFile(),
- $e->getLine()
- ));
-
- $wrapper = $e;
- while ($prev = $wrapper->getPrevious()) {
+ $prev = $e;
+ do {
if ($exception === $wrapper = $prev) {
throw $e;
}
- }
+ } while ($prev = $wrapper->getPrevious());
- $prev = new \ReflectionProperty('Exception', 'previous');
+ $prev = new \ReflectionProperty($wrapper instanceof \Exception ? \Exception::class : \Error::class, 'previous');
$prev->setAccessible(true);
$prev->setValue($wrapper, $exception);
throw $e;
}
-
- throw $exception;
- }
-
- private function processMessage(PsrConsumer $consumer, PsrProcessor $processor, PsrMessage $message, Context $context)
- {
- $this->logger->info('Message received from the queue: '.$context->getPsrQueue()->getQueueName());
- $this->logger->debug('Headers: {headers}', ['headers' => new VarExport($message->getHeaders())]);
- $this->logger->debug('Properties: {properties}', ['properties' => new VarExport($message->getProperties())]);
- $this->logger->debug('Payload: {payload}', ['payload' => new VarExport($message->getBody())]);
-
- $this->extension->onPreReceived($context);
- if (!$context->getResult()) {
- $result = $processor->process($message, $this->psrContext);
- $context->setResult($result);
- }
-
- $this->extension->onResult($context);
-
- switch ($context->getResult()) {
- case Result::ACK:
- $consumer->acknowledge($message);
- break;
- case Result::REJECT:
- $consumer->reject($message, false);
- break;
- case Result::REQUEUE:
- $consumer->reject($message, true);
- break;
- default:
- throw new \LogicException(sprintf('Status is not supported: %s', $context->getResult()));
- }
-
- $this->logger->info(sprintf('Message processed: %s', $context->getResult()));
-
- $this->extension->onPostReceived($context);
}
}
diff --git a/pkg/enqueue/Consumption/QueueConsumerInterface.php b/pkg/enqueue/Consumption/QueueConsumerInterface.php
new file mode 100644
index 000000000..ee2565252
--- /dev/null
+++ b/pkg/enqueue/Consumption/QueueConsumerInterface.php
@@ -0,0 +1,40 @@
+status = (string) $status;
@@ -72,17 +70,14 @@ public function getReason()
}
/**
- * @return PsrMessage|null
+ * @return InteropMessage|null
*/
public function getReply()
{
return $this->reply;
}
- /**
- * @param PsrMessage|null $reply
- */
- public function setReply(PsrMessage $reply = null)
+ public function setReply(?InteropMessage $reply = null)
{
$this->reply = $reply;
}
@@ -94,7 +89,7 @@ public function setReply(PsrMessage $reply = null)
*/
public static function ack($reason = '')
{
- return new static(self::ACK, $reason);
+ return new self(self::ACK, $reason);
}
/**
@@ -104,7 +99,7 @@ public static function ack($reason = '')
*/
public static function reject($reason)
{
- return new static(self::REJECT, $reason);
+ return new self(self::REJECT, $reason);
}
/**
@@ -114,21 +109,20 @@ public static function reject($reason)
*/
public static function requeue($reason = '')
{
- return new static(self::REQUEUE, $reason);
+ return new self(self::REQUEUE, $reason);
}
/**
- * @param PsrMessage $replyMessage
* @param string $status
* @param string|null $reason
*
* @return static
*/
- public static function reply(PsrMessage $replyMessage, $status = self::ACK, $reason = null)
+ public static function reply(InteropMessage $replyMessage, $status = self::ACK, $reason = null)
{
$status = null === $status ? self::ACK : $status;
- $result = new static($status, $reason);
+ $result = new self($status, $reason);
$result->setReply($replyMessage);
return $result;
diff --git a/pkg/enqueue/Consumption/StartExtensionInterface.php b/pkg/enqueue/Consumption/StartExtensionInterface.php
new file mode 100644
index 000000000..98571061c
--- /dev/null
+++ b/pkg/enqueue/Consumption/StartExtensionInterface.php
@@ -0,0 +1,13 @@
+services = $services;
+ }
+
+ public function get($id)
+ {
+ if (false == $this->has($id)) {
+ throw new NotFoundException(sprintf('The service "%s" not found.', $id));
+ }
+
+ return $this->services[$id];
+ }
+
+ public function has(string $id): bool
+ {
+ return array_key_exists($id, $this->services);
+ }
+}
diff --git a/pkg/enqueue/Container/NotFoundException.php b/pkg/enqueue/Container/NotFoundException.php
new file mode 100644
index 000000000..fcc3386e6
--- /dev/null
+++ b/pkg/enqueue/Container/NotFoundException.php
@@ -0,0 +1,9 @@
+doctrine = $doctrine;
+ $this->fallbackFactory = $fallbackFactory;
+ }
+
+ public function create($config): ConnectionFactory
+ {
+ if (is_string($config)) {
+ $config = ['dsn' => $config];
+ }
+
+ if (false == is_array($config)) {
+ throw new \InvalidArgumentException('The config must be either array or DSN string.');
+ }
+
+ if (false == array_key_exists('dsn', $config)) {
+ throw new \InvalidArgumentException('The config must have dsn key set.');
+ }
+
+ $dsn = Dsn::parseFirst($config['dsn']);
+
+ if ('doctrine' === $dsn->getScheme()) {
+ $config = $dsn->getQuery();
+ $config['connection_name'] = $dsn->getHost();
+
+ return new ManagerRegistryConnectionFactory($this->doctrine, $config);
+ }
+
+ return $this->fallbackFactory->create($config);
+ }
+}
diff --git a/pkg/enqueue/Doctrine/DoctrineDriverFactory.php b/pkg/enqueue/Doctrine/DoctrineDriverFactory.php
new file mode 100644
index 000000000..aab6489aa
--- /dev/null
+++ b/pkg/enqueue/Doctrine/DoctrineDriverFactory.php
@@ -0,0 +1,41 @@
+fallbackFactory = $fallbackFactory;
+ }
+
+ public function create(ConnectionFactory $factory, Config $config, RouteCollection $collection): DriverInterface
+ {
+ $dsn = $config->getTransportOption('dsn');
+
+ if (empty($dsn)) {
+ throw new \LogicException('This driver factory relies on dsn option from transport config. The option is empty or not set.');
+ }
+
+ $dsn = Dsn::parseFirst($dsn);
+
+ if ('doctrine' === $dsn->getScheme()) {
+ return new DbalDriver($factory->createContext(), $config, $collection);
+ }
+
+ return $this->fallbackFactory->create($factory, $config, $collection);
+ }
+}
diff --git a/pkg/enqueue/Doctrine/DoctrineSchemaCompilerPass.php b/pkg/enqueue/Doctrine/DoctrineSchemaCompilerPass.php
new file mode 100644
index 000000000..0eb378470
--- /dev/null
+++ b/pkg/enqueue/Doctrine/DoctrineSchemaCompilerPass.php
@@ -0,0 +1,39 @@
+hasDefinition('doctrine')) {
+ return;
+ }
+
+ foreach ($container->getParameter('enqueue.transports') as $name) {
+ $diUtils = DiUtils::create(TransportFactory::MODULE, $name);
+
+ $container->register($diUtils->format('connection_factory_factory.outer'), DoctrineConnectionFactoryFactory::class)
+ ->setDecoratedService($diUtils->format('connection_factory_factory'), $diUtils->format('connection_factory_factory.inner'))
+ ->addArgument(new Reference('doctrine'))
+ ->addArgument(new Reference($diUtils->format('connection_factory_factory.inner')))
+ ;
+ }
+
+ foreach ($container->getParameter('enqueue.clients') as $name) {
+ $diUtils = DiUtils::create(ClientFactory::MODULE, $name);
+
+ $container->register($diUtils->format('driver_factory.outer'), DoctrineDriverFactory::class)
+ ->setDecoratedService($diUtils->format('driver_factory'), $diUtils->format('driver_factory.inner'))
+ ->addArgument(new Reference($diUtils->format('driver_factory.inner')))
+ ;
+ }
+ }
+}
diff --git a/pkg/enqueue/ProcessorRegistryInterface.php b/pkg/enqueue/ProcessorRegistryInterface.php
new file mode 100644
index 000000000..5306c3035
--- /dev/null
+++ b/pkg/enqueue/ProcessorRegistryInterface.php
@@ -0,0 +1,12 @@
+Supporting Enqueue
+
+Enqueue is an MIT-licensed open source project with its ongoing development made possible entirely by the support of community and our customers. If you'd like to join them, please consider:
+
+- [Become a sponsor](https://www.patreon.com/makasim)
+- [Become our client](http://forma-pro.com/)
+
+---
+
# Message Queue.
[](https://gitter.im/php-enqueue/Lobby)
-[](https://travis-ci.org/php-enqueue/enqueue)
+[](https://github.com/php-enqueue/enqueue/actions?query=workflow%3ACI)
[](https://packagist.org/packages/enqueue/enqueue)
[](https://packagist.org/packages/enqueue/enqueue)
-
-It contains advanced features build on top of a transport component.
+
+It contains advanced features build on top of a transport component.
Client component kind of plug and play things or consumption component that simplify message processing a lot.
-Read more about it in documentation.
+Read more about it in documentation.
## Resources
* [Site](https://enqueue.forma-pro.com/)
-* [Documentation](https://github.com/php-enqueue/enqueue-dev/blob/master/docs/index.md)
+* [Documentation](https://php-enqueue.github.io/)
* [Questions](https://gitter.im/php-enqueue/Lobby)
* [Issue Tracker](https://github.com/php-enqueue/enqueue-dev/issues)
## Developed by Forma-Pro
-Forma-Pro is a full stack development company which interests also spread to open source development.
-Being a team of strong professionals we have an aim an ability to help community by developing cutting edge solutions in the areas of e-commerce, docker & microservice oriented architecture where we have accumulated a huge many-years experience.
+Forma-Pro is a full stack development company which interests also spread to open source development.
+Being a team of strong professionals we have an aim an ability to help community by developing cutting edge solutions in the areas of e-commerce, docker & microservice oriented architecture where we have accumulated a huge many-years experience.
Our main specialization is Symfony framework based solution, but we are always looking to the technologies that allow us to do our job the best way. We are committed to creating solutions that revolutionize the way how things are developed in aspects of architecture & scalability.
If you have any questions and inquires about our open source development, this product particularly or any other matter feel free to contact at opensource@forma-pro.com
## License
-It is released under the [MIT License](LICENSE).
\ No newline at end of file
+It is released under the [MIT License](LICENSE).
diff --git a/pkg/enqueue/Resources.php b/pkg/enqueue/Resources.php
new file mode 100644
index 000000000..4c500006f
--- /dev/null
+++ b/pkg/enqueue/Resources.php
@@ -0,0 +1,211 @@
+ [
+ * schemes => [schemes strings],
+ * package => package name,
+ * ].
+ *
+ * @var array
+ */
+ private static $knownConnections;
+
+ private function __construct()
+ {
+ }
+
+ public static function getAvailableConnections(): array
+ {
+ $map = self::getKnownConnections();
+
+ $availableMap = [];
+ foreach ($map as $connectionClass => $item) {
+ if (\class_exists($connectionClass)) {
+ $availableMap[$connectionClass] = $item;
+ }
+ }
+
+ return $availableMap;
+ }
+
+ public static function getKnownSchemes(): array
+ {
+ $map = self::getKnownConnections();
+
+ $schemes = [];
+ foreach ($map as $connectionClass => $item) {
+ foreach ($item['schemes'] as $scheme) {
+ $schemes[$scheme] = $connectionClass;
+ }
+ }
+
+ return $schemes;
+ }
+
+ public static function getAvailableSchemes(): array
+ {
+ $map = self::getAvailableConnections();
+
+ $schemes = [];
+ foreach ($map as $connectionClass => $item) {
+ foreach ($item['schemes'] as $scheme) {
+ $schemes[$scheme] = $connectionClass;
+ }
+ }
+
+ return $schemes;
+ }
+
+ public static function getKnownConnections(): array
+ {
+ if (null === self::$knownConnections) {
+ $map = [];
+
+ $map[FsConnectionFactory::class] = [
+ 'schemes' => ['file'],
+ 'supportedSchemeExtensions' => [],
+ 'package' => 'enqueue/fs',
+ ];
+ $map[AmqpBunnyConnectionFactory::class] = [
+ 'schemes' => ['amqp'],
+ 'supportedSchemeExtensions' => ['bunny'],
+ 'package' => 'enqueue/amqp-bunny',
+ ];
+ $map[AmqpExtConnectionFactory::class] = [
+ 'schemes' => ['amqp', 'amqps'],
+ 'supportedSchemeExtensions' => ['ext'],
+ 'package' => 'enqueue/amqp-ext',
+ ];
+ $map[AmqpLibConnectionFactory::class] = [
+ 'schemes' => ['amqp', 'amqps'],
+ 'supportedSchemeExtensions' => ['lib'],
+ 'package' => 'enqueue/amqp-lib',
+ ];
+
+ $map[DbalConnectionFactory::class] = [
+ 'schemes' => [
+ 'db2',
+ 'ibm-db2',
+ 'mssql',
+ 'sqlsrv',
+ 'mysql',
+ 'mysql2',
+ 'mysql',
+ 'pgsql',
+ 'postgres',
+ 'sqlite',
+ 'sqlite3',
+ 'sqlite',
+ ],
+ 'supportedSchemeExtensions' => ['pdo'],
+ 'package' => 'enqueue/dbal',
+ ];
+
+ $map[NullConnectionFactory::class] = [
+ 'schemes' => ['null'],
+ 'supportedSchemeExtensions' => [],
+ 'package' => 'enqueue/null',
+ ];
+ $map[GearmanConnectionFactory::class] = [
+ 'schemes' => ['gearman'],
+ 'supportedSchemeExtensions' => [],
+ 'package' => 'enqueue/gearman',
+ ];
+ $map[PheanstalkConnectionFactory::class] = [
+ 'schemes' => ['beanstalk'],
+ 'supportedSchemeExtensions' => ['pheanstalk'],
+ 'package' => 'enqueue/pheanstalk',
+ ];
+ $map[RdKafkaConnectionFactory::class] = [
+ 'schemes' => ['kafka', 'rdkafka'],
+ 'supportedSchemeExtensions' => ['rdkafka'],
+ 'package' => 'enqueue/rdkafka',
+ ];
+ $map[RedisConnectionFactory::class] = [
+ 'schemes' => ['redis', 'rediss'],
+ 'supportedSchemeExtensions' => ['predis', 'phpredis'],
+ 'package' => 'enqueue/redis',
+ ];
+ $map[StompConnectionFactory::class] = [
+ 'schemes' => ['stomp'],
+ 'supportedSchemeExtensions' => ['rabbitmq'],
+ 'package' => 'enqueue/stomp', ];
+ $map[SqsConnectionFactory::class] = [
+ 'schemes' => ['sqs'],
+ 'supportedSchemeExtensions' => [],
+ 'package' => 'enqueue/sqs', ];
+ $map[SnsConnectionFactory::class] = [
+ 'schemes' => ['sns'],
+ 'supportedSchemeExtensions' => [],
+ 'package' => 'enqueue/sns', ];
+ $map[SnsQsConnectionFactory::class] = [
+ 'schemes' => ['snsqs'],
+ 'supportedSchemeExtensions' => [],
+ 'package' => 'enqueue/snsqs', ];
+ $map[GpsConnectionFactory::class] = [
+ 'schemes' => ['gps'],
+ 'supportedSchemeExtensions' => [],
+ 'package' => 'enqueue/gps', ];
+ $map[MongodbConnectionFactory::class] = [
+ 'schemes' => ['mongodb'],
+ 'supportedSchemeExtensions' => [],
+ 'package' => 'enqueue/mongodb',
+ ];
+ $map[WampConnectionFactory::class] = [
+ 'schemes' => ['wamp', 'ws'],
+ 'supportedSchemeExtensions' => [],
+ 'package' => 'enqueue/wamp',
+ ];
+
+ self::$knownConnections = $map;
+ }
+
+ return self::$knownConnections;
+ }
+
+ public static function addConnection(string $connectionFactoryClass, array $schemes, array $extensions, string $package): void
+ {
+ if (\class_exists($connectionFactoryClass)) {
+ if (false == (new \ReflectionClass($connectionFactoryClass))->implementsInterface(ConnectionFactory::class)) {
+ throw new \InvalidArgumentException(\sprintf('The connection factory class "%s" must implement "%s" interface.', $connectionFactoryClass, ConnectionFactory::class));
+ }
+ }
+
+ if (empty($schemes)) {
+ throw new \InvalidArgumentException('Schemes could not be empty.');
+ }
+ if (empty($package)) {
+ throw new \InvalidArgumentException('Package name could not be empty.');
+ }
+
+ self::getKnownConnections();
+ self::$knownConnections[$connectionFactoryClass] = [
+ 'schemes' => $schemes,
+ 'supportedSchemeExtensions' => $extensions,
+ 'package' => $package,
+ ];
+ }
+}
diff --git a/pkg/enqueue/Router/Recipient.php b/pkg/enqueue/Router/Recipient.php
index dc0ab4260..d2f668f42 100644
--- a/pkg/enqueue/Router/Recipient.php
+++ b/pkg/enqueue/Router/Recipient.php
@@ -2,33 +2,29 @@
namespace Enqueue\Router;
-use Interop\Queue\PsrDestination;
-use Interop\Queue\PsrMessage;
+use Interop\Queue\Destination;
+use Interop\Queue\Message as InteropMessage;
class Recipient
{
/**
- * @var PsrDestination
+ * @var Destination
*/
private $destination;
/**
- * @var PsrMessage
+ * @var InteropMessage
*/
private $message;
- /**
- * @param PsrDestination $destination
- * @param PsrMessage $message
- */
- public function __construct(PsrDestination $destination, PsrMessage $message)
+ public function __construct(Destination $destination, InteropMessage $message)
{
$this->destination = $destination;
$this->message = $message;
}
/**
- * @return PsrDestination
+ * @return Destination
*/
public function getDestination()
{
@@ -36,7 +32,7 @@ public function getDestination()
}
/**
- * @return PsrMessage
+ * @return InteropMessage
*/
public function getMessage()
{
diff --git a/pkg/enqueue/Router/RecipientListRouterInterface.php b/pkg/enqueue/Router/RecipientListRouterInterface.php
index 78a354c6a..6bb950fdc 100644
--- a/pkg/enqueue/Router/RecipientListRouterInterface.php
+++ b/pkg/enqueue/Router/RecipientListRouterInterface.php
@@ -2,14 +2,12 @@
namespace Enqueue\Router;
-use Interop\Queue\PsrMessage;
+use Interop\Queue\Message as InteropMessage;
interface RecipientListRouterInterface
{
/**
- * @param PsrMessage $message
- *
* @return \Traversable|Recipient[]
*/
- public function route(PsrMessage $message);
+ public function route(InteropMessage $message);
}
diff --git a/pkg/enqueue/Router/RouteRecipientListProcessor.php b/pkg/enqueue/Router/RouteRecipientListProcessor.php
index 59df35510..22488e33f 100644
--- a/pkg/enqueue/Router/RouteRecipientListProcessor.php
+++ b/pkg/enqueue/Router/RouteRecipientListProcessor.php
@@ -2,29 +2,23 @@
namespace Enqueue\Router;
-use Interop\Queue\PsrContext;
-use Interop\Queue\PsrMessage;
-use Interop\Queue\PsrProcessor;
+use Interop\Queue\Context;
+use Interop\Queue\Message as InteropMessage;
+use Interop\Queue\Processor;
-class RouteRecipientListProcessor implements PsrProcessor
+class RouteRecipientListProcessor implements Processor
{
/**
* @var RecipientListRouterInterface
*/
private $router;
- /**
- * @param RecipientListRouterInterface $router
- */
public function __construct(RecipientListRouterInterface $router)
{
$this->router = $router;
}
- /**
- * {@inheritdoc}
- */
- public function process(PsrMessage $message, PsrContext $context)
+ public function process(InteropMessage $message, Context $context)
{
$producer = $context->createProducer();
foreach ($this->router->route($message) as $recipient) {
diff --git a/pkg/enqueue/Rpc/Promise.php b/pkg/enqueue/Rpc/Promise.php
index 91e0aaa22..01b47e1f6 100644
--- a/pkg/enqueue/Rpc/Promise.php
+++ b/pkg/enqueue/Rpc/Promise.php
@@ -2,7 +2,7 @@
namespace Enqueue\Rpc;
-use Interop\Queue\PsrMessage;
+use Interop\Queue\Message as InteropMessage;
class Promise
{
@@ -27,15 +27,10 @@ class Promise
private $deleteReplyQueue;
/**
- * @var PsrMessage
+ * @var InteropMessage
*/
private $message;
- /**
- * @param \Closure $receiveCallback
- * @param \Closure $receiveNoWaitCallback
- * @param \Closure $finallyCallback
- */
public function __construct(\Closure $receiveCallback, \Closure $receiveNoWaitCallback, \Closure $finallyCallback)
{
$this->receiveCallback = $receiveCallback;
@@ -52,7 +47,7 @@ public function __construct(\Closure $receiveCallback, \Closure $receiveNoWaitCa
*
* @throws TimeoutException if the wait timeout is reached
*
- * @return PsrMessage
+ * @return InteropMessage
*/
public function receive($timeout = null)
{
@@ -72,7 +67,7 @@ public function receive($timeout = null)
/**
* Non blocking function. Returns message or null.
*
- * @return PsrMessage|null
+ * @return InteropMessage|null
*/
public function receiveNoWait()
{
@@ -106,18 +101,16 @@ public function isDeleteReplyQueue()
}
/**
- * @param \Closure $cb
- * @param array $args
+ * @param array $args
*
- * @return PsrMessage
+ * @return InteropMessage
*/
private function doReceive(\Closure $cb, ...$args)
{
$message = call_user_func_array($cb, $args);
- if (null !== $message && false == $message instanceof PsrMessage) {
- throw new \RuntimeException(sprintf(
- 'Expected "%s" but got: "%s"', PsrMessage::class, is_object($message) ? get_class($message) : gettype($message)));
+ if (null !== $message && false == $message instanceof InteropMessage) {
+ throw new \RuntimeException(sprintf('Expected "%s" but got: "%s"', InteropMessage::class, is_object($message) ? $message::class : gettype($message)));
}
return $message;
diff --git a/pkg/enqueue/Rpc/RpcClient.php b/pkg/enqueue/Rpc/RpcClient.php
index d429ac9af..bd3d7cedb 100644
--- a/pkg/enqueue/Rpc/RpcClient.php
+++ b/pkg/enqueue/Rpc/RpcClient.php
@@ -3,14 +3,14 @@
namespace Enqueue\Rpc;
use Enqueue\Util\UUID;
-use Interop\Queue\PsrContext;
-use Interop\Queue\PsrDestination;
-use Interop\Queue\PsrMessage;
+use Interop\Queue\Context;
+use Interop\Queue\Destination;
+use Interop\Queue\Message as InteropMessage;
class RpcClient
{
/**
- * @var PsrContext
+ * @var Context
*/
private $context;
@@ -19,38 +19,30 @@ class RpcClient
*/
private $rpcFactory;
- /**
- * @param PsrContext $context
- * @param RpcFactory $promiseFactory
- */
- public function __construct(PsrContext $context, RpcFactory $promiseFactory = null)
+ public function __construct(Context $context, ?RpcFactory $promiseFactory = null)
{
$this->context = $context;
$this->rpcFactory = $promiseFactory ?: new RpcFactory($context);
}
/**
- * @param PsrDestination $destination
- * @param PsrMessage $message
- * @param int $timeout
+ * @param int $timeout
*
* @throws TimeoutException if the wait timeout is reached
*
- * @return PsrMessage
+ * @return InteropMessage
*/
- public function call(PsrDestination $destination, PsrMessage $message, $timeout)
+ public function call(Destination $destination, InteropMessage $message, $timeout)
{
return $this->callAsync($destination, $message, $timeout)->receive();
}
/**
- * @param PsrDestination $destination
- * @param PsrMessage $message
- * @param int $timeout
+ * @param int $timeout
*
* @return Promise
*/
- public function callAsync(PsrDestination $destination, PsrMessage $message, $timeout)
+ public function callAsync(Destination $destination, InteropMessage $message, $timeout)
{
if ($timeout < 1) {
throw new \InvalidArgumentException(sprintf('Timeout must be positive not zero integer. Got %s', $timeout));
diff --git a/pkg/enqueue/Rpc/RpcFactory.php b/pkg/enqueue/Rpc/RpcFactory.php
index 195fd959a..9100babd3 100644
--- a/pkg/enqueue/Rpc/RpcFactory.php
+++ b/pkg/enqueue/Rpc/RpcFactory.php
@@ -2,19 +2,16 @@
namespace Enqueue\Rpc;
-use Interop\Queue\PsrContext;
+use Interop\Queue\Context;
class RpcFactory
{
/**
- * @var PsrContext
+ * @var Context
*/
private $context;
- /**
- * @param PsrContext $context
- */
- public function __construct(PsrContext $context)
+ public function __construct(Context $context)
{
$this->context = $context;
}
diff --git a/pkg/enqueue/Rpc/TimeoutException.php b/pkg/enqueue/Rpc/TimeoutException.php
index a0b065511..a7f68b967 100644
--- a/pkg/enqueue/Rpc/TimeoutException.php
+++ b/pkg/enqueue/Rpc/TimeoutException.php
@@ -12,6 +12,6 @@ class TimeoutException extends \LogicException
*/
public static function create($timeout, $correlationId)
{
- return new static(sprintf('Rpc call timeout is reached without receiving a reply message. Timeout: %s, CorrelationId: %s', $timeout, $correlationId));
+ return new self(sprintf('Rpc call timeout is reached without receiving a reply message. Timeout: %s, CorrelationId: %s', $timeout, $correlationId));
}
}
diff --git a/pkg/enqueue/Symfony/AmqpTransportFactory.php b/pkg/enqueue/Symfony/AmqpTransportFactory.php
deleted file mode 100644
index e69bf44de..000000000
--- a/pkg/enqueue/Symfony/AmqpTransportFactory.php
+++ /dev/null
@@ -1,253 +0,0 @@
-name = $name;
- }
-
- /**
- * {@inheritdoc}
- */
- public function addConfiguration(ArrayNodeDefinition $builder)
- {
- $transportsMap = static::getAvailableTransportsMap();
-
- $builder
- ->beforeNormalization()
- ->ifTrue(function ($v) {
- return empty($v);
- })
- ->then(function ($v) {
- return ['dsn' => 'amqp:'];
- })
- ->ifString()
- ->then(function ($v) {
- return ['dsn' => $v];
- })
- ->end()
- ->children()
- ->scalarNode('driver')
- ->validate()
- ->always(function ($v) use ($transportsMap) {
- $drivers = array_keys($transportsMap);
- if (empty($transportsMap)) {
- throw new \InvalidArgumentException('There is no amqp driver available. Please consider installing one of the packages: enqueue/amqp-ext, enqueue/amqp-lib, enqueue/amqp-bunny.');
- }
-
- if ($v && false == in_array($v, $drivers, true)) {
- throw new \InvalidArgumentException(sprintf('Unexpected driver given "%s". Available are "%s"', $v, implode('", "', $drivers)));
- }
-
- return $v;
- })
- ->end()
- ->end()
- ->scalarNode('dsn')
- ->info('The connection to AMQP broker set as a string. Other parameters could be used as defaults')
- ->end()
- ->scalarNode('host')
- ->info('The host to connect too. Note: Max 1024 characters')
- ->end()
- ->scalarNode('port')
- ->info('Port on the host.')
- ->end()
- ->scalarNode('user')
- ->info('The user name to use. Note: Max 128 characters.')
- ->end()
- ->scalarNode('pass')
- ->info('Password. Note: Max 128 characters.')
- ->end()
- ->scalarNode('vhost')
- ->info('The virtual host on the host. Note: Max 128 characters.')
- ->end()
- ->floatNode('connection_timeout')
- ->min(0)
- ->info('Connection timeout. Note: 0 or greater seconds. May be fractional.')
- ->end()
- ->floatNode('read_timeout')
- ->min(0)
- ->info('Timeout in for income activity. Note: 0 or greater seconds. May be fractional.')
- ->end()
- ->floatNode('write_timeout')
- ->min(0)
- ->info('Timeout in for outcome activity. Note: 0 or greater seconds. May be fractional.')
- ->end()
- ->floatNode('heartbeat')
- ->min(0)
- ->info('How often to send heartbeat. 0 means off.')
- ->end()
- ->booleanNode('persisted')->end()
- ->booleanNode('lazy')->end()
- ->enumNode('receive_method')
- ->values(['basic_get', 'basic_consume'])
- ->info('The receive strategy to be used. We suggest to use basic_consume as it is more performant. Though you need AMQP extension 1.9.1 or higher')
- ->end()
- ->floatNode('qos_prefetch_size')
- ->min(0)
- ->info('The server will send a message in advance if it is equal to or smaller in size than the available prefetch size. May be set to zero, meaning "no specific limit"')
- ->end()
- ->floatNode('qos_prefetch_count')
- ->min(0)
- ->info('Specifies a prefetch window in terms of whole messages')
- ->end()
- ->booleanNode('qos_global')
- ->info('If "false" the QoS settings apply to the current channel only. If this field is "true", they are applied to the entire connection.')
- ->end()
- ->variableNode('driver_options')
- ->info('The options that are specific to the amqp transport you chose. For example amqp+lib have insist, keepalive, stream options. amqp+bunny has tcp_nodelay extra option.')
- ->end()
- ->booleanNode('ssl_on')
- ->info('Should be true if you want to use secure connections. False by default')
- ->end()
- ->booleanNode('ssl_verify')
- ->info('This option determines whether ssl client verifies that the server cert is for the server it is known as. True by default.')
- ->end()
- ->scalarNode('ssl_cacert')
- ->info('Location of Certificate Authority file on local filesystem which should be used with the verify_peer context option to authenticate the identity of the remote peer. A string.')
- ->end()
- ->scalarNode('ssl_cert')
- ->info('Path to local certificate file on filesystem. It must be a PEM encoded file which contains your certificate and private key. A string')
- ->end()
- ->scalarNode('ssl_key')
- ->info('Path to local private key file on filesystem in case of separate files for certificate (local_cert) and private key. A string.')
- ->end()
- ;
- }
-
- /**
- * {@inheritdoc}
- */
- public function createConnectionFactory(ContainerBuilder $container, array $config)
- {
- if (array_key_exists('driver_options', $config) && is_array($config['driver_options'])) {
- $driverOptions = $config['driver_options'];
- unset($config['driver_options']);
-
- $config = array_replace($driverOptions, $config);
- }
-
- $factory = new Definition(AmqpConnectionFactory::class);
- $factory->setFactory([self::class, 'createConnectionFactoryFactory']);
- $factory->setArguments([$config]);
-
- $factoryId = sprintf('enqueue.transport.%s.connection_factory', $this->getName());
- $container->setDefinition($factoryId, $factory);
-
- return $factoryId;
- }
-
- /**
- * {@inheritdoc}
- */
- public function createContext(ContainerBuilder $container, array $config)
- {
- $factoryId = sprintf('enqueue.transport.%s.connection_factory', $this->getName());
-
- $context = new Definition(AmqpContext::class);
- $context->setPublic(true);
- $context->setFactory([new Reference($factoryId), 'createContext']);
-
- $contextId = sprintf('enqueue.transport.%s.context', $this->getName());
- $container->setDefinition($contextId, $context);
-
- return $contextId;
- }
-
- /**
- * {@inheritdoc}
- */
- public function createDriver(ContainerBuilder $container, array $config)
- {
- $driver = new Definition(AmqpDriver::class);
- $driver->setPublic(true);
- $driver->setArguments([
- new Reference(sprintf('enqueue.transport.%s.context', $this->getName())),
- new Reference('enqueue.client.config'),
- new Reference('enqueue.client.meta.queue_meta_registry'),
- ]);
-
- $driverId = sprintf('enqueue.client.%s.driver', $this->getName());
- $container->setDefinition($driverId, $driver);
-
- return $driverId;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return $this->name;
- }
-
- public static function createConnectionFactoryFactory(array $config)
- {
- if (false == empty($config['driver'])) {
- $transportsMap = static::getAvailableTransportsMap();
-
- if (false == array_key_exists($config['driver'], $transportsMap)) {
- throw new \InvalidArgumentException(sprintf('Unexpected driver given "invalidDriver". Available are "%s"', implode('", "', array_keys($transportsMap))));
- }
-
- $connectionFactoryClass = $transportsMap[$config['driver']];
-
- unset($config['driver']);
-
- return new $connectionFactoryClass($config);
- }
-
- $dsn = array_key_exists('dsn', $config) ? $config['dsn'] : 'amqp:';
- $factory = dsn_to_connection_factory($dsn);
-
- if (false == $factory instanceof AmqpConnectionFactory) {
- throw new \LogicException(sprintf('Factory must be instance of "%s" but got "%s"', AmqpConnectionFactory::class, get_class($factory)));
- }
-
- $factoryClass = get_class($factory);
-
- return new $factoryClass($config);
- }
-
- /**
- * @return string[]
- */
- private static function getAvailableTransportsMap()
- {
- $map = [];
- if (class_exists(AmqpExtConnectionFactory::class)) {
- $map['ext'] = AmqpExtConnectionFactory::class;
- }
- if (class_exists(AmqpLibConnectionFactory::class)) {
- $map['lib'] = AmqpLibConnectionFactory::class;
- }
- if (class_exists(AmqpBunnyConnectionFactory::class)) {
- $map['bunny'] = AmqpBunnyConnectionFactory::class;
- }
-
- return $map;
- }
-}
diff --git a/pkg/enqueue/Symfony/Client/ConsumeCommand.php b/pkg/enqueue/Symfony/Client/ConsumeCommand.php
new file mode 100644
index 000000000..5a0676705
--- /dev/null
+++ b/pkg/enqueue/Symfony/Client/ConsumeCommand.php
@@ -0,0 +1,181 @@
+container = $container;
+ $this->defaultClient = $defaultClient;
+ $this->queueConsumerIdPattern = $queueConsumerIdPattern;
+ $this->driverIdPattern = $driverIdPattern;
+ $this->processorIdPattern = $processorIdPatter;
+
+ parent::__construct();
+ }
+
+ protected function configure(): void
+ {
+ $this->configureLimitsExtensions();
+ $this->configureSetupBrokerExtension();
+ $this->configureQueueConsumerOptions();
+ $this->configureLoggerExtension();
+
+ $this
+ ->setAliases(['enq:c'])
+ ->setDescription('A client\'s worker that processes messages. '.
+ 'By default it connects to default queue. '.
+ 'It select an appropriate message processor based on a message headers')
+ ->addArgument('client-queue-names', InputArgument::IS_ARRAY, 'Queues to consume messages from')
+ ->addOption('skip', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'Queues to skip consumption of messages from', [])
+ ->addOption('client', 'c', InputOption::VALUE_OPTIONAL, 'The client to consume messages from.', $this->defaultClient)
+ ;
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int
+ {
+ $client = $input->getOption('client');
+
+ try {
+ $consumer = $this->getQueueConsumer($client);
+ } catch (NotFoundExceptionInterface $e) {
+ throw new \LogicException(sprintf('Client "%s" is not supported.', $client), null, $e);
+ }
+
+ $driver = $this->getDriver($client);
+ $processor = $this->getProcessor($client);
+
+ $this->setQueueConsumerOptions($consumer, $input);
+
+ $allQueues[$driver->getConfig()->getDefaultQueue()] = true;
+ $allQueues[$driver->getConfig()->getRouterQueue()] = true;
+ foreach ($driver->getRouteCollection()->all() as $route) {
+ if (false == $route->getQueue()) {
+ continue;
+ }
+ if ($route->isProcessorExternal()) {
+ continue;
+ }
+
+ $allQueues[$route->getQueue()] = $route->isPrefixQueue();
+ }
+
+ $selectedQueues = $input->getArgument('client-queue-names');
+ if (empty($selectedQueues)) {
+ $queues = $allQueues;
+ } else {
+ $queues = [];
+ foreach ($selectedQueues as $queue) {
+ if (false == array_key_exists($queue, $allQueues)) {
+ throw new \LogicException(sprintf('There is no such queue "%s". Available are "%s"', $queue, implode('", "', array_keys($allQueues))));
+ }
+
+ $queues[$queue] = $allQueues[$queue];
+ }
+ }
+
+ foreach ($input->getOption('skip') as $skipQueue) {
+ unset($queues[$skipQueue]);
+ }
+
+ foreach ($queues as $queue => $prefix) {
+ $queue = $driver->createQueue($queue, $prefix);
+ $consumer->bind($queue, $processor);
+ }
+
+ $runtimeExtensionChain = $this->getRuntimeExtensions($input, $output);
+ $exitStatusExtension = new ExitStatusExtension();
+
+ $consumer->consume(new ChainExtension([$runtimeExtensionChain, $exitStatusExtension]));
+
+ return $exitStatusExtension->getExitStatus() ?? 0;
+ }
+
+ protected function getRuntimeExtensions(InputInterface $input, OutputInterface $output): ExtensionInterface
+ {
+ $extensions = [];
+ $extensions = array_merge($extensions, $this->getLimitsExtensions($input, $output));
+
+ $driver = $this->getDriver($input->getOption('client'));
+
+ if ($setupBrokerExtension = $this->getSetupBrokerExtension($input, $driver)) {
+ $extensions[] = $setupBrokerExtension;
+ }
+
+ if ($loggerExtension = $this->getLoggerExtension($input, $output)) {
+ array_unshift($extensions, $loggerExtension);
+ }
+
+ return new ChainExtension($extensions);
+ }
+
+ private function getDriver(string $name): DriverInterface
+ {
+ return $this->container->get(sprintf($this->driverIdPattern, $name));
+ }
+
+ private function getQueueConsumer(string $name): QueueConsumerInterface
+ {
+ return $this->container->get(sprintf($this->queueConsumerIdPattern, $name));
+ }
+
+ private function getProcessor(string $name): Processor
+ {
+ return $this->container->get(sprintf($this->processorIdPattern, $name));
+ }
+}
diff --git a/pkg/enqueue/Symfony/Client/ConsumeMessagesCommand.php b/pkg/enqueue/Symfony/Client/ConsumeMessagesCommand.php
deleted file mode 100644
index a3817b3e5..000000000
--- a/pkg/enqueue/Symfony/Client/ConsumeMessagesCommand.php
+++ /dev/null
@@ -1,135 +0,0 @@
-consumer = $consumer;
- $this->processor = $processor;
- $this->queueMetaRegistry = $queueMetaRegistry;
- $this->driver = $driver;
- }
-
- /**
- * {@inheritdoc}
- */
- protected function configure()
- {
- $this->configureLimitsExtensions();
- $this->configureSetupBrokerExtension();
- $this->configureQueueConsumerOptions();
-
- $this
- ->setName('enqueue:consume')
- ->setAliases(['enq:c'])
- ->setDescription('A client\'s worker that processes messages. '.
- 'By default it connects to default queue. '.
- 'It select an appropriate message processor based on a message headers')
- ->addArgument('client-queue-names', InputArgument::IS_ARRAY, 'Queues to consume messages from')
- ->addOption('skip', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'Queues to skip consumption of messages from', [])
- ;
- }
-
- /**
- * {@inheritdoc}
- */
- protected function execute(InputInterface $input, OutputInterface $output)
- {
- $this->setQueueConsumerOptions($this->consumer, $input);
-
- $queueMetas = [];
- if ($clientQueueNames = $input->getArgument('client-queue-names')) {
- foreach ($clientQueueNames as $clientQueueName) {
- $queueMetas[] = $this->queueMetaRegistry->getQueueMeta($clientQueueName);
- }
- } else {
- /** @var QueueMeta[] $queueMetas */
- $queueMetas = iterator_to_array($this->queueMetaRegistry->getQueuesMeta());
-
- foreach ($queueMetas as $index => $queueMeta) {
- if (in_array($queueMeta->getClientName(), $input->getOption('skip'), true)) {
- unset($queueMetas[$index]);
- }
- }
- }
-
- foreach ($queueMetas as $queueMeta) {
- $queue = $this->driver->createQueue($queueMeta->getClientName());
- $this->consumer->bind($queue, $this->processor);
- }
-
- $this->consumer->consume($this->getRuntimeExtensions($input, $output));
- }
-
- /**
- * @param InputInterface $input
- * @param OutputInterface $output
- *
- * @return ChainExtension
- */
- protected function getRuntimeExtensions(InputInterface $input, OutputInterface $output)
- {
- $extensions = [new LoggerExtension(new ConsoleLogger($output))];
- $extensions = array_merge($extensions, $this->getLimitsExtensions($input, $output));
-
- if ($setupBrokerExtension = $this->getSetupBrokerExtension($input, $this->driver)) {
- $extensions[] = $setupBrokerExtension;
- }
-
- return new ChainExtension($extensions);
- }
-}
diff --git a/pkg/enqueue/Symfony/Client/ContainerAwareProcessorRegistry.php b/pkg/enqueue/Symfony/Client/ContainerAwareProcessorRegistry.php
deleted file mode 100644
index b378eb45d..000000000
--- a/pkg/enqueue/Symfony/Client/ContainerAwareProcessorRegistry.php
+++ /dev/null
@@ -1,68 +0,0 @@
-processors = $processors;
- }
-
- /**
- * @param string $processorName
- * @param string $serviceId
- */
- public function set($processorName, $serviceId)
- {
- $this->processors[$processorName] = $serviceId;
- }
-
- /**
- * {@inheritdoc}
- */
- public function get($processorName)
- {
- if (30300 > Kernel::VERSION_ID) {
- // Symfony 3.2 and below make service identifiers lowercase, so we do the same.
- // To be removed when dropping support for Symfony < 3.3.
- $processorName = strtolower($processorName);
- }
-
- if (false == isset($this->processors[$processorName])) {
- throw new \LogicException(sprintf('Processor was not found. processorName: "%s"', $processorName));
- }
-
- if (null === $this->container) {
- throw new \LogicException('Container was not set');
- }
-
- $processor = $this->container->get($this->processors[$processorName]);
-
- if (false == $processor instanceof PsrProcessor) {
- throw new \LogicException(sprintf(
- 'Invalid instance of message processor. expected: "%s", got: "%s"',
- PsrProcessor::class,
- is_object($processor) ? get_class($processor) : gettype($processor)
- ));
- }
-
- return $processor;
- }
-}
diff --git a/pkg/enqueue/Symfony/Client/DependencyInjection/AnalyzeRouteCollectionPass.php b/pkg/enqueue/Symfony/Client/DependencyInjection/AnalyzeRouteCollectionPass.php
new file mode 100644
index 000000000..577f15902
--- /dev/null
+++ b/pkg/enqueue/Symfony/Client/DependencyInjection/AnalyzeRouteCollectionPass.php
@@ -0,0 +1,107 @@
+hasParameter('enqueue.clients')) {
+ throw new \LogicException('The "enqueue.clients" parameter must be set.');
+ }
+
+ $names = $container->getParameter('enqueue.clients');
+
+ foreach ($names as $name) {
+ $diUtils = DiUtils::create(ClientFactory::MODULE, $name);
+
+ $routeCollectionId = $diUtils->format('route_collection');
+ if (false == $container->hasDefinition($routeCollectionId)) {
+ throw new \LogicException(sprintf('Service "%s" not found', $routeCollectionId));
+ }
+
+ $collection = RouteCollection::fromArray($container->getDefinition($routeCollectionId)->getArgument(0));
+
+ $this->exclusiveCommandsCouldNotBeRunOnDefaultQueue($collection);
+ $this->exclusiveCommandProcessorMustBeSingleOnGivenQueue($collection);
+ $this->customQueueNamesUnique($collection);
+ $this->defaultQueueMustBePrefixed($collection);
+ }
+ }
+
+ private function exclusiveCommandsCouldNotBeRunOnDefaultQueue(RouteCollection $collection): void
+ {
+ foreach ($collection->all() as $route) {
+ if ($route->isCommand() && $route->isProcessorExclusive() && false == $route->getQueue()) {
+ throw new \LogicException(sprintf('The command "%s" processor "%s" is exclusive but queue is not specified. Exclusive processors could not be run on a default queue.', $route->getSource(), $route->getProcessor()));
+ }
+ }
+ }
+
+ private function exclusiveCommandProcessorMustBeSingleOnGivenQueue(RouteCollection $collection): void
+ {
+ $prefixedQueues = [];
+ $queues = [];
+ foreach ($collection->all() as $route) {
+ if (false == $route->isCommand()) {
+ continue;
+ }
+ if (false == $route->isProcessorExclusive()) {
+ continue;
+ }
+
+ if ($route->isPrefixQueue()) {
+ if (array_key_exists($route->getQueue(), $prefixedQueues)) {
+ throw new \LogicException(sprintf('The command "%s" processor "%s" is exclusive. The queue "%s" already has another exclusive command processor "%s" bound to it.', $route->getSource(), $route->getProcessor(), $route->getQueue(), $prefixedQueues[$route->getQueue()]));
+ }
+
+ $prefixedQueues[$route->getQueue()] = $route->getProcessor();
+ } else {
+ if (array_key_exists($route->getQueue(), $queues)) {
+ throw new \LogicException(sprintf('The command "%s" processor "%s" is exclusive. The queue "%s" already has another exclusive command processor "%s" bound to it.', $route->getSource(), $route->getProcessor(), $route->getQueue(), $queues[$route->getQueue()]));
+ }
+
+ $queues[$route->getQueue()] = $route->getProcessor();
+ }
+ }
+ }
+
+ private function defaultQueueMustBePrefixed(RouteCollection $collection): void
+ {
+ foreach ($collection->all() as $route) {
+ if (false == $route->getQueue() && false == $route->isPrefixQueue()) {
+ throw new \LogicException('The default queue must be prefixed.');
+ }
+ }
+ }
+
+ private function customQueueNamesUnique(RouteCollection $collection): void
+ {
+ $prefixedQueues = [];
+ $notPrefixedQueues = [];
+
+ foreach ($collection->all() as $route) {
+ // default queue
+ $queueName = $route->getQueue();
+ if (false == $queueName) {
+ return;
+ }
+
+ $route->isPrefixQueue() ?
+ $prefixedQueues[$queueName] = $queueName :
+ $notPrefixedQueues[$queueName] = $queueName
+ ;
+ }
+
+ foreach ($notPrefixedQueues as $queueName) {
+ if (array_key_exists($queueName, $prefixedQueues)) {
+ throw new \LogicException(sprintf('There are prefixed and not prefixed queue with the same name "%s". This is not allowed.', $queueName));
+ }
+ }
+ }
+}
diff --git a/pkg/enqueue/Symfony/Client/DependencyInjection/BuildClientExtensionsPass.php b/pkg/enqueue/Symfony/Client/DependencyInjection/BuildClientExtensionsPass.php
new file mode 100644
index 000000000..92124f243
--- /dev/null
+++ b/pkg/enqueue/Symfony/Client/DependencyInjection/BuildClientExtensionsPass.php
@@ -0,0 +1,63 @@
+hasParameter('enqueue.clients')) {
+ throw new \LogicException('The "enqueue.clients" parameter must be set.');
+ }
+
+ $names = $container->getParameter('enqueue.clients');
+ $defaultName = $container->getParameter('enqueue.default_client');
+
+ foreach ($names as $name) {
+ $diUtils = DiUtils::create(ClientFactory::MODULE, $name);
+
+ $extensionsId = $diUtils->format('client_extensions');
+ if (false == $container->hasDefinition($extensionsId)) {
+ throw new \LogicException(sprintf('Service "%s" not found', $extensionsId));
+ }
+
+ $tags = array_merge(
+ $container->findTaggedServiceIds('enqueue.client_extension'),
+ $container->findTaggedServiceIds('enqueue.client.extension') // TODO BC
+ );
+
+ $groupByPriority = [];
+ foreach ($tags as $serviceId => $tagAttributes) {
+ foreach ($tagAttributes as $tagAttribute) {
+ $client = $tagAttribute['client'] ?? $defaultName;
+
+ if ($client !== $name && 'all' !== $client) {
+ continue;
+ }
+
+ $priority = (int) ($tagAttribute['priority'] ?? 0);
+
+ $groupByPriority[$priority][] = new Reference($serviceId);
+ }
+ }
+
+ krsort($groupByPriority, \SORT_NUMERIC);
+
+ $flatExtensions = [];
+ foreach ($groupByPriority as $extension) {
+ $flatExtensions = array_merge($flatExtensions, $extension);
+ }
+
+ $extensionsService = $container->getDefinition($extensionsId);
+ $extensionsService->replaceArgument(0, array_merge(
+ $extensionsService->getArgument(0),
+ $flatExtensions
+ ));
+ }
+ }
+}
diff --git a/pkg/enqueue/Symfony/Client/DependencyInjection/BuildCommandSubscriberRoutesPass.php b/pkg/enqueue/Symfony/Client/DependencyInjection/BuildCommandSubscriberRoutesPass.php
new file mode 100644
index 000000000..4adc09e9d
--- /dev/null
+++ b/pkg/enqueue/Symfony/Client/DependencyInjection/BuildCommandSubscriberRoutesPass.php
@@ -0,0 +1,135 @@
+hasParameter('enqueue.clients')) {
+ throw new \LogicException('The "enqueue.clients" parameter must be set.');
+ }
+
+ $names = $container->getParameter('enqueue.clients');
+ $defaultName = $container->getParameter('enqueue.default_client');
+
+ foreach ($names as $name) {
+ $diUtils = DiUtils::create(ClientFactory::MODULE, $name);
+ $routeCollectionId = $diUtils->format('route_collection');
+ if (false == $container->hasDefinition($routeCollectionId)) {
+ throw new \LogicException(sprintf('Service "%s" not found', $routeCollectionId));
+ }
+
+ $tag = 'enqueue.command_subscriber';
+ $routeCollection = new RouteCollection([]);
+ foreach ($container->findTaggedServiceIds($tag) as $serviceId => $tagAttributes) {
+ $processorDefinition = $container->getDefinition($serviceId);
+ if ($processorDefinition->getFactory()) {
+ throw new \LogicException('The command subscriber tag could not be applied to a service created by factory.');
+ }
+
+ $processorClass = $processorDefinition->getClass() ?? $serviceId;
+ if (false == class_exists($processorClass)) {
+ throw new \LogicException(sprintf('The processor class "%s" could not be found.', $processorClass));
+ }
+
+ if (false == is_subclass_of($processorClass, CommandSubscriberInterface::class)) {
+ throw new \LogicException(sprintf('The processor must implement "%s" interface to be used with the tag "%s"', CommandSubscriberInterface::class, $tag));
+ }
+
+ foreach ($tagAttributes as $tagAttribute) {
+ $client = $tagAttribute['client'] ?? $defaultName;
+
+ if ($client !== $name && 'all' !== $client) {
+ continue;
+ }
+
+ /** @var CommandSubscriberInterface $processorClass */
+ $commands = $processorClass::getSubscribedCommand();
+
+ if (empty($commands)) {
+ throw new \LogicException('Command subscriber must return something.');
+ }
+
+ if (is_string($commands)) {
+ $commands = [$commands];
+ }
+
+ if (!is_array($commands)) {
+ throw new \LogicException('Command subscriber configuration is invalid. Should be an array or string.');
+ }
+
+ // 0.8 command subscriber
+ if (isset($commands['processorName'])) {
+ @trigger_error('The command subscriber 0.8 syntax is deprecated since Enqueue 0.9.', \E_USER_DEPRECATED);
+
+ $source = $commands['processorName'];
+ $processor = $params['processorName'] ?? $serviceId;
+
+ $options = $commands;
+ unset(
+ $options['processorName'],
+ $options['queueName'],
+ $options['queueNameHardcoded'],
+ $options['exclusive'],
+ $options['topic'],
+ $options['source'],
+ $options['source_type'],
+ $options['processor'],
+ $options['options']
+ );
+
+ $options['processor_service_id'] = $serviceId;
+
+ if (isset($commands['queueName'])) {
+ $options['queue'] = $commands['queueName'];
+ }
+
+ if (isset($commands['queueNameHardcoded']) && $commands['queueNameHardcoded']) {
+ $options['prefix_queue'] = false;
+ }
+
+ $routeCollection->add(new Route($source, Route::COMMAND, $processor, $options));
+
+ continue;
+ }
+
+ if (isset($commands['command'])) {
+ $commands = [$commands];
+ }
+
+ foreach ($commands as $key => $params) {
+ if (is_string($params)) {
+ $routeCollection->add(new Route($params, Route::COMMAND, $serviceId, ['processor_service_id' => $serviceId]));
+ } elseif (is_array($params)) {
+ $source = $params['command'] ?? null;
+ $processor = $params['processor'] ?? $serviceId;
+ unset($params['command'], $params['source'], $params['source_type'], $params['processor'], $params['options']);
+ $options = $params;
+ $options['processor_service_id'] = $serviceId;
+
+ $routeCollection->add(new Route($source, Route::COMMAND, $processor, $options));
+ } else {
+ throw new \LogicException(sprintf('Command subscriber configuration is invalid for "%s::getSubscribedCommand()". "%s"', $processorClass, json_encode($processorClass::getSubscribedCommand())));
+ }
+ }
+ }
+ }
+
+ $rawRoutes = $routeCollection->toArray();
+
+ $routeCollectionService = $container->getDefinition($routeCollectionId);
+ $routeCollectionService->replaceArgument(0, array_merge(
+ $routeCollectionService->getArgument(0),
+ $rawRoutes
+ ));
+ }
+ }
+}
diff --git a/pkg/enqueue/Symfony/Client/DependencyInjection/BuildConsumptionExtensionsPass.php b/pkg/enqueue/Symfony/Client/DependencyInjection/BuildConsumptionExtensionsPass.php
new file mode 100644
index 000000000..274847c90
--- /dev/null
+++ b/pkg/enqueue/Symfony/Client/DependencyInjection/BuildConsumptionExtensionsPass.php
@@ -0,0 +1,63 @@
+hasParameter('enqueue.clients')) {
+ throw new \LogicException('The "enqueue.clients" parameter must be set.');
+ }
+
+ $names = $container->getParameter('enqueue.clients');
+ $defaultName = $container->getParameter('enqueue.default_client');
+
+ foreach ($names as $name) {
+ $diUtils = DiUtils::create(ClientFactory::MODULE, $name);
+
+ $extensionsId = $diUtils->format('consumption_extensions');
+ if (false == $container->hasDefinition($extensionsId)) {
+ throw new \LogicException(sprintf('Service "%s" not found', $extensionsId));
+ }
+
+ $tags = array_merge(
+ $container->findTaggedServiceIds('enqueue.consumption_extension'),
+ $container->findTaggedServiceIds('enqueue.consumption.extension') // TODO BC
+ );
+
+ $groupByPriority = [];
+ foreach ($tags as $serviceId => $tagAttributes) {
+ foreach ($tagAttributes as $tagAttribute) {
+ $client = $tagAttribute['client'] ?? $defaultName;
+
+ if ($client !== $name && 'all' !== $client) {
+ continue;
+ }
+
+ $priority = (int) ($tagAttribute['priority'] ?? 0);
+
+ $groupByPriority[$priority][] = new Reference($serviceId);
+ }
+ }
+
+ krsort($groupByPriority, \SORT_NUMERIC);
+
+ $flatExtensions = [];
+ foreach ($groupByPriority as $extension) {
+ $flatExtensions = array_merge($flatExtensions, $extension);
+ }
+
+ $extensionsService = $container->getDefinition($extensionsId);
+ $extensionsService->replaceArgument(0, array_merge(
+ $extensionsService->getArgument(0),
+ $flatExtensions
+ ));
+ }
+ }
+}
diff --git a/pkg/enqueue/Symfony/Client/DependencyInjection/BuildProcessorRegistryPass.php b/pkg/enqueue/Symfony/Client/DependencyInjection/BuildProcessorRegistryPass.php
new file mode 100644
index 000000000..3759dd209
--- /dev/null
+++ b/pkg/enqueue/Symfony/Client/DependencyInjection/BuildProcessorRegistryPass.php
@@ -0,0 +1,57 @@
+hasParameter('enqueue.clients')) {
+ throw new \LogicException('The "enqueue.clients" parameter must be set.');
+ }
+
+ $names = $container->getParameter('enqueue.clients');
+
+ foreach ($names as $name) {
+ $diUtils = DiUtils::create(ClientFactory::MODULE, $name);
+
+ $processorRegistryId = $diUtils->format('processor_registry');
+ if (false == $container->hasDefinition($processorRegistryId)) {
+ throw new \LogicException(sprintf('Service "%s" not found', $processorRegistryId));
+ }
+
+ $routeCollectionId = $diUtils->format('route_collection');
+ if (false == $container->hasDefinition($routeCollectionId)) {
+ throw new \LogicException(sprintf('Service "%s" not found', $routeCollectionId));
+ }
+
+ $routerProcessorId = $diUtils->format('router_processor');
+ if (false == $container->hasDefinition($routerProcessorId)) {
+ throw new \LogicException(sprintf('Service "%s" not found', $routerProcessorId));
+ }
+
+ $routeCollection = RouteCollection::fromArray($container->getDefinition($routeCollectionId)->getArgument(0));
+
+ $map = [];
+ foreach ($routeCollection->all() as $route) {
+ if (false == $processorServiceId = $route->getOption('processor_service_id')) {
+ throw new \LogicException('The route option "processor_service_id" is required');
+ }
+
+ $map[$route->getProcessor()] = new Reference($processorServiceId);
+ }
+
+ $map[$diUtils->parameter('router_processor')] = new Reference($routerProcessorId);
+
+ $registry = $container->getDefinition($processorRegistryId);
+ $registry->setArgument(0, ServiceLocatorTagPass::register($container, $map, $processorRegistryId));
+ }
+ }
+}
diff --git a/pkg/enqueue/Symfony/Client/DependencyInjection/BuildProcessorRoutesPass.php b/pkg/enqueue/Symfony/Client/DependencyInjection/BuildProcessorRoutesPass.php
new file mode 100644
index 000000000..e88cb1f83
--- /dev/null
+++ b/pkg/enqueue/Symfony/Client/DependencyInjection/BuildProcessorRoutesPass.php
@@ -0,0 +1,77 @@
+hasParameter('enqueue.clients')) {
+ throw new \LogicException('The "enqueue.clients" parameter must be set.');
+ }
+
+ $names = $container->getParameter('enqueue.clients');
+ $defaultName = $container->getParameter('enqueue.default_client');
+
+ foreach ($names as $name) {
+ $diUtils = DiUtils::create(ClientFactory::MODULE, $name);
+ $routeCollectionId = $diUtils->format('route_collection');
+ if (false == $container->hasDefinition($routeCollectionId)) {
+ throw new \LogicException(sprintf('Service "%s" not found', $routeCollectionId));
+ }
+
+ $tag = 'enqueue.processor';
+ $routeCollection = new RouteCollection([]);
+ foreach ($container->findTaggedServiceIds($tag) as $serviceId => $tagAttributes) {
+ foreach ($tagAttributes as $tagAttribute) {
+ $client = $tagAttribute['client'] ?? $defaultName;
+
+ if ($client !== $name && 'all' !== $client) {
+ continue;
+ }
+
+ $topic = $tagAttribute['topic'] ?? null;
+ $command = $tagAttribute['command'] ?? null;
+
+ if (false == $topic && false == $command) {
+ throw new \LogicException(sprintf('Either "topic" or "command" tag attribute must be set on service "%s". None is set.', $serviceId));
+ }
+ if ($topic && $command) {
+ throw new \LogicException(sprintf('Either "topic" or "command" tag attribute must be set on service "%s". Both are set.', $serviceId));
+ }
+
+ $source = $command ?: $topic;
+ $sourceType = $command ? Route::COMMAND : Route::TOPIC;
+ $processor = $tagAttribute['processor'] ?? $serviceId;
+
+ unset(
+ $tagAttribute['topic'],
+ $tagAttribute['command'],
+ $tagAttribute['source'],
+ $tagAttribute['source_type'],
+ $tagAttribute['processor'],
+ $tagAttribute['options']
+ );
+ $options = $tagAttribute;
+ $options['processor_service_id'] = $serviceId;
+
+ $routeCollection->add(new Route($source, $sourceType, $processor, $options));
+ }
+ }
+
+ $rawRoutes = $routeCollection->toArray();
+
+ $routeCollectionService = $container->getDefinition($routeCollectionId);
+ $routeCollectionService->replaceArgument(0, array_merge(
+ $routeCollectionService->getArgument(0),
+ $rawRoutes
+ ));
+ }
+ }
+}
diff --git a/pkg/enqueue/Symfony/Client/DependencyInjection/BuildTopicSubscriberRoutesPass.php b/pkg/enqueue/Symfony/Client/DependencyInjection/BuildTopicSubscriberRoutesPass.php
new file mode 100644
index 000000000..ef01e6fcf
--- /dev/null
+++ b/pkg/enqueue/Symfony/Client/DependencyInjection/BuildTopicSubscriberRoutesPass.php
@@ -0,0 +1,127 @@
+hasParameter('enqueue.clients')) {
+ throw new \LogicException('The "enqueue.clients" parameter must be set.');
+ }
+
+ $names = $container->getParameter('enqueue.clients');
+ $defaultName = $container->getParameter('enqueue.default_client');
+
+ foreach ($names as $name) {
+ $diUtils = DiUtils::create(ClientFactory::MODULE, $name);
+ $routeCollectionId = $diUtils->format('route_collection');
+ if (false == $container->hasDefinition($routeCollectionId)) {
+ throw new \LogicException(sprintf('Service "%s" not found', $routeCollectionId));
+ }
+
+ $tag = 'enqueue.topic_subscriber';
+ $routeCollection = new RouteCollection([]);
+ foreach ($container->findTaggedServiceIds($tag) as $serviceId => $tagAttributes) {
+ $processorDefinition = $container->getDefinition($serviceId);
+ if ($processorDefinition->getFactory()) {
+ throw new \LogicException('The topic subscriber tag could not be applied to a service created by factory.');
+ }
+
+ $processorClass = $processorDefinition->getClass() ?? $serviceId;
+ if (false == class_exists($processorClass)) {
+ throw new \LogicException(sprintf('The processor class "%s" could not be found.', $processorClass));
+ }
+
+ if (false == is_subclass_of($processorClass, TopicSubscriberInterface::class)) {
+ throw new \LogicException(sprintf('The processor must implement "%s" interface to be used with the tag "%s"', TopicSubscriberInterface::class, $tag));
+ }
+
+ foreach ($tagAttributes as $tagAttribute) {
+ $client = $tagAttribute['client'] ?? $defaultName;
+
+ if ($client !== $name && 'all' !== $client) {
+ continue;
+ }
+
+ /** @var TopicSubscriberInterface $processorClass */
+ $topics = $processorClass::getSubscribedTopics();
+
+ if (empty($topics)) {
+ throw new \LogicException('Topic subscriber must return something.');
+ }
+
+ if (is_string($topics)) {
+ $topics = [$topics];
+ }
+
+ if (!is_array($topics)) {
+ throw new \LogicException('Topic subscriber configuration is invalid. Should be an array or string.');
+ }
+
+ foreach ($topics as $key => $params) {
+ if (is_string($params)) {
+ $routeCollection->add(new Route($params, Route::TOPIC, $serviceId, ['processor_service_id' => $serviceId]));
+
+ // 0.8 topic subscriber
+ } elseif (is_array($params) && is_string($key)) {
+ @trigger_error('The topic subscriber 0.8 syntax is deprecated since Enqueue 0.9.', \E_USER_DEPRECATED);
+
+ $source = $key;
+ $processor = $params['processorName'] ?? $serviceId;
+
+ $options = $params;
+ unset(
+ $options['processorName'],
+ $options['queueName'],
+ $options['queueNameHardcoded'],
+ $options['topic'],
+ $options['source'],
+ $options['source_type'],
+ $options['processor'],
+ $options['options']
+ );
+
+ $options['processor_service_id'] = $serviceId;
+
+ if (isset($params['queueName'])) {
+ $options['queue'] = $params['queueName'];
+ }
+
+ if (isset($params['queueNameHardcoded']) && $params['queueNameHardcoded']) {
+ $options['prefix_queue'] = false;
+ }
+
+ $routeCollection->add(new Route($source, Route::TOPIC, $processor, $options));
+ } elseif (is_array($params)) {
+ $source = $params['topic'] ?? null;
+ $processor = $params['processor'] ?? $serviceId;
+ unset($params['topic'], $params['source'], $params['source_type'], $params['processor'], $params['options']);
+ $options = $params;
+ $options['processor_service_id'] = $serviceId;
+
+ $routeCollection->add(new Route($source, Route::TOPIC, $processor, $options));
+ } else {
+ throw new \LogicException(sprintf('Topic subscriber configuration is invalid for "%s::getSubscribedTopics()". Got "%s"', $processorClass, json_encode($processorClass::getSubscribedTopics())));
+ }
+ }
+ }
+ }
+
+ $rawRoutes = $routeCollection->toArray();
+
+ $routeCollectionService = $container->getDefinition($routeCollectionId);
+ $routeCollectionService->replaceArgument(0, array_merge(
+ $routeCollectionService->getArgument(0),
+ $rawRoutes
+ ));
+ }
+ }
+}
diff --git a/pkg/enqueue/Symfony/Client/DependencyInjection/ClientFactory.php b/pkg/enqueue/Symfony/Client/DependencyInjection/ClientFactory.php
new file mode 100644
index 000000000..be020dcff
--- /dev/null
+++ b/pkg/enqueue/Symfony/Client/DependencyInjection/ClientFactory.php
@@ -0,0 +1,254 @@
+default = $default;
+ $this->diUtils = DiUtils::create(self::MODULE, $name);
+ }
+
+ public static function getConfiguration(bool $debug, string $name = 'client'): NodeDefinition
+ {
+ $builder = new ArrayNodeDefinition($name);
+
+ $builder->children()
+ ->booleanNode('traceable_producer')->defaultValue($debug)->end()
+ ->scalarNode('prefix')->defaultValue('enqueue')->end()
+ ->scalarNode('separator')->defaultValue('.')->end()
+ ->scalarNode('app_name')->defaultValue('app')->end()
+ ->scalarNode('router_topic')->defaultValue('default')->cannotBeEmpty()->end()
+ ->scalarNode('router_queue')->defaultValue('default')->cannotBeEmpty()->end()
+ ->scalarNode('router_processor')->defaultNull()->end()
+ ->integerNode('redelivered_delay_time')->min(0)->defaultValue(0)->end()
+ ->scalarNode('default_queue')->defaultValue('default')->cannotBeEmpty()->end()
+ ->arrayNode('driver_options')->addDefaultsIfNotSet()->info('The array contains driver specific options')->ignoreExtraKeys(false)->end()
+ ->end()
+ ;
+
+ return $builder;
+ }
+
+ public function build(ContainerBuilder $container, array $config): void
+ {
+ $container->register($this->diUtils->format('context'), Context::class)
+ ->setFactory([$this->diUtils->reference('driver'), 'getContext'])
+ ;
+
+ $container->register($this->diUtils->format('driver_factory'), DriverFactory::class);
+
+ $routerProcessor = empty($config['router_processor'])
+ ? $this->diUtils->format('router_processor')
+ : $config['router_processor']
+ ;
+
+ $container->register($this->diUtils->format('config'), Config::class)
+ ->setArguments([
+ $config['prefix'],
+ $config['separator'],
+ $config['app_name'],
+ $config['router_topic'],
+ $config['router_queue'],
+ $config['default_queue'],
+ $routerProcessor,
+ $config['transport'],
+ $config['driver_options'] ?? [],
+ ]);
+
+ $container->setParameter($this->diUtils->format('router_processor'), $routerProcessor);
+ $container->setParameter($this->diUtils->format('router_queue_name'), $config['router_queue']);
+ $container->setParameter($this->diUtils->format('default_queue_name'), $config['default_queue']);
+
+ $container->register($this->diUtils->format('route_collection'), RouteCollection::class)
+ ->addArgument([])
+ ->setFactory([RouteCollection::class, 'fromArray'])
+ ;
+
+ $container->register($this->diUtils->format('producer'), Producer::class)
+ // @deprecated
+ ->setPublic(true)
+ ->addArgument($this->diUtils->reference('driver'))
+ ->addArgument($this->diUtils->reference('rpc_factory'))
+ ->addArgument($this->diUtils->reference('client_extensions'))
+ ;
+
+ $lazyProducer = $container->register($this->diUtils->format('lazy_producer'), LazyProducer::class);
+ $lazyProducer->addArgument(ServiceLocatorTagPass::register($container, [
+ $this->diUtils->format('producer') => new Reference($this->diUtils->format('producer')),
+ ]));
+ $lazyProducer->addArgument($this->diUtils->format('producer'));
+
+ $container->register($this->diUtils->format('spool_producer'), SpoolProducer::class)
+ ->addArgument($this->diUtils->reference('lazy_producer'))
+ ;
+
+ $container->register($this->diUtils->format('client_extensions'), ChainExtension::class)
+ ->addArgument([])
+ ;
+
+ $container->register($this->diUtils->format('rpc_factory'), RpcFactory::class)
+ ->addArgument($this->diUtils->reference('context'))
+ ;
+
+ $container->register($this->diUtils->format('router_processor'), RouterProcessor::class)
+ ->addArgument($this->diUtils->reference('driver'))
+ ;
+
+ $container->register($this->diUtils->format('processor_registry'), ContainerProcessorRegistry::class);
+
+ $container->register($this->diUtils->format('delegate_processor'), DelegateProcessor::class)
+ ->addArgument($this->diUtils->reference('processor_registry'))
+ ;
+
+ $container->register($this->diUtils->format('set_router_properties_extension'), SetRouterPropertiesExtension::class)
+ ->addArgument($this->diUtils->reference('driver'))
+ ->addTag('enqueue.consumption_extension', ['priority' => 100, 'client' => $this->diUtils->getConfigName()])
+ ;
+
+ $container->register($this->diUtils->format('queue_consumer'), QueueConsumer::class)
+ ->addArgument($this->diUtils->reference('context'))
+ ->addArgument($this->diUtils->reference('consumption_extensions'))
+ ->addArgument([])
+ ->addArgument(new Reference('logger', ContainerInterface::NULL_ON_INVALID_REFERENCE))
+ ->addArgument($config['consumption']['receive_timeout'])
+ ;
+
+ $container->register($this->diUtils->format('consumption_extensions'), ConsumptionChainExtension::class)
+ ->addArgument([])
+ ;
+
+ $container->register($this->diUtils->format('flush_spool_producer_extension'), FlushSpoolProducerExtension::class)
+ ->addArgument($this->diUtils->reference('spool_producer'))
+ ->addTag('enqueue.consumption.extension', ['priority' => -100, 'client' => $this->diUtils->getConfigName()])
+ ;
+
+ $container->register($this->diUtils->format('exclusive_command_extension'), ExclusiveCommandExtension::class)
+ ->addArgument($this->diUtils->reference('driver'))
+ ->addTag('enqueue.consumption.extension', ['priority' => 100, 'client' => $this->diUtils->getConfigName()])
+ ;
+
+ if ($config['traceable_producer']) {
+ $container->register($this->diUtils->format('traceable_producer'), TraceableProducer::class)
+ ->setDecoratedService($this->diUtils->format('producer'))
+ ->addArgument($this->diUtils->reference('traceable_producer.inner'))
+ ;
+ }
+
+ if ($config['redelivered_delay_time']) {
+ $container->register($this->diUtils->format('delay_redelivered_message_extension'), DelayRedeliveredMessageExtension::class)
+ ->addArgument($this->diUtils->reference('driver'))
+ ->addArgument($config['redelivered_delay_time'])
+ ->addTag('enqueue.consumption_extension', ['priority' => 10, 'client' => $this->diUtils->getConfigName()])
+ ;
+
+ $container->getDefinition($this->diUtils->format('delay_redelivered_message_extension'))
+ ->replaceArgument(1, $config['redelivered_delay_time'])
+ ;
+ }
+
+ $locatorId = 'enqueue.locator';
+ if ($container->hasDefinition($locatorId)) {
+ $locator = $container->getDefinition($locatorId);
+ $locator->replaceArgument(0, array_replace($locator->getArgument(0), [
+ $this->diUtils->format('queue_consumer') => $this->diUtils->reference('queue_consumer'),
+ $this->diUtils->format('driver') => $this->diUtils->reference('driver'),
+ $this->diUtils->format('delegate_processor') => $this->diUtils->reference('delegate_processor'),
+ $this->diUtils->format('producer') => $this->diUtils->reference('lazy_producer'),
+ ]));
+ }
+
+ if ($this->default) {
+ $container->setAlias(ProducerInterface::class, $this->diUtils->format('lazy_producer'));
+ $container->setAlias(SpoolProducer::class, $this->diUtils->format('spool_producer'));
+
+ if (DiUtils::DEFAULT_CONFIG !== $this->diUtils->getConfigName()) {
+ $container->setAlias($this->diUtils->formatDefault('producer'), $this->diUtils->format('producer'));
+ $container->setAlias($this->diUtils->formatDefault('spool_producer'), $this->diUtils->format('spool_producer'));
+ }
+ }
+ }
+
+ public function createDriver(ContainerBuilder $container, array $config): string
+ {
+ $factoryId = DiUtils::create(TransportFactory::MODULE, $this->diUtils->getConfigName())->format('connection_factory');
+ $driverId = $this->diUtils->format('driver');
+ $driverFactoryId = $this->diUtils->format('driver_factory');
+
+ $container->register($driverId, DriverInterface::class)
+ ->setFactory([new Reference($driverFactoryId), 'create'])
+ ->addArgument(new Reference($factoryId))
+ ->addArgument($this->diUtils->reference('config'))
+ ->addArgument($this->diUtils->reference('route_collection'))
+ ;
+
+ if ($this->default) {
+ $container->setAlias(DriverInterface::class, $driverId);
+
+ if (DiUtils::DEFAULT_CONFIG !== $this->diUtils->getConfigName()) {
+ $container->setAlias($this->diUtils->formatDefault('driver'), $driverId);
+ }
+ }
+
+ return $driverId;
+ }
+
+ public function createFlushSpoolProducerListener(ContainerBuilder $container): void
+ {
+ $container->register($this->diUtils->format('flush_spool_producer_listener'), FlushSpoolProducerListener::class)
+ ->addArgument($this->diUtils->reference('spool_producer'))
+ ->addTag('kernel.event_subscriber')
+ ;
+ }
+}
diff --git a/pkg/enqueue/Symfony/Client/FlushSpoolProducerListener.php b/pkg/enqueue/Symfony/Client/FlushSpoolProducerListener.php
index 1f5fdcba7..00543f6de 100644
--- a/pkg/enqueue/Symfony/Client/FlushSpoolProducerListener.php
+++ b/pkg/enqueue/Symfony/Client/FlushSpoolProducerListener.php
@@ -14,9 +14,6 @@ class FlushSpoolProducerListener implements EventSubscriberInterface
*/
private $producer;
- /**
- * @param SpoolProducer $producer
- */
public function __construct(SpoolProducer $producer)
{
$this->producer = $producer;
@@ -27,10 +24,7 @@ public function flushMessages()
$this->producer->flush();
}
- /**
- * {@inheritdoc}
- */
- public static function getSubscribedEvents()
+ public static function getSubscribedEvents(): array
{
$events = [];
diff --git a/pkg/enqueue/Symfony/Client/LazyProducer.php b/pkg/enqueue/Symfony/Client/LazyProducer.php
new file mode 100644
index 000000000..8dd3aadba
--- /dev/null
+++ b/pkg/enqueue/Symfony/Client/LazyProducer.php
@@ -0,0 +1,37 @@
+container = $container;
+ $this->producerId = $producerId;
+ }
+
+ public function sendEvent(string $topic, $message): void
+ {
+ $this->getRealProducer()->sendEvent($topic, $message);
+ }
+
+ public function sendCommand(string $command, $message, bool $needReply = false): ?Promise
+ {
+ return $this->getRealProducer()->sendCommand($command, $message, $needReply);
+ }
+
+ private function getRealProducer(): ProducerInterface
+ {
+ return $this->container->get($this->producerId);
+ }
+}
diff --git a/pkg/enqueue/Symfony/Client/Meta/QueuesCommand.php b/pkg/enqueue/Symfony/Client/Meta/QueuesCommand.php
deleted file mode 100644
index a1f9f54fe..000000000
--- a/pkg/enqueue/Symfony/Client/Meta/QueuesCommand.php
+++ /dev/null
@@ -1,73 +0,0 @@
-queueMetaRegistry = $queueRegistry;
- }
-
- /**
- * {@inheritdoc}
- */
- protected function configure()
- {
- $this
- ->setName('enqueue:queues')
- ->setAliases([
- 'enq:m:q',
- 'debug:enqueue:queues',
- ])
- ->setDescription('A command shows all available queues and some information about them.')
- ;
- }
-
- /**
- * {@inheritdoc}
- */
- protected function execute(InputInterface $input, OutputInterface $output)
- {
- $table = new Table($output);
- $table->setHeaders(['Client Name', 'Transport Name', 'Processors']);
-
- $count = 0;
- $firstRow = true;
- foreach ($this->queueMetaRegistry->getQueuesMeta() as $queueMeta) {
- if (false == $firstRow) {
- $table->addRow(new TableSeparator());
- }
-
- $table->addRow([
- $queueMeta->getClientName(),
- $queueMeta->getClientName() == $queueMeta->getTransportName() ? '(same)' : $queueMeta->getTransportName(),
- implode(PHP_EOL, $queueMeta->getProcessors()),
- ]);
-
- ++$count;
- $firstRow = false;
- }
-
- $output->writeln(sprintf('Found %s destinations', $count));
- $output->writeln('');
- $table->render();
- }
-}
diff --git a/pkg/enqueue/Symfony/Client/Meta/TopicsCommand.php b/pkg/enqueue/Symfony/Client/Meta/TopicsCommand.php
deleted file mode 100644
index 51019a7d6..000000000
--- a/pkg/enqueue/Symfony/Client/Meta/TopicsCommand.php
+++ /dev/null
@@ -1,69 +0,0 @@
-topicRegistry = $topicRegistry;
- }
-
- /**
- * {@inheritdoc}
- */
- protected function configure()
- {
- $this
- ->setName('enqueue:topics')
- ->setAliases([
- 'enq:m:t',
- 'debug:enqueue:topics',
- ])
- ->setDescription('A command shows all available topics and some information about them.')
- ;
- }
-
- /**
- * {@inheritdoc}
- */
- protected function execute(InputInterface $input, OutputInterface $output)
- {
- $table = new Table($output);
- $table->setHeaders(['Topic', 'Description', 'Processors']);
-
- $count = 0;
- $firstRow = true;
- foreach ($this->topicRegistry->getTopicsMeta() as $topic) {
- if (false == $firstRow) {
- $table->addRow(new TableSeparator());
- }
-
- $table->addRow([$topic->getName(), $topic->getDescription(), implode(PHP_EOL, $topic->getProcessors())]);
-
- ++$count;
- $firstRow = false;
- }
-
- $output->writeln(sprintf('Found %s topics', $count));
- $output->writeln('');
- $table->render();
- }
-}
diff --git a/pkg/enqueue/Symfony/Client/ProduceCommand.php b/pkg/enqueue/Symfony/Client/ProduceCommand.php
new file mode 100644
index 000000000..bd23c16c3
--- /dev/null
+++ b/pkg/enqueue/Symfony/Client/ProduceCommand.php
@@ -0,0 +1,92 @@
+container = $container;
+ $this->defaultClient = $defaultClient;
+ $this->producerIdPattern = $producerIdPattern;
+
+ parent::__construct();
+ }
+
+ protected function configure(): void
+ {
+ $this
+ ->setDescription('Sends an event to the topic')
+ ->addArgument('message', InputArgument::REQUIRED, 'A message')
+ ->addOption('header', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'The message headers')
+ ->addOption('client', 'c', InputOption::VALUE_OPTIONAL, 'The client to consume messages from.', $this->defaultClient)
+ ->addOption('topic', null, InputOption::VALUE_OPTIONAL, 'The topic to send a message to')
+ ->addOption('command', null, InputOption::VALUE_OPTIONAL, 'The command to send a message to')
+ ;
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int
+ {
+ $topic = $input->getOption('topic');
+ $command = $input->getOption('command');
+ $message = $input->getArgument('message');
+ $headers = (array) $input->getOption('header');
+ $client = $input->getOption('client');
+
+ if ($topic && $command) {
+ throw new \LogicException('Either topic or command option should be set, both are set.');
+ }
+
+ try {
+ $producer = $this->getProducer($client);
+ } catch (NotFoundExceptionInterface $e) {
+ throw new \LogicException(sprintf('Client "%s" is not supported.', $client), null, $e);
+ }
+
+ if ($topic) {
+ $producer->sendEvent($topic, new Message($message, [], $headers));
+
+ $output->writeln('An event is sent');
+ } elseif ($command) {
+ $producer->sendCommand($command, $message);
+
+ $output->writeln('A command is sent');
+ } else {
+ throw new \LogicException('Either topic or command option should be set, none is set.');
+ }
+
+ return 0;
+ }
+
+ private function getProducer(string $client): ProducerInterface
+ {
+ return $this->container->get(sprintf($this->producerIdPattern, $client));
+ }
+}
diff --git a/pkg/enqueue/Symfony/Client/ProduceMessageCommand.php b/pkg/enqueue/Symfony/Client/ProduceMessageCommand.php
deleted file mode 100644
index a9f9ef90a..000000000
--- a/pkg/enqueue/Symfony/Client/ProduceMessageCommand.php
+++ /dev/null
@@ -1,54 +0,0 @@
-producer = $producer;
- }
-
- /**
- * {@inheritdoc}
- */
- protected function configure()
- {
- $this
- ->setName('enqueue:produce')
- ->setAliases(['enq:p'])
- ->setDescription('A command to send a message to topic')
- ->addArgument('topic', InputArgument::REQUIRED, 'A topic to send message to')
- ->addArgument('message', InputArgument::REQUIRED, 'A message to send')
- ;
- }
-
- /**
- * {@inheritdoc}
- */
- protected function execute(InputInterface $input, OutputInterface $output)
- {
- $this->producer->sendEvent(
- $input->getArgument('topic'),
- $input->getArgument('message')
- );
-
- $output->writeln('Message is sent');
- }
-}
diff --git a/pkg/enqueue/Symfony/Client/RoutesCommand.php b/pkg/enqueue/Symfony/Client/RoutesCommand.php
new file mode 100644
index 000000000..0646e37bb
--- /dev/null
+++ b/pkg/enqueue/Symfony/Client/RoutesCommand.php
@@ -0,0 +1,162 @@
+container = $container;
+ $this->defaultClient = $defaultClient;
+ $this->driverIdPatter = $driverIdPatter;
+
+ parent::__construct();
+ }
+
+ protected function configure(): void
+ {
+ $this
+ ->setAliases(['debug:enqueue:routes'])
+ ->setDescription('A command lists all registered routes.')
+ ->addOption('show-route-options', null, InputOption::VALUE_NONE, 'Adds ability to hide options.')
+ ->addOption('client', 'c', InputOption::VALUE_OPTIONAL, 'The client to consume messages from.', $this->defaultClient)
+ ;
+
+ $this->driver = null;
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int
+ {
+ try {
+ $this->driver = $this->getDriver($input->getOption('client'));
+ } catch (NotFoundExceptionInterface $e) {
+ throw new \LogicException(sprintf('Client "%s" is not supported.', $input->getOption('client')), null, $e);
+ }
+
+ $routes = $this->driver->getRouteCollection()->all();
+ $output->writeln(sprintf('Found %s routes', count($routes)));
+ $output->writeln('');
+
+ if ($routes) {
+ $table = new Table($output);
+ $table->setHeaders(['Type', 'Source', 'Queue', 'Processor', 'Options']);
+
+ $firstRow = true;
+ foreach ($routes as $route) {
+ if (false == $firstRow) {
+ $table->addRow(new TableSeparator());
+
+ $firstRow = false;
+ }
+
+ if ($route->isCommand()) {
+ continue;
+ }
+
+ $table->addRow([
+ $this->formatSourceType($route),
+ $route->getSource(),
+ $this->formatQueue($route),
+ $this->formatProcessor($route),
+ $input->getOption('show-route-options') ? $this->formatOptions($route) : '(hidden)',
+ ]);
+ }
+
+ foreach ($routes as $route) {
+ if ($route->isTopic()) {
+ continue;
+ }
+
+ $table->addRow([
+ $this->formatSourceType($route),
+ $route->getSource(),
+ $this->formatQueue($route),
+ $this->formatProcessor($route),
+ $input->getOption('show-route-options') ? $this->formatOptions($route) : '(hidden)',
+ ]);
+ }
+
+ $table->render();
+ }
+
+ return 0;
+ }
+
+ private function formatSourceType(Route $route): string
+ {
+ if ($route->isCommand()) {
+ return 'command';
+ }
+
+ if ($route->isTopic()) {
+ return 'topic';
+ }
+
+ return 'unknown';
+ }
+
+ private function formatProcessor(Route $route): string
+ {
+ if ($route->isProcessorExternal()) {
+ return 'n\a (external)';
+ }
+
+ $processor = $route->getProcessor();
+
+ return $route->isProcessorExclusive() ? $processor.' (exclusive)' : $processor;
+ }
+
+ private function formatQueue(Route $route): string
+ {
+ $queue = $route->getQueue() ?: $this->driver->getConfig()->getDefaultQueue();
+
+ return $route->isPrefixQueue() ? $queue.' (prefixed)' : $queue.' (as is)';
+ }
+
+ private function formatOptions(Route $route): string
+ {
+ return var_export($route->getOptions(), true);
+ }
+
+ private function getDriver(string $client): DriverInterface
+ {
+ return $this->container->get(sprintf($this->driverIdPatter, $client));
+ }
+}
+
+function enqueue()
+{
+}
diff --git a/pkg/enqueue/Symfony/Client/SetupBrokerCommand.php b/pkg/enqueue/Symfony/Client/SetupBrokerCommand.php
index c825bd2c4..b74902aa6 100644
--- a/pkg/enqueue/Symfony/Client/SetupBrokerCommand.php
+++ b/pkg/enqueue/Symfony/Client/SetupBrokerCommand.php
@@ -3,47 +3,68 @@
namespace Enqueue\Symfony\Client;
use Enqueue\Client\DriverInterface;
+use Psr\Container\ContainerInterface;
+use Psr\Container\NotFoundExceptionInterface;
+use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Logger\ConsoleLogger;
use Symfony\Component\Console\Output\OutputInterface;
+#[AsCommand('enqueue:setup-broker')]
class SetupBrokerCommand extends Command
{
/**
- * @var DriverInterface
+ * @var ContainerInterface
*/
- private $driver;
+ private $container;
/**
- * @param DriverInterface $driver
+ * @var string
*/
- public function __construct(DriverInterface $driver)
+ private $defaultClient;
+
+ /**
+ * @var string
+ */
+ private $driverIdPattern;
+
+ public function __construct(ContainerInterface $container, string $defaultClient, string $driverIdPattern = 'enqueue.client.%s.driver')
{
- parent::__construct(null);
+ $this->container = $container;
+ $this->defaultClient = $defaultClient;
+ $this->driverIdPattern = $driverIdPattern;
- $this->driver = $driver;
+ parent::__construct();
}
- /**
- * {@inheritdoc}
- */
- protected function configure()
+ protected function configure(): void
{
$this
- ->setName('enqueue:setup-broker')
->setAliases(['enq:sb'])
- ->setDescription('Creates all required queues')
+ ->setDescription('Setup broker. Configure the broker, creates queues, topics and so on.')
+ ->addOption('client', 'c', InputOption::VALUE_OPTIONAL, 'The client to consume messages from.', $this->defaultClient)
;
}
- /**
- * {@inheritdoc}
- */
- protected function execute(InputInterface $input, OutputInterface $output)
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
- $output->writeln('Setup Broker');
+ $client = $input->getOption('client');
+
+ try {
+ $this->getDriver($client)->setupBroker(new ConsoleLogger($output));
+ } catch (NotFoundExceptionInterface $e) {
+ throw new \LogicException(sprintf('Client "%s" is not supported.', $client), null, $e);
+ }
+
+ $output->writeln('Broker set up');
- $this->driver->setupBroker(new ConsoleLogger($output));
+ return 0;
+ }
+
+ private function getDriver(string $client): DriverInterface
+ {
+ return $this->container->get(sprintf($this->driverIdPattern, $client));
}
}
diff --git a/pkg/enqueue/Symfony/Client/SetupBrokerExtensionCommandTrait.php b/pkg/enqueue/Symfony/Client/SetupBrokerExtensionCommandTrait.php
index 2888f5636..bcc4f7bb2 100644
--- a/pkg/enqueue/Symfony/Client/SetupBrokerExtensionCommandTrait.php
+++ b/pkg/enqueue/Symfony/Client/SetupBrokerExtensionCommandTrait.php
@@ -10,9 +10,6 @@
trait SetupBrokerExtensionCommandTrait
{
- /**
- * {@inheritdoc}
- */
protected function configureSetupBrokerExtension()
{
$this
@@ -21,10 +18,7 @@ protected function configureSetupBrokerExtension()
}
/**
- * @param InputInterface $input
- * @param DriverInterface $driver
- *
- * @return ExtensionInterface
+ * @return ExtensionInterface|null
*/
protected function getSetupBrokerExtension(InputInterface $input, DriverInterface $driver)
{
diff --git a/pkg/enqueue/Symfony/Client/SimpleConsumeCommand.php b/pkg/enqueue/Symfony/Client/SimpleConsumeCommand.php
new file mode 100644
index 000000000..fafc35d05
--- /dev/null
+++ b/pkg/enqueue/Symfony/Client/SimpleConsumeCommand.php
@@ -0,0 +1,26 @@
+ $queueConsumer,
+ 'driver' => $driver,
+ 'processor' => $processor,
+ ]),
+ 'default',
+ 'queue_consumer',
+ 'driver',
+ 'processor'
+ );
+ }
+}
diff --git a/pkg/enqueue/Symfony/Client/SimpleProduceCommand.php b/pkg/enqueue/Symfony/Client/SimpleProduceCommand.php
new file mode 100644
index 000000000..5d7f76533
--- /dev/null
+++ b/pkg/enqueue/Symfony/Client/SimpleProduceCommand.php
@@ -0,0 +1,18 @@
+ $producer]),
+ 'default',
+ 'producer'
+ );
+ }
+}
diff --git a/pkg/enqueue/Symfony/Client/SimpleRoutesCommand.php b/pkg/enqueue/Symfony/Client/SimpleRoutesCommand.php
new file mode 100644
index 000000000..0023f14ae
--- /dev/null
+++ b/pkg/enqueue/Symfony/Client/SimpleRoutesCommand.php
@@ -0,0 +1,18 @@
+ $driver]),
+ 'default',
+ 'driver'
+ );
+ }
+}
diff --git a/pkg/enqueue/Symfony/Client/SimpleSetupBrokerCommand.php b/pkg/enqueue/Symfony/Client/SimpleSetupBrokerCommand.php
new file mode 100644
index 000000000..aae19f84b
--- /dev/null
+++ b/pkg/enqueue/Symfony/Client/SimpleSetupBrokerCommand.php
@@ -0,0 +1,18 @@
+ $driver]),
+ 'default',
+ 'driver'
+ );
+ }
+}
diff --git a/pkg/enqueue/Symfony/Consumption/ChooseLoggerCommandTrait.php b/pkg/enqueue/Symfony/Consumption/ChooseLoggerCommandTrait.php
new file mode 100644
index 000000000..c229c14b0
--- /dev/null
+++ b/pkg/enqueue/Symfony/Consumption/ChooseLoggerCommandTrait.php
@@ -0,0 +1,35 @@
+addOption('logger', null, InputOption::VALUE_OPTIONAL, 'A logger to be used. Could be "default", "null", "stdout".', 'default')
+ ;
+ }
+
+ protected function getLoggerExtension(InputInterface $input, OutputInterface $output): ?LoggerExtension
+ {
+ $logger = $input->getOption('logger');
+ switch ($logger) {
+ case 'null':
+ return new LoggerExtension(new NullLogger());
+ case 'stdout':
+ return new LoggerExtension(new ConsoleLogger($output));
+ case 'default':
+ return null;
+ default:
+ throw new \LogicException(sprintf('The logger "%s" is not supported', $logger));
+ }
+ }
+}
diff --git a/pkg/enqueue/Symfony/Consumption/ConfigurableConsumeCommand.php b/pkg/enqueue/Symfony/Consumption/ConfigurableConsumeCommand.php
new file mode 100644
index 000000000..230a0dc69
--- /dev/null
+++ b/pkg/enqueue/Symfony/Consumption/ConfigurableConsumeCommand.php
@@ -0,0 +1,122 @@
+container = $container;
+ $this->defaultTransport = $defaultTransport;
+ $this->queueConsumerIdPattern = $queueConsumerIdPattern;
+ $this->processorRegistryIdPattern = $processorRegistryIdPattern;
+
+ parent::__construct();
+ }
+
+ protected function configure(): void
+ {
+ $this->configureLimitsExtensions();
+ $this->configureQueueConsumerOptions();
+ $this->configureLoggerExtension();
+
+ $this
+ ->setDescription('A worker that consumes message from a broker. '.
+ 'To use this broker you have to explicitly set a queue to consume from '.
+ 'and a message processor service')
+ ->addArgument('processor', InputArgument::REQUIRED, 'A message processor.')
+ ->addArgument('queues', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, 'A queue to consume from', [])
+ ->addOption('transport', 't', InputOption::VALUE_OPTIONAL, 'The transport to consume messages from.', $this->defaultTransport)
+ ;
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int
+ {
+ $transport = $input->getOption('transport');
+
+ try {
+ $consumer = $this->getQueueConsumer($transport);
+ } catch (NotFoundExceptionInterface $e) {
+ throw new \LogicException(sprintf('Transport "%s" is not supported.', $transport), null, $e);
+ }
+
+ $this->setQueueConsumerOptions($consumer, $input);
+
+ $processor = $this->getProcessorRegistry($transport)->get($input->getArgument('processor'));
+
+ $queues = $input->getArgument('queues');
+ if (empty($queues) && $processor instanceof QueueSubscriberInterface) {
+ $queues = $processor::getSubscribedQueues();
+ }
+
+ if (empty($queues)) {
+ throw new \LogicException(sprintf('The queue is not provided. The processor must implement "%s" interface and it must return not empty array of queues or a queue set using as a second argument.', QueueSubscriberInterface::class));
+ }
+
+ $extensions = $this->getLimitsExtensions($input, $output);
+
+ if ($loggerExtension = $this->getLoggerExtension($input, $output)) {
+ array_unshift($extensions, $loggerExtension);
+ }
+
+ foreach ($queues as $queue) {
+ $consumer->bind($queue, $processor);
+ }
+
+ $consumer->consume(new ChainExtension($extensions));
+
+ return 0;
+ }
+
+ private function getQueueConsumer(string $name): QueueConsumerInterface
+ {
+ return $this->container->get(sprintf($this->queueConsumerIdPattern, $name));
+ }
+
+ private function getProcessorRegistry(string $name): ProcessorRegistryInterface
+ {
+ return $this->container->get(sprintf($this->processorRegistryIdPattern, $name));
+ }
+}
diff --git a/pkg/enqueue/Symfony/Consumption/ConsumeCommand.php b/pkg/enqueue/Symfony/Consumption/ConsumeCommand.php
new file mode 100644
index 000000000..1c82f3cfb
--- /dev/null
+++ b/pkg/enqueue/Symfony/Consumption/ConsumeCommand.php
@@ -0,0 +1,91 @@
+container = $container;
+ $this->defaultTransport = $defaultTransport;
+ $this->queueConsumerIdPattern = $queueConsumerIdPattern;
+
+ parent::__construct();
+ }
+
+ protected function configure(): void
+ {
+ $this->configureLimitsExtensions();
+ $this->configureQueueConsumerOptions();
+ $this->configureLoggerExtension();
+
+ $this
+ ->addOption('transport', 't', InputOption::VALUE_OPTIONAL, 'The transport to consume messages from.', $this->defaultTransport)
+ ->setDescription('A worker that consumes message from a broker. '.
+ 'To use this broker you have to configure queue consumer before adding to the command')
+ ;
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int
+ {
+ $transport = $input->getOption('transport');
+
+ try {
+ // QueueConsumer must be pre configured outside of the command!
+ $consumer = $this->getQueueConsumer($transport);
+ } catch (NotFoundExceptionInterface $e) {
+ throw new \LogicException(sprintf('Transport "%s" is not supported.', $transport), null, $e);
+ }
+
+ $this->setQueueConsumerOptions($consumer, $input);
+
+ $extensions = $this->getLimitsExtensions($input, $output);
+
+ if ($loggerExtension = $this->getLoggerExtension($input, $output)) {
+ array_unshift($extensions, $loggerExtension);
+ }
+
+ $exitStatusExtension = new ExitStatusExtension();
+ array_unshift($extensions, $exitStatusExtension);
+
+ $consumer->consume(new ChainExtension($extensions));
+
+ return $exitStatusExtension->getExitStatus() ?? 0;
+ }
+
+ private function getQueueConsumer(string $name): QueueConsumerInterface
+ {
+ return $this->container->get(sprintf($this->queueConsumerIdPattern, $name));
+ }
+}
diff --git a/pkg/enqueue/Symfony/Consumption/ConsumeMessagesCommand.php b/pkg/enqueue/Symfony/Consumption/ConsumeMessagesCommand.php
deleted file mode 100644
index c2c7695f1..000000000
--- a/pkg/enqueue/Symfony/Consumption/ConsumeMessagesCommand.php
+++ /dev/null
@@ -1,65 +0,0 @@
-consumer = $consumer;
- }
-
- /**
- * {@inheritdoc}
- */
- protected function configure()
- {
- $this->configureLimitsExtensions();
- $this->configureQueueConsumerOptions();
-
- $this
- ->setName('enqueue:transport:consume')
- ->setDescription('A worker that consumes message from a broker. '.
- 'To use this broker you have to configure queue consumer before adding to the command')
- ;
- }
-
- /**
- * {@inheritdoc}
- */
- protected function execute(InputInterface $input, OutputInterface $output)
- {
- $this->setQueueConsumerOptions($this->consumer, $input);
-
- $extensions = $this->getLimitsExtensions($input, $output);
- array_unshift($extensions, new LoggerExtension(new ConsoleLogger($output)));
-
- $runtimeExtensions = new ChainExtension($extensions);
-
- $this->consumer->consume($runtimeExtensions);
- }
-}
diff --git a/pkg/enqueue/Symfony/Consumption/ContainerAwareConsumeMessagesCommand.php b/pkg/enqueue/Symfony/Consumption/ContainerAwareConsumeMessagesCommand.php
deleted file mode 100644
index 297dfa58d..000000000
--- a/pkg/enqueue/Symfony/Consumption/ContainerAwareConsumeMessagesCommand.php
+++ /dev/null
@@ -1,100 +0,0 @@
-consumer = $consumer;
- }
-
- /**
- * {@inheritdoc}
- */
- protected function configure()
- {
- $this->configureLimitsExtensions();
- $this->configureQueueConsumerOptions();
-
- $this
- ->setName('enqueue:transport:consume')
- ->setDescription('A worker that consumes message from a broker. '.
- 'To use this broker you have to explicitly set a queue to consume from '.
- 'and a message processor service')
- ->addArgument('processor-service', InputArgument::REQUIRED, 'A message processor service')
- ->addOption('queue', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'Queues to consume from', [])
- ;
- }
-
- /**
- * {@inheritdoc}
- */
- protected function execute(InputInterface $input, OutputInterface $output)
- {
- $this->setQueueConsumerOptions($this->consumer, $input);
-
- /** @var PsrProcessor $processor */
- $processor = $this->container->get($input->getArgument('processor-service'));
- if (false == $processor instanceof PsrProcessor) {
- throw new \LogicException(sprintf(
- 'Invalid message processor service given. It must be an instance of %s but %s',
- PsrProcessor::class,
- get_class($processor)
- ));
- }
-
- $queues = $input->getOption('queue');
- if (empty($queues) && $processor instanceof QueueSubscriberInterface) {
- $queues = $processor::getSubscribedQueues();
- }
-
- if (empty($queues)) {
- throw new \LogicException(sprintf(
- 'The queues are not provided. The processor must implement "%s" interface and it must return not empty array of queues or queues set using --queue option.',
- QueueSubscriberInterface::class
- ));
- }
-
- $extensions = $this->getLimitsExtensions($input, $output);
- array_unshift($extensions, new LoggerExtension(new ConsoleLogger($output)));
-
- $runtimeExtensions = new ChainExtension($extensions);
-
- foreach ($queues as $queue) {
- $this->consumer->bind($queue, $processor);
- }
-
- $this->consumer->consume($runtimeExtensions);
- }
-}
diff --git a/pkg/enqueue/Symfony/Consumption/LimitsExtensionsCommandTrait.php b/pkg/enqueue/Symfony/Consumption/LimitsExtensionsCommandTrait.php
index 2a756180c..d8351acc5 100644
--- a/pkg/enqueue/Symfony/Consumption/LimitsExtensionsCommandTrait.php
+++ b/pkg/enqueue/Symfony/Consumption/LimitsExtensionsCommandTrait.php
@@ -13,9 +13,6 @@
trait LimitsExtensionsCommandTrait
{
- /**
- * {@inheritdoc}
- */
protected function configureLimitsExtensions()
{
$this
@@ -26,9 +23,6 @@ protected function configureLimitsExtensions()
}
/**
- * @param InputInterface $input
- * @param OutputInterface $output
- *
* @throws \Exception
*
* @return ExtensionInterface[]
@@ -61,8 +55,8 @@ protected function getLimitsExtensions(InputInterface $input, OutputInterface $o
}
$niceness = $input->getOption('niceness');
- if ($niceness) {
- $extensions[] = new NicenessExtension($niceness);
+ if (!empty($niceness) && is_numeric($niceness)) {
+ $extensions[] = new NicenessExtension((int) $niceness);
}
return $extensions;
diff --git a/pkg/enqueue/Symfony/Consumption/QueueConsumerOptionsCommandTrait.php b/pkg/enqueue/Symfony/Consumption/QueueConsumerOptionsCommandTrait.php
index c6ffd985f..fd736f226 100644
--- a/pkg/enqueue/Symfony/Consumption/QueueConsumerOptionsCommandTrait.php
+++ b/pkg/enqueue/Symfony/Consumption/QueueConsumerOptionsCommandTrait.php
@@ -2,33 +2,21 @@
namespace Enqueue\Symfony\Consumption;
-use Enqueue\Consumption\QueueConsumer;
+use Enqueue\Consumption\QueueConsumerInterface;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
trait QueueConsumerOptionsCommandTrait
{
- /**
- * {@inheritdoc}
- */
protected function configureQueueConsumerOptions()
{
$this
- ->addOption('idle-timeout', null, InputOption::VALUE_REQUIRED, 'The time in milliseconds queue consumer idle if no message has been received.')
->addOption('receive-timeout', null, InputOption::VALUE_REQUIRED, 'The time in milliseconds queue consumer waits for a message.')
;
}
- /**
- * @param QueueConsumer $consumer
- * @param InputInterface $input
- */
- protected function setQueueConsumerOptions(QueueConsumer $consumer, InputInterface $input)
+ protected function setQueueConsumerOptions(QueueConsumerInterface $consumer, InputInterface $input)
{
- if (null !== $idleTimeout = $input->getOption('idle-timeout')) {
- $consumer->setIdleTimeout((int) $idleTimeout);
- }
-
if (null !== $receiveTimeout = $input->getOption('receive-timeout')) {
$consumer->setReceiveTimeout((int) $receiveTimeout);
}
diff --git a/pkg/enqueue/Symfony/Consumption/SimpleConsumeCommand.php b/pkg/enqueue/Symfony/Consumption/SimpleConsumeCommand.php
new file mode 100644
index 000000000..90d0e362e
--- /dev/null
+++ b/pkg/enqueue/Symfony/Consumption/SimpleConsumeCommand.php
@@ -0,0 +1,18 @@
+ $consumer]),
+ 'default',
+ 'queue_consumer'
+ );
+ }
+}
diff --git a/pkg/enqueue/Symfony/ContainerProcessorRegistry.php b/pkg/enqueue/Symfony/ContainerProcessorRegistry.php
new file mode 100644
index 000000000..b259d2379
--- /dev/null
+++ b/pkg/enqueue/Symfony/ContainerProcessorRegistry.php
@@ -0,0 +1,29 @@
+locator = $locator;
+ }
+
+ public function get(string $processorName): Processor
+ {
+ if (false == $this->locator->has($processorName)) {
+ throw new \LogicException(sprintf('Service locator does not have a processor with name "%s".', $processorName));
+ }
+
+ return $this->locator->get($processorName);
+ }
+}
diff --git a/pkg/enqueue/Symfony/DefaultTransportFactory.php b/pkg/enqueue/Symfony/DefaultTransportFactory.php
deleted file mode 100644
index fa45d2544..000000000
--- a/pkg/enqueue/Symfony/DefaultTransportFactory.php
+++ /dev/null
@@ -1,230 +0,0 @@
-name = $name;
- }
-
- /**
- * {@inheritdoc}
- */
- public function addConfiguration(ArrayNodeDefinition $builder)
- {
- $builder
- ->beforeNormalization()
- ->always(function ($v) {
- if (is_array($v)) {
- if (empty($v['dsn']) && empty($v['alias'])) {
- throw new \LogicException('Either dsn or alias option must be set');
- }
-
- return $v;
- }
-
- if (empty($v)) {
- return ['dsn' => 'null:'];
- }
-
- if (is_string($v)) {
- return false !== strpos($v, ':') || false !== strpos($v, 'env_') ?
- ['dsn' => $v] :
- ['alias' => $v];
- }
- })
- ->end()
- ->children()
- ->scalarNode('alias')->cannotBeEmpty()->end()
- ->scalarNode('dsn')->cannotBeEmpty()->end()
- ->end()
- ->end()
- ;
- }
-
- public function createConnectionFactory(ContainerBuilder $container, array $config)
- {
- if (isset($config['alias'])) {
- $aliasId = sprintf('enqueue.transport.%s.connection_factory', $config['alias']);
- } else {
- $dsn = $this->resolveDSN($container, $config['dsn']);
-
- $aliasId = $this->findFactory($dsn)->createConnectionFactory($container, $config);
- }
-
- $factoryId = sprintf('enqueue.transport.%s.connection_factory', $this->getName());
-
- $container->setAlias($factoryId, new Alias($aliasId, true));
- $container->setAlias('enqueue.transport.connection_factory', new Alias($factoryId, true));
-
- return $factoryId;
- }
-
- /**
- * {@inheritdoc}
- */
- public function createContext(ContainerBuilder $container, array $config)
- {
- if (isset($config['alias'])) {
- $aliasId = sprintf('enqueue.transport.%s.context', $config['alias']);
- } else {
- $dsn = $this->resolveDSN($container, $config['dsn']);
-
- $aliasId = $this->findFactory($dsn)->createContext($container, $config);
- }
-
- $contextId = sprintf('enqueue.transport.%s.context', $this->getName());
-
- $container->setAlias($contextId, new Alias($aliasId, true));
- $container->setAlias('enqueue.transport.context', new Alias($contextId, true));
-
- return $contextId;
- }
-
- /**
- * {@inheritdoc}
- */
- public function createDriver(ContainerBuilder $container, array $config)
- {
- if (isset($config['alias'])) {
- $aliasId = sprintf('enqueue.client.%s.driver', $config['alias']);
- } else {
- $dsn = $this->resolveDSN($container, $config['dsn']);
-
- $aliasId = $this->findFactory($dsn)->createDriver($container, $config);
- }
-
- $driverId = sprintf('enqueue.client.%s.driver', $this->getName());
-
- $container->setAlias($driverId, new Alias($aliasId, true));
- $container->setAlias('enqueue.client.driver', new Alias($driverId, true));
-
- return $driverId;
- }
-
- /**
- * @return string
- */
- public function getName()
- {
- return $this->name;
- }
-
- /**
- * This is a quick fix to the exception "Incompatible use of dynamic environment variables "ENQUEUE_DSN" found in parameters."
- * TODO: We'll have to come up with a better solution.
- *
- * @param ContainerBuilder $container
- * @param $dsn
- *
- * @return array|false|string
- */
- private function resolveDSN(ContainerBuilder $container, $dsn)
- {
- if (method_exists($container, 'resolveEnvPlaceholders')) {
- $dsn = $container->resolveEnvPlaceholders($dsn);
-
- $matches = [];
- if (preg_match('/%env\((.*?)\)/', $dsn, $matches)) {
- if (false === $realDsn = getenv($matches[1])) {
- throw new \LogicException(sprintf('The env "%s" var is not defined', $matches[1]));
- }
-
- return $realDsn;
- }
- }
-
- return $dsn;
- }
-
- /**
- * @param string
- * @param mixed $dsn
- *
- * @return TransportFactoryInterface
- */
- private function findFactory($dsn)
- {
- $factory = dsn_to_connection_factory($dsn);
-
- if ($factory instanceof AmqpConnectionFactory) {
- return new AmqpTransportFactory('default_amqp');
- }
-
- if ($factory instanceof FsConnectionFactory) {
- return new FsTransportFactory('default_fs');
- }
-
- if ($factory instanceof DbalConnectionFactory) {
- return new DbalTransportFactory('default_dbal');
- }
-
- if ($factory instanceof NullConnectionFactory) {
- return new NullTransportFactory('default_null');
- }
-
- if ($factory instanceof GpsConnectionFactory) {
- return new GpsTransportFactory('default_gps');
- }
-
- if ($factory instanceof RedisConnectionFactory) {
- return new RedisTransportFactory('default_redis');
- }
-
- if ($factory instanceof SqsConnectionFactory) {
- return new SqsTransportFactory('default_sqs');
- }
-
- if ($factory instanceof StompConnectionFactory) {
- return new StompTransportFactory('default_stomp');
- }
-
- if ($factory instanceof RdKafkaConnectionFactory) {
- return new RdKafkaTransportFactory('default_kafka');
- }
-
- if ($factory instanceof MongodbConnectionFactory) {
- return new MongodbTransportFactory('default_mongodb');
- }
-
- throw new \LogicException(sprintf(
- 'There is no supported transport factory for the connection factory "%s" created from DSN "%s"',
- get_class($factory),
- $dsn
- ));
- }
-}
diff --git a/pkg/enqueue/Symfony/DependencyInjection/BuildConsumptionExtensionsPass.php b/pkg/enqueue/Symfony/DependencyInjection/BuildConsumptionExtensionsPass.php
new file mode 100644
index 000000000..99f274ec5
--- /dev/null
+++ b/pkg/enqueue/Symfony/DependencyInjection/BuildConsumptionExtensionsPass.php
@@ -0,0 +1,60 @@
+hasParameter('enqueue.transports')) {
+ throw new \LogicException('The "enqueue.transports" parameter must be set.');
+ }
+
+ $names = $container->getParameter('enqueue.transports');
+ $defaultName = $container->getParameter('enqueue.default_transport');
+
+ foreach ($names as $name) {
+ $diUtils = DiUtils::create(TransportFactory::MODULE, $name);
+
+ $extensionsId = $diUtils->format('consumption_extensions');
+ if (false == $container->hasDefinition($extensionsId)) {
+ throw new \LogicException(sprintf('Service "%s" not found', $extensionsId));
+ }
+
+ $tags = $container->findTaggedServiceIds('enqueue.transport.consumption_extension');
+
+ $groupByPriority = [];
+ foreach ($tags as $serviceId => $tagAttributes) {
+ foreach ($tagAttributes as $tagAttribute) {
+ $transport = $tagAttribute['transport'] ?? $defaultName;
+
+ if ($transport !== $name && 'all' !== $transport) {
+ continue;
+ }
+
+ $priority = (int) ($tagAttribute['priority'] ?? 0);
+
+ $groupByPriority[$priority][] = new Reference($serviceId);
+ }
+ }
+
+ krsort($groupByPriority, \SORT_NUMERIC);
+
+ $flatExtensions = [];
+ foreach ($groupByPriority as $extension) {
+ $flatExtensions = array_merge($flatExtensions, $extension);
+ }
+
+ $extensionsService = $container->getDefinition($extensionsId);
+ $extensionsService->replaceArgument(0, array_merge(
+ $extensionsService->getArgument(0),
+ $flatExtensions
+ ));
+ }
+ }
+}
diff --git a/pkg/enqueue/Symfony/DependencyInjection/BuildProcessorRegistryPass.php b/pkg/enqueue/Symfony/DependencyInjection/BuildProcessorRegistryPass.php
new file mode 100644
index 000000000..cc6e04270
--- /dev/null
+++ b/pkg/enqueue/Symfony/DependencyInjection/BuildProcessorRegistryPass.php
@@ -0,0 +1,50 @@
+hasParameter('enqueue.transports')) {
+ throw new \LogicException('The "enqueue.transports" parameter must be set.');
+ }
+
+ $names = $container->getParameter('enqueue.transports');
+ $defaultName = $container->getParameter('enqueue.default_transport');
+
+ foreach ($names as $name) {
+ $diUtils = DiUtils::create(TransportFactory::MODULE, $name);
+
+ $processorRegistryId = $diUtils->format('processor_registry');
+ if (false == $container->hasDefinition($processorRegistryId)) {
+ throw new \LogicException(sprintf('Service "%s" not found', $processorRegistryId));
+ }
+
+ $tag = 'enqueue.transport.processor';
+ $map = [];
+ foreach ($container->findTaggedServiceIds($tag) as $serviceId => $tagAttributes) {
+ foreach ($tagAttributes as $tagAttribute) {
+ $transport = $tagAttribute['transport'] ?? $defaultName;
+
+ if ($transport !== $name && 'all' !== $transport) {
+ continue;
+ }
+
+ $processor = $tagAttribute['processor'] ?? $serviceId;
+
+ $map[$processor] = new Reference($serviceId);
+ }
+ }
+
+ $registry = $container->getDefinition($processorRegistryId);
+ $registry->setArgument(0, ServiceLocatorTagPass::register($container, $map, $processorRegistryId));
+ }
+ }
+}
diff --git a/pkg/enqueue/Symfony/DependencyInjection/TransportFactory.php b/pkg/enqueue/Symfony/DependencyInjection/TransportFactory.php
new file mode 100644
index 000000000..944b1a30d
--- /dev/null
+++ b/pkg/enqueue/Symfony/DependencyInjection/TransportFactory.php
@@ -0,0 +1,266 @@
+default = $default;
+ $this->diUtils = DiUtils::create(self::MODULE, $name);
+ }
+
+ public static function getConfiguration(string $name = 'transport'): NodeDefinition
+ {
+ $knownSchemes = array_keys(Resources::getKnownSchemes());
+ $availableSchemes = array_keys(Resources::getAvailableSchemes());
+
+ $builder = new ArrayNodeDefinition($name);
+ $builder
+ ->info('The transport option could accept a string DSN, an array with DSN key, or null. It accept extra options. To find out what option you can set, look at connection factory constructor docblock.')
+ ->beforeNormalization()
+ ->always(function ($v) {
+ if (empty($v)) {
+ return ['dsn' => 'null:'];
+ }
+
+ if (is_array($v)) {
+ if (isset($v['factory_class']) && isset($v['factory_service'])) {
+ throw new \LogicException('Both options factory_class and factory_service are set. Please choose one.');
+ }
+
+ if (isset($v['connection_factory_class']) && (isset($v['factory_class']) || isset($v['factory_service']))) {
+ throw new \LogicException('The option connection_factory_class must not be used with factory_class or factory_service at the same time. Please choose one.');
+ }
+
+ return $v;
+ }
+
+ if (is_string($v)) {
+ return ['dsn' => $v];
+ }
+
+ throw new \LogicException(sprintf('The value must be array, null or string. Got "%s"', gettype($v)));
+ })
+ ->end()
+ ->isRequired()
+ ->ignoreExtraKeys(false)
+ ->children()
+ ->scalarNode('dsn')
+ ->cannotBeEmpty()
+ ->isRequired()
+ ->info(sprintf(
+ 'The MQ broker DSN. These schemes are supported: "%s", to use these "%s" you have to install a package.',
+ implode('", "', $knownSchemes),
+ implode('", "', $availableSchemes)
+ ))
+ ->end()
+ ->scalarNode('connection_factory_class')
+ ->info(sprintf('The connection factory class should implement "%s" interface', ConnectionFactory::class))
+ ->end()
+ ->scalarNode('factory_service')
+ ->info(sprintf('The factory class should implement "%s" interface', ConnectionFactoryFactoryInterface::class))
+ ->end()
+ ->scalarNode('factory_class')
+ ->info(sprintf('The factory service should be a class that implements "%s" interface', ConnectionFactoryFactoryInterface::class))
+ ->end()
+ ->end()
+ ;
+
+ return $builder;
+ }
+
+ public static function getQueueConsumerConfiguration(string $name = 'consumption'): ArrayNodeDefinition
+ {
+ $builder = new ArrayNodeDefinition($name);
+
+ $builder
+ ->addDefaultsIfNotSet()->children()
+ ->integerNode('receive_timeout')
+ ->min(0)
+ ->defaultValue(10000)
+ ->info('the time in milliseconds queue consumer waits for a message (10000 ms by default)')
+ ->end()
+ ;
+
+ return $builder;
+ }
+
+ public function buildConnectionFactory(ContainerBuilder $container, array $config): void
+ {
+ $factoryId = $this->diUtils->format('connection_factory');
+
+ $factoryFactoryId = $this->diUtils->format('connection_factory_factory');
+ $container->register($factoryFactoryId, $config['factory_class'] ?? ConnectionFactoryFactory::class);
+
+ $factoryFactoryService = new Reference(
+ $config['factory_service'] ?? $factoryFactoryId
+ );
+
+ unset($config['factory_service'], $config['factory_class']);
+
+ $connectionFactoryClass = $config['connection_factory_class'] ?? null;
+ unset($config['connection_factory_class']);
+
+ if (isset($connectionFactoryClass)) {
+ $container->register($factoryId, $connectionFactoryClass)
+ ->addArgument($config)
+ ;
+ } else {
+ $container->register($factoryId, ConnectionFactory::class)
+ ->setFactory([$factoryFactoryService, 'create'])
+ ->addArgument($config)
+ ;
+ }
+
+ if ($this->default) {
+ $container->setAlias(ConnectionFactory::class, $factoryId);
+
+ if (DiUtils::DEFAULT_CONFIG !== $this->diUtils->getConfigName()) {
+ $container->setAlias($this->diUtils->formatDefault('connection_factory'), $factoryId);
+ }
+ }
+ }
+
+ public function buildContext(ContainerBuilder $container, array $config): void
+ {
+ $factoryId = $this->diUtils->format('connection_factory');
+ $this->assertServiceExists($container, $factoryId);
+
+ $contextId = $this->diUtils->format('context');
+
+ $container->register($contextId, Context::class)
+ ->setFactory([new Reference($factoryId), 'createContext'])
+ ;
+
+ $this->addServiceToLocator($container, 'context');
+
+ if ($this->default) {
+ $container->setAlias(Context::class, $contextId);
+
+ if (DiUtils::DEFAULT_CONFIG !== $this->diUtils->getConfigName()) {
+ $container->setAlias($this->diUtils->formatDefault('context'), $contextId);
+ }
+ }
+ }
+
+ public function buildQueueConsumer(ContainerBuilder $container, array $config): void
+ {
+ $contextId = $this->diUtils->format('context');
+ $this->assertServiceExists($container, $contextId);
+
+ $container->setParameter($this->diUtils->format('receive_timeout'), $config['receive_timeout'] ?? 10000);
+
+ $logExtensionId = $this->diUtils->format('log_extension');
+ $container->register($logExtensionId, LogExtension::class)
+ ->addTag('enqueue.transport.consumption_extension', ['transport' => $this->diUtils->getConfigName(), 'priority' => -100])
+ ;
+
+ $container->register($this->diUtils->format('consumption_extensions'), ChainExtension::class)
+ ->addArgument([])
+ ;
+
+ $container->register($this->diUtils->format('queue_consumer'), QueueConsumer::class)
+ ->addArgument(new Reference($contextId))
+ ->addArgument(new Reference($this->diUtils->format('consumption_extensions')))
+ ->addArgument([])
+ ->addArgument(new Reference('logger', ContainerInterface::NULL_ON_INVALID_REFERENCE))
+ ->addArgument($this->diUtils->parameter('receive_timeout'))
+ ;
+
+ $container->register($this->diUtils->format('processor_registry'), ContainerProcessorRegistry::class);
+
+ $this->addServiceToLocator($container, 'queue_consumer');
+ $this->addServiceToLocator($container, 'processor_registry');
+
+ if ($this->default) {
+ $container->setAlias(QueueConsumerInterface::class, $this->diUtils->format('queue_consumer'));
+
+ if (DiUtils::DEFAULT_CONFIG !== $this->diUtils->getConfigName()) {
+ $container->setAlias($this->diUtils->formatDefault('queue_consumer'), $this->diUtils->format('queue_consumer'));
+ }
+ }
+ }
+
+ public function buildRpcClient(ContainerBuilder $container, array $config): void
+ {
+ $contextId = $this->diUtils->format('context');
+ $this->assertServiceExists($container, $contextId);
+
+ $container->register($this->diUtils->format('rpc_factory'), RpcFactory::class)
+ ->addArgument(new Reference($contextId))
+ ;
+
+ $container->register($this->diUtils->format('rpc_client'), RpcClient::class)
+ ->addArgument(new Reference($contextId))
+ ->addArgument(new Reference($this->diUtils->format('rpc_factory')))
+ ;
+
+ if ($this->default) {
+ $container->setAlias(RpcClient::class, $this->diUtils->format('rpc_client'));
+
+ if (DiUtils::DEFAULT_CONFIG !== $this->diUtils->getConfigName()) {
+ $container->setAlias($this->diUtils->formatDefault('rpc_client'), $this->diUtils->format('rpc_client'));
+ }
+ }
+ }
+
+ private function assertServiceExists(ContainerBuilder $container, string $serviceId): void
+ {
+ if (false == $container->hasDefinition($serviceId)) {
+ throw new \InvalidArgumentException(sprintf('The service "%s" does not exist.', $serviceId));
+ }
+ }
+
+ private function addServiceToLocator(ContainerBuilder $container, string $serviceName): void
+ {
+ $locatorId = 'enqueue.locator';
+
+ if ($container->hasDefinition($locatorId)) {
+ $locator = $container->getDefinition($locatorId);
+
+ $map = $locator->getArgument(0);
+ $map[$this->diUtils->format($serviceName)] = $this->diUtils->reference($serviceName);
+
+ $locator->replaceArgument(0, $map);
+ }
+ }
+}
diff --git a/pkg/enqueue/Symfony/DiUtils.php b/pkg/enqueue/Symfony/DiUtils.php
new file mode 100644
index 000000000..be45287be
--- /dev/null
+++ b/pkg/enqueue/Symfony/DiUtils.php
@@ -0,0 +1,81 @@
+moduleName = $moduleName;
+ $this->configName = $configName;
+ }
+
+ public static function create(string $moduleName, string $configName): self
+ {
+ return new self($moduleName, $configName);
+ }
+
+ public function getModuleName(): string
+ {
+ return $this->moduleName;
+ }
+
+ public function getConfigName(): string
+ {
+ return $this->configName;
+ }
+
+ public function reference(string $serviceName, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE): Reference
+ {
+ return new Reference($this->format($serviceName), $invalidBehavior);
+ }
+
+ public function referenceDefault(string $serviceName, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE): Reference
+ {
+ return new Reference($this->formatDefault($serviceName), $invalidBehavior);
+ }
+
+ public function parameter(string $serviceName): string
+ {
+ $fullName = $this->format($serviceName);
+
+ return "%$fullName%";
+ }
+
+ public function parameterDefault(string $serviceName): string
+ {
+ $fullName = $this->formatDefault($serviceName);
+
+ return "%$fullName%";
+ }
+
+ public function format(string $serviceName): string
+ {
+ return $this->doFormat($this->moduleName, $this->configName, $serviceName);
+ }
+
+ public function formatDefault(string $serviceName): string
+ {
+ return $this->doFormat($this->moduleName, self::DEFAULT_CONFIG, $serviceName);
+ }
+
+ private function doFormat(string $moduleName, string $configName, string $serviceName): string
+ {
+ return sprintf('enqueue.%s.%s.%s', $moduleName, $configName, $serviceName);
+ }
+}
diff --git a/pkg/enqueue/Symfony/DriverFactoryInterface.php b/pkg/enqueue/Symfony/DriverFactoryInterface.php
deleted file mode 100644
index 0b1ab027d..000000000
--- a/pkg/enqueue/Symfony/DriverFactoryInterface.php
+++ /dev/null
@@ -1,21 +0,0 @@
-info($message)
+ ->beforeNormalization()
+ ->always(function () {
+ return [];
+ })
+ ->end()
+ ->validate()
+ ->always(function () use ($message) {
+ throw new \InvalidArgumentException($message);
+ })
+ ->end()
+ ;
+
+ return $node;
+ }
+}
diff --git a/pkg/enqueue/Symfony/MissingTransportFactory.php b/pkg/enqueue/Symfony/MissingTransportFactory.php
deleted file mode 100644
index 25e6791fa..000000000
--- a/pkg/enqueue/Symfony/MissingTransportFactory.php
+++ /dev/null
@@ -1,94 +0,0 @@
-name = $name;
- $this->packages = $packages;
- }
-
- /**
- * {@inheritdoc}
- */
- public function addConfiguration(ArrayNodeDefinition $builder)
- {
- if (1 == count($this->packages)) {
- $message = sprintf(
- 'In order to use the transport "%s" install a package "%s"',
- $this->getName(),
- implode('", "', $this->packages)
- );
- } else {
- $message = sprintf(
- 'In order to use the transport "%s" install one of the packages "%s"',
- $this->getName(),
- implode('", "', $this->packages)
- );
- }
-
- $builder
- ->info($message)
- ->beforeNormalization()
- ->always(function () {
- return [];
- })
- ->end()
- ->validate()
- ->always(function () use ($message) {
- throw new \InvalidArgumentException($message);
- })
- ->end()
- ;
- }
-
- /**
- * {@inheritdoc}
- */
- public function createConnectionFactory(ContainerBuilder $container, array $config)
- {
- throw new \LogicException('Should not be called');
- }
-
- /**
- * {@inheritdoc}
- */
- public function createContext(ContainerBuilder $container, array $config)
- {
- throw new \LogicException('Should not be called');
- }
-
- /**
- * {@inheritdoc}
- */
- public function createDriver(ContainerBuilder $container, array $config)
- {
- throw new \LogicException('Should not be called');
- }
-
- /**
- * @return string
- */
- public function getName()
- {
- return $this->name;
- }
-}
diff --git a/pkg/enqueue/Symfony/RabbitMqAmqpTransportFactory.php b/pkg/enqueue/Symfony/RabbitMqAmqpTransportFactory.php
deleted file mode 100644
index 94ee9234e..000000000
--- a/pkg/enqueue/Symfony/RabbitMqAmqpTransportFactory.php
+++ /dev/null
@@ -1,69 +0,0 @@
-children()
- ->scalarNode('delay_strategy')
- ->defaultValue('dlx')
- ->info('The delay strategy to be used. Possible values are "dlx", "delayed_message_plugin" or service id')
- ->end()
- ;
- }
-
- /**
- * {@inheritdoc}
- */
- public function createConnectionFactory(ContainerBuilder $container, array $config)
- {
- $factoryId = parent::createConnectionFactory($container, $config);
-
- $this->registerDelayStrategy($container, $config, $factoryId, $this->getName());
-
- return $factoryId;
- }
-
- /**
- * {@inheritdoc}
- */
- public function createDriver(ContainerBuilder $container, array $config)
- {
- $driver = new Definition(RabbitMqDriver::class);
- $driver->setPublic(true);
- $driver->setArguments([
- new Reference(sprintf('enqueue.transport.%s.context', $this->getName())),
- new Reference('enqueue.client.config'),
- new Reference('enqueue.client.meta.queue_meta_registry'),
- ]);
- $driverId = sprintf('enqueue.client.%s.driver', $this->getName());
- $container->setDefinition($driverId, $driver);
-
- return $driverId;
- }
-}
diff --git a/pkg/enqueue/Symfony/TransportFactoryInterface.php b/pkg/enqueue/Symfony/TransportFactoryInterface.php
deleted file mode 100644
index d2be801ca..000000000
--- a/pkg/enqueue/Symfony/TransportFactoryInterface.php
+++ /dev/null
@@ -1,35 +0,0 @@
-assertClassImplements(ProcessorRegistryInterface::class, ArrayProcessorRegistry::class);
}
- public function testCouldBeConstructedWithoutAnyArgument()
- {
- new ArrayProcessorRegistry();
- }
-
public function testShouldThrowExceptionIfProcessorIsNotSet()
{
$registry = new ArrayProcessorRegistry();
@@ -51,10 +47,10 @@ public function testShouldAllowGetProcessorAddedViaAddMethod()
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|PsrProcessor
+ * @return MockObject|Processor
*/
protected function createProcessorMock()
{
- return $this->createMock(PsrProcessor::class);
+ return $this->createMock(Processor::class);
}
}
diff --git a/pkg/enqueue/Tests/Client/Amqp/AmqpDriverTest.php b/pkg/enqueue/Tests/Client/Amqp/AmqpDriverTest.php
deleted file mode 100644
index a82fda082..000000000
--- a/pkg/enqueue/Tests/Client/Amqp/AmqpDriverTest.php
+++ /dev/null
@@ -1,417 +0,0 @@
-assertClassImplements(DriverInterface::class, AmqpDriver::class);
- }
-
- public function testCouldBeConstructedWithRequiredArguments()
- {
- new AmqpDriver(
- $this->createAmqpContextMock(),
- $this->createDummyConfig(),
- $this->createDummyQueueMetaRegistry()
- );
- }
-
- public function testShouldReturnConfigObject()
- {
- $config = $this->createDummyConfig();
-
- $driver = new AmqpDriver($this->createAmqpContextMock(), $config, $this->createDummyQueueMetaRegistry());
-
- $this->assertSame($config, $driver->getConfig());
- }
-
- public function testShouldCreateAndReturnQueueInstance()
- {
- $expectedQueue = new AmqpQueue('aName');
-
- $context = $this->createAmqpContextMock();
- $context
- ->expects($this->once())
- ->method('createQueue')
- ->with('aprefix.afooqueue')
- ->willReturn($expectedQueue)
- ;
-
- $driver = new AmqpDriver($context, $this->createDummyConfig(), $this->createDummyQueueMetaRegistry());
-
- $queue = $driver->createQueue('aFooQueue');
-
- $this->assertSame($expectedQueue, $queue);
- $this->assertSame([], $queue->getArguments());
- $this->assertSame(2, $queue->getFlags());
- $this->assertNull($queue->getConsumerTag());
- }
-
- public function testShouldCreateAndReturnQueueInstanceWithHardcodedTransportName()
- {
- $expectedQueue = new AmqpQueue('aName');
-
- $context = $this->createAmqpContextMock();
- $context
- ->expects($this->once())
- ->method('createQueue')
- ->with('aBarQueue')
- ->willReturn($expectedQueue)
- ;
-
- $driver = new AmqpDriver($context, $this->createDummyConfig(), $this->createDummyQueueMetaRegistry());
-
- $queue = $driver->createQueue('aBarQueue');
-
- $this->assertSame($expectedQueue, $queue);
- }
-
- public function testShouldConvertTransportMessageToClientMessage()
- {
- $transportMessage = new AmqpMessage();
- $transportMessage->setBody('body');
- $transportMessage->setHeaders(['hkey' => 'hval']);
- $transportMessage->setProperties(['key' => 'val']);
- $transportMessage->setHeader('content_type', 'ContentType');
- $transportMessage->setHeader('expiration', '12345000');
- $transportMessage->setMessageId('MessageId');
- $transportMessage->setTimestamp(1000);
- $transportMessage->setReplyTo('theReplyTo');
- $transportMessage->setCorrelationId('theCorrelationId');
-
- $driver = new AmqpDriver(
- $this->createAmqpContextMock(),
- $this->createDummyConfig(),
- $this->createDummyQueueMetaRegistry()
- );
-
- $clientMessage = $driver->createClientMessage($transportMessage);
-
- $this->assertInstanceOf(Message::class, $clientMessage);
- $this->assertSame('body', $clientMessage->getBody());
- $this->assertSame([
- 'hkey' => 'hval',
- 'content_type' => 'ContentType',
- 'expiration' => '12345000',
- 'message_id' => 'MessageId',
- 'timestamp' => 1000,
- 'reply_to' => 'theReplyTo',
- 'correlation_id' => 'theCorrelationId',
- ], $clientMessage->getHeaders());
- $this->assertSame([
- 'key' => 'val',
- ], $clientMessage->getProperties());
- $this->assertSame('MessageId', $clientMessage->getMessageId());
- $this->assertSame(12345, $clientMessage->getExpire());
- $this->assertSame('ContentType', $clientMessage->getContentType());
- $this->assertSame(1000, $clientMessage->getTimestamp());
- $this->assertSame('theReplyTo', $clientMessage->getReplyTo());
- $this->assertSame('theCorrelationId', $clientMessage->getCorrelationId());
- }
-
- public function testShouldThrowExceptionIfExpirationIsNotNumeric()
- {
- $transportMessage = new AmqpMessage();
- $transportMessage->setHeader('expiration', 'is-not-numeric');
-
- $driver = new AmqpDriver(
- $this->createAmqpContextMock(),
- $this->createDummyConfig(),
- $this->createDummyQueueMetaRegistry()
- );
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('expiration header is not numeric. "is-not-numeric"');
-
- $driver->createClientMessage($transportMessage);
- }
-
- public function testShouldConvertClientMessageToTransportMessage()
- {
- $clientMessage = new Message();
- $clientMessage->setBody('body');
- $clientMessage->setHeaders(['hkey' => 'hval']);
- $clientMessage->setProperties(['key' => 'val']);
- $clientMessage->setContentType('ContentType');
- $clientMessage->setExpire(123);
- $clientMessage->setMessageId('MessageId');
- $clientMessage->setTimestamp(1000);
- $clientMessage->setReplyTo('theReplyTo');
- $clientMessage->setCorrelationId('theCorrelationId');
-
- $context = $this->createAmqpContextMock();
- $context
- ->expects($this->once())
- ->method('createMessage')
- ->willReturn(new AmqpMessage())
- ;
-
- $driver = new AmqpDriver(
- $context,
- $this->createDummyConfig(),
- $this->createDummyQueueMetaRegistry()
- );
-
- $transportMessage = $driver->createTransportMessage($clientMessage);
-
- $this->assertInstanceOf(AmqpMessage::class, $transportMessage);
- $this->assertSame('body', $transportMessage->getBody());
- $this->assertSame([
- 'hkey' => 'hval',
- 'message_id' => 'MessageId',
- 'timestamp' => 1000,
- 'reply_to' => 'theReplyTo',
- 'correlation_id' => 'theCorrelationId',
- 'content_type' => 'ContentType',
- 'delivery_mode' => 2,
- 'expiration' => '123000',
- ], $transportMessage->getHeaders());
- $this->assertSame([
- 'key' => 'val',
- ], $transportMessage->getProperties());
- $this->assertSame('MessageId', $transportMessage->getMessageId());
- $this->assertSame(1000, $transportMessage->getTimestamp());
- $this->assertSame('theReplyTo', $transportMessage->getReplyTo());
- $this->assertSame('theCorrelationId', $transportMessage->getCorrelationId());
- }
-
- public function testShouldSendMessageToRouter()
- {
- $topic = new AmqpTopic('');
- $transportMessage = new AmqpMessage();
-
- $producer = $this->createAmqpProducerMock();
- $producer
- ->expects($this->once())
- ->method('send')
- ->with($this->identicalTo($topic), $this->identicalTo($transportMessage))
- ;
- $context = $this->createAmqpContextMock();
- $context
- ->expects($this->once())
- ->method('createTopic')
- ->willReturn($topic)
- ;
- $context
- ->expects($this->once())
- ->method('createProducer')
- ->willReturn($producer)
- ;
- $context
- ->expects($this->once())
- ->method('createMessage')
- ->willReturn($transportMessage)
- ;
-
- $driver = new AmqpDriver(
- $context,
- $this->createDummyConfig(),
- $this->createDummyQueueMetaRegistry()
- );
-
- $message = new Message();
- $message->setProperty(Config::PARAMETER_TOPIC_NAME, 'topic');
-
- $driver->sendToRouter($message);
- }
-
- public function testShouldThrowExceptionIfTopicParameterIsNotSet()
- {
- $driver = new AmqpDriver(
- $this->createAmqpContextMock(),
- $this->createDummyConfig(),
- $this->createDummyQueueMetaRegistry()
- );
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('Topic name parameter is required but is not set');
-
- $driver->sendToRouter(new Message());
- }
-
- public function testShouldSendMessageToProcessor()
- {
- $queue = new AmqpQueue('');
- $transportMessage = new AmqpMessage();
-
- $producer = $this->createAmqpProducerMock();
- $producer
- ->expects($this->once())
- ->method('send')
- ->with($this->identicalTo($queue), $this->identicalTo($transportMessage))
- ;
- $context = $this->createAmqpContextMock();
- $context
- ->expects($this->once())
- ->method('createQueue')
- ->willReturn($queue)
- ;
- $context
- ->expects($this->once())
- ->method('createProducer')
- ->willReturn($producer)
- ;
- $context
- ->expects($this->once())
- ->method('createMessage')
- ->willReturn($transportMessage)
- ;
-
- $driver = new AmqpDriver(
- $context,
- $this->createDummyConfig(),
- $this->createDummyQueueMetaRegistry()
- );
-
- $message = new Message();
- $message->setProperty(Config::PARAMETER_PROCESSOR_NAME, 'processor');
- $message->setProperty(Config::PARAMETER_PROCESSOR_QUEUE_NAME, 'aFooQueue');
-
- $driver->sendToProcessor($message);
- }
-
- public function testShouldThrowExceptionIfProcessorNameParameterIsNotSet()
- {
- $driver = new AmqpDriver(
- $this->createAmqpContextMock(),
- $this->createDummyConfig(),
- $this->createDummyQueueMetaRegistry()
- );
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('Processor name parameter is required but is not set');
-
- $driver->sendToProcessor(new Message());
- }
-
- public function testShouldThrowExceptionIfProcessorQueueNameParameterIsNotSet()
- {
- $driver = new AmqpDriver(
- $this->createAmqpContextMock(),
- $this->createDummyConfig(),
- $this->createDummyQueueMetaRegistry()
- );
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('Queue name parameter is required but is not set');
-
- $message = new Message();
- $message->setProperty(Config::PARAMETER_PROCESSOR_NAME, 'processor');
-
- $driver->sendToProcessor($message);
- }
-
- public function testShouldSetupBroker()
- {
- $routerTopic = new AmqpTopic('');
- $routerQueue = new AmqpQueue('');
-
- $processorQueue = new AmqpQueue('');
-
- $context = $this->createAmqpContextMock();
- // setup router
- $context
- ->expects($this->at(0))
- ->method('createTopic')
- ->willReturn($routerTopic)
- ;
- $context
- ->expects($this->at(1))
- ->method('createQueue')
- ->willReturn($routerQueue)
- ;
- $context
- ->expects($this->at(2))
- ->method('declareTopic')
- ->with($this->identicalTo($routerTopic))
- ;
- $context
- ->expects($this->at(3))
- ->method('declareQueue')
- ->with($this->identicalTo($routerQueue))
- ;
- $context
- ->expects($this->at(4))
- ->method('bind')
- ->with($this->isInstanceOf(AmqpBind::class))
- ;
- // setup processor queue
- $context
- ->expects($this->at(5))
- ->method('createQueue')
- ->willReturn($processorQueue)
- ;
- $context
- ->expects($this->at(6))
- ->method('declareQueue')
- ->with($this->identicalTo($processorQueue))
- ;
-
- $meta = new QueueMetaRegistry($this->createDummyConfig(), [
- 'default' => [],
- ]);
-
- $driver = new AmqpDriver(
- $context,
- $this->createDummyConfig(),
- $meta
- );
-
- $driver->setupBroker();
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject|AmqpContext
- */
- private function createAmqpContextMock()
- {
- return $this->createMock(AmqpContext::class);
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject|AmqpProducer
- */
- private function createAmqpProducerMock()
- {
- return $this->createMock(AmqpProducer::class);
- }
-
- /**
- * @return QueueMetaRegistry
- */
- private function createDummyQueueMetaRegistry()
- {
- $registry = new QueueMetaRegistry($this->createDummyConfig(), []);
- $registry->add('default');
- $registry->add('aFooQueue');
- $registry->add('aBarQueue', 'aBarQueue');
-
- return $registry;
- }
-
- /**
- * @return Config
- */
- private function createDummyConfig()
- {
- return Config::create('aPrefix');
- }
-}
diff --git a/pkg/enqueue/Tests/Client/Amqp/RabbitMqDriverTest.php b/pkg/enqueue/Tests/Client/Amqp/RabbitMqDriverTest.php
deleted file mode 100644
index 3b67ef52e..000000000
--- a/pkg/enqueue/Tests/Client/Amqp/RabbitMqDriverTest.php
+++ /dev/null
@@ -1,599 +0,0 @@
-assertClassImplements(DriverInterface::class, RabbitMqDriver::class);
- }
-
- public function testShouldExtendsAmqpDriverClass()
- {
- $this->assertClassExtends(AmqpDriver::class, RabbitMqDriver::class);
- }
-
- public function testCouldBeConstructedWithRequiredArguments()
- {
- new RabbitMqDriver(
- $this->createAmqpContextMock(),
- Config::create(),
- $this->createDummyQueueMetaRegistry()
- );
- }
-
- public function testShouldReturnConfigObject()
- {
- $config = Config::create();
-
- $driver = new RabbitMqDriver($this->createAmqpContextMock(), $config, $this->createDummyQueueMetaRegistry());
-
- $this->assertSame($config, $driver->getConfig());
- }
-
- public function testShouldCreateAndReturnQueueInstance()
- {
- $expectedQueue = new AmqpQueue('aName');
-
- $context = $this->createAmqpContextMock();
- $context
- ->expects($this->once())
- ->method('createQueue')
- ->with('aprefix.afooqueue')
- ->willReturn($expectedQueue)
- ;
-
- $driver = new AmqpDriver($context, Config::create(), $this->createDummyQueueMetaRegistry());
-
- $queue = $driver->createQueue('aFooQueue');
-
- $this->assertSame($expectedQueue, $queue);
- $this->assertSame([], $queue->getArguments());
- $this->assertSame(2, $queue->getFlags());
- $this->assertNull($queue->getConsumerTag());
- }
-
- public function testShouldCreateAndReturnQueueInstanceWithHardcodedTransportName()
- {
- $expectedQueue = new AmqpQueue('aName');
-
- $context = $this->createAmqpContextMock();
- $context
- ->expects($this->once())
- ->method('createQueue')
- ->with('aBarQueue')
- ->willReturn($expectedQueue)
- ;
-
- $driver = new AmqpDriver($context, Config::create(), $this->createDummyQueueMetaRegistry());
-
- $queue = $driver->createQueue('aBarQueue');
-
- $this->assertSame($expectedQueue, $queue);
- }
-
- public function testShouldConvertTransportMessageToClientMessage()
- {
- $transportMessage = new AmqpMessage();
- $transportMessage->setBody('body');
- $transportMessage->setHeaders(['hkey' => 'hval']);
- $transportMessage->setProperties(['key' => 'val']);
- $transportMessage->setProperty('enqueue-delay', '5678000');
- $transportMessage->setHeader('content_type', 'ContentType');
- $transportMessage->setHeader('expiration', '12345000');
- $transportMessage->setHeader('priority', 3);
- $transportMessage->setMessageId('MessageId');
- $transportMessage->setTimestamp(1000);
- $transportMessage->setReplyTo('theReplyTo');
- $transportMessage->setCorrelationId('theCorrelationId');
-
- $driver = new RabbitMqDriver(
- $this->createAmqpContextMock(),
- new Config('', '', '', '', '', '', ['delay_strategy' => 'dlx']),
- $this->createDummyQueueMetaRegistry()
- );
-
- $clientMessage = $driver->createClientMessage($transportMessage);
-
- $this->assertInstanceOf(Message::class, $clientMessage);
- $this->assertSame('body', $clientMessage->getBody());
- $this->assertSame([
- 'hkey' => 'hval',
- 'content_type' => 'ContentType',
- 'expiration' => '12345000',
- 'priority' => 3,
- 'message_id' => 'MessageId',
- 'timestamp' => 1000,
- 'reply_to' => 'theReplyTo',
- 'correlation_id' => 'theCorrelationId',
- ], $clientMessage->getHeaders());
- $this->assertSame([
- 'key' => 'val',
- 'enqueue-delay' => '5678000',
- ], $clientMessage->getProperties());
- $this->assertSame('MessageId', $clientMessage->getMessageId());
- $this->assertSame(12345, $clientMessage->getExpire());
- $this->assertSame(5678, $clientMessage->getDelay());
- $this->assertSame('ContentType', $clientMessage->getContentType());
- $this->assertSame(1000, $clientMessage->getTimestamp());
- $this->assertSame(MessagePriority::HIGH, $clientMessage->getPriority());
- $this->assertSame('theReplyTo', $clientMessage->getReplyTo());
- $this->assertSame('theCorrelationId', $clientMessage->getCorrelationId());
- }
-
- public function testShouldThrowExceptionIfXDelayIsNotNumeric()
- {
- $transportMessage = new AmqpMessage();
- $transportMessage->setProperty('enqueue-delay', 'is-not-numeric');
-
- $driver = new RabbitMqDriver(
- $this->createAmqpContextMock(),
- Config::create(),
- $this->createDummyQueueMetaRegistry()
- );
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('"enqueue-delay" header is not numeric. "is-not-numeric"');
-
- $driver->createClientMessage($transportMessage);
- }
-
- public function testShouldThrowExceptionIfExpirationIsNotNumeric()
- {
- $transportMessage = new AmqpMessage();
- $transportMessage->setHeader('expiration', 'is-not-numeric');
-
- $driver = new RabbitMqDriver(
- $this->createAmqpContextMock(),
- Config::create(),
- $this->createDummyQueueMetaRegistry()
- );
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('expiration header is not numeric. "is-not-numeric"');
-
- $driver->createClientMessage($transportMessage);
- }
-
- public function testShouldThrowExceptionIfCantConvertTransportPriorityToClientPriority()
- {
- $transportMessage = new AmqpMessage();
- $transportMessage->setHeader('priority', 'unknown');
-
- $driver = new RabbitMqDriver(
- $this->createAmqpContextMock(),
- Config::create(),
- $this->createDummyQueueMetaRegistry()
- );
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('Cant convert transport priority to client: "unknown"');
-
- $driver->createClientMessage($transportMessage);
- }
-
- public function testShouldThrowExceptionIfCantConvertClientPriorityToTransportPriority()
- {
- $clientMessage = new Message();
- $clientMessage->setPriority('unknown');
-
- $context = $this->createAmqpContextMock();
- $context
- ->expects($this->once())
- ->method('createMessage')
- ->willReturn(new AmqpMessage())
- ;
-
- $driver = new RabbitMqDriver(
- $context,
- Config::create(),
- $this->createDummyQueueMetaRegistry()
- );
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('Given priority could not be converted to client\'s one. Got: unknown');
-
- $driver->createTransportMessage($clientMessage);
- }
-
- public function testShouldConvertClientMessageToTransportMessage()
- {
- $clientMessage = new Message();
- $clientMessage->setBody('body');
- $clientMessage->setHeaders(['hkey' => 'hval']);
- $clientMessage->setProperties(['key' => 'val']);
- $clientMessage->setContentType('ContentType');
- $clientMessage->setExpire(123);
- $clientMessage->setPriority(MessagePriority::VERY_HIGH);
- $clientMessage->setDelay(432);
- $clientMessage->setMessageId('MessageId');
- $clientMessage->setTimestamp(1000);
- $clientMessage->setReplyTo('theReplyTo');
- $clientMessage->setCorrelationId('theCorrelationId');
-
- $context = $this->createAmqpContextMock();
- $context
- ->expects($this->once())
- ->method('createMessage')
- ->willReturn(new AmqpMessage())
- ;
-
- $driver = new RabbitMqDriver(
- $context,
- new Config('', '', '', '', '', '', ['delay_strategy' => 'dlx']),
- $this->createDummyQueueMetaRegistry()
- );
-
- $transportMessage = $driver->createTransportMessage($clientMessage);
-
- $this->assertInstanceOf(AmqpMessage::class, $transportMessage);
- $this->assertSame('body', $transportMessage->getBody());
- $this->assertSame([
- 'hkey' => 'hval',
- 'message_id' => 'MessageId',
- 'timestamp' => 1000,
- 'reply_to' => 'theReplyTo',
- 'correlation_id' => 'theCorrelationId',
- 'content_type' => 'ContentType',
- 'delivery_mode' => 2,
- 'expiration' => '123000',
- 'priority' => 4,
- ], $transportMessage->getHeaders());
- $this->assertSame([
- 'key' => 'val',
- 'enqueue-delay' => 432000,
- ], $transportMessage->getProperties());
- $this->assertSame('MessageId', $transportMessage->getMessageId());
- $this->assertSame(1000, $transportMessage->getTimestamp());
- $this->assertSame('theReplyTo', $transportMessage->getReplyTo());
- $this->assertSame('theCorrelationId', $transportMessage->getCorrelationId());
- }
-
- public function testThrowIfDelayNotSupportedOnConvertClientMessageToTransportMessage()
- {
- $clientMessage = new Message();
- $clientMessage->setDelay(432);
-
- $context = $this->createAmqpContextMock();
- $context
- ->expects($this->once())
- ->method('createMessage')
- ->willReturn(new AmqpMessage())
- ;
-
- $driver = new RabbitMqDriver(
- $context,
- new Config('', '', '', '', '', '', ['delay_strategy' => null]),
- $this->createDummyQueueMetaRegistry()
- );
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('The message delaying is not supported. In order to use delay feature install RabbitMQ delay strategy.');
- $driver->createTransportMessage($clientMessage);
- }
-
- public function testShouldSendMessageToRouter()
- {
- $topic = new AmqpTopic('');
- $transportMessage = new AmqpMessage();
-
- $producer = $this->createAmqpProducerMock();
- $producer
- ->expects($this->once())
- ->method('send')
- ->with($this->identicalTo($topic), $this->identicalTo($transportMessage))
- ;
- $context = $this->createAmqpContextMock();
- $context
- ->expects($this->once())
- ->method('createTopic')
- ->willReturn($topic)
- ;
- $context
- ->expects($this->once())
- ->method('createProducer')
- ->willReturn($producer)
- ;
- $context
- ->expects($this->once())
- ->method('createMessage')
- ->willReturn($transportMessage)
- ;
-
- $driver = new RabbitMqDriver(
- $context,
- Config::create(),
- $this->createDummyQueueMetaRegistry()
- );
-
- $message = new Message();
- $message->setProperty(Config::PARAMETER_TOPIC_NAME, 'topic');
-
- $driver->sendToRouter($message);
- }
-
- public function testShouldThrowExceptionIfTopicParameterIsNotSet()
- {
- $driver = new RabbitMqDriver(
- $this->createAmqpContextMock(),
- Config::create(),
- $this->createDummyQueueMetaRegistry()
- );
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('Topic name parameter is required but is not set');
-
- $driver->sendToRouter(new Message());
- }
-
- public function testShouldSendMessageToProcessor()
- {
- $queue = new AmqpQueue('');
- $transportMessage = new AmqpMessage();
-
- $producer = $this->createAmqpProducerMock();
- $producer
- ->expects($this->once())
- ->method('send')
- ->with($this->identicalTo($queue), $this->identicalTo($transportMessage))
- ;
- $context = $this->createAmqpContextMock();
- $context
- ->expects($this->once())
- ->method('createQueue')
- ->willReturn($queue)
- ;
- $context
- ->expects($this->once())
- ->method('createProducer')
- ->willReturn($producer)
- ;
- $context
- ->expects($this->once())
- ->method('createMessage')
- ->willReturn($transportMessage)
- ;
-
- $driver = new RabbitMqDriver(
- $context,
- Config::create(),
- $this->createDummyQueueMetaRegistry()
- );
-
- $message = new Message();
- $message->setProperty(Config::PARAMETER_PROCESSOR_NAME, 'processor');
- $message->setProperty(Config::PARAMETER_PROCESSOR_QUEUE_NAME, 'aFooQueue');
-
- $driver->sendToProcessor($message);
- }
-
- public function testShouldSendMessageToProcessorWithDeliveryDelay()
- {
- $queue = new AmqpQueue('');
- $transportMessage = new AmqpMessage();
-
- $producer = $this->createAmqpProducerMock();
- $producer
- ->expects($this->once())
- ->method('send')
- ->with($this->identicalTo($queue), $this->identicalTo($transportMessage))
- ;
- $producer
- ->expects($this->once())
- ->method('setDeliveryDelay')
- ->with($this->identicalTo(10000))
- ;
- $context = $this->createAmqpContextMock();
- $context
- ->expects($this->once())
- ->method('createQueue')
- ->willReturn($queue)
- ;
- $context
- ->expects($this->once())
- ->method('createProducer')
- ->willReturn($producer)
- ;
- $context
- ->expects($this->once())
- ->method('createMessage')
- ->willReturn($transportMessage)
- ;
-
- $driver = new RabbitMqDriver(
- $context,
- new Config('', '', '', '', '', '', ['delay_strategy' => 'dlx']),
- $this->createDummyQueueMetaRegistry()
- );
-
- $message = new Message();
- $message->setProperty(Config::PARAMETER_PROCESSOR_NAME, 'processor');
- $message->setProperty(Config::PARAMETER_PROCESSOR_QUEUE_NAME, 'aFooQueue');
- $message->setDelay(10);
-
- $driver->sendToProcessor($message);
- }
-
- public function testShouldThrowExceptionIfProcessorNameParameterIsNotSet()
- {
- $driver = new RabbitMqDriver(
- $this->createAmqpContextMock(),
- Config::create(),
- $this->createDummyQueueMetaRegistry()
- );
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('Processor name parameter is required but is not set');
-
- $driver->sendToProcessor(new Message());
- }
-
- public function testShouldThrowExceptionIfProcessorQueueNameParameterIsNotSet()
- {
- $driver = new RabbitMqDriver(
- $this->createAmqpContextMock(),
- Config::create(),
- $this->createDummyQueueMetaRegistry()
- );
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('Queue name parameter is required but is not set');
-
- $message = new Message();
- $message->setProperty(Config::PARAMETER_PROCESSOR_NAME, 'processor');
-
- $driver->sendToProcessor($message);
- }
-
- public function testShouldSetupBrokerWhenDelayPluginNotInstalled()
- {
- $routerTopic = new AmqpTopic('');
- $routerQueue = new AmqpQueue('');
-
- $processorQueue = new AmqpQueue('');
-
- $context = $this->createAmqpContextMock();
- // setup router
- $context
- ->expects($this->at(0))
- ->method('createTopic')
- ->willReturn($routerTopic)
- ;
- $context
- ->expects($this->at(1))
- ->method('createQueue')
- ->willReturn($routerQueue)
- ;
- $context
- ->expects($this->at(2))
- ->method('declareTopic')
- ->with($this->identicalTo($routerTopic))
- ;
- $context
- ->expects($this->at(3))
- ->method('declareQueue')
- ->with($this->identicalTo($routerQueue))
- ;
- $context
- ->expects($this->at(4))
- ->method('bind')
- ->with($this->isInstanceOf(AmqpBind::class))
- ;
- // setup processor queue
- $context
- ->expects($this->at(5))
- ->method('createQueue')
- ->willReturn($processorQueue)
- ;
-
- $config = Config::create('', '', '', '', '', '', ['delay_strategy' => null]);
-
- $meta = new QueueMetaRegistry($config, ['default' => []]);
-
- $driver = new RabbitMqDriver($context, $config, $meta);
-
- $driver->setupBroker();
- }
-
- public function testShouldSetupBroker()
- {
- $routerTopic = new AmqpTopic('');
- $routerQueue = new AmqpQueue('');
-
- $processorQueue = new AmqpQueue('');
-
- $context = $this->createAmqpContextMock();
- // setup router
- $context
- ->expects($this->at(0))
- ->method('createTopic')
- ->willReturn($routerTopic)
- ;
- $context
- ->expects($this->at(1))
- ->method('createQueue')
- ->willReturn($routerQueue)
- ;
- $context
- ->expects($this->at(2))
- ->method('declareTopic')
- ->with($this->identicalTo($routerTopic))
- ;
- $context
- ->expects($this->at(3))
- ->method('declareQueue')
- ->with($this->identicalTo($routerQueue))
- ;
- $context
- ->expects($this->at(4))
- ->method('bind')
- ->with($this->isInstanceOf(AmqpBind::class))
- ;
- // setup processor queue
- $context
- ->expects($this->at(5))
- ->method('createQueue')
- ->willReturn($processorQueue)
- ;
- $context
- ->expects($this->at(6))
- ->method('declareQueue')
- ->with($this->identicalTo($processorQueue))
- ;
-
- $config = Config::create('', '', '', '', '', '', ['delay_strategy' => 'dlx']);
-
- $meta = new QueueMetaRegistry($config, ['default' => []]);
-
- $driver = new RabbitMqDriver($context, $config, $meta);
-
- $driver->setupBroker();
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject|AmqpContext
- */
- private function createAmqpContextMock()
- {
- return $this->createMock(AmqpContext::class);
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject|AmqpProducer
- */
- private function createAmqpProducerMock()
- {
- return $this->createMock(AmqpProducer::class);
- }
-
- /**
- * @return QueueMetaRegistry
- */
- private function createDummyQueueMetaRegistry()
- {
- $registry = new QueueMetaRegistry(Config::create('aPrefix'), []);
- $registry->add('aFooQueue');
- $registry->add('aBarQueue', 'aBarQueue');
-
- return $registry;
- }
-}
diff --git a/pkg/enqueue/Tests/Client/ChainExtensionTest.php b/pkg/enqueue/Tests/Client/ChainExtensionTest.php
index 3b1d82f9a..0f42bcf18 100644
--- a/pkg/enqueue/Tests/Client/ChainExtensionTest.php
+++ b/pkg/enqueue/Tests/Client/ChainExtensionTest.php
@@ -3,9 +3,16 @@
namespace Enqueue\Tests\Client;
use Enqueue\Client\ChainExtension;
+use Enqueue\Client\DriverInterface;
+use Enqueue\Client\DriverPreSend;
use Enqueue\Client\ExtensionInterface;
use Enqueue\Client\Message;
+use Enqueue\Client\PostSend;
+use Enqueue\Client\PreSend;
+use Enqueue\Client\ProducerInterface;
use Enqueue\Test\ClassExtensionTrait;
+use Interop\Queue\Destination;
+use Interop\Queue\Message as TransportMessage;
use PHPUnit\Framework\TestCase;
class ChainExtensionTest extends TestCase
@@ -17,57 +24,129 @@ public function testShouldImplementExtensionInterface()
$this->assertClassImplements(ExtensionInterface::class, ChainExtension::class);
}
- public function testCouldBeConstructedWithExtensionsArray()
+ public function testShouldBeFinal()
{
- new ChainExtension([$this->createExtension(), $this->createExtension()]);
+ $this->assertClassFinal(ChainExtension::class);
}
- public function testShouldProxyOnPreSendToAllInternalExtensions()
+ public function testThrowIfArrayContainsNotExtension()
{
- $message = new Message();
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Invalid extension given');
+
+ new ChainExtension([$this->createExtension(), new \stdClass()]);
+ }
+
+ public function testShouldProxyOnPreSendEventToAllInternalExtensions()
+ {
+ $preSend = new PreSend(
+ 'aCommandOrTopic',
+ new Message(),
+ $this->createMock(ProducerInterface::class),
+ $this->createMock(DriverInterface::class)
+ );
+
+ $fooExtension = $this->createExtension();
+ $fooExtension
+ ->expects($this->once())
+ ->method('onPreSendEvent')
+ ->with($this->identicalTo($preSend))
+ ;
+ $barExtension = $this->createExtension();
+ $barExtension
+ ->expects($this->once())
+ ->method('onPreSendEvent')
+ ->with($this->identicalTo($preSend))
+ ;
+
+ $extensions = new ChainExtension([$fooExtension, $barExtension]);
+
+ $extensions->onPreSendEvent($preSend);
+ }
+
+ public function testShouldProxyOnPreSendCommandToAllInternalExtensions()
+ {
+ $preSend = new PreSend(
+ 'aCommandOrTopic',
+ new Message(),
+ $this->createMock(ProducerInterface::class),
+ $this->createMock(DriverInterface::class)
+ );
+
+ $fooExtension = $this->createExtension();
+ $fooExtension
+ ->expects($this->once())
+ ->method('onPreSendCommand')
+ ->with($this->identicalTo($preSend))
+ ;
+ $barExtension = $this->createExtension();
+ $barExtension
+ ->expects($this->once())
+ ->method('onPreSendCommand')
+ ->with($this->identicalTo($preSend))
+ ;
+
+ $extensions = new ChainExtension([$fooExtension, $barExtension]);
+
+ $extensions->onPreSendCommand($preSend);
+ }
+
+ public function testShouldProxyOnDriverPreSendToAllInternalExtensions()
+ {
+ $driverPreSend = new DriverPreSend(
+ new Message(),
+ $this->createMock(ProducerInterface::class),
+ $this->createMock(DriverInterface::class)
+ );
$fooExtension = $this->createExtension();
$fooExtension
->expects($this->once())
- ->method('onPreSend')
- ->with('topic', $this->identicalTo($message))
+ ->method('onDriverPreSend')
+ ->with($this->identicalTo($driverPreSend))
;
$barExtension = $this->createExtension();
$barExtension
->expects($this->once())
- ->method('onPreSend')
- ->with('topic', $this->identicalTo($message))
+ ->method('onDriverPreSend')
+ ->with($this->identicalTo($driverPreSend))
;
$extensions = new ChainExtension([$fooExtension, $barExtension]);
- $extensions->onPreSend('topic', $message);
+ $extensions->onDriverPreSend($driverPreSend);
}
- public function testShouldProxyOnPostSendToAllInternalExtensions()
+ public function testShouldProxyOnPostSentToAllInternalExtensions()
{
- $message = new Message();
+ $postSend = new PostSend(
+ new Message(),
+ $this->createMock(ProducerInterface::class),
+ $this->createMock(DriverInterface::class),
+ $this->createMock(Destination::class),
+ $this->createMock(TransportMessage::class)
+ );
$fooExtension = $this->createExtension();
$fooExtension
->expects($this->once())
->method('onPostSend')
- ->with('topic', $this->identicalTo($message))
+ ->with($this->identicalTo($postSend))
;
$barExtension = $this->createExtension();
$barExtension
->expects($this->once())
->method('onPostSend')
- ->with('topic', $this->identicalTo($message))
+ ->with($this->identicalTo($postSend))
;
$extensions = new ChainExtension([$fooExtension, $barExtension]);
- $extensions->onPostSend('topic', $message);
+ $extensions->onPostSend($postSend);
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|ExtensionInterface
+ * @return \PHPUnit\Framework\MockObject\MockObject|ExtensionInterface
*/
protected function createExtension()
{
diff --git a/pkg/enqueue/Tests/Client/ConfigTest.php b/pkg/enqueue/Tests/Client/ConfigTest.php
index 1ecb0f952..09b80e2c1 100644
--- a/pkg/enqueue/Tests/Client/ConfigTest.php
+++ b/pkg/enqueue/Tests/Client/ConfigTest.php
@@ -7,139 +7,246 @@
class ConfigTest extends TestCase
{
- public function testShouldReturnRouterProcessorNameSetInConstructor()
+ public function testShouldReturnPrefixSetInConstructor()
{
$config = new Config(
- 'aPrefix',
+ 'thePrefix',
+ 'theSeparator',
'aApp',
'aRouterTopicName',
'aRouterQueueName',
'aDefaultQueueName',
- 'aRouterProcessorName'
+ 'aRouterProcessorName',
+ [],
+ []
);
- $this->assertEquals('aRouterProcessorName', $config->getRouterProcessorName());
+ $this->assertEquals('thePrefix', $config->getPrefix());
}
- public function testShouldReturnRouterTopicNameSetInConstructor()
+ /**
+ * @dataProvider provideEmptyStrings
+ */
+ public function testShouldTrimReturnPrefixSetInConstructor(string $empty)
{
$config = new Config(
- 'aPrefix',
+ $empty,
'aApp',
+ 'theSeparator',
'aRouterTopicName',
'aRouterQueueName',
'aDefaultQueueName',
- 'aRouterProcessorName'
+ 'aRouterProcessorName',
+ [],
+ []
);
- $this->assertEquals('aRouterTopicName', $config->getRouterTopicName());
+ $this->assertSame('', $config->getPrefix());
}
- public function testShouldReturnRouterQueueNameSetInConstructor()
+ public function testShouldReturnAppNameSetInConstructor()
{
$config = new Config(
'aPrefix',
- 'aApp',
+ 'theSeparator',
+ 'theApp',
'aRouterTopicName',
'aRouterQueueName',
'aDefaultQueueName',
- 'aRouterProcessorName'
+ 'aRouterProcessorName',
+ [],
+ []
);
- $this->assertEquals('aRouterQueueName', $config->getRouterQueueName());
+ $this->assertEquals('theApp', $config->getApp());
}
- public function testShouldReturnDefaultQueueNameSetInConstructor()
+ /**
+ * @dataProvider provideEmptyStrings
+ */
+ public function testShouldTrimReturnAppNameSetInConstructor(string $empty)
{
$config = new Config(
'aPrefix',
- 'aApp',
+ 'theSeparator',
+ $empty,
'aRouterTopicName',
'aRouterQueueName',
'aDefaultQueueName',
- 'aRouterProcessorName'
+ 'aRouterProcessorName',
+ [],
+ []
);
- $this->assertEquals('aDefaultQueueName', $config->getDefaultProcessorQueueName());
+ $this->assertSame('', $config->getApp());
}
- public function testShouldCreateRouterTopicName()
+ public function testShouldReturnRouterProcessorNameSetInConstructor()
{
$config = new Config(
'aPrefix',
+ 'theSeparator',
'aApp',
'aRouterTopicName',
'aRouterQueueName',
'aDefaultQueueName',
- 'aRouterProcessorName'
+ 'aRouterProcessorName',
+ [],
+ []
);
- $this->assertEquals('aprefix.aname', $config->createTransportRouterTopicName('aName'));
+ $this->assertEquals('aRouterProcessorName', $config->getRouterProcessor());
}
- public function testShouldCreateProcessorQueueName()
+ public function testShouldReturnRouterTopicNameSetInConstructor()
{
$config = new Config(
'aPrefix',
+ 'theSeparator',
'aApp',
'aRouterTopicName',
'aRouterQueueName',
'aDefaultQueueName',
- 'aRouterProcessorName'
+ 'aRouterProcessorName',
+ [],
+ []
);
- $this->assertEquals('aprefix.aapp.aname', $config->createTransportQueueName('aName'));
+ $this->assertEquals('aRouterTopicName', $config->getRouterTopic());
}
- public function testShouldCreateProcessorQueueNameWithoutAppName()
+ public function testShouldReturnRouterQueueNameSetInConstructor()
{
$config = new Config(
'aPrefix',
- '',
+ 'theSeparator',
+ 'aApp',
'aRouterTopicName',
'aRouterQueueName',
'aDefaultQueueName',
- 'aRouterProcessorName'
+ 'aRouterProcessorName',
+ [],
+ []
);
- $this->assertEquals('aprefix.aname', $config->createTransportQueueName('aName'));
+ $this->assertEquals('aRouterQueueName', $config->getRouterQueue());
}
- public function testShouldCreateProcessorQueueNameWithoutPrefix()
+ public function testShouldReturnDefaultQueueNameSetInConstructor()
{
$config = new Config(
- '',
+ 'aPrefix',
+ 'theSeparator',
'aApp',
'aRouterTopicName',
'aRouterQueueName',
'aDefaultQueueName',
- 'aRouterProcessorName'
+ 'aRouterProcessorName',
+ [],
+ []
);
- $this->assertEquals('aapp.aname', $config->createTransportQueueName('aName'));
+ $this->assertEquals('aDefaultQueueName', $config->getDefaultQueue());
}
- public function testShouldCreateProcessorQueueNameWithoutPrefixAndAppName()
+ public function testShouldCreateDefaultConfig()
{
- $config = new Config(
+ $config = Config::create();
+
+ $this->assertSame('default', $config->getDefaultQueue());
+ $this->assertSame('router', $config->getRouterProcessor());
+ $this->assertSame('default', $config->getRouterQueue());
+ $this->assertSame('router', $config->getRouterTopic());
+ }
+
+ /**
+ * @dataProvider provideEmptyStrings
+ */
+ public function testThrowIfRouterTopicNameIsEmpty(string $empty)
+ {
+ $this->expectException(\InvalidArgumentException::class);
+ $this->expectExceptionMessage('Router topic is empty.');
+ new Config(
'',
'',
- 'aRouterTopicName',
+ '',
+ $empty,
'aRouterQueueName',
'aDefaultQueueName',
- 'aRouterProcessorName'
+ 'aRouterProcessorName',
+ [],
+ []
+ );
+ }
+
+ /**
+ * @dataProvider provideEmptyStrings
+ */
+ public function testThrowIfRouterQueueNameIsEmpty(string $empty)
+ {
+ $this->expectException(\InvalidArgumentException::class);
+ $this->expectExceptionMessage('Router queue is empty.');
+ new Config(
+ '',
+ '',
+ '',
+ 'aRouterTopicName',
+ $empty,
+ 'aDefaultQueueName',
+ 'aRouterProcessorName',
+ [],
+ []
+ );
+ }
+
+ /**
+ * @dataProvider provideEmptyStrings
+ */
+ public function testThrowIfDefaultQueueNameIsEmpty(string $empty)
+ {
+ $this->expectException(\InvalidArgumentException::class);
+ $this->expectExceptionMessage('Default processor queue name is empty.');
+ new Config(
+ '',
+ '',
+ '',
+ 'aRouterTopicName',
+ 'aRouterQueueName',
+ $empty,
+ 'aRouterProcessorName',
+ [],
+ []
);
+ }
- $this->assertEquals('aname', $config->createTransportQueueName('aName'));
+ /**
+ * @dataProvider provideEmptyStrings
+ */
+ public function testThrowIfRouterProcessorNameIsEmpty(string $empty)
+ {
+ $this->expectException(\InvalidArgumentException::class);
+ $this->expectExceptionMessage('Router processor name is empty.');
+ new Config(
+ '',
+ '',
+ '',
+ 'aRouterTopicName',
+ 'aRouterQueueName',
+ 'aDefaultQueueName',
+ $empty,
+ [],
+ []
+ );
}
- public function testShouldCreateDefaultConfig()
+ public function provideEmptyStrings()
{
- $config = Config::create();
+ yield [''];
+
+ yield [' '];
+
+ yield [' '];
- $this->assertSame('default', $config->getDefaultProcessorQueueName());
- $this->assertSame('router', $config->getRouterProcessorName());
- $this->assertSame('default', $config->getRouterQueueName());
- $this->assertSame('router', $config->getRouterTopicName());
+ yield ["\t"];
}
}
diff --git a/pkg/enqueue/Tests/Client/ConsumptionExtension/DelayRedeliveredMessageExtensionTest.php b/pkg/enqueue/Tests/Client/ConsumptionExtension/DelayRedeliveredMessageExtensionTest.php
index b61a3416c..a660126ad 100644
--- a/pkg/enqueue/Tests/Client/ConsumptionExtension/DelayRedeliveredMessageExtensionTest.php
+++ b/pkg/enqueue/Tests/Client/ConsumptionExtension/DelayRedeliveredMessageExtensionTest.php
@@ -4,22 +4,25 @@
use Enqueue\Client\ConsumptionExtension\DelayRedeliveredMessageExtension;
use Enqueue\Client\DriverInterface;
+use Enqueue\Client\DriverSendResult;
use Enqueue\Client\Message;
-use Enqueue\Consumption\Context;
+use Enqueue\Consumption\Context\MessageReceived;
use Enqueue\Consumption\Result;
use Enqueue\Null\NullMessage;
use Enqueue\Null\NullQueue;
-use Interop\Queue\PsrContext;
+use Enqueue\Test\TestLogger;
+use Interop\Queue\Consumer;
+use Interop\Queue\Context as InteropContext;
+use Interop\Queue\Destination;
+use Interop\Queue\Message as TransportMessage;
+use Interop\Queue\Processor;
+use Interop\Queue\Queue;
+use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
-use Psr\Log\LoggerInterface;
+use Psr\Log\NullLogger;
class DelayRedeliveredMessageExtensionTest extends TestCase
{
- public function testCouldBeConstructedWithRequiredArguments()
- {
- new DelayRedeliveredMessageExtension($this->createDriverMock(), 12345);
- }
-
public function testShouldSendDelayedMessageAndRejectOriginalMessage()
{
$queue = new NullQueue('queue');
@@ -38,6 +41,7 @@ public function testShouldSendDelayedMessageAndRejectOriginalMessage()
->expects(self::once())
->method('sendToProcessor')
->with(self::isInstanceOf(Message::class))
+ ->willReturn($this->createDriverSendResult())
;
$driver
->expects(self::once())
@@ -46,32 +50,23 @@ public function testShouldSendDelayedMessageAndRejectOriginalMessage()
->willReturn($delayedMessage)
;
- $logger = $this->createLoggerMock();
- $logger
- ->expects(self::at(0))
- ->method('debug')
- ->with('[DelayRedeliveredMessageExtension] Send delayed message')
- ;
- $logger
- ->expects(self::at(1))
- ->method('debug')
- ->with(
- '[DelayRedeliveredMessageExtension] '.
- 'Reject redelivered original message by setting reject status to context.'
- )
- ;
+ $logger = new TestLogger();
- $context = new Context($this->createPsrContextMock());
- $context->setPsrQueue($queue);
- $context->setPsrMessage($originMessage);
- $context->setLogger($logger);
+ $messageReceived = new MessageReceived(
+ $this->createContextMock(),
+ $this->createConsumerStub($queue),
+ $originMessage,
+ $this->createProcessorMock(),
+ 1,
+ $logger
+ );
- $this->assertNull($context->getResult());
+ $this->assertNull($messageReceived->getResult());
$extension = new DelayRedeliveredMessageExtension($driver, 12345);
- $extension->onPreReceived($context);
+ $extension->onMessageReceived($messageReceived);
- $result = $context->getResult();
+ $result = $messageReceived->getResult();
$this->assertInstanceOf(Result::class, $result);
$this->assertSame(Result::REJECT, $result->getStatus());
$this->assertSame('A new copy of the message was sent with a delay. The original message is rejected', $result->getReason());
@@ -80,6 +75,16 @@ public function testShouldSendDelayedMessageAndRejectOriginalMessage()
$this->assertEquals([
'enqueue.redelivery_count' => 1,
], $delayedMessage->getProperties());
+
+ self::assertTrue(
+ $logger->hasDebugThatContains('[DelayRedeliveredMessageExtension] Send delayed message')
+ );
+ self::assertTrue(
+ $logger->hasDebugThatContains(
+ '[DelayRedeliveredMessageExtension] '.
+ 'Reject redelivered original message by setting reject status to context.'
+ )
+ );
}
public function testShouldDoNothingIfMessageIsNotRedelivered()
@@ -92,13 +97,19 @@ public function testShouldDoNothingIfMessageIsNotRedelivered()
->method('sendToProcessor')
;
- $context = new Context($this->createPsrContextMock());
- $context->setPsrMessage($message);
+ $messageReceived = new MessageReceived(
+ $this->createContextMock(),
+ $this->createConsumerStub(null),
+ $message,
+ $this->createProcessorMock(),
+ 1,
+ new NullLogger()
+ );
$extension = new DelayRedeliveredMessageExtension($driver, 12345);
- $extension->onPreReceived($context);
+ $extension->onMessageReceived($messageReceived);
- $this->assertNull($context->getResult());
+ $this->assertNull($messageReceived->getResult());
}
public function testShouldDoNothingIfMessageIsRedeliveredButResultWasAlreadySetOnContext()
@@ -112,35 +123,64 @@ public function testShouldDoNothingIfMessageIsRedeliveredButResultWasAlreadySetO
->method('sendToProcessor')
;
- $context = new Context($this->createPsrContextMock());
- $context->setPsrMessage($message);
- $context->setResult('aStatus');
+ $messageReceived = new MessageReceived(
+ $this->createContextMock(),
+ $this->createConsumerStub(null),
+ $message,
+ $this->createProcessorMock(),
+ 1,
+ new NullLogger()
+ );
+ $messageReceived->setResult(Result::ack());
$extension = new DelayRedeliveredMessageExtension($driver, 12345);
- $extension->onPreReceived($context);
+ $extension->onMessageReceived($messageReceived);
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|DriverInterface
+ * @return MockObject
*/
- private function createDriverMock()
+ private function createDriverMock(): DriverInterface
{
return $this->createMock(DriverInterface::class);
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|PsrContext
+ * @return MockObject
+ */
+ private function createContextMock(): InteropContext
+ {
+ return $this->createMock(InteropContext::class);
+ }
+
+ /**
+ * @return MockObject
*/
- private function createPsrContextMock()
+ private function createProcessorMock(): Processor
{
- return $this->createMock(PsrContext::class);
+ return $this->createMock(Processor::class);
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|LoggerInterface
+ * @return MockObject|Consumer
*/
- private function createLoggerMock()
+ private function createConsumerStub(?Queue $queue): Consumer
+ {
+ $consumerMock = $this->createMock(Consumer::class);
+ $consumerMock
+ ->expects($this->any())
+ ->method('getQueue')
+ ->willReturn($queue ?? new NullQueue('queue'))
+ ;
+
+ return $consumerMock;
+ }
+
+ private function createDriverSendResult(): DriverSendResult
{
- return $this->createMock(LoggerInterface::class);
+ return new DriverSendResult(
+ $this->createMock(Destination::class),
+ $this->createMock(TransportMessage::class)
+ );
}
}
diff --git a/pkg/enqueue/Tests/Client/ConsumptionExtension/ExclusiveCommandExtensionTest.php b/pkg/enqueue/Tests/Client/ConsumptionExtension/ExclusiveCommandExtensionTest.php
index acbcb41ab..b1e47c898 100644
--- a/pkg/enqueue/Tests/Client/ConsumptionExtension/ExclusiveCommandExtensionTest.php
+++ b/pkg/enqueue/Tests/Client/ConsumptionExtension/ExclusiveCommandExtensionTest.php
@@ -4,14 +4,19 @@
use Enqueue\Client\Config;
use Enqueue\Client\ConsumptionExtension\ExclusiveCommandExtension;
-use Enqueue\Client\ExtensionInterface as ClientExtensionInterface;
-use Enqueue\Client\Message;
-use Enqueue\Consumption\Context;
-use Enqueue\Consumption\ExtensionInterface as ConsumptionExtensionInterface;
-use Enqueue\Null\NullContext;
+use Enqueue\Client\DriverInterface;
+use Enqueue\Client\Route;
+use Enqueue\Client\RouteCollection;
+use Enqueue\Consumption\Context\MessageReceived;
+use Enqueue\Consumption\MessageReceivedExtensionInterface;
use Enqueue\Null\NullMessage;
use Enqueue\Null\NullQueue;
use Enqueue\Test\ClassExtensionTrait;
+use Interop\Queue\Consumer;
+use Interop\Queue\Context as InteropContext;
+use Interop\Queue\Processor;
+use Interop\Queue\Queue;
+use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\NullLogger;
@@ -19,176 +24,263 @@ class ExclusiveCommandExtensionTest extends TestCase
{
use ClassExtensionTrait;
- public function testShouldImplementConsumptionExtensionInterface()
+ public function testShouldImplementMessageReceivedExtensionInterface()
{
- $this->assertClassImplements(ConsumptionExtensionInterface::class, ExclusiveCommandExtension::class);
+ $this->assertClassImplements(MessageReceivedExtensionInterface::class, ExclusiveCommandExtension::class);
}
- public function testShouldImplementClientExtensionInterface()
+ public function testShouldBeFinal()
{
- $this->assertClassImplements(ClientExtensionInterface::class, ExclusiveCommandExtension::class);
- }
-
- public function testCouldBeConstructedWithQueueNameToProcessorNameMap()
- {
- new ExclusiveCommandExtension([]);
-
- new ExclusiveCommandExtension(['fooQueueName' => 'fooProcessorName']);
+ $this->assertClassFinal(ExclusiveCommandExtension::class);
}
public function testShouldDoNothingIfMessageHasTopicPropertySetOnPreReceive()
{
$message = new NullMessage();
- $message->setProperty(Config::PARAMETER_TOPIC_NAME, 'aTopic');
+ $message->setProperty(Config::TOPIC, 'aTopic');
- $context = new Context(new NullContext());
- $context->setPsrMessage($message);
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->never())
+ ->method('createQueue')
+ ;
- $extension = new ExclusiveCommandExtension([
- 'aFooQueueName' => 'aFooProcessorName',
- ]);
+ $messageReceived = new MessageReceived(
+ $this->createContextMock(),
+ $this->createConsumerStub(null),
+ $message,
+ $this->createProcessorMock(),
+ 1,
+ new NullLogger()
+ );
+
+ $extension = new ExclusiveCommandExtension($driver);
- $extension->onPreReceived($context);
+ $extension->onMessageReceived($messageReceived);
- self::assertNull($context->getResult());
+ self::assertNull($messageReceived->getResult());
$this->assertEquals([
- 'enqueue.topic_name' => 'aTopic',
+ Config::TOPIC => 'aTopic',
], $message->getProperties());
}
- public function testShouldDoNothingIfMessageHasProcessorNamePropertySetOnPreReceive()
+ public function testShouldDoNothingIfMessageHasCommandPropertySetOnPreReceive()
{
$message = new NullMessage();
- $message->setProperty(Config::PARAMETER_PROCESSOR_NAME, 'aProcessor');
+ $message->setProperty(Config::COMMAND, 'aCommand');
- $context = new Context(new NullContext());
- $context->setPsrMessage($message);
+ $messageReceived = new MessageReceived(
+ $this->createContextMock(),
+ $this->createConsumerStub(null),
+ $message,
+ $this->createProcessorMock(),
+ 1,
+ new NullLogger()
+ );
- $extension = new ExclusiveCommandExtension([
- 'aFooQueueName' => 'aFooProcessorName',
- ]);
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->never())
+ ->method('createQueue')
+ ;
+
+ $extension = new ExclusiveCommandExtension($driver);
- $extension->onPreReceived($context);
+ $extension->onMessageReceived($messageReceived);
- self::assertNull($context->getResult());
+ self::assertNull($messageReceived->getResult());
$this->assertEquals([
- 'enqueue.processor_name' => 'aProcessor',
+ Config::COMMAND => 'aCommand',
], $message->getProperties());
}
- public function testShouldDoNothingIfMessageHasProcessorQueueNamePropertySetOnPreReceive()
+ public function testShouldDoNothingIfMessageHasProcessorPropertySetOnPreReceive()
{
$message = new NullMessage();
- $message->setProperty(Config::PARAMETER_PROCESSOR_QUEUE_NAME, 'aProcessorQueueName');
+ $message->setProperty(Config::PROCESSOR, 'aProcessor');
- $context = new Context(new NullContext());
- $context->setPsrMessage($message);
+ $messageReceived = new MessageReceived(
+ $this->createContextMock(),
+ $this->createConsumerStub(null),
+ $message,
+ $this->createProcessorMock(),
+ 1,
+ new NullLogger()
+ );
- $extension = new ExclusiveCommandExtension([
- 'aFooQueueName' => 'aFooProcessorName',
- ]);
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->never())
+ ->method('createQueue')
+ ;
+
+ $extension = new ExclusiveCommandExtension($driver);
- $extension->onPreReceived($context);
+ $extension->onMessageReceived($messageReceived);
- self::assertNull($context->getResult());
+ self::assertNull($messageReceived->getResult());
$this->assertEquals([
- 'enqueue.processor_queue_name' => 'aProcessorQueueName',
+ Config::PROCESSOR => 'aProcessor',
], $message->getProperties());
}
- public function testShouldDoNothingIfCurrentQueueIsNotInTheMap()
+ public function testShouldDoNothingIfCurrentQueueHasNoExclusiveProcessor()
{
$message = new NullMessage();
$queue = new NullQueue('aBarQueueName');
- $context = new Context(new NullContext());
- $context->setPsrMessage($message);
- $context->setPsrQueue($queue);
+ $messageReceived = new MessageReceived(
+ $this->createContextMock(),
+ $this->createConsumerStub($queue),
+ $message,
+ $this->createProcessorMock(),
+ 1,
+ new NullLogger()
+ );
- $extension = new ExclusiveCommandExtension([
- 'aFooQueueName' => 'aFooProcessorName',
- ]);
+ $extension = new ExclusiveCommandExtension($this->createDriverStub(new RouteCollection([])));
- $extension->onPreReceived($context);
+ $extension->onMessageReceived($messageReceived);
- self::assertNull($context->getResult());
+ self::assertNull($messageReceived->getResult());
$this->assertEquals([], $message->getProperties());
}
- public function testShouldSetCommandPropertiesIfCurrentQueueInTheMap()
+ public function testShouldSetCommandPropertiesIfCurrentQueueHasExclusiveCommandProcessor()
{
$message = new NullMessage();
- $queue = new NullQueue('aFooQueueName');
-
- $context = new Context(new NullContext());
- $context->setPsrMessage($message);
- $context->setPsrQueue($queue);
- $context->setLogger(new NullLogger());
-
- $extension = new ExclusiveCommandExtension([
- 'aFooQueueName' => 'aFooProcessorName',
+ $queue = new NullQueue('fooQueue');
+
+ $messageReceived = new MessageReceived(
+ $this->createContextMock(),
+ $this->createConsumerStub($queue),
+ $message,
+ $this->createProcessorMock(),
+ 1,
+ new NullLogger()
+ );
+
+ $routeCollection = new RouteCollection([
+ new Route('fooCommand', Route::COMMAND, 'theFooProcessor', [
+ 'exclusive' => true,
+ 'queue' => 'fooQueue',
+ ]),
+ new Route('barCommand', Route::COMMAND, 'theFooProcessor', [
+ 'exclusive' => true,
+ 'queue' => 'barQueue',
+ ]),
]);
- $extension->onPreReceived($context);
+ $driver = $this->createDriverStub($routeCollection);
+ $driver
+ ->expects($this->any())
+ ->method('createRouteQueue')
+ ->with($this->isInstanceOf(Route::class))
+ ->willReturnCallback(function (Route $route) {
+ return new NullQueue($route->getQueue());
+ })
+ ;
+
+ $extension = new ExclusiveCommandExtension($driver);
+ $extension->onMessageReceived($messageReceived);
- self::assertNull($context->getResult());
+ self::assertNull($messageReceived->getResult());
$this->assertEquals([
- 'enqueue.topic_name' => '__command__',
- 'enqueue.processor_queue_name' => 'aFooQueueName',
- 'enqueue.processor_name' => 'aFooProcessorName',
- 'enqueue.command_name' => 'aFooProcessorName',
+ Config::PROCESSOR => 'theFooProcessor',
+ Config::COMMAND => 'fooCommand',
], $message->getProperties());
}
- public function testShouldDoNothingOnPreSendIfTopicNotCommandOne()
+ public function testShouldDoNothingIfAnotherQueue()
{
- $message = new Message();
-
- $extension = new ExclusiveCommandExtension([
- 'aFooQueueName' => 'aFooProcessorName',
+ $message = new NullMessage();
+ $queue = new NullQueue('barQueue');
+
+ $messageReceived = new MessageReceived(
+ $this->createContextMock(),
+ $this->createConsumerStub($queue),
+ $message,
+ $this->createProcessorMock(),
+ 1,
+ new NullLogger()
+ );
+
+ $routeCollection = new RouteCollection([
+ new Route('fooCommand', Route::COMMAND, 'theFooProcessor', [
+ 'exclusive' => true,
+ 'queue' => 'fooQueue',
+ ]),
+ new Route('barCommand', Route::COMMAND, 'theFooProcessor', [
+ 'exclusive' => false,
+ 'queue' => 'barQueue',
+ ]),
]);
- $extension->onPreSend('aTopic', $message);
+ $driver = $this->createDriverStub($routeCollection);
+ $driver
+ ->expects($this->any())
+ ->method('createQueue')
+ ->willReturnCallback(function (string $queueName) {
+ return new NullQueue($queueName);
+ })
+ ;
+
+ $extension = new ExclusiveCommandExtension($driver);
+ $extension->onMessageReceived($messageReceived);
+
+ self::assertNull($messageReceived->getResult());
$this->assertEquals([], $message->getProperties());
}
- public function testShouldDoNothingIfCommandNotExclusive()
+ /**
+ * @return MockObject|DriverInterface
+ */
+ private function createDriverStub(?RouteCollection $routeCollection = null): DriverInterface
{
- $message = new Message();
- $message->setProperty(Config::PARAMETER_COMMAND_NAME, 'theBarProcessorName');
-
- $extension = new ExclusiveCommandExtension([
- 'aFooQueueName' => 'aFooProcessorName',
- ]);
-
- $extension->onPreSend(Config::COMMAND_TOPIC, $message);
-
- $this->assertEquals([
- 'enqueue.command_name' => 'theBarProcessorName',
- ], $message->getProperties());
+ $driver = $this->createMock(DriverInterface::class);
+ $driver
+ ->expects($this->any())
+ ->method('getRouteCollection')
+ ->willReturn($routeCollection ?? new RouteCollection([]))
+ ;
+
+ return $driver;
}
- public function testShouldForceExclusiveCommandQueue()
+ /**
+ * @return MockObject
+ */
+ private function createContextMock(): InteropContext
{
- $message = new Message();
- $message->setProperty(Config::PARAMETER_COMMAND_NAME, 'aFooProcessorName');
-
- $extension = new ExclusiveCommandExtension([
- 'aFooQueueName' => 'aFooProcessorName',
- ]);
+ return $this->createMock(InteropContext::class);
+ }
- $extension->onPreSend(Config::COMMAND_TOPIC, $message);
+ /**
+ * @return MockObject
+ */
+ private function createProcessorMock(): Processor
+ {
+ return $this->createMock(Processor::class);
+ }
- $this->assertEquals([
- 'enqueue.command_name' => 'aFooProcessorName',
- 'enqueue.processor_name' => 'aFooProcessorName',
- 'enqueue.processor_queue_name' => 'aFooQueueName',
- ], $message->getProperties());
+ /**
+ * @return MockObject|Consumer
+ */
+ private function createConsumerStub(?Queue $queue): Consumer
+ {
+ $consumerMock = $this->createMock(Consumer::class);
+ $consumerMock
+ ->expects($this->any())
+ ->method('getQueue')
+ ->willReturn($queue ?? new NullQueue('queue'))
+ ;
+
+ return $consumerMock;
}
}
diff --git a/pkg/enqueue/Tests/Client/ConsumptionExtension/FlushSpoolProducerExtensionTest.php b/pkg/enqueue/Tests/Client/ConsumptionExtension/FlushSpoolProducerExtensionTest.php
index 1469c99bb..6a782c524 100644
--- a/pkg/enqueue/Tests/Client/ConsumptionExtension/FlushSpoolProducerExtensionTest.php
+++ b/pkg/enqueue/Tests/Client/ConsumptionExtension/FlushSpoolProducerExtensionTest.php
@@ -4,86 +4,33 @@
use Enqueue\Client\ConsumptionExtension\FlushSpoolProducerExtension;
use Enqueue\Client\SpoolProducer;
-use Enqueue\Consumption\Context;
-use Enqueue\Consumption\ExtensionInterface;
+use Enqueue\Consumption\Context\End;
+use Enqueue\Consumption\Context\PostMessageReceived;
+use Enqueue\Consumption\EndExtensionInterface;
+use Enqueue\Consumption\PostMessageReceivedExtensionInterface;
use Enqueue\Test\ClassExtensionTrait;
+use Interop\Queue\Consumer;
+use Interop\Queue\Context;
+use Interop\Queue\Message;
+use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
+use Psr\Log\NullLogger;
class FlushSpoolProducerExtensionTest extends TestCase
{
use ClassExtensionTrait;
- public function testShouldImplementExtensionInterface()
+ public function testShouldImplementPostMessageReceivedExtensionInterface()
{
- $this->assertClassImplements(ExtensionInterface::class, FlushSpoolProducerExtension::class);
+ $this->assertClassImplements(PostMessageReceivedExtensionInterface::class, FlushSpoolProducerExtension::class);
}
- public function testCouldBeConstructedWithSpoolProducerAsFirstArgument()
+ public function testShouldImplementEndExtensionInterface()
{
- new FlushSpoolProducerExtension($this->createSpoolProducerMock());
+ $this->assertClassImplements(EndExtensionInterface::class, FlushSpoolProducerExtension::class);
}
- public function testShouldDoNothingOnStart()
- {
- $producer = $this->createSpoolProducerMock();
- $producer
- ->expects(self::never())
- ->method('flush')
- ;
-
- $extension = new FlushSpoolProducerExtension($producer);
- $extension->onStart($this->createContextMock());
- }
-
- public function testShouldDoNothingOnBeforeReceive()
- {
- $producer = $this->createSpoolProducerMock();
- $producer
- ->expects(self::never())
- ->method('flush')
- ;
-
- $extension = new FlushSpoolProducerExtension($producer);
- $extension->onBeforeReceive($this->createContextMock());
- }
-
- public function testShouldDoNothingOnPreReceived()
- {
- $producer = $this->createSpoolProducerMock();
- $producer
- ->expects(self::never())
- ->method('flush')
- ;
-
- $extension = new FlushSpoolProducerExtension($producer);
- $extension->onPreReceived($this->createContextMock());
- }
-
- public function testShouldDoNothingOnResult()
- {
- $producer = $this->createSpoolProducerMock();
- $producer
- ->expects(self::never())
- ->method('flush')
- ;
-
- $extension = new FlushSpoolProducerExtension($producer);
- $extension->onResult($this->createContextMock());
- }
-
- public function testShouldDoNothingOnIdle()
- {
- $producer = $this->createSpoolProducerMock();
- $producer
- ->expects(self::never())
- ->method('flush')
- ;
-
- $extension = new FlushSpoolProducerExtension($producer);
- $extension->onIdle($this->createContextMock());
- }
-
- public function testShouldFlushSpoolProducerOnInterrupted()
+ public function testShouldFlushSpoolProducerOnEnd()
{
$producer = $this->createSpoolProducerMock();
$producer
@@ -91,8 +38,10 @@ public function testShouldFlushSpoolProducerOnInterrupted()
->method('flush')
;
+ $end = new End($this->createInteropContextMock(), 1, 2, new NullLogger());
+
$extension = new FlushSpoolProducerExtension($producer);
- $extension->onInterrupted($this->createContextMock());
+ $extension->onEnd($end);
}
public function testShouldFlushSpoolProducerOnPostReceived()
@@ -103,20 +52,29 @@ public function testShouldFlushSpoolProducerOnPostReceived()
->method('flush')
;
+ $context = new PostMessageReceived(
+ $this->createInteropContextMock(),
+ $this->createMock(Consumer::class),
+ $this->createMock(Message::class),
+ 'aResult',
+ 1,
+ new NullLogger()
+ );
+
$extension = new FlushSpoolProducerExtension($producer);
- $extension->onPostReceived($this->createContextMock());
+ $extension->onPostMessageReceived($context);
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|Context
+ * @return MockObject
*/
- private function createContextMock()
+ private function createInteropContextMock(): Context
{
return $this->createMock(Context::class);
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|SpoolProducer
+ * @return MockObject|SpoolProducer
*/
private function createSpoolProducerMock()
{
diff --git a/pkg/enqueue/Tests/Client/ConsumptionExtension/LogExtensionTest.php b/pkg/enqueue/Tests/Client/ConsumptionExtension/LogExtensionTest.php
new file mode 100644
index 000000000..db757676b
--- /dev/null
+++ b/pkg/enqueue/Tests/Client/ConsumptionExtension/LogExtensionTest.php
@@ -0,0 +1,536 @@
+assertClassImplements(StartExtensionInterface::class, LogExtension::class);
+ }
+
+ public function testShouldImplementEndExtensionInterface()
+ {
+ $this->assertClassImplements(EndExtensionInterface::class, LogExtension::class);
+ }
+
+ public function testShouldImplementMessageReceivedExtensionInterface()
+ {
+ $this->assertClassImplements(MessageReceivedExtensionInterface::class, LogExtension::class);
+ }
+
+ public function testShouldImplementPostMessageReceivedExtensionInterface()
+ {
+ $this->assertClassImplements(PostMessageReceivedExtensionInterface::class, LogExtension::class);
+ }
+
+ public function testShouldSubClassOfLogExtension()
+ {
+ $this->assertClassExtends(\Enqueue\Consumption\Extension\LogExtension::class, LogExtension::class);
+ }
+
+ public function testShouldLogStartOnStart()
+ {
+ $logger = $this->createLogger();
+ $logger
+ ->expects($this->once())
+ ->method('debug')
+ ->with('Consumption has started')
+ ;
+
+ $context = new Start($this->createContextMock(), $logger, [], 1, 1);
+
+ $extension = new LogExtension();
+ $extension->onStart($context);
+ }
+
+ public function testShouldLogEndOnEnd()
+ {
+ $logger = $this->createLogger();
+ $logger
+ ->expects($this->once())
+ ->method('debug')
+ ->with('Consumption has ended')
+ ;
+
+ $context = new End($this->createContextMock(), 1, 2, $logger);
+
+ $extension = new LogExtension();
+ $extension->onEnd($context);
+ }
+
+ public function testShouldLogMessageReceived()
+ {
+ $logger = $this->createLogger();
+ $logger
+ ->expects($this->once())
+ ->method('debug')
+ ->with('Received from {queueName} {body}', [
+ 'queueName' => 'aQueue',
+ 'redelivered' => false,
+ 'body' => Stringify::that('aBody'),
+ 'properties' => Stringify::that(['aProp' => 'aPropVal']),
+ 'headers' => Stringify::that(['aHeader' => 'aHeaderVal']),
+ ])
+ ;
+
+ $consumerMock = $this->createConsumerStub(new NullQueue('aQueue'));
+ $message = new NullMessage('aBody');
+ $message->setProperty('aProp', 'aPropVal');
+ $message->setHeader('aHeader', 'aHeaderVal');
+
+ $context = new MessageReceived($this->createContextMock(), $consumerMock, $message, $this->createProcessorMock(), 1, $logger);
+
+ $extension = new LogExtension();
+ $extension->onMessageReceived($context);
+ }
+
+ public function testShouldLogMessageProcessedWithStringResult()
+ {
+ $logger = $this->createLogger();
+ $logger
+ ->expects($this->once())
+ ->method('log')
+ ->with(LogLevel::INFO,
+ 'Processed from {queueName} {body} {result}',
+ [
+ 'queueName' => 'aQueue',
+ 'body' => Stringify::that('aBody'),
+ 'properties' => Stringify::that(['aProp' => 'aPropVal']),
+ 'headers' => Stringify::that(['aHeader' => 'aHeaderVal']),
+ 'result' => 'aResult',
+ 'reason' => '',
+ ]
+ )
+ ;
+
+ $consumerMock = $this->createConsumerStub(new NullQueue('aQueue'));
+ $message = new NullMessage('aBody');
+ $message->setProperty('aProp', 'aPropVal');
+ $message->setHeader('aHeader', 'aHeaderVal');
+
+ $context = new PostMessageReceived($this->createContextMock(), $consumerMock, $message, 'aResult', 1, $logger);
+
+ $extension = new LogExtension();
+ $extension->onPostMessageReceived($context);
+ }
+
+ public function testShouldLogRejectedMessageAsError()
+ {
+ $logger = $this->createLogger();
+ $logger
+ ->expects($this->once())
+ ->method('log')
+ ->with(LogLevel::ERROR,
+ 'Processed from {queueName} {body} {result}',
+ [
+ 'queueName' => 'aQueue',
+ 'body' => Stringify::that('aBody'),
+ 'properties' => Stringify::that(['aProp' => 'aPropVal']),
+ 'headers' => Stringify::that(['aHeader' => 'aHeaderVal']),
+ 'result' => 'reject',
+ 'reason' => '',
+ ]
+ )
+ ;
+
+ $consumerMock = $this->createConsumerStub(new NullQueue('aQueue'));
+ $message = new NullMessage('aBody');
+ $message->setProperty('aProp', 'aPropVal');
+ $message->setHeader('aHeader', 'aHeaderVal');
+
+ $context = new PostMessageReceived($this->createContextMock(), $consumerMock, $message, Processor::REJECT, 1, $logger);
+
+ $extension = new LogExtension();
+ $extension->onPostMessageReceived($context);
+ }
+
+ public function testShouldLogMessageProcessedWithResultObject()
+ {
+ $logger = $this->createLogger();
+ $logger
+ ->expects($this->once())
+ ->method('log')
+ ->with(LogLevel::INFO,
+ 'Processed from {queueName} {body} {result}',
+ [
+ 'queueName' => 'aQueue',
+ 'body' => Stringify::that('aBody'),
+ 'properties' => Stringify::that(['aProp' => 'aPropVal']),
+ 'headers' => Stringify::that(['aHeader' => 'aHeaderVal']),
+ 'result' => 'ack',
+ 'reason' => '',
+ ]
+ )
+ ;
+
+ $consumerMock = $this->createConsumerStub(new NullQueue('aQueue'));
+ $message = new NullMessage('aBody');
+ $message->setProperty('aProp', 'aPropVal');
+ $message->setHeader('aHeader', 'aHeaderVal');
+
+ $context = new PostMessageReceived($this->createContextMock(), $consumerMock, $message, Result::ack(), 1, $logger);
+
+ $extension = new LogExtension();
+ $extension->onPostMessageReceived($context);
+ }
+
+ public function testShouldLogMessageProcessedWithReasonResultObject()
+ {
+ $logger = $this->createLogger();
+ $logger
+ ->expects($this->once())
+ ->method('log')
+ ->with(LogLevel::INFO,
+ 'Processed from {queueName} {body} {result} {reason}',
+ [
+ 'queueName' => 'aQueue',
+ 'body' => Stringify::that('aBody'),
+ 'properties' => Stringify::that(['aProp' => 'aPropVal']),
+ 'headers' => Stringify::that(['aHeader' => 'aHeaderVal']),
+ 'result' => 'ack',
+ 'reason' => 'aReason',
+ ]
+ )
+ ;
+
+ $consumerMock = $this->createConsumerStub(new NullQueue('aQueue'));
+ $message = new NullMessage('aBody');
+ $message->setProperty('aProp', 'aPropVal');
+ $message->setHeader('aHeader', 'aHeaderVal');
+
+ $context = new PostMessageReceived($this->createContextMock(), $consumerMock, $message, Result::ack('aReason'), 1, $logger);
+
+ $extension = new LogExtension();
+ $extension->onPostMessageReceived($context);
+ }
+
+ public function testShouldLogProcessedCommandMessageWithStringResult()
+ {
+ $logger = $this->createLogger();
+ $logger
+ ->expects($this->once())
+ ->method('log')
+ ->with(LogLevel::INFO,
+ '[client] Processed {command} {body} {result}',
+ [
+ 'queueName' => 'aQueue',
+ 'body' => Stringify::that('aBody'),
+ 'properties' => Stringify::that(['aProp' => 'aPropVal', Config::COMMAND => 'aCommand']),
+ 'headers' => Stringify::that(['aHeader' => 'aHeaderVal']),
+ 'result' => 'aResult',
+ 'reason' => '',
+ 'command' => 'aCommand',
+ ]
+ )
+ ;
+
+ $consumerMock = $this->createConsumerStub(new NullQueue('aQueue'));
+ $message = new NullMessage('aBody');
+ $message->setProperty(Config::COMMAND, 'aCommand');
+ $message->setProperty('aProp', 'aPropVal');
+ $message->setHeader('aHeader', 'aHeaderVal');
+
+ $context = new PostMessageReceived($this->createContextMock(), $consumerMock, $message, 'aResult', 1, $logger);
+
+ $extension = new LogExtension();
+ $extension->onPostMessageReceived($context);
+ }
+
+ public function testShouldLogRejectedCommandMessageAsError()
+ {
+ $logger = $this->createLogger();
+ $logger
+ ->expects($this->once())
+ ->method('log')
+ ->with(LogLevel::ERROR,
+ '[client] Processed {command} {body} {result}',
+ [
+ 'queueName' => 'aQueue',
+ 'body' => Stringify::that('aBody'),
+ 'properties' => Stringify::that(['aProp' => 'aPropVal', Config::COMMAND => 'aCommand']),
+ 'headers' => Stringify::that(['aHeader' => 'aHeaderVal']),
+ 'result' => 'reject',
+ 'reason' => '',
+ 'command' => 'aCommand',
+ ]
+ )
+ ;
+
+ $consumerMock = $this->createConsumerStub(new NullQueue('aQueue'));
+ $message = new NullMessage('aBody');
+ $message->setProperty('aProp', 'aPropVal');
+ $message->setProperty(Config::COMMAND, 'aCommand');
+ $message->setHeader('aHeader', 'aHeaderVal');
+
+ $context = new PostMessageReceived($this->createContextMock(), $consumerMock, $message, Processor::REJECT, 1, $logger);
+
+ $extension = new LogExtension();
+ $extension->onPostMessageReceived($context);
+ }
+
+ public function testShouldLogProcessedCommandMessageWithResultObject()
+ {
+ $logger = $this->createLogger();
+ $logger
+ ->expects($this->once())
+ ->method('log')
+ ->with(LogLevel::INFO,
+ '[client] Processed {command} {body} {result}',
+ [
+ 'queueName' => 'aQueue',
+ 'body' => Stringify::that('aBody'),
+ 'properties' => Stringify::that(['aProp' => 'aPropVal', Config::COMMAND => 'aCommand']),
+ 'headers' => Stringify::that(['aHeader' => 'aHeaderVal']),
+ 'result' => 'ack',
+ 'reason' => '',
+ 'command' => 'aCommand',
+ ]
+ )
+ ;
+
+ $consumerMock = $this->createConsumerStub(new NullQueue('aQueue'));
+ $message = new NullMessage('aBody');
+ $message->setProperty('aProp', 'aPropVal');
+ $message->setProperty(Config::COMMAND, 'aCommand');
+ $message->setHeader('aHeader', 'aHeaderVal');
+
+ $context = new PostMessageReceived($this->createContextMock(), $consumerMock, $message, Result::ack(), 1, $logger);
+
+ $extension = new LogExtension();
+ $extension->onPostMessageReceived($context);
+ }
+
+ public function testShouldLogProcessedCommandMessageWithReasonResultObject()
+ {
+ $logger = $this->createLogger();
+ $logger
+ ->expects($this->once())
+ ->method('log')
+ ->with(LogLevel::INFO,
+ '[client] Processed {command} {body} {result} {reason}',
+ [
+ 'queueName' => 'aQueue',
+ 'body' => Stringify::that('aBody'),
+ 'properties' => Stringify::that(['aProp' => 'aPropVal', Config::COMMAND => 'aCommand']),
+ 'headers' => Stringify::that(['aHeader' => 'aHeaderVal']),
+ 'result' => 'ack',
+ 'reason' => 'aReason',
+ 'command' => 'aCommand',
+ ]
+ )
+ ;
+
+ $consumerMock = $this->createConsumerStub(new NullQueue('aQueue'));
+ $message = new NullMessage('aBody');
+ $message->setProperty('aProp', 'aPropVal');
+ $message->setProperty(Config::COMMAND, 'aCommand');
+ $message->setHeader('aHeader', 'aHeaderVal');
+
+ $context = new PostMessageReceived($this->createContextMock(), $consumerMock, $message, Result::ack('aReason'), 1, $logger);
+
+ $extension = new LogExtension();
+ $extension->onPostMessageReceived($context);
+ }
+
+ public function testShouldLogProcessedTopicProcessorMessageWithStringResult()
+ {
+ $logger = $this->createLogger();
+ $logger
+ ->expects($this->once())
+ ->method('log')
+ ->with(LogLevel::INFO,
+ '[client] Processed {topic} -> {processor} {body} {result}',
+ [
+ 'queueName' => 'aQueue',
+ 'body' => Stringify::that('aBody'),
+ 'properties' => Stringify::that(['aProp' => 'aPropVal', Config::TOPIC => 'aTopic', Config::PROCESSOR => 'aProcessor']),
+ 'headers' => Stringify::that(['aHeader' => 'aHeaderVal']),
+ 'result' => 'aResult',
+ 'reason' => '',
+ 'topic' => 'aTopic',
+ 'processor' => 'aProcessor',
+ ]
+ )
+ ;
+
+ $consumerMock = $this->createConsumerStub(new NullQueue('aQueue'));
+ $message = new NullMessage('aBody');
+ $message->setProperty(Config::TOPIC, 'aTopic');
+ $message->setProperty(Config::PROCESSOR, 'aProcessor');
+ $message->setProperty('aProp', 'aPropVal');
+ $message->setHeader('aHeader', 'aHeaderVal');
+
+ $context = new PostMessageReceived($this->createContextMock(), $consumerMock, $message, 'aResult', 1, $logger);
+
+ $extension = new LogExtension();
+ $extension->onPostMessageReceived($context);
+ }
+
+ public function testShouldLogRejectedTopicProcessorMessageAsError()
+ {
+ $logger = $this->createLogger();
+ $logger
+ ->expects($this->once())
+ ->method('log')
+ ->with(LogLevel::ERROR,
+ '[client] Processed {topic} -> {processor} {body} {result}',
+ [
+ 'queueName' => 'aQueue',
+ 'body' => Stringify::that('aBody'),
+ 'properties' => Stringify::that(['aProp' => 'aPropVal', Config::TOPIC => 'aTopic', Config::PROCESSOR => 'aProcessor']),
+ 'headers' => Stringify::that(['aHeader' => 'aHeaderVal']),
+ 'result' => 'reject',
+ 'reason' => '',
+ 'topic' => 'aTopic',
+ 'processor' => 'aProcessor',
+ ]
+ )
+ ;
+
+ $consumerMock = $this->createConsumerStub(new NullQueue('aQueue'));
+ $message = new NullMessage('aBody');
+ $message->setProperty(Config::TOPIC, 'aTopic');
+ $message->setProperty(Config::PROCESSOR, 'aProcessor');
+ $message->setProperty('aProp', 'aPropVal');
+ $message->setHeader('aHeader', 'aHeaderVal');
+
+ $context = new PostMessageReceived($this->createContextMock(), $consumerMock, $message, Processor::REJECT, 1, $logger);
+
+ $extension = new LogExtension();
+ $extension->onPostMessageReceived($context);
+ }
+
+ public function testShouldLogProcessedTopicProcessorMessageWithResultObject()
+ {
+ $logger = $this->createLogger();
+ $logger
+ ->expects($this->once())
+ ->method('log')
+ ->with(LogLevel::INFO,
+ '[client] Processed {topic} -> {processor} {body} {result}',
+ [
+ 'queueName' => 'aQueue',
+ 'body' => Stringify::that('aBody'),
+ 'properties' => Stringify::that(['aProp' => 'aPropVal', Config::TOPIC => 'aTopic', Config::PROCESSOR => 'aProcessor']),
+ 'headers' => Stringify::that(['aHeader' => 'aHeaderVal']),
+ 'result' => 'ack',
+ 'reason' => '',
+ 'topic' => 'aTopic',
+ 'processor' => 'aProcessor',
+ ]
+ )
+ ;
+
+ $consumerMock = $this->createConsumerStub(new NullQueue('aQueue'));
+ $message = new NullMessage('aBody');
+ $message->setProperty(Config::TOPIC, 'aTopic');
+ $message->setProperty(Config::PROCESSOR, 'aProcessor');
+ $message->setProperty('aProp', 'aPropVal');
+ $message->setHeader('aHeader', 'aHeaderVal');
+
+ $context = new PostMessageReceived($this->createContextMock(), $consumerMock, $message, Result::ack(), 1, $logger);
+
+ $extension = new LogExtension();
+ $extension->onPostMessageReceived($context);
+ }
+
+ public function testShouldLogProcessedTopicProcessorMessageWithReasonResultObject()
+ {
+ $logger = $this->createLogger();
+ $logger
+ ->expects($this->once())
+ ->method('log')
+ ->with(LogLevel::INFO,
+ '[client] Processed {topic} -> {processor} {body} {result} {reason}',
+ [
+ 'queueName' => 'aQueue',
+ 'body' => Stringify::that('aBody'),
+ 'properties' => Stringify::that(['aProp' => 'aPropVal', Config::TOPIC => 'aTopic', Config::PROCESSOR => 'aProcessor']),
+ 'headers' => Stringify::that(['aHeader' => 'aHeaderVal']),
+ 'result' => 'ack',
+ 'reason' => 'aReason',
+ 'topic' => 'aTopic',
+ 'processor' => 'aProcessor',
+ ]
+ )
+ ;
+
+ $consumerMock = $this->createConsumerStub(new NullQueue('aQueue'));
+ $message = new NullMessage('aBody');
+ $message->setProperty(Config::TOPIC, 'aTopic');
+ $message->setProperty(Config::PROCESSOR, 'aProcessor');
+ $message->setProperty('aProp', 'aPropVal');
+ $message->setHeader('aHeader', 'aHeaderVal');
+
+ $context = new PostMessageReceived($this->createContextMock(), $consumerMock, $message, Result::ack('aReason'), 1, $logger);
+
+ $extension = new LogExtension();
+ $extension->onPostMessageReceived($context);
+ }
+
+ /**
+ * @return MockObject
+ */
+ private function createConsumerStub(Queue $queue): Consumer
+ {
+ $consumerMock = $this->createMock(Consumer::class);
+ $consumerMock
+ ->expects($this->any())
+ ->method('getQueue')
+ ->willReturn($queue)
+ ;
+
+ return $consumerMock;
+ }
+
+ /**
+ * @return MockObject
+ */
+ private function createContextMock(): Context
+ {
+ return $this->createMock(Context::class);
+ }
+
+ /**
+ * @return MockObject
+ */
+ private function createProcessorMock(): Processor
+ {
+ return $this->createMock(Processor::class);
+ }
+
+ /**
+ * @return MockObject|LoggerInterface
+ */
+ private function createLogger()
+ {
+ return $this->createMock(LoggerInterface::class);
+ }
+}
diff --git a/pkg/enqueue/Tests/Client/ConsumptionExtension/SetRouterPropertiesExtensionTest.php b/pkg/enqueue/Tests/Client/ConsumptionExtension/SetRouterPropertiesExtensionTest.php
index 6dc723c37..d521aefca 100644
--- a/pkg/enqueue/Tests/Client/ConsumptionExtension/SetRouterPropertiesExtensionTest.php
+++ b/pkg/enqueue/Tests/Client/ConsumptionExtension/SetRouterPropertiesExtensionTest.php
@@ -5,31 +5,31 @@
use Enqueue\Client\Config;
use Enqueue\Client\ConsumptionExtension\SetRouterPropertiesExtension;
use Enqueue\Client\DriverInterface;
-use Enqueue\Consumption\Context;
-use Enqueue\Consumption\ExtensionInterface;
+use Enqueue\Consumption\Context\MessageReceived;
+use Enqueue\Consumption\MessageReceivedExtensionInterface;
use Enqueue\Null\NullMessage;
use Enqueue\Null\NullQueue;
use Enqueue\Test\ClassExtensionTrait;
-use Interop\Queue\PsrContext;
+use Interop\Queue\Consumer;
+use Interop\Queue\Context as InteropContext;
+use Interop\Queue\Processor;
+use Interop\Queue\Queue;
+use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
+use Psr\Log\NullLogger;
class SetRouterPropertiesExtensionTest extends TestCase
{
use ClassExtensionTrait;
- public function testShouldImplementExtensionInterface()
+ public function testShouldImplementMessageReceivedExtensionInterface()
{
- $this->assertClassImplements(ExtensionInterface::class, SetRouterPropertiesExtension::class);
- }
-
- public function testCouldBeConstructedWithRequiredArguments()
- {
- new SetRouterPropertiesExtension($this->createDriverMock());
+ $this->assertClassImplements(MessageReceivedExtensionInterface::class, SetRouterPropertiesExtension::class);
}
public function testShouldSetRouterProcessorPropertyIfNotSetAndOnRouterQueue()
{
- $config = Config::create('test', '', '', 'router-queue', '', 'router-processor-name');
+ $config = Config::create('test', '.', '', '', 'router-queue', '', 'router-processor-name');
$queue = new NullQueue('test.router-queue');
$driver = $this->createDriverMock();
@@ -46,17 +46,23 @@ public function testShouldSetRouterProcessorPropertyIfNotSetAndOnRouterQueue()
;
$message = new NullMessage();
+ $message->setProperty(Config::TOPIC, 'aTopic');
- $context = new Context($this->createPsrContextMock());
- $context->setPsrMessage($message);
- $context->setPsrQueue(new NullQueue('test.router-queue'));
+ $messageReceived = new MessageReceived(
+ $this->createContextMock(),
+ $this->createConsumerStub(new NullQueue('test.router-queue')),
+ $message,
+ $this->createProcessorMock(),
+ 1,
+ new NullLogger()
+ );
$extension = new SetRouterPropertiesExtension($driver);
- $extension->onPreReceived($context);
+ $extension->onMessageReceived($messageReceived);
$this->assertEquals([
- 'enqueue.processor_name' => 'router-processor-name',
- 'enqueue.processor_queue_name' => 'router-queue',
+ Config::PROCESSOR => 'router-processor-name',
+ Config::TOPIC => 'aTopic',
], $message->getProperties());
}
@@ -79,15 +85,23 @@ public function testShouldNotSetRouterProcessorPropertyIfNotSetAndNotOnRouterQue
;
$message = new NullMessage();
+ $message->setProperty(Config::TOPIC, 'aTopic');
- $context = new Context($this->createPsrContextMock());
- $context->setPsrMessage($message);
- $context->setPsrQueue(new NullQueue('test.another-queue'));
+ $messageReceived = new MessageReceived(
+ $this->createContextMock(),
+ $this->createConsumerStub(new NullQueue('test.another-queue')),
+ $message,
+ $this->createProcessorMock(),
+ 1,
+ new NullLogger()
+ );
$extension = new SetRouterPropertiesExtension($driver);
- $extension->onPreReceived($context);
+ $extension->onMessageReceived($messageReceived);
- $this->assertEquals([], $message->getProperties());
+ $this->assertEquals([
+ Config::TOPIC => 'aTopic',
+ ], $message->getProperties());
}
public function testShouldNotSetAnyPropertyIfProcessorNamePropertyAlreadySet()
@@ -99,32 +113,86 @@ public function testShouldNotSetAnyPropertyIfProcessorNamePropertyAlreadySet()
;
$message = new NullMessage();
- $message->setProperty(Config::PARAMETER_PROCESSOR_NAME, 'non-router-processor');
+ $message->setProperty(Config::PROCESSOR, 'non-router-processor');
- $context = new Context($this->createPsrContextMock());
- $context->setPsrMessage($message);
+ $messageReceived = new MessageReceived(
+ $this->createContextMock(),
+ $this->createConsumerStub(null),
+ $message,
+ $this->createProcessorMock(),
+ 1,
+ new NullLogger()
+ );
$extension = new SetRouterPropertiesExtension($driver);
- $extension->onPreReceived($context);
+ $extension->onMessageReceived($messageReceived);
$this->assertEquals([
- 'enqueue.processor_name' => 'non-router-processor',
+ 'enqueue.processor' => 'non-router-processor',
], $message->getProperties());
}
+ public function testShouldSkipMessagesWithoutTopicPropertySet()
+ {
+ $driver = $this->createDriverMock();
+ $driver
+ ->expects($this->never())
+ ->method('getConfig')
+ ;
+
+ $message = new NullMessage();
+
+ $messageReceived = new MessageReceived(
+ $this->createContextMock(),
+ $this->createConsumerStub(null),
+ $message,
+ $this->createProcessorMock(),
+ 1,
+ new NullLogger()
+ );
+
+ $extension = new SetRouterPropertiesExtension($driver);
+ $extension->onMessageReceived($messageReceived);
+
+ $this->assertEquals([], $message->getProperties());
+ }
+
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|PsrContext
+ * @return MockObject|InteropContext
*/
- protected function createPsrContextMock()
+ protected function createContextMock(): InteropContext
{
- return $this->createMock(PsrContext::class);
+ return $this->createMock(InteropContext::class);
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|DriverInterface
+ * @return MockObject|DriverInterface
*/
- protected function createDriverMock()
+ protected function createDriverMock(): DriverInterface
{
return $this->createMock(DriverInterface::class);
}
+
+ /**
+ * @return MockObject
+ */
+ private function createProcessorMock(): Processor
+ {
+ return $this->createMock(Processor::class);
+ }
+
+ /**
+ * @return MockObject|Consumer
+ */
+ private function createConsumerStub(?Queue $queue): Consumer
+ {
+ $consumerMock = $this->createMock(Consumer::class);
+ $consumerMock
+ ->expects($this->any())
+ ->method('getQueue')
+ ->willReturn($queue ?? new NullQueue('queue'))
+ ;
+
+ return $consumerMock;
+ }
}
diff --git a/pkg/enqueue/Tests/Client/ConsumptionExtension/SetupBrokerExtensionTest.php b/pkg/enqueue/Tests/Client/ConsumptionExtension/SetupBrokerExtensionTest.php
index 21b011fe2..fbd367975 100644
--- a/pkg/enqueue/Tests/Client/ConsumptionExtension/SetupBrokerExtensionTest.php
+++ b/pkg/enqueue/Tests/Client/ConsumptionExtension/SetupBrokerExtensionTest.php
@@ -4,10 +4,11 @@
use Enqueue\Client\ConsumptionExtension\SetupBrokerExtension;
use Enqueue\Client\DriverInterface;
-use Enqueue\Consumption\Context;
-use Enqueue\Consumption\ExtensionInterface;
+use Enqueue\Consumption\Context\Start;
+use Enqueue\Consumption\StartExtensionInterface;
use Enqueue\Test\ClassExtensionTrait;
-use Interop\Queue\PsrContext;
+use Interop\Queue\Context as InteropContext;
+use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\NullLogger;
@@ -15,14 +16,9 @@ class SetupBrokerExtensionTest extends TestCase
{
use ClassExtensionTrait;
- public function testShouldImplementExtensionInterface()
+ public function testShouldImplementStartExtensionInterface()
{
- $this->assertClassImplements(ExtensionInterface::class, SetupBrokerExtension::class);
- }
-
- public function testCouldBeConstructedWithRequiredArguments()
- {
- new SetupBrokerExtension($this->createDriverMock());
+ $this->assertClassImplements(StartExtensionInterface::class, SetupBrokerExtension::class);
}
public function testShouldSetupBroker()
@@ -36,8 +32,7 @@ public function testShouldSetupBroker()
->with($this->identicalTo($logger))
;
- $context = new Context($this->createMock(PsrContext::class));
- $context->setLogger($logger);
+ $context = new Start($this->createMock(InteropContext::class), $logger, [], 0, 0);
$extension = new SetupBrokerExtension($driver);
$extension->onStart($context);
@@ -54,8 +49,7 @@ public function testShouldSetupBrokerOnlyOnce()
->with($this->identicalTo($logger))
;
- $context = new Context($this->createMock(PsrContext::class));
- $context->setLogger($logger);
+ $context = new Start($this->createMock(InteropContext::class), $logger, [], 0, 0);
$extension = new SetupBrokerExtension($driver);
$extension->onStart($context);
@@ -63,7 +57,7 @@ public function testShouldSetupBrokerOnlyOnce()
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|DriverInterface
+ * @return MockObject|DriverInterface
*/
private function createDriverMock()
{
diff --git a/pkg/enqueue/Tests/Client/DelegateProcessorTest.php b/pkg/enqueue/Tests/Client/DelegateProcessorTest.php
index f107dde6f..9743cf4f3 100644
--- a/pkg/enqueue/Tests/Client/DelegateProcessorTest.php
+++ b/pkg/enqueue/Tests/Client/DelegateProcessorTest.php
@@ -4,36 +4,30 @@
use Enqueue\Client\Config;
use Enqueue\Client\DelegateProcessor;
-use Enqueue\Client\ProcessorRegistryInterface;
use Enqueue\Null\NullMessage;
-use Interop\Queue\PsrContext;
-use Interop\Queue\PsrProcessor;
+use Enqueue\ProcessorRegistryInterface;
+use Interop\Queue\Context;
+use Interop\Queue\Processor;
+use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
class DelegateProcessorTest extends TestCase
{
- public function testCouldBeConstructedWithRequiredArguments()
- {
- new DelegateProcessor($this->createProcessorRegistryMock());
- }
-
public function testShouldThrowExceptionIfProcessorNameIsNotSet()
{
- $this->setExpectedException(
- \LogicException::class,
- 'Got message without required parameter: "enqueue.processor_name"'
- );
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Got message without required parameter: "enqueue.processor"');
$processor = new DelegateProcessor($this->createProcessorRegistryMock());
- $processor->process(new NullMessage(), $this->createPsrContextMock());
+ $processor->process(new NullMessage(), $this->createContextMock());
}
public function testShouldProcessMessage()
{
- $session = $this->createPsrContextMock();
+ $session = $this->createContextMock();
$message = new NullMessage();
$message->setProperties([
- Config::PARAMETER_PROCESSOR_NAME => 'processor-name',
+ Config::PROCESSOR => 'processor-name',
]);
$processor = $this->createProcessorMock();
@@ -41,7 +35,7 @@ public function testShouldProcessMessage()
->expects($this->once())
->method('process')
->with($this->identicalTo($message), $this->identicalTo($session))
- ->will($this->returnValue('return-value'))
+ ->willReturn('return-value')
;
$processorRegistry = $this->createProcessorRegistryMock();
@@ -49,7 +43,7 @@ public function testShouldProcessMessage()
->expects($this->once())
->method('get')
->with('processor-name')
- ->will($this->returnValue($processor))
+ ->willReturn($processor)
;
$processor = new DelegateProcessor($processorRegistry);
@@ -59,7 +53,7 @@ public function testShouldProcessMessage()
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|ProcessorRegistryInterface
+ * @return MockObject|ProcessorRegistryInterface
*/
protected function createProcessorRegistryMock()
{
@@ -67,18 +61,18 @@ protected function createProcessorRegistryMock()
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|PsrContext
+ * @return MockObject|Context
*/
- protected function createPsrContextMock()
+ protected function createContextMock()
{
- return $this->createMock(PsrContext::class);
+ return $this->createMock(Context::class);
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|PsrProcessor
+ * @return MockObject|Processor
*/
protected function createProcessorMock()
{
- return $this->createMock(PsrProcessor::class);
+ return $this->createMock(Processor::class);
}
}
diff --git a/pkg/enqueue/Tests/Client/Driver/AmqpDriverTest.php b/pkg/enqueue/Tests/Client/Driver/AmqpDriverTest.php
new file mode 100644
index 000000000..2cfb170b9
--- /dev/null
+++ b/pkg/enqueue/Tests/Client/Driver/AmqpDriverTest.php
@@ -0,0 +1,360 @@
+assertClassImplements(DriverInterface::class, AmqpDriver::class);
+ }
+
+ public function testShouldBeSubClassOfGenericDriver()
+ {
+ $this->assertClassExtends(GenericDriver::class, AmqpDriver::class);
+ }
+
+ public function testThrowIfPriorityIsNotSupportedOnCreateTransportMessage()
+ {
+ $clientMessage = new Message();
+ $clientMessage->setPriority('invalidPriority');
+
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($this->createMessage())
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([])
+ );
+
+ $this->expectException(\InvalidArgumentException::class);
+ $this->expectExceptionMessage('Cant convert client priority "invalidPriority" to transport one. Could be one of "enqueue.message_queue.client.very_low_message_priority", "enqueue.message_queue.client.low_message_priority", "enqueue.message_queue.client.normal_message_priority');
+ $driver->createTransportMessage($clientMessage);
+ }
+
+ public function testShouldSetExpirationHeaderFromClientMessageExpireInMillisecondsOnCreateTransportMessage()
+ {
+ $clientMessage = new Message();
+ $clientMessage->setExpire(333);
+
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($this->createMessage())
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([])
+ );
+
+ /** @var AmqpMessage $transportMessage */
+ $transportMessage = $driver->createTransportMessage($clientMessage);
+
+ $this->assertSame(333000, $transportMessage->getExpiration());
+ $this->assertSame('333000', $transportMessage->getHeader('expiration'));
+ }
+
+ public function testShouldSetPersistedDeliveryModeOnCreateTransportMessage()
+ {
+ $clientMessage = new Message();
+
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($this->createMessage())
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([])
+ );
+
+ /** @var AmqpMessage $transportMessage */
+ $transportMessage = $driver->createTransportMessage($clientMessage);
+
+ $this->assertSame(AmqpMessage::DELIVERY_MODE_PERSISTENT, $transportMessage->getDeliveryMode());
+ }
+
+ public function testShouldCreateDurableQueue()
+ {
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createQueue')
+ ->willReturn($this->createQueue('aName'))
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([])
+ );
+
+ /** @var AmqpQueue $queue */
+ $queue = $driver->createQueue('aName');
+
+ $this->assertSame(AmqpQueue::FLAG_DURABLE, $queue->getFlags());
+ }
+
+ public function testShouldResetPriorityAndExpirationAndNeverCallProducerDeliveryDelayOnSendMessageToRouter()
+ {
+ $topic = $this->createTopic('');
+ $transportMessage = $this->createMessage();
+
+ $producer = $this->createProducerMock();
+ $producer
+ ->expects($this->once())
+ ->method('send')
+ ->with($this->identicalTo($topic), $this->identicalTo($transportMessage))
+ ;
+ $producer
+ ->expects($this->never())
+ ->method('setDeliveryDelay')
+ ;
+
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createTopic')
+ ->willReturn($topic)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createProducer')
+ ->willReturn($producer)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($transportMessage)
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([])
+ );
+
+ $message = new Message();
+ $message->setProperty(Config::TOPIC, 'topic');
+ $message->setExpire(123);
+ $message->setPriority(MessagePriority::HIGH);
+
+ $driver->sendToRouter($message);
+
+ $this->assertNull($transportMessage->getExpiration());
+ $this->assertNull($transportMessage->getPriority());
+ }
+
+ public function testShouldSetupBroker()
+ {
+ $routerTopic = $this->createTopic('');
+ $routerQueue = $this->createQueue('');
+ $processorWithDefaultQueue = $this->createQueue('default');
+ $processorWithCustomQueue = $this->createQueue('custom');
+ $context = $this->createContextMock();
+ // setup router
+ $context
+ ->expects($this->at(0))
+ ->method('createTopic')
+ ->willReturn($routerTopic)
+ ;
+ $context
+ ->expects($this->at(1))
+ ->method('declareTopic')
+ ->with($this->identicalTo($routerTopic))
+ ;
+
+ $context
+ ->expects($this->at(2))
+ ->method('createQueue')
+ ->willReturn($routerQueue)
+ ;
+ $context
+ ->expects($this->at(3))
+ ->method('declareQueue')
+ ->with($this->identicalTo($routerQueue))
+ ;
+
+ $context
+ ->expects($this->at(4))
+ ->method('bind')
+ ->with($this->isInstanceOf(AmqpBind::class))
+ ;
+
+ // setup processor with default queue
+ $context
+ ->expects($this->at(5))
+ ->method('createQueue')
+ ->with($this->getDefaultQueueTransportName())
+ ->willReturn($processorWithDefaultQueue)
+ ;
+ $context
+ ->expects($this->at(6))
+ ->method('declareQueue')
+ ->with($this->identicalTo($processorWithDefaultQueue))
+ ;
+
+ $context
+ ->expects($this->at(7))
+ ->method('createQueue')
+ ->with($this->getCustomQueueTransportName())
+ ->willReturn($processorWithCustomQueue)
+ ;
+ $context
+ ->expects($this->at(8))
+ ->method('declareQueue')
+ ->with($this->identicalTo($processorWithCustomQueue))
+ ;
+
+ $driver = new AmqpDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([
+ new Route('aTopic', Route::TOPIC, 'aProcessor'),
+ new Route('aCommand', Route::COMMAND, 'aProcessor', ['queue' => 'custom']),
+ ])
+ );
+ $driver->setupBroker();
+ }
+
+ public function testShouldNotDeclareSameQueues()
+ {
+ $context = $this->createContextMock();
+
+ // setup processor with default queue
+ $context
+ ->expects($this->any())
+ ->method('createTopic')
+ ->willReturn($this->createTopic(''))
+ ;
+ $context
+ ->expects($this->any())
+ ->method('createQueue')
+ ->willReturn($this->createQueue('custom'))
+ ;
+ $context
+ ->expects($this->exactly(2))
+ ->method('declareQueue')
+ ;
+
+ $driver = new AmqpDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([
+ new Route('aTopic', Route::TOPIC, 'aProcessor', ['queue' => 'custom']),
+ new Route('aCommand', Route::COMMAND, 'aProcessor', ['queue' => 'custom']),
+ ])
+ );
+ $driver->setupBroker();
+ }
+
+ protected function createDriver(...$args): DriverInterface
+ {
+ return new AmqpDriver(...$args);
+ }
+
+ /**
+ * @return AmqpContext
+ */
+ protected function createContextMock(): Context
+ {
+ return $this->createMock(AmqpContext::class);
+ }
+
+ /**
+ * @return AmqpProducer
+ */
+ protected function createProducerMock(): InteropProducer
+ {
+ return $this->createMock(AmqpProducer::class);
+ }
+
+ /**
+ * @return AmqpQueue
+ */
+ protected function createQueue(string $name): InteropQueue
+ {
+ return new AmqpQueue($name);
+ }
+
+ protected function createTopic(string $name): AmqpTopic
+ {
+ return new AmqpTopic($name);
+ }
+
+ /**
+ * @return AmqpMessage
+ */
+ protected function createMessage(): InteropMessage
+ {
+ return new AmqpMessage();
+ }
+
+ protected function getRouterTransportName(): string
+ {
+ return 'aprefix.router';
+ }
+
+ protected function assertTransportMessage(InteropMessage $transportMessage): void
+ {
+ $this->assertSame('body', $transportMessage->getBody());
+ Assert::assertArraySubset([
+ 'hkey' => 'hval',
+ 'delivery_mode' => AmqpMessage::DELIVERY_MODE_PERSISTENT,
+ 'content_type' => 'ContentType',
+ 'expiration' => '123000',
+ 'priority' => 3,
+ 'message_id' => 'theMessageId',
+ 'timestamp' => 1000,
+ 'reply_to' => 'theReplyTo',
+ 'correlation_id' => 'theCorrelationId',
+ ], $transportMessage->getHeaders());
+ $this->assertEquals([
+ 'pkey' => 'pval',
+ Config::CONTENT_TYPE => 'ContentType',
+ Config::PRIORITY => MessagePriority::HIGH,
+ Config::EXPIRE => 123,
+ Config::DELAY => 345,
+ ], $transportMessage->getProperties());
+ $this->assertSame('theMessageId', $transportMessage->getMessageId());
+ $this->assertSame(1000, $transportMessage->getTimestamp());
+ $this->assertSame('theReplyTo', $transportMessage->getReplyTo());
+ $this->assertSame('theCorrelationId', $transportMessage->getCorrelationId());
+ }
+}
diff --git a/pkg/enqueue/Tests/Client/Driver/DbalDriverTest.php b/pkg/enqueue/Tests/Client/Driver/DbalDriverTest.php
new file mode 100644
index 000000000..554a399f9
--- /dev/null
+++ b/pkg/enqueue/Tests/Client/Driver/DbalDriverTest.php
@@ -0,0 +1,101 @@
+assertClassImplements(DriverInterface::class, DbalDriver::class);
+ }
+
+ public function testShouldBeSubClassOfGenericDriver()
+ {
+ $this->assertClassExtends(GenericDriver::class, DbalDriver::class);
+ }
+
+ public function testShouldSetupBroker()
+ {
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('getTableName')
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createDataBaseTable')
+ ;
+
+ $driver = new DbalDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([])
+ );
+
+ $driver->setupBroker();
+ }
+
+ protected function createDriver(...$args): DriverInterface
+ {
+ return new DbalDriver(...$args);
+ }
+
+ /**
+ * @return DbalContext
+ */
+ protected function createContextMock(): Context
+ {
+ return $this->createMock(DbalContext::class);
+ }
+
+ /**
+ * @return DbalProducer
+ */
+ protected function createProducerMock(): InteropProducer
+ {
+ return $this->createMock(DbalProducer::class);
+ }
+
+ /**
+ * @return DbalDestination
+ */
+ protected function createQueue(string $name): InteropQueue
+ {
+ return new DbalDestination($name);
+ }
+
+ /**
+ * @return DbalDestination
+ */
+ protected function createTopic(string $name): InteropTopic
+ {
+ return new DbalDestination($name);
+ }
+
+ /**
+ * @return DbalMessage
+ */
+ protected function createMessage(): InteropMessage
+ {
+ return new DbalMessage();
+ }
+}
diff --git a/pkg/enqueue/Tests/Client/Driver/FsDriverTest.php b/pkg/enqueue/Tests/Client/Driver/FsDriverTest.php
new file mode 100644
index 000000000..f1cd02f9b
--- /dev/null
+++ b/pkg/enqueue/Tests/Client/Driver/FsDriverTest.php
@@ -0,0 +1,125 @@
+assertClassImplements(DriverInterface::class, FsDriver::class);
+ }
+
+ public function testShouldBeSubClassOfGenericDriver()
+ {
+ $this->assertClassExtends(GenericDriver::class, FsDriver::class);
+ }
+
+ public function testShouldSetupBroker()
+ {
+ $routerQueue = new FsDestination(TempFile::generate());
+
+ $processorQueue = new FsDestination(TempFile::generate());
+
+ $context = $this->createContextMock();
+ // setup router
+ $context
+ ->expects($this->at(0))
+ ->method('createQueue')
+ ->willReturn($routerQueue)
+ ;
+ $context
+ ->expects($this->at(1))
+ ->method('declareDestination')
+ ->with($this->identicalTo($routerQueue))
+ ;
+ // setup processor queue
+ $context
+ ->expects($this->at(2))
+ ->method('createQueue')
+ ->willReturn($processorQueue)
+ ;
+ $context
+ ->expects($this->at(3))
+ ->method('declareDestination')
+ ->with($this->identicalTo($processorQueue))
+ ;
+
+ $routeCollection = new RouteCollection([
+ new Route('aTopic', Route::TOPIC, 'aProcessor'),
+ ]);
+
+ $driver = new FsDriver(
+ $context,
+ $this->createDummyConfig(),
+ $routeCollection
+ );
+
+ $driver->setupBroker();
+ }
+
+ protected function createDriver(...$args): DriverInterface
+ {
+ return new FsDriver(...$args);
+ }
+
+ /**
+ * @return FsContext
+ */
+ protected function createContextMock(): Context
+ {
+ return $this->createMock(FsContext::class);
+ }
+
+ /**
+ * @return FsProducer
+ */
+ protected function createProducerMock(): InteropProducer
+ {
+ return $this->createMock(FsProducer::class);
+ }
+
+ /**
+ * @return FsDestination
+ */
+ protected function createQueue(string $name): InteropQueue
+ {
+ return new FsDestination(new \SplFileInfo($name));
+ }
+
+ /**
+ * @return FsDestination
+ */
+ protected function createTopic(string $name): InteropTopic
+ {
+ return new FsDestination(new \SplFileInfo($name));
+ }
+
+ /**
+ * @return FsMessage
+ */
+ protected function createMessage(): InteropMessage
+ {
+ return new FsMessage();
+ }
+}
diff --git a/pkg/enqueue/Tests/Client/Driver/GenericDriverTest.php b/pkg/enqueue/Tests/Client/Driver/GenericDriverTest.php
new file mode 100644
index 000000000..78f7f6e83
--- /dev/null
+++ b/pkg/enqueue/Tests/Client/Driver/GenericDriverTest.php
@@ -0,0 +1,83 @@
+assertClassImplements(DriverInterface::class, GenericDriver::class);
+ }
+
+ protected function createDriver(...$args): DriverInterface
+ {
+ return new GenericDriver(...$args);
+ }
+
+ protected function createContextMock(): Context
+ {
+ return $this->createMock(Context::class);
+ }
+
+ protected function createProducerMock(): InteropProducer
+ {
+ return $this->createMock(InteropProducer::class);
+ }
+
+ protected function createQueue(string $name): InteropQueue
+ {
+ return new NullQueue($name);
+ }
+
+ protected function createTopic(string $name): InteropTopic
+ {
+ return new NullTopic($name);
+ }
+
+ protected function createMessage(): InteropMessage
+ {
+ return new NullMessage();
+ }
+
+ protected function assertTransportMessage(InteropMessage $transportMessage): void
+ {
+ $this->assertSame('body', $transportMessage->getBody());
+ Assert::assertArraySubset([
+ 'hkey' => 'hval',
+ 'message_id' => 'theMessageId',
+ 'timestamp' => 1000,
+ 'reply_to' => 'theReplyTo',
+ 'correlation_id' => 'theCorrelationId',
+ ], $transportMessage->getHeaders());
+ $this->assertEquals([
+ 'pkey' => 'pval',
+ Config::CONTENT_TYPE => 'ContentType',
+ Config::PRIORITY => MessagePriority::HIGH,
+ Config::EXPIRE => 123,
+ Config::DELAY => 345,
+ ], $transportMessage->getProperties());
+ $this->assertSame('theMessageId', $transportMessage->getMessageId());
+ $this->assertSame(1000, $transportMessage->getTimestamp());
+ $this->assertSame('theReplyTo', $transportMessage->getReplyTo());
+ $this->assertSame('theCorrelationId', $transportMessage->getCorrelationId());
+ }
+}
diff --git a/pkg/enqueue/Tests/Client/Driver/GenericDriverTestsTrait.php b/pkg/enqueue/Tests/Client/Driver/GenericDriverTestsTrait.php
new file mode 100644
index 000000000..d5ad498a9
--- /dev/null
+++ b/pkg/enqueue/Tests/Client/Driver/GenericDriverTestsTrait.php
@@ -0,0 +1,1249 @@
+createDriver(
+ $this->createContextMock(),
+ $this->createDummyConfig(),
+ new RouteCollection([])
+ );
+
+ $this->assertInstanceOf(DriverInterface::class, $driver);
+ }
+
+ public function testShouldReturnContextSetInConstructor()
+ {
+ $context = $this->createContextMock();
+
+ $driver = $this->createDriver($context, $this->createDummyConfig(), new RouteCollection([]));
+
+ $this->assertSame($context, $driver->getContext());
+ }
+
+ public function testShouldReturnConfigObjectSetInConstructor()
+ {
+ $config = $this->createDummyConfig();
+
+ $driver = $this->createDriver($this->createContextMock(), $config, new RouteCollection([]));
+
+ $this->assertSame($config, $driver->getConfig());
+ }
+
+ public function testShouldReturnRouteCollectionSetInConstructor()
+ {
+ $routeCollection = new RouteCollection([]);
+
+ /** @var DriverInterface $driver */
+ $driver = $this->createDriver($this->createContextMock(), $this->createDummyConfig(), $routeCollection);
+
+ $this->assertSame($routeCollection, $driver->getRouteCollection());
+ }
+
+ public function testShouldCreateAndReturnQueueInstanceWithPrefixAndAppName()
+ {
+ $expectedQueue = $this->createQueue('aName');
+
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createQueue')
+ ->with($this->getPrefixAppFooQueueTransportName())
+ ->willReturn($expectedQueue)
+ ;
+
+ $config = new Config(
+ 'aPrefix',
+ '.',
+ 'anAppName',
+ 'aRouterTopicName',
+ 'aRouterQueueName',
+ 'aDefaultQueue',
+ 'aRouterProcessor',
+ [],
+ []
+ );
+
+ $driver = $this->createDriver($context, $config, new RouteCollection([]));
+
+ $queue = $driver->createQueue('aFooQueue');
+
+ $this->assertSame($expectedQueue, $queue);
+ }
+
+ public function testShouldCreateAndReturnQueueInstanceWithPrefixWithoutAppName()
+ {
+ $expectedQueue = $this->createQueue('aName');
+
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createQueue')
+ ->with($this->getPrefixFooQueueTransportName())
+ ->willReturn($expectedQueue)
+ ;
+
+ $config = new Config(
+ 'aPrefix',
+ '.',
+ '',
+ 'aRouterTopicName',
+ 'aRouterQueueName',
+ 'aDefaultQueue',
+ 'aRouterProcessor',
+ [],
+ []
+ );
+
+ $driver = $this->createDriver($context, $config, new RouteCollection([]));
+
+ $queue = $driver->createQueue('aFooQueue');
+
+ $this->assertSame($expectedQueue, $queue);
+ }
+
+ public function testShouldCreateAndReturnQueueInstanceWithAppNameAndWithoutPrefix()
+ {
+ $expectedQueue = $this->createQueue('aName');
+
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createQueue')
+ ->with($this->getAppFooQueueTransportName())
+ ->willReturn($expectedQueue)
+ ;
+
+ $config = new Config(
+ '',
+ '.',
+ 'anAppName',
+ 'aRouterTopicName',
+ 'aRouterQueueName',
+ 'aDefaultQueue',
+ 'aRouterProcessor',
+ [],
+ []
+ );
+
+ $driver = $this->createDriver($context, $config, new RouteCollection([]));
+
+ $queue = $driver->createQueue('aFooQueue');
+
+ $this->assertSame($expectedQueue, $queue);
+ }
+
+ public function testShouldCreateAndReturnQueueInstanceWithoutPrefixAndAppName()
+ {
+ $expectedQueue = $this->createQueue('aName');
+
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createQueue')
+ ->with('afooqueue')
+ ->willReturn($expectedQueue)
+ ;
+
+ $config = new Config(
+ '',
+ '.',
+ '',
+ 'aRouterTopicName',
+ 'aRouterQueueName',
+ 'aDefaultQueue',
+ 'aRouterProcessor',
+ [],
+ []
+ );
+
+ $driver = $this->createDriver($context, $config, new RouteCollection([]));
+
+ $queue = $driver->createQueue('aFooQueue');
+
+ $this->assertSame($expectedQueue, $queue);
+ }
+
+ public function testShouldCreateAndReturnQueueInstance()
+ {
+ $expectedQueue = $this->createQueue('aName');
+
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createQueue')
+ ->with($this->getPrefixFooQueueTransportName())
+ ->willReturn($expectedQueue)
+ ;
+
+ $driver = $this->createDriver($context, $this->createDummyConfig(), new RouteCollection([]));
+
+ $queue = $driver->createQueue('aFooQueue');
+
+ $this->assertSame($expectedQueue, $queue);
+ }
+
+ public function testShouldCreateClientMessageFromTransportOne()
+ {
+ $transportMessage = $this->createMessage();
+ $transportMessage->setBody('body');
+ $transportMessage->setHeaders(['hkey' => 'hval']);
+ $transportMessage->setProperty('pkey', 'pval');
+ $transportMessage->setProperty(Config::CONTENT_TYPE, 'theContentType');
+ $transportMessage->setProperty(Config::EXPIRE, '22');
+ $transportMessage->setProperty(Config::PRIORITY, MessagePriority::HIGH);
+ $transportMessage->setProperty('enqueue.delay', '44');
+ $transportMessage->setMessageId('theMessageId');
+ $transportMessage->setTimestamp(1000);
+ $transportMessage->setReplyTo('theReplyTo');
+ $transportMessage->setCorrelationId('theCorrelationId');
+
+ $driver = $this->createDriver(
+ $this->createContextMock(),
+ $this->createDummyConfig(),
+ new RouteCollection([])
+ );
+
+ $clientMessage = $driver->createClientMessage($transportMessage);
+
+ $this->assertClientMessage($clientMessage);
+ }
+
+ public function testShouldCreateTransportMessageFromClientOne()
+ {
+ $clientMessage = new Message();
+ $clientMessage->setBody('body');
+ $clientMessage->setHeaders(['hkey' => 'hval']);
+ $clientMessage->setProperties(['pkey' => 'pval']);
+ $clientMessage->setContentType('ContentType');
+ $clientMessage->setExpire(123);
+ $clientMessage->setDelay(345);
+ $clientMessage->setPriority(MessagePriority::HIGH);
+ $clientMessage->setMessageId('theMessageId');
+ $clientMessage->setTimestamp(1000);
+ $clientMessage->setReplyTo('theReplyTo');
+ $clientMessage->setCorrelationId('theCorrelationId');
+
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($this->createMessage())
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([])
+ );
+
+ $transportMessage = $driver->createTransportMessage($clientMessage);
+
+ $this->assertTransportMessage($transportMessage);
+ }
+
+ public function testShouldSendMessageToRouter()
+ {
+ $transportMessage = $this->createMessage();
+
+ $producer = $this->createProducerMock();
+ $producer
+ ->expects($this->once())
+ ->method('send')
+ ->willReturnCallback(function (Destination $topic, InteropMessage $message) use ($transportMessage) {
+ $this->assertSame(
+ $this->getRouterTransportName(),
+ $topic instanceof InteropTopic ? $topic->getTopicName() : $topic->getQueueName());
+ $this->assertSame($transportMessage, $message);
+ })
+ ;
+ $context = $this->createContextStub();
+ $context
+ ->expects($this->once())
+ ->method('createProducer')
+ ->willReturn($producer)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($transportMessage)
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([])
+ );
+
+ $message = new Message();
+ $message->setProperty(Config::TOPIC, 'topic');
+
+ $driver->sendToRouter($message);
+ }
+
+ public function testShouldNotInitDeliveryDelayOnSendMessageToRouter()
+ {
+ $transportMessage = $this->createMessage();
+
+ $producer = $this->createProducerMock();
+ $producer
+ ->expects($this->once())
+ ->method('send')
+ ;
+ $producer
+ ->expects($this->never())
+ ->method('setDeliveryDelay')
+ ;
+
+ $context = $this->createContextStub();
+ $context
+ ->expects($this->once())
+ ->method('createProducer')
+ ->willReturn($producer)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($transportMessage)
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([])
+ );
+
+ $message = new Message();
+ $message->setDelay(456);
+ $message->setProperty(Config::TOPIC, 'topic');
+
+ $driver->sendToRouter($message);
+ }
+
+ public function testShouldNotInitTimeToLiveOnSendMessageToRouter()
+ {
+ $transportMessage = $this->createMessage();
+
+ $producer = $this->createProducerMock();
+ $producer
+ ->expects($this->once())
+ ->method('send')
+ ;
+ $producer
+ ->expects($this->never())
+ ->method('setTimeToLive')
+ ;
+
+ $context = $this->createContextStub();
+ $context
+ ->expects($this->once())
+ ->method('createProducer')
+ ->willReturn($producer)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($transportMessage)
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([])
+ );
+
+ $message = new Message();
+ $message->setExpire(456);
+ $message->setProperty(Config::TOPIC, 'topic');
+
+ $driver->sendToRouter($message);
+ }
+
+ public function testShouldNotInitPriorityOnSendMessageToRouter()
+ {
+ $transportMessage = $this->createMessage();
+
+ $producer = $this->createProducerMock();
+ $producer
+ ->expects($this->once())
+ ->method('send')
+ ;
+ $producer
+ ->expects($this->never())
+ ->method('setPriority')
+ ;
+
+ $context = $this->createContextStub();
+ $context
+ ->expects($this->once())
+ ->method('createProducer')
+ ->willReturn($producer)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($transportMessage)
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([])
+ );
+
+ $message = new Message();
+ $message->setPriority(MessagePriority::HIGH);
+ $message->setProperty(Config::TOPIC, 'topic');
+
+ $driver->sendToRouter($message);
+ }
+
+ public function testThrowIfTopicIsNotSetOnSendToRouter()
+ {
+ $driver = $this->createDriver(
+ $this->createContextMock(),
+ $this->createDummyConfig(),
+ new RouteCollection([])
+ );
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Topic name parameter is required but is not set');
+
+ $driver->sendToRouter(new Message());
+ }
+
+ public function testThrowIfCommandSetOnSendToRouter()
+ {
+ $driver = $this->createDriver(
+ $this->createContextMock(),
+ $this->createDummyConfig(),
+ new RouteCollection([])
+ );
+
+ $message = new Message();
+ $message->setProperty(Config::COMMAND, 'aCommand');
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Command must not be send to router but go directly to its processor.');
+
+ $driver->sendToRouter($message);
+ }
+
+ public function testShouldSendMessageToRouterProcessor()
+ {
+ $queue = $this->createQueue('');
+ $transportMessage = $this->createMessage();
+
+ $producer = $this->createProducerMock();
+ $producer
+ ->expects($this->once())
+ ->method('send')
+ ->with($this->identicalTo($queue), $this->identicalTo($transportMessage))
+ ;
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createQueue')
+ ->with($this->getDefaultQueueTransportName())
+ ->willReturn($queue)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createProducer')
+ ->willReturn($producer)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($transportMessage)
+ ;
+
+ $config = $this->createDummyConfig();
+
+ $driver = $this->createDriver(
+ $context,
+ $config,
+ new RouteCollection([
+ new Route('topic', Route::TOPIC, 'processor', [
+ 'queue' => 'custom',
+ ]),
+ ])
+ );
+
+ $message = new Message();
+ $message->setProperty(Config::TOPIC, 'topic');
+ $message->setProperty(Config::PROCESSOR, $config->getRouterProcessor());
+
+ $driver->sendToProcessor($message);
+ }
+
+ public function testShouldSendTopicMessageToProcessorToDefaultQueue()
+ {
+ $queue = $this->createQueue('');
+ $transportMessage = $this->createMessage();
+
+ $producer = $this->createProducerMock();
+ $producer
+ ->expects($this->once())
+ ->method('send')
+ ->with($this->identicalTo($queue), $this->identicalTo($transportMessage))
+ ;
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createQueue')
+ ->with($this->getDefaultQueueTransportName())
+ ->willReturn($queue)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createProducer')
+ ->willReturn($producer)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($transportMessage)
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([
+ new Route('topic', Route::TOPIC, 'processor'),
+ ])
+ );
+
+ $message = new Message();
+ $message->setProperty(Config::TOPIC, 'topic');
+ $message->setProperty(Config::PROCESSOR, 'processor');
+
+ $driver->sendToProcessor($message);
+ }
+
+ public function testShouldSendTopicMessageToProcessorToCustomQueue()
+ {
+ $queue = $this->createQueue('');
+ $transportMessage = $this->createMessage();
+
+ $producer = $this->createProducerMock();
+ $producer
+ ->expects($this->once())
+ ->method('send')
+ ->with($this->identicalTo($queue), $this->identicalTo($transportMessage))
+ ;
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createQueue')
+ ->with($this->getCustomQueueTransportName())
+ ->willReturn($queue)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createProducer')
+ ->willReturn($producer)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($transportMessage)
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([
+ new Route('topic', Route::TOPIC, 'processor', ['queue' => 'custom']),
+ ])
+ );
+
+ $message = new Message();
+ $message->setProperty(Config::TOPIC, 'topic');
+ $message->setProperty(Config::PROCESSOR, 'processor');
+
+ $driver->sendToProcessor($message);
+ }
+
+ public function testShouldInitDeliveryDelayIfDelayPropertyOnSendToProcessor()
+ {
+ $queue = $this->createQueue('');
+ $transportMessage = $this->createMessage();
+
+ $producer = $this->createProducerMock();
+ $producer
+ ->expects($this->once())
+ ->method('setDeliveryDelay')
+ ->with(456000)
+ ;
+ $producer
+ ->expects($this->once())
+ ->method('send')
+ ->with($this->identicalTo($queue), $this->identicalTo($transportMessage))
+ ;
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createQueue')
+ ->with($this->getDefaultQueueTransportName())
+ ->willReturn($queue)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createProducer')
+ ->willReturn($producer)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($transportMessage)
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([
+ new Route('topic', Route::TOPIC, 'processor'),
+ ])
+ );
+
+ $message = new Message();
+ $message->setDelay(456);
+ $message->setProperty(Config::TOPIC, 'topic');
+ $message->setProperty(Config::PROCESSOR, 'processor');
+
+ $driver->sendToProcessor($message);
+ }
+
+ public function testShouldSetInitTimeToLiveIfExpirePropertyOnSendToProcessor()
+ {
+ $queue = $this->createQueue('');
+ $transportMessage = $this->createMessage();
+
+ $producer = $this->createProducerMock();
+ $producer
+ ->expects($this->once())
+ ->method('setTimeToLive')
+ ->with(678000)
+ ;
+ $producer
+ ->expects($this->once())
+ ->method('send')
+ ->with($this->identicalTo($queue), $this->identicalTo($transportMessage))
+ ;
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createQueue')
+ ->with($this->getDefaultQueueTransportName())
+ ->willReturn($queue)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createProducer')
+ ->willReturn($producer)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($transportMessage)
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([
+ new Route('topic', Route::TOPIC, 'processor'),
+ ])
+ );
+
+ $message = new Message();
+ $message->setExpire(678);
+ $message->setProperty(Config::TOPIC, 'topic');
+ $message->setProperty(Config::PROCESSOR, 'processor');
+
+ $driver->sendToProcessor($message);
+ }
+
+ public function testShouldSetInitPriorityIfPriorityPropertyOnSendToProcessor()
+ {
+ $queue = $this->createQueue('');
+ $transportMessage = $this->createMessage();
+
+ $producer = $this->createProducerMock();
+ $producer
+ ->expects($this->once())
+ ->method('setPriority')
+ ->with(3)
+ ;
+ $producer
+ ->expects($this->once())
+ ->method('send')
+ ->with($this->identicalTo($queue), $this->identicalTo($transportMessage))
+ ;
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createQueue')
+ ->with($this->getDefaultQueueTransportName())
+ ->willReturn($queue)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createProducer')
+ ->willReturn($producer)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($transportMessage)
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([
+ new Route('topic', Route::TOPIC, 'processor'),
+ ])
+ );
+
+ $message = new Message();
+ $message->setPriority(MessagePriority::HIGH);
+ $message->setProperty(Config::TOPIC, 'topic');
+ $message->setProperty(Config::PROCESSOR, 'processor');
+
+ $driver->sendToProcessor($message);
+ }
+
+ public function testThrowIfNoRouteFoundForTopicMessageOnSendToProcessor()
+ {
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->never())
+ ->method('createProducer')
+ ;
+ $context
+ ->expects($this->never())
+ ->method('createMessage')
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([])
+ );
+
+ $message = new Message();
+ $message->setProperty(Config::TOPIC, 'topic');
+ $message->setProperty(Config::PROCESSOR, 'processor');
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('There is no route for topic "topic" and processor "processor"');
+ $driver->sendToProcessor($message);
+ }
+
+ public function testShouldSetRouterProcessorIfProcessorPropertyEmptyOnSendToProcessor()
+ {
+ $queue = $this->createQueue('');
+ $transportMessage = $this->createMessage();
+
+ $producer = $this->createProducerMock();
+ $producer
+ ->expects($this->once())
+ ->method('send')
+ ->with($this->identicalTo($queue), $this->identicalTo($transportMessage))
+ ;
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createQueue')
+ ->with($this->getDefaultQueueTransportName())
+ ->willReturn($queue)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createProducer')
+ ->willReturn($producer)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($transportMessage)
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([
+ new Route('topic', Route::TOPIC, 'expectedProcessor'),
+ ])
+ );
+
+ $message = new Message();
+ $message->setProperty(Config::TOPIC, 'topic');
+
+ $driver->sendToProcessor($message);
+
+ $this->assertSame('router', $message->getProperty(Config::PROCESSOR));
+ }
+
+ public function testShouldSendCommandMessageToProcessorToDefaultQueue()
+ {
+ $queue = $this->createQueue('');
+ $transportMessage = $this->createMessage();
+
+ $producer = $this->createProducerMock();
+ $producer
+ ->expects($this->once())
+ ->method('send')
+ ->with($this->identicalTo($queue), $this->identicalTo($transportMessage))
+ ;
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createQueue')
+ ->with($this->getDefaultQueueTransportName())
+ ->willReturn($queue)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createProducer')
+ ->willReturn($producer)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($transportMessage)
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([
+ new Route('command', Route::COMMAND, 'processor'),
+ ])
+ );
+
+ $message = new Message();
+ $message->setProperty(Config::COMMAND, 'command');
+ $message->setProperty(Config::PROCESSOR, 'processor');
+
+ $driver->sendToProcessor($message);
+ }
+
+ public function testShouldSendCommandMessageToProcessorToCustomQueue()
+ {
+ $queue = $this->createQueue('');
+ $transportMessage = $this->createMessage();
+
+ $producer = $this->createProducerMock();
+ $producer
+ ->expects($this->once())
+ ->method('send')
+ ->with($this->identicalTo($queue), $this->identicalTo($transportMessage))
+ ;
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createQueue')
+ ->with($this->getCustomQueueTransportName())
+ ->willReturn($queue)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createProducer')
+ ->willReturn($producer)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($transportMessage)
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([
+ new Route('command', Route::COMMAND, 'processor', ['queue' => 'custom']),
+ ])
+ );
+
+ $message = new Message();
+ $message->setProperty(Config::COMMAND, 'command');
+ $message->setProperty(Config::PROCESSOR, 'processor');
+
+ $driver->sendToProcessor($message);
+ }
+
+ public function testThrowIfNoRouteFoundForCommandMessageOnSendToProcessor()
+ {
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->never())
+ ->method('createProducer')
+ ;
+ $context
+ ->expects($this->never())
+ ->method('createMessage')
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([])
+ );
+
+ $message = new Message();
+ $message->setProperty(Config::COMMAND, 'command');
+ $message->setProperty(Config::PROCESSOR, 'processor');
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('There is no route for command "command".');
+ $driver->sendToProcessor($message);
+ }
+
+ public function testShouldOverwriteProcessorPropertySetByOneFromCommandRouteOnSendToProcessor()
+ {
+ $queue = $this->createQueue('');
+ $transportMessage = $this->createMessage();
+
+ $producer = $this->createProducerMock();
+ $producer
+ ->expects($this->once())
+ ->method('send')
+ ->with($this->identicalTo($queue), $this->identicalTo($transportMessage))
+ ;
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createQueue')
+ ->with($this->getCustomQueueTransportName())
+ ->willReturn($queue)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createProducer')
+ ->willReturn($producer)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($transportMessage)
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([
+ new Route('command', Route::COMMAND, 'expectedProcessor', ['queue' => 'custom']),
+ ])
+ );
+
+ $message = new Message();
+ $message->setProperty(Config::COMMAND, 'command');
+ $message->setProperty(Config::PROCESSOR, 'processorShouldBeOverwritten');
+
+ $driver->sendToProcessor($message);
+
+ $this->assertSame('expectedProcessor', $message->getProperty(Config::PROCESSOR));
+ }
+
+ public function testShouldNotInitDeliveryDelayOnSendMessageToProcessorIfPropertyNull()
+ {
+ $queue = $this->createQueue('');
+ $transportMessage = $this->createMessage();
+
+ $producer = $this->createProducerMock();
+ $producer
+ ->expects($this->never())
+ ->method('setDeliveryDelay')
+ ;
+ $producer
+ ->expects($this->once())
+ ->method('send')
+ ;
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createQueue')
+ ->willReturn($queue)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createProducer')
+ ->willReturn($producer)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($transportMessage)
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([
+ new Route('command', Route::COMMAND, 'expectedProcessor', ['queue' => 'custom']),
+ ])
+ );
+
+ $message = new Message();
+ $message->setProperty(Config::COMMAND, 'command');
+ $message->setDelay(null);
+
+ $driver->sendToProcessor($message);
+ }
+
+ public function testShouldNotInitPriorityOnSendMessageToProcessorIfPropertyNull()
+ {
+ $queue = $this->createQueue('');
+ $transportMessage = $this->createMessage();
+
+ $producer = $this->createProducerMock();
+ $producer
+ ->expects($this->never())
+ ->method('setPriority')
+ ;
+ $producer
+ ->expects($this->once())
+ ->method('send')
+ ;
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createQueue')
+ ->willReturn($queue)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createProducer')
+ ->willReturn($producer)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($transportMessage)
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([
+ new Route('command', Route::COMMAND, 'expectedProcessor', ['queue' => 'custom']),
+ ])
+ );
+
+ $message = new Message();
+ $message->setProperty(Config::COMMAND, 'command');
+ $message->setPriority(null);
+
+ $driver->sendToProcessor($message);
+ }
+
+ public function testShouldNotInitTimeToLiveOnSendMessageToProcessorIfPropertyNull()
+ {
+ $queue = $this->createQueue('');
+ $transportMessage = $this->createMessage();
+
+ $producer = $this->createProducerMock();
+ $producer
+ ->expects($this->never())
+ ->method('setTimeToLive')
+ ;
+ $producer
+ ->expects($this->once())
+ ->method('send')
+ ;
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createQueue')
+ ->willReturn($queue)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createProducer')
+ ->willReturn($producer)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($transportMessage)
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([
+ new Route('command', Route::COMMAND, 'expectedProcessor', ['queue' => 'custom']),
+ ])
+ );
+
+ $message = new Message();
+ $message->setProperty(Config::COMMAND, 'command');
+ $message->setExpire(null);
+
+ $driver->sendToProcessor($message);
+ }
+
+ public function testThrowIfNeitherTopicNorCommandAreSentOnSendToProcessor()
+ {
+ $driver = $this->createDriver(
+ $this->createContextMock(),
+ $this->createDummyConfig(),
+ new RouteCollection([])
+ );
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Queue name parameter is required but is not set');
+
+ $message = new Message();
+ $message->setProperty(Config::PROCESSOR, 'processor');
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Either topic or command parameter must be set.');
+ $driver->sendToProcessor($message);
+ }
+
+ abstract protected function createDriver(...$args): DriverInterface;
+
+ /**
+ * @return \PHPUnit\Framework\MockObject\MockObject
+ */
+ abstract protected function createContextMock(): Context;
+
+ /**
+ * @return \PHPUnit\Framework\MockObject\MockObject
+ */
+ abstract protected function createProducerMock(): InteropProducer;
+
+ abstract protected function createQueue(string $name): InteropQueue;
+
+ abstract protected function createTopic(string $name): InteropTopic;
+
+ abstract protected function createMessage(): InteropMessage;
+
+ /**
+ * @return \PHPUnit\Framework\MockObject\MockObject
+ */
+ protected function createContextStub(): Context
+ {
+ $context = $this->createContextMock();
+
+ $context
+ ->expects($this->any())
+ ->method('createQueue')
+ ->willReturnCallback(function (string $name) {
+ return $this->createQueue($name);
+ })
+ ;
+
+ $context
+ ->expects($this->any())
+ ->method('createTopic')
+ ->willReturnCallback(function (string $name) {
+ return $this->createTopic($name);
+ })
+ ;
+
+ return $context;
+ }
+
+ protected function assertTransportMessage(InteropMessage $transportMessage): void
+ {
+ $this->assertSame('body', $transportMessage->getBody());
+ $this->assertEquals([
+ 'hkey' => 'hval',
+ 'message_id' => 'theMessageId',
+ 'timestamp' => 1000,
+ 'reply_to' => 'theReplyTo',
+ 'correlation_id' => 'theCorrelationId',
+ ], $transportMessage->getHeaders());
+ $this->assertEquals([
+ 'pkey' => 'pval',
+ Config::CONTENT_TYPE => 'ContentType',
+ Config::PRIORITY => MessagePriority::HIGH,
+ Config::EXPIRE => 123,
+ Config::DELAY => 345,
+ ], $transportMessage->getProperties());
+ $this->assertSame('theMessageId', $transportMessage->getMessageId());
+ $this->assertSame(1000, $transportMessage->getTimestamp());
+ $this->assertSame('theReplyTo', $transportMessage->getReplyTo());
+ $this->assertSame('theCorrelationId', $transportMessage->getCorrelationId());
+ }
+
+ protected function assertClientMessage(Message $clientMessage): void
+ {
+ $this->assertSame('body', $clientMessage->getBody());
+ Assert::assertArraySubset([
+ 'hkey' => 'hval',
+ ], $clientMessage->getHeaders());
+ Assert::assertArraySubset([
+ 'pkey' => 'pval',
+ Config::CONTENT_TYPE => 'theContentType',
+ Config::EXPIRE => '22',
+ Config::PRIORITY => MessagePriority::HIGH,
+ Config::DELAY => '44',
+ ], $clientMessage->getProperties());
+ $this->assertSame('theMessageId', $clientMessage->getMessageId());
+ $this->assertSame(22, $clientMessage->getExpire());
+ $this->assertSame(44, $clientMessage->getDelay());
+ $this->assertSame(MessagePriority::HIGH, $clientMessage->getPriority());
+ $this->assertSame('theContentType', $clientMessage->getContentType());
+ $this->assertSame(1000, $clientMessage->getTimestamp());
+ $this->assertSame('theReplyTo', $clientMessage->getReplyTo());
+ $this->assertSame('theCorrelationId', $clientMessage->getCorrelationId());
+ }
+
+ protected function createDummyConfig(): Config
+ {
+ return Config::create('aPrefix');
+ }
+
+ protected function getDefaultQueueTransportName(): string
+ {
+ return 'aprefix.default';
+ }
+
+ protected function getCustomQueueTransportName(): string
+ {
+ return 'aprefix.custom';
+ }
+
+ protected function getRouterTransportName(): string
+ {
+ return 'aprefix.default';
+ }
+
+ protected function getPrefixAppFooQueueTransportName(): string
+ {
+ return 'aprefix.anappname.afooqueue';
+ }
+
+ protected function getPrefixFooQueueTransportName(): string
+ {
+ return 'aprefix.afooqueue';
+ }
+
+ protected function getAppFooQueueTransportName(): string
+ {
+ return 'anappname.afooqueue';
+ }
+}
diff --git a/pkg/enqueue/Tests/Client/Driver/GpsDriverTest.php b/pkg/enqueue/Tests/Client/Driver/GpsDriverTest.php
new file mode 100644
index 000000000..c0cac0458
--- /dev/null
+++ b/pkg/enqueue/Tests/Client/Driver/GpsDriverTest.php
@@ -0,0 +1,142 @@
+assertClassImplements(DriverInterface::class, GpsDriver::class);
+ }
+
+ public function testShouldBeSubClassOfGenericDriver()
+ {
+ $this->assertClassExtends(GenericDriver::class, GpsDriver::class);
+ }
+
+ public function testShouldSetupBroker()
+ {
+ $routerTopic = new GpsTopic('');
+ $routerQueue = new GpsQueue('');
+
+ $processorTopic = new GpsTopic($this->getDefaultQueueTransportName());
+ $processorQueue = new GpsQueue($this->getDefaultQueueTransportName());
+
+ $context = $this->createContextMock();
+ // setup router
+ $context
+ ->expects($this->at(0))
+ ->method('createTopic')
+ ->willReturn($routerTopic)
+ ;
+ $context
+ ->expects($this->at(1))
+ ->method('createQueue')
+ ->willReturn($routerQueue)
+ ;
+ $context
+ ->expects($this->at(2))
+ ->method('subscribe')
+ ->with($this->identicalTo($routerTopic), $this->identicalTo($routerQueue))
+ ;
+ $context
+ ->expects($this->at(3))
+ ->method('createQueue')
+ ->with($this->getDefaultQueueTransportName())
+ ->willReturn($processorQueue)
+ ;
+ // setup processor queue
+ $context
+ ->expects($this->at(4))
+ ->method('createTopic')
+ ->with($this->getDefaultQueueTransportName())
+ ->willReturn($processorTopic)
+ ;
+ $context
+ ->expects($this->at(5))
+ ->method('subscribe')
+ ->with($this->identicalTo($processorTopic), $this->identicalTo($processorQueue))
+ ;
+
+ $driver = new GpsDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([
+ new Route('aTopic', Route::TOPIC, 'aProcessor'),
+ ])
+ );
+
+ $driver->setupBroker();
+ }
+
+ protected function createDriver(...$args): DriverInterface
+ {
+ return new GpsDriver(...$args);
+ }
+
+ /**
+ * @return GpsContext
+ */
+ protected function createContextMock(): Context
+ {
+ return $this->createMock(GpsContext::class);
+ }
+
+ /**
+ * @return GpsProducer
+ */
+ protected function createProducerMock(): InteropProducer
+ {
+ return $this->createMock(GpsProducer::class);
+ }
+
+ /**
+ * @return GpsQueue
+ */
+ protected function createQueue(string $name): InteropQueue
+ {
+ return new GpsQueue($name);
+ }
+
+ /**
+ * @return GpsTopic
+ */
+ protected function createTopic(string $name): InteropTopic
+ {
+ return new GpsTopic($name);
+ }
+
+ /**
+ * @return GpsMessage
+ */
+ protected function createMessage(): InteropMessage
+ {
+ return new GpsMessage();
+ }
+
+ protected function getRouterTransportName(): string
+ {
+ return 'aprefix.router';
+ }
+}
diff --git a/pkg/enqueue/Tests/Client/Driver/MongodbDriverTest.php b/pkg/enqueue/Tests/Client/Driver/MongodbDriverTest.php
new file mode 100644
index 000000000..697c757d8
--- /dev/null
+++ b/pkg/enqueue/Tests/Client/Driver/MongodbDriverTest.php
@@ -0,0 +1,105 @@
+assertClassImplements(DriverInterface::class, MongodbDriver::class);
+ }
+
+ public function testShouldBeSubClassOfGenericDriver()
+ {
+ $this->assertClassExtends(GenericDriver::class, MongodbDriver::class);
+ }
+
+ public function testShouldSetupBroker()
+ {
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createCollection')
+ ;
+ $context
+ ->expects($this->once())
+ ->method('getConfig')
+ ->willReturn([
+ 'dbname' => 'aDb',
+ 'collection_name' => 'aCol',
+ ])
+ ;
+
+ $driver = new MongodbDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([])
+ );
+
+ $driver->setupBroker();
+ }
+
+ protected function createDriver(...$args): DriverInterface
+ {
+ return new MongodbDriver(...$args);
+ }
+
+ /**
+ * @return MongodbContext
+ */
+ protected function createContextMock(): Context
+ {
+ return $this->createMock(MongodbContext::class);
+ }
+
+ /**
+ * @return MongodbProducer
+ */
+ protected function createProducerMock(): InteropProducer
+ {
+ return $this->createMock(MongodbProducer::class);
+ }
+
+ /**
+ * @return MongodbDestination
+ */
+ protected function createQueue(string $name): InteropQueue
+ {
+ return new MongodbDestination($name);
+ }
+
+ /**
+ * @return MongodbDestination
+ */
+ protected function createTopic(string $name): InteropTopic
+ {
+ return new MongodbDestination($name);
+ }
+
+ /**
+ * @return MongodbMessage
+ */
+ protected function createMessage(): InteropMessage
+ {
+ return new MongodbMessage();
+ }
+}
diff --git a/pkg/enqueue/Tests/Client/Driver/RabbitMqDriverTest.php b/pkg/enqueue/Tests/Client/Driver/RabbitMqDriverTest.php
new file mode 100644
index 000000000..b209d85bc
--- /dev/null
+++ b/pkg/enqueue/Tests/Client/Driver/RabbitMqDriverTest.php
@@ -0,0 +1,139 @@
+assertClassImplements(DriverInterface::class, RabbitMqDriver::class);
+ }
+
+ public function testShouldBeSubClassOfGenericDriver()
+ {
+ $this->assertClassExtends(GenericDriver::class, RabbitMqDriver::class);
+ }
+
+ public function testShouldBeSubClassOfAmqpDriver()
+ {
+ $this->assertClassExtends(AmqpDriver::class, RabbitMqDriver::class);
+ }
+
+ public function testShouldCreateQueueWithMaxPriorityArgument()
+ {
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createQueue')
+ ->willReturn($this->createQueue('aName'))
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([])
+ );
+
+ /** @var AmqpQueue $queue */
+ $queue = $driver->createQueue('aName');
+
+ $this->assertSame(['x-max-priority' => 4], $queue->getArguments());
+ }
+
+ protected function createDriver(...$args): DriverInterface
+ {
+ return new RabbitMqDriver(...$args);
+ }
+
+ /**
+ * @return AmqpContext
+ */
+ protected function createContextMock(): Context
+ {
+ return $this->createMock(AmqpContext::class);
+ }
+
+ /**
+ * @return AmqpProducer
+ */
+ protected function createProducerMock(): InteropProducer
+ {
+ return $this->createMock(AmqpProducer::class);
+ }
+
+ /**
+ * @return AmqpQueue
+ */
+ protected function createQueue(string $name): InteropQueue
+ {
+ return new AmqpQueue($name);
+ }
+
+ protected function createTopic(string $name): AmqpTopic
+ {
+ return new AmqpTopic($name);
+ }
+
+ /**
+ * @return AmqpMessage
+ */
+ protected function createMessage(): InteropMessage
+ {
+ return new AmqpMessage();
+ }
+
+ protected function getRouterTransportName(): string
+ {
+ return 'aprefix.router';
+ }
+
+ protected function assertTransportMessage(InteropMessage $transportMessage): void
+ {
+ $this->assertSame('body', $transportMessage->getBody());
+ Assert::assertArraySubset([
+ 'hkey' => 'hval',
+ 'delivery_mode' => AmqpMessage::DELIVERY_MODE_PERSISTENT,
+ 'content_type' => 'ContentType',
+ 'expiration' => '123000',
+ 'priority' => 3,
+ 'message_id' => 'theMessageId',
+ 'timestamp' => 1000,
+ 'reply_to' => 'theReplyTo',
+ 'correlation_id' => 'theCorrelationId',
+ ], $transportMessage->getHeaders());
+ $this->assertEquals([
+ 'pkey' => 'pval',
+ Config::CONTENT_TYPE => 'ContentType',
+ Config::PRIORITY => MessagePriority::HIGH,
+ Config::EXPIRE => 123,
+ Config::DELAY => 345,
+ ], $transportMessage->getProperties());
+ $this->assertSame('theMessageId', $transportMessage->getMessageId());
+ $this->assertSame(1000, $transportMessage->getTimestamp());
+ $this->assertSame('theReplyTo', $transportMessage->getReplyTo());
+ $this->assertSame('theCorrelationId', $transportMessage->getCorrelationId());
+ }
+}
diff --git a/pkg/enqueue/Tests/Client/Driver/RabbitMqStompDriverTest.php b/pkg/enqueue/Tests/Client/Driver/RabbitMqStompDriverTest.php
new file mode 100644
index 000000000..9fc72be1e
--- /dev/null
+++ b/pkg/enqueue/Tests/Client/Driver/RabbitMqStompDriverTest.php
@@ -0,0 +1,590 @@
+assertClassImplements(DriverInterface::class, RabbitMqStompDriver::class);
+ }
+
+ public function testShouldBeSubClassOfGenericDriver()
+ {
+ $this->assertClassExtends(GenericDriver::class, RabbitMqStompDriver::class);
+ }
+
+ public function testShouldBeSubClassOfStompDriver()
+ {
+ $this->assertClassExtends(StompDriver::class, RabbitMqStompDriver::class);
+ }
+
+ public function testShouldCreateAndReturnStompQueueInstance()
+ {
+ $expectedQueue = new StompDestination(ExtensionType::RABBITMQ);
+
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createQueue')
+ ->with('aprefix.afooqueue')
+ ->willReturn($expectedQueue)
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([]),
+ $this->createManagementClientMock()
+ );
+
+ $queue = $driver->createQueue('aFooQueue');
+
+ $expectedHeaders = [
+ 'durable' => true,
+ 'auto-delete' => false,
+ 'exclusive' => false,
+ 'x-max-priority' => 4,
+ ];
+
+ $this->assertSame($expectedQueue, $queue);
+ $this->assertTrue($queue->isDurable());
+ $this->assertFalse($queue->isAutoDelete());
+ $this->assertFalse($queue->isExclusive());
+ $this->assertSame($expectedHeaders, $queue->getHeaders());
+ }
+
+ public function testThrowIfClientPriorityInvalidOnCreateTransportMessage()
+ {
+ $clientMessage = new Message();
+ $clientMessage->setPriority('unknown');
+
+ $transportMessage = new StompMessage();
+
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($transportMessage)
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([]),
+ $this->createManagementClientMock()
+ );
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Cant convert client priority to transport: "unknown"');
+
+ $driver->createTransportMessage($clientMessage);
+ }
+
+ public function testThrowIfDelayIsSetButDelayPluginInstalledOptionIsFalse()
+ {
+ $clientMessage = new Message();
+ $clientMessage->setDelay(123);
+
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn(new StompMessage())
+ ;
+
+ $config = Config::create(
+ 'aPrefix',
+ '.',
+ '',
+ null,
+ null,
+ null,
+ null,
+ ['delay_plugin_installed' => false]
+ );
+
+ $driver = $this->createDriver(
+ $context,
+ $config,
+ new RouteCollection([]),
+ $this->createManagementClientMock()
+ );
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('The message delaying is not supported. In order to use delay feature install RabbitMQ delay plugin.');
+
+ $driver->createTransportMessage($clientMessage);
+ }
+
+ public function testShouldSetXDelayHeaderIfDelayPluginInstalledOptionIsTrue()
+ {
+ $clientMessage = new Message();
+ $clientMessage->setDelay(123);
+
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn(new StompMessage())
+ ;
+
+ $config = Config::create(
+ 'aPrefix',
+ '.',
+ '',
+ null,
+ null,
+ null,
+ null,
+ ['delay_plugin_installed' => true]
+ );
+
+ $driver = $this->createDriver(
+ $context,
+ $config,
+ new RouteCollection([]),
+ $this->createManagementClientMock()
+ );
+
+ $transportMessage = $driver->createTransportMessage($clientMessage);
+
+ $this->assertSame('123000', $transportMessage->getHeader('x-delay'));
+ }
+
+ public function testShouldInitDeliveryDelayIfDelayPropertyOnSendToProcessor()
+ {
+ $this->shouldSendMessageToDelayExchangeIfDelaySet();
+ }
+
+ public function shouldSendMessageToDelayExchangeIfDelaySet()
+ {
+ $queue = new StompDestination(ExtensionType::RABBITMQ);
+ $queue->setStompName('queueName');
+
+ $delayTopic = new StompDestination(ExtensionType::RABBITMQ);
+ $delayTopic->setStompName('delayTopic');
+
+ $transportMessage = new StompMessage();
+
+ $producer = $this->createProducerMock();
+ $producer
+ ->expects($this->at(0))
+ ->method('setDeliveryDelay')
+ ->with(10000)
+ ;
+ $producer
+ ->expects($this->at(1))
+ ->method('setDeliveryDelay')
+ ->with(null)
+ ;
+ $producer
+ ->expects($this->once())
+ ->method('send')
+ ->with($this->identicalTo($delayTopic), $this->identicalTo($transportMessage))
+ ;
+
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createQueue')
+ ->willReturn($queue)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createTopic')
+ ->willReturn($delayTopic)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createProducer')
+ ->willReturn($producer)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($transportMessage)
+ ;
+
+ $config = Config::create(
+ 'aPrefix',
+ '.',
+ '',
+ null,
+ null,
+ null,
+ null,
+ ['delay_plugin_installed' => true]
+ );
+
+ $driver = $this->createDriver(
+ $context,
+ $config,
+ new RouteCollection([
+ new Route('topic', Route::TOPIC, 'processor'),
+ ]),
+ $this->createManagementClientMock()
+ );
+
+ $message = new Message();
+ $message->setProperty(Config::TOPIC, 'topic');
+ $message->setProperty(Config::PROCESSOR, 'processor');
+ $message->setDelay(10);
+
+ $driver->sendToProcessor($message);
+ }
+
+ public function testShouldNotSetupBrokerIfManagementPluginInstalledOptionIsNotEnabled()
+ {
+ $config = Config::create(
+ 'aPrefix',
+ '.',
+ '',
+ null,
+ null,
+ null,
+ null,
+ ['management_plugin_installed' => false]
+ );
+
+ $driver = $this->createDriver(
+ $this->createContextMock(),
+ $config,
+ new RouteCollection([]),
+ $this->createManagementClientMock()
+ );
+
+ $logger = new TestLogger();
+
+ $driver->setupBroker($logger);
+
+ self::assertTrue(
+ $logger->hasDebugThatContains(
+ '[RabbitMqStompDriver] Could not setup broker. The option `management_plugin_installed` is not enabled. Please enable that option and install rabbit management plugin'
+ )
+ );
+ }
+
+ public function testShouldSetupBroker()
+ {
+ $routeCollection = new RouteCollection([
+ new Route('topic', Route::TOPIC, 'processor'),
+ ]);
+
+ $managementClient = $this->createManagementClientMock();
+ $managementClient
+ ->expects($this->at(0))
+ ->method('declareExchange')
+ ->with('aprefix.router', [
+ 'type' => 'fanout',
+ 'durable' => true,
+ 'auto_delete' => false,
+ ])
+ ;
+ $managementClient
+ ->expects($this->at(1))
+ ->method('declareQueue')
+ ->with('aprefix.default', [
+ 'durable' => true,
+ 'auto_delete' => false,
+ 'arguments' => [
+ 'x-max-priority' => 4,
+ ],
+ ])
+ ;
+ $managementClient
+ ->expects($this->at(2))
+ ->method('bind')
+ ->with('aprefix.router', 'aprefix.default', 'aprefix.default')
+ ;
+ $managementClient
+ ->expects($this->at(3))
+ ->method('declareQueue')
+ ->with('aprefix.default', [
+ 'durable' => true,
+ 'auto_delete' => false,
+ 'arguments' => [
+ 'x-max-priority' => 4,
+ ],
+ ])
+ ;
+
+ $contextMock = $this->createContextMock();
+ $contextMock
+ ->expects($this->any())
+ ->method('createQueue')
+ ->willReturnCallback(function (string $name) {
+ $destination = new StompDestination(ExtensionType::RABBITMQ);
+ $destination->setType(StompDestination::TYPE_QUEUE);
+ $destination->setStompName($name);
+
+ return $destination;
+ })
+ ;
+
+ $config = Config::create(
+ 'aPrefix',
+ '.',
+ '',
+ null,
+ null,
+ null,
+ null,
+ ['delay_plugin_installed' => false, 'management_plugin_installed' => true]
+ );
+
+ $driver = $this->createDriver(
+ $contextMock,
+ $config,
+ $routeCollection,
+ $managementClient
+ );
+
+ $logger = new TestLogger();
+
+ $driver->setupBroker($logger);
+
+ self::assertTrue(
+ $logger->hasDebugThatContains(
+ '[RabbitMqStompDriver] Declare router exchange: aprefix.router'
+ )
+ );
+ self::assertTrue(
+ $logger->hasDebugThatContains(
+ '[RabbitMqStompDriver] Declare router queue: aprefix.default'
+ )
+ );
+ self::assertTrue(
+ $logger->hasDebugThatContains(
+ '[RabbitMqStompDriver] Bind router queue to exchange: aprefix.default -> aprefix.router'
+ )
+ );
+ self::assertTrue(
+ $logger->hasDebugThatContains(
+ '[RabbitMqStompDriver] Declare processor queue: aprefix.default'
+ )
+ );
+ }
+
+ public function testSetupBrokerShouldCreateDelayExchangeIfEnabled()
+ {
+ $routeCollection = new RouteCollection([
+ new Route('topic', Route::TOPIC, 'processor'),
+ ]);
+
+ $managementClient = $this->createManagementClientMock();
+ $managementClient
+ ->expects($this->at(4))
+ ->method('declareExchange')
+ ->with('aprefix.default.delayed', [
+ 'type' => 'x-delayed-message',
+ 'durable' => true,
+ 'auto_delete' => false,
+ 'arguments' => [
+ 'x-delayed-type' => 'direct',
+ ],
+ ])
+ ;
+ $managementClient
+ ->expects($this->at(5))
+ ->method('bind')
+ ->with('aprefix.default.delayed', 'aprefix.default', 'aprefix.default')
+ ;
+
+ $config = Config::create(
+ 'aPrefix',
+ '.',
+ '',
+ null,
+ null,
+ null,
+ null,
+ ['delay_plugin_installed' => true, 'management_plugin_installed' => true]
+ );
+
+ $contextMock = $this->createContextMock();
+ $contextMock
+ ->expects($this->any())
+ ->method('createQueue')
+ ->willReturnCallback(function (string $name) {
+ $destination = new StompDestination(ExtensionType::RABBITMQ);
+ $destination->setType(StompDestination::TYPE_QUEUE);
+ $destination->setStompName($name);
+
+ return $destination;
+ })
+ ;
+ $contextMock
+ ->expects($this->any())
+ ->method('createTopic')
+ ->willReturnCallback(function (string $name) {
+ $destination = new StompDestination(ExtensionType::RABBITMQ);
+ $destination->setType(StompDestination::TYPE_TOPIC);
+ $destination->setStompName($name);
+
+ return $destination;
+ })
+ ;
+
+ $driver = $this->createDriver(
+ $contextMock,
+ $config,
+ $routeCollection,
+ $managementClient
+ );
+
+ $logger = new TestLogger();
+
+ $driver->setupBroker($logger);
+
+ self::assertTrue(
+ $logger->hasDebugThatContains(
+ '[RabbitMqStompDriver] Declare delay exchange: aprefix.default.delayed'
+ )
+ );
+ self::assertTrue(
+ $logger->hasDebugThatContains(
+ '[RabbitMqStompDriver] Bind processor queue to delay exchange: aprefix.default -> aprefix.default.delayed'
+ )
+ );
+ }
+
+ protected function createDriver(...$args): DriverInterface
+ {
+ return new RabbitMqStompDriver(
+ $args[0],
+ $args[1],
+ $args[2],
+ isset($args[3]) ? $args[3] : $this->createManagementClientMock()
+ );
+ }
+
+ /**
+ * @return StompContext
+ */
+ protected function createContextMock(): Context
+ {
+ return $this->createMock(StompContext::class);
+ }
+
+ /**
+ * @return StompProducer
+ */
+ protected function createProducerMock(): InteropProducer
+ {
+ return $this->createMock(StompProducer::class);
+ }
+
+ /**
+ * @return StompDestination
+ */
+ protected function createQueue(string $name): InteropQueue
+ {
+ $destination = new StompDestination(ExtensionType::RABBITMQ);
+ $destination->setType(StompDestination::TYPE_QUEUE);
+ $destination->setStompName($name);
+
+ return $destination;
+ }
+
+ /**
+ * @return StompDestination
+ */
+ protected function createTopic(string $name): InteropTopic
+ {
+ $destination = new StompDestination(ExtensionType::RABBITMQ);
+ $destination->setType(StompDestination::TYPE_TOPIC);
+ $destination->setStompName($name);
+
+ return $destination;
+ }
+
+ /**
+ * @return StompMessage
+ */
+ protected function createMessage(): InteropMessage
+ {
+ return new StompMessage();
+ }
+
+ protected function assertTransportMessage(InteropMessage $transportMessage): void
+ {
+ $this->assertSame('body', $transportMessage->getBody());
+ $this->assertEquals([
+ 'hkey' => 'hval',
+ 'message_id' => 'theMessageId',
+ 'timestamp' => 1000,
+ 'reply-to' => 'theReplyTo',
+ 'persistent' => true,
+ 'correlation_id' => 'theCorrelationId',
+ 'expiration' => '123000',
+ 'priority' => 3,
+ 'x-delay' => '345000',
+ ], $transportMessage->getHeaders());
+ $this->assertEquals([
+ 'pkey' => 'pval',
+ Config::CONTENT_TYPE => 'ContentType',
+ Config::PRIORITY => MessagePriority::HIGH,
+ Config::EXPIRE => 123,
+ Config::DELAY => 345,
+ ], $transportMessage->getProperties());
+ $this->assertSame('theMessageId', $transportMessage->getMessageId());
+ $this->assertSame(1000, $transportMessage->getTimestamp());
+ $this->assertSame('theReplyTo', $transportMessage->getReplyTo());
+ $this->assertSame('theCorrelationId', $transportMessage->getCorrelationId());
+ }
+
+ protected function createDummyConfig(): Config
+ {
+ return Config::create(
+ 'aPrefix',
+ '.',
+ '',
+ null,
+ null,
+ null,
+ null,
+ ['delay_plugin_installed' => true, 'management_plugin_installed' => true]
+ );
+ }
+
+ protected function getRouterTransportName(): string
+ {
+ return '/topic/aprefix.router';
+ }
+
+ /**
+ * @return \PHPUnit\Framework\MockObject\MockObject
+ */
+ private function createManagementClientMock(): StompManagementClient
+ {
+ return $this->createMock(StompManagementClient::class);
+ }
+}
diff --git a/pkg/enqueue/Tests/Client/Driver/RdKafkaDriverTest.php b/pkg/enqueue/Tests/Client/Driver/RdKafkaDriverTest.php
new file mode 100644
index 000000000..c5e40e71d
--- /dev/null
+++ b/pkg/enqueue/Tests/Client/Driver/RdKafkaDriverTest.php
@@ -0,0 +1,122 @@
+assertClassImplements(DriverInterface::class, RdKafkaDriver::class);
+ }
+
+ public function testShouldBeSubClassOfGenericDriver()
+ {
+ $this->assertClassExtends(GenericDriver::class, RdKafkaDriver::class);
+ }
+
+ public function testShouldSetupBroker()
+ {
+ $routerTopic = new RdKafkaTopic('');
+ $routerQueue = new RdKafkaTopic('');
+
+ $processorTopic = new RdKafkaTopic('');
+
+ $context = $this->createContextMock();
+
+ $context
+ ->expects($this->at(0))
+ ->method('createQueue')
+ ->willReturn($routerTopic)
+ ;
+ $context
+ ->expects($this->at(1))
+ ->method('createQueue')
+ ->willReturn($routerQueue)
+ ;
+ $context
+ ->expects($this->at(2))
+ ->method('createQueue')
+ ->willReturn($processorTopic)
+ ;
+
+ $driver = new RdKafkaDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([
+ new Route('topic', Route::TOPIC, 'processor'),
+ ])
+ );
+
+ $driver->setupBroker();
+ }
+
+ protected function createDriver(...$args): DriverInterface
+ {
+ return new RdKafkaDriver(...$args);
+ }
+
+ /**
+ * @return RdKafkaContext
+ */
+ protected function createContextMock(): Context
+ {
+ return $this->createMock(RdKafkaContext::class);
+ }
+
+ /**
+ * @return RdKafkaProducer
+ */
+ protected function createProducerMock(): InteropProducer
+ {
+ return $this->createMock(RdKafkaProducer::class);
+ }
+
+ /**
+ * @return RdKafkaTopic
+ */
+ protected function createQueue(string $name): InteropQueue
+ {
+ return new RdKafkaTopic($name);
+ }
+
+ protected function createTopic(string $name): RdKafkaTopic
+ {
+ return new RdKafkaTopic($name);
+ }
+
+ /**
+ * @return RdKafkaMessage
+ */
+ protected function createMessage(): InteropMessage
+ {
+ return new RdKafkaMessage();
+ }
+
+ /**
+ * @return Config
+ */
+ private function createDummyConfig()
+ {
+ return Config::create('aPrefix');
+ }
+}
diff --git a/pkg/enqueue/Tests/Client/Driver/SqsDriverTest.php b/pkg/enqueue/Tests/Client/Driver/SqsDriverTest.php
new file mode 100644
index 000000000..2e3005e6a
--- /dev/null
+++ b/pkg/enqueue/Tests/Client/Driver/SqsDriverTest.php
@@ -0,0 +1,153 @@
+assertClassImplements(DriverInterface::class, SqsDriver::class);
+ }
+
+ public function testShouldBeSubClassOfGenericDriver()
+ {
+ $this->assertClassExtends(GenericDriver::class, SqsDriver::class);
+ }
+
+ public function testShouldSetupBroker()
+ {
+ $routerQueue = new SqsDestination('');
+ $processorQueue = new SqsDestination('');
+
+ $context = $this->createContextMock();
+ // setup router
+ $context
+ ->expects($this->at(0))
+ ->method('createQueue')
+ ->with('aprefix_dot_default')
+ ->willReturn($routerQueue)
+ ;
+ $context
+ ->expects($this->at(1))
+ ->method('declareQueue')
+ ->with($this->identicalTo($routerQueue))
+ ;
+ // setup processor queue
+ $context
+ ->expects($this->at(2))
+ ->method('createQueue')
+ ->with('aprefix_dot_default')
+ ->willReturn($processorQueue)
+ ;
+ $context
+ ->expects($this->at(3))
+ ->method('declareQueue')
+ ->with($this->identicalTo($processorQueue))
+ ;
+
+ $driver = new SqsDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([
+ new Route('topic', Route::TOPIC, 'processor'),
+ ])
+ );
+
+ $driver->setupBroker();
+ }
+
+ protected function createDriver(...$args): DriverInterface
+ {
+ return new SqsDriver(...$args);
+ }
+
+ /**
+ * @return SqsContext
+ */
+ protected function createContextMock(): Context
+ {
+ return $this->createMock(SqsContext::class);
+ }
+
+ /**
+ * @return SqsProducer
+ */
+ protected function createProducerMock(): InteropProducer
+ {
+ return $this->createMock(SqsProducer::class);
+ }
+
+ /**
+ * @return SqsDestination
+ */
+ protected function createQueue(string $name): InteropQueue
+ {
+ return new SqsDestination($name);
+ }
+
+ /**
+ * @return SqsDestination
+ */
+ protected function createTopic(string $name): InteropTopic
+ {
+ return new SqsDestination($name);
+ }
+
+ /**
+ * @return SqsMessage
+ */
+ protected function createMessage(): InteropMessage
+ {
+ return new SqsMessage();
+ }
+
+ protected function getPrefixAppFooQueueTransportName(): string
+ {
+ return 'aprefix_dot_anappname_dot_afooqueue';
+ }
+
+ protected function getPrefixFooQueueTransportName(): string
+ {
+ return 'aprefix_dot_afooqueue';
+ }
+
+ protected function getAppFooQueueTransportName(): string
+ {
+ return 'anappname_dot_afooqueue';
+ }
+
+ protected function getDefaultQueueTransportName(): string
+ {
+ return 'aprefix_dot_default';
+ }
+
+ protected function getCustomQueueTransportName(): string
+ {
+ return 'aprefix_dot_custom';
+ }
+
+ protected function getRouterTransportName(): string
+ {
+ return 'aprefix_dot_default';
+ }
+}
diff --git a/pkg/enqueue/Tests/Client/Driver/StompDriverTest.php b/pkg/enqueue/Tests/Client/Driver/StompDriverTest.php
new file mode 100644
index 000000000..8f777fdbd
--- /dev/null
+++ b/pkg/enqueue/Tests/Client/Driver/StompDriverTest.php
@@ -0,0 +1,191 @@
+assertClassImplements(DriverInterface::class, StompDriver::class);
+ }
+
+ public function testShouldBeSubClassOfGenericDriver()
+ {
+ $this->assertClassExtends(GenericDriver::class, StompDriver::class);
+ }
+
+ public function testSetupBrokerShouldOnlyLogMessageThatStompDoesNotSupportBrokerSetup()
+ {
+ $driver = new StompDriver(
+ $this->createContextMock(),
+ $this->createDummyConfig(),
+ new RouteCollection([])
+ );
+
+ $logger = $this->createLoggerMock();
+ $logger
+ ->expects($this->once())
+ ->method('debug')
+ ->with('[StompDriver] Stomp protocol does not support broker configuration')
+ ;
+
+ $driver->setupBroker($logger);
+ }
+
+ public function testShouldCreateDurableQueue()
+ {
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createQueue')
+ ->willReturn($this->createQueue('aName'))
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([])
+ );
+
+ /** @var StompDestination $queue */
+ $queue = $driver->createQueue('aName');
+
+ $this->assertTrue($queue->isDurable());
+ $this->assertFalse($queue->isAutoDelete());
+ $this->assertFalse($queue->isExclusive());
+ }
+
+ public function testShouldSetPersistedTrueOnCreateTransportMessage()
+ {
+ $clientMessage = new Message();
+
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($this->createMessage())
+ ;
+
+ $driver = $this->createDriver(
+ $context,
+ $this->createDummyConfig(),
+ new RouteCollection([])
+ );
+
+ /** @var StompMessage $transportMessage */
+ $transportMessage = $driver->createTransportMessage($clientMessage);
+
+ $this->assertTrue($transportMessage->isPersistent());
+ }
+
+ protected function createDriver(...$args): DriverInterface
+ {
+ return new StompDriver(...$args);
+ }
+
+ /**
+ * @return StompContext
+ */
+ protected function createContextMock(): Context
+ {
+ return $this->createMock(StompContext::class);
+ }
+
+ /**
+ * @return StompProducer
+ */
+ protected function createProducerMock(): InteropProducer
+ {
+ return $this->createMock(StompProducer::class);
+ }
+
+ /**
+ * @return StompDestination
+ */
+ protected function createQueue(string $name): InteropQueue
+ {
+ $destination = new StompDestination(ExtensionType::RABBITMQ);
+ $destination->setType(StompDestination::TYPE_QUEUE);
+ $destination->setStompName($name);
+
+ return $destination;
+ }
+
+ /**
+ * @return StompDestination
+ */
+ protected function createTopic(string $name): InteropTopic
+ {
+ $destination = new StompDestination(ExtensionType::RABBITMQ);
+ $destination->setType(StompDestination::TYPE_TOPIC);
+ $destination->setStompName($name);
+
+ return $destination;
+ }
+
+ /**
+ * @return StompMessage
+ */
+ protected function createMessage(): InteropMessage
+ {
+ return new StompMessage();
+ }
+
+ protected function assertTransportMessage(InteropMessage $transportMessage): void
+ {
+ $this->assertSame('body', $transportMessage->getBody());
+ $this->assertEquals([
+ 'hkey' => 'hval',
+ 'message_id' => 'theMessageId',
+ 'timestamp' => 1000,
+ 'reply-to' => 'theReplyTo',
+ 'persistent' => true,
+ 'correlation_id' => 'theCorrelationId',
+ ], $transportMessage->getHeaders());
+ $this->assertEquals([
+ 'pkey' => 'pval',
+ Config::CONTENT_TYPE => 'ContentType',
+ Config::PRIORITY => MessagePriority::HIGH,
+ Config::EXPIRE => 123,
+ Config::DELAY => 345,
+ ], $transportMessage->getProperties());
+ $this->assertSame('theMessageId', $transportMessage->getMessageId());
+ $this->assertSame(1000, $transportMessage->getTimestamp());
+ $this->assertSame('theReplyTo', $transportMessage->getReplyTo());
+ $this->assertSame('theCorrelationId', $transportMessage->getCorrelationId());
+ }
+
+ protected function createLoggerMock(): LoggerInterface
+ {
+ return $this->createMock(LoggerInterface::class);
+ }
+
+ protected function getRouterTransportName(): string
+ {
+ return '/topic/aprefix.router';
+ }
+}
diff --git a/pkg/stomp/Tests/Client/ManagementClientTest.php b/pkg/enqueue/Tests/Client/Driver/StompManagementClientTest.php
similarity index 72%
rename from pkg/stomp/Tests/Client/ManagementClientTest.php
rename to pkg/enqueue/Tests/Client/Driver/StompManagementClientTest.php
index cc11007c9..081a62c5f 100644
--- a/pkg/stomp/Tests/Client/ManagementClientTest.php
+++ b/pkg/enqueue/Tests/Client/Driver/StompManagementClientTest.php
@@ -1,14 +1,14 @@
expects($this->once())
->method('create')
->with('vhost', 'name', ['options'])
+ ->willReturn([])
;
$client = $this->createClientMock();
@@ -26,7 +27,7 @@ public function testCouldDeclareExchange()
->willReturn($exchange)
;
- $management = new ManagementClient($client, 'vhost');
+ $management = new StompManagementClient($client, 'vhost');
$management->declareExchange('name', ['options']);
}
@@ -37,6 +38,7 @@ public function testCouldDeclareQueue()
->expects($this->once())
->method('create')
->with('vhost', 'name', ['options'])
+ ->willReturn([])
;
$client = $this->createClientMock();
@@ -46,7 +48,7 @@ public function testCouldDeclareQueue()
->willReturn($queue)
;
- $management = new ManagementClient($client, 'vhost');
+ $management = new StompManagementClient($client, 'vhost');
$management->declareQueue('name', ['options']);
}
@@ -57,6 +59,7 @@ public function testCouldBind()
->expects($this->once())
->method('create')
->with('vhost', 'exchange', 'queue', 'routing-key', ['arguments'])
+ ->willReturn([])
;
$client = $this->createClientMock();
@@ -66,19 +69,19 @@ public function testCouldBind()
->willReturn($binding)
;
- $management = new ManagementClient($client, 'vhost');
+ $management = new StompManagementClient($client, 'vhost');
$management->bind('exchange', 'queue', 'routing-key', ['arguments']);
}
public function testCouldCreateNewInstanceUsingFactory()
{
- $instance = ManagementClient::create('', '');
+ $instance = StompManagementClient::create('', '');
- $this->assertInstanceOf(ManagementClient::class, $instance);
+ $this->assertInstanceOf(StompManagementClient::class, $instance);
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|Client
+ * @return \PHPUnit\Framework\MockObject\MockObject|Client
*/
private function createClientMock()
{
@@ -86,7 +89,7 @@ private function createClientMock()
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|Exchange
+ * @return \PHPUnit\Framework\MockObject\MockObject|Exchange
*/
private function createExchangeMock()
{
@@ -94,7 +97,7 @@ private function createExchangeMock()
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|Queue
+ * @return \PHPUnit\Framework\MockObject\MockObject|Queue
*/
private function createQueueMock()
{
@@ -102,7 +105,7 @@ private function createQueueMock()
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|Binding
+ * @return \PHPUnit\Framework\MockObject\MockObject|Binding
*/
private function createBindingMock()
{
diff --git a/pkg/enqueue/Tests/Client/DriverFactoryTest.php b/pkg/enqueue/Tests/Client/DriverFactoryTest.php
new file mode 100644
index 000000000..3d9d7b9b5
--- /dev/null
+++ b/pkg/enqueue/Tests/Client/DriverFactoryTest.php
@@ -0,0 +1,186 @@
+assertTrue($rc->implementsInterface(DriverFactoryInterface::class));
+ }
+
+ public function testShouldBeFinal()
+ {
+ $rc = new \ReflectionClass(DriverFactory::class);
+
+ $this->assertTrue($rc->isFinal());
+ }
+
+ public function testThrowIfPackageThatSupportSchemeNotInstalled()
+ {
+ $scheme = 'scheme5b7aa7d7cd213';
+ $class = 'ConnectionClass5b7aa7d7cd213';
+
+ Resources::addDriver($class, [$scheme], [], ['thePackage', 'theOtherPackage']);
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('To use given scheme "scheme5b7aa7d7cd213" a package has to be installed. Run "composer req thePackage theOtherPackage" to add it.');
+ $factory = new DriverFactory();
+
+ $factory->create($this->createConnectionFactoryMock(), $this->createDummyConfig($scheme.'://foo'), new RouteCollection([]));
+ }
+
+ public function testThrowIfSchemeIsNotKnown()
+ {
+ $scheme = 'scheme5b7aa862e70a5';
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('A given scheme "scheme5b7aa862e70a5" is not supported. Maybe it is a custom driver, make sure you registered it with "Enqueue\Client\Resources::addDriver".');
+
+ $factory = new DriverFactory();
+
+ $factory->create($this->createConnectionFactoryMock(), $this->createDummyConfig($scheme.'://foo'), new RouteCollection([]));
+ }
+
+ public function testThrowIfDsnInvalid()
+ {
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('The DSN is invalid. It does not have scheme separator ":".');
+
+ $factory = new DriverFactory();
+
+ $factory->create($this->createConnectionFactoryMock(), $this->createDummyConfig('invalidDsn'), new RouteCollection([]));
+ }
+
+ /**
+ * @dataProvider provideDSN
+ */
+ public function testReturnsExpectedFactories(
+ string $dsn,
+ string $connectionFactoryClass,
+ string $contextClass,
+ array $conifg,
+ string $expectedDriverClass,
+ ) {
+ $connectionFactoryMock = $this->createMock($connectionFactoryClass);
+ $connectionFactoryMock
+ ->expects($this->once())
+ ->method('createContext')
+ ->willReturn($this->createMock($contextClass))
+ ;
+
+ $driverFactory = new DriverFactory();
+
+ $driver = $driverFactory->create($connectionFactoryMock, $this->createDummyConfig($dsn), new RouteCollection([]));
+
+ $this->assertInstanceOf($expectedDriverClass, $driver);
+ }
+
+ public static function provideDSN()
+ {
+ yield ['null:', NullConnectionFactory::class, NullContext::class, [], GenericDriver::class];
+
+ yield ['amqp:', AmqpConnectionFactory::class, AmqpContext::class, [], AmqpDriver::class];
+
+ yield ['amqp+rabbitmq:', AmqpConnectionFactory::class, AmqpContext::class, [], RabbitMqDriver::class];
+
+ yield ['mysql:', DbalConnectionFactory::class, DbalContext::class, [], DbalDriver::class];
+
+ yield ['file:', FsConnectionFactory::class, FsContext::class, [], FsDriver::class];
+
+ // https://github.com/php-enqueue/enqueue-dev/issues/511
+ // yield ['gearman:', GearmanConnectionFactory::class, NullContext::class, [], NullDriver::class];
+
+ yield ['gps:', GpsConnectionFactory::class, GpsContext::class, [], GpsDriver::class];
+
+ yield ['mongodb:', MongodbConnectionFactory::class, MongodbContext::class, [], MongodbDriver::class];
+
+ yield ['kafka:', RdKafkaConnectionFactory::class, RdKafkaContext::class, [], RdKafkaDriver::class];
+
+ yield ['redis:', RedisConnectionFactory::class, RedisContext::class, [], GenericDriver::class];
+
+ yield ['redis+predis:', RedisConnectionFactory::class, RedisContext::class, [], GenericDriver::class];
+
+ yield ['sqs:', SqsConnectionFactory::class, SqsContext::class, [], SqsDriver::class];
+
+ yield ['stomp:', StompConnectionFactory::class, StompContext::class, [], StompDriver::class];
+
+ yield ['stomp+rabbitmq:', StompConnectionFactory::class, StompContext::class, [], RabbitMqStompDriver::class];
+
+ yield ['stomp+foo+bar:', StompConnectionFactory::class, StompContext::class, [], StompDriver::class];
+
+ yield ['gearman:', GearmanConnectionFactory::class, GearmanContext::class, [], GenericDriver::class];
+
+ yield ['beanstalk:', PheanstalkConnectionFactory::class, PheanstalkContext::class, [], GenericDriver::class];
+ }
+
+ private function createDummyConfig(string $dsn): Config
+ {
+ return Config::create(
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ ['dsn' => $dsn],
+ []
+ );
+ }
+
+ private function createConnectionFactoryMock(): ConnectionFactory
+ {
+ return $this->createMock(ConnectionFactory::class);
+ }
+
+ private function createConfigMock(): Config
+ {
+ return $this->createMock(Config::class);
+ }
+}
diff --git a/pkg/enqueue/Tests/Client/DriverPreSendTest.php b/pkg/enqueue/Tests/Client/DriverPreSendTest.php
new file mode 100644
index 000000000..32af2a81f
--- /dev/null
+++ b/pkg/enqueue/Tests/Client/DriverPreSendTest.php
@@ -0,0 +1,84 @@
+createProducerMock();
+ $expectedDriver = $this->createDriverMock();
+
+ $context = new DriverPreSend(
+ $expectedMessage,
+ $expectedProducer,
+ $expectedDriver
+ );
+
+ $this->assertSame($expectedMessage, $context->getMessage());
+ $this->assertSame($expectedProducer, $context->getProducer());
+ $this->assertSame($expectedDriver, $context->getDriver());
+ }
+
+ public function testShouldAllowGetCommand()
+ {
+ $message = new Message();
+ $message->setProperty(Config::COMMAND, 'theCommand');
+
+ $context = new DriverPreSend(
+ $message,
+ $this->createProducerMock(),
+ $this->createDriverMock()
+ );
+
+ $this->assertFalse($context->isEvent());
+ $this->assertSame('theCommand', $context->getCommand());
+ }
+
+ public function testShouldAllowGetTopic()
+ {
+ $message = new Message();
+ $message->setProperty(Config::TOPIC, 'theTopic');
+
+ $context = new DriverPreSend(
+ $message,
+ $this->createProducerMock(),
+ $this->createDriverMock()
+ );
+
+ $this->assertTrue($context->isEvent());
+ $this->assertSame('theTopic', $context->getTopic());
+ }
+
+ /**
+ * @return \PHPUnit\Framework\MockObject\MockObject
+ */
+ private function createDriverMock(): DriverInterface
+ {
+ return $this->createMock(DriverInterface::class);
+ }
+
+ /**
+ * @return \PHPUnit\Framework\MockObject\MockObject
+ */
+ private function createProducerMock(): ProducerInterface
+ {
+ return $this->createMock(ProducerInterface::class);
+ }
+}
diff --git a/pkg/enqueue/Tests/Client/Extension/PrepareBodyExtensionTest.php b/pkg/enqueue/Tests/Client/Extension/PrepareBodyExtensionTest.php
new file mode 100644
index 000000000..c3032ccc8
--- /dev/null
+++ b/pkg/enqueue/Tests/Client/Extension/PrepareBodyExtensionTest.php
@@ -0,0 +1,131 @@
+assertTrue($rc->implementsInterface(PreSendEventExtensionInterface::class));
+ $this->assertTrue($rc->implementsInterface(PreSendCommandExtensionInterface::class));
+ }
+
+ /**
+ * @dataProvider provideMessages
+ *
+ * @param mixed|null $contentType
+ */
+ public function testShouldSendStringUnchangedAndAddPlainTextContentTypeIfEmpty(
+ $body,
+ $contentType,
+ string $expectedBody,
+ string $expectedContentType,
+ ) {
+ $message = new Message($body);
+ $message->setContentType($contentType);
+
+ $context = $this->createDummyPreSendContext('aTopic', $message);
+
+ $extension = new PrepareBodyExtension();
+
+ $extension->onPreSendEvent($context);
+
+ $this->assertSame($expectedBody, $message->getBody());
+ $this->assertSame($expectedContentType, $message->getContentType());
+ }
+
+ public function testThrowIfBodyIsObject()
+ {
+ $message = new Message(new \stdClass());
+
+ $context = $this->createDummyPreSendContext('aTopic', $message);
+
+ $extension = new PrepareBodyExtension();
+
+ $this->expectException(\InvalidArgumentException::class);
+ $this->expectExceptionMessage('The message\'s body must be either null, scalar, array or object (implements \JsonSerializable). Got: stdClass');
+
+ $extension->onPreSendEvent($context);
+ }
+
+ public function testThrowIfBodyIsArrayWithObjectsInsideOnSend()
+ {
+ $message = new Message(['foo' => new \stdClass()]);
+
+ $context = $this->createDummyPreSendContext('aTopic', $message);
+
+ $extension = new PrepareBodyExtension();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('The message\'s body must be an array of scalars. Found not scalar in the array: stdClass');
+
+ $extension->onPreSendEvent($context);
+ }
+
+ public function testShouldThrowExceptionIfBodyIsArrayWithObjectsInSubArraysInsideOnSend()
+ {
+ $message = new Message(['foo' => ['bar' => new \stdClass()]]);
+
+ $context = $this->createDummyPreSendContext('aTopic', $message);
+
+ $extension = new PrepareBodyExtension();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('The message\'s body must be an array of scalars. Found not scalar in the array: stdClass');
+
+ $extension->onPreSendEvent($context);
+ }
+
+ public static function provideMessages()
+ {
+ yield ['theBody', null, 'theBody', 'text/plain'];
+
+ yield ['theBody', 'foo/bar', 'theBody', 'foo/bar'];
+
+ yield [12345, null, '12345', 'text/plain'];
+
+ yield [12345, 'foo/bar', '12345', 'foo/bar'];
+
+ yield [12.345, null, '12.345', 'text/plain'];
+
+ yield [12.345, 'foo/bar', '12.345', 'foo/bar'];
+
+ yield [true, null, '1', 'text/plain'];
+
+ yield [true, 'foo/bar', '1', 'foo/bar'];
+
+ yield [null, null, '', 'text/plain'];
+
+ yield [null, 'foo/bar', '', 'foo/bar'];
+
+ yield [['foo' => 'fooVal'], null, '{"foo":"fooVal"}', 'application/json'];
+
+ yield [['foo' => 'fooVal'], 'foo/bar', '{"foo":"fooVal"}', 'foo/bar'];
+
+ yield [new JsonSerializableObject(), null, '{"foo":"fooVal"}', 'application/json'];
+
+ yield [new JsonSerializableObject(), 'foo/bar', '{"foo":"fooVal"}', 'foo/bar'];
+ }
+
+ private function createDummyPreSendContext($commandOrTopic, $message): PreSend
+ {
+ return new PreSend(
+ $commandOrTopic,
+ $message,
+ $this->createMock(ProducerInterface::class),
+ $this->createMock(DriverInterface::class)
+ );
+ }
+}
diff --git a/pkg/enqueue/Tests/Client/Meta/QueueMetaRegistryTest.php b/pkg/enqueue/Tests/Client/Meta/QueueMetaRegistryTest.php
deleted file mode 100644
index 787290fe6..000000000
--- a/pkg/enqueue/Tests/Client/Meta/QueueMetaRegistryTest.php
+++ /dev/null
@@ -1,146 +0,0 @@
- [],
- 'anotherQueueName' => [],
- ];
-
- $registry = new QueueMetaRegistry($this->createConfig(), $meta);
-
- $this->assertAttributeEquals($meta, 'meta', $registry);
- }
-
- public function testShouldAllowAddQueueMetaUsingAddMethod()
- {
- $registry = new QueueMetaRegistry($this->createConfig(), []);
-
- $registry->add('theFooQueueName', 'theTransportQueueName');
- $registry->add('theBarQueueName');
-
- $this->assertAttributeSame([
- 'theFooQueueName' => [
- 'transportName' => 'theTransportQueueName',
- 'processors' => [],
- ],
- 'theBarQueueName' => [
- 'transportName' => null,
- 'processors' => [],
- ],
- ], 'meta', $registry);
- }
-
- public function testShouldAllowAddSubscriber()
- {
- $registry = new QueueMetaRegistry($this->createConfig(), []);
-
- $registry->addProcessor('theFooQueueName', 'theFooProcessorName');
- $registry->addProcessor('theFooQueueName', 'theBarProcessorName');
- $registry->addProcessor('theBarQueueName', 'theBazProcessorName');
-
- $this->assertAttributeSame([
- 'theFooQueueName' => [
- 'transportName' => null,
- 'processors' => ['theFooProcessorName', 'theBarProcessorName'],
- ],
- 'theBarQueueName' => [
- 'transportName' => null,
- 'processors' => ['theBazProcessorName'],
- ],
- ], 'meta', $registry);
- }
-
- public function testThrowIfThereIsNotMetaForRequestedClientQueueName()
- {
- $registry = new QueueMetaRegistry($this->createConfig(), []);
-
- $this->expectException(\InvalidArgumentException::class);
- $this->expectExceptionMessage('The queue meta not found. Requested name `aName`');
- $registry->getQueueMeta('aName');
- }
-
- public function testShouldAllowGetQueueByNameWithDefaultInfo()
- {
- $queues = [
- 'theQueueName' => [],
- ];
-
- $registry = new QueueMetaRegistry($this->createConfig(), $queues);
-
- $queue = $registry->getQueueMeta('theQueueName');
-
- $this->assertInstanceOf(QueueMeta::class, $queue);
- $this->assertSame('theQueueName', $queue->getClientName());
- $this->assertSame('aprefix.anappname.thequeuename', $queue->getTransportName());
- $this->assertSame([], $queue->getProcessors());
- }
-
- public function testShouldAllowGetQueueByNameWithCustomInfo()
- {
- $queues = [
- 'theClientQueueName' => ['transportName' => 'theTransportName', 'processors' => ['theSubscriber']],
- ];
-
- $registry = new QueueMetaRegistry($this->createConfig(), $queues);
-
- $queue = $registry->getQueueMeta('theClientQueueName');
- $this->assertInstanceOf(QueueMeta::class, $queue);
- $this->assertSame('theClientQueueName', $queue->getClientName());
- $this->assertSame('theTransportName', $queue->getTransportName());
- $this->assertSame(['theSubscriber'], $queue->getProcessors());
- }
-
- public function testShouldNotAllowToOverwriteDefaultTransportNameByEmptyValue()
- {
- $registry = new QueueMetaRegistry($this->createConfig(), [
- 'theClientQueueName' => ['transportName' => null, 'processors' => []],
- ]);
-
- $queue = $registry->getQueueMeta('theClientQueueName');
- $this->assertInstanceOf(QueueMeta::class, $queue);
- $this->assertSame('aprefix.anappname.theclientqueuename', $queue->getTransportName());
- }
-
- public function testShouldAllowGetAllQueues()
- {
- $queues = [
- 'fooQueueName' => [],
- 'barQueueName' => [],
- ];
-
- $registry = new QueueMetaRegistry($this->createConfig(), $queues);
-
- $queues = $registry->getQueuesMeta();
- $this->assertInstanceOf(\Generator::class, $queues);
-
- $queues = iterator_to_array($queues);
- /* @var QueueMeta[] $queues */
-
- $this->assertContainsOnly(QueueMeta::class, $queues);
- $this->assertCount(2, $queues);
-
- $this->assertSame('fooQueueName', $queues[0]->getClientName());
- $this->assertSame('aprefix.anappname.fooqueuename', $queues[0]->getTransportName());
-
- $this->assertSame('barQueueName', $queues[1]->getClientName());
- $this->assertSame('aprefix.anappname.barqueuename', $queues[1]->getTransportName());
- }
-
- /**
- * @return Config
- */
- private function createConfig()
- {
- return new Config('aPrefix', 'anAppName', 'aRouterTopic', 'aRouterQueueName', 'aDefaultQueueName', 'aRouterProcessorName');
- }
-}
diff --git a/pkg/enqueue/Tests/Client/Meta/QueueMetaTest.php b/pkg/enqueue/Tests/Client/Meta/QueueMetaTest.php
deleted file mode 100644
index fde6dc52f..000000000
--- a/pkg/enqueue/Tests/Client/Meta/QueueMetaTest.php
+++ /dev/null
@@ -1,39 +0,0 @@
-assertAttributeEquals('aClientName', 'clientName', $meta);
- $this->assertAttributeEquals('aTransportName', 'transportName', $meta);
- $this->assertAttributeEquals([], 'processors', $meta);
- }
-
- public function testShouldAllowGetClientNameSetInConstructor()
- {
- $meta = new QueueMeta('theClientName', 'aTransportName');
-
- $this->assertSame('theClientName', $meta->getClientName());
- }
-
- public function testShouldAllowGetTransportNameSetInConstructor()
- {
- $meta = new QueueMeta('aClientName', 'theTransportName');
-
- $this->assertSame('theTransportName', $meta->getTransportName());
- }
-
- public function testShouldAllowGetSubscribersSetInConstructor()
- {
- $meta = new QueueMeta('aClientName', 'aTransportName', ['aSubscriber']);
-
- $this->assertSame(['aSubscriber'], $meta->getProcessors());
- }
-}
diff --git a/pkg/enqueue/Tests/Client/Meta/TopicMetaRegistryTest.php b/pkg/enqueue/Tests/Client/Meta/TopicMetaRegistryTest.php
deleted file mode 100644
index ce074b6b1..000000000
--- a/pkg/enqueue/Tests/Client/Meta/TopicMetaRegistryTest.php
+++ /dev/null
@@ -1,124 +0,0 @@
- [],
- 'anotherTopicName' => [],
- ];
-
- $registry = new TopicMetaRegistry($topics);
-
- $this->assertAttributeEquals($topics, 'meta', $registry);
- }
-
- public function testShouldAllowAddTopicMetaUsingAddMethod()
- {
- $registry = new TopicMetaRegistry([]);
-
- $registry->add('theFooTopicName', 'aDescription');
- $registry->add('theBarTopicName');
-
- $this->assertAttributeSame([
- 'theFooTopicName' => [
- 'description' => 'aDescription',
- 'processors' => [],
- ],
- 'theBarTopicName' => [
- 'description' => null,
- 'processors' => [],
- ],
- ], 'meta', $registry);
- }
-
- public function testShouldAllowAddSubscriber()
- {
- $registry = new TopicMetaRegistry([]);
-
- $registry->addProcessor('theFooTopicName', 'theFooProcessorName');
- $registry->addProcessor('theFooTopicName', 'theBarProcessorName');
- $registry->addProcessor('theBarTopicName', 'theBazProcessorName');
-
- $this->assertAttributeSame([
- 'theFooTopicName' => [
- 'description' => null,
- 'processors' => ['theFooProcessorName', 'theBarProcessorName'],
- ],
- 'theBarTopicName' => [
- 'description' => null,
- 'processors' => ['theBazProcessorName'],
- ],
- ], 'meta', $registry);
- }
-
- public function testThrowIfThereIsNotMetaForRequestedTopicName()
- {
- $registry = new TopicMetaRegistry([]);
-
- $this->setExpectedException(
- \InvalidArgumentException::class,
- 'The topic meta not found. Requested name `aName`'
- );
- $registry->getTopicMeta('aName');
- }
-
- public function testShouldAllowGetTopicByNameWithDefaultInfo()
- {
- $topics = [
- 'theTopicName' => [],
- ];
-
- $registry = new TopicMetaRegistry($topics);
-
- $topic = $registry->getTopicMeta('theTopicName');
- $this->assertInstanceOf(TopicMeta::class, $topic);
- $this->assertSame('theTopicName', $topic->getName());
- $this->assertSame('', $topic->getDescription());
- $this->assertSame([], $topic->getProcessors());
- }
-
- public function testShouldAllowGetTopicByNameWithCustomInfo()
- {
- $topics = [
- 'theTopicName' => ['description' => 'theDescription', 'processors' => ['theSubscriber']],
- ];
-
- $registry = new TopicMetaRegistry($topics);
-
- $topic = $registry->getTopicMeta('theTopicName');
- $this->assertInstanceOf(TopicMeta::class, $topic);
- $this->assertSame('theTopicName', $topic->getName());
- $this->assertSame('theDescription', $topic->getDescription());
- $this->assertSame(['theSubscriber'], $topic->getProcessors());
- }
-
- public function testShouldAllowGetAllTopics()
- {
- $topics = [
- 'fooTopicName' => [],
- 'barTopicName' => [],
- ];
-
- $registry = new TopicMetaRegistry($topics);
-
- $topics = $registry->getTopicsMeta();
- $this->assertInstanceOf(\Generator::class, $topics);
-
- $topics = iterator_to_array($topics);
- /* @var TopicMeta[] $topics */
-
- $this->assertContainsOnly(TopicMeta::class, $topics);
- $this->assertCount(2, $topics);
-
- $this->assertSame('fooTopicName', $topics[0]->getName());
- $this->assertSame('barTopicName', $topics[1]->getName());
- }
-}
diff --git a/pkg/enqueue/Tests/Client/Meta/TopicMetaTest.php b/pkg/enqueue/Tests/Client/Meta/TopicMetaTest.php
deleted file mode 100644
index 565a8f821..000000000
--- a/pkg/enqueue/Tests/Client/Meta/TopicMetaTest.php
+++ /dev/null
@@ -1,57 +0,0 @@
-assertAttributeEquals('aName', 'name', $topic);
- $this->assertAttributeEquals('', 'description', $topic);
- $this->assertAttributeEquals([], 'processors', $topic);
- }
-
- public function testCouldBeConstructedWithNameAndDescriptionOnly()
- {
- $topic = new TopicMeta('aName', 'aDescription');
-
- $this->assertAttributeEquals('aName', 'name', $topic);
- $this->assertAttributeEquals('aDescription', 'description', $topic);
- $this->assertAttributeEquals([], 'processors', $topic);
- }
-
- public function testCouldBeConstructedWithNameAndDescriptionAndSubscribers()
- {
- $topic = new TopicMeta('aName', 'aDescription', ['aSubscriber']);
-
- $this->assertAttributeEquals('aName', 'name', $topic);
- $this->assertAttributeEquals('aDescription', 'description', $topic);
- $this->assertAttributeEquals(['aSubscriber'], 'processors', $topic);
- }
-
- public function testShouldAllowGetNameSetInConstructor()
- {
- $topic = new TopicMeta('theName', 'aDescription');
-
- $this->assertSame('theName', $topic->getName());
- }
-
- public function testShouldAllowGetDescriptionSetInConstructor()
- {
- $topic = new TopicMeta('aName', 'theDescription');
-
- $this->assertSame('theDescription', $topic->getDescription());
- }
-
- public function testShouldAllowGetSubscribersSetInConstructor()
- {
- $topic = new TopicMeta('aName', '', ['aSubscriber']);
-
- $this->assertSame(['aSubscriber'], $topic->getProcessors());
- }
-}
diff --git a/pkg/enqueue/Tests/Client/PostSendTest.php b/pkg/enqueue/Tests/Client/PostSendTest.php
new file mode 100644
index 000000000..ba51710e7
--- /dev/null
+++ b/pkg/enqueue/Tests/Client/PostSendTest.php
@@ -0,0 +1,112 @@
+createProducerMock();
+ $expectedDriver = $this->createDriverMock();
+ $expectedDestination = $this->createDestinationMock();
+ $expectedTransportMessage = $this->createTransportMessageMock();
+
+ $context = new PostSend(
+ $expectedMessage,
+ $expectedProducer,
+ $expectedDriver,
+ $expectedDestination,
+ $expectedTransportMessage
+ );
+
+ $this->assertSame($expectedMessage, $context->getMessage());
+ $this->assertSame($expectedProducer, $context->getProducer());
+ $this->assertSame($expectedDriver, $context->getDriver());
+ $this->assertSame($expectedDestination, $context->getTransportDestination());
+ $this->assertSame($expectedTransportMessage, $context->getTransportMessage());
+ }
+
+ public function testShouldAllowGetCommand()
+ {
+ $message = new Message();
+ $message->setProperty(Config::COMMAND, 'theCommand');
+
+ $context = new PostSend(
+ $message,
+ $this->createProducerMock(),
+ $this->createDriverMock(),
+ $this->createDestinationMock(),
+ $this->createTransportMessageMock()
+ );
+
+ $this->assertFalse($context->isEvent());
+ $this->assertSame('theCommand', $context->getCommand());
+ }
+
+ public function testShouldAllowGetTopic()
+ {
+ $message = new Message();
+ $message->setProperty(Config::TOPIC, 'theTopic');
+
+ $context = new PostSend(
+ $message,
+ $this->createProducerMock(),
+ $this->createDriverMock(),
+ $this->createDestinationMock(),
+ $this->createTransportMessageMock()
+ );
+
+ $this->assertTrue($context->isEvent());
+ $this->assertSame('theTopic', $context->getTopic());
+ }
+
+ /**
+ * @return \PHPUnit\Framework\MockObject\MockObject
+ */
+ private function createDriverMock(): DriverInterface
+ {
+ return $this->createMock(DriverInterface::class);
+ }
+
+ /**
+ * @return \PHPUnit\Framework\MockObject\MockObject
+ */
+ private function createProducerMock(): ProducerInterface
+ {
+ return $this->createMock(ProducerInterface::class);
+ }
+
+ /**
+ * @return \PHPUnit\Framework\MockObject\MockObject|Destination
+ */
+ private function createDestinationMock(): Destination
+ {
+ return $this->createMock(Destination::class);
+ }
+
+ /**
+ * @return \PHPUnit\Framework\MockObject\MockObject|TransportMessage
+ */
+ private function createTransportMessageMock(): TransportMessage
+ {
+ return $this->createMock(TransportMessage::class);
+ }
+}
diff --git a/pkg/enqueue/Tests/Client/PreSendTest.php b/pkg/enqueue/Tests/Client/PreSendTest.php
new file mode 100644
index 000000000..01a7e5055
--- /dev/null
+++ b/pkg/enqueue/Tests/Client/PreSendTest.php
@@ -0,0 +1,116 @@
+createProducerMock();
+ $expectedDriver = $this->createDriverMock();
+
+ $context = new PreSend(
+ $expectedCommandOrTopic,
+ $expectedMessage,
+ $expectedProducer,
+ $expectedDriver
+ );
+
+ $this->assertSame($expectedCommandOrTopic, $context->getTopic());
+ $this->assertSame($expectedCommandOrTopic, $context->getCommand());
+ $this->assertSame($expectedMessage, $context->getMessage());
+ $this->assertSame($expectedProducer, $context->getProducer());
+ $this->assertSame($expectedDriver, $context->getDriver());
+
+ $this->assertEquals($expectedMessage, $context->getOriginalMessage());
+ $this->assertNotSame($expectedMessage, $context->getOriginalMessage());
+ }
+
+ public function testCouldChangeTopic()
+ {
+ $context = new PreSend(
+ 'aCommandOrTopic',
+ new Message(),
+ $this->createProducerMock(),
+ $this->createDriverMock()
+ );
+
+ // guard
+ $this->assertSame('aCommandOrTopic', $context->getTopic());
+
+ $context->changeTopic('theChangedTopic');
+
+ $this->assertSame('theChangedTopic', $context->getTopic());
+ }
+
+ public function testCouldChangeCommand()
+ {
+ $context = new PreSend(
+ 'aCommandOrTopic',
+ new Message(),
+ $this->createProducerMock(),
+ $this->createDriverMock()
+ );
+
+ // guard
+ $this->assertSame('aCommandOrTopic', $context->getCommand());
+
+ $context->changeCommand('theChangedCommand');
+
+ $this->assertSame('theChangedCommand', $context->getCommand());
+ }
+
+ public function testCouldChangeBody()
+ {
+ $context = new PreSend(
+ 'aCommandOrTopic',
+ new Message('aBody'),
+ $this->createProducerMock(),
+ $this->createDriverMock()
+ );
+
+ // guard
+ $this->assertSame('aBody', $context->getMessage()->getBody());
+ $this->assertNull($context->getMessage()->getContentType());
+
+ $context->changeBody('theChangedBody');
+ $this->assertSame('theChangedBody', $context->getMessage()->getBody());
+ $this->assertNull($context->getMessage()->getContentType());
+
+ $context->changeBody('theChangedBodyAgain', 'foo/bar');
+ $this->assertSame('theChangedBodyAgain', $context->getMessage()->getBody());
+ $this->assertSame('foo/bar', $context->getMessage()->getContentType());
+ }
+
+ /**
+ * @return \PHPUnit\Framework\MockObject\MockObject
+ */
+ private function createDriverMock(): DriverInterface
+ {
+ return $this->createMock(DriverInterface::class);
+ }
+
+ /**
+ * @return \PHPUnit\Framework\MockObject\MockObject
+ */
+ private function createProducerMock(): ProducerInterface
+ {
+ return $this->createMock(ProducerInterface::class);
+ }
+}
diff --git a/pkg/enqueue/Tests/Client/ProducerSendCommandTest.php b/pkg/enqueue/Tests/Client/ProducerSendCommandTest.php
new file mode 100644
index 000000000..9500e9d62
--- /dev/null
+++ b/pkg/enqueue/Tests/Client/ProducerSendCommandTest.php
@@ -0,0 +1,537 @@
+createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToProcessor')
+ ->with(self::identicalTo($message))
+ ->willReturn($this->createDriverSendResult())
+ ;
+ $driver
+ ->expects($this->never())
+ ->method('sendToRouter')
+ ;
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock());
+ $producer->sendCommand('command', $message);
+
+ $expectedProperties = [
+ 'enqueue.command' => 'command',
+ ];
+
+ self::assertEquals($expectedProperties, $message->getProperties());
+ }
+
+ public function testShouldSendCommandWithReply()
+ {
+ $message = new Message();
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToProcessor')
+ ->with(self::identicalTo($message))
+ ->willReturn($this->createDriverSendResult())
+ ;
+ $driver
+ ->expects($this->never())
+ ->method('sendToRouter')
+ ;
+
+ $expectedPromiseMock = $this->createMock(Promise::class);
+
+ $rpcFactoryMock = $this->createRpcFactoryMock();
+ $rpcFactoryMock
+ ->expects($this->once())
+ ->method('createReplyTo')
+ ->willReturn('theReplyQueue')
+ ;
+ $rpcFactoryMock
+ ->expects($this->once())
+ ->method('createPromise')
+ ->with(
+ 'theReplyQueue',
+ $this->logicalNot($this->isEmpty()),
+ 60000
+ )
+ ->willReturn($expectedPromiseMock)
+ ;
+
+ $producer = new Producer($driver, $rpcFactoryMock);
+ $actualPromise = $producer->sendCommand('command', $message, true);
+
+ $this->assertSame($expectedPromiseMock, $actualPromise);
+
+ self::assertEquals('theReplyQueue', $message->getReplyTo());
+ self::assertNotEmpty($message->getCorrelationId());
+ }
+
+ public function testShouldSendCommandWithReplyAndCustomReplyQueueAndCorrelationId()
+ {
+ $message = new Message();
+ $message->setReplyTo('theCustomReplyQueue');
+ $message->setCorrelationId('theCustomCorrelationId');
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToProcessor')
+ ->with(self::identicalTo($message))
+ ->willReturn($this->createDriverSendResult())
+ ;
+ $driver
+ ->expects($this->never())
+ ->method('sendToRouter')
+ ;
+
+ $expectedPromiseMock = $this->createMock(Promise::class);
+
+ $rpcFactoryMock = $this->createRpcFactoryMock();
+ $rpcFactoryMock
+ ->expects($this->never())
+ ->method('createReplyTo')
+ ;
+ $rpcFactoryMock
+ ->expects($this->once())
+ ->method('createPromise')
+ ->with(
+ 'theCustomReplyQueue',
+ 'theCustomCorrelationId',
+ 60000
+ )
+ ->willReturn($expectedPromiseMock)
+ ;
+
+ $producer = new Producer($driver, $rpcFactoryMock);
+ $actualPromise = $producer->sendCommand('command', $message, true);
+
+ $this->assertSame($expectedPromiseMock, $actualPromise);
+
+ self::assertEquals('theCustomReplyQueue', $message->getReplyTo());
+ self::assertSame('theCustomCorrelationId', $message->getCorrelationId());
+ }
+
+ public function testShouldOverwriteExpectedMessageProperties()
+ {
+ $message = new Message();
+ $message->setProperty(Config::COMMAND, 'commandShouldBeOverwritten');
+ $message->setScope('scopeShouldBeOverwritten');
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToProcessor')
+ ->willReturn($this->createDriverSendResult())
+ ;
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock());
+ $producer->sendCommand('expectedCommand', $message);
+
+ $expectedProperties = [
+ 'enqueue.command' => 'expectedCommand',
+ ];
+
+ self::assertEquals($expectedProperties, $message->getProperties());
+ self::assertSame(Message::SCOPE_APP, $message->getScope());
+ }
+
+ public function testShouldSendCommandWithoutPriorityByDefault()
+ {
+ $message = new Message();
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToProcessor')
+ ->with(self::identicalTo($message))
+ ->willReturn($this->createDriverSendResult())
+ ;
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock());
+ $producer->sendCommand('command', $message);
+
+ self::assertNull($message->getPriority());
+ }
+
+ public function testShouldSendCommandWithCustomPriority()
+ {
+ $message = new Message();
+ $message->setPriority(MessagePriority::HIGH);
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToProcessor')
+ ->with(self::identicalTo($message))
+ ->willReturn($this->createDriverSendResult())
+ ;
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock());
+ $producer->sendCommand('command', $message);
+
+ self::assertSame(MessagePriority::HIGH, $message->getPriority());
+ }
+
+ public function testShouldSendCommandWithGeneratedMessageId()
+ {
+ $message = new Message();
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToProcessor')
+ ->with(self::identicalTo($message))
+ ->willReturn($this->createDriverSendResult())
+ ;
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock());
+ $producer->sendCommand('command', $message);
+
+ self::assertNotEmpty($message->getMessageId());
+ }
+
+ public function testShouldSendCommandWithCustomMessageId()
+ {
+ $message = new Message();
+ $message->setMessageId('theCustomMessageId');
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToProcessor')
+ ->with(self::identicalTo($message))
+ ->willReturn($this->createDriverSendResult())
+ ;
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock());
+ $producer->sendCommand('command', $message);
+
+ self::assertSame('theCustomMessageId', $message->getMessageId());
+ }
+
+ public function testShouldSendCommandWithGeneratedTimestamp()
+ {
+ $message = new Message();
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToProcessor')
+ ->with(self::identicalTo($message))
+ ->willReturn($this->createDriverSendResult())
+ ;
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock());
+ $producer->sendCommand('command', $message);
+
+ self::assertNotEmpty($message->getTimestamp());
+ }
+
+ public function testShouldSendCommandWithCustomTimestamp()
+ {
+ $message = new Message();
+ $message->setTimestamp('theCustomTimestamp');
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToProcessor')
+ ->with(self::identicalTo($message))
+ ->willReturn($this->createDriverSendResult())
+ ;
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock());
+ $producer->sendCommand('command', $message);
+
+ self::assertSame('theCustomTimestamp', $message->getTimestamp());
+ }
+
+ public function testShouldSerializeMessageToJsonByDefault()
+ {
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToProcessor')
+ ->willReturnCallback(function (Message $message) {
+ $this->assertSame('{"foo":"fooVal"}', $message->getBody());
+
+ return $this->createDriverSendResult();
+ })
+ ;
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock());
+ $producer->sendCommand('command', ['foo' => 'fooVal']);
+ }
+
+ public function testShouldSerializeMessageByCustomExtension()
+ {
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToProcessor')
+ ->willReturnCallback(function (Message $message) {
+ $this->assertSame('theCommandBodySerializedByCustomExtension', $message->getBody());
+
+ return $this->createDriverSendResult();
+ })
+ ;
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock(), new ChainExtension([new CustomPrepareBodyClientExtension()]));
+ $producer->sendCommand('command', ['foo' => 'fooVal']);
+ }
+
+ public function testShouldSendCommandToApplicationRouter()
+ {
+ $message = new Message();
+ $message->setBody('aBody');
+ $message->setScope(Message::SCOPE_APP);
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToProcessor')
+ ->willReturnCallback(function (Message $message) {
+ self::assertSame('aBody', $message->getBody());
+ self::assertNull($message->getProperty(Config::PROCESSOR));
+ self::assertSame('command', $message->getProperty(Config::COMMAND));
+
+ return $this->createDriverSendResult();
+ })
+ ;
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock());
+ $producer->sendCommand('command', $message);
+ }
+
+ public function testThrowWhenProcessorNamePropertySetToApplicationRouter()
+ {
+ $message = new Message();
+ $message->setBody('aBody');
+ $message->setScope(Message::SCOPE_APP);
+ $message->setProperty(Config::PROCESSOR, 'aCustomProcessor');
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->never())
+ ->method('sendToProcessor')
+ ;
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock());
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('The enqueue.processor property must not be set.');
+ $producer->sendCommand('command', $message);
+ }
+
+ public function testShouldCallPreSendCommandExtensionMethodWhenSendToBus()
+ {
+ $message = new Message();
+ $message->setBody('aBody');
+ $message->setScope(Message::SCOPE_MESSAGE_BUS);
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToProcessor')
+ ->willReturn($this->createDriverSendResult())
+ ;
+
+ $extension = $this->createMock(ExtensionInterface::class);
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock(), $extension);
+
+ $extension
+ ->expects($this->at(0))
+ ->method('onPreSendCommand')
+ ->willReturnCallback(function (PreSend $context) use ($message, $producer, $driver) {
+ $this->assertSame($message, $context->getMessage());
+ $this->assertSame($producer, $context->getProducer());
+ $this->assertSame($driver, $context->getDriver());
+ $this->assertSame('command', $context->getCommand());
+
+ $this->assertEquals($message, $context->getOriginalMessage());
+ $this->assertNotSame($message, $context->getOriginalMessage());
+ });
+
+ $extension
+ ->expects($this->never())
+ ->method('onPreSendEvent')
+ ;
+
+ $producer->sendCommand('command', $message);
+ }
+
+ public function testShouldCallPreSendCommandExtensionMethodWhenSendToApplicationRouter()
+ {
+ $message = new Message();
+ $message->setBody('aBody');
+ $message->setScope(Message::SCOPE_APP);
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToProcessor')
+ ->willReturn($this->createDriverSendResult())
+ ;
+
+ $extension = $this->createMock(ExtensionInterface::class);
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock(), $extension);
+
+ $extension
+ ->expects($this->at(0))
+ ->method('onPreSendCommand')
+ ->willReturnCallback(function (PreSend $context) use ($message, $producer, $driver) {
+ $this->assertSame($message, $context->getMessage());
+ $this->assertSame($producer, $context->getProducer());
+ $this->assertSame($driver, $context->getDriver());
+ $this->assertSame('command', $context->getCommand());
+
+ $this->assertEquals($message, $context->getOriginalMessage());
+ $this->assertNotSame($message, $context->getOriginalMessage());
+ });
+
+ $extension
+ ->expects($this->never())
+ ->method('onPreSendEvent')
+ ;
+
+ $producer->sendCommand('command', $message);
+ }
+
+ public function testShouldCallPreDriverSendExtensionMethod()
+ {
+ $message = new Message();
+ $message->setBody('aBody');
+ $message->setScope(Message::SCOPE_APP);
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToProcessor')
+ ->willReturn($this->createDriverSendResult())
+ ;
+
+ $extension = $this->createMock(ExtensionInterface::class);
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock(), $extension);
+
+ $extension
+ ->expects($this->at(0))
+ ->method('onDriverPreSend')
+ ->willReturnCallback(function (DriverPreSend $context) use ($message, $producer, $driver) {
+ $this->assertSame($message, $context->getMessage());
+ $this->assertSame($producer, $context->getProducer());
+ $this->assertSame($driver, $context->getDriver());
+ $this->assertSame('command', $context->getCommand());
+
+ $this->assertTrue($context->isEvent());
+ });
+
+ $producer->sendCommand('command', $message);
+ }
+
+ public function testShouldCallPostSendExtensionMethod()
+ {
+ $message = new Message();
+ $message->setBody('aBody');
+ $message->setScope(Message::SCOPE_APP);
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToProcessor')
+ ->willReturn($this->createDriverSendResult())
+ ;
+
+ $extension = $this->createMock(ExtensionInterface::class);
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock(), $extension);
+
+ $extension
+ ->expects($this->at(0))
+ ->method('onPostSend')
+ ->willReturnCallback(function (PostSend $context) use ($message, $producer, $driver) {
+ $this->assertSame($message, $context->getMessage());
+ $this->assertSame($producer, $context->getProducer());
+ $this->assertSame($driver, $context->getDriver());
+ $this->assertSame('command', $context->getCommand());
+
+ $this->assertFalse($context->isEvent());
+ });
+
+ $producer->sendCommand('command', $message);
+ }
+
+ /**
+ * @return \PHPUnit\Framework\MockObject\MockObject
+ */
+ private function createRpcFactoryMock(): RpcFactory
+ {
+ return $this->createMock(RpcFactory::class);
+ }
+
+ /**
+ * @return \PHPUnit\Framework\MockObject\MockObject
+ */
+ private function createDriverStub(): DriverInterface
+ {
+ $config = new Config(
+ 'a_prefix',
+ '.',
+ 'an_app',
+ 'a_router_topic',
+ 'a_router_queue',
+ 'a_default_processor_queue',
+ 'a_router_processor_name',
+ [],
+ []
+ );
+
+ $driverMock = $this->createMock(DriverInterface::class);
+ $driverMock
+ ->expects($this->any())
+ ->method('getConfig')
+ ->willReturn($config)
+ ;
+
+ return $driverMock;
+ }
+
+ private function createDriverSendResult(): DriverSendResult
+ {
+ return new DriverSendResult(
+ $this->createMock(Destination::class),
+ $this->createMock(TransportMessage::class)
+ );
+ }
+}
diff --git a/pkg/enqueue/Tests/Client/ProducerSendEventTest.php b/pkg/enqueue/Tests/Client/ProducerSendEventTest.php
new file mode 100644
index 000000000..c92b49560
--- /dev/null
+++ b/pkg/enqueue/Tests/Client/ProducerSendEventTest.php
@@ -0,0 +1,557 @@
+createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToRouter')
+ ->with(self::identicalTo($message))
+ ->willReturn($this->createDriverSendResult())
+ ;
+ $driver
+ ->expects($this->never())
+ ->method('sendToProcessor')
+ ;
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock());
+ $producer->sendEvent('topic', $message);
+
+ $expectedProperties = [
+ 'enqueue.topic' => 'topic',
+ ];
+
+ self::assertEquals($expectedProperties, $message->getProperties());
+ }
+
+ public function testShouldOverwriteTopicProperty()
+ {
+ $message = new Message();
+ $message->setProperty(Config::TOPIC, 'topicShouldBeOverwritten');
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToRouter')
+ ->with(self::identicalTo($message))
+ ->willReturn($this->createDriverSendResult())
+ ;
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock());
+ $producer->sendEvent('expectedTopic', $message);
+
+ $expectedProperties = [
+ 'enqueue.topic' => 'expectedTopic',
+ ];
+
+ self::assertEquals($expectedProperties, $message->getProperties());
+ }
+
+ public function testShouldSendEventWithoutPriorityByDefault()
+ {
+ $message = new Message();
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToRouter')
+ ->with(self::identicalTo($message))
+ ->willReturn($this->createDriverSendResult())
+ ;
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock());
+ $producer->sendEvent('topic', $message);
+
+ self::assertNull($message->getPriority());
+ }
+
+ public function testShouldSendEventWithCustomPriority()
+ {
+ $message = new Message();
+ $message->setPriority(MessagePriority::HIGH);
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToRouter')
+ ->with(self::identicalTo($message))
+ ->willReturn($this->createDriverSendResult())
+ ;
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock());
+ $producer->sendEvent('topic', $message);
+
+ self::assertSame(MessagePriority::HIGH, $message->getPriority());
+ }
+
+ public function testShouldSendEventWithGeneratedMessageId()
+ {
+ $message = new Message();
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToRouter')
+ ->with(self::identicalTo($message))
+ ->willReturn($this->createDriverSendResult())
+ ;
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock());
+ $producer->sendEvent('topic', $message);
+
+ self::assertNotEmpty($message->getMessageId());
+ }
+
+ public function testShouldSendEventWithCustomMessageId()
+ {
+ $message = new Message();
+ $message->setMessageId('theCustomMessageId');
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToRouter')
+ ->with(self::identicalTo($message))
+ ->willReturn($this->createDriverSendResult())
+ ;
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock());
+ $producer->sendEvent('topic', $message);
+
+ self::assertSame('theCustomMessageId', $message->getMessageId());
+ }
+
+ public function testShouldSendEventWithGeneratedTimestamp()
+ {
+ $message = new Message();
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToRouter')
+ ->with(self::identicalTo($message))
+ ->willReturn($this->createDriverSendResult())
+ ;
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock());
+ $producer->sendEvent('topic', $message);
+
+ self::assertNotEmpty($message->getTimestamp());
+ }
+
+ public function testShouldSendEventWithCustomTimestamp()
+ {
+ $message = new Message();
+ $message->setTimestamp('theCustomTimestamp');
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToRouter')
+ ->with(self::identicalTo($message))
+ ->willReturn($this->createDriverSendResult())
+ ;
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock());
+ $producer->sendEvent('topic', $message);
+
+ self::assertSame('theCustomTimestamp', $message->getTimestamp());
+ }
+
+ public function testShouldSerializeMessageToJsonByDefault()
+ {
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToRouter')
+ ->willReturnCallback(function (Message $message) {
+ $this->assertSame('{"foo":"fooVal"}', $message->getBody());
+
+ return $this->createDriverSendResult();
+ })
+ ;
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock());
+ $producer->sendEvent('topic', ['foo' => 'fooVal']);
+ }
+
+ public function testShouldSerializeMessageByCustomExtension()
+ {
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToRouter')
+ ->willReturnCallback(function (Message $message) {
+ $this->assertSame('theEventBodySerializedByCustomExtension', $message->getBody());
+
+ return $this->createDriverSendResult();
+ })
+ ;
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock(), new ChainExtension([new CustomPrepareBodyClientExtension()]));
+ $producer->sendEvent('topic', ['foo' => 'fooVal']);
+ }
+
+ public function testThrowIfSendEventToMessageBusWithProcessorNamePropertySet()
+ {
+ $message = new Message();
+ $message->setBody('');
+ $message->setProperty(Config::PROCESSOR, 'aProcessor');
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->never())
+ ->method('sendToRouter')
+ ;
+ $driver
+ ->expects($this->never())
+ ->method('sendToProcessor')
+ ;
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock());
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('The enqueue.processor property must not be set.');
+ $producer->sendEvent('topic', $message);
+ }
+
+ public function testShouldSendEventToApplicationRouter()
+ {
+ $message = new Message();
+ $message->setBody('aBody');
+ $message->setScope(Message::SCOPE_APP);
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->never())
+ ->method('sendToRouter')
+ ;
+ $driver
+ ->expects($this->once())
+ ->method('sendToProcessor')
+ ->willReturnCallback(function (Message $message) {
+ self::assertSame('aBody', $message->getBody());
+
+ // null means a driver sends a message to router processor.
+ self::assertNull($message->getProperty(Config::PROCESSOR));
+
+ return $this->createDriverSendResult();
+ })
+ ;
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock());
+ $producer->sendEvent('topic', $message);
+ }
+
+ public function testThrowWhenProcessorNamePropertySetToApplicationRouter()
+ {
+ $message = new Message();
+ $message->setBody('aBody');
+ $message->setScope(Message::SCOPE_APP);
+ $message->setProperty(Config::PROCESSOR, 'aCustomProcessor');
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->never())
+ ->method('sendToProcessor')
+ ;
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock());
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('The enqueue.processor property must not be set.');
+ $producer->sendEvent('topic', $message);
+ }
+
+ public function testThrowIfUnSupportedScopeGivenOnSend()
+ {
+ $message = new Message();
+ $message->setScope('iDontKnowScope');
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->never())
+ ->method('sendToRouter')
+ ;
+ $driver
+ ->expects($this->never())
+ ->method('sendToProcessor')
+ ;
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock());
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('The message scope "iDontKnowScope" is not supported.');
+ $producer->sendEvent('topic', $message);
+ }
+
+ public function testShouldCallPreSendEventExtensionMethodWhenSendToBus()
+ {
+ $message = new Message();
+ $message->setBody('aBody');
+ $message->setScope(Message::SCOPE_MESSAGE_BUS);
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToRouter')
+ ->willReturn($this->createDriverSendResult())
+ ;
+
+ $extension = $this->createMock(ExtensionInterface::class);
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock(), $extension);
+
+ $extension
+ ->expects($this->at(0))
+ ->method('onPreSendEvent')
+ ->willReturnCallback(function (PreSend $context) use ($message, $producer, $driver) {
+ $this->assertSame($message, $context->getMessage());
+ $this->assertSame($producer, $context->getProducer());
+ $this->assertSame($driver, $context->getDriver());
+ $this->assertSame('topic', $context->getTopic());
+
+ $this->assertEquals($message, $context->getOriginalMessage());
+ $this->assertNotSame($message, $context->getOriginalMessage());
+ });
+
+ $extension
+ ->expects($this->never())
+ ->method('onPreSendCommand')
+ ;
+
+ $producer->sendEvent('topic', $message);
+ }
+
+ public function testShouldCallPreSendEventExtensionMethodWhenSendToApplicationRouter()
+ {
+ $message = new Message();
+ $message->setBody('aBody');
+ $message->setScope(Message::SCOPE_APP);
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToProcessor')
+ ->willReturn($this->createDriverSendResult())
+ ;
+
+ $extension = $this->createMock(ExtensionInterface::class);
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock(), $extension);
+
+ $extension
+ ->expects($this->at(0))
+ ->method('onPreSendEvent')
+ ->willReturnCallback(function (PreSend $context) use ($message, $producer, $driver) {
+ $this->assertSame($message, $context->getMessage());
+ $this->assertSame($producer, $context->getProducer());
+ $this->assertSame($driver, $context->getDriver());
+ $this->assertSame('topic', $context->getTopic());
+
+ $this->assertEquals($message, $context->getOriginalMessage());
+ $this->assertNotSame($message, $context->getOriginalMessage());
+ });
+
+ $extension
+ ->expects($this->never())
+ ->method('onPreSendCommand')
+ ;
+
+ $producer->sendEvent('topic', $message);
+ }
+
+ public function testShouldCallPreDriverSendExtensionMethodWhenSendToMessageBus()
+ {
+ $message = new Message();
+ $message->setBody('aBody');
+ $message->setScope(Message::SCOPE_MESSAGE_BUS);
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToRouter')
+ ->willReturn($this->createDriverSendResult())
+ ;
+
+ $extension = $this->createMock(ExtensionInterface::class);
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock(), $extension);
+
+ $extension
+ ->expects($this->at(0))
+ ->method('onDriverPreSend')
+ ->willReturnCallback(function (DriverPreSend $context) use ($message, $producer, $driver) {
+ $this->assertSame($message, $context->getMessage());
+ $this->assertSame($producer, $context->getProducer());
+ $this->assertSame($driver, $context->getDriver());
+ $this->assertSame('topic', $context->getTopic());
+
+ $this->assertTrue($context->isEvent());
+ });
+
+ $producer->sendEvent('topic', $message);
+ }
+
+ public function testShouldCallPreDriverSendExtensionMethodWhenSendToApplicationRouter()
+ {
+ $message = new Message();
+ $message->setBody('aBody');
+ $message->setScope(Message::SCOPE_APP);
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToProcessor')
+ ->willReturn($this->createDriverSendResult())
+ ;
+
+ $extension = $this->createMock(ExtensionInterface::class);
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock(), $extension);
+
+ $extension
+ ->expects($this->at(0))
+ ->method('onDriverPreSend')
+ ->willReturnCallback(function (DriverPreSend $context) use ($message, $producer, $driver) {
+ $this->assertSame($message, $context->getMessage());
+ $this->assertSame($producer, $context->getProducer());
+ $this->assertSame($driver, $context->getDriver());
+ $this->assertSame('topic', $context->getTopic());
+
+ $this->assertTrue($context->isEvent());
+ });
+
+ $producer->sendEvent('topic', $message);
+ }
+
+ public function testShouldCallPostSendExtensionMethodWhenSendToMessageBus()
+ {
+ $message = new Message();
+ $message->setBody('aBody');
+ $message->setScope(Message::SCOPE_MESSAGE_BUS);
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToRouter')
+ ->willReturn($this->createDriverSendResult())
+ ;
+
+ $extension = $this->createMock(ExtensionInterface::class);
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock(), $extension);
+
+ $extension
+ ->expects($this->at(0))
+ ->method('onPostSend')
+ ->willReturnCallback(function (PostSend $context) use ($message, $producer, $driver) {
+ $this->assertSame($message, $context->getMessage());
+ $this->assertSame($producer, $context->getProducer());
+ $this->assertSame($driver, $context->getDriver());
+ $this->assertSame('topic', $context->getTopic());
+
+ $this->assertTrue($context->isEvent());
+ });
+
+ $producer->sendEvent('topic', $message);
+ }
+
+ public function testShouldCallPostSendExtensionMethodWhenSendToApplicationRouter()
+ {
+ $message = new Message();
+ $message->setBody('aBody');
+ $message->setScope(Message::SCOPE_APP);
+
+ $driver = $this->createDriverStub();
+ $driver
+ ->expects($this->once())
+ ->method('sendToProcessor')
+ ->willReturn($this->createDriverSendResult())
+ ;
+
+ $extension = $this->createMock(ExtensionInterface::class);
+
+ $producer = new Producer($driver, $this->createRpcFactoryMock(), $extension);
+
+ $extension
+ ->expects($this->at(0))
+ ->method('onPostSend')
+ ->willReturnCallback(function (PostSend $context) use ($message, $producer, $driver) {
+ $this->assertSame($message, $context->getMessage());
+ $this->assertSame($producer, $context->getProducer());
+ $this->assertSame($driver, $context->getDriver());
+ $this->assertSame('topic', $context->getTopic());
+
+ $this->assertTrue($context->isEvent());
+ });
+
+ $producer->sendEvent('topic', $message);
+ }
+
+ /**
+ * @return \PHPUnit\Framework\MockObject\MockObject
+ */
+ private function createRpcFactoryMock(): RpcFactory
+ {
+ return $this->createMock(RpcFactory::class);
+ }
+
+ /**
+ * @return \PHPUnit\Framework\MockObject\MockObject
+ */
+ private function createDriverStub(): DriverInterface
+ {
+ $config = new Config(
+ 'a_prefix',
+ '.',
+ 'an_app',
+ 'a_router_topic',
+ 'a_router_queue',
+ 'a_default_processor_queue',
+ 'a_router_processor_name',
+ [],
+ []
+ );
+
+ $driverMock = $this->createMock(DriverInterface::class);
+ $driverMock
+ ->expects($this->any())
+ ->method('getConfig')
+ ->willReturn($config)
+ ;
+
+ return $driverMock;
+ }
+
+ private function createDriverSendResult(): DriverSendResult
+ {
+ return new DriverSendResult(
+ $this->createMock(Destination::class),
+ $this->createMock(TransportMessage::class)
+ );
+ }
+}
diff --git a/pkg/enqueue/Tests/Client/ProducerTest.php b/pkg/enqueue/Tests/Client/ProducerTest.php
index 0716dc50d..23b004ac3 100644
--- a/pkg/enqueue/Tests/Client/ProducerTest.php
+++ b/pkg/enqueue/Tests/Client/ProducerTest.php
@@ -2,14 +2,9 @@
namespace Enqueue\Tests\Client;
-use Enqueue\Client\Config;
use Enqueue\Client\DriverInterface;
-use Enqueue\Client\ExtensionInterface;
-use Enqueue\Client\Message;
-use Enqueue\Client\MessagePriority;
use Enqueue\Client\Producer;
use Enqueue\Client\ProducerInterface;
-use Enqueue\Null\NullQueue;
use Enqueue\Rpc\RpcFactory;
use Enqueue\Test\ClassExtensionTrait;
use PHPUnit\Framework\TestCase;
@@ -23,620 +18,24 @@ public function testShouldImplementProducerInterface()
self::assertClassImplements(ProducerInterface::class, Producer::class);
}
- public function testCouldBeConstructedWithDriverAsFirstArgument()
+ public function testShouldBeFinal()
{
- new Producer($this->createDriverStub(), $this->createRpcFactory());
- }
-
- public function testShouldSendMessageToRouter()
- {
- $message = new Message();
-
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->once())
- ->method('sendToRouter')
- ->with(self::identicalTo($message))
- ;
-
- $producer = new Producer($driver, $this->createRpcFactory());
- $producer->sendEvent('topic', $message);
-
- $expectedProperties = [
- 'enqueue.topic_name' => 'topic',
- 'enqueue.topic' => 'topic',
- ];
-
- self::assertEquals($expectedProperties, $message->getProperties());
- }
-
- public function testShouldSendMessageWithNormalPriorityByDefault()
- {
- $message = new Message();
-
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->once())
- ->method('sendToRouter')
- ->with(self::identicalTo($message))
- ;
-
- $producer = new Producer($driver, $this->createRpcFactory());
- $producer->sendEvent('topic', $message);
-
- self::assertSame(MessagePriority::NORMAL, $message->getPriority());
- }
-
- public function testShouldSendMessageWithCustomPriority()
- {
- $message = new Message();
- $message->setPriority(MessagePriority::HIGH);
-
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->once())
- ->method('sendToRouter')
- ->with(self::identicalTo($message))
- ;
-
- $producer = new Producer($driver, $this->createRpcFactory());
- $producer->sendEvent('topic', $message);
-
- self::assertSame(MessagePriority::HIGH, $message->getPriority());
- }
-
- public function testShouldSendMessageWithGeneratedMessageId()
- {
- $message = new Message();
-
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->once())
- ->method('sendToRouter')
- ->with(self::identicalTo($message))
- ;
-
- $producer = new Producer($driver, $this->createRpcFactory());
- $producer->sendEvent('topic', $message);
-
- self::assertNotEmpty($message->getMessageId());
- }
-
- public function testShouldSendMessageWithCustomMessageId()
- {
- $message = new Message();
- $message->setMessageId('theCustomMessageId');
-
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->once())
- ->method('sendToRouter')
- ->with(self::identicalTo($message))
- ;
-
- $producer = new Producer($driver, $this->createRpcFactory());
- $producer->sendEvent('topic', $message);
-
- self::assertSame('theCustomMessageId', $message->getMessageId());
- }
-
- public function testShouldSendMessageWithGeneratedTimestamp()
- {
- $message = new Message();
-
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->once())
- ->method('sendToRouter')
- ->with(self::identicalTo($message))
- ;
-
- $producer = new Producer($driver, $this->createRpcFactory());
- $producer->sendEvent('topic', $message);
-
- self::assertNotEmpty($message->getTimestamp());
- }
-
- public function testShouldSendMessageWithCustomTimestamp()
- {
- $message = new Message();
- $message->setTimestamp('theCustomTimestamp');
-
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->once())
- ->method('sendToRouter')
- ->with(self::identicalTo($message))
- ;
-
- $producer = new Producer($driver, $this->createRpcFactory());
- $producer->sendEvent('topic', $message);
-
- self::assertSame('theCustomTimestamp', $message->getTimestamp());
- }
-
- public function testShouldSendStringAsPlainText()
- {
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->once())
- ->method('sendToRouter')
- ->willReturnCallback(function (Message $message) {
- self::assertSame('theStringMessage', $message->getBody());
- self::assertSame('text/plain', $message->getContentType());
- })
- ;
-
- $producer = new Producer($driver, $this->createRpcFactory());
- $producer->sendEvent('topic', 'theStringMessage');
- }
-
- public function testShouldSendArrayAsJsonString()
- {
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->once())
- ->method('sendToRouter')
- ->willReturnCallback(function (Message $message) {
- self::assertSame('{"foo":"fooVal"}', $message->getBody());
- self::assertSame('application/json', $message->getContentType());
- })
- ;
-
- $producer = new Producer($driver, $this->createRpcFactory());
- $producer->sendEvent('topic', ['foo' => 'fooVal']);
- }
-
- public function testShouldConvertMessageArrayBodyJsonString()
- {
- $message = new Message();
- $message->setBody(['foo' => 'fooVal']);
-
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->once())
- ->method('sendToRouter')
- ->willReturnCallback(function (Message $message) {
- self::assertSame('{"foo":"fooVal"}', $message->getBody());
- self::assertSame('application/json', $message->getContentType());
- })
- ;
-
- $producer = new Producer($driver, $this->createRpcFactory());
- $producer->sendEvent('topic', $message);
- }
-
- public function testSendShouldForceScalarsToStringAndSetTextContentType()
- {
- $queue = new NullQueue('');
-
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->once())
- ->method('sendToRouter')
- ->willReturnCallback(function (Message $message) {
- self::assertEquals('text/plain', $message->getContentType());
-
- self::assertInternalType('string', $message->getBody());
- self::assertEquals('12345', $message->getBody());
- })
- ;
-
- $producer = new Producer($driver, $this->createRpcFactory());
- $producer->sendEvent($queue, 12345);
- }
-
- public function testSendShouldForceMessageScalarsBodyToStringAndSetTextContentType()
- {
- $queue = new NullQueue('');
-
- $message = new Message();
- $message->setBody(12345);
-
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->once())
- ->method('sendToRouter')
- ->willReturnCallback(function (Message $message) {
- self::assertEquals('text/plain', $message->getContentType());
-
- self::assertInternalType('string', $message->getBody());
- self::assertEquals('12345', $message->getBody());
- })
- ;
-
- $producer = new Producer($driver, $this->createRpcFactory());
- $producer->sendEvent($queue, $message);
- }
-
- public function testSendShouldForceNullToEmptyStringAndSetTextContentType()
- {
- $queue = new NullQueue('');
-
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->once())
- ->method('sendToRouter')
- ->willReturnCallback(function (Message $message) {
- self::assertEquals('text/plain', $message->getContentType());
-
- self::assertInternalType('string', $message->getBody());
- self::assertEquals('', $message->getBody());
- })
- ;
-
- $producer = new Producer($driver, $this->createRpcFactory());
- $producer->sendEvent($queue, null);
- }
-
- public function testSendShouldForceNullBodyToEmptyStringAndSetTextContentType()
- {
- $queue = new NullQueue('');
-
- $message = new Message();
- $message->setBody(null);
-
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->once())
- ->method('sendToRouter')
- ->willReturnCallback(function (Message $message) {
- self::assertEquals('text/plain', $message->getContentType());
-
- self::assertInternalType('string', $message->getBody());
- self::assertEquals('', $message->getBody());
- })
- ;
-
- $producer = new Producer($driver, $this->createRpcFactory());
- $producer->sendEvent($queue, $message);
- }
-
- public function testShouldThrowExceptionIfBodyIsObjectOnSend()
- {
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->never())
- ->method('sendToRouter')
- ;
- $driver
- ->expects($this->never())
- ->method('sendToProcessor')
- ;
-
- $producer = new Producer($driver, $this->createRpcFactory());
-
- $this->expectException(\InvalidArgumentException::class);
- $this->expectExceptionMessage('The message\'s body must be either null, scalar, array or object (implements \JsonSerializable). Got: stdClass');
-
- $producer->sendEvent('topic', new \stdClass());
- }
-
- public function testShouldThrowExceptionIfBodyIsArrayWithObjectsInsideOnSend()
- {
- $queue = new NullQueue('queue');
-
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->never())
- ->method('sendToRouter')
- ;
- $driver
- ->expects($this->never())
- ->method('sendToProcessor')
- ;
-
- $producer = new Producer($driver, $this->createRpcFactory());
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('The message\'s body must be an array of scalars. Found not scalar in the array: stdClass');
-
- $producer->sendEvent($queue, ['foo' => new \stdClass()]);
- }
-
- public function testShouldThrowExceptionIfBodyIsArrayWithObjectsInSubArraysInsideOnSend()
- {
- $queue = new NullQueue('queue');
-
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->never())
- ->method('sendToRouter')
- ;
- $driver
- ->expects($this->never())
- ->method('sendToProcessor')
- ;
-
- $producer = new Producer($driver, $this->createRpcFactory());
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('The message\'s body must be an array of scalars. Found not scalar in the array: stdClass');
-
- $producer->sendEvent($queue, ['foo' => ['bar' => new \stdClass()]]);
- }
-
- public function testShouldSendJsonSerializableObjectAsJsonStringToMessageBus()
- {
- $object = new JsonSerializableObject();
-
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->once())
- ->method('sendToRouter')
- ->willReturnCallback(function (Message $message) {
- self::assertSame('{"foo":"fooVal"}', $message->getBody());
- self::assertSame('application/json', $message->getContentType());
- })
- ;
-
- $producer = new Producer($driver, $this->createRpcFactory());
- $producer->sendEvent('topic', $object);
- }
-
- public function testShouldSendMessageJsonSerializableBodyAsJsonStringToMessageBus()
- {
- $object = new JsonSerializableObject();
-
- $message = new Message();
- $message->setBody($object);
-
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->once())
- ->method('sendToRouter')
- ->willReturnCallback(function (Message $message) {
- self::assertSame('{"foo":"fooVal"}', $message->getBody());
- self::assertSame('application/json', $message->getContentType());
- })
- ;
-
- $producer = new Producer($driver, $this->createRpcFactory());
- $producer->sendEvent('topic', $message);
- }
-
- public function testThrowIfTryToSendMessageToMessageBusWithProcessorNamePropertySet()
- {
- $object = new JsonSerializableObject();
-
- $message = new Message();
- $message->setBody($object);
- $message->setProperty(Config::PARAMETER_PROCESSOR_NAME, 'aProcessor');
-
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->never())
- ->method('sendToRouter')
- ;
- $driver
- ->expects($this->never())
- ->method('sendToProcessor')
- ;
-
- $producer = new Producer($driver, $this->createRpcFactory());
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('The enqueue.processor_name property must not be set for messages that are sent to message bus.');
- $producer->sendEvent('topic', $message);
- }
-
- public function testThrowIfTryToSendMessageToMessageBusWithProcessorQueueNamePropertySet()
- {
- $object = new JsonSerializableObject();
-
- $message = new Message();
- $message->setBody($object);
- $message->setProperty(Config::PARAMETER_PROCESSOR_QUEUE_NAME, 'aProcessorQueue');
-
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->never())
- ->method('sendToRouter')
- ;
- $driver
- ->expects($this->never())
- ->method('sendToProcessor')
- ;
-
- $producer = new Producer($driver, $this->createRpcFactory());
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('The enqueue.processor_queue_name property must not be set for messages that are sent to message bus.');
- $producer->sendEvent('topic', $message);
- }
-
- public function testThrowIfNotApplicationJsonContentTypeSetWithJsonSerializableBody()
- {
- $object = new JsonSerializableObject();
-
- $message = new Message();
- $message->setBody($object);
- $message->setContentType('foo/bar');
-
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->never())
- ->method('sendToRouter')
- ;
- $driver
- ->expects($this->never())
- ->method('sendToProcessor')
- ;
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('Content type "application/json" only allowed when body is array');
-
- $producer = new Producer($driver, $this->createRpcFactory());
- $producer->sendEvent('topic', $message);
- }
-
- public function testShouldSendMessageToApplicationRouter()
- {
- $message = new Message();
- $message->setBody('aBody');
- $message->setScope(Message::SCOPE_APP);
-
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->never())
- ->method('sendToRouter')
- ;
- $driver
- ->expects($this->once())
- ->method('sendToProcessor')
- ->willReturnCallback(function (Message $message) {
- self::assertSame('aBody', $message->getBody());
- self::assertSame('a_router_processor_name', $message->getProperty(Config::PARAMETER_PROCESSOR_NAME));
- self::assertSame('a_router_queue', $message->getProperty(Config::PARAMETER_PROCESSOR_QUEUE_NAME));
- })
- ;
-
- $producer = new Producer($driver, $this->createRpcFactory());
- $producer->sendEvent('topic', $message);
- }
-
- public function testShouldSendToCustomMessageToApplicationRouter()
- {
- $message = new Message();
- $message->setBody('aBody');
- $message->setScope(Message::SCOPE_APP);
- $message->setProperty(Config::PARAMETER_PROCESSOR_NAME, 'aCustomProcessor');
- $message->setProperty(Config::PARAMETER_PROCESSOR_QUEUE_NAME, 'aCustomProcessorQueue');
-
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->never())
- ->method('sendToRouter')
- ;
- $driver
- ->expects($this->once())
- ->method('sendToProcessor')
- ->willReturnCallback(function (Message $message) {
- self::assertSame('aBody', $message->getBody());
- self::assertSame('aCustomProcessor', $message->getProperty(Config::PARAMETER_PROCESSOR_NAME));
- self::assertSame('aCustomProcessorQueue', $message->getProperty(Config::PARAMETER_PROCESSOR_QUEUE_NAME));
- })
- ;
-
- $producer = new Producer($driver, $this->createRpcFactory());
- $producer->sendEvent('topic', $message);
- }
-
- public function testThrowIfUnSupportedScopeGivenOnSend()
- {
- $message = new Message();
- $message->setScope('iDontKnowScope');
-
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->never())
- ->method('sendToRouter')
- ;
- $driver
- ->expects($this->never())
- ->method('sendToProcessor')
- ;
-
- $producer = new Producer($driver, $this->createRpcFactory());
-
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('The message scope "iDontKnowScope" is not supported.');
- $producer->sendEvent('topic', $message);
- }
-
- public function testShouldCallPreSendPostSendExtensionMethodsWhenSendToRouter()
- {
- $message = new Message();
- $message->setBody('aBody');
- $message->setScope(Message::SCOPE_MESSAGE_BUS);
-
- $extension = $this->createMock(ExtensionInterface::class);
- $extension
- ->expects($this->at(0))
- ->method('onPreSend')
- ->with($this->identicalTo('topic'), $this->identicalTo($message))
- ;
- $extension
- ->expects($this->at(1))
- ->method('onPostSend')
- ->with($this->identicalTo('topic'), $this->identicalTo($message))
- ;
-
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->once())
- ->method('sendToRouter')
- ;
-
- $producer = new Producer($driver, $this->createRpcFactory(), $extension);
- $producer->sendEvent('topic', $message);
- }
-
- public function testShouldCallPreSendPostSendExtensionMethodsWhenSendToProcessor()
- {
- $message = new Message();
- $message->setBody('aBody');
- $message->setScope(Message::SCOPE_APP);
-
- $extension = $this->createMock(ExtensionInterface::class);
- $extension
- ->expects($this->at(0))
- ->method('onPreSend')
- ->with($this->identicalTo('topic'), $this->identicalTo($message))
- ;
- $extension
- ->expects($this->at(1))
- ->method('onPostSend')
- ->with($this->identicalTo('topic'), $this->identicalTo($message))
- ;
-
- $driver = $this->createDriverStub();
- $driver
- ->expects($this->once())
- ->method('sendToProcessor')
- ;
-
- $producer = new Producer($driver, $this->createRpcFactory(), $extension);
- $producer->sendEvent('topic', $message);
+ self::assertClassFinal(Producer::class);
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|RpcFactory
+ * @return \PHPUnit\Framework\MockObject\MockObject
*/
- private function createRpcFactory()
+ private function createRpcFactoryMock(): RpcFactory
{
return $this->createMock(RpcFactory::class);
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|DriverInterface
+ * @return \PHPUnit\Framework\MockObject\MockObject
*/
- private function createDriverStub()
- {
- $config = new Config(
- 'a_prefix',
- 'an_app',
- 'a_router_topic',
- 'a_router_queue',
- 'a_default_processor_queue',
- 'a_router_processor_name'
- );
-
- $driverMock = $this->createMock(DriverInterface::class);
- $driverMock
- ->expects($this->any())
- ->method('getConfig')
- ->willReturn($config)
- ;
-
- return $driverMock;
- }
-}
-
-class JsonSerializableObject implements \JsonSerializable
-{
- public function jsonSerialize()
+ private function createDriverMock(): DriverInterface
{
- return ['foo' => 'fooVal'];
+ return $this->createMock(DriverInterface::class);
}
}
diff --git a/pkg/enqueue/Tests/Client/ResourcesTest.php b/pkg/enqueue/Tests/Client/ResourcesTest.php
new file mode 100644
index 000000000..e79fb9dda
--- /dev/null
+++ b/pkg/enqueue/Tests/Client/ResourcesTest.php
@@ -0,0 +1,159 @@
+assertTrue($rc->isFinal());
+ }
+
+ public function testShouldConstructorBePrivate()
+ {
+ $rc = new \ReflectionClass(Resources::class);
+
+ $this->assertTrue($rc->getConstructor()->isPrivate());
+ }
+
+ public function testShouldGetAvailableDriverInExpectedFormat()
+ {
+ $availableDrivers = Resources::getAvailableDrivers();
+
+ self::assertIsArray($availableDrivers);
+ $this->assertGreaterThan(0, count($availableDrivers));
+
+ $driverInfo = $availableDrivers[0];
+
+ $this->assertArrayHasKey('driverClass', $driverInfo);
+ $this->assertSame(AmqpDriver::class, $driverInfo['driverClass']);
+
+ $this->assertArrayHasKey('schemes', $driverInfo);
+ $this->assertSame(['amqp', 'amqps'], $driverInfo['schemes']);
+
+ $this->assertArrayHasKey('requiredSchemeExtensions', $driverInfo);
+ $this->assertSame([], $driverInfo['requiredSchemeExtensions']);
+
+ $this->assertArrayHasKey('packages', $driverInfo);
+ $this->assertSame(['enqueue/enqueue', 'enqueue/amqp-bunny'], $driverInfo['packages']);
+ }
+
+ public function testShouldGetAvailableDriverWithRequiredExtensionInExpectedFormat()
+ {
+ $availableDrivers = Resources::getAvailableDrivers();
+
+ self::assertIsArray($availableDrivers);
+ $this->assertGreaterThan(0, count($availableDrivers));
+
+ $driverInfo = $availableDrivers[1];
+
+ $this->assertArrayHasKey('driverClass', $driverInfo);
+ $this->assertSame(RabbitMqDriver::class, $driverInfo['driverClass']);
+
+ $this->assertArrayHasKey('schemes', $driverInfo);
+ $this->assertSame(['amqp', 'amqps'], $driverInfo['schemes']);
+
+ $this->assertArrayHasKey('requiredSchemeExtensions', $driverInfo);
+ $this->assertSame(['rabbitmq'], $driverInfo['requiredSchemeExtensions']);
+
+ $this->assertArrayHasKey('packages', $driverInfo);
+ $this->assertSame(['enqueue/enqueue', 'enqueue/amqp-bunny'], $driverInfo['packages']);
+ }
+
+ public function testShouldGetKnownDriversInExpectedFormat()
+ {
+ $knownDrivers = Resources::getAvailableDrivers();
+
+ self::assertIsArray($knownDrivers);
+ $this->assertGreaterThan(0, count($knownDrivers));
+
+ $driverInfo = $knownDrivers[0];
+
+ $this->assertArrayHasKey('driverClass', $driverInfo);
+ $this->assertSame(AmqpDriver::class, $driverInfo['driverClass']);
+
+ $this->assertArrayHasKey('schemes', $driverInfo);
+ $this->assertSame(['amqp', 'amqps'], $driverInfo['schemes']);
+
+ $this->assertArrayHasKey('requiredSchemeExtensions', $driverInfo);
+ $this->assertSame([], $driverInfo['requiredSchemeExtensions']);
+
+ $this->assertArrayHasKey('packages', $driverInfo);
+ $this->assertSame(['enqueue/enqueue', 'enqueue/amqp-bunny'], $driverInfo['packages']);
+ }
+
+ public function testThrowsIfDriverClassNotImplementDriverFactoryInterfaceOnAddDriver()
+ {
+ $this->expectException(\InvalidArgumentException::class);
+ $this->expectExceptionMessage('The driver class "stdClass" must implement "Enqueue\Client\DriverInterface" interface.');
+
+ Resources::addDriver(\stdClass::class, [], [], ['foo']);
+ }
+
+ public function testThrowsIfNoSchemesProvidedOnAddDriver()
+ {
+ $driverClass = $this->getMockClass(DriverInterface::class);
+
+ $this->expectException(\InvalidArgumentException::class);
+ $this->expectExceptionMessage('Schemes could not be empty.');
+
+ Resources::addDriver($driverClass, [], [], ['foo']);
+ }
+
+ public function testThrowsIfNoPackageProvidedOnAddDriver()
+ {
+ $driverClass = $this->getMockClass(DriverInterface::class);
+
+ $this->expectException(\InvalidArgumentException::class);
+ $this->expectExceptionMessage('Packages could not be empty.');
+
+ Resources::addDriver($driverClass, ['foo'], [], []);
+ }
+
+ public function testShouldAllowRegisterDriverThatIsNotInstalled()
+ {
+ Resources::addDriver('theDriverClass', ['foo'], ['barExtension'], ['foo']);
+
+ $availableDrivers = Resources::getKnownDrivers();
+
+ $driverInfo = end($availableDrivers);
+
+ $this->assertSame('theDriverClass', $driverInfo['driverClass']);
+ }
+
+ public function testShouldAllowGetPreviouslyRegisteredDriver()
+ {
+ $driverClass = $this->getMockClass(DriverInterface::class);
+
+ Resources::addDriver(
+ $driverClass,
+ ['fooscheme', 'barscheme'],
+ ['fooextension', 'barextension'],
+ ['foo/bar']
+ );
+
+ $availableDrivers = Resources::getAvailableDrivers();
+
+ $driverInfo = end($availableDrivers);
+
+ $this->assertArrayHasKey('driverClass', $driverInfo);
+ $this->assertSame($driverClass, $driverInfo['driverClass']);
+
+ $this->assertArrayHasKey('schemes', $driverInfo);
+ $this->assertSame(['fooscheme', 'barscheme'], $driverInfo['schemes']);
+
+ $this->assertArrayHasKey('requiredSchemeExtensions', $driverInfo);
+ $this->assertSame(['fooextension', 'barextension'], $driverInfo['requiredSchemeExtensions']);
+
+ $this->assertArrayHasKey('packages', $driverInfo);
+ $this->assertSame(['foo/bar'], $driverInfo['packages']);
+ }
+}
diff --git a/pkg/enqueue/Tests/Client/RouterProcessorTest.php b/pkg/enqueue/Tests/Client/RouterProcessorTest.php
index e362c1e23..7d2971189 100644
--- a/pkg/enqueue/Tests/Client/RouterProcessorTest.php
+++ b/pkg/enqueue/Tests/Client/RouterProcessorTest.php
@@ -4,203 +4,218 @@
use Enqueue\Client\Config;
use Enqueue\Client\DriverInterface;
+use Enqueue\Client\DriverSendResult;
use Enqueue\Client\Message;
+use Enqueue\Client\Route;
+use Enqueue\Client\RouteCollection;
use Enqueue\Client\RouterProcessor;
use Enqueue\Consumption\Result;
use Enqueue\Null\NullContext;
use Enqueue\Null\NullMessage;
+use Enqueue\Test\ClassExtensionTrait;
+use Enqueue\Test\ReadAttributeTrait;
+use Interop\Queue\Destination;
+use Interop\Queue\Message as TransportMessage;
+use Interop\Queue\Processor;
use PHPUnit\Framework\TestCase;
class RouterProcessorTest extends TestCase
{
- public function testCouldBeConstructedWithDriverAsFirstArgument()
+ use ClassExtensionTrait;
+ use ReadAttributeTrait;
+
+ public function testShouldImplementProcessorInterface()
+ {
+ $this->assertClassImplements(Processor::class, RouterProcessor::class);
+ }
+
+ public function testShouldBeFinal()
{
- new RouterProcessor($this->createDriverMock());
+ $this->assertClassFinal(RouterProcessor::class);
}
- public function testCouldBeConstructedWithSessionAndRoutes()
+ public function testCouldBeConstructedWithDriver()
{
- $routes = [
- 'aTopicName' => [['aProcessorName', 'aQueueName']],
- 'anotherTopicName' => [['aProcessorName', 'aQueueName']],
- ];
+ $driver = $this->createDriverStub();
- $router = new RouterProcessor($this->createDriverMock(), $routes);
+ $processor = new RouterProcessor($driver);
- $this->assertAttributeEquals($routes, 'eventRoutes', $router);
+ $this->assertAttributeSame($driver, 'driver', $processor);
}
- public function testShouldRejectIfTopicNameParameterIsNotSet()
+ public function testShouldRejectIfTopicNotSet()
{
- $router = new RouterProcessor($this->createDriverMock());
+ $router = new RouterProcessor($this->createDriverStub());
$result = $router->process(new NullMessage(), new NullContext());
- $this->assertInstanceOf(Result::class, $result);
$this->assertEquals(Result::REJECT, $result->getStatus());
- $this->assertEquals('Got message without required parameter: "enqueue.topic_name"', $result->getReason());
+ $this->assertEquals('Topic property "enqueue.topic" is required but not set or empty.', $result->getReason());
+ }
+
+ public function testShouldRejectIfCommandSet()
+ {
+ $router = new RouterProcessor($this->createDriverStub());
+
+ $message = new NullMessage();
+ $message->setProperty(Config::COMMAND, 'aCommand');
+
+ $result = $router->process($message, new NullContext());
+
+ $this->assertEquals(Result::REJECT, $result->getStatus());
+ $this->assertEquals('Unexpected command "aCommand" got. Command must not go to the router.', $result->getReason());
}
- public function testShouldRouteOriginalMessageToEventRecipient()
+ public function testShouldRouteOriginalMessageToAllRecipients()
{
$message = new NullMessage();
$message->setBody('theBody');
$message->setHeaders(['aHeader' => 'aHeaderVal']);
- $message->setProperties(['aProp' => 'aPropVal', Config::PARAMETER_TOPIC_NAME => 'theTopicName']);
+ $message->setProperties(['aProp' => 'aPropVal', Config::TOPIC => 'theTopicName']);
- $clientMessage = new Message();
+ /** @var Message[] $routedMessages */
+ $routedMessages = new \ArrayObject();
- $routedMessage = null;
+ $routeCollection = new RouteCollection([
+ new Route('theTopicName', Route::TOPIC, 'aFooProcessor'),
+ new Route('theTopicName', Route::TOPIC, 'aBarProcessor'),
+ new Route('theTopicName', Route::TOPIC, 'aBazProcessor'),
+ ]);
- $driver = $this->createDriverMock();
+ $driver = $this->createDriverStub($routeCollection);
$driver
- ->expects($this->once())
+ ->expects($this->exactly(3))
->method('sendToProcessor')
- ->with($this->identicalTo($clientMessage))
+ ->willReturnCallback(function (Message $message) use ($routedMessages) {
+ $routedMessages->append($message);
+
+ return $this->createDriverSendResult();
+ })
;
$driver
- ->expects($this->once())
+ ->expects($this->exactly(3))
->method('createClientMessage')
- ->willReturnCallback(function (NullMessage $message) use (&$routedMessage, $clientMessage) {
- $routedMessage = $message;
-
- return $clientMessage;
+ ->willReturnCallback(function (NullMessage $message) {
+ return new Message($message->getBody(), $message->getProperties(), $message->getHeaders());
})
;
- $routes = [
- 'theTopicName' => [['aFooProcessor', 'aQueueName']],
- ];
+ $processor = new RouterProcessor($driver);
- $router = new RouterProcessor($driver, $routes);
+ $result = $processor->process($message, new NullContext());
- $result = $router->process($message, new NullContext());
+ $this->assertEquals(Result::ACK, $result->getStatus());
+ $this->assertEquals('Routed to "3" event subscribers', $result->getReason());
+
+ $this->assertContainsOnly(Message::class, $routedMessages);
+ $this->assertCount(3, $routedMessages);
- $this->assertEquals(Result::ACK, $result);
- $this->assertEquals([
- 'aProp' => 'aPropVal',
- 'enqueue.topic_name' => 'theTopicName',
- 'enqueue.processor_name' => 'aFooProcessor',
- 'enqueue.processor_queue_name' => 'aQueueName',
- ], $routedMessage->getProperties());
+ $this->assertSame('aFooProcessor', $routedMessages[0]->getProperty(Config::PROCESSOR));
+ $this->assertSame('aBarProcessor', $routedMessages[1]->getProperty(Config::PROCESSOR));
+ $this->assertSame('aBazProcessor', $routedMessages[2]->getProperty(Config::PROCESSOR));
}
- public function testShouldRouteOriginalMessageToCommandRecipient()
+ public function testShouldDoNothingIfNoRoutes()
{
$message = new NullMessage();
$message->setBody('theBody');
$message->setHeaders(['aHeader' => 'aHeaderVal']);
- $message->setProperties([
- 'aProp' => 'aPropVal',
- Config::PARAMETER_TOPIC_NAME => Config::COMMAND_TOPIC,
- Config::PARAMETER_COMMAND_NAME => 'theCommandName',
- ]);
+ $message->setProperties(['aProp' => 'aPropVal', Config::TOPIC => 'theTopicName']);
- $clientMessage = new Message();
+ /** @var Message[] $routedMessages */
+ $routedMessages = new \ArrayObject();
- $routedMessage = null;
+ $routeCollection = new RouteCollection([]);
- $driver = $this->createDriverMock();
+ $driver = $this->createDriverStub($routeCollection);
$driver
- ->expects($this->once())
+ ->expects($this->never())
->method('sendToProcessor')
- ->with($this->identicalTo($clientMessage))
+ ->willReturnCallback(function (Message $message) use ($routedMessages) {
+ $routedMessages->append($message);
+ })
;
$driver
- ->expects($this->once())
+ ->expects($this->never())
->method('createClientMessage')
- ->willReturnCallback(function (NullMessage $message) use (&$routedMessage, $clientMessage) {
- $routedMessage = $message;
-
- return $clientMessage;
+ ->willReturnCallback(function (NullMessage $message) {
+ return new Message($message->getBody(), $message->getProperties(), $message->getHeaders());
})
;
- $routes = [
- 'theCommandName' => 'aQueueName',
- ];
+ $processor = new RouterProcessor($driver);
- $router = new RouterProcessor($driver, [], $routes);
+ $result = $processor->process($message, new NullContext());
- $result = $router->process($message, new NullContext());
+ $this->assertEquals(Result::ACK, $result->getStatus());
+ $this->assertEquals('Routed to "0" event subscribers', $result->getReason());
- $this->assertEquals(Result::ACK, $result);
- $this->assertEquals([
- 'aProp' => 'aPropVal',
- 'enqueue.topic_name' => Config::COMMAND_TOPIC,
- 'enqueue.processor_name' => 'theCommandName',
- 'enqueue.command_name' => 'theCommandName',
- 'enqueue.processor_queue_name' => 'aQueueName',
- ], $routedMessage->getProperties());
+ $this->assertCount(0, $routedMessages);
}
- public function testShouldRejectCommandMessageIfCommandNamePropertyMissing()
+ public function testShouldDoNotModifyOriginalMessage()
{
$message = new NullMessage();
$message->setBody('theBody');
$message->setHeaders(['aHeader' => 'aHeaderVal']);
- $message->setProperties([
- 'aProp' => 'aPropVal',
- Config::PARAMETER_TOPIC_NAME => Config::COMMAND_TOPIC,
+ $message->setProperties(['aProp' => 'aPropVal', Config::TOPIC => 'theTopicName']);
+
+ /** @var Message[] $routedMessages */
+ $routedMessages = new \ArrayObject();
+
+ $routeCollection = new RouteCollection([
+ new Route('theTopicName', Route::TOPIC, 'aFooProcessor'),
+ new Route('theTopicName', Route::TOPIC, 'aBarProcessor'),
]);
- $driver = $this->createDriverMock();
+ $driver = $this->createDriverStub($routeCollection);
$driver
- ->expects($this->never())
+ ->expects($this->atLeastOnce())
->method('sendToProcessor')
- ;
+ ->willReturnCallback(function (Message $message) use ($routedMessages) {
+ $routedMessages->append($message);
+
+ return $this->createDriverSendResult();
+ });
$driver
- ->expects($this->never())
+ ->expects($this->atLeastOnce())
->method('createClientMessage')
- ;
-
- $routes = [
- 'theCommandName' => 'aQueueName',
- ];
-
- $router = new RouterProcessor($driver, [], $routes);
-
- $result = $router->process($message, new NullContext());
-
- $this->assertInstanceOf(Result::class, $result);
- $this->assertEquals(Result::REJECT, $result->getStatus());
- $this->assertEquals('Got message without required parameter: "enqueue.command_name"', $result->getReason());
- }
-
- public function testShouldAddEventRoute()
- {
- $router = new RouterProcessor($this->createDriverMock(), []);
+ ->willReturnCallback(function (NullMessage $message) {
+ return new Message($message->getBody(), $message->getProperties(), $message->getHeaders());
+ });
- $this->assertAttributeSame([], 'eventRoutes', $router);
+ $processor = new RouterProcessor($driver);
- $router->add('theTopicName', 'theQueueName', 'aProcessorName');
+ $result = $processor->process($message, new NullContext());
- $this->assertAttributeSame([
- 'theTopicName' => [
- ['aProcessorName', 'theQueueName'],
- ],
- ], 'eventRoutes', $router);
+ // guard
+ $this->assertEquals(Result::ACK, $result->getStatus());
- $this->assertAttributeSame([], 'commandRoutes', $router);
+ $this->assertSame('theBody', $message->getBody());
+ $this->assertSame(['aProp' => 'aPropVal', Config::TOPIC => 'theTopicName'], $message->getProperties());
+ $this->assertSame(['aHeader' => 'aHeaderVal'], $message->getHeaders());
}
- public function testShouldAddCommandRoute()
+ /**
+ * @return \PHPUnit\Framework\MockObject\MockObject|DriverInterface
+ */
+ private function createDriverStub(?RouteCollection $routeCollection = null): DriverInterface
{
- $router = new RouterProcessor($this->createDriverMock(), []);
-
- $this->assertAttributeSame([], 'eventRoutes', $router);
-
- $router->add(Config::COMMAND_TOPIC, 'theQueueName', 'aProcessorName');
+ $driver = $this->createMock(DriverInterface::class);
+ $driver
+ ->expects($this->any())
+ ->method('getRouteCollection')
+ ->willReturn($routeCollection ?? new RouteCollection([]))
+ ;
- $this->assertAttributeSame(['aProcessorName' => 'theQueueName'], 'commandRoutes', $router);
- $this->assertAttributeSame([], 'eventRoutes', $router);
+ return $driver;
}
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject|DriverInterface
- */
- protected function createDriverMock()
+ private function createDriverSendResult(): DriverSendResult
{
- return $this->createMock(DriverInterface::class);
+ return new DriverSendResult(
+ $this->createMock(Destination::class),
+ $this->createMock(TransportMessage::class)
+ );
}
}
diff --git a/pkg/enqueue/Tests/Client/SpoolProducerTest.php b/pkg/enqueue/Tests/Client/SpoolProducerTest.php
index 8c00dedcd..014fe4962 100644
--- a/pkg/enqueue/Tests/Client/SpoolProducerTest.php
+++ b/pkg/enqueue/Tests/Client/SpoolProducerTest.php
@@ -18,11 +18,6 @@ public function testShouldImplementProducerInterface()
self::assertClassImplements(ProducerInterface::class, SpoolProducer::class);
}
- public function testCouldBeConstructedWithRealProducer()
- {
- new SpoolProducer($this->createProducerMock());
- }
-
public function testShouldQueueEventMessageOnSend()
{
$message = new Message();
@@ -154,7 +149,7 @@ public function testShouldSendImmediatelyCommandMessageWithNeedReplyTrue()
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|ProducerInterface
+ * @return \PHPUnit\Framework\MockObject\MockObject|ProducerInterface
*/
protected function createProducerMock()
{
diff --git a/pkg/enqueue/Tests/Client/TraceableProducerTest.php b/pkg/enqueue/Tests/Client/TraceableProducerTest.php
index 42c9c8b8f..b0df066ce 100644
--- a/pkg/enqueue/Tests/Client/TraceableProducerTest.php
+++ b/pkg/enqueue/Tests/Client/TraceableProducerTest.php
@@ -2,7 +2,7 @@
namespace Enqueue\Tests\Client;
-use Enqueue\Client\Config;
+use DMS\PHPUnitExtensions\ArraySubset\Assert;
use Enqueue\Client\Message;
use Enqueue\Client\ProducerInterface;
use Enqueue\Client\TraceableProducer;
@@ -18,11 +18,6 @@ public function testShouldImplementProducerInterface()
$this->assertClassImplements(ProducerInterface::class, TraceableProducer::class);
}
- public function testCouldBeConstructedWithInternalMessageProducer()
- {
- new TraceableProducer($this->createProducerMock());
- }
-
public function testShouldPassAllArgumentsToInternalEventMessageProducerSendMethod()
{
$topic = 'theTopic';
@@ -46,7 +41,7 @@ public function testShouldCollectInfoIfStringGivenAsEventMessage()
$producer->sendEvent('aFooTopic', 'aFooBody');
- $this->assertSame([
+ Assert::assertArraySubset([
[
'topic' => 'aFooTopic',
'command' => null,
@@ -61,6 +56,8 @@ public function testShouldCollectInfoIfStringGivenAsEventMessage()
'messageId' => null,
],
], $producer->getTraces());
+
+ $this->assertArrayHasKey('sentAt', $producer->getTraces()[0]);
}
public function testShouldCollectInfoIfArrayGivenAsEventMessage()
@@ -69,7 +66,7 @@ public function testShouldCollectInfoIfArrayGivenAsEventMessage()
$producer->sendEvent('aFooTopic', ['foo' => 'fooVal', 'bar' => 'barVal']);
- $this->assertSame([
+ Assert::assertArraySubset([
[
'topic' => 'aFooTopic',
'command' => null,
@@ -84,6 +81,8 @@ public function testShouldCollectInfoIfArrayGivenAsEventMessage()
'messageId' => null,
],
], $producer->getTraces());
+
+ $this->assertArrayHasKey('sentAt', $producer->getTraces()[0]);
}
public function testShouldCollectInfoIfEventMessageObjectGivenAsMessage()
@@ -103,7 +102,7 @@ public function testShouldCollectInfoIfEventMessageObjectGivenAsMessage()
$producer->sendEvent('aFooTopic', $message);
- $this->assertSame([
+ Assert::assertArraySubset([
[
'topic' => 'aFooTopic',
'command' => null,
@@ -118,6 +117,8 @@ public function testShouldCollectInfoIfEventMessageObjectGivenAsMessage()
'messageId' => 'theMessageId',
],
], $producer->getTraces());
+
+ $this->assertArrayHasKey('sentAt', $producer->getTraces()[0]);
}
public function testShouldNotStoreAnythingIfInternalEventMessageProducerThrowsException()
@@ -163,9 +164,9 @@ public function testShouldCollectInfoIfStringGivenAsCommandMessage()
$producer->sendCommand('aFooCommand', 'aFooBody');
- $this->assertSame([
+ Assert::assertArraySubset([
[
- 'topic' => Config::COMMAND_TOPIC,
+ 'topic' => null,
'command' => 'aFooCommand',
'body' => 'aFooBody',
'headers' => [],
@@ -178,6 +179,8 @@ public function testShouldCollectInfoIfStringGivenAsCommandMessage()
'messageId' => null,
],
], $producer->getTraces());
+
+ $this->assertArrayHasKey('sentAt', $producer->getTraces()[0]);
}
public function testShouldCollectInfoIfArrayGivenAsCommandMessage()
@@ -186,9 +189,9 @@ public function testShouldCollectInfoIfArrayGivenAsCommandMessage()
$producer->sendCommand('aFooCommand', ['foo' => 'fooVal', 'bar' => 'barVal']);
- $this->assertSame([
+ Assert::assertArraySubset([
[
- 'topic' => Config::COMMAND_TOPIC,
+ 'topic' => null,
'command' => 'aFooCommand',
'body' => ['foo' => 'fooVal', 'bar' => 'barVal'],
'headers' => [],
@@ -201,6 +204,8 @@ public function testShouldCollectInfoIfArrayGivenAsCommandMessage()
'messageId' => null,
],
], $producer->getTraces());
+
+ $this->assertArrayHasKey('sentAt', $producer->getTraces()[0]);
}
public function testShouldCollectInfoIfCommandMessageObjectGivenAsMessage()
@@ -220,9 +225,9 @@ public function testShouldCollectInfoIfCommandMessageObjectGivenAsMessage()
$producer->sendCommand('aFooCommand', $message);
- $this->assertSame([
+ Assert::assertArraySubset([
[
- 'topic' => Config::COMMAND_TOPIC,
+ 'topic' => null,
'command' => 'aFooCommand',
'body' => ['foo' => 'fooVal', 'bar' => 'barVal'],
'headers' => ['fooHeader' => 'fooVal'],
@@ -235,6 +240,8 @@ public function testShouldCollectInfoIfCommandMessageObjectGivenAsMessage()
'messageId' => 'theMessageId',
],
], $producer->getTraces());
+
+ $this->assertArrayHasKey('sentAt', $producer->getTraces()[0]);
}
public function testShouldNotStoreAnythingIfInternalCommandMessageProducerThrowsException()
@@ -264,9 +271,9 @@ public function testShouldAllowGetInfoSentToSameTopic()
$producer->sendEvent('aFooTopic', 'aFooBody');
$producer->sendEvent('aFooTopic', 'aFooBody');
- $this->assertArraySubset([
- ['topic' => 'aFooTopic', 'body' => 'aFooBody'],
- ['topic' => 'aFooTopic', 'body' => 'aFooBody'],
+ Assert::assertArraySubset([
+ ['topic' => 'aFooTopic', 'body' => 'aFooBody'],
+ ['topic' => 'aFooTopic', 'body' => 'aFooBody'],
], $producer->getTraces());
}
@@ -277,7 +284,7 @@ public function testShouldAllowGetInfoSentToDifferentTopics()
$producer->sendEvent('aFooTopic', 'aFooBody');
$producer->sendEvent('aBarTopic', 'aBarBody');
- $this->assertArraySubset([
+ Assert::assertArraySubset([
['topic' => 'aFooTopic', 'body' => 'aFooBody'],
['topic' => 'aBarTopic', 'body' => 'aBarBody'],
], $producer->getTraces());
@@ -290,11 +297,11 @@ public function testShouldAllowGetInfoSentToSpecialTopic()
$producer->sendEvent('aFooTopic', 'aFooBody');
$producer->sendEvent('aBarTopic', 'aBarBody');
- $this->assertArraySubset([
+ Assert::assertArraySubset([
['topic' => 'aFooTopic', 'body' => 'aFooBody'],
], $producer->getTopicTraces('aFooTopic'));
- $this->assertArraySubset([
+ Assert::assertArraySubset([
['topic' => 'aBarTopic', 'body' => 'aBarBody'],
], $producer->getTopicTraces('aBarTopic'));
}
@@ -306,7 +313,7 @@ public function testShouldAllowGetInfoSentToSameCommand()
$producer->sendCommand('aFooCommand', 'aFooBody');
$producer->sendCommand('aFooCommand', 'aFooBody');
- $this->assertArraySubset([
+ Assert::assertArraySubset([
['command' => 'aFooCommand', 'body' => 'aFooBody'],
['command' => 'aFooCommand', 'body' => 'aFooBody'],
], $producer->getTraces());
@@ -319,7 +326,7 @@ public function testShouldAllowGetInfoSentToDifferentCommands()
$producer->sendCommand('aFooCommand', 'aFooBody');
$producer->sendCommand('aBarCommand', 'aBarBody');
- $this->assertArraySubset([
+ Assert::assertArraySubset([
['command' => 'aFooCommand', 'body' => 'aFooBody'],
['command' => 'aBarCommand', 'body' => 'aBarBody'],
], $producer->getTraces());
@@ -332,11 +339,11 @@ public function testShouldAllowGetInfoSentToSpecialCommand()
$producer->sendCommand('aFooCommand', 'aFooBody');
$producer->sendCommand('aBarCommand', 'aBarBody');
- $this->assertArraySubset([
+ Assert::assertArraySubset([
['command' => 'aFooCommand', 'body' => 'aFooBody'],
], $producer->getCommandTraces('aFooCommand'));
- $this->assertArraySubset([
+ Assert::assertArraySubset([
['command' => 'aBarCommand', 'body' => 'aBarBody'],
], $producer->getCommandTraces('aBarCommand'));
}
@@ -347,7 +354,7 @@ public function testShouldAllowClearStoredTraces()
$producer->sendEvent('aFooTopic', 'aFooBody');
- //guard
+ // guard
$this->assertNotEmpty($producer->getTraces());
$producer->clearTraces();
@@ -355,7 +362,7 @@ public function testShouldAllowClearStoredTraces()
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|ProducerInterface
+ * @return \PHPUnit\Framework\MockObject\MockObject|ProducerInterface
*/
protected function createProducerMock()
{
diff --git a/pkg/enqueue/Tests/ConnectionFactoryFactoryTest.php b/pkg/enqueue/Tests/ConnectionFactoryFactoryTest.php
new file mode 100644
index 000000000..b6b5b4d67
--- /dev/null
+++ b/pkg/enqueue/Tests/ConnectionFactoryFactoryTest.php
@@ -0,0 +1,183 @@
+assertTrue($rc->implementsInterface(ConnectionFactoryFactoryInterface::class));
+ }
+
+ public function testShouldBeFinal()
+ {
+ $rc = new \ReflectionClass(ConnectionFactoryFactory::class);
+
+ $this->assertTrue($rc->isFinal());
+ }
+
+ /**
+ * @doesNotPerformAssertions
+ */
+ public function testShouldAcceptStringDSN()
+ {
+ $factory = new ConnectionFactoryFactory();
+
+ $factory->create('null:');
+ }
+
+ /**
+ * @doesNotPerformAssertions
+ */
+ public function testShouldAcceptArrayWithDsnKey()
+ {
+ $factory = new ConnectionFactoryFactory();
+
+ $factory->create(['dsn' => 'null:']);
+ }
+
+ public function testThrowIfInvalidConfigGiven()
+ {
+ $factory = new ConnectionFactoryFactory();
+
+ $this->expectException(\InvalidArgumentException::class);
+ $this->expectExceptionMessage('The config must be either array or DSN string.');
+ $factory->create(new \stdClass());
+ }
+
+ public function testThrowIfArrayConfigMissDsnKeyInvalidConfigGiven()
+ {
+ $factory = new ConnectionFactoryFactory();
+
+ $this->expectException(\InvalidArgumentException::class);
+ $this->expectExceptionMessage('The config must be either array or DSN string.');
+ $factory->create(new \stdClass());
+ }
+
+ public function testThrowIfPackageThatSupportSchemeNotInstalled()
+ {
+ $scheme = 'scheme5b7aa7d7cd213';
+ $class = 'ConnectionClass5b7aa7d7cd213';
+
+ Resources::addConnection($class, [$scheme], [], 'thePackage');
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('To use given scheme "scheme5b7aa7d7cd213" a package has to be installed. Run "composer req thePackage" to add it.');
+ (new ConnectionFactoryFactory())->create($scheme.'://foo');
+ }
+
+ public function testThrowIfSchemeIsNotKnown()
+ {
+ $scheme = 'scheme5b7aa862e70a5';
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('A given scheme "scheme5b7aa862e70a5" is not supported. Maybe it is a custom connection, make sure you registered it with "Enqueue\Resources::addConnection".');
+ (new ConnectionFactoryFactory())->create($scheme.'://foo');
+ }
+
+ public function testThrowIfDsnInvalid()
+ {
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('The DSN is invalid. It does not have scheme separator ":".');
+
+ (new ConnectionFactoryFactory())->create('invalid-scheme');
+ }
+
+ /**
+ * @dataProvider provideDSN
+ */
+ public function testReturnsExpectedFactories(string $dsn, string $expectedFactoryClass)
+ {
+ $connectionFactory = (new ConnectionFactoryFactory())->create($dsn);
+
+ $this->assertInstanceOf($expectedFactoryClass, $connectionFactory);
+ }
+
+ public static function provideDSN()
+ {
+ yield ['null:', NullConnectionFactory::class];
+
+ yield ['amqp:', AmqpBunnyConnectionFactory::class];
+
+ yield ['amqp+bunny:', AmqpBunnyConnectionFactory::class];
+
+ yield ['amqp+lib:', AmqpLibConnectionFactory::class];
+
+ yield ['amqp+ext:', AmqpExtConnectionFactory::class];
+
+ yield ['amqp+rabbitmq:', AmqpBunnyConnectionFactory::class];
+
+ yield ['amqp+rabbitmq+bunny:', AmqpBunnyConnectionFactory::class];
+
+ yield ['amqp+foo+bar+lib:', AmqpLibConnectionFactory::class];
+
+ yield ['amqp+rabbitmq+ext:', AmqpExtConnectionFactory::class];
+
+ yield ['amqp+rabbitmq+lib:', AmqpLibConnectionFactory::class];
+
+ // bunny does not support amqps, so it is skipped
+ yield ['amqps:', AmqpExtConnectionFactory::class];
+
+ // bunny does not support amqps, so it is skipped
+ yield ['amqps+ext:', AmqpExtConnectionFactory::class];
+
+ // bunny does not support amqps, so it is skipped
+ yield ['amqps+rabbitmq:', AmqpExtConnectionFactory::class];
+
+ yield ['amqps+ext+rabbitmq:', AmqpExtConnectionFactory::class];
+
+ yield ['amqps+lib+rabbitmq:', AmqpLibConnectionFactory::class];
+
+ yield ['mssql:', DbalConnectionFactory::class];
+
+ yield ['mysql:', DbalConnectionFactory::class];
+
+ yield ['pgsql:', DbalConnectionFactory::class];
+
+ yield ['file:', FsConnectionFactory::class];
+
+ // https://github.com/php-enqueue/enqueue-dev/issues/511
+ // yield ['gearman:', GearmanConnectionFactory::class];
+
+ yield ['gps:', GpsConnectionFactory::class];
+
+ yield ['mongodb:', MongodbConnectionFactory::class];
+
+ yield ['beanstalk:', PheanstalkConnectionFactory::class];
+
+ yield ['kafka:', RdKafkaConnectionFactory::class];
+
+ yield ['redis:', RedisConnectionFactory::class];
+
+ yield ['redis+predis:', RedisConnectionFactory::class];
+
+ yield ['redis+foo+bar+phpredis:', RedisConnectionFactory::class];
+
+ yield ['redis+phpredis:', RedisConnectionFactory::class];
+
+ yield ['sqs:', SqsConnectionFactory::class];
+
+ yield ['stomp:', StompConnectionFactory::class];
+ }
+}
diff --git a/pkg/enqueue/Tests/Consumption/CallbackProcessorTest.php b/pkg/enqueue/Tests/Consumption/CallbackProcessorTest.php
index 1b034d908..86adbd3a9 100644
--- a/pkg/enqueue/Tests/Consumption/CallbackProcessorTest.php
+++ b/pkg/enqueue/Tests/Consumption/CallbackProcessorTest.php
@@ -6,7 +6,7 @@
use Enqueue\Null\NullContext;
use Enqueue\Null\NullMessage;
use Enqueue\Test\ClassExtensionTrait;
-use Interop\Queue\PsrProcessor;
+use Interop\Queue\Processor;
use PHPUnit\Framework\TestCase;
class CallbackProcessorTest extends TestCase
@@ -15,13 +15,7 @@ class CallbackProcessorTest extends TestCase
public function testShouldImplementProcessorInterface()
{
- $this->assertClassImplements(PsrProcessor::class, CallbackProcessor::class);
- }
-
- public function testCouldBeConstructedWithCallableAsArgument()
- {
- new CallbackProcessor(function () {
- });
+ $this->assertClassImplements(Processor::class, CallbackProcessor::class);
}
public function testShouldCallCallbackAndProxyItsReturnedValue()
diff --git a/pkg/enqueue/Tests/Consumption/ChainExtensionTest.php b/pkg/enqueue/Tests/Consumption/ChainExtensionTest.php
index 4c412c661..198d00012 100644
--- a/pkg/enqueue/Tests/Consumption/ChainExtensionTest.php
+++ b/pkg/enqueue/Tests/Consumption/ChainExtensionTest.php
@@ -3,10 +3,26 @@
namespace Enqueue\Tests\Consumption;
use Enqueue\Consumption\ChainExtension;
-use Enqueue\Consumption\Context;
+use Enqueue\Consumption\Context\End;
+use Enqueue\Consumption\Context\InitLogger;
+use Enqueue\Consumption\Context\MessageReceived;
+use Enqueue\Consumption\Context\MessageResult;
+use Enqueue\Consumption\Context\PostConsume;
+use Enqueue\Consumption\Context\PostMessageReceived;
+use Enqueue\Consumption\Context\PreConsume;
+use Enqueue\Consumption\Context\PreSubscribe;
+use Enqueue\Consumption\Context\Start;
use Enqueue\Consumption\ExtensionInterface;
use Enqueue\Test\ClassExtensionTrait;
+use Interop\Queue\Consumer;
+use Interop\Queue\Context;
+use Interop\Queue\Message;
+use Interop\Queue\Processor;
+use Interop\Queue\SubscriptionConsumer;
+use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
+use Psr\Log\LoggerInterface;
+use Psr\Log\NullLogger;
class ChainExtensionTest extends TestCase
{
@@ -17,14 +33,31 @@ public function testShouldImplementExtensionInterface()
$this->assertClassImplements(ExtensionInterface::class, ChainExtension::class);
}
- public function testCouldBeConstructedWithExtensionsArray()
+ public function testShouldProxyOnInitLoggerToAllInternalExtensions()
{
- new ChainExtension([$this->createExtension(), $this->createExtension()]);
+ $context = new InitLogger(new NullLogger());
+
+ $fooExtension = $this->createExtension();
+ $fooExtension
+ ->expects($this->once())
+ ->method('onInitLogger')
+ ->with($this->identicalTo($context))
+ ;
+ $barExtension = $this->createExtension();
+ $barExtension
+ ->expects($this->once())
+ ->method('onInitLogger')
+ ->with($this->identicalTo($context))
+ ;
+
+ $extensions = new ChainExtension([$fooExtension, $barExtension]);
+
+ $extensions->onInitLogger($context);
}
public function testShouldProxyOnStartToAllInternalExtensions()
{
- $context = $this->createContextMock();
+ $context = new Start($this->createInteropContextMock(), $this->createLoggerMock(), [], 0, 0);
$fooExtension = $this->createExtension();
$fooExtension
@@ -44,53 +77,100 @@ public function testShouldProxyOnStartToAllInternalExtensions()
$extensions->onStart($context);
}
- public function testShouldProxyOnBeforeReceiveToAllInternalExtensions()
+ public function testShouldProxyOnPreSubscribeToAllInternalExtensions()
{
- $context = $this->createContextMock();
+ $context = new PreSubscribe(
+ $this->createInteropContextMock(),
+ $this->createInteropProcessorMock(),
+ $this->createInteropConsumerMock(),
+ $this->createLoggerMock()
+ );
$fooExtension = $this->createExtension();
$fooExtension
->expects($this->once())
- ->method('onBeforeReceive')
+ ->method('onPreSubscribe')
->with($this->identicalTo($context))
;
$barExtension = $this->createExtension();
$barExtension
->expects($this->once())
- ->method('onBeforeReceive')
+ ->method('onPreSubscribe')
->with($this->identicalTo($context))
;
$extensions = new ChainExtension([$fooExtension, $barExtension]);
- $extensions->onBeforeReceive($context);
+ $extensions->onPreSubscribe($context);
+ }
+
+ public function testShouldProxyOnPreConsumeToAllInternalExtensions()
+ {
+ $context = new PreConsume(
+ $this->createInteropContextMock(),
+ $this->createSubscriptionConsumerMock(),
+ new NullLogger(),
+ 1,
+ 2,
+ 3
+ );
+
+ $fooExtension = $this->createExtension();
+ $fooExtension
+ ->expects($this->once())
+ ->method('onPreConsume')
+ ->with($this->identicalTo($context))
+ ;
+ $barExtension = $this->createExtension();
+ $barExtension
+ ->expects($this->once())
+ ->method('onPreConsume')
+ ->with($this->identicalTo($context))
+ ;
+
+ $extensions = new ChainExtension([$fooExtension, $barExtension]);
+ $extensions->onPreConsume($context);
}
public function testShouldProxyOnPreReceiveToAllInternalExtensions()
{
- $context = $this->createContextMock();
+ $context = new MessageReceived(
+ $this->createInteropContextMock(),
+ $this->createMock(Consumer::class),
+ $this->createMock(Message::class),
+ $this->createMock(Processor::class),
+ 1,
+ new NullLogger()
+ );
$fooExtension = $this->createExtension();
$fooExtension
->expects($this->once())
- ->method('onPreReceived')
+ ->method('onMessageReceived')
->with($this->identicalTo($context))
;
$barExtension = $this->createExtension();
$barExtension
->expects($this->once())
- ->method('onPreReceived')
+ ->method('onMessageReceived')
->with($this->identicalTo($context))
;
$extensions = new ChainExtension([$fooExtension, $barExtension]);
- $extensions->onPreReceived($context);
+ $extensions->onMessageReceived($context);
}
public function testShouldProxyOnResultToAllInternalExtensions()
{
- $context = $this->createContextMock();
+ $context = new MessageResult(
+ $this->createInteropContextMock(),
+ $this->createInteropConsumerMock(),
+ $this->createMock(Message::class),
+ 'aResult',
+ 1,
+ new NullLogger()
+ );
$fooExtension = $this->createExtension();
$fooExtension
@@ -112,83 +192,129 @@ public function testShouldProxyOnResultToAllInternalExtensions()
public function testShouldProxyOnPostReceiveToAllInternalExtensions()
{
- $context = $this->createContextMock();
+ $context = new PostMessageReceived(
+ $this->createInteropContextMock(),
+ $this->createMock(Consumer::class),
+ $this->createMock(Message::class),
+ 'aResult',
+ 1,
+ new NullLogger()
+ );
$fooExtension = $this->createExtension();
$fooExtension
->expects($this->once())
- ->method('onPostReceived')
+ ->method('onPostMessageReceived')
->with($this->identicalTo($context))
;
$barExtension = $this->createExtension();
$barExtension
->expects($this->once())
- ->method('onPostReceived')
+ ->method('onPostMessageReceived')
->with($this->identicalTo($context))
;
$extensions = new ChainExtension([$fooExtension, $barExtension]);
- $extensions->onPostReceived($context);
+ $extensions->onPostMessageReceived($context);
}
- public function testShouldProxyOnIdleToAllInternalExtensions()
+ public function testShouldProxyOnPostConsumeToAllInternalExtensions()
{
- $context = $this->createContextMock();
+ $postConsume = new PostConsume(
+ $this->createInteropContextMock(),
+ $this->createSubscriptionConsumerMock(),
+ 1,
+ 1,
+ 1,
+ new NullLogger()
+ );
$fooExtension = $this->createExtension();
$fooExtension
->expects($this->once())
- ->method('onIdle')
- ->with($this->identicalTo($context))
+ ->method('onPostConsume')
+ ->with($this->identicalTo($postConsume))
;
$barExtension = $this->createExtension();
$barExtension
->expects($this->once())
- ->method('onIdle')
- ->with($this->identicalTo($context))
+ ->method('onPostConsume')
+ ->with($this->identicalTo($postConsume))
;
$extensions = new ChainExtension([$fooExtension, $barExtension]);
- $extensions->onIdle($context);
+ $extensions->onPostConsume($postConsume);
}
- public function testShouldProxyOnInterruptedToAllInternalExtensions()
+ public function testShouldProxyOnEndToAllInternalExtensions()
{
- $context = $this->createContextMock();
+ $context = new End($this->createInteropContextMock(), 1, 2, new NullLogger());
$fooExtension = $this->createExtension();
$fooExtension
->expects($this->once())
- ->method('onInterrupted')
+ ->method('onEnd')
->with($this->identicalTo($context))
;
$barExtension = $this->createExtension();
$barExtension
->expects($this->once())
- ->method('onInterrupted')
+ ->method('onEnd')
->with($this->identicalTo($context))
;
$extensions = new ChainExtension([$fooExtension, $barExtension]);
- $extensions->onInterrupted($context);
+ $extensions->onEnd($context);
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|Context
+ * @return MockObject
*/
- protected function createContextMock()
+ protected function createLoggerMock(): LoggerInterface
+ {
+ return $this->createMock(LoggerInterface::class);
+ }
+
+ /**
+ * @return MockObject
+ */
+ protected function createInteropContextMock(): Context
{
return $this->createMock(Context::class);
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|ExtensionInterface
+ * @return MockObject
+ */
+ protected function createInteropConsumerMock(): Consumer
+ {
+ return $this->createMock(Consumer::class);
+ }
+
+ /**
+ * @return MockObject
+ */
+ protected function createInteropProcessorMock(): Processor
+ {
+ return $this->createMock(Processor::class);
+ }
+
+ /**
+ * @return MockObject|ExtensionInterface
*/
protected function createExtension()
{
return $this->createMock(ExtensionInterface::class);
}
+
+ /**
+ * @return MockObject
+ */
+ private function createSubscriptionConsumerMock(): SubscriptionConsumer
+ {
+ return $this->createMock(SubscriptionConsumer::class);
+ }
}
diff --git a/pkg/enqueue/Tests/Consumption/ContextTest.php b/pkg/enqueue/Tests/Consumption/ContextTest.php
deleted file mode 100644
index a0f6b266a..000000000
--- a/pkg/enqueue/Tests/Consumption/ContextTest.php
+++ /dev/null
@@ -1,258 +0,0 @@
-createPsrContext());
- }
-
- public function testShouldAllowGetSessionSetInConstructor()
- {
- $psrContext = $this->createPsrContext();
-
- $context = new Context($psrContext);
-
- $this->assertSame($psrContext, $context->getPsrContext());
- }
-
- public function testShouldAllowGetMessageConsumerPreviouslySet()
- {
- $messageConsumer = $this->createPsrConsumer();
-
- $context = new Context($this->createPsrContext());
- $context->setPsrConsumer($messageConsumer);
-
- $this->assertSame($messageConsumer, $context->getPsrConsumer());
- }
-
- public function testThrowOnTryToChangeMessageConsumerIfAlreadySet()
- {
- $messageConsumer = $this->createPsrConsumer();
- $anotherMessageConsumer = $this->createPsrConsumer();
-
- $context = new Context($this->createPsrContext());
-
- $context->setPsrConsumer($messageConsumer);
-
- $this->expectException(IllegalContextModificationException::class);
-
- $context->setPsrConsumer($anotherMessageConsumer);
- }
-
- public function testShouldAllowGetMessageProducerPreviouslySet()
- {
- $processorMock = $this->createProcessorMock();
-
- $context = new Context($this->createPsrContext());
- $context->setPsrProcessor($processorMock);
-
- $this->assertSame($processorMock, $context->getPsrProcessor());
- }
-
- public function testThrowOnTryToChangeProcessorIfAlreadySet()
- {
- $processor = $this->createProcessorMock();
- $anotherProcessor = $this->createProcessorMock();
-
- $context = new Context($this->createPsrContext());
-
- $context->setPsrProcessor($processor);
-
- $this->expectException(IllegalContextModificationException::class);
-
- $context->setPsrProcessor($anotherProcessor);
- }
-
- public function testShouldAllowGetLoggerPreviouslySet()
- {
- $logger = new NullLogger();
-
- $context = new Context($this->createPsrContext());
- $context->setLogger($logger);
-
- $this->assertSame($logger, $context->getLogger());
- }
-
- public function testShouldSetExecutionInterruptedToFalseInConstructor()
- {
- $context = new Context($this->createPsrContext());
-
- $this->assertFalse($context->isExecutionInterrupted());
- }
-
- public function testShouldAllowGetPreviouslySetMessage()
- {
- /** @var PsrMessage $message */
- $message = $this->createMock(PsrMessage::class);
-
- $context = new Context($this->createPsrContext());
-
- $context->setPsrMessage($message);
-
- $this->assertSame($message, $context->getPsrMessage());
- }
-
- public function testThrowOnTryToChangeMessageIfAlreadySet()
- {
- /** @var PsrMessage $message */
- $message = $this->createMock(PsrMessage::class);
-
- $context = new Context($this->createPsrContext());
-
- $this->expectException(IllegalContextModificationException::class);
- $this->expectExceptionMessage('The message could be set once');
-
- $context->setPsrMessage($message);
- $context->setPsrMessage($message);
- }
-
- public function testShouldAllowGetPreviouslySetException()
- {
- $exception = new \Exception();
-
- $context = new Context($this->createPsrContext());
-
- $context->setException($exception);
-
- $this->assertSame($exception, $context->getException());
- }
-
- public function testShouldAllowGetPreviouslySetResult()
- {
- $result = 'aResult';
-
- $context = new Context($this->createPsrContext());
-
- $context->setResult($result);
-
- $this->assertSame($result, $context->getResult());
- }
-
- public function testThrowOnTryToChangeResultIfAlreadySet()
- {
- $result = 'aResult';
-
- $context = new Context($this->createPsrContext());
-
- $this->expectException(IllegalContextModificationException::class);
- $this->expectExceptionMessage('The result modification is not allowed');
-
- $context->setResult($result);
- $context->setResult($result);
- }
-
- public function testShouldAllowGetPreviouslySetExecutionInterrupted()
- {
- $context = new Context($this->createPsrContext());
-
- // guard
- $this->assertFalse($context->isExecutionInterrupted());
-
- $context->setExecutionInterrupted(true);
-
- $this->assertTrue($context->isExecutionInterrupted());
- }
-
- public function testThrowOnTryToRollbackExecutionInterruptedIfAlreadySetToTrue()
- {
- $context = new Context($this->createPsrContext());
-
- $this->expectException(IllegalContextModificationException::class);
- $this->expectExceptionMessage('The execution once interrupted could not be roll backed');
-
- $context->setExecutionInterrupted(true);
- $context->setExecutionInterrupted(false);
- }
-
- public function testNotThrowOnSettingExecutionInterruptedToTrueIfAlreadySetToTrue()
- {
- $context = new Context($this->createPsrContext());
-
- $context->setExecutionInterrupted(true);
- $context->setExecutionInterrupted(true);
- }
-
- public function testShouldAllowGetPreviouslySetLogger()
- {
- $expectedLogger = new NullLogger();
-
- $context = new Context($this->createPsrContext());
-
- $context->setLogger($expectedLogger);
-
- $this->assertSame($expectedLogger, $context->getLogger());
- }
-
- public function testThrowOnSettingLoggerIfAlreadySet()
- {
- $context = new Context($this->createPsrContext());
-
- $context->setLogger(new NullLogger());
-
- $this->expectException(IllegalContextModificationException::class);
- $this->expectExceptionMessage('The logger modification is not allowed');
-
- $context->setLogger(new NullLogger());
- }
-
- public function testShouldAllowGetPreviouslySetQueue()
- {
- $context = new Context($this->createPsrContext());
-
- $context->setPsrQueue($queue = new NullQueue(''));
-
- $this->assertSame($queue, $context->getPsrQueue());
- }
-
- public function testThrowOnSettingQueueNameIfAlreadySet()
- {
- $context = new Context($this->createPsrContext());
-
- $context->setPsrQueue(new NullQueue(''));
-
- $this->expectException(IllegalContextModificationException::class);
- $this->expectExceptionMessage('The queue modification is not allowed');
-
- $context->setPsrQueue(new NullQueue(''));
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject|PsrContext
- */
- protected function createPsrContext()
- {
- return $this->createMock(PsrContext::class);
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject|PsrConsumer
- */
- protected function createPsrConsumer()
- {
- return $this->createMock(PsrConsumer::class);
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject|PsrProcessor
- */
- protected function createProcessorMock()
- {
- return $this->createMock(PsrProcessor::class);
- }
-}
diff --git a/pkg/enqueue/Tests/Consumption/EmptyExtensionTraitTest.php b/pkg/enqueue/Tests/Consumption/EmptyExtensionTraitTest.php
deleted file mode 100644
index 32ea8612a..000000000
--- a/pkg/enqueue/Tests/Consumption/EmptyExtensionTraitTest.php
+++ /dev/null
@@ -1,20 +0,0 @@
-assertClassImplements(ExceptionInterface::class, ConsumptionInterruptedException::class);
- }
-
- public function testShouldExtendLogicException()
- {
- $this->assertClassExtends(\LogicException::class, ConsumptionInterruptedException::class);
- }
-
- public function testCouldBeConstructedWithoutAnyArguments()
- {
- new ConsumptionInterruptedException();
- }
-}
diff --git a/pkg/enqueue/Tests/Consumption/Exception/IllegalContextModificationExceptionTest.php b/pkg/enqueue/Tests/Consumption/Exception/IllegalContextModificationExceptionTest.php
index 0885b500e..241f4adf9 100644
--- a/pkg/enqueue/Tests/Consumption/Exception/IllegalContextModificationExceptionTest.php
+++ b/pkg/enqueue/Tests/Consumption/Exception/IllegalContextModificationExceptionTest.php
@@ -20,9 +20,4 @@ public function testShouldExtendLogicException()
{
$this->assertClassExtends(\LogicException::class, IllegalContextModificationException::class);
}
-
- public function testCouldBeConstructedWithoutAnyArguments()
- {
- new IllegalContextModificationException();
- }
}
diff --git a/pkg/enqueue/Tests/Consumption/Exception/InvalidArgumentExceptionTest.php b/pkg/enqueue/Tests/Consumption/Exception/InvalidArgumentExceptionTest.php
index 296c76225..c1c5db362 100644
--- a/pkg/enqueue/Tests/Consumption/Exception/InvalidArgumentExceptionTest.php
+++ b/pkg/enqueue/Tests/Consumption/Exception/InvalidArgumentExceptionTest.php
@@ -21,11 +21,6 @@ public function testShouldExtendLogicException()
$this->assertClassExtends(\LogicException::class, InvalidArgumentException::class);
}
- public function testCouldBeConstructedWithoutAnyArguments()
- {
- new InvalidArgumentException();
- }
-
public function testThrowIfAssertInstanceOfNotSameAsExpected()
{
$this->expectException(InvalidArgumentException::class);
@@ -36,6 +31,9 @@ public function testThrowIfAssertInstanceOfNotSameAsExpected()
InvalidArgumentException::assertInstanceOf(new \SplStack(), \SplQueue::class);
}
+ /**
+ * @doesNotPerformAssertions
+ */
public function testShouldDoNothingIfAssertDestinationInstanceOfSameAsExpected()
{
InvalidArgumentException::assertInstanceOf(new \SplQueue(), \SplQueue::class);
diff --git a/pkg/enqueue/Tests/Consumption/Exception/LogicExceptionTest.php b/pkg/enqueue/Tests/Consumption/Exception/LogicExceptionTest.php
index ddd258098..2655609ae 100644
--- a/pkg/enqueue/Tests/Consumption/Exception/LogicExceptionTest.php
+++ b/pkg/enqueue/Tests/Consumption/Exception/LogicExceptionTest.php
@@ -20,9 +20,4 @@ public function testShouldExtendLogicException()
{
$this->assertClassExtends(\LogicException::class, LogicException::class);
}
-
- public function testCouldBeConstructedWithoutAnyArguments()
- {
- new LogicException();
- }
}
diff --git a/pkg/enqueue/Tests/Consumption/Extension/LimitConsumedMessagesExtensionTest.php b/pkg/enqueue/Tests/Consumption/Extension/LimitConsumedMessagesExtensionTest.php
index 250c5778d..137e30ba4 100644
--- a/pkg/enqueue/Tests/Consumption/Extension/LimitConsumedMessagesExtensionTest.php
+++ b/pkg/enqueue/Tests/Consumption/Extension/LimitConsumedMessagesExtensionTest.php
@@ -2,41 +2,84 @@
namespace Enqueue\Tests\Consumption\Extension;
-use Enqueue\Consumption\Context;
+use Enqueue\Consumption\Context\PostMessageReceived;
+use Enqueue\Consumption\Context\PreConsume;
use Enqueue\Consumption\Extension\LimitConsumedMessagesExtension;
-use Interop\Queue\PsrConsumer;
-use Interop\Queue\PsrContext;
-use Interop\Queue\PsrProcessor;
+use Interop\Queue\Consumer;
+use Interop\Queue\Context;
+use Interop\Queue\Message;
+use Interop\Queue\SubscriptionConsumer;
+use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
+use Psr\Log\NullLogger;
class LimitConsumedMessagesExtensionTest extends TestCase
{
- public function testCouldBeConstructedWithRequiredArguments()
+ public function testOnPreConsumeShouldInterruptWhenLimitIsReached()
{
- new LimitConsumedMessagesExtension(12345);
- }
+ $logger = $this->createLoggerMock();
+ $logger
+ ->expects($this->once())
+ ->method('debug')
+ ->with('[LimitConsumedMessagesExtension] Message consumption is interrupted since'.
+ ' the message limit reached. limit: "3"')
+ ;
- public function testShouldThrowExceptionIfMessageLimitIsNotInt()
- {
- $this->setExpectedException(
- \InvalidArgumentException::class,
- 'Expected message limit is int but got: "double"'
+ $context = new PreConsume(
+ $this->createInteropContextMock(),
+ $this->createSubscriptionConsumerMock(),
+ $logger,
+ 1,
+ 2,
+ 3
+ );
+
+ // guard
+ $this->assertFalse($context->isExecutionInterrupted());
+
+ // test
+ $extension = new LimitConsumedMessagesExtension(3);
+
+ $extension->onPreConsume($context);
+ $this->assertFalse($context->isExecutionInterrupted());
+
+ $postReceivedMessage = new PostMessageReceived(
+ $this->createInteropContextMock(),
+ $this->createMock(Consumer::class),
+ $this->createMock(Message::class),
+ 'aResult',
+ 1,
+ new NullLogger()
);
- new LimitConsumedMessagesExtension(0.0);
+ $extension->onPostMessageReceived($postReceivedMessage);
+ $extension->onPostMessageReceived($postReceivedMessage);
+ $extension->onPostMessageReceived($postReceivedMessage);
+
+ $extension->onPreConsume($context);
+ $this->assertTrue($context->isExecutionInterrupted());
}
- public function testOnBeforeReceiveShouldInterruptExecutionIfLimitIsZero()
+ public function testOnPreConsumeShouldInterruptExecutionIfLimitIsZero()
{
- $context = $this->createContext();
- $context->getLogger()
+ $logger = $this->createLoggerMock();
+ $logger
->expects($this->once())
->method('debug')
->with('[LimitConsumedMessagesExtension] Message consumption is interrupted since'.
' the message limit reached. limit: "0"')
;
+ $context = new PreConsume(
+ $this->createInteropContextMock(),
+ $this->createSubscriptionConsumerMock(),
+ $logger,
+ 1,
+ 2,
+ 3
+ );
+
// guard
$this->assertFalse($context->isExecutionInterrupted());
@@ -44,20 +87,29 @@ public function testOnBeforeReceiveShouldInterruptExecutionIfLimitIsZero()
$extension = new LimitConsumedMessagesExtension(0);
// consume 1
- $extension->onBeforeReceive($context);
+ $extension->onPreConsume($context);
$this->assertTrue($context->isExecutionInterrupted());
}
- public function testOnBeforeReceiveShouldInterruptExecutionIfLimitIsLessThatZero()
+ public function testOnPreConsumeShouldInterruptExecutionIfLimitIsLessThatZero()
{
- $context = $this->createContext();
- $context->getLogger()
+ $logger = $this->createLoggerMock();
+ $logger
->expects($this->once())
->method('debug')
->with('[LimitConsumedMessagesExtension] Message consumption is interrupted since'.
' the message limit reached. limit: "-1"')
;
+ $context = new PreConsume(
+ $this->createInteropContextMock(),
+ $this->createSubscriptionConsumerMock(),
+ $logger,
+ 1,
+ 2,
+ 3
+ );
+
// guard
$this->assertFalse($context->isExecutionInterrupted());
@@ -65,45 +117,65 @@ public function testOnBeforeReceiveShouldInterruptExecutionIfLimitIsLessThatZero
$extension = new LimitConsumedMessagesExtension(-1);
// consume 1
- $extension->onBeforeReceive($context);
+ $extension->onPreConsume($context);
$this->assertTrue($context->isExecutionInterrupted());
}
public function testOnPostReceivedShouldInterruptExecutionIfMessageLimitExceeded()
{
- $context = $this->createContext();
- $context->getLogger()
+ $logger = $this->createLoggerMock();
+ $logger
->expects($this->once())
->method('debug')
->with('[LimitConsumedMessagesExtension] Message consumption is interrupted since'.
' the message limit reached. limit: "2"')
;
+ $postReceivedMessage = new PostMessageReceived(
+ $this->createInteropContextMock(),
+ $this->createMock(Consumer::class),
+ $this->createMock(Message::class),
+ 'aResult',
+ 1,
+ $logger
+ );
+
// guard
- $this->assertFalse($context->isExecutionInterrupted());
+ $this->assertFalse($postReceivedMessage->isExecutionInterrupted());
// test
$extension = new LimitConsumedMessagesExtension(2);
// consume 1
- $extension->onPostReceived($context);
- $this->assertFalse($context->isExecutionInterrupted());
+ $extension->onPostMessageReceived($postReceivedMessage);
+ $this->assertFalse($postReceivedMessage->isExecutionInterrupted());
// consume 2 and exit
- $extension->onPostReceived($context);
- $this->assertTrue($context->isExecutionInterrupted());
+ $extension->onPostMessageReceived($postReceivedMessage);
+ $this->assertTrue($postReceivedMessage->isExecutionInterrupted());
}
/**
- * @return Context
+ * @return MockObject
*/
- protected function createContext()
+ protected function createInteropContextMock(): Context
{
- $context = new Context($this->createMock(PsrContext::class));
- $context->setLogger($this->createMock(LoggerInterface::class));
- $context->setPsrConsumer($this->createMock(PsrConsumer::class));
- $context->setPsrProcessor($this->createMock(PsrProcessor::class));
+ return $this->createMock(Context::class);
+ }
- return $context;
+ /**
+ * @return MockObject
+ */
+ private function createSubscriptionConsumerMock(): SubscriptionConsumer
+ {
+ return $this->createMock(SubscriptionConsumer::class);
+ }
+
+ /**
+ * @return MockObject
+ */
+ private function createLoggerMock(): LoggerInterface
+ {
+ return $this->createMock(LoggerInterface::class);
}
}
diff --git a/pkg/enqueue/Tests/Consumption/Extension/LimitConsumerMemoryExtensionTest.php b/pkg/enqueue/Tests/Consumption/Extension/LimitConsumerMemoryExtensionTest.php
index 74514e58c..25ac85895 100644
--- a/pkg/enqueue/Tests/Consumption/Extension/LimitConsumerMemoryExtensionTest.php
+++ b/pkg/enqueue/Tests/Consumption/Extension/LimitConsumerMemoryExtensionTest.php
@@ -2,137 +2,197 @@
namespace Enqueue\Tests\Consumption\Extension;
-use Enqueue\Consumption\Context;
+use Enqueue\Consumption\Context\PostConsume;
+use Enqueue\Consumption\Context\PostMessageReceived;
+use Enqueue\Consumption\Context\PreConsume;
use Enqueue\Consumption\Extension\LimitConsumerMemoryExtension;
-use Interop\Queue\PsrConsumer;
-use Interop\Queue\PsrContext;
-use Interop\Queue\PsrProcessor;
+use Interop\Queue\Consumer;
+use Interop\Queue\Context;
+use Interop\Queue\Message;
+use Interop\Queue\SubscriptionConsumer;
+use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
+use Psr\Log\NullLogger;
class LimitConsumerMemoryExtensionTest extends TestCase
{
- public function testCouldBeConstructedWithRequiredArguments()
- {
- new LimitConsumerMemoryExtension(12345);
- }
-
public function testShouldThrowExceptionIfMemoryLimitIsNotInt()
{
- $this->setExpectedException(\InvalidArgumentException::class, 'Expected memory limit is int but got: "double"');
+ $this->expectException(\InvalidArgumentException::class);
+ $this->expectExceptionMessage('Expected memory limit is int but got: "double"');
new LimitConsumerMemoryExtension(0.0);
}
- public function testOnIdleShouldInterruptExecutionIfMemoryLimitReached()
+ public function testOnPostConsumeShouldInterruptExecutionIfMemoryLimitReached()
{
- $context = $this->createPsrContext();
- $context->getLogger()
+ $logger = $this->createLoggerMock();
+ $logger
->expects($this->once())
->method('debug')
->with($this->stringContains('[LimitConsumerMemoryExtension] Interrupt execution as memory limit reached.'))
;
+ $postConsume = new PostConsume(
+ $this->createInteropContextMock(),
+ $this->createSubscriptionConsumerMock(),
+ 1,
+ 1,
+ 1,
+ $logger
+ );
+
// guard
- $this->assertFalse($context->isExecutionInterrupted());
+ $this->assertFalse($postConsume->isExecutionInterrupted());
// test
$extension = new LimitConsumerMemoryExtension(1);
- $extension->onIdle($context);
+ $extension->onPostConsume($postConsume);
- $this->assertTrue($context->isExecutionInterrupted());
+ $this->assertTrue($postConsume->isExecutionInterrupted());
}
public function testOnPostReceivedShouldInterruptExecutionIfMemoryLimitReached()
{
- $context = $this->createPsrContext();
- $context->getLogger()
+ $logger = $this->createLoggerMock();
+ $logger
->expects($this->once())
->method('debug')
->with($this->stringContains('[LimitConsumerMemoryExtension] Interrupt execution as memory limit reached.'))
;
+ $postReceivedMessage = new PostMessageReceived(
+ $this->createInteropContextMock(),
+ $this->createMock(Consumer::class),
+ $this->createMock(Message::class),
+ 'aResult',
+ 1,
+ $logger
+ );
+
// guard
- $this->assertFalse($context->isExecutionInterrupted());
+ $this->assertFalse($postReceivedMessage->isExecutionInterrupted());
// test
$extension = new LimitConsumerMemoryExtension(1);
- $extension->onPostReceived($context);
+ $extension->onPostMessageReceived($postReceivedMessage);
- $this->assertTrue($context->isExecutionInterrupted());
+ $this->assertTrue($postReceivedMessage->isExecutionInterrupted());
}
- public function testOnBeforeReceivedShouldInterruptExecutionIfMemoryLimitReached()
+ public function testOnPreConsumeShouldInterruptExecutionIfMemoryLimitReached()
{
- $context = $this->createPsrContext();
- $context->getLogger()
+ $logger = $this->createLoggerMock();
+ $logger
->expects($this->once())
->method('debug')
->with($this->stringContains('[LimitConsumerMemoryExtension] Interrupt execution as memory limit reached.'))
;
+ $context = new PreConsume(
+ $this->createInteropContextMock(),
+ $this->createSubscriptionConsumerMock(),
+ $logger,
+ 1,
+ 2,
+ 3
+ );
+
// guard
$this->assertFalse($context->isExecutionInterrupted());
// test
$extension = new LimitConsumerMemoryExtension(1);
- $extension->onBeforeReceive($context);
+ $extension->onPreConsume($context);
$this->assertTrue($context->isExecutionInterrupted());
}
- public function testOnBeforeReceiveShouldNotInterruptExecutionIfMemoryLimitIsNotReached()
+ public function testOnPreConsumeShouldNotInterruptExecutionIfMemoryLimitIsNotReached()
{
- $context = $this->createPsrContext();
+ $context = new PreConsume(
+ $this->createInteropContextMock(),
+ $this->createSubscriptionConsumerMock(),
+ new NullLogger(),
+ 1,
+ 2,
+ 3
+ );
// guard
$this->assertFalse($context->isExecutionInterrupted());
// test
- $extension = new LimitConsumerMemoryExtension(PHP_INT_MAX);
- $extension->onBeforeReceive($context);
+ $extension = new LimitConsumerMemoryExtension(\PHP_INT_MAX);
+ $extension->onPreConsume($context);
$this->assertFalse($context->isExecutionInterrupted());
}
- public function testOnIdleShouldNotInterruptExecutionIfMemoryLimitIsNotReached()
+ public function testOnPostConsumeShouldNotInterruptExecutionIfMemoryLimitIsNotReached()
{
- $context = $this->createPsrContext();
+ $postConsume = new PostConsume(
+ $this->createInteropContextMock(),
+ $this->createSubscriptionConsumerMock(),
+ 1,
+ 1,
+ 1,
+ new NullLogger()
+ );
// guard
- $this->assertFalse($context->isExecutionInterrupted());
+ $this->assertFalse($postConsume->isExecutionInterrupted());
// test
- $extension = new LimitConsumerMemoryExtension(PHP_INT_MAX);
- $extension->onIdle($context);
+ $extension = new LimitConsumerMemoryExtension(\PHP_INT_MAX);
+ $extension->onPostConsume($postConsume);
- $this->assertFalse($context->isExecutionInterrupted());
+ $this->assertFalse($postConsume->isExecutionInterrupted());
}
- public function testOnPostReceivedShouldNotInterruptExecutionIfMemoryLimitIsNotReached()
+ public function testOnPostMessageReceivedShouldNotInterruptExecutionIfMemoryLimitIsNotReached()
{
- $context = $this->createPsrContext();
+ $postReceivedMessage = new PostMessageReceived(
+ $this->createInteropContextMock(),
+ $this->createMock(Consumer::class),
+ $this->createMock(Message::class),
+ 'aResult',
+ 1,
+ new NullLogger()
+ );
// guard
- $this->assertFalse($context->isExecutionInterrupted());
+ $this->assertFalse($postReceivedMessage->isExecutionInterrupted());
// test
- $extension = new LimitConsumerMemoryExtension(PHP_INT_MAX);
- $extension->onPostReceived($context);
+ $extension = new LimitConsumerMemoryExtension(\PHP_INT_MAX);
+ $extension->onPostMessageReceived($postReceivedMessage);
- $this->assertFalse($context->isExecutionInterrupted());
+ $this->assertFalse($postReceivedMessage->isExecutionInterrupted());
}
/**
- * @return Context
+ * @return MockObject
*/
- protected function createPsrContext()
+ protected function createInteropContextMock(): Context
{
- $context = new Context($this->createMock(PsrContext::class));
- $context->setLogger($this->createMock(LoggerInterface::class));
- $context->setPsrConsumer($this->createMock(PsrConsumer::class));
- $context->setPsrProcessor($this->createMock(PsrProcessor::class));
+ return $this->createMock(Context::class);
+ }
- return $context;
+ /**
+ * @return MockObject
+ */
+ private function createSubscriptionConsumerMock(): SubscriptionConsumer
+ {
+ return $this->createMock(SubscriptionConsumer::class);
+ }
+
+ /**
+ * @return MockObject
+ */
+ private function createLoggerMock(): LoggerInterface
+ {
+ return $this->createMock(LoggerInterface::class);
}
}
diff --git a/pkg/enqueue/Tests/Consumption/Extension/LimitConsumptionTimeExtensionTest.php b/pkg/enqueue/Tests/Consumption/Extension/LimitConsumptionTimeExtensionTest.php
index fffeb9439..fa6cb76a1 100644
--- a/pkg/enqueue/Tests/Consumption/Extension/LimitConsumptionTimeExtensionTest.php
+++ b/pkg/enqueue/Tests/Consumption/Extension/LimitConsumptionTimeExtensionTest.php
@@ -2,24 +2,31 @@
namespace Enqueue\Tests\Consumption\Extension;
-use Enqueue\Consumption\Context;
+use Enqueue\Consumption\Context\PostConsume;
+use Enqueue\Consumption\Context\PostMessageReceived;
+use Enqueue\Consumption\Context\PreConsume;
use Enqueue\Consumption\Extension\LimitConsumptionTimeExtension;
-use Interop\Queue\PsrConsumer;
-use Interop\Queue\PsrContext;
-use Interop\Queue\PsrProcessor;
+use Interop\Queue\Consumer;
+use Interop\Queue\Context;
+use Interop\Queue\Message;
+use Interop\Queue\SubscriptionConsumer;
+use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
+use Psr\Log\NullLogger;
class LimitConsumptionTimeExtensionTest extends TestCase
{
- public function testCouldBeConstructedWithRequiredArguments()
+ public function testOnPreConsumeShouldInterruptExecutionIfConsumptionTimeExceeded()
{
- new LimitConsumptionTimeExtension(new \DateTime('+1 day'));
- }
-
- public function testOnBeforeReceiveShouldInterruptExecutionIfConsumptionTimeExceeded()
- {
- $context = $this->createContext();
+ $context = new PreConsume(
+ $this->createInteropContextMock(),
+ $this->createSubscriptionConsumerMock(),
+ new NullLogger(),
+ 1,
+ 2,
+ 3
+ );
// guard
$this->assertFalse($context->isExecutionInterrupted());
@@ -27,44 +34,65 @@ public function testOnBeforeReceiveShouldInterruptExecutionIfConsumptionTimeExce
// test
$extension = new LimitConsumptionTimeExtension(new \DateTime('-2 second'));
- $extension->onBeforeReceive($context);
+ $extension->onPreConsume($context);
$this->assertTrue($context->isExecutionInterrupted());
}
- public function testOnIdleShouldInterruptExecutionIfConsumptionTimeExceeded()
+ public function testOnPostConsumeShouldInterruptExecutionIfConsumptionTimeExceeded()
{
- $context = $this->createContext();
+ $postConsume = new PostConsume(
+ $this->createInteropContextMock(),
+ $this->createSubscriptionConsumerMock(),
+ 1,
+ 1,
+ 1,
+ new NullLogger()
+ );
// guard
- $this->assertFalse($context->isExecutionInterrupted());
+ $this->assertFalse($postConsume->isExecutionInterrupted());
// test
$extension = new LimitConsumptionTimeExtension(new \DateTime('-2 second'));
- $extension->onIdle($context);
+ $extension->onPostConsume($postConsume);
- $this->assertTrue($context->isExecutionInterrupted());
+ $this->assertTrue($postConsume->isExecutionInterrupted());
}
public function testOnPostReceivedShouldInterruptExecutionIfConsumptionTimeExceeded()
{
- $context = $this->createContext();
+ $postReceivedMessage = new PostMessageReceived(
+ $this->createInteropContextMock(),
+ $this->createMock(Consumer::class),
+ $this->createMock(Message::class),
+ 'aResult',
+ 1,
+ new NullLogger()
+ );
// guard
- $this->assertFalse($context->isExecutionInterrupted());
+ $this->assertFalse($postReceivedMessage->isExecutionInterrupted());
// test
$extension = new LimitConsumptionTimeExtension(new \DateTime('-2 second'));
- $extension->onPostReceived($context);
+ $extension->onPostMessageReceived($postReceivedMessage);
- $this->assertTrue($context->isExecutionInterrupted());
+ $this->assertTrue($postReceivedMessage->isExecutionInterrupted());
}
- public function testOnBeforeReceiveShouldNotInterruptExecutionIfConsumptionTimeIsNotExceeded()
+ public function testOnPreConsumeShouldNotInterruptExecutionIfConsumptionTimeIsNotExceeded()
{
- $context = $this->createContext();
+ $context = new PreConsume(
+ $this->createInteropContextMock(),
+ $this->createSubscriptionConsumerMock(),
+ new NullLogger(),
+ 1,
+ 2,
+ 3
+ );
// guard
$this->assertFalse($context->isExecutionInterrupted());
@@ -72,51 +100,76 @@ public function testOnBeforeReceiveShouldNotInterruptExecutionIfConsumptionTimeI
// test
$extension = new LimitConsumptionTimeExtension(new \DateTime('+2 second'));
- $extension->onBeforeReceive($context);
+ $extension->onPreConsume($context);
$this->assertFalse($context->isExecutionInterrupted());
}
- public function testOnIdleShouldNotInterruptExecutionIfConsumptionTimeIsNotExceeded()
+ public function testOnPostConsumeShouldNotInterruptExecutionIfConsumptionTimeIsNotExceeded()
{
- $context = $this->createContext();
+ $postConsume = new PostConsume(
+ $this->createInteropContextMock(),
+ $this->createSubscriptionConsumerMock(),
+ 1,
+ 1,
+ 1,
+ new NullLogger()
+ );
// guard
- $this->assertFalse($context->isExecutionInterrupted());
+ $this->assertFalse($postConsume->isExecutionInterrupted());
// test
$extension = new LimitConsumptionTimeExtension(new \DateTime('+2 second'));
- $extension->onIdle($context);
+ $extension->onPostConsume($postConsume);
- $this->assertFalse($context->isExecutionInterrupted());
+ $this->assertFalse($postConsume->isExecutionInterrupted());
}
public function testOnPostReceivedShouldNotInterruptExecutionIfConsumptionTimeIsNotExceeded()
{
- $context = $this->createContext();
+ $postReceivedMessage = new PostMessageReceived(
+ $this->createInteropContextMock(),
+ $this->createMock(Consumer::class),
+ $this->createMock(Message::class),
+ 'aResult',
+ 1,
+ new NullLogger()
+ );
// guard
- $this->assertFalse($context->isExecutionInterrupted());
+ $this->assertFalse($postReceivedMessage->isExecutionInterrupted());
// test
$extension = new LimitConsumptionTimeExtension(new \DateTime('+2 second'));
- $extension->onPostReceived($context);
+ $extension->onPostMessageReceived($postReceivedMessage);
- $this->assertFalse($context->isExecutionInterrupted());
+ $this->assertFalse($postReceivedMessage->isExecutionInterrupted());
+ }
+
+ /**
+ * @return MockObject
+ */
+ protected function createInteropContextMock(): Context
+ {
+ return $this->createMock(Context::class);
}
/**
- * @return Context
+ * @return MockObject
*/
- protected function createContext()
+ private function createSubscriptionConsumerMock(): SubscriptionConsumer
{
- $context = new Context($this->createMock(PsrContext::class));
- $context->setLogger($this->createMock(LoggerInterface::class));
- $context->setPsrConsumer($this->createMock(PsrConsumer::class));
- $context->setPsrProcessor($this->createMock(PsrProcessor::class));
+ return $this->createMock(SubscriptionConsumer::class);
+ }
- return $context;
+ /**
+ * @return MockObject
+ */
+ private function createLoggerMock(): LoggerInterface
+ {
+ return $this->createMock(LoggerInterface::class);
}
}
diff --git a/pkg/enqueue/Tests/Consumption/Extension/LogExtensionTest.php b/pkg/enqueue/Tests/Consumption/Extension/LogExtensionTest.php
new file mode 100644
index 000000000..006a2c549
--- /dev/null
+++ b/pkg/enqueue/Tests/Consumption/Extension/LogExtensionTest.php
@@ -0,0 +1,266 @@
+assertClassImplements(StartExtensionInterface::class, LogExtension::class);
+ }
+
+ public function testShouldImplementEndExtensionInterface()
+ {
+ $this->assertClassImplements(EndExtensionInterface::class, LogExtension::class);
+ }
+
+ public function testShouldImplementMessageReceivedExtensionInterface()
+ {
+ $this->assertClassImplements(MessageReceivedExtensionInterface::class, LogExtension::class);
+ }
+
+ public function testShouldImplementPostMessageReceivedExtensionInterface()
+ {
+ $this->assertClassImplements(PostMessageReceivedExtensionInterface::class, LogExtension::class);
+ }
+
+ public function testShouldLogStartOnStart()
+ {
+ $logger = $this->createLogger();
+ $logger
+ ->expects($this->once())
+ ->method('debug')
+ ->with('Consumption has started')
+ ;
+
+ $context = new Start($this->createContextMock(), $logger, [], 1, 1);
+
+ $extension = new LogExtension();
+ $extension->onStart($context);
+ }
+
+ public function testShouldLogEndOnEnd()
+ {
+ $logger = $this->createLogger();
+ $logger
+ ->expects($this->once())
+ ->method('debug')
+ ->with('Consumption has ended')
+ ;
+
+ $context = new End($this->createContextMock(), 1, 2, $logger);
+
+ $extension = new LogExtension();
+ $extension->onEnd($context);
+ }
+
+ public function testShouldLogMessageReceived()
+ {
+ $logger = $this->createLogger();
+ $logger
+ ->expects($this->once())
+ ->method('debug')
+ ->with('Received from {queueName} {body}', [
+ 'queueName' => 'aQueue',
+ 'redelivered' => false,
+ 'body' => Stringify::that('aBody'),
+ 'properties' => Stringify::that(['aProp' => 'aPropVal']),
+ 'headers' => Stringify::that(['aHeader' => 'aHeaderVal']),
+ ])
+ ;
+
+ $consumerMock = $this->createConsumerStub(new NullQueue('aQueue'));
+ $message = new NullMessage('aBody');
+ $message->setProperty('aProp', 'aPropVal');
+ $message->setHeader('aHeader', 'aHeaderVal');
+
+ $context = new MessageReceived($this->createContextMock(), $consumerMock, $message, $this->createProcessorMock(), 1, $logger);
+
+ $extension = new LogExtension();
+ $extension->onMessageReceived($context);
+ }
+
+ public function testShouldLogMessageProcessedWithStringResult()
+ {
+ $logger = $this->createLogger();
+ $logger
+ ->expects($this->once())
+ ->method('log')
+ ->with(LogLevel::INFO,
+ 'Processed from {queueName} {body} {result}',
+ [
+ 'queueName' => 'aQueue',
+ 'body' => Stringify::that('aBody'),
+ 'properties' => Stringify::that(['aProp' => 'aPropVal']),
+ 'headers' => Stringify::that(['aHeader' => 'aHeaderVal']),
+ 'result' => 'aResult',
+ 'reason' => '',
+ ]
+ )
+ ;
+
+ $consumerMock = $this->createConsumerStub(new NullQueue('aQueue'));
+ $message = new NullMessage('aBody');
+ $message->setProperty('aProp', 'aPropVal');
+ $message->setHeader('aHeader', 'aHeaderVal');
+
+ $context = new PostMessageReceived($this->createContextMock(), $consumerMock, $message, 'aResult', 1, $logger);
+
+ $extension = new LogExtension();
+ $extension->onPostMessageReceived($context);
+ }
+
+ public function testShouldLogRejectedMessageAsError()
+ {
+ $logger = $this->createLogger();
+ $logger
+ ->expects($this->once())
+ ->method('log')
+ ->with(LogLevel::ERROR,
+ 'Processed from {queueName} {body} {result}',
+ [
+ 'queueName' => 'aQueue',
+ 'body' => Stringify::that('aBody'),
+ 'properties' => Stringify::that(['aProp' => 'aPropVal']),
+ 'headers' => Stringify::that(['aHeader' => 'aHeaderVal']),
+ 'result' => 'reject',
+ 'reason' => '',
+ ]
+ )
+ ;
+
+ $consumerMock = $this->createConsumerStub(new NullQueue('aQueue'));
+ $message = new NullMessage('aBody');
+ $message->setProperty('aProp', 'aPropVal');
+ $message->setHeader('aHeader', 'aHeaderVal');
+
+ $context = new PostMessageReceived($this->createContextMock(), $consumerMock, $message, Processor::REJECT, 1, $logger);
+
+ $extension = new LogExtension();
+ $extension->onPostMessageReceived($context);
+ }
+
+ public function testShouldLogMessageProcessedWithResultObject()
+ {
+ $logger = $this->createLogger();
+ $logger
+ ->expects($this->once())
+ ->method('log')
+ ->with(LogLevel::INFO,
+ 'Processed from {queueName} {body} {result}',
+ [
+ 'queueName' => 'aQueue',
+ 'body' => Stringify::that('aBody'),
+ 'properties' => Stringify::that(['aProp' => 'aPropVal']),
+ 'headers' => Stringify::that(['aHeader' => 'aHeaderVal']),
+ 'result' => 'ack',
+ 'reason' => '',
+ ]
+ )
+ ;
+
+ $consumerMock = $this->createConsumerStub(new NullQueue('aQueue'));
+ $message = new NullMessage('aBody');
+ $message->setProperty('aProp', 'aPropVal');
+ $message->setHeader('aHeader', 'aHeaderVal');
+
+ $context = new PostMessageReceived($this->createContextMock(), $consumerMock, $message, Result::ack(), 1, $logger);
+
+ $extension = new LogExtension();
+ $extension->onPostMessageReceived($context);
+ }
+
+ public function testShouldLogMessageProcessedWithReasonResultObject()
+ {
+ $logger = $this->createLogger();
+ $logger
+ ->expects($this->once())
+ ->method('log')
+ ->with(LogLevel::INFO,
+ 'Processed from {queueName} {body} {result} {reason}',
+ [
+ 'queueName' => 'aQueue',
+ 'body' => Stringify::that('aBody'),
+ 'properties' => Stringify::that(['aProp' => 'aPropVal']),
+ 'headers' => Stringify::that(['aHeader' => 'aHeaderVal']),
+ 'result' => 'ack',
+ 'reason' => 'aReason',
+ ]
+ )
+ ;
+
+ $consumerMock = $this->createConsumerStub(new NullQueue('aQueue'));
+ $message = new NullMessage('aBody');
+ $message->setProperty('aProp', 'aPropVal');
+ $message->setHeader('aHeader', 'aHeaderVal');
+
+ $context = new PostMessageReceived($this->createContextMock(), $consumerMock, $message, Result::ack('aReason'), 1, $logger);
+
+ $extension = new LogExtension();
+ $extension->onPostMessageReceived($context);
+ }
+
+ /**
+ * @return MockObject
+ */
+ private function createConsumerStub(Queue $queue): Consumer
+ {
+ $consumerMock = $this->createMock(Consumer::class);
+ $consumerMock
+ ->expects($this->any())
+ ->method('getQueue')
+ ->willReturn($queue)
+ ;
+
+ return $consumerMock;
+ }
+
+ /**
+ * @return MockObject
+ */
+ private function createContextMock(): Context
+ {
+ return $this->createMock(Context::class);
+ }
+
+ /**
+ * @return MockObject
+ */
+ private function createProcessorMock(): Processor
+ {
+ return $this->createMock(Processor::class);
+ }
+
+ /**
+ * @return MockObject|LoggerInterface
+ */
+ private function createLogger()
+ {
+ return $this->createMock(LoggerInterface::class);
+ }
+}
diff --git a/pkg/enqueue/Tests/Consumption/Extension/LoggerExtensionTest.php b/pkg/enqueue/Tests/Consumption/Extension/LoggerExtensionTest.php
index 68bc7003f..666892e0e 100644
--- a/pkg/enqueue/Tests/Consumption/Extension/LoggerExtensionTest.php
+++ b/pkg/enqueue/Tests/Consumption/Extension/LoggerExtensionTest.php
@@ -2,199 +2,78 @@
namespace Enqueue\Tests\Consumption\Extension;
-use Enqueue\Consumption\Context;
+use Enqueue\Consumption\Context\InitLogger;
use Enqueue\Consumption\Extension\LoggerExtension;
-use Enqueue\Consumption\ExtensionInterface;
-use Enqueue\Consumption\Result;
-use Enqueue\Null\NullMessage;
+use Enqueue\Consumption\InitLoggerExtensionInterface;
use Enqueue\Test\ClassExtensionTrait;
-use Interop\Queue\PsrConsumer;
-use Interop\Queue\PsrContext;
+use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
+use Psr\Log\NullLogger;
class LoggerExtensionTest extends TestCase
{
use ClassExtensionTrait;
- public function testShouldImplementExtensionInterface()
+ public function testShouldImplementInitLoggerExtensionInterface()
{
- $this->assertClassImplements(ExtensionInterface::class, LoggerExtension::class);
+ $this->assertClassImplements(InitLoggerExtensionInterface::class, LoggerExtension::class);
}
- public function testCouldBeConstructedWithLoggerAsFirstArgument()
- {
- new LoggerExtension($this->createLogger());
- }
-
- public function testShouldSetLoggerToContextOnStart()
+ public function testShouldSetLoggerToContextOnInitLogger()
{
$logger = $this->createLogger();
$extension = new LoggerExtension($logger);
- $context = new Context($this->createPsrContextMock());
+ $previousLogger = new NullLogger();
+ $context = new InitLogger($previousLogger);
- $extension->onStart($context);
+ $extension->onInitLogger($context);
$this->assertSame($logger, $context->getLogger());
}
public function testShouldAddInfoMessageOnStart()
{
- $logger = $this->createLogger();
- $logger
- ->expects($this->once())
- ->method('debug')
- ->with($this->stringStartsWith('Set context\'s logger'))
- ;
-
- $extension = new LoggerExtension($logger);
-
- $context = new Context($this->createPsrContextMock());
-
- $extension->onStart($context);
- }
-
- public function testShouldLogRejectMessageStatus()
- {
- $logger = $this->createLogger();
- $logger
- ->expects($this->once())
- ->method('error')
- ->with('reason', ['body' => 'message body', 'headers' => [], 'properties' => []])
- ;
-
- $extension = new LoggerExtension($logger);
-
- $message = new NullMessage();
- $message->setBody('message body');
-
- $context = new Context($this->createPsrContextMock());
- $context->setResult(Result::reject('reason'));
- $context->setPsrMessage($message);
-
- $extension->onPostReceived($context);
- }
-
- public function testShouldLogRequeueMessageStatus()
- {
- $logger = $this->createLogger();
- $logger
- ->expects($this->once())
- ->method('error')
- ->with('reason', ['body' => 'message body', 'headers' => [], 'properties' => []])
- ;
-
- $extension = new LoggerExtension($logger);
-
- $message = new NullMessage();
- $message->setBody('message body');
-
- $context = new Context($this->createPsrContextMock());
- $context->setResult(Result::requeue('reason'));
- $context->setPsrMessage($message);
-
- $extension->onPostReceived($context);
- }
-
- public function testShouldNotLogRequeueMessageStatusIfReasonIsEmpty()
- {
- $logger = $this->createLogger();
- $logger
- ->expects($this->never())
- ->method('error')
- ;
-
- $extension = new LoggerExtension($logger);
+ $previousLogger = $this->createLogger();
- $context = new Context($this->createPsrContextMock());
- $context->setResult(Result::requeue());
-
- $extension->onPostReceived($context);
- }
-
- public function testShouldLogAckMessageStatus()
- {
$logger = $this->createLogger();
$logger
->expects($this->once())
- ->method('info')
- ->with('reason', ['body' => 'message body', 'headers' => [], 'properties' => []])
+ ->method('debug')
+ ->with(sprintf('Change logger from "%s" to "%s"', $logger::class, $previousLogger::class))
;
$extension = new LoggerExtension($logger);
- $message = new NullMessage();
- $message->setBody('message body');
+ $context = new InitLogger($previousLogger);
- $context = new Context($this->createPsrContextMock());
- $context->setResult(Result::ack('reason'));
- $context->setPsrMessage($message);
-
- $extension->onPostReceived($context);
+ $extension->onInitLogger($context);
}
- public function testShouldNotLogAckMessageStatusIfReasonIsEmpty()
+ public function testShouldDoNothingIfSameLoggerInstanceAlreadySet()
{
$logger = $this->createLogger();
$logger
->expects($this->never())
- ->method('info')
- ;
-
- $extension = new LoggerExtension($logger);
-
- $context = new Context($this->createPsrContextMock());
- $context->setResult(Result::ack());
-
- $extension->onPostReceived($context);
- }
-
- public function testShouldNotSetLoggerIfOneHasBeenSetOnStart()
- {
- $logger = $this->createLogger();
-
- $alreadySetLogger = $this->createLogger();
- $alreadySetLogger
- ->expects($this->once())
->method('debug')
- ->with(sprintf(
- 'Skip setting context\'s logger "%s". Another one "%s" has already been set.',
- get_class($logger),
- get_class($alreadySetLogger)
- ))
;
$extension = new LoggerExtension($logger);
- $context = new Context($this->createPsrContextMock());
- $context->setLogger($alreadySetLogger);
+ $context = new InitLogger($logger);
- $extension->onStart($context);
- }
+ $extension->onInitLogger($context);
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject|PsrContext
- */
- protected function createPsrContextMock()
- {
- return $this->createMock(PsrContext::class);
+ $this->assertSame($logger, $context->getLogger());
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|LoggerInterface
+ * @return MockObject|LoggerInterface
*/
protected function createLogger()
{
return $this->createMock(LoggerInterface::class);
}
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject|PsrConsumer
- */
- protected function createConsumerMock()
- {
- return $this->createMock(PsrConsumer::class);
- }
}
diff --git a/pkg/enqueue/Tests/Consumption/Extension/NicenessExtensionTest.php b/pkg/enqueue/Tests/Consumption/Extension/NicenessExtensionTest.php
index 1cabdaff0..734bc8417 100644
--- a/pkg/enqueue/Tests/Consumption/Extension/NicenessExtensionTest.php
+++ b/pkg/enqueue/Tests/Consumption/Extension/NicenessExtensionTest.php
@@ -2,21 +2,15 @@
namespace Enqueue\Tests\Consumption\Extension;
-use Enqueue\Consumption\Context;
+use Enqueue\Consumption\Context\Start;
use Enqueue\Consumption\Extension\NicenessExtension;
-use Interop\Queue\PsrConsumer;
-use Interop\Queue\PsrContext;
-use Interop\Queue\PsrProcessor;
+use Interop\Queue\Context as InteropContext;
+use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
-use Psr\Log\LoggerInterface;
+use Psr\Log\NullLogger;
class NicenessExtensionTest extends TestCase
{
- public function testCouldBeConstructedWithRequiredArguments()
- {
- new NicenessExtension(0);
- }
-
public function testShouldThrowExceptionOnInvalidArgument()
{
$this->expectException(\InvalidArgumentException::class);
@@ -28,20 +22,17 @@ public function testShouldThrowWarningOnInvalidArgument()
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('proc_nice(): Only a super user may attempt to increase the priority of a process');
+ $context = new Start($this->createContextMock(), new NullLogger(), [], 0, 0);
+
$extension = new NicenessExtension(-1);
- $extension->onStart($this->createContext());
+ $extension->onStart($context);
}
/**
- * @return Context
+ * @return MockObject|InteropContext
*/
- protected function createContext()
+ protected function createContextMock(): InteropContext
{
- $context = new Context($this->createMock(PsrContext::class));
- $context->setLogger($this->createMock(LoggerInterface::class));
- $context->setPsrConsumer($this->createMock(PsrConsumer::class));
- $context->setPsrProcessor($this->createMock(PsrProcessor::class));
-
- return $context;
+ return $this->createMock(InteropContext::class);
}
}
diff --git a/pkg/enqueue/Tests/Consumption/Extension/ReplyExtensionTest.php b/pkg/enqueue/Tests/Consumption/Extension/ReplyExtensionTest.php
index 49120559e..cb65816ce 100644
--- a/pkg/enqueue/Tests/Consumption/Extension/ReplyExtensionTest.php
+++ b/pkg/enqueue/Tests/Consumption/Extension/ReplyExtensionTest.php
@@ -2,15 +2,17 @@
namespace Enqueue\Tests\Consumption\Extension;
-use Enqueue\Consumption\Context;
+use Enqueue\Consumption\Context\PostMessageReceived;
use Enqueue\Consumption\Extension\ReplyExtension;
-use Enqueue\Consumption\ExtensionInterface;
+use Enqueue\Consumption\PostMessageReceivedExtensionInterface;
use Enqueue\Consumption\Result;
use Enqueue\Null\NullMessage;
use Enqueue\Null\NullQueue;
use Enqueue\Test\ClassExtensionTrait;
-use Interop\Queue\PsrContext;
-use Interop\Queue\PsrProducer;
+use Interop\Queue\Consumer;
+use Interop\Queue\Context;
+use Interop\Queue\Producer as InteropProducer;
+use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\NullLogger;
@@ -18,52 +20,25 @@ class ReplyExtensionTest extends TestCase
{
use ClassExtensionTrait;
- public function testShouldImplementExtensionInterface()
+ public function testShouldImplementPostMessageReceivedExtensionInterface()
{
- $this->assertClassImplements(ExtensionInterface::class, ReplyExtension::class);
- }
-
- public function testCouldBeConstructedWithoutAnyArguments()
- {
- new ReplyExtension();
- }
-
- public function testShouldDoNothingOnPreReceived()
- {
- $extension = new ReplyExtension();
-
- $extension->onPreReceived(new Context($this->createNeverUsedContextMock()));
- }
-
- public function testShouldDoNothingOnStart()
- {
- $extension = new ReplyExtension();
-
- $extension->onStart(new Context($this->createNeverUsedContextMock()));
- }
-
- public function testShouldDoNothingOnBeforeReceive()
- {
- $extension = new ReplyExtension();
-
- $extension->onBeforeReceive(new Context($this->createNeverUsedContextMock()));
- }
-
- public function testShouldDoNothingOnInterrupted()
- {
- $extension = new ReplyExtension();
-
- $extension->onInterrupted(new Context($this->createNeverUsedContextMock()));
+ $this->assertClassImplements(PostMessageReceivedExtensionInterface::class, ReplyExtension::class);
}
public function testShouldDoNothingIfReceivedMessageNotHaveReplyToSet()
{
$extension = new ReplyExtension();
- $context = new Context($this->createNeverUsedContextMock());
- $context->setPsrMessage(new NullMessage());
+ $postReceivedMessage = new PostMessageReceived(
+ $this->createNeverUsedContextMock(),
+ $this->createMock(Consumer::class),
+ new NullMessage(),
+ 'aResult',
+ 1,
+ new NullLogger()
+ );
- $extension->onPostReceived($context);
+ $extension->onPostMessageReceived($postReceivedMessage);
}
public function testShouldDoNothingIfContextResultIsNotInstanceOfResult()
@@ -73,11 +48,16 @@ public function testShouldDoNothingIfContextResultIsNotInstanceOfResult()
$message = new NullMessage();
$message->setReplyTo('aReplyToQueue');
- $context = new Context($this->createNeverUsedContextMock());
- $context->setPsrMessage($message);
- $context->setResult('notInstanceOfResult');
+ $postReceivedMessage = new PostMessageReceived(
+ $this->createNeverUsedContextMock(),
+ $this->createMock(Consumer::class),
+ $message,
+ 'notInstanceOfResult',
+ 1,
+ new NullLogger()
+ );
- $extension->onPostReceived($context);
+ $extension->onPostMessageReceived($postReceivedMessage);
}
public function testShouldDoNothingIfResultInstanceOfResultButReplyMessageNotSet()
@@ -87,11 +67,16 @@ public function testShouldDoNothingIfResultInstanceOfResultButReplyMessageNotSet
$message = new NullMessage();
$message->setReplyTo('aReplyToQueue');
- $context = new Context($this->createNeverUsedContextMock());
- $context->setPsrMessage($message);
- $context->setResult(Result::ack());
+ $postReceivedMessage = new PostMessageReceived(
+ $this->createNeverUsedContextMock(),
+ $this->createMock(Consumer::class),
+ $message,
+ Result::ack(),
+ 1,
+ new NullLogger()
+ );
- $extension->onPostReceived($context);
+ $extension->onPostMessageReceived($postReceivedMessage);
}
public function testShouldSendReplyMessageToReplyQueueOnPostReceived()
@@ -107,15 +92,15 @@ public function testShouldSendReplyMessageToReplyQueueOnPostReceived()
$replyQueue = new NullQueue('aReplyName');
- $producerMock = $this->createMock(PsrProducer::class);
+ $producerMock = $this->createMock(InteropProducer::class);
$producerMock
->expects($this->once())
->method('send')
->with($replyQueue, $replyMessage)
;
- /** @var \PHPUnit_Framework_MockObject_MockObject|PsrContext $contextMock */
- $contextMock = $this->createMock(PsrContext::class);
+ /** @var MockObject|Context $contextMock */
+ $contextMock = $this->createMock(Context::class);
$contextMock
->expects($this->once())
->method('createQueue')
@@ -127,20 +112,32 @@ public function testShouldSendReplyMessageToReplyQueueOnPostReceived()
->willReturn($producerMock)
;
- $context = new Context($contextMock);
- $context->setPsrMessage($message);
- $context->setResult(Result::reply($replyMessage));
- $context->setLogger(new NullLogger());
+ $postReceivedMessage = new PostMessageReceived(
+ $contextMock,
+ $this->createMock(Consumer::class),
+ $message,
+ Result::reply($replyMessage),
+ 1,
+ new NullLogger()
+ );
+
+ $extension->onPostMessageReceived($postReceivedMessage);
+ }
- $extension->onPostReceived($context);
+ /**
+ * @return MockObject
+ */
+ protected function createInteropContextMock(): Context
+ {
+ return $this->createMock(Context::class);
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|PsrContext
+ * @return MockObject
*/
- private function createNeverUsedContextMock()
+ private function createNeverUsedContextMock(): Context
{
- $contextMock = $this->createMock(PsrContext::class);
+ $contextMock = $this->createMock(Context::class);
$contextMock
->expects($this->never())
->method('createProducer')
diff --git a/pkg/enqueue/Tests/Consumption/FallbackSubscriptionConsumerTest.php b/pkg/enqueue/Tests/Consumption/FallbackSubscriptionConsumerTest.php
index b054180ed..73fba7bfd 100644
--- a/pkg/enqueue/Tests/Consumption/FallbackSubscriptionConsumerTest.php
+++ b/pkg/enqueue/Tests/Consumption/FallbackSubscriptionConsumerTest.php
@@ -3,23 +3,22 @@
namespace Enqueue\Tests\Consumption;
use Enqueue\Consumption\FallbackSubscriptionConsumer;
-use Interop\Queue\PsrConsumer;
-use Interop\Queue\PsrMessage;
-use Interop\Queue\PsrQueue;
-use Interop\Queue\PsrSubscriptionConsumer;
-
-class FallbackSubscriptionConsumerTest extends \PHPUnit_Framework_TestCase
+use Enqueue\Test\ReadAttributeTrait;
+use Interop\Queue\Consumer;
+use Interop\Queue\Message as InteropMessage;
+use Interop\Queue\Queue as InteropQueue;
+use Interop\Queue\SubscriptionConsumer;
+use PHPUnit\Framework\TestCase;
+
+class FallbackSubscriptionConsumerTest extends TestCase
{
- public function testShouldImplementPsrSubscriptionConsumerInterface()
+ use ReadAttributeTrait;
+
+ public function testShouldImplementSubscriptionConsumerInterface()
{
$rc = new \ReflectionClass(FallbackSubscriptionConsumer::class);
- $this->assertTrue($rc->implementsInterface(PsrSubscriptionConsumer::class));
- }
-
- public function testCouldBeConstructedWithoutAnyArguments()
- {
- new FallbackSubscriptionConsumer();
+ $this->assertTrue($rc->implementsInterface(SubscriptionConsumer::class));
}
public function testShouldInitSubscribersPropertyWithEmptyArray()
@@ -65,6 +64,9 @@ public function testThrowsIfTrySubscribeAnotherConsumerToAlreadySubscribedQueue(
$subscriptionConsumer->subscribe($barConsumer, $barCallback);
}
+ /**
+ * @doesNotPerformAssertions
+ */
public function testShouldAllowSubscribeSameConsumerAndCallbackSecondTime()
{
$subscriptionConsumer = new FallbackSubscriptionConsumer();
@@ -145,38 +147,22 @@ public function testShouldConsumeMessagesFromTwoQueuesInExpectedOrder()
$fourthMessage = $this->createMessageStub('fourth');
$fifthMessage = $this->createMessageStub('fifth');
- $fooMessages = [null, $firstMessage, null, $secondMessage, $thirdMessage];
-
$fooConsumer = $this->createConsumerStub('foo_queue');
$fooConsumer
->expects($this->any())
->method('receiveNoWait')
- ->willReturnCallback(function () use (&$fooMessages) {
- if (empty($fooMessages)) {
- return null;
- }
-
- return array_shift($fooMessages);
- })
+ ->willReturnOnConsecutiveCalls(null, $firstMessage, null, $secondMessage, $thirdMessage)
;
- $barMessages = [$fourthMessage, null, null, $fifthMessage];
-
$barConsumer = $this->createConsumerStub('bar_queue');
$barConsumer
->expects($this->any())
->method('receiveNoWait')
- ->willReturnCallback(function () use (&$barMessages) {
- if (empty($barMessages)) {
- return null;
- }
-
- return array_shift($barMessages);
- })
+ ->willReturnOnConsecutiveCalls($fourthMessage, null, null, $fifthMessage)
;
$actualOrder = [];
- $callback = function (PsrMessage $message, PsrConsumer $consumer) use (&$actualOrder) {
+ $callback = function (InteropMessage $message, Consumer $consumer) use (&$actualOrder) {
$actualOrder[] = [$message->getBody(), $consumer->getQueue()->getQueueName()];
};
@@ -226,13 +212,13 @@ public function testShouldConsumeTillTimeoutIsReached()
}
/**
- * @param null|mixed $body
+ * @param mixed|null $body
*
- * @return PsrMessage|\PHPUnit_Framework_MockObject_MockObject
+ * @return InteropMessage|\PHPUnit\Framework\MockObject\MockObject
*/
private function createMessageStub($body = null)
{
- $messageMock = $this->createMock(PsrMessage::class);
+ $messageMock = $this->createMock(InteropMessage::class);
$messageMock
->expects($this->any())
->method('getBody')
@@ -243,19 +229,19 @@ private function createMessageStub($body = null)
}
/**
- * @param null|mixed $queueName
+ * @param mixed|null $queueName
*
- * @return PsrConsumer|\PHPUnit_Framework_MockObject_MockObject
+ * @return Consumer|\PHPUnit\Framework\MockObject\MockObject
*/
private function createConsumerStub($queueName = null)
{
- $queueMock = $this->createMock(PsrQueue::class);
+ $queueMock = $this->createMock(InteropQueue::class);
$queueMock
->expects($this->any())
->method('getQueueName')
->willReturn($queueName);
- $consumerMock = $this->createMock(PsrConsumer::class);
+ $consumerMock = $this->createMock(Consumer::class);
$consumerMock
->expects($this->any())
->method('getQueue')
diff --git a/pkg/enqueue/Tests/Consumption/Mock/BreakCycleExtension.php b/pkg/enqueue/Tests/Consumption/Mock/BreakCycleExtension.php
index b61d8dd8d..cbc2f8b1e 100644
--- a/pkg/enqueue/Tests/Consumption/Mock/BreakCycleExtension.php
+++ b/pkg/enqueue/Tests/Consumption/Mock/BreakCycleExtension.php
@@ -2,14 +2,20 @@
namespace Enqueue\Tests\Consumption\Mock;
-use Enqueue\Consumption\Context;
-use Enqueue\Consumption\EmptyExtensionTrait;
+use Enqueue\Consumption\Context\End;
+use Enqueue\Consumption\Context\InitLogger;
+use Enqueue\Consumption\Context\MessageReceived;
+use Enqueue\Consumption\Context\MessageResult;
+use Enqueue\Consumption\Context\PostConsume;
+use Enqueue\Consumption\Context\PostMessageReceived;
+use Enqueue\Consumption\Context\PreConsume;
+use Enqueue\Consumption\Context\PreSubscribe;
+use Enqueue\Consumption\Context\ProcessorException;
+use Enqueue\Consumption\Context\Start;
use Enqueue\Consumption\ExtensionInterface;
class BreakCycleExtension implements ExtensionInterface
{
- use EmptyExtensionTrait;
-
protected $cycles = 1;
private $limit;
@@ -19,15 +25,51 @@ public function __construct($limit)
$this->limit = $limit;
}
- public function onPostReceived(Context $context)
+ public function onInitLogger(InitLogger $context): void
+ {
+ }
+
+ public function onPostMessageReceived(PostMessageReceived $context): void
+ {
+ if ($this->cycles >= $this->limit) {
+ $context->interruptExecution();
+ } else {
+ ++$this->cycles;
+ }
+ }
+
+ public function onEnd(End $context): void
+ {
+ }
+
+ public function onMessageReceived(MessageReceived $context): void
+ {
+ }
+
+ public function onResult(MessageResult $context): void
+ {
+ }
+
+ public function onPreConsume(PreConsume $context): void
+ {
+ }
+
+ public function onPreSubscribe(PreSubscribe $context): void
+ {
+ }
+
+ public function onProcessorException(ProcessorException $context): void
+ {
+ }
+
+ public function onStart(Start $context): void
{
- $this->onIdle($context);
}
- public function onIdle(Context $context)
+ public function onPostConsume(PostConsume $context): void
{
if ($this->cycles >= $this->limit) {
- $context->setExecutionInterrupted(true);
+ $context->interruptExecution();
} else {
++$this->cycles;
}
diff --git a/pkg/enqueue/Tests/Consumption/Mock/DummySubscriptionConsumer.php b/pkg/enqueue/Tests/Consumption/Mock/DummySubscriptionConsumer.php
new file mode 100644
index 000000000..40351484d
--- /dev/null
+++ b/pkg/enqueue/Tests/Consumption/Mock/DummySubscriptionConsumer.php
@@ -0,0 +1,48 @@
+messages as list($message, $queueName)) {
+ /** @var InteropMessage $message */
+ /** @var string $queueName */
+ if (false == call_user_func($this->subscriptions[$queueName][1], $message, $this->subscriptions[$queueName][0])) {
+ return;
+ }
+ }
+ }
+
+ public function subscribe(Consumer $consumer, callable $callback): void
+ {
+ $this->subscriptions[$consumer->getQueue()->getQueueName()] = [$consumer, $callback];
+ }
+
+ public function unsubscribe(Consumer $consumer): void
+ {
+ unset($this->subscriptions[$consumer->getQueue()->getQueueName()]);
+ }
+
+ public function unsubscribeAll(): void
+ {
+ $this->subscriptions = [];
+ }
+
+ public function addMessage(InteropMessage $message, string $queueName): void
+ {
+ $this->messages[] = [$message, $queueName];
+ }
+}
diff --git a/pkg/enqueue/Tests/Consumption/QueueConsumerTest.php b/pkg/enqueue/Tests/Consumption/QueueConsumerTest.php
index 196f75598..2bcc253e7 100644
--- a/pkg/enqueue/Tests/Consumption/QueueConsumerTest.php
+++ b/pkg/enqueue/Tests/Consumption/QueueConsumerTest.php
@@ -2,61 +2,92 @@
namespace Enqueue\Tests\Consumption;
+use Enqueue\Consumption\BoundProcessor;
use Enqueue\Consumption\CallbackProcessor;
use Enqueue\Consumption\ChainExtension;
-use Enqueue\Consumption\Context;
+use Enqueue\Consumption\Context\End;
+use Enqueue\Consumption\Context\InitLogger;
+use Enqueue\Consumption\Context\MessageReceived;
+use Enqueue\Consumption\Context\MessageResult;
+use Enqueue\Consumption\Context\PostConsume;
+use Enqueue\Consumption\Context\PostMessageReceived;
+use Enqueue\Consumption\Context\PreConsume;
+use Enqueue\Consumption\Context\PreSubscribe;
+use Enqueue\Consumption\Context\ProcessorException;
+use Enqueue\Consumption\Context\Start;
use Enqueue\Consumption\Exception\InvalidArgumentException;
+use Enqueue\Consumption\Extension\ExitStatusExtension;
use Enqueue\Consumption\ExtensionInterface;
use Enqueue\Consumption\QueueConsumer;
use Enqueue\Consumption\Result;
use Enqueue\Null\NullQueue;
+use Enqueue\Test\ReadAttributeTrait;
use Enqueue\Tests\Consumption\Mock\BreakCycleExtension;
-use Interop\Queue\PsrConsumer;
-use Interop\Queue\PsrContext;
-use Interop\Queue\PsrMessage;
-use Interop\Queue\PsrProcessor;
-use Interop\Queue\PsrQueue;
+use Enqueue\Tests\Consumption\Mock\DummySubscriptionConsumer;
+use Interop\Queue\Consumer;
+use Interop\Queue\Context as InteropContext;
+use Interop\Queue\Exception\SubscriptionConsumerNotSupportedException;
+use Interop\Queue\Message;
+use Interop\Queue\Processor;
+use Interop\Queue\Queue;
+use Interop\Queue\SubscriptionConsumer;
use PHPUnit\Framework\TestCase;
+use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
class QueueConsumerTest extends TestCase
{
- public function testCouldBeConstructedWithConnectionAndExtensionsAsArguments()
+ use ReadAttributeTrait;
+
+ public function testShouldSetEmptyArrayToBoundProcessorsPropertyInConstructor()
{
- new QueueConsumer($this->createPsrContextStub(), null, 0);
+ $consumer = new QueueConsumer($this->createContextStub(), null, [], null, 0);
+
+ $this->assertAttributeSame([], 'boundProcessors', $consumer);
}
- public function testCouldBeConstructedWithConnectionOnly()
+ public function testShouldSetProvidedBoundProcessorsToThePropertyInConstructor()
{
- new QueueConsumer($this->createPsrContextStub());
+ $boundProcessors = [
+ new BoundProcessor(new NullQueue('foo'), $this->createProcessorMock()),
+ new BoundProcessor(new NullQueue('bar'), $this->createProcessorMock()),
+ ];
+
+ $consumer = new QueueConsumer($this->createContextStub(), null, $boundProcessors, null, 0);
+
+ $this->assertAttributeSame($boundProcessors, 'boundProcessors', $consumer);
}
- public function testCouldBeConstructedWithConnectionAndSingleExtension()
+ public function testShouldSetNullLoggerIfNoneProvidedInConstructor()
{
- new QueueConsumer($this->createPsrContextStub(), $this->createExtension());
+ $consumer = new QueueConsumer($this->createContextStub(), null, [], null, 0);
+
+ $this->assertAttributeInstanceOf(NullLogger::class, 'logger', $consumer);
}
- public function testShouldSetEmptyArrayToBoundProcessorsPropertyInConstructor()
+ public function testShouldSetProvidedLoggerToThePropertyInConstructor()
{
- $consumer = new QueueConsumer($this->createPsrContextStub(), null, 0);
+ $expectedLogger = $this->createMock(LoggerInterface::class);
- $this->assertAttributeSame([], 'boundProcessors', $consumer);
+ $consumer = new QueueConsumer($this->createContextStub(), null, [], $expectedLogger, 0);
+
+ $this->assertAttributeSame($expectedLogger, 'logger', $consumer);
}
- public function testShouldAllowGetConnectionSetInConstructor()
+ public function testShouldAllowGetContextSetInConstructor()
{
- $expectedConnection = $this->createPsrContextStub();
+ $expectedContext = $this->createContextStub();
- $consumer = new QueueConsumer($expectedConnection, null, 0);
+ $consumer = new QueueConsumer($expectedContext, null, [], null, 0);
- $this->assertSame($expectedConnection, $consumer->getPsrContext());
+ $this->assertSame($expectedContext, $consumer->getContext());
}
public function testThrowIfQueueNameEmptyOnBind()
{
$processorMock = $this->createProcessorMock();
- $consumer = new QueueConsumer($this->createPsrContextStub(), null, 0);
+ $consumer = new QueueConsumer($this->createContextStub());
$this->expectException(\LogicException::class);
$this->expectExceptionMessage('The queue name must be not empty.');
@@ -67,7 +98,7 @@ public function testThrowIfQueueAlreadyBoundToProcessorOnBind()
{
$processorMock = $this->createProcessorMock();
- $consumer = new QueueConsumer($this->createPsrContextStub(), null, 0);
+ $consumer = new QueueConsumer($this->createContextStub());
$consumer->bind(new NullQueue('theQueueName'), $processorMock);
@@ -81,45 +112,31 @@ public function testShouldAllowBindProcessorToQueue()
$queue = new NullQueue('theQueueName');
$processorMock = $this->createProcessorMock();
- $consumer = new QueueConsumer($this->createPsrContextStub(), null, 0);
+ $consumer = new QueueConsumer($this->createContextStub());
$consumer->bind($queue, $processorMock);
- $this->assertAttributeSame(['theQueueName' => [$queue, $processorMock]], 'boundProcessors', $consumer);
+ $this->assertAttributeEquals(
+ ['theQueueName' => new BoundProcessor($queue, $processorMock)],
+ 'boundProcessors',
+ $consumer
+ );
}
public function testThrowIfQueueNeitherInstanceOfQueueNorString()
{
$processorMock = $this->createProcessorMock();
- $consumer = new QueueConsumer($this->createPsrContextStub(), null, 0);
+ $consumer = new QueueConsumer($this->createContextStub());
$this->expectException(InvalidArgumentException::class);
- $this->expectExceptionMessage('The argument must be an instance of Interop\Queue\PsrQueue but got stdClass.');
+ $this->expectExceptionMessage('The argument must be an instance of Interop\Queue\Queue but got stdClass.');
$consumer->bind(new \stdClass(), $processorMock);
}
- public function testThrowIfProcessorNeitherInstanceOfProcessorNorCallable()
- {
- $consumer = new QueueConsumer($this->createPsrContextStub(), null, 0);
-
- $this->expectException(InvalidArgumentException::class);
- $this->expectExceptionMessage('The argument must be an instance of Interop\Queue\PsrProcessor but got stdClass.');
- $consumer->bind(new NullQueue(''), new \stdClass());
- }
-
- public function testCouldSetGetIdleTimeout()
- {
- $consumer = new QueueConsumer($this->createPsrContextStub(), null, 0);
-
- $consumer->setIdleTimeout(123456);
-
- $this->assertSame(123456, $consumer->getIdleTimeout());
- }
-
public function testCouldSetGetReceiveTimeout()
{
- $consumer = new QueueConsumer($this->createPsrContextStub(), null, 0);
+ $consumer = new QueueConsumer($this->createContextStub());
$consumer->setReceiveTimeout(123456);
@@ -134,7 +151,7 @@ public function testShouldAllowBindCallbackToQueueName()
$queueName = 'theQueueName';
$queue = new NullQueue($queueName);
- $context = $this->createMock(PsrContext::class);
+ $context = $this->createContextWithoutSubscriptionConsumerMock();
$context
->expects($this->once())
->method('createQueue')
@@ -142,49 +159,129 @@ public function testShouldAllowBindCallbackToQueueName()
->willReturn($queue)
;
- $consumer = new QueueConsumer($context, null, 0);
+ $consumer = new QueueConsumer($context);
- $consumer->bind($queueName, $callback);
+ $consumer->bindCallback($queueName, $callback);
$boundProcessors = $this->readAttribute($consumer, 'boundProcessors');
- $this->assertInternalType('array', $boundProcessors);
+ self::assertIsArray($boundProcessors);
$this->assertCount(1, $boundProcessors);
$this->assertArrayHasKey($queueName, $boundProcessors);
- $this->assertInternalType('array', $boundProcessors[$queueName]);
- $this->assertCount(2, $boundProcessors[$queueName]);
- $this->assertSame($queue, $boundProcessors[$queueName][0]);
- $this->assertInstanceOf(CallbackProcessor::class, $boundProcessors[$queueName][1]);
+ $this->assertInstanceOf(BoundProcessor::class, $boundProcessors[$queueName]);
+ $this->assertSame($queue, $boundProcessors[$queueName]->getQueue());
+ $this->assertInstanceOf(CallbackProcessor::class, $boundProcessors[$queueName]->getProcessor());
}
public function testShouldReturnSelfOnBind()
{
$processorMock = $this->createProcessorMock();
- $consumer = new QueueConsumer($this->createPsrContextStub(), null, 0);
+ $consumer = new QueueConsumer($this->createContextStub());
- $this->assertSame($consumer, $consumer->bind(new NullQueue('aQueueName'), $processorMock));
+ $this->assertSame($consumer, $consumer->bind(new NullQueue('foo_queue'), $processorMock));
+ }
+
+ public function testShouldUseContextSubscriptionConsumerIfSupport()
+ {
+ $expectedQueue = new NullQueue('theQueueName');
+
+ $contextSubscriptionConsumer = $this->createSubscriptionConsumerMock();
+ $contextSubscriptionConsumer
+ ->expects($this->once())
+ ->method('consume')
+ ;
+
+ $fallbackSubscriptionConsumer = $this->createSubscriptionConsumerMock();
+ $fallbackSubscriptionConsumer
+ ->expects($this->never())
+ ->method('consume')
+ ;
+
+ $contextMock = $this->createMock(InteropContext::class);
+ $contextMock
+ ->expects($this->once())
+ ->method('createConsumer')
+ ->with($this->identicalTo($expectedQueue))
+ ->willReturn($this->createConsumerStub())
+ ;
+ $contextMock
+ ->expects($this->once())
+ ->method('createSubscriptionConsumer')
+ ->willReturn($contextSubscriptionConsumer)
+ ;
+
+ $processorMock = $this->createProcessorMock();
+ $processorMock
+ ->expects($this->never())
+ ->method('process')
+ ;
+
+ $queueConsumer = new QueueConsumer($contextMock, new BreakCycleExtension(1));
+ $queueConsumer->setFallbackSubscriptionConsumer($fallbackSubscriptionConsumer);
+ $queueConsumer->bind($expectedQueue, $processorMock);
+ $queueConsumer->consume();
+ }
+
+ public function testShouldUseFallbackSubscriptionConsumerIfNotSupported()
+ {
+ $expectedQueue = new NullQueue('theQueueName');
+
+ $contextSubscriptionConsumer = $this->createSubscriptionConsumerMock();
+ $contextSubscriptionConsumer
+ ->expects($this->never())
+ ->method('consume')
+ ;
+
+ $fallbackSubscriptionConsumer = $this->createSubscriptionConsumerMock();
+ $fallbackSubscriptionConsumer
+ ->expects($this->once())
+ ->method('consume')
+ ;
+
+ $contextMock = $this->createContextWithoutSubscriptionConsumerMock();
+ $contextMock
+ ->expects($this->once())
+ ->method('createConsumer')
+ ->with($this->identicalTo($expectedQueue))
+ ->willReturn($this->createConsumerStub())
+ ;
+ $contextMock
+ ->expects($this->once())
+ ->method('createSubscriptionConsumer')
+ ->willThrowException(SubscriptionConsumerNotSupportedException::providerDoestNotSupportIt())
+ ;
+
+ $processorMock = $this->createProcessorMock();
+ $processorMock
+ ->expects($this->never())
+ ->method('process')
+ ;
+
+ $queueConsumer = new QueueConsumer($contextMock, new BreakCycleExtension(1));
+ $queueConsumer->setFallbackSubscriptionConsumer($fallbackSubscriptionConsumer);
+ $queueConsumer->bind($expectedQueue, $processorMock);
+ $queueConsumer->consume();
}
public function testShouldSubscribeToGivenQueueWithExpectedTimeout()
{
$expectedQueue = new NullQueue('theQueueName');
- $messageConsumerMock = $this->createMock(PsrConsumer::class);
- $messageConsumerMock
+ $subscriptionConsumerMock = $this->createSubscriptionConsumerMock();
+ $subscriptionConsumerMock
->expects($this->once())
- ->method('receive')
+ ->method('consume')
->with(12345)
- ->willReturn(null)
;
- $contextMock = $this->createMock(PsrContext::class);
+ $contextMock = $this->createContextWithoutSubscriptionConsumerMock();
$contextMock
->expects($this->once())
->method('createConsumer')
->with($this->identicalTo($expectedQueue))
- ->willReturn($messageConsumerMock)
+ ->willReturn($this->createConsumerStub())
;
$processorMock = $this->createProcessorMock();
@@ -193,28 +290,28 @@ public function testShouldSubscribeToGivenQueueWithExpectedTimeout()
->method('process')
;
- $queueConsumer = new QueueConsumer($contextMock, new BreakCycleExtension(1), 0, 12345);
+ $queueConsumer = new QueueConsumer($contextMock, new BreakCycleExtension(1), [], null, 12345);
+ $queueConsumer->setFallbackSubscriptionConsumer($subscriptionConsumerMock);
$queueConsumer->bind($expectedQueue, $processorMock);
$queueConsumer->consume();
}
- public function testShouldSubscribeToGivenQueueAndQuitAfterFifthIdleCycle()
+ public function testShouldSubscribeToGivenQueueAndQuitAfterFifthConsumeCycle()
{
$expectedQueue = new NullQueue('theQueueName');
- $messageConsumerMock = $this->createMock(PsrConsumer::class);
- $messageConsumerMock
+ $subscriptionConsumerMock = $this->createSubscriptionConsumerMock();
+ $subscriptionConsumerMock
->expects($this->exactly(5))
- ->method('receive')
- ->willReturn(null)
+ ->method('consume')
;
- $contextMock = $this->createMock(PsrContext::class);
+ $contextMock = $this->createContextWithoutSubscriptionConsumerMock();
$contextMock
->expects($this->once())
->method('createConsumer')
->with($this->identicalTo($expectedQueue))
- ->willReturn($messageConsumerMock)
+ ->willReturn($this->createConsumerStub())
;
$processorMock = $this->createProcessorMock();
@@ -223,17 +320,30 @@ public function testShouldSubscribeToGivenQueueAndQuitAfterFifthIdleCycle()
->method('process')
;
- $queueConsumer = new QueueConsumer($contextMock, new BreakCycleExtension(5), 0);
+ $queueConsumer = new QueueConsumer($contextMock, new BreakCycleExtension(5));
+ $queueConsumer->setFallbackSubscriptionConsumer($subscriptionConsumerMock);
$queueConsumer->bind($expectedQueue, $processorMock);
$queueConsumer->consume();
}
public function testShouldProcessFiveMessagesAndQuit()
{
- $messageMock = $this->createMessageMock();
- $messageConsumerStub = $this->createMessageConsumerStub($messageMock);
+ $fooQueue = new NullQueue('foo_queue');
+
+ $firstMessageMock = $this->createMessageMock();
+ $secondMessageMock = $this->createMessageMock();
+ $thirdMessageMock = $this->createMessageMock();
+ $fourthMessageMock = $this->createMessageMock();
+ $fifthMessageMock = $this->createMessageMock();
+
+ $subscriptionConsumerMock = new DummySubscriptionConsumer();
+ $subscriptionConsumerMock->addMessage($firstMessageMock, 'foo_queue');
+ $subscriptionConsumerMock->addMessage($secondMessageMock, 'foo_queue');
+ $subscriptionConsumerMock->addMessage($thirdMessageMock, 'foo_queue');
+ $subscriptionConsumerMock->addMessage($fourthMessageMock, 'foo_queue');
+ $subscriptionConsumerMock->addMessage($fifthMessageMock, 'foo_queue');
- $contextStub = $this->createPsrContextStub($messageConsumerStub);
+ $contextStub = $this->createContextStub();
$processorMock = $this->createProcessorMock();
$processorMock
@@ -242,8 +352,9 @@ public function testShouldProcessFiveMessagesAndQuit()
->willReturn(Result::ACK)
;
- $queueConsumer = new QueueConsumer($contextStub, new BreakCycleExtension(5), 0);
- $queueConsumer->bind(new NullQueue('aQueueName'), $processorMock);
+ $queueConsumer = new QueueConsumer($contextStub, new BreakCycleExtension(5));
+ $queueConsumer->setFallbackSubscriptionConsumer($subscriptionConsumerMock);
+ $queueConsumer->bind($fooQueue, $processorMock);
$queueConsumer->consume();
}
@@ -251,14 +362,18 @@ public function testShouldProcessFiveMessagesAndQuit()
public function testShouldAckMessageIfProcessorReturnSuchStatus()
{
$messageMock = $this->createMessageMock();
- $messageConsumerStub = $this->createMessageConsumerStub($messageMock);
- $messageConsumerStub
+
+ $subscriptionConsumerMock = new DummySubscriptionConsumer();
+ $subscriptionConsumerMock->addMessage($messageMock, 'foo_queue');
+
+ $consumerStub = $this->createConsumerStub('foo_queue');
+ $consumerStub
->expects($this->once())
->method('acknowledge')
->with($this->identicalTo($messageMock))
;
- $contextStub = $this->createPsrContextStub($messageConsumerStub);
+ $contextStub = $this->createContextStub($consumerStub);
$processorMock = $this->createProcessorMock();
$processorMock
@@ -268,8 +383,9 @@ public function testShouldAckMessageIfProcessorReturnSuchStatus()
->willReturn(Result::ACK)
;
- $queueConsumer = new QueueConsumer($contextStub, new BreakCycleExtension(1), 0);
- $queueConsumer->bind(new NullQueue('aQueueName'), $processorMock);
+ $queueConsumer = new QueueConsumer($contextStub, new BreakCycleExtension(1));
+ $queueConsumer->setFallbackSubscriptionConsumer($subscriptionConsumerMock);
+ $queueConsumer->bind(new NullQueue('foo_queue'), $processorMock);
$queueConsumer->consume();
}
@@ -277,9 +393,13 @@ public function testShouldAckMessageIfProcessorReturnSuchStatus()
public function testThrowIfProcessorReturnNull()
{
$messageMock = $this->createMessageMock();
- $messageConsumerStub = $this->createMessageConsumerStub($messageMock);
- $contextStub = $this->createPsrContextStub($messageConsumerStub);
+ $subscriptionConsumerMock = new DummySubscriptionConsumer();
+ $subscriptionConsumerMock->addMessage($messageMock, 'foo_queue');
+
+ $consumerStub = $this->createConsumerStub('foo_queue');
+
+ $contextStub = $this->createContextStub($consumerStub);
$processorMock = $this->createProcessorMock();
$processorMock
@@ -289,8 +409,9 @@ public function testThrowIfProcessorReturnNull()
->willReturn(null)
;
- $queueConsumer = new QueueConsumer($contextStub, new BreakCycleExtension(1), 0);
- $queueConsumer->bind(new NullQueue('aQueueName'), $processorMock);
+ $queueConsumer = new QueueConsumer($contextStub, new BreakCycleExtension(1));
+ $queueConsumer->setFallbackSubscriptionConsumer($subscriptionConsumerMock);
+ $queueConsumer->bind(new NullQueue('foo_queue'), $processorMock);
$this->expectException(\LogicException::class);
$this->expectExceptionMessage('Status is not supported');
@@ -300,14 +421,18 @@ public function testThrowIfProcessorReturnNull()
public function testShouldRejectMessageIfProcessorReturnSuchStatus()
{
$messageMock = $this->createMessageMock();
- $messageConsumerStub = $this->createMessageConsumerStub($messageMock);
- $messageConsumerStub
+
+ $subscriptionConsumerMock = new DummySubscriptionConsumer();
+ $subscriptionConsumerMock->addMessage($messageMock, 'foo_queue');
+
+ $consumerStub = $this->createConsumerStub('foo_queue');
+ $consumerStub
->expects($this->once())
->method('reject')
->with($this->identicalTo($messageMock), false)
;
- $contextStub = $this->createPsrContextStub($messageConsumerStub);
+ $contextStub = $this->createContextStub($consumerStub);
$processorMock = $this->createProcessorMock();
$processorMock
@@ -317,8 +442,43 @@ public function testShouldRejectMessageIfProcessorReturnSuchStatus()
->willReturn(Result::REJECT)
;
- $queueConsumer = new QueueConsumer($contextStub, new BreakCycleExtension(1), 0);
- $queueConsumer->bind(new NullQueue('aQueueName'), $processorMock);
+ $queueConsumer = new QueueConsumer($contextStub, new BreakCycleExtension(1));
+ $queueConsumer->setFallbackSubscriptionConsumer($subscriptionConsumerMock);
+ $queueConsumer->bind(new NullQueue('foo_queue'), $processorMock);
+
+ $queueConsumer->consume();
+ }
+
+ public function testShouldDoNothingIfProcessorReturnsAlreadyAcknowledged()
+ {
+ $messageMock = $this->createMessageMock();
+
+ $subscriptionConsumerMock = new DummySubscriptionConsumer();
+ $subscriptionConsumerMock->addMessage($messageMock, 'foo_queue');
+
+ $consumerStub = $this->createConsumerStub('foo_queue');
+ $consumerStub
+ ->expects($this->never())
+ ->method('reject')
+ ;
+ $consumerStub
+ ->expects($this->never())
+ ->method('acknowledge')
+ ;
+
+ $contextStub = $this->createContextStub($consumerStub);
+
+ $processorMock = $this->createProcessorMock();
+ $processorMock
+ ->expects($this->once())
+ ->method('process')
+ ->with($this->identicalTo($messageMock))
+ ->willReturn(Result::ALREADY_ACKNOWLEDGED)
+ ;
+
+ $queueConsumer = new QueueConsumer($contextStub, new BreakCycleExtension(1));
+ $queueConsumer->setFallbackSubscriptionConsumer($subscriptionConsumerMock);
+ $queueConsumer->bind(new NullQueue('foo_queue'), $processorMock);
$queueConsumer->consume();
}
@@ -326,14 +486,18 @@ public function testShouldRejectMessageIfProcessorReturnSuchStatus()
public function testShouldRequeueMessageIfProcessorReturnSuchStatus()
{
$messageMock = $this->createMessageMock();
- $messageConsumerStub = $this->createMessageConsumerStub($messageMock);
- $messageConsumerStub
+
+ $subscriptionConsumerMock = new DummySubscriptionConsumer();
+ $subscriptionConsumerMock->addMessage($messageMock, 'foo_queue');
+
+ $consumerStub = $this->createConsumerStub('foo_queue');
+ $consumerStub
->expects($this->once())
->method('reject')
->with($this->identicalTo($messageMock), true)
;
- $contextStub = $this->createPsrContextStub($messageConsumerStub);
+ $contextStub = $this->createContextStub($consumerStub);
$processorMock = $this->createProcessorMock();
$processorMock
@@ -343,8 +507,9 @@ public function testShouldRequeueMessageIfProcessorReturnSuchStatus()
->willReturn(Result::REQUEUE)
;
- $queueConsumer = new QueueConsumer($contextStub, new BreakCycleExtension(1), 0);
- $queueConsumer->bind(new NullQueue('aQueueName'), $processorMock);
+ $queueConsumer = new QueueConsumer($contextStub, new BreakCycleExtension(1));
+ $queueConsumer->setFallbackSubscriptionConsumer($subscriptionConsumerMock);
+ $queueConsumer->bind(new NullQueue('foo_queue'), $processorMock);
$queueConsumer->consume();
}
@@ -352,9 +517,13 @@ public function testShouldRequeueMessageIfProcessorReturnSuchStatus()
public function testThrowIfProcessorReturnInvalidStatus()
{
$messageMock = $this->createMessageMock();
- $messageConsumerStub = $this->createMessageConsumerStub($messageMock);
- $contextStub = $this->createPsrContextStub($messageConsumerStub);
+ $subscriptionConsumerMock = new DummySubscriptionConsumer();
+ $subscriptionConsumerMock->addMessage($messageMock, 'foo_queue');
+
+ $consumerStub = $this->createConsumerStub('foo_queue');
+
+ $contextStub = $this->createContextStub($consumerStub);
$processorMock = $this->createProcessorMock();
$processorMock
@@ -364,8 +533,9 @@ public function testThrowIfProcessorReturnInvalidStatus()
->willReturn('invalidStatus')
;
- $queueConsumer = new QueueConsumer($contextStub, new BreakCycleExtension(1), 0);
- $queueConsumer->bind(new NullQueue('aQueueName'), $processorMock);
+ $queueConsumer = new QueueConsumer($contextStub, new BreakCycleExtension(1));
+ $queueConsumer->setFallbackSubscriptionConsumer($subscriptionConsumerMock);
+ $queueConsumer->bind(new NullQueue('foo_queue'), $processorMock);
$this->expectException(\LogicException::class);
$this->expectExceptionMessage('Status is not supported: invalidStatus');
@@ -377,17 +547,21 @@ public function testShouldNotPassMessageToProcessorIfItWasProcessedByExtension()
$extension = $this->createExtension();
$extension
->expects($this->once())
- ->method('onPreReceived')
- ->with($this->isInstanceOf(Context::class))
- ->willReturnCallback(function (Context $context) {
- $context->setResult(Result::ACK);
+ ->method('onMessageReceived')
+ ->with($this->isInstanceOf(MessageReceived::class))
+ ->willReturnCallback(function (MessageReceived $context) {
+ $context->setResult(Result::ack());
})
;
$messageMock = $this->createMessageMock();
- $messageConsumerStub = $this->createMessageConsumerStub($messageMock);
- $contextStub = $this->createPsrContextStub($messageConsumerStub);
+ $subscriptionConsumerMock = new DummySubscriptionConsumer();
+ $subscriptionConsumerMock->addMessage($messageMock, 'foo_queue');
+
+ $consumerStub = $this->createConsumerStub('foo_queue');
+
+ $contextStub = $this->createContextStub($consumerStub);
$processorMock = $this->createProcessorMock();
$processorMock
@@ -396,17 +570,46 @@ public function testShouldNotPassMessageToProcessorIfItWasProcessedByExtension()
;
$chainExtensions = new ChainExtension([$extension, new BreakCycleExtension(1)]);
- $queueConsumer = new QueueConsumer($contextStub, $chainExtensions, 0);
- $queueConsumer->bind(new NullQueue('aQueueName'), $processorMock);
+ $queueConsumer = new QueueConsumer($contextStub, $chainExtensions);
+ $queueConsumer->setFallbackSubscriptionConsumer($subscriptionConsumerMock);
+ $queueConsumer->bind(new NullQueue('foo_queue'), $processorMock);
+
+ $queueConsumer->consume();
+ }
+
+ public function testShouldCallOnInitLoggerExtensionMethod()
+ {
+ $consumerStub = $this->createConsumerStub('foo_queue');
+
+ $contextStub = $this->createContextStub($consumerStub);
+
+ $processorMock = $this->createProcessorMock();
+
+ $logger = $this->createMock(LoggerInterface::class);
+
+ $extension = $this->createExtension();
+ $extension
+ ->expects($this->once())
+ ->method('onInitLogger')
+ ->with($this->isInstanceOf(InitLogger::class))
+ ->willReturnCallback(function (InitLogger $context) use ($logger) {
+ $this->assertSame($logger, $context->getLogger());
+ })
+ ;
+
+ $chainExtensions = new ChainExtension([$extension, new BreakCycleExtension(1)]);
+ $queueConsumer = new QueueConsumer($contextStub, $chainExtensions, [], $logger);
+ $queueConsumer->setFallbackSubscriptionConsumer(new DummySubscriptionConsumer());
+ $queueConsumer->bind(new NullQueue('foo_queue'), $processorMock);
$queueConsumer->consume();
}
public function testShouldCallOnStartExtensionMethod()
{
- $messageConsumerStub = $this->createMessageConsumerStub($message = null);
+ $consumerStub = $this->createConsumerStub('foo_queue');
- $contextStub = $this->createPsrContextStub($messageConsumerStub);
+ $contextStub = $this->createContextStub($consumerStub);
$processorMock = $this->createProcessorMock();
@@ -414,472 +617,530 @@ public function testShouldCallOnStartExtensionMethod()
$extension
->expects($this->once())
->method('onStart')
- ->with($this->isInstanceOf(Context::class))
- ->willReturnCallback(function (Context $context) use ($contextStub) {
- $this->assertSame($contextStub, $context->getPsrContext());
- $this->assertNull($context->getPsrConsumer());
- $this->assertNull($context->getPsrProcessor());
- $this->assertNull($context->getLogger());
- $this->assertNull($context->getPsrMessage());
- $this->assertNull($context->getException());
- $this->assertNull($context->getResult());
- $this->assertNull($context->getPsrQueue());
- $this->assertFalse($context->isExecutionInterrupted());
+ ->with($this->isInstanceOf(Start::class))
+ ->willReturnCallback(function (Start $context) use ($contextStub) {
+ $this->assertSame($contextStub, $context->getContext());
+ $this->assertInstanceOf(NullLogger::class, $context->getLogger());
})
;
$chainExtensions = new ChainExtension([$extension, new BreakCycleExtension(1)]);
- $queueConsumer = new QueueConsumer($contextStub, $chainExtensions, 0);
- $queueConsumer->bind(new NullQueue('aQueueName'), $processorMock);
+ $queueConsumer = new QueueConsumer($contextStub, $chainExtensions);
+ $queueConsumer->setFallbackSubscriptionConsumer(new DummySubscriptionConsumer());
+ $queueConsumer->bind(new NullQueue('foo_queue'), $processorMock);
$queueConsumer->consume();
}
- public function testShouldCallOnIdleExtensionMethod()
+ public function testShouldCallOnStartWithLoggerProvidedInConstructor()
{
- $messageConsumerStub = $this->createMessageConsumerStub($message = null);
+ $consumerStub = $this->createConsumerStub('foo_queue');
- $contextStub = $this->createPsrContextStub($messageConsumerStub);
+ $contextStub = $this->createContextStub($consumerStub);
$processorMock = $this->createProcessorMock();
+ $expectedLogger = $this->createMock(LoggerInterface::class);
+
$extension = $this->createExtension();
$extension
->expects($this->once())
- ->method('onIdle')
- ->with($this->isInstanceOf(Context::class))
- ->willReturnCallback(function (Context $context) use (
- $contextStub,
- $messageConsumerStub,
- $processorMock
- ) {
- $this->assertSame($contextStub, $context->getPsrContext());
- $this->assertSame($messageConsumerStub, $context->getPsrConsumer());
- $this->assertSame($processorMock, $context->getPsrProcessor());
- $this->assertInstanceOf(NullLogger::class, $context->getLogger());
- $this->assertNull($context->getPsrMessage());
- $this->assertNull($context->getException());
- $this->assertNull($context->getResult());
- $this->assertFalse($context->isExecutionInterrupted());
+ ->method('onStart')
+ ->with($this->isInstanceOf(Start::class))
+ ->willReturnCallback(function (Start $context) use ($expectedLogger) {
+ $this->assertSame($expectedLogger, $context->getLogger());
})
;
$chainExtensions = new ChainExtension([$extension, new BreakCycleExtension(1)]);
- $queueConsumer = new QueueConsumer($contextStub, $chainExtensions, 0);
- $queueConsumer->bind(new NullQueue('aQueueName'), $processorMock);
+ $queueConsumer = new QueueConsumer($contextStub, $chainExtensions, [], $expectedLogger);
+ $queueConsumer->setFallbackSubscriptionConsumer(new DummySubscriptionConsumer());
+ $queueConsumer->bind(new NullQueue('foo_queue'), $processorMock);
$queueConsumer->consume();
}
- public function testShouldCallOnBeforeReceiveExtensionMethod()
+ public function testShouldInterruptExecutionOnStart()
{
- $expectedMessage = $this->createMessageMock();
- $messageConsumerStub = $this->createMessageConsumerStub($expectedMessage);
+ $consumerStub = $this->createConsumerStub('foo_queue');
- $contextStub = $this->createPsrContextStub($messageConsumerStub);
+ $contextStub = $this->createContextStub($consumerStub);
- $processorMock = $this->createProcessorStub();
+ $processorMock = $this->createProcessorMock();
+ $processorMock
+ ->expects($this->never())
+ ->method('process')
+ ;
- $queue = new NullQueue('aQueueName');
+ $expectedLogger = $this->createMock(LoggerInterface::class);
$extension = $this->createExtension();
$extension
->expects($this->once())
- ->method('onBeforeReceive')
- ->with($this->isInstanceOf(Context::class))
- ->willReturnCallback(function (Context $context) use (
- $contextStub,
- $messageConsumerStub,
- $processorMock,
- $queue
- ) {
- $this->assertSame($contextStub, $context->getPsrContext());
- $this->assertSame($messageConsumerStub, $context->getPsrConsumer());
- $this->assertSame($processorMock, $context->getPsrProcessor());
- $this->assertInstanceOf(NullLogger::class, $context->getLogger());
- $this->assertNull($context->getPsrMessage());
- $this->assertNull($context->getException());
- $this->assertNull($context->getResult());
- $this->assertFalse($context->isExecutionInterrupted());
- $this->assertSame($queue, $context->getPsrQueue());
+ ->method('onStart')
+ ->willReturnCallback(function (Start $context) {
+ $context->interruptExecution();
})
;
+ $extension
+ ->expects($this->once())
+ ->method('onEnd')
+ ;
+ $extension
+ ->expects($this->never())
+ ->method('onPreConsume')
+ ;
$chainExtensions = new ChainExtension([$extension, new BreakCycleExtension(1)]);
- $queueConsumer = new QueueConsumer($contextStub, $chainExtensions, 0);
- $queueConsumer->bind($queue, $processorMock);
+ $queueConsumer = new QueueConsumer($contextStub, $chainExtensions, [], $expectedLogger);
+ $queueConsumer->setFallbackSubscriptionConsumer(new DummySubscriptionConsumer());
+ $queueConsumer->bind(new NullQueue('foo_queue'), $processorMock);
$queueConsumer->consume();
}
- public function testShouldCallOnPreReceivedExtensionMethodWithExpectedContext()
+ public function testShouldCallPreSubscribeExtensionMethod()
{
- $expectedMessage = $this->createMessageMock();
- $messageConsumerStub = $this->createMessageConsumerStub($expectedMessage);
+ $consumerStub = $this->createConsumerStub('foo_queue');
- $contextStub = $this->createPsrContextStub($messageConsumerStub);
+ $contextStub = $this->createContextStub($consumerStub);
- $processorMock = $this->createProcessorStub();
+ $processorMock = $this->createProcessorMock();
$extension = $this->createExtension();
$extension
->expects($this->once())
- ->method('onPreReceived')
- ->with($this->isInstanceOf(Context::class))
- ->willReturnCallback(function (Context $context) use (
- $contextStub,
- $messageConsumerStub,
- $processorMock,
- $expectedMessage
- ) {
- $this->assertSame($contextStub, $context->getPsrContext());
- $this->assertSame($messageConsumerStub, $context->getPsrConsumer());
- $this->assertSame($processorMock, $context->getPsrProcessor());
- $this->assertSame($expectedMessage, $context->getPsrMessage());
+ ->method('onPreSubscribe')
+ ->with($this->isInstanceOf(PreSubscribe::class))
+ ->willReturnCallback(function (PreSubscribe $context) use ($contextStub, $consumerStub, $processorMock) {
+ $this->assertSame($contextStub, $context->getContext());
+ $this->assertSame($consumerStub, $context->getConsumer());
+ $this->assertSame($processorMock, $context->getProcessor());
$this->assertInstanceOf(NullLogger::class, $context->getLogger());
- $this->assertNull($context->getException());
- $this->assertNull($context->getResult());
- $this->assertFalse($context->isExecutionInterrupted());
})
;
$chainExtensions = new ChainExtension([$extension, new BreakCycleExtension(1)]);
- $queueConsumer = new QueueConsumer($contextStub, $chainExtensions, 0);
- $queueConsumer->bind(new NullQueue('aQueueName'), $processorMock);
+ $queueConsumer = new QueueConsumer($contextStub, $chainExtensions);
+ $queueConsumer->setFallbackSubscriptionConsumer(new DummySubscriptionConsumer());
+ $queueConsumer->bind(new NullQueue('foo_queue'), $processorMock);
$queueConsumer->consume();
}
- public function testShouldCallOnResultExtensionMethodWithExpectedContext()
+ public function testShouldCallPreSubscribeForEachBoundProcessor()
{
- $expectedMessage = $this->createMessageMock();
- $messageConsumerStub = $this->createMessageConsumerStub($expectedMessage);
+ $consumerStub = $this->createConsumerStub('foo_queue');
- $contextStub = $this->createPsrContextStub($messageConsumerStub);
+ $contextStub = $this->createContextStub($consumerStub);
- $processorMock = $this->createProcessorStub();
+ $processorMock = $this->createProcessorMock();
+
+ $extension = $this->createExtension();
+ $extension
+ ->expects($this->exactly(3))
+ ->method('onPreSubscribe')
+ ->with($this->isInstanceOf(PreSubscribe::class))
+ ;
+
+ $chainExtensions = new ChainExtension([$extension, new BreakCycleExtension(1)]);
+ $queueConsumer = new QueueConsumer($contextStub, $chainExtensions);
+ $queueConsumer->setFallbackSubscriptionConsumer(new DummySubscriptionConsumer());
+ $queueConsumer->bind(new NullQueue('foo_queue'), $processorMock);
+ $queueConsumer->bind(new NullQueue('bar_queue'), $processorMock);
+ $queueConsumer->bind(new NullQueue('baz_queue'), $processorMock);
+
+ $queueConsumer->consume();
+ }
+
+ public function testShouldCallOnPostConsumeExtensionMethod()
+ {
+ $consumerStub = $this->createConsumerStub('foo_queue');
+
+ $contextStub = $this->createContextStub($consumerStub);
+
+ $subscriptionConsumer = new DummySubscriptionConsumer();
+
+ $processorMock = $this->createProcessorMock();
$extension = $this->createExtension();
$extension
->expects($this->once())
- ->method('onResult')
- ->with($this->isInstanceOf(Context::class))
- ->willReturnCallback(function (Context $context) use (
- $contextStub,
- $messageConsumerStub,
- $processorMock,
- $expectedMessage
- ) {
- $this->assertSame($contextStub, $context->getPsrContext());
- $this->assertSame($messageConsumerStub, $context->getPsrConsumer());
- $this->assertSame($processorMock, $context->getPsrProcessor());
- $this->assertSame($expectedMessage, $context->getPsrMessage());
+ ->method('onPostConsume')
+ ->with($this->isInstanceOf(PostConsume::class))
+ ->willReturnCallback(function (PostConsume $context) use ($contextStub, $subscriptionConsumer) {
+ $this->assertSame($contextStub, $context->getContext());
+ $this->assertSame($subscriptionConsumer, $context->getSubscriptionConsumer());
+ $this->assertSame(1, $context->getCycle());
+ $this->assertSame(0, $context->getReceivedMessagesCount());
+ $this->assertGreaterThan(1, $context->getStartTime());
$this->assertInstanceOf(NullLogger::class, $context->getLogger());
- $this->assertNull($context->getException());
- $this->assertSame(Result::ACK, $context->getResult());
$this->assertFalse($context->isExecutionInterrupted());
})
;
$chainExtensions = new ChainExtension([$extension, new BreakCycleExtension(1)]);
- $queueConsumer = new QueueConsumer($contextStub, $chainExtensions, 0);
- $queueConsumer->bind(new NullQueue('aQueueName'), $processorMock);
+ $queueConsumer = new QueueConsumer($contextStub, $chainExtensions);
+ $queueConsumer->setFallbackSubscriptionConsumer($subscriptionConsumer);
+ $queueConsumer->bind(new NullQueue('foo_queue'), $processorMock);
$queueConsumer->consume();
}
- public function testShouldCallOnPostReceivedExtensionMethodWithExpectedContext()
+ public function testShouldCallOnPreConsumeExtensionMethod()
{
- $expectedMessage = $this->createMessageMock();
- $messageConsumerStub = $this->createMessageConsumerStub($expectedMessage);
+ $consumerStub = $this->createConsumerStub('foo_queue');
- $contextStub = $this->createPsrContextStub($messageConsumerStub);
+ $contextStub = $this->createContextStub($consumerStub);
$processorMock = $this->createProcessorStub();
+ $queue = new NullQueue('foo_queue');
+
$extension = $this->createExtension();
$extension
->expects($this->once())
- ->method('onPostReceived')
- ->with($this->isInstanceOf(Context::class))
- ->willReturnCallback(function (Context $context) use (
- $contextStub,
- $messageConsumerStub,
- $processorMock,
- $expectedMessage
- ) {
- $this->assertSame($contextStub, $context->getPsrContext());
- $this->assertSame($messageConsumerStub, $context->getPsrConsumer());
- $this->assertSame($processorMock, $context->getPsrProcessor());
- $this->assertSame($expectedMessage, $context->getPsrMessage());
+ ->method('onPreConsume')
+ ->with($this->isInstanceOf(PreConsume::class))
+ ->willReturnCallback(function (PreConsume $context) use ($contextStub) {
+ $this->assertSame($contextStub, $context->getContext());
$this->assertInstanceOf(NullLogger::class, $context->getLogger());
- $this->assertNull($context->getException());
- $this->assertSame(Result::ACK, $context->getResult());
+ $this->assertInstanceOf(SubscriptionConsumer::class, $context->getSubscriptionConsumer());
+ $this->assertSame(10000, $context->getReceiveTimeout());
+ $this->assertSame(1, $context->getCycle());
+ $this->assertGreaterThan(0, $context->getStartTime());
$this->assertFalse($context->isExecutionInterrupted());
})
;
$chainExtensions = new ChainExtension([$extension, new BreakCycleExtension(1)]);
- $queueConsumer = new QueueConsumer($contextStub, $chainExtensions, 0);
- $queueConsumer->bind(new NullQueue('aQueueName'), $processorMock);
+ $queueConsumer = new QueueConsumer($contextStub, $chainExtensions);
+ $queueConsumer->setFallbackSubscriptionConsumer(new DummySubscriptionConsumer());
+ $queueConsumer->bind($queue, $processorMock);
$queueConsumer->consume();
}
- public function testShouldAllowInterruptConsumingOnIdle()
+ public function testShouldCallOnPreConsumeExpectedAmountOfTimes()
{
- $messageConsumerStub = $this->createMessageConsumerStub($message = null);
+ $consumerStub = $this->createConsumerStub('foo_queue');
- $contextStub = $this->createPsrContextStub($messageConsumerStub);
+ $contextStub = $this->createContextStub($consumerStub);
- $processorMock = $this->createProcessorMock();
+ $processorMock = $this->createProcessorStub();
+
+ $queue = new NullQueue('foo_queue');
$extension = $this->createExtension();
$extension
- ->expects($this->once())
- ->method('onIdle')
- ->with($this->isInstanceOf(Context::class))
- ->willReturnCallback(function (Context $context) {
- $context->setExecutionInterrupted(true);
- })
+ ->expects($this->exactly(3))
+ ->method('onPreConsume')
;
+
+ $chainExtensions = new ChainExtension([$extension, new BreakCycleExtension(3)]);
+ $queueConsumer = new QueueConsumer($contextStub, $chainExtensions);
+ $queueConsumer->setFallbackSubscriptionConsumer(new DummySubscriptionConsumer());
+ $queueConsumer->bind($queue, $processorMock);
+
+ $queueConsumer->consume();
+ }
+
+ public function testShouldCallOnPreReceivedExtensionMethodWithExpectedContext()
+ {
+ $expectedMessage = $this->createMessageMock();
+
+ $subscriptionConsumerMock = new DummySubscriptionConsumer();
+ $subscriptionConsumerMock->addMessage($expectedMessage, 'foo_queue');
+
+ $consumerStub = $this->createConsumerStub('foo_queue');
+
+ $contextStub = $this->createContextStub($consumerStub);
+
+ $processorMock = $this->createProcessorStub();
+
+ $extension = $this->createExtension();
$extension
->expects($this->once())
- ->method('onInterrupted')
- ->with($this->isInstanceOf(Context::class))
- ->willReturnCallback(function (Context $context) use (
+ ->method('onMessageReceived')
+ ->with($this->isInstanceOf(MessageReceived::class))
+ ->willReturnCallback(function (MessageReceived $context) use (
$contextStub,
- $messageConsumerStub,
- $processorMock
+ $consumerStub,
+ $processorMock,
+ $expectedMessage
) {
- $this->assertSame($contextStub, $context->getPsrContext());
- $this->assertSame($messageConsumerStub, $context->getPsrConsumer());
- $this->assertSame($processorMock, $context->getPsrProcessor());
+ $this->assertSame($contextStub, $context->getContext());
+ $this->assertSame($consumerStub, $context->getConsumer());
+ $this->assertSame($processorMock, $context->getProcessor());
+ $this->assertSame($expectedMessage, $context->getMessage());
$this->assertInstanceOf(NullLogger::class, $context->getLogger());
- $this->assertNull($context->getPsrMessage());
- $this->assertNull($context->getException());
$this->assertNull($context->getResult());
- $this->assertTrue($context->isExecutionInterrupted());
})
;
$chainExtensions = new ChainExtension([$extension, new BreakCycleExtension(1)]);
- $queueConsumer = new QueueConsumer($contextStub, $chainExtensions, 0);
- $queueConsumer->bind(new NullQueue('aQueueName'), $processorMock);
+ $queueConsumer = new QueueConsumer($contextStub, $chainExtensions);
+ $queueConsumer->setFallbackSubscriptionConsumer($subscriptionConsumerMock);
+ $queueConsumer->bind(new NullQueue('foo_queue'), $processorMock);
$queueConsumer->consume();
}
- public function testShouldNotCloseContextWhenConsumptionInterrupted()
+ public function testShouldCallOnResultExtensionMethodWithExpectedContext()
{
- $messageConsumerStub = $this->createMessageConsumerStub($message = null);
+ $expectedMessage = $this->createMessageMock();
- $contextStub = $this->createPsrContextStub($messageConsumerStub);
- $contextStub
- ->expects($this->never())
- ->method('close')
- ;
+ $subscriptionConsumerMock = new DummySubscriptionConsumer();
+ $subscriptionConsumerMock->addMessage($expectedMessage, 'foo_queue');
- $processorMock = $this->createProcessorMock();
+ $consumerStub = $this->createConsumerStub('foo_queue');
+
+ $contextStub = $this->createContextStub($consumerStub);
+
+ $processorMock = $this->createProcessorStub();
$extension = $this->createExtension();
$extension
->expects($this->once())
- ->method('onIdle')
- ->with($this->isInstanceOf(Context::class))
- ->willReturnCallback(function (Context $context) {
- $context->setExecutionInterrupted(true);
+ ->method('onResult')
+ ->with($this->isInstanceOf(MessageResult::class))
+ ->willReturnCallback(function (MessageResult $context) use ($contextStub, $expectedMessage) {
+ $this->assertSame($contextStub, $context->getContext());
+ $this->assertSame($expectedMessage, $context->getMessage());
+ $this->assertInstanceOf(NullLogger::class, $context->getLogger());
+ $this->assertSame(Result::ACK, $context->getResult());
})
;
$chainExtensions = new ChainExtension([$extension, new BreakCycleExtension(1)]);
- $queueConsumer = new QueueConsumer($contextStub, $chainExtensions, 0);
- $queueConsumer->bind(new NullQueue('aQueueName'), $processorMock);
+ $queueConsumer = new QueueConsumer($contextStub, $chainExtensions);
+ $queueConsumer->setFallbackSubscriptionConsumer($subscriptionConsumerMock);
+ $queueConsumer->bind(new NullQueue('foo_queue'), $processorMock);
$queueConsumer->consume();
}
- public function testShouldNotCloseContextWhenConsumptionInterruptedByException()
+ public function testShouldCallOnProcessorExceptionExtensionMethodWithExpectedContext()
{
- $expectedException = new \Exception();
+ $exception = new \LogicException('Exception exception');
- $messageConsumerStub = $this->createMessageConsumerStub($message = $this->createMessageMock());
+ $expectedMessage = $this->createMessageMock();
- $contextStub = $this->createPsrContextStub($messageConsumerStub);
- $contextStub
- ->expects($this->never())
- ->method('close')
- ;
+ $subscriptionConsumerMock = new DummySubscriptionConsumer();
+ $subscriptionConsumerMock->addMessage($expectedMessage, 'foo_queue');
- $processorMock = $this->createProcessorMock();
+ $consumerStub = $this->createConsumerStub('foo_queue');
+
+ $contextStub = $this->createContextStub($consumerStub);
+
+ $processorMock = $this->createProcessorStub();
$processorMock
->expects($this->once())
->method('process')
- ->willThrowException($expectedException)
+ ->willThrowException($exception)
;
- $queueConsumer = new QueueConsumer($contextStub, new BreakCycleExtension(1), 0);
- $queueConsumer->bind(new NullQueue('aQueueName'), $processorMock);
-
- try {
- $queueConsumer->consume();
- } catch (\Exception $e) {
- $this->assertSame($expectedException, $e);
- $this->assertNull($e->getPrevious());
+ $extension = $this->createExtension();
+ $extension
+ ->expects($this->never())
+ ->method('onResult')
+ ;
+ $extension
+ ->expects($this->once())
+ ->method('onProcessorException')
+ ->with($this->isInstanceOf(ProcessorException::class))
+ ->willReturnCallback(function (ProcessorException $context) use ($contextStub, $expectedMessage, $exception) {
+ $this->assertSame($contextStub, $context->getContext());
+ $this->assertSame($expectedMessage, $context->getMessage());
+ $this->assertSame($exception, $context->getException());
+ $this->assertGreaterThan(1, $context->getReceivedAt());
+ $this->assertInstanceOf(NullLogger::class, $context->getLogger());
+ $this->assertNull($context->getResult());
+ })
+ ;
- return;
- }
+ $chainExtensions = new ChainExtension([$extension, new BreakCycleExtension(1)]);
+ $queueConsumer = new QueueConsumer($contextStub, $chainExtensions);
+ $queueConsumer->setFallbackSubscriptionConsumer($subscriptionConsumerMock);
+ $queueConsumer->bind(new NullQueue('foo_queue'), $processorMock);
- $this->fail('Exception throw is expected.');
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Exception exception');
+ $queueConsumer->consume();
}
- public function testShouldSetMainExceptionAsPreviousToExceptionThrownOnInterrupt()
+ public function testShouldContinueConsumptionIfResultSetOnProcessorExceptionExtension()
{
- $mainException = new \Exception();
- $expectedException = new \Exception();
+ $result = Result::ack();
- $messageConsumerStub = $this->createMessageConsumerStub($message = $this->createMessageMock());
+ $expectedMessage = $this->createMessageMock();
- $contextStub = $this->createPsrContextStub($messageConsumerStub);
+ $subscriptionConsumerMock = new DummySubscriptionConsumer();
+ $subscriptionConsumerMock->addMessage($expectedMessage, 'foo_queue');
- $processorMock = $this->createProcessorMock();
+ $consumerStub = $this->createConsumerStub('foo_queue');
+
+ $contextStub = $this->createContextStub($consumerStub);
+
+ $processorMock = $this->createProcessorStub();
$processorMock
->expects($this->once())
->method('process')
- ->willThrowException($mainException)
+ ->willThrowException(new \LogicException())
;
$extension = $this->createExtension();
$extension
- ->expects($this->atLeastOnce())
- ->method('onInterrupted')
- ->willThrowException($expectedException)
+ ->expects($this->once())
+ ->method('onProcessorException')
+ ->willReturnCallback(function (ProcessorException $context) use ($result) {
+ $context->setResult($result);
+ })
+ ;
+ $extension
+ ->expects($this->once())
+ ->method('onResult')
+ ->willReturnCallback(function (MessageResult $context) use ($result) {
+ $this->assertSame($result, $context->getResult());
+ })
;
$chainExtensions = new ChainExtension([$extension, new BreakCycleExtension(1)]);
- $queueConsumer = new QueueConsumer($contextStub, $chainExtensions, 0);
- $queueConsumer->bind(new NullQueue('aQueueName'), $processorMock);
+ $queueConsumer = new QueueConsumer($contextStub, $chainExtensions);
+ $queueConsumer->setFallbackSubscriptionConsumer($subscriptionConsumerMock);
+ $queueConsumer->bind(new NullQueue('foo_queue'), $processorMock);
- try {
- $queueConsumer->consume();
- } catch (\Exception $e) {
- $this->assertSame($expectedException, $e);
- $this->assertSame($mainException, $e->getPrevious());
-
- return;
- }
-
- $this->fail('Exception throw is expected.');
+ $queueConsumer->consume();
}
- public function testShouldAllowInterruptConsumingOnPreReceiveButProcessCurrentMessage()
+ public function testShouldCallOnPostMessageReceivedExtensionMethodWithExpectedContext()
{
$expectedMessage = $this->createMessageMock();
- $messageConsumerStub = $this->createMessageConsumerStub($expectedMessage);
- $contextStub = $this->createPsrContextStub($messageConsumerStub);
+ $subscriptionConsumerMock = new DummySubscriptionConsumer();
+ $subscriptionConsumerMock->addMessage($expectedMessage, 'foo_queue');
- $processorMock = $this->createProcessorMock();
- $processorMock
- ->expects($this->once())
- ->method('process')
- ->willReturn(Result::ACK)
- ;
+ $consumerStub = $this->createConsumerStub('foo_queue');
+
+ $contextStub = $this->createContextStub($consumerStub);
+
+ $processorMock = $this->createProcessorStub();
$extension = $this->createExtension();
$extension
->expects($this->once())
- ->method('onPreReceived')
- ->with($this->isInstanceOf(Context::class))
- ->willReturnCallback(function (Context $context) {
- $context->setExecutionInterrupted(true);
- })
- ;
- $extension
- ->expects($this->atLeastOnce())
- ->method('onInterrupted')
- ->with($this->isInstanceOf(Context::class))
- ->willReturnCallback(function (Context $context) use (
+ ->method('onPostMessageReceived')
+ ->with($this->isInstanceOf(PostMessageReceived::class))
+ ->willReturnCallback(function (PostMessageReceived $context) use (
$contextStub,
- $messageConsumerStub,
- $processorMock,
$expectedMessage
) {
- $this->assertSame($contextStub, $context->getPsrContext());
- $this->assertSame($messageConsumerStub, $context->getPsrConsumer());
- $this->assertSame($processorMock, $context->getPsrProcessor());
- $this->assertSame($expectedMessage, $context->getPsrMessage());
+ $this->assertSame($contextStub, $context->getContext());
+ $this->assertSame($expectedMessage, $context->getMessage());
$this->assertInstanceOf(NullLogger::class, $context->getLogger());
- $this->assertNull($context->getException());
$this->assertSame(Result::ACK, $context->getResult());
- $this->assertTrue($context->isExecutionInterrupted());
+ $this->assertFalse($context->isExecutionInterrupted());
})
;
$chainExtensions = new ChainExtension([$extension, new BreakCycleExtension(1)]);
- $queueConsumer = new QueueConsumer($contextStub, $chainExtensions, 0);
- $queueConsumer->bind(new NullQueue('aQueueName'), $processorMock);
+ $queueConsumer = new QueueConsumer($contextStub, $chainExtensions);
+ $queueConsumer->setFallbackSubscriptionConsumer($subscriptionConsumerMock);
+ $queueConsumer->bind(new NullQueue('foo_queue'), $processorMock);
$queueConsumer->consume();
}
- public function testShouldAllowInterruptConsumingOnResult()
+ public function testShouldAllowInterruptConsumingOnPostConsume()
{
- $expectedMessage = $this->createMessageMock();
- $messageConsumerStub = $this->createMessageConsumerStub($expectedMessage);
+ $consumerStub = $this->createConsumerStub('foo_queue');
- $contextStub = $this->createPsrContextStub($messageConsumerStub);
+ $contextStub = $this->createContextStub($consumerStub);
$processorMock = $this->createProcessorMock();
- $processorMock
- ->expects($this->once())
- ->method('process')
- ->willReturn(Result::ACK)
- ;
$extension = $this->createExtension();
$extension
->expects($this->once())
- ->method('onResult')
- ->with($this->isInstanceOf(Context::class))
- ->willReturnCallback(function (Context $context) {
- $context->setExecutionInterrupted(true);
+ ->method('onPostConsume')
+ ->with($this->isInstanceOf(PostConsume::class))
+ ->willReturnCallback(function (PostConsume $context) {
+ $context->interruptExecution();
})
;
$extension
- ->expects($this->atLeastOnce())
- ->method('onInterrupted')
- ->with($this->isInstanceOf(Context::class))
- ->willReturnCallback(function (Context $context) use (
- $contextStub,
- $messageConsumerStub,
- $processorMock,
- $expectedMessage
- ) {
- $this->assertSame($contextStub, $context->getPsrContext());
- $this->assertSame($messageConsumerStub, $context->getPsrConsumer());
- $this->assertSame($processorMock, $context->getPsrProcessor());
- $this->assertSame($expectedMessage, $context->getPsrMessage());
+ ->expects($this->once())
+ ->method('onEnd')
+ ->with($this->isInstanceOf(End::class))
+ ->willReturnCallback(function (End $context) use ($contextStub) {
+ $this->assertSame($contextStub, $context->getContext());
$this->assertInstanceOf(NullLogger::class, $context->getLogger());
- $this->assertNull($context->getException());
- $this->assertSame(Result::ACK, $context->getResult());
- $this->assertTrue($context->isExecutionInterrupted());
+ $this->assertGreaterThan(1, $context->getStartTime());
+ $this->assertGreaterThan(1, $context->getEndTime());
})
;
$chainExtensions = new ChainExtension([$extension, new BreakCycleExtension(1)]);
- $queueConsumer = new QueueConsumer($contextStub, $chainExtensions, 0);
- $queueConsumer->bind(new NullQueue('aQueueName'), $processorMock);
+ $queueConsumer = new QueueConsumer($contextStub, $chainExtensions);
+ $queueConsumer->setFallbackSubscriptionConsumer(new DummySubscriptionConsumer());
+ $queueConsumer->bind(new NullQueue('foo_queue'), $processorMock);
$queueConsumer->consume();
}
- public function testShouldAllowInterruptConsumingOnPostReceive()
+ public function testShouldSetMainExceptionAsPreviousToExceptionThrownOnProcessorException()
+ {
+ $mainException = new \Exception();
+ $expectedException = new \Exception();
+
+ $subscriptionConsumerMock = new DummySubscriptionConsumer();
+ $subscriptionConsumerMock->addMessage($this->createMessageMock(), 'foo_queue');
+
+ $consumerStub = $this->createConsumerStub('foo_queue');
+
+ $contextStub = $this->createContextStub($consumerStub);
+
+ $processorMock = $this->createProcessorMock();
+ $processorMock
+ ->expects($this->once())
+ ->method('process')
+ ->willThrowException($mainException)
+ ;
+
+ $extension = $this->createExtension();
+ $extension
+ ->expects($this->atLeastOnce())
+ ->method('onProcessorException')
+ ->willThrowException($expectedException)
+ ;
+
+ $chainExtensions = new ChainExtension([$extension, new BreakCycleExtension(1)]);
+ $queueConsumer = new QueueConsumer($contextStub, $chainExtensions);
+ $queueConsumer->setFallbackSubscriptionConsumer($subscriptionConsumerMock);
+ $queueConsumer->bind(new NullQueue('foo_queue'), $processorMock);
+
+ try {
+ $queueConsumer->consume();
+ } catch (\Exception $e) {
+ $this->assertSame($expectedException, $e);
+ $this->assertSame($mainException, $e->getPrevious());
+
+ return;
+ }
+
+ $this->fail('Exception throw is expected.');
+ }
+
+ public function testShouldAllowInterruptConsumingOnPostMessageReceived()
{
$expectedMessage = $this->createMessageMock();
- $messageConsumerStub = $this->createMessageConsumerStub($expectedMessage);
- $contextStub = $this->createPsrContextStub($messageConsumerStub);
+ $subscriptionConsumerMock = new DummySubscriptionConsumer();
+ $subscriptionConsumerMock->addMessage($expectedMessage, 'foo_queue');
+
+ $consumerStub = $this->createConsumerStub('foo_queue');
+
+ $contextStub = $this->createContextStub($consumerStub);
$processorMock = $this->createProcessorMock();
$processorMock
@@ -891,47 +1152,37 @@ public function testShouldAllowInterruptConsumingOnPostReceive()
$extension = $this->createExtension();
$extension
->expects($this->once())
- ->method('onPostReceived')
- ->with($this->isInstanceOf(Context::class))
- ->willReturnCallback(function (Context $context) {
- $context->setExecutionInterrupted(true);
+ ->method('onPostMessageReceived')
+ ->with($this->isInstanceOf(PostMessageReceived::class))
+ ->willReturnCallback(function (PostMessageReceived $context) {
+ $context->interruptExecution();
})
;
$extension
->expects($this->atLeastOnce())
- ->method('onInterrupted')
- ->with($this->isInstanceOf(Context::class))
- ->willReturnCallback(function (Context $context) use (
- $contextStub,
- $messageConsumerStub,
- $processorMock,
- $expectedMessage
- ) {
- $this->assertSame($contextStub, $context->getPsrContext());
- $this->assertSame($messageConsumerStub, $context->getPsrConsumer());
- $this->assertSame($processorMock, $context->getPsrProcessor());
- $this->assertSame($expectedMessage, $context->getPsrMessage());
- $this->assertInstanceOf(NullLogger::class, $context->getLogger());
- $this->assertNull($context->getException());
- $this->assertSame(Result::ACK, $context->getResult());
- $this->assertTrue($context->isExecutionInterrupted());
- })
+ ->method('onEnd')
+ ->with($this->isInstanceOf(End::class))
;
$chainExtensions = new ChainExtension([$extension, new BreakCycleExtension(1)]);
- $queueConsumer = new QueueConsumer($contextStub, $chainExtensions, 0);
- $queueConsumer->bind(new NullQueue('aQueueName'), $processorMock);
+ $queueConsumer = new QueueConsumer($contextStub, $chainExtensions);
+ $queueConsumer->setFallbackSubscriptionConsumer($subscriptionConsumerMock);
+ $queueConsumer->bind(new NullQueue('foo_queue'), $processorMock);
$queueConsumer->consume();
}
- public function testShouldCallOnInterruptedIfExceptionThrow()
+ public function testShouldNotCallOnEndIfExceptionThrow()
{
$expectedException = new \Exception('Process failed');
$expectedMessage = $this->createMessageMock();
- $messageConsumerStub = $this->createMessageConsumerStub($expectedMessage);
- $contextStub = $this->createPsrContextStub($messageConsumerStub);
+ $subscriptionConsumerMock = new DummySubscriptionConsumer();
+ $subscriptionConsumerMock->addMessage($expectedMessage, 'foo_queue');
+
+ $consumerStub = $this->createConsumerStub('foo_queue');
+
+ $contextStub = $this->createContextStub($consumerStub);
$processorMock = $this->createProcessorMock();
$processorMock
@@ -942,30 +1193,14 @@ public function testShouldCallOnInterruptedIfExceptionThrow()
$extension = $this->createExtension();
$extension
- ->expects($this->atLeastOnce())
- ->method('onInterrupted')
- ->with($this->isInstanceOf(Context::class))
- ->willReturnCallback(function (Context $context) use (
- $contextStub,
- $messageConsumerStub,
- $processorMock,
- $expectedMessage,
- $expectedException
- ) {
- $this->assertSame($contextStub, $context->getPsrContext());
- $this->assertSame($messageConsumerStub, $context->getPsrConsumer());
- $this->assertSame($processorMock, $context->getPsrProcessor());
- $this->assertSame($expectedMessage, $context->getPsrMessage());
- $this->assertSame($expectedException, $context->getException());
- $this->assertInstanceOf(NullLogger::class, $context->getLogger());
- $this->assertNull($context->getResult());
- $this->assertTrue($context->isExecutionInterrupted());
- })
+ ->expects($this->never())
+ ->method('onEnd')
;
$chainExtensions = new ChainExtension([$extension, new BreakCycleExtension(1)]);
- $queueConsumer = new QueueConsumer($contextStub, $chainExtensions, 0);
- $queueConsumer->bind(new NullQueue('aQueueName'), $processorMock);
+ $queueConsumer = new QueueConsumer($contextStub, $chainExtensions);
+ $queueConsumer->setFallbackSubscriptionConsumer($subscriptionConsumerMock);
+ $queueConsumer->bind(new NullQueue('foo_queue'), $processorMock);
$this->expectException(\Exception::class);
$this->expectExceptionMessage('Process failed');
@@ -975,9 +1210,13 @@ public function testShouldCallOnInterruptedIfExceptionThrow()
public function testShouldCallExtensionPassedOnRuntime()
{
$expectedMessage = $this->createMessageMock();
- $messageConsumerStub = $this->createMessageConsumerStub($expectedMessage);
- $contextStub = $this->createPsrContextStub($messageConsumerStub);
+ $subscriptionConsumerMock = new DummySubscriptionConsumer();
+ $subscriptionConsumerMock->addMessage($expectedMessage, 'foo_queue');
+
+ $consumerStub = $this->createConsumerStub('foo_queue');
+
+ $contextStub = $this->createContextStub($consumerStub);
$processorMock = $this->createProcessorMock();
$processorMock
@@ -987,44 +1226,59 @@ public function testShouldCallExtensionPassedOnRuntime()
;
$runtimeExtension = $this->createExtension();
+ $runtimeExtension
+ ->expects($this->once())
+ ->method('onInitLogger')
+ ->with($this->isInstanceOf(InitLogger::class))
+ ;
$runtimeExtension
->expects($this->once())
->method('onStart')
- ->with($this->isInstanceOf(Context::class))
+ ->with($this->isInstanceOf(Start::class))
;
$runtimeExtension
->expects($this->once())
- ->method('onBeforeReceive')
- ->with($this->isInstanceOf(Context::class))
+ ->method('onPreSubscribe')
+ ->with($this->isInstanceOf(PreSubscribe::class))
;
$runtimeExtension
->expects($this->once())
- ->method('onPreReceived')
- ->with($this->isInstanceOf(Context::class))
+ ->method('onPreConsume')
+ ->with($this->isInstanceOf(PreConsume::class))
+ ;
+ $runtimeExtension
+ ->expects($this->once())
+ ->method('onMessageReceived')
+ ->with($this->isInstanceOf(MessageReceived::class))
;
$runtimeExtension
->expects($this->once())
->method('onResult')
- ->with($this->isInstanceOf(Context::class))
+ ->with($this->isInstanceOf(MessageResult::class))
;
$runtimeExtension
->expects($this->once())
- ->method('onPostReceived')
- ->with($this->isInstanceOf(Context::class))
+ ->method('onPostMessageReceived')
+ ->with($this->isInstanceOf(PostMessageReceived::class))
;
- $queueConsumer = new QueueConsumer($contextStub, new BreakCycleExtension(1), 0);
- $queueConsumer->bind(new NullQueue('aQueueName'), $processorMock);
+ $queueConsumer = new QueueConsumer($contextStub, new BreakCycleExtension(1));
+ $queueConsumer->setFallbackSubscriptionConsumer($subscriptionConsumerMock);
+ $queueConsumer->bind(new NullQueue('foo_queue'), $processorMock);
$queueConsumer->consume(new ChainExtension([$runtimeExtension]));
}
- public function testShouldChangeLoggerOnStart()
+ public function testShouldChangeLoggerOnInitLogger()
{
$expectedMessage = $this->createMessageMock();
- $messageConsumerStub = $this->createMessageConsumerStub($expectedMessage);
- $contextStub = $this->createPsrContextStub($messageConsumerStub);
+ $subscriptionConsumerMock = new DummySubscriptionConsumer();
+ $subscriptionConsumerMock->addMessage($expectedMessage, 'foo_queue');
+
+ $consumerStub = $this->createConsumerStub('foo_queue');
+
+ $contextStub = $this->createContextStub($consumerStub);
$processorMock = $this->createProcessorMock();
$processorMock
@@ -1036,136 +1290,204 @@ public function testShouldChangeLoggerOnStart()
$expectedLogger = new NullLogger();
$extension = $this->createExtension();
+ $extension
+ ->expects($this->atLeastOnce())
+ ->method('onInitLogger')
+ ->with($this->isInstanceOf(InitLogger::class))
+ ->willReturnCallback(function (InitLogger $context) use ($expectedLogger) {
+ $context->changeLogger($expectedLogger);
+ })
+ ;
$extension
->expects($this->atLeastOnce())
->method('onStart')
- ->with($this->isInstanceOf(Context::class))
- ->willReturnCallback(function (Context $context) use ($expectedLogger) {
- $context->setLogger($expectedLogger);
+ ->with($this->isInstanceOf(Start::class))
+ ->willReturnCallback(function (Start $context) use ($expectedLogger) {
+ $this->assertSame($expectedLogger, $context->getLogger());
+ })
+ ;
+ $extension
+ ->expects($this->atLeastOnce())
+ ->method('onPreSubscribe')
+ ->with($this->isInstanceOf(PreSubscribe::class))
+ ->willReturnCallback(function (PreSubscribe $context) use ($expectedLogger) {
+ $this->assertSame($expectedLogger, $context->getLogger());
})
;
$extension
->expects($this->atLeastOnce())
- ->method('onBeforeReceive')
- ->with($this->isInstanceOf(Context::class))
- ->willReturnCallback(function (Context $context) use ($expectedLogger) {
+ ->method('onPreConsume')
+ ->with($this->isInstanceOf(PreConsume::class))
+ ->willReturnCallback(function (PreConsume $context) use ($expectedLogger) {
$this->assertSame($expectedLogger, $context->getLogger());
})
;
$extension
->expects($this->atLeastOnce())
- ->method('onPreReceived')
- ->with($this->isInstanceOf(Context::class))
- ->willReturnCallback(function (Context $context) use ($expectedLogger) {
+ ->method('onMessageReceived')
+ ->with($this->isInstanceOf(MessageReceived::class))
+ ->willReturnCallback(function (MessageReceived $context) use ($expectedLogger) {
$this->assertSame($expectedLogger, $context->getLogger());
})
;
$chainExtensions = new ChainExtension([$extension, new BreakCycleExtension(1)]);
- $queueConsumer = new QueueConsumer($contextStub, $chainExtensions, 0);
- $queueConsumer->bind(new NullQueue('aQueueName'), $processorMock);
+ $queueConsumer = new QueueConsumer($contextStub, $chainExtensions);
+ $queueConsumer->setFallbackSubscriptionConsumer($subscriptionConsumerMock);
+ $queueConsumer->bind(new NullQueue('foo_queue'), $processorMock);
$queueConsumer->consume();
}
- public function testShouldCallEachQueueOneByOne()
+ public function testShouldCallProcessorAsMessageComeAlong()
{
- $expectedMessage = $this->createMessageMock();
- $messageConsumerStub = $this->createMessageConsumerStub($expectedMessage);
+ $queue1 = new NullQueue('foo_queue');
+ $queue2 = new NullQueue('bar_queue');
+
+ $firstMessage = $this->createMessageMock();
+ $secondMessage = $this->createMessageMock();
+ $thirdMessage = $this->createMessageMock();
+
+ $subscriptionConsumerMock = new DummySubscriptionConsumer();
+ $subscriptionConsumerMock->addMessage($firstMessage, 'foo_queue');
+ $subscriptionConsumerMock->addMessage($secondMessage, 'bar_queue');
+ $subscriptionConsumerMock->addMessage($thirdMessage, 'foo_queue');
+
+ $fooConsumerStub = $this->createConsumerStub($queue1);
+ $barConsumerStub = $this->createConsumerStub($queue2);
- $contextStub = $this->createPsrContextStub($messageConsumerStub);
+ $consumers = [
+ 'foo_queue' => $fooConsumerStub,
+ 'bar_queue' => $barConsumerStub,
+ ];
+
+ $contextStub = $this->createContextWithoutSubscriptionConsumerMock();
+ $contextStub
+ ->expects($this->any())
+ ->method('createQueue')
+ ->willReturnCallback(function (string $queueName) {
+ return new NullQueue($queueName);
+ })
+ ;
+ $contextStub
+ ->expects($this->any())
+ ->method('createConsumer')
+ ->willReturnCallback(function (Queue $queue) use ($consumers) {
+ return $consumers[$queue->getQueueName()];
+ })
+ ;
$processorMock = $this->createProcessorStub();
$anotherProcessorMock = $this->createProcessorStub();
- $queue1 = new NullQueue('aQueueName');
- $queue2 = new NullQueue('aAnotherQueueName');
+ /** @var MessageReceived[] $actualContexts */
+ $actualContexts = [];
$extension = $this->createExtension();
$extension
- ->expects($this->at(1))
- ->method('onBeforeReceive')
- ->with($this->isInstanceOf(Context::class))
- ->willReturnCallback(function (Context $context) use ($processorMock, $queue1) {
- $this->assertSame($processorMock, $context->getPsrProcessor());
- $this->assertSame($queue1, $context->getPsrQueue());
- })
- ;
- $extension
- ->expects($this->at(5))
- ->method('onBeforeReceive')
- ->with($this->isInstanceOf(Context::class))
- ->willReturnCallback(function (Context $context) use ($anotherProcessorMock, $queue2) {
- $this->assertSame($anotherProcessorMock, $context->getPsrProcessor());
- $this->assertSame($queue2, $context->getPsrQueue());
+ ->expects($this->any())
+ ->method('onMessageReceived')
+ ->with($this->isInstanceOf(MessageReceived::class))
+ ->willReturnCallback(function (MessageReceived $context) use (&$actualContexts) {
+ $actualContexts[] = clone $context;
})
;
- $queueConsumer = new QueueConsumer($contextStub, new BreakCycleExtension(2), 0);
+ $queueConsumer = new QueueConsumer($contextStub, new BreakCycleExtension(3));
+ $queueConsumer->setFallbackSubscriptionConsumer($subscriptionConsumerMock);
$queueConsumer
->bind($queue1, $processorMock)
->bind($queue2, $anotherProcessorMock)
;
$queueConsumer->consume(new ChainExtension([$extension]));
+
+ $this->assertCount(3, $actualContexts);
+
+ $this->assertSame($firstMessage, $actualContexts[0]->getMessage());
+ $this->assertSame($secondMessage, $actualContexts[1]->getMessage());
+ $this->assertSame($thirdMessage, $actualContexts[2]->getMessage());
+
+ $this->assertSame($fooConsumerStub, $actualContexts[0]->getConsumer());
+ $this->assertSame($barConsumerStub, $actualContexts[1]->getConsumer());
+ $this->assertSame($fooConsumerStub, $actualContexts[2]->getConsumer());
+ }
+
+ public function testCaptureExitStatus()
+ {
+ $testExitCode = 5;
+
+ $stubExtension = $this->createExtension();
+
+ $stubExtension
+ ->expects($this->once())
+ ->method('onStart')
+ ->with($this->isInstanceOf(Start::class))
+ ->willReturnCallback(function (Start $context) use ($testExitCode) {
+ $context->interruptExecution($testExitCode);
+ })
+ ;
+
+ $exitExtension = new ExitStatusExtension();
+
+ $consumer = new QueueConsumer($this->createContextStub(), $stubExtension);
+ $consumer->consume(new ChainExtension([$exitExtension]));
+
+ $this->assertEquals($testExitCode, $exitExtension->getExitStatus());
}
/**
- * @param null|mixed $message
- *
- * @return \PHPUnit_Framework_MockObject_MockObject|PsrConsumer
+ * @return \PHPUnit\Framework\MockObject\MockObject
*/
- protected function createMessageConsumerStub($message = null)
+ private function createContextWithoutSubscriptionConsumerMock(): InteropContext
{
- $messageConsumerMock = $this->createMock(PsrConsumer::class);
- $messageConsumerMock
+ $contextMock = $this->createMock(InteropContext::class);
+ $contextMock
->expects($this->any())
- ->method('receive')
- ->willReturn($message)
+ ->method('createSubscriptionConsumer')
+ ->willThrowException(SubscriptionConsumerNotSupportedException::providerDoestNotSupportIt())
;
- return $messageConsumerMock;
+ return $contextMock;
}
/**
- * @param null|mixed $messageConsumer
- *
- * @return \PHPUnit_Framework_MockObject_MockObject|PsrContext
+ * @return \PHPUnit\Framework\MockObject\MockObject|InteropContext
*/
- protected function createPsrContextStub($messageConsumer = null)
+ private function createContextStub(?Consumer $consumer = null): InteropContext
{
- $context = $this->createMock(PsrContext::class);
- $context
- ->expects($this->any())
- ->method('createConsumer')
- ->willReturn($messageConsumer)
- ;
+ $context = $this->createContextWithoutSubscriptionConsumerMock();
$context
->expects($this->any())
->method('createQueue')
- ->willReturn($this->createMock(PsrQueue::class))
+ ->willReturnCallback(function (string $queueName) {
+ return new NullQueue($queueName);
+ })
;
$context
->expects($this->any())
- ->method('close')
+ ->method('createConsumer')
+ ->willReturnCallback(function (Queue $queue) use ($consumer) {
+ return $consumer ?: $this->createConsumerStub($queue);
+ })
;
return $context;
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|PsrProcessor
+ * @return \PHPUnit\Framework\MockObject\MockObject|Processor
*/
- protected function createProcessorMock()
+ private function createProcessorMock()
{
- return $this->createMock(PsrProcessor::class);
+ return $this->createMock(Processor::class);
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|PsrProcessor
+ * @return \PHPUnit\Framework\MockObject\MockObject|Processor
*/
- protected function createProcessorStub()
+ private function createProcessorStub()
{
$processorMock = $this->createProcessorMock();
$processorMock
@@ -1178,18 +1500,50 @@ protected function createProcessorStub()
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|PsrMessage
+ * @return \PHPUnit\Framework\MockObject\MockObject|Message
*/
- protected function createMessageMock()
+ private function createMessageMock(): Message
{
- return $this->createMock(PsrMessage::class);
+ return $this->createMock(Message::class);
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|ExtensionInterface
+ * @return \PHPUnit\Framework\MockObject\MockObject|ExtensionInterface
*/
- protected function createExtension()
+ private function createExtension()
{
return $this->createMock(ExtensionInterface::class);
}
+
+ /**
+ * @param mixed|null $queue
+ *
+ * @return \PHPUnit\Framework\MockObject\MockObject|Consumer
+ */
+ private function createConsumerStub($queue = null): Consumer
+ {
+ if (null === $queue) {
+ $queue = 'queue';
+ }
+ if (is_string($queue)) {
+ $queue = new NullQueue($queue);
+ }
+
+ $consumerMock = $this->createMock(Consumer::class);
+ $consumerMock
+ ->expects($this->any())
+ ->method('getQueue')
+ ->willReturn($queue)
+ ;
+
+ return $consumerMock;
+ }
+
+ /**
+ * @return SubscriptionConsumer|\PHPUnit\Framework\MockObject\MockObject
+ */
+ private function createSubscriptionConsumerMock(): SubscriptionConsumer
+ {
+ return $this->createMock(SubscriptionConsumer::class);
+ }
}
diff --git a/pkg/enqueue/Tests/DoctrineConnectionFactoryFactoryTest.php b/pkg/enqueue/Tests/DoctrineConnectionFactoryFactoryTest.php
new file mode 100644
index 000000000..14f7b1006
--- /dev/null
+++ b/pkg/enqueue/Tests/DoctrineConnectionFactoryFactoryTest.php
@@ -0,0 +1,71 @@
+registry = $this->prophesize(ManagerRegistry::class);
+ $this->fallbackFactory = $this->prophesize(ConnectionFactoryFactoryInterface::class);
+
+ $this->factory = new DoctrineConnectionFactoryFactory($this->registry->reveal(), $this->fallbackFactory->reveal());
+ }
+
+ public function testCreateWithoutArray()
+ {
+ $this->expectException(\InvalidArgumentException::class);
+ $this->expectExceptionMessage('The config must be either array or DSN string.');
+
+ $this->factory->create(true);
+ }
+
+ public function testCreateWithoutDsn()
+ {
+ $this->expectExceptionMessage(\InvalidArgumentException::class);
+ $this->expectExceptionMessage('The config must have dsn key set.');
+
+ $this->factory->create(['foo' => 'bar']);
+ }
+
+ public function testCreateWithDoctrineSchema()
+ {
+ $this->assertInstanceOf(
+ ManagerRegistryConnectionFactory::class,
+ $this->factory->create('doctrine://localhost:3306')
+ );
+ }
+
+ public function testCreateFallback()
+ {
+ $this->fallbackFactory
+ ->create(['dsn' => 'fallback://'])
+ ->shouldBeCalled();
+
+ $this->factory->create(['dsn' => 'fallback://']);
+ }
+}
diff --git a/pkg/enqueue/Tests/Functions/DsnToConnectionFactoryFunctionTest.php b/pkg/enqueue/Tests/Functions/DsnToConnectionFactoryFunctionTest.php
deleted file mode 100644
index 2c65eb6d9..000000000
--- a/pkg/enqueue/Tests/Functions/DsnToConnectionFactoryFunctionTest.php
+++ /dev/null
@@ -1,104 +0,0 @@
-expectException(\LogicException::class);
- $this->expectExceptionMessage('The scheme could not be parsed from DSN ""');
-
- \Enqueue\dsn_to_connection_factory('');
- }
-
- public function testThrowIfDsnMissingScheme()
- {
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('The scheme could not be parsed from DSN "dsnMissingScheme"');
-
- \Enqueue\dsn_to_connection_factory('dsnMissingScheme');
- }
-
- public function testThrowIfDsnNotSupported()
- {
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('The scheme "http" is not supported. Supported "file", "amqp+ext"');
-
- \Enqueue\dsn_to_connection_factory('http://schemenotsupported/');
- }
-
- /**
- * @dataProvider provideDSNs
- *
- * @param mixed $dsn
- * @param mixed $expectedFactoryClass
- */
- public function testReturnsExpectedFactoryInstance($dsn, $expectedFactoryClass)
- {
- $factory = \Enqueue\dsn_to_connection_factory($dsn);
-
- $this->assertInstanceOf($expectedFactoryClass, $factory);
- }
-
- public static function provideDSNs()
- {
- yield ['amqp:', AmqpExtConnectionFactory::class];
-
- yield ['amqps:', AmqpExtConnectionFactory::class];
-
- yield ['amqp+ext:', AmqpExtConnectionFactory::class];
-
- yield ['amqps+ext:', AmqpExtConnectionFactory::class];
-
- yield ['amqp+lib:', AmqpLibConnectionFactory::class];
-
- yield ['amqps+lib:', AmqpLibConnectionFactory::class];
-
- yield ['amqp+bunny:', AmqpBunnyConnectionFactory::class];
-
- yield ['amqp://user:pass@foo/vhost', AmqpExtConnectionFactory::class];
-
- yield ['file:', FsConnectionFactory::class];
-
- yield ['file:///foo/bar/baz', FsConnectionFactory::class];
-
- yield ['null:', NullConnectionFactory::class];
-
- yield ['mysql:', DbalConnectionFactory::class];
-
- yield ['pgsql:', DbalConnectionFactory::class];
-
- yield ['beanstalk:', PheanstalkConnectionFactory::class];
-
-// yield ['gearman:', GearmanConnectionFactory::class];
-
- yield ['kafka:', RdKafkaConnectionFactory::class];
-
- yield ['redis:', RedisConnectionFactory::class];
-
- yield ['stomp:', StompConnectionFactory::class];
-
- yield ['sqs:', SqsConnectionFactory::class];
-
- yield ['gps:', GpsConnectionFactory::class];
-
- yield ['mongodb:', MongodbConnectionFactory::class];
- }
-}
diff --git a/pkg/enqueue/Tests/Functions/DsnToContextFunctionTest.php b/pkg/enqueue/Tests/Functions/DsnToContextFunctionTest.php
deleted file mode 100644
index 2a8bc83bc..000000000
--- a/pkg/enqueue/Tests/Functions/DsnToContextFunctionTest.php
+++ /dev/null
@@ -1,73 +0,0 @@
-expectException(\LogicException::class);
- $this->expectExceptionMessage('The scheme could not be parsed from DSN ""');
-
- \Enqueue\dsn_to_context('');
- }
-
- public function testThrowIfDsnMissingScheme()
- {
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('The scheme could not be parsed from DSN "dsnMissingScheme"');
-
- \Enqueue\dsn_to_context('dsnMissingScheme');
- }
-
- public function testThrowIfDsnNotSupported()
- {
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('The scheme "http" is not supported. Supported "file", "amqp+ext"');
-
- \Enqueue\dsn_to_context('http://schemenotsupported/');
- }
-
- /**
- * @dataProvider provideDSNs
- *
- * @param mixed $dsn
- * @param mixed $expectedFactoryClass
- */
- public function testReturnsExpectedFactoryInstance($dsn, $expectedFactoryClass)
- {
- $factory = \Enqueue\dsn_to_context($dsn);
-
- $this->assertInstanceOf($expectedFactoryClass, $factory);
- }
-
- public static function provideDSNs()
- {
- yield ['amqp:', AmqpContext::class];
-
- yield ['amqp://user:pass@foo/vhost', AmqpContext::class];
-
- yield ['file:', FsContext::class];
-
- yield ['file://'.sys_get_temp_dir(), FsContext::class];
-
- yield ['null:', NullContext::class];
-
- yield ['redis:', RedisContext::class];
-
- yield ['stomp:', StompContext::class];
-
- yield ['sqs:', SqsContext::class];
-
- yield ['gps:', GpsContext::class];
- }
-}
diff --git a/pkg/enqueue/Tests/Mocks/CustomPrepareBodyClientExtension.php b/pkg/enqueue/Tests/Mocks/CustomPrepareBodyClientExtension.php
new file mode 100644
index 000000000..dd0e1a69e
--- /dev/null
+++ b/pkg/enqueue/Tests/Mocks/CustomPrepareBodyClientExtension.php
@@ -0,0 +1,20 @@
+getMessage()->setBody('theCommandBodySerializedByCustomExtension');
+ }
+
+ public function onPreSendEvent(PreSend $context): void
+ {
+ $context->getMessage()->setBody('theEventBodySerializedByCustomExtension');
+ }
+}
diff --git a/pkg/enqueue/Tests/Mocks/JsonSerializableObject.php b/pkg/enqueue/Tests/Mocks/JsonSerializableObject.php
new file mode 100644
index 000000000..84885c316
--- /dev/null
+++ b/pkg/enqueue/Tests/Mocks/JsonSerializableObject.php
@@ -0,0 +1,12 @@
+ 'fooVal'];
+ }
+}
diff --git a/pkg/enqueue/Tests/ResourcesTest.php b/pkg/enqueue/Tests/ResourcesTest.php
new file mode 100644
index 000000000..ec713fd03
--- /dev/null
+++ b/pkg/enqueue/Tests/ResourcesTest.php
@@ -0,0 +1,149 @@
+assertTrue($rc->isFinal());
+ }
+
+ public function testShouldConstructorBePrivate()
+ {
+ $rc = new \ReflectionClass(Resources::class);
+
+ $this->assertTrue($rc->getConstructor()->isPrivate());
+ }
+
+ public function testShouldGetAvailableConnectionsInExpectedFormat()
+ {
+ $availableConnections = Resources::getAvailableConnections();
+
+ self::assertIsArray($availableConnections);
+ $this->assertArrayHasKey(RedisConnectionFactory::class, $availableConnections);
+
+ $connectionInfo = $availableConnections[RedisConnectionFactory::class];
+ $this->assertArrayHasKey('schemes', $connectionInfo);
+ $this->assertSame(['redis', 'rediss'], $connectionInfo['schemes']);
+
+ $this->assertArrayHasKey('supportedSchemeExtensions', $connectionInfo);
+ $this->assertSame(['predis', 'phpredis'], $connectionInfo['supportedSchemeExtensions']);
+
+ $this->assertArrayHasKey('package', $connectionInfo);
+ $this->assertSame('enqueue/redis', $connectionInfo['package']);
+ }
+
+ public function testShouldGetKnownConnectionsInExpectedFormat()
+ {
+ $availableConnections = Resources::getKnownConnections();
+
+ self::assertIsArray($availableConnections);
+ $this->assertArrayHasKey(RedisConnectionFactory::class, $availableConnections);
+
+ $connectionInfo = $availableConnections[RedisConnectionFactory::class];
+ $this->assertArrayHasKey('schemes', $connectionInfo);
+ $this->assertSame(['redis', 'rediss'], $connectionInfo['schemes']);
+
+ $this->assertArrayHasKey('supportedSchemeExtensions', $connectionInfo);
+ $this->assertSame(['predis', 'phpredis'], $connectionInfo['supportedSchemeExtensions']);
+
+ $this->assertArrayHasKey('package', $connectionInfo);
+ $this->assertSame('enqueue/redis', $connectionInfo['package']);
+ }
+
+ public function testThrowsIfConnectionClassNotImplementConnectionFactoryInterfaceOnAddConnection()
+ {
+ $this->expectException(\InvalidArgumentException::class);
+ $this->expectExceptionMessage('The connection factory class "stdClass" must implement "Interop\Queue\ConnectionFactory" interface.');
+
+ Resources::addConnection(\stdClass::class, [], [], 'foo');
+ }
+
+ public function testThrowsIfNoSchemesProvidedOnAddConnection()
+ {
+ $connectionClass = $this->getMockClass(ConnectionFactory::class);
+
+ $this->expectException(\InvalidArgumentException::class);
+ $this->expectExceptionMessage('Schemes could not be empty.');
+
+ Resources::addConnection($connectionClass, [], [], 'foo');
+ }
+
+ public function testThrowsIfNoPackageProvidedOnAddConnection()
+ {
+ $connectionClass = $this->getMockClass(ConnectionFactory::class);
+
+ $this->expectException(\InvalidArgumentException::class);
+ $this->expectExceptionMessage('Package name could not be empty.');
+
+ Resources::addConnection($connectionClass, ['foo'], [], '');
+ }
+
+ public function testShouldAllowRegisterConnectionThatIsNotInstalled()
+ {
+ Resources::addConnection('theConnectionClass', ['foo'], [], 'foo');
+
+ $knownConnections = Resources::getKnownConnections();
+ self::assertIsArray($knownConnections);
+ $this->assertArrayHasKey('theConnectionClass', $knownConnections);
+
+ $availableConnections = Resources::getAvailableConnections();
+
+ self::assertIsArray($availableConnections);
+ $this->assertArrayNotHasKey('theConnectionClass', $availableConnections);
+ }
+
+ public function testShouldAllowGetPreviouslyRegisteredConnection()
+ {
+ $connectionClass = $this->getMockClass(ConnectionFactory::class);
+
+ Resources::addConnection(
+ $connectionClass,
+ ['fooscheme', 'barscheme'],
+ ['fooextension', 'barextension'],
+ 'foo/bar'
+ );
+
+ $availableConnections = Resources::getAvailableConnections();
+
+ self::assertIsArray($availableConnections);
+ $this->assertArrayHasKey($connectionClass, $availableConnections);
+
+ $connectionInfo = $availableConnections[$connectionClass];
+ $this->assertArrayHasKey('schemes', $connectionInfo);
+ $this->assertSame(['fooscheme', 'barscheme'], $connectionInfo['schemes']);
+
+ $this->assertArrayHasKey('supportedSchemeExtensions', $connectionInfo);
+ $this->assertSame(['fooextension', 'barextension'], $connectionInfo['supportedSchemeExtensions']);
+
+ $this->assertArrayHasKey('package', $connectionInfo);
+ $this->assertSame('foo/bar', $connectionInfo['package']);
+ }
+
+ public function testShouldHaveRegisteredWampConfiguration()
+ {
+ $availableConnections = Resources::getKnownConnections();
+
+ self::assertIsArray($availableConnections);
+ $this->assertArrayHasKey(WampConnectionFactory::class, $availableConnections);
+
+ $connectionInfo = $availableConnections[WampConnectionFactory::class];
+ $this->assertArrayHasKey('schemes', $connectionInfo);
+ $this->assertSame(['wamp', 'ws'], $connectionInfo['schemes']);
+
+ $this->assertArrayHasKey('supportedSchemeExtensions', $connectionInfo);
+ $this->assertSame([], $connectionInfo['supportedSchemeExtensions']);
+
+ $this->assertArrayHasKey('package', $connectionInfo);
+ $this->assertSame('enqueue/wamp', $connectionInfo['package']);
+ }
+}
diff --git a/pkg/enqueue/Tests/Router/RecipientTest.php b/pkg/enqueue/Tests/Router/RecipientTest.php
index 3f3737234..57cc83eed 100644
--- a/pkg/enqueue/Tests/Router/RecipientTest.php
+++ b/pkg/enqueue/Tests/Router/RecipientTest.php
@@ -3,26 +3,26 @@
namespace Enqueue\Tests\Router;
use Enqueue\Router\Recipient;
-use Interop\Queue\PsrDestination;
-use Interop\Queue\PsrMessage;
+use Interop\Queue\Destination;
+use Interop\Queue\Message as InteropMessage;
use PHPUnit\Framework\TestCase;
class RecipientTest extends TestCase
{
public function testShouldAllowGetMessageSetInConstructor()
{
- $message = $this->createMock(PsrMessage::class);
+ $message = $this->createMock(InteropMessage::class);
- $recipient = new Recipient($this->createMock(PsrDestination::class), $message);
+ $recipient = new Recipient($this->createMock(Destination::class), $message);
$this->assertSame($message, $recipient->getMessage());
}
public function testShouldAllowGetDestinationSetInConstructor()
{
- $destination = $this->createMock(PsrDestination::class);
+ $destination = $this->createMock(Destination::class);
- $recipient = new Recipient($destination, $this->createMock(PsrMessage::class));
+ $recipient = new Recipient($destination, $this->createMock(InteropMessage::class));
$this->assertSame($destination, $recipient->getDestination());
}
diff --git a/pkg/enqueue/Tests/Router/RouteRecipientListProcessorTest.php b/pkg/enqueue/Tests/Router/RouteRecipientListProcessorTest.php
index b7980430f..ae878fc53 100644
--- a/pkg/enqueue/Tests/Router/RouteRecipientListProcessorTest.php
+++ b/pkg/enqueue/Tests/Router/RouteRecipientListProcessorTest.php
@@ -9,9 +9,9 @@
use Enqueue\Router\RecipientListRouterInterface;
use Enqueue\Router\RouteRecipientListProcessor;
use Enqueue\Test\ClassExtensionTrait;
-use Interop\Queue\PsrContext;
-use Interop\Queue\PsrProcessor;
-use Interop\Queue\PsrProducer;
+use Interop\Queue\Context;
+use Interop\Queue\Processor;
+use Interop\Queue\Producer as InteropProducer;
use PHPUnit\Framework\TestCase;
class RouteRecipientListProcessorTest extends TestCase
@@ -20,12 +20,7 @@ class RouteRecipientListProcessorTest extends TestCase
public function testShouldImplementProcessorInterface()
{
- $this->assertClassImplements(PsrProcessor::class, RouteRecipientListProcessor::class);
- }
-
- public function testCouldBeConstructedWithRouterAsFirstArgument()
- {
- new RouteRecipientListProcessor($this->createRecipientListRouterMock());
+ $this->assertClassImplements(Processor::class, RouteRecipientListProcessor::class);
}
public function testShouldProduceRecipientsMessagesAndAckOriginalMessage()
@@ -55,7 +50,7 @@ public function testShouldProduceRecipientsMessagesAndAckOriginalMessage()
->with($this->identicalTo($barRecipient->getDestination()), $this->identicalTo($barRecipient->getMessage()))
;
- $sessionMock = $this->createPsrContextMock();
+ $sessionMock = $this->createContextMock();
$sessionMock
->expects($this->once())
->method('createProducer')
@@ -70,23 +65,23 @@ public function testShouldProduceRecipientsMessagesAndAckOriginalMessage()
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|PsrProducer
+ * @return \PHPUnit\Framework\MockObject\MockObject|InteropProducer
*/
protected function createProducerMock()
{
- return $this->createMock(PsrProducer::class);
+ return $this->createMock(InteropProducer::class);
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|PsrContext
+ * @return \PHPUnit\Framework\MockObject\MockObject|Context
*/
- protected function createPsrContextMock()
+ protected function createContextMock()
{
- return $this->createMock(PsrContext::class);
+ return $this->createMock(Context::class);
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|RecipientListRouterInterface
+ * @return \PHPUnit\Framework\MockObject\MockObject|RecipientListRouterInterface
*/
protected function createRecipientListRouterMock()
{
diff --git a/pkg/enqueue/Tests/Rpc/PromiseTest.php b/pkg/enqueue/Tests/Rpc/PromiseTest.php
index 7202e67fc..6762149ef 100644
--- a/pkg/enqueue/Tests/Rpc/PromiseTest.php
+++ b/pkg/enqueue/Tests/Rpc/PromiseTest.php
@@ -50,10 +50,10 @@ public function testOnReceiveShouldCallReceiveCallBackWithTimeout()
$receiveInvoked = false;
$receivePromise = null;
$receiveTimeout = null;
- $receivecb = function ($promise, $timout) use (&$receiveInvoked, &$receivePromise, &$receiveTimeout) {
+ $receivecb = function ($promise, $timeout) use (&$receiveInvoked, &$receivePromise, &$receiveTimeout) {
$receiveInvoked = true;
$receivePromise = $promise;
- $receiveTimeout = $timout;
+ $receiveTimeout = $timeout;
};
$promise = new Promise($receivecb, function () {}, function () {});
@@ -122,7 +122,7 @@ public function testOnReceiveShouldThrowExceptionIfCallbackReturnNotMessageInsta
$promise = new Promise($receivecb, function () {}, function () {});
$this->expectException(\RuntimeException::class);
- $this->expectExceptionMessage('Expected "Interop\Queue\PsrMessage" but got: "stdClass"');
+ $this->expectExceptionMessage('Expected "Interop\Queue\Message" but got: "stdClass"');
$promise->receive();
}
@@ -136,7 +136,7 @@ public function testOnReceiveNoWaitShouldThrowExceptionIfCallbackReturnNotMessag
$promise = new Promise(function () {}, $receivecb, function () {});
$this->expectException(\RuntimeException::class);
- $this->expectExceptionMessage('Expected "Interop\Queue\PsrMessage" but got: "stdClass"');
+ $this->expectExceptionMessage('Expected "Interop\Queue\Message" but got: "stdClass"');
$promise->receiveNoWait();
}
diff --git a/pkg/enqueue/Tests/Rpc/RpcClientTest.php b/pkg/enqueue/Tests/Rpc/RpcClientTest.php
index ce7aa2785..db4813c88 100644
--- a/pkg/enqueue/Tests/Rpc/RpcClientTest.php
+++ b/pkg/enqueue/Tests/Rpc/RpcClientTest.php
@@ -7,18 +7,14 @@
use Enqueue\Null\NullQueue;
use Enqueue\Rpc\Promise;
use Enqueue\Rpc\RpcClient;
-use Interop\Queue\PsrConsumer;
-use Interop\Queue\PsrContext;
-use Interop\Queue\PsrProducer;
+use Interop\Queue\Consumer;
+use Interop\Queue\Context;
+use Interop\Queue\Producer as InteropProducer;
+use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
class RpcClientTest extends TestCase
{
- public function testCouldBeConstructedWithPsrContextAsFirstArgument()
- {
- new RpcClient($this->createPsrContextMock());
- }
-
public function testShouldSetReplyToIfNotSet()
{
$context = new NullContext();
@@ -80,14 +76,14 @@ public function testShouldProduceMessageToQueue()
$message->setCorrelationId('theCorrelationId');
$message->setReplyTo('theReplyTo');
- $producer = $this->createPsrProducerMock();
+ $producer = $this->createInteropProducerMock();
$producer
->expects($this->once())
->method('send')
->with($this->identicalTo($queue), $this->identicalTo($message))
;
- $context = $this->createPsrContextMock();
+ $context = $this->createContextMock();
$context
->expects($this->once())
->method('createProducer')
@@ -110,7 +106,7 @@ public function testShouldReceiveMessageAndAckMessageIfCorrelationEquals()
$receivedMessage = new NullMessage();
$receivedMessage->setCorrelationId('theCorrelationId');
- $consumer = $this->createPsrConsumerMock();
+ $consumer = $this->createConsumerMock();
$consumer
->expects($this->once())
->method('receive')
@@ -127,11 +123,11 @@ public function testShouldReceiveMessageAndAckMessageIfCorrelationEquals()
->method('reject')
;
- $context = $this->createPsrContextMock();
+ $context = $this->createContextMock();
$context
->expects($this->once())
->method('createProducer')
- ->willReturn($this->createPsrProducerMock())
+ ->willReturn($this->createInteropProducerMock())
;
$context
->expects($this->atLeastOnce())
@@ -162,7 +158,7 @@ public function testShouldReceiveNoWaitMessageAndAckMessageIfCorrelationEquals()
$receivedMessage = new NullMessage();
$receivedMessage->setCorrelationId('theCorrelationId');
- $consumer = $this->createPsrConsumerMock();
+ $consumer = $this->createConsumerMock();
$consumer
->expects($this->once())
->method('receiveNoWait')
@@ -178,11 +174,11 @@ public function testShouldReceiveNoWaitMessageAndAckMessageIfCorrelationEquals()
->method('reject')
;
- $context = $this->createPsrContextMock();
+ $context = $this->createContextMock();
$context
->expects($this->once())
->method('createProducer')
- ->willReturn($this->createPsrProducerMock())
+ ->willReturn($this->createInteropProducerMock())
;
$context
->expects($this->atLeastOnce())
@@ -213,14 +209,14 @@ public function testShouldDeleteQueueAfterReceiveIfDeleteReplyQueueIsTrue()
$receivedMessage = new NullMessage();
$receivedMessage->setCorrelationId('theCorrelationId');
- $consumer = $this->createPsrConsumerMock();
+ $consumer = $this->createConsumerMock();
$consumer
->expects($this->once())
->method('receive')
->willReturn($receivedMessage)
;
- $context = $this->getMockBuilder(PsrContext::class)
+ $context = $this->getMockBuilder(Context::class)
->disableOriginalConstructor()
->setMethods(['deleteQueue'])
->getMockForAbstractClass()
@@ -229,7 +225,7 @@ public function testShouldDeleteQueueAfterReceiveIfDeleteReplyQueueIsTrue()
$context
->expects($this->once())
->method('createProducer')
- ->willReturn($this->createPsrProducerMock())
+ ->willReturn($this->createInteropProducerMock())
;
$context
->expects($this->atLeastOnce())
@@ -267,18 +263,18 @@ public function testShouldNotCallDeleteQueueIfDeleteReplyQueueIsTrueButContextHa
$receivedMessage = new NullMessage();
$receivedMessage->setCorrelationId('theCorrelationId');
- $consumer = $this->createPsrConsumerMock();
+ $consumer = $this->createConsumerMock();
$consumer
->expects($this->once())
->method('receive')
->willReturn($receivedMessage)
;
- $context = $this->createPsrContextMock();
+ $context = $this->createContextMock();
$context
->expects($this->once())
->method('createProducer')
- ->willReturn($this->createPsrProducerMock())
+ ->willReturn($this->createInteropProducerMock())
;
$context
->expects($this->once())
@@ -329,26 +325,26 @@ public function testShouldDoSyncCall()
}
/**
- * @return PsrContext|\PHPUnit_Framework_MockObject_MockObject|PsrProducer
+ * @return Context|MockObject|InteropProducer
*/
- private function createPsrProducerMock()
+ private function createInteropProducerMock()
{
- return $this->createMock(PsrProducer::class);
+ return $this->createMock(InteropProducer::class);
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|PsrConsumer
+ * @return MockObject|Consumer
*/
- private function createPsrConsumerMock()
+ private function createConsumerMock()
{
- return $this->createMock(PsrConsumer::class);
+ return $this->createMock(Consumer::class);
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|PsrContext
+ * @return MockObject|Context
*/
- private function createPsrContextMock()
+ private function createContextMock()
{
- return $this->createMock(PsrContext::class);
+ return $this->createMock(Context::class);
}
}
diff --git a/pkg/enqueue/Tests/Symfony/AmqpTransportFactoryTest.php b/pkg/enqueue/Tests/Symfony/AmqpTransportFactoryTest.php
deleted file mode 100644
index b27f5b5ca..000000000
--- a/pkg/enqueue/Tests/Symfony/AmqpTransportFactoryTest.php
+++ /dev/null
@@ -1,404 +0,0 @@
-assertClassImplements(TransportFactoryInterface::class, AmqpTransportFactory::class);
- }
-
- public function testCouldBeConstructedWithDefaultName()
- {
- $transport = new AmqpTransportFactory();
-
- $this->assertEquals('amqp', $transport->getName());
- }
-
- public function testCouldBeConstructedWithCustomName()
- {
- $transport = new AmqpTransportFactory('theCustomName');
-
- $this->assertEquals('theCustomName', $transport->getName());
- }
-
- public function testThrowIfCouldBeConstructedWithCustomName()
- {
- $transport = new AmqpTransportFactory('theCustomName');
-
- $this->assertEquals('theCustomName', $transport->getName());
- }
-
- public function testShouldAllowAddConfiguration()
- {
- $transport = new AmqpTransportFactory();
- $tb = new TreeBuilder();
- $rootNode = $tb->root('foo');
-
- $transport->addConfiguration($rootNode);
- $processor = new Processor();
- $config = $processor->process($tb->buildTree(), [[
- 'host' => 'localhost',
- 'port' => 5672,
- 'user' => 'guest',
- 'pass' => 'guest',
- 'vhost' => '/',
- 'read_timeout' => 3.,
- 'write_timeout' => 3.,
- 'connection_timeout' => 3.,
- 'heartbeat' => 0,
- 'persisted' => false,
- 'lazy' => true,
- 'qos_global' => false,
- 'qos_prefetch_size' => 0,
- 'qos_prefetch_count' => 1,
- 'receive_method' => 'basic_get',
- ]]);
-
- $this->assertEquals([
- 'host' => 'localhost',
- 'port' => 5672,
- 'user' => 'guest',
- 'pass' => 'guest',
- 'vhost' => '/',
- 'read_timeout' => 3.,
- 'write_timeout' => 3.,
- 'connection_timeout' => 3.,
- 'heartbeat' => 0,
- 'persisted' => false,
- 'lazy' => true,
- 'qos_global' => false,
- 'qos_prefetch_size' => 0,
- 'qos_prefetch_count' => 1,
- 'receive_method' => 'basic_get',
- ], $config);
- }
-
- public function testShouldAllowAddConfigurationWithDriverOptions()
- {
- $transport = new AmqpTransportFactory();
- $tb = new TreeBuilder();
- $rootNode = $tb->root('foo');
-
- $transport->addConfiguration($rootNode);
- $processor = new Processor();
- $config = $processor->process($tb->buildTree(), [[
- 'host' => 'localhost',
- 'driver_options' => [
- 'foo' => 'fooVal',
- ],
- ]]);
-
- $this->assertEquals([
- 'host' => 'localhost',
- 'driver_options' => [
- 'foo' => 'fooVal',
- ],
- ], $config);
- }
-
- public function testShouldAllowAddSslOptions()
- {
- $transport = new AmqpTransportFactory();
- $tb = new TreeBuilder();
- $rootNode = $tb->root('foo');
-
- $transport->addConfiguration($rootNode);
- $processor = new Processor();
- $config = $processor->process($tb->buildTree(), [[
- 'ssl_on' => true,
- 'ssl_verify' => false,
- 'ssl_cacert' => '/path/to/cacert.pem',
- 'ssl_cert' => '/path/to/cert.pem',
- 'ssl_key' => '/path/to/key.pem',
- ]]);
-
- $this->assertEquals([
- 'ssl_on' => true,
- 'ssl_verify' => false,
- 'ssl_cacert' => '/path/to/cacert.pem',
- 'ssl_cert' => '/path/to/cert.pem',
- 'ssl_key' => '/path/to/key.pem',
- ], $config);
- }
-
- public function testThrowIfNotSupportedDriverSet()
- {
- $transport = new AmqpTransportFactory();
- $tb = new TreeBuilder();
- $rootNode = $tb->root('foo');
-
- $transport->addConfiguration($rootNode);
- $processor = new Processor();
-
- $this->expectException(InvalidConfigurationException::class);
- $this->expectExceptionMessage('Invalid configuration for path "foo.driver": Unexpected driver given "invalidDriver"');
- $processor->process($tb->buildTree(), [[
- 'driver' => 'invalidDriver',
- ]]);
- }
-
- public function testShouldAllowSetDriver()
- {
- $transport = new AmqpTransportFactory();
- $tb = new TreeBuilder();
- $rootNode = $tb->root('foo');
-
- $transport->addConfiguration($rootNode);
- $processor = new Processor();
- $config = $processor->process($tb->buildTree(), [[
- 'driver' => 'ext',
- ]]);
-
- $this->assertEquals([
- 'driver' => 'ext',
- ], $config);
- }
-
- public function testShouldAllowAddConfigurationAsString()
- {
- $transport = new AmqpTransportFactory();
- $tb = new TreeBuilder();
- $rootNode = $tb->root('foo');
-
- $transport->addConfiguration($rootNode);
- $processor = new Processor();
- $config = $processor->process($tb->buildTree(), ['amqpDSN']);
-
- $this->assertEquals([
- 'dsn' => 'amqpDSN',
- ], $config);
- }
-
- public function testThrowIfInvalidReceiveMethodIsSet()
- {
- $transport = new AmqpTransportFactory();
- $tb = new TreeBuilder();
- $rootNode = $tb->root('foo');
-
- $transport->addConfiguration($rootNode);
- $processor = new Processor();
-
- $this->expectException(InvalidConfigurationException::class);
- $this->expectExceptionMessage('The value "anInvalidMethod" is not allowed for path "foo.receive_method". Permissible values: "basic_get", "basic_consume"');
- $processor->process($tb->buildTree(), [[
- 'receive_method' => 'anInvalidMethod',
- ]]);
- }
-
- public function testShouldAllowChangeReceiveMethod()
- {
- $transport = new AmqpTransportFactory();
- $tb = new TreeBuilder();
- $rootNode = $tb->root('foo');
-
- $transport->addConfiguration($rootNode);
- $processor = new Processor();
- $config = $processor->process($tb->buildTree(), [[
- 'receive_method' => 'basic_consume',
- ]]);
-
- $this->assertEquals([
- 'receive_method' => 'basic_consume',
- ], $config);
- }
-
- public function testShouldCreateConnectionFactoryForEmptyConfig()
- {
- $container = new ContainerBuilder();
-
- $transport = new AmqpTransportFactory();
-
- $serviceId = $transport->createConnectionFactory($container, []);
-
- $this->assertTrue($container->hasDefinition($serviceId));
- $factory = $container->getDefinition($serviceId);
- $this->assertEquals(AmqpConnectionFactory::class, $factory->getClass());
-
- $this->assertSame([[]], $factory->getArguments());
- }
-
- public function testShouldCreateConnectionFactoryFromDsnString()
- {
- $container = new ContainerBuilder();
-
- $transport = new AmqpTransportFactory();
-
- $serviceId = $transport->createConnectionFactory($container, [
- 'dsn' => 'theConnectionDSN:',
- ]);
-
- $this->assertTrue($container->hasDefinition($serviceId));
- $factory = $container->getDefinition($serviceId);
- $this->assertEquals(AmqpConnectionFactory::class, $factory->getClass());
- $this->assertSame([['dsn' => 'theConnectionDSN:']], $factory->getArguments());
- }
-
- public function testShouldCreateConnectionFactoryAndMergeDriverOptionsIfSet()
- {
- $container = new ContainerBuilder();
-
- $transport = new AmqpTransportFactory();
-
- $serviceId = $transport->createConnectionFactory($container, [
- 'host' => 'aHost',
- 'driver_options' => [
- 'foo' => 'fooVal',
- ],
- ]);
-
- $this->assertTrue($container->hasDefinition($serviceId));
- $factory = $container->getDefinition($serviceId);
- $this->assertEquals(AmqpConnectionFactory::class, $factory->getClass());
- $this->assertSame([['foo' => 'fooVal', 'host' => 'aHost']], $factory->getArguments());
- }
-
- public function testShouldCreateConnectionFactoryFromDsnStringPlushArrayOptions()
- {
- $container = new ContainerBuilder();
-
- $transport = new AmqpTransportFactory();
-
- $serviceId = $transport->createConnectionFactory($container, [
- 'host' => 'localhost',
- 'port' => 5672,
- 'user' => 'guest',
- 'pass' => 'guest',
- 'vhost' => '/',
- 'persisted' => false,
- ]);
-
- $this->assertTrue($container->hasDefinition($serviceId));
- $factory = $container->getDefinition($serviceId);
- $this->assertEquals(AmqpConnectionFactory::class, $factory->getClass());
- $this->assertSame([[
- 'host' => 'localhost',
- 'port' => 5672,
- 'user' => 'guest',
- 'pass' => 'guest',
- 'vhost' => '/',
- 'persisted' => false,
- ]], $factory->getArguments());
- }
-
- public function testShouldCreateContext()
- {
- $container = new ContainerBuilder();
-
- $transport = new AmqpTransportFactory();
-
- $serviceId = $transport->createContext($container, [
- 'host' => 'localhost',
- 'port' => 5672,
- 'user' => 'guest',
- 'pass' => 'guest',
- 'vhost' => '/',
- 'persisted' => false,
- ]);
-
- $this->assertEquals('enqueue.transport.amqp.context', $serviceId);
- $this->assertTrue($container->hasDefinition($serviceId));
-
- $context = $container->getDefinition('enqueue.transport.amqp.context');
- $this->assertInstanceOf(Reference::class, $context->getFactory()[0]);
- $this->assertEquals('enqueue.transport.amqp.connection_factory', (string) $context->getFactory()[0]);
- $this->assertEquals('createContext', $context->getFactory()[1]);
- }
-
- public function testShouldCreateDriver()
- {
- $container = new ContainerBuilder();
-
- $transport = new AmqpTransportFactory();
-
- $serviceId = $transport->createDriver($container, []);
-
- $this->assertEquals('enqueue.client.amqp.driver', $serviceId);
- $this->assertTrue($container->hasDefinition($serviceId));
-
- $driver = $container->getDefinition($serviceId);
- $this->assertSame(AmqpDriver::class, $driver->getClass());
-
- $this->assertInstanceOf(Reference::class, $driver->getArgument(0));
- $this->assertEquals('enqueue.transport.amqp.context', (string) $driver->getArgument(0));
-
- $this->assertInstanceOf(Reference::class, $driver->getArgument(1));
- $this->assertEquals('enqueue.client.config', (string) $driver->getArgument(1));
-
- $this->assertInstanceOf(Reference::class, $driver->getArgument(2));
- $this->assertEquals('enqueue.client.meta.queue_meta_registry', (string) $driver->getArgument(2));
- }
-
- public function testShouldCreateAmqpExtConnectionFactoryBySetDriver()
- {
- $factory = AmqpTransportFactory::createConnectionFactoryFactory(['driver' => 'ext']);
-
- $this->assertInstanceOf(\Enqueue\AmqpExt\AmqpConnectionFactory::class, $factory);
- }
-
- public function testShouldCreateAmqpLibConnectionFactoryBySetDriver()
- {
- $factory = AmqpTransportFactory::createConnectionFactoryFactory(['driver' => 'lib']);
-
- $this->assertInstanceOf(\Enqueue\AmqpLib\AmqpConnectionFactory::class, $factory);
- }
-
- public function testShouldCreateAmqpBunnyConnectionFactoryBySetDriver()
- {
- $factory = AmqpTransportFactory::createConnectionFactoryFactory(['driver' => 'bunny']);
-
- $this->assertInstanceOf(\Enqueue\AmqpBunny\AmqpConnectionFactory::class, $factory);
- }
-
- public function testShouldCreateAmqpExtFromConfigWithoutDriverAndDsn()
- {
- $factory = AmqpTransportFactory::createConnectionFactoryFactory(['host' => 'aHost']);
-
- $this->assertInstanceOf(\Enqueue\AmqpExt\AmqpConnectionFactory::class, $factory);
- }
-
- public function testThrowIfInvalidDriverGiven()
- {
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('Unexpected driver given "invalidDriver"');
-
- AmqpTransportFactory::createConnectionFactoryFactory(['driver' => 'invalidDriver']);
- }
-
- public function testShouldCreateAmqpExtFromDsn()
- {
- $factory = AmqpTransportFactory::createConnectionFactoryFactory(['dsn' => 'amqp:']);
-
- $this->assertInstanceOf(\Enqueue\AmqpExt\AmqpConnectionFactory::class, $factory);
- }
-
- public function testShouldCreateAmqpBunnyFromDsnWithDriver()
- {
- $factory = AmqpTransportFactory::createConnectionFactoryFactory(['dsn' => 'amqp+bunny:']);
-
- $this->assertInstanceOf(\Enqueue\AmqpBunny\AmqpConnectionFactory::class, $factory);
- }
-
- public function testThrowIfNotAmqpDsnProvided()
- {
- $this->expectException(\LogicException::class);
- $this->expectExceptionMessage('Factory must be instance of "Interop\Amqp\AmqpConnectionFactory" but got "Enqueue\Sqs\SqsConnectionFactory"');
-
- AmqpTransportFactory::createConnectionFactoryFactory(['dsn' => 'sqs:']);
- }
-}
diff --git a/pkg/enqueue/Tests/Symfony/Client/ConsumeCommandTest.php b/pkg/enqueue/Tests/Symfony/Client/ConsumeCommandTest.php
new file mode 100644
index 000000000..3758ca96a
--- /dev/null
+++ b/pkg/enqueue/Tests/Symfony/Client/ConsumeCommandTest.php
@@ -0,0 +1,703 @@
+assertClassExtends(Command::class, ConsumeCommand::class);
+ }
+
+ public function testShouldNotBeFinal()
+ {
+ $this->assertClassNotFinal(ConsumeCommand::class);
+ }
+
+ public function testShouldHaveAsCommandAttributeWithCommandName()
+ {
+ $commandClass = ConsumeCommand::class;
+
+ $reflectionClass = new \ReflectionClass($commandClass);
+
+ $attributes = $reflectionClass->getAttributes(AsCommand::class);
+
+ $this->assertNotEmpty($attributes, 'The command does not have the AsCommand attribute.');
+
+ // Get the first attribute instance (assuming there is only one AsCommand attribute)
+ $asCommandAttribute = $attributes[0];
+
+ // Verify the 'name' parameter value
+ $attributeInstance = $asCommandAttribute->newInstance();
+ $this->assertEquals('enqueue:consume', $attributeInstance->name, 'The command name is not set correctly in the AsCommand attribute.');
+ }
+
+ public function testShouldHaveExpectedOptions()
+ {
+ $command = new ConsumeCommand($this->createMock(ContainerInterface::class), 'default');
+
+ $options = $command->getDefinition()->getOptions();
+
+ $this->assertCount(9, $options);
+ $this->assertArrayHasKey('memory-limit', $options);
+ $this->assertArrayHasKey('message-limit', $options);
+ $this->assertArrayHasKey('time-limit', $options);
+ $this->assertArrayHasKey('receive-timeout', $options);
+ $this->assertArrayHasKey('niceness', $options);
+ $this->assertArrayHasKey('client', $options);
+ $this->assertArrayHasKey('logger', $options);
+ $this->assertArrayHasKey('skip', $options);
+ $this->assertArrayHasKey('setup-broker', $options);
+ }
+
+ public function testShouldHaveExpectedAttributes()
+ {
+ $command = new ConsumeCommand($this->createMock(ContainerInterface::class), 'default');
+
+ $arguments = $command->getDefinition()->getArguments();
+
+ $this->assertCount(1, $arguments);
+ $this->assertArrayHasKey('client-queue-names', $arguments);
+ }
+
+ public function testShouldBindDefaultQueueOnly()
+ {
+ $queue = new NullQueue('');
+
+ $routeCollection = new RouteCollection([]);
+
+ $processor = $this->createDelegateProcessorMock();
+
+ $consumer = $this->createQueueConsumerMock();
+ $consumer
+ ->expects($this->once())
+ ->method('bind')
+ ->with($this->identicalTo($queue), $this->identicalTo($processor))
+ ;
+ $consumer
+ ->expects($this->once())
+ ->method('consume')
+ ->with($this->isInstanceOf(ChainExtension::class))
+ ;
+
+ $driver = $this->createDriverStub($routeCollection);
+ $driver
+ ->expects($this->once())
+ ->method('createQueue')
+ ->with('default', true)
+ ->willReturn($queue)
+ ;
+
+ $command = new ConsumeCommand(new Container([
+ 'enqueue.client.default.queue_consumer' => $consumer,
+ 'enqueue.client.default.driver' => $driver,
+ 'enqueue.client.default.delegate_processor' => $processor,
+ ]), 'default');
+
+ $tester = new CommandTester($command);
+ $tester->execute([]);
+ }
+
+ public function testShouldUseRequestedClient()
+ {
+ $defaultProcessor = $this->createDelegateProcessorMock();
+
+ $defaultConsumer = $this->createQueueConsumerMock();
+ $defaultConsumer
+ ->expects($this->never())
+ ->method('bind')
+ ;
+ $defaultConsumer
+ ->expects($this->never())
+ ->method('consume')
+ ->with($this->isInstanceOf(ChainExtension::class))
+ ;
+
+ $defaultDriver = $this->createDriverStub(new RouteCollection([]));
+ $defaultDriver
+ ->expects($this->never())
+ ->method('createQueue')
+ ;
+
+ $queue = new NullQueue('');
+
+ $routeCollection = new RouteCollection([]);
+
+ $fooProcessor = $this->createDelegateProcessorMock();
+
+ $fooConsumer = $this->createQueueConsumerMock();
+ $fooConsumer
+ ->expects($this->once())
+ ->method('bind')
+ ->with($this->identicalTo($queue), $this->identicalTo($fooProcessor))
+ ;
+ $fooConsumer
+ ->expects($this->once())
+ ->method('consume')
+ ->with($this->isInstanceOf(ChainExtension::class))
+ ;
+
+ $fooDriver = $this->createDriverStub($routeCollection);
+ $fooDriver
+ ->expects($this->once())
+ ->method('createQueue')
+ ->with('default', true)
+ ->willReturn($queue)
+ ;
+
+ $command = new ConsumeCommand(new Container([
+ 'enqueue.client.default.queue_consumer' => $defaultConsumer,
+ 'enqueue.client.default.driver' => $defaultDriver,
+ 'enqueue.client.default.delegate_processor' => $defaultProcessor,
+ 'enqueue.client.foo.queue_consumer' => $fooConsumer,
+ 'enqueue.client.foo.driver' => $fooDriver,
+ 'enqueue.client.foo.delegate_processor' => $fooProcessor,
+ ]), 'default');
+
+ $tester = new CommandTester($command);
+ $tester->execute([
+ '--client' => 'foo',
+ ]);
+ }
+
+ public function testThrowIfNotDefinedClientRequested()
+ {
+ $routeCollection = new RouteCollection([]);
+
+ $processor = $this->createDelegateProcessorMock();
+
+ $consumer = $this->createQueueConsumerMock();
+ $consumer
+ ->expects($this->never())
+ ->method('bind')
+ ;
+ $consumer
+ ->expects($this->never())
+ ->method('consume')
+ ;
+
+ $driver = $this->createDriverStub($routeCollection);
+ $driver
+ ->expects($this->never())
+ ->method('createQueue')
+ ;
+
+ $command = new ConsumeCommand(new Container([
+ 'enqueue.client.default.queue_consumer' => $consumer,
+ 'enqueue.client.default.driver' => $driver,
+ 'enqueue.client.default.delegate_processor' => $processor,
+ ]), 'default');
+
+ $tester = new CommandTester($command);
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Client "not-defined" is not supported.');
+ $tester->execute([
+ '--client' => 'not-defined',
+ ]);
+ }
+
+ public function testShouldBindDefaultQueueIfRouteUseDifferentQueue()
+ {
+ $queue = new NullQueue('');
+
+ $routeCollection = new RouteCollection([
+ new Route('topic', Route::TOPIC, 'processor'),
+ ]);
+
+ $processor = $this->createDelegateProcessorMock();
+
+ $consumer = $this->createQueueConsumerMock();
+ $consumer
+ ->expects($this->once())
+ ->method('bind')
+ ->with($this->identicalTo($queue), $this->identicalTo($processor))
+ ;
+ $consumer
+ ->expects($this->once())
+ ->method('consume')
+ ->with($this->isInstanceOf(ChainExtension::class))
+ ;
+
+ $driver = $this->createDriverStub($routeCollection);
+ $driver
+ ->expects($this->once())
+ ->method('createQueue')
+ ->with('default', true)
+ ->willReturn($queue)
+ ;
+
+ $command = new ConsumeCommand(new Container([
+ 'enqueue.client.default.queue_consumer' => $consumer,
+ 'enqueue.client.default.driver' => $driver,
+ 'enqueue.client.default.delegate_processor' => $processor,
+ ]), 'default');
+
+ $tester = new CommandTester($command);
+ $tester->execute([]);
+ }
+
+ public function testShouldBindCustomExecuteConsumptionAndUseCustomClientDestinationName()
+ {
+ $defaultQueue = new NullQueue('');
+ $customQueue = new NullQueue('');
+
+ $routeCollection = new RouteCollection([
+ new Route('topic', Route::TOPIC, 'processor', ['queue' => 'custom']),
+ ]);
+
+ $processor = $this->createDelegateProcessorMock();
+
+ $driver = $this->createDriverStub($routeCollection);
+ $driver
+ ->expects($this->at(3))
+ ->method('createQueue')
+ ->with('default', true)
+ ->willReturn($defaultQueue)
+ ;
+ $driver
+ ->expects($this->at(4))
+ ->method('createQueue')
+ ->with('custom', true)
+ ->willReturn($customQueue)
+ ;
+
+ $consumer = $this->createQueueConsumerMock();
+ $consumer
+ ->expects($this->at(0))
+ ->method('bind')
+ ->with($this->identicalTo($defaultQueue), $this->identicalTo($processor))
+ ;
+ $consumer
+ ->expects($this->at(1))
+ ->method('bind')
+ ->with($this->identicalTo($customQueue), $this->identicalTo($processor))
+ ;
+ $consumer
+ ->expects($this->at(2))
+ ->method('consume')
+ ->with($this->isInstanceOf(ChainExtension::class))
+ ;
+
+ $command = new ConsumeCommand(new Container([
+ 'enqueue.client.default.queue_consumer' => $consumer,
+ 'enqueue.client.default.driver' => $driver,
+ 'enqueue.client.default.delegate_processor' => $processor,
+ ]), 'default');
+
+ $tester = new CommandTester($command);
+ $tester->execute([]);
+ }
+
+ public function testShouldBindUserProvidedQueues()
+ {
+ $queue = new NullQueue('');
+
+ $routeCollection = new RouteCollection([
+ new Route('topic', Route::TOPIC, 'processor', ['queue' => 'custom']),
+ new Route('topic', Route::TOPIC, 'processor', ['queue' => 'non-default-queue']),
+ ]);
+
+ $processor = $this->createDelegateProcessorMock();
+
+ $driver = $this->createDriverStub($routeCollection);
+ $driver
+ ->expects($this->once())
+ ->method('createQueue')
+ ->with('non-default-queue', true)
+ ->willReturn($queue)
+ ;
+
+ $consumer = $this->createQueueConsumerMock();
+ $consumer
+ ->expects($this->once())
+ ->method('bind')
+ ->with($this->identicalTo($queue), $this->identicalTo($processor))
+ ;
+ $consumer
+ ->expects($this->once())
+ ->method('consume')
+ ->with($this->isInstanceOf(ChainExtension::class))
+ ;
+
+ $command = new ConsumeCommand(new Container([
+ 'enqueue.client.default.queue_consumer' => $consumer,
+ 'enqueue.client.default.driver' => $driver,
+ 'enqueue.client.default.delegate_processor' => $processor,
+ ]), 'default');
+
+ $tester = new CommandTester($command);
+ $tester->execute([
+ 'client-queue-names' => ['non-default-queue'],
+ ]);
+ }
+
+ public function testShouldBindNotPrefixedQueue()
+ {
+ $queue = new NullQueue('');
+
+ $routeCollection = new RouteCollection([
+ new Route('topic', Route::TOPIC, 'processor', ['queue' => 'non-prefixed-queue', 'prefix_queue' => false]),
+ ]);
+
+ $processor = $this->createDelegateProcessorMock();
+
+ $driver = $this->createDriverStub($routeCollection);
+ $driver
+ ->expects($this->once())
+ ->method('createQueue')
+ ->with('non-prefixed-queue', false)
+ ->willReturn($queue)
+ ;
+
+ $consumer = $this->createQueueConsumerMock();
+ $consumer
+ ->expects($this->once())
+ ->method('bind')
+ ->with($this->identicalTo($queue), $this->identicalTo($processor))
+ ;
+ $consumer
+ ->expects($this->once())
+ ->method('consume')
+ ->with($this->isInstanceOf(ChainExtension::class))
+ ;
+
+ $command = new ConsumeCommand(new Container([
+ 'enqueue.client.default.queue_consumer' => $consumer,
+ 'enqueue.client.default.driver' => $driver,
+ 'enqueue.client.default.delegate_processor' => $processor,
+ ]), 'default');
+
+ $tester = new CommandTester($command);
+ $tester->execute([
+ 'client-queue-names' => ['non-prefixed-queue'],
+ ]);
+ }
+
+ public function testShouldBindQueuesOnlyOnce()
+ {
+ $defaultQueue = new NullQueue('');
+ $customQueue = new NullQueue('');
+
+ $routeCollection = new RouteCollection([
+ new Route('fooTopic', Route::TOPIC, 'processor', ['queue' => 'custom']),
+ new Route('barTopic', Route::TOPIC, 'processor', ['queue' => 'custom']),
+ new Route('ololoTopic', Route::TOPIC, 'processor', []),
+ ]);
+
+ $processor = $this->createDelegateProcessorMock();
+
+ $driver = $this->createDriverStub($routeCollection);
+ $driver
+ ->expects($this->at(3))
+ ->method('createQueue')
+ ->with('default', true)
+ ->willReturn($defaultQueue)
+ ;
+ $driver
+ ->expects($this->at(4))
+ ->method('createQueue', true)
+ ->with('custom')
+ ->willReturn($customQueue)
+ ;
+
+ $consumer = $this->createQueueConsumerMock();
+ $consumer
+ ->expects($this->at(0))
+ ->method('bind')
+ ->with($this->identicalTo($defaultQueue), $this->identicalTo($processor))
+ ;
+ $consumer
+ ->expects($this->at(1))
+ ->method('bind')
+ ->with($this->identicalTo($customQueue), $this->identicalTo($processor))
+ ;
+ $consumer
+ ->expects($this->at(2))
+ ->method('consume')
+ ->with($this->isInstanceOf(ChainExtension::class))
+ ;
+
+ $command = new ConsumeCommand(new Container([
+ 'enqueue.client.default.queue_consumer' => $consumer,
+ 'enqueue.client.default.driver' => $driver,
+ 'enqueue.client.default.delegate_processor' => $processor,
+ ]), 'default');
+
+ $tester = new CommandTester($command);
+ $tester->execute([]);
+ }
+
+ public function testShouldNotBindExternalRoutes()
+ {
+ $defaultQueue = new NullQueue('');
+
+ $routeCollection = new RouteCollection([
+ new Route('barTopic', Route::TOPIC, 'processor', ['queue' => null]),
+ new Route('fooTopic', Route::TOPIC, 'processor', ['queue' => 'external_queue', 'external' => true]),
+ ]);
+
+ $processor = $this->createDelegateProcessorMock();
+
+ $driver = $this->createDriverStub($routeCollection);
+ $driver
+ ->expects($this->exactly(1))
+ ->method('createQueue')
+ ->with('default', true)
+ ->willReturn($defaultQueue)
+ ;
+
+ $consumer = $this->createQueueConsumerMock();
+ $consumer
+ ->expects($this->exactly(1))
+ ->method('bind')
+ ->with($this->identicalTo($defaultQueue), $this->identicalTo($processor))
+ ;
+ $consumer
+ ->expects($this->at(1))
+ ->method('consume')
+ ->with($this->isInstanceOf(ChainExtension::class))
+ ;
+
+ $command = new ConsumeCommand(new Container([
+ 'enqueue.client.default.queue_consumer' => $consumer,
+ 'enqueue.client.default.driver' => $driver,
+ 'enqueue.client.default.delegate_processor' => $processor,
+ ]), 'default');
+
+ $tester = new CommandTester($command);
+ $tester->execute([]);
+ }
+
+ public function testShouldSkipQueueConsumptionAndUseCustomClientDestinationName()
+ {
+ $queue = new NullQueue('');
+
+ $processor = $this->createDelegateProcessorMock();
+
+ $consumer = $this->createQueueConsumerMock();
+ $consumer
+ ->expects($this->exactly(3))
+ ->method('bind')
+ ;
+ $consumer
+ ->expects($this->once())
+ ->method('consume')
+ ->with($this->isInstanceOf(ChainExtension::class))
+ ;
+
+ $routeCollection = new RouteCollection([
+ new Route('fooTopic', Route::TOPIC, 'processor', ['queue' => 'fooQueue']),
+ new Route('barTopic', Route::TOPIC, 'processor', ['queue' => 'barQueue']),
+ new Route('ololoTopic', Route::TOPIC, 'processor', ['queue' => 'ololoQueue']),
+ ]);
+
+ $driver = $this->createDriverStub($routeCollection);
+ $driver
+ ->expects($this->at(3))
+ ->method('createQueue', true)
+ ->with('default')
+ ->willReturn($queue)
+ ;
+ $driver
+ ->expects($this->at(4))
+ ->method('createQueue', true)
+ ->with('fooQueue')
+ ->willReturn($queue)
+ ;
+ $driver
+ ->expects($this->at(5))
+ ->method('createQueue', true)
+ ->with('ololoQueue')
+ ->willReturn($queue)
+ ;
+
+ $command = new ConsumeCommand(new Container([
+ 'enqueue.client.default.queue_consumer' => $consumer,
+ 'enqueue.client.default.driver' => $driver,
+ 'enqueue.client.default.delegate_processor' => $processor,
+ ]), 'default');
+
+ $tester = new CommandTester($command);
+ $tester->execute([
+ '--skip' => ['barQueue'],
+ ]);
+ }
+
+ public function testShouldReturnExitStatusIfSet()
+ {
+ $testExitCode = 678;
+
+ $stubExtension = $this->createExtension();
+
+ $stubExtension
+ ->expects($this->once())
+ ->method('onStart')
+ ->with($this->isInstanceOf(Start::class))
+ ->willReturnCallback(function (Start $context) use ($testExitCode) {
+ $context->interruptExecution($testExitCode);
+ })
+ ;
+
+ $defaultQueue = new NullQueue('default');
+
+ $routeCollection = new RouteCollection([]);
+
+ $processor = $this->createDelegateProcessorMock();
+
+ $driver = $this->createDriverStub($routeCollection);
+ $driver
+ ->expects($this->exactly(1))
+ ->method('createQueue')
+ ->with('default', true)
+ ->willReturn($defaultQueue)
+ ;
+
+ $consumer = new QueueConsumer($this->createContextStub(), $stubExtension);
+
+ $command = new ConsumeCommand(new Container([
+ 'enqueue.client.default.queue_consumer' => $consumer,
+ 'enqueue.client.default.driver' => $driver,
+ 'enqueue.client.default.delegate_processor' => $processor,
+ ]), 'default');
+
+ $tester = new CommandTester($command);
+ $tester->execute([]);
+
+ $this->assertEquals($testExitCode, $tester->getStatusCode());
+ }
+
+ /**
+ * @return \PHPUnit\Framework\MockObject\MockObject|DelegateProcessor
+ */
+ private function createDelegateProcessorMock()
+ {
+ return $this->createMock(DelegateProcessor::class);
+ }
+
+ /**
+ * @return \PHPUnit\Framework\MockObject\MockObject|QueueConsumerInterface
+ */
+ private function createQueueConsumerMock()
+ {
+ return $this->createMock(QueueConsumerInterface::class);
+ }
+
+ /**
+ * @return \PHPUnit\Framework\MockObject\MockObject|DriverInterface
+ */
+ private function createDriverStub(?RouteCollection $routeCollection = null): DriverInterface
+ {
+ $driverMock = $this->createMock(DriverInterface::class);
+ $driverMock
+ ->expects($this->any())
+ ->method('getRouteCollection')
+ ->willReturn($routeCollection ?? new RouteCollection([]))
+ ;
+
+ $driverMock
+ ->expects($this->any())
+ ->method('getConfig')
+ ->willReturn(Config::create('aPrefix', 'anApp'))
+ ;
+
+ return $driverMock;
+ }
+
+ /**
+ * @return \PHPUnit\Framework\MockObject\MockObject
+ */
+ private function createContextWithoutSubscriptionConsumerMock(): InteropContext
+ {
+ $contextMock = $this->createMock(InteropContext::class);
+ $contextMock
+ ->expects($this->any())
+ ->method('createSubscriptionConsumer')
+ ->willThrowException(SubscriptionConsumerNotSupportedException::providerDoestNotSupportIt())
+ ;
+
+ return $contextMock;
+ }
+
+ /**
+ * @return \PHPUnit\Framework\MockObject\MockObject|InteropContext
+ */
+ private function createContextStub(?Consumer $consumer = null): InteropContext
+ {
+ $context = $this->createContextWithoutSubscriptionConsumerMock();
+ $context
+ ->expects($this->any())
+ ->method('createQueue')
+ ->willReturnCallback(function (string $queueName) {
+ return new NullQueue($queueName);
+ })
+ ;
+ $context
+ ->expects($this->any())
+ ->method('createConsumer')
+ ->willReturnCallback(function (Queue $queue) use ($consumer) {
+ return $consumer ?: $this->createConsumerStub($queue);
+ })
+ ;
+
+ return $context;
+ }
+
+ /**
+ * @return \PHPUnit\Framework\MockObject\MockObject|ExtensionInterface
+ */
+ private function createExtension()
+ {
+ return $this->createMock(ExtensionInterface::class);
+ }
+
+ /**
+ * @param mixed|null $queue
+ *
+ * @return \PHPUnit\Framework\MockObject\MockObject|Consumer
+ */
+ private function createConsumerStub($queue = null): Consumer
+ {
+ if (null === $queue) {
+ $queue = 'queue';
+ }
+ if (is_string($queue)) {
+ $queue = new NullQueue($queue);
+ }
+
+ $consumerMock = $this->createMock(Consumer::class);
+ $consumerMock
+ ->expects($this->any())
+ ->method('getQueue')
+ ->willReturn($queue)
+ ;
+
+ return $consumerMock;
+ }
+}
diff --git a/pkg/enqueue/Tests/Symfony/Client/ConsumeMessagesCommandTest.php b/pkg/enqueue/Tests/Symfony/Client/ConsumeMessagesCommandTest.php
deleted file mode 100644
index 396417e2b..000000000
--- a/pkg/enqueue/Tests/Symfony/Client/ConsumeMessagesCommandTest.php
+++ /dev/null
@@ -1,283 +0,0 @@
-createQueueConsumerMock(),
- $this->createDelegateProcessorMock(),
- $this->createQueueMetaRegistry([]),
- $this->createDriverMock()
- );
- }
-
- public function testShouldHaveCommandName()
- {
- $command = new ConsumeMessagesCommand(
- $this->createQueueConsumerMock(),
- $this->createDelegateProcessorMock(),
- $this->createQueueMetaRegistry([]),
- $this->createDriverMock()
- );
-
- $this->assertEquals('enqueue:consume', $command->getName());
- }
-
- public function testShouldHaveCommandAliases()
- {
- $command = new ConsumeMessagesCommand(
- $this->createQueueConsumerMock(),
- $this->createDelegateProcessorMock(),
- $this->createQueueMetaRegistry([]),
- $this->createDriverMock()
- );
-
- $this->assertEquals(['enq:c'], $command->getAliases());
- }
-
- public function testShouldHaveExpectedOptions()
- {
- $command = new ConsumeMessagesCommand(
- $this->createQueueConsumerMock(),
- $this->createDelegateProcessorMock(),
- $this->createQueueMetaRegistry([]),
- $this->createDriverMock()
- );
-
- $options = $command->getDefinition()->getOptions();
-
- $this->assertCount(8, $options);
- $this->assertArrayHasKey('memory-limit', $options);
- $this->assertArrayHasKey('message-limit', $options);
- $this->assertArrayHasKey('time-limit', $options);
- $this->assertArrayHasKey('setup-broker', $options);
- $this->assertArrayHasKey('idle-timeout', $options);
- $this->assertArrayHasKey('receive-timeout', $options);
- $this->assertArrayHasKey('skip', $options);
- $this->assertArrayHasKey('niceness', $options);
- }
-
- public function testShouldHaveExpectedArguments()
- {
- $command = new ConsumeMessagesCommand(
- $this->createQueueConsumerMock(),
- $this->createDelegateProcessorMock(),
- $this->createQueueMetaRegistry([]),
- $this->createDriverMock()
- );
-
- $arguments = $command->getDefinition()->getArguments();
-
- $this->assertCount(1, $arguments);
- $this->assertArrayHasKey('client-queue-names', $arguments);
- }
-
- public function testShouldExecuteConsumptionAndUseDefaultQueueName()
- {
- $queue = new NullQueue('');
-
- $processor = $this->createDelegateProcessorMock();
-
- $context = $this->createPsrContextMock();
- $context
- ->expects($this->never())
- ->method('close')
- ;
-
- $consumer = $this->createQueueConsumerMock();
- $consumer
- ->expects($this->once())
- ->method('bind')
- ->with($this->identicalTo($queue), $this->identicalTo($processor))
- ;
- $consumer
- ->expects($this->once())
- ->method('consume')
- ->with($this->isInstanceOf(ChainExtension::class))
- ;
-
- $queueMetaRegistry = $this->createQueueMetaRegistry([
- 'default' => [],
- ]);
-
- $driver = $this->createDriverMock();
- $driver
- ->expects($this->once())
- ->method('createQueue')
- ->with('default')
- ->willReturn($queue)
- ;
-
- $command = new ConsumeMessagesCommand($consumer, $processor, $queueMetaRegistry, $driver);
-
- $tester = new CommandTester($command);
- $tester->execute([]);
- }
-
- public function testShouldExecuteConsumptionAndUseCustomClientDestinationName()
- {
- $queue = new NullQueue('');
-
- $processor = $this->createDelegateProcessorMock();
-
- $context = $this->createPsrContextMock();
- $context
- ->expects($this->never())
- ->method('close')
- ;
-
- $consumer = $this->createQueueConsumerMock();
- $consumer
- ->expects($this->once())
- ->method('bind')
- ->with($this->identicalTo($queue), $this->identicalTo($processor))
- ;
- $consumer
- ->expects($this->once())
- ->method('consume')
- ->with($this->isInstanceOf(ChainExtension::class))
- ;
-
- $queueMetaRegistry = $this->createQueueMetaRegistry([
- 'non-default-queue' => [],
- ]);
-
- $driver = $this->createDriverMock();
- $driver
- ->expects($this->once())
- ->method('createQueue')
- ->with('non-default-queue')
- ->willReturn($queue)
- ;
-
- $command = new ConsumeMessagesCommand($consumer, $processor, $queueMetaRegistry, $driver);
-
- $tester = new CommandTester($command);
- $tester->execute([
- 'client-queue-names' => ['non-default-queue'],
- ]);
- }
-
- public function testShouldSkipQueueConsumptionAndUseCustomClientDestinationName()
- {
- $queue = new NullQueue('');
-
- $processor = $this->createDelegateProcessorMock();
-
- $context = $this->createPsrContextMock();
- $context
- ->expects($this->never())
- ->method('close')
- ;
-
- $consumer = $this->createQueueConsumerMock();
- $consumer
- ->expects($this->exactly(2))
- ->method('bind')
- ;
- $consumer
- ->expects($this->once())
- ->method('consume')
- ->with($this->isInstanceOf(ChainExtension::class))
- ;
-
- $queueMetaRegistry = $this->createQueueMetaRegistry([
- 'fooQueue' => [
- 'transportName' => 'fooTransportQueue',
- ],
- 'barQueue' => [
- 'transportName' => 'barTransportQueue',
- ],
- 'ololoQueue' => [
- 'transportName' => 'ololoTransportQueue',
- ],
- ]);
-
- $driver = $this->createDriverMock();
- $driver
- ->expects($this->at(0))
- ->method('createQueue')
- ->with('fooQueue')
- ->willReturn($queue)
- ;
- $driver
- ->expects($this->at(1))
- ->method('createQueue')
- ->with('ololoQueue')
- ->willReturn($queue)
- ;
-
- $command = new ConsumeMessagesCommand($consumer, $processor, $queueMetaRegistry, $driver);
-
- $tester = new CommandTester($command);
- $tester->execute([
- '--skip' => ['barQueue'],
- ]);
- }
-
- /**
- * @param array $destinationNames
- *
- * @return QueueMetaRegistry
- */
- private function createQueueMetaRegistry(array $destinationNames)
- {
- $config = new Config(
- 'aPrefix',
- 'anApp',
- 'aRouterTopicName',
- 'aRouterQueueName',
- 'aDefaultQueueName',
- 'aRouterProcessorName'
- );
-
- return new QueueMetaRegistry($config, $destinationNames);
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject|PsrContext
- */
- private function createPsrContextMock()
- {
- return $this->createMock(PsrContext::class);
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject|DelegateProcessor
- */
- private function createDelegateProcessorMock()
- {
- return $this->createMock(DelegateProcessor::class);
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject|QueueConsumer
- */
- private function createQueueConsumerMock()
- {
- return $this->createMock(QueueConsumer::class);
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject|DriverInterface
- */
- private function createDriverMock()
- {
- return $this->createMock(DriverInterface::class);
- }
-}
diff --git a/pkg/enqueue/Tests/Symfony/Client/ContainerAwareProcessorRegistryTest.php b/pkg/enqueue/Tests/Symfony/Client/ContainerAwareProcessorRegistryTest.php
deleted file mode 100644
index 1d641d429..000000000
--- a/pkg/enqueue/Tests/Symfony/Client/ContainerAwareProcessorRegistryTest.php
+++ /dev/null
@@ -1,84 +0,0 @@
-assertClassImplements(ProcessorRegistryInterface::class, ContainerAwareProcessorRegistry::class);
- }
-
- public function testCouldBeConstructedWithoutAnyArgument()
- {
- new ContainerAwareProcessorRegistry();
- }
-
- public function testShouldThrowExceptionIfProcessorIsNotSet()
- {
- $this->setExpectedException(
- \LogicException::class,
- 'Processor was not found. processorName: "processor-name"'
- );
-
- $registry = new ContainerAwareProcessorRegistry();
- $registry->get('processor-name');
- }
-
- public function testShouldThrowExceptionIfContainerIsNotSet()
- {
- $this->setExpectedException(\LogicException::class, 'Container was not set');
-
- $registry = new ContainerAwareProcessorRegistry();
- $registry->set('processor-name', 'processor-id');
-
- $registry->get('processor-name');
- }
-
- public function testShouldThrowExceptionIfInstanceOfProcessorIsInvalid()
- {
- $this->setExpectedException(\LogicException::class, 'Container was not set');
-
- $processor = new \stdClass();
-
- $container = new Container();
- $container->set('processor-id', $processor);
-
- $registry = new ContainerAwareProcessorRegistry();
- $registry->set('processor-name', 'processor-id');
-
- $registry->get('processor-name');
- }
-
- public function testShouldReturnInstanceOfProcessor()
- {
- $this->setExpectedException(\LogicException::class, 'Container was not set');
-
- $processor = $this->createProcessorMock();
-
- $container = new Container();
- $container->set('processor-id', $processor);
-
- $registry = new ContainerAwareProcessorRegistry();
- $registry->set('processor-name', 'processor-id');
-
- $this->assertSame($processor, $registry->get('processor-name'));
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject|PsrProcessor
- */
- protected function createProcessorMock()
- {
- return $this->createMock(PsrProcessor::class);
- }
-}
diff --git a/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/AnalyzeRouteCollectionPassTest.php b/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/AnalyzeRouteCollectionPassTest.php
new file mode 100644
index 000000000..568de6488
--- /dev/null
+++ b/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/AnalyzeRouteCollectionPassTest.php
@@ -0,0 +1,167 @@
+assertClassImplements(CompilerPassInterface::class, AnalyzeRouteCollectionPass::class);
+ }
+
+ public function testShouldBeFinal()
+ {
+ $this->assertClassFinal(AnalyzeRouteCollectionPass::class);
+ }
+
+ public function testThrowIfEnqueueClientsParameterNotSet()
+ {
+ $pass = new AnalyzeRouteCollectionPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('The "enqueue.clients" parameter must be set.');
+ $pass->process(new ContainerBuilder());
+ }
+
+ public function testThrowsIfNoRouteCollectionServiceFoundForConfiguredTransport()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo', 'bar']);
+
+ $pass = new AnalyzeRouteCollectionPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Service "enqueue.client.foo.route_collection" not found');
+ $pass->process($container);
+ }
+
+ public function testThrowIfExclusiveCommandProcessorOnDefaultQueue()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['aName']);
+ $container->register('enqueue.client.aName.route_collection')->addArgument([
+ (new Route(
+ 'aCommand',
+ Route::COMMAND,
+ 'aBarProcessor',
+ ['exclusive' => true]
+ ))->toArray(),
+ ]);
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('The command "aCommand" processor "aBarProcessor" is exclusive but queue is not specified. Exclusive processors could not be run on a default queue.');
+ $pass = new AnalyzeRouteCollectionPass();
+
+ $pass->process($container);
+ }
+
+ public function testThrowIfTwoExclusiveCommandProcessorsWorkOnSamePrefixedQueue()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['aName']);
+ $container->register('enqueue.client.aName.route_collection')->addArgument([
+ (new Route(
+ 'aFooCommand',
+ Route::COMMAND,
+ 'aFooProcessor',
+ ['exclusive' => true, 'queue' => 'aQueue', 'prefix_queue' => true]
+ ))->toArray(),
+
+ (new Route(
+ 'aBarCommand',
+ Route::COMMAND,
+ 'aBarProcessor',
+ ['exclusive' => true, 'queue' => 'aQueue', 'prefix_queue' => true]
+ ))->toArray(),
+ ]);
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('The command "aBarCommand" processor "aBarProcessor" is exclusive. The queue "aQueue" already has another exclusive command processor "aFooProcessor" bound to it.');
+ $pass = new AnalyzeRouteCollectionPass();
+
+ $pass->process($container);
+ }
+
+ public function testThrowIfTwoExclusiveCommandProcessorsWorkOnSameQueue()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['aName']);
+ $container->register('enqueue.client.aName.route_collection')->addArgument([
+ (new Route(
+ 'aFooCommand',
+ Route::COMMAND,
+ 'aFooProcessor',
+ ['exclusive' => true, 'queue' => 'aQueue', 'prefix_queue' => false]
+ ))->toArray(),
+
+ (new Route(
+ 'aBarCommand',
+ Route::COMMAND,
+ 'aBarProcessor',
+ ['exclusive' => true, 'queue' => 'aQueue', 'prefix_queue' => false]
+ ))->toArray(),
+ ]);
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('The command "aBarCommand" processor "aBarProcessor" is exclusive. The queue "aQueue" already has another exclusive command processor "aFooProcessor" bound to it.');
+ $pass = new AnalyzeRouteCollectionPass();
+
+ $pass->process($container);
+ }
+
+ public function testThrowIfThereAreTwoQueuesWithSameNameAndOneNotPrefixed()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['aName']);
+ $container->register('enqueue.client.aName.route_collection')->addArgument([
+ (new Route(
+ 'aFooCommand',
+ Route::COMMAND,
+ 'aFooProcessor',
+ ['queue' => 'foo', 'prefix_queue' => false]
+ ))->toArray(),
+
+ (new Route(
+ 'aBarCommand',
+ Route::COMMAND,
+ 'aBarProcessor',
+ ['queue' => 'foo', 'prefix_queue' => true]
+ ))->toArray(),
+ ]);
+
+ $pass = new AnalyzeRouteCollectionPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('There are prefixed and not prefixed queue with the same name "foo". This is not allowed.');
+ $pass->process($container);
+ }
+
+ public function testThrowIfDefaultQueueNotPrefixed()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['aName']);
+ $container->register('enqueue.client.aName.route_collection')->addArgument([
+ (new Route(
+ 'aFooCommand',
+ Route::COMMAND,
+ 'aFooProcessor',
+ ['queue' => null, 'prefix_queue' => false]
+ ))->toArray(),
+ ]);
+
+ $pass = new AnalyzeRouteCollectionPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('The default queue must be prefixed.');
+ $pass->process($container);
+ }
+}
diff --git a/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/BuildClientExtensionsPassTest.php b/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/BuildClientExtensionsPassTest.php
new file mode 100644
index 000000000..753790369
--- /dev/null
+++ b/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/BuildClientExtensionsPassTest.php
@@ -0,0 +1,283 @@
+assertClassImplements(CompilerPassInterface::class, BuildClientExtensionsPass::class);
+ }
+
+ public function testShouldBeFinal()
+ {
+ $this->assertClassFinal(BuildClientExtensionsPass::class);
+ }
+
+ public function testThrowIfEnqueueClientsParameterNotSet()
+ {
+ $pass = new BuildClientExtensionsPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('The "enqueue.clients" parameter must be set.');
+ $pass->process(new ContainerBuilder());
+ }
+
+ public function testThrowsIfNoClientExtensionsServiceFoundForConfiguredTransport()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo', 'bar']);
+ $container->setParameter('enqueue.default_client', 'foo');
+
+ $pass = new BuildClientExtensionsPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Service "enqueue.client.foo.client_extensions" not found');
+ $pass->process($container);
+ }
+
+ public function testShouldRegisterClientExtension()
+ {
+ $extensions = new Definition();
+ $extensions->addArgument([]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['aName']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.aName.client_extensions', $extensions);
+
+ $container->register('aFooExtension', ExtensionInterface::class)
+ ->addTag('enqueue.client_extension', ['client' => 'aName'])
+ ;
+ $container->register('aBarExtension', ExtensionInterface::class)
+ ->addTag('enqueue.client_extension', ['client' => 'aName'])
+ ;
+
+ $pass = new BuildClientExtensionsPass();
+ $pass->process($container);
+
+ self::assertIsArray($extensions->getArgument(0));
+ $this->assertEquals([
+ new Reference('aFooExtension'),
+ new Reference('aBarExtension'),
+ ], $extensions->getArgument(0));
+ }
+
+ public function testShouldIgnoreOtherClientExtensions()
+ {
+ $extensions = new Definition();
+ $extensions->addArgument([]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['aName']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.aName.client_extensions', $extensions);
+
+ $container->register('aFooExtension', ExtensionInterface::class)
+ ->addTag('enqueue.client_extension', ['client' => 'aName'])
+ ;
+ $container->register('aBarExtension', ExtensionInterface::class)
+ ->addTag('enqueue.client_extension', ['client' => 'anotherName'])
+ ;
+
+ $pass = new BuildClientExtensionsPass();
+ $pass->process($container);
+
+ self::assertIsArray($extensions->getArgument(0));
+ $this->assertEquals([
+ new Reference('aFooExtension'),
+ ], $extensions->getArgument(0));
+ }
+
+ public function testShouldAddExtensionIfClientAll()
+ {
+ $extensions = new Definition();
+ $extensions->addArgument([]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['aName']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.aName.client_extensions', $extensions);
+
+ $container->register('aFooExtension', ExtensionInterface::class)
+ ->addTag('enqueue.client_extension', ['client' => 'all'])
+ ;
+ $container->register('aBarExtension', ExtensionInterface::class)
+ ->addTag('enqueue.client_extension', ['client' => 'anotherName'])
+ ;
+
+ $pass = new BuildClientExtensionsPass();
+ $pass->process($container);
+
+ self::assertIsArray($extensions->getArgument(0));
+ $this->assertEquals([
+ new Reference('aFooExtension'),
+ ], $extensions->getArgument(0));
+ }
+
+ public function testShouldTreatTagsWithoutClientAsDefaultClient()
+ {
+ $extensions = new Definition();
+ $extensions->addArgument([]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.client_extensions', $extensions);
+
+ $container->register('aFooExtension', ExtensionInterface::class)
+ ->addTag('enqueue.client_extension')
+ ;
+ $container->register('aBarExtension', ExtensionInterface::class)
+ ->addTag('enqueue.client_extension')
+ ;
+
+ $pass = new BuildClientExtensionsPass();
+ $pass->process($container);
+
+ self::assertIsArray($extensions->getArgument(0));
+ $this->assertEquals([
+ new Reference('aFooExtension'),
+ new Reference('aBarExtension'),
+ ], $extensions->getArgument(0));
+ }
+
+ public function testShouldOrderExtensionsByPriority()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+
+ $extensions = new Definition();
+ $extensions->addArgument([]);
+ $container->setDefinition('enqueue.client.foo.client_extensions', $extensions);
+
+ $extension = new Definition();
+ $extension->addTag('enqueue.client_extension', ['priority' => 6]);
+ $container->setDefinition('foo_extension', $extension);
+
+ $extension = new Definition();
+ $extension->addTag('enqueue.client_extension', ['priority' => -5]);
+ $container->setDefinition('bar_extension', $extension);
+
+ $extension = new Definition();
+ $extension->addTag('enqueue.client_extension', ['priority' => 2]);
+ $container->setDefinition('baz_extension', $extension);
+
+ $pass = new BuildClientExtensionsPass();
+ $pass->process($container);
+
+ $orderedExtensions = $extensions->getArgument(0);
+
+ $this->assertCount(3, $orderedExtensions);
+ $this->assertEquals(new Reference('foo_extension'), $orderedExtensions[0]);
+ $this->assertEquals(new Reference('baz_extension'), $orderedExtensions[1]);
+ $this->assertEquals(new Reference('bar_extension'), $orderedExtensions[2]);
+ }
+
+ public function testShouldAssumePriorityZeroIfPriorityIsNotSet()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+
+ $extensions = new Definition();
+ $extensions->addArgument([]);
+ $container->setDefinition('enqueue.client.foo.client_extensions', $extensions);
+
+ $extension = new Definition();
+ $extension->addTag('enqueue.client_extension');
+ $container->setDefinition('foo_extension', $extension);
+
+ $extension = new Definition();
+ $extension->addTag('enqueue.client_extension', ['priority' => 1]);
+ $container->setDefinition('bar_extension', $extension);
+
+ $extension = new Definition();
+ $extension->addTag('enqueue.client_extension', ['priority' => -1]);
+ $container->setDefinition('baz_extension', $extension);
+
+ $pass = new BuildClientExtensionsPass();
+ $pass->process($container);
+
+ $orderedExtensions = $extensions->getArgument(0);
+
+ $this->assertCount(3, $orderedExtensions);
+ $this->assertEquals(new Reference('bar_extension'), $orderedExtensions[0]);
+ $this->assertEquals(new Reference('foo_extension'), $orderedExtensions[1]);
+ $this->assertEquals(new Reference('baz_extension'), $orderedExtensions[2]);
+ }
+
+ public function testShouldMergeWithAddedPreviously()
+ {
+ $extensions = new Definition();
+ $extensions->addArgument([
+ 'aBarExtension' => 'aBarServiceIdAddedPreviously',
+ 'aOloloExtension' => 'aOloloServiceIdAddedPreviously',
+ ]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.client_extensions', $extensions);
+
+ $container->register('aFooExtension', ExtensionInterface::class)
+ ->addTag('enqueue.client_extension')
+ ;
+ $container->register('aBarExtension', ExtensionInterface::class)
+ ->addTag('enqueue.client_extension')
+ ;
+
+ $pass = new BuildClientExtensionsPass();
+ $pass->process($container);
+
+ self::assertIsArray($extensions->getArgument(0));
+ $this->assertCount(4, $extensions->getArgument(0));
+ }
+
+ public function testShouldRegisterProcessorWithMatchedNameToCorrespondingExtensions()
+ {
+ $fooExtensions = new Definition();
+ $fooExtensions->addArgument([]);
+
+ $barExtensions = new Definition();
+ $barExtensions->addArgument([]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo', 'bar']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.client_extensions', $fooExtensions);
+ $container->setDefinition('enqueue.client.bar.client_extensions', $barExtensions);
+
+ $container->register('aFooExtension', ExtensionInterface::class)
+ ->addTag('enqueue.client_extension', ['client' => 'foo'])
+ ;
+ $container->register('aBarExtension', ExtensionInterface::class)
+ ->addTag('enqueue.client_extension', ['client' => 'bar'])
+ ;
+
+ $pass = new BuildClientExtensionsPass();
+ $pass->process($container);
+
+ self::assertIsArray($fooExtensions->getArgument(0));
+ $this->assertEquals([
+ new Reference('aFooExtension'),
+ ], $fooExtensions->getArgument(0));
+
+ self::assertIsArray($barExtensions->getArgument(0));
+ $this->assertEquals([
+ new Reference('aBarExtension'),
+ ], $barExtensions->getArgument(0));
+ }
+}
diff --git a/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/BuildCommandSubscriberRoutesPassTest.php b/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/BuildCommandSubscriberRoutesPassTest.php
new file mode 100644
index 000000000..e1ed297c6
--- /dev/null
+++ b/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/BuildCommandSubscriberRoutesPassTest.php
@@ -0,0 +1,459 @@
+assertClassImplements(CompilerPassInterface::class, BuildCommandSubscriberRoutesPass::class);
+ }
+
+ public function testShouldBeFinal()
+ {
+ $this->assertClassFinal(BuildCommandSubscriberRoutesPass::class);
+ }
+
+ public function testThrowIfEnqueueClientsParameterNotSet()
+ {
+ $pass = new BuildCommandSubscriberRoutesPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('The "enqueue.clients" parameter must be set.');
+ $pass->process(new ContainerBuilder());
+ }
+
+ public function testThrowsIfNoRouteCollectionServiceFoundForConfiguredTransport()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo', 'bar']);
+ $container->setParameter('enqueue.default_client', 'baz');
+
+ $pass = new BuildCommandSubscriberRoutesPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Service "enqueue.client.foo.route_collection" not found');
+ $pass->process($container);
+ }
+
+ public function testThrowIfTaggedProcessorIsBuiltByFactory()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['aName']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->register('enqueue.client.aName.route_collection', RouteCollection::class)
+ ->addArgument([])
+ ;
+ $container->register('aProcessor', Processor::class)
+ ->setFactory('foo')
+ ->addTag('enqueue.command_subscriber')
+ ;
+
+ $pass = new BuildCommandSubscriberRoutesPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('The command subscriber tag could not be applied to a service created by factory.');
+ $pass->process($container);
+ }
+
+ public function testShouldRegisterProcessorWithMatchedName()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', get_class($this->createCommandSubscriberProcessor()))
+ ->addTag('enqueue.command_subscriber', ['client' => 'foo'])
+ ;
+ $container->register('aProcessor', get_class($this->createCommandSubscriberProcessor()))
+ ->addTag('enqueue.command_subscriber', ['client' => 'bar'])
+ ;
+
+ $pass = new BuildCommandSubscriberRoutesPass();
+
+ $pass->process($container);
+
+ self::assertIsArray($routeCollection->getArgument(0));
+ $this->assertCount(1, $routeCollection->getArgument(0));
+ }
+
+ public function testShouldRegisterProcessorWithoutNameToDefaultClient()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', get_class($this->createCommandSubscriberProcessor()))
+ ->addTag('enqueue.command_subscriber')
+ ;
+ $container->register('aProcessor', get_class($this->createCommandSubscriberProcessor()))
+ ->addTag('enqueue.command_subscriber', ['client' => 'bar'])
+ ;
+
+ $pass = new BuildCommandSubscriberRoutesPass();
+
+ $pass->process($container);
+
+ self::assertIsArray($routeCollection->getArgument(0));
+ $this->assertCount(1, $routeCollection->getArgument(0));
+ }
+
+ public function testShouldRegisterProcessorIfClientNameEqualsAll()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', get_class($this->createCommandSubscriberProcessor()))
+ ->addTag('enqueue.command_subscriber', ['client' => 'all'])
+ ;
+ $container->register('aProcessor', get_class($this->createCommandSubscriberProcessor()))
+ ->addTag('enqueue.command_subscriber', ['client' => 'bar'])
+ ;
+
+ $pass = new BuildCommandSubscriberRoutesPass();
+
+ $pass->process($container);
+
+ self::assertIsArray($routeCollection->getArgument(0));
+ $this->assertCount(1, $routeCollection->getArgument(0));
+ }
+
+ public function testShouldRegisterProcessorIfCommandsIsString()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $processor = $this->createCommandSubscriberProcessor('fooCommand');
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', $processor::class)
+ ->addTag('enqueue.command_subscriber')
+ ;
+
+ $pass = new BuildCommandSubscriberRoutesPass();
+ $pass->process($container);
+
+ self::assertIsArray($routeCollection->getArgument(0));
+ $this->assertCount(1, $routeCollection->getArgument(0));
+
+ $this->assertEquals(
+ [
+ [
+ 'source' => 'fooCommand',
+ 'source_type' => 'enqueue.client.command_route',
+ 'processor' => 'aFooProcessor',
+ 'processor_service_id' => 'aFooProcessor',
+ ],
+ ],
+ $routeCollection->getArgument(0)
+ );
+ }
+
+ public function testThrowIfCommandSubscriberReturnsNothing()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $processor = $this->createCommandSubscriberProcessor(null);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', $processor::class)
+ ->addTag('enqueue.command_subscriber')
+ ;
+
+ $pass = new BuildCommandSubscriberRoutesPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Command subscriber must return something.');
+ $pass->process($container);
+ }
+
+ public function testShouldRegisterProcessorIfCommandsAreStrings()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $processor = $this->createCommandSubscriberProcessor(['fooCommand', 'barCommand']);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', $processor::class)
+ ->addTag('enqueue.command_subscriber')
+ ;
+
+ $pass = new BuildCommandSubscriberRoutesPass();
+ $pass->process($container);
+
+ self::assertIsArray($routeCollection->getArgument(0));
+ $this->assertCount(2, $routeCollection->getArgument(0));
+
+ $this->assertEquals(
+ [
+ [
+ 'source' => 'fooCommand',
+ 'source_type' => 'enqueue.client.command_route',
+ 'processor' => 'aFooProcessor',
+ 'processor_service_id' => 'aFooProcessor',
+ ],
+ [
+ 'source' => 'barCommand',
+ 'source_type' => 'enqueue.client.command_route',
+ 'processor' => 'aFooProcessor',
+ 'processor_service_id' => 'aFooProcessor',
+ ],
+ ],
+ $routeCollection->getArgument(0)
+ );
+ }
+
+ public function testShouldRegisterProcessorIfParamSingleCommandArray()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $processor = $this->createCommandSubscriberProcessor([
+ 'command' => 'fooCommand',
+ 'processor' => 'aCustomFooProcessorName',
+ 'anOption' => 'aFooVal',
+ ]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', $processor::class)
+ ->addTag('enqueue.command_subscriber')
+ ;
+
+ $pass = new BuildCommandSubscriberRoutesPass();
+ $pass->process($container);
+
+ self::assertIsArray($routeCollection->getArgument(0));
+
+ $this->assertCount(1, $routeCollection->getArgument(0));
+
+ $this->assertEquals(
+ [
+ [
+ 'source' => 'fooCommand',
+ 'source_type' => 'enqueue.client.command_route',
+ 'processor' => 'aCustomFooProcessorName',
+ 'processor_service_id' => 'aFooProcessor',
+ 'anOption' => 'aFooVal',
+ ],
+ ],
+ $routeCollection->getArgument(0)
+ );
+ }
+
+ public function testShouldRegisterProcessorIfCommandsAreParamArrays()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $processor = $this->createCommandSubscriberProcessor([
+ ['command' => 'fooCommand', 'processor' => 'aCustomFooProcessorName', 'anOption' => 'aFooVal'],
+ ['command' => 'barCommand', 'processor' => 'aCustomBarProcessorName', 'anOption' => 'aBarVal'],
+ ]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', $processor::class)
+ ->addTag('enqueue.command_subscriber')
+ ;
+
+ $pass = new BuildCommandSubscriberRoutesPass();
+ $pass->process($container);
+
+ self::assertIsArray($routeCollection->getArgument(0));
+ $this->assertCount(2, $routeCollection->getArgument(0));
+
+ $this->assertEquals(
+ [
+ [
+ 'source' => 'fooCommand',
+ 'source_type' => 'enqueue.client.command_route',
+ 'processor' => 'aCustomFooProcessorName',
+ 'processor_service_id' => 'aFooProcessor',
+ 'anOption' => 'aFooVal',
+ ],
+ [
+ 'source' => 'barCommand',
+ 'source_type' => 'enqueue.client.command_route',
+ 'processor' => 'aCustomBarProcessorName',
+ 'processor_service_id' => 'aFooProcessor',
+ 'anOption' => 'aBarVal',
+ ],
+ ],
+ $routeCollection->getArgument(0)
+ );
+ }
+
+ public function testThrowIfCommandSubscriberParamsInvalid()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $processor = $this->createCommandSubscriberProcessor(['fooBar', true]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', $processor::class)
+ ->addTag('enqueue.command_subscriber')
+ ;
+
+ $pass = new BuildCommandSubscriberRoutesPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Command subscriber configuration is invalid');
+ $pass->process($container);
+ }
+
+ public function testShouldMergeExtractedRoutesWithAlreadySetInCollection()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([
+ (new Route('aCommand', Route::COMMAND, 'aProcessor'))->toArray(),
+ (new Route('aCommand', Route::COMMAND, 'aProcessor'))->toArray(),
+ ]);
+
+ $processor = $this->createCommandSubscriberProcessor(['fooCommand']);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', $processor::class)
+ ->addTag('enqueue.command_subscriber')
+ ;
+
+ $pass = new BuildCommandSubscriberRoutesPass();
+ $pass->process($container);
+
+ self::assertIsArray($routeCollection->getArgument(0));
+ $this->assertCount(3, $routeCollection->getArgument(0));
+
+ $this->assertEquals(
+ [
+ [
+ 'source' => 'aCommand',
+ 'source_type' => 'enqueue.client.command_route',
+ 'processor' => 'aProcessor',
+ ],
+ [
+ 'source' => 'aCommand',
+ 'source_type' => 'enqueue.client.command_route',
+ 'processor' => 'aProcessor',
+ ],
+ [
+ 'source' => 'fooCommand',
+ 'source_type' => 'enqueue.client.command_route',
+ 'processor' => 'aFooProcessor',
+ 'processor_service_id' => 'aFooProcessor',
+ ],
+ ],
+ $routeCollection->getArgument(0)
+ );
+ }
+
+ public function testShouldRegister08CommandProcessor()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $processor = $this->createCommandSubscriberProcessor([
+ 'processorName' => 'fooCommand',
+ 'queueName' => 'a_client_queue_name',
+ 'queueNameHardcoded' => true,
+ 'exclusive' => true,
+ 'anOption' => 'aFooVal',
+ ]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['default']);
+ $container->setParameter('enqueue.default_client', 'default');
+ $container->setDefinition('enqueue.client.default.route_collection', $routeCollection);
+ $container->register('aFooProcessor', $processor::class)
+ ->addTag('enqueue.command_subscriber')
+ ;
+
+ $pass = new BuildCommandSubscriberRoutesPass();
+ $pass->process($container);
+
+ self::assertIsArray($routeCollection->getArgument(0));
+ $this->assertCount(1, $routeCollection->getArgument(0));
+
+ $this->assertEquals(
+ [
+ [
+ 'source' => 'fooCommand',
+ 'source_type' => 'enqueue.client.command_route',
+ 'processor' => 'aFooProcessor',
+ 'processor_service_id' => 'aFooProcessor',
+ 'anOption' => 'aFooVal',
+ 'queue' => 'a_client_queue_name',
+ 'prefix_queue' => false,
+ ],
+ ],
+ $routeCollection->getArgument(0)
+ );
+ }
+
+ private function createCommandSubscriberProcessor($commandSubscriberReturns = ['aCommand'])
+ {
+ $processor = new class implements Processor, CommandSubscriberInterface {
+ public static $return;
+
+ public function process(InteropMessage $message, Context $context)
+ {
+ return self::ACK;
+ }
+
+ public static function getSubscribedCommand()
+ {
+ return static::$return;
+ }
+ };
+
+ $processor::$return = $commandSubscriberReturns;
+
+ return $processor;
+ }
+}
diff --git a/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/BuildConsumptionExtensionsPassTest.php b/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/BuildConsumptionExtensionsPassTest.php
new file mode 100644
index 000000000..c2975051b
--- /dev/null
+++ b/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/BuildConsumptionExtensionsPassTest.php
@@ -0,0 +1,283 @@
+assertClassImplements(CompilerPassInterface::class, BuildConsumptionExtensionsPass::class);
+ }
+
+ public function testShouldBeFinal()
+ {
+ $this->assertClassFinal(BuildConsumptionExtensionsPass::class);
+ }
+
+ public function testThrowIfEnqueueClientsParameterNotSet()
+ {
+ $pass = new BuildConsumptionExtensionsPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('The "enqueue.clients" parameter must be set.');
+ $pass->process(new ContainerBuilder());
+ }
+
+ public function testThrowsIfNoConsumptionExtensionsServiceFoundForConfiguredTransport()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo', 'bar']);
+ $container->setParameter('enqueue.default_client', 'baz');
+
+ $pass = new BuildConsumptionExtensionsPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Service "enqueue.client.foo.consumption_extensions" not found');
+ $pass->process($container);
+ }
+
+ public function testShouldRegisterClientExtension()
+ {
+ $extensions = new Definition();
+ $extensions->addArgument([]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.consumption_extensions', $extensions);
+
+ $container->register('aFooExtension', ExtensionInterface::class)
+ ->addTag('enqueue.consumption_extension', ['client' => 'foo'])
+ ;
+ $container->register('aBarExtension', ExtensionInterface::class)
+ ->addTag('enqueue.consumption_extension', ['client' => 'foo'])
+ ;
+
+ $pass = new BuildConsumptionExtensionsPass();
+ $pass->process($container);
+
+ self::assertIsArray($extensions->getArgument(0));
+ $this->assertEquals([
+ new Reference('aFooExtension'),
+ new Reference('aBarExtension'),
+ ], $extensions->getArgument(0));
+ }
+
+ public function testShouldIgnoreOtherClientExtensions()
+ {
+ $extensions = new Definition();
+ $extensions->addArgument([]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.consumption_extensions', $extensions);
+
+ $container->register('aFooExtension', ExtensionInterface::class)
+ ->addTag('enqueue.consumption_extension', ['client' => 'foo'])
+ ;
+ $container->register('aBarExtension', ExtensionInterface::class)
+ ->addTag('enqueue.consumption_extension', ['client' => 'anotherName'])
+ ;
+
+ $pass = new BuildConsumptionExtensionsPass();
+ $pass->process($container);
+
+ self::assertIsArray($extensions->getArgument(0));
+ $this->assertEquals([
+ new Reference('aFooExtension'),
+ ], $extensions->getArgument(0));
+ }
+
+ public function testShouldAddExtensionIfClientAll()
+ {
+ $extensions = new Definition();
+ $extensions->addArgument([]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.consumption_extensions', $extensions);
+
+ $container->register('aFooExtension', ExtensionInterface::class)
+ ->addTag('enqueue.consumption_extension', ['client' => 'all'])
+ ;
+ $container->register('aBarExtension', ExtensionInterface::class)
+ ->addTag('enqueue.consumption_extension', ['client' => 'anotherName'])
+ ;
+
+ $pass = new BuildConsumptionExtensionsPass();
+ $pass->process($container);
+
+ self::assertIsArray($extensions->getArgument(0));
+ $this->assertEquals([
+ new Reference('aFooExtension'),
+ ], $extensions->getArgument(0));
+ }
+
+ public function testShouldTreatTagsWithoutClientAsDefaultClient()
+ {
+ $extensions = new Definition();
+ $extensions->addArgument([]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.consumption_extensions', $extensions);
+
+ $container->register('aFooExtension', ExtensionInterface::class)
+ ->addTag('enqueue.consumption_extension')
+ ;
+ $container->register('aBarExtension', ExtensionInterface::class)
+ ->addTag('enqueue.consumption_extension')
+ ;
+
+ $pass = new BuildConsumptionExtensionsPass();
+ $pass->process($container);
+
+ self::assertIsArray($extensions->getArgument(0));
+ $this->assertEquals([
+ new Reference('aFooExtension'),
+ new Reference('aBarExtension'),
+ ], $extensions->getArgument(0));
+ }
+
+ public function testShouldOrderExtensionsByPriority()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+
+ $extensions = new Definition();
+ $extensions->addArgument([]);
+ $container->setDefinition('enqueue.client.foo.consumption_extensions', $extensions);
+
+ $extension = new Definition();
+ $extension->addTag('enqueue.consumption_extension', ['priority' => 6]);
+ $container->setDefinition('foo_extension', $extension);
+
+ $extension = new Definition();
+ $extension->addTag('enqueue.consumption_extension', ['priority' => -5]);
+ $container->setDefinition('bar_extension', $extension);
+
+ $extension = new Definition();
+ $extension->addTag('enqueue.consumption_extension', ['priority' => 2]);
+ $container->setDefinition('baz_extension', $extension);
+
+ $pass = new BuildConsumptionExtensionsPass();
+ $pass->process($container);
+
+ $orderedExtensions = $extensions->getArgument(0);
+
+ $this->assertCount(3, $orderedExtensions);
+ $this->assertEquals(new Reference('foo_extension'), $orderedExtensions[0]);
+ $this->assertEquals(new Reference('baz_extension'), $orderedExtensions[1]);
+ $this->assertEquals(new Reference('bar_extension'), $orderedExtensions[2]);
+ }
+
+ public function testShouldAssumePriorityZeroIfPriorityIsNotSet()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+
+ $extensions = new Definition();
+ $extensions->addArgument([]);
+ $container->setDefinition('enqueue.client.foo.consumption_extensions', $extensions);
+
+ $extension = new Definition();
+ $extension->addTag('enqueue.consumption_extension');
+ $container->setDefinition('foo_extension', $extension);
+
+ $extension = new Definition();
+ $extension->addTag('enqueue.consumption_extension', ['priority' => 1]);
+ $container->setDefinition('bar_extension', $extension);
+
+ $extension = new Definition();
+ $extension->addTag('enqueue.consumption_extension', ['priority' => -1]);
+ $container->setDefinition('baz_extension', $extension);
+
+ $pass = new BuildConsumptionExtensionsPass();
+ $pass->process($container);
+
+ $orderedExtensions = $extensions->getArgument(0);
+
+ $this->assertCount(3, $orderedExtensions);
+ $this->assertEquals(new Reference('bar_extension'), $orderedExtensions[0]);
+ $this->assertEquals(new Reference('foo_extension'), $orderedExtensions[1]);
+ $this->assertEquals(new Reference('baz_extension'), $orderedExtensions[2]);
+ }
+
+ public function testShouldMergeWithAddedPreviously()
+ {
+ $extensions = new Definition();
+ $extensions->addArgument([
+ 'aBarExtension' => 'aBarServiceIdAddedPreviously',
+ 'aOloloExtension' => 'aOloloServiceIdAddedPreviously',
+ ]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.consumption_extensions', $extensions);
+
+ $container->register('aFooExtension', ExtensionInterface::class)
+ ->addTag('enqueue.consumption_extension')
+ ;
+ $container->register('aBarExtension', ExtensionInterface::class)
+ ->addTag('enqueue.consumption_extension')
+ ;
+
+ $pass = new BuildConsumptionExtensionsPass();
+ $pass->process($container);
+
+ self::assertIsArray($extensions->getArgument(0));
+ $this->assertCount(4, $extensions->getArgument(0));
+ }
+
+ public function testShouldRegisterProcessorWithMatchedNameToCorrespondingExtensions()
+ {
+ $fooExtensions = new Definition();
+ $fooExtensions->addArgument([]);
+
+ $barExtensions = new Definition();
+ $barExtensions->addArgument([]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo', 'bar']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.consumption_extensions', $fooExtensions);
+ $container->setDefinition('enqueue.client.bar.consumption_extensions', $barExtensions);
+
+ $container->register('aFooExtension', ExtensionInterface::class)
+ ->addTag('enqueue.consumption_extension', ['client' => 'foo'])
+ ;
+ $container->register('aBarExtension', ExtensionInterface::class)
+ ->addTag('enqueue.consumption_extension', ['client' => 'bar'])
+ ;
+
+ $pass = new BuildConsumptionExtensionsPass();
+ $pass->process($container);
+
+ self::assertIsArray($fooExtensions->getArgument(0));
+ $this->assertEquals([
+ new Reference('aFooExtension'),
+ ], $fooExtensions->getArgument(0));
+
+ self::assertIsArray($barExtensions->getArgument(0));
+ $this->assertEquals([
+ new Reference('aBarExtension'),
+ ], $barExtensions->getArgument(0));
+ }
+}
diff --git a/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/BuildProcessorRegistryPassTest.php b/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/BuildProcessorRegistryPassTest.php
new file mode 100644
index 000000000..5c9ac4840
--- /dev/null
+++ b/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/BuildProcessorRegistryPassTest.php
@@ -0,0 +1,151 @@
+assertClassImplements(CompilerPassInterface::class, BuildProcessorRegistryPass::class);
+ }
+
+ public function testShouldBeFinal()
+ {
+ $this->assertClassFinal(BuildProcessorRegistryPass::class);
+ }
+
+ public function testThrowIfEnqueueClientsParameterNotSet()
+ {
+ $pass = new BuildProcessorRegistryPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('The "enqueue.clients" parameter must be set.');
+ $pass->process(new ContainerBuilder());
+ }
+
+ public function testThrowsIfNoProcessorRegistryServiceFoundForConfiguredTransport()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo', 'bar']);
+
+ $pass = new BuildProcessorRegistryPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Service "enqueue.client.foo.processor_registry" not found');
+ $pass->process($container);
+ }
+
+ public function testThrowsIfNoRouteCollectionServiceFoundForConfiguredTransport()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo', 'bar']);
+ $container->register('enqueue.client.foo.processor_registry');
+
+ $pass = new BuildProcessorRegistryPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Service "enqueue.client.foo.route_collection" not found');
+ $pass->process($container);
+ }
+
+ public function testThrowsIfNoRouteProcessorServiceFoundForConfiguredTransport()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo', 'bar']);
+ $container->register('enqueue.client.foo.processor_registry');
+ $container->register('enqueue.client.foo.route_collection');
+
+ $pass = new BuildProcessorRegistryPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Service "enqueue.client.foo.router_processor" not found');
+ $pass->process($container);
+ }
+
+ public function testThrowIfProcessorServiceIdOptionNotSet()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['aName']);
+ $container->register('enqueue.client.aName.route_collection')->addArgument([
+ (new Route('aCommand', Route::COMMAND, 'aProcessor'))->toArray(),
+ ]);
+ $container->register('enqueue.client.aName.processor_registry')->addArgument([]);
+ $container->register('enqueue.client.aName.router_processor');
+
+ $pass = new BuildProcessorRegistryPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('The route option "processor_service_id" is required');
+ $pass->process($container);
+ }
+
+ public function testShouldPassLocatorAsFirstArgument()
+ {
+ $registry = new Definition();
+ $registry->addArgument([]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['aName']);
+ $container->register('enqueue.client.aName.route_collection')->addArgument([
+ (new Route(
+ 'aCommand',
+ Route::COMMAND,
+ 'aBarProcessor',
+ ['processor_service_id' => 'aBarServiceId']
+ ))->toArray(),
+ (new Route(
+ 'aTopic',
+ Route::TOPIC,
+ 'aFooProcessor',
+ ['processor_service_id' => 'aFooServiceId']
+ ))->toArray(),
+ ]);
+ $container->setDefinition('enqueue.client.aName.processor_registry', $registry);
+ $container->register('enqueue.client.aName.router_processor');
+
+ $pass = new BuildProcessorRegistryPass();
+ $pass->process($container);
+
+ $this->assertLocatorServices($container, $registry->getArgument(0), [
+ '%enqueue.client.aName.router_processor%' => 'enqueue.client.aName.router_processor',
+ 'aBarProcessor' => 'aBarServiceId',
+ 'aFooProcessor' => 'aFooServiceId',
+ ]);
+ }
+
+ private function assertLocatorServices(ContainerBuilder $container, $locatorId, array $locatorServices)
+ {
+ $this->assertInstanceOf(Reference::class, $locatorId);
+ $locatorId = (string) $locatorId;
+
+ $this->assertTrue($container->hasDefinition($locatorId));
+ $this->assertMatchesRegularExpression('/\.?service_locator\..*?\.enqueue\./', $locatorId);
+
+ $match = [];
+ if (false == preg_match('/(\.?service_locator\..*?)\.enqueue\./', $locatorId, $match)) {
+ $this->fail('preg_match should not failed');
+ }
+
+ $this->assertTrue($container->hasDefinition($match[1]));
+ $locator = $container->getDefinition($match[1]);
+
+ $this->assertContainsOnly(ServiceClosureArgument::class, $locator->getArgument(0));
+ $actualServices = array_map(function (ServiceClosureArgument $value) {
+ return (string) $value->getValues()[0];
+ }, $locator->getArgument(0));
+
+ $this->assertEquals($locatorServices, $actualServices);
+ }
+}
diff --git a/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/BuildProcessorRoutesPassTest.php b/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/BuildProcessorRoutesPassTest.php
new file mode 100644
index 000000000..0351c45f5
--- /dev/null
+++ b/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/BuildProcessorRoutesPassTest.php
@@ -0,0 +1,302 @@
+assertClassImplements(CompilerPassInterface::class, BuildProcessorRoutesPass::class);
+ }
+
+ public function testShouldBeFinal()
+ {
+ $this->assertClassFinal(BuildProcessorRoutesPass::class);
+ }
+
+ public function testThrowIfEnqueueClientsParameterNotSet()
+ {
+ $pass = new BuildProcessorRoutesPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('The "enqueue.clients" parameter must be set.');
+ $pass->process(new ContainerBuilder());
+ }
+
+ public function testThrowsIfNoRouteCollectionServiceFoundForConfiguredTransport()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo', 'bar']);
+ $container->setParameter('enqueue.default_client', 'baz');
+
+ $pass = new BuildProcessorRoutesPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Service "enqueue.client.foo.route_collection" not found');
+ $pass->process($container);
+ }
+
+ public function testThrowIfBothTopicAndCommandAttributesAreSet()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', 'aProcessorClass')
+ ->addTag('enqueue.processor', ['topic' => 'foo', 'command' => 'bar'])
+ ;
+
+ $pass = new BuildProcessorRoutesPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Either "topic" or "command" tag attribute must be set on service "aFooProcessor". Both are set.');
+ $pass->process($container);
+ }
+
+ public function testThrowIfNeitherTopicNorCommandAttributesAreSet()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', 'aProcessorClass')
+ ->addTag('enqueue.processor', [])
+ ;
+
+ $pass = new BuildProcessorRoutesPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Either "topic" or "command" tag attribute must be set on service "aFooProcessor". None is set.');
+ $pass->process($container);
+ }
+
+ public function testShouldRegisterProcessorWithMatchedName()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'bar');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', 'aProcessorClass')
+ ->addTag('enqueue.processor', ['client' => 'foo', 'topic' => 'foo'])
+ ;
+ $container->register('aProcessor', 'aProcessorClass')
+ ->addTag('enqueue.processor', ['client' => 'bar', 'command' => 'foo'])
+ ;
+
+ $pass = new BuildProcessorRoutesPass();
+
+ $pass->process($container);
+
+ self::assertIsArray($routeCollection->getArgument(0));
+ $this->assertCount(1, $routeCollection->getArgument(0));
+ }
+
+ public function testShouldRegisterProcessorWithoutNameToDefaultClient()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', 'aProcessorClass')
+ ->addTag('enqueue.processor', ['topic' => 'foo'])
+ ;
+ $container->register('aProcessor', 'aProcessorClass')
+ ->addTag('enqueue.processor', ['client' => 'bar', 'command' => 'foo'])
+ ;
+
+ $pass = new BuildProcessorRoutesPass();
+
+ $pass->process($container);
+
+ self::assertIsArray($routeCollection->getArgument(0));
+ $this->assertCount(1, $routeCollection->getArgument(0));
+ }
+
+ public function testShouldRegisterProcessorIfClientNameEqualsAll()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', 'aProcessorClass')
+ ->addTag('enqueue.processor', ['client' => 'all', 'topic' => 'foo'])
+ ;
+ $container->register('aProcessor', 'aProcessorClass')
+ ->addTag('enqueue.processor', ['client' => 'bar', 'command' => 'foo'])
+ ;
+
+ $pass = new BuildProcessorRoutesPass();
+
+ $pass->process($container);
+
+ self::assertIsArray($routeCollection->getArgument(0));
+ $this->assertCount(1, $routeCollection->getArgument(0));
+ }
+
+ public function testShouldRegisterAsTopicProcessor()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', 'aProcessorClass')
+ ->addTag('enqueue.processor', ['topic' => 'aTopic'])
+ ;
+
+ $pass = new BuildProcessorRoutesPass();
+ $pass->process($container);
+
+ self::assertIsArray($routeCollection->getArgument(0));
+ $this->assertCount(1, $routeCollection->getArgument(0));
+
+ $this->assertEquals(
+ [
+ [
+ 'source' => 'aTopic',
+ 'source_type' => 'enqueue.client.topic_route',
+ 'processor' => 'aFooProcessor',
+ 'processor_service_id' => 'aFooProcessor',
+ ],
+ ],
+ $routeCollection->getArgument(0)
+ );
+ }
+
+ public function testShouldRegisterAsCommandProcessor()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', 'aProcessorClass')
+ ->addTag('enqueue.processor', ['command' => 'aCommand'])
+ ;
+
+ $pass = new BuildProcessorRoutesPass();
+ $pass->process($container);
+
+ self::assertIsArray($routeCollection->getArgument(0));
+ $this->assertCount(1, $routeCollection->getArgument(0));
+
+ $this->assertEquals(
+ [
+ [
+ 'source' => 'aCommand',
+ 'source_type' => 'enqueue.client.command_route',
+ 'processor' => 'aFooProcessor',
+ 'processor_service_id' => 'aFooProcessor',
+ ],
+ ],
+ $routeCollection->getArgument(0)
+ );
+ }
+
+ public function testShouldRegisterWithCustomProcessorName()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', 'aProcessorClass')
+ ->addTag('enqueue.processor', ['command' => 'aCommand', 'processor' => 'customProcessorName'])
+ ;
+
+ $pass = new BuildProcessorRoutesPass();
+ $pass->process($container);
+
+ self::assertIsArray($routeCollection->getArgument(0));
+ $this->assertCount(1, $routeCollection->getArgument(0));
+
+ $this->assertEquals(
+ [
+ [
+ 'source' => 'aCommand',
+ 'source_type' => 'enqueue.client.command_route',
+ 'processor' => 'customProcessorName',
+ 'processor_service_id' => 'aFooProcessor',
+ ],
+ ],
+ $routeCollection->getArgument(0)
+ );
+ }
+
+ public function testShouldMergeExtractedRoutesWithAlreadySetInCollection()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([
+ (new Route('aTopic', Route::TOPIC, 'aProcessor'))->toArray(),
+ (new Route('aCommand', Route::COMMAND, 'aProcessor'))->toArray(),
+ ]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', 'aProcessorClass')
+ ->addTag('enqueue.processor', ['command' => 'fooCommand'])
+ ;
+
+ $pass = new BuildProcessorRoutesPass();
+ $pass->process($container);
+
+ self::assertIsArray($routeCollection->getArgument(0));
+ $this->assertCount(3, $routeCollection->getArgument(0));
+
+ $this->assertEquals(
+ [
+ [
+ 'source' => 'aTopic',
+ 'source_type' => 'enqueue.client.topic_route',
+ 'processor' => 'aProcessor',
+ ],
+ [
+ 'source' => 'aCommand',
+ 'source_type' => 'enqueue.client.command_route',
+ 'processor' => 'aProcessor',
+ ],
+ [
+ 'source' => 'fooCommand',
+ 'source_type' => 'enqueue.client.command_route',
+ 'processor' => 'aFooProcessor',
+ 'processor_service_id' => 'aFooProcessor',
+ ],
+ ],
+ $routeCollection->getArgument(0)
+ );
+ }
+}
diff --git a/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/BuildTopicSubscriberRoutesPassTest.php b/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/BuildTopicSubscriberRoutesPassTest.php
new file mode 100644
index 000000000..a954d9a41
--- /dev/null
+++ b/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/BuildTopicSubscriberRoutesPassTest.php
@@ -0,0 +1,423 @@
+assertClassImplements(CompilerPassInterface::class, BuildTopicSubscriberRoutesPass::class);
+ }
+
+ public function testShouldBeFinal()
+ {
+ $this->assertClassFinal(BuildTopicSubscriberRoutesPass::class);
+ }
+
+ public function testThrowIfEnqueueClientsParameterNotSet()
+ {
+ $pass = new BuildTopicSubscriberRoutesPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('The "enqueue.clients" parameter must be set.');
+ $pass->process(new ContainerBuilder());
+ }
+
+ public function testThrowsIfNoRouteCollectionServiceFoundForConfiguredTransport()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo', 'bar']);
+ $container->setParameter('enqueue.default_client', 'baz');
+
+ $pass = new BuildTopicSubscriberRoutesPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Service "enqueue.client.foo.route_collection" not found');
+ $pass->process($container);
+ }
+
+ public function testThrowIfTaggedProcessorIsBuiltByFactory()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->register('enqueue.client.foo.route_collection', RouteCollection::class)
+ ->addArgument([])
+ ;
+ $container->register('aProcessor', Processor::class)
+ ->setFactory('foo')
+ ->addTag('enqueue.topic_subscriber')
+ ;
+
+ $pass = new BuildTopicSubscriberRoutesPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('The topic subscriber tag could not be applied to a service created by factory.');
+ $pass->process($container);
+ }
+
+ public function testShouldRegisterProcessorWithMatchedName()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'bar');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', get_class($this->createTopicSubscriberProcessor()))
+ ->addTag('enqueue.topic_subscriber', ['client' => 'foo'])
+ ;
+ $container->register('aProcessor', get_class($this->createTopicSubscriberProcessor()))
+ ->addTag('enqueue.topic_subscriber', ['client' => 'bar'])
+ ;
+
+ $pass = new BuildTopicSubscriberRoutesPass();
+
+ $pass->process($container);
+
+ self::assertIsArray($routeCollection->getArgument(0));
+ $this->assertCount(1, $routeCollection->getArgument(0));
+ }
+
+ public function testShouldRegisterProcessorWithoutNameToDefaultClient()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', get_class($this->createTopicSubscriberProcessor()))
+ ->addTag('enqueue.topic_subscriber')
+ ;
+ $container->register('aProcessor', get_class($this->createTopicSubscriberProcessor()))
+ ->addTag('enqueue.topic_subscriber', ['client' => 'bar'])
+ ;
+
+ $pass = new BuildTopicSubscriberRoutesPass();
+
+ $pass->process($container);
+
+ self::assertIsArray($routeCollection->getArgument(0));
+ $this->assertCount(1, $routeCollection->getArgument(0));
+ }
+
+ public function testShouldRegisterProcessorIfClientNameEqualsAll()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', get_class($this->createTopicSubscriberProcessor()))
+ ->addTag('enqueue.topic_subscriber', ['client' => 'all'])
+ ;
+ $container->register('aProcessor', get_class($this->createTopicSubscriberProcessor()))
+ ->addTag('enqueue.topic_subscriber', ['client' => 'bar'])
+ ;
+
+ $pass = new BuildTopicSubscriberRoutesPass();
+
+ $pass->process($container);
+
+ self::assertIsArray($routeCollection->getArgument(0));
+ $this->assertCount(1, $routeCollection->getArgument(0));
+ }
+
+ public function testShouldRegisterProcessorIfTopicsIsString()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $processor = $this->createTopicSubscriberProcessor('fooTopic');
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', $processor::class)
+ ->addTag('enqueue.topic_subscriber')
+ ;
+
+ $pass = new BuildTopicSubscriberRoutesPass();
+ $pass->process($container);
+
+ self::assertIsArray($routeCollection->getArgument(0));
+ $this->assertCount(1, $routeCollection->getArgument(0));
+
+ $this->assertEquals(
+ [
+ [
+ 'source' => 'fooTopic',
+ 'source_type' => 'enqueue.client.topic_route',
+ 'processor' => 'aFooProcessor',
+ 'processor_service_id' => 'aFooProcessor',
+ ],
+ ],
+ $routeCollection->getArgument(0)
+ );
+ }
+
+ public function testThrowIfTopicSubscriberReturnsNothing()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $processor = $this->createTopicSubscriberProcessor(null);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', $processor::class)
+ ->addTag('enqueue.topic_subscriber')
+ ;
+
+ $pass = new BuildTopicSubscriberRoutesPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Topic subscriber must return something.');
+ $pass->process($container);
+ }
+
+ public function testShouldRegisterProcessorIfTopicsAreStrings()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $processor = $this->createTopicSubscriberProcessor(['fooTopic', 'barTopic']);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', $processor::class)
+ ->addTag('enqueue.topic_subscriber')
+ ;
+
+ $pass = new BuildTopicSubscriberRoutesPass();
+ $pass->process($container);
+
+ self::assertIsArray($routeCollection->getArgument(0));
+ $this->assertCount(2, $routeCollection->getArgument(0));
+
+ $this->assertEquals(
+ [
+ [
+ 'source' => 'fooTopic',
+ 'source_type' => 'enqueue.client.topic_route',
+ 'processor' => 'aFooProcessor',
+ 'processor_service_id' => 'aFooProcessor',
+ ],
+ [
+ 'source' => 'barTopic',
+ 'source_type' => 'enqueue.client.topic_route',
+ 'processor' => 'aFooProcessor',
+ 'processor_service_id' => 'aFooProcessor',
+ ],
+ ],
+ $routeCollection->getArgument(0)
+ );
+ }
+
+ public function testShouldRegisterProcessorIfTopicsAreParamArrays()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $processor = $this->createTopicSubscriberProcessor([
+ ['topic' => 'fooTopic', 'processor' => 'aCustomFooProcessorName', 'anOption' => 'aFooVal'],
+ ['topic' => 'barTopic', 'processor' => 'aCustomBarProcessorName', 'anOption' => 'aBarVal'],
+ ]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', $processor::class)
+ ->addTag('enqueue.topic_subscriber')
+ ;
+
+ $pass = new BuildTopicSubscriberRoutesPass();
+ $pass->process($container);
+
+ self::assertIsArray($routeCollection->getArgument(0));
+ $this->assertCount(2, $routeCollection->getArgument(0));
+
+ $this->assertEquals(
+ [
+ [
+ 'source' => 'fooTopic',
+ 'source_type' => 'enqueue.client.topic_route',
+ 'processor' => 'aCustomFooProcessorName',
+ 'processor_service_id' => 'aFooProcessor',
+ 'anOption' => 'aFooVal',
+ ],
+ [
+ 'source' => 'barTopic',
+ 'source_type' => 'enqueue.client.topic_route',
+ 'processor' => 'aCustomBarProcessorName',
+ 'processor_service_id' => 'aFooProcessor',
+ 'anOption' => 'aBarVal',
+ ],
+ ],
+ $routeCollection->getArgument(0)
+ );
+ }
+
+ public function testThrowIfTopicSubscriberParamsInvalid()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $processor = $this->createTopicSubscriberProcessor(['fooBar', true]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', $processor::class)
+ ->addTag('enqueue.topic_subscriber')
+ ;
+
+ $pass = new BuildTopicSubscriberRoutesPass();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Topic subscriber configuration is invalid');
+ $pass->process($container);
+ }
+
+ public function testShouldMergeExtractedRoutesWithAlreadySetInCollection()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([
+ (new Route('aTopic', Route::TOPIC, 'aProcessor'))->toArray(),
+ (new Route('aCommand', Route::COMMAND, 'aProcessor'))->toArray(),
+ ]);
+
+ $processor = $this->createTopicSubscriberProcessor(['fooTopic']);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['foo']);
+ $container->setParameter('enqueue.default_client', 'foo');
+ $container->setDefinition('enqueue.client.foo.route_collection', $routeCollection);
+ $container->register('aFooProcessor', $processor::class)
+ ->addTag('enqueue.topic_subscriber')
+ ;
+
+ $pass = new BuildTopicSubscriberRoutesPass();
+ $pass->process($container);
+
+ self::assertIsArray($routeCollection->getArgument(0));
+ $this->assertCount(3, $routeCollection->getArgument(0));
+
+ $this->assertEquals(
+ [
+ [
+ 'source' => 'aTopic',
+ 'source_type' => 'enqueue.client.topic_route',
+ 'processor' => 'aProcessor',
+ ],
+ [
+ 'source' => 'aCommand',
+ 'source_type' => 'enqueue.client.command_route',
+ 'processor' => 'aProcessor',
+ ],
+ [
+ 'source' => 'fooTopic',
+ 'source_type' => 'enqueue.client.topic_route',
+ 'processor' => 'aFooProcessor',
+ 'processor_service_id' => 'aFooProcessor',
+ ],
+ ],
+ $routeCollection->getArgument(0)
+ );
+ }
+
+ public function testShouldRegister08TopicSubscriber()
+ {
+ $routeCollection = new Definition(RouteCollection::class);
+ $routeCollection->addArgument([]);
+
+ $processor = $this->createTopicSubscriberProcessor([
+ 'fooTopic' => ['processorName' => 'aCustomFooProcessorName', 'queueName' => 'fooQueue', 'queueNameHardcoded' => true, 'anOption' => 'aFooVal'],
+ 'barTopic' => ['processorName' => 'aCustomBarProcessorName', 'anOption' => 'aBarVal'],
+ ]);
+
+ $container = new ContainerBuilder();
+ $container->setParameter('enqueue.clients', ['default']);
+ $container->setParameter('enqueue.default_client', 'default');
+ $container->setDefinition('enqueue.client.default.route_collection', $routeCollection);
+ $container->register('aFooProcessor', $processor::class)
+ ->addTag('enqueue.topic_subscriber')
+ ;
+
+ $pass = new BuildTopicSubscriberRoutesPass();
+ $pass->process($container);
+
+ self::assertIsArray($routeCollection->getArgument(0));
+ $this->assertCount(2, $routeCollection->getArgument(0));
+
+ $this->assertEquals(
+ [
+ [
+ 'source' => 'fooTopic',
+ 'source_type' => 'enqueue.client.topic_route',
+ 'processor' => 'aCustomFooProcessorName',
+ 'processor_service_id' => 'aFooProcessor',
+ 'anOption' => 'aFooVal',
+ 'queue' => 'fooQueue',
+ 'prefix_queue' => false,
+ ],
+ [
+ 'source' => 'barTopic',
+ 'source_type' => 'enqueue.client.topic_route',
+ 'processor' => 'aCustomBarProcessorName',
+ 'processor_service_id' => 'aFooProcessor',
+ 'anOption' => 'aBarVal',
+ ],
+ ],
+ $routeCollection->getArgument(0)
+ );
+ }
+
+ private function createTopicSubscriberProcessor($topicSubscriberReturns = ['aTopic'])
+ {
+ $processor = new class implements Processor, TopicSubscriberInterface {
+ public static $return;
+
+ public function process(InteropMessage $message, Context $context)
+ {
+ return self::ACK;
+ }
+
+ public static function getSubscribedTopics()
+ {
+ return static::$return;
+ }
+ };
+
+ $processor::$return = $topicSubscriberReturns;
+
+ return $processor;
+ }
+}
diff --git a/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/ClientFactoryTest.php b/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/ClientFactoryTest.php
new file mode 100644
index 000000000..9f37dff47
--- /dev/null
+++ b/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/ClientFactoryTest.php
@@ -0,0 +1,54 @@
+assertClassFinal(ClientFactory::class);
+ }
+
+ public function testThrowIfEmptyNameGivenOnConstruction()
+ {
+ $this->expectException(\InvalidArgumentException::class);
+ $this->expectExceptionMessage('The name could not be empty.');
+
+ new ClientFactory('');
+ }
+
+ public function testShouldCreateDriverFromDsn()
+ {
+ $container = new ContainerBuilder();
+
+ $transport = new ClientFactory('default');
+
+ $serviceId = $transport->createDriver($container, ['dsn' => 'foo://bar/baz', 'foo' => 'fooVal']);
+
+ $this->assertEquals('enqueue.client.default.driver', $serviceId);
+
+ $this->assertTrue($container->hasDefinition('enqueue.client.default.driver'));
+
+ $this->assertNotEmpty($container->getDefinition('enqueue.client.default.driver')->getFactory());
+ $this->assertEquals(
+ [new Reference('enqueue.client.default.driver_factory'), 'create'],
+ $container->getDefinition('enqueue.client.default.driver')->getFactory())
+ ;
+ $this->assertEquals(
+ [
+ new Reference('enqueue.transport.default.connection_factory'),
+ new Reference('enqueue.client.default.config'),
+ new Reference('enqueue.client.default.route_collection'),
+ ],
+ $container->getDefinition('enqueue.client.default.driver')->getArguments())
+ ;
+ }
+}
diff --git a/pkg/enqueue/Tests/Symfony/Client/FlushSpoolProducerListenerTest.php b/pkg/enqueue/Tests/Symfony/Client/FlushSpoolProducerListenerTest.php
index a1fe06e7a..539d332ee 100644
--- a/pkg/enqueue/Tests/Symfony/Client/FlushSpoolProducerListenerTest.php
+++ b/pkg/enqueue/Tests/Symfony/Client/FlushSpoolProducerListenerTest.php
@@ -23,7 +23,7 @@ public function testShouldSubscribeOnKernelTerminateEvent()
{
$events = FlushSpoolProducerListener::getSubscribedEvents();
- $this->assertInternalType('array', $events);
+ self::assertIsArray($events);
$this->assertArrayHasKey(KernelEvents::TERMINATE, $events);
$this->assertEquals('flushMessages', $events[KernelEvents::TERMINATE]);
@@ -33,17 +33,12 @@ public function testShouldSubscribeOnConsoleTerminateEvent()
{
$events = FlushSpoolProducerListener::getSubscribedEvents();
- $this->assertInternalType('array', $events);
+ self::assertIsArray($events);
$this->assertArrayHasKey(ConsoleEvents::TERMINATE, $events);
$this->assertEquals('flushMessages', $events[ConsoleEvents::TERMINATE]);
}
- public function testCouldBeConstructedWithSpoolProducerAsFirstArgument()
- {
- new FlushSpoolProducerListener($this->createSpoolProducerMock());
- }
-
public function testShouldFlushSpoolProducerOnFlushMessagesCall()
{
$producerMock = $this->createSpoolProducerMock();
@@ -58,7 +53,7 @@ public function testShouldFlushSpoolProducerOnFlushMessagesCall()
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|SpoolProducer
+ * @return \PHPUnit\Framework\MockObject\MockObject|SpoolProducer
*/
private function createSpoolProducerMock()
{
diff --git a/pkg/enqueue/Tests/Symfony/Client/Meta/QueuesCommandTest.php b/pkg/enqueue/Tests/Symfony/Client/Meta/QueuesCommandTest.php
deleted file mode 100644
index f0720c7cb..000000000
--- a/pkg/enqueue/Tests/Symfony/Client/Meta/QueuesCommandTest.php
+++ /dev/null
@@ -1,109 +0,0 @@
-assertClassExtends(Command::class, QueuesCommand::class);
- }
-
- public function testCouldBeConstructedWithQueueMetaRegistryAsFirstArgument()
- {
- new QueuesCommand($this->createQueueMetaRegistryStub());
- }
-
- public function testShouldHaveCommandName()
- {
- $command = new QueuesCommand($this->createQueueMetaRegistryStub());
-
- $this->assertEquals('enqueue:queues', $command->getName());
- }
-
- public function testShouldHaveCommandAliases()
- {
- $command = new QueuesCommand($this->createQueueMetaRegistryStub());
-
- $this->assertEquals(['enq:m:q', 'debug:enqueue:queues'], $command->getAliases());
- }
-
- public function testShouldShowMessageFoundZeroDestinationsIfAnythingInRegistry()
- {
- $command = new QueuesCommand($this->createQueueMetaRegistryStub());
-
- $output = $this->executeCommand($command);
-
- $this->assertContains('Found 0 destinations', $output);
- }
-
- public function testShouldShowMessageFoundTwoDestinations()
- {
- $command = new QueuesCommand($this->createQueueMetaRegistryStub([
- new QueueMeta('aClientName', 'aDestinationName'),
- new QueueMeta('anotherClientName', 'anotherDestinationName'),
- ]));
-
- $output = $this->executeCommand($command);
-
- $this->assertContains('Found 2 destinations', $output);
- }
-
- public function testShouldShowInfoAboutDestinations()
- {
- $command = new QueuesCommand($this->createQueueMetaRegistryStub([
- new QueueMeta('aFooClientName', 'aFooDestinationName', ['fooSubscriber']),
- new QueueMeta('aBarClientName', 'aBarDestinationName', ['barSubscriber']),
- ]));
-
- $output = $this->executeCommand($command);
-
- $this->assertContains('aFooClientName', $output);
- $this->assertContains('aFooDestinationName', $output);
- $this->assertContains('fooSubscriber', $output);
- $this->assertContains('aBarClientName', $output);
- $this->assertContains('aBarDestinationName', $output);
- $this->assertContains('barSubscriber', $output);
- }
-
- /**
- * @param Command $command
- * @param string[] $arguments
- *
- * @return string
- */
- protected function executeCommand(Command $command, array $arguments = [])
- {
- $tester = new CommandTester($command);
- $tester->execute($arguments);
-
- return $tester->getDisplay();
- }
-
- /**
- * @param mixed $destinations
- *
- * @return \PHPUnit_Framework_MockObject_MockObject|QueueMetaRegistry
- */
- protected function createQueueMetaRegistryStub($destinations = [])
- {
- $registryMock = $this->createMock(QueueMetaRegistry::class);
- $registryMock
- ->expects($this->any())
- ->method('getQueuesMeta')
- ->willReturn($destinations)
- ;
-
- return $registryMock;
- }
-}
diff --git a/pkg/enqueue/Tests/Symfony/Client/Meta/TopicsCommandTest.php b/pkg/enqueue/Tests/Symfony/Client/Meta/TopicsCommandTest.php
deleted file mode 100644
index 4efdd2f66..000000000
--- a/pkg/enqueue/Tests/Symfony/Client/Meta/TopicsCommandTest.php
+++ /dev/null
@@ -1,91 +0,0 @@
-assertClassExtends(Command::class, TopicsCommand::class);
- }
-
- public function testCouldBeConstructedWithTopicMetaRegistryAsFirstArgument()
- {
- new TopicsCommand(new TopicMetaRegistry([]));
- }
-
- public function testShouldHaveCommandName()
- {
- $command = new TopicsCommand(new TopicMetaRegistry([]));
-
- $this->assertEquals('enqueue:topics', $command->getName());
- }
-
- public function testShouldHaveCommandAliases()
- {
- $command = new TopicsCommand(new TopicMetaRegistry([]));
-
- $this->assertEquals(['enq:m:t', 'debug:enqueue:topics'], $command->getAliases());
- }
-
- public function testShouldShowMessageFoundZeroTopicsIfAnythingInRegistry()
- {
- $command = new TopicsCommand(new TopicMetaRegistry([]));
-
- $output = $this->executeCommand($command);
-
- $this->assertContains('Found 0 topics', $output);
- }
-
- public function testShouldShowMessageFoundTwoTopics()
- {
- $command = new TopicsCommand(new TopicMetaRegistry([
- 'fooTopic' => [],
- 'barTopic' => [],
- ]));
-
- $output = $this->executeCommand($command);
-
- $this->assertContains('Found 2 topics', $output);
- }
-
- public function testShouldShowInfoAboutTopics()
- {
- $command = new TopicsCommand(new TopicMetaRegistry([
- 'fooTopic' => ['description' => 'fooDescription', 'processors' => ['fooSubscriber']],
- 'barTopic' => ['description' => 'barDescription', 'processors' => ['barSubscriber']],
- ]));
-
- $output = $this->executeCommand($command);
-
- $this->assertContains('fooTopic', $output);
- $this->assertContains('fooDescription', $output);
- $this->assertContains('fooSubscriber', $output);
- $this->assertContains('barTopic', $output);
- $this->assertContains('barDescription', $output);
- $this->assertContains('barSubscriber', $output);
- }
-
- /**
- * @param Command $command
- * @param string[] $arguments
- *
- * @return string
- */
- protected function executeCommand(Command $command, array $arguments = [])
- {
- $tester = new CommandTester($command);
- $tester->execute($arguments);
-
- return $tester->getDisplay();
- }
-}
diff --git a/pkg/enqueue/Tests/Symfony/Client/Mock/SetupBrokerExtensionCommand.php b/pkg/enqueue/Tests/Symfony/Client/Mock/SetupBrokerExtensionCommand.php
index fe7a352a5..c21750592 100644
--- a/pkg/enqueue/Tests/Symfony/Client/Mock/SetupBrokerExtensionCommand.php
+++ b/pkg/enqueue/Tests/Symfony/Client/Mock/SetupBrokerExtensionCommand.php
@@ -3,8 +3,8 @@
namespace Enqueue\Tests\Symfony\Client\Mock;
use Enqueue\Client\Config;
-use Enqueue\Client\Meta\QueueMetaRegistry;
-use Enqueue\Null\Client\NullDriver;
+use Enqueue\Client\Driver\GenericDriver;
+use Enqueue\Client\RouteCollection;
use Enqueue\Null\NullContext;
use Enqueue\Symfony\Client\SetupBrokerExtensionCommandTrait;
use Symfony\Component\Console\Command\Command;
@@ -29,12 +29,14 @@ protected function configure()
$this->configureSetupBrokerExtension();
}
- protected function execute(InputInterface $input, OutputInterface $output)
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
- $this->extension = $this->getSetupBrokerExtension($input, new NullDriver(
+ $this->extension = $this->getSetupBrokerExtension($input, new GenericDriver(
new NullContext(),
Config::create(),
- new QueueMetaRegistry(Config::create(), [])
+ new RouteCollection([])
));
+
+ return 0;
}
}
diff --git a/pkg/enqueue/Tests/Symfony/Client/ProduceCommandTest.php b/pkg/enqueue/Tests/Symfony/Client/ProduceCommandTest.php
new file mode 100644
index 000000000..daa909175
--- /dev/null
+++ b/pkg/enqueue/Tests/Symfony/Client/ProduceCommandTest.php
@@ -0,0 +1,284 @@
+assertClassExtends(Command::class, ProduceCommand::class);
+ }
+
+ public function testShouldNotBeFinal()
+ {
+ $this->assertClassNotFinal(ProduceCommand::class);
+ }
+
+ public function testShouldHaveAsCommandAttributeWithCommandName()
+ {
+ $commandClass = ProduceCommand::class;
+
+ $reflectionClass = new \ReflectionClass($commandClass);
+
+ $attributes = $reflectionClass->getAttributes(AsCommand::class);
+
+ $this->assertNotEmpty($attributes, 'The command does not have the AsCommand attribute.');
+
+ // Get the first attribute instance (assuming there is only one AsCommand attribute)
+ $asCommandAttribute = $attributes[0];
+
+ // Verify the 'name' parameter value
+ $attributeInstance = $asCommandAttribute->newInstance();
+ $this->assertEquals('enqueue:produce', $attributeInstance->name, 'The command name is not set correctly in the AsCommand attribute.');
+ }
+
+ public function testShouldHaveExpectedOptions()
+ {
+ $command = new ProduceCommand($this->createMock(ContainerInterface::class), 'default');
+
+ $options = $command->getDefinition()->getOptions();
+ $this->assertCount(4, $options);
+ $this->assertArrayHasKey('client', $options);
+ $this->assertArrayHasKey('topic', $options);
+ $this->assertArrayHasKey('command', $options);
+ $this->assertArrayHasKey('header', $options);
+ }
+
+ public function testShouldHaveExpectedAttributes()
+ {
+ $command = new ProduceCommand($this->createMock(ContainerInterface::class), 'default');
+
+ $arguments = $command->getDefinition()->getArguments();
+ $this->assertCount(1, $arguments);
+
+ $this->assertArrayHasKey('message', $arguments);
+ }
+
+ public function testThrowIfNeitherTopicNorCommandOptionsAreSet()
+ {
+ $producerMock = $this->createProducerMock();
+ $producerMock
+ ->expects($this->never())
+ ->method('sendEvent')
+ ;
+ $producerMock
+ ->expects($this->never())
+ ->method('sendCommand')
+ ;
+
+ $command = new ProduceCommand(new Container([
+ 'enqueue.client.default.producer' => $producerMock,
+ ]), 'default');
+
+ $tester = new CommandTester($command);
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Either topic or command option should be set, none is set.');
+ $tester->execute([
+ 'message' => 'theMessage',
+ ]);
+ }
+
+ public function testThrowIfBothTopicAndCommandOptionsAreSet()
+ {
+ $producerMock = $this->createProducerMock();
+ $producerMock
+ ->expects($this->never())
+ ->method('sendEvent')
+ ;
+ $producerMock
+ ->expects($this->never())
+ ->method('sendCommand')
+ ;
+
+ $command = new ProduceCommand(new Container([
+ 'enqueue.client.default.producer' => $producerMock,
+ ]), 'default');
+
+ $tester = new CommandTester($command);
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Either topic or command option should be set, both are set.');
+ $tester->execute([
+ 'message' => 'theMessage',
+ '--topic' => 'theTopic',
+ '--command' => 'theCommand',
+ ]);
+ }
+
+ public function testShouldSendEventToDefaultTransport()
+ {
+ $header = 'Content-Type: text/plain';
+ $payload = 'theMessage';
+
+ $producerMock = $this->createProducerMock();
+ $producerMock
+ ->expects($this->once())
+ ->method('sendEvent')
+ ->with('theTopic', new Message($payload, [], [$header]))
+ ;
+ $producerMock
+ ->expects($this->never())
+ ->method('sendCommand')
+ ;
+
+ $command = new ProduceCommand(new Container([
+ 'enqueue.client.default.producer' => $producerMock,
+ ]), 'default');
+
+ $tester = new CommandTester($command);
+ $tester->execute([
+ 'message' => $payload,
+ '--header' => $header,
+ '--topic' => 'theTopic',
+ ]);
+ }
+
+ public function testShouldSendCommandToDefaultTransport()
+ {
+ $producerMock = $this->createProducerMock();
+ $producerMock
+ ->expects($this->once())
+ ->method('sendCommand')
+ ->with('theCommand', 'theMessage')
+ ;
+ $producerMock
+ ->expects($this->never())
+ ->method('sendEvent')
+ ;
+
+ $command = new ProduceCommand(new Container([
+ 'enqueue.client.default.producer' => $producerMock,
+ ]), 'default');
+
+ $tester = new CommandTester($command);
+ $tester->execute([
+ 'message' => 'theMessage',
+ '--command' => 'theCommand',
+ ]);
+ }
+
+ public function testShouldSendEventToFooTransport()
+ {
+ $header = 'Content-Type: text/plain';
+ $payload = 'theMessage';
+
+ $defaultProducerMock = $this->createProducerMock();
+ $defaultProducerMock
+ ->expects($this->never())
+ ->method('sendEvent')
+ ;
+ $defaultProducerMock
+ ->expects($this->never())
+ ->method('sendCommand')
+ ;
+
+ $fooProducerMock = $this->createProducerMock();
+ $fooProducerMock
+ ->expects($this->once())
+ ->method('sendEvent')
+ ->with('theTopic', new Message($payload, [], [$header]))
+ ;
+ $fooProducerMock
+ ->expects($this->never())
+ ->method('sendCommand')
+ ;
+
+ $command = new ProduceCommand(new Container([
+ 'enqueue.client.default.producer' => $defaultProducerMock,
+ 'enqueue.client.foo.producer' => $fooProducerMock,
+ ]), 'default');
+
+ $tester = new CommandTester($command);
+ $tester->execute([
+ 'message' => $payload,
+ '--header' => $header,
+ '--topic' => 'theTopic',
+ '--client' => 'foo',
+ ]);
+ }
+
+ public function testShouldSendCommandToFooTransport()
+ {
+ $defaultProducerMock = $this->createProducerMock();
+ $defaultProducerMock
+ ->expects($this->never())
+ ->method('sendEvent')
+ ;
+ $defaultProducerMock
+ ->expects($this->never())
+ ->method('sendCommand')
+ ;
+
+ $fooProducerMock = $this->createProducerMock();
+ $fooProducerMock
+ ->expects($this->once())
+ ->method('sendCommand')
+ ->with('theCommand', 'theMessage')
+ ;
+ $fooProducerMock
+ ->expects($this->never())
+ ->method('sendEvent')
+ ;
+
+ $command = new ProduceCommand(new Container([
+ 'enqueue.client.default.producer' => $defaultProducerMock,
+ 'enqueue.client.foo.producer' => $fooProducerMock,
+ ]), 'default');
+
+ $tester = new CommandTester($command);
+ $tester->execute([
+ 'message' => 'theMessage',
+ '--command' => 'theCommand',
+ '--client' => 'foo',
+ ]);
+ }
+
+ public function testThrowIfClientNotFound()
+ {
+ $defaultProducerMock = $this->createProducerMock();
+ $defaultProducerMock
+ ->expects($this->never())
+ ->method('sendEvent')
+ ;
+ $defaultProducerMock
+ ->expects($this->never())
+ ->method('sendCommand')
+ ;
+
+ $command = new ProduceCommand(new Container([
+ 'enqueue.client.default.producer' => $defaultProducerMock,
+ ]), 'default');
+
+ $tester = new CommandTester($command);
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Client "bar" is not supported.');
+ $tester->execute([
+ 'message' => 'theMessage',
+ '--command' => 'theCommand',
+ '--client' => 'bar',
+ ]);
+ }
+
+ /**
+ * @return \PHPUnit\Framework\MockObject\MockObject|ProducerInterface
+ */
+ private function createProducerMock()
+ {
+ return $this->createMock(ProducerInterface::class);
+ }
+}
diff --git a/pkg/enqueue/Tests/Symfony/Client/ProduceMessageCommandTest.php b/pkg/enqueue/Tests/Symfony/Client/ProduceMessageCommandTest.php
deleted file mode 100644
index 2cd80952e..000000000
--- a/pkg/enqueue/Tests/Symfony/Client/ProduceMessageCommandTest.php
+++ /dev/null
@@ -1,75 +0,0 @@
-createProducerMock());
- }
-
- public function testShouldHaveCommandName()
- {
- $command = new ProduceMessageCommand($this->createProducerMock());
-
- $this->assertEquals('enqueue:produce', $command->getName());
- }
-
- public function testShouldHaveCommandAliases()
- {
- $command = new ProduceMessageCommand($this->createProducerMock());
-
- $this->assertEquals(['enq:p'], $command->getAliases());
- }
-
- public function testShouldHaveExpectedOptions()
- {
- $command = new ProduceMessageCommand($this->createProducerMock());
-
- $options = $command->getDefinition()->getOptions();
- $this->assertCount(0, $options);
- }
-
- public function testShouldHaveExpectedAttributes()
- {
- $command = new ProduceMessageCommand($this->createProducerMock());
-
- $arguments = $command->getDefinition()->getArguments();
- $this->assertCount(2, $arguments);
-
- $this->assertArrayHasKey('topic', $arguments);
- $this->assertArrayHasKey('message', $arguments);
- }
-
- public function testShouldExecuteConsumptionAndUseDefaultQueueName()
- {
- $producerMock = $this->createProducerMock();
- $producerMock
- ->expects($this->once())
- ->method('sendEvent')
- ->with('theTopic', 'theMessage')
- ;
-
- $command = new ProduceMessageCommand($producerMock);
-
- $tester = new CommandTester($command);
- $tester->execute([
- 'topic' => 'theTopic',
- 'message' => 'theMessage',
- ]);
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject|ProducerInterface
- */
- private function createProducerMock()
- {
- return $this->createMock(ProducerInterface::class);
- }
-}
diff --git a/pkg/enqueue/Tests/Symfony/Client/RoutesCommandTest.php b/pkg/enqueue/Tests/Symfony/Client/RoutesCommandTest.php
new file mode 100644
index 000000000..89bd7f745
--- /dev/null
+++ b/pkg/enqueue/Tests/Symfony/Client/RoutesCommandTest.php
@@ -0,0 +1,366 @@
+assertClassExtends(Command::class, RoutesCommand::class);
+ }
+
+ public function testShouldNotBeFinal()
+ {
+ $this->assertClassNotFinal(RoutesCommand::class);
+ }
+
+ public function testShouldHaveAsCommandAttributeWithCommandName()
+ {
+ $commandClass = RoutesCommand::class;
+
+ $reflectionClass = new \ReflectionClass($commandClass);
+
+ $attributes = $reflectionClass->getAttributes(AsCommand::class);
+
+ $this->assertNotEmpty($attributes, 'The command does not have the AsCommand attribute.');
+
+ // Get the first attribute instance (assuming there is only one AsCommand attribute)
+ $asCommandAttribute = $attributes[0];
+
+ // Verify the 'name' parameter value
+ $attributeInstance = $asCommandAttribute->newInstance();
+ $this->assertEquals('enqueue:routes', $attributeInstance->name, 'The command name is not set correctly in the AsCommand attribute.');
+ }
+
+ public function testShouldHaveCommandAliases()
+ {
+ $command = new RoutesCommand($this->createMock(ContainerInterface::class), 'default');
+
+ $this->assertEquals(['debug:enqueue:routes'], $command->getAliases());
+ }
+
+ public function testShouldHaveExpectedOptions()
+ {
+ $command = new RoutesCommand($this->createMock(ContainerInterface::class), 'default');
+
+ $options = $command->getDefinition()->getOptions();
+ $this->assertCount(2, $options);
+
+ $this->assertArrayHasKey('show-route-options', $options);
+ $this->assertArrayHasKey('client', $options);
+ }
+
+ public function testShouldHaveExpectedAttributes()
+ {
+ $command = new RoutesCommand($this->createMock(ContainerInterface::class), 'default');
+
+ $arguments = $command->getDefinition()->getArguments();
+ $this->assertCount(0, $arguments);
+ }
+
+ public function testShouldOutputEmptyRouteCollection()
+ {
+ $routeCollection = new RouteCollection([]);
+
+ $command = new RoutesCommand(new Container([
+ 'enqueue.client.default.driver' => $this->createDriverStub(Config::create(), $routeCollection),
+ ]), 'default');
+
+ $tester = new CommandTester($command);
+
+ $tester->execute([]);
+
+ $expectedOutput = <<<'OUTPUT'
+Found 0 routes
+
+
+OUTPUT;
+
+ $this->assertCommandOutput($expectedOutput, $tester);
+ }
+
+ public function testShouldUseFooDriver()
+ {
+ $routeCollection = new RouteCollection([
+ new Route('fooTopic', Route::TOPIC, 'processor'),
+ ]);
+
+ $defaultDriverMock = $this->createMock(DriverInterface::class);
+ $defaultDriverMock
+ ->expects($this->never())
+ ->method('getConfig')
+ ;
+
+ $defaultDriverMock
+ ->expects($this->never())
+ ->method('getRouteCollection')
+ ;
+
+ $fooDriverMock = $this->createDriverStub(Config::create(), $routeCollection);
+
+ $command = new RoutesCommand(new Container([
+ 'enqueue.client.default.driver' => $defaultDriverMock,
+ 'enqueue.client.foo.driver' => $fooDriverMock,
+ ]), 'default');
+
+ $tester = new CommandTester($command);
+ $tester->execute([
+ '--client' => 'foo',
+ ]);
+
+ $this->assertStringContainsString('Found 1 routes', $tester->getDisplay());
+ }
+
+ public function testThrowIfClientNotFound()
+ {
+ $defaultDriverMock = $this->createMock(DriverInterface::class);
+ $defaultDriverMock
+ ->expects($this->never())
+ ->method('getConfig')
+ ;
+
+ $defaultDriverMock
+ ->expects($this->never())
+ ->method('getRouteCollection')
+ ;
+
+ $command = new RoutesCommand(new Container([
+ 'enqueue.client.default.driver' => $defaultDriverMock,
+ ]), 'default');
+
+ $tester = new CommandTester($command);
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Client "foo" is not supported.');
+ $tester->execute([
+ '--client' => 'foo',
+ ]);
+ }
+
+ public function testShouldOutputTopicRouteInfo()
+ {
+ $routeCollection = new RouteCollection([
+ new Route('fooTopic', Route::TOPIC, 'processor'),
+ new Route('barTopic', Route::TOPIC, 'processor'),
+ ]);
+
+ $command = new RoutesCommand(new Container([
+ 'enqueue.client.default.driver' => $this->createDriverStub(Config::create(), $routeCollection),
+ ]), 'default');
+
+ $tester = new CommandTester($command);
+
+ $tester->execute([]);
+
+ $expectedOutput = <<<'OUTPUT'
+Found 2 routes
+
++-------+----------+--------------------+-----------+----------+
+| Type | Source | Queue | Processor | Options |
++-------+----------+--------------------+-----------+----------+
+| topic | fooTopic | default (prefixed) | processor | (hidden) |
+| topic | barTopic | default (prefixed) | processor | (hidden) |
++-------+----------+--------------------+-----------+----------+
+
+OUTPUT;
+
+ $this->assertCommandOutput($expectedOutput, $tester);
+ }
+
+ public function testShouldOutputCommandRouteInfo()
+ {
+ $routeCollection = new RouteCollection([
+ new Route('fooCommand', Route::COMMAND, 'processor', ['foo' => 'fooVal', 'bar' => 'barVal']),
+ new Route('barCommand', Route::COMMAND, 'processor', ['foo' => 'fooVal', 'bar' => 'barVal']),
+ ]);
+
+ $command = new RoutesCommand(new Container([
+ 'enqueue.client.default.driver' => $this->createDriverStub(Config::create(), $routeCollection),
+ ]), 'default');
+
+ $tester = new CommandTester($command);
+
+ $tester->execute([]);
+
+ $expectedOutput = <<<'OUTPUT'
+Found 2 routes
+
++---------+------------+--------------------+-----------+----------+
+| Type | Source | Queue | Processor | Options |
++---------+------------+--------------------+-----------+----------+
+| command | fooCommand | default (prefixed) | processor | (hidden) |
+| command | barCommand | default (prefixed) | processor | (hidden) |
++---------+------------+--------------------+-----------+----------+
+
+OUTPUT;
+
+ $this->assertCommandOutput($expectedOutput, $tester);
+ }
+
+ public function testShouldCorrectlyOutputPrefixedCustomQueue()
+ {
+ $routeCollection = new RouteCollection([
+ new Route('fooCommand', Route::COMMAND, 'processor', ['queue' => 'foo']),
+ new Route('barTopic', Route::TOPIC, 'processor', ['queue' => 'bar']),
+ ]);
+
+ $command = new RoutesCommand(new Container([
+ 'enqueue.client.default.driver' => $this->createDriverStub(Config::create(), $routeCollection),
+ ]), 'default');
+
+ $tester = new CommandTester($command);
+
+ $exitCode = $tester->execute([]);
+ $this->assertSame(0, $exitCode);
+
+ $expectedOutput = <<<'OUTPUT'
+Found 2 routes
+
++---------+------------+----------------+-----------+----------+
+| Type | Source | Queue | Processor | Options |
++---------+------------+----------------+-----------+----------+
+| topic | barTopic | bar (prefixed) | processor | (hidden) |
+| command | fooCommand | foo (prefixed) | processor | (hidden) |
++---------+------------+----------------+-----------+----------+
+
+OUTPUT;
+
+ $this->assertCommandOutput($expectedOutput, $tester);
+ }
+
+ public function testShouldCorrectlyOutputNotPrefixedCustomQueue()
+ {
+ $routeCollection = new RouteCollection([
+ new Route('fooCommand', Route::COMMAND, 'processor', ['queue' => 'foo', 'prefix_queue' => false]),
+ new Route('barTopic', Route::TOPIC, 'processor', ['queue' => 'bar', 'prefix_queue' => false]),
+ ]);
+
+ $command = new RoutesCommand(new Container([
+ 'enqueue.client.default.driver' => $this->createDriverStub(Config::create(), $routeCollection),
+ ]), 'default');
+
+ $tester = new CommandTester($command);
+
+ $tester->execute([]);
+
+ $expectedOutput = <<<'OUTPUT'
+Found 2 routes
+
++---------+------------+-------------+-----------+----------+
+| Type | Source | Queue | Processor | Options |
++---------+------------+-------------+-----------+----------+
+| topic | barTopic | bar (as is) | processor | (hidden) |
+| command | fooCommand | foo (as is) | processor | (hidden) |
++---------+------------+-------------+-----------+----------+
+
+OUTPUT;
+
+ $this->assertCommandOutput($expectedOutput, $tester);
+ }
+
+ public function testShouldCorrectlyOutputExternalRoute()
+ {
+ $routeCollection = new RouteCollection([
+ new Route('fooCommand', Route::COMMAND, 'processor', ['external' => true]),
+ new Route('barTopic', Route::TOPIC, 'processor', ['external' => true]),
+ ]);
+
+ $command = new RoutesCommand(new Container([
+ 'enqueue.client.default.driver' => $this->createDriverStub(Config::create(), $routeCollection),
+ ]), 'default');
+
+ $tester = new CommandTester($command);
+
+ $tester->execute([]);
+
+ $expectedOutput = <<