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 @@ +
# | -Topic | -Command | -Message | -Priority | -
---|---|---|---|---|
{{ loop.index }} | -{{ sentMessage.topic|default(null) }} | -{{ sentMessage.command|default(null) }} | -- |
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 @@ -