├── .gitignore ├── .travis.yml ├── README.md ├── composer.json ├── phpunit.xml.dist ├── src ├── Shell │ └── Task │ │ └── QueueWorkerTask.php └── SimpleQueue.php ├── tests ├── TestCase │ ├── Shell │ │ └── Task │ │ │ └── QueueWorkerTaskTest.php │ └── SimpleQueueTest.php ├── bootstrap.php └── fixtures │ ├── SimpleQueueTest_testDeleteMessage │ ├── SimpleQueueTest_testGetAttributes │ ├── SimpleQueueTest_testReceiveMessage │ ├── SimpleQueueTest_testSend │ ├── SimpleQueueTest_testSendBatch │ ├── SimpleQueueTest_testSendBatchEmpty │ └── SimpleQueueTest_testSendInvalidCredentials └── todo.txt /.gitignore: -------------------------------------------------------------------------------- 1 | /tmp 2 | /vendor 3 | /.idea 4 | composer.lock 5 | .php_cs* 6 | /coverage 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.6 5 | - 7.0 6 | - 7.1 7 | 8 | sudo: false 9 | 10 | env: 11 | matrix: 12 | - DB=mysql db_dsn='mysql://travis@0.0.0.0/cakephp_test' 13 | - DB=pgsql db_dsn='postgres://postgres@127.0.0.1/cakephp_test' 14 | - DB=sqlite db_dsn='sqlite:///:memory:' 15 | 16 | global: 17 | - DEFAULT=1 18 | 19 | matrix: 20 | fast_finish: true 21 | 22 | include: 23 | - php: 5.6 24 | env: PHPCS=1 DEFAULT=0 25 | 26 | - php: 5.6 27 | env: COVERALLS=1 DEFAULT=0 DB=mysql db_dsn='mysql://travis@0.0.0.0/cakephp_test' 28 | 29 | before_script: 30 | - composer self-update 31 | - composer install --prefer-dist --no-interaction 32 | 33 | - sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'CREATE DATABASE cakephp_test;'; fi" 34 | - sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'CREATE DATABASE cakephp_test;' -U postgres; fi" 35 | 36 | - sh -c "if [ '$PHPCS' = '1' ]; then composer require 'cakephp/cakephp-codesniffer:@stable'; fi" 37 | 38 | - sh -c "if [ '$COVERALLS' = '1' ]; then composer require --dev 'satooshi/php-coveralls:@stable'; fi" 39 | - sh -c "if [ '$COVERALLS' = '1' ]; then mkdir -p build/logs; fi" 40 | 41 | script: 42 | - sh -c "if [ '$DEFAULT' = '1' ]; then ./vendor/bin/phpunit --stderr; fi" 43 | - sh -c "if [ '$PHPCS' = '1' ]; then ./vendor/bin/phpcs -p -n --extensions=php --standard=vendor/cakephp/cakephp-codesniffer/CakePHP ./src ./tests; fi" 44 | - sh -c "if [ '$COVERALLS' = '1' ]; then ./vendor/bin/phpunit --stderr --coverage-clover build/logs/clover.xml; fi" 45 | - sh -c "if [ '$COVERALLS' = '1' ]; then php vendor/bin/coveralls -c .coveralls.yml -v; fi" 46 | 47 | notifications: 48 | email: false 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS Simple Queue Service for CakePHP 3 # 2 | 3 | [![Build Status](https://travis-ci.org/lorenzo/cakephp-sqs.png?branch=master)](https://travis-ci.org/lorenzo/cakephp-sqs) 4 | 5 | This plugin is an adaptor for the original AWS SDK classes related to the Simple Queue Service (SQS). What in offers is an utility 6 | class that will handle construction and configuration of the HTTP client based on the information stored in the Configure class. 7 | 8 | Additionally, it provides a Task class that will help you build long lived worker processes in no time. 9 | 10 | ## Requirements ## 11 | 12 | * CakePHP 3.4.x 13 | * PHP 5.6+ 14 | 15 | ## Installation ## 16 | 17 | The only installation method supported by this plugin is by using composer. Just add this to your composer.json configuration: 18 | 19 | composer require lorenzo/cakephp-sqs 20 | 21 | ### Enable plugin 22 | 23 | You need to enable the plugin your `config/bootstrap.php` file: 24 | 25 | Plugin::load('CakeSQS'); 26 | 27 | ### Configuration 28 | 29 | The plugin expects the following configuration data in the Configure keys: 30 | 31 | Configure::write('CakeSQS', [ 32 | 'connection' => [ 33 | /** 34 | * @see http://docs.aws.amazon.com/aws-sdk-php/v3/api/class-Aws.Sqs.SqsClient.html#___construct 35 | * for all possible config params 36 | */ 37 | 'credentials' => [ 38 | 'key' => 'Your amazon key', 39 | 'secret' => 'Your amazon secret', 40 | ], 41 | 'version' => '2012-11-05', // you don't need to change this 42 | 'region' => 'eu-central-1' // must match the region where the sqs queue was created 43 | ], 44 | 'queues' => [ 45 | 'testQueue1' => 'sqs queue url, for example: https://sqs.eu-central-1.amazonaws.com/12345/someQueue' 46 | ] 47 | ]); 48 | 49 | Or you can configure the connector class via `setConfig` 50 | 51 | $this->SimpleQueue = new SimpleQueue(); 52 | $this->SimpleQueue->setConfig([ 53 | 'connection.credentials' => [ 54 | 'key' => 'SOMEKEY', 55 | 'secret' => 'SOMESECRET', 56 | ], 57 | 'queues.testQueue1' => 'sqs queue url, for example: https://sqs.eu-central-1.amazonaws.com/12345/someQueue' 58 | ]); 59 | 60 | 61 | ## Storing a message in the Queue 62 | 63 | $this->SimpleQueue->send('testQueue1', [ 64 | 'key1' => 'value1', 65 | 'key2' => 'value2', 66 | ]); 67 | 68 | The return value is an \Aws\Result object 69 | 70 | ## Storing multiple messages as a batch 71 | 72 | $this->SimpleQueue->send('testQueue1', [ 73 | 'key1' => 'value1', 74 | 'key2' => 'value2', 75 | ]); 76 | 77 | The return value of this method is an array with all messages that could not be stored (if any), having the same numeric position 78 | in the array as the one you sent. For example if the second and forth messages in your array failed, then the array will contain: 79 | 80 | [1 => 'Error Message', 3 => 'Another error message'] 81 | 82 | ## Receiving a message from a queue 83 | 84 | $msgResult = $this->SimpleQueue->receiveMessage('testQueue1'); 85 | 86 | The return value is unaltered from the AWS SDK. Please refer to its documentation for more info. For example: 87 | 88 | $msgResult = $this->SimpleQueue->receiveMessage('testQueue1'); 89 | $msgResult->search('Messages'); 90 | // would return 91 | [ 92 | [ 93 | 'MessageId' => '929a9cfe-0d45-494c-80fc-41ec6e2e017d', 94 | 'ReceiptHandle' => 'AQEBEYj8zzBaKn8PpJiHgvyznyo7H0BQYH7MBy7429K/ad53lXLRh5yu2Yb0EH9o22WskOCTX7enwcGxTc7JQLQPcJwFwJB/L29pVOyDvZc8fI2XPjd+7jbN91H6PqfHUUsryiDHkA36ZH0tWKjFOVt986GKptqdON+BbinT2KIjd5NLwN2sr7kWgWKhva6YSC/BIWTsSUyAfiFGRDLksNtMiXJk2nFzwvINGU7khBdDpZ0xZxmhhPvT3TPQeSukZNEp859yZLVA9t69Vx2Rrtf/3vGfZj9NjSVrEMcquP8zDrmIicp5+ILtm1qYJxq2lsYH0LHTwGtIQC1nW+J7D/t3JAFZdgohsdXEl3T+KIig2APUgJz4Mp/ze3gzIrY7/Y+plII+MnrISdBSmDnoRRpF/g==', 95 | 'MD5OfBody' => 'ff45cc3835165307ef414c23ca2c6f67', 96 | 'Body' => '{"key1":"value1","key2":"value2"}' 97 | ] 98 | ]; 99 | 100 | ## Deleting a message from a queue 101 | 102 | $msgResult = $this->SimpleQueue->receiveMessage('testQueue1'); 103 | $handle = $msgResult['Messages'][0]['ReceiptHandle']; 104 | $this->SimpleQueue->deleteMessage('testQueue1', $handle); 105 | 106 | 107 | ## Setting up a worker shell 108 | 109 | As mentioned before, this plugin helps you create long lived worker shells that will process jobs one at a time as 110 | messages are received from a set of queues in CakeSQS. This is an example 111 | 112 | 'xxx', 132 | 'secret' => 'yyy', 133 | ]; 134 | 135 | Configure::write('CakeSQS.connection.credentials', $credentials); 136 | Configure::write('CakeSQS.queues.testQueue1', 'https://sqs.eu-central-1.amazonaws.com/zzzz/testQueue1'); 137 | 138 | $queue = new SimpleQueue(); 139 | debug($queue->send('testQueue1', 'some-data')); 140 | } 141 | 142 | public function workForever() 143 | { 144 | $credentials = [ 145 | 'key' => 'xxx', 146 | 'secret' => 'yyy', 147 | ]; 148 | 149 | Configure::write('CakeSQS.connection.credentials', $credentials); 150 | Configure::write('CakeSQS.queues.testQueue1', 'https://sqs.eu-central-1.amazonaws.com/zzz/testQueue1'); 151 | 152 | $this->QueueWorker->addFunction('testQueue1', function ($item) { 153 | debug($item); 154 | 155 | return true; // return true to delete the message upon processing, false to leave the message in the queue 156 | }); 157 | $this->QueueWorker->work(); 158 | } 159 | } 160 | 161 | The functions registered to handle jobs will receive the message body from the queue after decoding it using `json_decode`. 162 | 163 | IMPORTANT: return true to delete the message upon processing, false to leave the message in the queue and re - process later 164 | 165 | ## Kill worker softly with SIGHUP 166 | 167 | To kill a long lived worker shell in the middle of the iterations loop, you can send SIGHUP by calling `kill -1 PID` on the commandline (PID is the process Id of your running worker shell). 168 | 169 | This will cause the current iteration to finish and stop the worker afterwards. 170 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lorenzo/cakephp-sqs", 3 | "description": "CakePHP Aws Simple Queue System", 4 | "type": "cakephp-plugin", 5 | "keywords": ["cakephp", "queue", "aws", "sqs"], 6 | "homepage": "https://github.com/lorenzo/cakephp-sqs", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "José Lorenzo Rodríguez", 11 | "role": "Author" 12 | }, 13 | { 14 | "name": "Cake Development Corporation", 15 | "role": "Contributor" 16 | } 17 | ], 18 | "require": { 19 | "cakephp/cakephp": "^3.3.0", 20 | "aws/aws-sdk-php": "~3.32" 21 | }, 22 | "require-dev": { 23 | "phpunit/phpunit": "5.*", 24 | "php-vcr/php-vcr": "dev-fix-stream-emulation as 1.3.3", 25 | "php-vcr/phpunit-testlistener-vcr": "~2.0" 26 | }, 27 | "autoload": { 28 | "psr-4": { 29 | "CakeSQS\\": "src" 30 | } 31 | }, 32 | "autoload-dev": { 33 | "psr-4": { 34 | "CakeSQS\\Test\\": "tests", 35 | "CakeSQS\\Test\\Fixture\\": "tests" 36 | } 37 | }, 38 | "repositories": [ 39 | { 40 | "type": "vcs", 41 | "url": "https://github.com/markstory/php-vcr" 42 | } 43 | ] 44 | } 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | ./tests/ 11 | 12 | 13 | 14 | 15 | 16 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | ./src/ 30 | ./plugins/*/src/ 31 | 32 | 33 | ./vendor/ 34 | ./vendor/ 35 | 36 | ./tests/ 37 | ./tests/ 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/Shell/Task/QueueWorkerTask.php: -------------------------------------------------------------------------------- 1 | log(sprintf("Starting %s worker", $name), 'info', 'sqs'); 58 | 59 | if (function_exists('pcntl_signal')) { 60 | pcntl_signal(SIGHUP, function () { 61 | $this->exit = true; 62 | }); 63 | } 64 | 65 | $simpleQueue = $this->getSimpleQueue(); 66 | $i = 0; 67 | $infinite_loop = ($iterations == -1); 68 | while (($i < $iterations) || $infinite_loop) { 69 | foreach ($this->callbacks as $queue => $callback) { 70 | if (!$this->_triggerEvent('Queue.beforeWork')) { 71 | break 2; 72 | } 73 | 74 | $job = $simpleQueue->receiveMessage($queue); 75 | if (!empty($job) && $job->get('Messages')) { 76 | $this->_work($queue, $job); 77 | } 78 | 79 | if (!$this->_triggerEvent('Queue.afterWork')) { 80 | break 2; 81 | } 82 | } 83 | if ($iterations > -1) { 84 | $i++; 85 | } 86 | 87 | if (function_exists('pcntl_signal_dispatch')) { 88 | pcntl_signal_dispatch(); 89 | } 90 | 91 | if ($this->exit == true) { 92 | $this->log(sprintf("SIGHUP Received in iteration %d of %d", $i, $iterations), 'info', 'sqs'); 93 | break 1; 94 | } 95 | } 96 | $this->log(sprintf("Finished %s worker", $name), 'info', 'sqs'); 97 | } 98 | 99 | /** 100 | * Get the client object 101 | * 102 | * @return SimpleQueue 103 | */ 104 | public function getSimpleQueue() 105 | { 106 | if (empty($this->simpleQueue)) { 107 | $this->simpleQueue = new SimpleQueue(); 108 | } 109 | 110 | return $this->simpleQueue; 111 | } 112 | 113 | /** 114 | * Registers a callback as a worker function for a specific task name 115 | * 116 | * @param string $name the name of the queue to subscribe to 117 | * @param callable $callback the object that contains the worker method 118 | * @return void 119 | */ 120 | public function addFunction($name, $callback) 121 | { 122 | $this->log(sprintf('Adding callback "%s" for queue "%s"', $name, $this->getSimpleQueue()->queueUrl($name)), 'info', 'sqs'); 123 | 124 | if (!is_callable($callback)) { 125 | throw new \RuntimeException(sprintf('Invalid callback, provided object must be callable')); 126 | } 127 | 128 | $this->callbacks[$name] = $callback; 129 | } 130 | 131 | /** 132 | * Get the Event Manager 133 | * 134 | * If none exist it creates a new instance 135 | * 136 | * @return EventManager 137 | */ 138 | public function getEventManager() 139 | { 140 | if ($this->eventManager === null) { 141 | $this->eventManager = EventManager::instance(); 142 | } 143 | 144 | return $this->eventManager; 145 | } 146 | 147 | /** 148 | * Trigger an event 149 | * 150 | * @param string $name The event name 151 | * @param mixed $data The event data 152 | * @return bool If the event was stopped or not 153 | */ 154 | protected function _triggerEvent($name, $data = null) 155 | { 156 | $event = new Event($name, $this, $data); 157 | $this->getEventManager()->dispatch($event); 158 | 159 | return !$event->isStopped(); 160 | } 161 | 162 | /** 163 | * The function that is used for all jobs, it will sub-dispatch to the real function 164 | * Useful for registering closures 165 | * 166 | * @param string $name name of the queue 167 | * @param \Aws\Result $job message 168 | * @return void 169 | */ 170 | protected function _work($name, $job) 171 | { 172 | foreach ($job->get('Messages') as $message) { 173 | $data = json_decode($message['Body'], true); 174 | $messageAttributes = isset($message['MessageAttributes']) ? $message['MessageAttributes'] : []; 175 | $return = call_user_func($this->callbacks[$name], $data, $message['ReceiptHandle'], $messageAttributes); 176 | if ($return === true) { 177 | $this->getSimpleQueue()->deleteMessage($name, $message['ReceiptHandle']); 178 | } 179 | } 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/SimpleQueue.php: -------------------------------------------------------------------------------- 1 | [ 20 | /* 21 | * @see http://docs.aws.amazon.com/aws-sdk-php/v3/api/class-Aws.Sqs.SqsClient.html#___construct 22 | * for all possible config params 23 | */ 24 | 'credentials' => [ 25 | 'key' => 'Your amazon key', 26 | 'secret' => 'Your amazon secret', 27 | ], 28 | 'version' => '2012-11-05', 29 | 'region' => 'eu-central-1' // must match the region where the sqs queue was created 30 | ], 31 | 'queues' => [ 32 | // sqs queue urls, for example: https://sqs.eu-central-1.amazonaws.com/12345/someQueue 33 | ] 34 | ]; 35 | 36 | /** 37 | * SimpleQueue constructor. 38 | * Configuration will be loaded by default from CakeSQS key 39 | * 40 | * @param array $config Configuration override 41 | */ 42 | public function __construct($config = []) 43 | { 44 | $this->setConfig(Configure::read('CakeSQS')); 45 | $this->setConfig($config); 46 | } 47 | 48 | /** 49 | * Holds a reference to a SqsClient connection 50 | * 51 | * @var SqsClient 52 | **/ 53 | protected $_client = null; 54 | 55 | /** 56 | * The number of exceptions that have been caught 57 | * that weren't fatal 58 | * 59 | * @var int 60 | */ 61 | protected $_exceptionCount = 0; 62 | 63 | /** 64 | * Gets the configured client connection to CakeSQS. If none is set, it will create 65 | * a new one out of the configuration stored using the Configure class. It is also 66 | * possible to provide you own client instance already configured and initialized. 67 | * 68 | * @param SqsClient $client if set null current configured client will be used 69 | * if set to false, currently configured client will be destroyed 70 | * 71 | * @return SqsClient|null 72 | */ 73 | public function client($client = null) 74 | { 75 | if ($client instanceof SqsClient) { 76 | $this->_client = $client; 77 | } 78 | 79 | if ($client === false) { 80 | return $this->_client = null; 81 | } 82 | 83 | if (empty($this->_client)) { 84 | $this->_client = new SqsClient($this->getConfig('connection')); 85 | } 86 | 87 | return $this->_client; 88 | } 89 | 90 | /** 91 | * Stores a new message in the queue so an external client can work upon it 92 | * 93 | * @param string $taskName a task name as defined in the configure key CakeSQS.queues 94 | * @param mixed $data payload data to associate to the new queued message 95 | * @return \Aws\Result|null success 96 | **/ 97 | public function send($taskName, $data = null) 98 | { 99 | $url = $this->queueUrl($taskName); 100 | $data = json_encode($data); 101 | 102 | $result = $this->client()->sendMessage([ 103 | 'QueueUrl' => $url, 104 | 'MessageBody' => $data, 105 | ]); 106 | 107 | if (empty($result->get('MessageId'))) { 108 | Log::error(sprintf('Could not create background job for task %s', $taskName)); 109 | 110 | return null; 111 | } 112 | 113 | return $result; 114 | } 115 | 116 | /** 117 | * Stores multiple messages in the queue so it an external client can work upon them. 118 | * For performance reasons, it is better to create jobs in batches instead of one a time 119 | * if you plan to create several jobs in the same process or request. 120 | * 121 | * @param string $taskName a task name as defined in the configure key CakeSQS.queues 122 | * @param array $payloads list of payload data to associate to the new queued message 123 | * for each entry in the array a new message in the queue will be created 124 | * 125 | * @return array list of messages that failed to be sent or false if an exception was caught 126 | **/ 127 | public function sendBatch($taskName, array $payloads) 128 | { 129 | $url = $this->queueUrl($taskName); 130 | 131 | $result = $this->client()->sendMessageBatch([ 132 | 'QueueUrl' => $url, 133 | 'Entries' => array_map(function ($e) use (&$i) { 134 | return ['Id' => 'a' . ($i++), 'MessageBody' => json_encode($e)]; 135 | }, $payloads) 136 | ]); 137 | 138 | $failed = []; 139 | foreach ((array)$result->get('Failed') as $f) { 140 | $failed[(int)substr($f['Id'], 1)] = $f['Message']; 141 | } 142 | 143 | if (!empty($failed)) { 144 | Log::warning(sprintf('Failed sending %d messages for queue: %s', count($failed), $taskName)); 145 | } 146 | 147 | return $failed; 148 | } 149 | 150 | /** 151 | * Gets a pending message for an specific queue. 152 | * 153 | * @param string $taskName the name of the queue for which you want to get one message 154 | * @param array $options options to be passed to receiveMessage method (it may include ReceiveMessages and WaitTimeSeconds for long polling) 155 | * @return \Aws\Result|false 156 | * @see http://docs.aws.amazon.com/aws-sdk-php-2/latest/class-Aws.Sqs.SqsClient.html#_receiveMessage 157 | */ 158 | public function receiveMessage($taskName, $options = []) 159 | { 160 | $url = $this->queueUrl($taskName); 161 | 162 | $options['QueueUrl'] = $url; 163 | $options['MessageAttributeNames'] = ['All']; 164 | return $this->client()->receiveMessage($options); 165 | } 166 | 167 | /** 168 | * Deletes a message from the specified task queue. This is used to acknowledge that 169 | * the message was received and that it should not be enqueued again. 170 | * 171 | * @param string $taskName the name of the queue for which you want to delete one message 172 | * @param string $id the ResourceHandle string originally received with the message 173 | * @return \Aws\Result|false 174 | * @see http://docs.aws.amazon.com/aws-sdk-php-2/latest/class-Aws.Sqs.SqsClient.html#_deleteMessage 175 | */ 176 | public function deleteMessage($taskName, $id) 177 | { 178 | $url = $this->queueUrl($taskName); 179 | 180 | return $this->client()->deleteMessage([ 181 | 'QueueUrl' => $url, 182 | 'ReceiptHandle' => $id 183 | ]); 184 | } 185 | 186 | /** 187 | * Gets queue attributes 188 | * 189 | * @param string $taskName the name of the queue for which you want to get one message 190 | * @param array $attributes list with attributes that you want to receive 191 | * @return \Aws\Result|false 192 | */ 193 | public function getAttributes($taskName, $attributes) 194 | { 195 | $url = $this->queueUrl($taskName); 196 | 197 | return $this->client()->getQueueAttributes([ 198 | 'QueueUrl' => $url, 199 | 'AttributeNames' => $attributes, 200 | ]); 201 | } 202 | 203 | /** 204 | * Returns the url for an specific task name as configured 205 | * 206 | * @param string $taskName name of the queue 207 | * @return string 208 | */ 209 | public function queueUrl($taskName) 210 | { 211 | $url = $this->getConfig('queues.' . $taskName); 212 | if (empty($url)) { 213 | throw new \InvalidArgumentException("$taskName URL was not configured. Use Configure::write('CakeSQS.queues.$taskName', '\$url');"); 214 | } 215 | 216 | return $url; 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /tests/TestCase/Shell/Task/QueueWorkerTaskTest.php: -------------------------------------------------------------------------------- 1 | task = new QueueWorkerTask(); 28 | } 29 | 30 | /** 31 | * Restores everything back to normal 32 | * 33 | * @return void 34 | **/ 35 | public function tearDown() 36 | { 37 | parent::tearDown(); 38 | Log::drop('queuetest'); 39 | Configure::write('CakeSQS', []); 40 | unset($this->logger); 41 | } 42 | 43 | /** 44 | * Tests getWorker function 45 | * 46 | * @return void 47 | */ 48 | public function testGetSimpleQueue() 49 | { 50 | $this->assertInstanceOf('\CakeSQS\SimpleQueue', $this->task->getSimpleQueue()); 51 | } 52 | 53 | /** 54 | * Tests getEventManager function 55 | * 56 | * @return void 57 | */ 58 | public function testGetEventManager() 59 | { 60 | $this->assertInstanceOf('\Cake\Event\EventManager', $this->task->getEventManager()); 61 | } 62 | 63 | /** 64 | * Tests the infinite-looping worker function 65 | * 66 | * @expectedException Exception 67 | * @expectedExceptionMessage break the cycle 68 | * @return void 69 | */ 70 | public function testWork() 71 | { 72 | Configure::write('CakeSQS.queues.job1', 'http://ok.dk/'); 73 | Configure::write('CakeSQS.queues.job2', 'http://ok.dk/'); 74 | 75 | /** 76 | * @var QueueWorkerTask 77 | */ 78 | $task = $this->getMockBuilder('\CakeSQS\Shell\Task\QueueWorkerTask') 79 | ->setMethods(['getEventManager', 'log', 'getSimpleQueue']) 80 | ->getMock(); 81 | 82 | // Making a mocked SimpleQueuesTable and making getWorker always return it 83 | $queue = $this->getMockBuilder('\CakeSQS\SimpleQueue') 84 | ->setMethods(['receiveMessage', 'deleteMessage']) 85 | ->getMock(); 86 | 87 | $task 88 | ->expects($this->any()) 89 | ->method('getSimpleQueue') 90 | ->will($this->returnValue($queue)); 91 | 92 | //Making a mocked CakeEventManager and making getEventManager always return it 93 | $manager = $this->getMockBuilder('\Cake\Event\EventManager') 94 | ->setMethods(['dispatch']) 95 | ->getMock(); 96 | 97 | $task 98 | ->expects($this->any()) 99 | ->method('getEventManager') 100 | ->will($this->returnValue($manager)); 101 | 102 | $manager 103 | ->expects($this->at(0)) 104 | ->method('dispatch') 105 | ->with(new Event('Queue.beforeWork', $task)); 106 | $manager 107 | ->expects($this->at(1)) 108 | ->method('dispatch') 109 | ->with(new Event('Queue.afterWork', $task)); 110 | 111 | // Faking the first message that will be received from the job1 queue 112 | $message = [['ReceiptHandle' => 'myId', 'Body' => json_encode('foo')]]; 113 | $model = $this->getMockBuilder('\Aws\Result') 114 | ->setMethods(['get']) 115 | ->getMock(); 116 | $model 117 | ->expects($this->exactly(2)) 118 | ->method('get') 119 | ->with('Messages') 120 | ->will($this->returnValue($message)); 121 | $queue 122 | ->expects($this->at(0)) 123 | ->method('receiveMessage') 124 | ->with('job1') 125 | ->will($this->returnValue($model)); 126 | 127 | // Telling the task to handle the queue job1 with a method in this tests class 128 | $task->addFunction('job1', [$this, 'handleJob']); 129 | 130 | // the second queue to manage will be job2 131 | $manager 132 | ->expects($this->at(2)) 133 | ->method('dispatch') 134 | ->with(new Event('Queue.beforeWork', $task)); 135 | $manager 136 | ->expects($this->at(3)) 137 | ->method('dispatch') 138 | ->with(new Event('Queue.afterWork', $task)); 139 | 140 | // Faking the first message that will be received from the job2 queue 141 | $message = [['ReceiptHandle' => 'mySecondID', 'Body' => json_encode('foo2')]]; 142 | $model = $this->getMockBuilder('\Aws\Result') 143 | ->setMethods(['get']) 144 | ->getMock(); 145 | $model 146 | ->expects($this->exactly(2)) 147 | ->method('get') 148 | ->with('Messages') 149 | ->will($this->returnValue($message)); 150 | $queue 151 | ->expects($this->at(2)) 152 | ->method('receiveMessage') 153 | ->with('job2') 154 | ->will($this->returnValue($model)); 155 | 156 | // Telling the task to handle the queue job2 with a method in this tests class 157 | $task->addFunction('job2', [$this, 'handleJob2']); 158 | 159 | // In the next cycle of the infinte loop it is the turn to manage job1 again 160 | $manager 161 | ->expects($this->at(4)) 162 | ->method('dispatch') 163 | ->with(new Event('Queue.beforeWork', $task)); 164 | 165 | // Faking the first message that will be received from the job1 queue 166 | // This time and exception will be thrown to break the infinite loop 167 | $message = [['ReceiptHandle' => 'myThirdId', 'Body' => json_encode('foo3')]]; 168 | $model = $this->getMockBuilder('\Aws\Result') 169 | ->setMethods(['get']) 170 | ->getMock(); 171 | $model 172 | ->expects($this->exactly(2)) 173 | ->method('get') 174 | ->with('Messages') 175 | ->will($this->returnValue($message)); 176 | $queue 177 | ->expects($this->at(3)) 178 | ->method('receiveMessage') 179 | ->with('job1') 180 | ->will($this->returnValue($model)); 181 | 182 | // Only the first handleJob function returns true, so only message will be deleted 183 | $queue->expects($this->once())->method('deleteMessage')->with('job1', 'myId'); 184 | 185 | $task->work(100); 186 | } 187 | 188 | /** 189 | * Function that will handle jobs generated by the first queue 190 | * when data equals foo3 it will throw an exception 191 | * 192 | * @return boolean 193 | */ 194 | public function handleJob($data) 195 | { 196 | if ($data === 'foo3') { 197 | throw new \Exception('break the cycle'); 198 | } 199 | 200 | $this->assertEquals('foo', $data); 201 | 202 | return true; 203 | } 204 | 205 | /** 206 | * Function that will handle jobs generated by the second queue 207 | * 208 | * @return boolean 209 | */ 210 | public function handleJob2($data) 211 | { 212 | $this->assertEquals('foo2', $data); 213 | 214 | return false; 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /tests/TestCase/SimpleQueueTest.php: -------------------------------------------------------------------------------- 1 | SimpleQueue = new SimpleQueue(); 25 | $this->SimpleQueue->setConfig([ 26 | 'connection.credentials' => [ 27 | 'key' => 'SOMEKEY', 28 | 'secret' => 'SOMESECRET', 29 | ], 30 | 'queues.testQueue1' => 'https://sqs.eu-central-1.amazonaws.com/925075006686/testQueue1' 31 | ]); 32 | 33 | VCR::configure() 34 | ->enableRequestMatchers(['method', 'url', 'body']) 35 | ->setMode('none'); 36 | } 37 | 38 | /** 39 | * tearDown method 40 | * 41 | * @return void 42 | */ 43 | public function tearDown() 44 | { 45 | unset($this->SimpleQueue); 46 | 47 | parent::tearDown(); 48 | } 49 | 50 | public function testClientFalse() 51 | { 52 | $this->assertNull($this->SimpleQueue->client(false)); 53 | } 54 | 55 | /** 56 | * @vcr SimpleQueueTest_testSend 57 | */ 58 | public function testSend() 59 | { 60 | $expected = [ 61 | 'statusCode' => 200, 62 | 'effectiveUri' => 'https://sqs.eu-central-1.amazonaws.com/925075006686/testQueue1', 63 | 'headers' => [ 64 | 'date' => 'Fri, 11 Aug 2017 17:57:20 GMT', 65 | 'content-type' => 'text/xml', 66 | 'content-length' => '378', 67 | 'connection' => 'keep-alive', 68 | 'x-amzn-requestid' => '584723bf-d1e0-525a-93f3-71b823a0c451' 69 | ], 70 | 'transferStats' => [ 71 | 'http' => [[]] 72 | ] 73 | ]; 74 | // Following request will be recorded once and replayed in future test runs 75 | $result = $this->SimpleQueue->send('testQueue1', [ 76 | 'key1' => 'value1', 77 | 'key2' => 'value2', 78 | ]); 79 | $this->assertSame($expected, $result->get('@metadata')); 80 | } 81 | 82 | /** 83 | * @vcr SimpleQueueTest_testSendInvalidCredentials 84 | * @expectedException \Aws\Sqs\Exception\SqsException 85 | * @expectedExceptionMessage Error executing "SendMessage" on "https://sqs.eu-central-1.amazonaws.com/925075006686/testQueue1"; AWS HTTP error: Client error: `POST https://sqs.eu-central-1.amazonaws.com/925075006686/testQueue1` resulted in a `403 Forbidden` response: 86 | * SenderI (truncated...) 87 | * InvalidClientTokenId (client): The security token included in the request is invalid. - SenderInvalidClientTokenIdThe security token included in the request is invalid.067bf701-313d-53e2-9cae-a506c403e953 88 | */ 89 | public function testSendInvalidCredentials() 90 | { 91 | $this->SimpleQueue->setConfig([ 92 | 'connection.credentials' => [ 93 | 'key' => 'INVALID', 94 | 'secret' => 'INVALID', 95 | ], 96 | 'queues.testQueue1' => 'https://sqs.eu-central-1.amazonaws.com/925075006686/testQueue1' 97 | ]); 98 | 99 | // Following request will be recorded once and replayed in future test runs 100 | $result = $this->SimpleQueue->send('testQueue1', [ 101 | 'key1' => 'value1', 102 | 'key2' => 'value2', 103 | ]); 104 | } 105 | 106 | /** 107 | * @vcr SimpleQueueTest_testSendBatch 108 | */ 109 | public function testSendBatch() 110 | { 111 | $result = $this->SimpleQueue->sendBatch('testQueue1', [ 112 | ['message1' => 'value1'], 113 | ['message3' => 'value2'], 114 | ]); 115 | 116 | $this->assertEmpty($result); 117 | } 118 | 119 | /** 120 | * @vcr SimpleQueueTest_testSendBatchEmpty 121 | */ 122 | public function testSendBatchEmpty() 123 | { 124 | $result = $this->SimpleQueue->sendBatch('testQueue1', [null]); 125 | 126 | $this->assertEmpty($result); 127 | } 128 | 129 | /** 130 | * @vcr SimpleQueueTest_testReceiveMessage 131 | */ 132 | public function testReceiveMessage() 133 | { 134 | $expected = [ 135 | [ 136 | 'MessageId' => '929a9cfe-0d45-494c-80fc-41ec6e2e017d', 137 | 'ReceiptHandle' => 'AQEBEYj8zzBaKn8PpJiHgvyznyo7H0BQYH7MBy7429K/ad53lXLRh5yu2Yb0EH9o22WskOCTX7enwcGxTc7JQLQPcJwFwJB/L29pVOyDvZc8fI2XPjd+7jbN91H6PqfHUUsryiDHkA36ZH0tWKjFOVt986GKptqdON+BbinT2KIjd5NLwN2sr7kWgWKhva6YSC/BIWTsSUyAfiFGRDLksNtMiXJk2nFzwvINGU7khBdDpZ0xZxmhhPvT3TPQeSukZNEp859yZLVA9t69Vx2Rrtf/3vGfZj9NjSVrEMcquP8zDrmIicp5+ILtm1qYJxq2lsYH0LHTwGtIQC1nW+J7D/t3JAFZdgohsdXEl3T+KIig2APUgJz4Mp/ze3gzIrY7/Y+plII+MnrISdBSmDnoRRpF/g==', 138 | 'MD5OfBody' => 'ff45cc3835165307ef414c23ca2c6f67', 139 | 'Body' => '{"key1":"value1","key2":"value2"}' 140 | ] 141 | ]; 142 | $msgResult = $this->SimpleQueue->receiveMessage('testQueue1'); 143 | $this->assertSame($expected, $msgResult->search('Messages')); 144 | } 145 | 146 | /** 147 | * @vcr SimpleQueueTest_testDeleteMessage 148 | */ 149 | public function testDeleteMessage() 150 | { 151 | $handle = 'AQEBq+H6ahm2aPuY5CfsGCFvHMXkyfAGFxLENt05KyxdJ4d7dOzk72HmWIr9HDvMHVwR2QDCvSTr2L9UjSDpjArj4sbnTKVG5RTuSX/LM7D5k5haVf9rQZEQmiqzAXpgpXINDIwSHmOmtrUXavlD+tcPDIgb7b8azopfiA00GvTOk24TGe/7FHj7KACcwm/ptoXqeNKZ/KMUA5DfI7Oaqc6ra+/N/99phj17yWbA6UPQEo5IGXMDI+TLsm6NQa7OqcFvw6JrYdbFCJboX61tYOKGn3u47ahUDY/YIMJTH/GVALuSHSzMGmZOgys6xzl95HQDmCqPnA2UN1VE1RmxYOm2beXQredSVu1TqgnaQlLIv5Y1/E9IElJJPN2ADqhGLZZyM9Vjp8uG9FQP67VL11HSIQ=='; 152 | // Following request will be recorded once and replayed in future test runs 153 | $msgResult = $this->SimpleQueue->deleteMessage('testQueue1', $handle); 154 | $this->assertSame(200, $msgResult['@metadata']['statusCode']); 155 | } 156 | 157 | /** 158 | * @vcr SimpleQueueTest_testGetAttributes 159 | */ 160 | public function testGetAttributes() 161 | { 162 | $msgResult = $this->SimpleQueue->getAttributes('testQueue1', ['ApproximateNumberOfMessages']); 163 | $this->assertSame('17', $msgResult['Attributes']['ApproximateNumberOfMessages']); 164 | } 165 | 166 | /** 167 | * @expectedException \InvalidArgumentException 168 | */ 169 | public function testQueueUrl() 170 | { 171 | $this->SimpleQueue->queueUrl('notfound'); 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | dirname(dirname(__FILE__)) . DS]); 24 | -------------------------------------------------------------------------------- /tests/fixtures/SimpleQueueTest_testDeleteMessage: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://sqs.eu-central-1.amazonaws.com/925075006686/testQueue1' 6 | headers: 7 | Host: sqs.eu-central-1.amazonaws.com 8 | Expect: null 9 | Accept-Encoding: null 10 | Content-Type: application/x-www-form-urlencoded 11 | aws-sdk-invocation-id: 5b8a49ff123792092e89fd13d3340878 12 | aws-sdk-retry: 0/0 13 | X-Amz-Date: 20170811T183740Z 14 | Authorization: 'AWS4-HMAC-SHA256 Credential=SOMEKEY/20170811/eu-central-1/sqs/aws4_request, SignedHeaders=aws-sdk-invocation-id;aws-sdk-retry;host;x-amz-date, Signature=e0d9ee105f1c641ff579c548a99512b6d30a3f4415c9e390a1571b2f4c432ef7' 15 | User-Agent: 'aws-sdk-php/3.32.6 GuzzleHttp/6.2.1 curl/7.47.0 PHP/7.1.6-1~ubuntu16.04.1+deb.sury.org+1' 16 | Accept: null 17 | body: 'Action=DeleteMessage&Version=2012-11-05&QueueUrl=https%3A%2F%2Fsqs.eu-central-1.amazonaws.com%2F925075006686%2FtestQueue1&ReceiptHandle=AQEBq%2BH6ahm2aPuY5CfsGCFvHMXkyfAGFxLENt05KyxdJ4d7dOzk72HmWIr9HDvMHVwR2QDCvSTr2L9UjSDpjArj4sbnTKVG5RTuSX%2FLM7D5k5haVf9rQZEQmiqzAXpgpXINDIwSHmOmtrUXavlD%2BtcPDIgb7b8azopfiA00GvTOk24TGe%2F7FHj7KACcwm%2FptoXqeNKZ%2FKMUA5DfI7Oaqc6ra%2B%2FN%2F99phj17yWbA6UPQEo5IGXMDI%2BTLsm6NQa7OqcFvw6JrYdbFCJboX61tYOKGn3u47ahUDY%2FYIMJTH%2FGVALuSHSzMGmZOgys6xzl95HQDmCqPnA2UN1VE1RmxYOm2beXQredSVu1TqgnaQlLIv5Y1%2FE9IElJJPN2ADqhGLZZyM9Vjp8uG9FQP67VL11HSIQ%3D%3D' 18 | response: 19 | status: 20 | http_version: '1.1' 21 | code: '200' 22 | message: OK 23 | headers: 24 | Server: Server 25 | Date: 'Fri, 11 Aug 2017 18:37:45 GMT' 26 | Content-Type: text/xml 27 | Content-Length: '215' 28 | Connection: keep-alive 29 | x-amzn-RequestId: 864e1bed-24ef-5e94-8e4b-49eadf562d1f 30 | body: '864e1bed-24ef-5e94-8e4b-49eadf562d1f' 31 | -------------------------------------------------------------------------------- /tests/fixtures/SimpleQueueTest_testGetAttributes: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://sqs.eu-central-1.amazonaws.com/925075006686/testQueue1' 6 | headers: 7 | Host: sqs.eu-central-1.amazonaws.com 8 | Expect: null 9 | Accept-Encoding: null 10 | Content-Type: application/x-www-form-urlencoded 11 | aws-sdk-invocation-id: f06c85213e9d79918efbec951e42a32e 12 | aws-sdk-retry: 0/0 13 | X-Amz-Date: 20170811T184023Z 14 | Authorization: 'AWS4-HMAC-SHA256 Credential=SOMEKEY/20170811/eu-central-1/sqs/aws4_request, SignedHeaders=aws-sdk-invocation-id;aws-sdk-retry;host;x-amz-date, Signature=a1bea66f096510cb93274cf0112c754a576e322a858f2e6bb23b923d9762e752' 15 | User-Agent: 'aws-sdk-php/3.32.6 GuzzleHttp/6.2.1 curl/7.47.0 PHP/7.1.6-1~ubuntu16.04.1+deb.sury.org+1' 16 | Accept: null 17 | body: 'Action=GetQueueAttributes&Version=2012-11-05&QueueUrl=https%3A%2F%2Fsqs.eu-central-1.amazonaws.com%2F925075006686%2FtestQueue1&AttributeName.1=ApproximateNumberOfMessages' 18 | response: 19 | status: 20 | http_version: '1.1' 21 | code: '200' 22 | message: OK 23 | headers: 24 | Server: Server 25 | Date: 'Fri, 11 Aug 2017 18:40:24 GMT' 26 | Content-Type: text/xml 27 | Content-Length: '358' 28 | Connection: keep-alive 29 | x-amzn-RequestId: b3f8fe2b-e360-57f1-9da9-ac2c1f38b8c7 30 | body: 'ApproximateNumberOfMessages17b3f8fe2b-e360-57f1-9da9-ac2c1f38b8c7' 31 | -------------------------------------------------------------------------------- /tests/fixtures/SimpleQueueTest_testReceiveMessage: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://sqs.eu-central-1.amazonaws.com/925075006686/testQueue1' 6 | headers: 7 | Host: sqs.eu-central-1.amazonaws.com 8 | Expect: null 9 | Accept-Encoding: null 10 | Content-Type: application/x-www-form-urlencoded 11 | aws-sdk-invocation-id: 281cdcbee028b4cf7030653be0c6f46f 12 | aws-sdk-retry: 0/0 13 | X-Amz-Date: 20170811T181901Z 14 | Authorization: 'AWS4-HMAC-SHA256 Credential=SOMEKEY/20170811/eu-central-1/sqs/aws4_request, SignedHeaders=aws-sdk-invocation-id;aws-sdk-retry;host;x-amz-date, Signature=d1315a63b162181209b8da82937d5754e4ede78de5e00cbcc2a39cb031d7c79e' 15 | User-Agent: 'aws-sdk-php/3.32.6 GuzzleHttp/6.2.1 curl/7.47.0 PHP/7.1.6-1~ubuntu16.04.1+deb.sury.org+1' 16 | Accept: null 17 | body: 'Action=ReceiveMessage&Version=2012-11-05&QueueUrl=https%3A%2F%2Fsqs.eu-central-1.amazonaws.com%2F925075006686%2FtestQueue1' 18 | response: 19 | status: 20 | http_version: '1.1' 21 | code: '200' 22 | message: OK 23 | headers: 24 | Server: Server 25 | Date: 'Fri, 11 Aug 2017 18:19:06 GMT' 26 | Content-Type: text/xml 27 | Content-Length: '924' 28 | Connection: keep-alive 29 | x-amzn-RequestId: a2f625cc-6f96-583c-80b5-77cb98cc3771 30 | body: '929a9cfe-0d45-494c-80fc-41ec6e2e017dAQEBEYj8zzBaKn8PpJiHgvyznyo7H0BQYH7MBy7429K/ad53lXLRh5yu2Yb0EH9o22WskOCTX7enwcGxTc7JQLQPcJwFwJB/L29pVOyDvZc8fI2XPjd+7jbN91H6PqfHUUsryiDHkA36ZH0tWKjFOVt986GKptqdON+BbinT2KIjd5NLwN2sr7kWgWKhva6YSC/BIWTsSUyAfiFGRDLksNtMiXJk2nFzwvINGU7khBdDpZ0xZxmhhPvT3TPQeSukZNEp859yZLVA9t69Vx2Rrtf/3vGfZj9NjSVrEMcquP8zDrmIicp5+ILtm1qYJxq2lsYH0LHTwGtIQC1nW+J7D/t3JAFZdgohsdXEl3T+KIig2APUgJz4Mp/ze3gzIrY7/Y+plII+MnrISdBSmDnoRRpF/g==ff45cc3835165307ef414c23ca2c6f67{"key1":"value1","key2":"value2"}a2f625cc-6f96-583c-80b5-77cb98cc3771' 31 | -------------------------------------------------------------------------------- /tests/fixtures/SimpleQueueTest_testSend: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://sqs.eu-central-1.amazonaws.com/925075006686/testQueue1' 6 | headers: 7 | Host: sqs.eu-central-1.amazonaws.com 8 | Expect: null 9 | Accept-Encoding: null 10 | Content-Type: application/x-www-form-urlencoded 11 | aws-sdk-invocation-id: fae98718059fa8c95b175077625b5398 12 | aws-sdk-retry: 0/0 13 | X-Amz-Date: 20170811T175719Z 14 | Authorization: 'AWS4-HMAC-SHA256 Credential=SOMEKEY/20170811/eu-central-1/sqs/aws4_request, SignedHeaders=aws-sdk-invocation-id;aws-sdk-retry;host;x-amz-date, Signature=8b4346f53866b084a00eee6a56e3b68d58fedb33c4480cd170d41fd5ba79c39e' 15 | User-Agent: 'aws-sdk-php/3.32.6 GuzzleHttp/6.2.1 curl/7.47.0 PHP/7.1.6-1~ubuntu16.04.1+deb.sury.org+1' 16 | Accept: null 17 | body: 'Action=SendMessage&Version=2012-11-05&QueueUrl=https%3A%2F%2Fsqs.eu-central-1.amazonaws.com%2F925075006686%2FtestQueue1&MessageBody=%7B%22key1%22%3A%22value1%22%2C%22key2%22%3A%22value2%22%7D' 18 | response: 19 | status: 20 | http_version: '1.1' 21 | code: '200' 22 | message: OK 23 | headers: 24 | Server: Server 25 | Date: 'Fri, 11 Aug 2017 17:57:20 GMT' 26 | Content-Type: text/xml 27 | Content-Length: '378' 28 | Connection: keep-alive 29 | x-amzn-RequestId: 584723bf-d1e0-525a-93f3-71b823a0c451 30 | body: '105da437-8fc5-49c7-b238-8268caca3213ff45cc3835165307ef414c23ca2c6f67584723bf-d1e0-525a-93f3-71b823a0c451' 31 | -------------------------------------------------------------------------------- /tests/fixtures/SimpleQueueTest_testSendBatch: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://sqs.eu-central-1.amazonaws.com/925075006686/testQueue1' 6 | headers: 7 | Host: sqs.eu-central-1.amazonaws.com 8 | Expect: null 9 | Accept-Encoding: null 10 | Content-Type: application/x-www-form-urlencoded 11 | aws-sdk-invocation-id: 5fe5aad42b6a3b510195b7e5ed0babd5 12 | aws-sdk-retry: 0/0 13 | X-Amz-Date: 20170811T180259Z 14 | Authorization: 'AWS4-HMAC-SHA256 Credential=SOMEKEY/20170811/eu-central-1/sqs/aws4_request, SignedHeaders=aws-sdk-invocation-id;aws-sdk-retry;host;x-amz-date, Signature=4703281d2e79eb960182a483e2a37a7956458fe267acdb037625f6a94a57b9d5' 15 | User-Agent: 'aws-sdk-php/3.32.6 GuzzleHttp/6.2.1 curl/7.47.0 PHP/7.1.6-1~ubuntu16.04.1+deb.sury.org+1' 16 | Accept: null 17 | body: 'Action=SendMessageBatch&Version=2012-11-05&QueueUrl=https%3A%2F%2Fsqs.eu-central-1.amazonaws.com%2F925075006686%2FtestQueue1&SendMessageBatchRequestEntry.1.Id=a&SendMessageBatchRequestEntry.1.MessageBody=%7B%22message1%22%3A%22value1%22%7D&SendMessageBatchRequestEntry.2.Id=a1&SendMessageBatchRequestEntry.2.MessageBody=%7B%22message3%22%3A%22value2%22%7D' 18 | response: 19 | status: 20 | http_version: '1.1' 21 | code: '200' 22 | message: OK 23 | headers: 24 | Server: Server 25 | Date: 'Fri, 11 Aug 2017 18:03:05 GMT' 26 | Content-Type: text/xml 27 | Content-Length: '665' 28 | Connection: keep-alive 29 | x-amzn-RequestId: f3fdd08f-e4cc-5607-b735-828817554589 30 | body: 'a88fa7c44-aa3c-49de-8433-60a2613d1b94caa36fef90e1c60cc304f54fff8ae68ca1f092f894-9c87-4c7f-9f3a-0b3598882f6dac3a76e6c8807786ac72c7ccdc794721f3fdd08f-e4cc-5607-b735-828817554589' 31 | -------------------------------------------------------------------------------- /tests/fixtures/SimpleQueueTest_testSendBatchEmpty: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://sqs.eu-central-1.amazonaws.com/925075006686/testQueue1' 6 | headers: 7 | Host: sqs.eu-central-1.amazonaws.com 8 | Expect: null 9 | Accept-Encoding: null 10 | Content-Type: application/x-www-form-urlencoded 11 | aws-sdk-invocation-id: 083d61d2ff9f8f7b6ecfedc82719a1e4 12 | aws-sdk-retry: 0/0 13 | X-Amz-Date: 20170811T181300Z 14 | Authorization: 'AWS4-HMAC-SHA256 Credential=SOMEKEY/20170811/eu-central-1/sqs/aws4_request, SignedHeaders=aws-sdk-invocation-id;aws-sdk-retry;host;x-amz-date, Signature=314df0ba882e69a7be334d1f06ea0254d6ede680eb34245047b58e8514d060ff' 15 | User-Agent: 'aws-sdk-php/3.32.6 GuzzleHttp/6.2.1 curl/7.47.0 PHP/7.1.6-1~ubuntu16.04.1+deb.sury.org+1' 16 | Accept: null 17 | body: 'Action=SendMessageBatch&Version=2012-11-05&QueueUrl=https%3A%2F%2Fsqs.eu-central-1.amazonaws.com%2F925075006686%2FtestQueue1&SendMessageBatchRequestEntry.1.Id=a&SendMessageBatchRequestEntry.1.MessageBody=null' 18 | response: 19 | status: 20 | http_version: '1.1' 21 | code: '200' 22 | message: OK 23 | headers: 24 | Server: Server 25 | Date: 'Fri, 11 Aug 2017 18:13:01 GMT' 26 | Content-Type: text/xml 27 | Content-Length: '467' 28 | Connection: keep-alive 29 | x-amzn-RequestId: caf6c214-12cf-5d2a-b36e-9013e722227a 30 | body: 'a0b6e22eb-e546-4333-82bb-67d9d9b62c0e37a6259cc0c1dae299a7866489dff0bdcaf6c214-12cf-5d2a-b36e-9013e722227a' 31 | -------------------------------------------------------------------------------- /tests/fixtures/SimpleQueueTest_testSendInvalidCredentials: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://sqs.eu-central-1.amazonaws.com/925075006686/testQueue1' 6 | headers: 7 | Host: sqs.eu-central-1.amazonaws.com 8 | Expect: null 9 | Accept-Encoding: null 10 | Content-Type: application/x-www-form-urlencoded 11 | aws-sdk-invocation-id: b736cee282c1cfbaccc73186247bcf46 12 | aws-sdk-retry: 0/0 13 | X-Amz-Date: 20170811T181005Z 14 | Authorization: 'AWS4-HMAC-SHA256 Credential=INVALID/20170811/eu-central-1/sqs/aws4_request, SignedHeaders=aws-sdk-invocation-id;aws-sdk-retry;host;x-amz-date, Signature=bf49d8485da57d27263d33aed1ef82f12673b98bebfa1f7411760cf4193b63c5' 15 | User-Agent: 'aws-sdk-php/3.32.6 GuzzleHttp/6.2.1 curl/7.47.0 PHP/7.1.6-1~ubuntu16.04.1+deb.sury.org+1' 16 | Accept: null 17 | body: 'Action=SendMessage&Version=2012-11-05&QueueUrl=https%3A%2F%2Fsqs.eu-central-1.amazonaws.com%2F925075006686%2FtestQueue1&MessageBody=%7B%22key1%22%3A%22value1%22%2C%22key2%22%3A%22value2%22%7D' 18 | response: 19 | status: 20 | http_version: '1.1' 21 | code: '403' 22 | message: Forbidden 23 | headers: 24 | Server: Server 25 | Date: 'Fri, 11 Aug 2017 18:10:06 GMT' 26 | Content-Type: text/xml 27 | Content-Length: '311' 28 | Connection: close 29 | x-amzn-RequestId: 067bf701-313d-53e2-9cae-a506c403e953 30 | body: 'SenderInvalidClientTokenIdThe security token included in the request is invalid.067bf701-313d-53e2-9cae-a506c403e953' 31 | -------------------------------------------------------------------------------- /todo.txt: -------------------------------------------------------------------------------- 1 | * fix travis 2 | 3 | --------------------------------------------------------------------------------