diff --git a/.travis.yml b/.travis.yml
index 095fb584a..d10e9a3fa 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -40,13 +40,13 @@ install:
- rm $HOME/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini;
- echo "memory_limit=2048M" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
- composer require symfony/symfony:${SYMFONY_VERSION} --no-update
- - composer install --ignore-platform-reqs # ext-amqp is not installed
+ - composer install
- if [ "$FUNCTIONAL_TESTS" = true ]; then docker --version; fi
- if [ "$FUNCTIONAL_TESTS" = true ]; then docker-compose --version; fi
- if [ "$FUNCTIONAL_TESTS" = true ]; then bin/dev -b; fi
script:
- - if [ "$PHPSTAN" = true ]; then php -d memory_limit=512M bin/phpstan analyse -l 1 -c phpstan.neon pkg/amqp-ext pkg/async-event-dispatcher pkg/dbal pkg/enqueue pkg/enqueue-bundle pkg/fs pkg/gearman pkg/job-queue pkg/null pkg/pheanstalk pkg/redis pkg/simple-client pkg/sqs pkg/stomp pkg/test pkg/rdkafka; fi
+ - if [ "$PHPSTAN" = true ]; then composer require "phpstan/phpstan:0.7.0" ; php -d memory_limit=512M bin/phpstan analyse -l 1 -c phpstan.neon pkg/amqp-ext pkg/async-event-dispatcher pkg/dbal pkg/enqueue pkg/enqueue-bundle pkg/fs pkg/gearman pkg/job-queue pkg/null pkg/pheanstalk pkg/redis pkg/simple-client pkg/sqs pkg/stomp pkg/test pkg/rdkafka; fi
- if [ "$PHP_CS_FIXER" = true ]; then IFS=$'\n'; COMMIT_SCA_FILES=($(git diff --name-only --diff-filter=ACMRTUXB "${TRAVIS_COMMIT_RANGE}")); unset IFS; fi
- if [ "$PHP_CS_FIXER" = true ]; then ./bin/php-cs-fixer fix --config=.php_cs.dist -v --dry-run --stop-on-violation --using-cache=no --path-mode=intersection -- "${COMMIT_SCA_FILES[@]}"; fi
- if [ "$UNIT_TESTS" = true ]; then bin/phpunit --exclude-group=functional; fi
diff --git a/README.md b/README.md
index 54422d16c..0a27fc228 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@ Features:
* [Feature rich](docs/quick_tour.md).
* Implements [JMS](https://docs.oracle.com/javaee/7/api/javax/jms/package-summary.html) like transports based on a[queue-interop](https://github.com/queue-interop/queue-interop) interfaces.
* Supported transports
- * AMQP based on [the ext](docs/transport/amqp.md), [the lib](docs/transport/amqp_lib.md)
+ * Amqp based on [the ext](docs/transport/amqp.md), [bunny](docs/transport/amqp_bunny.md), [the lib](docs/transport/amqp_lib.md)
* [Beanstalk](docs/transport/pheanstalk.md)
* [STOMP](docs/transport/stomp.md)
* [Amazon SQS](docs/transport/sqs.md)
diff --git a/bin/dev b/bin/dev
index d57602c96..df04fee23 100755
--- a/bin/dev
+++ b/bin/dev
@@ -27,7 +27,7 @@ while getopts "bustefcd" OPTION; do
COMPOSE_PROJECT_NAME=mqdev docker-compose run -e CHANGELOG_GITHUB_TOKEN=${CHANGELOG_GITHUB_TOKEN:-""} --workdir="/mqdev" --rm generate-changelog github_changelog_generator --future-release "$2" --simple-list
;;
- d) COMPOSE_PROJECT_NAME=mqdev docker-compose run --workdir="/mqdev" --rm dev php pkg/enqueue-bundle/Tests/Functional/app/console.php config:dump-reference enqueue
+ d) COMPOSE_PROJECT_NAME=mqdev docker-compose run --workdir="/mqdev" --rm dev php pkg/enqueue-bundle/Tests/Functional/app/console.php config:dump-reference enqueue -vvv
;;
\?)
echo "Invalid option: -$OPTARG" >&2
diff --git a/bin/release b/bin/release
index 37f0c544c..0cff197d6 100755
--- a/bin/release
+++ b/bin/release
@@ -14,7 +14,7 @@ fi
CURRENT_BRANCH=`git rev-parse --abbrev-ref HEAD`
-for REMOTE in origin stomp amqp-ext pheanstalk gearman sqs fs redis dbal null rdkafka enqueue simple-client enqueue-bundle job-queue test async-event-dispatcher
+for REMOTE in origin stomp amqp-ext amqp-lib amqp-bunny amqp-tools pheanstalk gearman sqs fs redis dbal null rdkafka enqueue simple-client enqueue-bundle job-queue test async-event-dispatcher
do
echo ""
echo ""
diff --git a/bin/subtree-split b/bin/subtree-split
index 3c0137bc8..ece707c24 100755
--- a/bin/subtree-split
+++ b/bin/subtree-split
@@ -47,6 +47,9 @@ remote enqueue git@github.com:php-enqueue/enqueue.git
remote simple-client git@github.com:php-enqueue/simple-client.git
remote stomp git@github.com:php-enqueue/stomp.git
remote amqp-ext git@github.com:php-enqueue/amqp-ext.git
+remote amqp-lib git@github.com:php-enqueue/amqp-lib.git
+remote amqp-bunny git@github.com:php-enqueue/amqp-bunny.git
+remote amqp-tools git@github.com:php-enqueue/amqp-tools.git
remote pheanstalk git@github.com:php-enqueue/pheanstalk.git
remote gearman git@github.com:php-enqueue/gearman.git
remote fs git@github.com:php-enqueue/fs.git
@@ -64,6 +67,9 @@ split 'pkg/enqueue' enqueue
split 'pkg/simple-client' simple-client
split 'pkg/stomp' stomp
split 'pkg/amqp-ext' amqp-ext
+split 'pkg/amqp-lib' amqp-lib
+split 'pkg/amqp-bunny' amqp-bunny
+split 'pkg/amqp-tools' amqp-tools
split 'pkg/pheanstalk' pheanstalk
split 'pkg/gearman' gearman
split 'pkg/rdkafka' rdkafka
diff --git a/composer.json b/composer.json
index 49c274e6d..3212a3a78 100644
--- a/composer.json
+++ b/composer.json
@@ -8,6 +8,8 @@
"enqueue/stomp": "*@dev",
"enqueue/amqp-ext": "*@dev",
"enqueue/amqp-lib": "*@dev",
+ "enqueue/amqp-bunny": "*@dev",
+ "enqueue/amqp-tools": "*@dev",
"php-amqplib/php-amqplib": "^2.7@dev",
"enqueue/redis": "*@dev",
"enqueue/fs": "*@dev",
@@ -23,7 +25,8 @@
"enqueue/simple-client": "*@dev",
"enqueue/test": "*@dev",
"enqueue/async-event-dispatcher": "*@dev",
- "queue-interop/queue-interop": "^0.5@dev",
+ "queue-interop/queue-interop": "^0.6@dev",
+ "queue-interop/amqp-interop": "^0.6@dev",
"queue-interop/queue-spec": "^0.5@dev",
"phpunit/phpunit": "^5",
@@ -35,8 +38,7 @@
"symfony/event-dispatcher": "^2.8|^3",
"symfony/console": "^2.8|^3",
"friendsofphp/php-cs-fixer": "^2",
- "empi89/php-amqp-stubs": "*@dev",
- "phpstan/phpstan": "^0.7.0"
+ "empi89/php-amqp-stubs": "*@dev"
},
"autoload": {
"files": [
@@ -51,7 +53,12 @@
}
},
"config": {
- "bin-dir": "bin"
+ "bin-dir": "bin",
+ "platform": {
+ "ext-amqp": "1.7",
+ "ext-gearman": "1.1",
+ "ext-rdkafka": "3.3"
+ }
},
"repositories": [
{
@@ -74,6 +81,14 @@
"type": "path",
"url": "pkg/amqp-lib"
},
+ {
+ "type": "path",
+ "url": "pkg/amqp-bunny"
+ },
+ {
+ "type": "path",
+ "url": "pkg/amqp-tools"
+ },
{
"type": "path",
"url": "pkg/redis"
diff --git a/docs/bundle/config_reference.md b/docs/bundle/config_reference.md
index a891d75cf..cfb08fa08 100644
--- a/docs/bundle/config_reference.md
+++ b/docs/bundle/config_reference.md
@@ -68,6 +68,9 @@ enqueue:
write_timeout: ~
persisted: false
lazy: true
+
+ # The receive strategy to be used. We suggest to use basic_consume as it is more performant. Though you need AMQP extension 1.9.1 or higher
+ receive_method: basic_get # One of "basic_get"; "basic_consume"
rabbitmq_amqp:
# The connection to AMQP broker set as a string. Other parameters are ignored if set
@@ -99,6 +102,86 @@ enqueue:
persisted: false
lazy: true
+ # The receive strategy to be used. We suggest to use basic_consume as it is more performant. Though you need AMQP extension 1.9.1 or higher
+ receive_method: basic_get # One of "basic_get"; "basic_consume"
+
+ # The option tells whether RabbitMQ broker has delay plugin installed or not
+ delay_plugin_installed: false
+ amqp_lib:
+
+ # The connection to AMQP broker set as a string. Other parameters are ignored if set
+ dsn: ~
+
+ # The host to connect too. Note: Max 1024 characters
+ host: localhost
+
+ # Port on the host.
+ port: 5672
+
+ # The user name to use. Note: Max 128 characters.
+ user: guest
+
+ # Password. Note: Max 128 characters.
+ pass: guest
+
+ # The virtual host on the host. Note: Max 128 characters.
+ vhost: /
+
+ # Connection timeout. Note: 0 or greater seconds. May be fractional.
+ connection_timeout: !!float 3
+ read_write_timeout: !!float 3
+
+ # Timeout in for income activity. Note: 0 or greater seconds. May be fractional.
+ read_timeout: 3
+
+ # Timeout in for outcome activity. Note: 0 or greater seconds. May be fractional.
+ write_timeout: 3
+ lazy: true
+ stream: true
+ insist: false
+ keepalive: false
+
+ # The receive strategy to be used. We suggest to use basic_consume as it is more performant. Though you need AMQP extension 1.9.1 or higher
+ receive_method: basic_get # One of "basic_get"; "basic_consume"
+ heartbeat: 0
+ rabbitmq_amqp_lib:
+
+ # The connection to AMQP broker set as a string. Other parameters are ignored if set
+ dsn: ~
+
+ # The host to connect too. Note: Max 1024 characters
+ host: localhost
+
+ # Port on the host.
+ port: 5672
+
+ # The user name to use. Note: Max 128 characters.
+ user: guest
+
+ # Password. Note: Max 128 characters.
+ pass: guest
+
+ # The virtual host on the host. Note: Max 128 characters.
+ vhost: /
+
+ # Connection timeout. Note: 0 or greater seconds. May be fractional.
+ connection_timeout: !!float 3
+ read_write_timeout: !!float 3
+
+ # Timeout in for income activity. Note: 0 or greater seconds. May be fractional.
+ read_timeout: 3
+
+ # Timeout in for outcome activity. Note: 0 or greater seconds. May be fractional.
+ write_timeout: 3
+ lazy: true
+ stream: true
+ insist: false
+ keepalive: false
+
+ # The receive strategy to be used. We suggest to use basic_consume as it is more performant. Though you need AMQP extension 1.9.1 or higher
+ receive_method: basic_get # One of "basic_get"; "basic_consume"
+ heartbeat: 0
+
# The option tells whether RabbitMQ broker has delay plugin installed or not
delay_plugin_installed: false
fs:
@@ -155,11 +238,62 @@ enqueue:
# the connection will be performed as later as possible, if the option set to true
lazy: true
+ amqp_bunny:
+
+ # The connection to AMQP broker set as a string. Other parameters are ignored if set
+ dsn: ~
+
+ # The host to connect too. Note: Max 1024 characters
+ host: localhost
+
+ # Port on the host.
+ port: 5672
+
+ # The user name to use. Note: Max 128 characters.
+ user: guest
+
+ # Password. Note: Max 128 characters.
+ pass: guest
+
+ # The virtual host on the host. Note: Max 128 characters.
+ vhost: /
+ lazy: true
+
+ # The receive strategy to be used. We suggest to use basic_consume as it is more performant. Though you need AMQP extension 1.9.1 or higher
+ receive_method: basic_get # One of "basic_get"; "basic_consume"
+ heartbeat: 0
+ rabbitmq_amqp_bunny:
+
+ # The connection to AMQP broker set as a string. Other parameters are ignored if set
+ dsn: ~
+
+ # The host to connect too. Note: Max 1024 characters
+ host: localhost
+
+ # Port on the host.
+ port: 5672
+
+ # The user name to use. Note: Max 128 characters.
+ user: guest
+
+ # Password. Note: Max 128 characters.
+ pass: guest
+
+ # The virtual host on the host. Note: Max 128 characters.
+ vhost: /
+ lazy: true
+
+ # The receive strategy to be used. We suggest to use basic_consume as it is more performant. Though you need AMQP extension 1.9.1 or higher
+ receive_method: basic_get # One of "basic_get"; "basic_consume"
+ heartbeat: 0
+
+ # The option tells whether RabbitMQ broker has delay plugin installed or not
+ delay_plugin_installed: false
client:
traceable_producer: false
prefix: enqueue
app_name: app
- router_topic: router
+ router_topic: default
router_queue: default
router_processor: enqueue.client.router_processor
default_processor_queue: default
@@ -167,7 +301,6 @@ enqueue:
job: false
async_events:
enabled: false
- spool_producer: false
extensions:
doctrine_ping_connection_extension: false
doctrine_clear_identity_map_extension: false
diff --git a/docs/elastica-bundle/populate-command-optimization.md b/docs/elastica-bundle/populate-command-optimization.md
new file mode 100644
index 000000000..8c5cab739
--- /dev/null
+++ b/docs/elastica-bundle/populate-command-optimization.md
@@ -0,0 +1,114 @@
+# Enqueue Elastica Bundle
+
+Improves performance of `fos:elastica:populate` commands by distributing the work among consumers.
+The performance gain depends on how much consumers you run.
+For example 10 consumers may give you 5 to 7 times better performance.
+
+## Installation
+
+Install packages using [composer](https://getcomposer.org/)
+
+```bash
+$ composer require enqueue/elastica-bundle friendsofsymfony/elastica-bundle
+```
+
+Add bundles to `AppKernel`
+
+```php
+createContext();
+
+// create a log channel
+$log = new Logger('name');
+$log->pushHandler(new QueueInteropHandler($context));
+
+// add records to the log
+$log->warning('Foo');
+$log->error('Bar');
+```
+
+the consumer may look like this:
+
+```php
+createContext();
+
+$consumer = new QueueConsumer($context);
+$consumer->bind('log', function(PsrMessage $message) {
+ echo $message->getBody().PHP_EOL;
+
+ return PsrProcessor::ACK;
+});
+
+$consumer->consume();
+
+```
+
+[back to index](../index.md)
\ No newline at end of file
diff --git a/docs/transport/amqp.md b/docs/transport/amqp.md
index 0862cee10..8fd374521 100644
--- a/docs/transport/amqp.md
+++ b/docs/transport/amqp.md
@@ -1,6 +1,6 @@
# AMQP transport
-Implements [AMQP specifications](https://www.rabbitmq.com/specification.html).
+Implements [AMQP specifications](https://www.rabbitmq.com/specification.html) and implements [amqp interop](https://github.com/queue-interop/amqp-interop) interfaces.
Build on top of [php amqp extension](https://github.com/pdezwart/php-amqp).
* [Installation](#installation)
@@ -10,6 +10,9 @@ Build on top of [php amqp extension](https://github.com/pdezwart/php-amqp).
* [Bind queue to topic](#bind-queue-to-topic)
* [Send message to topic](#send-message-to-topic)
* [Send message to queue](#send-message-to-queue)
+* [Send priority message](#send-priority-message)
+* [Send expiration message](#send-expiration-message)
+* [Send delayed message](#send-delayed-message)
* [Consume message](#consume-message)
* [Purge queue messages](#purge-queue-messages)
@@ -56,10 +59,12 @@ Declare topic operation creates a topic on a broker side.
```php
createTopic('foo');
-$fooTopic->addFlag(AMQP_EX_TYPE_FANOUT);
+$fooTopic->addFlag(AmqpTopic::TYPE_FANOUT);
$psrContext->declareTopic($fooTopic);
// to remove topic use delete topic method
@@ -72,10 +77,12 @@ Declare queue operation creates a queue on a broker side.
```php
createQueue('foo');
-$fooQueue->addFlag(AMQP_DURABLE);
+$fooQueue->addFlag(AmqpQueue::FLAG_DURABLE);
$psrContext->declareQueue($fooQueue);
// to remove topic use delete queue method
@@ -88,11 +95,13 @@ Connects a queue to the topic. So messages from that topic comes to the queue an
```php
bind($fooTopic, $fooQueue);
+$psrContext->bind(new AmqpBind($fooTopic, $fooQueue));
```
## Send message to topic
@@ -100,7 +109,7 @@ $psrContext->bind($fooTopic, $fooQueue);
```php
createMessage('Hello world!');
@@ -112,19 +121,80 @@ $psrContext->createProducer()->send($fooTopic, $message);
```php
createMessage('Hello world!');
$psrContext->createProducer()->send($fooQueue, $message);
```
+## Send priority message
+
+```php
+createQueue('foo');
+$fooQueue->addFlag(AmqpQueue::FLAG_DURABLE);
+$fooQueue->setArguments(['x-max-priority' => 10]);
+$psrContext->declareQueue($fooQueue);
+
+$message = $psrContext->createMessage('Hello world!');
+
+$psrContext->createProducer()
+ ->setPriority(5) // the higher priority the sooner a message gets to a consumer
+ //
+ ->send($fooQueue, $message)
+;
+```
+
+## Send expiration message
+
+```php
+createMessage('Hello world!');
+
+$psrContext->createProducer()
+ ->setTimeToLive(60000) // 60 sec
+ //
+ ->send($fooQueue, $message)
+;
+```
+
+## Send delayed message
+
+AMQP specification says nothing about message delaying hence the producer throws `DeliveryDelayNotSupportedException`.
+Though the producer (and the context) accepts a delivry delay strategy and if it is set it uses it to send delayed message.
+The `enqueue/amqp-tools` package provides two RabbitMQ delay strategies, to use them you have to install that package
+
+```php
+createMessage('Hello world!');
+
+$psrContext->createProducer()
+ ->setDelayStrategy(new RabbitMqDlxDelayStrategy())
+ ->setDeliveryDelay(5000) // 5 sec
+
+ ->send($fooQueue, $message)
+;
+````
+
## Consume message:
```php
createConsumer($fooQueue);
@@ -141,11 +211,11 @@ $consumer->acknowledge($message);
```php
createQueue('aQueue');
-$psrContext->purge($queue);
+$psrContext->purgeQueue($queue);
```
[back to index](../index.md)
\ No newline at end of file
diff --git a/docs/transport/amqp_bunny.md b/docs/transport/amqp_bunny.md
new file mode 100644
index 000000000..28c78c8cc
--- /dev/null
+++ b/docs/transport/amqp_bunny.md
@@ -0,0 +1,221 @@
+# AMQP transport
+
+Implements [AMQP specifications](https://www.rabbitmq.com/specification.html) and implements [amqp interop](https://github.com/queue-interop/amqp-interop) interfaces.
+Build on top of [bunny lib](https://github.com/jakubkulhan/bunny).
+
+* [Installation](#installation)
+* [Create context](#create-context)
+* [Declare topic](#declare-topic)
+* [Declare queue](#decalre-queue)
+* [Bind queue to topic](#bind-queue-to-topic)
+* [Send message to topic](#send-message-to-topic)
+* [Send message to queue](#send-message-to-queue)
+* [Send priority message](#send-priority-message)
+* [Send expiration message](#send-expiration-message)
+* [Send delayed message](#send-delayed-message)
+* [Consume message](#consume-message)
+* [Purge queue messages](#purge-queue-messages)
+
+## Installation
+
+```bash
+$ composer require enqueue/amqp-bunny
+```
+
+## Create context
+
+```php
+ 'example.com',
+ 'port' => 1000,
+ 'vhost' => '/',
+ 'user' => 'user',
+ 'pass' => 'pass',
+ 'persisted' => false,
+]);
+
+// same as above but given as DSN string
+$connectionFactory = new AmqpConnectionFactory('amqp://user:pass@example.com:10000/%2f');
+
+$psrContext = $connectionFactory->createContext();
+```
+
+## Declare topic.
+
+Declare topic operation creates a topic on a broker side.
+
+```php
+createTopic('foo');
+$fooTopic->setType(AmqpTopic::TYPE_FANOUT);
+$psrContext->declareTopic($fooTopic);
+
+// to remove topic use delete topic method
+//$psrContext->deleteTopic($fooTopic);
+```
+
+## Declare queue.
+
+Declare queue operation creates a queue on a broker side.
+
+```php
+createQueue('foo');
+$fooQueue->addFlag(AmqpQueue::FLAG_DURABLE);
+$psrContext->declareQueue($fooQueue);
+
+// to remove topic use delete queue method
+//$psrContext->deleteQueue($fooQueue);
+```
+
+## Bind queue to topic
+
+Connects a queue to the topic. So messages from that topic comes to the queue and could be processed.
+
+```php
+bind(new AmqpBind($fooTopic, $fooQueue));
+```
+
+## Send message to topic
+
+```php
+createMessage('Hello world!');
+
+$psrContext->createProducer()->send($fooTopic, $message);
+```
+
+## Send message to queue
+
+```php
+createMessage('Hello world!');
+
+$psrContext->createProducer()->send($fooQueue, $message);
+```
+
+## Send priority message
+
+```php
+createQueue('foo');
+$fooQueue->addFlag(AmqpQueue::FLAG_DURABLE);
+$fooQueue->setArguments(['x-max-priority' => 10]);
+$psrContext->declareQueue($fooQueue);
+
+$message = $psrContext->createMessage('Hello world!');
+
+$psrContext->createProducer()
+ ->setPriority(5) // the higher priority the sooner a message gets to a consumer
+ //
+ ->send($fooQueue, $message)
+;
+```
+
+## Send expiration message
+
+```php
+createMessage('Hello world!');
+
+$psrContext->createProducer()
+ ->setTimeToLive(60000) // 60 sec
+ //
+ ->send($fooQueue, $message)
+;
+```
+
+## Send delayed message
+
+AMQP specification says nothing about message delaying hence the producer throws `DeliveryDelayNotSupportedException`.
+Though the producer (and the context) accepts a delivry delay strategy and if it is set it uses it to send delayed message.
+The `enqueue/amqp-tools` package provides two RabbitMQ delay strategies, to use them you have to install that package
+
+```php
+createMessage('Hello world!');
+
+$psrContext->createProducer()
+ ->setDelayStrategy(new RabbitMqDlxDelayStrategy())
+ ->setDeliveryDelay(5000) // 5 sec
+
+ ->send($fooQueue, $message)
+;
+````
+
+## Consume message:
+
+```php
+createConsumer($fooQueue);
+
+$message = $consumer->receive();
+
+// process a message
+
+$consumer->acknowledge($message);
+// $consumer->reject($message);
+```
+
+## Purge queue messages:
+
+```php
+createQueue('aQueue');
+
+$psrContext->purgeQueue($queue);
+```
+
+[back to index](../index.md)
\ No newline at end of file
diff --git a/docs/transport/amqp_lib.md b/docs/transport/amqp_lib.md
index 5e972f3f1..59061352d 100644
--- a/docs/transport/amqp_lib.md
+++ b/docs/transport/amqp_lib.md
@@ -1,6 +1,6 @@
# AMQP transport
-Implements [AMQP specifications](https://www.rabbitmq.com/specification.html).
+Implements [AMQP specifications](https://www.rabbitmq.com/specification.html) and implements [amqp interop](https://github.com/queue-interop/amqp-interop) interfaces.
Build on top of [php amqp lib](https://github.com/php-amqplib/php-amqplib).
* [Installation](#installation)
@@ -10,6 +10,9 @@ Build on top of [php amqp lib](https://github.com/php-amqplib/php-amqplib).
* [Bind queue to topic](#bind-queue-to-topic)
* [Send message to topic](#send-message-to-topic)
* [Send message to queue](#send-message-to-queue)
+* [Send priority message](#send-priority-message)
+* [Send expiration message](#send-expiration-message)
+* [Send delayed message](#send-delayed-message)
* [Consume message](#consume-message)
* [Purge queue messages](#purge-queue-messages)
@@ -56,10 +59,12 @@ Declare topic operation creates a topic on a broker side.
```php
createTopic('foo');
-$fooTopic->setType('fanout');
+$fooTopic->setType(AmqpTopic::TYPE_FANOUT);
$psrContext->declareTopic($fooTopic);
// to remove topic use delete topic method
@@ -72,10 +77,12 @@ Declare queue operation creates a queue on a broker side.
```php
createQueue('foo');
-$fooQueue->setDurable(true);
+$fooQueue->addFlag(AmqpQueue::FLAG_DURABLE);
$psrContext->declareQueue($fooQueue);
// to remove topic use delete queue method
@@ -88,11 +95,13 @@ Connects a queue to the topic. So messages from that topic comes to the queue an
```php
bind($fooTopic, $fooQueue);
+$psrContext->bind(new AmqpBind($fooTopic, $fooQueue));
```
## Send message to topic
@@ -100,7 +109,7 @@ $psrContext->bind($fooTopic, $fooQueue);
```php
createMessage('Hello world!');
@@ -112,19 +121,80 @@ $psrContext->createProducer()->send($fooTopic, $message);
```php
createMessage('Hello world!');
$psrContext->createProducer()->send($fooQueue, $message);
```
+## Send priority message
+
+```php
+createQueue('foo');
+$fooQueue->addFlag(AmqpQueue::FLAG_DURABLE);
+$fooQueue->setArguments(['x-max-priority' => 10]);
+$psrContext->declareQueue($fooQueue);
+
+$message = $psrContext->createMessage('Hello world!');
+
+$psrContext->createProducer()
+ ->setPriority(5) // the higher priority the sooner a message gets to a consumer
+ //
+ ->send($fooQueue, $message)
+;
+```
+
+## Send expiration message
+
+```php
+createMessage('Hello world!');
+
+$psrContext->createProducer()
+ ->setTimeToLive(60000) // 60 sec
+ //
+ ->send($fooQueue, $message)
+;
+```
+
+## Send delayed message
+
+AMQP specification says nothing about message delaying hence the producer throws `DeliveryDelayNotSupportedException`.
+Though the producer (and the context) accepts a delivry delay strategy and if it is set it uses it to send delayed message.
+The `enqueue/amqp-tools` package provides two RabbitMQ delay strategies, to use them you have to install that package
+
+```php
+createMessage('Hello world!');
+
+$psrContext->createProducer()
+ ->setDelayStrategy(new RabbitMqDlxDelayStrategy())
+ ->setDeliveryDelay(5000) // 5 sec
+
+ ->send($fooQueue, $message)
+;
+````
+
## Consume message:
```php
createConsumer($fooQueue);
@@ -141,11 +211,11 @@ $consumer->acknowledge($message);
```php
createQueue('aQueue');
-$psrContext->purge($queue);
+$psrContext->purgeQueue($queue);
```
[back to index](../index.md)
\ No newline at end of file
diff --git a/docs/transport/filesystem.md b/docs/transport/filesystem.md
index 34a7a5146..3b529eadc 100644
--- a/docs/transport/filesystem.md
+++ b/docs/transport/filesystem.md
@@ -9,6 +9,7 @@ A message is a line inside the file.
* [Create context](#create-context)
* [Send message to topic](#send-message-to-topic)
* [Send message to queue](#send-message-to-queue)
+* [Send expiration message](#send-expiration-message)
* [Consume message](#consume-message)
* [Purge queue messages](#purge-queue-messages)
@@ -72,6 +73,22 @@ $message = $psrContext->createMessage('Hello world!');
$psrContext->createProducer()->send($fooQueue, $message);
```
+## Send expiration message
+
+```php
+createQueue('aQueue');
+$message = $psrContext->createMessage('Hello world!');
+
+$psrContext->createProducer()
+ ->setTimeToLive(60000) // 60 sec
+ //
+ ->send($fooQueue, $message)
+;
+```
+
## Consume message:
```php
diff --git a/docs/transport/sqs.md b/docs/transport/sqs.md
index 86e3971e5..b799b1f21 100644
--- a/docs/transport/sqs.md
+++ b/docs/transport/sqs.md
@@ -7,6 +7,7 @@ It uses internally official [aws sdk library](https://packagist.org/packages/aws
* [Create context](#create-context)
* [Declare queue](#decalre-queue)
* [Send message to queue](#send-message-to-queue)
+* [Send delay message](#send-delay-message)
* [Consume message](#consume-message)
* [Purge queue messages](#purge-queue-messages)
@@ -58,6 +59,22 @@ $message = $psrContext->createMessage('Hello world!');
$psrContext->createProducer()->send($fooQueue, $message);
```
+## Send delay message
+
+```php
+createQueue('foo');
+$message = $psrContext->createMessage('Hello world!');
+
+$psrContext->createProducer()
+ ->setDeliveryDelay(60000) // 60 sec
+
+ ->send($fooQueue, $message)
+;
+```
+
## Consume message:
```php
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 8ea7f3d2b..451898eb0 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -25,6 +25,10 @@
pkg/amqp-ext/Tests
+
+ pkg/amqp-bunny/Tests
+
+
pkg/fs/Tests
diff --git a/pkg/amqp-bunny/.gitignore b/pkg/amqp-bunny/.gitignore
new file mode 100644
index 000000000..a770439e5
--- /dev/null
+++ b/pkg/amqp-bunny/.gitignore
@@ -0,0 +1,6 @@
+*~
+/composer.lock
+/composer.phar
+/phpunit.xml
+/vendor/
+/.idea/
diff --git a/pkg/amqp-bunny/.travis.yml b/pkg/amqp-bunny/.travis.yml
new file mode 100644
index 000000000..a3f4ced92
--- /dev/null
+++ b/pkg/amqp-bunny/.travis.yml
@@ -0,0 +1,21 @@
+sudo: false
+
+git:
+ depth: 1
+
+language: php
+
+php:
+ - '5.6'
+ - '7.0'
+
+cache:
+ directories:
+ - $HOME/.composer/cache
+
+install:
+ - composer self-update
+ - composer install
+
+script:
+ - vendor/bin/phpunit --exclude-group=functional
diff --git a/pkg/amqp-bunny/AmqpConnectionFactory.php b/pkg/amqp-bunny/AmqpConnectionFactory.php
new file mode 100644
index 000000000..422650d80
--- /dev/null
+++ b/pkg/amqp-bunny/AmqpConnectionFactory.php
@@ -0,0 +1,169 @@
+ 'amqp.host The host to connect too. Note: Max 1024 characters.',
+ * 'port' => 'amqp.port Port on the host.',
+ * 'vhost' => 'amqp.vhost The virtual host on the host. Note: Max 128 characters.',
+ * 'user' => 'amqp.user The user name to use. Note: Max 128 characters.',
+ * 'pass' => 'amqp.password Password. Note: Max 128 characters.',
+ * 'lazy' => 'the connection will be performed as later as possible, if the option set to true',
+ * 'receive_method' => 'Could be either basic_get or basic_consume',
+ * 'qos_prefetch_size' => 'The server will send a message in advance if it is equal to or smaller in size than the available prefetch size. May be set to zero, meaning "no specific limit"',
+ * 'qos_prefetch_count' => 'Specifies a prefetch window in terms of whole messages.',
+ * 'qos_global' => 'If "false" the QoS settings apply to the current channel only. If this field is "true", they are applied to the entire connection.',
+ * ]
+ *
+ * or
+ *
+ * amqp://user:pass@host:10000/vhost?lazy=true&socket=true
+ *
+ * @param array|string $config
+ */
+ public function __construct($config = 'amqp://')
+ {
+ if (is_string($config) && 0 === strpos($config, 'amqp+bunny://')) {
+ $config = str_replace('amqp+bunny://', 'amqp://', $config);
+ }
+
+ if (empty($config) || 'amqp://' === $config) {
+ $config = [];
+ } elseif (is_string($config)) {
+ $config = $this->parseDsn($config);
+ } elseif (is_array($config)) {
+ } else {
+ throw new \LogicException('The config must be either an array of options, a DSN string or null');
+ }
+
+ $this->config = array_replace($this->defaultConfig(), $config);
+
+ $supportedMethods = ['basic_get', 'basic_consume'];
+ if (false == in_array($this->config['receive_method'], $supportedMethods, true)) {
+ throw new \LogicException(sprintf(
+ 'Invalid "receive_method" option value "%s". It could be only "%s"',
+ $this->config['receive_method'],
+ implode('", "', $supportedMethods)
+ ));
+ }
+ }
+
+ /**
+ * @return AmqpContext
+ */
+ public function createContext()
+ {
+ if ($this->config['lazy']) {
+ $context = new AmqpContext(function () {
+ return $this->establishConnection()->channel();
+ }, $this->config);
+ $context->setDelayStrategy($this->delayStrategy);
+
+ return $context;
+ }
+
+ $context = new AmqpContext($this->establishConnection()->channel(), $this->config);
+ $context->setDelayStrategy($this->delayStrategy);
+
+ return $context;
+ }
+
+ /**
+ * @return Client
+ */
+ private function establishConnection()
+ {
+ if (false == $this->client) {
+ $this->client = new Client($this->config);
+ $this->client->connect();
+ }
+
+ return $this->client;
+ }
+
+ /**
+ * @param string $dsn
+ *
+ * @return array
+ */
+ private function parseDsn($dsn)
+ {
+ $dsnConfig = parse_url(https://github.com/$dsn);
+ if (false === $dsnConfig) {
+ throw new \LogicException(sprintf('Failed to parse DSN "%s"', $dsn));
+ }
+
+ $dsnConfig = array_replace([
+ 'scheme' => null,
+ 'host' => null,
+ 'port' => null,
+ 'user' => null,
+ 'pass' => null,
+ 'path' => null,
+ 'query' => null,
+ ], $dsnConfig);
+
+ if ('amqp' !== $dsnConfig['scheme']) {
+ throw new \LogicException(sprintf('The given DSN scheme "%s" is not supported. Could be "amqp" only.', $dsnConfig['scheme']));
+ }
+
+ if ($dsnConfig['query']) {
+ $query = [];
+ parse_str($dsnConfig['query'], $query);
+
+ $dsnConfig = array_replace($query, $dsnConfig);
+ }
+
+ $dsnConfig['vhost'] = ltrim($dsnConfig['path'], '/');
+
+ unset($dsnConfig['scheme'], $dsnConfig['query'], $dsnConfig['fragment'], $dsnConfig['path']);
+
+ $dsnConfig = array_map(function ($value) {
+ return urldecode($value);
+ }, $dsnConfig);
+
+ return $dsnConfig;
+ }
+
+ /**
+ * @return array
+ */
+ private function defaultConfig()
+ {
+ return [
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'lazy' => true,
+ 'vhost' => '/',
+ 'heartbeat' => 0,
+ 'receive_method' => 'basic_get',
+ 'qos_prefetch_size' => 0,
+ 'qos_prefetch_count' => 1,
+ 'qos_global' => false,
+ ];
+ }
+}
diff --git a/pkg/amqp-bunny/AmqpConsumer.php b/pkg/amqp-bunny/AmqpConsumer.php
new file mode 100644
index 000000000..1b59f31e8
--- /dev/null
+++ b/pkg/amqp-bunny/AmqpConsumer.php
@@ -0,0 +1,299 @@
+channel = $channel;
+ $this->queue = $queue;
+ $this->buffer = $buffer;
+ $this->receiveMethod = $receiveMethod;
+ $this->flags = self::FLAG_NOPARAM;
+
+ $this->isInit = false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setConsumerTag($consumerTag)
+ {
+ if ($this->isInit) {
+ throw new Exception('Consumer tag is not mutable after it has been subscribed to broker');
+ }
+
+ $this->consumerTag = $consumerTag;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getConsumerTag()
+ {
+ return $this->consumerTag;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function clearFlags()
+ {
+ $this->flags = self::FLAG_NOPARAM;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addFlag($flag)
+ {
+ $this->flags |= $flag;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFlags()
+ {
+ return $this->flags;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setFlags($flags)
+ {
+ $this->flags = $flags;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getQueue()
+ {
+ return $this->queue;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function receive($timeout = 0)
+ {
+ if ('basic_get' == $this->receiveMethod) {
+ return $this->receiveBasicGet($timeout);
+ }
+
+ if ('basic_consume' == $this->receiveMethod) {
+ return $this->receiveBasicConsume($timeout);
+ }
+
+ throw new \LogicException('The "receiveMethod" is not supported');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function receiveNoWait()
+ {
+ if ($message = $this->channel->get($this->queue->getQueueName(), (bool) ($this->getFlags() & InteropAmqpConsumer::FLAG_NOACK))) {
+ $this->bunnyMessages[$message->deliveryTag] = $message;
+
+ return $this->convertMessage($message);
+ }
+ }
+
+ /**
+ * @param InteropAmqpMessage $message
+ */
+ public function acknowledge(PsrMessage $message)
+ {
+ InvalidMessageException::assertMessageInstanceOf($message, InteropAmqpMessage::class);
+
+ if (isset($this->bunnyMessages[$message->getDeliveryTag()])) {
+ $this->channel->ack($this->bunnyMessages[$message->getDeliveryTag()]);
+
+ unset($this->bunnyMessages[$message->getDeliveryTag()]);
+ }
+ }
+
+ /**
+ * @param InteropAmqpMessage $message
+ * @param bool $requeue
+ */
+ public function reject(PsrMessage $message, $requeue = false)
+ {
+ InvalidMessageException::assertMessageInstanceOf($message, InteropAmqpMessage::class);
+
+ if (isset($this->bunnyMessages[$message->getDeliveryTag()])) {
+ $this->channel->reject($this->bunnyMessages[$message->getDeliveryTag()], $requeue);
+
+ unset($this->bunnyMessages[$message->getDeliveryTag()]);
+ }
+ }
+
+ /**
+ * @param Message $bunnyMessage
+ *
+ * @return InteropAmqpMessage
+ */
+ private function convertMessage(Message $bunnyMessage)
+ {
+ $headers = $bunnyMessage->headers;
+
+ $properties = [];
+ if (isset($headers['application_headers'])) {
+ $properties = $headers['application_headers'];
+ }
+ unset($headers['application_headers']);
+
+ $message = new AmqpMessage($bunnyMessage->content, $properties, $headers);
+ $message->setDeliveryTag($bunnyMessage->deliveryTag);
+ $message->setRedelivered($bunnyMessage->redelivered);
+ $message->setRoutingKey($bunnyMessage->routingKey);
+
+ return $message;
+ }
+
+ /**
+ * @param int $timeout
+ *
+ * @return InteropAmqpMessage|null
+ */
+ private function receiveBasicGet($timeout)
+ {
+ $end = microtime(true) + ($timeout / 1000);
+
+ while (0 === $timeout || microtime(true) < $end) {
+ if ($message = $this->receiveNoWait()) {
+ return $message;
+ }
+
+ usleep(100000); //100ms
+ }
+ }
+
+ /**
+ * @param int $timeout
+ *
+ * @return InteropAmqpMessage|null
+ */
+ private function receiveBasicConsume($timeout)
+ {
+ if (false === $this->isInit) {
+ $callback = function (Message $message, Channel $channel, Client $bunny) {
+ $receivedMessage = $this->convertMessage($message);
+ $receivedMessage->setConsumerTag($message->consumerTag);
+
+ $this->bunnyMessages[$message->deliveryTag] = $message;
+ $this->buffer->push($receivedMessage->getConsumerTag(), $receivedMessage);
+
+ $bunny->stop();
+ };
+
+ $frame = $this->channel->consume(
+ $callback,
+ $this->queue->getQueueName(),
+ $this->getConsumerTag() ?: $this->getQueue()->getConsumerTag(),
+ (bool) ($this->getFlags() & InteropAmqpConsumer::FLAG_NOLOCAL),
+ (bool) ($this->getFlags() & InteropAmqpConsumer::FLAG_NOACK),
+ (bool) ($this->getFlags() & InteropAmqpConsumer::FLAG_EXCLUSIVE),
+ (bool) ($this->getFlags() & InteropAmqpConsumer::FLAG_NOWAIT)
+ );
+
+ $this->consumerTag = $frame->consumerTag;
+
+ if (empty($this->consumerTag)) {
+ throw new Exception('Got empty consumer tag');
+ }
+
+ $this->isInit = true;
+ }
+
+ if ($message = $this->buffer->pop($this->consumerTag)) {
+ return $message;
+ }
+
+ while (true) {
+ $start = microtime(true);
+
+ $this->channel->getClient()->run($timeout / 1000);
+
+ if ($message = $this->buffer->pop($this->consumerTag)) {
+ return $message;
+ }
+
+ // is here when consumed message is not for this consumer
+
+ // as timeout is infinite have to continue consumption, but it can overflow message buffer
+ if ($timeout <= 0) {
+ continue;
+ }
+
+ // compute remaining timeout and continue until time is up
+ $stop = microtime(true);
+ $timeout -= ($stop - $start) * 1000;
+
+ if ($timeout <= 0) {
+ break;
+ }
+ }
+ }
+}
diff --git a/pkg/amqp-bunny/AmqpContext.php b/pkg/amqp-bunny/AmqpContext.php
new file mode 100644
index 000000000..84508e856
--- /dev/null
+++ b/pkg/amqp-bunny/AmqpContext.php
@@ -0,0 +1,331 @@
+config = array_replace([
+ 'receive_method' => 'basic_get',
+ 'qos_prefetch_size' => 0,
+ 'qos_prefetch_count' => 1,
+ 'qos_global' => false,
+ ], $config);
+
+ if ($bunnyChannel instanceof Channel) {
+ $this->bunnyChannel = $bunnyChannel;
+ } elseif (is_callable($bunnyChannel)) {
+ $this->bunnyChannelFactory = $bunnyChannel;
+ } else {
+ throw new \InvalidArgumentException('The bunnyChannel argument must be either \Bunny\Channel or callable that return it.');
+ }
+
+ $this->buffer = new Buffer();
+ }
+
+ /**
+ * @param string|null $body
+ * @param array $properties
+ * @param array $headers
+ *
+ * @return InteropAmqpMessage
+ */
+ public function createMessage($body = '', array $properties = [], array $headers = [])
+ {
+ return new AmqpMessage($body, $properties, $headers);
+ }
+
+ /**
+ * @param string $name
+ *
+ * @return InteropAmqpQueue
+ */
+ public function createQueue($name)
+ {
+ return new AmqpQueue($name);
+ }
+
+ /**
+ * @param string $name
+ *
+ * @return InteropAmqpTopic
+ */
+ public function createTopic($name)
+ {
+ return new AmqpTopic($name);
+ }
+
+ /**
+ * @param PsrDestination $destination
+ *
+ * @return AmqpConsumer
+ */
+ public function createConsumer(PsrDestination $destination)
+ {
+ $destination instanceof PsrTopic
+ ? InvalidDestinationException::assertDestinationInstanceOf($destination, InteropAmqpTopic::class)
+ : InvalidDestinationException::assertDestinationInstanceOf($destination, InteropAmqpQueue::class)
+ ;
+
+ if ($destination instanceof AmqpTopic) {
+ $queue = $this->createTemporaryQueue();
+ $this->bind(new AmqpBind($destination, $queue, $queue->getQueueName()));
+
+ return new AmqpConsumer($this->getBunnyChannel(), $queue, $this->buffer, $this->config['receive_method']);
+ }
+
+ return new AmqpConsumer($this->getBunnyChannel(), $destination, $this->buffer, $this->config['receive_method']);
+ }
+
+ /**
+ * @return AmqpProducer
+ */
+ public function createProducer()
+ {
+ $producer = new AmqpProducer($this->getBunnyChannel(), $this);
+ $producer->setDelayStrategy($this->delayStrategy);
+
+ return $producer;
+ }
+
+ /**
+ * @return InteropAmqpQueue
+ */
+ public function createTemporaryQueue()
+ {
+ $frame = $this->getBunnyChannel()->queueDeclare('', false, false, true, false);
+
+ $queue = $this->createQueue($frame->queue);
+ $queue->addFlag(InteropAmqpQueue::FLAG_EXCLUSIVE);
+
+ return $queue;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function declareTopic(InteropAmqpTopic $topic)
+ {
+ $this->getBunnyChannel()->exchangeDeclare(
+ $topic->getTopicName(),
+ $topic->getType(),
+ (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_PASSIVE),
+ (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_DURABLE),
+ (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_AUTODELETE),
+ (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_INTERNAL),
+ (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_NOWAIT),
+ $topic->getArguments()
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function deleteTopic(InteropAmqpTopic $topic)
+ {
+ $this->getBunnyChannel()->exchangeDelete(
+ $topic->getTopicName(),
+ (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_IFUNUSED),
+ (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_NOWAIT)
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function declareQueue(InteropAmqpQueue $queue)
+ {
+ $frame = $this->getBunnyChannel()->queueDeclare(
+ $queue->getQueueName(),
+ (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_PASSIVE),
+ (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_DURABLE),
+ (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_EXCLUSIVE),
+ (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_AUTODELETE),
+ (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_NOWAIT),
+ $queue->getArguments()
+ );
+
+ return $frame->messageCount;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function deleteQueue(InteropAmqpQueue $queue)
+ {
+ $this->getBunnyChannel()->queueDelete(
+ $queue->getQueueName(),
+ (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_IFUNUSED),
+ (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_IFEMPTY),
+ (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_NOWAIT)
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function purgeQueue(InteropAmqpQueue $queue)
+ {
+ $this->getBunnyChannel()->queuePurge(
+ $queue->getQueueName(),
+ (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_NOWAIT)
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function bind(InteropAmqpBind $bind)
+ {
+ if ($bind->getSource() instanceof InteropAmqpQueue && $bind->getTarget() instanceof InteropAmqpQueue) {
+ throw new Exception('Is not possible to bind queue to queue. It is possible to bind topic to queue or topic to topic');
+ }
+
+ // bind exchange to exchange
+ if ($bind->getSource() instanceof InteropAmqpTopic && $bind->getTarget() instanceof InteropAmqpTopic) {
+ $this->getBunnyChannel()->exchangeBind(
+ $bind->getTarget()->getTopicName(),
+ $bind->getSource()->getTopicName(),
+ $bind->getRoutingKey(),
+ (bool) ($bind->getFlags() & InteropAmqpBind::FLAG_NOWAIT),
+ $bind->getArguments()
+ );
+ // bind queue to exchange
+ } elseif ($bind->getSource() instanceof InteropAmqpQueue) {
+ $this->getBunnyChannel()->queueBind(
+ $bind->getSource()->getQueueName(),
+ $bind->getTarget()->getTopicName(),
+ $bind->getRoutingKey(),
+ (bool) ($bind->getFlags() & InteropAmqpBind::FLAG_NOWAIT),
+ $bind->getArguments()
+ );
+ // bind exchange to queue
+ } else {
+ $this->getBunnyChannel()->queueBind(
+ $bind->getTarget()->getQueueName(),
+ $bind->getSource()->getTopicName(),
+ $bind->getRoutingKey(),
+ (bool) ($bind->getFlags() & InteropAmqpBind::FLAG_NOWAIT),
+ $bind->getArguments()
+ );
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function unbind(InteropAmqpBind $bind)
+ {
+ if ($bind->getSource() instanceof InteropAmqpQueue && $bind->getTarget() instanceof InteropAmqpQueue) {
+ throw new Exception('Is not possible to bind queue to queue. It is possible to bind topic to queue or topic to topic');
+ }
+
+ // bind exchange to exchange
+ if ($bind->getSource() instanceof InteropAmqpTopic && $bind->getTarget() instanceof InteropAmqpTopic) {
+ $this->getBunnyChannel()->exchangeUnbind(
+ $bind->getTarget()->getTopicName(),
+ $bind->getSource()->getTopicName(),
+ $bind->getRoutingKey(),
+ (bool) ($bind->getFlags() & InteropAmqpBind::FLAG_NOWAIT),
+ $bind->getArguments()
+ );
+ // bind queue to exchange
+ } elseif ($bind->getSource() instanceof InteropAmqpQueue) {
+ $this->getBunnyChannel()->queueUnbind(
+ $bind->getSource()->getQueueName(),
+ $bind->getTarget()->getTopicName(),
+ $bind->getRoutingKey(),
+ $bind->getArguments()
+ );
+ // bind exchange to queue
+ } else {
+ $this->getBunnyChannel()->queueUnbind(
+ $bind->getTarget()->getQueueName(),
+ $bind->getSource()->getTopicName(),
+ $bind->getRoutingKey(),
+ $bind->getArguments()
+ );
+ }
+ }
+
+ public function close()
+ {
+ if ($this->bunnyChannel) {
+ $this->bunnyChannel->close();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setQos($prefetchSize, $prefetchCount, $global)
+ {
+ $this->getBunnyChannel()->qos($prefetchSize, $prefetchCount, $global);
+ }
+
+ /**
+ * @return Channel
+ */
+ public function getBunnyChannel()
+ {
+ if (false == $this->bunnyChannel) {
+ $bunnyChannel = call_user_func($this->bunnyChannelFactory);
+ if (false == $bunnyChannel instanceof Channel) {
+ throw new \LogicException(sprintf(
+ 'The factory must return instance of \Bunny\Channel. It returned %s',
+ is_object($bunnyChannel) ? get_class($bunnyChannel) : gettype($bunnyChannel)
+ ));
+ }
+
+ $this->bunnyChannel = $bunnyChannel;
+ }
+
+ return $this->bunnyChannel;
+ }
+}
diff --git a/pkg/amqp-bunny/AmqpProducer.php b/pkg/amqp-bunny/AmqpProducer.php
new file mode 100644
index 000000000..282fdcbd7
--- /dev/null
+++ b/pkg/amqp-bunny/AmqpProducer.php
@@ -0,0 +1,162 @@
+channel = $channel;
+ $this->context = $context;
+ }
+
+ /**
+ * @param InteropAmqpTopic|InteropAmqpQueue $destination
+ * @param InteropAmqpMessage $message
+ */
+ public function send(PsrDestination $destination, PsrMessage $message)
+ {
+ $destination instanceof PsrTopic
+ ? InvalidDestinationException::assertDestinationInstanceOf($destination, InteropAmqpTopic::class)
+ : InvalidDestinationException::assertDestinationInstanceOf($destination, InteropAmqpQueue::class);
+
+ InvalidMessageException::assertMessageInstanceOf($message, InteropAmqpMessage::class);
+
+ if (null !== $this->priority && null === $message->getPriority()) {
+ $message->setPriority($this->priority);
+ }
+
+ if (null !== $this->timeToLive && null === $message->getExpiration()) {
+ $message->setExpiration($this->timeToLive);
+ }
+
+ $amqpProperties = $message->getHeaders();
+
+ if ($appProperties = $message->getProperties()) {
+ $amqpProperties['application_headers'] = $appProperties;
+ }
+
+ if ($this->deliveryDelay) {
+ $this->delayStrategy->delayMessage($this->context, $destination, $message, $this->deliveryDelay);
+ } elseif ($destination instanceof InteropAmqpTopic) {
+ $this->channel->publish(
+ $message->getBody(),
+ $amqpProperties,
+ $destination->getTopicName(),
+ $message->getRoutingKey(),
+ (bool) ($message->getFlags() & InteropAmqpMessage::FLAG_MANDATORY),
+ (bool) ($message->getFlags() & InteropAmqpMessage::FLAG_IMMEDIATE)
+ );
+ } else {
+ $this->channel->publish(
+ $message->getBody(),
+ $amqpProperties,
+ '',
+ $destination->getQueueName(),
+ (bool) ($message->getFlags() & InteropAmqpMessage::FLAG_MANDATORY),
+ (bool) ($message->getFlags() & InteropAmqpMessage::FLAG_IMMEDIATE)
+ );
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setDeliveryDelay($deliveryDelay)
+ {
+ if (null === $this->delayStrategy) {
+ throw DeliveryDelayNotSupportedException::providerDoestNotSupportIt();
+ }
+
+ $this->deliveryDelay = $deliveryDelay;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDeliveryDelay()
+ {
+ return $this->deliveryDelay;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setPriority($priority)
+ {
+ $this->priority = $priority;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPriority()
+ {
+ return $this->priority;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setTimeToLive($timeToLive)
+ {
+ $this->timeToLive = $timeToLive;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTimeToLive()
+ {
+ return $this->timeToLive;
+ }
+}
diff --git a/pkg/amqp-bunny/Buffer.php b/pkg/amqp-bunny/Buffer.php
new file mode 100644
index 000000000..1912274f7
--- /dev/null
+++ b/pkg/amqp-bunny/Buffer.php
@@ -0,0 +1,43 @@
+ [AmqpMessage, AmqpMessage ...]]
+ */
+ private $messages;
+
+ public function __construct()
+ {
+ $this->messages = [];
+ }
+
+ /**
+ * @param string $consumerTag
+ * @param AmqpMessage $message
+ */
+ public function push($consumerTag, AmqpMessage $message)
+ {
+ if (false == array_key_exists($consumerTag, $this->messages)) {
+ $this->messages[$consumerTag] = [];
+ }
+
+ $this->messages[$consumerTag][] = $message;
+ }
+
+ /**
+ * @param string $consumerTag
+ *
+ * @return AmqpMessage|null
+ */
+ public function pop($consumerTag)
+ {
+ if (false == empty($this->messages[$consumerTag])) {
+ return array_shift($this->messages[$consumerTag]);
+ }
+ }
+}
diff --git a/pkg/amqp-bunny/LICENSE b/pkg/amqp-bunny/LICENSE
new file mode 100644
index 000000000..d9736f8bf
--- /dev/null
+++ b/pkg/amqp-bunny/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+Copyright (c) 2017 Kotliar Maksym
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/pkg/amqp-bunny/README.md b/pkg/amqp-bunny/README.md
new file mode 100644
index 000000000..5d600f97d
--- /dev/null
+++ b/pkg/amqp-bunny/README.md
@@ -0,0 +1,26 @@
+# AMQP Transport
+
+[](https://gitter.im/php-enqueue/Lobby)
+[](https://travis-ci.org/php-enqueue/amqp-bunny)
+[](https://packagist.org/packages/enqueue/amqp-bunny)
+[](https://packagist.org/packages/enqueue/amqp-bunny)
+
+This is an implementation of [amqp interop](https://github.com/queue-interop/amqp-interop). It uses [bunny](https://github.com/jakubkulhan/bunny) internally.
+
+## Resources
+
+* [Documentation](https://github.com/php-enqueue/enqueue-dev/blob/master/docs/index.md)
+* [Questions](https://gitter.im/php-enqueue/Lobby)
+* [Issue Tracker](https://github.com/php-enqueue/enqueue-dev/issues)
+
+## Developed by Forma-Pro
+
+Forma-Pro is a full stack development company which interests also spread to open source development.
+Being a team of strong professionals we have an aim an ability to help community by developing cutting edge solutions in the areas of e-commerce, docker & microservice oriented architecture where we have accumulated a huge many-years experience.
+Our main specialization is Symfony framework based solution, but we are always looking to the technologies that allow us to do our job the best way. We are committed to creating solutions that revolutionize the way how things are developed in aspects of architecture & scalability.
+
+If you have any questions and inquires about our open source development, this product particularly or any other matter feel free to contact at opensource@forma-pro.com
+
+## License
+
+It is released under the [MIT License](LICENSE).
\ No newline at end of file
diff --git a/pkg/amqp-bunny/Symfony/AmqpBunnyTransportFactory.php b/pkg/amqp-bunny/Symfony/AmqpBunnyTransportFactory.php
new file mode 100644
index 000000000..f83202839
--- /dev/null
+++ b/pkg/amqp-bunny/Symfony/AmqpBunnyTransportFactory.php
@@ -0,0 +1,140 @@
+name = $name;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addConfiguration(ArrayNodeDefinition $builder)
+ {
+ $builder
+ ->beforeNormalization()
+ ->ifString()
+ ->then(function ($v) {
+ return ['dsn' => $v];
+ })
+ ->end()
+ ->children()
+ ->scalarNode('dsn')
+ ->info('The connection to AMQP broker set as a string. Other parameters are ignored if set')
+ ->end()
+ ->scalarNode('host')
+ ->defaultValue('localhost')
+ ->cannotBeEmpty()
+ ->info('The host to connect too. Note: Max 1024 characters')
+ ->end()
+ ->scalarNode('port')
+ ->defaultValue(5672)
+ ->cannotBeEmpty()
+ ->info('Port on the host.')
+ ->end()
+ ->scalarNode('user')
+ ->defaultValue('guest')
+ ->cannotBeEmpty()
+ ->info('The user name to use. Note: Max 128 characters.')
+ ->end()
+ ->scalarNode('pass')
+ ->defaultValue('guest')
+ ->cannotBeEmpty()
+ ->info('Password. Note: Max 128 characters.')
+ ->end()
+ ->scalarNode('vhost')
+ ->defaultValue('/')
+ ->cannotBeEmpty()
+ ->info('The virtual host on the host. Note: Max 128 characters.')
+ ->end()
+ ->booleanNode('lazy')
+ ->defaultTrue()
+ ->end()
+ ->enumNode('receive_method')
+ ->values(['basic_get', 'basic_consume'])
+ ->defaultValue('basic_get')
+ ->info('The receive strategy to be used. We suggest to use basic_consume as it is more performant. Though you need AMQP extension 1.9.1 or higher')
+ ->end()
+ ->integerNode('heartbeat')
+ ->defaultValue(0)
+ ->end()
+ ;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createConnectionFactory(ContainerBuilder $container, array $config)
+ {
+ $factory = new Definition(AmqpConnectionFactory::class);
+ $factory->setArguments(isset($config['dsn']) ? [$config['dsn']] : [$config]);
+
+ $factoryId = sprintf('enqueue.transport.%s.connection_factory', $this->getName());
+ $container->setDefinition($factoryId, $factory);
+
+ return $factoryId;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createContext(ContainerBuilder $container, array $config)
+ {
+ $factoryId = sprintf('enqueue.transport.%s.connection_factory', $this->getName());
+
+ $context = new Definition(AmqpContext::class);
+ $context->setFactory([new Reference($factoryId), 'createContext']);
+
+ $contextId = sprintf('enqueue.transport.%s.context', $this->getName());
+ $container->setDefinition($contextId, $context);
+
+ return $contextId;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createDriver(ContainerBuilder $container, array $config)
+ {
+ $driver = new Definition(AmqpDriver::class);
+ $driver->setArguments([
+ new Reference(sprintf('enqueue.transport.%s.context', $this->getName())),
+ new Reference('enqueue.client.config'),
+ new Reference('enqueue.client.meta.queue_meta_registry'),
+ ]);
+
+ $driverId = sprintf('enqueue.client.%s.driver', $this->getName());
+ $container->setDefinition($driverId, $driver);
+
+ return $driverId;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+}
diff --git a/pkg/amqp-bunny/Symfony/RabbitMqAmqpBunnyTransportFactory.php b/pkg/amqp-bunny/Symfony/RabbitMqAmqpBunnyTransportFactory.php
new file mode 100644
index 000000000..20de33382
--- /dev/null
+++ b/pkg/amqp-bunny/Symfony/RabbitMqAmqpBunnyTransportFactory.php
@@ -0,0 +1,53 @@
+children()
+ ->booleanNode('delay_plugin_installed')
+ ->defaultFalse()
+ ->info('The option tells whether RabbitMQ broker has delay plugin installed or not')
+ ->end()
+ ;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createDriver(ContainerBuilder $container, array $config)
+ {
+ $driver = new Definition(RabbitMqDriver::class);
+ $driver->setArguments([
+ new Reference(sprintf('enqueue.transport.%s.context', $this->getName())),
+ new Reference('enqueue.client.config'),
+ new Reference('enqueue.client.meta.queue_meta_registry'),
+ ]);
+ $driverId = sprintf('enqueue.client.%s.driver', $this->getName());
+ $container->setDefinition($driverId, $driver);
+
+ return $driverId;
+ }
+}
diff --git a/pkg/amqp-bunny/Tests/AmqpConnectionFactoryConfigTest.php b/pkg/amqp-bunny/Tests/AmqpConnectionFactoryConfigTest.php
new file mode 100644
index 000000000..e659cef68
--- /dev/null
+++ b/pkg/amqp-bunny/Tests/AmqpConnectionFactoryConfigTest.php
@@ -0,0 +1,235 @@
+expectException(\LogicException::class);
+ $this->expectExceptionMessage('The config must be either an array of options, a DSN string or null');
+
+ new AmqpConnectionFactory(new \stdClass());
+ }
+
+ public function testThrowIfSchemeIsNotAmqp()
+ {
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('The given DSN scheme "http" is not supported. Could be "amqp" only.');
+
+ new AmqpConnectionFactory('http://example.com/');
+ }
+
+ public function testThrowIfDsnCouldNotBeParsed()
+ {
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Failed to parse DSN "amqp://:@/"');
+
+ new AmqpConnectionFactory('amqp://:@/');
+ }
+
+ public function testThrowIfReceiveMenthodIsInvalid()
+ {
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Invalid "receive_method" option value "invalidMethod". It could be only "basic_get", "basic_consume"');
+
+ new AmqpConnectionFactory(['receive_method' => 'invalidMethod']);
+ }
+
+ /**
+ * @dataProvider provideConfigs
+ *
+ * @param mixed $config
+ * @param mixed $expectedConfig
+ */
+ public function testShouldParseConfigurationAsExpected($config, $expectedConfig)
+ {
+ $factory = new AmqpConnectionFactory($config);
+
+ $this->assertAttributeEquals($expectedConfig, 'config', $factory);
+ }
+
+ public static function provideConfigs()
+ {
+ yield [
+ null,
+ [
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'vhost' => '/',
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'receive_method' => 'basic_get',
+ 'heartbeat' => 0,
+ 'qos_prefetch_size' => 0,
+ 'qos_prefetch_count' => 1,
+ 'qos_global' => false,
+ 'lazy' => true,
+ ],
+ ];
+
+ // some examples from Appendix A: Examples (https://www.rabbitmq.com/uri-spec.html)
+
+ yield [
+ 'amqp+bunny://user:pass@host:10000/vhost',
+ [
+ 'host' => 'host',
+ 'port' => '10000',
+ 'vhost' => 'vhost',
+ 'user' => 'user',
+ 'pass' => 'pass',
+ 'receive_method' => 'basic_get',
+ 'heartbeat' => 0,
+ 'qos_prefetch_size' => 0,
+ 'qos_prefetch_count' => 1,
+ 'qos_global' => false,
+ 'lazy' => true,
+ ],
+ ];
+
+ yield [
+ 'amqp://user:pass@host:10000/vhost',
+ [
+ 'host' => 'host',
+ 'port' => '10000',
+ 'vhost' => 'vhost',
+ 'user' => 'user',
+ 'pass' => 'pass',
+ 'receive_method' => 'basic_get',
+ 'heartbeat' => 0,
+ 'qos_prefetch_size' => 0,
+ 'qos_prefetch_count' => 1,
+ 'qos_global' => false,
+ 'lazy' => true,
+ ],
+ ];
+
+ yield [
+ 'amqp://user%61:%61pass@ho%61st:10000/v%2fhost',
+ [
+ 'host' => 'hoast',
+ 'port' => '10000',
+ 'vhost' => 'v/host',
+ 'user' => 'usera',
+ 'pass' => 'apass',
+ 'receive_method' => 'basic_get',
+ 'heartbeat' => 0,
+ 'qos_prefetch_size' => 0,
+ 'qos_prefetch_count' => 1,
+ 'qos_global' => false,
+ 'lazy' => true,
+ ],
+ ];
+
+ yield [
+ 'amqp://',
+ [
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'vhost' => '/',
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'receive_method' => 'basic_get',
+ 'heartbeat' => 0,
+ 'qos_prefetch_size' => 0,
+ 'qos_prefetch_count' => 1,
+ 'qos_global' => false,
+ 'lazy' => true,
+ ],
+ ];
+
+ yield [
+ 'amqp://user:pass@host:10000/vhost?qos_prefetch_count=2&qos_prefetch_size=1',
+ [
+ 'host' => 'host',
+ 'port' => '10000',
+ 'vhost' => 'vhost',
+ 'user' => 'user',
+ 'pass' => 'pass',
+ 'receive_method' => 'basic_get',
+ 'heartbeat' => 0,
+ 'qos_prefetch_size' => '1',
+ 'qos_prefetch_count' => '2',
+ 'qos_global' => false,
+ 'lazy' => true,
+ ],
+ ];
+
+ yield [
+ [],
+ [
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'vhost' => '/',
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'receive_method' => 'basic_get',
+ 'heartbeat' => 0,
+ 'qos_prefetch_size' => 0,
+ 'qos_prefetch_count' => 1,
+ 'qos_global' => false,
+ 'lazy' => true,
+ ],
+ ];
+
+ yield [
+ ['qos_global' => true, 'host' => 'host'],
+ [
+ 'host' => 'host',
+ 'port' => 5672,
+ 'vhost' => '/',
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'receive_method' => 'basic_get',
+ 'heartbeat' => 0,
+ 'qos_prefetch_size' => 0,
+ 'qos_prefetch_count' => 1,
+ 'qos_global' => true,
+ 'lazy' => true,
+ ],
+ ];
+
+ yield [
+ ['qos_prefetch_count' => 123, 'qos_prefetch_size' => 321],
+ [
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'vhost' => '/',
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'receive_method' => 'basic_get',
+ 'heartbeat' => 0,
+ 'qos_prefetch_size' => 321,
+ 'qos_prefetch_count' => 123,
+ 'qos_global' => false,
+ 'lazy' => true,
+ ],
+ ];
+
+ yield [
+ 'amqp://user:pass@host:10000/vhost?qos_prefetch_size=123&qos_prefetch_count=321',
+ [
+ 'host' => 'host',
+ 'port' => '10000',
+ 'vhost' => 'vhost',
+ 'user' => 'user',
+ 'pass' => 'pass',
+ 'receive_method' => 'basic_get',
+ 'heartbeat' => 0,
+ 'qos_prefetch_size' => 123,
+ 'qos_prefetch_count' => 321,
+ 'qos_global' => false,
+ 'lazy' => true,
+ ],
+ ];
+ }
+}
diff --git a/pkg/amqp-bunny/Tests/AmqpConsumerTest.php b/pkg/amqp-bunny/Tests/AmqpConsumerTest.php
new file mode 100644
index 000000000..bc716174a
--- /dev/null
+++ b/pkg/amqp-bunny/Tests/AmqpConsumerTest.php
@@ -0,0 +1,242 @@
+assertClassImplements(PsrConsumer::class, AmqpConsumer::class);
+ }
+
+ public function testCouldBeConstructedWithContextAndQueueAndBufferAsArguments()
+ {
+ new AmqpConsumer(
+ $this->createChannelMock(),
+ new AmqpQueue('aName'),
+ new Buffer(),
+ 'basic_get'
+ );
+ }
+
+ public function testShouldReturnQueue()
+ {
+ $queue = new AmqpQueue('aName');
+
+ $consumer = new AmqpConsumer($this->createChannelMock(), $queue, new Buffer(), 'basic_get');
+
+ $this->assertSame($queue, $consumer->getQueue());
+ }
+
+ public function testOnAcknowledgeShouldThrowExceptionIfNotAmqpMessage()
+ {
+ $consumer = new AmqpConsumer($this->createChannelMock(), new AmqpQueue('aName'), new Buffer(), 'basic_get');
+
+ $this->expectException(InvalidMessageException::class);
+ $this->expectExceptionMessage('The message must be an instance of Interop\Amqp\AmqpMessage but');
+
+ $consumer->acknowledge(new NullMessage());
+ }
+
+ public function testOnRejectShouldThrowExceptionIfNotAmqpMessage()
+ {
+ $consumer = new AmqpConsumer($this->createChannelMock(), new AmqpQueue('aName'), new Buffer(), 'basic_get');
+
+ $this->expectException(InvalidMessageException::class);
+ $this->expectExceptionMessage('The message must be an instance of Interop\Amqp\AmqpMessage but');
+
+ $consumer->reject(new NullMessage());
+ }
+
+ public function testOnAcknowledgeShouldAcknowledgeMessage()
+ {
+ $bunnyMessage = new Message('', 'delivery-tag', true, '', '', [], 'body');
+
+ $channel = $this->createChannelMock();
+ $channel
+ ->expects($this->once())
+ ->method('get')
+ ->willReturn($bunnyMessage)
+ ;
+ $channel
+ ->expects($this->once())
+ ->method('ack')
+ ->with($this->identicalTo($bunnyMessage))
+ ;
+
+ $consumer = new AmqpConsumer($channel, new AmqpQueue('aName'), new Buffer(), 'basic_get');
+
+ $message = $consumer->receiveNoWait();
+
+ // guard
+ $this->assertSame('delivery-tag', $message->getDeliveryTag());
+
+ $consumer->acknowledge($message);
+ }
+
+ public function testOnRejectShouldRejectMessage()
+ {
+ $bunnyMessage = new Message('', 'delivery-tag', true, '', '', [], 'body');
+
+ $channel = $this->createChannelMock();
+ $channel
+ ->expects($this->once())
+ ->method('get')
+ ->willReturn($bunnyMessage)
+ ;
+ $channel
+ ->expects($this->once())
+ ->method('reject')
+ ->with($this->identicalTo($bunnyMessage), $this->isFalse())
+ ;
+
+ $consumer = new AmqpConsumer($channel, new AmqpQueue('aName'), new Buffer(), 'basic_get');
+
+ $message = $consumer->receiveNoWait();
+
+ // guard
+ $this->assertSame('delivery-tag', $message->getDeliveryTag());
+
+ $consumer->reject($message, false);
+ }
+
+ public function testOnRejectShouldRequeueMessage()
+ {
+ $bunnyMessage = new Message('', 'delivery-tag', true, '', '', [], 'body');
+
+ $channel = $this->createChannelMock();
+ $channel
+ ->expects($this->once())
+ ->method('get')
+ ->willReturn($bunnyMessage)
+ ;
+ $channel
+ ->expects($this->once())
+ ->method('reject')
+ ->with($this->identicalTo($bunnyMessage), $this->isTrue())
+ ;
+
+ $consumer = new AmqpConsumer($channel, new AmqpQueue('aName'), new Buffer(), 'basic_get');
+
+ $message = $consumer->receiveNoWait();
+
+ // guard
+ $this->assertSame('delivery-tag', $message->getDeliveryTag());
+
+ $consumer->reject($message, true);
+ }
+
+ public function testShouldReturnMessageOnReceiveNoWait()
+ {
+ $bunnyMessage = new Message('', 'delivery-tag', true, '', '', [], 'body');
+
+ $channel = $this->createChannelMock();
+ $channel
+ ->expects($this->once())
+ ->method('get')
+ ->willReturn($bunnyMessage)
+ ;
+
+ $consumer = new AmqpConsumer($channel, new AmqpQueue('aName'), new Buffer(), 'basic_get');
+
+ $message = new AmqpMessage();
+ $message->setDeliveryTag('delivery-tag');
+
+ $message = $consumer->receiveNoWait();
+
+ $this->assertInstanceOf(AmqpMessage::class, $message);
+ $this->assertSame('body', $message->getBody());
+ $this->assertSame('delivery-tag', $message->getDeliveryTag());
+ $this->assertTrue($message->isRedelivered());
+ }
+
+ public function testShouldReturnMessageOnReceiveWithReceiveMethodBasicGet()
+ {
+ $bunnyMessage = new Message('', 'delivery-tag', true, '', '', [], 'body');
+
+ $channel = $this->createChannelMock();
+ $channel
+ ->expects($this->once())
+ ->method('get')
+ ->willReturn($bunnyMessage)
+ ;
+
+ $consumer = new AmqpConsumer($channel, new AmqpQueue('aName'), new Buffer(), 'basic_get');
+
+ $message = new AmqpMessage();
+ $message->setDeliveryTag('delivery-tag');
+
+ $message = $consumer->receive();
+
+ $this->assertInstanceOf(AmqpMessage::class, $message);
+ $this->assertSame('body', $message->getBody());
+ $this->assertSame('delivery-tag', $message->getDeliveryTag());
+ $this->assertTrue($message->isRedelivered());
+ }
+
+ public function testShouldCallExpectedMethodsWhenReceiveWithBasicConsumeMethod()
+ {
+ $frame = new MethodBasicConsumeOkFrame();
+ $frame->consumerTag = 'theConsumerTag';
+
+ $client = $this->createClientMock();
+ $client
+ ->expects($this->atLeastOnce())
+ ->method('run')
+ ;
+
+ $channel = $this->createChannelMock();
+ $channel
+ ->expects($this->once())
+ ->method('consume')
+ ->willReturn($frame)
+ ;
+ $channel
+ ->expects($this->atLeastOnce())
+ ->method('getClient')
+ ->willReturn($client)
+ ;
+
+ $consumer = new AmqpConsumer($channel, new AmqpQueue('aName'), new Buffer(), 'basic_consume');
+
+ $message = new AmqpMessage();
+ $message->setDeliveryTag('delivery-tag');
+ $consumer->receive(1234);
+
+ $this->assertSame('theConsumerTag', $consumer->getConsumerTag());
+ }
+
+ /**
+ * @return \PHPUnit_Framework_MockObject_MockObject|Client
+ */
+ public function createClientMock()
+ {
+ return $this->createMock(Client::class);
+ }
+
+ /**
+ * @return \PHPUnit_Framework_MockObject_MockObject|Channel
+ */
+ public function createChannelMock()
+ {
+ return $this->createMock(Channel::class);
+ }
+}
diff --git a/pkg/amqp-bunny/Tests/AmqpContextTest.php b/pkg/amqp-bunny/Tests/AmqpContextTest.php
new file mode 100644
index 000000000..74f435ea5
--- /dev/null
+++ b/pkg/amqp-bunny/Tests/AmqpContextTest.php
@@ -0,0 +1,245 @@
+createChannelMock();
+ $channel
+ ->expects($this->once())
+ ->method('exchangeDeclare')
+ ->with(
+ $this->identicalTo('name'),
+ $this->identicalTo('type'),
+ $this->isTrue(),
+ $this->isTrue(),
+ $this->isTrue(),
+ $this->isTrue(),
+ $this->isTrue(),
+ $this->identicalTo(['key' => 'value'])
+ )
+ ;
+
+ $topic = new AmqpTopic('name');
+ $topic->setType('type');
+ $topic->setArguments(['key' => 'value']);
+ $topic->addFlag(AmqpTopic::FLAG_DURABLE);
+ $topic->addFlag(AmqpTopic::FLAG_NOWAIT);
+ $topic->addFlag(AmqpTopic::FLAG_PASSIVE);
+ $topic->addFlag(AmqpTopic::FLAG_INTERNAL);
+ $topic->addFlag(AmqpTopic::FLAG_AUTODELETE);
+
+ $session = new AmqpContext($channel);
+ $session->declareTopic($topic);
+ }
+
+ public function testShouldDeleteTopic()
+ {
+ $channel = $this->createChannelMock();
+ $channel
+ ->expects($this->once())
+ ->method('exchangeDelete')
+ ->with(
+ $this->identicalTo('name'),
+ $this->isTrue(),
+ $this->isTrue()
+ )
+ ;
+
+ $topic = new AmqpTopic('name');
+ $topic->setType('type');
+ $topic->setArguments(['key' => 'value']);
+ $topic->addFlag(AmqpTopic::FLAG_IFUNUSED);
+ $topic->addFlag(AmqpTopic::FLAG_NOWAIT);
+
+ $session = new AmqpContext($channel);
+ $session->deleteTopic($topic);
+ }
+
+ public function testShouldDeclareQueue()
+ {
+ $frame = new MethodQueueDeclareOkFrame();
+ $frame->queue = 'name';
+ $frame->messageCount = 123;
+
+ $channel = $this->createChannelMock();
+ $channel
+ ->expects($this->once())
+ ->method('queueDeclare')
+ ->with(
+ $this->identicalTo('name'),
+ $this->isTrue(),
+ $this->isTrue(),
+ $this->isTrue(),
+ $this->isTrue(),
+ $this->isTrue(),
+ $this->identicalTo(['key' => 'value'])
+ )
+ ->willReturn($frame)
+ ;
+
+ $queue = new AmqpQueue('name');
+ $queue->setArguments(['key' => 'value']);
+ $queue->addFlag(AmqpQueue::FLAG_AUTODELETE);
+ $queue->addFlag(AmqpQueue::FLAG_DURABLE);
+ $queue->addFlag(AmqpQueue::FLAG_NOWAIT);
+ $queue->addFlag(AmqpQueue::FLAG_PASSIVE);
+ $queue->addFlag(AmqpQueue::FLAG_EXCLUSIVE);
+ $queue->addFlag(AmqpQueue::FLAG_NOWAIT);
+
+ $session = new AmqpContext($channel);
+
+ $this->assertSame(123, $session->declareQueue($queue));
+ }
+
+ public function testShouldDeleteQueue()
+ {
+ $channel = $this->createChannelMock();
+ $channel
+ ->expects($this->once())
+ ->method('queueDelete')
+ ->with(
+ $this->identicalTo('name'),
+ $this->isTrue(),
+ $this->isTrue(),
+ $this->isTrue()
+ )
+ ;
+
+ $queue = new AmqpQueue('name');
+ $queue->setArguments(['key' => 'value']);
+ $queue->addFlag(AmqpQueue::FLAG_IFUNUSED);
+ $queue->addFlag(AmqpQueue::FLAG_IFEMPTY);
+ $queue->addFlag(AmqpQueue::FLAG_NOWAIT);
+
+ $session = new AmqpContext($channel);
+ $session->deleteQueue($queue);
+ }
+
+ public function testBindShouldBindTopicToTopic()
+ {
+ $source = new AmqpTopic('source');
+ $target = new AmqpTopic('target');
+
+ $channel = $this->createChannelMock();
+ $channel
+ ->expects($this->once())
+ ->method('exchangeBind')
+ ->with($this->identicalTo('target'), $this->identicalTo('source'), $this->identicalTo('routing-key'), $this->isTrue())
+ ;
+
+ $context = new AmqpContext($channel);
+ $context->bind(new AmqpBind($target, $source, 'routing-key', 12345));
+ }
+
+ public function testBindShouldBindTopicToQueue()
+ {
+ $source = new AmqpTopic('source');
+ $target = new AmqpQueue('target');
+
+ $channel = $this->createChannelMock();
+ $channel
+ ->expects($this->exactly(2))
+ ->method('queueBind')
+ ->with($this->identicalTo('target'), $this->identicalTo('source'), $this->identicalTo('routing-key'), $this->isTrue())
+ ;
+
+ $context = new AmqpContext($channel);
+ $context->bind(new AmqpBind($target, $source, 'routing-key', 12345));
+ $context->bind(new AmqpBind($source, $target, 'routing-key', 12345));
+ }
+
+ public function testShouldUnBindTopicFromTopic()
+ {
+ $source = new AmqpTopic('source');
+ $target = new AmqpTopic('target');
+
+ $channel = $this->createChannelMock();
+ $channel
+ ->expects($this->once())
+ ->method('exchangeUnbind')
+ ->with($this->identicalTo('target'), $this->identicalTo('source'), $this->identicalTo('routing-key'), $this->isTrue())
+ ;
+
+ $context = new AmqpContext($channel);
+ $context->unbind(new AmqpBind($target, $source, 'routing-key', 12345));
+ }
+
+ public function testShouldUnBindTopicFromQueue()
+ {
+ $source = new AmqpTopic('source');
+ $target = new AmqpQueue('target');
+
+ $channel = $this->createChannelMock();
+ $channel
+ ->expects($this->exactly(2))
+ ->method('queueUnbind')
+ ->with($this->identicalTo('target'), $this->identicalTo('source'), $this->identicalTo('routing-key'), ['key' => 'value'])
+ ;
+
+ $context = new AmqpContext($channel);
+ $context->unbind(new AmqpBind($target, $source, 'routing-key', 12345, ['key' => 'value']));
+ $context->unbind(new AmqpBind($source, $target, 'routing-key', 12345, ['key' => 'value']));
+ }
+
+ public function testShouldCloseChannelConnection()
+ {
+ $channel = $this->createChannelMock();
+ $channel
+ ->expects($this->once())
+ ->method('close')
+ ;
+
+ $context = new AmqpContext($channel);
+ $context->createProducer();
+
+ $context->close();
+ }
+
+ public function testShouldPurgeQueue()
+ {
+ $queue = new AmqpQueue('queue');
+ $queue->addFlag(AmqpQueue::FLAG_NOWAIT);
+
+ $channel = $this->createChannelMock();
+ $channel
+ ->expects($this->once())
+ ->method('queuePurge')
+ ->with($this->identicalTo('queue'), $this->isTrue())
+ ;
+
+ $context = new AmqpContext($channel);
+ $context->purgeQueue($queue);
+ }
+
+ public function testShouldSetQos()
+ {
+ $channel = $this->createChannelMock();
+ $channel
+ ->expects($this->once())
+ ->method('qos')
+ ->with($this->identicalTo(123), $this->identicalTo(456), $this->isTrue())
+ ;
+
+ $context = new AmqpContext($channel);
+ $context->setQos(123, 456, true);
+ }
+
+ /**
+ * @return \PHPUnit_Framework_MockObject_MockObject|Channel
+ */
+ public function createChannelMock()
+ {
+ return $this->createMock(Channel::class);
+ }
+}
diff --git a/pkg/amqp-bunny/Tests/AmqpProducerTest.php b/pkg/amqp-bunny/Tests/AmqpProducerTest.php
new file mode 100644
index 000000000..ddb067858
--- /dev/null
+++ b/pkg/amqp-bunny/Tests/AmqpProducerTest.php
@@ -0,0 +1,214 @@
+createBunnyChannelMock(), $this->createContextMock());
+ }
+
+ public function testShouldImplementPsrProducerInterface()
+ {
+ $this->assertClassImplements(PsrProducer::class, AmqpProducer::class);
+ }
+
+ public function testShouldThrowExceptionWhenDestinationTypeIsInvalid()
+ {
+ $producer = new AmqpProducer($this->createBunnyChannelMock(), $this->createContextMock());
+
+ $this->expectException(InvalidDestinationException::class);
+ $this->expectExceptionMessage('The destination must be an instance of Interop\Amqp\AmqpQueue but got');
+
+ $producer->send($this->createDestinationMock(), new AmqpMessage());
+ }
+
+ public function testShouldThrowExceptionWhenMessageTypeIsInvalid()
+ {
+ $producer = new AmqpProducer($this->createBunnyChannelMock(), $this->createContextMock());
+
+ $this->expectException(InvalidMessageException::class);
+ $this->expectExceptionMessage('The message must be an instance of Interop\Amqp\AmqpMessage but it is');
+
+ $producer->send(new AmqpTopic('name'), $this->createMessageMock());
+ }
+
+ public function testShouldPublishMessageToTopic()
+ {
+ $channel = $this->createBunnyChannelMock();
+ $channel
+ ->expects($this->once())
+ ->method('publish')
+ ->with('body', [], 'topic', 'routing-key', false, false)
+ ;
+
+ $topic = new AmqpTopic('topic');
+
+ $message = new AmqpMessage('body');
+ $message->setRoutingKey('routing-key');
+
+ $producer = new AmqpProducer($channel, $this->createContextMock());
+ $producer->send($topic, $message);
+ }
+
+ public function testShouldPublishMessageToQueue()
+ {
+ $channel = $this->createBunnyChannelMock();
+ $channel
+ ->expects($this->once())
+ ->method('publish')
+ ->with('body', [], '', 'queue', false, false)
+ ;
+
+ $queue = new AmqpQueue('queue');
+
+ $producer = new AmqpProducer($channel, $this->createContextMock());
+ $producer->send($queue, new AmqpMessage('body'));
+ }
+
+ public function testShouldDelayMessage()
+ {
+ $channel = $this->createBunnyChannelMock();
+ $channel
+ ->expects($this->never())
+ ->method('publish')
+ ;
+
+ $message = new AmqpMessage('body');
+ $context = $this->createContextMock();
+ $queue = new AmqpQueue('queue');
+
+ $delayStrategy = $this->createDelayStrategyMock();
+ $delayStrategy
+ ->expects($this->once())
+ ->method('delayMessage')
+ ->with($this->identicalTo($context), $this->identicalTo($queue), $this->identicalTo($message), 10000)
+ ;
+
+ $producer = new AmqpProducer($channel, $context);
+ $producer->setDelayStrategy($delayStrategy);
+ $producer->setDeliveryDelay(10000);
+
+ $producer->send($queue, $message);
+ }
+
+ public function testShouldThrowExceptionOnSetDeliveryDelayWhenDeliveryStrategyIsNotSet()
+ {
+ $channel = $this->createBunnyChannelMock();
+ $channel
+ ->expects($this->never())
+ ->method('publish')
+ ;
+
+ $producer = new AmqpProducer($channel, $this->createContextMock());
+
+ $this->expectException(DeliveryDelayNotSupportedException::class);
+ $this->expectExceptionMessage('The provider does not support delivery delay feature');
+
+ $producer->setDeliveryDelay(10000);
+ }
+
+ public function testShouldSetMessageHeaders()
+ {
+ $channel = $this->createBunnyChannelMock();
+ $channel
+ ->expects($this->once())
+ ->method('publish')
+ ->with($this->anything(), ['content_type' => 'text/plain'])
+ ;
+
+ $producer = new AmqpProducer($channel, $this->createContextMock());
+ $producer->send(new AmqpTopic('name'), new AmqpMessage('body', [], ['content_type' => 'text/plain']));
+ }
+
+ public function testShouldSetMessageProperties()
+ {
+ $channel = $this->createBunnyChannelMock();
+ $channel
+ ->expects($this->once())
+ ->method('publish')
+ ->with($this->anything(), ['application_headers' => ['key' => 'value']])
+ ;
+
+ $producer = new AmqpProducer($channel, $this->createContextMock());
+ $producer->send(new AmqpTopic('name'), new AmqpMessage('body', ['key' => 'value']));
+ }
+
+ public function testShouldPropagateFlags()
+ {
+ $channel = $this->createBunnyChannelMock();
+ $channel
+ ->expects($this->once())
+ ->method('publish')
+ ->with($this->anything(), $this->anything(), $this->anything(), $this->anything(), true, true)
+ ;
+
+ $message = new AmqpMessage('body');
+ $message->addFlag(InteropAmqpMessage::FLAG_IMMEDIATE);
+ $message->addFlag(InteropAmqpMessage::FLAG_MANDATORY);
+
+ $producer = new AmqpProducer($channel, $this->createContextMock());
+ $producer->send(new AmqpTopic('name'), $message);
+ }
+
+ /**
+ * @return \PHPUnit_Framework_MockObject_MockObject|PsrMessage
+ */
+ private function createMessageMock()
+ {
+ return $this->createMock(PsrMessage::class);
+ }
+
+ /**
+ * @return \PHPUnit_Framework_MockObject_MockObject|PsrDestination
+ */
+ private function createDestinationMock()
+ {
+ return $this->createMock(PsrDestination::class);
+ }
+
+ /**
+ * @return \PHPUnit_Framework_MockObject_MockObject|Channel
+ */
+ private function createBunnyChannelMock()
+ {
+ return $this->createMock(Channel::class);
+ }
+
+ /**
+ * @return \PHPUnit_Framework_MockObject_MockObject|AmqpContext
+ */
+ private function createContextMock()
+ {
+ return $this->createMock(AmqpContext::class);
+ }
+
+ /**
+ * @return \PHPUnit_Framework_MockObject_MockObject|DelayStrategy
+ */
+ private function createDelayStrategyMock()
+ {
+ return $this->createMock(DelayStrategy::class);
+ }
+}
diff --git a/pkg/amqp-bunny/Tests/BufferTest.php b/pkg/amqp-bunny/Tests/BufferTest.php
new file mode 100644
index 000000000..6cb1ef0ad
--- /dev/null
+++ b/pkg/amqp-bunny/Tests/BufferTest.php
@@ -0,0 +1,64 @@
+assertAttributeSame([], 'messages', $buffer);
+ }
+
+ public function testShouldReturnNullIfNoMessagesInBuffer()
+ {
+ $buffer = new Buffer();
+
+ $this->assertNull($buffer->pop('aConsumerTag'));
+ $this->assertNull($buffer->pop('anotherConsumerTag'));
+ }
+
+ public function testShouldPushMessageToBuffer()
+ {
+ $fooMessage = new AmqpMessage();
+ $barMessage = new AmqpMessage();
+ $bazMessage = new AmqpMessage();
+
+ $buffer = new Buffer();
+
+ $buffer->push('aConsumerTag', $fooMessage);
+ $buffer->push('aConsumerTag', $barMessage);
+
+ $buffer->push('anotherConsumerTag', $bazMessage);
+
+ $this->assertAttributeSame([
+ 'aConsumerTag' => [$fooMessage, $barMessage],
+ 'anotherConsumerTag' => [$bazMessage],
+ ], 'messages', $buffer);
+ }
+
+ public function testShouldPopMessageFromBuffer()
+ {
+ $fooMessage = new AmqpMessage();
+ $barMessage = new AmqpMessage();
+
+ $buffer = new Buffer();
+
+ $buffer->push('aConsumerTag', $fooMessage);
+ $buffer->push('aConsumerTag', $barMessage);
+
+ $this->assertSame($fooMessage, $buffer->pop('aConsumerTag'));
+ $this->assertSame($barMessage, $buffer->pop('aConsumerTag'));
+ $this->assertNull($buffer->pop('aConsumerTag'));
+ }
+}
diff --git a/pkg/amqp-bunny/Tests/Spec/AmqpConnectionFactoryTest.php b/pkg/amqp-bunny/Tests/Spec/AmqpConnectionFactoryTest.php
new file mode 100644
index 000000000..d8d481527
--- /dev/null
+++ b/pkg/amqp-bunny/Tests/Spec/AmqpConnectionFactoryTest.php
@@ -0,0 +1,14 @@
+createMock(Channel::class);
+
+ return new AmqpContext($channel);
+ }
+}
diff --git a/pkg/amqp-bunny/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php b/pkg/amqp-bunny/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php
new file mode 100644
index 000000000..c5d7ed40b
--- /dev/null
+++ b/pkg/amqp-bunny/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php
@@ -0,0 +1,37 @@
+setDelayStrategy(new RabbitMqDelayPluginDelayStrategy());
+
+ return $factory->createContext();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function createQueue(PsrContext $context, $queueName)
+ {
+ $queue = parent::createQueue($context, $queueName);
+
+ $context->declareQueue($queue);
+
+ return $queue;
+ }
+}
diff --git a/pkg/amqp-bunny/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest.php b/pkg/amqp-bunny/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest.php
new file mode 100644
index 000000000..7795d01b8
--- /dev/null
+++ b/pkg/amqp-bunny/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest.php
@@ -0,0 +1,37 @@
+setDelayStrategy(new RabbitMqDlxDelayStrategy());
+
+ return $factory->createContext();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function createQueue(PsrContext $context, $queueName)
+ {
+ $queue = parent::createQueue($context, $queueName);
+
+ $context->declareQueue($queue);
+
+ return $queue;
+ }
+}
diff --git a/pkg/amqp-bunny/Tests/Spec/AmqpSendAndReceivePriorityMessagesFromQueueTest.php b/pkg/amqp-bunny/Tests/Spec/AmqpSendAndReceivePriorityMessagesFromQueueTest.php
new file mode 100644
index 000000000..c70f89079
--- /dev/null
+++ b/pkg/amqp-bunny/Tests/Spec/AmqpSendAndReceivePriorityMessagesFromQueueTest.php
@@ -0,0 +1,40 @@
+createContext();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param AmqpContext $context
+ */
+ protected function createQueue(PsrContext $context, $queueName)
+ {
+ $queue = $context->createQueue($queueName);
+ $queue->setArguments(['x-max-priority' => 10]);
+
+ $context->declareQueue($queue);
+ $context->purgeQueue($queue);
+
+ return $queue;
+ }
+}
diff --git a/pkg/amqp-bunny/Tests/Spec/AmqpSendAndReceiveTimeToLiveMessagesFromQueueTest.php b/pkg/amqp-bunny/Tests/Spec/AmqpSendAndReceiveTimeToLiveMessagesFromQueueTest.php
new file mode 100644
index 000000000..5f5e07c0f
--- /dev/null
+++ b/pkg/amqp-bunny/Tests/Spec/AmqpSendAndReceiveTimeToLiveMessagesFromQueueTest.php
@@ -0,0 +1,38 @@
+createContext();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param AmqpContext $context
+ */
+ protected function createQueue(PsrContext $context, $queueName)
+ {
+ $queue = $context->createQueue($queueName);
+ $context->declareQueue($queue);
+ $context->purgeQueue($queue);
+
+ return $queue;
+ }
+}
diff --git a/pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveFromQueueTest.php b/pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveFromQueueTest.php
new file mode 100644
index 000000000..1111103c1
--- /dev/null
+++ b/pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveFromQueueTest.php
@@ -0,0 +1,38 @@
+createContext();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param AmqpContext $context
+ */
+ protected function createQueue(PsrContext $context, $queueName)
+ {
+ $queue = $context->createQueue($queueName);
+ $context->declareQueue($queue);
+ $context->purgeQueue($queue);
+
+ return $queue;
+ }
+}
diff --git a/pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveFromTopicTest.php b/pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveFromTopicTest.php
new file mode 100644
index 000000000..4647239ef
--- /dev/null
+++ b/pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveFromTopicTest.php
@@ -0,0 +1,40 @@
+createContext();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param AmqpContext $context
+ */
+ protected function createTopic(PsrContext $context, $topicName)
+ {
+ $topic = $context->createTopic($topicName);
+ $topic->setType(AmqpTopic::TYPE_FANOUT);
+ $topic->addFlag(AmqpTopic::FLAG_DURABLE);
+ $context->declareTopic($topic);
+
+ return $topic;
+ }
+}
diff --git a/pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveNoWaitFromQueueTest.php b/pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveNoWaitFromQueueTest.php
new file mode 100644
index 000000000..461e98680
--- /dev/null
+++ b/pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveNoWaitFromQueueTest.php
@@ -0,0 +1,38 @@
+createContext();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param AmqpContext $context
+ */
+ protected function createQueue(PsrContext $context, $queueName)
+ {
+ $queue = $context->createQueue($queueName);
+ $context->declareQueue($queue);
+ $context->purgeQueue($queue);
+
+ return $queue;
+ }
+}
diff --git a/pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveNoWaitFromTopicTest.php b/pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveNoWaitFromTopicTest.php
new file mode 100644
index 000000000..8fa295b52
--- /dev/null
+++ b/pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveNoWaitFromTopicTest.php
@@ -0,0 +1,40 @@
+createContext();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param AmqpContext $context
+ */
+ protected function createTopic(PsrContext $context, $topicName)
+ {
+ $topic = $context->createTopic($topicName);
+ $topic->setType(AmqpTopic::TYPE_FANOUT);
+ $topic->addFlag(AmqpTopic::FLAG_DURABLE);
+ $context->declareTopic($topic);
+
+ return $topic;
+ }
+}
diff --git a/pkg/amqp-bunny/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicConsumeMethodTest.php b/pkg/amqp-bunny/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicConsumeMethodTest.php
new file mode 100644
index 000000000..49f502695
--- /dev/null
+++ b/pkg/amqp-bunny/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicConsumeMethodTest.php
@@ -0,0 +1,61 @@
+createContext();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param AmqpContext $context
+ */
+ protected function createQueue(PsrContext $context, $queueName)
+ {
+ $queueName .= '_basic_consume';
+
+ $queue = $context->createQueue($queueName);
+ $context->declareQueue($queue);
+ $context->purgeQueue($queue);
+
+ $context->bind(new AmqpBind($context->createTopic($queueName), $queue));
+
+ return $queue;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param AmqpContext $context
+ */
+ protected function createTopic(PsrContext $context, $topicName)
+ {
+ $topicName .= '_basic_consume';
+
+ $topic = $context->createTopic($topicName);
+ $topic->setType(AmqpTopic::TYPE_FANOUT);
+ $topic->addFlag(AmqpTopic::FLAG_DURABLE);
+ $context->declareTopic($topic);
+
+ return $topic;
+ }
+}
diff --git a/pkg/amqp-bunny/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicGetMethodTest.php b/pkg/amqp-bunny/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicGetMethodTest.php
new file mode 100644
index 000000000..c06dac310
--- /dev/null
+++ b/pkg/amqp-bunny/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicGetMethodTest.php
@@ -0,0 +1,57 @@
+createContext();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param AmqpContext $context
+ */
+ protected function createQueue(PsrContext $context, $queueName)
+ {
+ $queue = $context->createQueue($queueName);
+ $context->declareQueue($queue);
+ $context->purgeQueue($queue);
+
+ $context->bind(new AmqpBind($context->createTopic($queueName), $queue));
+
+ return $queue;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param AmqpContext $context
+ */
+ protected function createTopic(PsrContext $context, $topicName)
+ {
+ $topic = $context->createTopic($topicName);
+ $topic->setType(AmqpTopic::TYPE_FANOUT);
+ $topic->addFlag(AmqpTopic::FLAG_DURABLE);
+ $context->declareTopic($topic);
+
+ return $topic;
+ }
+}
diff --git a/pkg/amqp-bunny/Tests/Spec/AmqpSendToTopicAndReceiveNoWaitFromQueueTest.php b/pkg/amqp-bunny/Tests/Spec/AmqpSendToTopicAndReceiveNoWaitFromQueueTest.php
new file mode 100644
index 000000000..547c3b775
--- /dev/null
+++ b/pkg/amqp-bunny/Tests/Spec/AmqpSendToTopicAndReceiveNoWaitFromQueueTest.php
@@ -0,0 +1,57 @@
+createContext();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param AmqpContext $context
+ */
+ protected function createQueue(PsrContext $context, $queueName)
+ {
+ $queue = $context->createQueue($queueName);
+ $context->declareQueue($queue);
+ $context->purgeQueue($queue);
+
+ $context->bind(new AmqpBind($context->createTopic($queueName), $queue));
+
+ return $queue;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param AmqpContext $context
+ */
+ protected function createTopic(PsrContext $context, $topicName)
+ {
+ $topic = $context->createTopic($topicName);
+ $topic->setType(AmqpTopic::TYPE_FANOUT);
+ $topic->addFlag(AmqpTopic::FLAG_DURABLE);
+ $context->declareTopic($topic);
+
+ return $topic;
+ }
+}
diff --git a/pkg/amqp-bunny/Tests/Symfony/AmqpBunnyTransportFactoryTest.php b/pkg/amqp-bunny/Tests/Symfony/AmqpBunnyTransportFactoryTest.php
new file mode 100644
index 000000000..9b2a68bc2
--- /dev/null
+++ b/pkg/amqp-bunny/Tests/Symfony/AmqpBunnyTransportFactoryTest.php
@@ -0,0 +1,218 @@
+assertClassImplements(TransportFactoryInterface::class, AmqpBunnyTransportFactory::class);
+ }
+
+ public function testCouldBeConstructedWithDefaultName()
+ {
+ $transport = new AmqpBunnyTransportFactory();
+
+ $this->assertEquals('amqp_bunny', $transport->getName());
+ }
+
+ public function testCouldBeConstructedWithCustomName()
+ {
+ $transport = new AmqpBunnyTransportFactory('theCustomName');
+
+ $this->assertEquals('theCustomName', $transport->getName());
+ }
+
+ public function testShouldAllowAddConfiguration()
+ {
+ $transport = new AmqpBunnyTransportFactory();
+ $tb = new TreeBuilder();
+ $rootNode = $tb->root('foo');
+
+ $transport->addConfiguration($rootNode);
+ $processor = new Processor();
+ $config = $processor->process($tb->buildTree(), []);
+
+ $this->assertEquals([
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'vhost' => '/',
+ 'lazy' => true,
+ 'receive_method' => 'basic_get',
+ 'heartbeat' => 0,
+ ], $config);
+ }
+
+ public function testShouldAllowAddConfigurationAsString()
+ {
+ $transport = new AmqpBunnyTransportFactory();
+ $tb = new TreeBuilder();
+ $rootNode = $tb->root('foo');
+
+ $transport->addConfiguration($rootNode);
+ $processor = new Processor();
+ $config = $processor->process($tb->buildTree(), ['amqpDSN']);
+
+ $this->assertEquals([
+ 'dsn' => 'amqpDSN',
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'vhost' => '/',
+ 'lazy' => true,
+ 'receive_method' => 'basic_get',
+ 'heartbeat' => 0,
+ ], $config);
+ }
+
+ public function testThrowIfInvalidReceiveMethodIsSet()
+ {
+ $transport = new AmqpBunnyTransportFactory();
+ $tb = new TreeBuilder();
+ $rootNode = $tb->root('foo');
+
+ $transport->addConfiguration($rootNode);
+ $processor = new Processor();
+
+ $this->expectException(InvalidConfigurationException::class);
+ $this->expectExceptionMessage('The value "anInvalidMethod" is not allowed for path "foo.receive_method". Permissible values: "basic_get", "basic_consume"');
+ $processor->process($tb->buildTree(), [[
+ 'receive_method' => 'anInvalidMethod',
+ ]]);
+ }
+
+ public function testShouldAllowChangeReceiveMethod()
+ {
+ $transport = new AmqpBunnyTransportFactory();
+ $tb = new TreeBuilder();
+ $rootNode = $tb->root('foo');
+
+ $transport->addConfiguration($rootNode);
+ $processor = new Processor();
+ $config = $processor->process($tb->buildTree(), [[
+ 'receive_method' => 'basic_consume',
+ ]]);
+
+ $this->assertEquals([
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'vhost' => '/',
+ 'lazy' => true,
+ 'receive_method' => 'basic_consume',
+ 'heartbeat' => 0,
+ ], $config);
+ }
+
+ public function testShouldCreateConnectionFactory()
+ {
+ $container = new ContainerBuilder();
+
+ $transport = new AmqpBunnyTransportFactory();
+
+ $serviceId = $transport->createConnectionFactory($container, [
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'vhost' => '/',
+ ]);
+
+ $this->assertTrue($container->hasDefinition($serviceId));
+ $factory = $container->getDefinition($serviceId);
+ $this->assertEquals(AmqpConnectionFactory::class, $factory->getClass());
+ $this->assertSame([[
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'vhost' => '/',
+ ]], $factory->getArguments());
+ }
+
+ public function testShouldCreateConnectionFactoryFromDsnString()
+ {
+ $container = new ContainerBuilder();
+
+ $transport = new AmqpBunnyTransportFactory();
+
+ $serviceId = $transport->createConnectionFactory($container, [
+ 'dsn' => 'theConnectionDSN',
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'vhost' => '/',
+ ]);
+
+ $this->assertTrue($container->hasDefinition($serviceId));
+ $factory = $container->getDefinition($serviceId);
+ $this->assertEquals(AmqpConnectionFactory::class, $factory->getClass());
+ $this->assertSame(['theConnectionDSN'], $factory->getArguments());
+ }
+
+ public function testShouldCreateContext()
+ {
+ $container = new ContainerBuilder();
+
+ $transport = new AmqpBunnyTransportFactory();
+
+ $serviceId = $transport->createContext($container, [
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'vhost' => '/',
+ ]);
+
+ $this->assertEquals('enqueue.transport.amqp_bunny.context', $serviceId);
+ $this->assertTrue($container->hasDefinition($serviceId));
+
+ $context = $container->getDefinition('enqueue.transport.amqp_bunny.context');
+ $this->assertInstanceOf(Reference::class, $context->getFactory()[0]);
+ $this->assertEquals('enqueue.transport.amqp_bunny.connection_factory', (string) $context->getFactory()[0]);
+ $this->assertEquals('createContext', $context->getFactory()[1]);
+ }
+
+ public function testShouldCreateDriver()
+ {
+ $container = new ContainerBuilder();
+
+ $transport = new AmqpBunnyTransportFactory();
+
+ $serviceId = $transport->createDriver($container, []);
+
+ $this->assertEquals('enqueue.client.amqp_bunny.driver', $serviceId);
+ $this->assertTrue($container->hasDefinition($serviceId));
+
+ $driver = $container->getDefinition($serviceId);
+ $this->assertSame(AmqpDriver::class, $driver->getClass());
+
+ $this->assertInstanceOf(Reference::class, $driver->getArgument(0));
+ $this->assertEquals('enqueue.transport.amqp_bunny.context', (string) $driver->getArgument(0));
+
+ $this->assertInstanceOf(Reference::class, $driver->getArgument(1));
+ $this->assertEquals('enqueue.client.config', (string) $driver->getArgument(1));
+
+ $this->assertInstanceOf(Reference::class, $driver->getArgument(2));
+ $this->assertEquals('enqueue.client.meta.queue_meta_registry', (string) $driver->getArgument(2));
+ }
+}
diff --git a/pkg/amqp-bunny/Tests/Symfony/RabbitMqAmqpBunnyTransportFactoryTest.php b/pkg/amqp-bunny/Tests/Symfony/RabbitMqAmqpBunnyTransportFactoryTest.php
new file mode 100644
index 000000000..4dd11871b
--- /dev/null
+++ b/pkg/amqp-bunny/Tests/Symfony/RabbitMqAmqpBunnyTransportFactoryTest.php
@@ -0,0 +1,137 @@
+assertClassImplements(TransportFactoryInterface::class, RabbitMqAmqpBunnyTransportFactory::class);
+ }
+
+ public function testShouldExtendAmqpTransportFactoryClass()
+ {
+ $this->assertClassExtends(AmqpBunnyTransportFactory::class, RabbitMqAmqpBunnyTransportFactory::class);
+ }
+
+ public function testCouldBeConstructedWithDefaultName()
+ {
+ $transport = new RabbitMqAmqpBunnyTransportFactory();
+
+ $this->assertEquals('rabbitmq_amqp_bunny', $transport->getName());
+ }
+
+ public function testCouldBeConstructedWithCustomName()
+ {
+ $transport = new RabbitMqAmqpBunnyTransportFactory('theCustomName');
+
+ $this->assertEquals('theCustomName', $transport->getName());
+ }
+
+ public function testShouldAllowAddConfiguration()
+ {
+ $transport = new RabbitMqAmqpBunnyTransportFactory();
+ $tb = new TreeBuilder();
+ $rootNode = $tb->root('foo');
+
+ $transport->addConfiguration($rootNode);
+ $processor = new Processor();
+ $config = $processor->process($tb->buildTree(), []);
+
+ $this->assertEquals([
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'vhost' => '/',
+ 'delay_plugin_installed' => false,
+ 'lazy' => true,
+ 'receive_method' => 'basic_get',
+ 'heartbeat' => 0,
+ ], $config);
+ }
+
+ public function testShouldCreateConnectionFactory()
+ {
+ $container = new ContainerBuilder();
+
+ $transport = new RabbitMqAmqpBunnyTransportFactory();
+
+ $serviceId = $transport->createConnectionFactory($container, [
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'vhost' => '/',
+ 'persisted' => false,
+ 'delay_plugin_installed' => false,
+ ]);
+
+ $this->assertTrue($container->hasDefinition($serviceId));
+ $factory = $container->getDefinition($serviceId);
+ $this->assertEquals(AmqpConnectionFactory::class, $factory->getClass());
+ $this->assertSame([[
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'vhost' => '/',
+ 'persisted' => false,
+ 'delay_plugin_installed' => false,
+ ]], $factory->getArguments());
+ }
+
+ public function testShouldCreateContext()
+ {
+ $container = new ContainerBuilder();
+
+ $transport = new RabbitMqAmqpBunnyTransportFactory();
+
+ $serviceId = $transport->createContext($container, [
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'vhost' => '/',
+ 'persisted' => false,
+ 'delay_plugin_installed' => false,
+ ]);
+
+ $this->assertEquals('enqueue.transport.rabbitmq_amqp_bunny.context', $serviceId);
+ $this->assertTrue($container->hasDefinition($serviceId));
+
+ $context = $container->getDefinition('enqueue.transport.rabbitmq_amqp_bunny.context');
+ $this->assertInstanceOf(Reference::class, $context->getFactory()[0]);
+ $this->assertEquals('enqueue.transport.rabbitmq_amqp_bunny.connection_factory', (string) $context->getFactory()[0]);
+ $this->assertEquals('createContext', $context->getFactory()[1]);
+ }
+
+ public function testShouldCreateDriver()
+ {
+ $container = new ContainerBuilder();
+
+ $transport = new RabbitMqAmqpBunnyTransportFactory();
+
+ $serviceId = $transport->createDriver($container, []);
+
+ $this->assertEquals('enqueue.client.rabbitmq_amqp_bunny.driver', $serviceId);
+ $this->assertTrue($container->hasDefinition($serviceId));
+
+ $driver = $container->getDefinition($serviceId);
+ $this->assertSame(RabbitMqDriver::class, $driver->getClass());
+ }
+}
diff --git a/pkg/amqp-bunny/composer.json b/pkg/amqp-bunny/composer.json
new file mode 100644
index 000000000..109dedd00
--- /dev/null
+++ b/pkg/amqp-bunny/composer.json
@@ -0,0 +1,43 @@
+{
+ "name": "enqueue/amqp-bunny",
+ "type": "library",
+ "description": "Message Queue Amqp Transport",
+ "keywords": ["messaging", "queue", "amqp", "bunny"],
+ "license": "MIT",
+ "repositories": [
+ {
+ "type": "vcs",
+ "url": "git@github.com:php-enqueue/test.git"
+ }
+ ],
+ "require": {
+ "php": ">=5.6",
+
+ "queue-interop/amqp-interop": "^0.6@dev",
+ "bunny/bunny": "^0.2.4",
+ "enqueue/amqp-tools": "^0.7@dev",
+ "psr/log": "^1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~5.4.0",
+ "enqueue/test": "^0.7@dev",
+ "enqueue/enqueue": "^0.7@dev",
+ "enqueue/null": "^0.7@dev",
+ "queue-interop/queue-spec": "^0.5@dev"
+ },
+ "autoload": {
+ "psr-4": { "Enqueue\\AmqpBunny\\": "" },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "suggest": {
+ "enqueue/enqueue": "If you'd like to use advanced features like Client abstract layer or Symfony integration features"
+ },
+ "minimum-stability": "dev",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "0.7.x-dev"
+ }
+ }
+}
diff --git a/pkg/amqp-bunny/phpunit.xml.dist b/pkg/amqp-bunny/phpunit.xml.dist
new file mode 100644
index 000000000..7d6c5ed3e
--- /dev/null
+++ b/pkg/amqp-bunny/phpunit.xml.dist
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+ ./Tests
+
+
+
+
+
+ .
+
+ ./vendor
+ ./Tests
+
+
+
+
diff --git a/pkg/amqp-ext/.travis.yml b/pkg/amqp-ext/.travis.yml
index ad53bf6b4..2f48cf85d 100644
--- a/pkg/amqp-ext/.travis.yml
+++ b/pkg/amqp-ext/.travis.yml
@@ -14,8 +14,9 @@ cache:
- $HOME/.composer/cache
install:
+ - php Tests/fix_composer_json.php
- composer self-update
- - composer install --prefer-source --ignore-platform-reqs # ext-amqp is not installed
+ - composer install
script:
- vendor/bin/phpunit --exclude-group=functional
diff --git a/pkg/amqp-ext/AmqpConnectionFactory.php b/pkg/amqp-ext/AmqpConnectionFactory.php
index 15e1d6841..ebf4d40df 100644
--- a/pkg/amqp-ext/AmqpConnectionFactory.php
+++ b/pkg/amqp-ext/AmqpConnectionFactory.php
@@ -2,10 +2,14 @@
namespace Enqueue\AmqpExt;
-use Interop\Queue\PsrConnectionFactory;
+use Enqueue\AmqpTools\DelayStrategyAware;
+use Enqueue\AmqpTools\DelayStrategyAwareTrait;
+use Interop\Amqp\AmqpConnectionFactory as InteropAmqpConnectionFactory;
-class AmqpConnectionFactory implements PsrConnectionFactory
+class AmqpConnectionFactory implements InteropAmqpConnectionFactory, DelayStrategyAware
{
+ use DelayStrategyAwareTrait;
+
/**
* @var array
*/
@@ -43,6 +47,10 @@ class AmqpConnectionFactory implements PsrConnectionFactory
*/
public function __construct($config = 'amqp://')
{
+ if (is_string($config) && 0 === strpos($config, 'amqp+ext://')) {
+ $config = str_replace('amqp+ext://', 'amqp://', $config);
+ }
+
if (empty($config) || 'amqp://' === $config) {
$config = [];
} elseif (is_string($config)) {
@@ -79,12 +87,18 @@ public function __construct($config = 'amqp://')
public function createContext()
{
if ($this->config['lazy']) {
- return new AmqpContext(function () {
+ $context = new AmqpContext(function () {
return $this->createExtContext($this->establishConnection());
}, $this->config['receive_method']);
+ $context->setDelayStrategy($this->delayStrategy);
+
+ return $context;
}
- return new AmqpContext($this->createExtContext($this->establishConnection()), $this->config['receive_method']);
+ $context = new AmqpContext($this->createExtContext($this->establishConnection()), $this->config['receive_method']);
+ $context->setDelayStrategy($this->delayStrategy);
+
+ return $context;
}
/**
diff --git a/pkg/amqp-ext/AmqpConsumer.php b/pkg/amqp-ext/AmqpConsumer.php
index 5834232e4..4a3591d37 100644
--- a/pkg/amqp-ext/AmqpConsumer.php
+++ b/pkg/amqp-ext/AmqpConsumer.php
@@ -2,11 +2,15 @@
namespace Enqueue\AmqpExt;
+use Interop\Amqp\AmqpConsumer as InteropAmqpConsumer;
+use Interop\Amqp\AmqpMessage as InteropAmqpMessage;
+use Interop\Amqp\AmqpQueue;
+use Interop\Amqp\Impl\AmqpMessage;
+use Interop\Queue\Exception;
use Interop\Queue\InvalidMessageException;
-use Interop\Queue\PsrConsumer;
use Interop\Queue\PsrMessage;
-class AmqpConsumer implements PsrConsumer
+class AmqpConsumer implements InteropAmqpConsumer
{
/**
* @var AmqpContext
@@ -38,6 +42,16 @@ class AmqpConsumer implements PsrConsumer
*/
private $receiveMethod;
+ /**
+ * @var int
+ */
+ private $flags;
+
+ /**
+ * @var string
+ */
+ private $consumerTag;
+
/**
* @param AmqpContext $context
* @param AmqpQueue $queue
@@ -50,10 +64,63 @@ public function __construct(AmqpContext $context, AmqpQueue $queue, Buffer $buff
$this->context = $context;
$this->buffer = $buffer;
$this->receiveMethod = $receiveMethod;
+ $this->flags = self::FLAG_NOPARAM;
$this->isInit = false;
}
+ /**
+ * {@inheritdoc}
+ */
+ public function setConsumerTag($consumerTag)
+ {
+ if ($this->isInit) {
+ throw new Exception('Consumer tag is not mutable after it has been subscribed to broker');
+ }
+
+ $this->consumerTag = $consumerTag;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getConsumerTag()
+ {
+ return $this->consumerTag;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function clearFlags()
+ {
+ $this->flags = self::FLAG_NOPARAM;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addFlag($flag)
+ {
+ $this->flags |= $flag;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFlags()
+ {
+ return $this->flags;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setFlags($flags)
+ {
+ $this->flags = $flags;
+ }
+
/**
* {@inheritdoc}
*
@@ -67,7 +134,7 @@ public function getQueue()
/**
* {@inheritdoc}
*
- * @return AmqpMessage|null
+ * @return InteropAmqpMessage|null
*/
public function receive($timeout = 0)
{
@@ -89,7 +156,7 @@ public function receive($timeout = 0)
*/
public function receiveNoWait()
{
- if ($extMessage = $this->getExtQueue()->get()) {
+ if ($extMessage = $this->getExtQueue()->get(Flags::convertConsumerFlags($this->flags))) {
return $this->convertMessage($extMessage);
}
}
@@ -101,7 +168,7 @@ public function receiveNoWait()
*/
public function acknowledge(PsrMessage $message)
{
- InvalidMessageException::assertMessageInstanceOf($message, AmqpMessage::class);
+ InvalidMessageException::assertMessageInstanceOf($message, InteropAmqpMessage::class);
$this->getExtQueue()->ack($message->getDeliveryTag());
}
@@ -113,7 +180,7 @@ public function acknowledge(PsrMessage $message)
*/
public function reject(PsrMessage $message, $requeue = false)
{
- InvalidMessageException::assertMessageInstanceOf($message, AmqpMessage::class);
+ InvalidMessageException::assertMessageInstanceOf($message, InteropAmqpMessage::class);
$this->getExtQueue()->reject(
$message->getDeliveryTag(),
@@ -124,7 +191,7 @@ public function reject(PsrMessage $message, $requeue = false)
/**
* @param int $timeout
*
- * @return AmqpMessage|null
+ * @return InteropAmqpMessage|null
*/
private function receiveBasicGet($timeout)
{
@@ -142,7 +209,7 @@ private function receiveBasicGet($timeout)
/**
* @param int $timeout
*
- * @return AmqpMessage|null
+ * @return InteropAmqpMessage|null
*/
private function receiveBasicConsume($timeout)
{
@@ -158,7 +225,7 @@ private function receiveBasicConsume($timeout)
$extConnection->setReadTimeout($timeout / 1000);
if (false == $this->isInit) {
- $this->getExtQueue()->consume(null, AMQP_NOPARAM);
+ $this->getExtQueue()->consume(null, Flags::convertConsumerFlags($this->flags), $this->consumerTag);
$this->isInit = true;
}
@@ -220,6 +287,7 @@ private function convertMessage(\AMQPEnvelope $extEnvelope)
);
$message->setRedelivered($extEnvelope->isRedelivery());
$message->setDeliveryTag($extEnvelope->getDeliveryTag());
+ $message->setRoutingKey($extEnvelope->getRoutingKey());
return $message;
}
@@ -232,7 +300,7 @@ private function getExtQueue()
if (false == $this->extQueue) {
$extQueue = new \AMQPQueue($this->context->getExtChannel());
$extQueue->setName($this->queue->getQueueName());
- $extQueue->setFlags($this->queue->getFlags());
+ $extQueue->setFlags(Flags::convertQueueFlags($this->queue->getFlags()));
$extQueue->setArguments($this->queue->getArguments());
$this->extQueue = $extQueue;
diff --git a/pkg/amqp-ext/AmqpContext.php b/pkg/amqp-ext/AmqpContext.php
index 70f18512e..6d2d4e38f 100644
--- a/pkg/amqp-ext/AmqpContext.php
+++ b/pkg/amqp-ext/AmqpContext.php
@@ -2,14 +2,25 @@
namespace Enqueue\AmqpExt;
+use Enqueue\AmqpTools\DelayStrategyAware;
+use Enqueue\AmqpTools\DelayStrategyAwareTrait;
+use Interop\Amqp\AmqpBind as InteropAmqpBind;
+use Interop\Amqp\AmqpContext as InteropAmqpContext;
+use Interop\Amqp\AmqpQueue as InteropAmqpQueue;
+use Interop\Amqp\AmqpTopic as InteropAmqpTopic;
+use Interop\Amqp\Impl\AmqpBind;
+use Interop\Amqp\Impl\AmqpMessage;
+use Interop\Amqp\Impl\AmqpQueue;
+use Interop\Amqp\Impl\AmqpTopic;
+use Interop\Queue\Exception;
use Interop\Queue\InvalidDestinationException;
-use Interop\Queue\PsrContext;
use Interop\Queue\PsrDestination;
-use Interop\Queue\PsrQueue;
use Interop\Queue\PsrTopic;
-class AmqpContext implements PsrContext
+class AmqpContext implements InteropAmqpContext, DelayStrategyAware
{
+ use DelayStrategyAwareTrait;
+
/**
* @var \AMQPChannel
*/
@@ -53,8 +64,6 @@ public function __construct($extChannel, $receiveMethod)
/**
* {@inheritdoc}
- *
- * @return AmqpMessage
*/
public function createMessage($body = '', array $properties = [], array $headers = [])
{
@@ -63,8 +72,6 @@ public function createMessage($body = '', array $properties = [], array $headers
/**
* {@inheritdoc}
- *
- * @return AmqpTopic
*/
public function createTopic($topicName)
{
@@ -72,36 +79,30 @@ public function createTopic($topicName)
}
/**
- * @param AmqpTopic|PsrDestination $destination
+ * {@inheritdoc}
*/
- public function deleteTopic(PsrDestination $destination)
+ public function deleteTopic(InteropAmqpTopic $topic)
{
- InvalidDestinationException::assertDestinationInstanceOf($destination, AmqpTopic::class);
-
$extExchange = new \AMQPExchange($this->getExtChannel());
- $extExchange->delete($destination->getTopicName(), $destination->getFlags());
+ $extExchange->delete($topic->getTopicName(), Flags::convertTopicFlags($topic->getFlags()));
}
/**
- * @param AmqpTopic|PsrDestination $destination
+ * {@inheritdoc}
*/
- public function declareTopic(PsrDestination $destination)
+ public function declareTopic(InteropAmqpTopic $topic)
{
- InvalidDestinationException::assertDestinationInstanceOf($destination, AmqpTopic::class);
-
$extExchange = new \AMQPExchange($this->getExtChannel());
- $extExchange->setName($destination->getTopicName());
- $extExchange->setType($destination->getType());
- $extExchange->setArguments($destination->getArguments());
- $extExchange->setFlags($destination->getFlags());
+ $extExchange->setName($topic->getTopicName());
+ $extExchange->setType($topic->getType());
+ $extExchange->setArguments($topic->getArguments());
+ $extExchange->setFlags(Flags::convertTopicFlags($topic->getFlags()));
$extExchange->declareExchange();
}
/**
* {@inheritdoc}
- *
- * @return AmqpQueue
*/
public function createQueue($queueName)
{
@@ -109,54 +110,106 @@ public function createQueue($queueName)
}
/**
- * @param AmqpQueue|PsrDestination $destination
+ * {@inheritdoc}
*/
- public function deleteQueue(PsrDestination $destination)
+ public function deleteQueue(InteropAmqpQueue $queue)
{
- InvalidDestinationException::assertDestinationInstanceOf($destination, AmqpQueue::class);
-
$extQueue = new \AMQPQueue($this->getExtChannel());
- $extQueue->setName($destination->getQueueName());
- $extQueue->delete($destination->getFlags());
+ $extQueue->setName($queue->getQueueName());
+ $extQueue->delete(Flags::convertQueueFlags($queue->getFlags()));
}
/**
- * @param AmqpQueue|PsrDestination $destination
- *
- * @return int
+ * {@inheritdoc}
*/
- public function declareQueue(PsrDestination $destination)
+ public function declareQueue(InteropAmqpQueue $queue)
{
- InvalidDestinationException::assertDestinationInstanceOf($destination, AmqpQueue::class);
-
$extQueue = new \AMQPQueue($this->getExtChannel());
- $extQueue->setFlags($destination->getFlags());
- $extQueue->setArguments($destination->getArguments());
+ $extQueue->setName($queue->getQueueName());
+ $extQueue->setArguments($queue->getArguments());
+ $extQueue->setFlags(Flags::convertQueueFlags($queue->getFlags()));
+
+ return $extQueue->declareQueue();
+ }
- if ($destination->getQueueName()) {
- $extQueue->setName($destination->getQueueName());
+ /**
+ * {@inheritdoc}
+ */
+ public function purgeQueue(InteropAmqpQueue $queue)
+ {
+ $amqpQueue = new \AMQPQueue($this->getExtChannel());
+ $amqpQueue->setName($queue->getQueueName());
+ $amqpQueue->purge();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function bind(InteropAmqpBind $bind)
+ {
+ if ($bind->getSource() instanceof InteropAmqpQueue && $bind->getTarget() instanceof InteropAmqpQueue) {
+ throw new Exception('Is not possible to bind queue to queue. It is possible to bind topic to queue or topic to topic');
}
- $count = $extQueue->declareQueue();
+ // bind exchange to exchange
+ if ($bind->getSource() instanceof InteropAmqpTopic && $bind->getTarget() instanceof InteropAmqpTopic) {
+ $exchange = new \AMQPExchange($this->getExtChannel());
+ $exchange->setName($bind->getSource()->getTopicName());
+ $exchange->bind($bind->getTarget()->getTopicName(), $bind->getRoutingKey(), $bind->getArguments());
+ // bind queue to exchange
+ } elseif ($bind->getSource() instanceof InteropAmqpQueue) {
+ $queue = new \AMQPQueue($this->getExtChannel());
+ $queue->setName($bind->getSource()->getQueueName());
+ $queue->bind($bind->getTarget()->getTopicName(), $bind->getRoutingKey(), $bind->getArguments());
+ // bind exchange to queue
+ } else {
+ $queue = new \AMQPQueue($this->getExtChannel());
+ $queue->setName($bind->getTarget()->getQueueName());
+ $queue->bind($bind->getSource()->getTopicName(), $bind->getRoutingKey(), $bind->getArguments());
+ }
+ }
- if (false == $destination->getQueueName()) {
- $destination->setQueueName($extQueue->getName());
+ /**
+ * {@inheritdoc}
+ */
+ public function unbind(InteropAmqpBind $bind)
+ {
+ if ($bind->getSource() instanceof InteropAmqpQueue && $bind->getTarget() instanceof InteropAmqpQueue) {
+ throw new Exception('Is not possible to unbind queue to queue. It is possible to unbind topic from queue or topic from topic');
}
- return $count;
+ // unbind exchange from exchange
+ if ($bind->getSource() instanceof InteropAmqpTopic && $bind->getTarget() instanceof InteropAmqpTopic) {
+ $exchange = new \AMQPExchange($this->getExtChannel());
+ $exchange->setName($bind->getSource()->getTopicName());
+ $exchange->unbind($bind->getTarget()->getTopicName(), $bind->getRoutingKey(), $bind->getArguments());
+ // unbind queue from exchange
+ } elseif ($bind->getSource() instanceof InteropAmqpQueue) {
+ $queue = new \AMQPQueue($this->getExtChannel());
+ $queue->setName($bind->getSource()->getQueueName());
+ $queue->unbind($bind->getTarget()->getTopicName(), $bind->getRoutingKey(), $bind->getArguments());
+ // unbind exchange from queue
+ } else {
+ $queue = new \AMQPQueue($this->getExtChannel());
+ $queue->setName($bind->getTarget()->getQueueName());
+ $queue->unbind($bind->getSource()->getTopicName(), $bind->getRoutingKey(), $bind->getArguments());
+ }
}
/**
* {@inheritdoc}
*
- * @return AmqpQueue
+ * @return InteropAmqpQueue
*/
public function createTemporaryQueue()
{
- $queue = $this->createQueue(null);
- $queue->addFlag(AMQP_EXCLUSIVE);
+ $extQueue = new \AMQPQueue($this->getExtChannel());
+ $extQueue->setFlags(AMQP_EXCLUSIVE);
+
+ $extQueue->declareQueue();
- $this->declareQueue($queue);
+ $queue = $this->createQueue($extQueue->getName());
+ $queue->addFlag(InteropAmqpQueue::FLAG_EXCLUSIVE);
return $queue;
}
@@ -168,7 +221,10 @@ public function createTemporaryQueue()
*/
public function createProducer()
{
- return new AmqpProducer($this->getExtChannel());
+ $producer = new AmqpProducer($this->getExtChannel(), $this);
+ $producer->setDelayStrategy($this->delayStrategy);
+
+ return $producer;
}
/**
@@ -181,13 +237,13 @@ public function createProducer()
public function createConsumer(PsrDestination $destination)
{
$destination instanceof PsrTopic
- ? InvalidDestinationException::assertDestinationInstanceOf($destination, AmqpTopic::class)
- : InvalidDestinationException::assertDestinationInstanceOf($destination, AmqpQueue::class)
+ ? InvalidDestinationException::assertDestinationInstanceOf($destination, InteropAmqpTopic::class)
+ : InvalidDestinationException::assertDestinationInstanceOf($destination, InteropAmqpQueue::class)
;
if ($destination instanceof AmqpTopic) {
$queue = $this->createTemporaryQueue();
- $this->bind($destination, $queue);
+ $this->bind(new AmqpBind($destination, $queue, $queue->getQueueName()));
return new AmqpConsumer($this, $queue, $this->buffer, $this->receiveMethod);
}
@@ -195,6 +251,9 @@ public function createConsumer(PsrDestination $destination)
return new AmqpConsumer($this, $destination, $this->buffer, $this->receiveMethod);
}
+ /**
+ * {@inheritdoc}
+ */
public function close()
{
$extConnection = $this->getExtChannel()->getConnection();
@@ -204,25 +263,11 @@ public function close()
}
/**
- * @param AmqpTopic|PsrDestination $source
- * @param AmqpQueue|PsrDestination $target
- */
- public function bind(PsrDestination $source, PsrDestination $target)
- {
- InvalidDestinationException::assertDestinationInstanceOf($source, AmqpTopic::class);
- InvalidDestinationException::assertDestinationInstanceOf($target, AmqpQueue::class);
-
- $amqpQueue = new \AMQPQueue($this->getExtChannel());
- $amqpQueue->setName($target->getQueueName());
- $amqpQueue->bind($source->getTopicName(), $amqpQueue->getName(), $target->getBindArguments());
- }
-
- /**
- * @return \AMQPConnection
+ * {@inheritdoc}
*/
- public function getExtConnection()
+ public function setQos($prefetchSize, $prefetchCount, $global)
{
- return $this->getExtChannel()->getConnection();
+ $this->getExtChannel()->qos($prefetchSize, $prefetchCount);
}
/**
@@ -244,18 +289,4 @@ public function getExtChannel()
return $this->extChannel;
}
-
- /**
- * Purge all messages from the given queue.
- *
- * @param PsrQueue $queue
- */
- public function purge(PsrQueue $queue)
- {
- InvalidDestinationException::assertDestinationInstanceOf($queue, AmqpQueue::class);
-
- $amqpQueue = new \AMQPQueue($this->getExtChannel());
- $amqpQueue->setName($queue->getQueueName());
- $amqpQueue->purge();
- }
}
diff --git a/pkg/amqp-ext/AmqpMessage.php b/pkg/amqp-ext/AmqpMessage.php
deleted file mode 100644
index b7278ef85..000000000
--- a/pkg/amqp-ext/AmqpMessage.php
+++ /dev/null
@@ -1,273 +0,0 @@
-body = $body;
- $this->properties = $properties;
- $this->headers = $headers;
-
- $this->redelivered = false;
- $this->flags = AMQP_NOPARAM;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getBody()
- {
- return $this->body;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setBody($body)
- {
- $this->body = $body;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setProperties(array $properties)
- {
- $this->properties = $properties;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getProperties()
- {
- return $this->properties;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setProperty($name, $value)
- {
- $this->properties[$name] = $value;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getProperty($name, $default = null)
- {
- return array_key_exists($name, $this->properties) ? $this->properties[$name] : $default;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setHeaders(array $headers)
- {
- $this->headers = $headers;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getHeaders()
- {
- return $this->headers;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setHeader($name, $value)
- {
- $this->headers[$name] = $value;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getHeader($name, $default = null)
- {
- return array_key_exists($name, $this->headers) ? $this->headers[$name] : $default;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setRedelivered($redelivered)
- {
- $this->redelivered = (bool) $redelivered;
- }
-
- /**
- * {@inheritdoc}
- */
- public function isRedelivered()
- {
- return $this->redelivered;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setCorrelationId($correlationId)
- {
- $this->setHeader('correlation_id', $correlationId);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getCorrelationId()
- {
- return $this->getHeader('correlation_id');
- }
-
- /**
- * {@inheritdoc}
- */
- public function setMessageId($messageId)
- {
- $this->setHeader('message_id', $messageId);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getMessageId()
- {
- return $this->getHeader('message_id');
- }
-
- /**
- * {@inheritdoc}
- */
- public function getTimestamp()
- {
- $value = $this->getHeader('timestamp');
-
- return $value === null ? null : (int) $value;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setTimestamp($timestamp)
- {
- $this->setHeader('timestamp', $timestamp);
- }
-
- /**
- * {@inheritdoc}
- */
- public function setReplyTo($replyTo)
- {
- $this->setHeader('reply_to', $replyTo);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getReplyTo()
- {
- return $this->getHeader('reply_to');
- }
-
- /**
- * @return null|string
- */
- public function getDeliveryTag()
- {
- return $this->deliveryTag;
- }
-
- /**
- * @param null|string $deliveryTag
- */
- public function setDeliveryTag($deliveryTag)
- {
- $this->deliveryTag = $deliveryTag;
- }
-
- /**
- * @return string|null
- */
- public function getConsumerTag()
- {
- return $this->consumerTag;
- }
-
- /**
- * @param string|null $consumerTag
- */
- public function setConsumerTag($consumerTag)
- {
- $this->consumerTag = $consumerTag;
- }
-
- public function clearFlags()
- {
- $this->flags = AMQP_NOPARAM;
- }
-
- /**
- * @param int $flag
- */
- public function addFlag($flag)
- {
- $this->flags = $this->flags | $flag;
- }
-
- /**
- * @return int
- */
- public function getFlags()
- {
- return $this->flags;
- }
-}
diff --git a/pkg/amqp-ext/AmqpProducer.php b/pkg/amqp-ext/AmqpProducer.php
index 0ced3e6b2..456da6bfd 100644
--- a/pkg/amqp-ext/AmqpProducer.php
+++ b/pkg/amqp-ext/AmqpProducer.php
@@ -2,26 +2,56 @@
namespace Enqueue\AmqpExt;
+use Enqueue\AmqpTools\DelayStrategyAware;
+use Enqueue\AmqpTools\DelayStrategyAwareTrait;
+use Interop\Amqp\AmqpMessage;
+use Interop\Amqp\AmqpProducer as InteropAmqpProducer;
+use Interop\Amqp\AmqpQueue;
+use Interop\Amqp\AmqpTopic;
+use Interop\Queue\DeliveryDelayNotSupportedException;
use Interop\Queue\InvalidDestinationException;
use Interop\Queue\InvalidMessageException;
use Interop\Queue\PsrDestination;
use Interop\Queue\PsrMessage;
-use Interop\Queue\PsrProducer;
use Interop\Queue\PsrTopic;
-class AmqpProducer implements PsrProducer
+class AmqpProducer implements InteropAmqpProducer, DelayStrategyAware
{
+ use DelayStrategyAwareTrait;
+
+ /**
+ * @var int|null
+ */
+ private $priority;
+
+ /**
+ * @var int|float|null
+ */
+ private $timeToLive;
+
/**
* @var \AMQPChannel
*/
private $amqpChannel;
+ /**
+ * @var AmqpContext
+ */
+ private $context;
+
+ /**
+ * @var int
+ */
+ private $deliveryDelay;
+
/**
* @param \AMQPChannel $ampqChannel
+ * @param AmqpContext $context
*/
- public function __construct(\AMQPChannel $ampqChannel)
+ public function __construct(\AMQPChannel $ampqChannel, AmqpContext $context)
{
$this->amqpChannel = $ampqChannel;
+ $this->context = $context;
}
/**
@@ -39,23 +69,33 @@ public function send(PsrDestination $destination, PsrMessage $message)
InvalidMessageException::assertMessageInstanceOf($message, AmqpMessage::class);
+ if (null !== $this->priority && null === $message->getPriority()) {
+ $message->setPriority($this->priority);
+ }
+
+ if (null !== $this->timeToLive && null === $message->getExpiration()) {
+ $message->setExpiration($this->timeToLive);
+ }
+
$amqpAttributes = $message->getHeaders();
if ($message->getProperties()) {
$amqpAttributes['headers'] = $message->getProperties();
}
- if ($destination instanceof AmqpTopic) {
+ if ($this->deliveryDelay) {
+ $this->delayStrategy->delayMessage($this->context, $destination, $message, $this->deliveryDelay);
+ } elseif ($destination instanceof AmqpTopic) {
$amqpExchange = new \AMQPExchange($this->amqpChannel);
$amqpExchange->setType($destination->getType());
$amqpExchange->setName($destination->getTopicName());
- $amqpExchange->setFlags($destination->getFlags());
+ $amqpExchange->setFlags(Flags::convertTopicFlags($destination->getFlags()));
$amqpExchange->setArguments($destination->getArguments());
$amqpExchange->publish(
$message->getBody(),
- $destination->getRoutingKey(),
- $message->getFlags(),
+ $message->getRoutingKey(),
+ Flags::convertMessageFlags($message->getFlags()),
$amqpAttributes
);
} else {
@@ -66,9 +106,65 @@ public function send(PsrDestination $destination, PsrMessage $message)
$amqpExchange->publish(
$message->getBody(),
$destination->getQueueName(),
- $message->getFlags(),
+ Flags::convertMessageFlags($message->getFlags()),
$amqpAttributes
);
}
}
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setDeliveryDelay($deliveryDelay)
+ {
+ if (null === $this->delayStrategy) {
+ throw DeliveryDelayNotSupportedException::providerDoestNotSupportIt();
+ }
+
+ $this->deliveryDelay = $deliveryDelay;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDeliveryDelay()
+ {
+ return $this->deliveryDelay;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setPriority($priority)
+ {
+ $this->priority = $priority;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPriority()
+ {
+ return $this->priority;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setTimeToLive($timeToLive)
+ {
+ $this->timeToLive = $timeToLive;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTimeToLive()
+ {
+ return $this->timeToLive;
+ }
}
diff --git a/pkg/amqp-ext/AmqpQueue.php b/pkg/amqp-ext/AmqpQueue.php
deleted file mode 100644
index bbd0867e2..000000000
--- a/pkg/amqp-ext/AmqpQueue.php
+++ /dev/null
@@ -1,130 +0,0 @@
-name = $name;
-
- $this->arguments = [];
- $this->bindArguments = [];
- $this->flags = AMQP_NOPARAM;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getQueueName()
- {
- return $this->name;
- }
-
- /**
- * @param string $name
- */
- public function setQueueName($name)
- {
- $this->name = $name;
- }
-
- /**
- * @return string
- */
- public function getConsumerTag()
- {
- return $this->consumerTag;
- }
-
- /**
- * @param string $consumerTag
- */
- public function setConsumerTag($consumerTag)
- {
- $this->consumerTag = $consumerTag;
- }
-
- /**
- * @param int $flag
- */
- public function addFlag($flag)
- {
- $this->flags |= $flag;
- }
-
- public function clearFlags()
- {
- $this->flags = AMQP_NOPARAM;
- }
-
- /**
- * @return int
- */
- public function getFlags()
- {
- return $this->flags;
- }
-
- /**
- * @return array
- */
- public function getArguments()
- {
- return $this->arguments;
- }
-
- /**
- * @param array $arguments
- */
- public function setArguments(array $arguments = null)
- {
- $this->arguments = $arguments;
- }
-
- /**
- * @return array
- */
- public function getBindArguments()
- {
- return $this->bindArguments;
- }
-
- /**
- * @param array $arguments
- */
- public function setBindArguments(array $arguments = null)
- {
- $this->bindArguments = $arguments;
- }
-}
diff --git a/pkg/amqp-ext/AmqpTopic.php b/pkg/amqp-ext/AmqpTopic.php
deleted file mode 100644
index 784d6ba24..000000000
--- a/pkg/amqp-ext/AmqpTopic.php
+++ /dev/null
@@ -1,130 +0,0 @@
-name = $name;
-
- $this->type = AMQP_EX_TYPE_DIRECT;
- $this->flags = AMQP_NOPARAM;
- $this->arguments = [];
- }
-
- /**
- * {@inheritdoc}
- */
- public function getTopicName()
- {
- return $this->name;
- }
-
- /**
- * @param string $name
- */
- public function setTopicName($name)
- {
- $this->name = $name;
- }
-
- /**
- * @return string
- */
- public function getType()
- {
- return $this->type;
- }
-
- /**
- * @param string $type
- */
- public function setType($type)
- {
- $this->type = $type;
- }
-
- /**
- * @param int $flag
- */
- public function addFlag($flag)
- {
- $this->flags |= $flag;
- }
-
- public function clearFlags()
- {
- $this->flags = AMQP_NOPARAM;
- }
-
- /**
- * @return int
- */
- public function getFlags()
- {
- return $this->flags;
- }
-
- /**
- * @return array
- */
- public function getArguments()
- {
- return $this->arguments;
- }
-
- /**
- * @param array $arguments
- */
- public function setArguments(array $arguments = null)
- {
- $this->arguments = $arguments;
- }
-
- /**
- * @return string
- */
- public function getRoutingKey()
- {
- return $this->routingKey;
- }
-
- /**
- * @param string $routingKey
- */
- public function setRoutingKey($routingKey)
- {
- $this->routingKey = $routingKey;
- }
-}
diff --git a/pkg/amqp-ext/Buffer.php b/pkg/amqp-ext/Buffer.php
index e3f500e29..a192e605b 100644
--- a/pkg/amqp-ext/Buffer.php
+++ b/pkg/amqp-ext/Buffer.php
@@ -2,6 +2,8 @@
namespace Enqueue\AmqpExt;
+use Interop\Amqp\AmqpMessage;
+
class Buffer
{
/**
diff --git a/pkg/amqp-ext/DeliveryMode.php b/pkg/amqp-ext/DeliveryMode.php
deleted file mode 100644
index 3dac593d6..000000000
--- a/pkg/amqp-ext/DeliveryMode.php
+++ /dev/null
@@ -1,9 +0,0 @@
- 'host',
+ 'port' => 10000,
+ 'vhost' => 'vhost',
+ 'user' => 'user',
+ 'pass' => 'pass',
+ 'read_timeout' => null,
+ 'write_timeout' => null,
+ 'connect_timeout' => null,
+ 'persisted' => false,
+ 'lazy' => true,
+ 'pre_fetch_count' => null,
+ 'pre_fetch_size' => null,
+ 'receive_method' => 'basic_get',
+ ],
+ ];
+
yield [
'amqp://user:pass@host:10000/vhost',
[
diff --git a/pkg/amqp-ext/Tests/AmqpConsumerTest.php b/pkg/amqp-ext/Tests/AmqpConsumerTest.php
index 1927cc2c9..5d184c321 100644
--- a/pkg/amqp-ext/Tests/AmqpConsumerTest.php
+++ b/pkg/amqp-ext/Tests/AmqpConsumerTest.php
@@ -4,9 +4,9 @@
use Enqueue\AmqpExt\AmqpConsumer;
use Enqueue\AmqpExt\AmqpContext;
-use Enqueue\AmqpExt\AmqpQueue;
use Enqueue\AmqpExt\Buffer;
use Enqueue\Test\ClassExtensionTrait;
+use Interop\Amqp\Impl\AmqpQueue;
use Interop\Queue\PsrConsumer;
use PHPUnit\Framework\TestCase;
diff --git a/pkg/amqp-ext/Tests/AmqpContextTest.php b/pkg/amqp-ext/Tests/AmqpContextTest.php
index aa152a6f4..d3ed3a671 100644
--- a/pkg/amqp-ext/Tests/AmqpContextTest.php
+++ b/pkg/amqp-ext/Tests/AmqpContextTest.php
@@ -4,14 +4,14 @@
use Enqueue\AmqpExt\AmqpConsumer;
use Enqueue\AmqpExt\AmqpContext;
-use Enqueue\AmqpExt\AmqpMessage;
use Enqueue\AmqpExt\AmqpProducer;
-use Enqueue\AmqpExt\AmqpQueue;
-use Enqueue\AmqpExt\AmqpTopic;
use Enqueue\AmqpExt\Buffer;
use Enqueue\Null\NullQueue;
use Enqueue\Null\NullTopic;
use Enqueue\Test\ClassExtensionTrait;
+use Interop\Amqp\Impl\AmqpMessage;
+use Interop\Amqp\Impl\AmqpQueue;
+use Interop\Amqp\Impl\AmqpTopic;
use Interop\Queue\InvalidDestinationException;
use Interop\Queue\PsrContext;
use PHPUnit\Framework\TestCase;
@@ -86,27 +86,8 @@ public function testShouldCreateTopicWithGivenName()
$this->assertInstanceOf(AmqpTopic::class, $topic);
$this->assertSame('theName', $topic->getTopicName());
- $this->assertSame(\AMQP_NOPARAM, $topic->getFlags());
+ $this->assertSame(AmqpTopic::FLAG_NOPARAM, $topic->getFlags());
$this->assertSame([], $topic->getArguments());
- $this->assertSame(null, $topic->getRoutingKey());
- }
-
- public function testShouldThrowIfNotAmqpTopicGivenOnDeleteTopicCall()
- {
- $context = new AmqpContext($this->createExtChannelMock(), 'basic_get');
-
- $this->expectException(InvalidDestinationException::class);
- $this->expectExceptionMessage('The destination must be an instance of Enqueue\AmqpExt\AmqpTopic but got Enqueue\Null\NullTopic.');
- $context->deleteTopic(new NullTopic('aName'));
- }
-
- public function testShouldThrowIfNotAmqpTopicGivenOnDeclareTopicCall()
- {
- $context = new AmqpContext($this->createExtChannelMock(), 'basic_get');
-
- $this->expectException(InvalidDestinationException::class);
- $this->expectExceptionMessage('The destination must be an instance of Enqueue\AmqpExt\AmqpTopic but got Enqueue\Null\NullTopic.');
- $context->declareTopic(new NullTopic('aName'));
}
public function testShouldCreateQueueWithGivenName()
@@ -117,30 +98,11 @@ public function testShouldCreateQueueWithGivenName()
$this->assertInstanceOf(AmqpQueue::class, $queue);
$this->assertSame('theName', $queue->getQueueName());
- $this->assertSame(\AMQP_NOPARAM, $queue->getFlags());
+ $this->assertSame(AmqpQueue::FLAG_NOPARAM, $queue->getFlags());
$this->assertSame([], $queue->getArguments());
- $this->assertSame([], $queue->getBindArguments());
$this->assertSame(null, $queue->getConsumerTag());
}
- public function testShouldThrowIfNotAmqpQueueGivenOnDeleteQueueCall()
- {
- $context = new AmqpContext($this->createExtChannelMock(), 'basic_get');
-
- $this->expectException(InvalidDestinationException::class);
- $this->expectExceptionMessage('The destination must be an instance of Enqueue\AmqpExt\AmqpQueue but got Enqueue\Null\NullQueue.');
- $context->deleteQueue(new NullQueue('aName'));
- }
-
- public function testShouldThrowIfNotAmqpQueueGivenOnDeclareQueueCall()
- {
- $context = new AmqpContext($this->createExtChannelMock(), 'basic_get');
-
- $this->expectException(InvalidDestinationException::class);
- $this->expectExceptionMessage('The destination must be an instance of Enqueue\AmqpExt\AmqpQueue but got Enqueue\Null\NullQueue.');
- $context->declareQueue(new NullQueue('aName'));
- }
-
public function testShouldReturnAmqpProducer()
{
$context = new AmqpContext($this->createExtChannelMock(), 'basic_get');
@@ -172,7 +134,7 @@ public function testShouldThrowIfNotAmqpQueueGivenOnCreateConsumerCall()
$context = new AmqpContext($this->createExtChannelMock(), 'basic_get');
$this->expectException(InvalidDestinationException::class);
- $this->expectExceptionMessage('The destination must be an instance of Enqueue\AmqpExt\AmqpQueue but got Enqueue\Null\NullQueue.');
+ $this->expectExceptionMessage('The destination must be an instance of Interop\Amqp\AmqpQueue but got Enqueue\Null\NullQueue.');
$context->createConsumer(new NullQueue('aName'));
}
@@ -181,11 +143,11 @@ public function testShouldThrowIfNotAmqpTopicGivenOnCreateConsumerCall()
$context = new AmqpContext($this->createExtChannelMock(), 'basic_get');
$this->expectException(InvalidDestinationException::class);
- $this->expectExceptionMessage('The destination must be an instance of Enqueue\AmqpExt\AmqpTopic but got Enqueue\Null\NullTopic.');
+ $this->expectExceptionMessage('The destination must be an instance of Interop\Amqp\AmqpTopic but got Enqueue\Null\NullTopic.');
$context->createConsumer(new NullTopic('aName'));
}
- public function shouldDoNothingIfConnectionAlreadyClosed()
+ public function testShouldDoNothingIfConnectionAlreadyClosed()
{
$extConnectionMock = $this->createExtConnectionMock();
$extConnectionMock
@@ -286,33 +248,6 @@ public function testShouldClosePersistedConnection()
$context->close();
}
- public function testShouldThrowIfSourceNotAmqpTopicOnBindCall()
- {
- $context = new AmqpContext($this->createExtChannelMock(), 'basic_get');
-
- $this->expectException(InvalidDestinationException::class);
- $this->expectExceptionMessage('The destination must be an instance of Enqueue\AmqpExt\AmqpTopic but got Enqueue\Null\NullTopic.');
- $context->bind(new NullTopic('aName'), new AmqpQueue('aName'));
- }
-
- public function testShouldThrowIfTargetNotAmqpQueueOnBindCall()
- {
- $context = new AmqpContext($this->createExtChannelMock(), 'basic_get');
-
- $this->expectException(InvalidDestinationException::class);
- $this->expectExceptionMessage('The destination must be an instance of Enqueue\AmqpExt\AmqpQueue but got Enqueue\Null\NullQueue.');
- $context->bind(new AmqpTopic('aName'), new NullQueue('aName'));
- }
-
- public function testShouldThrowIfGivenQueueNotAmqpQueueOnPurge()
- {
- $context = new AmqpContext($this->createExtChannelMock(), 'basic_get');
-
- $this->expectException(InvalidDestinationException::class);
- $this->expectExceptionMessage('The destination must be an instance of Enqueue\AmqpExt\AmqpQueue but got Enqueue\Null\NullQueue.');
- $context->purge(new NullQueue('aName'));
- }
-
/**
* @return \PHPUnit_Framework_MockObject_MockObject|\AMQPChannel
*/
diff --git a/pkg/amqp-ext/Tests/AmqpMessageTest.php b/pkg/amqp-ext/Tests/AmqpMessageTest.php
deleted file mode 100644
index a8674b0fa..000000000
--- a/pkg/amqp-ext/Tests/AmqpMessageTest.php
+++ /dev/null
@@ -1,118 +0,0 @@
-assertClassImplements(PsrMessage::class, AmqpMessage::class);
- }
-
- public function testCouldBeConstructedWithoutArguments()
- {
- $message = new AmqpMessage();
-
- $this->assertSame('', $message->getBody());
- $this->assertSame([], $message->getProperties());
- $this->assertSame([], $message->getHeaders());
- }
-
- public function testCouldBeConstructedWithOptionalArguments()
- {
- $message = new AmqpMessage('theBody', ['barProp' => 'barPropVal'], ['fooHeader' => 'fooHeaderVal']);
-
- $this->assertSame('theBody', $message->getBody());
- $this->assertSame(['barProp' => 'barPropVal'], $message->getProperties());
- $this->assertSame(['fooHeader' => 'fooHeaderVal'], $message->getHeaders());
- }
-
- public function testShouldSetNoParamFlagInConstructor()
- {
- $message = new AmqpMessage();
-
- $this->assertSame(\AMQP_NOPARAM, $message->getFlags());
- }
-
- public function testShouldSetCorrelationIdAsHeader()
- {
- $message = new AmqpMessage();
- $message->setCorrelationId('theCorrelationId');
-
- $this->assertSame(['correlation_id' => 'theCorrelationId'], $message->getHeaders());
- }
-
- public function testShouldSetSetMessageIdAsHeader()
- {
- $message = new AmqpMessage();
- $message->setMessageId('theMessageId');
-
- $this->assertSame(['message_id' => 'theMessageId'], $message->getHeaders());
- }
-
- public function testShouldSetTimestampAsHeader()
- {
- $message = new AmqpMessage();
- $message->setTimestamp('theTimestamp');
-
- $this->assertSame(['timestamp' => 'theTimestamp'], $message->getHeaders());
- }
-
- public function testShouldSetReplyToAsHeader()
- {
- $message = new AmqpMessage();
- $message->setReplyTo('theReply');
-
- $this->assertSame(['reply_to' => 'theReply'], $message->getHeaders());
- }
-
- public function testShouldReturnPreviouslySetDeliveryTag()
- {
- $message = new AmqpMessage();
-
- $message->setDeliveryTag('theDeliveryTag');
-
- $this->assertSame('theDeliveryTag', $message->getDeliveryTag());
- }
-
- public function testShouldReturnPreviouslySetConsumerTag()
- {
- $message = new AmqpMessage();
-
- $message->setConsumerTag('theConsumerTag');
-
- $this->assertSame('theConsumerTag', $message->getConsumerTag());
- }
-
- public function testShouldAllowAddFlags()
- {
- $message = new AmqpMessage();
-
- $message->addFlag(AMQP_DURABLE);
- $message->addFlag(AMQP_PASSIVE);
-
- $this->assertSame(AMQP_DURABLE | AMQP_PASSIVE, $message->getFlags());
- }
-
- public function testShouldClearPreviouslySetFlags()
- {
- $message = new AmqpMessage();
-
- $message->addFlag(AMQP_DURABLE);
- $message->addFlag(AMQP_PASSIVE);
-
- //guard
- $this->assertSame(AMQP_DURABLE | AMQP_PASSIVE, $message->getFlags());
-
- $message->clearFlags();
-
- $this->assertSame(AMQP_NOPARAM, $message->getFlags());
- }
-}
diff --git a/pkg/amqp-ext/Tests/AmqpQueueTest.php b/pkg/amqp-ext/Tests/AmqpQueueTest.php
deleted file mode 100644
index 63cd7e42c..000000000
--- a/pkg/amqp-ext/Tests/AmqpQueueTest.php
+++ /dev/null
@@ -1,103 +0,0 @@
-assertClassImplements(PsrQueue::class, AmqpQueue::class);
- }
-
- public function testCouldBeConstructedWithQueueNameArgument()
- {
- new AmqpQueue('aName');
- }
-
- public function testShouldReturnQueueNameSetInConstructor()
- {
- $queue = new AmqpQueue('theName');
-
- $this->assertSame('theName', $queue->getQueueName());
- }
-
- public function testShouldReturnPreviouslySetQueueName()
- {
- $queue = new AmqpQueue('aName');
-
- $queue->setQueueName('theAnotherQueueName');
-
- $this->assertSame('theAnotherQueueName', $queue->getQueueName());
- }
-
- public function testShouldSetEmptyArrayAsArgumentsInConstructor()
- {
- $queue = new AmqpQueue('aName');
-
- $this->assertSame([], $queue->getArguments());
- }
-
- public function testShouldSetEmptyArrayAsBindArgumentsInConstructor()
- {
- $queue = new AmqpQueue('aName');
-
- $this->assertSame([], $queue->getBindArguments());
- }
-
- public function testShouldSetNoParamFlagInConstructor()
- {
- $queue = new AmqpQueue('aName');
-
- $this->assertSame(AMQP_NOPARAM, $queue->getFlags());
- }
-
- public function testShouldAllowAddFlags()
- {
- $queue = new AmqpQueue('aName');
-
- $queue->addFlag(AMQP_DURABLE);
- $queue->addFlag(AMQP_PASSIVE);
-
- $this->assertSame(AMQP_DURABLE | AMQP_PASSIVE, $queue->getFlags());
- }
-
- public function testShouldClearPreviouslySetFlags()
- {
- $queue = new AmqpQueue('aName');
-
- $queue->addFlag(AMQP_DURABLE);
- $queue->addFlag(AMQP_PASSIVE);
-
- //guard
- $this->assertSame(AMQP_DURABLE | AMQP_PASSIVE, $queue->getFlags());
-
- $queue->clearFlags();
-
- $this->assertSame(AMQP_NOPARAM, $queue->getFlags());
- }
-
- public function testShouldAllowGetPreviouslySetArguments()
- {
- $queue = new AmqpQueue('aName');
-
- $queue->setArguments(['foo' => 'fooVal', 'bar' => 'barVal']);
-
- $this->assertSame(['foo' => 'fooVal', 'bar' => 'barVal'], $queue->getArguments());
- }
-
- public function testShouldAllowGetPreviouslySetBindArguments()
- {
- $queue = new AmqpQueue('aName');
-
- $queue->setBindArguments(['foo' => 'fooVal', 'bar' => 'barVal']);
-
- $this->assertSame(['foo' => 'fooVal', 'bar' => 'barVal'], $queue->getBindArguments());
- }
-}
diff --git a/pkg/amqp-ext/Tests/AmqpTopicTest.php b/pkg/amqp-ext/Tests/AmqpTopicTest.php
deleted file mode 100644
index 3a0c2bd56..000000000
--- a/pkg/amqp-ext/Tests/AmqpTopicTest.php
+++ /dev/null
@@ -1,115 +0,0 @@
-assertClassImplements(PsrTopic::class, AmqpTopic::class);
- }
-
- public function testCouldBeConstructedWithTopicNameAsArgument()
- {
- new AmqpTopic('aName');
- }
-
- public function testShouldReturnTopicNameSetInConstructor()
- {
- $topic = new AmqpTopic('theName');
-
- $this->assertSame('theName', $topic->getTopicName());
- }
-
- public function testShouldReturnPreviouslySetTopicName()
- {
- $topic = new AmqpTopic('aName');
-
- $topic->setTopicName('theAnotherTopicName');
-
- $this->assertSame('theAnotherTopicName', $topic->getTopicName());
- }
-
- public function testShouldSetEmptyArrayAsArgumentsInConstructor()
- {
- $topic = new AmqpTopic('aName');
-
- $this->assertSame([], $topic->getArguments());
- }
-
- public function testShouldSetDirectTypeInConstructor()
- {
- $topic = new AmqpTopic('aName');
-
- $this->assertSame(\AMQP_EX_TYPE_DIRECT, $topic->getType());
- }
-
- public function testShouldSetNoParamFlagInConstructor()
- {
- $topic = new AmqpTopic('aName');
-
- $this->assertSame(AMQP_NOPARAM, $topic->getFlags());
- }
-
- public function testShouldAllowAddFlags()
- {
- $topic = new AmqpTopic('aName');
-
- $topic->addFlag(AMQP_DURABLE);
- $topic->addFlag(AMQP_PASSIVE);
-
- $this->assertSame(AMQP_DURABLE | AMQP_PASSIVE, $topic->getFlags());
- }
-
- public function testShouldClearPreviouslySetFlags()
- {
- $topic = new AmqpTopic('aName');
-
- $topic->addFlag(AMQP_DURABLE);
- $topic->addFlag(AMQP_PASSIVE);
-
- //guard
- $this->assertSame(AMQP_DURABLE | AMQP_PASSIVE, $topic->getFlags());
-
- $topic->clearFlags();
-
- $this->assertSame(AMQP_NOPARAM, $topic->getFlags());
- }
-
- public function testShouldAllowGetPreviouslySetArguments()
- {
- $topic = new AmqpTopic('aName');
-
- $topic->setArguments(['foo' => 'fooVal', 'bar' => 'barVal']);
-
- $this->assertSame(['foo' => 'fooVal', 'bar' => 'barVal'], $topic->getArguments());
- }
-
- public function testShouldAllowGetPreviouslySetType()
- {
- $topic = new AmqpTopic('aName');
-
- $topic->setType(\AMQP_EX_TYPE_FANOUT);
-
- $this->assertSame(\AMQP_EX_TYPE_FANOUT, $topic->getType());
- }
-
- public function testShouldAllowGetPreviouslySetRoutingKey()
- {
- $topic = new AmqpTopic('aName');
-
- //guard
- $this->assertSame(null, $topic->getRoutingKey());
-
- $topic->setRoutingKey('theRoutingKey');
-
- $this->assertSame('theRoutingKey', $topic->getRoutingKey());
- }
-}
diff --git a/pkg/amqp-ext/Tests/BufferTest.php b/pkg/amqp-ext/Tests/BufferTest.php
index 151481f91..977365ce6 100644
--- a/pkg/amqp-ext/Tests/BufferTest.php
+++ b/pkg/amqp-ext/Tests/BufferTest.php
@@ -2,8 +2,8 @@
namespace Enqueue\AmqpExt\Tests;
-use Enqueue\AmqpExt\AmqpMessage;
use Enqueue\AmqpExt\Buffer;
+use Interop\Amqp\Impl\AmqpMessage;
use PHPUnit\Framework\TestCase;
class BufferTest extends TestCase
diff --git a/pkg/amqp-ext/Tests/Functional/AmqpCommonUseCasesTest.php b/pkg/amqp-ext/Tests/Functional/AmqpCommonUseCasesTest.php
index 70a2c2605..ceba5f51c 100644
--- a/pkg/amqp-ext/Tests/Functional/AmqpCommonUseCasesTest.php
+++ b/pkg/amqp-ext/Tests/Functional/AmqpCommonUseCasesTest.php
@@ -3,9 +3,10 @@
namespace Enqueue\AmqpExt\Tests\Functional;
use Enqueue\AmqpExt\AmqpContext;
-use Enqueue\AmqpExt\AmqpMessage;
use Enqueue\Test\RabbitmqAmqpExtension;
use Enqueue\Test\RabbitmqManagmentExtensionTrait;
+use Interop\Amqp\Impl\AmqpBind;
+use Interop\Amqp\Impl\AmqpMessage;
use PHPUnit\Framework\TestCase;
/**
@@ -133,7 +134,7 @@ public function testProduceAndReceiveOneMessageSentDirectlyToTopic()
$queue = $this->amqpContext->createQueue('amqp_ext.test');
$this->amqpContext->declareQueue($queue);
- $this->amqpContext->bind($topic, $queue);
+ $this->amqpContext->bind(new AmqpBind($topic, $queue));
$message = $this->amqpContext->createMessage(__METHOD__);
@@ -209,7 +210,7 @@ public function testPurgeMessagesFromQueue()
$producer->send($queue, $message);
$producer->send($queue, $message);
- $this->amqpContext->purge($queue);
+ $this->amqpContext->purgeQueue($queue);
$this->assertNull($consumer->receive(1));
}
diff --git a/pkg/amqp-ext/Tests/Functional/AmqpRpcUseCasesTest.php b/pkg/amqp-ext/Tests/Functional/AmqpRpcUseCasesTest.php
index 197afa836..3db7ec63c 100644
--- a/pkg/amqp-ext/Tests/Functional/AmqpRpcUseCasesTest.php
+++ b/pkg/amqp-ext/Tests/Functional/AmqpRpcUseCasesTest.php
@@ -3,11 +3,11 @@
namespace Enqueue\AmqpExt\Tests\Functional;
use Enqueue\AmqpExt\AmqpContext;
-use Enqueue\AmqpExt\AmqpMessage;
use Enqueue\Rpc\Promise;
use Enqueue\Rpc\RpcClient;
use Enqueue\Test\RabbitmqAmqpExtension;
use Enqueue\Test\RabbitmqManagmentExtensionTrait;
+use Interop\Amqp\Impl\AmqpMessage;
use PHPUnit\Framework\TestCase;
/**
diff --git a/pkg/amqp-ext/Tests/Spec/AmqpMessageTest.php b/pkg/amqp-ext/Tests/Spec/AmqpMessageTest.php
index aa32ea893..ea36b648c 100644
--- a/pkg/amqp-ext/Tests/Spec/AmqpMessageTest.php
+++ b/pkg/amqp-ext/Tests/Spec/AmqpMessageTest.php
@@ -2,7 +2,7 @@
namespace Enqueue\AmqpExt\Tests\Spec;
-use Enqueue\AmqpExt\AmqpMessage;
+use Interop\Amqp\Impl\AmqpMessage;
use Interop\Queue\Spec\PsrMessageSpec;
class AmqpMessageTest extends PsrMessageSpec
diff --git a/pkg/amqp-ext/Tests/Spec/AmqpProducerTest.php b/pkg/amqp-ext/Tests/Spec/AmqpProducerTest.php
new file mode 100644
index 000000000..5c988c101
--- /dev/null
+++ b/pkg/amqp-ext/Tests/Spec/AmqpProducerTest.php
@@ -0,0 +1,22 @@
+createContext()->createProducer();
+ }
+}
diff --git a/pkg/amqp-ext/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php b/pkg/amqp-ext/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php
new file mode 100644
index 000000000..bb1b0c183
--- /dev/null
+++ b/pkg/amqp-ext/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php
@@ -0,0 +1,37 @@
+setDelayStrategy(new RabbitMqDelayPluginDelayStrategy());
+
+ return $factory->createContext();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function createQueue(PsrContext $context, $queueName)
+ {
+ $queue = parent::createQueue($context, $queueName);
+
+ $context->declareQueue($queue);
+
+ return $queue;
+ }
+}
diff --git a/pkg/amqp-ext/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest.php b/pkg/amqp-ext/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest.php
new file mode 100644
index 000000000..74d6233f1
--- /dev/null
+++ b/pkg/amqp-ext/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest.php
@@ -0,0 +1,37 @@
+setDelayStrategy(new RabbitMqDlxDelayStrategy());
+
+ return $factory->createContext();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function createQueue(PsrContext $context, $queueName)
+ {
+ $queue = parent::createQueue($context, $queueName);
+
+ $context->declareQueue($queue);
+
+ return $queue;
+ }
+}
diff --git a/pkg/amqp-ext/Tests/Spec/AmqpSendAndReceivePriorityMessagesFromQueueTest.php b/pkg/amqp-ext/Tests/Spec/AmqpSendAndReceivePriorityMessagesFromQueueTest.php
new file mode 100644
index 000000000..e8251eea0
--- /dev/null
+++ b/pkg/amqp-ext/Tests/Spec/AmqpSendAndReceivePriorityMessagesFromQueueTest.php
@@ -0,0 +1,40 @@
+createContext();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param AmqpContext $context
+ */
+ protected function createQueue(PsrContext $context, $queueName)
+ {
+ $queue = $context->createQueue($queueName);
+ $queue->setArguments(['x-max-priority' => 10]);
+
+ $context->declareQueue($queue);
+ $context->purgeQueue($queue);
+
+ return $queue;
+ }
+}
diff --git a/pkg/amqp-ext/Tests/Spec/AmqpSendAndReceiveTimeToLiveMessagesFromQueueTest.php b/pkg/amqp-ext/Tests/Spec/AmqpSendAndReceiveTimeToLiveMessagesFromQueueTest.php
new file mode 100644
index 000000000..16a67127c
--- /dev/null
+++ b/pkg/amqp-ext/Tests/Spec/AmqpSendAndReceiveTimeToLiveMessagesFromQueueTest.php
@@ -0,0 +1,38 @@
+createContext();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param AmqpContext $context
+ */
+ protected function createQueue(PsrContext $context, $queueName)
+ {
+ $queue = $context->createQueue($queueName);
+ $context->declareQueue($queue);
+ $context->purgeQueue($queue);
+
+ return $queue;
+ }
+}
diff --git a/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveFromQueueTest.php b/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveFromQueueTest.php
index f2068feb2..92436483b 100644
--- a/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveFromQueueTest.php
+++ b/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveFromQueueTest.php
@@ -31,7 +31,7 @@ protected function createQueue(PsrContext $context, $queueName)
{
$queue = $context->createQueue($queueName);
$context->declareQueue($queue);
- $context->purge($queue);
+ $context->purgeQueue($queue);
return $queue;
}
diff --git a/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveFromTopicTest.php b/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveFromTopicTest.php
index be99e3f1f..c13da615e 100644
--- a/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveFromTopicTest.php
+++ b/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveFromTopicTest.php
@@ -4,6 +4,7 @@
use Enqueue\AmqpExt\AmqpConnectionFactory;
use Enqueue\AmqpExt\AmqpContext;
+use Interop\Amqp\AmqpTopic;
use Interop\Queue\PsrContext;
use Interop\Queue\Spec\SendToAndReceiveFromTopicSpec;
@@ -30,8 +31,8 @@ protected function createContext()
protected function createTopic(PsrContext $context, $topicName)
{
$topic = $context->createTopic($topicName);
- $topic->setType(\AMQP_EX_TYPE_FANOUT);
- $topic->addFlag(\AMQP_DURABLE);
+ $topic->setType(AmqpTopic::TYPE_FANOUT);
+ $topic->addFlag(AmqpTopic::FLAG_DURABLE);
$context->declareTopic($topic);
return $topic;
diff --git a/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveNoWaitFromQueueTest.php b/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveNoWaitFromQueueTest.php
index 25431d54e..dd5035efa 100644
--- a/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveNoWaitFromQueueTest.php
+++ b/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveNoWaitFromQueueTest.php
@@ -31,7 +31,7 @@ protected function createQueue(PsrContext $context, $queueName)
{
$queue = $context->createQueue($queueName);
$context->declareQueue($queue);
- $context->purge($queue);
+ $context->purgeQueue($queue);
return $queue;
}
diff --git a/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveNoWaitFromTopicTest.php b/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveNoWaitFromTopicTest.php
index d3993220e..2db18a6ce 100644
--- a/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveNoWaitFromTopicTest.php
+++ b/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveNoWaitFromTopicTest.php
@@ -4,6 +4,7 @@
use Enqueue\AmqpExt\AmqpConnectionFactory;
use Enqueue\AmqpExt\AmqpContext;
+use Interop\Amqp\AmqpTopic;
use Interop\Queue\PsrContext;
use Interop\Queue\Spec\SendToAndReceiveNoWaitFromTopicSpec;
@@ -30,8 +31,8 @@ protected function createContext()
protected function createTopic(PsrContext $context, $topicName)
{
$topic = $context->createTopic($topicName);
- $topic->setType(\AMQP_EX_TYPE_FANOUT);
- $topic->addFlag(\AMQP_DURABLE);
+ $topic->setType(AmqpTopic::TYPE_FANOUT);
+ $topic->addFlag(AmqpTopic::FLAG_DURABLE);
$context->declareTopic($topic);
return $topic;
diff --git a/pkg/amqp-ext/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueTest.php b/pkg/amqp-ext/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueTest.php
index 8c01e552c..be29f1a4f 100644
--- a/pkg/amqp-ext/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueTest.php
+++ b/pkg/amqp-ext/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueTest.php
@@ -4,6 +4,8 @@
use Enqueue\AmqpExt\AmqpConnectionFactory;
use Enqueue\AmqpExt\AmqpContext;
+use Interop\Amqp\AmqpTopic;
+use Interop\Amqp\Impl\AmqpBind;
use Interop\Queue\PsrContext;
use Interop\Queue\Spec\SendToTopicAndReceiveFromQueueSpec;
@@ -31,9 +33,9 @@ protected function createQueue(PsrContext $context, $queueName)
{
$queue = $context->createQueue($queueName);
$context->declareQueue($queue);
- $context->purge($queue);
+ $context->purgeQueue($queue);
- $context->bind($context->createTopic($queueName), $queue);
+ $context->bind(new AmqpBind($context->createTopic($queueName), $queue));
return $queue;
}
@@ -46,8 +48,8 @@ protected function createQueue(PsrContext $context, $queueName)
protected function createTopic(PsrContext $context, $topicName)
{
$topic = $context->createTopic($topicName);
- $topic->setType(\AMQP_EX_TYPE_FANOUT);
- $topic->addFlag(\AMQP_DURABLE);
+ $topic->setType(AmqpTopic::TYPE_FANOUT);
+ $topic->addFlag(AmqpTopic::FLAG_DURABLE);
$context->declareTopic($topic);
return $topic;
diff --git a/pkg/amqp-ext/Tests/Spec/AmqpSendToTopicAndReceiveNoWaitFromQueueTest.php b/pkg/amqp-ext/Tests/Spec/AmqpSendToTopicAndReceiveNoWaitFromQueueTest.php
index bdb27f13d..fa6633052 100644
--- a/pkg/amqp-ext/Tests/Spec/AmqpSendToTopicAndReceiveNoWaitFromQueueTest.php
+++ b/pkg/amqp-ext/Tests/Spec/AmqpSendToTopicAndReceiveNoWaitFromQueueTest.php
@@ -4,6 +4,8 @@
use Enqueue\AmqpExt\AmqpConnectionFactory;
use Enqueue\AmqpExt\AmqpContext;
+use Interop\Amqp\AmqpTopic;
+use Interop\Amqp\Impl\AmqpBind;
use Interop\Queue\PsrContext;
use Interop\Queue\Spec\SendToTopicAndReceiveNoWaitFromQueueSpec;
@@ -31,9 +33,9 @@ protected function createQueue(PsrContext $context, $queueName)
{
$queue = $context->createQueue($queueName);
$context->declareQueue($queue);
- $context->purge($queue);
+ $context->purgeQueue($queue);
- $context->bind($context->createTopic($queueName), $queue);
+ $context->bind(new AmqpBind($context->createTopic($queueName), $queue));
return $queue;
}
@@ -46,8 +48,8 @@ protected function createQueue(PsrContext $context, $queueName)
protected function createTopic(PsrContext $context, $topicName)
{
$topic = $context->createTopic($topicName);
- $topic->setType(\AMQP_EX_TYPE_FANOUT);
- $topic->addFlag(\AMQP_DURABLE);
+ $topic->setType(AmqpTopic::TYPE_FANOUT);
+ $topic->addFlag(AmqpTopic::FLAG_DURABLE);
$context->declareTopic($topic);
return $topic;
diff --git a/pkg/amqp-ext/Tests/Symfony/AmqpTransportFactoryTest.php b/pkg/amqp-ext/Tests/Symfony/AmqpTransportFactoryTest.php
index eafeaa96d..115211b38 100644
--- a/pkg/amqp-ext/Tests/Symfony/AmqpTransportFactoryTest.php
+++ b/pkg/amqp-ext/Tests/Symfony/AmqpTransportFactoryTest.php
@@ -3,8 +3,8 @@
namespace Enqueue\AmqpExt\Tests\Symfony;
use Enqueue\AmqpExt\AmqpConnectionFactory;
-use Enqueue\AmqpExt\Client\AmqpDriver;
use Enqueue\AmqpExt\Symfony\AmqpTransportFactory;
+use Enqueue\Client\Amqp\AmqpDriver;
use Enqueue\Symfony\TransportFactoryInterface;
use Enqueue\Test\ClassExtensionTrait;
use PHPUnit\Framework\TestCase;
diff --git a/pkg/amqp-ext/Tests/Symfony/RabbitMqAmqpTransportFactoryTest.php b/pkg/amqp-ext/Tests/Symfony/RabbitMqAmqpTransportFactoryTest.php
index a553f9b01..46f530042 100644
--- a/pkg/amqp-ext/Tests/Symfony/RabbitMqAmqpTransportFactoryTest.php
+++ b/pkg/amqp-ext/Tests/Symfony/RabbitMqAmqpTransportFactoryTest.php
@@ -3,9 +3,9 @@
namespace Enqueue\AmqpExt\Tests\Symfony;
use Enqueue\AmqpExt\AmqpConnectionFactory;
-use Enqueue\AmqpExt\Client\RabbitMqDriver;
use Enqueue\AmqpExt\Symfony\AmqpTransportFactory;
use Enqueue\AmqpExt\Symfony\RabbitMqAmqpTransportFactory;
+use Enqueue\Client\Amqp\RabbitMqDriver;
use Enqueue\Symfony\TransportFactoryInterface;
use Enqueue\Test\ClassExtensionTrait;
use PHPUnit\Framework\TestCase;
diff --git a/pkg/amqp-ext/Tests/fix_composer_json.php b/pkg/amqp-ext/Tests/fix_composer_json.php
new file mode 100644
index 000000000..fc430e276
--- /dev/null
+++ b/pkg/amqp-ext/Tests/fix_composer_json.php
@@ -0,0 +1,9 @@
+=5.6",
"ext-amqp": "^1.6",
- "queue-interop/queue-interop": "^0.5@dev",
+
+ "queue-interop/amqp-interop": "^0.6@dev",
+ "enqueue/amqp-tools": "^0.7@dev",
"psr/log": "^1"
},
"require-dev": {
"phpunit/phpunit": "~5.4.0",
- "enqueue/test": "^0.6@dev",
- "enqueue/enqueue": "^0.6@dev",
- "enqueue/null": "^0.6@dev",
+ "enqueue/test": "^0.7@dev",
+ "enqueue/enqueue": "^0.7@dev",
+ "enqueue/null": "^0.7@dev",
"queue-interop/queue-spec": "^0.5@dev",
"empi89/php-amqp-stubs": "*@dev",
"symfony/dependency-injection": "^2.8|^3",
@@ -38,7 +40,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
- "dev-master": "0.6.x-dev"
+ "dev-master": "0.7.x-dev"
}
}
}
diff --git a/pkg/amqp-ext/examples/consume.php b/pkg/amqp-ext/examples/consume.php
index 4f74acb54..ece61b1d4 100644
--- a/pkg/amqp-ext/examples/consume.php
+++ b/pkg/amqp-ext/examples/consume.php
@@ -34,20 +34,17 @@
$queue = $context->createQueue('bar');
$barConsumer = $context->createConsumer($queue);
-$consumer = $context->createConsumer($queue);
-
-$fooConsumer->receive(1);
-$barConsumer->receive(1);
-
$consumers = [$fooConsumer, $barConsumer];
$consumer = $consumers[rand(0, 1)];
while (true) {
if ($m = $consumer->receive(1)) {
- $consumer = $consumers[rand(0, 1)];
+ echo $m->getBody(), PHP_EOL;
$consumer->acknowledge($m);
}
+
+ $consumer = $consumers[rand(0, 1)];
}
echo 'Done'."\n";
diff --git a/pkg/amqp-ext/examples/produce.php b/pkg/amqp-ext/examples/produce.php
index 8c29dcdf2..a905e49be 100644
--- a/pkg/amqp-ext/examples/produce.php
+++ b/pkg/amqp-ext/examples/produce.php
@@ -16,6 +16,9 @@
}
use Enqueue\AmqpExt\AmqpConnectionFactory;
+use Interop\Amqp\AmqpQueue;
+use Interop\Amqp\AmqpTopic;
+use Interop\Amqp\Impl\AmqpBind;
$config = [
'host' => getenv('SYMFONY__RABBITMQ__HOST'),
@@ -29,28 +32,28 @@
$context = $factory->createContext();
$topic = $context->createTopic('test.amqp.ext');
-$topic->addFlag(AMQP_DURABLE);
-$topic->setType(AMQP_EX_TYPE_FANOUT);
+$topic->addFlag(AmqpTopic::FLAG_DURABLE);
+$topic->setType(AmqpTopic::TYPE_FANOUT);
$topic->setArguments(['alternate-exchange' => 'foo']);
$context->deleteTopic($topic);
$context->declareTopic($topic);
$fooQueue = $context->createQueue('foo');
-$fooQueue->addFlag(AMQP_DURABLE);
+$fooQueue->addFlag(AmqpQueue::FLAG_DURABLE);
$context->deleteQueue($fooQueue);
$context->declareQueue($fooQueue);
-$context->bind($topic, $fooQueue);
+$context->bind(new AmqpBind($topic, $fooQueue));
$barQueue = $context->createQueue('bar');
-$barQueue->addFlag(AMQP_DURABLE);
+$barQueue->addFlag(AmqpQueue::FLAG_DURABLE);
$context->deleteQueue($barQueue);
$context->declareQueue($barQueue);
-$context->bind($topic, $barQueue);
+$context->bind(new AmqpBind($topic, $barQueue));
$message = $context->createMessage('Hello Bar!');
diff --git a/pkg/amqp-lib/AmqpConnectionFactory.php b/pkg/amqp-lib/AmqpConnectionFactory.php
index ac2e31bb1..c00998c6f 100644
--- a/pkg/amqp-lib/AmqpConnectionFactory.php
+++ b/pkg/amqp-lib/AmqpConnectionFactory.php
@@ -2,15 +2,19 @@
namespace Enqueue\AmqpLib;
-use Interop\Queue\PsrConnectionFactory;
+use Enqueue\AmqpTools\DelayStrategyAware;
+use Enqueue\AmqpTools\DelayStrategyAwareTrait;
+use Interop\Amqp\AmqpConnectionFactory as InteropAmqpConnectionFactory;
use PhpAmqpLib\Connection\AbstractConnection;
use PhpAmqpLib\Connection\AMQPLazyConnection;
use PhpAmqpLib\Connection\AMQPLazySocketConnection;
use PhpAmqpLib\Connection\AMQPSocketConnection;
use PhpAmqpLib\Connection\AMQPStreamConnection;
-class AmqpConnectionFactory implements PsrConnectionFactory
+class AmqpConnectionFactory implements InteropAmqpConnectionFactory, DelayStrategyAware
{
+ use DelayStrategyAwareTrait;
+
/**
* @var array
*/
@@ -33,6 +37,9 @@ class AmqpConnectionFactory implements PsrConnectionFactory
* 'lazy' => 'the connection will be performed as later as possible, if the option set to true',
* 'stream' => 'stream or socket connection',
* 'receive_method' => 'Could be either basic_get or basic_consume',
+ * 'qos_prefetch_size' => 'The server will send a message in advance if it is equal to or smaller in size than the available prefetch size. May be set to zero, meaning "no specific limit"',
+ * 'qos_prefetch_count' => 'Specifies a prefetch window in terms of whole messages.',
+ * 'qos_global' => 'If "false" the QoS settings apply to the current channel only. If this field is "true", they are applied to the entire connection.',
* ]
*
* or
@@ -43,6 +50,10 @@ class AmqpConnectionFactory implements PsrConnectionFactory
*/
public function __construct($config = 'amqp://')
{
+ if (is_string($config) && 0 === strpos($config, 'amqp+lib://')) {
+ $config = str_replace('amqp+lib://', 'amqp://', $config);
+ }
+
if (empty($config) || 'amqp://' === $config) {
$config = [];
} elseif (is_string($config)) {
@@ -69,7 +80,10 @@ public function __construct($config = 'amqp://')
*/
public function createContext()
{
- return new AmqpContext($this->establishConnection(), $this->config['receive_method']);
+ $context = new AmqpContext($this->establishConnection(), $this->config);
+ $context->setDelayStrategy($this->delayStrategy);
+
+ return $context;
}
/**
@@ -224,6 +238,9 @@ private function defaultConfig()
'connection_timeout' => 3.0,
'read_write_timeout' => 3.0,
'receive_method' => 'basic_get',
+ 'qos_prefetch_size' => 0,
+ 'qos_prefetch_count' => 1,
+ 'qos_global' => false,
];
}
}
diff --git a/pkg/amqp-lib/AmqpConsumer.php b/pkg/amqp-lib/AmqpConsumer.php
index d73f1e843..f08289bd9 100644
--- a/pkg/amqp-lib/AmqpConsumer.php
+++ b/pkg/amqp-lib/AmqpConsumer.php
@@ -2,16 +2,19 @@
namespace Enqueue\AmqpLib;
+use Interop\Amqp\AmqpConsumer as InteropAmqpConsumer;
+use Interop\Amqp\AmqpMessage as InteropAmqpMessage;
+use Interop\Amqp\AmqpQueue as InteropAmqpQueue;
+use Interop\Amqp\Impl\AmqpMessage;
use Interop\Queue\Exception;
use Interop\Queue\InvalidMessageException;
-use Interop\Queue\PsrConsumer;
use Interop\Queue\PsrMessage;
use PhpAmqpLib\Channel\AMQPChannel;
use PhpAmqpLib\Exception\AMQPTimeoutException;
use PhpAmqpLib\Message\AMQPMessage as LibAMQPMessage;
use PhpAmqpLib\Wire\AMQPTable;
-class AmqpConsumer implements PsrConsumer
+class AmqpConsumer implements InteropAmqpConsumer
{
/**
* @var AMQPChannel
@@ -19,7 +22,7 @@ class AmqpConsumer implements PsrConsumer
private $channel;
/**
- * @var AmqpQueue
+ * @var InteropAmqpQueue
*/
private $queue;
@@ -39,9 +42,9 @@ class AmqpConsumer implements PsrConsumer
private $receiveMethod;
/**
- * @var AmqpMessage
+ * @var int
*/
- private $receivedMessage;
+ private $flags;
/**
* @var string
@@ -49,23 +52,76 @@ class AmqpConsumer implements PsrConsumer
private $consumerTag;
/**
- * @param AMQPChannel $channel
- * @param AmqpQueue $queue
- * @param Buffer $buffer
- * @param string $receiveMethod
+ * @param AMQPChannel $channel
+ * @param InteropAmqpQueue $queue
+ * @param Buffer $buffer
+ * @param string $receiveMethod
*/
- public function __construct(AMQPChannel $channel, AmqpQueue $queue, Buffer $buffer, $receiveMethod)
+ public function __construct(AMQPChannel $channel, InteropAmqpQueue $queue, Buffer $buffer, $receiveMethod)
{
$this->channel = $channel;
$this->queue = $queue;
$this->buffer = $buffer;
$this->receiveMethod = $receiveMethod;
+ $this->flags = self::FLAG_NOPARAM;
$this->isInit = false;
}
/**
- * @return AmqpQueue
+ * {@inheritdoc}
+ */
+ public function setConsumerTag($consumerTag)
+ {
+ if ($this->isInit) {
+ throw new Exception('Consumer tag is not mutable after it has been subscribed to broker');
+ }
+
+ $this->consumerTag = $consumerTag;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getConsumerTag()
+ {
+ return $this->consumerTag;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function clearFlags()
+ {
+ $this->flags = self::FLAG_NOPARAM;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addFlag($flag)
+ {
+ $this->flags |= $flag;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFlags()
+ {
+ return $this->flags;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setFlags($flags)
+ {
+ $this->flags = $flags;
+ }
+
+ /**
+ * @return InteropAmqpQueue
*/
public function getQueue()
{
@@ -75,7 +131,7 @@ public function getQueue()
/**
* {@inheritdoc}
*
- * @return AmqpMessage|null
+ * @return InteropAmqpMessage|null
*/
public function receive($timeout = 0)
{
@@ -91,32 +147,32 @@ public function receive($timeout = 0)
}
/**
- * @return AmqpMessage|null
+ * @return InteropAmqpMessage|null
*/
public function receiveNoWait()
{
- if ($message = $this->channel->basic_get($this->queue->getQueueName())) {
+ if ($message = $this->channel->basic_get($this->queue->getQueueName(), (bool) ($this->getFlags() & InteropAmqpConsumer::FLAG_NOACK))) {
return $this->convertMessage($message);
}
}
/**
- * @param AmqpMessage $message
+ * @param InteropAmqpMessage $message
*/
public function acknowledge(PsrMessage $message)
{
- InvalidMessageException::assertMessageInstanceOf($message, AmqpMessage::class);
+ InvalidMessageException::assertMessageInstanceOf($message, InteropAmqpMessage::class);
$this->channel->basic_ack($message->getDeliveryTag());
}
/**
- * @param AmqpMessage $message
- * @param bool $requeue
+ * @param InteropAmqpMessage $message
+ * @param bool $requeue
*/
public function reject(PsrMessage $message, $requeue = false)
{
- InvalidMessageException::assertMessageInstanceOf($message, AmqpMessage::class);
+ InvalidMessageException::assertMessageInstanceOf($message, InteropAmqpMessage::class);
$this->channel->basic_reject($message->getDeliveryTag(), $requeue);
}
@@ -124,7 +180,7 @@ public function reject(PsrMessage $message, $requeue = false)
/**
* @param LibAMQPMessage $amqpMessage
*
- * @return AmqpMessage
+ * @return InteropAmqpMessage
*/
private function convertMessage(LibAMQPMessage $amqpMessage)
{
@@ -140,6 +196,7 @@ private function convertMessage(LibAMQPMessage $amqpMessage)
$message = new AmqpMessage($amqpMessage->getBody(), $properties, $headers);
$message->setDeliveryTag($amqpMessage->delivery_info['delivery_tag']);
$message->setRedelivered($amqpMessage->delivery_info['redelivered']);
+ $message->setRoutingKey($amqpMessage->delivery_info['routing_key']);
return $message;
}
@@ -147,7 +204,7 @@ private function convertMessage(LibAMQPMessage $amqpMessage)
/**
* @param int $timeout
*
- * @return AmqpMessage|null
+ * @return InteropAmqpMessage|null
*/
private function receiveBasicGet($timeout)
{
@@ -165,36 +222,29 @@ private function receiveBasicGet($timeout)
/**
* @param int $timeout
*
- * @return AmqpMessage|null
+ * @return InteropAmqpMessage|null
*/
private function receiveBasicConsume($timeout)
{
if (false === $this->isInit) {
$callback = function (LibAMQPMessage $message) {
$receivedMessage = $this->convertMessage($message);
- $consumerTag = $message->delivery_info['consumer_tag'];
+ $receivedMessage->setConsumerTag($message->delivery_info['consumer_tag']);
- if ($this->consumerTag === $consumerTag) {
- $this->receivedMessage = $receivedMessage;
- } else {
- // not our message, put it to buffer and continue.
- $this->buffer->push($consumerTag, $receivedMessage);
- }
+ $this->buffer->push($receivedMessage->getConsumerTag(), $receivedMessage);
};
- $this->channel->basic_qos(0, 1, false);
-
$consumerTag = $this->channel->basic_consume(
$this->queue->getQueueName(),
- $this->queue->getConsumerTag(),
- $this->queue->isNoLocal(),
- $this->queue->isNoAck(),
- $this->queue->isExclusive(),
- $this->queue->isNoWait(),
+ $this->getConsumerTag() ?: $this->getQueue()->getConsumerTag(),
+ (bool) ($this->getFlags() & InteropAmqpConsumer::FLAG_NOLOCAL),
+ (bool) ($this->getFlags() & InteropAmqpConsumer::FLAG_NOACK),
+ (bool) ($this->getFlags() & InteropAmqpConsumer::FLAG_EXCLUSIVE),
+ (bool) ($this->getFlags() & InteropAmqpConsumer::FLAG_NOWAIT),
$callback
);
- $this->consumerTag = $consumerTag ?: $this->queue->getConsumerTag();
+ $this->consumerTag = $consumerTag ?: $this->getQueue()->getConsumerTag();
if (empty($this->consumerTag)) {
throw new Exception('Got empty consumer tag');
@@ -207,13 +257,32 @@ private function receiveBasicConsume($timeout)
return $message;
}
- $this->receivedMessage = null;
-
try {
- $this->channel->wait(null, false, $timeout);
+ while (true) {
+ $start = microtime(true);
+
+ $this->channel->wait(null, false, $timeout / 1000);
+
+ if ($message = $this->buffer->pop($this->consumerTag)) {
+ return $message;
+ }
+
+ // is here when consumed message is not for this consumer
+
+ // as timeout is infinite have to continue consumption, but it can overflow message buffer
+ if ($timeout <= 0) {
+ continue;
+ }
+
+ // compute remaining timeout and continue until time is up
+ $stop = microtime(true);
+ $timeout -= ($stop - $start) * 1000;
+
+ if ($timeout <= 0) {
+ break;
+ }
+ }
} catch (AMQPTimeoutException $e) {
}
-
- return $this->receivedMessage;
}
}
diff --git a/pkg/amqp-lib/AmqpContext.php b/pkg/amqp-lib/AmqpContext.php
index 168766ad5..1a82bb317 100644
--- a/pkg/amqp-lib/AmqpContext.php
+++ b/pkg/amqp-lib/AmqpContext.php
@@ -2,17 +2,29 @@
namespace Enqueue\AmqpLib;
+use Enqueue\AmqpTools\DelayStrategyAware;
+use Enqueue\AmqpTools\DelayStrategyAwareTrait;
+use Interop\Amqp\AmqpBind as InteropAmqpBind;
+use Interop\Amqp\AmqpContext as InteropAmqpContext;
+use Interop\Amqp\AmqpMessage as InteropAmqpMessage;
+use Interop\Amqp\AmqpQueue as InteropAmqpQueue;
+use Interop\Amqp\AmqpTopic as InteropAmqpTopic;
+use Interop\Amqp\Impl\AmqpBind;
+use Interop\Amqp\Impl\AmqpMessage;
+use Interop\Amqp\Impl\AmqpQueue;
+use Interop\Amqp\Impl\AmqpTopic;
use Interop\Queue\Exception;
use Interop\Queue\InvalidDestinationException;
-use Interop\Queue\PsrContext;
use Interop\Queue\PsrDestination;
-use Interop\Queue\PsrQueue;
use Interop\Queue\PsrTopic;
use PhpAmqpLib\Channel\AMQPChannel;
use PhpAmqpLib\Connection\AbstractConnection;
+use PhpAmqpLib\Wire\AMQPTable;
-class AmqpContext implements PsrContext
+class AmqpContext implements InteropAmqpContext, DelayStrategyAware
{
+ use DelayStrategyAwareTrait;
+
/**
* @var AbstractConnection
*/
@@ -26,7 +38,7 @@ class AmqpContext implements PsrContext
/**
* @var string
*/
- private $receiveMethod;
+ private $config;
/**
* @var Buffer
@@ -35,12 +47,18 @@ class AmqpContext implements PsrContext
/**
* @param AbstractConnection $connection
- * @param string $receiveMethod
+ * @param array $config
*/
- public function __construct(AbstractConnection $connection, $receiveMethod)
+ public function __construct(AbstractConnection $connection, $config = [])
{
+ $this->config = array_replace([
+ 'receive_method' => 'basic_get',
+ 'qos_prefetch_size' => 0,
+ 'qos_prefetch_count' => 1,
+ 'qos_global' => false,
+ ], $config);
+
$this->connection = $connection;
- $this->receiveMethod = $receiveMethod;
$this->buffer = new Buffer();
}
@@ -49,7 +67,7 @@ public function __construct(AbstractConnection $connection, $receiveMethod)
* @param array $properties
* @param array $headers
*
- * @return AmqpMessage
+ * @return InteropAmqpMessage
*/
public function createMessage($body = '', array $properties = [], array $headers = [])
{
@@ -59,7 +77,7 @@ public function createMessage($body = '', array $properties = [], array $headers
/**
* @param string $name
*
- * @return AmqpQueue
+ * @return InteropAmqpQueue
*/
public function createQueue($name)
{
@@ -69,7 +87,7 @@ public function createQueue($name)
/**
* @param string $name
*
- * @return AmqpTopic
+ * @return InteropAmqpTopic
*/
public function createTopic($name)
{
@@ -84,18 +102,18 @@ public function createTopic($name)
public function createConsumer(PsrDestination $destination)
{
$destination instanceof PsrTopic
- ? InvalidDestinationException::assertDestinationInstanceOf($destination, AmqpTopic::class)
- : InvalidDestinationException::assertDestinationInstanceOf($destination, AmqpQueue::class)
+ ? InvalidDestinationException::assertDestinationInstanceOf($destination, InteropAmqpTopic::class)
+ : InvalidDestinationException::assertDestinationInstanceOf($destination, InteropAmqpQueue::class)
;
if ($destination instanceof AmqpTopic) {
$queue = $this->createTemporaryQueue();
- $this->bind($destination, $queue);
+ $this->bind(new AmqpBind($destination, $queue, $queue->getQueueName()));
- return new AmqpConsumer($this->getChannel(), $queue, $this->buffer, $this->receiveMethod);
+ return new AmqpConsumer($this->getChannel(), $queue, $this->buffer, $this->config['receive_method']);
}
- return new AmqpConsumer($this->getChannel(), $destination, $this->buffer, $this->receiveMethod);
+ return new AmqpConsumer($this->getChannel(), $destination, $this->buffer, $this->config['receive_method']);
}
/**
@@ -103,126 +121,170 @@ public function createConsumer(PsrDestination $destination)
*/
public function createProducer()
{
- return new AmqpProducer($this->getChannel());
+ $producer = new AmqpProducer($this->getChannel(), $this);
+ $producer->setDelayStrategy($this->delayStrategy);
+
+ return $producer;
}
/**
- * @return AmqpQueue
+ * @return InteropAmqpQueue
*/
public function createTemporaryQueue()
{
- $queue = $this->createQueue(null);
- $queue->setExclusive(true);
+ list($name) = $this->getChannel()->queue_declare('', false, false, true, false);
- $this->declareQueue($queue);
+ $queue = $this->createQueue($name);
+ $queue->addFlag(InteropAmqpQueue::FLAG_EXCLUSIVE);
return $queue;
}
/**
- * @param AmqpTopic $destination
+ * {@inheritdoc}
*/
- public function declareTopic(PsrDestination $destination)
+ public function declareTopic(InteropAmqpTopic $topic)
{
- InvalidDestinationException::assertDestinationInstanceOf($destination, AmqpTopic::class);
-
$this->getChannel()->exchange_declare(
- $destination->getTopicName(),
- $destination->getType(),
- $destination->isPassive(),
- $destination->isDurable(),
- $destination->isAutoDelete(),
- $destination->isInternal(),
- $destination->isNoWait(),
- $destination->getArguments(),
- $destination->getTicket()
+ $topic->getTopicName(),
+ $topic->getType(),
+ (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_PASSIVE),
+ (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_DURABLE),
+ (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_AUTODELETE),
+ (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_INTERNAL),
+ (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_NOWAIT),
+ $topic->getArguments() ? new AMQPTable($topic->getArguments()) : null
);
}
/**
- * @param AmqpQueue $destination
+ * {@inheritdoc}
*/
- public function declareQueue(PsrDestination $destination)
+ public function deleteTopic(InteropAmqpTopic $topic)
{
- InvalidDestinationException::assertDestinationInstanceOf($destination, AmqpQueue::class);
+ $this->getChannel()->exchange_delete(
+ $topic->getTopicName(),
+ (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_IFUNUSED),
+ (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_NOWAIT)
+ );
+ }
- $this->getChannel()->queue_declare(
- $destination->getQueueName(),
- $destination->isPassive(),
- $destination->isDurable(),
- $destination->isExclusive(),
- $destination->isAutoDelete(),
- $destination->isNoWait(),
- $destination->getArguments(),
- $destination->getTicket()
+ /**
+ * {@inheritdoc}
+ */
+ public function declareQueue(InteropAmqpQueue $queue)
+ {
+ list(, $messageCount) = $this->getChannel()->queue_declare(
+ $queue->getQueueName(),
+ (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_PASSIVE),
+ (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_DURABLE),
+ (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_EXCLUSIVE),
+ (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_AUTODELETE),
+ (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_NOWAIT),
+ $queue->getArguments() ? new AMQPTable($queue->getArguments()) : null
);
+
+ return $messageCount;
}
/**
- * @param AmqpTopic|AmqpQueue $source
- * @param AmqpTopic|AmqpQueue $target
- *
- * @throws Exception
+ * {@inheritdoc}
*/
- public function bind(PsrDestination $source, PsrDestination $target)
+ public function deleteQueue(InteropAmqpQueue $queue)
{
- $source instanceof PsrTopic
- ? InvalidDestinationException::assertDestinationInstanceOf($source, AmqpTopic::class)
- : InvalidDestinationException::assertDestinationInstanceOf($source, AmqpQueue::class)
- ;
+ $this->getChannel()->queue_delete(
+ $queue->getQueueName(),
+ (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_IFUNUSED),
+ (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_IFEMPTY),
+ (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_NOWAIT)
+ );
+ }
- $target instanceof PsrTopic
- ? InvalidDestinationException::assertDestinationInstanceOf($target, AmqpTopic::class)
- : InvalidDestinationException::assertDestinationInstanceOf($target, AmqpQueue::class)
- ;
+ /**
+ * {@inheritdoc}
+ */
+ public function purgeQueue(InteropAmqpQueue $queue)
+ {
+ $this->getChannel()->queue_purge(
+ $queue->getQueueName(),
+ (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_NOWAIT)
+ );
+ }
- if ($source instanceof AmqpQueue && $target instanceof AmqpQueue) {
+ /**
+ * {@inheritdoc}
+ */
+ public function bind(InteropAmqpBind $bind)
+ {
+ if ($bind->getSource() instanceof InteropAmqpQueue && $bind->getTarget() instanceof InteropAmqpQueue) {
throw new Exception('Is not possible to bind queue to queue. It is possible to bind topic to queue or topic to topic');
}
// bind exchange to exchange
- if ($source instanceof AmqpTopic && $target instanceof AmqpTopic) {
+ if ($bind->getSource() instanceof InteropAmqpTopic && $bind->getTarget() instanceof InteropAmqpTopic) {
$this->getChannel()->exchange_bind(
- $target->getTopicName(),
- $source->getTopicName(),
- $source->getRoutingKey(),
- $source->isNowait(),
- $source->getArguments(),
- $source->getTicket()
+ $bind->getTarget()->getTopicName(),
+ $bind->getSource()->getTopicName(),
+ $bind->getRoutingKey(),
+ (bool) ($bind->getFlags() & InteropAmqpBind::FLAG_NOWAIT),
+ $bind->getArguments()
);
// bind queue to exchange
- } elseif ($source instanceof AmqpQueue) {
+ } elseif ($bind->getSource() instanceof InteropAmqpQueue) {
$this->getChannel()->queue_bind(
- $source->getQueueName(),
- $target->getTopicName(),
- $target->getRoutingKey(),
- $target->isNowait(),
- $target->getArguments(),
- $target->getTicket()
+ $bind->getSource()->getQueueName(),
+ $bind->getTarget()->getTopicName(),
+ $bind->getRoutingKey(),
+ (bool) ($bind->getFlags() & InteropAmqpBind::FLAG_NOWAIT),
+ $bind->getArguments()
);
// bind exchange to queue
} else {
$this->getChannel()->queue_bind(
- $target->getQueueName(),
- $source->getTopicName(),
- $source->getRoutingKey(),
- $source->isNowait(),
- $source->getArguments(),
- $source->getTicket()
+ $bind->getTarget()->getQueueName(),
+ $bind->getSource()->getTopicName(),
+ $bind->getRoutingKey(),
+ (bool) ($bind->getFlags() & InteropAmqpBind::FLAG_NOWAIT),
+ $bind->getArguments()
);
}
}
/**
- * Purge all messages from the given queue.
- *
- * @param PsrQueue $queue
+ * {@inheritdoc}
*/
- public function purge(PsrQueue $queue)
+ public function unbind(InteropAmqpBind $bind)
{
- InvalidDestinationException::assertDestinationInstanceOf($queue, AmqpQueue::class);
+ if ($bind->getSource() instanceof InteropAmqpQueue && $bind->getTarget() instanceof InteropAmqpQueue) {
+ throw new Exception('Is not possible to bind queue to queue. It is possible to bind topic to queue or topic to topic');
+ }
- $this->getChannel()->queue_purge($queue->getQueueName());
+ // bind exchange to exchange
+ if ($bind->getSource() instanceof InteropAmqpTopic && $bind->getTarget() instanceof InteropAmqpTopic) {
+ $this->getChannel()->exchange_unbind(
+ $bind->getTarget()->getTopicName(),
+ $bind->getSource()->getTopicName(),
+ $bind->getRoutingKey(),
+ (bool) ($bind->getFlags() & InteropAmqpBind::FLAG_NOWAIT),
+ $bind->getArguments()
+ );
+ // bind queue to exchange
+ } elseif ($bind->getSource() instanceof InteropAmqpQueue) {
+ $this->getChannel()->queue_unbind(
+ $bind->getSource()->getQueueName(),
+ $bind->getTarget()->getTopicName(),
+ $bind->getRoutingKey(),
+ $bind->getArguments()
+ );
+ // bind exchange to queue
+ } else {
+ $this->getChannel()->queue_unbind(
+ $bind->getTarget()->getQueueName(),
+ $bind->getSource()->getTopicName(),
+ $bind->getRoutingKey(),
+ $bind->getArguments()
+ );
+ }
}
public function close()
@@ -232,6 +294,14 @@ public function close()
}
}
+ /**
+ * {@inheritdoc}
+ */
+ public function setQos($prefetchSize, $prefetchCount, $global)
+ {
+ $this->getChannel()->basic_qos($prefetchSize, $prefetchCount, $global);
+ }
+
/**
* @return AMQPChannel
*/
@@ -239,6 +309,11 @@ private function getChannel()
{
if (null === $this->channel) {
$this->channel = $this->connection->channel();
+ $this->channel->basic_qos(
+ $this->config['qos_prefetch_size'],
+ $this->config['qos_prefetch_count'],
+ $this->config['qos_global']
+ );
}
return $this->channel;
diff --git a/pkg/amqp-lib/AmqpMessage.php b/pkg/amqp-lib/AmqpMessage.php
deleted file mode 100644
index f391d7364..000000000
--- a/pkg/amqp-lib/AmqpMessage.php
+++ /dev/null
@@ -1,295 +0,0 @@
-body = $body;
- $this->properties = $properties;
- $this->headers = $headers;
- $this->redelivered = false;
- }
-
- /**
- * @return string
- */
- public function getBody()
- {
- return $this->body;
- }
-
- /**
- * @param string $body
- */
- public function setBody($body)
- {
- $this->body = $body;
- }
-
- /**
- * @param array $properties
- */
- public function setProperties(array $properties)
- {
- $this->properties = $properties;
- }
-
- /**
- * @return array
- */
- public function getProperties()
- {
- return $this->properties;
- }
-
- /**
- * @param string $name
- * @param mixed $value
- */
- public function setProperty($name, $value)
- {
- $this->properties[$name] = $value;
- }
-
- /**
- * @param string $name
- * @param mixed $default
- *
- * @return mixed
- */
- public function getProperty($name, $default = null)
- {
- return array_key_exists($name, $this->properties) ? $this->properties[$name] : $default;
- }
-
- /**
- * @param array $headers
- */
- public function setHeaders(array $headers)
- {
- $this->headers = $headers;
- }
-
- /**
- * @return array
- */
- public function getHeaders()
- {
- return $this->headers;
- }
-
- /**
- * @param string $name
- * @param mixed $value
- */
- public function setHeader($name, $value)
- {
- $this->headers[$name] = $value;
- }
-
- /**
- * @param string $name
- * @param mixed $default
- *
- * @return mixed
- */
- public function getHeader($name, $default = null)
- {
- return array_key_exists($name, $this->headers) ? $this->headers[$name] : $default;
- }
-
- /**
- * @param bool $redelivered
- */
- public function setRedelivered($redelivered)
- {
- $this->redelivered = (bool) $redelivered;
- }
-
- /**
- * @return bool
- */
- public function isRedelivered()
- {
- return $this->redelivered;
- }
-
- /**
- * @param string $correlationId
- */
- public function setCorrelationId($correlationId)
- {
- $this->setHeader('correlation_id', $correlationId);
- }
-
- /**
- * @return string
- */
- public function getCorrelationId()
- {
- return $this->getHeader('correlation_id');
- }
-
- /**
- * @param string $messageId
- */
- public function setMessageId($messageId)
- {
- $this->setHeader('message_id', $messageId);
- }
-
- /**
- * @return string
- */
- public function getMessageId()
- {
- return $this->getHeader('message_id');
- }
-
- /**
- * @return int
- */
- public function getTimestamp()
- {
- $value = $this->getHeader('timestamp');
-
- return $value === null ? null : (int) $value;
- }
-
- /**
- * @param int $timestamp
- */
- public function setTimestamp($timestamp)
- {
- $this->setHeader('timestamp', $timestamp);
- }
-
- /**
- * @param string|null $replyTo
- */
- public function setReplyTo($replyTo)
- {
- $this->setHeader('reply_to', $replyTo);
- }
-
- /**
- * @return string|null
- */
- public function getReplyTo()
- {
- return $this->getHeader('reply_to');
- }
-
- /**
- * @return string
- */
- public function getDeliveryTag()
- {
- return $this->deliveryTag;
- }
-
- /**
- * @param string $deliveryTag
- */
- public function setDeliveryTag($deliveryTag)
- {
- $this->deliveryTag = $deliveryTag;
- }
-
- /**
- * @return bool
- */
- public function isMandatory()
- {
- return $this->mandatory;
- }
-
- /**
- * @param int $mandatory
- */
- public function setMandatory($mandatory)
- {
- $this->mandatory = $mandatory;
- }
-
- /**
- * @return bool
- */
- public function isImmediate()
- {
- return $this->immediate;
- }
-
- /**
- * @param bool $immediate
- */
- public function setImmediate($immediate)
- {
- $this->immediate = $immediate;
- }
-
- /**
- * @return int
- */
- public function getTicket()
- {
- return $this->ticket;
- }
-
- /**
- * @param int $ticket
- */
- public function setTicket($ticket)
- {
- $this->ticket = $ticket;
- }
-}
diff --git a/pkg/amqp-lib/AmqpProducer.php b/pkg/amqp-lib/AmqpProducer.php
index b5cf61805..7da4b6acc 100644
--- a/pkg/amqp-lib/AmqpProducer.php
+++ b/pkg/amqp-lib/AmqpProducer.php
@@ -2,43 +2,81 @@
namespace Enqueue\AmqpLib;
+use Enqueue\AmqpTools\DelayStrategyAware;
+use Enqueue\AmqpTools\DelayStrategyAwareTrait;
+use Interop\Amqp\AmqpMessage as InteropAmqpMessage;
+use Interop\Amqp\AmqpProducer as InteropAmqpProducer;
+use Interop\Amqp\AmqpQueue as InteropAmqpQueue;
+use Interop\Amqp\AmqpTopic as InteropAmqpTopic;
+use Interop\Queue\DeliveryDelayNotSupportedException;
use Interop\Queue\InvalidDestinationException;
use Interop\Queue\InvalidMessageException;
use Interop\Queue\PsrDestination;
use Interop\Queue\PsrMessage;
-use Interop\Queue\PsrProducer;
use Interop\Queue\PsrTopic;
use PhpAmqpLib\Channel\AMQPChannel;
use PhpAmqpLib\Message\AMQPMessage as LibAMQPMessage;
use PhpAmqpLib\Wire\AMQPTable;
-class AmqpProducer implements PsrProducer
+class AmqpProducer implements InteropAmqpProducer, DelayStrategyAware
{
+ use DelayStrategyAwareTrait;
+
+ /**
+ * @var int|null
+ */
+ private $priority;
+
+ /**
+ * @var int|float|null
+ */
+ private $timeToLive;
+
+ /**
+ * @var int
+ */
+ private $deliveryDelay;
+
/**
* @var AMQPChannel
*/
private $channel;
+ /**
+ * @var AmqpContext
+ */
+ private $context;
+
/**
* @param AMQPChannel $channel
+ * @param AmqpContext $context
*/
- public function __construct(AMQPChannel $channel)
+ public function __construct(AMQPChannel $channel, AmqpContext $context)
{
$this->channel = $channel;
+ $this->context = $context;
}
/**
- * @param AmqpTopic|AmqpQueue $destination
- * @param AmqpMessage $message
+ * @param InteropAmqpTopic|InteropAmqpQueue $destination
+ * @param InteropAmqpMessage $message
*/
public function send(PsrDestination $destination, PsrMessage $message)
{
$destination instanceof PsrTopic
- ? InvalidDestinationException::assertDestinationInstanceOf($destination, AmqpTopic::class)
- : InvalidDestinationException::assertDestinationInstanceOf($destination, AmqpQueue::class)
+ ? InvalidDestinationException::assertDestinationInstanceOf($destination, InteropAmqpTopic::class)
+ : InvalidDestinationException::assertDestinationInstanceOf($destination, InteropAmqpQueue::class)
;
- InvalidMessageException::assertMessageInstanceOf($message, AmqpMessage::class);
+ InvalidMessageException::assertMessageInstanceOf($message, InteropAmqpMessage::class);
+
+ if (null !== $this->priority && null === $message->getPriority()) {
+ $message->setPriority($this->priority);
+ }
+
+ if (null !== $this->timeToLive && null === $message->getExpiration()) {
+ $message->setExpiration($this->timeToLive);
+ }
$amqpProperties = $message->getHeaders();
@@ -48,24 +86,80 @@ public function send(PsrDestination $destination, PsrMessage $message)
$amqpMessage = new LibAMQPMessage($message->getBody(), $amqpProperties);
- if ($destination instanceof AmqpTopic) {
+ if ($this->deliveryDelay) {
+ $this->delayStrategy->delayMessage($this->context, $destination, $message, $this->deliveryDelay);
+ } elseif ($destination instanceof InteropAmqpTopic) {
$this->channel->basic_publish(
$amqpMessage,
$destination->getTopicName(),
- $destination->getRoutingKey(),
- $message->isMandatory(),
- $message->isImmediate(),
- $message->getTicket()
+ $message->getRoutingKey(),
+ (bool) ($message->getFlags() & InteropAmqpMessage::FLAG_MANDATORY),
+ (bool) ($message->getFlags() & InteropAmqpMessage::FLAG_IMMEDIATE)
);
} else {
$this->channel->basic_publish(
$amqpMessage,
'',
$destination->getQueueName(),
- $message->isMandatory(),
- $message->isImmediate(),
- $message->getTicket()
+ (bool) ($message->getFlags() & InteropAmqpMessage::FLAG_MANDATORY),
+ (bool) ($message->getFlags() & InteropAmqpMessage::FLAG_IMMEDIATE)
);
}
}
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setDeliveryDelay($deliveryDelay)
+ {
+ if (null === $this->delayStrategy) {
+ throw DeliveryDelayNotSupportedException::providerDoestNotSupportIt();
+ }
+
+ $this->deliveryDelay = $deliveryDelay;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDeliveryDelay()
+ {
+ return $this->deliveryDelay;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setPriority($priority)
+ {
+ $this->priority = $priority;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPriority()
+ {
+ return $this->priority;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setTimeToLive($timeToLive)
+ {
+ $this->timeToLive = $timeToLive;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTimeToLive()
+ {
+ return $this->timeToLive;
+ }
}
diff --git a/pkg/amqp-lib/AmqpQueue.php b/pkg/amqp-lib/AmqpQueue.php
deleted file mode 100644
index 5c6551c73..000000000
--- a/pkg/amqp-lib/AmqpQueue.php
+++ /dev/null
@@ -1,243 +0,0 @@
-name = $name;
- $this->passive = false;
- $this->durable = false;
- $this->exclusive = false;
- $this->autoDelete = true;
- $this->noWait = false;
- $this->noLocal = false;
- $this->noAck = false;
- }
-
- /**
- * @return string
- */
- public function getQueueName()
- {
- return $this->name;
- }
-
- /**
- * @return bool
- */
- public function isPassive()
- {
- return $this->passive;
- }
-
- /**
- * @param bool $passive
- */
- public function setPassive($passive)
- {
- $this->passive = (bool) $passive;
- }
-
- /**
- * @return bool
- */
- public function isDurable()
- {
- return $this->durable;
- }
-
- /**
- * @param bool $durable
- */
- public function setDurable($durable)
- {
- $this->durable = (bool) $durable;
- }
-
- /**
- * @return bool
- */
- public function isExclusive()
- {
- return $this->exclusive;
- }
-
- /**
- * @param bool $exclusive
- */
- public function setExclusive($exclusive)
- {
- $this->exclusive = (bool) $exclusive;
- }
-
- /**
- * @return bool
- */
- public function isAutoDelete()
- {
- return $this->autoDelete;
- }
-
- /**
- * @param bool $autoDelete
- */
- public function setAutoDelete($autoDelete)
- {
- $this->autoDelete = (bool) $autoDelete;
- }
-
- /**
- * @return bool
- */
- public function isNoWait()
- {
- return $this->noWait;
- }
-
- /**
- * @param bool $noWait
- */
- public function setNoWait($noWait)
- {
- $this->noWait = (bool) $noWait;
- }
-
- /**
- * @return array|null
- */
- public function getArguments()
- {
- return $this->arguments;
- }
-
- /**
- * @param array|null $arguments
- */
- public function setArguments(array $arguments = null)
- {
- $this->arguments = $arguments;
- }
-
- /**
- * @return int
- */
- public function getTicket()
- {
- return $this->ticket;
- }
-
- /**
- * @param int $ticket
- */
- public function setTicket($ticket)
- {
- $this->ticket = $ticket;
- }
-
- /**
- * @return string
- */
- public function getConsumerTag()
- {
- return $this->consumerTag;
- }
-
- /**
- * @param string $consumerTag
- */
- public function setConsumerTag($consumerTag)
- {
- $this->consumerTag = $consumerTag;
- }
-
- /**
- * @return bool
- */
- public function isNoLocal()
- {
- return $this->noLocal;
- }
-
- /**
- * @param bool $noLocal
- */
- public function setNoLocal($noLocal)
- {
- $this->noLocal = $noLocal;
- }
-
- /**
- * @return bool
- */
- public function isNoAck()
- {
- return $this->noAck;
- }
-
- /**
- * @param bool $noAck
- */
- public function setNoAck($noAck)
- {
- $this->noAck = $noAck;
- }
-}
diff --git a/pkg/amqp-lib/AmqpTopic.php b/pkg/amqp-lib/AmqpTopic.php
deleted file mode 100644
index a1d029853..000000000
--- a/pkg/amqp-lib/AmqpTopic.php
+++ /dev/null
@@ -1,224 +0,0 @@
-name = $name;
- $this->type = 'direct';
- $this->passive = false;
- $this->durable = false;
- $this->autoDelete = true;
- $this->internal = false;
- $this->noWait = false;
- }
-
- /**
- * @return string
- */
- public function getTopicName()
- {
- return $this->name;
- }
-
- /**
- * @return string
- */
- public function getType()
- {
- return $this->type;
- }
-
- /**
- * @param string $type
- */
- public function setType($type)
- {
- $this->type = $type;
- }
-
- /**
- * @return bool
- */
- public function isPassive()
- {
- return $this->passive;
- }
-
- /**
- * @param bool $passive
- */
- public function setPassive($passive)
- {
- $this->passive = (bool) $passive;
- }
-
- /**
- * @return bool
- */
- public function isDurable()
- {
- return $this->durable;
- }
-
- /**
- * @param bool $durable
- */
- public function setDurable($durable)
- {
- $this->durable = (bool) $durable;
- }
-
- /**
- * @return bool
- */
- public function isAutoDelete()
- {
- return $this->autoDelete;
- }
-
- /**
- * @param bool $autoDelete
- */
- public function setAutoDelete($autoDelete)
- {
- $this->autoDelete = (bool) $autoDelete;
- }
-
- /**
- * @return bool
- */
- public function isInternal()
- {
- return $this->internal;
- }
-
- /**
- * @param bool $internal
- */
- public function setInternal($internal)
- {
- $this->internal = (bool) $internal;
- }
-
- /**
- * @return bool
- */
- public function isNoWait()
- {
- return $this->noWait;
- }
-
- /**
- * @param bool $noWait
- */
- public function setNoWait($noWait)
- {
- $this->noWait = (bool) $noWait;
- }
-
- /**
- * @return array|null
- */
- public function getArguments()
- {
- return $this->arguments;
- }
-
- /**
- * @param array|null $arguments
- */
- public function setArguments(array $arguments = null)
- {
- $this->arguments = $arguments;
- }
-
- /**
- * @return int
- */
- public function getTicket()
- {
- return $this->ticket;
- }
-
- /**
- * @param int $ticket
- */
- public function setTicket($ticket)
- {
- $this->ticket = $ticket;
- }
-
- /**
- * @return string
- */
- public function getRoutingKey()
- {
- return $this->routingKey;
- }
-
- /**
- * @param string $routingKey
- */
- public function setRoutingKey($routingKey)
- {
- $this->routingKey = $routingKey;
- }
-}
diff --git a/pkg/amqp-lib/Buffer.php b/pkg/amqp-lib/Buffer.php
index 55c06f619..27732806e 100644
--- a/pkg/amqp-lib/Buffer.php
+++ b/pkg/amqp-lib/Buffer.php
@@ -2,6 +2,8 @@
namespace Enqueue\AmqpLib;
+use Interop\Amqp\AmqpMessage;
+
class Buffer
{
/**
diff --git a/pkg/amqp-lib/README.md b/pkg/amqp-lib/README.md
new file mode 100644
index 000000000..9d92954a3
--- /dev/null
+++ b/pkg/amqp-lib/README.md
@@ -0,0 +1,26 @@
+# AMQP Transport
+
+[](https://gitter.im/php-enqueue/Lobby)
+[](https://travis-ci.org/php-enqueue/amqp-lib)
+[](https://packagist.org/packages/enqueue/amqp-lib)
+[](https://packagist.org/packages/enqueue/amqp-lib)
+
+This is an implementation of [amqp interop](https://github.com/queue-interop/amqp-interop). It uses [php-amqplib](https://github.com/php-amqplib/php-amqplib) internally.
+
+## Resources
+
+* [Documentation](https://github.com/php-enqueue/enqueue-dev/blob/master/docs/index.md)
+* [Questions](https://gitter.im/php-enqueue/Lobby)
+* [Issue Tracker](https://github.com/php-enqueue/enqueue-dev/issues)
+
+## Developed by Forma-Pro
+
+Forma-Pro is a full stack development company which interests also spread to open source development.
+Being a team of strong professionals we have an aim an ability to help community by developing cutting edge solutions in the areas of e-commerce, docker & microservice oriented architecture where we have accumulated a huge many-years experience.
+Our main specialization is Symfony framework based solution, but we are always looking to the technologies that allow us to do our job the best way. We are committed to creating solutions that revolutionize the way how things are developed in aspects of architecture & scalability.
+
+If you have any questions and inquires about our open source development, this product particularly or any other matter feel free to contact at opensource@forma-pro.com
+
+## License
+
+It is released under the [MIT License](LICENSE).
\ No newline at end of file
diff --git a/pkg/amqp-lib/Symfony/AmqpLibTransportFactory.php b/pkg/amqp-lib/Symfony/AmqpLibTransportFactory.php
new file mode 100644
index 000000000..f2fbacdf5
--- /dev/null
+++ b/pkg/amqp-lib/Symfony/AmqpLibTransportFactory.php
@@ -0,0 +1,168 @@
+name = $name;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addConfiguration(ArrayNodeDefinition $builder)
+ {
+ $builder
+ ->beforeNormalization()
+ ->ifString()
+ ->then(function ($v) {
+ return ['dsn' => $v];
+ })
+ ->end()
+ ->children()
+ ->scalarNode('dsn')
+ ->info('The connection to AMQP broker set as a string. Other parameters are ignored if set')
+ ->end()
+ ->scalarNode('host')
+ ->defaultValue('localhost')
+ ->cannotBeEmpty()
+ ->info('The host to connect too. Note: Max 1024 characters')
+ ->end()
+ ->scalarNode('port')
+ ->defaultValue(5672)
+ ->cannotBeEmpty()
+ ->info('Port on the host.')
+ ->end()
+ ->scalarNode('user')
+ ->defaultValue('guest')
+ ->cannotBeEmpty()
+ ->info('The user name to use. Note: Max 128 characters.')
+ ->end()
+ ->scalarNode('pass')
+ ->defaultValue('guest')
+ ->cannotBeEmpty()
+ ->info('Password. Note: Max 128 characters.')
+ ->end()
+ ->scalarNode('vhost')
+ ->defaultValue('/')
+ ->cannotBeEmpty()
+ ->info('The virtual host on the host. Note: Max 128 characters.')
+ ->end()
+ ->integerNode('connection_timeout')
+ ->defaultValue(3.0)
+ ->min(0)
+ ->info('Connection timeout. Note: 0 or greater seconds. May be fractional.')
+ ->end()
+ ->integerNode('read_write_timeout')
+ ->defaultValue(3.0)
+ ->min(0)
+ ->end()
+ ->integerNode('read_timeout')
+ ->defaultValue(3)
+ ->min(0)
+ ->info('Timeout in for income activity. Note: 0 or greater seconds. May be fractional.')
+ ->end()
+ ->integerNode('write_timeout')
+ ->defaultValue(3)
+ ->min(0)
+ ->info('Timeout in for outcome activity. Note: 0 or greater seconds. May be fractional.')
+ ->end()
+ ->booleanNode('lazy')
+ ->defaultTrue()
+ ->end()
+ ->booleanNode('stream')
+ ->defaultTrue()
+ ->end()
+ ->booleanNode('insist')
+ ->defaultFalse()
+ ->end()
+ ->booleanNode('keepalive')
+ ->defaultFalse()
+ ->end()
+ ->enumNode('receive_method')
+ ->values(['basic_get', 'basic_consume'])
+ ->defaultValue('basic_get')
+ ->info('The receive strategy to be used. We suggest to use basic_consume as it is more performant. Though you need AMQP extension 1.9.1 or higher')
+ ->end()
+ ->integerNode('heartbeat')
+ ->defaultValue(0)
+ ->end()
+ ;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createConnectionFactory(ContainerBuilder $container, array $config)
+ {
+ $factory = new Definition(AmqpConnectionFactory::class);
+ $factory->setArguments(isset($config['dsn']) ? [$config['dsn']] : [$config]);
+
+ $factoryId = sprintf('enqueue.transport.%s.connection_factory', $this->getName());
+ $container->setDefinition($factoryId, $factory);
+
+ return $factoryId;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createContext(ContainerBuilder $container, array $config)
+ {
+ $factoryId = sprintf('enqueue.transport.%s.connection_factory', $this->getName());
+
+ $context = new Definition(AmqpContext::class);
+ $context->setFactory([new Reference($factoryId), 'createContext']);
+
+ $contextId = sprintf('enqueue.transport.%s.context', $this->getName());
+ $container->setDefinition($contextId, $context);
+
+ return $contextId;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createDriver(ContainerBuilder $container, array $config)
+ {
+ $driver = new Definition(AmqpDriver::class);
+ $driver->setArguments([
+ new Reference(sprintf('enqueue.transport.%s.context', $this->getName())),
+ new Reference('enqueue.client.config'),
+ new Reference('enqueue.client.meta.queue_meta_registry'),
+ ]);
+
+ $driverId = sprintf('enqueue.client.%s.driver', $this->getName());
+ $container->setDefinition($driverId, $driver);
+
+ return $driverId;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+}
diff --git a/pkg/amqp-lib/Symfony/RabbitMqAmqpLibTransportFactory.php b/pkg/amqp-lib/Symfony/RabbitMqAmqpLibTransportFactory.php
new file mode 100644
index 000000000..20765c6b1
--- /dev/null
+++ b/pkg/amqp-lib/Symfony/RabbitMqAmqpLibTransportFactory.php
@@ -0,0 +1,53 @@
+children()
+ ->booleanNode('delay_plugin_installed')
+ ->defaultFalse()
+ ->info('The option tells whether RabbitMQ broker has delay plugin installed or not')
+ ->end()
+ ;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createDriver(ContainerBuilder $container, array $config)
+ {
+ $driver = new Definition(RabbitMqDriver::class);
+ $driver->setArguments([
+ new Reference(sprintf('enqueue.transport.%s.context', $this->getName())),
+ new Reference('enqueue.client.config'),
+ new Reference('enqueue.client.meta.queue_meta_registry'),
+ ]);
+ $driverId = sprintf('enqueue.client.%s.driver', $this->getName());
+ $container->setDefinition($driverId, $driver);
+
+ return $driverId;
+ }
+}
diff --git a/pkg/amqp-lib/Tests/AmqpConnectionFactoryConfigTest.php b/pkg/amqp-lib/Tests/AmqpConnectionFactoryConfigTest.php
index 31a1ca0ef..71597c9a7 100644
--- a/pkg/amqp-lib/Tests/AmqpConnectionFactoryConfigTest.php
+++ b/pkg/amqp-lib/Tests/AmqpConnectionFactoryConfigTest.php
@@ -81,11 +81,41 @@ public static function provideConfigs()
'heartbeat' => 0,
'connection_timeout' => 3.0,
'read_write_timeout' => 3.0,
+ 'qos_prefetch_size' => 0,
+ 'qos_prefetch_count' => 1,
+ 'qos_global' => false,
],
];
// some examples from Appendix A: Examples (https://www.rabbitmq.com/uri-spec.html)
+ yield [
+ 'amqp+lib://user:pass@host:10000/vhost',
+ [
+ 'host' => 'host',
+ 'port' => 10000,
+ 'vhost' => 'vhost',
+ 'user' => 'user',
+ 'pass' => 'pass',
+ 'read_timeout' => 3,
+ 'write_timeout' => 3,
+ 'lazy' => true,
+ 'receive_method' => 'basic_get',
+ 'stream' => true,
+ 'insist' => false,
+ 'login_method' => 'AMQPLAIN',
+ 'login_response' => null,
+ 'locale' => 'en_US',
+ 'keepalive' => false,
+ 'heartbeat' => 0,
+ 'connection_timeout' => 3.0,
+ 'read_write_timeout' => 3.0,
+ 'qos_prefetch_size' => 0,
+ 'qos_prefetch_count' => 1,
+ 'qos_global' => false,
+ ],
+ ];
+
yield [
'amqp://user:pass@host:10000/vhost',
[
@@ -107,6 +137,9 @@ public static function provideConfigs()
'heartbeat' => 0,
'connection_timeout' => 3.0,
'read_write_timeout' => 3.0,
+ 'qos_prefetch_size' => 0,
+ 'qos_prefetch_count' => 1,
+ 'qos_global' => false,
],
];
@@ -131,6 +164,9 @@ public static function provideConfigs()
'heartbeat' => 0,
'connection_timeout' => 3.0,
'read_write_timeout' => 3.0,
+ 'qos_prefetch_size' => 0,
+ 'qos_prefetch_count' => 1,
+ 'qos_global' => false,
],
];
@@ -155,6 +191,9 @@ public static function provideConfigs()
'heartbeat' => 0,
'connection_timeout' => 3.0,
'read_write_timeout' => 3.0,
+ 'qos_prefetch_size' => 0,
+ 'qos_prefetch_count' => 1,
+ 'qos_global' => false,
],
];
@@ -179,6 +218,9 @@ public static function provideConfigs()
'heartbeat' => 0,
'connection_timeout' => '2',
'read_write_timeout' => 3.0,
+ 'qos_prefetch_size' => 0,
+ 'qos_prefetch_count' => 1,
+ 'qos_global' => false,
],
];
@@ -203,6 +245,9 @@ public static function provideConfigs()
'heartbeat' => 0,
'connection_timeout' => 3.0,
'read_write_timeout' => 3.0,
+ 'qos_prefetch_size' => 0,
+ 'qos_prefetch_count' => 1,
+ 'qos_global' => false,
],
];
@@ -227,6 +272,9 @@ public static function provideConfigs()
'heartbeat' => 0,
'connection_timeout' => 3.0,
'read_write_timeout' => 3.0,
+ 'qos_prefetch_size' => 0,
+ 'qos_prefetch_count' => 1,
+ 'qos_global' => false,
],
];
@@ -251,6 +299,9 @@ public static function provideConfigs()
'heartbeat' => 0,
'connection_timeout' => 123,
'read_write_timeout' => 321,
+ 'qos_prefetch_size' => 0,
+ 'qos_prefetch_count' => 1,
+ 'qos_global' => false,
],
];
@@ -275,6 +326,9 @@ public static function provideConfigs()
'heartbeat' => 0,
'connection_timeout' => '123',
'read_write_timeout' => '321',
+ 'qos_prefetch_size' => 0,
+ 'qos_prefetch_count' => 1,
+ 'qos_global' => false,
],
];
}
diff --git a/pkg/amqp-lib/Tests/AmqpConsumerTest.php b/pkg/amqp-lib/Tests/AmqpConsumerTest.php
index a77443223..f4462e2ad 100644
--- a/pkg/amqp-lib/Tests/AmqpConsumerTest.php
+++ b/pkg/amqp-lib/Tests/AmqpConsumerTest.php
@@ -3,12 +3,12 @@
namespace Enqueue\AmqpLib\Tests;
use Enqueue\AmqpLib\AmqpConsumer;
-use Enqueue\AmqpLib\AmqpMessage;
-use Enqueue\AmqpLib\AmqpQueue;
use Enqueue\AmqpLib\Buffer;
use Enqueue\Null\NullMessage;
use Enqueue\Test\ClassExtensionTrait;
use Enqueue\Test\WriteAttributeTrait;
+use Interop\Amqp\Impl\AmqpMessage;
+use Interop\Amqp\Impl\AmqpQueue;
use Interop\Queue\InvalidMessageException;
use Interop\Queue\PsrConsumer;
use PhpAmqpLib\Channel\AMQPChannel;
@@ -48,7 +48,7 @@ public function testOnAcknowledgeShouldThrowExceptionIfNotAmqpMessage()
$consumer = new AmqpConsumer($this->createChannelMock(), new AmqpQueue('aName'), new Buffer(), 'basic_get');
$this->expectException(InvalidMessageException::class);
- $this->expectExceptionMessage('The message must be an instance of Enqueue\AmqpLib\AmqpMessage but');
+ $this->expectExceptionMessage('The message must be an instance of Interop\Amqp\AmqpMessage but');
$consumer->acknowledge(new NullMessage());
}
@@ -58,7 +58,7 @@ public function testOnRejectShouldThrowExceptionIfNotAmqpMessage()
$consumer = new AmqpConsumer($this->createChannelMock(), new AmqpQueue('aName'), new Buffer(), 'basic_get');
$this->expectException(InvalidMessageException::class);
- $this->expectExceptionMessage('The message must be an instance of Enqueue\AmqpLib\AmqpMessage but');
+ $this->expectExceptionMessage('The message must be an instance of Interop\Amqp\AmqpMessage but');
$consumer->reject(new NullMessage());
}
@@ -157,21 +157,18 @@ public function testShouldCallExpectedMethodsWhenReceiveWithBasicConsumeMethod()
->method('basic_consume')
->willReturn('consumer-tag')
;
- $channel
- ->expects($this->once())
- ->method('basic_qos')
- ->with($this->identicalTo(0), $this->identicalTo(1), $this->isFalse())
- ;
$channel
->expects($this->once())
->method('wait')
- ;
+ ->willReturnCallback(function () {
+ usleep(2000);
+ });
$consumer = new AmqpConsumer($channel, new AmqpQueue('aName'), new Buffer(), 'basic_consume');
$message = new AmqpMessage();
$message->setDeliveryTag('delivery-tag');
- $consumer->receive();
+ $consumer->receive(1);
}
/**
diff --git a/pkg/amqp-lib/Tests/AmqpContextTest.php b/pkg/amqp-lib/Tests/AmqpContextTest.php
index 17070f072..80dee492a 100644
--- a/pkg/amqp-lib/Tests/AmqpContextTest.php
+++ b/pkg/amqp-lib/Tests/AmqpContextTest.php
@@ -3,12 +3,9 @@
namespace Enqueue\AmqpLib\Tests;
use Enqueue\AmqpLib\AmqpContext;
-use Enqueue\AmqpLib\AmqpQueue;
-use Enqueue\AmqpLib\AmqpTopic;
-use Enqueue\Null\NullQueue;
-use Enqueue\Null\NullTopic;
-use Interop\Queue\Exception;
-use Interop\Queue\InvalidDestinationException;
+use Interop\Amqp\Impl\AmqpBind;
+use Interop\Amqp\Impl\AmqpQueue;
+use Interop\Amqp\Impl\AmqpTopic;
use PhpAmqpLib\Channel\AMQPChannel;
use PhpAmqpLib\Connection\AbstractConnection;
use PHPUnit\Framework\TestCase;
@@ -30,7 +27,7 @@ public function testShouldDeclareTopic()
$this->isTrue(),
$this->isTrue(),
$this->identicalTo(['key' => 'value']),
- $this->identicalTo(12345)
+ $this->isNull()
)
;
@@ -44,18 +41,46 @@ public function testShouldDeclareTopic()
$topic = new AmqpTopic('name');
$topic->setType('type');
$topic->setArguments(['key' => 'value']);
- $topic->setAutoDelete(true);
- $topic->setDurable(true);
- $topic->setInternal(true);
- $topic->setNoWait(true);
- $topic->setPassive(true);
- $topic->setRoutingKey('routing-key');
- $topic->setTicket(12345);
-
- $session = new AmqpContext($connection, '');
+ $topic->addFlag(AmqpTopic::FLAG_DURABLE);
+ $topic->addFlag(AmqpTopic::FLAG_NOWAIT);
+ $topic->addFlag(AmqpTopic::FLAG_PASSIVE);
+ $topic->addFlag(AmqpTopic::FLAG_INTERNAL);
+ $topic->addFlag(AmqpTopic::FLAG_AUTODELETE);
+
+ $session = new AmqpContext($connection);
$session->declareTopic($topic);
}
+ public function testShouldDeleteTopic()
+ {
+ $channel = $this->createChannelMock();
+ $channel
+ ->expects($this->once())
+ ->method('exchange_delete')
+ ->with(
+ $this->identicalTo('name'),
+ $this->isTrue(),
+ $this->isTrue()
+ )
+ ;
+
+ $connection = $this->createConnectionMock();
+ $connection
+ ->expects($this->once())
+ ->method('channel')
+ ->willReturn($channel)
+ ;
+
+ $topic = new AmqpTopic('name');
+ $topic->setType('type');
+ $topic->setArguments(['key' => 'value']);
+ $topic->addFlag(AmqpTopic::FLAG_IFUNUSED);
+ $topic->addFlag(AmqpTopic::FLAG_NOWAIT);
+
+ $session = new AmqpContext($connection);
+ $session->deleteTopic($topic);
+ }
+
public function testShouldDeclareQueue()
{
$channel = $this->createChannelMock();
@@ -70,7 +95,7 @@ public function testShouldDeclareQueue()
$this->isTrue(),
$this->isTrue(),
$this->identicalTo(['key' => 'value']),
- $this->identicalTo(12345)
+ $this->isNull()
)
;
@@ -83,50 +108,96 @@ public function testShouldDeclareQueue()
$queue = new AmqpQueue('name');
$queue->setArguments(['key' => 'value']);
- $queue->setAutoDelete(true);
- $queue->setDurable(true);
- $queue->setNoWait(true);
- $queue->setPassive(true);
- $queue->setTicket(12345);
- $queue->setConsumerTag('consumer-tag');
- $queue->setExclusive(true);
- $queue->setNoLocal(true);
-
- $session = new AmqpContext($connection, '');
+ $queue->addFlag(AmqpQueue::FLAG_AUTODELETE);
+ $queue->addFlag(AmqpQueue::FLAG_DURABLE);
+ $queue->addFlag(AmqpQueue::FLAG_NOWAIT);
+ $queue->addFlag(AmqpQueue::FLAG_PASSIVE);
+ $queue->addFlag(AmqpQueue::FLAG_EXCLUSIVE);
+ $queue->addFlag(AmqpQueue::FLAG_NOWAIT);
+
+ $session = new AmqpContext($connection);
$session->declareQueue($queue);
}
- public function testDeclareBindShouldThrowExceptionIfSourceDestinationIsInvalid()
+ public function testShouldDeleteQueue()
{
- $context = new AmqpContext($this->createConnectionMock(), '');
+ $channel = $this->createChannelMock();
+ $channel
+ ->expects($this->once())
+ ->method('queue_delete')
+ ->with(
+ $this->identicalTo('name'),
+ $this->isTrue(),
+ $this->isTrue(),
+ $this->isTrue()
+ )
+ ;
- $this->expectException(InvalidDestinationException::class);
- $this->expectExceptionMessage('The destination must be an instance of Enqueue\AmqpLib\AmqpTopic but got');
+ $connection = $this->createConnectionMock();
+ $connection
+ ->expects($this->once())
+ ->method('channel')
+ ->willReturn($channel)
+ ;
+
+ $queue = new AmqpQueue('name');
+ $queue->setArguments(['key' => 'value']);
+ $queue->addFlag(AmqpQueue::FLAG_IFUNUSED);
+ $queue->addFlag(AmqpQueue::FLAG_IFEMPTY);
+ $queue->addFlag(AmqpQueue::FLAG_NOWAIT);
- $context->bind(new NullTopic(''), new AmqpTopic('name'));
+ $session = new AmqpContext($connection);
+ $session->deleteQueue($queue);
}
- public function testDeclareBindShouldThrowExceptionIfTargetDestinationIsInvalid()
+ public function testBindShouldBindTopicToTopic()
{
- $context = new AmqpContext($this->createConnectionMock(), '');
+ $source = new AmqpTopic('source');
+ $target = new AmqpTopic('target');
- $this->expectException(InvalidDestinationException::class);
- $this->expectExceptionMessage('The destination must be an instance of Enqueue\AmqpLib\AmqpTopic but got');
+ $channel = $this->createChannelMock();
+ $channel
+ ->expects($this->once())
+ ->method('exchange_bind')
+ ->with($this->identicalTo('target'), $this->identicalTo('source'), $this->identicalTo('routing-key'), $this->isTrue())
+ ;
+
+ $connection = $this->createConnectionMock();
+ $connection
+ ->expects($this->once())
+ ->method('channel')
+ ->willReturn($channel)
+ ;
- $context->bind(new AmqpQueue('name'), new NullTopic(''));
+ $context = new AmqpContext($connection);
+ $context->bind(new AmqpBind($target, $source, 'routing-key', 12345));
}
- public function testDeclareBindShouldThrowExceptionWhenSourceAndTargetAreQueues()
+ public function testBindShouldBindTopicToQueue()
{
- $context = new AmqpContext($this->createConnectionMock(), '');
+ $source = new AmqpTopic('source');
+ $target = new AmqpQueue('target');
- $this->expectException(Exception::class);
- $this->expectExceptionMessage('Is not possible to bind queue to queue. It is possible to bind topic to queue or topic to topic');
+ $channel = $this->createChannelMock();
+ $channel
+ ->expects($this->exactly(2))
+ ->method('queue_bind')
+ ->with($this->identicalTo('target'), $this->identicalTo('source'), $this->identicalTo('routing-key'), $this->isTrue())
+ ;
+
+ $connection = $this->createConnectionMock();
+ $connection
+ ->expects($this->once())
+ ->method('channel')
+ ->willReturn($channel)
+ ;
- $context->bind(new AmqpQueue('name'), new AmqpQueue('name'));
+ $context = new AmqpContext($connection);
+ $context->bind(new AmqpBind($target, $source, 'routing-key', 12345));
+ $context->bind(new AmqpBind($source, $target, 'routing-key', 12345));
}
- public function testDeclareBindShouldBindTopicToTopic()
+ public function testShouldUnBindTopicFromTopic()
{
$source = new AmqpTopic('source');
$target = new AmqpTopic('target');
@@ -134,8 +205,8 @@ public function testDeclareBindShouldBindTopicToTopic()
$channel = $this->createChannelMock();
$channel
->expects($this->once())
- ->method('exchange_bind')
- ->with('target', 'source')
+ ->method('exchange_unbind')
+ ->with($this->identicalTo('target'), $this->identicalTo('source'), $this->identicalTo('routing-key'), $this->isTrue())
;
$connection = $this->createConnectionMock();
@@ -145,11 +216,11 @@ public function testDeclareBindShouldBindTopicToTopic()
->willReturn($channel)
;
- $context = new AmqpContext($connection, '');
- $context->bind($source, $target);
+ $context = new AmqpContext($connection);
+ $context->unbind(new AmqpBind($target, $source, 'routing-key', 12345));
}
- public function testDeclareBindShouldBindTopicToQueue()
+ public function testShouldUnBindTopicFromQueue()
{
$source = new AmqpTopic('source');
$target = new AmqpQueue('target');
@@ -157,8 +228,8 @@ public function testDeclareBindShouldBindTopicToQueue()
$channel = $this->createChannelMock();
$channel
->expects($this->exactly(2))
- ->method('queue_bind')
- ->with('target', 'source')
+ ->method('queue_unbind')
+ ->with($this->identicalTo('target'), $this->identicalTo('source'), $this->identicalTo('routing-key'), ['key' => 'value'])
;
$connection = $this->createConnectionMock();
@@ -168,9 +239,9 @@ public function testDeclareBindShouldBindTopicToQueue()
->willReturn($channel)
;
- $context = new AmqpContext($connection, '');
- $context->bind($source, $target);
- $context->bind($target, $source);
+ $context = new AmqpContext($connection);
+ $context->unbind(new AmqpBind($target, $source, 'routing-key', 12345, ['key' => 'value']));
+ $context->unbind(new AmqpBind($source, $target, 'routing-key', 12345, ['key' => 'value']));
}
public function testShouldCloseChannelConnection()
@@ -188,31 +259,47 @@ public function testShouldCloseChannelConnection()
->willReturn($channel)
;
- $context = new AmqpContext($connection, '');
+ $context = new AmqpContext($connection);
$context->createProducer();
$context->close();
}
- public function testPurgeShouldThrowExceptionIfDestinationIsNotAmqpQueue()
- {
- $context = new AmqpContext($this->createConnectionMock(), '');
-
- $this->expectException(InvalidDestinationException::class);
- $this->expectExceptionMessage('The destination must be an instance of Enqueue\AmqpLib\AmqpQueue but got');
-
- $context->purge(new NullQueue(''));
- }
-
public function testShouldPurgeQueue()
{
$queue = new AmqpQueue('queue');
+ $queue->addFlag(AmqpQueue::FLAG_NOWAIT);
$channel = $this->createChannelMock();
$channel
->expects($this->once())
->method('queue_purge')
- ->with('queue')
+ ->with($this->identicalTo('queue'), $this->isTrue())
+ ;
+
+ $connection = $this->createConnectionMock();
+ $connection
+ ->expects($this->once())
+ ->method('channel')
+ ->willReturn($channel)
+ ;
+
+ $context = new AmqpContext($connection);
+ $context->purgeQueue($queue);
+ }
+
+ public function testShouldSetQos()
+ {
+ $channel = $this->createChannelMock();
+ $channel
+ ->expects($this->at(0))
+ ->method('basic_qos')
+ ->with($this->identicalTo(0), $this->identicalTo(1), $this->isFalse())
+ ;
+ $channel
+ ->expects($this->at(1))
+ ->method('basic_qos')
+ ->with($this->identicalTo(123), $this->identicalTo(456), $this->isTrue())
;
$connection = $this->createConnectionMock();
@@ -222,8 +309,8 @@ public function testShouldPurgeQueue()
->willReturn($channel)
;
- $context = new AmqpContext($connection, '');
- $context->purge($queue);
+ $context = new AmqpContext($connection);
+ $context->setQos(123, 456, true);
}
/**
diff --git a/pkg/amqp-lib/Tests/AmqpMessageTest.php b/pkg/amqp-lib/Tests/AmqpMessageTest.php
deleted file mode 100644
index 7c927a2cf..000000000
--- a/pkg/amqp-lib/Tests/AmqpMessageTest.php
+++ /dev/null
@@ -1,55 +0,0 @@
-setDeliveryTag('theDeliveryTag');
-
- $this->assertSame('theDeliveryTag', $message->getDeliveryTag());
- }
-
- public function testShouldAllowGetPreviouslySetMandatory()
- {
- $topic = new AmqpMessage('aName');
-
- $topic->setMandatory(false);
- $this->assertFalse($topic->isMandatory());
-
- $topic->setMandatory(true);
- $this->assertTrue($topic->isMandatory());
- }
-
- public function testShouldAllowGetPreviouslySetImmediate()
- {
- $topic = new AmqpMessage('aName');
-
- $topic->setImmediate(false);
- $this->assertFalse($topic->isImmediate());
-
- $topic->setImmediate(true);
- $this->assertTrue($topic->isImmediate());
- }
-
- public function testShouldAllowGetPreviouslySetTicket()
- {
- $topic = new AmqpMessage('aName');
-
- //guard
- $this->assertSame(null, $topic->getTicket());
-
- $topic->setTicket('ticket');
-
- $this->assertSame('ticket', $topic->getTicket());
- }
-}
diff --git a/pkg/amqp-lib/Tests/AmqpProducerTest.php b/pkg/amqp-lib/Tests/AmqpProducerTest.php
index cfad057f4..1d389bf3c 100644
--- a/pkg/amqp-lib/Tests/AmqpProducerTest.php
+++ b/pkg/amqp-lib/Tests/AmqpProducerTest.php
@@ -2,11 +2,11 @@
namespace Enqueue\AmqpLib\Tests;
-use Enqueue\AmqpLib\AmqpMessage;
use Enqueue\AmqpLib\AmqpProducer;
-use Enqueue\AmqpLib\AmqpQueue;
-use Enqueue\AmqpLib\AmqpTopic;
use Enqueue\Test\ClassExtensionTrait;
+use Interop\Amqp\Impl\AmqpMessage;
+use Interop\Amqp\Impl\AmqpQueue;
+use Interop\Amqp\Impl\AmqpTopic;
use Interop\Queue\InvalidDestinationException;
use Interop\Queue\InvalidMessageException;
use Interop\Queue\PsrDestination;
@@ -36,7 +36,7 @@ public function testShouldThrowExceptionWhenDestinationTypeIsInvalid()
$producer = new AmqpProducer($this->createAmqpChannelMock());
$this->expectException(InvalidDestinationException::class);
- $this->expectExceptionMessage('The destination must be an instance of Enqueue\AmqpLib\AmqpQueue but got');
+ $this->expectExceptionMessage('The destination must be an instance of Interop\Amqp\AmqpQueue but got');
$producer->send($this->createDestinationMock(), new AmqpMessage());
}
@@ -46,7 +46,7 @@ public function testShouldThrowExceptionWhenMessageTypeIsInvalid()
$producer = new AmqpProducer($this->createAmqpChannelMock());
$this->expectException(InvalidMessageException::class);
- $this->expectExceptionMessage('The message must be an instance of Enqueue\AmqpLib\AmqpMessage but it is');
+ $this->expectExceptionMessage('The message must be an instance of Interop\Amqp\AmqpMessage but it is');
$producer->send(new AmqpTopic('name'), $this->createMessageMock());
}
@@ -66,10 +66,12 @@ public function testShouldPublishMessageToTopic()
;
$topic = new AmqpTopic('topic');
- $topic->setRoutingKey('routing-key');
+
+ $message = new AmqpMessage('body');
+ $message->setRoutingKey('routing-key');
$producer = new AmqpProducer($channel);
- $producer->send($topic, new AmqpMessage('body'));
+ $producer->send($topic, $message);
$this->assertEquals('body', $amqpMessage->getBody());
}
diff --git a/pkg/amqp-lib/Tests/AmqpQueueTest.php b/pkg/amqp-lib/Tests/AmqpQueueTest.php
deleted file mode 100644
index 34aceeba7..000000000
--- a/pkg/amqp-lib/Tests/AmqpQueueTest.php
+++ /dev/null
@@ -1,122 +0,0 @@
-setPassive(false);
- $this->assertFalse($topic->isPassive());
-
- $topic->setPassive(true);
- $this->assertTrue($topic->isPassive());
- }
-
- public function testShouldAllowGetPreviouslySetDurable()
- {
- $topic = new AmqpQueue('aName');
-
- $topic->setDurable(false);
- $this->assertFalse($topic->isDurable());
-
- $topic->setDurable(true);
- $this->assertTrue($topic->isDurable());
- }
-
- public function testShouldAllowGetPreviouslySetExclusive()
- {
- $topic = new AmqpQueue('aName');
-
- $topic->setExclusive(false);
- $this->assertFalse($topic->isExclusive());
-
- $topic->setExclusive(true);
- $this->assertTrue($topic->isExclusive());
- }
-
- public function testShouldAllowGetPreviouslySetAutoDelete()
- {
- $topic = new AmqpQueue('aName');
-
- $topic->setAutoDelete(false);
- $this->assertFalse($topic->isAutoDelete());
-
- $topic->setAutoDelete(true);
- $this->assertTrue($topic->isAutoDelete());
- }
-
- public function testShouldAllowGetPreviouslySetNoWait()
- {
- $topic = new AmqpQueue('aName');
-
- $topic->setNoWait(false);
- $this->assertFalse($topic->isNoWait());
-
- $topic->setNoWait(true);
- $this->assertTrue($topic->isNoWait());
- }
-
- public function testShouldAllowGetPreviouslySetArguments()
- {
- $queue = new AmqpQueue('aName');
-
- $queue->setArguments(['foo' => 'fooVal', 'bar' => 'barVal']);
-
- $this->assertSame(['foo' => 'fooVal', 'bar' => 'barVal'], $queue->getArguments());
- }
-
- public function testShouldAllowGetPreviouslySetTicket()
- {
- $topic = new AmqpQueue('aName');
-
- //guard
- $this->assertSame(null, $topic->getTicket());
-
- $topic->setTicket('ticket');
-
- $this->assertSame('ticket', $topic->getTicket());
- }
-
- public function testShouldAllowGetPreviouslySetConsumerTag()
- {
- $topic = new AmqpQueue('aName');
-
- //guard
- $this->assertSame(null, $topic->getConsumerTag());
-
- $topic->setConsumerTag('consumer-tag');
-
- $this->assertSame('consumer-tag', $topic->getConsumerTag());
- }
-
- public function testShouldAllowGetPreviouslySetNoLocal()
- {
- $topic = new AmqpQueue('aName');
-
- $topic->setNoLocal(false);
- $this->assertFalse($topic->isNoLocal());
-
- $topic->setNoLocal(true);
- $this->assertTrue($topic->isNoLocal());
- }
-
- public function testShouldAllowGetPreviouslySetNoAck()
- {
- $topic = new AmqpQueue('aName');
-
- $topic->setNoAck(false);
- $this->assertFalse($topic->isNoAck());
-
- $topic->setNoAck(true);
- $this->assertTrue($topic->isNoAck());
- }
-}
diff --git a/pkg/amqp-lib/Tests/AmqpTopicTest.php b/pkg/amqp-lib/Tests/AmqpTopicTest.php
deleted file mode 100644
index 2e4649639..000000000
--- a/pkg/amqp-lib/Tests/AmqpTopicTest.php
+++ /dev/null
@@ -1,116 +0,0 @@
-assertSame('direct', $topic->getType());
- }
-
- public function testShouldAllowGetPreviouslySetType()
- {
- $topic = new AmqpTopic('aName');
-
- $topic->setType('fanout');
-
- $this->assertSame('fanout', $topic->getType());
- }
-
- public function testShouldAllowGetPreviouslySetPassive()
- {
- $topic = new AmqpTopic('aName');
-
- $topic->setPassive(false);
- $this->assertFalse($topic->isPassive());
-
- $topic->setPassive(true);
- $this->assertTrue($topic->isPassive());
- }
-
- public function testShouldAllowGetPreviouslySetDurable()
- {
- $topic = new AmqpTopic('aName');
-
- $topic->setDurable(false);
- $this->assertFalse($topic->isDurable());
-
- $topic->setDurable(true);
- $this->assertTrue($topic->isDurable());
- }
-
- public function testShouldAllowGetPreviouslySetAutoDelete()
- {
- $topic = new AmqpTopic('aName');
-
- $topic->setAutoDelete(false);
- $this->assertFalse($topic->isAutoDelete());
-
- $topic->setAutoDelete(true);
- $this->assertTrue($topic->isAutoDelete());
- }
-
- public function testShouldAllowGetPreviouslySetInternal()
- {
- $topic = new AmqpTopic('aName');
-
- $topic->setInternal(false);
- $this->assertFalse($topic->isInternal());
-
- $topic->setInternal(true);
- $this->assertTrue($topic->isInternal());
- }
-
- public function testShouldAllowGetPreviouslySetNoWait()
- {
- $topic = new AmqpTopic('aName');
-
- $topic->setNoWait(false);
- $this->assertFalse($topic->isNoWait());
-
- $topic->setNoWait(true);
- $this->assertTrue($topic->isNoWait());
- }
-
- public function testShouldAllowGetPreviouslySetArguments()
- {
- $topic = new AmqpTopic('aName');
-
- $topic->setArguments(['foo' => 'fooVal', 'bar' => 'barVal']);
-
- $this->assertSame(['foo' => 'fooVal', 'bar' => 'barVal'], $topic->getArguments());
- }
-
- public function testShouldAllowGetPreviouslySetTicket()
- {
- $topic = new AmqpTopic('aName');
-
- //guard
- $this->assertSame(null, $topic->getTicket());
-
- $topic->setTicket('ticket');
-
- $this->assertSame('ticket', $topic->getTicket());
- }
-
- public function testShouldAllowGetPreviouslySetRoutingKey()
- {
- $topic = new AmqpTopic('aName');
-
- //guard
- $this->assertSame(null, $topic->getRoutingKey());
-
- $topic->setRoutingKey('theRoutingKey');
-
- $this->assertSame('theRoutingKey', $topic->getRoutingKey());
- }
-}
diff --git a/pkg/amqp-lib/Tests/BufferTest.php b/pkg/amqp-lib/Tests/BufferTest.php
index 981ff2b16..bebe435cb 100644
--- a/pkg/amqp-lib/Tests/BufferTest.php
+++ b/pkg/amqp-lib/Tests/BufferTest.php
@@ -2,8 +2,8 @@
namespace Enqueue\AmqpLib\Tests;
-use Enqueue\AmqpLib\AmqpMessage;
use Enqueue\AmqpLib\Buffer;
+use Interop\Amqp\Impl\AmqpMessage;
use PHPUnit\Framework\TestCase;
class BufferTest extends TestCase
diff --git a/pkg/amqp-lib/Tests/Spec/AmqpContextTest.php b/pkg/amqp-lib/Tests/Spec/AmqpContextTest.php
index 087336d5a..5e3d8bb8e 100644
--- a/pkg/amqp-lib/Tests/Spec/AmqpContextTest.php
+++ b/pkg/amqp-lib/Tests/Spec/AmqpContextTest.php
@@ -20,6 +20,6 @@ protected function createContext()
->willReturn($channel)
;
- return new AmqpContext($con, '');
+ return new AmqpContext($con);
}
}
diff --git a/pkg/amqp-lib/Tests/Spec/AmqpMessageTest.php b/pkg/amqp-lib/Tests/Spec/AmqpMessageTest.php
deleted file mode 100644
index 57b93cbd0..000000000
--- a/pkg/amqp-lib/Tests/Spec/AmqpMessageTest.php
+++ /dev/null
@@ -1,17 +0,0 @@
-setDelayStrategy(new RabbitMqDelayPluginDelayStrategy());
+
+ return $factory->createContext();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function createQueue(PsrContext $context, $queueName)
+ {
+ $queue = parent::createQueue($context, $queueName);
+
+ $context->declareQueue($queue);
+
+ return $queue;
+ }
+}
diff --git a/pkg/amqp-lib/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest.php b/pkg/amqp-lib/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest.php
new file mode 100644
index 000000000..ca2284443
--- /dev/null
+++ b/pkg/amqp-lib/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest.php
@@ -0,0 +1,37 @@
+setDelayStrategy(new RabbitMqDlxDelayStrategy());
+
+ return $factory->createContext();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function createQueue(PsrContext $context, $queueName)
+ {
+ $queue = parent::createQueue($context, $queueName);
+
+ $context->declareQueue($queue);
+
+ return $queue;
+ }
+}
diff --git a/pkg/amqp-lib/Tests/Spec/AmqpSendAndReceivePriorityMessagesFromQueueTest.php b/pkg/amqp-lib/Tests/Spec/AmqpSendAndReceivePriorityMessagesFromQueueTest.php
new file mode 100644
index 000000000..881c8dd8c
--- /dev/null
+++ b/pkg/amqp-lib/Tests/Spec/AmqpSendAndReceivePriorityMessagesFromQueueTest.php
@@ -0,0 +1,40 @@
+createContext();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param AmqpContext $context
+ */
+ protected function createQueue(PsrContext $context, $queueName)
+ {
+ $queue = $context->createQueue($queueName);
+ $queue->setArguments(['x-max-priority' => 10]);
+
+ $context->declareQueue($queue);
+ $context->purgeQueue($queue);
+
+ return $queue;
+ }
+}
diff --git a/pkg/amqp-lib/Tests/Spec/AmqpSendAndReceiveTimeToLiveMessagesFromQueueTest.php b/pkg/amqp-lib/Tests/Spec/AmqpSendAndReceiveTimeToLiveMessagesFromQueueTest.php
new file mode 100644
index 000000000..b62882fad
--- /dev/null
+++ b/pkg/amqp-lib/Tests/Spec/AmqpSendAndReceiveTimeToLiveMessagesFromQueueTest.php
@@ -0,0 +1,38 @@
+createContext();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param AmqpContext $context
+ */
+ protected function createQueue(PsrContext $context, $queueName)
+ {
+ $queue = $context->createQueue($queueName);
+ $context->declareQueue($queue);
+ $context->purgeQueue($queue);
+
+ return $queue;
+ }
+}
diff --git a/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveFromQueueTest.php b/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveFromQueueTest.php
index c2f4626fc..3a31b46cf 100644
--- a/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveFromQueueTest.php
+++ b/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveFromQueueTest.php
@@ -31,7 +31,7 @@ protected function createQueue(PsrContext $context, $queueName)
{
$queue = $context->createQueue($queueName);
$context->declareQueue($queue);
- $context->purge($queue);
+ $context->purgeQueue($queue);
return $queue;
}
diff --git a/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveFromTopicTest.php b/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveFromTopicTest.php
index dfce6ccdf..d1e78e900 100644
--- a/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveFromTopicTest.php
+++ b/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveFromTopicTest.php
@@ -4,6 +4,7 @@
use Enqueue\AmqpLib\AmqpConnectionFactory;
use Enqueue\AmqpLib\AmqpContext;
+use Interop\Amqp\AmqpTopic;
use Interop\Queue\PsrContext;
use Interop\Queue\Spec\SendToAndReceiveFromTopicSpec;
@@ -30,8 +31,8 @@ protected function createContext()
protected function createTopic(PsrContext $context, $topicName)
{
$topic = $context->createTopic($topicName);
- $topic->setType('fanout');
- $topic->setDurable(true);
+ $topic->setType(AmqpTopic::TYPE_FANOUT);
+ $topic->addFlag(AmqpTopic::FLAG_DURABLE);
$context->declareTopic($topic);
return $topic;
diff --git a/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveNoWaitFromQueueTest.php b/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveNoWaitFromQueueTest.php
index b4db35c10..d36b168fc 100644
--- a/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveNoWaitFromQueueTest.php
+++ b/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveNoWaitFromQueueTest.php
@@ -31,7 +31,7 @@ protected function createQueue(PsrContext $context, $queueName)
{
$queue = $context->createQueue($queueName);
$context->declareQueue($queue);
- $context->purge($queue);
+ $context->purgeQueue($queue);
return $queue;
}
diff --git a/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveNoWaitFromTopicTest.php b/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveNoWaitFromTopicTest.php
index a50fc4c67..d237895e0 100644
--- a/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveNoWaitFromTopicTest.php
+++ b/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveNoWaitFromTopicTest.php
@@ -4,6 +4,7 @@
use Enqueue\AmqpLib\AmqpConnectionFactory;
use Enqueue\AmqpLib\AmqpContext;
+use Interop\Amqp\AmqpTopic;
use Interop\Queue\PsrContext;
use Interop\Queue\Spec\SendToAndReceiveNoWaitFromTopicSpec;
@@ -30,8 +31,8 @@ protected function createContext()
protected function createTopic(PsrContext $context, $topicName)
{
$topic = $context->createTopic($topicName);
- $topic->setType('fanout');
- $topic->setDurable(true);
+ $topic->setType(AmqpTopic::TYPE_FANOUT);
+ $topic->addFlag(AmqpTopic::FLAG_DURABLE);
$context->declareTopic($topic);
return $topic;
diff --git a/pkg/amqp-lib/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicConsumeMethodTest.php b/pkg/amqp-lib/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicConsumeMethodTest.php
index 8af921998..5947a7cd1 100644
--- a/pkg/amqp-lib/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicConsumeMethodTest.php
+++ b/pkg/amqp-lib/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicConsumeMethodTest.php
@@ -4,6 +4,8 @@
use Enqueue\AmqpLib\AmqpConnectionFactory;
use Enqueue\AmqpLib\AmqpContext;
+use Interop\Amqp\AmqpTopic;
+use Interop\Amqp\Impl\AmqpBind;
use Interop\Queue\PsrContext;
use Interop\Queue\Spec\SendToTopicAndReceiveFromQueueSpec;
@@ -33,9 +35,9 @@ protected function createQueue(PsrContext $context, $queueName)
$queue = $context->createQueue($queueName);
$context->declareQueue($queue);
- $context->purge($queue);
+ $context->purgeQueue($queue);
- $context->bind($context->createTopic($queueName), $queue);
+ $context->bind(new AmqpBind($context->createTopic($queueName), $queue));
return $queue;
}
@@ -50,8 +52,8 @@ protected function createTopic(PsrContext $context, $topicName)
$topicName .= '_basic_consume';
$topic = $context->createTopic($topicName);
- $topic->setType('fanout');
- $topic->setDurable(true);
+ $topic->setType(AmqpTopic::TYPE_FANOUT);
+ $topic->addFlag(AmqpTopic::FLAG_DURABLE);
$context->declareTopic($topic);
return $topic;
diff --git a/pkg/amqp-lib/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicGetMethodTest.php b/pkg/amqp-lib/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicGetMethodTest.php
index 28192181f..c5512ef35 100644
--- a/pkg/amqp-lib/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicGetMethodTest.php
+++ b/pkg/amqp-lib/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicGetMethodTest.php
@@ -4,6 +4,8 @@
use Enqueue\AmqpLib\AmqpConnectionFactory;
use Enqueue\AmqpLib\AmqpContext;
+use Interop\Amqp\AmqpTopic;
+use Interop\Amqp\Impl\AmqpBind;
use Interop\Queue\PsrContext;
use Interop\Queue\Spec\SendToTopicAndReceiveFromQueueSpec;
@@ -31,9 +33,9 @@ protected function createQueue(PsrContext $context, $queueName)
{
$queue = $context->createQueue($queueName);
$context->declareQueue($queue);
- $context->purge($queue);
+ $context->purgeQueue($queue);
- $context->bind($context->createTopic($queueName), $queue);
+ $context->bind(new AmqpBind($context->createTopic($queueName), $queue));
return $queue;
}
@@ -46,8 +48,8 @@ protected function createQueue(PsrContext $context, $queueName)
protected function createTopic(PsrContext $context, $topicName)
{
$topic = $context->createTopic($topicName);
- $topic->setType('fanout');
- $topic->setDurable(true);
+ $topic->setType(AmqpTopic::TYPE_FANOUT);
+ $topic->addFlag(AmqpTopic::FLAG_DURABLE);
$context->declareTopic($topic);
return $topic;
diff --git a/pkg/amqp-lib/Tests/Spec/AmqpSendToTopicAndReceiveNoWaitFromQueueTest.php b/pkg/amqp-lib/Tests/Spec/AmqpSendToTopicAndReceiveNoWaitFromQueueTest.php
index 6b4b1906b..783496ffa 100644
--- a/pkg/amqp-lib/Tests/Spec/AmqpSendToTopicAndReceiveNoWaitFromQueueTest.php
+++ b/pkg/amqp-lib/Tests/Spec/AmqpSendToTopicAndReceiveNoWaitFromQueueTest.php
@@ -4,6 +4,8 @@
use Enqueue\AmqpLib\AmqpConnectionFactory;
use Enqueue\AmqpLib\AmqpContext;
+use Interop\Amqp\AmqpTopic;
+use Interop\Amqp\Impl\AmqpBind;
use Interop\Queue\PsrContext;
use Interop\Queue\Spec\SendToTopicAndReceiveNoWaitFromQueueSpec;
@@ -31,9 +33,9 @@ protected function createQueue(PsrContext $context, $queueName)
{
$queue = $context->createQueue($queueName);
$context->declareQueue($queue);
- $context->purge($queue);
+ $context->purgeQueue($queue);
- $context->bind($context->createTopic($queueName), $queue);
+ $context->bind(new AmqpBind($context->createTopic($queueName), $queue));
return $queue;
}
@@ -46,8 +48,8 @@ protected function createQueue(PsrContext $context, $queueName)
protected function createTopic(PsrContext $context, $topicName)
{
$topic = $context->createTopic($topicName);
- $topic->setType('fanout');
- $topic->setDurable(true);
+ $topic->setType(AmqpTopic::TYPE_FANOUT);
+ $topic->addFlag(AmqpTopic::FLAG_DURABLE);
$context->declareTopic($topic);
return $topic;
diff --git a/pkg/amqp-lib/Tests/Spec/AmqpTopicTest.php b/pkg/amqp-lib/Tests/Spec/AmqpTopicTest.php
deleted file mode 100644
index 89717f01f..000000000
--- a/pkg/amqp-lib/Tests/Spec/AmqpTopicTest.php
+++ /dev/null
@@ -1,14 +0,0 @@
-assertClassImplements(TransportFactoryInterface::class, AmqpLibTransportFactory::class);
+ }
+
+ public function testCouldBeConstructedWithDefaultName()
+ {
+ $transport = new AmqpLibTransportFactory();
+
+ $this->assertEquals('amqp_lib', $transport->getName());
+ }
+
+ public function testCouldBeConstructedWithCustomName()
+ {
+ $transport = new AmqpLibTransportFactory('theCustomName');
+
+ $this->assertEquals('theCustomName', $transport->getName());
+ }
+
+ public function testShouldAllowAddConfiguration()
+ {
+ $transport = new AmqpLibTransportFactory();
+ $tb = new TreeBuilder();
+ $rootNode = $tb->root('foo');
+
+ $transport->addConfiguration($rootNode);
+ $processor = new Processor();
+ $config = $processor->process($tb->buildTree(), []);
+
+ $this->assertEquals([
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'vhost' => '/',
+ 'lazy' => true,
+ 'receive_method' => 'basic_get',
+ 'connection_timeout' => 3.0,
+ 'read_write_timeout' => 3.0,
+ 'read_timeout' => 3,
+ 'write_timeout' => 3,
+ 'stream' => true,
+ 'insist' => false,
+ 'keepalive' => false,
+ 'heartbeat' => 0,
+ ], $config);
+ }
+
+ public function testShouldAllowAddConfigurationAsString()
+ {
+ $transport = new AmqpLibTransportFactory();
+ $tb = new TreeBuilder();
+ $rootNode = $tb->root('foo');
+
+ $transport->addConfiguration($rootNode);
+ $processor = new Processor();
+ $config = $processor->process($tb->buildTree(), ['amqpDSN']);
+
+ $this->assertEquals([
+ 'dsn' => 'amqpDSN',
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'vhost' => '/',
+ 'lazy' => true,
+ 'receive_method' => 'basic_get',
+ 'connection_timeout' => 3.0,
+ 'read_write_timeout' => 3.0,
+ 'read_timeout' => 3,
+ 'write_timeout' => 3,
+ 'stream' => true,
+ 'insist' => false,
+ 'keepalive' => false,
+ 'heartbeat' => 0,
+ ], $config);
+ }
+
+ public function testThrowIfInvalidReceiveMethodIsSet()
+ {
+ $transport = new AmqpLibTransportFactory();
+ $tb = new TreeBuilder();
+ $rootNode = $tb->root('foo');
+
+ $transport->addConfiguration($rootNode);
+ $processor = new Processor();
+
+ $this->expectException(InvalidConfigurationException::class);
+ $this->expectExceptionMessage('The value "anInvalidMethod" is not allowed for path "foo.receive_method". Permissible values: "basic_get", "basic_consume"');
+ $processor->process($tb->buildTree(), [[
+ 'receive_method' => 'anInvalidMethod',
+ ]]);
+ }
+
+ public function testShouldAllowChangeReceiveMethod()
+ {
+ $transport = new AmqpLibTransportFactory();
+ $tb = new TreeBuilder();
+ $rootNode = $tb->root('foo');
+
+ $transport->addConfiguration($rootNode);
+ $processor = new Processor();
+ $config = $processor->process($tb->buildTree(), [[
+ 'receive_method' => 'basic_consume',
+ ]]);
+
+ $this->assertEquals([
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'vhost' => '/',
+ 'lazy' => true,
+ 'receive_method' => 'basic_consume',
+ 'connection_timeout' => 3.0,
+ 'read_write_timeout' => 3.0,
+ 'read_timeout' => 3,
+ 'write_timeout' => 3,
+ 'stream' => true,
+ 'insist' => false,
+ 'keepalive' => false,
+ 'heartbeat' => 0,
+ ], $config);
+ }
+
+ public function testShouldCreateConnectionFactory()
+ {
+ $container = new ContainerBuilder();
+
+ $transport = new AmqpLibTransportFactory();
+
+ $serviceId = $transport->createConnectionFactory($container, [
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'vhost' => '/',
+ ]);
+
+ $this->assertTrue($container->hasDefinition($serviceId));
+ $factory = $container->getDefinition($serviceId);
+ $this->assertEquals(AmqpConnectionFactory::class, $factory->getClass());
+ $this->assertSame([[
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'vhost' => '/',
+ ]], $factory->getArguments());
+ }
+
+ public function testShouldCreateConnectionFactoryFromDsnString()
+ {
+ $container = new ContainerBuilder();
+
+ $transport = new AmqpLibTransportFactory();
+
+ $serviceId = $transport->createConnectionFactory($container, [
+ 'dsn' => 'theConnectionDSN',
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'vhost' => '/',
+ ]);
+
+ $this->assertTrue($container->hasDefinition($serviceId));
+ $factory = $container->getDefinition($serviceId);
+ $this->assertEquals(AmqpConnectionFactory::class, $factory->getClass());
+ $this->assertSame(['theConnectionDSN'], $factory->getArguments());
+ }
+
+ public function testShouldCreateContext()
+ {
+ $container = new ContainerBuilder();
+
+ $transport = new AmqpLibTransportFactory();
+
+ $serviceId = $transport->createContext($container, [
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'vhost' => '/',
+ ]);
+
+ $this->assertEquals('enqueue.transport.amqp_lib.context', $serviceId);
+ $this->assertTrue($container->hasDefinition($serviceId));
+
+ $context = $container->getDefinition('enqueue.transport.amqp_lib.context');
+ $this->assertInstanceOf(Reference::class, $context->getFactory()[0]);
+ $this->assertEquals('enqueue.transport.amqp_lib.connection_factory', (string) $context->getFactory()[0]);
+ $this->assertEquals('createContext', $context->getFactory()[1]);
+ }
+
+ public function testShouldCreateDriver()
+ {
+ $container = new ContainerBuilder();
+
+ $transport = new AmqpLibTransportFactory();
+
+ $serviceId = $transport->createDriver($container, []);
+
+ $this->assertEquals('enqueue.client.amqp_lib.driver', $serviceId);
+ $this->assertTrue($container->hasDefinition($serviceId));
+
+ $driver = $container->getDefinition($serviceId);
+ $this->assertSame(AmqpDriver::class, $driver->getClass());
+
+ $this->assertInstanceOf(Reference::class, $driver->getArgument(0));
+ $this->assertEquals('enqueue.transport.amqp_lib.context', (string) $driver->getArgument(0));
+
+ $this->assertInstanceOf(Reference::class, $driver->getArgument(1));
+ $this->assertEquals('enqueue.client.config', (string) $driver->getArgument(1));
+
+ $this->assertInstanceOf(Reference::class, $driver->getArgument(2));
+ $this->assertEquals('enqueue.client.meta.queue_meta_registry', (string) $driver->getArgument(2));
+ }
+}
diff --git a/pkg/amqp-lib/Tests/Symfony/RabbitMqAmqpLibTransportFactoryTest.php b/pkg/amqp-lib/Tests/Symfony/RabbitMqAmqpLibTransportFactoryTest.php
new file mode 100644
index 000000000..22b1b4354
--- /dev/null
+++ b/pkg/amqp-lib/Tests/Symfony/RabbitMqAmqpLibTransportFactoryTest.php
@@ -0,0 +1,144 @@
+assertClassImplements(TransportFactoryInterface::class, RabbitMqAmqpLibTransportFactory::class);
+ }
+
+ public function testShouldExtendAmqpTransportFactoryClass()
+ {
+ $this->assertClassExtends(AmqpLibTransportFactory::class, RabbitMqAmqpLibTransportFactory::class);
+ }
+
+ public function testCouldBeConstructedWithDefaultName()
+ {
+ $transport = new RabbitMqAmqpLibTransportFactory();
+
+ $this->assertEquals('rabbitmq_amqp_lib', $transport->getName());
+ }
+
+ public function testCouldBeConstructedWithCustomName()
+ {
+ $transport = new RabbitMqAmqpLibTransportFactory('theCustomName');
+
+ $this->assertEquals('theCustomName', $transport->getName());
+ }
+
+ public function testShouldAllowAddConfiguration()
+ {
+ $transport = new RabbitMqAmqpLibTransportFactory();
+ $tb = new TreeBuilder();
+ $rootNode = $tb->root('foo');
+
+ $transport->addConfiguration($rootNode);
+ $processor = new Processor();
+ $config = $processor->process($tb->buildTree(), []);
+
+ $this->assertEquals([
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'vhost' => '/',
+ 'delay_plugin_installed' => false,
+ 'lazy' => true,
+ 'receive_method' => 'basic_get',
+ 'connection_timeout' => 3.0,
+ 'read_write_timeout' => 3.0,
+ 'read_timeout' => 3,
+ 'write_timeout' => 3,
+ 'stream' => true,
+ 'insist' => false,
+ 'keepalive' => false,
+ 'heartbeat' => 0,
+ ], $config);
+ }
+
+ public function testShouldCreateConnectionFactory()
+ {
+ $container = new ContainerBuilder();
+
+ $transport = new RabbitMqAmqpLibTransportFactory();
+
+ $serviceId = $transport->createConnectionFactory($container, [
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'vhost' => '/',
+ 'persisted' => false,
+ 'delay_plugin_installed' => false,
+ ]);
+
+ $this->assertTrue($container->hasDefinition($serviceId));
+ $factory = $container->getDefinition($serviceId);
+ $this->assertEquals(AmqpConnectionFactory::class, $factory->getClass());
+ $this->assertSame([[
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'vhost' => '/',
+ 'persisted' => false,
+ 'delay_plugin_installed' => false,
+ ]], $factory->getArguments());
+ }
+
+ public function testShouldCreateContext()
+ {
+ $container = new ContainerBuilder();
+
+ $transport = new RabbitMqAmqpLibTransportFactory();
+
+ $serviceId = $transport->createContext($container, [
+ 'host' => 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'vhost' => '/',
+ 'persisted' => false,
+ 'delay_plugin_installed' => false,
+ ]);
+
+ $this->assertEquals('enqueue.transport.rabbitmq_amqp_lib.context', $serviceId);
+ $this->assertTrue($container->hasDefinition($serviceId));
+
+ $context = $container->getDefinition('enqueue.transport.rabbitmq_amqp_lib.context');
+ $this->assertInstanceOf(Reference::class, $context->getFactory()[0]);
+ $this->assertEquals('enqueue.transport.rabbitmq_amqp_lib.connection_factory', (string) $context->getFactory()[0]);
+ $this->assertEquals('createContext', $context->getFactory()[1]);
+ }
+
+ public function testShouldCreateDriver()
+ {
+ $container = new ContainerBuilder();
+
+ $transport = new RabbitMqAmqpLibTransportFactory();
+
+ $serviceId = $transport->createDriver($container, []);
+
+ $this->assertEquals('enqueue.client.rabbitmq_amqp_lib.driver', $serviceId);
+ $this->assertTrue($container->hasDefinition($serviceId));
+
+ $driver = $container->getDefinition($serviceId);
+ $this->assertSame(RabbitMqDriver::class, $driver->getClass());
+ }
+}
diff --git a/pkg/amqp-lib/composer.json b/pkg/amqp-lib/composer.json
index 16c83929f..efb9a200e 100644
--- a/pkg/amqp-lib/composer.json
+++ b/pkg/amqp-lib/composer.json
@@ -13,14 +13,16 @@
"require": {
"php": ">=5.6",
"php-amqplib/php-amqplib": "^2.7@dev",
- "queue-interop/queue-interop": "^0.5@dev",
+ "queue-interop/queue-interop": "^0.6@dev",
+ "queue-interop/amqp-interop": "^0.6@dev",
+ "enqueue/amqp-tools": "^0.7@dev",
"psr/log": "^1"
},
"require-dev": {
"phpunit/phpunit": "~5.4.0",
- "enqueue/test": "^0.6@dev",
- "enqueue/enqueue": "^0.6@dev",
- "enqueue/null": "^0.6@dev",
+ "enqueue/test": "^0.7@dev",
+ "enqueue/enqueue": "^0.7@dev",
+ "enqueue/null": "^0.7@dev",
"queue-interop/queue-spec": "^0.5@dev",
"symfony/dependency-injection": "^2.8|^3",
"symfony/config": "^2.8|^3"
@@ -37,7 +39,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
- "dev-master": "0.6.x-dev"
+ "dev-master": "0.7.x-dev"
}
}
}
diff --git a/pkg/amqp-lib/examples/consume.php b/pkg/amqp-lib/examples/consume.php
new file mode 100644
index 000000000..9af598bc5
--- /dev/null
+++ b/pkg/amqp-lib/examples/consume.php
@@ -0,0 +1,51 @@
+ getenv('SYMFONY__RABBITMQ__HOST'),
+ 'port' => getenv('SYMFONY__RABBITMQ__AMQP__PORT'),
+ 'user' => getenv('SYMFONY__RABBITMQ__USER'),
+ 'pass' => getenv('SYMFONY__RABBITMQ__PASSWORD'),
+ 'vhost' => getenv('SYMFONY__RABBITMQ__VHOST'),
+ 'receive_method' => 'basic_consume',
+];
+
+$factory = new AmqpConnectionFactory($config);
+$context = $factory->createContext();
+
+$queue = $context->createQueue('foo');
+$fooConsumer = $context->createConsumer($queue);
+
+$queue = $context->createQueue('bar');
+$barConsumer = $context->createConsumer($queue);
+
+$consumers = [$fooConsumer, $barConsumer];
+
+$consumer = $consumers[rand(0, 1)];
+
+while (true) {
+ if ($m = $consumer->receive(100)) {
+ echo $m->getBody(), PHP_EOL;
+ $consumer->acknowledge($m);
+ }
+
+ $consumer = $consumers[rand(0, 1)];
+}
+
+echo 'Done'."\n";
diff --git a/pkg/amqp-lib/examples/produce.php b/pkg/amqp-lib/examples/produce.php
new file mode 100644
index 000000000..4f9a83192
--- /dev/null
+++ b/pkg/amqp-lib/examples/produce.php
@@ -0,0 +1,65 @@
+ getenv('SYMFONY__RABBITMQ__HOST'),
+ 'port' => getenv('SYMFONY__RABBITMQ__AMQP__PORT'),
+ 'user' => getenv('SYMFONY__RABBITMQ__USER'),
+ 'pass' => getenv('SYMFONY__RABBITMQ__PASSWORD'),
+ 'vhost' => getenv('SYMFONY__RABBITMQ__VHOST'),
+];
+
+$factory = new AmqpConnectionFactory($config);
+$context = $factory->createContext();
+
+$topic = $context->createTopic('test.amqp.ext');
+$topic->addFlag(AmqpTopic::FLAG_DURABLE);
+$topic->setType(AmqpTopic::TYPE_FANOUT);
+//$topic->setArguments(['alternate-exchange' => 'foo']);
+
+$context->deleteTopic($topic);
+$context->declareTopic($topic);
+
+$fooQueue = $context->createQueue('foo');
+$fooQueue->addFlag(AmqpQueue::FLAG_DURABLE);
+
+$context->deleteQueue($fooQueue);
+$context->declareQueue($fooQueue);
+
+$context->bind(new AmqpBind($topic, $fooQueue));
+
+$barQueue = $context->createQueue('bar');
+$barQueue->addFlag(AmqpQueue::FLAG_DURABLE);
+
+$context->deleteQueue($barQueue);
+$context->declareQueue($barQueue);
+
+$context->bind(new AmqpBind($topic, $barQueue));
+
+$message = $context->createMessage('Hello Bar!');
+
+while (true) {
+ $context->createProducer()->send($fooQueue, $message);
+ $context->createProducer()->send($barQueue, $message);
+}
+
+echo 'Done'."\n";
diff --git a/pkg/amqp-lib/tutorial/emit_log.php b/pkg/amqp-lib/tutorial/emit_log.php
new file mode 100644
index 000000000..bc9fd4c2b
--- /dev/null
+++ b/pkg/amqp-lib/tutorial/emit_log.php
@@ -0,0 +1,33 @@
+ 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+];
+
+$connection = new AmqpConnectionFactory($config);
+$context = $connection->createContext();
+
+$topic = $context->createTopic('logs');
+$topic->setType(AmqpTopic::TYPE_FANOUT);
+
+$context->declareTopic($topic);
+
+$data = implode(' ', array_slice($argv, 1));
+if (empty($data)) {
+ $data = 'info: Hello World!';
+}
+$message = $context->createMessage($data);
+
+$context->createProducer()->send($topic, $message);
+
+echo ' [x] Sent ', $data, "\n";
+
+$context->close();
diff --git a/pkg/amqp-lib/tutorial/emit_log_direct.php b/pkg/amqp-lib/tutorial/emit_log_direct.php
new file mode 100644
index 000000000..87e890854
--- /dev/null
+++ b/pkg/amqp-lib/tutorial/emit_log_direct.php
@@ -0,0 +1,37 @@
+ 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+];
+
+$connection = new AmqpConnectionFactory($config);
+$context = $connection->createContext();
+
+$topic = $context->createTopic('direct_logs');
+$topic->setType(AmqpTopic::TYPE_DIRECT);
+
+$context->declareTopic($topic);
+
+$severity = isset($argv[1]) && !empty($argv[1]) ? $argv[1] : 'info';
+
+$data = implode(' ', array_slice($argv, 2));
+if (empty($data)) {
+ $data = 'Hello World!';
+}
+
+$message = $context->createMessage($data);
+$message->setRoutingKey($severity);
+
+$context->createProducer()->send($topic, $message);
+
+echo ' [x] Sent ',$severity,':',$data," \n";
+
+$context->close();
diff --git a/pkg/amqp-lib/tutorial/emit_log_topic.php b/pkg/amqp-lib/tutorial/emit_log_topic.php
new file mode 100644
index 000000000..ab181865c
--- /dev/null
+++ b/pkg/amqp-lib/tutorial/emit_log_topic.php
@@ -0,0 +1,37 @@
+ 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+];
+
+$connection = new AmqpConnectionFactory($config);
+$context = $connection->createContext();
+
+$topic = $context->createTopic('topic_logs');
+$topic->setType(AmqpTopic::TYPE_TOPIC);
+
+$context->declareTopic($topic);
+
+$routing_key = isset($argv[1]) && !empty($argv[1]) ? $argv[1] : 'anonymous.info';
+
+$data = implode(' ', array_slice($argv, 2));
+if (empty($data)) {
+ $data = 'Hello World!';
+}
+
+$message = $context->createMessage($data);
+$message->setRoutingKey($routing_key);
+
+$context->createProducer()->send($topic, $message);
+
+echo ' [x] Sent ',$routing_key,':',$data," \n";
+
+$context->close();
diff --git a/pkg/amqp-lib/tutorial/new_task.php b/pkg/amqp-lib/tutorial/new_task.php
new file mode 100644
index 000000000..5c3c836f8
--- /dev/null
+++ b/pkg/amqp-lib/tutorial/new_task.php
@@ -0,0 +1,35 @@
+ 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+];
+
+$connection = new AmqpConnectionFactory($config);
+$context = $connection->createContext();
+
+$queue = $context->createQueue('task_queue');
+$queue->addFlag(AmqpQueue::FLAG_DURABLE);
+
+$context->declareQueue($queue);
+
+$data = implode(' ', array_slice($argv, 1));
+if (empty($data)) {
+ $data = 'Hello World!';
+}
+$message = $context->createMessage($data);
+$message->setDeliveryMode(AmqpMessage::DELIVERY_MODE_PERSISTENT);
+
+$context->createProducer()->send($queue, $message);
+
+echo ' [x] Sent ', $data, "\n";
+
+$context->close();
diff --git a/pkg/amqp-lib/tutorial/receive.php b/pkg/amqp-lib/tutorial/receive.php
new file mode 100644
index 000000000..337421020
--- /dev/null
+++ b/pkg/amqp-lib/tutorial/receive.php
@@ -0,0 +1,33 @@
+ 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'receive_method' => 'basic_consume',
+];
+
+$connection = new AmqpConnectionFactory($config);
+$context = $connection->createContext();
+
+$queue = $context->createQueue('hello');
+$context->declareQueue($queue);
+
+$consumer = $context->createConsumer($queue);
+$consumer->addFlag(AmqpConsumer::FLAG_NOACK);
+
+echo ' [*] Waiting for messages. To exit press CTRL+C', "\n";
+
+while (true) {
+ if ($message = $consumer->receive()) {
+ echo ' [x] Received ', $message->getBody(), "\n";
+ }
+}
+
+$context->close();
diff --git a/pkg/amqp-lib/tutorial/receive_logs.php b/pkg/amqp-lib/tutorial/receive_logs.php
new file mode 100644
index 000000000..bf68bf1fb
--- /dev/null
+++ b/pkg/amqp-lib/tutorial/receive_logs.php
@@ -0,0 +1,41 @@
+ 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'receive_method' => 'basic_consume',
+];
+
+$connection = new AmqpConnectionFactory($config);
+$context = $connection->createContext();
+
+$topic = $context->createTopic('logs');
+$topic->setType(AmqpTopic::TYPE_FANOUT);
+
+$context->declareTopic($topic);
+
+$queue = $context->createTemporaryQueue();
+
+$context->bind(new AmqpBind($topic, $queue));
+
+$consumer = $context->createConsumer($queue);
+$consumer->addFlag(AmqpConsumer::FLAG_NOACK);
+
+echo ' [*] Waiting for logs. To exit press CTRL+C', "\n";
+
+while (true) {
+ if ($message = $consumer->receive()) {
+ echo ' [x] ', $message->getBody(), "\n";
+ }
+}
+
+$context->close();
diff --git a/pkg/amqp-lib/tutorial/receive_logs_direct.php b/pkg/amqp-lib/tutorial/receive_logs_direct.php
new file mode 100644
index 000000000..699d5108f
--- /dev/null
+++ b/pkg/amqp-lib/tutorial/receive_logs_direct.php
@@ -0,0 +1,49 @@
+ 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'receive_method' => 'basic_consume',
+];
+
+$connection = new AmqpConnectionFactory($config);
+$context = $connection->createContext();
+
+$topic = $context->createTopic('direct_logs');
+$topic->setType(AmqpTopic::TYPE_DIRECT);
+
+$context->declareTopic($topic);
+
+$queue = $context->createTemporaryQueue();
+
+$severities = array_slice($argv, 1);
+if (empty($severities)) {
+ file_put_contents('php://stderr', "Usage: $argv[0] [info] [warning] [error]\n");
+ exit(1);
+}
+
+foreach ($severities as $severity) {
+ $context->bind(new AmqpBind($topic, $queue, $severity));
+}
+
+$consumer = $context->createConsumer($queue);
+$consumer->addFlag(AmqpConsumer::FLAG_NOACK);
+
+echo ' [*] Waiting for logs. To exit press CTRL+C', "\n";
+
+while (true) {
+ if ($message = $consumer->receive()) {
+ echo ' [x] '.$message->getRoutingKey().':'.$message->getBody()."\n";
+ }
+}
+
+$context->close();
diff --git a/pkg/amqp-lib/tutorial/receive_logs_topic.php b/pkg/amqp-lib/tutorial/receive_logs_topic.php
new file mode 100644
index 000000000..a149be84c
--- /dev/null
+++ b/pkg/amqp-lib/tutorial/receive_logs_topic.php
@@ -0,0 +1,49 @@
+ 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'receive_method' => 'basic_consume',
+];
+
+$connection = new AmqpConnectionFactory($config);
+$context = $connection->createContext();
+
+$topic = $context->createTopic('topic_logs');
+$topic->setType(AmqpTopic::TYPE_TOPIC);
+
+$context->declareTopic($topic);
+
+$queue = $context->createTemporaryQueue();
+
+$binding_keys = array_slice($argv, 1);
+if (empty($binding_keys)) {
+ file_put_contents('php://stderr', "Usage: $argv[0] [binding_key]\n");
+ exit(1);
+}
+
+foreach ($binding_keys as $binding_key) {
+ $context->bind(new AmqpBind($topic, $queue, $binding_key));
+}
+
+$consumer = $context->createConsumer($queue);
+$consumer->addFlag(AmqpConsumer::FLAG_NOACK);
+
+echo ' [*] Waiting for logs. To exit press CTRL+C', "\n";
+
+while (true) {
+ if ($message = $consumer->receive()) {
+ echo ' [x] '.$message->getRoutingKey().':'.$message->getBody()."\n";
+ }
+}
+
+$context->close();
diff --git a/pkg/amqp-lib/tutorial/rpc_client.php b/pkg/amqp-lib/tutorial/rpc_client.php
new file mode 100644
index 000000000..9c34510dd
--- /dev/null
+++ b/pkg/amqp-lib/tutorial/rpc_client.php
@@ -0,0 +1,56 @@
+ 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'receive_method' => 'basic_consume',
+];
+
+class FibonacciRpcClient
+{
+ /** @var \Interop\Amqp\AmqpContext */
+ private $context;
+
+ /** @var \Interop\Amqp\AmqpQueue */
+ private $callback_queue;
+
+ public function __construct(array $config)
+ {
+ $this->context = (new AmqpConnectionFactory($config))->createContext();
+ $this->callback_queue = $this->context->createTemporaryQueue();
+ }
+
+ public function call($n)
+ {
+ $corr_id = uniqid();
+
+ $message = $this->context->createMessage((string) $n);
+ $message->setCorrelationId($corr_id);
+ $message->setReplyTo($this->callback_queue->getQueueName());
+
+ $this->context->createProducer()->send(
+ $this->context->createQueue('rpc_queue'),
+ $message
+ );
+
+ $consumer = $this->context->createConsumer($this->callback_queue);
+
+ while (true) {
+ if ($message = $consumer->receive()) {
+ if ($message->getCorrelationId() == $corr_id) {
+ return (int) ($message->getBody());
+ }
+ }
+ }
+ }
+}
+
+$fibonacci_rpc = new FibonacciRpcClient($config);
+$response = $fibonacci_rpc->call(30);
+echo ' [.] Got ', $response, "\n";
diff --git a/pkg/amqp-lib/tutorial/rpc_server.php b/pkg/amqp-lib/tutorial/rpc_server.php
new file mode 100644
index 000000000..9e848dce0
--- /dev/null
+++ b/pkg/amqp-lib/tutorial/rpc_server.php
@@ -0,0 +1,54 @@
+ 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'receive_method' => 'basic_consume',
+];
+
+function fib($n)
+{
+ if ($n == 0) {
+ return 0;
+ }
+
+ if ($n == 1) {
+ return 1;
+ }
+
+ return fib($n - 1) + fib($n - 2);
+}
+
+$connection = new AmqpConnectionFactory($config);
+$context = $connection->createContext();
+$context->setQos(0, 1, false);
+
+$rpc_queue = $context->createQueue('rpc_queue');
+$context->declareQueue($rpc_queue);
+
+$consumer = $context->createConsumer($rpc_queue);
+
+echo " [x] Awaiting RPC requests\n";
+
+while (true) {
+ if ($req = $consumer->receive()) {
+ $n = (int) ($req->getBody());
+ echo ' [.] fib(', $n, ")\n";
+
+ $msg = $context->createMessage((string) fib($n));
+ $msg->setCorrelationId($req->getCorrelationId());
+
+ $reply_queue = $context->createQueue($req->getReplyTo());
+ $context->createProducer()->send($reply_queue, $msg);
+
+ $consumer->acknowledge($req);
+ }
+}
+
+$context->close();
diff --git a/pkg/amqp-lib/tutorial/send.php b/pkg/amqp-lib/tutorial/send.php
new file mode 100644
index 000000000..5f1d89b62
--- /dev/null
+++ b/pkg/amqp-lib/tutorial/send.php
@@ -0,0 +1,26 @@
+ 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+];
+
+$connection = new AmqpConnectionFactory($config);
+$context = $connection->createContext();
+
+$queue = $context->createQueue('hello');
+$context->declareQueue($queue);
+
+$message = $context->createMessage('Hello World!');
+
+$context->createProducer()->send($queue, $message);
+
+echo " [x] Sent 'Hello World!'\n";
+
+$context->close();
diff --git a/pkg/amqp-lib/tutorial/worker.php b/pkg/amqp-lib/tutorial/worker.php
new file mode 100644
index 000000000..3f908b6a6
--- /dev/null
+++ b/pkg/amqp-lib/tutorial/worker.php
@@ -0,0 +1,38 @@
+ 'localhost',
+ 'port' => 5672,
+ 'user' => 'guest',
+ 'pass' => 'guest',
+ 'receive_method' => 'basic_consume',
+];
+
+$connection = new AmqpConnectionFactory($config);
+$context = $connection->createContext();
+$context->setQos(0, 1, false);
+
+$queue = $context->createQueue('task_queue');
+$queue->addFlag(AmqpQueue::FLAG_DURABLE);
+
+$context->declareQueue($queue);
+
+$consumer = $context->createConsumer($queue);
+
+echo ' [*] Waiting for messages. To exit press CTRL+C', "\n";
+
+while (true) {
+ if ($message = $consumer->receive()) {
+ echo ' [x] Received ', $message->getBody(), "\n";
+ sleep(substr_count($message->getBody(), '.'));
+ echo ' [x] Done', "\n";
+ $consumer->acknowledge($message);
+ }
+}
+
+$context->close();
diff --git a/pkg/amqp-tools/DelayStrategy.php b/pkg/amqp-tools/DelayStrategy.php
new file mode 100644
index 000000000..ba1bcc3d2
--- /dev/null
+++ b/pkg/amqp-tools/DelayStrategy.php
@@ -0,0 +1,18 @@
+delayStrategy = $delayStrategy;
+
+ return $this;
+ }
+}
diff --git a/pkg/amqp-tools/LICENSE b/pkg/amqp-tools/LICENSE
new file mode 100644
index 000000000..d9736f8bf
--- /dev/null
+++ b/pkg/amqp-tools/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+Copyright (c) 2017 Kotliar Maksym
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/pkg/amqp-tools/README.md b/pkg/amqp-tools/README.md
new file mode 100644
index 000000000..787df3aaa
--- /dev/null
+++ b/pkg/amqp-tools/README.md
@@ -0,0 +1,27 @@
+# AMQP tools
+
+[](https://gitter.im/php-enqueue/Lobby)
+[](https://travis-ci.org/php-enqueue/amqp-tools)
+[](https://packagist.org/packages/enqueue/amqp-tools)
+[](https://packagist.org/packages/enqueue/amqp-tools)
+
+Provides features that are not part of the AMQP spec but could be built on top of.
+The tools could be used with any [amqp interop](https://github.com/queue-interop/queue-interop#amqp-interop) compatible transport.
+
+## Resources
+
+* [Documentation](https://github.com/php-enqueue/enqueue-dev/blob/master/docs/index.md)
+* [Questions](https://gitter.im/php-enqueue/Lobby)
+* [Issue Tracker](https://github.com/php-enqueue/enqueue-dev/issues)
+
+## Developed by Forma-Pro
+
+Forma-Pro is a full stack development company which interests also spread to open source development.
+Being a team of strong professionals we have an aim an ability to help community by developing cutting edge solutions in the areas of e-commerce, docker & microservice oriented architecture where we have accumulated a huge many-years experience.
+Our main specialization is Symfony framework based solution, but we are always looking to the technologies that allow us to do our job the best way. We are committed to creating solutions that revolutionize the way how things are developed in aspects of architecture & scalability.
+
+If you have any questions and inquires about our open source development, this product particularly or any other matter feel free to contact at opensource@forma-pro.com
+
+## License
+
+It is released under the [MIT License](LICENSE).
\ No newline at end of file
diff --git a/pkg/amqp-tools/RabbitMqDelayPluginDelayStrategy.php b/pkg/amqp-tools/RabbitMqDelayPluginDelayStrategy.php
new file mode 100644
index 000000000..fc4103789
--- /dev/null
+++ b/pkg/amqp-tools/RabbitMqDelayPluginDelayStrategy.php
@@ -0,0 +1,57 @@
+createMessage($message->getBody(), $message->getProperties(), $message->getHeaders());
+ $delayMessage->setProperty('x-delay', (int) $delayMsec);
+ $delayMessage->setRoutingKey($message->getRoutingKey());
+
+ if ($dest instanceof AmqpTopic) {
+ $delayTopic = $context->createTopic('enqueue.'.$dest->getTopicName().'.delayed');
+ $delayTopic->setType('x-delayed-message');
+ $delayTopic->addFlag($dest->getFlags());
+ $delayTopic->setArgument('x-delayed-type', $dest->getType());
+
+ $context->declareTopic($delayTopic);
+ $context->bind(new AmqpBind($dest, $delayTopic, $delayMessage->getRoutingKey()));
+ } elseif ($dest instanceof AmqpQueue) {
+ $delayTopic = $context->createTopic('enqueue.queue.delayed');
+ $delayTopic->setType('x-delayed-message');
+ $delayTopic->addFlag(AmqpTopic::FLAG_DURABLE);
+ $delayTopic->setArgument('x-delayed-type', AmqpTopic::TYPE_DIRECT);
+
+ $delayMessage->setRoutingKey($dest->getQueueName());
+
+ $context->declareTopic($delayTopic);
+ $context->bind(new AmqpBind($dest, $delayTopic, $delayMessage->getRoutingKey()));
+ } else {
+ throw new InvalidDestinationException(sprintf('The destination must be an instance of %s but got %s.',
+ AmqpTopic::class.'|'.AmqpQueue::class,
+ get_class($dest)
+ ));
+ }
+
+ $producer = $context->createProducer();
+
+ if ($producer instanceof DelayStrategyAware) {
+ $producer->setDelayStrategy(null);
+ }
+
+ $producer->send($delayTopic, $delayMessage);
+ }
+}
diff --git a/pkg/amqp-tools/RabbitMqDlxDelayStrategy.php b/pkg/amqp-tools/RabbitMqDlxDelayStrategy.php
new file mode 100644
index 000000000..6211885e3
--- /dev/null
+++ b/pkg/amqp-tools/RabbitMqDlxDelayStrategy.php
@@ -0,0 +1,55 @@
+getProperties();
+
+ // The x-death header must be removed because of the bug in RabbitMQ.
+ // It was reported that the bug is fixed since 3.5.4 but I tried with 3.6.1 and the bug still there.
+ // https://github.com/rabbitmq/rabbitmq-server/issues/216
+ unset($properties['x-death']);
+
+ $delayMessage = $context->createMessage($message->getBody(), $properties, $message->getHeaders());
+ $delayMessage->setRoutingKey($message->getRoutingKey());
+
+ if ($dest instanceof AmqpTopic) {
+ $routingKey = $message->getRoutingKey() ? '.'.$message->getRoutingKey() : '';
+ $name = sprintf('enqueue.%s%s.%s.x.delay', $dest->getTopicName(), $routingKey, $delayMsec);
+
+ $delayQueue = $context->createQueue($name);
+ $delayQueue->addFlag(AmqpTopic::FLAG_DURABLE);
+ $delayQueue->setArgument('x-message-ttl', $delayMsec);
+ $delayQueue->setArgument('x-dead-letter-exchange', $dest->getTopicName());
+ $delayQueue->setArgument('x-dead-letter-routing-key', (string) $delayMessage->getRoutingKey());
+ } elseif ($dest instanceof AmqpQueue) {
+ $delayQueue = $context->createQueue('enqueue.'.$dest->getQueueName().'.'.$delayMsec.'.delayed');
+ $delayQueue->addFlag(AmqpTopic::FLAG_DURABLE);
+ $delayQueue->setArgument('x-message-ttl', $delayMsec);
+ $delayQueue->setArgument('x-dead-letter-exchange', '');
+ $delayQueue->setArgument('x-dead-letter-routing-key', $dest->getQueueName());
+ } else {
+ throw new InvalidDestinationException(sprintf('The destination must be an instance of %s but got %s.',
+ AmqpTopic::class.'|'.AmqpQueue::class,
+ get_class($dest)
+ ));
+ }
+
+ $context->declareQueue($delayQueue);
+
+ $context->createProducer()->send($delayQueue, $delayMessage);
+ }
+}
diff --git a/pkg/amqp-tools/Tests/RabbitMqDelayPluginDelayStrategyTest.php b/pkg/amqp-tools/Tests/RabbitMqDelayPluginDelayStrategyTest.php
new file mode 100644
index 000000000..9f19e59d5
--- /dev/null
+++ b/pkg/amqp-tools/Tests/RabbitMqDelayPluginDelayStrategyTest.php
@@ -0,0 +1,217 @@
+assertClassImplements(DelayStrategy::class, RabbitMqDelayPluginDelayStrategy::class);
+ }
+
+ public function testShouldSendDelayedMessageToTopic()
+ {
+ $delayedTopic = new AmqpTopic('the-topic');
+ $delayedMessage = new AmqpMessage();
+
+ $producer = $this->createProducerMock();
+ $producer
+ ->expects($this->once())
+ ->method('send')
+ ->with($this->identicalTo($delayedTopic), $this->identicalTo($delayedMessage))
+ ;
+
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createTopic')
+ ->with($this->identicalTo('enqueue.the-topic.delayed'))
+ ->willReturn($delayedTopic)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('declareTopic')
+ ->with($this->identicalTo($delayedTopic))
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createProducer')
+ ->willReturn($producer)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->with($this->identicalTo('the body'), $this->identicalTo(['key' => 'value']), $this->identicalTo(['hkey' => 'hvalue']))
+ ->willReturn($delayedMessage)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('bind')
+ ->with($this->isInstanceOf(AmqpBind::class))
+ ;
+
+ $message = new AmqpMessage('the body', ['key' => 'value'], ['hkey' => 'hvalue']);
+ $message->setRoutingKey('the-routing-key');
+
+ $dest = new AmqpTopic('the-topic');
+ $dest->setFlags(12345);
+
+ $strategy = new RabbitMqDelayPluginDelayStrategy();
+ $strategy->delayMessage($context, $dest, $message, 10000);
+
+ $this->assertSame(12345, $delayedTopic->getFlags());
+ $this->assertSame('x-delayed-message', $delayedTopic->getType());
+ $this->assertSame([
+ 'x-delayed-type' => 'direct',
+ ], $delayedTopic->getArguments());
+
+ $this->assertSame(['x-delay' => 10000], $delayedMessage->getProperties());
+ $this->assertSame('the-routing-key', $delayedMessage->getRoutingKey());
+ }
+
+ public function testShouldSendDelayedMessageToQueue()
+ {
+ $delayedTopic = new AmqpTopic('the-topic');
+ $delayedMessage = new AmqpMessage();
+
+ $producer = $this->createProducerMock();
+ $producer
+ ->expects($this->once())
+ ->method('send')
+ ->with($this->identicalTo($delayedTopic), $this->identicalTo($delayedMessage))
+ ;
+
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createTopic')
+ ->with($this->identicalTo('enqueue.queue.delayed'))
+ ->willReturn($delayedTopic)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('declareTopic')
+ ->with($this->identicalTo($delayedTopic))
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createProducer')
+ ->willReturn($producer)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->with($this->identicalTo('the body'), $this->identicalTo(['key' => 'value']), $this->identicalTo(['hkey' => 'hvalue']))
+ ->willReturn($delayedMessage)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('bind')
+ ->with($this->isInstanceOf(AmqpBind::class))
+ ;
+
+ $message = new AmqpMessage('the body', ['key' => 'value'], ['hkey' => 'hvalue']);
+ $message->setRoutingKey('the-routing-key');
+
+ $dest = new AmqpQueue('the-queue');
+
+ $strategy = new RabbitMqDelayPluginDelayStrategy();
+ $strategy->delayMessage($context, $dest, $message, 10000);
+
+ $this->assertSame(AmqpQueue::FLAG_DURABLE, $delayedTopic->getFlags());
+ $this->assertSame('x-delayed-message', $delayedTopic->getType());
+ $this->assertSame([
+ 'x-delayed-type' => 'direct',
+ ], $delayedTopic->getArguments());
+
+ $this->assertSame(['x-delay' => 10000], $delayedMessage->getProperties());
+ $this->assertSame('the-queue', $delayedMessage->getRoutingKey());
+ }
+
+ public function testShouldThrowExceptionIfInvalidDestination()
+ {
+ $delayedMessage = new AmqpMessage();
+
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($delayedMessage)
+ ;
+
+ $strategy = new RabbitMqDelayPluginDelayStrategy();
+
+ $this->expectException(InvalidDestinationException::class);
+ $this->expectExceptionMessage('The destination must be an instance of Interop\Amqp\AmqpTopic|Interop\Amqp\AmqpQueue but got');
+
+ $strategy->delayMessage($context, $this->createMock(AmqpDestination::class), new AmqpMessage(), 10000);
+ }
+
+ /**
+ * @return \PHPUnit_Framework_MockObject_MockObject|AmqpContext
+ */
+ private function createContextMock()
+ {
+ return $this->createMock(AmqpContext::class);
+ }
+
+ /**
+ * @return \PHPUnit_Framework_MockObject_MockObject|TestProducer
+ */
+ private function createProducerMock()
+ {
+ return $this->createMock(TestProducer::class);
+ }
+}
+
+class TestProducer implements AmqpProducer, DelayStrategy
+{
+ public function delayMessage(AmqpContext $context, AmqpDestination $dest, \Interop\Amqp\AmqpMessage $message, $delayMsec)
+ {
+ }
+
+ public function send(PsrDestination $destination, PsrMessage $message)
+ {
+ }
+
+ public function setDeliveryDelay($deliveryDelay)
+ {
+ }
+
+ public function getDeliveryDelay()
+ {
+ }
+
+ public function setPriority($priority)
+ {
+ }
+
+ public function getPriority()
+ {
+ }
+
+ public function setTimeToLive($timeToLive)
+ {
+ }
+
+ public function getTimeToLive()
+ {
+ }
+}
diff --git a/pkg/amqp-tools/Tests/RabbitMqDlxDelayStrategyTest.php b/pkg/amqp-tools/Tests/RabbitMqDlxDelayStrategyTest.php
new file mode 100644
index 000000000..9531fe4ce
--- /dev/null
+++ b/pkg/amqp-tools/Tests/RabbitMqDlxDelayStrategyTest.php
@@ -0,0 +1,198 @@
+assertClassImplements(DelayStrategy::class, RabbitMqDlxDelayStrategy::class);
+ }
+
+ public function testShouldSendDelayedMessageToTopic()
+ {
+ $delayedQueue = new AmqpQueue('the-queue');
+ $delayedMessage = new AmqpMessage();
+
+ $producer = $this->createProducerMock();
+ $producer
+ ->expects($this->once())
+ ->method('send')
+ ->with($this->identicalTo($delayedQueue), $this->identicalTo($delayedMessage))
+ ;
+
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createQueue')
+ ->with($this->identicalTo('enqueue.the-topic.the-routing-key.10000.x.delay'))
+ ->willReturn($delayedQueue)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('declareQueue')
+ ->with($this->identicalTo($delayedQueue))
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createProducer')
+ ->willReturn($producer)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->with($this->identicalTo('the body'), $this->identicalTo(['key' => 'value']), $this->identicalTo(['hkey' => 'hvalue']))
+ ->willReturn($delayedMessage)
+ ;
+
+ $message = new AmqpMessage('the body', ['key' => 'value'], ['hkey' => 'hvalue']);
+ $message->setRoutingKey('the-routing-key');
+
+ $dest = new AmqpTopic('the-topic');
+
+ $strategy = new RabbitMqDlxDelayStrategy();
+ $strategy->delayMessage($context, $dest, $message, 10000);
+
+ $this->assertSame(AmqpQueue::FLAG_DURABLE, $delayedQueue->getFlags());
+ $this->assertSame([
+ 'x-message-ttl' => 10000,
+ 'x-dead-letter-exchange' => 'the-topic',
+ 'x-dead-letter-routing-key' => 'the-routing-key',
+ ], $delayedQueue->getArguments());
+ }
+
+ public function testShouldSendDelayedMessageToQueue()
+ {
+ $delayedQueue = new AmqpQueue('the-queue');
+ $delayedMessage = new AmqpMessage();
+
+ $producer = $this->createProducerMock();
+ $producer
+ ->expects($this->once())
+ ->method('send')
+ ->with($this->identicalTo($delayedQueue), $this->identicalTo($delayedMessage))
+ ;
+
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createQueue')
+ ->with($this->identicalTo('enqueue.the-queue.10000.delayed'))
+ ->willReturn($delayedQueue)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('declareQueue')
+ ->with($this->identicalTo($delayedQueue))
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createProducer')
+ ->willReturn($producer)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->with($this->identicalTo('the body'), $this->identicalTo(['key' => 'value']), $this->identicalTo(['hkey' => 'hvalue']))
+ ->willReturn($delayedMessage)
+ ;
+
+ $message = new AmqpMessage('the body', ['key' => 'value'], ['hkey' => 'hvalue']);
+ $message->setRoutingKey('the-routing-key');
+
+ $dest = new AmqpQueue('the-queue');
+
+ $strategy = new RabbitMqDlxDelayStrategy();
+ $strategy->delayMessage($context, $dest, $message, 10000);
+
+ $this->assertSame(AmqpQueue::FLAG_DURABLE, $delayedQueue->getFlags());
+ $this->assertSame([
+ 'x-message-ttl' => 10000,
+ 'x-dead-letter-exchange' => '',
+ 'x-dead-letter-routing-key' => 'the-queue',
+ ], $delayedQueue->getArguments());
+ }
+
+ public function testShouldUnsetXDeathProperty()
+ {
+ $delayedQueue = new AmqpQueue('the-queue');
+ $delayedMessage = new AmqpMessage();
+
+ $producer = $this->createProducerMock();
+
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createQueue')
+ ->with($this->identicalTo('enqueue.the-queue.10000.delayed'))
+ ->willReturn($delayedQueue)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createProducer')
+ ->willReturn($producer)
+ ;
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->with($this->identicalTo('the body'), $this->identicalTo(['key' => 'value']), $this->identicalTo(['hkey' => 'hvalue']))
+ ->willReturn($delayedMessage)
+ ;
+
+ $message = new AmqpMessage('the body', ['key' => 'value', 'x-death' => 'value'], ['hkey' => 'hvalue']);
+
+ $dest = new AmqpQueue('the-queue');
+
+ $strategy = new RabbitMqDlxDelayStrategy();
+ $strategy->delayMessage($context, $dest, $message, 10000);
+ }
+
+ public function testShouldThrowExceptionIfInvalidDestination()
+ {
+ $delayedMessage = new AmqpMessage();
+
+ $context = $this->createContextMock();
+ $context
+ ->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($delayedMessage)
+ ;
+
+ $strategy = new RabbitMqDlxDelayStrategy();
+
+ $this->expectException(InvalidDestinationException::class);
+ $this->expectExceptionMessage('The destination must be an instance of Interop\Amqp\AmqpTopic|Interop\Amqp\AmqpQueue but got');
+
+ $strategy->delayMessage($context, $this->createMock(AmqpDestination::class), new AmqpMessage(), 10000);
+ }
+
+ /**
+ * @return \PHPUnit_Framework_MockObject_MockObject|AmqpContext
+ */
+ private function createContextMock()
+ {
+ return $this->createMock(AmqpContext::class);
+ }
+
+ /**
+ * @return \PHPUnit_Framework_MockObject_MockObject|AmqpProducer
+ */
+ private function createProducerMock()
+ {
+ return $this->createMock(AmqpProducer::class);
+ }
+}
diff --git a/pkg/amqp-tools/composer.json b/pkg/amqp-tools/composer.json
new file mode 100644
index 000000000..8ebc33de6
--- /dev/null
+++ b/pkg/amqp-tools/composer.json
@@ -0,0 +1,35 @@
+{
+ "name": "enqueue/amqp-tools",
+ "type": "library",
+ "description": "Message Queue Amqp Tools",
+ "keywords": ["messaging", "queue", "amqp"],
+ "license": "MIT",
+ "repositories": [
+ {
+ "type": "vcs",
+ "url": "git@github.com:php-enqueue/test.git"
+ }
+ ],
+ "require": {
+ "php": ">=5.6",
+ "queue-interop/queue-interop": "^0.6@dev",
+ "queue-interop/amqp-interop": "^0.6@dev"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~5.4.0",
+ "enqueue/test": "^0.7@dev",
+ "enqueue/null": "^0.7@dev"
+ },
+ "autoload": {
+ "psr-4": { "Enqueue\\AmqpTools\\": "" },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "minimum-stability": "dev",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "0.7.x-dev"
+ }
+ }
+}
diff --git a/pkg/async-event-dispatcher/composer.json b/pkg/async-event-dispatcher/composer.json
index f6010afe7..3ccb9f1d9 100644
--- a/pkg/async-event-dispatcher/composer.json
+++ b/pkg/async-event-dispatcher/composer.json
@@ -12,7 +12,7 @@
],
"require": {
"php": ">=5.6",
- "queue-interop/queue-interop": "^0.5@dev",
+ "queue-interop/queue-interop": "^0.6@dev",
"symfony/event-dispatcher": "^2.8|^3"
},
"require-dev": {
@@ -21,7 +21,7 @@
"symfony/config": "^2.8|^3",
"symfony/http-kernel": "^2.8|^3",
"symfony/filesystem": "^2.8|^3",
- "enqueue/null": "^0.6@dev"
+ "enqueue/null": "^0.7@dev"
},
"suggest": {
"symfony/dependency-injection": "^2.8|^3 If you'd like to use async event dispatcher container extension."
@@ -35,7 +35,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
- "dev-master": "0.6.x-dev"
+ "dev-master": "0.7.x-dev"
}
}
}
diff --git a/pkg/dbal/DbalProducer.php b/pkg/dbal/DbalProducer.php
index 8668a68ce..4d125bb10 100644
--- a/pkg/dbal/DbalProducer.php
+++ b/pkg/dbal/DbalProducer.php
@@ -85,4 +85,64 @@ public function send(PsrDestination $destination, PsrMessage $message)
throw new Exception('The transport fails to send the message due to some internal error.', null, $e);
}
}
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setDeliveryDelay($deliveryDelay)
+ {
+ if (null === $deliveryDelay) {
+ return;
+ }
+
+ throw new \LogicException('Not implemented');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDeliveryDelay()
+ {
+ return null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setPriority($priority)
+ {
+ if (null === $priority) {
+ return;
+ }
+
+ throw new \LogicException('Not implemented');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPriority()
+ {
+ return null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setTimeToLive($timeToLive)
+ {
+ if (null === $timeToLive) {
+ return;
+ }
+
+ throw new \LogicException('Not implemented');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTimeToLive()
+ {
+ return null;
+ }
}
diff --git a/pkg/dbal/composer.json b/pkg/dbal/composer.json
index 2d550d8ba..579f59992 100644
--- a/pkg/dbal/composer.json
+++ b/pkg/dbal/composer.json
@@ -12,15 +12,15 @@
],
"require": {
"php": ">=5.6",
- "queue-interop/queue-interop": "^0.5@dev",
+ "queue-interop/queue-interop": "^0.6@dev",
"doctrine/dbal": "~2.5",
"psr/log": "^1"
},
"require-dev": {
"phpunit/phpunit": "~5.4.0",
- "enqueue/test": "^0.6@dev",
- "enqueue/enqueue": "^0.6@dev",
- "enqueue/null": "^0.6@dev",
+ "enqueue/test": "^0.7@dev",
+ "enqueue/enqueue": "^0.7@dev",
+ "enqueue/null": "^0.7@dev",
"queue-interop/queue-spec": "^0.5@dev",
"symfony/dependency-injection": "^2.8|^3",
"symfony/config": "^2.8|^3"
@@ -37,7 +37,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
- "dev-master": "0.6.x-dev"
+ "dev-master": "0.7.x-dev"
}
}
}
diff --git a/pkg/enqueue-bundle/DependencyInjection/Compiler/BuildExclusiveCommandsExtensionPass.php b/pkg/enqueue-bundle/DependencyInjection/Compiler/BuildExclusiveCommandsExtensionPass.php
index f01468f0d..978341ab7 100644
--- a/pkg/enqueue-bundle/DependencyInjection/Compiler/BuildExclusiveCommandsExtensionPass.php
+++ b/pkg/enqueue-bundle/DependencyInjection/Compiler/BuildExclusiveCommandsExtensionPass.php
@@ -32,7 +32,7 @@ public function process(ContainerBuilder $container)
continue;
}
- if (false == isset($subscription['exclusive'])) {
+ if (false == isset($subscription['exclusive']) || $subscription['exclusive'] === false) {
continue;
}
diff --git a/pkg/enqueue-bundle/DependencyInjection/Configuration.php b/pkg/enqueue-bundle/DependencyInjection/Configuration.php
index 7fe7b13db..c02b0c508 100644
--- a/pkg/enqueue-bundle/DependencyInjection/Configuration.php
+++ b/pkg/enqueue-bundle/DependencyInjection/Configuration.php
@@ -44,7 +44,7 @@ public function getConfigTreeBuilder()
->booleanNode('traceable_producer')->defaultFalse()->end()
->scalarNode('prefix')->defaultValue('enqueue')->end()
->scalarNode('app_name')->defaultValue('app')->end()
- ->scalarNode('router_topic')->defaultValue('router')->cannotBeEmpty()->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('enqueue.client.router_processor')->end()
->scalarNode('default_processor_queue')->defaultValue(Config::DEFAULT_PROCESSOR_QUEUE_NAME)->cannotBeEmpty()->end()
diff --git a/pkg/enqueue-bundle/EnqueueBundle.php b/pkg/enqueue-bundle/EnqueueBundle.php
index 3ce3480d1..9f7400e40 100644
--- a/pkg/enqueue-bundle/EnqueueBundle.php
+++ b/pkg/enqueue-bundle/EnqueueBundle.php
@@ -2,9 +2,15 @@
namespace Enqueue\Bundle;
+use Enqueue\AmqpBunny\AmqpContext as AmqpBunnyContext;
+use Enqueue\AmqpBunny\Symfony\AmqpBunnyTransportFactory;
+use Enqueue\AmqpBunny\Symfony\RabbitMqAmqpBunnyTransportFactory;
use Enqueue\AmqpExt\AmqpContext;
use Enqueue\AmqpExt\Symfony\AmqpTransportFactory;
use Enqueue\AmqpExt\Symfony\RabbitMqAmqpTransportFactory;
+use Enqueue\AmqpLib\AmqpContext as AmqpLibContext;
+use Enqueue\AmqpLib\Symfony\AmqpLibTransportFactory;
+use Enqueue\AmqpLib\Symfony\RabbitMqAmqpLibTransportFactory;
use Enqueue\AsyncEventDispatcher\DependencyInjection\AsyncEventsPass;
use Enqueue\AsyncEventDispatcher\DependencyInjection\AsyncTransformersPass;
use Enqueue\Bundle\DependencyInjection\Compiler\BuildClientExtensionsPass;
@@ -58,6 +64,11 @@ public function build(ContainerBuilder $container)
$extension->addTransportFactory(new RabbitMqAmqpTransportFactory());
}
+ if (class_exists(AmqpLibContext::class)) {
+ $extension->addTransportFactory(new AmqpLibTransportFactory());
+ $extension->addTransportFactory(new RabbitMqAmqpLibTransportFactory());
+ }
+
if (class_exists(FsContext::class)) {
$extension->addTransportFactory(new FsTransportFactory());
}
@@ -74,6 +85,11 @@ public function build(ContainerBuilder $container)
$extension->addTransportFactory(new SqsTransportFactory());
}
+ if (class_exists(AmqpBunnyContext::class)) {
+ $extension->addTransportFactory(new AmqpBunnyTransportFactory());
+ $extension->addTransportFactory(new RabbitMqAmqpBunnyTransportFactory());
+ }
+
$container->addCompilerPass(new AsyncEventsPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 100);
$container->addCompilerPass(new AsyncTransformersPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 100);
}
diff --git a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/ConfigurationTest.php b/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/ConfigurationTest.php
index a5e99b40a..bd3162a43 100644
--- a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/ConfigurationTest.php
+++ b/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/ConfigurationTest.php
@@ -145,7 +145,7 @@ public function testShouldSetDefaultConfigurationForClient()
'prefix' => 'enqueue',
'app_name' => 'app',
'router_processor' => 'enqueue.client.router_processor',
- 'router_topic' => 'router',
+ 'router_topic' => 'default',
'router_queue' => 'default',
'default_processor_queue' => 'default',
'traceable_producer' => false,
diff --git a/pkg/enqueue-bundle/Tests/Unit/EnqueueBundleTest.php b/pkg/enqueue-bundle/Tests/Unit/EnqueueBundleTest.php
index b9b369b5c..3b8d69a9d 100644
--- a/pkg/enqueue-bundle/Tests/Unit/EnqueueBundleTest.php
+++ b/pkg/enqueue-bundle/Tests/Unit/EnqueueBundleTest.php
@@ -2,8 +2,12 @@
namespace Enqueue\Bundle\Tests\Unit;
+use Enqueue\AmqpBunny\Symfony\AmqpBunnyTransportFactory;
+use Enqueue\AmqpBunny\Symfony\RabbitMqAmqpBunnyTransportFactory;
use Enqueue\AmqpExt\Symfony\AmqpTransportFactory;
use Enqueue\AmqpExt\Symfony\RabbitMqAmqpTransportFactory;
+use Enqueue\AmqpLib\Symfony\AmqpLibTransportFactory;
+use Enqueue\AmqpLib\Symfony\RabbitMqAmqpLibTransportFactory;
use Enqueue\Bundle\DependencyInjection\Compiler\BuildClientExtensionsPass;
use Enqueue\Bundle\DependencyInjection\Compiler\BuildClientRoutingPass;
use Enqueue\Bundle\DependencyInjection\Compiler\BuildConsumptionExtensionsPass;
@@ -132,7 +136,7 @@ public function testShouldRegisterAmqpAndRabbitMqAmqpTransportFactories()
$bundle->build($container);
}
- public function testShouldRegisterFSTransportFactory()
+ public function testShouldRegisterAmqpLibAndRabbitMqAmqpLibTransportFactories()
{
$extensionMock = $this->createEnqueueExtensionMock();
@@ -142,6 +146,28 @@ public function testShouldRegisterFSTransportFactory()
$extensionMock
->expects($this->at(4))
->method('addTransportFactory')
+ ->with($this->isInstanceOf(AmqpLibTransportFactory::class))
+ ;
+ $extensionMock
+ ->expects($this->at(5))
+ ->method('addTransportFactory')
+ ->with($this->isInstanceOf(RabbitMqAmqpLibTransportFactory::class))
+ ;
+
+ $bundle = new EnqueueBundle();
+ $bundle->build($container);
+ }
+
+ public function testShouldRegisterFSTransportFactory()
+ {
+ $extensionMock = $this->createEnqueueExtensionMock();
+
+ $container = new ContainerBuilder();
+ $container->registerExtension($extensionMock);
+
+ $extensionMock
+ ->expects($this->at(6))
+ ->method('addTransportFactory')
->with($this->isInstanceOf(FsTransportFactory::class))
;
@@ -157,7 +183,7 @@ public function testShouldRegisterRedisTransportFactory()
$container->registerExtension($extensionMock);
$extensionMock
- ->expects($this->at(5))
+ ->expects($this->at(7))
->method('addTransportFactory')
->with($this->isInstanceOf(RedisTransportFactory::class))
;
@@ -174,7 +200,7 @@ public function testShouldRegisterDbalTransportFactory()
$container->registerExtension($extensionMock);
$extensionMock
- ->expects($this->at(6))
+ ->expects($this->at(8))
->method('addTransportFactory')
->with($this->isInstanceOf(DbalTransportFactory::class))
;
@@ -191,7 +217,7 @@ public function testShouldRegisterSqsTransportFactory()
$container->registerExtension($extensionMock);
$extensionMock
- ->expects($this->at(7))
+ ->expects($this->at(9))
->method('addTransportFactory')
->with($this->isInstanceOf(SqsTransportFactory::class))
;
@@ -200,6 +226,28 @@ public function testShouldRegisterSqsTransportFactory()
$bundle->build($container);
}
+ public function testShouldRegisterAmqpBunnyTransportFactory()
+ {
+ $extensionMock = $this->createEnqueueExtensionMock();
+
+ $container = new ContainerBuilder();
+ $container->registerExtension($extensionMock);
+
+ $extensionMock
+ ->expects($this->at(10))
+ ->method('addTransportFactory')
+ ->with($this->isInstanceOf(AmqpBunnyTransportFactory::class))
+ ;
+ $extensionMock
+ ->expects($this->at(11))
+ ->method('addTransportFactory')
+ ->with($this->isInstanceOf(RabbitMqAmqpBunnyTransportFactory::class))
+ ;
+
+ $bundle = new EnqueueBundle();
+ $bundle->build($container);
+ }
+
/**
* @return \PHPUnit_Framework_MockObject_MockObject|EnqueueExtension
*/
diff --git a/pkg/enqueue-bundle/composer.json b/pkg/enqueue-bundle/composer.json
index 6a00b724e..9d1f50435 100644
--- a/pkg/enqueue-bundle/composer.json
+++ b/pkg/enqueue-bundle/composer.json
@@ -13,20 +13,23 @@
"require": {
"php": ">=5.6",
"symfony/framework-bundle": "^2.8|^3",
- "enqueue/enqueue": "^0.6@dev",
- "enqueue/null": "^0.6@dev",
- "enqueue/async-event-dispatcher": "^0.6@dev"
+ "enqueue/enqueue": "^0.7@dev",
+ "enqueue/null": "^0.7@dev",
+ "enqueue/async-event-dispatcher": "^0.7@dev"
},
"require-dev": {
"phpunit/phpunit": "~5.5",
- "enqueue/stomp": "^0.6@dev",
- "enqueue/amqp-ext": "^0.6@dev",
- "enqueue/job-queue": "^0.6@dev",
- "enqueue/fs": "^0.6@dev",
- "enqueue/redis": "^0.6@dev",
- "enqueue/dbal": "^0.6@dev",
- "enqueue/sqs": "^0.6@dev",
- "enqueue/test": "^0.6@dev",
+ "enqueue/stomp": "^0.7@dev",
+ "enqueue/amqp-ext": "^0.7@dev",
+ "php-amqplib/php-amqplib": "^2.7@dev",
+ "enqueue/amqp-lib": "^0.7@dev",
+ "enqueue/amqp-bunny": "^0.7@dev",
+ "enqueue/job-queue": "^0.7@dev",
+ "enqueue/fs": "^0.7@dev",
+ "enqueue/redis": "^0.7@dev",
+ "enqueue/dbal": "^0.7@dev",
+ "enqueue/sqs": "^0.7@dev",
+ "enqueue/test": "^0.7@dev",
"doctrine/doctrine-bundle": "~1.2",
"symfony/monolog-bundle": "^2.8|^3",
"symfony/browser-kit": "^2.8|^3",
@@ -40,7 +43,7 @@
},
"extra": {
"branch-alias": {
- "dev-master": "0.6.x-dev"
+ "dev-master": "0.7.x-dev"
}
}
}
diff --git a/pkg/enqueue/.travis.yml b/pkg/enqueue/.travis.yml
index aaa1849c3..2f48cf85d 100644
--- a/pkg/enqueue/.travis.yml
+++ b/pkg/enqueue/.travis.yml
@@ -14,8 +14,9 @@ cache:
- $HOME/.composer/cache
install:
+ - php Tests/fix_composer_json.php
- composer self-update
- - composer install --prefer-source --ignore-platform-reqs
+ - composer install
script:
- vendor/bin/phpunit --exclude-group=functional
diff --git a/pkg/amqp-ext/Client/AmqpDriver.php b/pkg/enqueue/Client/Amqp/AmqpDriver.php
similarity index 87%
rename from pkg/amqp-ext/Client/AmqpDriver.php
rename to pkg/enqueue/Client/Amqp/AmqpDriver.php
index a1d918ca4..e8b5871d3 100644
--- a/pkg/amqp-ext/Client/AmqpDriver.php
+++ b/pkg/enqueue/Client/Amqp/AmqpDriver.php
@@ -1,16 +1,16 @@
getQueueName());
$this->context->declareQueue($routerQueue);
$log('Bind router queue to exchange: %s -> %s', $routerQueue->getQueueName(), $routerTopic->getTopicName());
- $this->context->bind($routerTopic, $routerQueue);
+ $this->context->bind(new AmqpBind($routerTopic, $routerQueue, $routerQueue->getQueueName()));
// setup queues
foreach ($this->queueMetaRegistry->getQueuesMeta() as $meta) {
@@ -118,7 +118,7 @@ public function createQueue($queueName)
$transportName = $this->queueMetaRegistry->getQueueMeta($queueName)->getTransportName();
$queue = $this->context->createQueue($transportName);
- $queue->addFlag(AMQP_DURABLE);
+ $queue->addFlag(AmqpQueue::FLAG_DURABLE);
return $queue;
}
@@ -133,14 +133,6 @@ public function createTransportMessage(Message $message)
$headers = $message->getHeaders();
$properties = $message->getProperties();
- $headers['content_type'] = $message->getContentType();
-
- if ($message->getExpire()) {
- $headers['expiration'] = (string) ($message->getExpire() * 1000);
- }
-
- $headers['delivery_mode'] = DeliveryMode::PERSISTENT;
-
$transportMessage = $this->context->createMessage();
$transportMessage->setBody($message->getBody());
$transportMessage->setHeaders($headers);
@@ -149,6 +141,12 @@ public function createTransportMessage(Message $message)
$transportMessage->setTimestamp($message->getTimestamp());
$transportMessage->setReplyTo($message->getReplyTo());
$transportMessage->setCorrelationId($message->getCorrelationId());
+ $transportMessage->setContentType($message->getContentType());
+ $transportMessage->setDeliveryMode(AmqpMessage::DELIVERY_MODE_PERSISTENT);
+
+ if ($message->getExpire()) {
+ $transportMessage->setExpiration((string) ($message->getExpire() * 1000));
+ }
return $transportMessage;
}
@@ -165,10 +163,9 @@ public function createClientMessage(PsrMessage $message)
$clientMessage->setBody($message->getBody());
$clientMessage->setHeaders($message->getHeaders());
$clientMessage->setProperties($message->getProperties());
+ $clientMessage->setContentType($message->getContentType());
- $clientMessage->setContentType($message->getHeader('content_type'));
-
- if ($expiration = $message->getHeader('expiration')) {
+ if ($expiration = $message->getExpiration()) {
if (false == is_numeric($expiration)) {
throw new \LogicException(sprintf('expiration header is not numeric. "%s"', $expiration));
}
@@ -200,8 +197,8 @@ private function createRouterTopic()
$topic = $this->context->createTopic(
$this->config->createTransportRouterTopicName($this->config->getRouterTopicName())
);
- $topic->setType(AMQP_EX_TYPE_FANOUT);
- $topic->addFlag(AMQP_DURABLE);
+ $topic->setType(AmqpTopic::TYPE_FANOUT);
+ $topic->addFlag(AmqpTopic::FLAG_DURABLE);
return $topic;
}
diff --git a/pkg/amqp-ext/Client/RabbitMqDriver.php b/pkg/enqueue/Client/Amqp/RabbitMqDriver.php
similarity index 92%
rename from pkg/amqp-ext/Client/RabbitMqDriver.php
rename to pkg/enqueue/Client/Amqp/RabbitMqDriver.php
index 2254ea448..e65095e87 100644
--- a/pkg/amqp-ext/Client/RabbitMqDriver.php
+++ b/pkg/enqueue/Client/Amqp/RabbitMqDriver.php
@@ -1,16 +1,17 @@
setHeader('priority', $this->priorityMap[$priority]);
+ $transportMessage->setPriority($this->priorityMap[$priority]);
}
if ($message->getDelay()) {
@@ -135,7 +136,7 @@ public function createClientMessage(PsrMessage $message)
{
$clientMessage = parent::createClientMessage($message);
- if ($priority = $message->getHeader('priority')) {
+ if ($priority = $message->getPriority()) {
if (false === $clientPriority = array_search($priority, $this->priorityMap, true)) {
throw new \LogicException(sprintf('Cant convert transport priority to client: "%s"', $priority));
}
@@ -178,7 +179,7 @@ public function setupBroker(LoggerInterface $logger = null)
$this->context->declareTopic($delayTopic);
$log('Bind processor queue to delay exchange: %s -> %s', $queue->getQueueName(), $delayTopic->getTopicName());
- $this->context->bind($delayTopic, $queue);
+ $this->context->bind(new AmqpBind($delayTopic, $queue, $queue->getQueueName()));
}
}
}
@@ -194,9 +195,8 @@ private function createDelayedTopic(AmqpQueue $queue)
// in order to use delay feature make sure the rabbitmq_delayed_message_exchange plugin is installed.
$delayTopic = $this->context->createTopic($queueName.'.delayed');
- $delayTopic->setRoutingKey($queueName);
$delayTopic->setType('x-delayed-message');
- $delayTopic->addFlag(AMQP_DURABLE);
+ $delayTopic->addFlag(AmqpTopic::FLAG_DURABLE);
$delayTopic->setArguments([
'x-delayed-type' => 'direct',
]);
diff --git a/pkg/amqp-ext/Tests/Client/AmqpDriverTest.php b/pkg/enqueue/Tests/Client/Amqp/AmqpDriverTest.php
similarity index 89%
rename from pkg/amqp-ext/Tests/Client/AmqpDriverTest.php
rename to pkg/enqueue/Tests/Client/Amqp/AmqpDriverTest.php
index 9484dbc2c..a82fda082 100644
--- a/pkg/amqp-ext/Tests/Client/AmqpDriverTest.php
+++ b/pkg/enqueue/Tests/Client/Amqp/AmqpDriverTest.php
@@ -1,18 +1,19 @@
createPsrContextMock(),
+ $this->createAmqpContextMock(),
$this->createDummyConfig(),
$this->createDummyQueueMetaRegistry()
);
@@ -37,7 +38,7 @@ public function testShouldReturnConfigObject()
{
$config = $this->createDummyConfig();
- $driver = new AmqpDriver($this->createPsrContextMock(), $config, $this->createDummyQueueMetaRegistry());
+ $driver = new AmqpDriver($this->createAmqpContextMock(), $config, $this->createDummyQueueMetaRegistry());
$this->assertSame($config, $driver->getConfig());
}
@@ -46,7 +47,7 @@ public function testShouldCreateAndReturnQueueInstance()
{
$expectedQueue = new AmqpQueue('aName');
- $context = $this->createPsrContextMock();
+ $context = $this->createAmqpContextMock();
$context
->expects($this->once())
->method('createQueue')
@@ -62,14 +63,13 @@ public function testShouldCreateAndReturnQueueInstance()
$this->assertSame([], $queue->getArguments());
$this->assertSame(2, $queue->getFlags());
$this->assertNull($queue->getConsumerTag());
- $this->assertSame([], $queue->getBindArguments());
}
public function testShouldCreateAndReturnQueueInstanceWithHardcodedTransportName()
{
$expectedQueue = new AmqpQueue('aName');
- $context = $this->createPsrContextMock();
+ $context = $this->createAmqpContextMock();
$context
->expects($this->once())
->method('createQueue')
@@ -98,7 +98,7 @@ public function testShouldConvertTransportMessageToClientMessage()
$transportMessage->setCorrelationId('theCorrelationId');
$driver = new AmqpDriver(
- $this->createPsrContextMock(),
+ $this->createAmqpContextMock(),
$this->createDummyConfig(),
$this->createDummyQueueMetaRegistry()
);
@@ -133,7 +133,7 @@ public function testShouldThrowExceptionIfExpirationIsNotNumeric()
$transportMessage->setHeader('expiration', 'is-not-numeric');
$driver = new AmqpDriver(
- $this->createPsrContextMock(),
+ $this->createAmqpContextMock(),
$this->createDummyConfig(),
$this->createDummyQueueMetaRegistry()
);
@@ -157,7 +157,7 @@ public function testShouldConvertClientMessageToTransportMessage()
$clientMessage->setReplyTo('theReplyTo');
$clientMessage->setCorrelationId('theCorrelationId');
- $context = $this->createPsrContextMock();
+ $context = $this->createAmqpContextMock();
$context
->expects($this->once())
->method('createMessage')
@@ -176,13 +176,13 @@ public function testShouldConvertClientMessageToTransportMessage()
$this->assertSame('body', $transportMessage->getBody());
$this->assertSame([
'hkey' => 'hval',
- 'content_type' => 'ContentType',
- 'expiration' => '123000',
- 'delivery_mode' => 2,
'message_id' => 'MessageId',
'timestamp' => 1000,
'reply_to' => 'theReplyTo',
'correlation_id' => 'theCorrelationId',
+ 'content_type' => 'ContentType',
+ 'delivery_mode' => 2,
+ 'expiration' => '123000',
], $transportMessage->getHeaders());
$this->assertSame([
'key' => 'val',
@@ -198,13 +198,13 @@ public function testShouldSendMessageToRouter()
$topic = new AmqpTopic('');
$transportMessage = new AmqpMessage();
- $producer = $this->createPsrProducerMock();
+ $producer = $this->createAmqpProducerMock();
$producer
->expects($this->once())
->method('send')
->with($this->identicalTo($topic), $this->identicalTo($transportMessage))
;
- $context = $this->createPsrContextMock();
+ $context = $this->createAmqpContextMock();
$context
->expects($this->once())
->method('createTopic')
@@ -236,7 +236,7 @@ public function testShouldSendMessageToRouter()
public function testShouldThrowExceptionIfTopicParameterIsNotSet()
{
$driver = new AmqpDriver(
- $this->createPsrContextMock(),
+ $this->createAmqpContextMock(),
$this->createDummyConfig(),
$this->createDummyQueueMetaRegistry()
);
@@ -252,13 +252,13 @@ public function testShouldSendMessageToProcessor()
$queue = new AmqpQueue('');
$transportMessage = new AmqpMessage();
- $producer = $this->createPsrProducerMock();
+ $producer = $this->createAmqpProducerMock();
$producer
->expects($this->once())
->method('send')
->with($this->identicalTo($queue), $this->identicalTo($transportMessage))
;
- $context = $this->createPsrContextMock();
+ $context = $this->createAmqpContextMock();
$context
->expects($this->once())
->method('createQueue')
@@ -291,7 +291,7 @@ public function testShouldSendMessageToProcessor()
public function testShouldThrowExceptionIfProcessorNameParameterIsNotSet()
{
$driver = new AmqpDriver(
- $this->createPsrContextMock(),
+ $this->createAmqpContextMock(),
$this->createDummyConfig(),
$this->createDummyQueueMetaRegistry()
);
@@ -305,7 +305,7 @@ public function testShouldThrowExceptionIfProcessorNameParameterIsNotSet()
public function testShouldThrowExceptionIfProcessorQueueNameParameterIsNotSet()
{
$driver = new AmqpDriver(
- $this->createPsrContextMock(),
+ $this->createAmqpContextMock(),
$this->createDummyConfig(),
$this->createDummyQueueMetaRegistry()
);
@@ -326,7 +326,7 @@ public function testShouldSetupBroker()
$processorQueue = new AmqpQueue('');
- $context = $this->createPsrContextMock();
+ $context = $this->createAmqpContextMock();
// setup router
$context
->expects($this->at(0))
@@ -351,7 +351,7 @@ public function testShouldSetupBroker()
$context
->expects($this->at(4))
->method('bind')
- ->with($this->identicalTo($routerTopic), $this->identicalTo($routerQueue))
+ ->with($this->isInstanceOf(AmqpBind::class))
;
// setup processor queue
$context
@@ -381,17 +381,17 @@ public function testShouldSetupBroker()
/**
* @return \PHPUnit_Framework_MockObject_MockObject|AmqpContext
*/
- private function createPsrContextMock()
+ private function createAmqpContextMock()
{
return $this->createMock(AmqpContext::class);
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|PsrProducer
+ * @return \PHPUnit_Framework_MockObject_MockObject|AmqpProducer
*/
- private function createPsrProducerMock()
+ private function createAmqpProducerMock()
{
- return $this->createMock(PsrProducer::class);
+ return $this->createMock(AmqpProducer::class);
}
/**
diff --git a/pkg/amqp-ext/Tests/Client/RabbitMqDriverTest.php b/pkg/enqueue/Tests/Client/Amqp/RabbitMqDriverTest.php
similarity index 90%
rename from pkg/amqp-ext/Tests/Client/RabbitMqDriverTest.php
rename to pkg/enqueue/Tests/Client/Amqp/RabbitMqDriverTest.php
index edb66ffb2..698fc5c3e 100644
--- a/pkg/amqp-ext/Tests/Client/RabbitMqDriverTest.php
+++ b/pkg/enqueue/Tests/Client/Amqp/RabbitMqDriverTest.php
@@ -1,20 +1,21 @@
createPsrContextMock(),
+ $this->createAmqpContextMock(),
Config::create(),
$this->createDummyQueueMetaRegistry()
);
@@ -44,7 +45,7 @@ public function testShouldReturnConfigObject()
{
$config = Config::create();
- $driver = new RabbitMqDriver($this->createPsrContextMock(), $config, $this->createDummyQueueMetaRegistry());
+ $driver = new RabbitMqDriver($this->createAmqpContextMock(), $config, $this->createDummyQueueMetaRegistry());
$this->assertSame($config, $driver->getConfig());
}
@@ -53,7 +54,7 @@ public function testShouldCreateAndReturnQueueInstance()
{
$expectedQueue = new AmqpQueue('aName');
- $context = $this->createPsrContextMock();
+ $context = $this->createAmqpContextMock();
$context
->expects($this->once())
->method('createQueue')
@@ -69,14 +70,13 @@ public function testShouldCreateAndReturnQueueInstance()
$this->assertSame([], $queue->getArguments());
$this->assertSame(2, $queue->getFlags());
$this->assertNull($queue->getConsumerTag());
- $this->assertSame([], $queue->getBindArguments());
}
public function testShouldCreateAndReturnQueueInstanceWithHardcodedTransportName()
{
$expectedQueue = new AmqpQueue('aName');
- $context = $this->createPsrContextMock();
+ $context = $this->createAmqpContextMock();
$context
->expects($this->once())
->method('createQueue')
@@ -107,7 +107,7 @@ public function testShouldConvertTransportMessageToClientMessage()
$transportMessage->setCorrelationId('theCorrelationId');
$driver = new RabbitMqDriver(
- $this->createPsrContextMock(),
+ $this->createAmqpContextMock(),
new Config('', '', '', '', '', '', ['delay_plugin_installed' => true]),
$this->createDummyQueueMetaRegistry()
);
@@ -146,7 +146,7 @@ public function testShouldThrowExceptionIfXDelayIsNotNumeric()
$transportMessage->setProperty('x-delay', 'is-not-numeric');
$driver = new RabbitMqDriver(
- $this->createPsrContextMock(),
+ $this->createAmqpContextMock(),
Config::create(),
$this->createDummyQueueMetaRegistry()
);
@@ -163,7 +163,7 @@ public function testShouldThrowExceptionIfExpirationIsNotNumeric()
$transportMessage->setHeader('expiration', 'is-not-numeric');
$driver = new RabbitMqDriver(
- $this->createPsrContextMock(),
+ $this->createAmqpContextMock(),
Config::create(),
$this->createDummyQueueMetaRegistry()
);
@@ -180,7 +180,7 @@ public function testShouldThrowExceptionIfCantConvertTransportPriorityToClientPr
$transportMessage->setHeader('priority', 'unknown');
$driver = new RabbitMqDriver(
- $this->createPsrContextMock(),
+ $this->createAmqpContextMock(),
Config::create(),
$this->createDummyQueueMetaRegistry()
);
@@ -196,7 +196,7 @@ public function testShouldThrowExceptionIfCantConvertClientPriorityToTransportPr
$clientMessage = new Message();
$clientMessage->setPriority('unknown');
- $context = $this->createPsrContextMock();
+ $context = $this->createAmqpContextMock();
$context
->expects($this->once())
->method('createMessage')
@@ -230,7 +230,7 @@ public function testShouldConvertClientMessageToTransportMessage()
$clientMessage->setReplyTo('theReplyTo');
$clientMessage->setCorrelationId('theCorrelationId');
- $context = $this->createPsrContextMock();
+ $context = $this->createAmqpContextMock();
$context
->expects($this->once())
->method('createMessage')
@@ -249,13 +249,13 @@ public function testShouldConvertClientMessageToTransportMessage()
$this->assertSame('body', $transportMessage->getBody());
$this->assertSame([
'hkey' => 'hval',
- 'content_type' => 'ContentType',
- 'expiration' => '123000',
- 'delivery_mode' => 2,
'message_id' => 'MessageId',
'timestamp' => 1000,
'reply_to' => 'theReplyTo',
'correlation_id' => 'theCorrelationId',
+ 'content_type' => 'ContentType',
+ 'delivery_mode' => 2,
+ 'expiration' => '123000',
'priority' => 4,
], $transportMessage->getHeaders());
$this->assertSame([
@@ -273,7 +273,7 @@ public function testThrowIfDelayNotSupportedOnConvertClientMessageToTransportMes
$clientMessage = new Message();
$clientMessage->setDelay(432);
- $context = $this->createPsrContextMock();
+ $context = $this->createAmqpContextMock();
$context
->expects($this->once())
->method('createMessage')
@@ -296,13 +296,13 @@ public function testShouldSendMessageToRouter()
$topic = new AmqpTopic('');
$transportMessage = new AmqpMessage();
- $producer = $this->createPsrProducerMock();
+ $producer = $this->createAmqpProducerMock();
$producer
->expects($this->once())
->method('send')
->with($this->identicalTo($topic), $this->identicalTo($transportMessage))
;
- $context = $this->createPsrContextMock();
+ $context = $this->createAmqpContextMock();
$context
->expects($this->once())
->method('createTopic')
@@ -334,7 +334,7 @@ public function testShouldSendMessageToRouter()
public function testShouldThrowExceptionIfTopicParameterIsNotSet()
{
$driver = new RabbitMqDriver(
- $this->createPsrContextMock(),
+ $this->createAmqpContextMock(),
Config::create(),
$this->createDummyQueueMetaRegistry()
);
@@ -350,13 +350,13 @@ public function testShouldSendMessageToProcessor()
$queue = new AmqpQueue('');
$transportMessage = new AmqpMessage();
- $producer = $this->createPsrProducerMock();
+ $producer = $this->createAmqpProducerMock();
$producer
->expects($this->once())
->method('send')
->with($this->identicalTo($queue), $this->identicalTo($transportMessage))
;
- $context = $this->createPsrContextMock();
+ $context = $this->createAmqpContextMock();
$context
->expects($this->once())
->method('createQueue')
@@ -392,13 +392,13 @@ public function testShouldSendMessageToDelayExchangeIfDelaySet()
$delayTopic = new AmqpTopic('');
$transportMessage = new AmqpMessage();
- $producer = $this->createPsrProducerMock();
+ $producer = $this->createAmqpProducerMock();
$producer
->expects($this->once())
->method('send')
->with($this->identicalTo($delayTopic), $this->identicalTo($transportMessage))
;
- $context = $this->createPsrContextMock();
+ $context = $this->createAmqpContextMock();
$context
->expects($this->once())
->method('createQueue')
@@ -437,7 +437,7 @@ public function testShouldSendMessageToDelayExchangeIfDelaySet()
public function testShouldThrowExceptionIfProcessorNameParameterIsNotSet()
{
$driver = new RabbitMqDriver(
- $this->createPsrContextMock(),
+ $this->createAmqpContextMock(),
Config::create(),
$this->createDummyQueueMetaRegistry()
);
@@ -451,7 +451,7 @@ public function testShouldThrowExceptionIfProcessorNameParameterIsNotSet()
public function testShouldThrowExceptionIfProcessorQueueNameParameterIsNotSet()
{
$driver = new RabbitMqDriver(
- $this->createPsrContextMock(),
+ $this->createAmqpContextMock(),
Config::create(),
$this->createDummyQueueMetaRegistry()
);
@@ -471,9 +471,8 @@ public function testShouldSetupBrokerWhenDelayPluginNotInstalled()
$routerQueue = new AmqpQueue('');
$processorQueue = new AmqpQueue('');
- $delayTopic = new AmqpTopic('');
- $context = $this->createPsrContextMock();
+ $context = $this->createAmqpContextMock();
// setup router
$context
->expects($this->at(0))
@@ -498,7 +497,7 @@ public function testShouldSetupBrokerWhenDelayPluginNotInstalled()
$context
->expects($this->at(4))
->method('bind')
- ->with($this->identicalTo($routerTopic), $this->identicalTo($routerQueue))
+ ->with($this->isInstanceOf(AmqpBind::class))
;
// setup processor queue
$context
@@ -524,7 +523,7 @@ public function testShouldSetupBroker()
$processorQueue = new AmqpQueue('');
$delayTopic = new AmqpTopic('');
- $context = $this->createPsrContextMock();
+ $context = $this->createAmqpContextMock();
// setup router
$context
->expects($this->at(0))
@@ -549,7 +548,7 @@ public function testShouldSetupBroker()
$context
->expects($this->at(4))
->method('bind')
- ->with($this->identicalTo($routerTopic), $this->identicalTo($routerQueue))
+ ->with($this->isInstanceOf(AmqpBind::class))
;
// setup processor queue
$context
@@ -581,7 +580,7 @@ public function testShouldSetupBroker()
$context
->expects($this->at(10))
->method('bind')
- ->with($this->identicalTo($delayTopic), $this->identicalTo($processorQueue))
+ ->with($this->isInstanceOf(AmqpBind::class))
;
$config = Config::create('', '', '', '', '', '', ['delay_plugin_installed' => true]);
@@ -596,17 +595,17 @@ public function testShouldSetupBroker()
/**
* @return \PHPUnit_Framework_MockObject_MockObject|AmqpContext
*/
- private function createPsrContextMock()
+ private function createAmqpContextMock()
{
return $this->createMock(AmqpContext::class);
}
/**
- * @return \PHPUnit_Framework_MockObject_MockObject|PsrProducer
+ * @return \PHPUnit_Framework_MockObject_MockObject|AmqpProducer
*/
- private function createPsrProducerMock()
+ private function createAmqpProducerMock()
{
- return $this->createMock(PsrProducer::class);
+ return $this->createMock(AmqpProducer::class);
}
/**
diff --git a/pkg/enqueue/Tests/Functions/DsnToConnectionFactoryFunctionTest.php b/pkg/enqueue/Tests/Functions/DsnToConnectionFactoryFunctionTest.php
index eb9447f95..fd455b15d 100644
--- a/pkg/enqueue/Tests/Functions/DsnToConnectionFactoryFunctionTest.php
+++ b/pkg/enqueue/Tests/Functions/DsnToConnectionFactoryFunctionTest.php
@@ -32,7 +32,7 @@ public function testThrowIfDsnMissingScheme()
public function testThrowIfDsnNotSupported()
{
$this->expectException(\LogicException::class);
- $this->expectExceptionMessage('The scheme "http" is not supported. Supported "file", "amqp", "null"');
+ $this->expectExceptionMessage('The scheme "http" is not supported. Supported "file", "amqp+ext"');
\Enqueue\dsn_to_connection_factory('http://schemenotsupported/');
}
@@ -68,7 +68,7 @@ public static function provideDSNs()
yield ['beanstalk://', PheanstalkConnectionFactory::class];
-// yield ['gearman://', GearmanConnectionFactory::class];
+ // yield ['gearman://', GearmanConnectionFactory::class];
yield ['rdkafka://', RdKafkaConnectionFactory::class];
}
diff --git a/pkg/enqueue/Tests/Functions/DsnToContextFunctionTest.php b/pkg/enqueue/Tests/Functions/DsnToContextFunctionTest.php
index d088bae93..54daf8c5f 100644
--- a/pkg/enqueue/Tests/Functions/DsnToContextFunctionTest.php
+++ b/pkg/enqueue/Tests/Functions/DsnToContextFunctionTest.php
@@ -28,7 +28,7 @@ public function testThrowIfDsnMissingScheme()
public function testThrowIfDsnNotSupported()
{
$this->expectException(\LogicException::class);
- $this->expectExceptionMessage('The scheme "http" is not supported. Supported "file", "amqp", "null"');
+ $this->expectExceptionMessage('The scheme "http" is not supported. Supported "file", "amqp+ext"');
\Enqueue\dsn_to_context('http://schemenotsupported/');
}
diff --git a/pkg/enqueue/Tests/fix_composer_json.php b/pkg/enqueue/Tests/fix_composer_json.php
new file mode 100644
index 000000000..bce1ebb75
--- /dev/null
+++ b/pkg/enqueue/Tests/fix_composer_json.php
@@ -0,0 +1,11 @@
+=5.6",
- "queue-interop/queue-interop": "^0.5@dev",
- "enqueue/null": "^0.6@dev",
+ "queue-interop/queue-interop": "^0.6@dev",
+ "enqueue/null": "^0.7@dev",
"ramsey/uuid": "^2|^3.5"
},
"require-dev": {
@@ -23,14 +23,14 @@
"symfony/config": "^2.8|^3",
"symfony/event-dispatcher": "^2.8|^3",
"symfony/http-kernel": "^2.8|^3",
- "enqueue/amqp-ext": "^0.6@dev",
- "enqueue/pheanstalk": "^0.6@dev",
- "enqueue/gearman": "^0.6@dev",
- "enqueue/rdkafka": "^0.6@dev",
- "enqueue/dbal": "^0.6@dev",
- "enqueue/fs": "^0.6@dev",
- "enqueue/test": "^0.6@dev",
- "enqueue/simple-client": "^0.6@dev",
+ "enqueue/amqp-ext": "^0.7@dev",
+ "enqueue/pheanstalk": "^0.7@dev",
+ "enqueue/gearman": "^0.7@dev",
+ "enqueue/rdkafka": "^0.7@dev",
+ "enqueue/dbal": "^0.7@dev",
+ "enqueue/fs": "^0.7@dev",
+ "enqueue/test": "^0.7@dev",
+ "enqueue/simple-client": "^0.7@dev",
"empi89/php-amqp-stubs": "*@dev"
},
"suggest": {
@@ -54,7 +54,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
- "dev-master": "0.6.x-dev"
+ "dev-master": "0.7.x-dev"
}
}
}
diff --git a/pkg/enqueue/functions.php b/pkg/enqueue/functions.php
index b071e0279..215899c50 100644
--- a/pkg/enqueue/functions.php
+++ b/pkg/enqueue/functions.php
@@ -2,7 +2,9 @@
namespace Enqueue;
-use Enqueue\AmqpExt\AmqpConnectionFactory;
+use Enqueue\AmqpBunny\AmqpConnectionFactory as AmqpBunnyConnectionFactory;
+use Enqueue\AmqpExt\AmqpConnectionFactory as AmqpExtConnectionFactory;
+use Enqueue\AmqpLib\AmqpConnectionFactory as AmqpLibConnectionFactory;
use Enqueue\Consumption\QueueConsumer;
use Enqueue\Dbal\DbalConnectionFactory;
use Enqueue\Fs\FsConnectionFactory;
@@ -26,8 +28,22 @@ function dsn_to_connection_factory($dsn)
$map['file'] = FsConnectionFactory::class;
}
- if (class_exists(AmqpConnectionFactory::class)) {
- $map['amqp'] = AmqpConnectionFactory::class;
+ if (class_exists(AmqpExtConnectionFactory::class)) {
+ $map['amqp+ext'] = AmqpExtConnectionFactory::class;
+ }
+ if (class_exists(AmqpBunnyConnectionFactory::class)) {
+ $map['amqp+lib'] = AmqpBunnyConnectionFactory::class;
+ }
+ if (class_exists(AmqpLibConnectionFactory::class)) {
+ $map['amqp+bunny'] = AmqpBunnyConnectionFactory::class;
+ }
+
+ if (class_exists(AmqpExtConnectionFactory::class)) {
+ $map['amqp'] = AmqpExtConnectionFactory::class;
+ } elseif (class_exists(AmqpBunnyConnectionFactory::class)) {
+ $map['amqp'] = AmqpBunnyConnectionFactory::class;
+ } elseif (class_exists(AmqpLibConnectionFactory::class)) {
+ $map['amqp'] = AmqpLibConnectionFactory::class;
}
if (class_exists(NullConnectionFactory::class)) {
diff --git a/pkg/fs/FsConsumer.php b/pkg/fs/FsConsumer.php
index d51f8e1e5..6dca254f2 100644
--- a/pkg/fs/FsConsumer.php
+++ b/pkg/fs/FsConsumer.php
@@ -89,7 +89,14 @@ public function receiveNoWait()
if ($rawMessage) {
try {
- $this->preFetchedMessages[] = FsMessage::jsonUnserialize($rawMessage);
+ $fetchedMessage = FsMessage::jsonUnserialize($rawMessage);
+ $expireAt = $fetchedMessage->getHeader('x-expire-at');
+ if ($expireAt && $expireAt - microtime(true) < 0) {
+ // message has expired, just drop it.
+ return;
+ }
+
+ $this->preFetchedMessages[] = $fetchedMessage;
} catch (\Exception $e) {
throw new \LogicException(sprintf("Cannot decode json message '%s'", $rawMessage), null, $e);
}
diff --git a/pkg/fs/FsProducer.php b/pkg/fs/FsProducer.php
index a61584321..a8dbac925 100644
--- a/pkg/fs/FsProducer.php
+++ b/pkg/fs/FsProducer.php
@@ -2,8 +2,10 @@
namespace Enqueue\Fs;
+use Interop\Queue\DeliveryDelayNotSupportedException;
use Interop\Queue\InvalidDestinationException;
use Interop\Queue\InvalidMessageException;
+use Interop\Queue\PriorityNotSupportedException;
use Interop\Queue\PsrDestination;
use Interop\Queue\PsrMessage;
use Interop\Queue\PsrProducer;
@@ -11,6 +13,11 @@
class FsProducer implements PsrProducer
{
+ /**
+ * @var float|int|null
+ */
+ private $timeToLive;
+
/**
* @var FsContext
*/
@@ -41,6 +48,10 @@ public function send(PsrDestination $destination, PsrMessage $message)
return;
}
+ if (null !== $this->timeToLive) {
+ $message->setHeader('x-expire-at', microtime(true) + ($this->timeToLive / 1000));
+ }
+
$rawMessage = '|'.json_encode($message);
if (JSON_ERROR_NONE !== json_last_error()) {
@@ -56,4 +67,62 @@ public function send(PsrDestination $destination, PsrMessage $message)
fwrite($file, $rawMessage);
});
}
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setDeliveryDelay($deliveryDelay)
+ {
+ if (null === $deliveryDelay) {
+ return;
+ }
+
+ throw DeliveryDelayNotSupportedException::providerDoestNotSupportIt();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDeliveryDelay()
+ {
+ return null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setPriority($priority)
+ {
+ if (null === $priority) {
+ return;
+ }
+
+ throw PriorityNotSupportedException::providerDoestNotSupportIt();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPriority()
+ {
+ return null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setTimeToLive($timeToLive)
+ {
+ $this->timeToLive = $timeToLive;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTimeToLive()
+ {
+ return null;
+ }
}
diff --git a/pkg/fs/Tests/Spec/FsSendAndReceiveTimeToLiveMessagesFromQueueTest.php b/pkg/fs/Tests/Spec/FsSendAndReceiveTimeToLiveMessagesFromQueueTest.php
new file mode 100644
index 000000000..3dd1697c7
--- /dev/null
+++ b/pkg/fs/Tests/Spec/FsSendAndReceiveTimeToLiveMessagesFromQueueTest.php
@@ -0,0 +1,20 @@
+createContext();
+ }
+}
diff --git a/pkg/fs/composer.json b/pkg/fs/composer.json
index 55317f73b..a80d9cde8 100644
--- a/pkg/fs/composer.json
+++ b/pkg/fs/composer.json
@@ -12,16 +12,16 @@
],
"require": {
"php": ">=5.6",
- "queue-interop/queue-interop": "^0.5@dev",
+ "queue-interop/queue-interop": "^0.6@dev",
"symfony/filesystem": "^2.8|^3",
"makasim/temp-file": "^0.2",
"psr/log": "^1"
},
"require-dev": {
"phpunit/phpunit": "~5.5",
- "enqueue/enqueue": "^0.6@dev",
- "enqueue/null": "^0.6@dev",
- "enqueue/test": "^0.6@dev",
+ "enqueue/enqueue": "^0.7@dev",
+ "enqueue/null": "^0.7@dev",
+ "enqueue/test": "^0.7@dev",
"queue-interop/queue-spec": "^0.5@dev",
"symfony/dependency-injection": "^2.8|^3",
"symfony/config": "^2.8|^3"
@@ -35,7 +35,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
- "dev-master": "0.6.x-dev"
+ "dev-master": "0.7.x-dev"
}
}
}
diff --git a/pkg/gearman/GearmanProducer.php b/pkg/gearman/GearmanProducer.php
index c7c072c76..73a2c073b 100644
--- a/pkg/gearman/GearmanProducer.php
+++ b/pkg/gearman/GearmanProducer.php
@@ -41,4 +41,64 @@ public function send(PsrDestination $destination, PsrMessage $message)
throw new \GearmanException(sprintf('The return code is not %s (GEARMAN_SUCCESS) but %s', \GEARMAN_SUCCESS, $code));
}
}
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setDeliveryDelay($deliveryDelay)
+ {
+ if (null === $deliveryDelay) {
+ return;
+ }
+
+ throw new \LogicException('Not implemented');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDeliveryDelay()
+ {
+ return null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setPriority($priority)
+ {
+ if (null === $priority) {
+ return;
+ }
+
+ throw new \LogicException('Not implemented');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPriority()
+ {
+ return null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setTimeToLive($timeToLive)
+ {
+ if (null === $timeToLive) {
+ return;
+ }
+
+ throw new \LogicException('Not implemented');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTimeToLive()
+ {
+ return null;
+ }
}
diff --git a/pkg/gearman/composer.json b/pkg/gearman/composer.json
index e70fc7134..002a0c5ea 100644
--- a/pkg/gearman/composer.json
+++ b/pkg/gearman/composer.json
@@ -13,13 +13,13 @@
"require": {
"php": ">=5.6",
"ext-gearman": "^1.1",
- "queue-interop/queue-interop": "^0.5@dev"
+ "queue-interop/queue-interop": "^0.6@dev"
},
"require-dev": {
"phpunit/phpunit": "~5.4.0",
- "enqueue/test": "^0.6@dev",
- "enqueue/enqueue": "^0.6@dev",
- "enqueue/null": "^0.6@dev",
+ "enqueue/test": "^0.7@dev",
+ "enqueue/enqueue": "^0.7@dev",
+ "enqueue/null": "^0.7@dev",
"queue-interop/queue-spec": "^0.5@dev",
"symfony/dependency-injection": "^2.8|^3",
"symfony/config": "^2.8|^3"
@@ -36,7 +36,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
- "dev-master": "0.6.x-dev"
+ "dev-master": "0.7.x-dev"
}
}
}
diff --git a/pkg/job-queue/composer.json b/pkg/job-queue/composer.json
index ae9e1b16d..918df1bdd 100644
--- a/pkg/job-queue/composer.json
+++ b/pkg/job-queue/composer.json
@@ -13,13 +13,13 @@
"require": {
"php": ">=5.6",
"symfony/framework-bundle": "^2.8|^3",
- "enqueue/enqueue": "^0.6@dev",
- "enqueue/null": "^0.6@dev",
+ "enqueue/enqueue": "^0.7@dev",
+ "enqueue/null": "^0.7@dev",
"doctrine/orm": "~2.4"
},
"require-dev": {
"phpunit/phpunit": "~5.5",
- "enqueue/test": "^0.6@dev",
+ "enqueue/test": "^0.7@dev",
"doctrine/doctrine-bundle": "~1.2",
"symfony/browser-kit": "^2.8|^3",
"symfony/expression-language": "^2.8|^3"
@@ -33,7 +33,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
- "dev-master": "0.6.x-dev"
+ "dev-master": "0.7.x-dev"
}
}
}
diff --git a/pkg/null/NullProducer.php b/pkg/null/NullProducer.php
index 307d992e8..47169a635 100644
--- a/pkg/null/NullProducer.php
+++ b/pkg/null/NullProducer.php
@@ -8,10 +8,70 @@
class NullProducer implements PsrProducer
{
+ private $priority;
+
+ private $timeToLive;
+
+ private $deliveryDelay;
+
/**
* {@inheritdoc}
*/
public function send(PsrDestination $destination, PsrMessage $message)
{
}
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setDeliveryDelay($deliveryDelay)
+ {
+ $this->deliveryDelay = $deliveryDelay;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDeliveryDelay()
+ {
+ return $this->deliveryDelay;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setPriority($priority)
+ {
+ $this->priority = $priority;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPriority()
+ {
+ return $this->priority;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setTimeToLive($timeToLive)
+ {
+ $this->timeToLive = $timeToLive;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTimeToLive()
+ {
+ return $this->timeToLive;
+ }
}
diff --git a/pkg/null/composer.json b/pkg/null/composer.json
index 5cf4e612f..8635a4288 100644
--- a/pkg/null/composer.json
+++ b/pkg/null/composer.json
@@ -12,13 +12,13 @@
],
"require": {
"php": ">=5.6",
- "queue-interop/queue-interop": "^0.5@dev",
+ "queue-interop/queue-interop": "^0.6@dev",
"psr/log": "^1"
},
"require-dev": {
"phpunit/phpunit": "~5.5",
- "enqueue/enqueue": "^0.6@dev",
- "enqueue/test": "^0.6@dev",
+ "enqueue/enqueue": "^0.7@dev",
+ "enqueue/test": "^0.7@dev",
"queue-interop/queue-spec": "^0.5@dev",
"symfony/dependency-injection": "^2.8|^3",
"symfony/config": "^2.8|^3"
@@ -32,7 +32,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
- "dev-master": "0.6.x-dev"
+ "dev-master": "0.7.x-dev"
}
}
}
diff --git a/pkg/pheanstalk/PheanstalkProducer.php b/pkg/pheanstalk/PheanstalkProducer.php
index 92ea44bec..08255e170 100644
--- a/pkg/pheanstalk/PheanstalkProducer.php
+++ b/pkg/pheanstalk/PheanstalkProducer.php
@@ -51,4 +51,64 @@ public function send(PsrDestination $destination, PsrMessage $message)
$message->getTimeToRun()
);
}
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setDeliveryDelay($deliveryDelay)
+ {
+ if (null === $deliveryDelay) {
+ return;
+ }
+
+ throw new \LogicException('Not implemented');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDeliveryDelay()
+ {
+ return null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setPriority($priority)
+ {
+ if (null === $priority) {
+ return;
+ }
+
+ throw new \LogicException('Not implemented');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPriority()
+ {
+ return null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setTimeToLive($timeToLive)
+ {
+ if (null === $timeToLive) {
+ return;
+ }
+
+ throw new \LogicException('Not implemented');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTimeToLive()
+ {
+ return null;
+ }
}
diff --git a/pkg/pheanstalk/composer.json b/pkg/pheanstalk/composer.json
index 8812fe21f..16e2cda6b 100644
--- a/pkg/pheanstalk/composer.json
+++ b/pkg/pheanstalk/composer.json
@@ -13,13 +13,13 @@
"require": {
"php": ">=5.6",
"pda/pheanstalk": "^3",
- "queue-interop/queue-interop": "^0.5@dev"
+ "queue-interop/queue-interop": "^0.6@dev"
},
"require-dev": {
"phpunit/phpunit": "~5.4.0",
- "enqueue/test": "^0.6@dev",
- "enqueue/enqueue": "^0.6@dev",
- "enqueue/null": "^0.6@dev",
+ "enqueue/test": "^0.7@dev",
+ "enqueue/enqueue": "^0.7@dev",
+ "enqueue/null": "^0.7@dev",
"queue-interop/queue-spec": "^0.5@dev",
"symfony/dependency-injection": "^2.8|^3",
"symfony/config": "^2.8|^3"
@@ -36,7 +36,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
- "dev-master": "0.6.x-dev"
+ "dev-master": "0.7.x-dev"
}
}
}
diff --git a/pkg/rdkafka/.travis.yml b/pkg/rdkafka/.travis.yml
index aaa1849c3..2f48cf85d 100644
--- a/pkg/rdkafka/.travis.yml
+++ b/pkg/rdkafka/.travis.yml
@@ -14,8 +14,9 @@ cache:
- $HOME/.composer/cache
install:
+ - php Tests/fix_composer_json.php
- composer self-update
- - composer install --prefer-source --ignore-platform-reqs
+ - composer install
script:
- vendor/bin/phpunit --exclude-group=functional
diff --git a/pkg/rdkafka/RdKafkaProducer.php b/pkg/rdkafka/RdKafkaProducer.php
index b99c3300b..ffad80075 100644
--- a/pkg/rdkafka/RdKafkaProducer.php
+++ b/pkg/rdkafka/RdKafkaProducer.php
@@ -42,4 +42,64 @@ public function send(PsrDestination $destination, PsrMessage $message)
$topic = $this->producer->newTopic($destination->getTopicName(), $destination->getConf());
$topic->produce($partition, 0 /* must be 0 */, $payload, $key);
}
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setDeliveryDelay($deliveryDelay)
+ {
+ if (null === $deliveryDelay) {
+ return;
+ }
+
+ throw new \LogicException('Not implemented');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDeliveryDelay()
+ {
+ return null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setPriority($priority)
+ {
+ if (null === $priority) {
+ return;
+ }
+
+ throw new \LogicException('Not implemented');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPriority()
+ {
+ return null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setTimeToLive($timeToLive)
+ {
+ if (null === $timeToLive) {
+ return;
+ }
+
+ throw new \LogicException('Not implemented');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTimeToLive()
+ {
+ return null;
+ }
}
diff --git a/pkg/rdkafka/Tests/Spec/RdKafkaSendToAndReceiveFromTopicTest.php b/pkg/rdkafka/Tests/Spec/RdKafkaSendToAndReceiveFromTopicTest.php
index 808721681..4bb32d7a5 100644
--- a/pkg/rdkafka/Tests/Spec/RdKafkaSendToAndReceiveFromTopicTest.php
+++ b/pkg/rdkafka/Tests/Spec/RdKafkaSendToAndReceiveFromTopicTest.php
@@ -8,6 +8,7 @@
/**
* @group functional
+ * @retry 5
*/
class RdKafkaSendToAndReceiveFromTopicTest extends SendToAndReceiveFromTopicSpec
{
diff --git a/pkg/rdkafka/Tests/fix_composer_json.php b/pkg/rdkafka/Tests/fix_composer_json.php
new file mode 100644
index 000000000..b778f6f69
--- /dev/null
+++ b/pkg/rdkafka/Tests/fix_composer_json.php
@@ -0,0 +1,9 @@
+=5.6",
"ext-rdkafka": "^3.0.3",
- "queue-interop/queue-interop": "^0.5@dev",
+ "queue-interop/queue-interop": "^0.6@dev",
"psr/log": "^1"
},
"require-dev": {
"phpunit/phpunit": "~5.4.0",
- "enqueue/test": "^0.6@dev",
- "enqueue/enqueue": "^0.6@dev",
- "enqueue/null": "^0.6@dev",
+ "enqueue/test": "^0.7@dev",
+ "enqueue/enqueue": "^0.7@dev",
+ "enqueue/null": "^0.7@dev",
"queue-interop/queue-spec": "^0.5@dev",
"kwn/php-rdkafka-stubs": "^1.0.2"
},
@@ -47,7 +47,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
- "dev-master": "0.6.x-dev"
+ "dev-master": "0.7.x-dev"
}
}
}
diff --git a/pkg/redis/RedisProducer.php b/pkg/redis/RedisProducer.php
index 55f65b1c2..e34506b3a 100644
--- a/pkg/redis/RedisProducer.php
+++ b/pkg/redis/RedisProducer.php
@@ -36,4 +36,64 @@ public function send(PsrDestination $destination, PsrMessage $message)
$this->redis->lpush($destination->getName(), json_encode($message));
}
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setDeliveryDelay($deliveryDelay)
+ {
+ if (null === $deliveryDelay) {
+ return;
+ }
+
+ throw new \LogicException('Not implemented');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDeliveryDelay()
+ {
+ return null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setPriority($priority)
+ {
+ if (null === $priority) {
+ return;
+ }
+
+ throw new \LogicException('Not implemented');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPriority()
+ {
+ return null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setTimeToLive($timeToLive)
+ {
+ if (null === $timeToLive) {
+ return;
+ }
+
+ throw new \LogicException('Not implemented');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTimeToLive()
+ {
+ return null;
+ }
}
diff --git a/pkg/redis/composer.json b/pkg/redis/composer.json
index c66dac27a..6af42f97d 100644
--- a/pkg/redis/composer.json
+++ b/pkg/redis/composer.json
@@ -12,15 +12,15 @@
],
"require": {
"php": ">=5.6",
- "queue-interop/queue-interop": "^0.5@dev",
+ "queue-interop/queue-interop": "^0.6@dev",
"psr/log": "^1"
},
"require-dev": {
"phpunit/phpunit": "~5.4.0",
"predis/predis": "^1.1",
- "enqueue/test": "^0.6@dev",
- "enqueue/enqueue": "^0.6@dev",
- "enqueue/null": "^0.6@dev",
+ "enqueue/test": "^0.7@dev",
+ "enqueue/enqueue": "^0.7@dev",
+ "enqueue/null": "^0.7@dev",
"queue-interop/queue-spec": "^0.5@dev",
"symfony/dependency-injection": "^2.8|^3",
"symfony/config": "^2.8|^3"
@@ -39,7 +39,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
- "dev-master": "0.6.x-dev"
+ "dev-master": "0.7.x-dev"
}
}
}
diff --git a/pkg/simple-client/SimpleClientContainerExtension.php b/pkg/simple-client/SimpleClientContainerExtension.php
index 7fea6f03b..f10a7b186 100644
--- a/pkg/simple-client/SimpleClientContainerExtension.php
+++ b/pkg/simple-client/SimpleClientContainerExtension.php
@@ -172,7 +172,7 @@ private function createConfiguration()
->arrayNode('client')->children()
->scalarNode('prefix')->defaultValue('enqueue')->end()
->scalarNode('app_name')->defaultValue('app')->end()
- ->scalarNode('router_topic')->defaultValue('router')->cannotBeEmpty()->end()
+ ->scalarNode('router_topic')->defaultValue(Config::DEFAULT_PROCESSOR_QUEUE_NAME)->cannotBeEmpty()->end()
->scalarNode('router_queue')->defaultValue(Config::DEFAULT_PROCESSOR_QUEUE_NAME)->cannotBeEmpty()->end()
->scalarNode('default_processor_queue')->defaultValue(Config::DEFAULT_PROCESSOR_QUEUE_NAME)->cannotBeEmpty()->end()
->integerNode('redelivered_delay_time')->min(0)->defaultValue(0)->end()
diff --git a/pkg/simple-client/composer.json b/pkg/simple-client/composer.json
index 22d24d414..ee7f87067 100644
--- a/pkg/simple-client/composer.json
+++ b/pkg/simple-client/composer.json
@@ -12,17 +12,17 @@
],
"require": {
"php": ">=5.6",
- "enqueue/enqueue": "^0.6@dev",
+ "enqueue/enqueue": "^0.7@dev",
"symfony/dependency-injection": "^2.8|^3",
"symfony/config": "^2.8|^3",
"symfony/console": "^2.8|^3"
},
"require-dev": {
"phpunit/phpunit": "~5.5",
- "enqueue/test": "^0.6@dev",
- "enqueue/amqp-ext": "^0.6@dev",
- "enqueue/fs": "^0.6@dev",
- "enqueue/null": "^0.6@dev"
+ "enqueue/test": "^0.7@dev",
+ "enqueue/amqp-ext": "^0.7@dev",
+ "enqueue/fs": "^0.7@dev",
+ "enqueue/null": "^0.7@dev"
},
"autoload": {
"psr-4": { "Enqueue\\SimpleClient\\": "" },
@@ -33,7 +33,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
- "dev-master": "0.6.x-dev"
+ "dev-master": "0.7.x-dev"
}
}
}
diff --git a/pkg/sqs/Client/SqsDriver.php b/pkg/sqs/Client/SqsDriver.php
index dc14bf2ff..c86237309 100644
--- a/pkg/sqs/Client/SqsDriver.php
+++ b/pkg/sqs/Client/SqsDriver.php
@@ -97,7 +97,7 @@ public function setupBroker(LoggerInterface $logger = null)
{
$logger = $logger ?: new NullLogger();
$log = function ($text, ...$args) use ($logger) {
- $logger->debug(sprintf('[AmqpDriver] '.$text, ...$args));
+ $logger->debug(sprintf('[SqsDriver] '.$text, ...$args));
};
// setup router
diff --git a/pkg/sqs/SqsProducer.php b/pkg/sqs/SqsProducer.php
index 0ea55340d..3acdce608 100644
--- a/pkg/sqs/SqsProducer.php
+++ b/pkg/sqs/SqsProducer.php
@@ -4,12 +4,19 @@
use Interop\Queue\InvalidDestinationException;
use Interop\Queue\InvalidMessageException;
+use Interop\Queue\PriorityNotSupportedException;
use Interop\Queue\PsrDestination;
use Interop\Queue\PsrMessage;
use Interop\Queue\PsrProducer;
+use Interop\Queue\TimeToLiveNotSupportedException;
class SqsProducer implements PsrProducer
{
+ /**
+ * @var int|float|null
+ */
+ private $deliveryDelay;
+
/**
* @var SqsContext
*/
@@ -55,6 +62,10 @@ public function send(PsrDestination $destination, PsrMessage $message)
'QueueUrl' => $this->context->getQueueUrl($destination),
];
+ if (null !== $this->deliveryDelay) {
+ $arguments['DelaySeconds'] = (int) $this->deliveryDelay / 1000;
+ }
+
if ($message->getDelaySeconds()) {
$arguments['DelaySeconds'] = $message->getDelaySeconds();
}
@@ -73,4 +84,62 @@ public function send(PsrDestination $destination, PsrMessage $message)
throw new \RuntimeException('Message was not sent');
}
}
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setDeliveryDelay($deliveryDelay)
+ {
+ $this->deliveryDelay = $deliveryDelay;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDeliveryDelay()
+ {
+ return $this->deliveryDelay;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setPriority($priority)
+ {
+ if (null === $priority) {
+ return;
+ }
+
+ throw PriorityNotSupportedException::providerDoestNotSupportIt();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPriority()
+ {
+ return null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setTimeToLive($timeToLive)
+ {
+ if (null === $timeToLive) {
+ return;
+ }
+
+ throw TimeToLiveNotSupportedException::providerDoestNotSupportIt();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTimeToLive()
+ {
+ return null;
+ }
}
diff --git a/pkg/sqs/Tests/Functional/SqsConsumptionUseCasesTest.php b/pkg/sqs/Tests/Functional/SqsConsumptionUseCasesTest.php
index 35e978c23..490c70ebf 100644
--- a/pkg/sqs/Tests/Functional/SqsConsumptionUseCasesTest.php
+++ b/pkg/sqs/Tests/Functional/SqsConsumptionUseCasesTest.php
@@ -9,6 +9,7 @@
use Enqueue\Consumption\QueueConsumer;
use Enqueue\Consumption\Result;
use Enqueue\Sqs\SqsContext;
+use Enqueue\Test\RetryTrait;
use Enqueue\Test\SqsExtension;
use Interop\Queue\PsrContext;
use Interop\Queue\PsrMessage;
@@ -18,6 +19,7 @@
class SqsConsumptionUseCasesTest extends TestCase
{
use SqsExtension;
+ use RetryTrait;
/**
* @var SqsContext
@@ -43,6 +45,9 @@ protected function setUp()
}
}
+ /**
+ * @retry 5
+ */
public function testConsumeOneMessageAndExit()
{
$queue = $this->context->createQueue('enqueue_test_queue');
@@ -64,6 +69,9 @@ public function testConsumeOneMessageAndExit()
$this->assertEquals(__METHOD__, $processor->lastProcessedMessage->getBody());
}
+ /**
+ * @retry 5
+ */
public function testConsumeOneMessageAndSendReplyExit()
{
$queue = $this->context->createQueue('enqueue_test_queue');
diff --git a/pkg/sqs/Tests/Spec/SqsProducerTest.php b/pkg/sqs/Tests/Spec/SqsProducerTest.php
new file mode 100644
index 000000000..cd61b9d2a
--- /dev/null
+++ b/pkg/sqs/Tests/Spec/SqsProducerTest.php
@@ -0,0 +1,26 @@
+ getenv('AWS__SQS__KEY'),
+ 'secret' => getenv('AWS__SQS__SECRET'),
+ 'region' => getenv('AWS__SQS__REGION'),
+ ]);
+
+ return $factory->createContext()->createProducer();
+ }
+}
diff --git a/pkg/sqs/Tests/Spec/SqsSendAndReceiveDelayedMessageFromQueueTest.php b/pkg/sqs/Tests/Spec/SqsSendAndReceiveDelayedMessageFromQueueTest.php
new file mode 100644
index 000000000..9fd3e96b8
--- /dev/null
+++ b/pkg/sqs/Tests/Spec/SqsSendAndReceiveDelayedMessageFromQueueTest.php
@@ -0,0 +1,47 @@
+ getenv('AWS__SQS__KEY'),
+ 'secret' => getenv('AWS__SQS__SECRET'),
+ 'region' => getenv('AWS__SQS__REGION'),
+ ]);
+
+ return $factory->createContext();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param SqsContext $context
+ */
+ protected function createQueue(PsrContext $context, $queueName)
+ {
+ $queueName = $queueName.time();
+
+ $queue = $context->createQueue($queueName);
+ $context->declareQueue($queue);
+
+ return $queue;
+ }
+}
diff --git a/pkg/sqs/Tests/Spec/SqsSendToAndReceiveFromQueueTest.php b/pkg/sqs/Tests/Spec/SqsSendToAndReceiveFromQueueTest.php
new file mode 100644
index 000000000..3e73cd489
--- /dev/null
+++ b/pkg/sqs/Tests/Spec/SqsSendToAndReceiveFromQueueTest.php
@@ -0,0 +1,43 @@
+ getenv('AWS__SQS__KEY'),
+ 'secret' => getenv('AWS__SQS__SECRET'),
+ 'region' => getenv('AWS__SQS__REGION'),
+ ]);
+
+ return $factory->createContext();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param SqsContext $context
+ */
+ protected function createQueue(PsrContext $context, $queueName)
+ {
+ $queueName = $queueName.time();
+
+ $queue = $context->createQueue($queueName);
+ $context->declareQueue($queue);
+
+ return $queue;
+ }
+}
diff --git a/pkg/sqs/Tests/Spec/SqsSendToAndReceiveFromTopicTest.php b/pkg/sqs/Tests/Spec/SqsSendToAndReceiveFromTopicTest.php
new file mode 100644
index 000000000..5c4595e88
--- /dev/null
+++ b/pkg/sqs/Tests/Spec/SqsSendToAndReceiveFromTopicTest.php
@@ -0,0 +1,43 @@
+ getenv('AWS__SQS__KEY'),
+ 'secret' => getenv('AWS__SQS__SECRET'),
+ 'region' => getenv('AWS__SQS__REGION'),
+ ]);
+
+ return $factory->createContext();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param SqsContext $context
+ */
+ protected function createTopic(PsrContext $context, $topicName)
+ {
+ $topicName = $topicName.time();
+
+ $topic = $context->createTopic($topicName);
+ $context->declareQueue($topic);
+
+ return $topic;
+ }
+}
diff --git a/pkg/sqs/Tests/Spec/SqsSendToAndReceiveNoWaitFromQueueTest.php b/pkg/sqs/Tests/Spec/SqsSendToAndReceiveNoWaitFromQueueTest.php
new file mode 100644
index 000000000..9301c647b
--- /dev/null
+++ b/pkg/sqs/Tests/Spec/SqsSendToAndReceiveNoWaitFromQueueTest.php
@@ -0,0 +1,24 @@
+markTestSkipped('The test is fragile. This is how SQS.');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function createContext()
+ {
+ throw new \LogicException('Should not be ever called');
+ }
+}
diff --git a/pkg/sqs/Tests/Spec/SqsSendToAndReceiveNoWaitFromTopicTest.php b/pkg/sqs/Tests/Spec/SqsSendToAndReceiveNoWaitFromTopicTest.php
new file mode 100644
index 000000000..3d9149b05
--- /dev/null
+++ b/pkg/sqs/Tests/Spec/SqsSendToAndReceiveNoWaitFromTopicTest.php
@@ -0,0 +1,24 @@
+markTestSkipped('The test is fragile. This is how SQS.');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function createContext()
+ {
+ throw new \LogicException('Should not be ever called');
+ }
+}
diff --git a/pkg/sqs/Tests/Spec/SqsSendToTopicAndReceiveFromQueueTest.php b/pkg/sqs/Tests/Spec/SqsSendToTopicAndReceiveFromQueueTest.php
new file mode 100644
index 000000000..a9db45362
--- /dev/null
+++ b/pkg/sqs/Tests/Spec/SqsSendToTopicAndReceiveFromQueueTest.php
@@ -0,0 +1,24 @@
+markTestSkipped('The SQS does not support it');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function createContext()
+ {
+ throw new \LogicException('Should not be ever called');
+ }
+}
diff --git a/pkg/sqs/Tests/Spec/SqsSendToTopicAndReceiveNoWaitFromQueueTest.php b/pkg/sqs/Tests/Spec/SqsSendToTopicAndReceiveNoWaitFromQueueTest.php
new file mode 100644
index 000000000..bbb9be63a
--- /dev/null
+++ b/pkg/sqs/Tests/Spec/SqsSendToTopicAndReceiveNoWaitFromQueueTest.php
@@ -0,0 +1,24 @@
+markTestSkipped('The SQS does not support it');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function createContext()
+ {
+ throw new \LogicException('Should not be ever called');
+ }
+}
diff --git a/pkg/sqs/Tests/SqsProducerTest.php b/pkg/sqs/Tests/SqsProducerTest.php
index 9be09ce78..445b9cef0 100644
--- a/pkg/sqs/Tests/SqsProducerTest.php
+++ b/pkg/sqs/Tests/SqsProducerTest.php
@@ -130,6 +130,56 @@ public function testShouldSendMessage()
$producer->send($destination, $message);
}
+ public function testShouldSendDelayedMessage()
+ {
+ $expectedArguments = [
+ 'MessageAttributes' => [
+ 'Headers' => [
+ 'DataType' => 'String',
+ 'StringValue' => '[{"hkey":"hvaleu"},{"key":"value"}]',
+ ],
+ ],
+ 'MessageBody' => 'theBody',
+ 'QueueUrl' => 'theQueueUrl',
+ 'DelaySeconds' => 12345,
+ 'MessageDeduplicationId' => 'theDeduplicationId',
+ 'MessageGroupId' => 'groupId',
+ ];
+
+ $client = $this->createSqsClientMock();
+ $client
+ ->expects($this->once())
+ ->method('sendMessage')
+ ->with($this->identicalTo($expectedArguments))
+ ->willReturn(new Result())
+ ;
+
+ $context = $this->createSqsContextMock();
+ $context
+ ->expects($this->once())
+ ->method('getQueueUrl')
+ ->willReturn('theQueueUrl')
+ ;
+ $context
+ ->expects($this->once())
+ ->method('getClient')
+ ->will($this->returnValue($client))
+ ;
+
+ $destination = new SqsDestination('queue-name');
+ $message = new SqsMessage('theBody', ['key' => 'value'], ['hkey' => 'hvaleu']);
+ $message->setDelaySeconds(12345);
+ $message->setMessageDeduplicationId('theDeduplicationId');
+ $message->setMessageGroupId('groupId');
+
+ $this->expectException(\RuntimeException::class);
+ $this->expectExceptionMessage('Message was not sent');
+
+ $producer = new SqsProducer($context);
+ $producer->setDeliveryDelay(5000);
+ $producer->send($destination, $message);
+ }
+
/**
* @return \PHPUnit_Framework_MockObject_MockObject|SqsContext
*/
diff --git a/pkg/sqs/composer.json b/pkg/sqs/composer.json
index 14a820964..e14063309 100644
--- a/pkg/sqs/composer.json
+++ b/pkg/sqs/composer.json
@@ -12,14 +12,14 @@
],
"require": {
"php": ">=5.6",
- "queue-interop/queue-interop": "^0.5@dev",
+ "queue-interop/queue-interop": "^0.6@dev",
"aws/aws-sdk-php": "~3.26",
"psr/log": "^1"
},
"require-dev": {
"phpunit/phpunit": "~5.4.0",
- "enqueue/test": "^0.6@dev",
- "enqueue/enqueue": "^0.6@dev",
+ "enqueue/test": "^0.7@dev",
+ "enqueue/enqueue": "^0.7@dev",
"queue-interop/queue-spec": "^0.5@dev",
"symfony/dependency-injection": "^2.8|^3",
"symfony/config": "^2.8|^3"
@@ -36,7 +36,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
- "dev-master": "0.6.x-dev"
+ "dev-master": "0.7.x-dev"
}
}
}
diff --git a/pkg/stomp/StompProducer.php b/pkg/stomp/StompProducer.php
index 17bafbebe..8e386fc3b 100644
--- a/pkg/stomp/StompProducer.php
+++ b/pkg/stomp/StompProducer.php
@@ -44,4 +44,64 @@ public function send(PsrDestination $destination, PsrMessage $message)
$this->stomp->send($destination->getQueueName(), $stompMessage);
}
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setDeliveryDelay($deliveryDelay)
+ {
+ if (null === $deliveryDelay) {
+ return;
+ }
+
+ throw new \LogicException('Not implemented');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDeliveryDelay()
+ {
+ return null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setPriority($priority)
+ {
+ if (null === $priority) {
+ return;
+ }
+
+ throw new \LogicException('Not implemented');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPriority()
+ {
+ return null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setTimeToLive($timeToLive)
+ {
+ if (null === $timeToLive) {
+ return;
+ }
+
+ throw new \LogicException('Not implemented');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTimeToLive()
+ {
+ return null;
+ }
}
diff --git a/pkg/stomp/composer.json b/pkg/stomp/composer.json
index 6600f4642..996dce855 100644
--- a/pkg/stomp/composer.json
+++ b/pkg/stomp/composer.json
@@ -13,16 +13,16 @@
"require": {
"php": ">=5.6",
"stomp-php/stomp-php": "^4",
- "queue-interop/queue-interop": "^0.5@dev",
+ "queue-interop/queue-interop": "^0.6@dev",
"php-http/guzzle6-adapter": "^1.1",
"richardfullmer/rabbitmq-management-api": "^2.0",
"psr/log": "^1"
},
"require-dev": {
"phpunit/phpunit": "~5.4.0",
- "enqueue/test": "^0.6@dev",
- "enqueue/enqueue": "^0.6@dev",
- "enqueue/null": "^0.6@dev",
+ "enqueue/test": "^0.7@dev",
+ "enqueue/enqueue": "^0.7@dev",
+ "enqueue/null": "^0.7@dev",
"queue-interop/queue-spec": "^0.5@dev",
"symfony/dependency-injection": "^2.8|^3",
"symfony/config": "^2.8|^3"
@@ -39,7 +39,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
- "dev-master": "0.6.x-dev"
+ "dev-master": "0.7.x-dev"
}
}
}
diff --git a/pkg/test/RetryTrait.php b/pkg/test/RetryTrait.php
new file mode 100644
index 000000000..cc8c377e4
--- /dev/null
+++ b/pkg/test/RetryTrait.php
@@ -0,0 +1,50 @@
+getNumberOfRetries();
+ for ($i = 0; $i < $numberOfRetires; ++$i) {
+ try {
+ parent::runBare();
+
+ return;
+ } catch (\PHPUnit_Framework_IncompleteTestError $e) {
+ throw $e;
+ } catch (\PHPUnit_Framework_SkippedTestError $e) {
+ throw $e;
+ } catch (\Throwable $e) {
+ // last one thrown below
+ } catch (\Exception $e) {
+ // last one thrown below
+ }
+ }
+
+ if ($e) {
+ throw $e;
+ }
+ }
+
+ /**
+ * @return int
+ */
+ private function getNumberOfRetries()
+ {
+ $annotations = $this->getAnnotations();
+
+ if (isset($annotations['method']['retry'])) {
+ return $annotations['method']['retry'];
+ }
+
+ if (isset($annotations['class']['retry'][0])) {
+ return $annotations['class']['retry'][0];
+ }
+
+ return 1;
+ }
+}
diff --git a/pkg/test/composer.json b/pkg/test/composer.json
index 5b0c9d638..5c89bfd2e 100644
--- a/pkg/test/composer.json
+++ b/pkg/test/composer.json
@@ -7,7 +7,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
- "dev-master": "0.6.x-dev"
+ "dev-master": "0.7.x-dev"
}
}
}