You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2019/08/02 14:46:33 UTC

[camel] 05/08: CAMEL-12003: Add failFast option to mock endpoint

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 9d2306bce947ddf58a8dcc185c302cf02c41316a
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Aug 2 09:08:09 2019 +0200

    CAMEL-12003: Add failFast option to mock endpoint
---
 .../src/main/docs/dataset-component.adoc           |  3 +-
 .../camel/component/dataset/DataSetEndpoint.java   |  7 +-
 .../apache/camel/component/mock/MockEndpoint.java  | 79 +++++++++++++++++++---
 .../component/dataset/DataSetProducerTest.java     | 28 +++-----
 .../camel/component/mock/MockEndpointTest.java     |  3 +-
 .../dsl/DataSetEndpointBuilderFactory.java         | 30 ++++++++
 6 files changed, 114 insertions(+), 36 deletions(-)

diff --git a/components/camel-dataset/src/main/docs/dataset-component.adoc b/components/camel-dataset/src/main/docs/dataset-component.adoc
index 0abd769..d9fc80c 100644
--- a/components/camel-dataset/src/main/docs/dataset-component.adoc
+++ b/components/camel-dataset/src/main/docs/dataset-component.adoc
@@ -78,7 +78,7 @@ with the following path and query parameters:
 |===
 
 
