├── .github
└── workflows
│ └── test.yaml
├── .gitignore
├── .scrutinizer.yml
├── CHANGELOG
├── CODEOWNERS
├── Command
├── AnonConsumerCommand.php
├── BaseConsumerCommand.php
├── BaseRabbitMqCommand.php
├── BatchConsumerCommand.php
├── ConsumerCommand.php
├── DeleteCommand.php
├── DynamicConsumerCommand.php
├── MultipleConsumerCommand.php
├── PurgeConsumerCommand.php
├── RpcServerCommand.php
├── SetupFabricCommand.php
└── StdInProducerCommand.php
├── DataCollector
└── MessageDataCollector.php
├── DependencyInjection
├── Compiler
│ ├── InjectEventDispatcherPass.php
│ └── RegisterPartsPass.php
├── Configuration.php
└── OldSoundRabbitMqExtension.php
├── Event
├── AMQPEvent.php
├── AbstractAMQPEvent.php
├── AfterProcessingMessageEvent.php
├── BeforeProcessingMessageEvent.php
├── OnConsumeEvent.php
└── OnIdleEvent.php
├── MemoryChecker
├── MemoryConsumptionChecker.php
└── NativeMemoryUsageProvider.php
├── OldSoundRabbitMqBundle.php
├── Provider
├── ConnectionParametersProviderInterface.php
├── QueueOptionsProviderInterface.php
└── QueuesProviderInterface.php
├── README.md
├── RabbitMq
├── AMQPConnectionFactory.php
├── AMQPLoggedChannel.php
├── AmqpPartsHolder.php
├── AnonConsumer.php
├── BaseAmqp.php
├── BaseConsumer.php
├── BatchConsumer.php
├── BatchConsumerInterface.php
├── Binding.php
├── Consumer.php
├── ConsumerInterface.php
├── DequeuerAwareInterface.php
├── DequeuerInterface.php
├── DynamicConsumer.php
├── Exception
│ ├── AckStopConsumerException.php
│ ├── QueueNotFoundException.php
│ └── StopConsumerException.php
├── Fallback.php
├── MultipleConsumer.php
├── Producer.php
├── ProducerInterface.php
├── RpcClient.php
└── RpcServer.php
├── Resources
├── config
│ └── rabbitmq.xml
├── meta
│ └── LICENSE.md
└── views
│ └── Collector
│ └── collector.html.twig
├── Tests
├── Command
│ ├── BaseCommandTest.php
│ ├── ConsumerCommandTest.php
│ ├── DynamicConsumerCommandTest.php
│ ├── MultipleConsumerCommandTest.php
│ └── PurgeCommandTest.php
├── DependencyInjection
│ ├── Fixtures
│ │ ├── collector.yml
│ │ ├── collector_disabled.yml
│ │ ├── config_with_enable_logger.yml
│ │ ├── exchange_arguments.yml
│ │ ├── no_collector.yml
│ │ ├── no_exchange_options.yml
│ │ ├── rpc-clients.yml
│ │ └── test.yml
│ └── OldSoundRabbitMqExtensionTest.php
├── Event
│ ├── AfterProcessingMessageEventTest.php
│ ├── BeforeProcessingMessageEventTest.php
│ └── OnIdleEventTest.php
├── Manager
│ └── MemoryConsumptionCheckerTest.php
├── RabbitMq
│ ├── AMQPConnectionFactoryTest.php
│ ├── BaseAmqpTest.php
│ ├── BaseConsumerTest.php
│ ├── BindingTest.php
│ ├── ConsumerTest.php
│ ├── DynamicConsumerTest.php
│ ├── Fixtures
│ │ ├── AMQPConnection.php
│ │ └── AMQPSocketConnection.php
│ ├── MultipleConsumerTest.php
│ ├── RpcClientTest.php
│ └── RpcServerTest.php
└── bootstrap.php
├── composer.json
├── phpstan.neon.dist
└── phpunit.xml.dist
/.github/workflows/test.yaml:
--------------------------------------------------------------------------------
1 | name: Test
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | test:
7 | name: PHP ${{ matrix.php-version }} + Symfony ${{ matrix.symfony-version }}
8 |
9 | runs-on: ubuntu-18.04
10 |
11 | continue-on-error: ${{ matrix.experimental }}
12 |
13 | strategy:
14 | matrix:
15 | include:
16 | - php-version: '7.1'
17 | symfony-version: '^4.3'
18 | composer-version: v1
19 | stability: stable
20 | coverage: none
21 | experimental: false
22 | - php-version: '7.2'
23 | symfony-version: '^4.3'
24 | composer-version: v1
25 | stability: stable
26 | coverage: none
27 | experimental: false
28 | - php-version: '7.2'
29 | symfony-version: '^5.0'
30 | composer-version: v1
31 | stability: stable
32 | coverage: none
33 | experimental: false
34 | - php-version: '7.3'
35 | symfony-version: '^5.0'
36 | composer-version: v1
37 | stability: stable
38 | coverage: none
39 | experimental: false
40 | - php-version: '7.4'
41 | symfony-version: '^5.0'
42 | composer-version: v2
43 | stability: stable
44 | coverage: xdebug
45 | experimental: false
46 | - php-version: '8.0'
47 | symfony-version: '^5.0'
48 | composer-version: v2
49 | stability: RC
50 | coverage: none
51 | experimental: false
52 |
53 | steps:
54 | - name: Checkout
55 | uses: actions/checkout@v2
56 |
57 | - name: Setup PHP
58 | uses: shivammathur/setup-php@v2
59 | with:
60 | coverage: ${{ matrix.coverage }}
61 | ini-values: "memory_limit=-1"
62 | php-version: ${{ matrix.php-version }}
63 | tools: composer:${{ matrix.composer-version }}
64 |
65 | - name: Validate composer.json
66 | run: composer validate --no-check-lock
67 |
68 | - name: Configure Symfony version
69 | run: composer require --no-update symfony/framework-bundle "${{ matrix.symfony-version }}"
70 |
71 | - name: Configure composer stability
72 | if: matrix.stability != 'stable'
73 | run: composer config minimum-stability "${{ matrix.stability }}"
74 |
75 | - name: Install Composer dependencies
76 | uses: ramsey/composer-install@v1
77 | with:
78 | composer-options: "--prefer-dist"
79 |
80 | - name: Setup problem matchers for PHP
81 | run: echo "::add-matcher::${{ runner.tool_cache }}/php.json"
82 |
83 | - name: Setup problem matchers for PHPUnit
84 | run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
85 |
86 | - name: Run PHPUnit
87 | if: matrix.coverage == 'none'
88 | run: vendor/bin/phpunit
89 |
90 | - name: Run PHPUnit with coverage
91 | if: matrix.coverage != 'none'
92 | run: vendor/bin/phpunit --coverage-clover=coverage.clover
93 |
94 | - name: Run PHPStan
95 | run: vendor/bin/phpstan analyse
96 |
97 | - name: Upload Scrutinizer coverage
98 | if: matrix.coverage != 'none'
99 | continue-on-error: true
100 | uses: sudo-bot/action-scrutinizer@latest
101 | with:
102 | cli-args: "--format=php-clover coverage.clover"
103 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | composer.lock
2 | composer.phar
3 | vendor
--------------------------------------------------------------------------------
/.scrutinizer.yml:
--------------------------------------------------------------------------------
1 | build:
2 | dependencies:
3 | before:
4 | - composer config minimum-stability RC
5 | nodes:
6 | analysis:
7 | tests:
8 | override:
9 | - php-scrutinizer-run
10 | filter:
11 | excluded_paths:
12 | - tests/*
13 | - vendor/*
14 | checks:
15 | php:
16 | code_rating: true
17 | remove_extra_empty_lines: true
18 | remove_php_closing_tag: true
19 | remove_trailing_whitespace: true
20 | fix_use_statements:
21 | remove_unused: true
22 | preserve_multiple: false
23 | preserve_blanklines: true
24 | order_alphabetically: true
25 | fix_php_opening_tag: true
26 | fix_linefeed: true
27 | fix_line_ending: true
28 | fix_identation_4spaces: true
29 | fix_doc_comments: true
30 | tools:
31 | external_code_coverage: true
32 | php_code_sniffer:
33 | config:
34 | standard: PSR2
35 | filter:
36 | paths: ['src']
37 | php_loc:
38 | enabled: true
39 | excluded_dirs: [vendor, tests, examples]
40 | php_cpd:
41 | enabled: true
42 | excluded_dirs: [vendor, tests, examples]
43 |
--------------------------------------------------------------------------------
/CHANGELOG:
--------------------------------------------------------------------------------
1 | - 2017-01-22
2 | * Add `graceful_max_execution_timeout`
3 |
4 | - 2015-02-07
5 | * Added possibility to set serialize/unserialize function for rpc servers/clients
6 |
7 | - 2014-11-27
8 | * Added interface `OldSound\RabbitMqBundle\Provider\QueuesProviderInterface`
9 | * Added `queues_provider` configuration for multiple consumer
10 |
11 | - 2014-07-21
12 | * Added `reconnect` method into `OldSound\RabbitMqBundle\RabbitMq\BaseAmqp`
13 |
14 | - 2014-02-24
15 | * Add a parameter to RPC client configuration to disable auto unserialize when adding call results to results array.
16 |
17 | - 2013-01-18
18 | * adds an an optional parameter for the AMQP Message Properties for the publish method of the Producer, so they can be set as well. For example, seeting the application_headers is now possible.
19 |
20 | - 2012-06-04
21 | * Revert PR #46. It is still possible to override parameter classes but in a proper way.
22 | * Some default options for exchanges declared in the "producers" config section
23 | have changed to match the defaults of exchanges declared in the "consumers" section.
24 | The affected settings are:
25 | * `durable` was changed from `false` to `true`,
26 | * `auto_delete` was changed from `true` to `false`.
27 | * Adds basic_reject functionality to consumers. A message can be rejected by returning `false` from a callback.
28 |
29 | - 2012-05-29
30 | * Merged PR #46 adding compiler passes for the configuration. Now the parameter classes can be overriden.
31 | * Treats queue arguments as a variableNode in the configuration to allow declaring HA Queues.
32 |
33 | - 2012-01-03
34 | * Merged PR #14 Now instances of `PhpAmqpLib\Message\AMQPMessage` are passed to consumers instead of just the message body.
35 | The message body can be obtained then by writing `$msg->body` inside the `execute` method.
36 | * Merged PR #13 removing the need for the ContainerAwareInterface on consumers.
37 | * `rabbitmq:consumer` now takes a `--route` argument that can be used to specify the routing key.
38 |
39 | - 2011-11-25:
40 | * Fixed autoload configuration example
41 | * Adds a producer that can publish data coming from STDIN. The use case will be to use it in combination with unix pipes.
42 |
43 | - 2011-11-24:
44 | * The rabbitmq:consumer command consumes messages forever unless the -m option is provided.
45 | * The -m option for the rabbitmq:consumer command must be greater null or greater than 0.
46 | * Fixed issues #2 #7 #11 and #12.
47 | * Updated the bundle to use the latest version from videlalvaro/php-amqplib.
48 | * Updated installation/setup instructions.
49 |
--------------------------------------------------------------------------------
/CODEOWNERS:
--------------------------------------------------------------------------------
1 | #####################################################
2 | #
3 | # List of approvers for EmagTechLabs/RabbitMQBundle
4 | #
5 | #####################################################
6 | #
7 | # Learn about CODEOWNERS file format:
8 | # https://help.github.com/en/articles/about-code-owners
9 | #
10 |
11 | * @mihaileu
12 |
--------------------------------------------------------------------------------
/Command/AnonConsumerCommand.php:
--------------------------------------------------------------------------------
1 | setName('rabbitmq:anon-consumer');
12 | $this->setDescription('Executes an anonymous consumer');
13 | $this->getDefinition()->getOption('messages')->setDefault(1);
14 | $this->getDefinition()->getOption('route')->setDefault('#');
15 |
16 | }
17 |
18 | protected function getConsumerService()
19 | {
20 | return 'old_sound_rabbit_mq.%s_anon';
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Command/BaseConsumerCommand.php:
--------------------------------------------------------------------------------
1 | consumer instanceof Consumer) {
23 | // Process current message, then halt consumer
24 | $this->consumer->forceStopConsumer();
25 |
26 | // Halt consumer if waiting for a new message from the queue
27 | try {
28 | $this->consumer->stopConsuming();
29 | } catch (AMQPTimeoutException $e) {}
30 | }
31 | }
32 |
33 | public function restartConsumer()
34 | {
35 | // TODO: Implement restarting of consumer
36 | }
37 |
38 | protected function configure()
39 | {
40 | parent::configure();
41 |
42 | $this
43 | ->addArgument('name', InputArgument::REQUIRED, 'Consumer Name')
44 | ->addOption('messages', 'm', InputOption::VALUE_OPTIONAL, 'Messages to consume', 0)
45 | ->addOption('route', 'r', InputOption::VALUE_OPTIONAL, 'Routing Key', '')
46 | ->addOption('memory-limit', 'l', InputOption::VALUE_OPTIONAL, 'Allowed memory for this process (MB)', null)
47 | ->addOption('debug', 'd', InputOption::VALUE_NONE, 'Enable Debugging')
48 | ->addOption('without-signals', 'w', InputOption::VALUE_NONE, 'Disable catching of system signals')
49 | ;
50 | }
51 |
52 | /**
53 | * Executes the current command.
54 | *
55 | * @param InputInterface $input An InputInterface instance
56 | * @param OutputInterface $output An OutputInterface instance
57 | *
58 | * @return integer 0 if everything went fine, or an error code
59 | *
60 | * @throws \InvalidArgumentException When the number of messages to consume is less than 0
61 | * @throws \BadFunctionCallException When the pcntl is not installed and option -s is true
62 | */
63 | protected function execute(InputInterface $input, OutputInterface $output)
64 | {
65 | if (defined('AMQP_WITHOUT_SIGNALS') === false) {
66 | define('AMQP_WITHOUT_SIGNALS', $input->getOption('without-signals'));
67 | }
68 |
69 | if (!AMQP_WITHOUT_SIGNALS && extension_loaded('pcntl')) {
70 | if (!function_exists('pcntl_signal')) {
71 | throw new \BadFunctionCallException("Function 'pcntl_signal' is referenced in the php.ini 'disable_functions' and can't be called.");
72 | }
73 |
74 | pcntl_signal(SIGTERM, array(&$this, 'stopConsumer'));
75 | pcntl_signal(SIGINT, array(&$this, 'stopConsumer'));
76 | pcntl_signal(SIGHUP, array(&$this, 'restartConsumer'));
77 | }
78 |
79 | if (defined('AMQP_DEBUG') === false) {
80 | define('AMQP_DEBUG', (bool) $input->getOption('debug'));
81 | }
82 |
83 | $this->amount = $input->getOption('messages');
84 |
85 | if (0 > (int) $this->amount) {
86 | throw new \InvalidArgumentException("The -m option should be null or greater than 0");
87 | }
88 | $this->initConsumer($input);
89 |
90 | return $this->consumer->consume($this->amount);
91 | }
92 |
93 | protected function initConsumer($input)
94 | {
95 | $this->consumer = $this->getContainer()
96 | ->get(sprintf($this->getConsumerService(), $input->getArgument('name')));
97 |
98 | if (!is_null($input->getOption('memory-limit')) && ctype_digit((string) $input->getOption('memory-limit')) && $input->getOption('memory-limit') > 0) {
99 | $this->consumer->setMemoryLimit($input->getOption('memory-limit'));
100 | }
101 | $this->consumer->setRoutingKey($input->getOption('route'));
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/Command/BaseRabbitMqCommand.php:
--------------------------------------------------------------------------------
1 | container = $container;
22 | }
23 |
24 | /**
25 | * @return ContainerInterface
26 | */
27 | public function getContainer()
28 | {
29 | return $this->container;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Command/BatchConsumerCommand.php:
--------------------------------------------------------------------------------
1 | consumer instanceof BatchConsumer) {
22 | // Process current message, then halt consumer
23 | $this->consumer->forceStopConsumer();
24 |
25 | // Halt consumer if waiting for a new message from the queue
26 | try {
27 | $this->consumer->stopConsuming();
28 | } catch (AMQPTimeoutException $e) {}
29 | }
30 | }
31 |
32 | protected function configure()
33 | {
34 | parent::configure();
35 |
36 | $this
37 | ->setName('rabbitmq:batch:consumer')
38 | ->addArgument('name', InputArgument::REQUIRED, 'Consumer Name')
39 | ->addOption('batches', 'b', InputOption::VALUE_OPTIONAL, 'Number of batches to consume', 0)
40 | ->addOption('route', 'r', InputOption::VALUE_OPTIONAL, 'Routing Key', '')
41 | ->addOption('memory-limit', 'l', InputOption::VALUE_OPTIONAL, 'Allowed memory for this process', null)
42 | ->addOption('debug', 'd', InputOption::VALUE_NONE, 'Enable Debugging')
43 | ->addOption('without-signals', 'w', InputOption::VALUE_NONE, 'Disable catching of system signals')
44 | ->setDescription('Executes a Batch Consumer');
45 | ;
46 | }
47 |
48 | /**
49 | * Executes the current command.
50 | *
51 | * @param InputInterface $input An InputInterface instance
52 | * @param OutputInterface $output An OutputInterface instance
53 | *
54 | * @return integer 0 if everything went fine, or an error code
55 | *
56 | * @throws \InvalidArgumentException When the number of batches to consume is less than 0
57 | * @throws \BadFunctionCallException When the pcntl is not installed and option -s is true
58 | */
59 | protected function execute(InputInterface $input, OutputInterface $output)
60 | {
61 | if (defined('AMQP_WITHOUT_SIGNALS') === false) {
62 | define('AMQP_WITHOUT_SIGNALS', $input->getOption('without-signals'));
63 | }
64 |
65 | if (!AMQP_WITHOUT_SIGNALS && extension_loaded('pcntl')) {
66 | if (!function_exists('pcntl_signal')) {
67 | throw new \BadFunctionCallException("Function 'pcntl_signal' is referenced in the php.ini 'disable_functions' and can't be called.");
68 | }
69 |
70 | pcntl_signal(SIGTERM, array(&$this, 'stopConsumer'));
71 | pcntl_signal(SIGINT, array(&$this, 'stopConsumer'));
72 | }
73 |
74 | if (defined('AMQP_DEBUG') === false) {
75 | define('AMQP_DEBUG', (bool) $input->getOption('debug'));
76 | }
77 |
78 | $batchAmountTarget = (int) $input->getOption('batches');
79 |
80 | if (0 > $batchAmountTarget) {
81 | throw new \InvalidArgumentException("The -b option should be greater than 0");
82 | }
83 |
84 | $this->initConsumer($input);
85 |
86 | return $this->consumer->consume($batchAmountTarget);
87 | }
88 |
89 | /**
90 | * @param InputInterface $input
91 | */
92 | protected function initConsumer(InputInterface $input)
93 | {
94 | $this->consumer = $this->getContainer()
95 | ->get(sprintf($this->getConsumerService(), $input->getArgument('name')));
96 |
97 | if (null !== $input->getOption('memory-limit') &&
98 | ctype_digit((string) $input->getOption('memory-limit')) &&
99 | (int) $input->getOption('memory-limit') > 0
100 | ) {
101 | $this->consumer->setMemoryLimit($input->getOption('memory-limit'));
102 | }
103 | $this->consumer->setRoutingKey($input->getOption('route'));
104 | }
105 |
106 | /**
107 | * @return string
108 | */
109 | protected function getConsumerService()
110 | {
111 | return 'old_sound_rabbit_mq.%s_batch';
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/Command/ConsumerCommand.php:
--------------------------------------------------------------------------------
1 | setDescription('Executes a consumer');
11 | $this->setName('rabbitmq:consumer');
12 | }
13 |
14 | protected function getConsumerService()
15 | {
16 | return 'old_sound_rabbit_mq.%s_consumer';
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Command/DeleteCommand.php:
--------------------------------------------------------------------------------
1 | addArgument('name', InputArgument::REQUIRED, 'Consumer Name')
19 | ->setDescription('Delete a consumer\'s queue')
20 | ->addOption('no-confirmation', null, InputOption::VALUE_NONE, 'Whether it must be confirmed before deleting');
21 |
22 | $this->setName('rabbitmq:delete');
23 | }
24 |
25 | /**
26 | * @param InputInterface $input
27 | * @param OutputInterface $output
28 | *
29 | * @return int
30 | */
31 | protected function execute(InputInterface $input, OutputInterface $output)
32 | {
33 | $noConfirmation = (bool) $input->getOption('no-confirmation');
34 |
35 | if (!$noConfirmation && $input->isInteractive()) {
36 | $question = new ConfirmationQuestion(
37 | sprintf(
38 | '
7 |
8 | {% endset %}
9 | {% set text %}
10 |
Exchange | 36 |Message body | 37 |
---|---|
{{ log.exchange }} | 43 |{{ log.msg.body }} | 44 |
50 | No messages were sent. 51 |
52 | {% endif %} 53 | {% endblock %} 54 | -------------------------------------------------------------------------------- /Tests/Command/BaseCommandTest.php: -------------------------------------------------------------------------------- 1 | application = $this->getMockBuilder('Symfony\\Component\\Console\\Application') 17 | ->disableOriginalConstructor() 18 | ->getMock(); 19 | $this->definition = $this->getMockBuilder('Symfony\\Component\\Console\\Input\\InputDefinition') 20 | ->disableOriginalConstructor() 21 | ->getMock(); 22 | $this->helperSet = $this->getMockBuilder('Symfony\\Component\\Console\\Helper\\HelperSet')->getMock(); 23 | 24 | $this->application->expects($this->any()) 25 | ->method('getDefinition') 26 | ->will($this->returnValue($this->definition)); 27 | $this->definition->expects($this->any()) 28 | ->method('getArguments') 29 | ->will($this->returnValue(array())); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Tests/Command/ConsumerCommandTest.php: -------------------------------------------------------------------------------- 1 | definition->expects($this->any()) 14 | ->method('getOptions') 15 | ->will($this->returnValue(array( 16 | new InputOption('--verbose', '-v', InputOption::VALUE_NONE, 'Increase verbosity of messages.'), 17 | new InputOption('--env', '-e', InputOption::VALUE_REQUIRED, 'The Environment name.', 'dev'), 18 | new InputOption('--no-debug', null, InputOption::VALUE_NONE, 'Switches off debug mode.'), 19 | ))); 20 | $this->application->expects($this->once()) 21 | ->method('getHelperSet') 22 | ->will($this->returnValue($this->helperSet)); 23 | 24 | $this->command = new ConsumerCommand(); 25 | $this->command->setApplication($this->application); 26 | } 27 | 28 | /** 29 | * testInputsDefinitionCommand 30 | */ 31 | public function testInputsDefinitionCommand() 32 | { 33 | $definition = $this->command->getDefinition(); 34 | // check argument 35 | $this->assertTrue($definition->hasArgument('name')); 36 | $this->assertTrue($definition->getArgument('name')->isRequired()); // Name is required to find the service 37 | 38 | //check options 39 | $this->assertTrue($definition->hasOption('messages')); 40 | $this->assertTrue($definition->getOption('messages')->isValueOptional()); // It should accept value 41 | 42 | $this->assertTrue($definition->hasOption('route')); 43 | $this->assertTrue($definition->getOption('route')->isValueOptional()); // It should accept value 44 | 45 | $this->assertTrue($definition->hasOption('without-signals')); 46 | $this->assertFalse($definition->getOption('without-signals')->acceptValue()); // It shouldn't accept value because it is a true/false input 47 | 48 | $this->assertTrue($definition->hasOption('debug')); 49 | $this->assertFalse($definition->getOption('debug')->acceptValue()); // It shouldn't accept value because it is a true/false input 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Tests/Command/DynamicConsumerCommandTest.php: -------------------------------------------------------------------------------- 1 | definition->expects($this->any()) 15 | ->method('getOptions') 16 | ->will($this->returnValue(array( 17 | new InputOption('--verbose', '-v', InputOption::VALUE_NONE, 'Increase verbosity of messages.'), 18 | new InputOption('--env', '-e', InputOption::VALUE_REQUIRED, 'The Environment name.', 'dev'), 19 | new InputOption('--no-debug', null, InputOption::VALUE_NONE, 'Switches off debug mode.'), 20 | ))); 21 | $this->application->expects($this->once()) 22 | ->method('getHelperSet') 23 | ->will($this->returnValue($this->helperSet)); 24 | 25 | $this->command = new DynamicConsumerCommand(); 26 | $this->command->setApplication($this->application); 27 | } 28 | 29 | /** 30 | * testInputsDefinitionCommand 31 | */ 32 | public function testInputsDefinitionCommand() 33 | { 34 | // check argument 35 | $definition = $this->command->getDefinition(); 36 | $this->assertTrue($definition->hasArgument('name')); 37 | $this->assertTrue($definition->getArgument('name')->isRequired()); // Name is required to find the service 38 | 39 | $this->assertTrue($definition->hasArgument('context')); 40 | $this->assertTrue($definition->getArgument('context')->isRequired()); // Context is required for the queue options provider 41 | 42 | //check options 43 | $this->assertTrue($definition->hasOption('messages')); 44 | $this->assertTrue($definition->getOption('messages')->isValueOptional()); // It should accept value 45 | 46 | $this->assertTrue($definition->hasOption('route')); 47 | $this->assertTrue($definition->getOption('route')->isValueOptional()); // It should accept value 48 | 49 | $this->assertTrue($definition->hasOption('without-signals')); 50 | $this->assertFalse($definition->getOption('without-signals')->acceptValue()); // It shouldn't accept value because it is a true/false input 51 | 52 | $this->assertTrue($definition->hasOption('debug')); 53 | $this->assertFalse($definition->getOption('debug')->acceptValue()); // It shouldn't accept value because it is a true/false input 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Tests/Command/MultipleConsumerCommandTest.php: -------------------------------------------------------------------------------- 1 | definition->expects($this->any()) 15 | ->method('getOptions') 16 | ->will($this->returnValue(array( 17 | new InputOption('--verbose', '-v', InputOption::VALUE_NONE, 'Increase verbosity of messages.'), 18 | new InputOption('--env', '-e', InputOption::VALUE_REQUIRED, 'The Environment name.', 'dev'), 19 | new InputOption('--no-debug', null, InputOption::VALUE_NONE, 'Switches off debug mode.'), 20 | ))); 21 | $this->application->expects($this->once()) 22 | ->method('getHelperSet') 23 | ->will($this->returnValue($this->helperSet)); 24 | 25 | $this->command = new MultipleConsumerCommand(); 26 | $this->command->setApplication($this->application); 27 | } 28 | 29 | /** 30 | * testInputsDefinitionCommand 31 | */ 32 | public function testInputsDefinitionCommand() 33 | { 34 | // check argument 35 | $definition = $this->command->getDefinition(); 36 | $this->assertTrue($definition->hasArgument('name')); 37 | $this->assertTrue($definition->getArgument('name')->isRequired()); // Name is required to find the service 38 | 39 | $this->assertTrue($definition->hasArgument('context')); 40 | $this->assertFalse($definition->getArgument('context')->isRequired()); // Context is required for the queue options provider 41 | 42 | //check options 43 | $this->assertTrue($definition->hasOption('messages')); 44 | $this->assertTrue($definition->getOption('messages')->isValueOptional()); // It should accept value 45 | 46 | $this->assertTrue($definition->hasOption('route')); 47 | $this->assertTrue($definition->getOption('route')->isValueOptional()); // It should accept value 48 | 49 | $this->assertTrue($definition->hasOption('without-signals')); 50 | $this->assertFalse($definition->getOption('without-signals')->acceptValue()); // It shouldn't accept value because it is a true/false input 51 | 52 | $this->assertTrue($definition->hasOption('debug')); 53 | $this->assertFalse($definition->getOption('debug')->acceptValue()); // It shouldn't accept value because it is a true/false input 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Tests/Command/PurgeCommandTest.php: -------------------------------------------------------------------------------- 1 | definition->expects($this->any()) 14 | ->method('getOptions') 15 | ->will($this->returnValue(array( 16 | new InputOption('--no-confirmation', null, InputOption::VALUE_NONE, 'Switches off confirmation mode.'), 17 | ))); 18 | $this->application->expects($this->once()) 19 | ->method('getHelperSet') 20 | ->will($this->returnValue($this->helperSet)); 21 | 22 | $this->command = new PurgeConsumerCommand(); 23 | $this->command->setApplication($this->application); 24 | } 25 | 26 | /** 27 | * testInputsDefinitionCommand 28 | */ 29 | public function testInputsDefinitionCommand() 30 | { 31 | // check argument 32 | $definition = $this->command->getDefinition(); 33 | $this->assertTrue($definition->hasArgument('name')); 34 | $this->assertTrue($definition->getArgument('name')->isRequired()); // Name is required to find the service 35 | 36 | //check options 37 | $this->assertTrue($definition->hasOption('no-confirmation')); 38 | $this->assertFalse($definition->getOption('no-confirmation')->acceptValue()); // It shouldn't accept value because it is a true/false input 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Tests/DependencyInjection/Fixtures/collector.yml: -------------------------------------------------------------------------------- 1 | old_sound_rabbit_mq: 2 | 3 | enable_collector: true 4 | 5 | connections: 6 | default: 7 | 8 | producers: 9 | default_producer: 10 | exchange_options: 11 | name: default_exchange 12 | type: direct 13 | 14 | consumers: 15 | default_consumer: 16 | exchange_options: 17 | name: default_exchange 18 | type: direct 19 | queue_options: 20 | name: default_queue 21 | callback: default.callback 22 | 23 | services: 24 | default.callback: 25 | -------------------------------------------------------------------------------- /Tests/DependencyInjection/Fixtures/collector_disabled.yml: -------------------------------------------------------------------------------- 1 | old_sound_rabbit_mq: 2 | 3 | enable_collector: false 4 | 5 | connections: 6 | default: 7 | 8 | producers: 9 | default_producer: 10 | exchange_options: 11 | name: default_exchange 12 | type: direct 13 | 14 | consumers: 15 | default_consumer: 16 | exchange_options: 17 | name: default_exchange 18 | type: direct 19 | queue_options: 20 | name: default_queue 21 | callback: default.callback 22 | services: 23 | default.callback: 24 | 25 | -------------------------------------------------------------------------------- /Tests/DependencyInjection/Fixtures/config_with_enable_logger.yml: -------------------------------------------------------------------------------- 1 | old_sound_rabbit_mq: 2 | 3 | enable_collector: true 4 | 5 | connections: 6 | default: 7 | 8 | producers: 9 | default_producer: 10 | exchange_options: 11 | name: default_exchange 12 | type: direct 13 | 14 | consumers: 15 | default_consumer: 16 | exchange_options: 17 | name: default_exchange 18 | type: direct 19 | queue_options: 20 | name: default_queue 21 | callback: default.callback 22 | enable_logger: true 23 | services: 24 | logger: 25 | class: \stdClass 26 | default.callback: 27 | 28 | -------------------------------------------------------------------------------- /Tests/DependencyInjection/Fixtures/exchange_arguments.yml: -------------------------------------------------------------------------------- 1 | old_sound_rabbit_mq: 2 | 3 | enable_collector: true 4 | 5 | connections: 6 | default: 7 | 8 | producers: 9 | producer: 10 | exchange_options: 11 | name: default_exchange 12 | type: direct 13 | arguments: {name: bar} 14 | 15 | consumers: 16 | consumer: 17 | exchange_options: 18 | name: default_exchange 19 | type: direct 20 | arguments: {name: bar} 21 | queue_options: 22 | name: foo_queue 23 | callback: consumer.callback 24 | services: 25 | consumer.callback: 26 | -------------------------------------------------------------------------------- /Tests/DependencyInjection/Fixtures/no_collector.yml: -------------------------------------------------------------------------------- 1 | old_sound_rabbit_mq: 2 | 3 | enable_collector: true 4 | 5 | connections: 6 | default: 7 | -------------------------------------------------------------------------------- /Tests/DependencyInjection/Fixtures/no_exchange_options.yml: -------------------------------------------------------------------------------- 1 | old_sound_rabbit_mq: 2 | 3 | connections: 4 | default: 5 | 6 | producers: 7 | producer: 8 | connection: default -------------------------------------------------------------------------------- /Tests/DependencyInjection/Fixtures/rpc-clients.yml: -------------------------------------------------------------------------------- 1 | old_sound_rabbit_mq: 2 | enable_collector: true 3 | connections: 4 | foo_connection: 5 | host: foo_host 6 | port: 123 7 | user: foo_user 8 | password: foo_password 9 | vhost: /foo 10 | default: 11 | rpc_clients: 12 | foo_client: 13 | connection: foo_connection 14 | unserializer: json_decode 15 | direct_reply_to: true 16 | lazy_client: 17 | connection: default 18 | lazy: true 19 | 20 | default_client: 21 | -------------------------------------------------------------------------------- /Tests/DependencyInjection/Fixtures/test.yml: -------------------------------------------------------------------------------- 1 | old_sound_rabbit_mq: 2 | 3 | enable_collector: true 4 | 5 | connections: 6 | foo_connection: 7 | host: foo_host 8 | port: 123 9 | user: foo_user 10 | password: foo_password 11 | vhost: /foo 12 | 13 | ssl_connection: 14 | host: ssl_host 15 | port: 123 16 | user: ssl_user 17 | password: ssl_password 18 | vhost: /ssl 19 | ssl_context: 20 | verify_peer: false 21 | 22 | lazy_connection: 23 | host: lazy_host 24 | port: 456 25 | user: lazy_user 26 | password: lazy_password 27 | vhost: /lazy 28 | lazy: true 29 | 30 | socket_connection: 31 | host: bar_host 32 | port: 789 33 | user: socket_user 34 | password: socket_password 35 | vhost: /socket 36 | lazy: false 37 | use_socket: true 38 | 39 | lazy_socket: 40 | host: joe_host 41 | port: 987 42 | user: lazy_socket_user 43 | password: lazy_socket_password 44 | vhost: /lazy_socket 45 | lazy: true 46 | use_socket: true 47 | 48 | default: 49 | default2: 50 | foo_default: 51 | bar_default: 52 | 53 | producers: 54 | foo_producer: 55 | class: My\Foo\Producer 56 | connection: foo_connection 57 | exchange_options: 58 | name: foo_exchange 59 | type: direct 60 | passive: true 61 | durable: false 62 | auto_delete: true 63 | internal: true 64 | nowait: true 65 | arguments: null 66 | ticket: null 67 | 68 | foo_producer_aliased: 69 | class: My\Foo\Producer 70 | connection: foo_connection 71 | exchange_options: 72 | name: foo_exchange 73 | type: direct 74 | passive: true 75 | durable: false 76 | auto_delete: true 77 | internal: true 78 | nowait: true 79 | arguments: null 80 | ticket: null 81 | service_alias: foo_producer_alias 82 | 83 | 84 | default_producer: 85 | exchange_options: 86 | name: default_exchange 87 | type: direct 88 | 89 | consumers: 90 | foo_consumer: 91 | connection: foo_connection 92 | timeout_wait: 3 93 | exchange_options: 94 | name: foo_exchange 95 | type: direct 96 | passive: true 97 | durable: false 98 | auto_delete: true 99 | internal: true 100 | nowait: true 101 | arguments: null 102 | ticket: null 103 | queue_options: 104 | name: foo_queue 105 | passive: true 106 | durable: false 107 | exclusive: true 108 | auto_delete: true 109 | nowait: true 110 | arguments: null 111 | ticket: null 112 | routing_keys: 113 | - 'android.#.upload' 114 | - 'iphone.upload' 115 | callback: foo.callback 116 | 117 | default_consumer: 118 | exchange_options: 119 | name: default_exchange 120 | type: direct 121 | queue_options: 122 | name: default_queue 123 | callback: default.callback 124 | 125 | qos_test_consumer: 126 | connection: foo_connection 127 | exchange_options: 128 | name: foo_exchange 129 | type: direct 130 | queue_options: 131 | name: foo_queue 132 | qos_options: 133 | prefetch_size: 1024 134 | prefetch_count: 1 135 | global: true 136 | callback: foo.callback 137 | 138 | multiple_consumers: 139 | multi_test_consumer: 140 | connection: foo_connection 141 | timeout_wait: 3 142 | exchange_options: 143 | name: foo_multiple_exchange 144 | type: direct 145 | queues: 146 | multi-test-1: 147 | name: multi_test_1 148 | callback: foo.multiple_test1.callback 149 | multi-test-2: 150 | name: foo_bar_2 151 | passive: true 152 | durable: false 153 | exclusive: true 154 | auto_delete: true 155 | nowait: true 156 | arguments: null 157 | ticket: null 158 | routing_keys: 159 | - 'android.upload' 160 | - 'iphone.upload' 161 | callback: foo.multiple_test2.callback 162 | queues_provider: foo.queues_provider 163 | 164 | dynamic_consumers: 165 | foo_dyn_consumer: 166 | connection: foo_default 167 | exchange_options: 168 | name: foo_dynamic_exchange 169 | type: direct 170 | callback: foo.dynamic.callback 171 | queue_options_provider: foo.dynamic.provider 172 | bar_dyn_consumer: 173 | connection: bar_default 174 | exchange_options: 175 | name: bar_dynamic_exchange 176 | type: direct 177 | callback: bar.dynamic.callback 178 | queue_options_provider: bar.dynamic.provider 179 | bindings: 180 | - {exchange: foo, destination: bar, routing_key: baz} 181 | - {exchange: moo, connection: default2, destination: cow, nowait: true, destination_is_exchange: true, arguments: {moo: cow}} 182 | anon_consumers: 183 | foo_anon_consumer: 184 | connection: foo_connection 185 | exchange_options: 186 | name: foo_anon_exchange 187 | type: direct 188 | passive: true 189 | durable: false 190 | auto_delete: true 191 | internal: true 192 | nowait: true 193 | arguments: null 194 | ticket: null 195 | callback: foo_anon.callback 196 | 197 | default_anon_consumer: 198 | exchange_options: 199 | name: default_anon_exchange 200 | type: direct 201 | callback: default_anon.callback 202 | 203 | rpc_clients: 204 | foo_client: 205 | connection: foo_connection 206 | unserializer: json_decode 207 | direct_reply_to: true 208 | 209 | default_client: 210 | 211 | rpc_servers: 212 | foo_server: 213 | connection: foo_connection 214 | callback: foo_server.callback 215 | serializer: json_encode 216 | 217 | default_server: 218 | callback: default_server.callback 219 | 220 | server_with_queue_options: 221 | callback: server_with_queue_options.callback 222 | queue_options: 223 | name: "server_with_queue_options-queue" 224 | 225 | server_with_exchange_options: 226 | callback: server_with_exchange_options.callback 227 | exchange_options: 228 | name: exchange 229 | type: topic 230 | services: 231 | foo.callback: 232 | default.callback: 233 | foo.multiple_test1.callback: 234 | foo.multiple_test2.callback: 235 | foo.queues_provider: 236 | foo.dynamic.callback: 237 | foo.dynamic.provider: 238 | bar.dynamic.provider: 239 | bar.dynamic.callback: 240 | foo_anon.callback: 241 | default_anon.callback: 242 | foo_server.callback: 243 | default_server.callback: 244 | server_with_queue_options.callback: 245 | server_with_exchange_options.callback: 246 | -------------------------------------------------------------------------------- /Tests/Event/AfterProcessingMessageEventTest.php: -------------------------------------------------------------------------------- 1 | getMockBuilder('\PhpAmqpLib\Connection\AMQPStreamConnection') 21 | ->disableOriginalConstructor() 22 | ->getMock(), 23 | $this->getMockBuilder('\PhpAmqpLib\Channel\AMQPChannel') 24 | ->disableOriginalConstructor() 25 | ->getMock() 26 | ); 27 | } 28 | 29 | public function testEvent() 30 | { 31 | $AMQPMessage = new AMQPMessage('body'); 32 | $consumer = $this->getConsumer(); 33 | $event = new AfterProcessingMessageEvent($consumer, $AMQPMessage); 34 | $this->assertSame($AMQPMessage, $event->getAMQPMessage()); 35 | $this->assertSame($consumer, $event->getConsumer()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Tests/Event/BeforeProcessingMessageEventTest.php: -------------------------------------------------------------------------------- 1 | getMockBuilder('\PhpAmqpLib\Connection\AMQPStreamConnection') 21 | ->disableOriginalConstructor() 22 | ->getMock(), 23 | $this->getMockBuilder('\PhpAmqpLib\Channel\AMQPChannel') 24 | ->disableOriginalConstructor() 25 | ->getMock() 26 | ); 27 | } 28 | 29 | public function testEvent() 30 | { 31 | $AMQPMessage = new AMQPMessage('body'); 32 | $consumer = $this->getConsumer(); 33 | $event = new BeforeProcessingMessageEvent($consumer, $AMQPMessage); 34 | $this->assertSame($AMQPMessage, $event->getAMQPMessage()); 35 | $this->assertSame($consumer, $event->getConsumer()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Tests/Event/OnIdleEventTest.php: -------------------------------------------------------------------------------- 1 | getMockBuilder('\PhpAmqpLib\Connection\AMQPStreamConnection') 20 | ->disableOriginalConstructor() 21 | ->getMock(), 22 | $this->getMockBuilder('\PhpAmqpLib\Channel\AMQPChannel') 23 | ->disableOriginalConstructor() 24 | ->getMock() 25 | ); 26 | } 27 | 28 | public function testShouldAllowGetConsumerSetInConstructor() 29 | { 30 | $consumer = $this->getConsumer(); 31 | $event = new OnIdleEvent($consumer); 32 | 33 | $this->assertSame($consumer, $event->getConsumer()); 34 | } 35 | 36 | public function testShouldSetForceStopToTrueInConstructor() 37 | { 38 | $consumer = $this->getConsumer(); 39 | $event = new OnIdleEvent($consumer); 40 | 41 | $this->assertTrue($event->isForceStop()); 42 | } 43 | 44 | public function testShouldReturnPreviouslySetForceStop() 45 | { 46 | $consumer = $this->getConsumer(); 47 | $event = new OnIdleEvent($consumer); 48 | 49 | //guard 50 | $this->assertTrue($event->isForceStop()); 51 | 52 | $event->setForceStop(false); 53 | $this->assertFalse($event->isForceStop()); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Tests/Manager/MemoryConsumptionCheckerTest.php: -------------------------------------------------------------------------------- 1 | getMockBuilder('OldSound\\RabbitMqBundle\\MemoryChecker\\NativeMemoryUsageProvider')->getMock(); 23 | $memoryUsageProvider->expects($this->any())->method('getMemoryUsage')->willReturn($currentMemoryUsage); 24 | 25 | $memoryManager = new MemoryConsumptionChecker($memoryUsageProvider); 26 | 27 | $this->assertFalse($memoryManager->isRamAlmostOverloaded($maxConsumptionAllowed, $allowedConsumptionUntil)); 28 | } 29 | 30 | public function testMemoryIsAlmostOverloaded() 31 | { 32 | $currentMemoryUsage = '9M'; 33 | $allowedConsumptionUntil = '2M'; 34 | $maxConsumptionAllowed = '10M'; 35 | 36 | $memoryUsageProvider = $this->getMockBuilder('OldSound\\RabbitMqBundle\\MemoryChecker\\NativeMemoryUsageProvider')->getMock(); 37 | $memoryUsageProvider->expects($this->any())->method('getMemoryUsage')->willReturn($currentMemoryUsage); 38 | 39 | $memoryManager = new MemoryConsumptionChecker($memoryUsageProvider); 40 | 41 | $this->assertTrue($memoryManager->isRamAlmostOverloaded($maxConsumptionAllowed, $allowedConsumptionUntil)); 42 | } 43 | 44 | public function testMemoryExactValueIsNotAlmostOverloaded() 45 | { 46 | $currentMemoryUsage = '7M'; 47 | $maxConsumptionAllowed = '10M'; 48 | 49 | $memoryUsageProvider = $this->getMockBuilder('OldSound\\RabbitMqBundle\\MemoryChecker\\NativeMemoryUsageProvider')->getMock(); 50 | $memoryUsageProvider->expects($this->any())->method('getMemoryUsage')->willReturn($currentMemoryUsage); 51 | 52 | $memoryManager = new MemoryConsumptionChecker($memoryUsageProvider); 53 | 54 | $this->assertFalse($memoryManager->isRamAlmostOverloaded($maxConsumptionAllowed)); 55 | } 56 | 57 | public function testMemoryExactValueIsAlmostOverloaded() 58 | { 59 | $currentMemoryUsage = '11M'; 60 | $maxConsumptionAllowed = '10M'; 61 | 62 | $memoryUsageProvider = $this->getMockBuilder('OldSound\\RabbitMqBundle\\MemoryChecker\\NativeMemoryUsageProvider')->getMock(); 63 | $memoryUsageProvider->expects($this->any())->method('getMemoryUsage')->willReturn($currentMemoryUsage); 64 | 65 | $memoryManager = new MemoryConsumptionChecker($memoryUsageProvider); 66 | 67 | $this->assertTrue($memoryManager->isRamAlmostOverloaded($maxConsumptionAllowed)); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Tests/RabbitMq/AMQPConnectionFactoryTest.php: -------------------------------------------------------------------------------- 1 | createConnection(); 23 | $this->assertInstanceOf('OldSound\RabbitMqBundle\Tests\RabbitMq\Fixtures\AMQPConnection', $instance); 24 | $this->assertEquals(array( 25 | 'localhost', // host 26 | 5672, // port 27 | 'guest', // user 28 | 'guest', // password 29 | '/', // vhost 30 | false, // insist 31 | "AMQPLAIN", // login method 32 | null, // login response 33 | "en_US", // locale 34 | 3, // connection timeout 35 | 3, // read write timeout 36 | null, // context 37 | false, // keepalive 38 | 0, // heartbeat 39 | ), $instance->constructParams); 40 | } 41 | 42 | public function testSocketConnection() 43 | { 44 | $factory = new AMQPConnectionFactory( 45 | 'OldSound\RabbitMqBundle\Tests\RabbitMq\Fixtures\AMQPSocketConnection', 46 | array() 47 | ); 48 | 49 | /** @var AMQPSocketConnection $instance */ 50 | $instance = $factory->createConnection(); 51 | $this->assertInstanceOf('PhpAmqpLib\Connection\AMQPSocketConnection', $instance); 52 | $this->assertEquals(array( 53 | 'localhost', // host 54 | 5672, // port 55 | 'guest', // user 56 | 'guest', // password 57 | '/', // vhost 58 | false, // insist 59 | "AMQPLAIN", // login method 60 | null, // login response 61 | "en_US", // locale 62 | 3, // read_timeout 63 | false, // keepalive 64 | 3, // write_timeout 65 | 0, // heartbeat 66 | ), $instance->constructParams); 67 | } 68 | 69 | public function testSocketConnectionWithParams() 70 | { 71 | $factory = new AMQPConnectionFactory( 72 | 'OldSound\RabbitMqBundle\Tests\RabbitMq\Fixtures\AMQPSocketConnection', 73 | array( 74 | 'read_timeout' => 31, 75 | 'write_timeout' => 32, 76 | ) 77 | ); 78 | 79 | /** @var AMQPSocketConnection $instance */ 80 | $instance = $factory->createConnection(); 81 | $this->assertInstanceOf('PhpAmqpLib\Connection\AMQPSocketConnection', $instance); 82 | $this->assertEquals(array( 83 | 'localhost', // host 84 | 5672, // port 85 | 'guest', // user 86 | 'guest', // password 87 | '/', // vhost 88 | false, // insist 89 | "AMQPLAIN", // login method 90 | null, // login response 91 | "en_US", // locale 92 | 31, // read_timeout 93 | false, // keepalive 94 | 32, // write_timeout 95 | 0, // heartbeat 96 | ), $instance->constructParams); 97 | } 98 | 99 | public function testStandardConnectionParameters() 100 | { 101 | $factory = new AMQPConnectionFactory( 102 | 'OldSound\RabbitMqBundle\Tests\RabbitMq\Fixtures\AMQPConnection', 103 | array( 104 | 'host' => 'foo_host', 105 | 'port' => 123, 106 | 'user' => 'foo_user', 107 | 'password' => 'foo_password', 108 | 'vhost' => '/vhost', 109 | ) 110 | ); 111 | 112 | /** @var AMQPConnection $instance */ 113 | $instance = $factory->createConnection(); 114 | $this->assertInstanceOf('OldSound\RabbitMqBundle\Tests\RabbitMq\Fixtures\AMQPConnection', $instance); 115 | $this->assertEquals(array( 116 | 'foo_host', // host 117 | 123, // port 118 | 'foo_user', // user 119 | 'foo_password', // password 120 | '/vhost', // vhost 121 | false, // insist 122 | "AMQPLAIN", // login method 123 | null, // login response 124 | "en_US", // locale 125 | 3, // connection timeout 126 | 3, // read write timeout 127 | null, // context 128 | false, // keepalive 129 | 0, // heartbeat 130 | ), $instance->constructParams); 131 | } 132 | 133 | public function testSetConnectionParametersWithUrl() 134 | { 135 | $factory = new AMQPConnectionFactory( 136 | 'OldSound\RabbitMqBundle\Tests\RabbitMq\Fixtures\AMQPConnection', 137 | array( 138 | 'url' => 'amqp://bar_user:bar_password@bar_host:321/whost?keepalive=1&connection_timeout=6&read_write_timeout=6', 139 | 'host' => 'foo_host', 140 | 'port' => 123, 141 | 'user' => 'foo_user', 142 | 'password' => 'foo_password', 143 | 'vhost' => '/vhost', 144 | ) 145 | ); 146 | 147 | /** @var AMQPConnection $instance */ 148 | $instance = $factory->createConnection(); 149 | $this->assertInstanceOf('OldSound\RabbitMqBundle\Tests\RabbitMq\Fixtures\AMQPConnection', $instance); 150 | $this->assertEquals(array( 151 | 'bar_host', // host 152 | 321, // port 153 | 'bar_user', // user 154 | 'bar_password', // password 155 | 'whost', // vhost 156 | false, // insist 157 | "AMQPLAIN", // login method 158 | null, // login response 159 | "en_US", // locale 160 | 6, // connection timeout 161 | 6, // read write timeout 162 | null, // context 163 | true, // keepalive 164 | 0, // heartbeat 165 | ), $instance->constructParams); 166 | } 167 | 168 | public function testSetConnectionParametersWithUrlEncoded() 169 | { 170 | $factory = new AMQPConnectionFactory( 171 | 'OldSound\RabbitMqBundle\Tests\RabbitMq\Fixtures\AMQPConnection', 172 | array( 173 | 'url' => 'amqp://user%61:%61pass@ho%61st:10000/v%2fhost?keepalive=1&connection_timeout=6&read_write_timeout=6', 174 | ) 175 | ); 176 | 177 | /** @var AMQPConnection $instance */ 178 | $instance = $factory->createConnection(); 179 | $this->assertInstanceOf('OldSound\RabbitMqBundle\Tests\RabbitMq\Fixtures\AMQPConnection', $instance); 180 | $this->assertEquals(array( 181 | 'hoast', // host 182 | 10000, // port 183 | 'usera', // user 184 | 'apass', // password 185 | 'v/host', // vhost 186 | false, // insist 187 | "AMQPLAIN", // login method 188 | null, // login response 189 | "en_US", // locale 190 | 6, // connection timeout 191 | 6, // read write timeout 192 | null, // context 193 | true, // keepalive 194 | 0, // heartbeat 195 | ), $instance->constructParams); 196 | } 197 | 198 | public function testSetConnectionParametersWithUrlWithoutVhost() 199 | { 200 | $factory = new AMQPConnectionFactory( 201 | 'OldSound\RabbitMqBundle\Tests\RabbitMq\Fixtures\AMQPConnection', 202 | array( 203 | 'url' => 'amqp://user:pass@host:321/?keepalive=1&connection_timeout=6&read_write_timeout=6', 204 | ) 205 | ); 206 | 207 | /** @var AMQPConnection $instance */ 208 | $instance = $factory->createConnection(); 209 | $this->assertInstanceOf('OldSound\RabbitMqBundle\Tests\RabbitMq\Fixtures\AMQPConnection', $instance); 210 | $this->assertEquals(array( 211 | 'host', // host 212 | 321, // port 213 | 'user', // user 214 | 'pass', // password 215 | '', // vhost 216 | false, // insist 217 | "AMQPLAIN", // login method 218 | null, // login response 219 | "en_US", // locale 220 | 6, // connection timeout 221 | 6, // read write timeout 222 | null, // context 223 | true, // keepalive 224 | 0, // heartbeat 225 | ), $instance->constructParams); 226 | } 227 | 228 | public function testSSLConnectionParameters() 229 | { 230 | $factory = new AMQPConnectionFactory( 231 | 'OldSound\RabbitMqBundle\Tests\RabbitMq\Fixtures\AMQPConnection', 232 | array( 233 | 'host' => 'ssl_host', 234 | 'port' => 123, 235 | 'user' => 'ssl_user', 236 | 'password' => 'ssl_password', 237 | 'vhost' => '/ssl', 238 | 'ssl_context' => array( 239 | 'verify_peer' => false, 240 | ), 241 | ) 242 | ); 243 | 244 | /** @var AMQPConnection $instance */ 245 | $instance = $factory->createConnection(); 246 | $this->assertInstanceOf('OldSound\RabbitMqBundle\Tests\RabbitMq\Fixtures\AMQPConnection', $instance); 247 | $this->assertArrayHasKey(11, $instance->constructParams); 248 | $context = $instance->constructParams[11]; 249 | // unset to check whole array at once later 250 | $instance->constructParams[11] = null; 251 | $this->assertIsResource($context); 252 | $this->assertEquals('stream-context', get_resource_type($context)); 253 | $options = stream_context_get_options($context); 254 | $this->assertEquals(array('ssl' => array('verify_peer' => false)), $options); 255 | $this->assertEquals(array( 256 | 'ssl_host', // host 257 | 123, // port 258 | 'ssl_user', // user 259 | 'ssl_password', // password 260 | '/ssl', // vhost 261 | false, // insist 262 | "AMQPLAIN", // login method 263 | null, // login response 264 | "en_US", // locale 265 | 3, // connection timeout 266 | 3, // read write timeout 267 | null, // context checked earlier 268 | false, // keepalive 269 | 0, // heartbeat 270 | ), $instance->constructParams); 271 | } 272 | 273 | public function testConnectionsParametersProviderWithConstructorArgs() 274 | { 275 | $connectionParametersProvider = $this->prepareConnectionParametersProvider(); 276 | $connectionParametersProvider->expects($this->once()) 277 | ->method('getConnectionParameters') 278 | ->will($this->returnValue( 279 | array( 280 | 'constructor_args' => array(1,2,3,4) 281 | ) 282 | )); 283 | $factory = new AMQPConnectionFactory( 284 | 'OldSound\RabbitMqBundle\Tests\RabbitMq\Fixtures\AMQPConnection', 285 | array(), 286 | $connectionParametersProvider 287 | ); 288 | 289 | /** @var AMQPConnection $instance */ 290 | $instance = $factory->createConnection(); 291 | $this->assertInstanceOf('OldSound\RabbitMqBundle\Tests\RabbitMq\Fixtures\AMQPConnection', $instance); 292 | $this->assertEquals(array(1,2,3,4), $instance->constructParams); 293 | } 294 | 295 | public function testConnectionsParametersProvider() 296 | { 297 | $connectionParametersProvider = $this->prepareConnectionParametersProvider(); 298 | $connectionParametersProvider->expects($this->once()) 299 | ->method('getConnectionParameters') 300 | ->will($this->returnValue( 301 | array( 302 | 'host' => '1.2.3.4', 303 | 'port' => 5678, 304 | 'user' => 'admin', 305 | 'password' => 'admin', 306 | 'vhost' => 'foo', 307 | ) 308 | )); 309 | $factory = new AMQPConnectionFactory( 310 | 'OldSound\RabbitMqBundle\Tests\RabbitMq\Fixtures\AMQPConnection', 311 | array(), 312 | $connectionParametersProvider 313 | ); 314 | 315 | /** @var AMQPConnection $instance */ 316 | $instance = $factory->createConnection(); 317 | $this->assertInstanceOf('OldSound\RabbitMqBundle\Tests\RabbitMq\Fixtures\AMQPConnection', $instance); 318 | $this->assertEquals(array( 319 | '1.2.3.4', // host 320 | 5678, // port 321 | 'admin', // user 322 | 'admin', // password 323 | 'foo', // vhost 324 | false, // insist 325 | "AMQPLAIN", // login method 326 | null, // login response 327 | "en_US", // locale 328 | 3, // connection timeout 329 | 3, // read write timeout 330 | null, // context 331 | false, // keepalive 332 | 0, // heartbeat 333 | ), $instance->constructParams); 334 | } 335 | 336 | /** 337 | * Preparing ConnectionParametersProviderInterface instance 338 | * 339 | * @return ConnectionParametersProviderInterface|MockObject 340 | */ 341 | private function prepareConnectionParametersProvider() 342 | { 343 | return $this->getMockBuilder('OldSound\RabbitMqBundle\Provider\ConnectionParametersProviderInterface') 344 | ->getMock(); 345 | } 346 | } 347 | -------------------------------------------------------------------------------- /Tests/RabbitMq/BaseAmqpTest.php: -------------------------------------------------------------------------------- 1 | getMockBuilder('PhpAmqpLib\Connection\AbstractConnection') 18 | ->disableOriginalConstructor() 19 | ->getMock(); 20 | 21 | $connection 22 | ->method('connectOnConstruct') 23 | ->willReturn(false); 24 | $connection 25 | ->expects(static::never()) 26 | ->method('channel'); 27 | 28 | new Consumer($connection, null); 29 | } 30 | 31 | public function testNotLazyConnection() 32 | { 33 | $connection = $this->getMockBuilder('PhpAmqpLib\Connection\AbstractConnection') 34 | ->disableOriginalConstructor() 35 | ->getMock(); 36 | 37 | $connection 38 | ->method('connectOnConstruct') 39 | ->willReturn(true); 40 | $connection 41 | ->expects(static::once()) 42 | ->method('channel'); 43 | 44 | new Consumer($connection, null); 45 | } 46 | 47 | public function testDispatchEvent() 48 | { 49 | /** @var BaseAmqp|MockObject $baseAmqpConsumer */ 50 | $baseAmqpConsumer = $this->getMockBuilder('OldSound\RabbitMqBundle\RabbitMq\BaseAmqp') 51 | ->disableOriginalConstructor() 52 | ->getMock(); 53 | 54 | $eventDispatcher = $this->getMockBuilder('Symfony\Contracts\EventDispatcher\EventDispatcherInterface') 55 | ->disableOriginalConstructor() 56 | ->getMock(); 57 | 58 | $baseAmqpConsumer->expects($this->atLeastOnce()) 59 | ->method('getEventDispatcher') 60 | ->willReturn($eventDispatcher); 61 | 62 | $eventDispatcher->expects($this->once()) 63 | ->method('dispatch') 64 | ->with(new AMQPEvent(), AMQPEvent::ON_CONSUME) 65 | ->willReturn(new AMQPEvent()); 66 | 67 | $this->invokeMethod('dispatchEvent', $baseAmqpConsumer, array(AMQPEvent::ON_CONSUME, new AMQPEvent())); 68 | } 69 | 70 | /** 71 | * @param string $name 72 | * @param MockObject $obj 73 | * @param array $params 74 | * 75 | * @return mixed 76 | */ 77 | protected function invokeMethod($name, $obj, $params) 78 | { 79 | $class = new \ReflectionClass(get_class($obj)); 80 | $method = $class->getMethod($name); 81 | $method->setAccessible(true); 82 | 83 | return $method->invokeArgs($obj, $params); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Tests/RabbitMq/BaseConsumerTest.php: -------------------------------------------------------------------------------- 1 | getMockBuilder('\PhpAmqpLib\Connection\AMQPStreamConnection') 16 | ->disableOriginalConstructor() 17 | ->getMock(); 18 | 19 | $this->consumer = $this->getMockBuilder('\OldSound\RabbitMqBundle\RabbitMq\BaseConsumer') 20 | ->setConstructorArgs(array($amqpConnection)) 21 | ->getMockForAbstractClass(); 22 | } 23 | 24 | public function testItExtendsBaseAmqpInterface() 25 | { 26 | $this->assertInstanceOf('OldSound\RabbitMqBundle\RabbitMq\BaseAmqp', $this->consumer); 27 | } 28 | 29 | public function testItImplementsDequeuerInterface() 30 | { 31 | $this->assertInstanceOf('OldSound\RabbitMqBundle\RabbitMq\DequeuerInterface', $this->consumer); 32 | } 33 | 34 | public function testItsIdleTimeoutIsMutable() 35 | { 36 | $this->assertEquals(0, $this->consumer->getIdleTimeout()); 37 | $this->consumer->setIdleTimeout(42); 38 | $this->assertEquals(42, $this->consumer->getIdleTimeout()); 39 | } 40 | 41 | public function testItsIdleTimeoutExitCodeIsMutable() 42 | { 43 | $this->assertEquals(0, $this->consumer->getIdleTimeoutExitCode()); 44 | $this->consumer->setIdleTimeoutExitCode(43); 45 | $this->assertEquals(43, $this->consumer->getIdleTimeoutExitCode()); 46 | } 47 | 48 | public function testForceStopConsumer() 49 | { 50 | $this->assertAttributeEquals(false, 'forceStop', $this->consumer); 51 | $this->consumer->forceStopConsumer(); 52 | $this->assertAttributeEquals(true, 'forceStop', $this->consumer); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Tests/RabbitMq/BindingTest.php: -------------------------------------------------------------------------------- 1 | getMockBuilder('\PhpAmqpLib\Connection\AMQPStreamConnection') 24 | ->disableOriginalConstructor() 25 | ->getMock(); 26 | } 27 | 28 | protected function prepareAMQPChannel($channelId = null) 29 | { 30 | $channelMock = $this->getMockBuilder('\PhpAmqpLib\Channel\AMQPChannel') 31 | ->disableOriginalConstructor() 32 | ->getMock(); 33 | 34 | $channelMock->expects($this->any()) 35 | ->method('getChannelId') 36 | ->willReturn($channelId); 37 | return $channelMock; 38 | } 39 | 40 | public function testQueueBind() 41 | { 42 | $ch = $this->prepareAMQPChannel('channel_id'); 43 | $con = $this->prepareAMQPConnection(); 44 | 45 | $source = 'example_source'; 46 | $destination = 'example_destination'; 47 | $key = 'example_key'; 48 | $ch->expects($this->once()) 49 | ->method('queue_bind') 50 | ->will($this->returnCallback(function ($d, $s, $k, $n, $a) use ($destination, $source, $key) { 51 | Assert::assertSame($destination, $d); 52 | Assert::assertSame($source, $s); 53 | Assert::assertSame($key, $k); 54 | Assert::assertFalse($n); 55 | Assert::assertNull($a); 56 | })); 57 | 58 | $binding = $this->getBinding($con, $ch); 59 | $binding->setExchange($source); 60 | $binding->setDestination($destination); 61 | $binding->setRoutingKey($key); 62 | $binding->setupFabric(); 63 | } 64 | 65 | public function testExhangeBind() 66 | { 67 | $ch = $this->prepareAMQPChannel('channel_id'); 68 | $con = $this->prepareAMQPConnection(); 69 | 70 | $source = 'example_source'; 71 | $destination = 'example_destination'; 72 | $key = 'example_key'; 73 | $ch->expects($this->once()) 74 | ->method('exchange_bind') 75 | ->will($this->returnCallback(function ($d, $s, $k, $n, $a) use ($destination, $source, $key) { 76 | Assert::assertSame($destination, $d); 77 | Assert::assertSame($source, $s); 78 | Assert::assertSame($key, $k); 79 | Assert::assertFalse($n); 80 | Assert::assertNull($a); 81 | })); 82 | 83 | $binding = $this->getBinding($con, $ch); 84 | $binding->setExchange($source); 85 | $binding->setDestination($destination); 86 | $binding->setRoutingKey($key); 87 | $binding->setDestinationIsExchange(true); 88 | $binding->setupFabric(); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Tests/RabbitMq/DynamicConsumerTest.php: -------------------------------------------------------------------------------- 1 | getMockBuilder('\OldSound\RabbitMqBundle\Provider\QueueOptionsProviderInterface') 24 | ->getMock(); 25 | } 26 | 27 | public function testQueueOptionsPrivider() 28 | { 29 | $amqpConnection = $this->prepareAMQPConnection(); 30 | $amqpChannel = $this->prepareAMQPChannel(); 31 | $consumer = $this->getConsumer($amqpConnection, $amqpChannel); 32 | $consumer->setContext('foo'); 33 | 34 | $queueOptionsProvider = $this->prepareQueueOptionsProvider(); 35 | $queueOptionsProvider->expects($this->once()) 36 | ->method('getQueueOptions') 37 | ->will($this->returnValue( 38 | array( 39 | 'name' => 'queue_foo', 40 | 'routing_keys' => array( 41 | 'foo.*' 42 | ) 43 | ) 44 | )); 45 | 46 | $consumer->setQueueOptionsProvider($queueOptionsProvider); 47 | 48 | $reflectionClass = new \ReflectionClass(get_class($consumer)); 49 | $reflectionMethod = $reflectionClass->getMethod('mergeQueueOptions'); 50 | $reflectionMethod->setAccessible(true); 51 | $reflectionMethod->invoke($consumer); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Tests/RabbitMq/Fixtures/AMQPConnection.php: -------------------------------------------------------------------------------- 1 | constructParams = func_get_args(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Tests/RabbitMq/Fixtures/AMQPSocketConnection.php: -------------------------------------------------------------------------------- 1 | constructParams = func_get_args(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Tests/RabbitMq/MultipleConsumerTest.php: -------------------------------------------------------------------------------- 1 | amqpConnection = $this->prepareAMQPConnection(); 46 | $this->amqpChannel = $this->prepareAMQPChannel(); 47 | $this->multipleConsumer = new MultipleConsumer($this->amqpConnection, $this->amqpChannel); 48 | } 49 | 50 | /** 51 | * Check if the message is requeued or not correctly. 52 | * 53 | * @dataProvider processMessageProvider 54 | */ 55 | public function testProcessMessage($processFlag, $expectedMethod, $expectedRequeue = null) 56 | { 57 | $callback = $this->prepareCallback($processFlag); 58 | 59 | $this->multipleConsumer->setQueues( 60 | array( 61 | 'test-1' => array('callback' => $callback), 62 | 'test-2' => array('callback' => $callback) 63 | ) 64 | ); 65 | 66 | $this->prepareAMQPChannelExpectations($expectedMethod, $expectedRequeue); 67 | 68 | // Create a default message 69 | $amqpMessage = new AMQPMessage('foo body'); 70 | $amqpMessage->delivery_info['channel'] = $this->amqpChannel; 71 | $amqpMessage->delivery_info['delivery_tag'] = 0; 72 | 73 | $this->multipleConsumer->processQueueMessage('test-1', $amqpMessage); 74 | $this->multipleConsumer->processQueueMessage('test-2', $amqpMessage); 75 | } 76 | 77 | /** 78 | * Check queues provider works well 79 | * 80 | * @dataProvider processMessageProvider 81 | */ 82 | public function testQueuesProvider($processFlag, $expectedMethod, $expectedRequeue = null) 83 | { 84 | $callback = $this->prepareCallback($processFlag); 85 | 86 | $queuesProvider = $this->prepareQueuesProvider(); 87 | $queuesProvider->expects($this->once()) 88 | ->method('getQueues') 89 | ->will($this->returnValue( 90 | array( 91 | 'test-1' => array('callback' => $callback), 92 | 'test-2' => array('callback' => $callback) 93 | ) 94 | )); 95 | 96 | $this->multipleConsumer->setQueuesProvider($queuesProvider); 97 | 98 | /** 99 | * We don't test consume method, which merges queues by calling $this->setupConsumer(); 100 | * So we need to invoke it manually 101 | */ 102 | $reflectionClass = new \ReflectionClass(get_class($this->multipleConsumer)); 103 | $reflectionMethod = $reflectionClass->getMethod('mergeQueues'); 104 | $reflectionMethod->setAccessible(true); 105 | $reflectionMethod->invoke($this->multipleConsumer); 106 | 107 | $this->prepareAMQPChannelExpectations($expectedMethod, $expectedRequeue); 108 | 109 | // Create a default message 110 | $amqpMessage = new AMQPMessage('foo body'); 111 | $amqpMessage->delivery_info['channel'] = $this->amqpChannel; 112 | $amqpMessage->delivery_info['delivery_tag'] = 0; 113 | 114 | $this->multipleConsumer->processQueueMessage('test-1', $amqpMessage); 115 | $this->multipleConsumer->processQueueMessage('test-2', $amqpMessage); 116 | } 117 | 118 | public function testQueuesPrivider() 119 | { 120 | $amqpConnection = $this->prepareAMQPConnection(); 121 | $amqpChannel = $this->prepareAMQPChannel(); 122 | $this->multipleConsumer->setContext('foo'); 123 | 124 | $queuesProvider = $this->prepareQueuesProvider(); 125 | $queuesProvider->expects($this->once()) 126 | ->method('getQueues') 127 | ->will($this->returnValue( 128 | array( 129 | 'queue_foo' => array() 130 | ) 131 | )); 132 | 133 | $this->multipleConsumer->setQueuesProvider($queuesProvider); 134 | 135 | $reflectionClass = new \ReflectionClass(get_class($this->multipleConsumer)); 136 | $reflectionMethod = $reflectionClass->getMethod('mergeQueues'); 137 | $reflectionMethod->setAccessible(true); 138 | $reflectionMethod->invoke($this->multipleConsumer); 139 | } 140 | 141 | /** 142 | * Check queues provider works well with static queues together 143 | * 144 | * @dataProvider processMessageProvider 145 | */ 146 | public function testQueuesProviderAndStaticQueuesTogether($processFlag, $expectedMethod, $expectedRequeue = null) 147 | { 148 | $callback = $this->prepareCallback($processFlag); 149 | 150 | $this->multipleConsumer->setQueues( 151 | array( 152 | 'test-1' => array('callback' => $callback), 153 | 'test-2' => array('callback' => $callback) 154 | ) 155 | ); 156 | 157 | $queuesProvider = $this->prepareQueuesProvider(); 158 | $queuesProvider->expects($this->once()) 159 | ->method('getQueues') 160 | ->will($this->returnValue( 161 | array( 162 | 'test-3' => array('callback' => $callback), 163 | 'test-4' => array('callback' => $callback) 164 | ) 165 | )); 166 | 167 | $this->multipleConsumer->setQueuesProvider($queuesProvider); 168 | 169 | /** 170 | * We don't test consume method, which merges queues by calling $this->setupConsumer(); 171 | * So we need to invoke it manually 172 | */ 173 | $reflectionClass = new \ReflectionClass(get_class($this->multipleConsumer)); 174 | $reflectionMethod = $reflectionClass->getMethod('mergeQueues'); 175 | $reflectionMethod->setAccessible(true); 176 | $reflectionMethod->invoke($this->multipleConsumer); 177 | 178 | $this->prepareAMQPChannelExpectations($expectedMethod, $expectedRequeue); 179 | 180 | // Create a default message 181 | $amqpMessage = new AMQPMessage('foo body'); 182 | $amqpMessage->delivery_info['channel'] = $this->amqpChannel; 183 | $amqpMessage->delivery_info['delivery_tag'] = 0; 184 | 185 | $this->multipleConsumer->processQueueMessage('test-1', $amqpMessage); 186 | $this->multipleConsumer->processQueueMessage('test-2', $amqpMessage); 187 | $this->multipleConsumer->processQueueMessage('test-3', $amqpMessage); 188 | $this->multipleConsumer->processQueueMessage('test-4', $amqpMessage); 189 | } 190 | 191 | public function processMessageProvider() 192 | { 193 | return array( 194 | array(null, 'basic_ack'), // Remove message from queue only if callback return not false 195 | array(true, 'basic_ack'), // Remove message from queue only if callback return not false 196 | array(false, 'basic_reject', true), // Reject and requeue message to RabbitMQ 197 | array(ConsumerInterface::MSG_ACK, 'basic_ack'), // Remove message from queue only if callback return not false 198 | array(ConsumerInterface::MSG_REJECT_REQUEUE, 'basic_reject', true), // Reject and requeue message to RabbitMQ 199 | array(ConsumerInterface::MSG_REJECT, 'basic_reject', false), // Reject and drop 200 | ); 201 | } 202 | 203 | /** 204 | * @dataProvider queueBindingRoutingKeyProvider 205 | */ 206 | public function testShouldConsiderQueueArgumentsOnQueueDeclaration($routingKeysOption, $expectedRoutingKey) 207 | { 208 | $queueName = 'test-queue-name'; 209 | $exchangeName = 'test-exchange-name'; 210 | $expectedArgs = ['test-argument' => ['S', 'test-value']]; 211 | 212 | $this->amqpChannel->expects($this->any()) 213 | ->method('getChannelId')->willReturn(0); 214 | 215 | $this->amqpChannel->expects($this->any()) 216 | ->method('queue_declare') 217 | ->willReturn([$queueName, 5, 0]); 218 | 219 | 220 | $this->multipleConsumer->setExchangeOptions([ 221 | 'declare' => false, 222 | 'name' => $exchangeName, 223 | 'type' => 'topic']); 224 | 225 | $this->multipleConsumer->setQueues([ 226 | $queueName => [ 227 | 'passive' => true, 228 | 'durable' => true, 229 | 'exclusive' => true, 230 | 'auto_delete' => true, 231 | 'nowait' => true, 232 | 'arguments' => $expectedArgs, 233 | 'ticket' => null, 234 | 'routing_keys' => $routingKeysOption] 235 | ]); 236 | 237 | $this->multipleConsumer->setRoutingKey('test-routing-key'); 238 | 239 | // we assert that arguments are passed to the bind method 240 | $this->amqpChannel->expects($this->once()) 241 | ->method('queue_bind') 242 | ->with($queueName, $exchangeName, $expectedRoutingKey, false, $expectedArgs); 243 | 244 | $this->multipleConsumer->setupFabric(); 245 | } 246 | 247 | public function queueBindingRoutingKeyProvider() 248 | { 249 | return array( 250 | array(array(), 'test-routing-key'), 251 | array(array('test-routing-key-2'), 'test-routing-key-2'), 252 | ); 253 | } 254 | 255 | /** 256 | * Preparing AMQP Connection 257 | * 258 | * @return MockObject|AMQPStreamConnection 259 | */ 260 | private function prepareAMQPConnection() 261 | { 262 | return $this->getMockBuilder('\PhpAmqpLib\Connection\AMQPStreamConnection') 263 | ->disableOriginalConstructor() 264 | ->getMock(); 265 | } 266 | 267 | /** 268 | * Preparing AMQP Connection 269 | * 270 | * @return MockObject|AMQPChannel 271 | */ 272 | private function prepareAMQPChannel() 273 | { 274 | return $this->getMockBuilder('\PhpAmqpLib\Channel\AMQPChannel') 275 | ->disableOriginalConstructor() 276 | ->getMock(); 277 | } 278 | 279 | /** 280 | * Preparing QueuesProviderInterface instance 281 | * 282 | * @return MockObject|QueuesProviderInterface 283 | */ 284 | private function prepareQueuesProvider() 285 | { 286 | return $this->getMockBuilder('\OldSound\RabbitMqBundle\Provider\QueuesProviderInterface') 287 | ->getMock(); 288 | } 289 | 290 | /** 291 | * Preparing AMQP Channel Expectations 292 | * 293 | * @param mixed $expectedMethod 294 | * @param string $expectedRequeue 295 | * 296 | * @return void 297 | */ 298 | private function prepareAMQPChannelExpectations($expectedMethod, $expectedRequeue) 299 | { 300 | $this->amqpChannel->expects($this->any()) 301 | ->method('basic_reject') 302 | ->will($this->returnCallback(function ($delivery_tag, $requeue) use ($expectedMethod, $expectedRequeue) { 303 | Assert::assertSame($expectedMethod, 'basic_reject'); // Check if this function should be called. 304 | Assert::assertSame($requeue, $expectedRequeue); // Check if the message should be requeued. 305 | })); 306 | 307 | $this->amqpChannel->expects($this->any()) 308 | ->method('basic_ack') 309 | ->will($this->returnCallback(function ($delivery_tag) use ($expectedMethod) { 310 | Assert::assertSame($expectedMethod, 'basic_ack'); // Check if this function should be called. 311 | })); 312 | } 313 | 314 | /** 315 | * Prepare callback 316 | * 317 | * @param bool $processFlag 318 | * @return callable 319 | */ 320 | private function prepareCallback($processFlag) 321 | { 322 | return function ($msg) use ($processFlag) { 323 | return $processFlag; 324 | }; 325 | } 326 | } 327 | -------------------------------------------------------------------------------- /Tests/RabbitMq/RpcClientTest.php: -------------------------------------------------------------------------------- 1 | getMockBuilder('\OldSound\RabbitMqBundle\RabbitMq\RpcClient') 16 | ->setMethods(array('sendReply', 'maybeStopConsumer')) 17 | ->disableOriginalConstructor() 18 | ->getMock(); 19 | /** @var AMQPMessage $message */ 20 | $message = $this->getMockBuilder('\PhpAmqpLib\Message\AMQPMessage') 21 | ->setMethods(array('get')) 22 | ->setConstructorArgs(array('message')) 23 | ->getMock(); 24 | $serializer = $this->getMockBuilder('\Symfony\Component\Serializer\SerializerInterface') 25 | ->setMethods(array('serialize', 'deserialize')) 26 | ->getMock(); 27 | $serializer->expects($this->once())->method('deserialize')->with('message', 'json', null); 28 | $client->initClient(true); 29 | $client->setUnserializer(function($data) use ($serializer) { 30 | $serializer->deserialize($data, 'json',''); 31 | }); 32 | $client->processMessage($message); 33 | } 34 | 35 | public function testProcessMessageWithNotifyMethod() 36 | { 37 | /** @var RpcClient $client */ 38 | $client = $this->getMockBuilder('\OldSound\RabbitMqBundle\RabbitMq\RpcClient') 39 | ->setMethods(array('sendReply', 'maybeStopConsumer')) 40 | ->disableOriginalConstructor() 41 | ->getMock(); 42 | $expectedNotify = 'message'; 43 | /** @var AMQPMessage $message */ 44 | $message = $this->getMockBuilder('\PhpAmqpLib\Message\AMQPMessage') 45 | ->setMethods(array('get')) 46 | ->setConstructorArgs(array($expectedNotify)) 47 | ->getMock(); 48 | $notified = false; 49 | $client->notify(function ($message) use (&$notified) { 50 | $notified = $message; 51 | }); 52 | 53 | $client->initClient(false); 54 | $client->processMessage($message); 55 | 56 | $this->assertSame($expectedNotify, $notified); 57 | } 58 | 59 | public function testInvalidParameterOnNotify() 60 | { 61 | /** @var RpcClient $client */ 62 | $client = $this->getMockBuilder('\OldSound\RabbitMqBundle\RabbitMq\RpcClient') 63 | ->setMethods(array('sendReply', 'maybeStopConsumer')) 64 | ->disableOriginalConstructor() 65 | ->getMock(); 66 | 67 | $this->expectException('\InvalidArgumentException'); 68 | 69 | $client->notify('not a callable'); 70 | } 71 | 72 | public function testChannelCancelOnGetRepliesException() 73 | { 74 | $client = $this->getMockBuilder('\OldSound\RabbitMqBundle\RabbitMq\RpcClient') 75 | ->setMethods(null) 76 | ->disableOriginalConstructor() 77 | ->getMock(); 78 | 79 | $channel = $this->createMock('\PhpAmqpLib\Channel\AMQPChannel'); 80 | $channel->expects($this->any()) 81 | ->method('getChannelId') 82 | ->willReturn('test'); 83 | $channel->expects($this->once()) 84 | ->method('wait') 85 | ->willThrowException(new AMQPTimeoutException()); 86 | 87 | $this->expectException('\PhpAmqpLib\Exception\AMQPTimeoutException'); 88 | 89 | $channel->expects($this->once()) 90 | ->method('basic_cancel'); 91 | 92 | $client->setChannel($channel); 93 | $client->addRequest('a', 'b', 'c'); 94 | 95 | $client->getReplies(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /Tests/RabbitMq/RpcServerTest.php: -------------------------------------------------------------------------------- 1 | getMockBuilder('\OldSound\RabbitMqBundle\RabbitMq\RpcServer') 15 | ->setMethods(array('sendReply', 'maybeStopConsumer')) 16 | ->disableOriginalConstructor() 17 | ->getMock(); 18 | $message = $this->getMockBuilder('\PhpAmqpLib\Message\AMQPMessage') 19 | ->setMethods( array('get')) 20 | ->getMock(); 21 | $message->delivery_info = array( 22 | 'channel' => $this->getMockBuilder('\PhpAmqpLib\Channel\AMQPChannel') 23 | ->setMethods(array())->setConstructorArgs(array()) 24 | ->setMockClassName('') 25 | ->disableOriginalConstructor() 26 | ->getMock(), 27 | 'delivery_tag' => null 28 | ); 29 | $server->setCallback(function() { 30 | return 'message'; 31 | }); 32 | $serializer = $this->getMockBuilder('\Symfony\Component\Serializer\SerializerInterface') 33 | ->setMethods(array('serialize', 'deserialize')) 34 | ->getMock(); 35 | $serializer->expects($this->once())->method('serialize')->with('message', 'json'); 36 | $server->setSerializer(function($data) use ($serializer) { 37 | $serializer->serialize($data, 'json'); 38 | }); 39 | $server->processMessage($message); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | 2 |