diff --git a/.travis.yml b/.travis.yml
index dcdd35ac..7104710a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -16,7 +16,7 @@ matrix:
- php: 7.3
env:
- - SYMFONY_VERSION=2.8.* SYMFONY_PHPUNIT_VERSION=6.5
+ - SYMFONY_VERSION=2.8.* SYMFONY_PHPUNIT_VERSION=6.5 COMPOSER_ROOT_VERSION=v1.26.0
before_install:
- phpenv config-add travis/z_php.ini
diff --git a/Core/Handlers/MessageHandler.php b/Core/Handlers/MessageHandler.php
index 6f5f0b7b..19eaf6ea 100644
--- a/Core/Handlers/MessageHandler.php
+++ b/Core/Handlers/MessageHandler.php
@@ -485,7 +485,7 @@ private function addCommonErrorHeadersToEnvelope(ErrorExchangeEnvelope $envelope
$envelope->setHeader(RetryExchangeEnvelope::HEADER_LAST_RETRY_AT, round(microtime(true) * 1000));
}
- $envelope->setHeader(ErrorExchangeEnvelope::HEADER_CREATED_AT, round(microtime(true) * 1000));
+ $envelope->setHeader(ErrorExchangeEnvelope::HEADER_CREATED_AT, \round(\microtime(true) * 1000));
$envelope->setHeader(ErrorExchangeEnvelope::HEADER_ERROR_MESSAGE, $errorDescription);
$envelope->setHeader(ErrorExchangeEnvelope::HEADER_ERROR_PROCESSOR_ID, $processor->getId());
$envelope->setHeader(ErrorExchangeEnvelope::HEADER_ERROR_PROCESSOR_DESCRIPTION, $processor->getDescription());
diff --git a/Resources/config/default_configured_consumers.yml b/Resources/config/default_configured_consumers.yml
index 192ce6e4..3f3acd39 100644
--- a/Resources/config/default_configured_consumers.yml
+++ b/Resources/config/default_configured_consumers.yml
@@ -9,7 +9,7 @@ smartbox_integration_framework:
description: A Generic Consumer for csv files
calls:
- [ setId, ['smartesb.consumers.generic_csv']]
- - [setConfigurableStepsProvider,[@smartesb.steps_provider.csv_file]]
+ - [setConfigurableStepsProvider,['@smartesb.steps_provider.csv_file']]
options:
stop_on_eof: true
@@ -22,9 +22,9 @@ smartbox_integration_framework:
query_steps:
- read_lines:
result_name: processed_lines
- max_lines: eval: options['batch_size']
+ max_lines: "eval: options['batch_size']"
query_result:
- lines: eval: results['processed_lines']
+ lines: "eval: results['processed_lines']"
on_consume: ~
\ No newline at end of file
diff --git a/Resources/config/default_configured_producers.yml b/Resources/config/default_configured_producers.yml
index a543be1b..abf16f8c 100644
--- a/Resources/config/default_configured_producers.yml
+++ b/Resources/config/default_configured_producers.yml
@@ -8,7 +8,7 @@ smartbox_integration_framework:
class: "%smartesb.producers.csv.class%"
description: Producer to write out csv files
calls:
- - [ setId, ['smartesb.producers.generic_csv']]
+ - [ setId, ["smartesb.producers.generic_csv"]]
- [setConfigurableStepsProvider,["@smartesb.steps_provider.csv_file"]]
options:
@@ -22,5 +22,5 @@ smartbox_integration_framework:
description: Append lines to the csv file
steps:
- append_lines:
- rows: eval: body['lines']
+ rows: "eval: body['lines']"
response: []
diff --git a/Resources/config/default_routing_itineraries.yml b/Resources/config/default_routing_itineraries.yml
index 3f0eb569..8d4cec7d 100644
--- a/Resources/config/default_routing_itineraries.yml
+++ b/Resources/config/default_routing_itineraries.yml
@@ -1,3 +1,3 @@
auto_generated_routes:
- resource: @smartesb.map.itineraries
+ resource: '@smartesb.map.itineraries'
type: itineraries
\ No newline at end of file
diff --git a/SmartboxIntegrationFrameworkBundle.php b/SmartboxIntegrationFrameworkBundle.php
index a9cd679a..8b82abb6 100644
--- a/SmartboxIntegrationFrameworkBundle.php
+++ b/SmartboxIntegrationFrameworkBundle.php
@@ -4,6 +4,7 @@
use Smartbox\Integration\FrameworkBundle\DependencyInjection\CompilerPasses\EventDeferringCompilerPass;
use Smartbox\Integration\FrameworkBundle\DependencyInjection\CompilerPasses\MockWebserviceClientsCompilerPass;
+use Smartbox\Integration\FrameworkBundle\DependencyInjection\CompilerPasses\SmokeTestCleaningPass;
use Smartbox\Integration\FrameworkBundle\DependencyInjection\CompilerPasses\SmokeTestConnectivityCompilerPass;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\ContainerBuilder;
diff --git a/Tests/App/AppKernel.php b/Tests/App/AppKernel.php
index e9fa6fd6..39701bf6 100644
--- a/Tests/App/AppKernel.php
+++ b/Tests/App/AppKernel.php
@@ -15,9 +15,11 @@ public function registerBundles()
new \Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(),
new \JMS\SerializerBundle\JMSSerializerBundle(),
new \BeSimple\SoapBundle\BeSimpleSoapBundle(),
+ new \Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
new \Smartbox\CoreBundle\SmartboxCoreBundle(),
new \Smartbox\Integration\FrameworkBundle\SmartboxIntegrationFrameworkBundle(),
+ new \Smartbox\Integration\CamelConfigBundle\SmartboxIntegrationCamelConfigBundle(),
];
}
diff --git a/Tests/App/Entity/EntityX.php b/Tests/App/Entity/EntityX.php
new file mode 100644
index 00000000..1c34f0fa
--- /dev/null
+++ b/Tests/App/Entity/EntityX.php
@@ -0,0 +1,42 @@
+x = $x;
+ }
+
+ /**
+ * @JMS\Type("integer")
+ * @JMS\Expose
+ * @JMS\Groups({"logs"})
+ *
+ * @var int
+ */
+ protected $x = 0;
+
+ /**
+ * @return int
+ */
+ public function getX()
+ {
+ return $this->x;
+ }
+
+ /**
+ * @param int $x
+ */
+ public function setX($x)
+ {
+ $this->x = $x;
+ }
+}
diff --git a/Tests/App/Producers/ErrorTriggerProducer.php b/Tests/App/Producers/ErrorTriggerProducer.php
new file mode 100644
index 00000000..41a7bd8d
--- /dev/null
+++ b/Tests/App/Producers/ErrorTriggerProducer.php
@@ -0,0 +1,88 @@
+getOptions();
+
+ if (self::$count < @$options[self::OPTION_NUMBER_ERRORS] || @$options[self::OPTION_FORCE]) {
+ $ex->getIn()->setBody(new EntityX(666));
+ ++self::$count;
+
+ if (@$options[self::OPTION_RECOVERABLE]) {
+ throw new SampleRecoverableException('test recoverable exception');
+ }
+
+ throw new \RuntimeException('test exception');
+ }
+ }
+
+ /**
+ * Key-Value array with the option name as key and the details as value.
+ *
+ * [OptionName => [description, array of valid values],..]
+ *
+ * @return array
+ */
+ public function getOptionsDescriptions()
+ {
+ $options = [
+ self::OPTION_RECOVERABLE => ['Whether the errors triggered are recoverable or not', []],
+ self::OPTION_FORCE => ['Force to throw the exception every time, not only "n" number of times', []],
+ self::OPTION_NUMBER_ERRORS => ['Define the number of times the exception will be throw', []]
+ ];
+
+ return $options;
+ }
+
+ /**
+ * 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)
+ {
+ $resolver->setRequired(self::OPTION_RECOVERABLE);
+ $resolver->setDefault(Protocol::OPTION_EXCHANGE_PATTERN, Protocol::EXCHANGE_PATTERN_IN_ONLY);
+ $resolver->setDefault(self::OPTION_RECOVERABLE, false);
+ $resolver->setDefault(self::OPTION_FORCE, false);
+ $resolver->setAllowedValues(Protocol::OPTION_EXCHANGE_PATTERN, [Protocol::EXCHANGE_PATTERN_IN_ONLY]);
+ $resolver->setDefault(self::OPTION_NUMBER_ERRORS, 1);
+ }
+}
diff --git a/Tests/App/Producers/HelperProducer.php b/Tests/App/Producers/HelperProducer.php
new file mode 100644
index 00000000..e560cc19
--- /dev/null
+++ b/Tests/App/Producers/HelperProducer.php
@@ -0,0 +1,93 @@
+getOptions();
+
+ /** @var EntityX $x */
+ $x = $ex->getIn()->getBody();
+ if (empty($x) || !($x instanceof EntityX)) {
+ throw new \InvalidArgumentException('Expected entity of type EntityX');
+ }
+
+ $operand = (int) @$options[self::OPTION_OPERAND];
+
+ switch (@$options[self::OPTION_OPERATION]) {
+ case self::OPERATION_MULTIPLY:
+ $message = $this->messageFactory->createMessage(new EntityX($x->getX() * $operand));
+ $ex->setOut($message);
+ break;
+ case self::OPERATION_ADD:
+ $message = $this->messageFactory->createMessage(new EntityX($x->getX() + $operand));
+ $ex->setOut($message);
+ break;
+ }
+ }
+
+ /**
+ * Key-Value array with the option name as key and the details as value.
+ *
+ * [OptionName => [description, array of valid values],..]
+ *
+ * @return array
+ */
+ public function getOptionsDescriptions()
+ {
+ $options = [
+ self::OPTION_OPERATION => ['Operation to apply to the EntityX in the body of the incoming messages', [
+ self::OPERATION_ADD => 'Adds operand to the entityX value',
+ self::OPERATION_MULTIPLY => 'Multiplies operand by the entityX value',
+ ]],
+ self::OPTION_OPERAND => ['Operand to use (number)', []],
+ ];
+
+ return $options;
+ }
+
+ /**
+ * 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)
+ {
+ $resolver->setRequired(self::OPTION_OPERATION);
+ $resolver->setAllowedValues(self::OPTION_OPERATION, [self::OPERATION_ADD, self::OPERATION_MULTIPLY]);
+
+ $resolver->setRequired(self::OPTION_OPERAND);
+ $resolver->setAllowedTypes(self::OPTION_OPERAND, ['numeric']);
+
+ $resolver->setDefault(Protocol::OPTION_EXCHANGE_PATTERN, Protocol::EXCHANGE_PATTERN_IN_OUT);
+ }
+}
diff --git a/Tests/App/Producers/SpyProducer.php b/Tests/App/Producers/SpyProducer.php
new file mode 100644
index 00000000..d4f65818
--- /dev/null
+++ b/Tests/App/Producers/SpyProducer.php
@@ -0,0 +1,94 @@
+getOptions();
+ /** @var EntityX $x */
+ $x = $ex->getIn()->getBody();
+
+ $path = $options[self::OPTION_PATH];
+
+ if (!array_key_exists($path, $this->array)) {
+ $this->array[$path] = [];
+ }
+
+ if ($x instanceof SerializableArray) {
+ $this->array[$path] = $x->toArray();
+ } else {
+ $this->array[$path][] = $x->getX();
+ }
+
+ }
+
+ /**
+ * @return array
+ */
+ public function getData($path)
+ {
+ if (array_key_exists($path, $this->array)) {
+ return $this->array[$path];
+ } else {
+ return [];
+ }
+ }
+
+ /**
+ * Key-Value array with the option name as key and the details as value.
+ *
+ * [OptionName => [description, array of valid values],..]
+ *
+ * @return array
+ */
+ public function getOptionsDescriptions()
+ {
+ $options = [
+ self::OPTION_PATH => ['Path to store the messages crossing this spy', []],
+ ];
+
+ return $options;
+ }
+
+ /**
+ * 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)
+ {
+ $resolver->setDefault(Protocol::OPTION_EXCHANGE_PATTERN, Protocol::EXCHANGE_PATTERN_IN_ONLY);
+ $resolver->setAllowedValues(Protocol::OPTION_EXCHANGE_PATTERN, [Protocol::EXCHANGE_PATTERN_IN_ONLY]);
+
+ $resolver->setRequired(self::OPTION_PATH);
+ $resolver->setAllowedTypes(self::OPTION_PATH, ['string']);
+ }
+}
diff --git a/Tests/App/Resources/Fixtures/Csv/happy-comma.csv b/Tests/App/Resources/Fixtures/Csv/happy-comma.csv
new file mode 100755
index 00000000..ce7db7b6
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/Csv/happy-comma.csv
@@ -0,0 +1,8 @@
+a1,b1,c1
+a2,b2,c2
+a3,b3,c3
+a4,b4,c4
+a5,b5,c5
+a6,b6,c6
+a7,b7,c7
+hello
diff --git a/Tests/App/Resources/Fixtures/Csv/happy.csv b/Tests/App/Resources/Fixtures/Csv/happy.csv
new file mode 100755
index 00000000..a88f868f
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/Csv/happy.csv
@@ -0,0 +1,8 @@
+a1|b1|c1
+a2|b2|c2
+a3|b3|c3
+a4|b4|c4
+a5|b5|c5
+a6|b6|c6
+a7|b7|c7
+hello
diff --git a/Tests/App/Resources/Fixtures/FlowsBuilderCompilerPassFailures/InvalidURI/CamelTestFlowInvalidURIError.xml b/Tests/App/Resources/Fixtures/FlowsBuilderCompilerPassFailures/InvalidURI/CamelTestFlowInvalidURIError.xml
new file mode 100644
index 00000000..589acc81
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/FlowsBuilderCompilerPassFailures/InvalidURI/CamelTestFlowInvalidURIError.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Tests/App/Resources/Fixtures/FlowsBuilderCompilerPassFailures/XMLBadFormed/CamelTestFlowXMLError.xml b/Tests/App/Resources/Fixtures/FlowsBuilderCompilerPassFailures/XMLBadFormed/CamelTestFlowXMLError.xml
new file mode 100644
index 00000000..e2640379
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/FlowsBuilderCompilerPassFailures/XMLBadFormed/CamelTestFlowXMLError.xml
@@ -0,0 +1,6 @@
+
+
+
+ to uri="custom://business_demo/getBoxInTransit"/>
+
+
\ No newline at end of file
diff --git a/Tests/App/Resources/Fixtures/FlowsBuilderCompilerPassFailures/findAbstractEndpointException/CamelTestFlowError.xml b/Tests/App/Resources/Fixtures/FlowsBuilderCompilerPassFailures/findAbstractEndpointException/CamelTestFlowError.xml
new file mode 100644
index 00000000..f61174e6
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/FlowsBuilderCompilerPassFailures/findAbstractEndpointException/CamelTestFlowError.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Tests/App/Resources/Fixtures/FlowsBuilderCompilerPassSuccess/CamelTestFlowSuccess.xml b/Tests/App/Resources/Fixtures/FlowsBuilderCompilerPassSuccess/CamelTestFlowSuccess.xml
new file mode 100644
index 00000000..f61174e6
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/FlowsBuilderCompilerPassSuccess/CamelTestFlowSuccess.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Tests/App/Resources/Fixtures/FlowsBuilderCompilerPassSuccess/Frozen/.gitkeep b/Tests/App/Resources/Fixtures/FlowsBuilderCompilerPassSuccess/Frozen/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/Tests/App/Resources/Fixtures/FrozenFlows/.gitkeep b/Tests/App/Resources/Fixtures/FrozenFlows/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/Tests/App/Resources/Fixtures/TestFlows/.project b/Tests/App/Resources/Fixtures/TestFlows/.project
new file mode 100644
index 00000000..ae845e9f
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/.project
@@ -0,0 +1,11 @@
+
+
+ TestFlows
+
+
+
+
+
+
+
+
diff --git a/Tests/App/Resources/Fixtures/TestFlows/AsyncErrorRecovery/recoverable.xml b/Tests/App/Resources/Fixtures/TestFlows/AsyncErrorRecovery/recoverable.xml
new file mode 100644
index 00000000..deb819cf
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/AsyncErrorRecovery/recoverable.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tests/App/Resources/Fixtures/TestFlows/AsyncErrorRecovery/test.yml~ b/Tests/App/Resources/Fixtures/TestFlows/AsyncErrorRecovery/test.yml~
new file mode 100644
index 00000000..122cab00
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/AsyncErrorRecovery/test.yml~
@@ -0,0 +1,17 @@
+steps:
+ - {type: configureHandler, name: async, retryDelay: 0 }
+
+ - {type: handle, from: test://queues/recoveryAsyncRecoverable, in: 1, out: 1}
+ - {type: consume, uri: queue://main/recoveryAsyncRecoverable, amount: 1 }
+
+ # Check that the message was partially processed
+ - { type: checkSpy, path: before_error/recoverable, values: [6]}
+
+ # Check that the message didn't succeed
+ - { type: checkSpy, path: after_error/recoverable, values: []}
+
+ # Check that we can recover and that previous steps are not repeated
+ - {type: consume, uri: queue://main/recoveryAsyncRecoverable, amount: 1 }
+
+ - { type: checkSpy, path: before_error/recoverable, values: [6]}
+ - { type: checkSpy, path: after_error/recoverable, values: [11]}
\ No newline at end of file
diff --git a/Tests/App/Resources/Fixtures/TestFlows/AsyncErrorRecoveryWithDelay/recoverableWithDelay.xml b/Tests/App/Resources/Fixtures/TestFlows/AsyncErrorRecoveryWithDelay/recoverableWithDelay.xml
new file mode 100644
index 00000000..468e2d6a
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/AsyncErrorRecoveryWithDelay/recoverableWithDelay.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tests/App/Resources/Fixtures/TestFlows/AsyncErrorRecoveryWithDelay/test.yml b/Tests/App/Resources/Fixtures/TestFlows/AsyncErrorRecoveryWithDelay/test.yml
new file mode 100644
index 00000000..3c73509f
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/AsyncErrorRecoveryWithDelay/test.yml
@@ -0,0 +1,34 @@
+steps:
+ - {type: handle, from: test://queues/delayRecoveryAsyncRecoverableWithDelay, in: 1, out: 1 }
+
+ # Configure the handler with a 5 second delay
+ - {type: configureHandler, name: async, retryDelay: 5 }
+
+ # Consume a first time
+ - {type: consume, uri: queue://main/delayRecoveryAsyncRecoverableWithDelay, amount: 1 }
+
+ # Check that the message was partially processed
+ - { type: checkSpy, path: before_error/recoverableDelay, values: [6]}
+
+ # Try to consume the message again
+ - {type: consume, uri: queue://main/delayRecoveryAsyncRecoverableWithDelay, amount: 1 }
+
+ # Check that the message has still the same value
+ - { type: checkSpy, path: before_error/recoverableDelay, values: [6] }
+
+ # Check that the message still didn't succeed
+ - { type: checkSpy, path: after_error/recoverableDelay, values: [] }
+
+ # Wait until the end of the delay
+ - {type: wait, delay: 5 }
+
+ # Check that we can recover and that previous steps are not repeated
+ - {type: consume, uri: queue://main/delayRecoveryAsyncRecoverableWithDelay, amount: 1 }
+
+ - { type: checkSpy, path: before_error/recoverableDelay, values: [6] }
+
+ # Check the final value
+ - { type: checkSpy, path: after_error/recoverableDelay, values: [11] }
+
+ # Reset the handler
+ - {type: configureHandler, name: async, retryDelay: 0 }
diff --git a/Tests/App/Resources/Fixtures/TestFlows/AsyncErrorRecoveryWithDelayProgressive/recoverableWithDelayProgressive.xml b/Tests/App/Resources/Fixtures/TestFlows/AsyncErrorRecoveryWithDelayProgressive/recoverableWithDelayProgressive.xml
new file mode 100644
index 00000000..16feb8ed
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/AsyncErrorRecoveryWithDelayProgressive/recoverableWithDelayProgressive.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tests/App/Resources/Fixtures/TestFlows/AsyncErrorRecoveryWithDelayProgressive/test.yml b/Tests/App/Resources/Fixtures/TestFlows/AsyncErrorRecoveryWithDelayProgressive/test.yml
new file mode 100644
index 00000000..8970d6da
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/AsyncErrorRecoveryWithDelayProgressive/test.yml
@@ -0,0 +1,51 @@
+steps:
+ - {type: handle, from: test://queues/delayRecoveryAsyncRecoverableWithDelayProgressive, in: 1, out: 1}
+
+ # Configure the handler with a 5 second delay
+ - {type: configureHandler, name: async, retryDelay: 5, retryStrategy: progressive, retryDelayFactor: 2}
+
+ # Consume a first time
+ - {type: consume, uri: queue://main/delayRecoveryAsyncRecoverableWithDelayProgressive, amount: 1}
+
+ # Check that the message was partially processed
+ - {type: checkSpy, path: before_error/recoverableDelayProgressive, values: [6]}
+
+ # Check that we can recover and that previous steps are not repeated
+ - {type: consume, uri: queue://main/delayRecoveryAsyncRecoverableWithDelayProgressive, amount: 1}
+
+ - {type: checkSpy, path: before_error/recoverableDelayProgressive, values: [6]}
+
+ # Check that the message still didn't succeed
+ - {type: checkSpy, path: after_error/recoverableDelayProgressive, values: []}
+
+ # Wait until the end of the delay
+ - {type: wait, delay: 5}
+
+ # Check that we can recover and that previous steps are not repeated
+ - {type: consume, uri: queue://main/delayRecoveryAsyncRecoverableWithDelayProgressive, amount: 1}
+
+ - {type: checkSpy, path: before_error/recoverableDelayProgressive, values: [6]}
+
+ - {type: checkSpy, path: after_error/recoverableDelayProgressive, values: []}
+
+ - {type: wait, delay: 5}
+
+ # Check that we can the delay is still not finished
+ - {type: consume, uri: queue://main/delayRecoveryAsyncRecoverableWithDelayProgressive, amount: 1}
+
+ - {type: checkSpy, path: before_error/recoverableDelayProgressive, values: [6]}
+
+ - {type: checkSpy, path: after_error/recoverableDelayProgressive, values: []}
+
+ - {type: wait, delay: 5}
+
+ # Check that we can recover and that previous steps are not repeated
+ - {type: consume, uri: queue://main/delayRecoveryAsyncRecoverableWithDelayProgressive, amount: 1}
+
+ - {type: checkSpy, path: before_error/recoverableDelayProgressive, values: [6]}
+
+ # Check the final value
+ - {type: checkSpy, path: after_error/recoverableDelayProgressive, values: [11]}
+
+ # Reset the handler
+ - {type: configureHandler, name: async, retryDelay: 0}
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Csv/csv.xml b/Tests/App/Resources/Fixtures/TestFlows/Csv/csv.xml
new file mode 100644
index 00000000..3274ab43
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Csv/csv.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Csv/csv2.xml b/Tests/App/Resources/Fixtures/TestFlows/Csv/csv2.xml
new file mode 100644
index 00000000..91eb06d7
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Csv/csv2.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Csv/csvGeneric.xml b/Tests/App/Resources/Fixtures/TestFlows/Csv/csvGeneric.xml
new file mode 100644
index 00000000..ebbf0bb4
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Csv/csvGeneric.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Csv/test.yml b/Tests/App/Resources/Fixtures/TestFlows/Csv/test.yml
new file mode 100644
index 00000000..b8fb44b0
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Csv/test.yml
@@ -0,0 +1,45 @@
+steps:
+ - {type: configureHandler, name: async, retryDelay: 0 }
+
+ # We need to copy the recource we will use for the generic test
+ - {type: copyTmpResource, from: Csv/happy-comma.csv }
+
+ # Consume one set of rows from the csv, the amount here is 1, but the consumer is set to read 3 lines
+ - {type: consume, uri: csv://test/consumer/read_happy, amount: 1 }
+
+ # Test that we returned 3 lines as expected from the csv
+ -
+ type: checkSpyArray
+ path: csv/read_file1
+ values:
+ lines:
+ - ['a1', 'b1', 'c1' ]
+ - ['a2', 'b2', 'c2' ]
+ - ['a3', 'b3', 'c3' ]
+
+ # Consume one set of rows from the csv, the amount here is 1, but the consumer is set to read 2 lines
+ - {type: consume, uri: csv://test/consumer_2/read_happy, amount: 1 }
+
+ # Test that we returned 2 lines as expected from the csv
+ -
+ type: checkSpyArray
+ path: csv/read_file2
+ values:
+ lines:
+ - ['a1', 'b1', 'c1' ]
+ - ['a2', 'b2', 'c2' ]
+
+ # And the csvGeneric
+ # Consume one set of rows from the csv, the amount here is 1, but the consumer is set to read 2 lines
+ - {type: consume, uri: csv://generic//tmp/integration-framework-test/happy-comma.csv, amount: 1 }
+
+ # Test that we returned 1 lines as expected from the csv
+ -
+ type: checkSpyArray
+ path: csv/read_file3
+ values:
+ lines:
+ - ['a1', 'b1', 'c1' ]
+
+ # Clean up all the tmp files after our selves
+ - {type: cleanTmpResources }
\ No newline at end of file
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Logging/exception.xml b/Tests/App/Resources/Fixtures/TestFlows/Logging/exception.xml
new file mode 100644
index 00000000..ceacb8f2
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Logging/exception.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Logging/test.yml b/Tests/App/Resources/Fixtures/TestFlows/Logging/test.yml
new file mode 100644
index 00000000..5e177a60
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Logging/test.yml
@@ -0,0 +1,8 @@
+steps:
+ - {type: expectedException, class: 'Smartbox\Integration\FrameworkBundle\Tests\Fixtures\Exceptions\TestException'}
+ - {type: handle, from: test://logging/exception, in: 1}
+ - {type: checkLogs, message: "Event \"smartesb.handler.before_handle\" occurred", level: "Debug"}
+ - {type: checkLogs, message: "Event \"smartesb.handler.before_process\" occurred", level: "Debug"}
+ - {type: checkLogs, message: "Event \"smartesb.handler.after_process\" occurred", level: "Debug"}
+ - {type: checkLogs, message: "Event \"smartesb.handler.after_handle\" occurred", level: "Debug"}
+ - {type: checkLogs, message: "This is a test exception", level: "Error"}
diff --git a/Tests/App/Resources/Fixtures/TestFlows/LoggingWithCustomErrorMessage/exception.xml b/Tests/App/Resources/Fixtures/TestFlows/LoggingWithCustomErrorMessage/exception.xml
new file mode 100644
index 00000000..62989344
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/LoggingWithCustomErrorMessage/exception.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tests/App/Resources/Fixtures/TestFlows/LoggingWithCustomErrorMessage/test.yml b/Tests/App/Resources/Fixtures/TestFlows/LoggingWithCustomErrorMessage/test.yml
new file mode 100644
index 00000000..72ca3a83
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/LoggingWithCustomErrorMessage/test.yml
@@ -0,0 +1,8 @@
+steps:
+ - {type: expectedException, class: 'Smartbox\Integration\FrameworkBundle\Tests\Fixtures\Exceptions\TestException'}
+ - {type: handle, from: test://logging/exceptionWithMessage, in: 1}
+ - {type: checkLogs, message: 'Event "smartesb.handler.before_handle" occurred', level: 'Debug'}
+ - {type: checkLogs, message: 'Event "smartesb.handler.before_process" occurred', level: 'Debug'}
+ - {type: checkLogs, message: 'Event "smartesb.handler.after_process" occurred', level: 'Debug'}
+ - {type: checkLogs, message: 'Event "smartesb.handler.after_handle" occurred', level: 'Debug'}
+ - {type: checkLogs, message: 'This is a custom message', level: 'Error'}
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Multicast/multicast.xml b/Tests/App/Resources/Fixtures/TestFlows/Multicast/multicast.xml
new file mode 100644
index 00000000..85c05ae2
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Multicast/multicast.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Multicast/test.yml b/Tests/App/Resources/Fixtures/TestFlows/Multicast/test.yml
new file mode 100644
index 00000000..3f39396c
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Multicast/test.yml
@@ -0,0 +1,4 @@
+steps:
+ - { type: handle, from: "test://multicast", in: 1, out: 1} # We perform no aggregation, so the main exchange doesn't change
+ - { type: checkSpy, path: "multicast/a", values: [5]}
+ - { type: checkSpy, path: "multicast/b", values: [2]}
\ No newline at end of file
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Pipeline/pipeline.xml b/Tests/App/Resources/Fixtures/TestFlows/Pipeline/pipeline.xml
new file mode 100644
index 00000000..bfeaad77
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Pipeline/pipeline.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Pipeline/test.yml b/Tests/App/Resources/Fixtures/TestFlows/Pipeline/test.yml
new file mode 100644
index 00000000..3a92676c
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Pipeline/test.yml
@@ -0,0 +1,3 @@
+steps:
+ - { type: handle, from: "test://pipeline", in: 1, out: 5}
+ - { type: checkSpy, path: "pipeline/a", values: [5]}
\ No newline at end of file
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Queue/enqueue.xml b/Tests/App/Resources/Fixtures/TestFlows/Queue/enqueue.xml
new file mode 100644
index 00000000..9d1c2145
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Queue/enqueue.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Queue/queueMulticast.xml b/Tests/App/Resources/Fixtures/TestFlows/Queue/queueMulticast.xml
new file mode 100644
index 00000000..85f6823c
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Queue/queueMulticast.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Queue/queueSimple.xml b/Tests/App/Resources/Fixtures/TestFlows/Queue/queueSimple.xml
new file mode 100644
index 00000000..e1f96fd3
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Queue/queueSimple.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Queue/test.yml b/Tests/App/Resources/Fixtures/TestFlows/Queue/test.yml
new file mode 100644
index 00000000..7328c7ea
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Queue/test.yml
@@ -0,0 +1,10 @@
+steps:
+ - { type: handle, from: "test://queues/simple", in: 1, out: in }
+ - { type: consume, uri: "queue://main/simple", amount: 1}
+ - { type: checkSpy, path: "queue/simple/result", values: [1+10] }
+
+ - { type: handle, from: "test://queues/multicast", in: 2, out: in } # Enqueue the message
+ - { type: consume, uri: "queue://main/multicast", amount: 3} # ...we need to consume also the 2 child exchanges
+ - { type: checkSpy, path: "queue/multicast/result", values: [2] }
+ - { type: checkSpy, path: "multicast/a", values: [2*5] }
+ - { type: checkSpy, path: "multicast/b", values: [2*2] }
\ No newline at end of file
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Router/router.xml b/Tests/App/Resources/Fixtures/TestFlows/Router/router.xml
new file mode 100644
index 00000000..24248d59
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Router/router.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+ (msg.getBody().getX() % 2) == 0
+
+
+
+
+
+
+
+
+
+
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Router/test.yml b/Tests/App/Resources/Fixtures/TestFlows/Router/test.yml
new file mode 100644
index 00000000..f26c389f
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Router/test.yml
@@ -0,0 +1,3 @@
+steps:
+ - { type: handle, from: "test://router", in: 1, out: 2}
+ - { type: handle, from: "test://router", in: 2, out: 10}
\ No newline at end of file
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Simple/simple.xml b/Tests/App/Resources/Fixtures/TestFlows/Simple/simple.xml
new file mode 100644
index 00000000..74cc581c
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Simple/simple.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Simple/test.yml b/Tests/App/Resources/Fixtures/TestFlows/Simple/test.yml
new file mode 100644
index 00000000..a5c46241
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Simple/test.yml
@@ -0,0 +1,5 @@
+steps:
+ - { type: handle, from: "test://simple1", in: 1, out: 5}
+ - { type: handle, from: "test://simple2", in: 1, out: 2}
+ - { type: handle, from: "test://simple3", in: 1, out: 6}
+ - { type: handle, from: "test://simple4", in: 1, out: 12}
\ No newline at end of file
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Subroutines/multicastSubroutine.xml b/Tests/App/Resources/Fixtures/TestFlows/Subroutines/multicastSubroutine.xml
new file mode 100644
index 00000000..267411bc
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Subroutines/multicastSubroutine.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Subroutines/routerSubroutine.xml b/Tests/App/Resources/Fixtures/TestFlows/Subroutines/routerSubroutine.xml
new file mode 100644
index 00000000..6fdf6467
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Subroutines/routerSubroutine.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Subroutines/simpleSubroutine.xml b/Tests/App/Resources/Fixtures/TestFlows/Subroutines/simpleSubroutine.xml
new file mode 100644
index 00000000..6ee8f084
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Subroutines/simpleSubroutine.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Subroutines/test.yml b/Tests/App/Resources/Fixtures/TestFlows/Subroutines/test.yml
new file mode 100644
index 00000000..ab3ba39b
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Subroutines/test.yml
@@ -0,0 +1,10 @@
+steps:
+ - { type: handle, from: "test://subroutines/simple", in: 1, out: 1 + 10}
+
+ - { type: handle, from: "test://subroutines/router", in: 1, out: (1*2)+10 }
+ - { type: handle, from: "test://subroutines/router", in: 2, out: (2*5)+10 }
+
+
+ - { type: handle, from: "test://subroutines/multicast", in: 1, out: 1+10 }
+ - { type: checkSpy, path: "multicast/a", values: [1*5] }
+ - { type: checkSpy, path: "multicast/b", values: [1*2] }
\ No newline at end of file
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Throttler/test.yml b/Tests/App/Resources/Fixtures/TestFlows/Throttler/test.yml
new file mode 100644
index 00000000..e6a4b63e
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Throttler/test.yml
@@ -0,0 +1,27 @@
+steps:
+
+# Send 2 messages, consume 2 messages, first one should pass, second one not
+ - { type: handle, from: "test://queues/throttler", in: 1, out: in } # Enqueue the message
+ - { type: handle, from: "test://queues/throttler", in: 1, out: in } # Enqueue the message
+
+ - { type: consume, uri: "queue://main/throttler", amount: 2} # Consume the two messages
+ - { type: checkSpy, path: "throttler/before", values: [1,1] }
+ - { type: checkSpy, path: "throttler/after", values: [5] } # spy contains only one result (second message is moved to the failed transactions)
+
+ - { type: wait, delay: 3 } # Wait until the end of the reset, then consume again and check that the message passes
+
+ - { type: handle, from: "test://queues/throttler", in: 2, out: in } # The queue will be empty so we enqueue a new message
+ - { type: consume, uri: "queue://main/throttler", amount: 1} # we consume the new message
+
+ - { type: checkSpy, path: "throttler/before", values: [1,1,2] } # We check the inputs of the three consumed messages
+ - { type: checkSpy, path: "throttler/after", values: [5,10] } # only the first and the last produced an output (the second was moved to the failed transactions)
+
+
+## Sync
+
+# First message should pass
+ - { type: handle, from: "test://throttler", in: 1, out: 5}
+
+# Second message should fail
+ - { type: expectedException, class: 'Smartbox\Integration\FrameworkBundle\Core\Processors\Exceptions\ThrottlingLimitReachedException'}
+ - { type: handle, from: "test://throttler", in: 1, out: 1}
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Throttler/test_async_delayed.yml b/Tests/App/Resources/Fixtures/TestFlows/Throttler/test_async_delayed.yml
new file mode 100644
index 00000000..1a6c6a0e
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Throttler/test_async_delayed.yml
@@ -0,0 +1,23 @@
+steps:
+#Async
+
+# Send 2 messages, consume 2 messages, first one should pass, second one not
+ - { type: handle, from: "test://queues/throttlerAsync", in: 1, out: in } # Enqueue the message
+ - { type: handle, from: "test://queues/throttlerAsync", in: 1, out: in } # Enqueue the message
+
+ - { type: consume, uri: "queue://main/throttlerAsync", amount: 2} # Consume the two messages
+ - { type: checkSpy, path: "throttlerAsync/before", values: [1,1] }
+ - { type: checkSpy, path: "throttlerAsync/after", values: [5] } # spy contains only one result (second message is throttled)
+
+ - { type: wait, delay: 4 } # Wait until the end of the reset, then consume again and check that the message passes
+
+ - { type: consume, uri: "queue://main/throttle", amount: 1} # When a message gets throttled it will be put in the uri defined in smartesb.handlers.async
+ - { type: checkSpy, path: "throttlerAsync/before", values: [1,1] }
+ - { type: checkSpy, path: "throttlerAsync/after", values: [5,5] } # spy now contains both results
+
+# First message should pass
+ - { type: handle, from: "test://throttlerAsync", in: 1, out: 5}
+
+# Second message should throw an exception
+ - { type: expectedException, class: 'Smartbox\Integration\FrameworkBundle\Core\Processors\Exceptions\ThrottledException'}
+ - { type: handle, from: "test://throttlerAsync", in: 1, out: 1}
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Throttler/throttler.xml b/Tests/App/Resources/Fixtures/TestFlows/Throttler/throttler.xml
new file mode 100644
index 00000000..0e072b7c
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Throttler/throttler.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+ 1+0
+
+
+
+
+
+
+
+ 1+0
+
+
+
+
+
+
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Throttler/throttler_async_delayed.xml b/Tests/App/Resources/Fixtures/TestFlows/Throttler/throttler_async_delayed.xml
new file mode 100644
index 00000000..31524905
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Throttler/throttler_async_delayed.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+ 1+0
+
+
+
+
+
+
+
+ 1+0
+
+
+
+
+
+
+
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Transformer/test.yml b/Tests/App/Resources/Fixtures/TestFlows/Transformer/test.yml
new file mode 100644
index 00000000..5d5faf00
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Transformer/test.yml
@@ -0,0 +1,2 @@
+steps:
+ - { type: handle, from: "test://transformer", in: 1, out: 11}
\ No newline at end of file
diff --git a/Tests/App/Resources/Fixtures/TestFlows/Transformer/transformer.xml b/Tests/App/Resources/Fixtures/TestFlows/Transformer/transformer.xml
new file mode 100644
index 00000000..acbc01ad
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/Transformer/transformer.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+ msg.getBody().setX(msg.getBody().getX()+10)
+
+
+
+
+
diff --git a/Tests/App/Resources/Fixtures/TestFlows/TryCatch/test_catched.yml b/Tests/App/Resources/Fixtures/TestFlows/TryCatch/test_catched.yml
new file mode 100644
index 00000000..07669824
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/TryCatch/test_catched.yml
@@ -0,0 +1,3 @@
+steps:
+ - { type: handle, from: "test://try1", in: 1, out: 22 }
+ - { type: handle, from: "test://try2", in: 1, out: 42 }
diff --git a/Tests/App/Resources/Fixtures/TestFlows/TryCatch/test_not_catched.yml b/Tests/App/Resources/Fixtures/TestFlows/TryCatch/test_not_catched.yml
new file mode 100644
index 00000000..693b27c0
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/TryCatch/test_not_catched.yml
@@ -0,0 +1,4 @@
+steps:
+ - { type: expectedException, class: 'Smartbox\Integration\FrameworkBundle\Tests\Fixtures\Exceptions\SampleRecoverableException'}
+ - { type: handle, from: "test://try3", in: 1, out: 21 }
+
diff --git a/Tests/App/Resources/Fixtures/TestFlows/TryCatch/test_with_recovery.yml b/Tests/App/Resources/Fixtures/TestFlows/TryCatch/test_with_recovery.yml
new file mode 100644
index 00000000..177d164f
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/TryCatch/test_with_recovery.yml
@@ -0,0 +1,17 @@
+steps:
+ - {type: configureHandler, name: async, retryDelay: 0 }
+
+ - {type: handle, from: test://queues/tryAsync, in: 1, out: 1}
+ - {type: consume, uri: queue://main/tryAsync, amount: 1 }
+
+ # Check that the message was partially processed
+ - { type: checkSpy, path: try/async/before_first_error, values: [6]}
+ - { type: checkSpy, path: try/async/after_first_error, values: []}
+ - { type: checkSpy, path: try/async/after_all, values: []}
+
+ # Check that we can recover, that previous steps are not repeated and that the try/catch still works
+ - {type: consume, uri: queue://main/tryAsync, amount: 1 }
+
+ - { type: checkSpy, path: try/async/before_first_error, values: [6]}
+ - { type: checkSpy, path: try/async/after_first_error, values: [11]}
+ - { type: checkSpy, path: try/async/after_all, values: [61]}
diff --git a/Tests/App/Resources/Fixtures/TestFlows/TryCatch/tryCatch.xml b/Tests/App/Resources/Fixtures/TestFlows/TryCatch/tryCatch.xml
new file mode 100644
index 00000000..75bad74b
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/TestFlows/TryCatch/tryCatch.xml
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+
+ try/catch description
+
+
+
+
+ 1 == 2
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1 == 2
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1 == 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ not isRecoverable(exception)
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tests/App/Resources/Fixtures/default/ok.json b/Tests/App/Resources/Fixtures/default/ok.json
new file mode 100644
index 00000000..77588190
--- /dev/null
+++ b/Tests/App/Resources/Fixtures/default/ok.json
@@ -0,0 +1 @@
+{"_type":"Smartbox\\ApiBundle\\Entity\\OK","_apiVersion":"v1"}
\ No newline at end of file
diff --git a/Tests/App/config/config.yml b/Tests/App/config/config.yml
index 94839ed4..88b3609b 100644
--- a/Tests/App/config/config.yml
+++ b/Tests/App/config/config.yml
@@ -1,6 +1,8 @@
imports:
- { resource: parameters.yml }
- { resource: services.yml }
+ - { resource: "@SmartboxIntegrationFrameworkBundle/Resources/config/default_configured_consumers.yml" }
+ - { resource: "@SmartboxIntegrationFrameworkBundle/Resources/config/default_configured_producers.yml" }
framework:
secret: "5yg6u543wrftg34"
@@ -24,12 +26,17 @@ monolog:
smartbox_core:
cache_drivers:
- null:
- service: ~
- fixtures_path: "%kernel.root_dir%/JsonFixtures"
+ array:
+ service: "@array_cache_service"
+ fixtures_path: '%kernel.root_dir%/JsonFixtures'
entities_namespaces:
- 'Smartbox\Integration\Framework\Entity'
+smartbox_integration_camel_config:
+ flows_directories:
+ - "%kernel.root_dir%/Resources/Fixtures/TestFlows"
+ frozen_flows_directory: "%kernel.root_dir%/Resources/Fixtures/FrozenFlows"
+
smartbox_integration_framework:
defer_events_to_uri: queue://events
queue_drivers:
@@ -57,18 +64,104 @@ smartbox_integration_framework:
retry_uri: queue://main/sync/retry
throw_exceptions: true
defer_new_exchanges: false
+ throttle_delay: 1
+ throttle_delay_factor: 1
+ throttle_strategy: fixed
+ throttle_uri: queue://main/throttle
async:
description: Message hanlder to handle messages comming from a queue
retries_max: 5
retry_delay: 0
- failed_uri: queue://main/async/failed
+ failed_uri: queue://main/failed/async
retry_uri: original
throw_exceptions: false
defer_new_exchanges: true
throttle_delay: 1
throttle_delay_factor: 1
throttle_strategy: fixed
- throttle_uri: queue://main/throttlerAsync
+ throttle_uri: queue://main/throttle
+
+ flows_version: 0
+
+ consumers:
+ test_csv:
+ class: Smartbox\Integration\FrameworkBundle\Components\FileService\Csv\CsvConfigurableConsumer
+ description: Consume from csv file
+ calls:
+ - [setConfigurableStepsProvider,['@smartesb.steps_provider.csv_file']]
+ options:
+ delimiter: '|'
+ enclosure: '"'
+ escape_char: '\'
+ stop_on_eof: true
+ methods:
+ read_happy:
+ description: Read out some | csv file, 3 lines at a time
+ query_steps:
+ - read_lines:
+ result_name: xyxx
+ max_lines: 3
+ filename: happy.csv
+ query_result:
+ lines: "eval: results['xyxx']"
+ on_consume: ~
+
+ test_csv_2:
+ class: Smartbox\Integration\FrameworkBundle\Components\FileService\Csv\CsvConfigurableConsumer
+ description: Consume from csv file
+ calls:
+ - [setConfigurableStepsProvider,['@smartesb.steps_provider.csv_file']]
+ options:
+ delimiter: ','
+ enclosure: '"'
+ escape_char: '\'
+ stop_on_eof: true
+ methods:
+ read_happy:
+ description: Read from a , csv file, 2 lines at a time
+ # The path to where our write flow test should have written
+ query_steps:
+ - read_lines:
+ result_name: xyxx
+ max_lines: 2
+ filename: happy-comma.csv
+ query_result:
+ lines: "eval: results['xyxx']"
+ on_consume: ~
+
+ producers:
+ test_csv:
+ class: Smartbox\Integration\FrameworkBundle\Components\FileService\Csv\CsvConfigurableProducer
+ description: Producer to write out csv files
+ calls:
+ - [setConfigurableStepsProvider,["@smartesb.steps_provider.csv_file"]]
+ options:
+ delimiter: ','
+ enclosure: '"'
+ escape_char: '\'
+ methods:
+ write_happy:
+ description: Append lines to the csv file
+ steps:
+ - append_lines:
+ rows: "eval: body['lines']"
+ response: []
+ mongo:
+ class: Smartbox\Integration\FrameworkBundle\Components\DB\DBConfigurableProducer
+ description: Producer to send messages to mongo
+ calls:
+ - [setConfigurableStepsProvider, ["@smartesb.steps_provider.nosql"]]
+ options: ~
+
+ methods:
+ insert:
+ description: Inserts a message in a mongo collection
+ steps:
+ - insertOne:
+ data: "eval: msg"
+
- flows_version: 0
\ No newline at end of file
+doctrine:
+ dbal:
+ default_connection: default
diff --git a/Tests/App/config/parameters.yml.dist b/Tests/App/config/parameters.yml.dist
index 079e4893..b35f6b67 100644
--- a/Tests/App/config/parameters.yml.dist
+++ b/Tests/App/config/parameters.yml.dist
@@ -10,3 +10,4 @@ parameters:
rabbitmq.password: guest
rabbitmq.vhost: /
rabbitmq.timeout: 15
+ logging_exception_test.class: \Smartbox\Integration\FrameworkBundle\Tests\Fixtures\Exceptions\TestException
diff --git a/Tests/App/config/routing_endpoints_test.yml b/Tests/App/config/routing_endpoints_test.yml
index 56831e1d..8434f53b 100644
--- a/Tests/App/config/routing_endpoints_test.yml
+++ b/Tests/App/config/routing_endpoints_test.yml
@@ -1,3 +1,88 @@
smartbox_integration_platform:
resource: "@SmartboxIntegrationFrameworkBundle/Resources/config/default_endpoint_routes.yml"
- prefix: /
\ No newline at end of file
+ prefix: /
+
+queues.generic:
+ path: "queue://{queue_driver}/{queue}"
+ defaults:
+ _protocol: "@smartesb.protocols.queue"
+ prefix: "test/"
+ persistent: false # For the tests we don't really want to persist our messages
+
+ requirements:
+ queue: "[a-zA-Z0-9/]+"
+
+nosql.configurable:
+ path: "nosql://{nosql_driver}/{method}/{collection}"
+ defaults:
+ _protocol: "@smartesb.protocols.configurable.nosql"
+ _producer: "@smartesb.producers.mongo"
+ _handler: "@smartesb.handlers.sync"
+ prefix: ""
+ nosql_driver: main
+ requirements:
+ collection: "[_-a-zA-Z0-9]+"
+ nosql_driver: "[a-zA-Z0-9]+"
+
+## For testing purposes
+test:
+ path: "test://{path}"
+ defaults:
+ _protocol: "@smartesb.protocols.direct"
+ requirements:
+ path: "[a-zA-Z0-9/_-]+"
+
+helper:
+ path: "helper://{operation}/{operand}"
+ defaults:
+ _protocol: "@smartesb.protocols.base"
+ _producer: "@producer.helper"
+
+spy:
+ path: "spy://{path}"
+ defaults:
+ _protocol: "@smartesb.protocols.base"
+ _producer: "@producer.spy"
+ requirements:
+ path: "[a-zA-Z0-9/_-]+"
+
+error.triggerer.recoverable:
+ path: "error://recoverable/{nb_errors}"
+ defaults:
+ _protocol: "@smartesb.protocols.base"
+ _producer: "@producer.error.triggerer"
+ recoverable: true
+ nb_errors: 1
+
+error.triggerer.unrecoverable:
+ path: "error://unrecoverable"
+ defaults:
+ _protocol: "@smartesb.protocols.base"
+ _producer: "@producer.error.triggerer"
+ recoverable: false
+
+csv.test.consumer.read:
+ path: "csv://test/consumer/{method}"
+ defaults:
+ _protocol: "@smartesb.protocols.configurable.csv_file"
+ _consumer: "@smartesb.consumers.test_csv"
+ _handler: "@smartesb.handlers.async"
+ path: "%kernel.root_dir%/Resources/Fixtures/Csv/"
+
+csv.test.consumer.read_2:
+ path: "csv://test/consumer_2/{method}"
+ defaults:
+ _protocol: "@smartesb.protocols.configurable.csv_file"
+ _consumer: "@smartesb.consumers.test_csv_2"
+ _handler: "@smartesb.handlers.async"
+ path: "/tmp/integration-framework-test"
+
+csv.test.producer.write:
+ path: "csv://test/producer/{method}/{default_path}"
+ defaults:
+ _protocol: "@smartesb.protocols.configurable.csv_file"
+ _producer: "@smartesb.producers.test_csv"
+ root_path: "/tmp/integration-framework-test"
+ delimiter: ","
+ requirements:
+ default_path: ".*"
\ No newline at end of file
diff --git a/Tests/App/config/routing_itineraries.yml b/Tests/App/config/routing_itineraries.yml
index 3f0eb569..8d4cec7d 100644
--- a/Tests/App/config/routing_itineraries.yml
+++ b/Tests/App/config/routing_itineraries.yml
@@ -1,3 +1,3 @@
auto_generated_routes:
- resource: @smartesb.map.itineraries
+ resource: '@smartesb.map.itineraries'
type: itineraries
\ No newline at end of file
diff --git a/Tests/App/config/services.yml b/Tests/App/config/services.yml
index 8583b7e1..28fc73f2 100644
--- a/Tests/App/config/services.yml
+++ b/Tests/App/config/services.yml
@@ -1,4 +1,14 @@
services:
- doctrine:
- class: Symfony\Bridge\Doctrine\RegistryInterface
- synthetic: true
\ No newline at end of file
+ producer.error.triggerer:
+ class: Smartbox\Integration\FrameworkBundle\Tests\App\Producers\ErrorTriggerProducer
+
+ producer.helper:
+ class: Smartbox\Integration\FrameworkBundle\Tests\App\Producers\HelperProducer
+ calls:
+ - [setMessageFactory, ['@smartesb.message_factory']]
+
+ producer.spy:
+ class: Smartbox\Integration\FrameworkBundle\Tests\App\Producers\SpyProducer
+
+ array_cache_service:
+ class: Smartbox\Integration\CamelConfigBundle\Tests\App\ArrayCacheService
\ No newline at end of file
diff --git a/Tests/Fixtures/Exceptions/TestException.php b/Tests/Fixtures/Exceptions/TestException.php
new file mode 100644
index 00000000..55943066
--- /dev/null
+++ b/Tests/Fixtures/Exceptions/TestException.php
@@ -0,0 +1,14 @@
+setUp();
+ $parser = new Parser();
+ $finder = new Finder();
+ $flowsDir = $this->getContainer()->getParameter('smartesb.flows_directories');
+ $finder->name('*.yml');
+ $finder->files()->in($flowsDir);
+
+ $res = [];
+
+ /** @var SplFileInfo $file */
+ foreach ($finder as $file) {
+ $res[] = [$file->getRelativePath(), $parser->parse(file_get_contents($file->getRealpath()))];
+ }
+
+ return $res;
+ }
+
+ /**
+ * @dataProvider flowsDataProvider
+ *
+ * @param $path
+ * @param array $conf
+ *
+ * @throws \Exception
+ */
+ public function testFlow($path, array $conf)
+ {
+ if (!array_key_exists('steps', $conf)) {
+ throw new \Exception('Missing steps');
+ }
+
+ /** @var Logger $logger */
+ $logger = $this->getContainer()->get('logger');
+ foreach ($logger->getHandlers() as $handler) {
+ if ($handler instanceof DebugHandler) {
+ $this->loggerHandler = $handler;
+ break;
+ }
+ }
+
+ foreach ($conf['steps'] as $step) {
+ $type = $step['type'];
+ switch ($type) {
+ case 'handle':
+ $this->handle($step);
+ break;
+ case 'checkSpy':
+ $this->checkSpy($step);
+ break;
+ case 'checkSpyArray':
+ $this->checkSpyArray($step);
+ break;
+ case 'consume':
+ $this->consume($step);
+ break;
+ case 'expectedException':
+ $this->expectedException($step);
+ break;
+ case 'checkLogs':
+ $this->checkLogs($step);
+ break;
+ case 'wait':
+ $this->wait($step);
+ break;
+ case 'configureHandler':
+ $this->configureHandler($step);
+ break;
+ case 'copyTmpResource':
+ $this->copyTmpResource($step);
+ break;
+ case 'cleanTmpResources':
+ $this->cleanTmpResources($step);
+ break;
+ }
+ }
+ }
+
+ /**
+ * @param array $conf
+ *
+ * @throws \Exception
+ * @throws \Smartbox\Integration\FrameworkBundle\Core\Handlers\HandlerException
+ */
+ private function handle(array $conf)
+ {
+ if (!array_key_exists('in', $conf) || !array_key_exists('from', $conf)) {
+ throw new \Exception('Missing parameter in handle step');
+ }
+
+ /** @var ExpressionEvaluator $evaluator */
+ $evaluator = $this->getContainer()->get('smartesb.util.evaluator');
+
+ $in = $evaluator->evaluateWithVars($conf['in'], []);
+
+ $message = $this->createMessage(new EntityX($in));
+ $handler = $this->getContainer()->get('smartesb.helper')->getHandler('sync');
+ $endpointFactory = $this->getContainer()->get('smartesb.endpoint_factory');
+ $endpoint = $endpointFactory->createEndpoint($conf['from'], EndpointFactory::MODE_CONSUME);
+
+ /** @var EntityX $result */
+ $result = $handler->handle($message, $endpoint)->getBody();
+
+ if (isset($conf['out'])) {
+ $out = $evaluator->evaluateWithVars($conf['out'], ['in' => $in]);
+ $this->assertEquals($out, $result->getX(), 'Unexpected result when handling message from: '.$conf['from']);
+ }
+ }
+
+ /**
+ * @param array $conf
+ *
+ * @throws \Exception
+ * @throws \Smartbox\Integration\FrameworkBundle\Core\Handlers\HandlerException
+ */
+ private function checkSpy(array $conf)
+ {
+ if (!array_key_exists('path', $conf) || !array_key_exists('values', $conf)) {
+ throw new \Exception('Missing parameter in checkSpy step');
+ }
+ $evaluator = $this->getContainer()->get('smartesb.util.evaluator');
+
+ $expectedValues = [];
+ foreach ($conf['values'] as $value) {
+ $expectedValues[] = $evaluator->evaluateWithVars($value, []);
+ }
+
+ $values = $this->getContainer()->get('producer.spy')->getData($conf['path']);
+
+ $this->assertEquals($expectedValues, $values, 'The spy '.$conf['path']." didn't contain the expected data");
+ }
+ /**
+ * @param array $conf
+ *
+ * @throws \Exception
+ * @throws \Smartbox\Integration\FrameworkBundle\Core\Handlers\HandlerException
+ */
+ private function checkSpyArray(array $conf)
+ {
+ if (!array_key_exists('path', $conf) || !array_key_exists('values', $conf)) {
+ throw new \Exception('Missing parameter in checkSpy step');
+ }
+
+ $expectedValues = $conf['values'];
+
+ $values = $this->getContainer()->get('producer.spy')->getData($conf['path']);
+
+ $this->assertSame($expectedValues, $values, 'The spy '.$conf['path']." didn't contain the expected data");
+ }
+
+ /**
+ * @param array $conf
+ *
+ * @throws \Exception
+ * @throws \Smartbox\Integration\FrameworkBundle\Core\Handlers\HandlerException
+ */
+ private function consume(array $conf)
+ {
+ if (!array_key_exists('uri', $conf) || !array_key_exists('amount', $conf)) {
+ throw new \Exception('Missing parameter uri in consume step');
+ }
+
+ $uri = $conf['uri'];
+
+ /** @var EndpointInterface $endpoint */
+ $endpoint = $this->getContainer()->get('smartesb.endpoint_factory')->createEndpoint($uri, EndpointFactory::MODE_CONSUME);
+ $endpoint->consume($conf['amount']);
+ }
+
+ private function expectedException(array $conf)
+ {
+ if (!array_key_exists('class', $conf)) {
+ $conf['class'] = ProcessingException::class;
+ }
+
+ $this->expectException($conf['class']);
+ }
+
+ private function checkLogs(array $conf)
+ {
+ if (!array_key_exists('level', $conf) || !array_key_exists('message', $conf)) {
+ throw new \Exception('Missing parameter in checkLogs step');
+ }
+
+ $level = $conf['level'];
+ $message = $conf['message'];
+
+ $this->assertTrue($this->loggerHandler->hasRecordThatContains($message, $level));
+ }
+
+ /**
+ * @param array $conf
+ *
+ * @throws \Exception
+ */
+ private function wait(array $conf)
+ {
+ if (!array_key_exists('delay', $conf)) {
+ throw new \Exception('Missing parameter in wait step');
+ }
+
+ $delay = $conf['delay'];
+ sleep($delay);
+ }
+
+ /**
+ * @param array $conf
+ *
+ * @throws \Exception
+ */
+ private function configureHandler(array $conf)
+ {
+ if (!array_key_exists('name', $conf)) {
+ throw new \Exception('Missing parameter in configureHandler step');
+ }
+
+ /** @var MessageHandler $handler */
+ $handler = $this->getContainer()->get('smartesb.helper')->getHandler($conf['name']);
+ if (array_key_exists('retryDelay', $conf)) {
+ $handler->setRetryDelay($conf['retryDelay']);
+ }
+
+ if (array_key_exists('retryStrategy', $conf)) {
+ $handler->setRetryStrategy($conf['retryStrategy']);
+ $handler->setRetryDelayFactor($conf['retryDelayFactor']);
+ }
+ }
+
+ /**
+ * Copy a test resource to self::TMP_FOLDER for using
+ *
+ * conf['from'] The resource in %kernel.root_path%/Test/App/Resources you would like copied
+ * to self::TMP_FOLDER
+ *
+ * If the self::TMP_FOLDER does not exist it will be created
+ *
+ * @param array $conf
+ *
+ * @throws \Exception
+ */
+ private function copyTmpResource(array $conf)
+ {
+ if (!array_key_exists('from', $conf)) {
+ throw new \Exception('Missing from parameter in copyTmpResource step');
+ }
+
+ $from_path = self::$kernel->getRootDir() . DIRECTORY_SEPARATOR . self::RESOURCE_FOLDER . DIRECTORY_SEPARATOR . $conf['from'];
+
+ if (!is_file($from_path)) {
+ throw new \Exception("The resource path {$from_path} is not a file!");
+ }
+
+
+ if (!is_dir(self::TMP_FOLDER)) {
+ mkdir(self::TMP_FOLDER);
+ }
+
+ $to_path = self::TMP_FOLDER . DIRECTORY_SEPARATOR . basename($conf['from']);
+
+ copy( $from_path, $to_path );
+ }
+
+ /**
+ * Clean up the copied and created file resources by removeing the folder self::TMP_FOLDER
+ *
+ * @param array $conf
+ *
+ * @throws \Exception
+ */
+ private function cleanTmpResources(array $conf)
+ {
+ $files = glob(self::TMP_FOLDER . DIRECTORY_SEPARATOR . '*');
+ foreach ($files as $file) {
+ if (is_file($file))
+ unlink($file); // delete file
+ }
+ //remove the folder
+ rmdir(self::TMP_FOLDER);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function tearDown()
+ {
+ parent::tearDown();
+ ErrorTriggerProducer::$count = 0;
+ }
+}
diff --git a/composer.json b/composer.json
index 4837e945..527b8ec9 100644
--- a/composer.json
+++ b/composer.json
@@ -28,7 +28,9 @@
"doctrine/doctrine-bundle": "^1.6",
"sensio/generator-bundle": "~2.3",
"mongodb/mongodb": "~1.0",
- "jms/serializer-bundle": "*"
+ "jms/serializer-bundle": "*",
+ "smartbox/camel-config-bundle": "dev-tidy/move-tests as v1.0.0",
+ "ext-mongodb": "*"
},
"scripts": {
"post-install-cmd": [