diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..4c397be --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,32 @@ +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" + with: + composer-options: "--prefer-source" + + - run: vendor/bin/phpunit --exclude-group=functional diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 880a93f..0000000 --- a/.travis.yml +++ /dev/null @@ -1,28 +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 --prefer-source - -script: - - vendor/bin/phpunit --exclude-group=functional diff --git a/Consumption/Extension/DoctrineClearIdentityMapExtension.php b/Consumption/Extension/DoctrineClearIdentityMapExtension.php index 9750fb3..d02b9a2 100644 --- a/Consumption/Extension/DoctrineClearIdentityMapExtension.php +++ b/Consumption/Extension/DoctrineClearIdentityMapExtension.php @@ -2,32 +2,23 @@ namespace Enqueue\Bundle\Consumption\Extension; -use Enqueue\Consumption\Context; -use Enqueue\Consumption\EmptyExtensionTrait; -use Enqueue\Consumption\ExtensionInterface; -use Symfony\Bridge\Doctrine\RegistryInterface; +use Doctrine\Persistence\ManagerRegistry; +use Enqueue\Consumption\Context\MessageReceived; +use Enqueue\Consumption\MessageReceivedExtensionInterface; -class DoctrineClearIdentityMapExtension implements ExtensionInterface +class DoctrineClearIdentityMapExtension implements MessageReceivedExtensionInterface { - use EmptyExtensionTrait; - /** - * @var RegistryInterface + * @var ManagerRegistry */ protected $registry; - /** - * @param RegistryInterface $registry - */ - public function __construct(RegistryInterface $registry) + public function __construct(ManagerRegistry $registry) { $this->registry = $registry; } - /** - * {@inheritdoc} - */ - public function onPreReceived(Context $context) + public function onMessageReceived(MessageReceived $context): void { foreach ($this->registry->getManagers() as $name => $manager) { $context->getLogger()->debug(sprintf( diff --git a/Consumption/Extension/DoctrineClosedEntityManagerExtension.php b/Consumption/Extension/DoctrineClosedEntityManagerExtension.php new file mode 100644 index 0000000..e5ad0c6 --- /dev/null +++ b/Consumption/Extension/DoctrineClosedEntityManagerExtension.php @@ -0,0 +1,65 @@ +registry = $registry; + } + + public function onPreConsume(PreConsume $context): void + { + if ($this->shouldBeStopped($context->getLogger())) { + $context->interruptExecution(); + } + } + + public function onPostConsume(PostConsume $context): void + { + if ($this->shouldBeStopped($context->getLogger())) { + $context->interruptExecution(); + } + } + + public function onPostMessageReceived(PostMessageReceived $context): void + { + if ($this->shouldBeStopped($context->getLogger())) { + $context->interruptExecution(); + } + } + + private function shouldBeStopped(LoggerInterface $logger): bool + { + foreach ($this->registry->getManagers() as $name => $manager) { + if (!$manager instanceof EntityManagerInterface || $manager->isOpen()) { + continue; + } + + $logger->debug(sprintf( + '[DoctrineClosedEntityManagerExtension] Interrupt execution as entity manager "%s" has been closed', + $name + )); + + return true; + } + + return false; + } +} diff --git a/Consumption/Extension/DoctrinePingConnectionExtension.php b/Consumption/Extension/DoctrinePingConnectionExtension.php index bbbed12..7fd9527 100644 --- a/Consumption/Extension/DoctrinePingConnectionExtension.php +++ b/Consumption/Extension/DoctrinePingConnectionExtension.php @@ -3,32 +3,23 @@ namespace Enqueue\Bundle\Consumption\Extension; use Doctrine\DBAL\Connection; -use Enqueue\Consumption\Context; -use Enqueue\Consumption\EmptyExtensionTrait; -use Enqueue\Consumption\ExtensionInterface; -use Symfony\Bridge\Doctrine\RegistryInterface; +use Doctrine\Persistence\ManagerRegistry; +use Enqueue\Consumption\Context\MessageReceived; +use Enqueue\Consumption\MessageReceivedExtensionInterface; -class DoctrinePingConnectionExtension implements ExtensionInterface +class DoctrinePingConnectionExtension implements MessageReceivedExtensionInterface { - use EmptyExtensionTrait; - /** - * @var RegistryInterface + * @var ManagerRegistry */ protected $registry; - /** - * @param RegistryInterface $registry - */ - public function __construct(RegistryInterface $registry) + public function __construct(ManagerRegistry $registry) { $this->registry = $registry; } - /** - * {@inheritdoc} - */ - public function onPreReceived(Context $context) + public function onMessageReceived(MessageReceived $context): void { /** @var Connection $connection */ foreach ($this->registry->getConnections() as $connection) { @@ -36,7 +27,7 @@ public function onPreReceived(Context $context) continue; } - if ($connection->ping()) { + if ($this->ping($connection)) { continue; } @@ -52,4 +43,23 @@ public function onPreReceived(Context $context) ); } } + + private function ping(Connection $connection): bool + { + set_error_handler(static function (int $severity, string $message, string $file, int $line): bool { + throw new \ErrorException($message, $severity, $severity, $file, $line); + }); + + try { + $dummySelectSQL = $connection->getDatabasePlatform()->getDummySelectSQL(); + + $connection->executeQuery($dummySelectSQL); + + return true; + } catch (\Throwable $exception) { + return false; + } finally { + restore_error_handler(); + } + } } diff --git a/Consumption/Extension/ResetServicesExtension.php b/Consumption/Extension/ResetServicesExtension.php new file mode 100644 index 0000000..0bf6421 --- /dev/null +++ b/Consumption/Extension/ResetServicesExtension.php @@ -0,0 +1,27 @@ +resetter = $resetter; + } + + public function onPostMessageReceived(PostMessageReceived $context): void + { + $context->getLogger()->debug('[ResetServicesExtension] Resetting services.'); + + $this->resetter->reset(); + } +} diff --git a/DependencyInjection/Compiler/AddTopicMetaPass.php b/DependencyInjection/Compiler/AddTopicMetaPass.php deleted file mode 100644 index 45becab..0000000 --- a/DependencyInjection/Compiler/AddTopicMetaPass.php +++ /dev/null @@ -1,66 +0,0 @@ -topicsMeta = []; - } - - /** - * @param string $topicName - * @param string $topicDescription - * @param array $topicSubscribers - * - * @return $this - */ - public function add($topicName, $topicDescription = '', array $topicSubscribers = []) - { - $this->topicsMeta[$topicName] = []; - - if ($topicDescription) { - $this->topicsMeta[$topicName]['description'] = $topicDescription; - } - - if ($topicSubscribers) { - $this->topicsMeta[$topicName]['processors'] = $topicSubscribers; - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function process(ContainerBuilder $container) - { - $metaRegistryId = TopicMetaRegistry::class; - - if (false == $container->hasDefinition($metaRegistryId)) { - return; - } - - $metaRegistry = $container->getDefinition($metaRegistryId); - - $metaRegistry->replaceArgument(0, array_merge_recursive($metaRegistry->getArgument(0), $this->topicsMeta)); - } - - /** - * @return static - */ - public static function create() - { - return new static(); - } -} diff --git a/DependencyInjection/Compiler/BuildClientExtensionsPass.php b/DependencyInjection/Compiler/BuildClientExtensionsPass.php deleted file mode 100644 index 5f83e83..0000000 --- a/DependencyInjection/Compiler/BuildClientExtensionsPass.php +++ /dev/null @@ -1,40 +0,0 @@ -hasDefinition('enqueue.client.extensions')) { - return; - } - - $tags = $container->findTaggedServiceIds('enqueue.client.extension'); - - $groupByPriority = []; - foreach ($tags as $serviceId => $tagAttributes) { - foreach ($tagAttributes as $tagAttribute) { - $priority = isset($tagAttribute['priority']) ? (int) $tagAttribute['priority'] : 0; - - $groupByPriority[$priority][] = new Reference($serviceId); - } - } - - krsort($groupByPriority, SORT_NUMERIC); - - $flatExtensions = []; - foreach ($groupByPriority as $extension) { - $flatExtensions = array_merge($flatExtensions, $extension); - } - - $container->getDefinition('enqueue.client.extensions')->replaceArgument(0, $flatExtensions); - } -} diff --git a/DependencyInjection/Compiler/BuildClientRoutingPass.php b/DependencyInjection/Compiler/BuildClientRoutingPass.php deleted file mode 100644 index 3511a3a..0000000 --- a/DependencyInjection/Compiler/BuildClientRoutingPass.php +++ /dev/null @@ -1,47 +0,0 @@ -hasDefinition($routerId)) { - return; - } - - $events = []; - $commands = []; - foreach ($container->findTaggedServiceIds($processorTagName) as $serviceId => $tagAttributes) { - $subscriptions = $this->extractSubscriptions($container, $serviceId, $tagAttributes); - - foreach ($subscriptions as $subscription) { - if (Config::COMMAND_TOPIC === $subscription['topicName']) { - $commands[$subscription['processorName']] = $subscription['queueName']; - } else { - $events[$subscription['topicName']][] = [ - $subscription['processorName'], - $subscription['queueName'], - ]; - } - } - } - - $router = $container->getDefinition($routerId); - $router->replaceArgument(1, $events); - $router->replaceArgument(2, $commands); - } -} diff --git a/DependencyInjection/Compiler/BuildConsumptionExtensionsPass.php b/DependencyInjection/Compiler/BuildConsumptionExtensionsPass.php deleted file mode 100644 index 20f2a38..0000000 --- a/DependencyInjection/Compiler/BuildConsumptionExtensionsPass.php +++ /dev/null @@ -1,36 +0,0 @@ -findTaggedServiceIds('enqueue.consumption.extension'); - - $groupByPriority = []; - foreach ($tags as $serviceId => $tagAttributes) { - foreach ($tagAttributes as $tagAttribute) { - $priority = isset($tagAttribute['priority']) ? (int) $tagAttribute['priority'] : 0; - - $groupByPriority[$priority][] = new Reference($serviceId); - } - } - - krsort($groupByPriority, SORT_NUMERIC); - - $flatExtensions = []; - foreach ($groupByPriority as $extension) { - $flatExtensions = array_merge($flatExtensions, $extension); - } - - $container->getDefinition('enqueue.consumption.extensions')->replaceArgument(0, $flatExtensions); - } -} diff --git a/DependencyInjection/Compiler/BuildExclusiveCommandsExtensionPass.php b/DependencyInjection/Compiler/BuildExclusiveCommandsExtensionPass.php deleted file mode 100644 index 3b0d906..0000000 --- a/DependencyInjection/Compiler/BuildExclusiveCommandsExtensionPass.php +++ /dev/null @@ -1,49 +0,0 @@ -hasDefinition($extensionId)) { - return; - } - - $queueMetaRegistry = $container->getDefinition($extensionId); - - $queueNameToProcessorNameMap = []; - foreach ($container->findTaggedServiceIds($processorTagName) as $serviceId => $tagAttributes) { - $subscriptions = $this->extractSubscriptions($container, $serviceId, $tagAttributes); - - foreach ($subscriptions as $subscription) { - if (Config::COMMAND_TOPIC != $subscription['topicName']) { - continue; - } - - if (false == isset($subscription['exclusive']) || false === $subscription['exclusive']) { - continue; - } - - if (false == $subscription['queueNameHardcoded']) { - throw new \LogicException('The exclusive command could be used only with queueNameHardcoded attribute set to true.'); - } - - $queueNameToProcessorNameMap[$subscription['queueName']] = $subscription['processorName']; - } - } - - $queueMetaRegistry->replaceArgument(0, $queueNameToProcessorNameMap); - } -} diff --git a/DependencyInjection/Compiler/BuildProcessorRegistryPass.php b/DependencyInjection/Compiler/BuildProcessorRegistryPass.php deleted file mode 100644 index ffff5b4..0000000 --- a/DependencyInjection/Compiler/BuildProcessorRegistryPass.php +++ /dev/null @@ -1,36 +0,0 @@ -hasDefinition($processorRegistryId)) { - return; - } - - $processorIds = []; - foreach ($container->findTaggedServiceIds($processorTagName) as $serviceId => $tagAttributes) { - $subscriptions = $this->extractSubscriptions($container, $serviceId, $tagAttributes); - - foreach ($subscriptions as $subscription) { - $processorIds[$subscription['processorName']] = $serviceId; - } - } - - $processorRegistryDef = $container->getDefinition($processorRegistryId); - $processorRegistryDef->setArguments([$processorIds]); - } -} diff --git a/DependencyInjection/Compiler/BuildQueueMetaRegistryPass.php b/DependencyInjection/Compiler/BuildQueueMetaRegistryPass.php deleted file mode 100644 index 5e82f32..0000000 --- a/DependencyInjection/Compiler/BuildQueueMetaRegistryPass.php +++ /dev/null @@ -1,41 +0,0 @@ -hasDefinition($queueMetaRegistryId)) { - return; - } - - $queueMetaRegistry = $container->getDefinition($queueMetaRegistryId); - - $configs = []; - foreach ($container->findTaggedServiceIds($processorTagName) as $serviceId => $tagAttributes) { - $subscriptions = $this->extractSubscriptions($container, $serviceId, $tagAttributes); - - foreach ($subscriptions as $subscription) { - $configs[$subscription['queueName']]['processors'][] = $subscription['processorName']; - - if ($subscription['queueNameHardcoded']) { - $configs[$subscription['queueName']]['transportName'] = $subscription['queueName']; - } - } - } - - $queueMetaRegistry->replaceArgument(1, $configs); - } -} diff --git a/DependencyInjection/Compiler/BuildTopicMetaSubscribersPass.php b/DependencyInjection/Compiler/BuildTopicMetaSubscribersPass.php deleted file mode 100644 index 2f5195f..0000000 --- a/DependencyInjection/Compiler/BuildTopicMetaSubscribersPass.php +++ /dev/null @@ -1,40 +0,0 @@ -hasDefinition(TopicMetaRegistry::class)) { - return; - } - - $topicsSubscribers = []; - foreach ($container->findTaggedServiceIds($processorTagName) as $serviceId => $tagAttributes) { - $subscriptions = $this->extractSubscriptions($container, $serviceId, $tagAttributes); - - foreach ($subscriptions as $subscription) { - $topicsSubscribers[$subscription['topicName']][] = $subscription['processorName']; - } - } - - $addTopicMetaPass = AddTopicMetaPass::create(); - foreach ($topicsSubscribers as $topicName => $subscribers) { - $addTopicMetaPass->add($topicName, '', $subscribers); - } - - $addTopicMetaPass->process($container); - } -} diff --git a/DependencyInjection/Compiler/ExtractProcessorTagSubscriptionsTrait.php b/DependencyInjection/Compiler/ExtractProcessorTagSubscriptionsTrait.php deleted file mode 100644 index 58fa576..0000000 --- a/DependencyInjection/Compiler/ExtractProcessorTagSubscriptionsTrait.php +++ /dev/null @@ -1,146 +0,0 @@ -getParameter(trim($value, '%')); - } catch (ParameterNotFoundException $e) { - return $value; - } - }; - - $processorClass = $container->getDefinition($processorServiceId)->getClass(); - if (false == class_exists($processorClass)) { - throw new \LogicException(sprintf('The class "%s" could not be found.', $processorClass)); - } - - $defaultQueueName = $resolve($container->getParameter('enqueue.client.default_queue_name')); - $subscriptionPrototype = [ - 'topicName' => null, - 'queueName' => null, - 'queueNameHardcoded' => false, - 'processorName' => null, - 'exclusive' => false, - ]; - - $data = []; - if (is_subclass_of($processorClass, CommandSubscriberInterface::class)) { - /** @var CommandSubscriberInterface $processorClass */ - $params = $processorClass::getSubscribedCommand(); - if (is_string($params)) { - if (empty($params)) { - throw new \LogicException('The processor name (it is also the command name) must not be empty.'); - } - - $data[] = [ - 'topicName' => Config::COMMAND_TOPIC, - 'queueName' => $defaultQueueName, - 'queueNameHardcoded' => false, - 'processorName' => $params, - ]; - } elseif (is_array($params)) { - $params = array_replace($subscriptionPrototype, $params); - if (false == $processorName = $resolve($params['processorName'])) { - throw new \LogicException('The processor name (it is also the command name) must not be empty.'); - } - - $data[] = [ - 'topicName' => Config::COMMAND_TOPIC, - 'queueName' => $resolve($params['queueName']) ?: $defaultQueueName, - 'queueNameHardcoded' => $resolve($params['queueNameHardcoded']), - 'processorName' => $processorName, - 'exclusive' => array_key_exists('exclusive', $params) ? $params['exclusive'] : false, - ]; - } else { - throw new \LogicException(sprintf( - 'Command subscriber configuration is invalid. "%s"', - json_encode($processorClass::getSubscribedCommand()) - )); - } - } - - if (is_subclass_of($processorClass, TopicSubscriberInterface::class)) { - /** @var TopicSubscriberInterface $processorClass */ - $topics = $processorClass::getSubscribedTopics(); - if (!is_array($topics)) { - throw new \LogicException(sprintf( - 'Topic subscriber configuration is invalid for "%s::getSubscribedTopics()": expected array, got %s.', - $processorClass, - gettype($topics) - )); - } - - foreach ($topics as $topicName => $params) { - if (is_string($params)) { - $data[] = [ - 'topicName' => $params, - 'queueName' => $defaultQueueName, - 'queueNameHardcoded' => false, - 'processorName' => $processorServiceId, - ]; - } elseif (is_array($params)) { - $params = array_replace($subscriptionPrototype, $params); - - $data[] = [ - 'topicName' => $topicName, - 'queueName' => $resolve($params['queueName']) ?: $defaultQueueName, - 'queueNameHardcoded' => $resolve($params['queueNameHardcoded']), - 'processorName' => $resolve($params['processorName']) ?: $processorServiceId, - ]; - } else { - throw new \LogicException(sprintf( - 'Topic subscriber configuration is invalid for "%s::getSubscribedTopics()". "%s"', - $processorClass, - json_encode($processorClass::getSubscribedTopics()) - )); - } - } - } - - if (false == ( - is_subclass_of($processorClass, CommandSubscriberInterface::class) || - is_subclass_of($processorClass, TopicSubscriberInterface::class) - )) { - foreach ($tagAttributes as $tagAttribute) { - $tagAttribute = array_replace($subscriptionPrototype, $tagAttribute); - - if (false == $tagAttribute['topicName']) { - throw new \LogicException(sprintf('Topic name is not set on message processor tag but it is required. Service %s', $processorServiceId)); - } - - $data[] = [ - 'topicName' => $resolve($tagAttribute['topicName']), - 'queueName' => $resolve($tagAttribute['queueName']) ?: $defaultQueueName, - 'queueNameHardcoded' => $resolve($tagAttribute['queueNameHardcoded']), - 'processorName' => $resolve($tagAttribute['processorName']) ?: $processorServiceId, - 'exclusive' => Config::COMMAND_TOPIC == $resolve($tagAttribute['topicName']) && - array_key_exists('exclusive', $tagAttribute) ? $tagAttribute['exclusive'] : false, - ]; - } - } - - return $data; - } -} diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 1db513e..733849d 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -2,84 +2,118 @@ namespace Enqueue\Bundle\DependencyInjection; -use Enqueue\Client\Config; -use Enqueue\Client\RouterProcessor; -use Enqueue\Symfony\TransportFactoryInterface; +use Enqueue\AsyncCommand\RunCommandProcessor; +use Enqueue\AsyncEventDispatcher\DependencyInjection\AsyncEventDispatcherExtension; +use Enqueue\JobQueue\Job; +use Enqueue\Monitoring\Symfony\DependencyInjection\MonitoringFactory; +use Enqueue\Symfony\Client\DependencyInjection\ClientFactory; +use Enqueue\Symfony\DependencyInjection\TransportFactory; +use Enqueue\Symfony\MissingComponentFactory; +use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; -class Configuration implements ConfigurationInterface +final class Configuration implements ConfigurationInterface { private $debug; - /** - * @var TransportFactoryInterface[] - */ - private $factories; - - /** - * @param TransportFactoryInterface[] $factories - * @param bool $debug - */ - public function __construct(array $factories, $debug) + public function __construct(bool $debug) { - $this->factories = $factories; $this->debug = $debug; } - /** - * {@inheritdoc} - */ - public function getConfigTreeBuilder() + public function getConfigTreeBuilder(): TreeBuilder { - $tb = new TreeBuilder(); - $rootNode = $tb->root('enqueue'); + if (method_exists(TreeBuilder::class, 'getRootNode')) { + $tb = new TreeBuilder('enqueue'); + $rootNode = $tb->getRootNode(); + } else { + $tb = new TreeBuilder(); + $rootNode = $tb->root('enqueue'); + } - $transportChildren = $rootNode->children() - ->arrayNode('transport')->isRequired()->children(); + $rootNode + ->requiresAtLeastOneElement() + ->useAttributeAsKey('key') + ->arrayPrototype() + ->children() + ->append(TransportFactory::getConfiguration()) + ->append(TransportFactory::getQueueConsumerConfiguration()) + ->append(ClientFactory::getConfiguration($this->debug)) + ->append($this->getMonitoringConfiguration()) + ->append($this->getAsyncCommandsConfiguration()) + ->append($this->getJobConfiguration()) + ->append($this->getAsyncEventsConfiguration()) + ->arrayNode('extensions')->addDefaultsIfNotSet()->children() + ->booleanNode('doctrine_ping_connection_extension')->defaultFalse()->end() + ->booleanNode('doctrine_clear_identity_map_extension')->defaultFalse()->end() + ->booleanNode('doctrine_odm_clear_identity_map_extension')->defaultFalse()->end() + ->booleanNode('doctrine_closed_entity_manager_extension')->defaultFalse()->end() + ->booleanNode('reset_services_extension')->defaultFalse()->end() + ->booleanNode('signal_extension')->defaultValue(function_exists('pcntl_signal_dispatch'))->end() + ->booleanNode('reply_extension')->defaultTrue()->end() + ->end()->end() + ->end() + ->end() + ; + + return $tb; + } - foreach ($this->factories as $factory) { - $factory->addConfiguration( - $transportChildren->arrayNode($factory->getName()) - ); + private function getMonitoringConfiguration(): ArrayNodeDefinition + { + if (false === class_exists(MonitoringFactory::class)) { + return MissingComponentFactory::getConfiguration('monitoring', ['enqueue/monitoring']); } - $rootNode->children() - ->arrayNode('client')->children() - ->booleanNode('traceable_producer')->defaultValue($this->debug)->end() - ->scalarNode('prefix')->defaultValue('enqueue')->end() - ->scalarNode('app_name')->defaultValue('app')->end() - ->scalarNode('router_topic')->defaultValue(Config::DEFAULT_PROCESSOR_QUEUE_NAME)->cannotBeEmpty()->end() - ->scalarNode('router_queue')->defaultValue(Config::DEFAULT_PROCESSOR_QUEUE_NAME)->cannotBeEmpty()->end() - ->scalarNode('router_processor')->defaultValue(RouterProcessor::class)->end() - ->scalarNode('default_processor_queue')->defaultValue(Config::DEFAULT_PROCESSOR_QUEUE_NAME)->cannotBeEmpty()->end() - ->integerNode('redelivered_delay_time')->min(0)->defaultValue(0)->end() - ->end()->end() - ->arrayNode('consumption')->addDefaultsIfNotSet()->children() - ->integerNode('idle_timeout') - ->min(0) - ->defaultValue(0) - ->info('the time in milliseconds queue consumer waits if no message received') - ->end() - ->integerNode('receive_timeout') - ->min(0) - ->defaultValue(100) - ->info('the time in milliseconds queue consumer waits for a message (100 ms by default)') + return MonitoringFactory::getConfiguration(); + } + + private function getAsyncCommandsConfiguration(): ArrayNodeDefinition + { + if (false === class_exists(RunCommandProcessor::class)) { + return MissingComponentFactory::getConfiguration('async_commands', ['enqueue/async-command']); + } + + return (new ArrayNodeDefinition('async_commands')) + ->children() + ->booleanNode('enabled')->defaultFalse()->end() + ->integerNode('timeout')->min(0)->defaultValue(60)->end() + ->scalarNode('command_name')->defaultNull()->end() + ->scalarNode('queue_name')->defaultNull()->end() + ->end() + ->addDefaultsIfNotSet() + ->canBeEnabled() + ; + } + + private function getJobConfiguration(): ArrayNodeDefinition + { + if (false === class_exists(Job::class)) { + return MissingComponentFactory::getConfiguration('job', ['enqueue/job-queue']); + } + + return (new ArrayNodeDefinition('job')) + ->children() + ->booleanNode('default_mapping') + ->defaultTrue() + ->info('Adds bundle\'s default Job entity mapping to application\'s entity manager') ->end() - ->end()->end() - ->booleanNode('job')->defaultFalse()->end() - ->arrayNode('async_events') - ->addDefaultsIfNotSet() - ->canBeEnabled() ->end() - ->arrayNode('extensions')->addDefaultsIfNotSet()->children() - ->booleanNode('doctrine_ping_connection_extension')->defaultFalse()->end() - ->booleanNode('doctrine_clear_identity_map_extension')->defaultFalse()->end() - ->booleanNode('signal_extension')->defaultValue(function_exists('pcntl_signal_dispatch'))->end() - ->booleanNode('reply_extension')->defaultTrue()->end() - ->end()->end() + ->addDefaultsIfNotSet() + ->canBeEnabled() ; + } - return $tb; + private function getAsyncEventsConfiguration(): ArrayNodeDefinition + { + if (false == class_exists(AsyncEventDispatcherExtension::class)) { + return MissingComponentFactory::getConfiguration('async_events', ['enqueue/async-event-dispatcher']); + } + + return (new ArrayNodeDefinition('async_events')) + ->addDefaultsIfNotSet() + ->canBeEnabled() + ; } } diff --git a/DependencyInjection/EnqueueExtension.php b/DependencyInjection/EnqueueExtension.php index 15cd06d..96fca6f 100644 --- a/DependencyInjection/EnqueueExtension.php +++ b/DependencyInjection/EnqueueExtension.php @@ -2,191 +2,159 @@ namespace Enqueue\Bundle\DependencyInjection; +use Enqueue\AsyncCommand\DependencyInjection\AsyncCommandExtension; use Enqueue\AsyncEventDispatcher\DependencyInjection\AsyncEventDispatcherExtension; +use Enqueue\Bundle\Consumption\Extension\DoctrineClearIdentityMapExtension; +use Enqueue\Bundle\Consumption\Extension\DoctrineClosedEntityManagerExtension; +use Enqueue\Bundle\Consumption\Extension\DoctrinePingConnectionExtension; +use Enqueue\Bundle\Consumption\Extension\ResetServicesExtension; +use Enqueue\Bundle\Profiler\MessageQueueCollector; use Enqueue\Client\CommandSubscriberInterface; -use Enqueue\Client\Producer; use Enqueue\Client\TopicSubscriberInterface; -use Enqueue\Client\TraceableProducer; -use Enqueue\Consumption\QueueConsumer; +use Enqueue\Consumption\Extension\ReplyExtension; +use Enqueue\Consumption\Extension\SignalExtension; use Enqueue\JobQueue\Job; -use Enqueue\Null\Symfony\NullTransportFactory; -use Enqueue\Symfony\DefaultTransportFactory; -use Enqueue\Symfony\DriverFactoryInterface; -use Enqueue\Symfony\TransportFactoryInterface; +use Enqueue\Monitoring\Symfony\DependencyInjection\MonitoringFactory; +use Enqueue\Symfony\Client\DependencyInjection\ClientFactory; +use Enqueue\Symfony\DependencyInjection\TransportFactory; +use Enqueue\Symfony\DiUtils; +use Interop\Queue\Context; use Symfony\Component\Config\FileLocator; use Symfony\Component\Config\Resource\FileResource; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Extension\Extension; use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\HttpKernel\DependencyInjection\Extension; -class EnqueueExtension extends Extension implements PrependExtensionInterface +final class EnqueueExtension extends Extension implements PrependExtensionInterface { - /** - * @var TransportFactoryInterface[] - */ - private $factories; - - public function __construct() - { - $this->factories = []; - - $this->addTransportFactory(new DefaultTransportFactory()); - $this->addTransportFactory(new NullTransportFactory()); - } - - /** - * @param TransportFactoryInterface $transportFactory - */ - public function addTransportFactory(TransportFactoryInterface $transportFactory) - { - $name = $transportFactory->getName(); - - if (array_key_exists($name, $this->factories)) { - throw new \LogicException(sprintf('Transport factory with such name already added. Name %s', $name)); - } - - $this->setTransportFactory($transportFactory); - } - - /** - * @param TransportFactoryInterface $transportFactory - */ - public function setTransportFactory(TransportFactoryInterface $transportFactory) - { - $name = $transportFactory->getName(); - - if (empty($name)) { - throw new \LogicException('Transport factory name cannot be empty'); - } - - $this->factories[$name] = $transportFactory; - } - - /** - * {@inheritdoc} - */ - public function load(array $configs, ContainerBuilder $container) + public function load(array $configs, ContainerBuilder $container): void { $config = $this->processConfiguration($this->getConfiguration($configs, $container), $configs); $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('services.yml'); - $this->setupAutowiringForProcessors($container); + // find default configuration + $defaultName = null; + foreach ($config as $name => $modules) { + // set first as default + if (null === $defaultName) { + $defaultName = $name; + } - foreach ($config['transport'] as $name => $transportConfig) { - $this->factories[$name]->createConnectionFactory($container, $transportConfig); - $this->factories[$name]->createContext($container, $transportConfig); + // or with name 'default' + if (DiUtils::DEFAULT_CONFIG === $name) { + $defaultName = $name; + } } - if (isset($config['client'])) { - $loader->load('client.yml'); - $loader->load('extensions/flush_spool_producer_extension.yml'); - $loader->load('extensions/exclusive_command_extension.yml'); - - foreach ($config['transport'] as $name => $transportConfig) { - if ($this->factories[$name] instanceof DriverFactoryInterface) { - $this->factories[$name]->createDriver($container, $transportConfig); - } + $transportNames = []; + $clientNames = []; + foreach ($config as $name => $modules) { + // transport & consumption + $transportNames[] = $name; + + $transportFactory = (new TransportFactory($name, $defaultName === $name)); + $transportFactory->buildConnectionFactory($container, $modules['transport']); + $transportFactory->buildContext($container, []); + $transportFactory->buildQueueConsumer($container, $modules['consumption']); + $transportFactory->buildRpcClient($container, []); + + // client + if (isset($modules['client'])) { + $clientNames[] = $name; + + $clientConfig = $modules['client']; + // todo + $clientConfig['transport'] = $modules['transport']; + $clientConfig['consumption'] = $modules['consumption']; + + $clientFactory = new ClientFactory($name, $defaultName === $name); + $clientFactory->build($container, $clientConfig); + $clientFactory->createDriver($container, $modules['transport']); + $clientFactory->createFlushSpoolProducerListener($container); } - if (isset($config['transport']['default']['alias']) && !isset($config['transport'][$config['transport']['default']['alias']])) { - throw new \LogicException(sprintf('Transport is not enabled: %s', $config['transport']['default']['alias'])); + // monitoring + if (isset($modules['monitoring'])) { + $monitoringFactory = new MonitoringFactory($name); + $monitoringFactory->buildStorage($container, $modules['monitoring']); + $monitoringFactory->buildConsumerExtension($container, $modules['monitoring']); + + if (isset($modules['client'])) { + $monitoringFactory->buildClientExtension($container, $modules['monitoring']); + } } - $configDef = $container->getDefinition('enqueue.client.config'); - $configDef->setArguments([ - $config['client']['prefix'], - $config['client']['app_name'], - $config['client']['router_topic'], - $config['client']['router_queue'], - $config['client']['default_processor_queue'], - $config['client']['router_processor'], - isset($config['transport']['default']['alias']) ? $config['transport'][$config['transport']['default']['alias']] : [], - ]); + // job-queue + if (false == empty($modules['job']['enabled'])) { + if (false === isset($modules['client'])) { + throw new \LogicException('Client is required for job-queue.'); + } - $container->setParameter('enqueue.client.router_queue_name', $config['client']['router_queue']); - $container->setParameter('enqueue.client.default_queue_name', $config['client']['default_processor_queue']); + if ($name !== $defaultName) { + throw new \LogicException('Job-queue supports only default configuration.'); + } - if ($config['client']['traceable_producer']) { - $container->register(TraceableProducer::class, TraceableProducer::class) - ->setDecoratedService(Producer::class) - ->setPublic(true) - ->addArgument(new Reference(sprintf('%s.inner', TraceableProducer::class))) - ; + $loader->load('job.yml'); } - if ($config['client']['redelivered_delay_time']) { - $loader->load('extensions/delay_redelivered_message_extension.yml'); + // async events + if (false == empty($modules['async_events']['enabled'])) { + if ($name !== $defaultName) { + throw new \LogicException('Async events supports only default configuration.'); + } - $container->getDefinition('enqueue.client.delay_redelivered_message_extension') - ->replaceArgument(1, $config['client']['redelivered_delay_time']) - ; + $extension = new AsyncEventDispatcherExtension(); + $extension->load([[ + 'context_service' => Context::class, + ]], $container); } } - // configure queue consumer - $container->getDefinition(QueueConsumer::class) - ->replaceArgument(2, $config['consumption']['idle_timeout']) - ->replaceArgument(3, $config['consumption']['receive_timeout']) - ; - - if ($container->hasDefinition('enqueue.client.queue_consumer')) { - $container->getDefinition('enqueue.client.queue_consumer') - ->replaceArgument(2, $config['consumption']['idle_timeout']) - ->replaceArgument(3, $config['consumption']['receive_timeout']) - ; - } - - if ($config['job']) { - if (!class_exists(Job::class)) { - throw new \LogicException('Seems "enqueue/job-queue" is not installed. Please fix this issue.'); - } - - $loader->load('job.yml'); + $defaultClient = null; + if (in_array($defaultName, $clientNames, true)) { + $defaultClient = $defaultName; } - if ($config['async_events']['enabled']) { - $extension = new AsyncEventDispatcherExtension(); - $extension->load([[ - 'context_service' => 'enqueue.transport.default.context', - ]], $container); - } + $container->setParameter('enqueue.transports', $transportNames); + $container->setParameter('enqueue.clients', $clientNames); - if ($config['extensions']['doctrine_ping_connection_extension']) { - $loader->load('extensions/doctrine_ping_connection_extension.yml'); - } + $container->setParameter('enqueue.default_transport', $defaultName); - if ($config['extensions']['doctrine_clear_identity_map_extension']) { - $loader->load('extensions/doctrine_clear_identity_map_extension.yml'); + if ($defaultClient) { + $container->setParameter('enqueue.default_client', $defaultClient); } - if ($config['extensions']['signal_extension']) { - $loader->load('extensions/signal_extension.yml'); + if ($defaultClient) { + $this->setupAutowiringForDefaultClientsProcessors($container, $defaultClient); } - if ($config['extensions']['reply_extension']) { - $loader->load('extensions/reply_extension.yml'); - } + $this->loadMessageQueueCollector($config, $container); + $this->loadAsyncCommands($config, $container); + + // extensions + $this->loadDoctrinePingConnectionExtension($config, $container); + $this->loadDoctrineClearIdentityMapExtension($config, $container); + $this->loadDoctrineOdmClearIdentityMapExtension($config, $container); + $this->loadDoctrineClosedEntityManagerExtension($config, $container); + $this->loadResetServicesExtension($config, $container); + $this->loadSignalExtension($config, $container); + $this->loadReplyExtension($config, $container); } - /** - * {@inheritdoc} - * - * @return Configuration - */ - public function getConfiguration(array $config, ContainerBuilder $container) + public function getConfiguration(array $config, ContainerBuilder $container): Configuration { $rc = new \ReflectionClass(Configuration::class); $container->addResource(new FileResource($rc->getFileName())); - return new Configuration($this->factories, $container->getParameter('kernel.debug')); + return new Configuration($container->getParameter('kernel.debug')); } - public function prepend(ContainerBuilder $container) + public function prepend(ContainerBuilder $container): void { $this->registerJobQueueDoctrineEntityMapping($container); } @@ -203,6 +171,18 @@ private function registerJobQueueDoctrineEntityMapping(ContainerBuilder $contain return; } + $config = $container->getExtensionConfig('enqueue'); + + if (!empty($config)) { + $processedConfig = $this->processConfiguration(new Configuration(false), $config); + + foreach ($processedConfig as $name => $modules) { + if (isset($modules['job']) && false === $modules['job']['default_mapping']) { + return; + } + } + } + foreach ($container->getExtensionConfig('doctrine') as $config) { // do not register mappings if dbal not configured. if (!empty($config['dbal'])) { @@ -225,18 +205,221 @@ private function registerJobQueueDoctrineEntityMapping(ContainerBuilder $contain } } - private function setupAutowiringForProcessors(ContainerBuilder $container) + private function setupAutowiringForDefaultClientsProcessors(ContainerBuilder $container, string $defaultClient) { - if (!method_exists($container, 'registerForAutoconfiguration')) { - return; - } - $container->registerForAutoconfiguration(TopicSubscriberInterface::class) ->setPublic(true) - ->addTag('enqueue.client.processor'); + ->addTag('enqueue.topic_subscriber', ['client' => $defaultClient]) + ; $container->registerForAutoconfiguration(CommandSubscriberInterface::class) ->setPublic(true) - ->addTag('enqueue.client.processor'); + ->addTag('enqueue.command_subscriber', ['client' => $defaultClient]) + ; + } + + private function loadDoctrinePingConnectionExtension(array $config, ContainerBuilder $container): void + { + $configNames = []; + foreach ($config as $name => $modules) { + if ($modules['extensions']['doctrine_ping_connection_extension']) { + $configNames[] = $name; + } + } + + if ([] === $configNames) { + return; + } + + $extension = $container->register('enqueue.consumption.doctrine_ping_connection_extension', DoctrinePingConnectionExtension::class) + ->addArgument(new Reference('doctrine')) + ; + + foreach ($configNames as $name) { + $extension->addTag('enqueue.consumption_extension', ['client' => $name]); + $extension->addTag('enqueue.transport.consumption_extension', ['transport' => $name]); + } + } + + private function loadDoctrineClearIdentityMapExtension(array $config, ContainerBuilder $container): void + { + $configNames = []; + foreach ($config as $name => $modules) { + if ($modules['extensions']['doctrine_clear_identity_map_extension']) { + $configNames[] = $name; + } + } + + if ([] === $configNames) { + return; + } + + $extension = $container->register('enqueue.consumption.doctrine_clear_identity_map_extension', DoctrineClearIdentityMapExtension::class) + ->addArgument(new Reference('doctrine')) + ; + + foreach ($configNames as $name) { + $extension->addTag('enqueue.consumption_extension', ['client' => $name]); + $extension->addTag('enqueue.transport.consumption_extension', ['transport' => $name]); + } + } + + private function loadDoctrineOdmClearIdentityMapExtension(array $config, ContainerBuilder $container): void + { + $configNames = []; + foreach ($config as $name => $modules) { + if ($modules['extensions']['doctrine_odm_clear_identity_map_extension']) { + $configNames[] = $name; + } + } + + if ([] === $configNames) { + return; + } + + $extension = $container->register('enqueue.consumption.doctrine_odm_clear_identity_map_extension', DoctrineClearIdentityMapExtension::class) + ->addArgument(new Reference('doctrine_mongodb')) + ; + + foreach ($configNames as $name) { + $extension->addTag('enqueue.consumption_extension', ['client' => $name]); + $extension->addTag('enqueue.transport.consumption_extension', ['transport' => $name]); + } + } + + private function loadDoctrineClosedEntityManagerExtension(array $config, ContainerBuilder $container) + { + $configNames = []; + foreach ($config as $name => $modules) { + if ($modules['extensions']['doctrine_closed_entity_manager_extension']) { + $configNames[] = $name; + } + } + + if ([] === $configNames) { + return; + } + + $extension = $container->register('enqueue.consumption.doctrine_closed_entity_manager_extension', DoctrineClosedEntityManagerExtension::class) + ->addArgument(new Reference('doctrine')); + + foreach ($configNames as $name) { + $extension->addTag('enqueue.consumption_extension', ['client' => $name]); + $extension->addTag('enqueue.transport.consumption_extension', ['transport' => $name]); + } + } + + private function loadResetServicesExtension(array $config, ContainerBuilder $container) + { + $configNames = []; + foreach ($config as $name => $modules) { + if ($modules['extensions']['reset_services_extension']) { + $configNames[] = $name; + } + } + + if ([] === $configNames) { + return; + } + + $extension = $container->register('enqueue.consumption.reset_services_extension', ResetServicesExtension::class) + ->addArgument(new Reference('services_resetter')); + + foreach ($configNames as $name) { + $extension->addTag('enqueue.consumption_extension', ['client' => $name]); + $extension->addTag('enqueue.transport.consumption_extension', ['transport' => $name]); + } + } + + private function loadSignalExtension(array $config, ContainerBuilder $container): void + { + $configNames = []; + foreach ($config as $name => $modules) { + if ($modules['extensions']['signal_extension']) { + $configNames[] = $name; + } + } + + if ([] === $configNames) { + return; + } + + $extension = $container->register('enqueue.consumption.signal_extension', SignalExtension::class); + + foreach ($configNames as $name) { + $extension->addTag('enqueue.consumption_extension', ['client' => $name]); + $extension->addTag('enqueue.transport.consumption_extension', ['transport' => $name]); + } + } + + private function loadReplyExtension(array $config, ContainerBuilder $container): void + { + $configNames = []; + foreach ($config as $name => $modules) { + if ($modules['extensions']['reply_extension']) { + $configNames[] = $name; + } + } + + if ([] === $configNames) { + return; + } + + $extension = $container->register('enqueue.consumption.reply_extension', ReplyExtension::class); + + foreach ($configNames as $name) { + $extension->addTag('enqueue.consumption_extension', ['client' => $name]); + $extension->addTag('enqueue.transport.consumption_extension', ['transport' => $name]); + } + } + + private function loadAsyncCommands(array $config, ContainerBuilder $container): void + { + $configs = []; + foreach ($config as $name => $modules) { + if (false === empty($modules['async_commands']['enabled'])) { + $configs[] = [ + 'name' => $name, + 'timeout' => $modules['async_commands']['timeout'], + 'command_name' => $modules['async_commands']['command_name'], + 'queue_name' => $modules['async_commands']['queue_name'], + ]; + } + } + + if (false == $configs) { + return; + } + + if (false == class_exists(AsyncCommandExtension::class)) { + throw new \LogicException('The "enqueue/async-command" package has to be installed.'); + } + + $extension = new AsyncCommandExtension(); + $extension->load(['clients' => $configs], $container); + } + + private function loadMessageQueueCollector(array $config, ContainerBuilder $container) + { + $configNames = []; + foreach ($config as $name => $modules) { + if (isset($modules['client'])) { + $configNames[] = $name; + } + } + + if (false == $configNames) { + return; + } + + $service = $container->register('enqueue.profiler.message_queue_collector', MessageQueueCollector::class); + $service->addTag('data_collector', [ + 'template' => '@Enqueue/Profiler/panel.html.twig', + 'id' => 'enqueue.message_queue', + ]); + + foreach ($configNames as $configName) { + $service->addMethodCall('addProducer', [$configName, DiUtils::create('client', $configName)->reference('producer')]); + } } } diff --git a/EnqueueBundle.php b/EnqueueBundle.php index 843cd49..5010ba0 100644 --- a/EnqueueBundle.php +++ b/EnqueueBundle.php @@ -2,124 +2,45 @@ namespace Enqueue\Bundle; -use Enqueue\AmqpBunny\AmqpConnectionFactory as AmqpBunnyConnectionFactory; -use Enqueue\AmqpExt\AmqpConnectionFactory as AmqpExtConnectionFactory; -use Enqueue\AmqpLib\AmqpConnectionFactory as AmqpLibConnectionFactory; +use Enqueue\AsyncEventDispatcher\DependencyInjection\AsyncEventDispatcherExtension; use Enqueue\AsyncEventDispatcher\DependencyInjection\AsyncEventsPass; use Enqueue\AsyncEventDispatcher\DependencyInjection\AsyncTransformersPass; -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\Dbal\DbalConnectionFactory; -use Enqueue\Dbal\Symfony\DbalTransportFactory; -use Enqueue\Fs\FsConnectionFactory; -use Enqueue\Fs\Symfony\FsTransportFactory; -use Enqueue\Gps\GpsConnectionFactory; -use Enqueue\Gps\Symfony\GpsTransportFactory; -use Enqueue\Mongodb\Symfony\MongodbTransportFactory; -use Enqueue\RdKafka\RdKafkaConnectionFactory; -use Enqueue\RdKafka\Symfony\RdKafkaTransportFactory; -use Enqueue\Redis\RedisConnectionFactory; -use Enqueue\Redis\Symfony\RedisTransportFactory; -use Enqueue\Sqs\SqsConnectionFactory; -use Enqueue\Sqs\Symfony\SqsTransportFactory; -use Enqueue\Stomp\StompConnectionFactory; -use Enqueue\Stomp\Symfony\RabbitMqStompTransportFactory; -use Enqueue\Stomp\Symfony\StompTransportFactory; -use Enqueue\Symfony\AmqpTransportFactory; -use Enqueue\Symfony\MissingTransportFactory; -use Enqueue\Symfony\RabbitMqAmqpTransportFactory; +use Enqueue\Doctrine\DoctrineSchemaCompilerPass; +use Enqueue\Symfony\Client\DependencyInjection\AnalyzeRouteCollectionPass; +use Enqueue\Symfony\Client\DependencyInjection\BuildClientExtensionsPass; +use Enqueue\Symfony\Client\DependencyInjection\BuildCommandSubscriberRoutesPass as BuildClientCommandSubscriberRoutesPass; +use Enqueue\Symfony\Client\DependencyInjection\BuildConsumptionExtensionsPass as BuildClientConsumptionExtensionsPass; +use Enqueue\Symfony\Client\DependencyInjection\BuildProcessorRegistryPass as BuildClientProcessorRegistryPass; +use Enqueue\Symfony\Client\DependencyInjection\BuildProcessorRoutesPass as BuildClientProcessorRoutesPass; +use Enqueue\Symfony\Client\DependencyInjection\BuildTopicSubscriberRoutesPass as BuildClientTopicSubscriberRoutesPass; +use Enqueue\Symfony\DependencyInjection\BuildConsumptionExtensionsPass; +use Enqueue\Symfony\DependencyInjection\BuildProcessorRegistryPass; use Symfony\Component\DependencyInjection\Compiler\PassConfig; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; class EnqueueBundle extends Bundle { - /** - * {@inheritdoc} - */ - public function build(ContainerBuilder $container) + public function build(ContainerBuilder $container): void { + // transport passes $container->addCompilerPass(new BuildConsumptionExtensionsPass()); - $container->addCompilerPass(new BuildClientRoutingPass()); $container->addCompilerPass(new BuildProcessorRegistryPass()); - $container->addCompilerPass(new BuildTopicMetaSubscribersPass()); - $container->addCompilerPass(new BuildQueueMetaRegistryPass()); - $container->addCompilerPass(new BuildClientExtensionsPass()); - $container->addCompilerPass(new BuildExclusiveCommandsExtensionPass()); - - /** @var EnqueueExtension $extension */ - $extension = $container->getExtension('enqueue'); - - if (class_exists(StompConnectionFactory::class)) { - $extension->setTransportFactory(new StompTransportFactory('stomp')); - $extension->setTransportFactory(new RabbitMqStompTransportFactory('rabbitmq_stomp')); - } else { - $extension->setTransportFactory(new MissingTransportFactory('stomp', ['enqueue/stomp'])); - $extension->setTransportFactory(new MissingTransportFactory('rabbitmq_stomp', ['enqueue/stomp'])); - } - - if ( - class_exists(AmqpBunnyConnectionFactory::class) || - class_exists(AmqpExtConnectionFactory::class) || - class_exists(AmqpLibConnectionFactory::class) - ) { - $extension->setTransportFactory(new AmqpTransportFactory('amqp')); - $extension->setTransportFactory(new RabbitMqAmqpTransportFactory('rabbitmq_amqp')); - } else { - $amqpPackages = ['enqueue/amqp-ext', 'enqueue/amqp-bunny', 'enqueue/amqp-lib']; - $extension->setTransportFactory(new MissingTransportFactory('amqp', $amqpPackages)); - $extension->setTransportFactory(new MissingTransportFactory('rabbitmq_amqp', $amqpPackages)); - } - - if (class_exists(FsConnectionFactory::class)) { - $extension->setTransportFactory(new FsTransportFactory('fs')); - } else { - $extension->setTransportFactory(new MissingTransportFactory('fs', ['enqueue/fs'])); - } - - if (class_exists(RedisConnectionFactory::class)) { - $extension->setTransportFactory(new RedisTransportFactory('redis')); - } else { - $extension->setTransportFactory(new MissingTransportFactory('redis', ['enqueue/redis'])); - } - - if (class_exists(DbalConnectionFactory::class)) { - $extension->setTransportFactory(new DbalTransportFactory('dbal')); - } else { - $extension->setTransportFactory(new MissingTransportFactory('dbal', ['enqueue/dbal'])); - } - - if (class_exists(SqsConnectionFactory::class)) { - $extension->setTransportFactory(new SqsTransportFactory('sqs')); - } else { - $extension->setTransportFactory(new MissingTransportFactory('sqs', ['enqueue/sqs'])); - } - if (class_exists(GpsConnectionFactory::class)) { - $extension->setTransportFactory(new GpsTransportFactory('gps')); - } else { - $extension->setTransportFactory(new MissingTransportFactory('gps', ['enqueue/gps'])); - } - - if (class_exists(RdKafkaConnectionFactory::class)) { - $extension->setTransportFactory(new RdKafkaTransportFactory('rdkafka')); - } else { - $extension->setTransportFactory(new MissingTransportFactory('rdkafka', ['enqueue/rdkafka'])); - } + // client passes + $container->addCompilerPass(new BuildClientConsumptionExtensionsPass()); + $container->addCompilerPass(new BuildClientExtensionsPass()); + $container->addCompilerPass(new BuildClientTopicSubscriberRoutesPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 100); + $container->addCompilerPass(new BuildClientCommandSubscriberRoutesPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 100); + $container->addCompilerPass(new BuildClientProcessorRoutesPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 100); + $container->addCompilerPass(new AnalyzeRouteCollectionPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 30); + $container->addCompilerPass(new BuildClientProcessorRegistryPass()); - if (class_exists(MongodbTransportFactory::class)) { - $extension->setTransportFactory(new MongodbTransportFactory('mongodb')); - } else { - $extension->setTransportFactory(new MissingTransportFactory('mongodb', ['enqueue/mongodb'])); + if (class_exists(AsyncEventDispatcherExtension::class)) { + $container->addCompilerPass(new AsyncEventsPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 100); + $container->addCompilerPass(new AsyncTransformersPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 100); } - $container->addCompilerPass(new AsyncEventsPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 100); - $container->addCompilerPass(new AsyncTransformersPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 100); + $container->addCompilerPass(new DoctrineSchemaCompilerPass()); } } diff --git a/Profiler/AbstractMessageQueueCollector.php b/Profiler/AbstractMessageQueueCollector.php new file mode 100644 index 0000000..e2e5eee --- /dev/null +++ b/Profiler/AbstractMessageQueueCollector.php @@ -0,0 +1,89 @@ +producers[$name] = $producer; + } + + public function getCount(): int + { + $count = 0; + foreach ($this->data as $name => $messages) { + $count += count($messages); + } + + return $count; + } + + /** + * @return array + */ + public function getSentMessages() + { + return $this->data; + } + + /** + * @param string $priority + * + * @return string + */ + public function prettyPrintPriority($priority) + { + $map = [ + MessagePriority::VERY_LOW => 'very low', + MessagePriority::LOW => 'low', + MessagePriority::NORMAL => 'normal', + MessagePriority::HIGH => 'high', + MessagePriority::VERY_HIGH => 'very high', + ]; + + return isset($map[$priority]) ? $map[$priority] : $priority; + } + + /** + * @return string + */ + public function ensureString($body) + { + return is_string($body) ? $body : JSON::encode($body); + } + + public function getName(): string + { + return 'enqueue.message_queue'; + } + + public function reset(): void + { + $this->data = []; + } + + protected function collectInternal(Request $request, Response $response): void + { + $this->data = []; + + foreach ($this->producers as $name => $producer) { + if ($producer instanceof TraceableProducer) { + $this->data[$name] = $producer->getTraces(); + } + } + } +} diff --git a/Profiler/MessageQueueCollector.php b/Profiler/MessageQueueCollector.php index 86bdd74..3c484a7 100644 --- a/Profiler/MessageQueueCollector.php +++ b/Profiler/MessageQueueCollector.php @@ -2,92 +2,13 @@ namespace Enqueue\Bundle\Profiler; -use Enqueue\Client\MessagePriority; -use Enqueue\Client\ProducerInterface; -use Enqueue\Client\TraceableProducer; -use Enqueue\Util\JSON; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\DataCollector\DataCollector; -class MessageQueueCollector extends DataCollector +class MessageQueueCollector extends AbstractMessageQueueCollector { - /** - * @var ProducerInterface - */ - private $producer; - - /** - * @param ProducerInterface $producer - */ - public function __construct(ProducerInterface $producer) - { - $this->producer = $producer; - } - - /** - * {@inheritdoc} - */ - public function collect(Request $request, Response $response, \Exception $exception = null) - { - $this->data = [ - 'sent_messages' => [], - ]; - - if ($this->producer instanceof TraceableProducer) { - $this->data['sent_messages'] = $this->producer->getTraces(); - } - } - - /** - * @return array - */ - public function getSentMessages() - { - return $this->data['sent_messages']; - } - - /** - * @param string $priority - * - * @return string - */ - public function prettyPrintPriority($priority) - { - $map = [ - MessagePriority::VERY_LOW => 'very low', - MessagePriority::LOW => 'low', - MessagePriority::NORMAL => 'normal', - MessagePriority::HIGH => 'high', - MessagePriority::VERY_HIGH => 'very high', - ]; - - return isset($map[$priority]) ? $map[$priority] : $priority; - } - - /** - * @param mixed $body - * - * @return string - */ - public function ensureString($body) - { - return is_string($body) ? $body : JSON::encode($body); - } - - /** - * {@inheritdoc} - */ - public function getName() - { - return 'enqueue.message_queue'; - } - - /** - * {@inheritdoc} - */ - public function reset() + public function collect(Request $request, Response $response, ?\Throwable $exception = null): void { - $this->data = []; + $this->collectInternal($request, $response); } } diff --git a/README.md b/README.md index a76ff62..2b8bbfe 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,37 @@ +

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 Bundle [![Gitter](https://badges.gitter.im/php-enqueue/Lobby.svg)](https://gitter.im/php-enqueue/Lobby) -[![Build Status](https://travis-ci.org/php-enqueue/enqueue-bundle.png?branch=master)](https://travis-ci.org/php-enqueue/enqueue-bundle) +[![Build Status](https://img.shields.io/github/actions/workflow/status/php-enqueue/enqueue-bundle/ci.yml?branch=master)](https://github.com/php-enqueue/enqueue-bundle/actions?query=workflow%3ACI) [![Total Downloads](https://poser.pugx.org/enqueue/enqueue-bundle/d/total.png)](https://packagist.org/packages/enqueue/enqueue-bundle) [![Latest Stable Version](https://poser.pugx.org/enqueue/enqueue-bundle/version.png)](https://packagist.org/packages/enqueue/enqueue-bundle) - -Integrates message queue components to Symfony application. + +Integrates message queue components to Symfony application. ## Resources * [Site](https://enqueue.forma-pro.com/) * [Quick tour](https://github.com/php-enqueue/enqueue-dev/blob/master/docs/bundle/quick_tour.md) -* [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/Resources/config/client.yml b/Resources/config/client.yml deleted file mode 100644 index d5bacbb..0000000 --- a/Resources/config/client.yml +++ /dev/null @@ -1,215 +0,0 @@ -services: - enqueue.client.config: - class: 'Enqueue\Client\Config' - public: false - - Enqueue\Client\Producer: - class: 'Enqueue\Client\Producer' - public: true - arguments: - - '@enqueue.client.driver' - - '@enqueue.client.rpc_factory' - - '@enqueue.client.extensions' - - Enqueue\Client\ProducerInterface: - public: true - alias: 'Enqueue\Client\Producer' - - # Deprecated. To be removed in 0.10. - enqueue.client.producer: - public: true - alias: 'Enqueue\Client\Producer' - - # Deprecated. To be removed in 0.10. - enqueue.producer: - public: true - alias: 'enqueue.client.producer' - - # Deprecated. To be removed in 0.10. - enqueue.client.producer_v2: - public: true - alias: 'enqueue.client.producer' - - Enqueue\Client\SpoolProducer: - class: 'Enqueue\Client\SpoolProducer' - public: true - arguments: - - '@Enqueue\Client\Producer' - - # Deprecated. To be removed in 0.10. - enqueue.client.spool_producer: - public: true - alias: 'Enqueue\Client\SpoolProducer' - - # Deprecated. To be removed in 0.10. - enqueue.spool_producer: - public: true - alias: 'enqueue.client.spool_producer' - - enqueue.client.extensions: - class: 'Enqueue\Client\ChainExtension' - public: false - arguments: - - [] - - enqueue.client.rpc_factory: - class: 'Enqueue\Rpc\RpcFactory' - public: false - arguments: - - '@enqueue.transport.context' - - Enqueue\Client\RouterProcessor: - class: 'Enqueue\Client\RouterProcessor' - public: true - arguments: - - '@enqueue.client.driver' - - [] - - [] - tags: - - - name: 'enqueue.client.processor' - topicName: '__router__' - queueName: '%enqueue.client.router_queue_name%' - - # Deprecated. To be removed in 0.10. - enqueue.client.router_processor: - public: true - alias: 'Enqueue\Client\RouterProcessor' - - enqueue.client.processor_registry: - class: 'Enqueue\Symfony\Client\ContainerAwareProcessorRegistry' - public: false - calls: - - ['setContainer', ['@service_container']] - - Enqueue\Client\Meta\TopicMetaRegistry: - class: 'Enqueue\Client\Meta\TopicMetaRegistry' - public: true - arguments: [[]] - - # Deprecated. To be removed in 0.10. - enqueue.client.meta.topic_meta_registry: - public: true - alias: 'Enqueue\Client\Meta\TopicMetaRegistry' - - Enqueue\Client\Meta\QueueMetaRegistry: - class: 'Enqueue\Client\Meta\QueueMetaRegistry' - public: true - arguments: ['@enqueue.client.config', []] - - # Deprecated. To be removed in 0.10. - enqueue.client.meta.queue_meta_registry: - public: true - alias: 'Enqueue\Client\Meta\QueueMetaRegistry' - - enqueue.client.delegate_processor: - class: 'Enqueue\Client\DelegateProcessor' - public: false - arguments: - - '@enqueue.client.processor_registry' - - enqueue.client.extension.set_router_properties: - class: 'Enqueue\Client\ConsumptionExtension\SetRouterPropertiesExtension' - public: false - arguments: - - '@enqueue.client.driver' - tags: - - { name: 'enqueue.consumption.extension', priority: 100 } - - enqueue.client.queue_consumer: - class: 'Enqueue\Consumption\QueueConsumer' - public: false - arguments: - - '@enqueue.transport.context' - - '@enqueue.consumption.extensions' - - ~ - - ~ - - Enqueue\Symfony\Client\ConsumeMessagesCommand: - class: 'Enqueue\Symfony\Client\ConsumeMessagesCommand' - public: true - arguments: - - '@enqueue.client.queue_consumer' - - '@enqueue.client.delegate_processor' - - '@Enqueue\Client\Meta\QueueMetaRegistry' - - '@enqueue.client.driver' - tags: - - { name: 'console.command' } - - # Deprecated. To be removed in 0.10. - enqueue.client.consume_messages_command: - public: true - alias: 'Enqueue\Symfony\Client\ConsumeMessagesCommand' - - Enqueue\Symfony\Client\ProduceMessageCommand: - class: 'Enqueue\Symfony\Client\ProduceMessageCommand' - public: true - arguments: - - '@Enqueue\Client\Producer' - tags: - - { name: 'console.command' } - - # Deprecated. To be removed in 0.10. - enqueue.client.produce_message_command: - public: true - alias: 'Enqueue\Symfony\Client\ProduceMessageCommand' - - Enqueue\Symfony\Client\Meta\TopicsCommand: - class: 'Enqueue\Symfony\Client\Meta\TopicsCommand' - public: true - arguments: - - '@Enqueue\Client\Meta\TopicMetaRegistry' - tags: - - { name: 'console.command' } - - # Deprecated. To be removed in 0.10. - enqueue.client.meta.topics_command: - public: true - alias: 'Enqueue\Symfony\Client\Meta\TopicsCommand' - - Enqueue\Symfony\Client\Meta\QueuesCommand: - class: 'Enqueue\Symfony\Client\Meta\QueuesCommand' - public: true - arguments: - - '@Enqueue\Client\Meta\QueueMetaRegistry' - tags: - - { name: 'console.command' } - - # Deprecated. To be removed in 0.10. - enqueue.client.meta.queues_command: - public: true - alias: 'Enqueue\Symfony\Client\Meta\QueuesCommand' - - Enqueue\Symfony\Client\SetupBrokerCommand: - class: 'Enqueue\Symfony\Client\SetupBrokerCommand' - public: true - arguments: - - '@enqueue.client.driver' - tags: - - { name: 'console.command' } - - # Deprecated. To be removed in 0.10. - enqueue.client.setup_broker_command: - public: true - alias: 'Enqueue\Symfony\Client\SetupBrokerCommand' - - enqueue.profiler.message_queue_collector: - class: 'Enqueue\Bundle\Profiler\MessageQueueCollector' - public: false - arguments: - - '@Enqueue\Client\Producer' - tags: - - { name: 'data_collector', template: '@Enqueue/Profiler/panel.html.twig', id: 'enqueue.message_queue' } - - Enqueue\Symfony\Client\FlushSpoolProducerListener: - class: 'Enqueue\Symfony\Client\FlushSpoolProducerListener' - public: true - arguments: - - '@Enqueue\Client\SpoolProducer' - tags: - - { name: 'kernel.event_subscriber' } - - # Deprecated. To be removed in 0.10. - enqueue.flush_spool_producer_listener: - public: true - alias: 'Enqueue\Symfony\Client\FlushSpoolProducerListener' diff --git a/Resources/config/extensions/delay_redelivered_message_extension.yml b/Resources/config/extensions/delay_redelivered_message_extension.yml deleted file mode 100644 index 24fff7e..0000000 --- a/Resources/config/extensions/delay_redelivered_message_extension.yml +++ /dev/null @@ -1,9 +0,0 @@ -services: - enqueue.client.delay_redelivered_message_extension: - class: 'Enqueue\Client\ConsumptionExtension\DelayRedeliveredMessageExtension' - public: false - arguments: - - '@enqueue.client.driver' - - ~ - tags: - - { name: 'enqueue.consumption.extension', priority: 10 } \ No newline at end of file diff --git a/Resources/config/extensions/doctrine_clear_identity_map_extension.yml b/Resources/config/extensions/doctrine_clear_identity_map_extension.yml deleted file mode 100644 index 932cb9b..0000000 --- a/Resources/config/extensions/doctrine_clear_identity_map_extension.yml +++ /dev/null @@ -1,8 +0,0 @@ -services: - enqueue.consumption.doctrine_clear_identity_map_extension: - class: 'Enqueue\Bundle\Consumption\Extension\DoctrineClearIdentityMapExtension' - public: false - arguments: - - '@doctrine' - tags: - - { name: 'enqueue.consumption.extension' } diff --git a/Resources/config/extensions/doctrine_ping_connection_extension.yml b/Resources/config/extensions/doctrine_ping_connection_extension.yml deleted file mode 100644 index 7b3383a..0000000 --- a/Resources/config/extensions/doctrine_ping_connection_extension.yml +++ /dev/null @@ -1,8 +0,0 @@ -services: - enqueue.consumption.doctrine_ping_connection_extension: - class: 'Enqueue\Bundle\Consumption\Extension\DoctrinePingConnectionExtension' - public: false - arguments: - - '@doctrine' - tags: - - { name: 'enqueue.consumption.extension' } diff --git a/Resources/config/extensions/exclusive_command_extension.yml b/Resources/config/extensions/exclusive_command_extension.yml deleted file mode 100644 index c79b980..0000000 --- a/Resources/config/extensions/exclusive_command_extension.yml +++ /dev/null @@ -1,9 +0,0 @@ -services: - enqueue.client.exclusive_command_extension: - class: 'Enqueue\Client\ConsumptionExtension\ExclusiveCommandExtension' - public: false - arguments: - - [] - tags: - - { name: 'enqueue.consumption.extension', priority: 100 } - - { name: 'enqueue.client.extension', priority: 100 } diff --git a/Resources/config/extensions/flush_spool_producer_extension.yml b/Resources/config/extensions/flush_spool_producer_extension.yml deleted file mode 100644 index 80bd3d4..0000000 --- a/Resources/config/extensions/flush_spool_producer_extension.yml +++ /dev/null @@ -1,8 +0,0 @@ -services: - enqueue.client.flush_spool_producer_extension: - class: 'Enqueue\Client\ConsumptionExtension\FlushSpoolProducerExtension' - public: false - arguments: - - '@Enqueue\Client\SpoolProducer' - tags: - - { name: 'enqueue.consumption.extension', priority: -100 } \ No newline at end of file diff --git a/Resources/config/extensions/reply_extension.yml b/Resources/config/extensions/reply_extension.yml deleted file mode 100644 index b52c46b..0000000 --- a/Resources/config/extensions/reply_extension.yml +++ /dev/null @@ -1,6 +0,0 @@ -services: - enqueue.consumption.reply_extension: - class: 'Enqueue\Consumption\Extension\ReplyExtension' - public: false - tags: - - { name: 'enqueue.consumption.extension' } \ No newline at end of file diff --git a/Resources/config/extensions/signal_extension.yml b/Resources/config/extensions/signal_extension.yml deleted file mode 100644 index e7609eb..0000000 --- a/Resources/config/extensions/signal_extension.yml +++ /dev/null @@ -1,6 +0,0 @@ -services: - enqueue.consumption.signal_extension: - class: 'Enqueue\Consumption\Extension\SignalExtension' - public: false - tags: - - { name: 'enqueue.consumption.extension' } \ No newline at end of file diff --git a/Resources/config/job.yml b/Resources/config/job.yml index 159aecc..0a368ae 100644 --- a/Resources/config/job.yml +++ b/Resources/config/job.yml @@ -20,7 +20,7 @@ services: public: true arguments: - '@Enqueue\JobQueue\Doctrine\JobStorage' - - '@Enqueue\Client\Producer' + - '@Enqueue\Client\ProducerInterface' # Deprecated. To be removed in 0.10. enqueue.job.processor: @@ -55,10 +55,10 @@ services: arguments: - '@Enqueue\JobQueue\Doctrine\JobStorage' - '@Enqueue\JobQueue\CalculateRootJobStatusService' - - '@Enqueue\Client\Producer' + - '@Enqueue\Client\ProducerInterface' - '@logger' tags: - - { name: 'enqueue.client.processor' } + - { name: 'enqueue.command_subscriber', client: 'default' } # Deprecated. To be removed in 0.10. enqueue.job.calculate_root_job_status_processor: @@ -70,10 +70,10 @@ services: public: true arguments: - '@Enqueue\JobQueue\Doctrine\JobStorage' - - '@Enqueue\Client\Producer' + - '@Enqueue\Client\ProducerInterface' - '@logger' tags: - - { name: 'enqueue.client.processor' } + - { name: 'enqueue.topic_subscriber', client: 'default' } # Deprecated. To be removed in 0.10. enqueue.job.dependent_job_processor: diff --git a/Resources/config/services.yml b/Resources/config/services.yml index 5ed9530..a207569 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -1,58 +1,54 @@ -parameters: - enqueue.queue_consumer.enable_subscription_consumer: false - enqueue.queue_consumer.default_idle_time: 0 - enqueue.queue_consumer.default_receive_timeout: 10 - services: - enqueue.consumption.extensions: - class: 'Enqueue\Consumption\ChainExtension' - public: false + enqueue.locator: + class: 'Symfony\Component\DependencyInjection\ServiceLocator' arguments: - [] + tags: ['container.service_locator'] - Enqueue\Consumption\QueueConsumer: - class: 'Enqueue\Consumption\QueueConsumer' - public: true + enqueue.transport.consume_command: + class: 'Enqueue\Symfony\Consumption\ConfigurableConsumeCommand' arguments: - - '@enqueue.transport.context' - - '@enqueue.consumption.extensions' - - '%enqueue.queue_consumer.default_idle_time%' - - '%enqueue.queue_consumer.default_receive_timeout%' - calls: - - ['enableSubscriptionConsumer', ['%enqueue.queue_consumer.enable_subscription_consumer%']] - - # Deprecated. To be removed in 0.10. - enqueue.consumption.queue_consumer: - public: true - alias: 'Enqueue\Consumption\QueueConsumer' + - '@enqueue.locator' + - '%enqueue.default_transport%' + - 'enqueue.transport.%s.queue_consumer' + - 'enqueue.transport.%s.processor_registry' + tags: + - { name: 'console.command' } - Enqueue\Symfony\Consumption\ContainerAwareConsumeMessagesCommand: - class: 'Enqueue\Symfony\Consumption\ContainerAwareConsumeMessagesCommand' - public: true + enqueue.client.consume_command: + class: 'Enqueue\Symfony\Client\ConsumeCommand' arguments: - - '@Enqueue\Consumption\QueueConsumer' + - '@enqueue.locator' + - '%enqueue.default_client%' + - 'enqueue.client.%s.queue_consumer' + - 'enqueue.client.%s.driver' + - 'enqueue.client.%s.delegate_processor' tags: - { name: 'console.command' } - # Deprecated. To be removed in 0.10. - enqueue.command.consume_messages: - public: true - alias: 'Enqueue\Symfony\Consumption\ContainerAwareConsumeMessagesCommand' - - enqueue.transport.rpc_factory: - class: 'Enqueue\Rpc\RpcFactory' - public: false + enqueue.client.produce_command: + class: 'Enqueue\Symfony\Client\ProduceCommand' arguments: - - '@enqueue.transport.context' + - '@enqueue.locator' + - '%enqueue.default_client%' + - 'enqueue.client.%s.producer' + tags: + - { name: 'console.command' } - Enqueue\Rpc\RpcClient: - class: 'Enqueue\Rpc\RpcClient' - public: true + enqueue.client.setup_broker_command: + class: 'Enqueue\Symfony\Client\SetupBrokerCommand' arguments: - - '@enqueue.transport.context' - - '@enqueue.transport.rpc_factory' + - '@enqueue.locator' + - '%enqueue.default_client%' + - 'enqueue.client.%s.driver' + tags: + - { name: 'console.command' } - # Deprecated. To be removed in 0.10. - enqueue.transport.rpc_client: - public: true - alias: 'Enqueue\Rpc\RpcClient' + enqueue.client.routes_command: + class: 'Enqueue\Symfony\Client\RoutesCommand' + arguments: + - '@enqueue.locator' + - '%enqueue.default_client%' + - 'enqueue.client.%s.driver' + tags: + - { name: 'console.command' } diff --git a/Resources/views/Profiler/panel.html.twig b/Resources/views/Profiler/panel.html.twig index 4d80568..ddd52a1 100644 --- a/Resources/views/Profiler/panel.html.twig +++ b/Resources/views/Profiler/panel.html.twig @@ -1,17 +1,17 @@ {% extends '@WebProfiler/Profiler/layout.html.twig' %} {% block toolbar %} - {% if collector.sentMessages|length > 0 %} + {% if collector.count > 0 %} {% set icon %} {{ include('@Enqueue/Icon/icon.svg') }} - {{ collector.sentMessages|length }} + {{ collector.count }} {% endset %} {% set text %}
Sent messages - {{ collector.sentMessages|length }} + {{ collector.count }}
{% endset %} @@ -20,53 +20,63 @@ {% endblock %} {% block menu %} - + {{ include('@Enqueue/Icon/icon.svg') }} Message Queue {% endblock %} {% block panel %} + {% if collector.count > 0 %}

Sent messages

- {% if collector.sentMessages|length > 0 %} - - - - - - - - - - - - {% for sentMessage in collector.sentMessages %} - - - - - - -
#TopicCommandMessagePriority
{{ loop.index }}{{ sentMessage.topic|default(null) }}{{ sentMessage.command|default(null) }} -
{% else %}

No messages were sent.

diff --git a/Tests/Functional/App/AbstractAsyncListener.php b/Tests/Functional/App/AbstractAsyncListener.php new file mode 100644 index 0000000..acf7406 --- /dev/null +++ b/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/Tests/Functional/App/AppKernel.php b/Tests/Functional/App/AppKernel.php index 59ac386..3cafeed 100644 --- a/Tests/Functional/App/AppKernel.php +++ b/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/Tests/Functional/App/AsyncListener.php b/Tests/Functional/App/AsyncListener.php index b55525f..23ab4af 100644 --- a/Tests/Functional/App/AsyncListener.php +++ b/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/Tests/Functional/App/CustomAppKernel.php b/Tests/Functional/App/CustomAppKernel.php index 4651961..81d7379 100644 --- a/Tests/Functional/App/CustomAppKernel.php +++ b/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/Tests/Functional/App/SqsCustomConnectionFactoryFactory.php b/Tests/Functional/App/SqsCustomConnectionFactoryFactory.php new file mode 100644 index 0000000..6ed70cd --- /dev/null +++ b/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/Tests/Functional/App/TestAsyncEventTransformer.php b/Tests/Functional/App/TestAsyncEventTransformer.php index 975cd42..0a83a04 100644 --- a/Tests/Functional/App/TestAsyncEventTransformer.php +++ b/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/Tests/Functional/App/TestAsyncListener.php b/Tests/Functional/App/TestAsyncListener.php index aa4884b..fd0ec1d 100644 --- a/Tests/Functional/App/TestAsyncListener.php +++ b/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/Tests/Functional/App/TestAsyncSubscriber.php b/Tests/Functional/App/TestAsyncSubscriber.php index 2b45bed..cd3beb4 100644 --- a/Tests/Functional/App/TestAsyncSubscriber.php +++ b/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/Tests/Functional/App/TestCommandSubscriberProcessor.php b/Tests/Functional/App/TestCommandSubscriberProcessor.php index bc45336..480992f 100644 --- a/Tests/Functional/App/TestCommandSubscriberProcessor.php +++ b/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/Tests/Functional/App/TestExclusiveCommandSubscriberProcessor.php b/Tests/Functional/App/TestExclusiveCommandSubscriberProcessor.php index 8f0001b..999ad1f 100644 --- a/Tests/Functional/App/TestExclusiveCommandSubscriberProcessor.php +++ b/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/Tests/Functional/App/TestTopicSubscriberProcessor.php b/Tests/Functional/App/TestTopicSubscriberProcessor.php new file mode 100644 index 0000000..2b9f16e --- /dev/null +++ b/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/Tests/Functional/App/config/config-sf5.yml b/Tests/Functional/App/config/config-sf5.yml new file mode 100644 index 0000000..e202bb8 --- /dev/null +++ b/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/Tests/Functional/App/config/config.yml b/Tests/Functional/App/config/config.yml index aa1d645..d3ca2a3 100644 --- a/Tests/Functional/App/config/config.yml +++ b/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/Tests/Functional/App/config/custom-config-sf5.yml b/Tests/Functional/App/config/custom-config-sf5.yml new file mode 100644 index 0000000..3519265 --- /dev/null +++ b/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/Tests/Functional/App/config/custom-config.yml b/Tests/Functional/App/config/custom-config.yml index 5407f84..d02f300 100644 --- a/Tests/Functional/App/config/custom-config.yml +++ b/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/Tests/Functional/Client/ConsumeMessagesCommandTest.php b/Tests/Functional/Client/ConsumeMessagesCommandTest.php deleted file mode 100644 index 5af6109..0000000 --- a/Tests/Functional/Client/ConsumeMessagesCommandTest.php +++ /dev/null @@ -1,19 +0,0 @@ -get(ConsumeMessagesCommand::class); - - $this->assertInstanceOf(ConsumeMessagesCommand::class, $command); - } -} diff --git a/Tests/Functional/Client/DriverTest.php b/Tests/Functional/Client/DriverTest.php deleted file mode 100644 index d4b290f..0000000 --- a/Tests/Functional/Client/DriverTest.php +++ /dev/null @@ -1,19 +0,0 @@ -get('enqueue.client.driver'); - - $this->assertInstanceOf(DriverInterface::class, $driver); - } -} diff --git a/Tests/Functional/Client/ProduceMessageCommandTest.php b/Tests/Functional/Client/ProduceMessageCommandTest.php deleted file mode 100644 index 0873705..0000000 --- a/Tests/Functional/Client/ProduceMessageCommandTest.php +++ /dev/null @@ -1,19 +0,0 @@ -get(ProduceMessageCommand::class); - - $this->assertInstanceOf(ProduceMessageCommand::class, $command); - } -} diff --git a/Tests/Functional/Client/ProducerTest.php b/Tests/Functional/Client/ProducerTest.php index 388cfa2..29a96aa 100644 --- a/Tests/Functional/Client/ProducerTest.php +++ b/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/Tests/Functional/Client/SpoolProducerTest.php b/Tests/Functional/Client/SpoolProducerTest.php index c8a1eaa..0bba433 100644 --- a/Tests/Functional/Client/SpoolProducerTest.php +++ b/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/Tests/Functional/ConsumeMessagesCommandTest.php b/Tests/Functional/ConsumeMessagesCommandTest.php deleted file mode 100644 index d9313c4..0000000 --- a/Tests/Functional/ConsumeMessagesCommandTest.php +++ /dev/null @@ -1,18 +0,0 @@ -get(ConsumeMessagesCommand::class); - - $this->assertInstanceOf(ConsumeMessagesCommand::class, $command); - } -} diff --git a/Tests/Functional/ContextTest.php b/Tests/Functional/ContextTest.php index 44c141a..87e2d95 100644 --- a/Tests/Functional/ContextTest.php +++ b/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/Tests/Functional/Events/AsyncListenerTest.php b/Tests/Functional/Events/AsyncListenerTest.php index b9be84e..7fb6fdd 100644 --- a/Tests/Functional/Events/AsyncListenerTest.php +++ b/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/Tests/Functional/Events/AsyncProcessorTest.php b/Tests/Functional/Events/AsyncProcessorTest.php index 4513069..d855675 100644 --- a/Tests/Functional/Events/AsyncProcessorTest.php +++ b/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/Tests/Functional/Events/AsyncSubscriberTest.php b/Tests/Functional/Events/AsyncSubscriberTest.php index c2e9dc0..4b14552 100644 --- a/Tests/Functional/Events/AsyncSubscriberTest.php +++ b/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/Tests/Functional/LazyProducerTest.php b/Tests/Functional/LazyProducerTest.php new file mode 100644 index 0000000..18375ae --- /dev/null +++ b/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/Tests/Functional/QueueConsumerTest.php b/Tests/Functional/QueueConsumerTest.php index 1c0b16a..e05d153 100644 --- a/Tests/Functional/QueueConsumerTest.php +++ b/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/Tests/Functional/QueueRegistryTest.php b/Tests/Functional/QueueRegistryTest.php deleted file mode 100644 index d608b8f..0000000 --- a/Tests/Functional/QueueRegistryTest.php +++ /dev/null @@ -1,18 +0,0 @@ -get(QueueMetaRegistry::class); - - $this->assertInstanceOf(QueueMetaRegistry::class, $connection); - } -} diff --git a/Tests/Functional/QueuesCommandTest.php b/Tests/Functional/QueuesCommandTest.php deleted file mode 100644 index 53a0086..0000000 --- a/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/Tests/Functional/RoutesCommandTest.php b/Tests/Functional/RoutesCommandTest.php new file mode 100644 index 0000000..66833b1 --- /dev/null +++ b/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/Tests/Functional/RpcClientTest.php b/Tests/Functional/RpcClientTest.php index 1b60661..3d99bcc 100644 --- a/Tests/Functional/RpcClientTest.php +++ b/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/Tests/Functional/TestCommandProcessor.php b/Tests/Functional/TestCommandProcessor.php index be6438a..dfc2bb8 100644 --- a/Tests/Functional/TestCommandProcessor.php +++ b/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/Tests/Functional/TestProcessor.php b/Tests/Functional/TestProcessor.php index a0086be..9b54bdf 100644 --- a/Tests/Functional/TestProcessor.php +++ b/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/Tests/Functional/TopicRegistryTest.php b/Tests/Functional/TopicRegistryTest.php deleted file mode 100644 index bd15aa7..0000000 --- a/Tests/Functional/TopicRegistryTest.php +++ /dev/null @@ -1,18 +0,0 @@ -get(TopicMetaRegistry::class); - - $this->assertInstanceOf(TopicMetaRegistry::class, $connection); - } -} diff --git a/Tests/Functional/TopicsCommandTest.php b/Tests/Functional/TopicsCommandTest.php deleted file mode 100644 index f5c1595..0000000 --- a/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/Tests/Functional/UseCasesTest.php b/Tests/Functional/UseCasesTest.php index 7e0bcfb..7417412 100644 --- a/Tests/Functional/UseCasesTest.php +++ b/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/Tests/Functional/WebTestCase.php b/Tests/Functional/WebTestCase.php index 4b254cc..6a348a9 100644 --- a/Tests/Functional/WebTestCase.php +++ b/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/Tests/Unit/Consumption/Extension/DoctrineClearIdentityMapExtensionTest.php b/Tests/Unit/Consumption/Extension/DoctrineClearIdentityMapExtensionTest.php index 08403bf..7c5c2dd 100644 --- a/Tests/Unit/Consumption/Extension/DoctrineClearIdentityMapExtensionTest.php +++ b/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/Tests/Unit/Consumption/Extension/DoctrineClosedEntityManagerExtensionTest.php b/Tests/Unit/Consumption/Extension/DoctrineClosedEntityManagerExtensionTest.php new file mode 100644 index 0000000..8e71203 --- /dev/null +++ b/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/Tests/Unit/Consumption/Extension/DoctrinePingConnectionExtensionTest.php b/Tests/Unit/Consumption/Extension/DoctrinePingConnectionExtensionTest.php index acc23bc..36df82e 100644 --- a/Tests/Unit/Consumption/Extension/DoctrinePingConnectionExtensionTest.php +++ b/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/Tests/Unit/Consumption/Extension/ResetServicesExtensionTest.php b/Tests/Unit/Consumption/Extension/ResetServicesExtensionTest.php new file mode 100644 index 0000000..63282a2 --- /dev/null +++ b/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/Tests/Unit/DependencyInjection/Compiler/AddTopicMetaPassTest.php b/Tests/Unit/DependencyInjection/Compiler/AddTopicMetaPassTest.php deleted file mode 100644 index 94537fd..0000000 --- a/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/Tests/Unit/DependencyInjection/Compiler/BuildClientExtensionsPassTest.php b/Tests/Unit/DependencyInjection/Compiler/BuildClientExtensionsPassTest.php deleted file mode 100644 index e98184b..0000000 --- a/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/Tests/Unit/DependencyInjection/Compiler/BuildClientRoutingPassTest.php b/Tests/Unit/DependencyInjection/Compiler/BuildClientRoutingPassTest.php deleted file mode 100644 index f1b6785..0000000 --- a/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/Tests/Unit/DependencyInjection/Compiler/BuildConsumptionExtensionsPassTest.php b/Tests/Unit/DependencyInjection/Compiler/BuildConsumptionExtensionsPassTest.php deleted file mode 100644 index a7614bc..0000000 --- a/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/Tests/Unit/DependencyInjection/Compiler/BuildExclusiveCommandsExtensionPassTest.php b/Tests/Unit/DependencyInjection/Compiler/BuildExclusiveCommandsExtensionPassTest.php deleted file mode 100644 index 395078a..0000000 --- a/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/Tests/Unit/DependencyInjection/Compiler/BuildProcessorRegistryPassTest.php b/Tests/Unit/DependencyInjection/Compiler/BuildProcessorRegistryPassTest.php deleted file mode 100644 index 9c7a00c..0000000 --- a/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/Tests/Unit/DependencyInjection/Compiler/BuildQueueMetaRegistryPassTest.php b/Tests/Unit/DependencyInjection/Compiler/BuildQueueMetaRegistryPassTest.php deleted file mode 100644 index 46c315a..0000000 --- a/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/Tests/Unit/DependencyInjection/Compiler/BuildTopicMetaSubscribersPassTest.php b/Tests/Unit/DependencyInjection/Compiler/BuildTopicMetaSubscribersPassTest.php deleted file mode 100644 index 7e166b0..0000000 --- a/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/Tests/Unit/DependencyInjection/Compiler/Mock/EmptyCommandSubscriber.php b/Tests/Unit/DependencyInjection/Compiler/Mock/EmptyCommandSubscriber.php deleted file mode 100644 index 27fb161..0000000 --- a/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/Tests/Unit/DependencyInjection/Compiler/Mock/ExclusiveCommandSubscriber.php b/Tests/Unit/DependencyInjection/Compiler/Mock/ExclusiveCommandSubscriber.php deleted file mode 100644 index 742758a..0000000 --- a/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/Tests/Unit/DependencyInjection/Compiler/Mock/InvalidCommandSubscriber.php b/Tests/Unit/DependencyInjection/Compiler/Mock/InvalidCommandSubscriber.php deleted file mode 100644 index 44b32a4..0000000 --- a/Tests/Unit/DependencyInjection/Compiler/Mock/InvalidCommandSubscriber.php +++ /dev/null @@ -1,13 +0,0 @@ - 'the-command-name', - 'queueName' => 'the-command-queue-name', - ]; - } -} diff --git a/Tests/Unit/DependencyInjection/Compiler/Mock/ProcessorNameTopicSubscriber.php b/Tests/Unit/DependencyInjection/Compiler/Mock/ProcessorNameTopicSubscriber.php deleted file mode 100644 index 9574ee4..0000000 --- a/Tests/Unit/DependencyInjection/Compiler/Mock/ProcessorNameTopicSubscriber.php +++ /dev/null @@ -1,17 +0,0 @@ - [ - 'processorName' => 'subscriber-processor-name', - ], - ]; - } -} diff --git a/Tests/Unit/DependencyInjection/Compiler/Mock/QueueNameTopicSubscriber.php b/Tests/Unit/DependencyInjection/Compiler/Mock/QueueNameTopicSubscriber.php deleted file mode 100644 index 6ed163d..0000000 --- a/Tests/Unit/DependencyInjection/Compiler/Mock/QueueNameTopicSubscriber.php +++ /dev/null @@ -1,17 +0,0 @@ - [ - 'queueName' => 'subscriber-queue-name', - ], - ]; - } -} diff --git a/Tests/Unit/DependencyInjection/Compiler/Mock/WithoutProcessorNameTopicSubscriber.php b/Tests/Unit/DependencyInjection/Compiler/Mock/WithoutProcessorNameTopicSubscriber.php deleted file mode 100644 index fa30d9f..0000000 --- a/Tests/Unit/DependencyInjection/Compiler/Mock/WithoutProcessorNameTopicSubscriber.php +++ /dev/null @@ -1,18 +0,0 @@ - [ - 'queueName' => 'a_queue_name', - 'queueNameHardcoded' => true, - ], - ]; - } -} diff --git a/Tests/Unit/DependencyInjection/ConfigurationTest.php b/Tests/Unit/DependencyInjection/ConfigurationTest.php index 05f4b5d..5330cde 100644 --- a/Tests/Unit/DependencyInjection/ConfigurationTest.php +++ b/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/Tests/Unit/DependencyInjection/EnqueueExtensionTest.php b/Tests/Unit/DependencyInjection/EnqueueExtensionTest.php index 4a59dc3..6358bd2 100644 --- a/Tests/Unit/DependencyInjection/EnqueueExtensionTest.php +++ b/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/Tests/Unit/EnqueueBundleTest.php b/Tests/Unit/EnqueueBundleTest.php index 270c4d3..7d5b023 100644 --- a/Tests/Unit/EnqueueBundleTest.php +++ b/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/Tests/Unit/Mocks/FooTransportFactory.php b/Tests/Unit/Mocks/FooTransportFactory.php deleted file mode 100644 index 5507d19..0000000 --- a/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/Tests/Unit/Mocks/TransportFactoryWithoutDriverFactory.php b/Tests/Unit/Mocks/TransportFactoryWithoutDriverFactory.php deleted file mode 100644 index f3a0032..0000000 --- a/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/Tests/Unit/Profiler/MessageQueueCollectorTest.php b/Tests/Unit/Profiler/MessageQueueCollectorTest.php index 62f7d6c..d6d638d 100644 --- a/Tests/Unit/Profiler/MessageQueueCollectorTest.php +++ b/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/Tests/fix_composer_json.php b/Tests/fix_composer_json.php index fc430e2..5c80237 100644 --- a/Tests/fix_composer_json.php +++ b/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/composer.json b/composer.json index 8890feb..99d237b 100644 --- a/composer.json +++ b/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/phpunit.xml.dist b/phpunit.xml.dist index ac0770e..974d2c3 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,16 +1,11 @@ - +