-=== Query Parameters (18 parameters):
+=== Query Parameters (19 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -92,6 +92,7 @@ with the following path and query parameters:
 | *consumeDelay* (producer) | Allows a delay to be specified which causes a delay when a message is consumed by the producer (to simulate slow processing) | 0 | long
 | *assertPeriod* (producer) | Sets a grace period after which the mock endpoint will re-assert to ensure the preliminary assertion is still valid. This is used for example to assert that exactly a number of messages arrives. For example if expectedMessageCount(int) was set to 5, then the assertion is satisfied when 5 or more message arrives. To ensure that exactly 5 messages arrives, then you would need to wait a little period to ensure no further message arrives. This is what you can us [...]
 | *expectedCount* (producer) | Specifies the expected number of message exchanges that should be received by this endpoint. Beware: If you want to expect that 0 messages, then take extra care, as 0 matches when the tests starts, so you need to set a assert period time to let the test run for a while to make sure there are still no messages arrived; for that use setAssertPeriod(long). An alternative is to use NotifyBuilder, and use the notifier to know when Camel is done routing some mess [...]
+| *failFast* (producer) | Sets whether assertIsSatisfied() should fail fast at the first detected failed expectation while it may otherwise wait for all expected messages to arrive before performing expectations verifications. Is by default true. Set to false to use behavior as in Camel 2.x. | false | boolean
 | *lazyStartProducer* (producer) | Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and [...]
 | *reportGroup* (producer) | A number that is used to turn on throughput logging based on groups of the size. |  | int
 | *resultMinimumWaitTime* (producer) | Sets the minimum expected amount of time (in millis) the assertIsSatisfied() will wait on a latch until it is satisfied | 0 | long
diff --git a/components/camel-dataset/src/main/java/org/apache/camel/component/dataset/DataSetEndpoint.java b/components/camel-dataset/src/main/java/org/apache/camel/component/dataset/DataSetEndpoint.java
index c72ab14..49074ed 100644
--- a/components/camel-dataset/src/main/java/org/apache/camel/component/dataset/DataSetEndpoint.java
+++ b/components/camel-dataset/src/main/java/org/apache/camel/component/dataset/DataSetEndpoint.java
@@ -45,7 +45,7 @@ import org.slf4j.LoggerFactory;
  * Camel will use the throughput logger when sending dataset's.
  */
 @UriEndpoint(firstVersion = "1.3.0", scheme = "dataset", title = "Dataset", syntax = "dataset:name",
-    label = "core,testing", excludeProperties = "failFast", lenientProperties = true)
+    label = "core,testing", lenientProperties = true)
 public class DataSetEndpoint extends MockEndpoint implements Service {
     private final transient Logger log;
     private final AtomicInteger receivedCounter = new AtomicInteger();
@@ -70,8 +70,6 @@ public class DataSetEndpoint extends MockEndpoint implements Service {
         this.log = LoggerFactory.getLogger(endpointUri);
         // optimize as we dont need to copy the exchange
         setCopyOnExchange(false);
-        // fail fast mode is not possible with dataset endpoints
-        setFailFast(false);
     }
 
     public static void assertEquals(String description, Object expected, Object actual, Exchange exchange) {
@@ -299,9 +297,6 @@ public class DataSetEndpoint extends MockEndpoint implements Service {
             reporter = createReporter();
         }
 
-        // fail fast mode is not possible with dataset endpoints
-        setFailFast(false);
-
         log.info(this + " expecting " + getExpectedCount() + " messages");
     }
 
diff --git a/components/camel-mock/src/main/java/org/apache/camel/component/mock/MockEndpoint.java b/components/camel-mock/src/main/java/org/apache/camel/component/mock/MockEndpoint.java
index 45b2f19..a7a613f 100644
--- a/components/camel-mock/src/main/java/org/apache/camel/component/mock/MockEndpoint.java
+++ b/components/camel-mock/src/main/java/org/apache/camel/component/mock/MockEndpoint.java
@@ -780,11 +780,19 @@ public class MockEndpoint extends DefaultEndpoint implements BrowsableEndpoint,
         for (int i = 0; i < predicates.length; i++) {
             final int messageIndex = i;
             final Predicate predicate = predicates[i];
-            final AssertionClause clause = new AssertionClause(this) {
+            final AssertionClause clause = new AssertionClauseTask(this) {
+                @Override
+                public void assertOnIndex(int index) {
+                    if (messageIndex == index) {
+                        addPredicate(predicate);
+                        applyAssertionOn(MockEndpoint.this, index, assertExchangeReceived(index));
+                    }
+                }
+
                 public void run() {
-                    addPredicate(predicate);
-                    // TODO: Is this correct
-                    applyAssertionOn(MockEndpoint.this, messageIndex, assertExchangeReceived(messageIndex));
+                    for (int i = 0; i < getReceivedExchanges().size(); i++) {
+                        assertOnIndex(i);
+                    }
                 }
             };
             expects(clause);
@@ -939,6 +947,7 @@ public class MockEndpoint extends DefaultEndpoint implements BrowsableEndpoint,
     public void expectsAscending(final Expression expression) {
         expects(new Runnable() {
             public void run() {
+                // TODO: Task
                 assertMessagesAscending(expression);
             }
         });
@@ -949,8 +958,14 @@ public class MockEndpoint extends DefaultEndpoint implements BrowsableEndpoint,
      * of the given expression such as a user generated counter value
      */
     public AssertionClause expectsAscending() {
-        // TODO: Task
-        final AssertionClause clause = new AssertionClause(this) {
+        final AssertionClause clause = new AssertionClauseTask(this) {
+            @Override
+            public void assertOnIndex(int index) {
+                // TODO: Make this smarter
+                // just run from top again
+                run();
+            }
+
             public void run() {
                 assertMessagesAscending(createExpression(getCamelContext()));
             }
@@ -997,9 +1012,26 @@ public class MockEndpoint extends DefaultEndpoint implements BrowsableEndpoint,
      *                {@link Object#hashCode()}
      */
     public void expectsNoDuplicates(final Expression expression) {
-        expects(new Runnable() {
+        expects(new AssertionTask() {
+            private Map<Object, Exchange> map = new HashMap<>();
+
+            @Override
+            public void assertOnIndex(int index) {
+                List<Exchange> list = getReceivedExchanges();
+                Exchange e2 = list.get(index);
+                Object key = expression.evaluate(e2, Object.class);
+                Exchange e1 = map.get(key);
+                if (e1 != null) {
+                    fail("Duplicate message found on message " + index + " has value: " + key + " for expression: " + expression + ". Exchanges: " + e1 + " and " + e2);
+                } else {
+                    map.put(key, e2);
+                }
+            }
+
             public void run() {
-                assertNoDuplicates(expression);
+                for (int i = 0; i < getReceivedExchanges().size(); i++) {
+                    assertOnIndex(i);
+                }
             }
         });
     }
@@ -1009,10 +1041,30 @@ public class MockEndpoint extends DefaultEndpoint implements BrowsableEndpoint,
      * the expression to determine the message ID
      */
     public AssertionClause expectsNoDuplicates() {
-        // TODO: Task
-        final AssertionClause clause = new AssertionClause(this) {
+        final AssertionClause clause = new AssertionClauseTask(this) {
+            private Map<Object, Exchange> map = new HashMap<>();
+            private Expression exp;
+
+            @Override
+            public void assertOnIndex(int index) {
+                if (exp == null) {
+                    exp = createExpression(getCamelContext());
+                }
+                List<Exchange> list = getReceivedExchanges();
+                Exchange e2 = list.get(index);
+                Object key = exp.evaluate(e2, Object.class);
+                Exchange e1 = map.get(key);
+                if (e1 != null) {
+                    fail("Duplicate message found on message " + index + " has value: " + key + " for expression: " + exp + ". Exchanges: " + e1 + " and " + e2);
+                } else {
+                    map.put(key, e2);
+                }
+            }
+
             public void run() {
-                assertNoDuplicates(createExpression(getCamelContext()));
+                for (int i = 0; i < getReceivedExchanges().size(); i++) {
+                    assertOnIndex(i);
+                }
             }
         };
         expects(clause);
@@ -1060,6 +1112,11 @@ public class MockEndpoint extends DefaultEndpoint implements BrowsableEndpoint,
         }
     }
 
+    /**
+     * Asserts among all the current received exchanges that there are no duplicate message
+     *
+     * @param expression  the expression to use for duplication check
+     */
     public void assertNoDuplicates(Expression expression) {
         Map<Object, Exchange> map = new HashMap<>();
         List<Exchange> list = getReceivedExchanges();
diff --git a/core/camel-core/src/test/java/org/apache/camel/component/dataset/DataSetProducerTest.java b/core/camel-core/src/test/java/org/apache/camel/component/dataset/DataSetProducerTest.java
index 0f48c5b..0aa7f24 100644
--- a/core/camel-core/src/test/java/org/apache/camel/component/dataset/DataSetProducerTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/component/dataset/DataSetProducerTest.java
@@ -20,7 +20,6 @@ import javax.naming.Context;
 
 import org.apache.camel.ContextTestSupport;
 import org.apache.camel.Exchange;
-import org.apache.camel.NoSuchHeaderException;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.mock.MockEndpoint;
 import org.junit.Assert;
@@ -168,11 +167,8 @@ public class DataSetProducerTest extends ContextTestSupport {
             assertMockEndpointsSatisfied();
         } catch (AssertionError assertionError) {
             // Check as much of the string as possible - but the ExchangeID at the end will be unique
-            String expectedErrorString = dataSetUriWithDataSetIndexSetToStrict
-                    + " Failed due to caught exception: "
-                    + NoSuchHeaderException.class.getName()
-                    + ": No '" + Exchange.DATASET_INDEX
-                    + "' header available of type: java.lang.Long. Exchange";
+            String expectedErrorString = "Caught exception on " + dataSetUriWithDataSetIndexSetToStrict + " due to:"
+                    + " No '" + Exchange.DATASET_INDEX + "' header available of type: java.lang.Long";
             String actualErrorString = assertionError.getMessage();
             if (actualErrorString.startsWith(expectedErrorString)) {
                 // This is what we expect
@@ -323,10 +319,9 @@ public class DataSetProducerTest extends ContextTestSupport {
             assertMockEndpointsSatisfied();
         } catch (AssertionError assertionError) {
             // Check as much of the string as possible - but the ExchangeID at the end will be unique
-            String expectedErrorString = dataSetUri + " Failed due to caught exception: "
-                    + AssertionError.class.getName()
-                    + ": Header: " + Exchange.DATASET_INDEX + " does not match. Expected: "
-                    + size / 2 + " but was: " + (size / 2 + 10) + " on Exchange";
+            String expectedErrorString = "Caught exception on " + dataSetUri + " due to: "
+                    + "Header: " + Exchange.DATASET_INDEX + " does not match. Expected: "
+                    + size / 2 + " but was: " + (size / 2 + 10);
             String actualErrorString = assertionError.getMessage();
             if (actualErrorString.startsWith(expectedErrorString)) {
                 // This is what we expect
@@ -397,10 +392,9 @@ public class DataSetProducerTest extends ContextTestSupport {
             assertMockEndpointsSatisfied();
         } catch (AssertionError assertionError) {
             // Check as much of the string as possible - but the ExchangeID at the end will be unique
-            String expectedErrorString = dataSetUriWithDataSetIndexSetToLenient + " Failed due to caught exception: "
-                    + AssertionError.class.getName()
-                    + ": Header: " + Exchange.DATASET_INDEX + " does not match. Expected: "
-                    + size / 2 + " but was: " + (size / 2 + 10) + " on Exchange";
+            String expectedErrorString = "Caught exception on " + dataSetUriWithDataSetIndexSetToLenient + " due to: "
+                    + "Header: " + Exchange.DATASET_INDEX + " does not match. Expected: "
+                    + size / 2 + " but was: " + (size / 2 + 10);
             String actualErrorString = assertionError.getMessage();
             if (actualErrorString.startsWith(expectedErrorString)) {
                 // This is what we expect
@@ -443,9 +437,9 @@ public class DataSetProducerTest extends ContextTestSupport {
             assertMockEndpointsSatisfied();
         } catch (AssertionError assertionError) {
             // Check as much of the string as possible - but the ExchangeID at the end will be unique
-            String expectedErrorString = dataSetUriWithDataSetIndexSetToStrict + " Failed due to caught exception: "
-                    + AssertionError.class.getName() + ": Header: " + Exchange.DATASET_INDEX
-                    + " does not match. Expected: " + size / 2 + " but was: " + (size / 2 + 10) + " on Exchange";
+            String expectedErrorString = "Caught exception on " + dataSetUriWithDataSetIndexSetToStrict + " due to: "
+                    + "Header: " + Exchange.DATASET_INDEX + " does not match. Expected: "
+                    + size / 2 + " but was: " + (size / 2 + 10);
             String actualErrorString = assertionError.getMessage();
             if (actualErrorString.startsWith(expectedErrorString)) {
                 // This is what we expect
diff --git a/core/camel-core/src/test/java/org/apache/camel/component/mock/MockEndpointTest.java b/core/camel-core/src/test/java/org/apache/camel/component/mock/MockEndpointTest.java
index ac8c3e4..550cd1f 100644
--- a/core/camel-core/src/test/java/org/apache/camel/component/mock/MockEndpointTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/component/mock/MockEndpointTest.java
@@ -810,10 +810,11 @@ public class MockEndpointTest extends ContextTestSupport {
     @Test
     public void testExpectedExchangePattern() throws Exception {
         MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedMessageCount(1);
+        mock.expectedMessageCount(2);
         mock.expectedExchangePattern(ExchangePattern.InOnly);
 
         template.sendBody("direct:a", "Hello World");
+        template.sendBody("direct:a", "Bye World");
 
         assertMockEndpointsSatisfied();
 
diff --git a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/DataSetEndpointBuilderFactory.java b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/DataSetEndpointBuilderFactory.java
index e22be35..f56d310 100644
--- a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/DataSetEndpointBuilderFactory.java
+++ b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/DataSetEndpointBuilderFactory.java
@@ -346,6 +346,36 @@ public interface DataSetEndpointBuilderFactory {
             return this;
         }
         /**
+         * Sets whether assertIsSatisfied() should fail fast at the first
+         * detected failed expectation while it may otherwise wait for all
+         * expected messages to arrive before performing expectations
+         * verifications. Is by default true. Set to false to use behavior as in
+         * Camel 2.x.
+         * 
+         * The option is a: <code>boolean</code> type.
+         * 
+         * Group: producer
+         */
+        default DataSetEndpointProducerBuilder failFast(boolean failFast) {
+            setProperty("failFast", failFast);
+            return this;
+        }
+        /**
+         * Sets whether assertIsSatisfied() should fail fast at the first
+         * detected failed expectation while it may otherwise wait for all
+         * expected messages to arrive before performing expectations
+         * verifications. Is by default true. Set to false to use behavior as in
+         * Camel 2.x.
+         * 
+         * The option will be converted to a <code>boolean</code> type.
+         * 
+         * Group: producer
+         */
+        default DataSetEndpointProducerBuilder failFast(String failFast) {
+            setProperty("failFast", failFast);
+            return this;
+        }
+        /**
          * Whether the producer should be started lazy (on the first message).
          * By starting lazy you can use this to allow CamelContext and routes to
          * startup in situations where a producer may otherwise fail during