From 0088a43f33b784298a993d03f57d74e08af91b9d Mon Sep 17 00:00:00 2001 From: Bertrand Drouhard Date: Mon, 5 Mar 2018 15:05:00 +0000 Subject: [PATCH 01/35] Provide a way to have a custom tests configuration --- .gitignore | 3 +++ .../{parameters.yml => parameters.yml.dist} | 0 composer.json | 15 ++++++++++++++- 3 files changed, 17 insertions(+), 1 deletion(-) rename Tests/App/config/{parameters.yml => parameters.yml.dist} (100%) diff --git a/.gitignore b/.gitignore index 1bb76567..9e0203f6 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,6 @@ composer.lock # PHP CS Fixer .php_cs.cache + +# Configuration file +Tests/App/config/parameters.yml diff --git a/Tests/App/config/parameters.yml b/Tests/App/config/parameters.yml.dist similarity index 100% rename from Tests/App/config/parameters.yml rename to Tests/App/config/parameters.yml.dist diff --git a/composer.json b/composer.json index 76615beb..0f42a58e 100644 --- a/composer.json +++ b/composer.json @@ -33,9 +33,22 @@ "sensio/generator-bundle": "~2.3", "mongodb/mongodb": "~1.0" }, + "scripts": { + "post-install-cmd": [ + "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters" + ], + "post-update-cmd": [ + "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters" + ] + }, "config": { "bin-dir": "bin" }, "minimum-stability": "dev", - "prefer-stable" : true + "prefer-stable" : true, + "extra": { + "incenteev-parameters": { + "file": "Tests/App/config/parameters.yml" + } + } } From 2bb20b086bd8455d0eaba6c9d09945323da3e58b Mon Sep 17 00:00:00 2001 From: Bertrand Drouhard Date: Wed, 14 Mar 2018 17:23:58 +0000 Subject: [PATCH 02/35] Add the ability to configure flows association in a Producer --- DependencyInjection/Configuration.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 2725cae4..d69af4b5 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -216,6 +216,11 @@ public function addProducersNode() ->isRequired() ->end() + ->arrayNode('flows') + ->info('List of flows that are using this method') + ->prototype('variable')->end() + ->end() + ->arrayNode(ConfigurableProducerInterface::CONF_STEPS) ->info('This are the steps to execute as part of this method') ->prototype('variable')->end() From 6aa187c1bf0674406cb6038280c87b4bce9255cc Mon Sep 17 00:00:00 2001 From: Bertrand Drouhard Date: Thu, 5 Apr 2018 17:21:32 +0000 Subject: [PATCH 03/35] Add feature to display Request and Response for Rest and Soap --- Tools/MockClients/FakeRestClient.php | 42 ++++++++++++++++++++++--- Tools/MockClients/FakeSoapClient.php | 47 ++++++++++++++++++---------- 2 files changed, 69 insertions(+), 20 deletions(-) diff --git a/Tools/MockClients/FakeRestClient.php b/Tools/MockClients/FakeRestClient.php index c611162e..b2d9b18b 100644 --- a/Tools/MockClients/FakeRestClient.php +++ b/Tools/MockClients/FakeRestClient.php @@ -23,7 +23,41 @@ public function send(RequestInterface $request, array $options = []) $this->checkInitialisation(); $this->actionName = $this->prepareActionName($request->getMethod(), $request->getUri()); - if (getenv('MOCKS_ENABLED') === 'true') { + $mocksEnabled = getenv('MOCKS_ENABLED'); + $displayRequest = getenv('DISPLAY_REQUEST'); + $recordResponse = getenv('RECORD_RESPONSE'); + + if ('true' === $mocksEnabled) { + $mocksMessage = 'MOCKS/'; + } else { + $mocksMessage = ''; + } + + if ('true' === $displayRequest) { + $requestUri = $request->getUri()->getScheme().'://'.$request->getUri()->getAuthority().$request->getUri()->getPath(); + if ($request->getUri()->getQuery()) { + $requestUri .= '?'.$request->getUri()->getQuery(); + } + $requestMethod = $request->getMethod(); + $requestBody = $options['body']; + $requestHeaders = []; + foreach ($options['headers'] as $headerName => $headerValue) { + $requestHeaders[] = $headerName.' => '.$headerValue; + } + $requestQuery = []; + foreach ($options['query'] as $queryName => $queryValue) { + $requestQuery[] = $queryName.' => '.$queryValue; + } + echo "\nREQUEST (".$mocksMessage.'REST) for '.$requestUri.' / '.$requestMethod; + echo "\n====================================================================================================="; + echo "\nHEADERS:\n".implode($requestHeaders, "\n"); + echo "\nQUERY:\n".implode($requestQuery, "\n"); + echo "\n\nBODY:\n".$requestBody; + echo "\n====================================================================================================="; + echo "\n\n"; + } + + if ('true' === $mocksEnabled) { try { return $this->getResponseFromCache($this->actionName, self::CACHE_SUFFIX); } catch (\InvalidArgumentException $e) { @@ -33,7 +67,7 @@ public function send(RequestInterface $request, array $options = []) $response = parent::send($request, $options); - if (getenv('RECORD_RESPONSE') === 'true') { + if ('true' === $recordResponse) { $this->setResponseInCache($this->actionName, $response, self::CACHE_SUFFIX); } @@ -48,7 +82,7 @@ public function request($method, $uri = null, array $options = []) $this->checkInitialisation(); $this->actionName = $this->prepareActionName($method, $uri); - if (getenv('MOCKS_ENABLED') === 'true') { + if ('true' === getenv('MOCKS_ENABLED')) { try { return $this->getResponseFromCache($this->actionName, self::CACHE_SUFFIX); } catch (\InvalidArgumentException $e) { @@ -58,7 +92,7 @@ public function request($method, $uri = null, array $options = []) $response = parent::request($method, $uri, $options); - if (getenv('RECORD_RESPONSE') === 'true') { + if ('true' === getenv('RECORD_RESPONSE')) { $this->setResponseInCache($this->actionName, $response, self::CACHE_SUFFIX); } diff --git a/Tools/MockClients/FakeSoapClient.php b/Tools/MockClients/FakeSoapClient.php index 345a77ad..b680dd24 100644 --- a/Tools/MockClients/FakeSoapClient.php +++ b/Tools/MockClients/FakeSoapClient.php @@ -18,10 +18,10 @@ public function __construct($wsdl, array $options = array()) if (isset($options['MockCacheDir'])) { $this->cacheDir = $options['MockCacheDir']; } - if (getenv('RECORD_RESPONSE') === 'true') { + if ('true' === getenv('RECORD_RESPONSE')) { $this->saveWsdlToCache($wsdl, $options); } - if (getenv('MOCKS_ENABLED') === 'true') { + if ('true' === getenv('MOCKS_ENABLED')) { $wsdl = $this->getWsdlPathFromCache($wsdl, $options); $options['resolve_wsdl_remote_includes'] = false; } @@ -59,33 +59,48 @@ public function __doRequest($request, $location, $action, $version, $oneWay = 0) $this->checkInitialisation(); $actionName = md5($location).'_'.$this->actionName; - if (getenv('MOCKS_ENABLED') === 'true') { + $mocksEnabled = getenv('MOCKS_ENABLED'); + $displayRequest = getenv('DISPLAY_REQUEST'); + $recordResponse = getenv('RECORD_RESPONSE'); + + if ('true' === $mocksEnabled) { + $mocksMessage = 'MOCKS/'; + } else { + $mocksMessage = ''; + } + + if ('true' === $displayRequest) { + echo "\nREQUEST (".$mocksMessage."SOAP) for $location / $action / Version $version"; + echo "\n====================================================================================================="; + echo "\n".$request; + echo "\n====================================================================================================="; + echo "\n\n"; + } + + if ('true' === $mocksEnabled) { try { $response = $this->getResponseFromCache($actionName, self::CACHE_SUFFIX); $this->lastResponseCode = 200; - return $response; } catch (\InvalidArgumentException $e) { - throw $e; + if ('true' === $recordResponse) { // If the mock does not exist but we want to record the response all the same, we make the real call to be able to record it + $response = parent::__doRequest($request, $location, $action, $version, $oneWay); + } else { + throw $e; + } } + } else { + $response = parent::__doRequest($request, $location, $action, $version, $oneWay); } - $response = parent::__doRequest($request, $location, $action, $version, $oneWay); - - if (getenv('DISPLAY_REQUEST') === 'true') { - echo "\nREQUEST for $location / $action / Version $version"; - echo "\n====================================================================================================="; - echo "\n".$request; - echo "\n====================================================================================================="; - echo "\n\n"; - echo "\nRESPONSE"; + if ('true' === $displayRequest) { + echo "\nRESPONSE (".$mocksMessage."SOAP) for $location / $action / Version $version"; echo "\n====================================================================================================="; echo "\n".$response; echo "\n====================================================================================================="; - echo "\n====================================================================================================="; echo "\n\n"; } - if (getenv('RECORD_RESPONSE') === 'true') { + if ('true' === $recordResponse) { $this->setResponseInCache($actionName, $response, self::CACHE_SUFFIX); } From b22148357ca637221c4e0fd690a829f538a2f4bc Mon Sep 17 00:00:00 2001 From: Bertrand Drouhard Date: Thu, 5 Apr 2018 17:23:36 +0000 Subject: [PATCH 04/35] Add feature to display Request and Response for Rest and Soap --- Tools/MockClients/FakeSoapClient.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Tools/MockClients/FakeSoapClient.php b/Tools/MockClients/FakeSoapClient.php index b680dd24..aa79ae77 100644 --- a/Tools/MockClients/FakeSoapClient.php +++ b/Tools/MockClients/FakeSoapClient.php @@ -82,11 +82,7 @@ public function __doRequest($request, $location, $action, $version, $oneWay = 0) $response = $this->getResponseFromCache($actionName, self::CACHE_SUFFIX); $this->lastResponseCode = 200; } catch (\InvalidArgumentException $e) { - if ('true' === $recordResponse) { // If the mock does not exist but we want to record the response all the same, we make the real call to be able to record it - $response = parent::__doRequest($request, $location, $action, $version, $oneWay); - } else { - throw $e; - } + throw $e; } } else { $response = parent::__doRequest($request, $location, $action, $version, $oneWay); From fd7528759fb21309224798bb6ad181e32959346d Mon Sep 17 00:00:00 2001 From: Bertrand Drouhard Date: Mon, 9 Apr 2018 16:25:48 +0000 Subject: [PATCH 05/35] Fixed REST Request display when no query or not headers --- Tools/MockClients/FakeRestClient.php | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/Tools/MockClients/FakeRestClient.php b/Tools/MockClients/FakeRestClient.php index b2d9b18b..756153be 100644 --- a/Tools/MockClients/FakeRestClient.php +++ b/Tools/MockClients/FakeRestClient.php @@ -39,20 +39,31 @@ public function send(RequestInterface $request, array $options = []) $requestUri .= '?'.$request->getUri()->getQuery(); } $requestMethod = $request->getMethod(); - $requestBody = $options['body']; + + $requestBody = ''; + if (isset($options['body'])) { + $requestBody = $options['body']; + } + $requestHeaders = []; - foreach ($options['headers'] as $headerName => $headerValue) { - $requestHeaders[] = $headerName.' => '.$headerValue; + if (isset($options['headers']) && is_array($options['headers'])) { + foreach ($options['headers'] as $headerName => $headerValue) { + $requestHeaders[] = $headerName.' => '.$headerValue; + } } + $requestQuery = []; - foreach ($options['query'] as $queryName => $queryValue) { - $requestQuery[] = $queryName.' => '.$queryValue; + if (isset($options['query']) && is_array($options['query'])) { + foreach ($options['query'] as $queryName => $queryValue) { + $requestQuery[] = $queryName.' => '.$queryValue; + } } + echo "\nREQUEST (".$mocksMessage.'REST) for '.$requestUri.' / '.$requestMethod; echo "\n====================================================================================================="; - echo "\nHEADERS:\n".implode($requestHeaders, "\n"); - echo "\nQUERY:\n".implode($requestQuery, "\n"); - echo "\n\nBODY:\n".$requestBody; + echo "\nHEADERS:\n".implode($requestHeaders, " \n"); + echo "\nQUERY:\n".implode($requestQuery, " \n"); + echo "\nBODY:\n".$requestBody; echo "\n====================================================================================================="; echo "\n\n"; } From dbb4896a6cbb1786d16531a9aedb9c9006d5f5e9 Mon Sep 17 00:00:00 2001 From: Bertrand Drouhard Date: Wed, 11 Apr 2018 11:44:02 +0000 Subject: [PATCH 06/35] Display REST Requests in a much nicer way with formatted json --- Tools/MockClients/FakeRestClient.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Tools/MockClients/FakeRestClient.php b/Tools/MockClients/FakeRestClient.php index 756153be..833f8556 100644 --- a/Tools/MockClients/FakeRestClient.php +++ b/Tools/MockClients/FakeRestClient.php @@ -63,7 +63,8 @@ public function send(RequestInterface $request, array $options = []) echo "\n====================================================================================================="; echo "\nHEADERS:\n".implode($requestHeaders, " \n"); echo "\nQUERY:\n".implode($requestQuery, " \n"); - echo "\nBODY:\n".$requestBody; + echo "\nRAW BODY:\n".$requestBody; + echo "\nPRETTY SEXY BODY:\n".$this->prettyJson($requestBody); echo "\n====================================================================================================="; echo "\n\n"; } @@ -85,6 +86,19 @@ public function send(RequestInterface $request, array $options = []) return $response; } + /** Return a much nicer json string. + * + * @param $uglyJson + * + * @return string + */ + private function prettyJson($uglyJson) + { + $json = json_decode($uglyJson); + + return json_encode($json, JSON_PRETTY_PRINT); + } + /** * {@inheritdoc} */ From 7338ee1f78bc0748e6e98dc393b6fb69b9ce400b Mon Sep 17 00:00:00 2001 From: Bertrand Drouhard Date: Wed, 11 Apr 2018 12:13:48 +0000 Subject: [PATCH 07/35] Display SOAP Requests and Responses in a much nicer way with formatted XML --- Tools/MockClients/FakeSoapClient.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Tools/MockClients/FakeSoapClient.php b/Tools/MockClients/FakeSoapClient.php index aa79ae77..4ca8feee 100644 --- a/Tools/MockClients/FakeSoapClient.php +++ b/Tools/MockClients/FakeSoapClient.php @@ -72,8 +72,14 @@ public function __doRequest($request, $location, $action, $version, $oneWay = 0) if ('true' === $displayRequest) { echo "\nREQUEST (".$mocksMessage."SOAP) for $location / $action / Version $version"; echo "\n====================================================================================================="; + echo "\nRAW REQUEST"; + echo "\n====================================================================================================="; echo "\n".$request; echo "\n====================================================================================================="; + echo "\nPRETTY SEXY REQUEST"; + echo "\n====================================================================================================="; + echo "\n".$this->prettyXML($request); + echo "\n====================================================================================================="; echo "\n\n"; } @@ -91,8 +97,14 @@ public function __doRequest($request, $location, $action, $version, $oneWay = 0) if ('true' === $displayRequest) { echo "\nRESPONSE (".$mocksMessage."SOAP) for $location / $action / Version $version"; echo "\n====================================================================================================="; + echo "\nRAW RESPONSE"; + echo "\n====================================================================================================="; echo "\n".$response; echo "\n====================================================================================================="; + echo "\nPRETTY SEXY RESPONSE"; + echo "\n====================================================================================================="; + echo "\n".$this->prettyXML($response); + echo "\n====================================================================================================="; echo "\n\n"; } @@ -102,4 +114,20 @@ public function __doRequest($request, $location, $action, $version, $oneWay = 0) return $response; } + + /** Return a much nicer XML string. + * + * @param $uglyXML + * + * @return string + */ + private function prettyXML($uglyXML) + { + $doc = new \DOMDocument(); + $doc->preserveWhiteSpace = false; + $doc->formatOutput = true; + $doc->loadXML($uglyXML); + + return $doc->saveXML(); + } } From 0329adb70efc4b920e7c5b86cc0e45f1a18dbad2 Mon Sep 17 00:00:00 2001 From: Bertrand Drouhard Date: Wed, 11 Apr 2018 13:33:20 +0000 Subject: [PATCH 08/35] Display REST response in flowstest, and can record pretty responses --- Tools/MockClients/FakeRestClient.php | 41 ++++++++++++++++++++++++---- Tools/MockClients/FakeSoapClient.php | 7 ++++- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/Tools/MockClients/FakeRestClient.php b/Tools/MockClients/FakeRestClient.php index 833f8556..5c341cd3 100644 --- a/Tools/MockClients/FakeRestClient.php +++ b/Tools/MockClients/FakeRestClient.php @@ -71,13 +71,23 @@ public function send(RequestInterface $request, array $options = []) if ('true' === $mocksEnabled) { try { - return $this->getResponseFromCache($this->actionName, self::CACHE_SUFFIX); + $response = $this->getResponseFromCache($this->actionName, self::CACHE_SUFFIX); } catch (\InvalidArgumentException $e) { throw $e; } + } else { + $response = parent::send($request, $options); } - $response = parent::send($request, $options); + if ('true' === $displayRequest) { + $content = $this->getResponseContent($response); + echo "\nRESPONSE (".$mocksMessage.'REST) for '.$requestUri.' / '.$requestMethod; + echo "\n====================================================================================================="; + echo "\nRAW RESPONSE:\n".$content; + echo "\nPRETTY SEXY RESPONSE:\n".$this->prettyJson($content); + echo "\n====================================================================================================="; + echo "\n\n"; + } if ('true' === $recordResponse) { $this->setResponseInCache($this->actionName, $response, self::CACHE_SUFFIX); @@ -142,9 +152,31 @@ protected function getResponseFromCache($resource, $suffix = null) return new Psr7\Response($response['status'], $response['headers'], $response['body'], $response['version'], $response['reason']); } + /** + * @param $resource + * @param Psr7\Response $response + * @param null $suffix + */ protected function setResponseInCache($resource, $response, $suffix = null) { - /* @var Psr7\Response $response */ + $prettyRecordedResponse = getenv('PRETTY_RECORDED_RESPONSE'); + + $content = $this->getResponseContent($response); + + if ('true' === $prettyRecordedResponse) { + $content = $this->prettyJson($content); + } + + $this->trait_setResponseInCache($resource, $content, $suffix); + } + + /** + * @param Psr7\Response $response + * + * @return string + */ + protected function getResponseContent($response) + { $content = json_encode( [ 'status' => $response->getStatusCode(), @@ -154,9 +186,8 @@ protected function setResponseInCache($resource, $response, $suffix = null) 'reason' => $response->getReasonPhrase(), ] ); - $response->getBody()->rewind(); - $this->trait_setResponseInCache($resource, $content, $suffix); + return $content; } } diff --git a/Tools/MockClients/FakeSoapClient.php b/Tools/MockClients/FakeSoapClient.php index 4ca8feee..9168a675 100644 --- a/Tools/MockClients/FakeSoapClient.php +++ b/Tools/MockClients/FakeSoapClient.php @@ -62,6 +62,7 @@ public function __doRequest($request, $location, $action, $version, $oneWay = 0) $mocksEnabled = getenv('MOCKS_ENABLED'); $displayRequest = getenv('DISPLAY_REQUEST'); $recordResponse = getenv('RECORD_RESPONSE'); + $prettyRecordedResponse = getenv('PRETTY_RECORDED_RESPONSE'); if ('true' === $mocksEnabled) { $mocksMessage = 'MOCKS/'; @@ -109,7 +110,11 @@ public function __doRequest($request, $location, $action, $version, $oneWay = 0) } if ('true' === $recordResponse) { - $this->setResponseInCache($actionName, $response, self::CACHE_SUFFIX); + $recordedResponse = $response; + if ('true' === $prettyRecordedResponse) { + $recordedResponse = $this->prettyXML($response); + } + $this->setResponseInCache($actionName, $recordedResponse, self::CACHE_SUFFIX); } return $response; From 4b4c1676e5bd245d163617fde70fc3cc15afa440 Mon Sep 17 00:00:00 2001 From: Bertrand Drouhard Date: Thu, 3 May 2018 13:13:36 +0000 Subject: [PATCH 09/35] New 'debug' step, a nasty hack to be able to easily display context variables in producers. --- Configurability/ConfigurableServiceHelper.php | 38 ++++++++++++++++--- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/Configurability/ConfigurableServiceHelper.php b/Configurability/ConfigurableServiceHelper.php index 560f846a..ba19799d 100644 --- a/Configurability/ConfigurableServiceHelper.php +++ b/Configurability/ConfigurableServiceHelper.php @@ -31,9 +31,11 @@ class ConfigurableServiceHelper const CONF_RECOVERABLE = 'recoverable'; const CONF_NO_RESULTS = 'noResults'; - const STEP_DEFINE = 'define'; + const STEP_DEFINE = 'define'; const STEP_VALIDATE = 'validate'; + const STEP_DEBUG = 'debug'; + const OPTION_METHOD = 'method'; const KEY_DESCRIPTION = 'description'; const KEY_RESPONSE = 'response'; @@ -96,11 +98,13 @@ public function createContext(array $options, MessageInterface $message = null, return $context; } - public function resolveArray($input, &$context){ + public function resolveArray($input, &$context) + { $output = []; - foreach($input as $key => $value){ - $output[$key] = $this->resolve($value,$context); + foreach ($input as $key => $value) { + $output[$key] = $this->resolve($value, $context); } + return $output; } @@ -163,8 +167,13 @@ public function executeStep($stepAction, &$stepActionParams, &$options, array &$ break; case self::STEP_VALIDATE: $this->validate($stepActionParams, $context); + return true; break; + case self::STEP_DEBUG: + $this->debug($stepActionParams, $context); + + return true; default: return false; break; @@ -196,7 +205,6 @@ public function define(array $definitions, array &$context) public function validate(array $stepConfig, array &$context) { - $config = $this->validateResolver->resolve($stepConfig); $rule = $config[self::CONF_RULE]; @@ -206,7 +214,7 @@ public function validate(array $stepConfig, array &$context) $display_message = $config[self::CONF_DISPLAY_MESSAGE]; $evaluation = $this->resolve($rule, $context); - if ($evaluation !== true) { + if (true !== $evaluation) { $message = $this->resolve($message, $context); if ($no_results) { throw new NoResultsException($message); @@ -224,6 +232,24 @@ public function validate(array $stepConfig, array &$context) } } + /** + * Nasty hack to be able to easily display context variables in producers. + * + * @param array $variables + * @param $context + */ + protected function debug($variables, &$context) + { + foreach ($variables as $var) { + echo "\n"; + echo 'context'.$var.' => '; + $command = 'print_r($context'.$var.');'; + eval($command); + } + + return; + } + public function runValidations(array $validations, array &$context) { if (!empty($validations)) { From 74a065d3c448dfb78b97e1f88eea69a43969f863 Mon Sep 17 00:00:00 2001 From: Bertrand Drouhard Date: Fri, 4 May 2018 11:38:10 +0000 Subject: [PATCH 10/35] Added parameters for debug step: display, exit and sleep --- Configurability/ConfigurableServiceHelper.php | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/Configurability/ConfigurableServiceHelper.php b/Configurability/ConfigurableServiceHelper.php index ba19799d..7bfe04b4 100644 --- a/Configurability/ConfigurableServiceHelper.php +++ b/Configurability/ConfigurableServiceHelper.php @@ -235,16 +235,35 @@ public function validate(array $stepConfig, array &$context) /** * Nasty hack to be able to easily display context variables in producers. * - * @param array $variables + * @param array $actions * @param $context */ - protected function debug($variables, &$context) + protected function debug($actions, &$context) { - foreach ($variables as $var) { - echo "\n"; - echo 'context'.$var.' => '; - $command = 'print_r($context'.$var.');'; - eval($command); + if (!is_array($actions)) { + return; + } + foreach ($actions as $action => $parameters) { + if ('display' == $action) { + foreach ($parameters as $var) { + echo "\n"; + echo 'context'.$var.' => '; + $command = 'print_r($context'.$var.');'; + eval($command); + } + flush(); + ob_flush(); + } + + if ('sleep' == $action) { + echo 'Sleeping for '.$parameters.' seconds due to sleep step...'."\n"; + sleep($parameters); + } + + if ('exit' == $action && false !== $parameters) { + echo 'Exit due to debug step'."\n"; + exit; + } } return; From 3ed4fb365df3b5392d3e9f1cd4c1f713f8d5d98e Mon Sep 17 00:00:00 2001 From: Bertrand Drouhard Date: Wed, 9 May 2018 09:37:29 +0000 Subject: [PATCH 11/35] Replaced PRETTY_RECORDED_RESPONSE with RAW_RECORDED_RESPONSE --- Tools/MockClients/FakeRestClient.php | 4 ++-- Tools/MockClients/FakeSoapClient.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Tools/MockClients/FakeRestClient.php b/Tools/MockClients/FakeRestClient.php index 5c341cd3..e45643ed 100644 --- a/Tools/MockClients/FakeRestClient.php +++ b/Tools/MockClients/FakeRestClient.php @@ -159,11 +159,11 @@ protected function getResponseFromCache($resource, $suffix = null) */ protected function setResponseInCache($resource, $response, $suffix = null) { - $prettyRecordedResponse = getenv('PRETTY_RECORDED_RESPONSE'); + $rawRecordedResponse = getenv('RAW_RECORDED_RESPONSE'); $content = $this->getResponseContent($response); - if ('true' === $prettyRecordedResponse) { + if ('true' !== $rawRecordedResponse) { // By default, we record a pretty response. $content = $this->prettyJson($content); } diff --git a/Tools/MockClients/FakeSoapClient.php b/Tools/MockClients/FakeSoapClient.php index 9168a675..eb530dc4 100644 --- a/Tools/MockClients/FakeSoapClient.php +++ b/Tools/MockClients/FakeSoapClient.php @@ -62,7 +62,7 @@ public function __doRequest($request, $location, $action, $version, $oneWay = 0) $mocksEnabled = getenv('MOCKS_ENABLED'); $displayRequest = getenv('DISPLAY_REQUEST'); $recordResponse = getenv('RECORD_RESPONSE'); - $prettyRecordedResponse = getenv('PRETTY_RECORDED_RESPONSE'); + $rawRecordedResponse = getenv('RAW_RECORDED_RESPONSE'); if ('true' === $mocksEnabled) { $mocksMessage = 'MOCKS/'; @@ -111,7 +111,7 @@ public function __doRequest($request, $location, $action, $version, $oneWay = 0) if ('true' === $recordResponse) { $recordedResponse = $response; - if ('true' === $prettyRecordedResponse) { + if ('true' !== $rawRecordedResponse) { // By default, we record a pretty response. $recordedResponse = $this->prettyXML($response); } $this->setResponseInCache($actionName, $recordedResponse, self::CACHE_SUFFIX); From 979ea2c2870c6b20368663a83b095558137ade8c Mon Sep 17 00:00:00 2001 From: Bertrand Drouhard Date: Wed, 9 May 2018 15:17:36 +0000 Subject: [PATCH 12/35] When DISPLAY_REQUEST, also display headers for SOAP calls --- Tools/MockClients/FakeSoapClient.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Tools/MockClients/FakeSoapClient.php b/Tools/MockClients/FakeSoapClient.php index eb530dc4..0ed9863b 100644 --- a/Tools/MockClients/FakeSoapClient.php +++ b/Tools/MockClients/FakeSoapClient.php @@ -71,8 +71,19 @@ public function __doRequest($request, $location, $action, $version, $oneWay = 0) } if ('true' === $displayRequest) { + $requestHeaders = []; + if (isset($this->requestHeaders) && is_array($this->requestHeaders)) { + foreach ($this->requestHeaders as $headerName => $headerValue) { + $requestHeaders[] = $headerName.' => '.$headerValue; + } + } + echo "\nREQUEST (".$mocksMessage."SOAP) for $location / $action / Version $version"; echo "\n====================================================================================================="; + echo "\nHEADERS"; + echo "\n====================================================================================================="; + echo "\n ".implode($requestHeaders, "\n "); + echo "\n====================================================================================================="; echo "\nRAW REQUEST"; echo "\n====================================================================================================="; echo "\n".$request; From 76797e9a2b91c5561f9bb596aaafd9395d072020 Mon Sep 17 00:00:00 2001 From: Bertrand Drouhard Date: Thu, 10 May 2018 10:54:47 +0000 Subject: [PATCH 13/35] Debug step, provide the full name of the variable to display --- Configurability/ConfigurableServiceHelper.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Configurability/ConfigurableServiceHelper.php b/Configurability/ConfigurableServiceHelper.php index 7bfe04b4..94c972c7 100644 --- a/Configurability/ConfigurableServiceHelper.php +++ b/Configurability/ConfigurableServiceHelper.php @@ -247,8 +247,8 @@ protected function debug($actions, &$context) if ('display' == $action) { foreach ($parameters as $var) { echo "\n"; - echo 'context'.$var.' => '; - $command = 'print_r($context'.$var.');'; + echo $var.' => '; + $command = 'print_r($'.$var.');'; eval($command); } flush(); From 2b6abda21dd82adcf253b9422f7454c19392e6ce Mon Sep 17 00:00:00 2001 From: Bertrand Drouhard Date: Thu, 10 May 2018 11:24:43 +0000 Subject: [PATCH 14/35] Added a break debug step to make xdebug stop and let you watch whatever you want --- Configurability/ConfigurableServiceHelper.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Configurability/ConfigurableServiceHelper.php b/Configurability/ConfigurableServiceHelper.php index 94c972c7..f4d01685 100644 --- a/Configurability/ConfigurableServiceHelper.php +++ b/Configurability/ConfigurableServiceHelper.php @@ -255,6 +255,12 @@ protected function debug($actions, &$context) ob_flush(); } + if ('break' == $action && false !== $parameters) { + if (function_exists('xdebug_break')) { + xdebug_break(); + } + } + if ('sleep' == $action) { echo 'Sleeping for '.$parameters.' seconds due to sleep step...'."\n"; sleep($parameters); From 277bad8c9818047cd159c97f3c2fccd23718e703 Mon Sep 17 00:00:00 2001 From: Bertrand Drouhard Date: Thu, 31 May 2018 15:37:23 +0000 Subject: [PATCH 15/35] In FakeRestClient, can display beautified body response --- Tools/MockClients/FakeRestClient.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Tools/MockClients/FakeRestClient.php b/Tools/MockClients/FakeRestClient.php index e45643ed..350c0f04 100644 --- a/Tools/MockClients/FakeRestClient.php +++ b/Tools/MockClients/FakeRestClient.php @@ -81,10 +81,12 @@ public function send(RequestInterface $request, array $options = []) if ('true' === $displayRequest) { $content = $this->getResponseContent($response); + $body = $this->getBodyContent($response); echo "\nRESPONSE (".$mocksMessage.'REST) for '.$requestUri.' / '.$requestMethod; echo "\n====================================================================================================="; echo "\nRAW RESPONSE:\n".$content; echo "\nPRETTY SEXY RESPONSE:\n".$this->prettyJson($content); + echo "\nPRETTY SEXY BODY:\n".$this->prettyJson($body); echo "\n====================================================================================================="; echo "\n\n"; } @@ -190,4 +192,17 @@ protected function getResponseContent($response) return $content; } + + /** + * @param Psr7\Response $response + * + * @return string + */ + protected function getBodyContent($response) + { + $body = $response->getBody()->getContents(); + $response->getBody()->rewind(); + + return $body; + } } From 591b060dbc3c1289732bcb9e551b41ddfbf81e93 Mon Sep 17 00:00:00 2001 From: Bertrand Drouhard Date: Tue, 16 Jan 2018 09:54:14 +0000 Subject: [PATCH 16/35] Feature: Optimize DBConfigurableConsumer with a slow mode after a certain period of inactivity --- Components/DB/DBConfigurableConsumer.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Components/DB/DBConfigurableConsumer.php b/Components/DB/DBConfigurableConsumer.php index 28b7c873..b72fcd81 100644 --- a/Components/DB/DBConfigurableConsumer.php +++ b/Components/DB/DBConfigurableConsumer.php @@ -23,6 +23,9 @@ class DBConfigurableConsumer extends Service implements ConfigurableConsumerInte use UsesLogger; use UsesSmartesbHelper; + const SLEEP_TIME = 100; // Duration of the pause made in the consume loop, when nothing to do (slow mode), in milliseconds. + const INACTIVITY_TRIGGER = 10; // Inactivity duration before switching to slow mode, in seconds. + /** @var ConfigurableStepsProviderInterface */ protected $configurableStepsProvider; @@ -110,12 +113,17 @@ protected function onConsume(EndpointInterface $endpoint, MessageInterface $mess */ public function consume(EndpointInterface $endpoint) { + $iFeelAsleep = false; + $wakeup = microtime(); + while (!$this->shouldStop()) { // Receive $message = $this->readMessage($endpoint); // Process if ($message) { + $iFeelAsleep = false; + $wakeup = microtime(); --$this->expirationCount; $endpoint->handle($message); @@ -127,6 +135,13 @@ public function consume(EndpointInterface $endpoint) $this->onConsume($endpoint, $message); } + if ($iFeelAsleep) { + usleep(self::SLEEP_TIME * 1000); // 100 ms + } + + if ((microtime() - $wakeup) > self::INACTIVITY_TRIGGER) { // I did nothing since the last x seconds, so I enter the slow mode... + $iFeelAsleep = true; + } } } } From e894c65f6f75e36a12120e4bcbccd2ff840d4506 Mon Sep 17 00:00:00 2001 From: Gary PEGEOT Date: Mon, 30 Jul 2018 14:06:09 +0100 Subject: [PATCH 17/35] Use PHPUnit bridge --- .travis.yml | 2 +- composer.json | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 45aac3e8..738749e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,7 +29,7 @@ before_script: - composer install --prefer-dist --no-interaction script: - - bin/phpunit --coverage-text --debug + - bin/simple-phpunit --coverage-text notifications: email: diff --git a/composer.json b/composer.json index 76615beb..fb3bc944 100644 --- a/composer.json +++ b/composer.json @@ -27,9 +27,7 @@ "smartbox/core-bundle": "^1.0.0" }, "require-dev": { - "phpunit/php-code-coverage": "~4.0", - "phpunit/phpunit-mock-objects": "~3.2", - "phpunit/phpunit": "~5.4", + "symfony/phpunit-bridge": "*", "sensio/generator-bundle": "~2.3", "mongodb/mongodb": "~1.0" }, From 5cb8987bb78b2f9fde269149fb49e5c1e3b3a889 Mon Sep 17 00:00:00 2001 From: Gary PEGEOT Date: Mon, 30 Jul 2018 14:07:18 +0100 Subject: [PATCH 18/35] Add options for inactivity trigger and duration --- Components/DB/Dbal/ConfigurableDbalProtocol.php | 10 +++++++--- .../DB/Dbal/ConfigurableDbalProtocolTest.php | 8 ++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Components/DB/Dbal/ConfigurableDbalProtocol.php b/Components/DB/Dbal/ConfigurableDbalProtocol.php index 723ebf83..ac371aba 100644 --- a/Components/DB/Dbal/ConfigurableDbalProtocol.php +++ b/Components/DB/Dbal/ConfigurableDbalProtocol.php @@ -11,6 +11,8 @@ class ConfigurableDbalProtocol extends Protocol implements DescriptableInterface const OPTION_METHOD = 'method'; const OPTION_STOP_ON_NO_RESULTS = 'stop_on_no_results'; const OPTION_DB_CONNECTION_NAME = 'db_connection_name'; + const OPTION_SLEEP_TIME = 'sleep_time_ms'; + const OPTION_INACTIVITY_TRIGGER = 'inactivity_trigger_sec'; /** * Get static default options. @@ -23,6 +25,8 @@ public function getOptionsDescriptions() self::OPTION_METHOD => ['Method to be executed in the consumer/producer', []], self::OPTION_STOP_ON_NO_RESULTS => ['Consumer should stop on when all the records have been processed.', []], self::OPTION_DB_CONNECTION_NAME => ['Option to chose which DB connection the consumer/producer should use', []], + self::OPTION_SLEEP_TIME => ['Duration of the pause made in the consume loop, when nothing to do (slow mode), in milliseconds.', []], + self::OPTION_INACTIVITY_TRIGGER => ['Inactivity duration before switching to slow mode, in seconds.', []], ]); } @@ -30,8 +34,6 @@ public function getOptionsDescriptions() * With this method this class can configure an OptionsResolver that will be used to validate the options. * * @param OptionsResolver $resolver - * - * @return mixed */ public function configureOptionsResolver(OptionsResolver $resolver) { @@ -41,11 +43,13 @@ public function configureOptionsResolver(OptionsResolver $resolver) $resolver->setDefaults([ self::OPTION_STOP_ON_NO_RESULTS => false, self::OPTION_DB_CONNECTION_NAME => '', + self::OPTION_SLEEP_TIME => 100, + self::OPTION_INACTIVITY_TRIGGER => 10, ]); $resolver->setAllowedTypes(self::OPTION_METHOD, ['string']); $resolver->setAllowedTypes(self::OPTION_STOP_ON_NO_RESULTS, ['bool']); - $resolver->setAllowedTypes(self::OPTION_DB_CONNECTION_NAME, ['string']); + $resolver->setAllowedTypes(self::OPTION_DB_CONNECTION_NAME, 'numeric'); } /** diff --git a/Tests/Unit/Components/DB/Dbal/ConfigurableDbalProtocolTest.php b/Tests/Unit/Components/DB/Dbal/ConfigurableDbalProtocolTest.php index 0b899ad2..355de8b8 100644 --- a/Tests/Unit/Components/DB/Dbal/ConfigurableDbalProtocolTest.php +++ b/Tests/Unit/Components/DB/Dbal/ConfigurableDbalProtocolTest.php @@ -10,8 +10,14 @@ */ class ConfigurableDbalProtocolTest extends \PHPUnit_Framework_TestCase { + /** + * @var ConfigurableDbalProtocol + */ private $dbalProtocol; + /** + * @var array + */ private $expectedOptions; protected function setUp() @@ -21,6 +27,8 @@ protected function setUp() ConfigurableDbalProtocol::OPTION_METHOD, ConfigurableDbalProtocol::OPTION_STOP_ON_NO_RESULTS, ConfigurableDbalProtocol::OPTION_DB_CONNECTION_NAME, + ConfigurableDbalProtocol::OPTION_SLEEP_TIME, + ConfigurableDbalProtocol::OPTION_INACTIVITY_TRIGGER, ]; } From 8ca5f161aa623881fcdfbe26844db10bddd61d30 Mon Sep 17 00:00:00 2001 From: Gary PEGEOT Date: Mon, 30 Jul 2018 14:08:52 +0100 Subject: [PATCH 19/35] Use options instead of constants --- Components/DB/DBConfigurableConsumer.php | 21 ++-- .../DB/DBConfigurableConsumerTest.php | 98 +++++++++++++++++++ 2 files changed, 105 insertions(+), 14 deletions(-) create mode 100644 Tests/Unit/Components/DB/DBConfigurableConsumerTest.php diff --git a/Components/DB/DBConfigurableConsumer.php b/Components/DB/DBConfigurableConsumer.php index b72fcd81..d80231b0 100644 --- a/Components/DB/DBConfigurableConsumer.php +++ b/Components/DB/DBConfigurableConsumer.php @@ -23,9 +23,6 @@ class DBConfigurableConsumer extends Service implements ConfigurableConsumerInte use UsesLogger; use UsesSmartesbHelper; - const SLEEP_TIME = 100; // Duration of the pause made in the consume loop, when nothing to do (slow mode), in milliseconds. - const INACTIVITY_TRIGGER = 10; // Inactivity duration before switching to slow mode, in seconds. - /** @var ConfigurableStepsProviderInterface */ protected $configurableStepsProvider; @@ -113,8 +110,9 @@ protected function onConsume(EndpointInterface $endpoint, MessageInterface $mess */ public function consume(EndpointInterface $endpoint) { - $iFeelAsleep = false; - $wakeup = microtime(); + $sleepTime = (int) $endpoint->getOption(ConfigurableDbalProtocol::OPTION_SLEEP_TIME) * 1000; + $inactivityTrigger = (int) $endpoint->getOption(ConfigurableDbalProtocol::OPTION_INACTIVITY_TRIGGER); + $wakeup = microtime(true); while (!$this->shouldStop()) { // Receive @@ -122,25 +120,20 @@ public function consume(EndpointInterface $endpoint) // Process if ($message) { - $iFeelAsleep = false; - $wakeup = microtime(); --$this->expirationCount; $endpoint->handle($message); if ($this->logger) { - $now = \DateTime::createFromFormat('U.u', microtime(true)); - $this->logger->info('A message was consumed on '.$now->format('Y-m-d H:i:s.u')); + $this->logger->info('A message was consumed on {date}', ['date' => date('Y-m-d H:i:s.u')]); } $this->onConsume($endpoint, $message); - } - if ($iFeelAsleep) { - usleep(self::SLEEP_TIME * 1000); // 100 ms + $wakeup = microtime(true); } - if ((microtime() - $wakeup) > self::INACTIVITY_TRIGGER) { // I did nothing since the last x seconds, so I enter the slow mode... - $iFeelAsleep = true; + if ((microtime(true) - $wakeup) > $inactivityTrigger) { // I did nothing since the last x seconds, so little nap... + usleep($sleepTime); } } } diff --git a/Tests/Unit/Components/DB/DBConfigurableConsumerTest.php b/Tests/Unit/Components/DB/DBConfigurableConsumerTest.php new file mode 100644 index 00000000..bfc99b06 --- /dev/null +++ b/Tests/Unit/Components/DB/DBConfigurableConsumerTest.php @@ -0,0 +1,98 @@ +messageFactory = $this->createMock(MessageFactory::class); + $this->stepProvider = $this->createMock(ConfigurableStepsProviderInterface::class); + $this->helper = $this->createMock(SmartesbHelper::class); + + $this->consumer = new DBConfigurableConsumer(); + $this->consumer->setConfHelper(new ConfigurableServiceHelper()); + $this->consumer->setConfigurableStepsProvider($this->stepProvider); + $this->consumer->setMessageFactory($this->messageFactory); + $this->consumer->setSmartesbHelper($this->helper); + $this->consumer->setExpirationCount(2); + $this->consumer->setMethodsConfiguration([ + 'myMethod' => [ + ConfigurableConsumerInterface::CONFIG_ON_CONSUME => [], + ConfigurableConsumerInterface::CONFIG_QUERY_STEPS => [], + ConfigurableConsumerInterface::CONFIG_QUERY_RESULT => $this->createMock(SerializableInterface::class), + ], + ]); + + $this->helper->expects($this->any())->method('getMessageFactory')->willReturn($this->messageFactory); + } + + public function testGetConfigurableStepsProvider() + { + $this->assertSame($this->stepProvider, $this->consumer->getConfigurableStepsProvider()); + } + + /** + * @group time-sensitive + */ + public function testConsume() + { + $options = [ + ConfigurableDbalProtocol::OPTION_METHOD => 'myMethod', + ConfigurableDbalProtocol::OPTION_STOP_ON_NO_RESULTS => true, + ConfigurableDbalProtocol::OPTION_SLEEP_TIME => 10000, + ConfigurableDbalProtocol::OPTION_INACTIVITY_TRIGGER => 1, + ]; + + /** @var EndpointInterface|\PHPUnit_Framework_MockObject_MockObject $endpoint */ + $endpoint = $this->createMock(EndpointInterface::class); + $endpoint->expects($this->any())->method('getOptions')->willReturn($options); + $endpoint->expects($this->any()) + ->method('getOption') + ->willReturnCallback(function ($key) use ($options) { + return $options[$key]; + }); + + $this->messageFactory->expects($this->exactly(2)) + ->method('createMessage') + ->willReturn($this->createMock(MessageInterface::class)); + + $start = microtime(true); + $this->consumer->consume($endpoint); + $this->assertLessThan(10, microtime(true) - $start, 'Execution should no last more than 10s'); + } +} From 90939a230247222e73df7257f3b5e47da4dbee8a Mon Sep 17 00:00:00 2001 From: Gary PEGEOT Date: Mon, 30 Jul 2018 14:47:10 +0100 Subject: [PATCH 20/35] Use DateTime instead of date. --- Components/DB/DBConfigurableConsumer.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Components/DB/DBConfigurableConsumer.php b/Components/DB/DBConfigurableConsumer.php index d80231b0..14e5108e 100644 --- a/Components/DB/DBConfigurableConsumer.php +++ b/Components/DB/DBConfigurableConsumer.php @@ -125,7 +125,10 @@ public function consume(EndpointInterface $endpoint) $endpoint->handle($message); if ($this->logger) { - $this->logger->info('A message was consumed on {date}', ['date' => date('Y-m-d H:i:s.u')]); + $this->logger->info( + 'A message was consumed on {date}', + ['date' => \DateTime::createFromFormat('U.u', microtime(true))->format('Y-m-d H:i:s.u')] + ); } $this->onConsume($endpoint, $message); From 3811229872aa7c2d8e9ed8daf91e7ad9e10a2cd7 Mon Sep 17 00:00:00 2001 From: Gary PEGEOT Date: Mon, 30 Jul 2018 15:07:29 +0100 Subject: [PATCH 21/35] Fix type --- Components/DB/Dbal/ConfigurableDbalProtocol.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Components/DB/Dbal/ConfigurableDbalProtocol.php b/Components/DB/Dbal/ConfigurableDbalProtocol.php index ac371aba..ca36c31b 100644 --- a/Components/DB/Dbal/ConfigurableDbalProtocol.php +++ b/Components/DB/Dbal/ConfigurableDbalProtocol.php @@ -49,7 +49,9 @@ public function configureOptionsResolver(OptionsResolver $resolver) $resolver->setAllowedTypes(self::OPTION_METHOD, ['string']); $resolver->setAllowedTypes(self::OPTION_STOP_ON_NO_RESULTS, ['bool']); - $resolver->setAllowedTypes(self::OPTION_DB_CONNECTION_NAME, 'numeric'); + $resolver->setAllowedTypes(self::OPTION_DB_CONNECTION_NAME, 'string'); + $resolver->setAllowedTypes(self::OPTION_SLEEP_TIME, 'numeric'); + $resolver->setAllowedTypes(self::OPTION_INACTIVITY_TRIGGER, 'numeric'); } /** From d061c5e4bb6bdd875a9010035408c4d82e47498f Mon Sep 17 00:00:00 2001 From: Bertrand Drouhard Date: Mon, 30 Jul 2018 17:45:29 +0000 Subject: [PATCH 22/35] Fixed deprecation notices for scarlar starting with @ --- Resources/config/consumers.yml | 2 +- Resources/config/default_endpoint_routes.yml | 14 ++++++------- Resources/config/events_deferring.yml | 2 +- Resources/config/producers.yml | 10 ++++----- Resources/config/protocols.yml | 22 ++++++++++---------- Resources/config/routing.yml | 12 +++++------ 6 files changed, 31 insertions(+), 31 deletions(-) diff --git a/Resources/config/consumers.yml b/Resources/config/consumers.yml index ad1ecdb1..b54fdd64 100644 --- a/Resources/config/consumers.yml +++ b/Resources/config/consumers.yml @@ -6,4 +6,4 @@ services: class: %smartesb.consumers.queue.class% calls: - [ setId, ['smartesb.consumers.queue']] - - [ setSmartesbHelper, [@smartesb.helper]] + - [ setSmartesbHelper, ['@smartesb.helper']] diff --git a/Resources/config/default_endpoint_routes.yml b/Resources/config/default_endpoint_routes.yml index 87a08cbe..2cd0ae99 100644 --- a/Resources/config/default_endpoint_routes.yml +++ b/Resources/config/default_endpoint_routes.yml @@ -1,29 +1,29 @@ queues.generic: - pattern: "queue://{queue_driver}/{queue}" + path: "queue://{queue_driver}/{queue}" defaults: - _protocol: @smartesb.protocols.queue + _protocol: "@smartesb.protocols.queue" prefix: "%kernel.environment%" requirements: queue: "[a-zA-Z0-9/]+" queue_driver: "[a-zA-Z0-9]+" direct: - pattern: "direct://{path}" + path: "direct://{path}" defaults: - _protocol: @smartesb.protocols.direct + _protocol: "@smartesb.protocols.direct" requirements: path: "[a-zA-Z0-9/_]+" service: - pattern: "service://{service}/{method}" + path: "service://{service}/{method}" defaults: - _protocol: @smartesb.protocols.service + _protocol: "@smartesb.protocols.service" requirements: service: "[a-zA-Z0-9/_.-]+" method: "[a-zA-Z0-9_]+" csv.generic: - pattern: "csv://generic/{path}" + path: "csv://generic/{path}" defaults: _protocol: "@smartesb.protocols.configurable.csv_file" _consumer: "@smartesb.consumers.generic_csv" diff --git a/Resources/config/events_deferring.yml b/Resources/config/events_deferring.yml index d20d5db3..57e6ee36 100644 --- a/Resources/config/events_deferring.yml +++ b/Resources/config/events_deferring.yml @@ -7,7 +7,7 @@ services: class: %smartesb.handlers.events_deferring.class% calls: - [setId, ['smartesb.handlers.events']] - - [setEventDispatcher, [@event_dispatcher]] + - [setEventDispatcher, ['@event_dispatcher']] - [setFlowsVersion, [%smartesb.flows_version%]] smartesb.registry.event_filters: diff --git a/Resources/config/producers.yml b/Resources/config/producers.yml index 5d2c993b..f9c6049e 100644 --- a/Resources/config/producers.yml +++ b/Resources/config/producers.yml @@ -12,26 +12,26 @@ services: class: %smartesb.producers.direct.class% calls: - [setId, ['smartesb.producer.direct']] - - [setItineraryResolver, [@smartesb.itineray_resolver]] + - [setItineraryResolver, ['@smartesb.itineray_resolver']] smartesb.producers.json_file: class: %smartesb.producers.json_file.class% calls: - [setId, ['smartesb.producers.json_file']] - - [setSerializer, [@serializer]] + - [setSerializer, ['@serializer']] # STOMP smartesb.producers.queue: class: %smartesb.producers.queue.class% calls: - [setId, ['smartesb.producers.queue']] - - [setSerializer, [@serializer]] - - [setDriverRegistry, [@smartesb.drivers.queue._registry]] + - [setSerializer, ['@serializer']] + - [setDriverRegistry, ['@smartesb.drivers.queue._registry']] # NoSQL smartesb.producers.service: class: %smartesb.producers.service.class% calls: - [setId, ['smartesb.producers.service']] - - [setContainer, [@service_container]] + - [setContainer, ['@service_container']] diff --git a/Resources/config/protocols.yml b/Resources/config/protocols.yml index 441a38b1..857a98fe 100644 --- a/Resources/config/protocols.yml +++ b/Resources/config/protocols.yml @@ -23,35 +23,35 @@ services: smartesb.protocols.direct: class: %smartesb.protocols.direct.class% calls: - - [setDefaultProducer, [@smartesb.producer.direct]] - - [setDefaultHandler, [@smartesb.handlers.sync]] + - [setDefaultProducer, ['@smartesb.producer.direct']] + - [setDefaultHandler, ['@smartesb.handlers.sync']] # JSON FILE smartesb.protocols.json_file: class: %smartesb.protocols.json_file.class% calls: - - [setDefaultProducer, [@smartesb.producers.json_file]] + - [setDefaultProducer, ['@smartesb.producers.json_file']] # Queues smartesb.protocols.service: class: %smartesb.protocols.service.class% calls: - - [setDefaultProducer, [@smartesb.producers.service]] - - [setDefaultHandler, [@smartesb.handlers.async]] + - [setDefaultProducer, ['@smartesb.producers.service']] + - [setDefaultHandler, ['@smartesb.handlers.async']] # Queues smartesb.protocols.queue: class: %smartesb.protocols.queue.class% calls: - - [setDefaultProducer, [@smartesb.producers.queue]] - - [setDefaultConsumer, [@smartesb.consumers.queue]] - - [setDefaultHandler, [@smartesb.handlers.async]] + - [setDefaultProducer, ['@smartesb.producers.queue']] + - [setDefaultConsumer, ['@smartesb.consumers.queue']] + - [setDefaultHandler, ['@smartesb.handlers.async']] #NoSQL smartesb.protocols.configurable.nosql: class: %smartesb.protocols.configurable.nosql.class% calls: - - [setDefaultHandler, [@smartesb.handlers.async]] + - [setDefaultHandler, ['@smartesb.handlers.async']] smartesb.protocols.configurable.webservice: class: %smartesb.protocols.configurable.webservice.class% @@ -65,10 +65,10 @@ services: smartesb.protocols.configurable.dbal: class: %smartesb.protocols.configurable.dbal.class% calls: - - [setDefaultHandler, [@smartesb.handlers.async]] + - [setDefaultHandler, ['@smartesb.handlers.async']] # Csv File smartesb.protocols.configurable.csv_file: class: "%smartesb.protocols.csv_file.class%" calls: - - [setDefaultHandler, [@smartesb.handlers.async]] + - [setDefaultHandler, ['@smartesb.handlers.async']] diff --git a/Resources/config/routing.yml b/Resources/config/routing.yml index c59debbe..23de8b4e 100644 --- a/Resources/config/routing.yml +++ b/Resources/config/routing.yml @@ -36,8 +36,8 @@ services: smartesb.router.itineraries: class: %smartesb.internal_router.class% arguments: - - @service_container - - @@SmartboxIntegrationFrameworkBundle/Resources/config/default_routing_itineraries.yml + - '@service_container' + - '@@SmartboxIntegrationFrameworkBundle/Resources/config/default_routing_itineraries.yml' - %smartesb.router.itineraries.options% tags: - { name: monolog.logger, channel: "router.itineraries" } @@ -45,7 +45,7 @@ services: smartesb.router.endpoints: class: %smartesb.internal_router.class% arguments: - - @service_container + - '@service_container' - "%kernel.root_dir%/config/routing_endpoints_%kernel.environment%.yml" - %smartesb.router.endpoints.options% tags: @@ -54,14 +54,14 @@ services: smartesb.router.itineraries.cache_warmer: class: %router.cache_warmer.class% arguments: - - @smartesb.router.itineraries + - '@smartesb.router.itineraries' tags: - { name: "kernel.cache_warmer" } smartesb.router.endpoints.cache_warmer: class: %router.cache_warmer.class% arguments: - - @smartesb.router.endpoints + - '@smartesb.router.endpoints' tags: - { name: "kernel.cache_warmer" } @@ -71,6 +71,6 @@ services: smartesb.routing.itineraries_routes_loader: class: Smartbox\Integration\FrameworkBundle\Configurability\Routing\ItinerariesRoutesLoader calls: - - [ setContainer, [ @service_container ] ] + - [ setContainer, [ '@service_container' ] ] tags: - { name: routing.loader } From 85e1121d3645f57d9ca4bb76d3e664cf32495cb5 Mon Sep 17 00:00:00 2001 From: Bertrand Drouhard Date: Mon, 30 Jul 2018 17:47:53 +0000 Subject: [PATCH 23/35] Use simple-phpunit instead of phpunit --- .travis.yml | 2 +- composer.json | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 45aac3e8..738749e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,7 +29,7 @@ before_script: - composer install --prefer-dist --no-interaction script: - - bin/phpunit --coverage-text --debug + - bin/simple-phpunit --coverage-text notifications: email: diff --git a/composer.json b/composer.json index 76615beb..fb3bc944 100644 --- a/composer.json +++ b/composer.json @@ -27,9 +27,7 @@ "smartbox/core-bundle": "^1.0.0" }, "require-dev": { - "phpunit/php-code-coverage": "~4.0", - "phpunit/phpunit-mock-objects": "~3.2", - "phpunit/phpunit": "~5.4", + "symfony/phpunit-bridge": "*", "sensio/generator-bundle": "~2.3", "mongodb/mongodb": "~1.0" }, From 7261cba4feba363504f18ed32398f42834f64e3b Mon Sep 17 00:00:00 2001 From: Bertrand Drouhard Date: Thu, 2 Aug 2018 14:56:13 +0000 Subject: [PATCH 24/35] Timing of a message to be processed --- Core/Consumers/AbstractConsumer.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Core/Consumers/AbstractConsumer.php b/Core/Consumers/AbstractConsumer.php index 58a8f622..a3b09e92 100644 --- a/Core/Consumers/AbstractConsumer.php +++ b/Core/Consumers/AbstractConsumer.php @@ -89,6 +89,7 @@ public function consume(EndpointInterface $endpoint) // Process if ($message) { + $startTimestamp = microtime(true); --$this->expirationCount; $this->process($endpoint, $message); @@ -102,6 +103,11 @@ public function consume(EndpointInterface $endpoint) } $this->confirmMessage($endpoint, $message); + $finishTimestamp = microtime(true); + + if ($this->logger) { + $this->logger->debug('This message was processed in '.round(($finishTimestamp - $startTimestamp) * 1000, 0).' ms.'); + } } } catch (\Exception $ex) { if (!$this->stop) { From c441eba751213a7913d23686764da8a279dc7854 Mon Sep 17 00:00:00 2001 From: Gary PEGEOT Date: Wed, 8 Aug 2018 11:52:12 +0100 Subject: [PATCH 25/35] Remove unneeded trait use; (#56) Already included by `Smartbox\Integration\FrameworkBundle\Service` --- Core/Processors/Processor.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/Processors/Processor.php b/Core/Processors/Processor.php index e05631cd..7cf785a9 100644 --- a/Core/Processors/Processor.php +++ b/Core/Processors/Processor.php @@ -21,7 +21,6 @@ abstract class Processor extends Service implements ProcessorInterface const CONTEXT_PROCESSOR_DESCRIPTION = 'processor_description'; use UsesValidator; - use UsesEventDispatcher; /** * @var string From 6a620b449e047d94a04f068f6902d025dbbac312 Mon Sep 17 00:00:00 2001 From: Shane McKinley Date: Wed, 15 Aug 2018 11:17:51 +0100 Subject: [PATCH 26/35] MINT-2779: Capture consumption time of a message, in queue conumser override dispatch of conumption time to include seriliazation time, test --- .../Queues/Drivers/ArrayQueueDriver.php | 8 ++ .../Queues/Drivers/QueueDriverInterface.php | 5 ++ .../Queues/Drivers/StompQueueDriver.php | 19 +++++ Components/Queues/QueueConsumer.php | 21 ++++++ Core/Consumers/AbstractConsumer.php | 21 ++++++ Events/TimingEvent.php | 30 ++++++++ Resources/config/consumers.yml | 1 + Tests/Unit/Consumer/AbstractConsumerTest.php | 74 +++++++++++++++++++ 8 files changed, 179 insertions(+) create mode 100644 Events/TimingEvent.php create mode 100644 Tests/Unit/Consumer/AbstractConsumerTest.php diff --git a/Components/Queues/Drivers/ArrayQueueDriver.php b/Components/Queues/Drivers/ArrayQueueDriver.php index e637af1c..489ba2bd 100644 --- a/Components/Queues/Drivers/ArrayQueueDriver.php +++ b/Components/Queues/Drivers/ArrayQueueDriver.php @@ -18,6 +18,14 @@ class ArrayQueueDriver extends Service implements QueueDriverInterface protected $subscribedQueue = false; protected $unacknowledgedFrame = null; + /** + * @return int + */ + public function getDeQueueingTimeMs() + { + return 0; + } + /** * @return array */ diff --git a/Components/Queues/Drivers/QueueDriverInterface.php b/Components/Queues/Drivers/QueueDriverInterface.php index c6f33b06..2ef27085 100644 --- a/Components/Queues/Drivers/QueueDriverInterface.php +++ b/Components/Queues/Drivers/QueueDriverInterface.php @@ -105,4 +105,9 @@ public function createQueueMessage(); * Clean all the opened resources, must be called just before terminating the current request. */ public function doDestroy(); + + /** + * @return int The time it took in ms to deque and deserialize the message + */ + public function getDeQueueingTimeMs(); } diff --git a/Components/Queues/Drivers/StompQueueDriver.php b/Components/Queues/Drivers/StompQueueDriver.php index a0810843..8f1e0b03 100644 --- a/Components/Queues/Drivers/StompQueueDriver.php +++ b/Components/Queues/Drivers/StompQueueDriver.php @@ -55,6 +55,11 @@ class StompQueueDriver extends Service implements QueueDriverInterface protected $subscriptionId = false; + /** + * @var int The time it took in ms to deserialize the message + */ + protected $deQueueingTimeMs = 0; + /** * @return bool */ @@ -151,6 +156,14 @@ public function setFormat($format) $this->format = $format; } + /** + * @return int + */ + public function getDeQueueingTimeMs() + { + return $this->deQueueingTimeMs; + } + /** {@inheritdoc} */ public function configure($host, $username, $password, $format = QueueDriverInterface::FORMAT_JSON, $version = self::STOMP_VERSION, $vhost = null, $timeout = 3, $sync = true) { @@ -269,6 +282,8 @@ public function receive() ); } + $this->deQueueingTimeMs = 0; + $this->currentFrame = $this->statefulStomp->read(); while ($this->currentFrame && !$this->isFrameFromSubscription($this->currentFrame)) { @@ -278,6 +293,7 @@ public function receive() $msg = null; if ($this->currentFrame) { + $start = microtime(true); $deserializationContext = new DeserializationContext(); if (!empty($version)) { $deserializationContext->setVersion($version); @@ -293,6 +309,9 @@ public function receive() foreach ($this->currentFrame->getHeaders() as $header => $value) { $msg->setHeader($header, $this->unescape($value)); } + + // Calculate how long it took to deserilize the message + $this->deQueueingTimeMs = (int) ((microtime(true) - $start) * 1000); } return $msg; diff --git a/Components/Queues/QueueConsumer.php b/Components/Queues/QueueConsumer.php index 2150a893..371e4ff0 100644 --- a/Components/Queues/QueueConsumer.php +++ b/Components/Queues/QueueConsumer.php @@ -8,12 +8,19 @@ use Smartbox\Integration\FrameworkBundle\Core\Endpoints\EndpointFactory; use Smartbox\Integration\FrameworkBundle\Core\Endpoints\EndpointInterface; use Smartbox\Integration\FrameworkBundle\Core\Messages\MessageInterface; +use Smartbox\Integration\FrameworkBundle\Events\TimingEvent; /** * Class QueueConsumer. */ class QueueConsumer extends AbstractConsumer implements ConsumerInterface { + + /** + * @var int The time it took in ms to deserialize the message + */ + protected $deQueueingTimeMs = 0; + /** * {@inheritdoc} */ @@ -62,6 +69,7 @@ protected function cleanUp(EndpointInterface $endpoint) protected function readMessage(EndpointInterface $endpoint) { $driver = $this->getQueueDriver($endpoint); + $this->deQueueingTimeMs = $driver->getDeQueueingTimeMs(); return $driver->receive(); } @@ -88,4 +96,17 @@ protected function confirmMessage(EndpointInterface $endpoint, MessageInterface $driver = $this->getQueueDriver($endpoint); $driver->ack(); } + + /** + * @inheritdoc + * + * @param $intervalMs int the timing interval that we would like to emanate + * @return mixed + */ + protected function dispatchConsumerTimingEvent($intervalMs) + { + $intervalMs = $intervalMs + $this->deQueueingTimeMs; + + parent::dispatchConsumerTimingEvent($intervalMs); + } } diff --git a/Core/Consumers/AbstractConsumer.php b/Core/Consumers/AbstractConsumer.php index 58a8f622..56f66772 100644 --- a/Core/Consumers/AbstractConsumer.php +++ b/Core/Consumers/AbstractConsumer.php @@ -4,8 +4,10 @@ use Smartbox\Integration\FrameworkBundle\Core\Endpoints\EndpointInterface; use Smartbox\Integration\FrameworkBundle\Core\Messages\MessageInterface; +use Smartbox\Integration\FrameworkBundle\DependencyInjection\Traits\UsesEventDispatcher; use Smartbox\Integration\FrameworkBundle\DependencyInjection\Traits\UsesLogger; use Smartbox\Integration\FrameworkBundle\DependencyInjection\Traits\UsesSmartesbHelper; +use Smartbox\Integration\FrameworkBundle\Events\TimingEvent; use Smartbox\Integration\FrameworkBundle\Service; /** @@ -16,6 +18,7 @@ abstract class AbstractConsumer extends Service implements ConsumerInterface use IsStopableConsumer; use UsesLogger; use UsesSmartesbHelper; + use UsesEventDispatcher; /** * Initializes the consumer for a given endpoint. @@ -89,6 +92,8 @@ public function consume(EndpointInterface $endpoint) // Process if ($message) { + $startConsumeTime = microtime(true); + --$this->expirationCount; $this->process($endpoint, $message); @@ -102,6 +107,9 @@ public function consume(EndpointInterface $endpoint) } $this->confirmMessage($endpoint, $message); + + $endConsumeTime = microtime(true); + $this->dispatchConsumerTimingEvent((int) (($endConsumeTime - $startConsumeTime) * 1000)); } } catch (\Exception $ex) { if (!$this->stop) { @@ -121,4 +129,17 @@ public function getName() return basename($name, 'Consumer'); } + + /** + * This function dispatchs a timing event with the amount of time it took to consume a message + * + * @param $intervalMs int the timing interval that we would like to emanate + * @return mixed + */ + protected function dispatchConsumerTimingEvent($intervalMs) + { + $event = new TimingEvent(TimingEvent::CONSUMER_TIMING); + $event->setIntervalMs($intervalMs); + $this->getEventDispatcher()->dispatch(TimingEvent::CONSUMER_TIMING, $event); + } } diff --git a/Events/TimingEvent.php b/Events/TimingEvent.php new file mode 100644 index 00000000..2351daa1 --- /dev/null +++ b/Events/TimingEvent.php @@ -0,0 +1,30 @@ +intervalMs; + } + + /** + * @param integer $intervalMs + */ + public function setIntervalMs($intervalMs) + { + $this->intervalMs = $intervalMs; + } +} \ No newline at end of file diff --git a/Resources/config/consumers.yml b/Resources/config/consumers.yml index b54fdd64..f057133a 100644 --- a/Resources/config/consumers.yml +++ b/Resources/config/consumers.yml @@ -7,3 +7,4 @@ services: calls: - [ setId, ['smartesb.consumers.queue']] - [ setSmartesbHelper, ['@smartesb.helper']] + - [ setEventDispatcher, ['@event_dispatcher']] diff --git a/Tests/Unit/Consumer/AbstractConsumerTest.php b/Tests/Unit/Consumer/AbstractConsumerTest.php new file mode 100644 index 00000000..1af9b400 --- /dev/null +++ b/Tests/Unit/Consumer/AbstractConsumerTest.php @@ -0,0 +1,74 @@ +getMockForAbstractClass(AbstractConsumer::class, + ['initialize', 'readMessage'], + '', + true, + true, + true, + ['shouldStop'] + ); + + $consumer + ->expects($this->once()) + ->method('initialize') + ; + + $consumer + ->expects($this->exactly(2)) + ->method('shouldStop') + ->willReturnOnConsecutiveCalls(false, true); + ; + + $consumer + ->expects($this->once()) + ->method('readMessage') + ->willReturn(new Message()); + ; + + $eventDispatcher = $this->getMockForAbstractClass(EventDispatcherInterface::class); + + $eventDispatcher->expects($this->once()) + ->method('dispatch') + ->with($this->equalTo('smartesb.consumer.timing'), $this->callback(function($event) use ($lowerBoundMs, $upperBoundMs){ + $this->assertInstanceOf(TimingEvent::class, $event); + $interval = $event->getIntervalMs(); + + //here we need to allow for a small variance in the amount of time taken to 'handle' the message + return $interval > $lowerBoundMs && $interval < $upperBoundMs; + })) + ; + + $consumer->setEventDispatcher($eventDispatcher); + + $endpoint = $this->createMock(Endpoint::class); + $endpoint->expects($this->once()) + ->method('handle') + ->will( + $this->returnCallback(function() use ($handleTimeUs) { + usleep($handleTimeUs); + }) + ) + ; + + $consumer->consume($endpoint); + } +} From 87cc041f7f4c92cd0045cdb65b42124eb98d82d1 Mon Sep 17 00:00:00 2001 From: Shane McKinley Date: Wed, 15 Aug 2018 12:22:09 +0100 Subject: [PATCH 27/35] Add message to TimingEvent --- Components/Queues/QueueConsumer.php | 4 ++-- Core/Consumers/AbstractConsumer.php | 6 ++++-- Events/TimingEvent.php | 21 +++++++++++++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/Components/Queues/QueueConsumer.php b/Components/Queues/QueueConsumer.php index 371e4ff0..dc5fc5c6 100644 --- a/Components/Queues/QueueConsumer.php +++ b/Components/Queues/QueueConsumer.php @@ -103,10 +103,10 @@ protected function confirmMessage(EndpointInterface $endpoint, MessageInterface * @param $intervalMs int the timing interval that we would like to emanate * @return mixed */ - protected function dispatchConsumerTimingEvent($intervalMs) + protected function dispatchConsumerTimingEvent($intervalMs, MessageInterface $message) { $intervalMs = $intervalMs + $this->deQueueingTimeMs; - parent::dispatchConsumerTimingEvent($intervalMs); + parent::dispatchConsumerTimingEvent($intervalMs, $message); } } diff --git a/Core/Consumers/AbstractConsumer.php b/Core/Consumers/AbstractConsumer.php index 56f66772..a87d5361 100644 --- a/Core/Consumers/AbstractConsumer.php +++ b/Core/Consumers/AbstractConsumer.php @@ -109,7 +109,7 @@ public function consume(EndpointInterface $endpoint) $this->confirmMessage($endpoint, $message); $endConsumeTime = microtime(true); - $this->dispatchConsumerTimingEvent((int) (($endConsumeTime - $startConsumeTime) * 1000)); + $this->dispatchConsumerTimingEvent((int) (($endConsumeTime - $startConsumeTime) * 1000), $message); } } catch (\Exception $ex) { if (!$this->stop) { @@ -134,12 +134,14 @@ public function getName() * This function dispatchs a timing event with the amount of time it took to consume a message * * @param $intervalMs int the timing interval that we would like to emanate + * @param MessageInterface $message * @return mixed */ - protected function dispatchConsumerTimingEvent($intervalMs) + protected function dispatchConsumerTimingEvent($intervalMs, MessageInterface $message) { $event = new TimingEvent(TimingEvent::CONSUMER_TIMING); $event->setIntervalMs($intervalMs); + $event->setMessage($message); $this->getEventDispatcher()->dispatch(TimingEvent::CONSUMER_TIMING, $event); } } diff --git a/Events/TimingEvent.php b/Events/TimingEvent.php index 2351daa1..f5aca1f3 100644 --- a/Events/TimingEvent.php +++ b/Events/TimingEvent.php @@ -12,6 +12,11 @@ class TimingEvent extends Event */ private $intervalMs; + /** + * @var \Smartbox\Integration\FrameworkBundle\Core\Messages\MessageInterface + */ + protected $message; + /** * @return integer */ @@ -27,4 +32,20 @@ public function setIntervalMs($intervalMs) { $this->intervalMs = $intervalMs; } + + /** + * @return \Smartbox\Integration\FrameworkBundle\Core\Messages\MessageInterface + */ + public function getMessage() + { + return $this->message; + } + + /** + * @param \Smartbox\Integration\FrameworkBundle\Core\Messages\MessageInterface $message + */ + public function setMessage($message) + { + $this->message = $message; + } } \ No newline at end of file From 4e339ff502896363b7d1a0cb5a73dd26420ff7aa Mon Sep 17 00:00:00 2001 From: Shane McKinley Date: Wed, 15 Aug 2018 12:23:17 +0100 Subject: [PATCH 28/35] CS fixer --- Components/Queues/Drivers/QueueDriverInterface.php | 3 +-- Components/Queues/Drivers/StompQueueDriver.php | 2 +- Components/Queues/QueueConsumer.php | 5 ++--- Core/Consumers/AbstractConsumer.php | 3 ++- Events/TimingEvent.php | 9 ++++----- Tests/Unit/Consumer/AbstractConsumerTest.php | 7 ++----- 6 files changed, 12 insertions(+), 17 deletions(-) diff --git a/Components/Queues/Drivers/QueueDriverInterface.php b/Components/Queues/Drivers/QueueDriverInterface.php index 2ef27085..a18d8acc 100644 --- a/Components/Queues/Drivers/QueueDriverInterface.php +++ b/Components/Queues/Drivers/QueueDriverInterface.php @@ -76,10 +76,9 @@ public function ack(); */ public function nack(); - /** * @param QueueMessageInterface $message - * @param string|null $destination + * @param string|null $destination * * @return bool */ diff --git a/Components/Queues/Drivers/StompQueueDriver.php b/Components/Queues/Drivers/StompQueueDriver.php index 8f1e0b03..98d2bc3b 100644 --- a/Components/Queues/Drivers/StompQueueDriver.php +++ b/Components/Queues/Drivers/StompQueueDriver.php @@ -165,7 +165,7 @@ public function getDeQueueingTimeMs() } /** {@inheritdoc} */ - public function configure($host, $username, $password, $format = QueueDriverInterface::FORMAT_JSON, $version = self::STOMP_VERSION, $vhost = null, $timeout = 3, $sync = true) + public function configure($host, $username, $password, $format = QueueDriverInterface::FORMAT_JSON, $version = self::STOMP_VERSION, $vhost = null, $timeout = 3, $sync = true) { $this->format = $format; $this->host = $host; diff --git a/Components/Queues/QueueConsumer.php b/Components/Queues/QueueConsumer.php index dc5fc5c6..1ed1b51e 100644 --- a/Components/Queues/QueueConsumer.php +++ b/Components/Queues/QueueConsumer.php @@ -8,14 +8,12 @@ use Smartbox\Integration\FrameworkBundle\Core\Endpoints\EndpointFactory; use Smartbox\Integration\FrameworkBundle\Core\Endpoints\EndpointInterface; use Smartbox\Integration\FrameworkBundle\Core\Messages\MessageInterface; -use Smartbox\Integration\FrameworkBundle\Events\TimingEvent; /** * Class QueueConsumer. */ class QueueConsumer extends AbstractConsumer implements ConsumerInterface { - /** * @var int The time it took in ms to deserialize the message */ @@ -98,9 +96,10 @@ protected function confirmMessage(EndpointInterface $endpoint, MessageInterface } /** - * @inheritdoc + * {@inheritdoc} * * @param $intervalMs int the timing interval that we would like to emanate + * * @return mixed */ protected function dispatchConsumerTimingEvent($intervalMs, MessageInterface $message) diff --git a/Core/Consumers/AbstractConsumer.php b/Core/Consumers/AbstractConsumer.php index a87d5361..a8749cd9 100644 --- a/Core/Consumers/AbstractConsumer.php +++ b/Core/Consumers/AbstractConsumer.php @@ -131,10 +131,11 @@ public function getName() } /** - * This function dispatchs a timing event with the amount of time it took to consume a message + * This function dispatchs a timing event with the amount of time it took to consume a message. * * @param $intervalMs int the timing interval that we would like to emanate * @param MessageInterface $message + * * @return mixed */ protected function dispatchConsumerTimingEvent($intervalMs, MessageInterface $message) diff --git a/Events/TimingEvent.php b/Events/TimingEvent.php index f5aca1f3..19aff9cc 100644 --- a/Events/TimingEvent.php +++ b/Events/TimingEvent.php @@ -2,13 +2,12 @@ namespace Smartbox\Integration\FrameworkBundle\Events; - class TimingEvent extends Event { const CONSUMER_TIMING = 'smartesb.consumer.timing'; /** - * @var integer + * @var int */ private $intervalMs; @@ -18,7 +17,7 @@ class TimingEvent extends Event protected $message; /** - * @return integer + * @return int */ public function getIntervalMs() { @@ -26,7 +25,7 @@ public function getIntervalMs() } /** - * @param integer $intervalMs + * @param int $intervalMs */ public function setIntervalMs($intervalMs) { @@ -48,4 +47,4 @@ public function setMessage($message) { $this->message = $message; } -} \ No newline at end of file +} diff --git a/Tests/Unit/Consumer/AbstractConsumerTest.php b/Tests/Unit/Consumer/AbstractConsumerTest.php index 1af9b400..825812b7 100644 --- a/Tests/Unit/Consumer/AbstractConsumerTest.php +++ b/Tests/Unit/Consumer/AbstractConsumerTest.php @@ -2,7 +2,6 @@ namespace Smartbox\Integration\FrameworkBundle\Tests\Unit\Consumer; - use Smartbox\Integration\FrameworkBundle\Core\Consumers\AbstractConsumer; use Smartbox\Integration\FrameworkBundle\Core\Endpoints\Endpoint; use Smartbox\Integration\FrameworkBundle\Core\Messages\Message; @@ -36,19 +35,17 @@ public function testConsumerTimeDispatched() ->expects($this->exactly(2)) ->method('shouldStop') ->willReturnOnConsecutiveCalls(false, true); - ; $consumer ->expects($this->once()) ->method('readMessage') ->willReturn(new Message()); - ; $eventDispatcher = $this->getMockForAbstractClass(EventDispatcherInterface::class); $eventDispatcher->expects($this->once()) ->method('dispatch') - ->with($this->equalTo('smartesb.consumer.timing'), $this->callback(function($event) use ($lowerBoundMs, $upperBoundMs){ + ->with($this->equalTo('smartesb.consumer.timing'), $this->callback(function ($event) use ($lowerBoundMs, $upperBoundMs) { $this->assertInstanceOf(TimingEvent::class, $event); $interval = $event->getIntervalMs(); @@ -63,7 +60,7 @@ public function testConsumerTimeDispatched() $endpoint->expects($this->once()) ->method('handle') ->will( - $this->returnCallback(function() use ($handleTimeUs) { + $this->returnCallback(function () use ($handleTimeUs) { usleep($handleTimeUs); }) ) From 1782399fe7af6b99a91b70b0909aa6ae13a5900a Mon Sep 17 00:00:00 2001 From: Shane McKinley Date: Wed, 15 Aug 2018 12:32:52 +0100 Subject: [PATCH 29/35] Increase upper bound --- Tests/Unit/Consumer/AbstractConsumerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Unit/Consumer/AbstractConsumerTest.php b/Tests/Unit/Consumer/AbstractConsumerTest.php index 825812b7..6542afc8 100644 --- a/Tests/Unit/Consumer/AbstractConsumerTest.php +++ b/Tests/Unit/Consumer/AbstractConsumerTest.php @@ -14,7 +14,7 @@ public function testConsumerTimeDispatched() { $handleTimeUs = 9.99 * 1000; $lowerBoundMs = 9; - $upperBoundMs = 13; + $upperBoundMs = 20; /** @var $messageInterface $messageInterface */ $consumer = $this->getMockForAbstractClass(AbstractConsumer::class, From 3487fdbd1ec69717fc9fc991b3807aa0714bbde9 Mon Sep 17 00:00:00 2001 From: Shane McKinley Date: Wed, 15 Aug 2018 12:56:19 +0100 Subject: [PATCH 30/35] Increase upper bound even more --- Tests/Unit/Consumer/AbstractConsumerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Unit/Consumer/AbstractConsumerTest.php b/Tests/Unit/Consumer/AbstractConsumerTest.php index 6542afc8..7eea6c44 100644 --- a/Tests/Unit/Consumer/AbstractConsumerTest.php +++ b/Tests/Unit/Consumer/AbstractConsumerTest.php @@ -14,7 +14,7 @@ public function testConsumerTimeDispatched() { $handleTimeUs = 9.99 * 1000; $lowerBoundMs = 9; - $upperBoundMs = 20; + $upperBoundMs = 30; /** @var $messageInterface $messageInterface */ $consumer = $this->getMockForAbstractClass(AbstractConsumer::class, From a5613aab3eafabf1a08692f87090c1fd37b4dce5 Mon Sep 17 00:00:00 2001 From: Shane McKinley Date: Wed, 15 Aug 2018 13:09:08 +0100 Subject: [PATCH 31/35] Remove EventDispatcher trait as already in service --- Core/Consumers/AbstractConsumer.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/Consumers/AbstractConsumer.php b/Core/Consumers/AbstractConsumer.php index a8749cd9..606c4923 100644 --- a/Core/Consumers/AbstractConsumer.php +++ b/Core/Consumers/AbstractConsumer.php @@ -18,7 +18,6 @@ abstract class AbstractConsumer extends Service implements ConsumerInterface use IsStopableConsumer; use UsesLogger; use UsesSmartesbHelper; - use UsesEventDispatcher; /** * Initializes the consumer for a given endpoint. From a5c6bc9763e68b0acf671d57f6261952ad684733 Mon Sep 17 00:00:00 2001 From: Shane McKinley Date: Wed, 15 Aug 2018 15:50:59 +0100 Subject: [PATCH 32/35] Add dispatching of consume time to dbal consumer --- Components/DB/DBConfigurableConsumer.php | 30 ++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/Components/DB/DBConfigurableConsumer.php b/Components/DB/DBConfigurableConsumer.php index 14e5108e..2f37029a 100644 --- a/Components/DB/DBConfigurableConsumer.php +++ b/Components/DB/DBConfigurableConsumer.php @@ -6,6 +6,7 @@ use Smartbox\Integration\FrameworkBundle\Components\DB\Dbal\ConfigurableDbalProtocol; use Smartbox\Integration\FrameworkBundle\Components\DB\NoSQL\NoSQLConfigurableProtocol; use Smartbox\Integration\FrameworkBundle\Configurability\IsConfigurableService; +use Smartbox\Integration\FrameworkBundle\Core\Consumers\AbstractConsumer; use Smartbox\Integration\FrameworkBundle\Core\Consumers\ConfigurableConsumerInterface; use Smartbox\Integration\FrameworkBundle\Core\Consumers\Exceptions\NoResultsException; use Smartbox\Integration\FrameworkBundle\Core\Consumers\IsStopableConsumer; @@ -16,7 +17,7 @@ use Smartbox\Integration\FrameworkBundle\DependencyInjection\Traits\UsesSmartesbHelper; use Smartbox\Integration\FrameworkBundle\Service; -class DBConfigurableConsumer extends Service implements ConfigurableConsumerInterface +class DBConfigurableConsumer extends AbstractConsumer implements ConfigurableConsumerInterface { use IsConfigurableService; use IsStopableConsumer; @@ -26,6 +27,13 @@ class DBConfigurableConsumer extends Service implements ConfigurableConsumerInte /** @var ConfigurableStepsProviderInterface */ protected $configurableStepsProvider; + /** + * {@inheritdoc} + */ + protected function initialize(EndpointInterface $endpoint) + { + } + /** * @return ConfigurableStepsProviderInterface */ @@ -116,6 +124,7 @@ public function consume(EndpointInterface $endpoint) while (!$this->shouldStop()) { // Receive + $startConsumeTime = microtime(true); $message = $this->readMessage($endpoint); // Process @@ -132,7 +141,8 @@ public function consume(EndpointInterface $endpoint) } $this->onConsume($endpoint, $message); - $wakeup = microtime(true); + $endConsumeTime = $wakeup = microtime(true); + $this->dispatchConsumerTimingEvent((int) (($endConsumeTime - $startConsumeTime) * 1000), $message); } if ((microtime(true) - $wakeup) > $inactivityTrigger) { // I did nothing since the last x seconds, so little nap... @@ -140,4 +150,20 @@ public function consume(EndpointInterface $endpoint) } } } + + /** + * {@inheritdoc} + */ + protected function cleanUp(EndpointInterface $endpoint) + { + //TODO: Connect to the steps provider and ask it to shut down its connection + } + + /** + * {@inheritdoc} + */ + protected function confirmMessage(EndpointInterface $endpoint, MessageInterface $message) + { + return $message; + } } From 885d458c61a7caa1d05bd69f66e4ada471e11dc4 Mon Sep 17 00:00:00 2001 From: Shane McKinley Date: Wed, 15 Aug 2018 15:58:55 +0100 Subject: [PATCH 33/35] Try to start align the dbal consumer to have the same pattern as an abstract consumer --- Components/DB/DBConfigurableConsumer.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Components/DB/DBConfigurableConsumer.php b/Components/DB/DBConfigurableConsumer.php index 2f37029a..19e631a6 100644 --- a/Components/DB/DBConfigurableConsumer.php +++ b/Components/DB/DBConfigurableConsumer.php @@ -140,7 +140,7 @@ public function consume(EndpointInterface $endpoint) ); } - $this->onConsume($endpoint, $message); + $this->confirmMessage($endpoint, $message); $endConsumeTime = $wakeup = microtime(true); $this->dispatchConsumerTimingEvent((int) (($endConsumeTime - $startConsumeTime) * 1000), $message); } @@ -149,6 +149,8 @@ public function consume(EndpointInterface $endpoint) usleep($sleepTime); } } + + $this->cleanUp($endpoint); } /** @@ -164,6 +166,7 @@ protected function cleanUp(EndpointInterface $endpoint) */ protected function confirmMessage(EndpointInterface $endpoint, MessageInterface $message) { + $this->onConsume($endpoint, $message); return $message; } } From 3e2b47c7504a7802058c06027fdfe392ddd974b5 Mon Sep 17 00:00:00 2001 From: Shane McKinley Date: Wed, 15 Aug 2018 17:13:19 +0100 Subject: [PATCH 34/35] Fix typo, update dispatch method to not die when there is no event dispatcher --- Components/Queues/Drivers/ArrayQueueDriver.php | 2 +- Components/Queues/Drivers/QueueDriverInterface.php | 4 ++-- Components/Queues/Drivers/StompQueueDriver.php | 10 +++++----- Components/Queues/QueueConsumer.php | 6 +++--- Core/Consumers/AbstractConsumer.php | 5 ++++- Tests/Unit/Consumer/AbstractConsumerTest.php | 13 ++++++++++++- 6 files changed, 27 insertions(+), 13 deletions(-) diff --git a/Components/Queues/Drivers/ArrayQueueDriver.php b/Components/Queues/Drivers/ArrayQueueDriver.php index 489ba2bd..51dda4b9 100644 --- a/Components/Queues/Drivers/ArrayQueueDriver.php +++ b/Components/Queues/Drivers/ArrayQueueDriver.php @@ -21,7 +21,7 @@ class ArrayQueueDriver extends Service implements QueueDriverInterface /** * @return int */ - public function getDeQueueingTimeMs() + public function getDequeueingTimeMs() { return 0; } diff --git a/Components/Queues/Drivers/QueueDriverInterface.php b/Components/Queues/Drivers/QueueDriverInterface.php index a18d8acc..00de3e1b 100644 --- a/Components/Queues/Drivers/QueueDriverInterface.php +++ b/Components/Queues/Drivers/QueueDriverInterface.php @@ -106,7 +106,7 @@ public function createQueueMessage(); public function doDestroy(); /** - * @return int The time it took in ms to deque and deserialize the message + * @return int The time it took in ms to de-queue and deserialize the message */ - public function getDeQueueingTimeMs(); + public function getDequeueingTimeMs(); } diff --git a/Components/Queues/Drivers/StompQueueDriver.php b/Components/Queues/Drivers/StompQueueDriver.php index 98d2bc3b..68abba13 100644 --- a/Components/Queues/Drivers/StompQueueDriver.php +++ b/Components/Queues/Drivers/StompQueueDriver.php @@ -58,7 +58,7 @@ class StompQueueDriver extends Service implements QueueDriverInterface /** * @var int The time it took in ms to deserialize the message */ - protected $deQueueingTimeMs = 0; + protected $dequeueingTimeMs = 0; /** * @return bool @@ -159,9 +159,9 @@ public function setFormat($format) /** * @return int */ - public function getDeQueueingTimeMs() + public function getDequeueingTimeMs() { - return $this->deQueueingTimeMs; + return $this->dequeueingTimeMs; } /** {@inheritdoc} */ @@ -282,7 +282,7 @@ public function receive() ); } - $this->deQueueingTimeMs = 0; + $this->dequeueingTimeMs = 0; $this->currentFrame = $this->statefulStomp->read(); @@ -311,7 +311,7 @@ public function receive() } // Calculate how long it took to deserilize the message - $this->deQueueingTimeMs = (int) ((microtime(true) - $start) * 1000); + $this->dequeueingTimeMs = (int) ((microtime(true) - $start) * 1000); } return $msg; diff --git a/Components/Queues/QueueConsumer.php b/Components/Queues/QueueConsumer.php index 1ed1b51e..c6e67a76 100644 --- a/Components/Queues/QueueConsumer.php +++ b/Components/Queues/QueueConsumer.php @@ -17,7 +17,7 @@ class QueueConsumer extends AbstractConsumer implements ConsumerInterface /** * @var int The time it took in ms to deserialize the message */ - protected $deQueueingTimeMs = 0; + protected $dequeueingTimeMs = 0; /** * {@inheritdoc} @@ -67,7 +67,7 @@ protected function cleanUp(EndpointInterface $endpoint) protected function readMessage(EndpointInterface $endpoint) { $driver = $this->getQueueDriver($endpoint); - $this->deQueueingTimeMs = $driver->getDeQueueingTimeMs(); + $this->dequeueingTimeMs = $driver->getDequeueingTimeMs(); return $driver->receive(); } @@ -104,7 +104,7 @@ protected function confirmMessage(EndpointInterface $endpoint, MessageInterface */ protected function dispatchConsumerTimingEvent($intervalMs, MessageInterface $message) { - $intervalMs = $intervalMs + $this->deQueueingTimeMs; + $intervalMs = $intervalMs + $this->dequeueingTimeMs; parent::dispatchConsumerTimingEvent($intervalMs, $message); } diff --git a/Core/Consumers/AbstractConsumer.php b/Core/Consumers/AbstractConsumer.php index 606c4923..7813a77d 100644 --- a/Core/Consumers/AbstractConsumer.php +++ b/Core/Consumers/AbstractConsumer.php @@ -142,6 +142,9 @@ protected function dispatchConsumerTimingEvent($intervalMs, MessageInterface $me $event = new TimingEvent(TimingEvent::CONSUMER_TIMING); $event->setIntervalMs($intervalMs); $event->setMessage($message); - $this->getEventDispatcher()->dispatch(TimingEvent::CONSUMER_TIMING, $event); + + if (null !== ($dispatcher = $this->getEventDispatcher())) { + $dispatcher->dispatch(TimingEvent::CONSUMER_TIMING, $event); + } } } diff --git a/Tests/Unit/Consumer/AbstractConsumerTest.php b/Tests/Unit/Consumer/AbstractConsumerTest.php index 7eea6c44..b648fc6c 100644 --- a/Tests/Unit/Consumer/AbstractConsumerTest.php +++ b/Tests/Unit/Consumer/AbstractConsumerTest.php @@ -16,7 +16,6 @@ public function testConsumerTimeDispatched() $lowerBoundMs = 9; $upperBoundMs = 30; - /** @var $messageInterface $messageInterface */ $consumer = $this->getMockForAbstractClass(AbstractConsumer::class, ['initialize', 'readMessage'], '', @@ -68,4 +67,16 @@ public function testConsumerTimeDispatched() $consumer->consume($endpoint); } + + + public function testDoesNotFailWhenNoDispatcher() + { + $consumer = $this->getMockForAbstractClass(AbstractConsumer::class); + + $class = new \ReflectionClass($consumer); + $method = $class->getMethod('dispatchConsumerTimingEvent'); + $method->setAccessible(true); + + $method->invokeArgs($consumer, [1, new Message()]); + } } From 793fe49f79ceb60549f33d64c70830de0ba0a626 Mon Sep 17 00:00:00 2001 From: Shane McKinley Date: Thu, 16 Aug 2018 09:23:07 +0100 Subject: [PATCH 35/35] Remove traits already defined in the abstract --- Components/DB/DBConfigurableConsumer.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/Components/DB/DBConfigurableConsumer.php b/Components/DB/DBConfigurableConsumer.php index 19e631a6..b941726d 100644 --- a/Components/DB/DBConfigurableConsumer.php +++ b/Components/DB/DBConfigurableConsumer.php @@ -20,9 +20,6 @@ class DBConfigurableConsumer extends AbstractConsumer implements ConfigurableConsumerInterface { use IsConfigurableService; - use IsStopableConsumer; - use UsesLogger; - use UsesSmartesbHelper; /** @var ConfigurableStepsProviderInterface */ protected $configurableStepsProvider;