You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ac...@apache.org on 2019/06/06 07:15:42 UTC

[camel] 03/03: fix(13606): Stop Olingo Index Classes generating NP Exceptions

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

acosentino pushed a commit to branch camel-2.24.x
in repository https://gitbox.apache.org/repos/asf/camel.git

commit a3794d195aa7bb707f404fbcd4005429eaf73f54
Author: phantomjinx <p....@phantomjinx.co.uk>
AuthorDate: Wed Jun 5 11:04:07 2019 +0100

    fix(13606): Stop Olingo Index Classes generating NP Exceptions
    
    * Olingo*Index
     * Provides null-checks to each method to avoid any NPE
    
    * Tests
     * The consumer testing routes were being started prior to the tests that
       concerned them. Consequently, it was hit/miss whether the tests would
       catch all messages generated by the routes. This matters for the
       'already seen' tests as adding more of there meant tests failed with
       messages having no bodies.
     * Consumer tests broken out into their own classes and camel context
       started in the test once the mock endpoints have been property setup.
---
 .../camel/component/olingo2/Olingo2Index.java      |  71 ++++++-
 .../olingo2/Olingo2ComponentConsumerTest.java      | 234 +++++++++++++++++++++
 ...Test.java => Olingo2ComponentProducerTest.java} | 148 +------------
 .../camel/component/olingo4/Olingo4Index.java      |  23 +-
 .../olingo4/Olingo4ComponentConsumerTest.java      | 211 +++++++++++++++++++
 ...Test.java => Olingo4ComponentProducerTest.java} | 134 +-----------
 6 files changed, 546 insertions(+), 275 deletions(-)

diff --git a/components/camel-olingo2/camel-olingo2-component/src/main/java/org/apache/camel/component/olingo2/Olingo2Index.java b/components/camel-olingo2/camel-olingo2-component/src/main/java/org/apache/camel/component/olingo2/Olingo2Index.java
index 1198a10..c6a0f2a 100644
--- a/components/camel-olingo2/camel-olingo2-component/src/main/java/org/apache/camel/component/olingo2/Olingo2Index.java
+++ b/components/camel-olingo2/camel-olingo2-component/src/main/java/org/apache/camel/component/olingo2/Olingo2Index.java
@@ -18,17 +18,47 @@ package org.apache.camel.component.olingo2;
 
 import java.lang.reflect.Array;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import org.apache.olingo.odata2.api.ep.entry.EntryMetadata;
 import org.apache.olingo.odata2.api.ep.entry.ODataEntry;
+import org.apache.olingo.odata2.api.ep.feed.FeedMetadata;
 import org.apache.olingo.odata2.api.ep.feed.ODataFeed;
 
 public class Olingo2Index {
 
     private Set<Integer> resultIndex = new HashSet<>();
 
+    private class EmptyODataFeed implements ODataFeed {
+
+        @Override
+        public List<ODataEntry> getEntries() {
+            return Collections.emptyList();
+        }
+
+        @Override
+        public FeedMetadata getFeedMetadata() {
+            return new FeedMetadata() {
+                @Override
+                public String getDeltaLink() {
+                    return null;
+                }
+
+                @Override
+                public Integer getInlineCount() {
+                    return 0;
+                }
+
+                @Override
+                public String getNextLink() {
+                    return null;
+                }
+            };
+        }
+    }
+
     /**
      * Hash only certain data since other parts change between message
      * exchanges.
@@ -64,18 +94,41 @@ public class Olingo2Index {
     }
 
     private Object filter(Object o) {
-        if (resultIndex.contains(o.hashCode())) {
+        if (o == null || resultIndex.contains(o.hashCode())) {
             return null;
         }
         return o;
     }
 
     private void indexDefault(Object o) {
+        if (o == null) {
+            return;
+        }
+
         resultIndex.add(o.hashCode());
     }
 
+    private Object filter(ODataEntry entry) {
+        if (entry == null || resultIndex.contains(hash(entry))) {
+            return null;
+        }
+        return entry;
+    }
+
+    private void index(ODataEntry entry) {
+        if (entry == null) {
+            return;
+        }
+
+        resultIndex.add(hash(entry));
+    }
+
     private Iterable<?> filter(Iterable<?> iterable) {
         List<Object> filtered = new ArrayList<>();
+        if (iterable == null) {
+            return filtered;
+        }
+
         for (Object o : iterable) {
             if (resultIndex.contains(o.hashCode())) {
                 continue;
@@ -87,12 +140,20 @@ public class Olingo2Index {
     }
 
     private void index(Iterable<?> iterable) {
+        if (iterable == null) {
+            return;
+        }
+
         for (Object o : iterable) {
             resultIndex.add(o.hashCode());
         }
     }
 
     private ODataFeed filter(ODataFeed odataFeed) {
+        if (odataFeed == null) {
+            return new EmptyODataFeed();
+        }
+
         List<ODataEntry> entries = odataFeed.getEntries();
 
         if (entries.isEmpty()) {
@@ -111,6 +172,10 @@ public class Olingo2Index {
     }
 
     private void index(ODataFeed odataFeed) {
+        if (odataFeed == null) {
+            return;
+        }
+
         for (ODataEntry entry : odataFeed.getEntries()) {
             resultIndex.add(hash(entry));
         }
@@ -124,6 +189,8 @@ public class Olingo2Index {
             index((ODataFeed) result);
         } else if (result instanceof Iterable) {
             index((Iterable<?>) result);
+        } else if (result instanceof ODataEntry) {
+            index((ODataEntry) result);
         } else {
             indexDefault(result);
         }
@@ -142,6 +209,8 @@ public class Olingo2Index {
                 result.add(Array.get(response, i));
             }
             response = filter(result);
+        } else if (response instanceof ODataEntry) {
+            response = filter((ODataEntry) response);
         } else {
             response = filter(response);
         }
diff --git a/components/camel-olingo2/camel-olingo2-component/src/test/java/org/apache/camel/component/olingo2/Olingo2ComponentConsumerTest.java b/components/camel-olingo2/camel-olingo2-component/src/test/java/org/apache/camel/component/olingo2/Olingo2ComponentConsumerTest.java
new file mode 100644
index 0000000..e95c53e
--- /dev/null
+++ b/components/camel-olingo2/camel-olingo2-component/src/test/java/org/apache/camel/component/olingo2/Olingo2ComponentConsumerTest.java
@@ -0,0 +1,234 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.olingo2;
+
+import java.util.Map;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.AvailablePortFinder;
+import org.apache.olingo.odata2.api.ep.entry.ODataEntry;
+import org.apache.olingo.odata2.api.ep.feed.ODataFeed;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Test class for {@link org.apache.camel.component.olingo2.api.Olingo2App} APIs.
+ * <p>
+ * The integration test runs against Apache Olingo 2.0 sample server
+ * which is dynamically installed and started during the test.
+ * </p>
+ */
+public class Olingo2ComponentConsumerTest extends AbstractOlingo2TestSupport {
+
+    private static final int PORT = AvailablePortFinder.getNextAvailable();
+    private static final String TEST_SERVICE_URL = "http://localhost:" + PORT + "/MyFormula.svc";
+
+    private static Olingo2SampleServer server;
+
+    public Olingo2ComponentConsumerTest() {
+        setDefaultTestProperty("serviceUri", "http://localhost:" + PORT + "/MyFormula.svc");
+    }
+
+    @BeforeClass
+    public static void beforeClass() throws Exception {
+        startServers(PORT);
+        Olingo2SampleServer.generateSampleData(TEST_SERVICE_URL);
+    }
+
+    @AfterClass
+    public static void afterClass() throws Exception {
+        if (server != null) {
+            server.stop();
+            server.destroy();
+        }
+    }
+
+    protected static void startServers(int port) throws Exception {
+        server = new Olingo2SampleServer(port, "/olingo2_ref");
+        server.start();
+    }
+
+    private void addRouteAndStartContext(RouteBuilder builder) throws Exception {
+        context().addRoutes(builder);
+        startCamelContext();
+    }
+
+    /**
+     * Read entity set of the People object
+     * and filter already seen items on subsequent exchanges
+     * Use a delay since the mock endpoint does not always get
+     * the correct number of exchanges before being satisfied.
+     *
+     * Note:
+     * - consumer.splitResults is set to false since this ensures the first returned message
+     *   contains all the results. This is preferred for the purposes of this test. The default
+     *   will mean the first n messages contain the results (where n is the result total) then
+     *   subsequent messages will be empty
+     */
+    @Test
+    public void testConsumerReadFilterAlreadySeen() throws Exception {
+        int expectedMsgCount = 3;
+        MockEndpoint mockEndpoint = getMockEndpoint("mock:consumer-alreadyseen");
+        mockEndpoint.expectedMessageCount(expectedMsgCount);
+        mockEndpoint.setResultWaitTime(60000);
+
+        RouteBuilder builder = new RouteBuilder() {
+            public void configure() {
+                from("olingo2://read/Manufacturers?filterAlreadySeen=true&"
+                        + "consumer.delay=2&consumer.sendEmptyMessageWhenIdle=true&"
+                        + "consumer.splitResult=false")
+                    .to("mock:consumer-alreadyseen");
+            };
+        };
+        addRouteAndStartContext(builder);
+
+        mockEndpoint.assertIsSatisfied();
+
+        for (int i = 0; i < expectedMsgCount; ++i) {
+            Object body = mockEndpoint.getExchanges().get(i).getIn().getBody();
+
+            if (i == 0) {
+                //
+                // First polled messages contained all the manufacturers
+                //
+                assertTrue(body instanceof ODataFeed);
+                ODataFeed set = (ODataFeed) body;
+                assertTrue(set.getEntries().size() > 0);
+            } else {
+                //
+                // Subsequent polling messages should be empty
+                // since the filterAlreadySeen property is true
+                //
+                assertNull(body);
+            }
+        }
+    }
+
+    @Test
+    public void testConsumerReadFilterAlreadySeenWithPredicateAndSplitResults() throws Exception {
+        int expectedMsgCount = 3;
+        MockEndpoint mockEndpoint = getMockEndpoint("mock:consumer-splitresult-kp-manufacturer");
+        mockEndpoint.expectedMinimumMessageCount(expectedMsgCount);
+
+        RouteBuilder builder = new RouteBuilder() {
+            public void configure() {
+                from("olingo2://read/Manufacturers('1')?filterAlreadySeen=true&"
+                        + "consumer.delay=2&consumer.sendEmptyMessageWhenIdle=true&"
+                        + "consumer.splitResult=true")
+                    .to("mock:consumer-splitresult-kp-manufacturer");
+            };
+        };
+        addRouteAndStartContext(builder);
+
+        mockEndpoint.assertIsSatisfied();
+
+        for (int i = 0; i < expectedMsgCount; ++i) {
+            Object body = mockEndpoint.getExchanges().get(i).getIn().getBody();
+
+            if (i == 0) {
+                //
+                // First polled messages contained all the entities
+                //
+                assertTrue(body instanceof ODataEntry);
+                ODataEntry entry = (ODataEntry) body;
+                Object nameValue = entry.getProperties().get("Name");
+                assertNotNull(nameValue);
+                assertEquals("Star Powered Racing", nameValue.toString());
+            } else {
+                //
+                // Subsequent polling messages should be empty
+                // since the filterAlreadySeen property is true
+                //
+                assertNull(body);
+            }
+        }
+    }
+
+    /**
+     * Read value of the People object and split the results
+     * into individual messages
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testConsumerReadClientValuesSplitResults() throws Exception {
+        MockEndpoint mockEndpoint = getMockEndpoint("mock:consumer-value");
+        mockEndpoint.expectedMinimumMessageCount(1);
+        mockEndpoint.setResultWaitTime(60000);
+
+        RouteBuilder builder = new RouteBuilder() {
+            public void configure() {
+                from("olingo2://read/Manufacturers('1')/Address?consumer.splitResult=true")
+                    .to("mock:consumer-value");
+            };
+        };
+        addRouteAndStartContext(builder);
+
+        mockEndpoint.assertIsSatisfied();
+        //
+        // 1 individual message in the exchange
+        //
+        Object body = mockEndpoint.getExchanges().get(0).getIn().getBody();
+        assertIsInstanceOf(Map.class, body);
+        Map<String, Object> value = (Map<String, Object>) body;
+        Object addrObj = value.get("Address");
+        assertIsInstanceOf(Map.class, addrObj);
+        Map<String, Object> addrMap = (Map<String, Object>) addrObj;
+        assertEquals("70173", addrMap.get("ZipCode"));
+        assertEquals("Star Street 137", addrMap.get("Street"));
+        assertEquals("Germany", addrMap.get("Country"));
+        assertEquals("Stuttgart", addrMap.get("City"));
+    }
+
+    /**
+     * Read entity set of the Manufacturers object and split the results
+     * into individual messages
+     */
+    @Test
+    public void testConsumerReadSplitResults() throws Exception {
+        int expectedMsgCount = 2;
+        MockEndpoint mockEndpoint = getMockEndpoint("mock:consumer-splitresult");
+        mockEndpoint.expectedMinimumMessageCount(expectedMsgCount);
+
+        RouteBuilder builder = new RouteBuilder() {
+            public void configure() {
+                from("olingo2://read/Manufacturers?consumer.splitResult=true")
+                    .to("mock:consumer-splitresult");
+            };
+        };
+
+        addRouteAndStartContext(builder);
+
+        mockEndpoint.assertIsSatisfied();
+
+        //
+        // 2 individual messages in the exchange,
+        // each containing a different entity.
+        //
+        for (int i = 0; i < expectedMsgCount; ++i) {
+            Object body = mockEndpoint.getExchanges().get(i).getIn().getBody();
+            assertTrue(body instanceof ODataEntry);
+            ODataEntry entry = (ODataEntry)body;
+            Map<String, Object> properties = entry.getProperties();
+            assertNotNull(properties);
+
+            Object name = properties.get("Name");
+            assertNotNull(name);
+            assertTrue(name.toString().contains("Powered Racing"));
+        }
+    }
+}
diff --git a/components/camel-olingo2/camel-olingo2-component/src/test/java/org/apache/camel/component/olingo2/Olingo2ComponentTest.java b/components/camel-olingo2/camel-olingo2-component/src/test/java/org/apache/camel/component/olingo2/Olingo2ComponentProducerTest.java
similarity index 73%
rename from components/camel-olingo2/camel-olingo2-component/src/test/java/org/apache/camel/component/olingo2/Olingo2ComponentTest.java
rename to components/camel-olingo2/camel-olingo2-component/src/test/java/org/apache/camel/component/olingo2/Olingo2ComponentProducerTest.java
index e544b79..589f2fd 100644
--- a/components/camel-olingo2/camel-olingo2-component/src/test/java/org/apache/camel/component/olingo2/Olingo2ComponentTest.java
+++ b/components/camel-olingo2/camel-olingo2-component/src/test/java/org/apache/camel/component/olingo2/Olingo2ComponentProducerTest.java
@@ -49,10 +49,10 @@ import org.slf4j.LoggerFactory;
  * which is dynamically installed and started during the test.
  * </p>
  */
-public class Olingo2ComponentTest extends AbstractOlingo2TestSupport {
+public class Olingo2ComponentProducerTest extends AbstractOlingo2TestSupport {
 
-    private static final Logger LOG = LoggerFactory.getLogger(Olingo2ComponentTest.class);
-    private static final int PORT = AvailablePortFinder.getNextAvailable();  
+    private static final Logger LOG = LoggerFactory.getLogger(Olingo2ComponentProducerTest.class);
+    private static final int PORT = AvailablePortFinder.getNextAvailable();
     private static final String ID_PROPERTY = "Id";
     private static final String MANUFACTURERS = "Manufacturers";
     private static final String TEST_MANUFACTURER = "Manufacturers('1')";
@@ -66,7 +66,7 @@ public class Olingo2ComponentTest extends AbstractOlingo2TestSupport {
 
     private static Olingo2SampleServer server;
 
-    public Olingo2ComponentTest() {
+    public Olingo2ComponentProducerTest() {
         setDefaultTestProperty("serviceUri", "http://localhost:" + PORT + "/MyFormula.svc");
     }
 
@@ -248,89 +248,10 @@ public class Olingo2ComponentTest extends AbstractOlingo2TestSupport {
     }
 
     /**
-     * Read entity set of the People object
-     * and filter already seen items on subsequent exchanges
-     * Use a delay since the mock endpoint does not always get
-     * the correct number of exchanges before being satisfied.
      *
-     * Note:
-     * - consumer.splitResults is set to false since this ensures the first returned message
-     *   contains all the results. This is preferred for the purposes of this test. The default
-     *   will mean the first n messages contain the results (where n is the result total) then
-     *   subsequent messages will be empty
-     */
-    @Test
-    public void testConsumerReadFilterAlreadySeen() throws Exception {
-        final Map<String, Object> headers = new HashMap<>();
-        String endpoint = "olingo2://read/Manufacturers?filterAlreadySeen=true&consumer.delay=2&consumer.sendEmptyMessageWhenIdle=true&consumer.splitResult=false";
-
-        int expectedMsgCount = 3;
-        MockEndpoint mockEndpoint = getMockEndpoint("mock:consumer-alreadyseen");
-        mockEndpoint.expectedMessageCount(expectedMsgCount);
-        mockEndpoint.setResultWaitTime(60000);
-
-        final ODataFeed manufacturers = (ODataFeed)requestBodyAndHeaders(endpoint, null, headers);
-        assertNotNull(manufacturers);
-        int expectedManufacturers = manufacturers.getEntries().size();
-
-        mockEndpoint.assertIsSatisfied();
-
-        for (int i = 0; i < expectedMsgCount; ++i) {
-            Object body = mockEndpoint.getExchanges().get(i).getIn().getBody();
-
-            if (i == 0) {
-                //
-                // First polled messages contained all the manufacturers
-                //
-                assertTrue(body instanceof ODataFeed);
-                ODataFeed set = (ODataFeed) body;
-                assertEquals(expectedManufacturers, set.getEntries().size());
-            } else {
-                //
-                // Subsequent polling messages should be empty
-                // since the filterAlreadySeen property is true
-                //
-                assertNull(body);
-            }
-        }
-    }
-
-    /**
-     * Read value of the People object and split the results
-     * into individual messages
-     */
-    @Test
-    public void testConsumerReadClientValuesSplitResults() throws Exception {
-        final Map<String, Object> headers = new HashMap<>();
-        String endpoint = "olingo2://read/Manufacturers('1')/Address?consumer.splitResult=true";
-
-        this.context.setTracing(true);
-        MockEndpoint mockEndpoint = getMockEndpoint("mock:consumer-value");
-        mockEndpoint.expectedMinimumMessageCount(1);
-        mockEndpoint.setResultWaitTime(60000);
-
-        final Map<String, Object> resultValue = requestBodyAndHeaders(endpoint, null, headers);
-        assertNotNull(resultValue);
-
-        mockEndpoint.assertIsSatisfied();
-        //
-        // 1 individual message in the exchange
-        //
-        Object body = mockEndpoint.getExchanges().get(0).getIn().getBody();
-        assertIsInstanceOf(Map.class, body);
-        Map<String, Object> value = (Map<String, Object>) body;
-        Object addrObj = value.get("Address");
-        assertIsInstanceOf(Map.class, addrObj);
-        Map<String, Object> addrMap = (Map<String, Object>) addrObj;
-        assertEquals("70173", addrMap.get("ZipCode"));
-        assertEquals("Star Street 137", addrMap.get("Street"));
-        assertEquals("Germany", addrMap.get("Country"));
-        assertEquals("Stuttgart", addrMap.get("City"));
-    }
-
-    /**
-     * Read entity set of the People object and with no filter already seen, all
-     * items should be present in each message
+     * Read entity set of the People object
+     * and with no filter already seen, all items
+     * should be present in each message
      *
      * @throws Exception
      */
@@ -410,49 +331,6 @@ public class Olingo2ComponentTest extends AbstractOlingo2TestSupport {
         }
     }
 
-    /**
-     * Read entity set of the Manufacturers object and split the results
-     * into individual messages
-     */
-    @Test
-    public void testConsumerReadSplitResults() throws Exception {
-        final Map<String, Object> headers = new HashMap<>();
-        String endpoint = "olingo2://read/Manufacturers?consumer.splitResult=true";
-
-        int expectedMsgCount = 2;
-        MockEndpoint mockEndpoint = getMockEndpoint("mock:consumer-splitresult");
-        mockEndpoint.expectedMessageCount(expectedMsgCount);
-
-        final ODataFeed odataFeed = (ODataFeed)requestBodyAndHeaders(endpoint, null, headers);
-        assertNotNull(odataFeed);
-
-        mockEndpoint.assertIsSatisfied();
-
-        //
-        // 2 individual messages in the exchange,
-        // each containing a different entity.
-        //
-        for (int i = 0; i < expectedMsgCount; ++i) {
-            Object body = mockEndpoint.getExchanges().get(i).getIn().getBody();
-            assertTrue(body instanceof ODataEntry);
-            ODataEntry entry = (ODataEntry)body;
-            Map<String, Object> properties = entry.getProperties();
-            assertNotNull(properties);
-
-            Object name = properties.get("Name");
-            assertNotNull(name);
-            switch(i) {
-            case 0:
-                assertEquals("Star Powered Racing", name);
-                break;
-            case 1:
-                assertEquals("Horse Powered Racing", name);
-                break;
-            default:
-            }
-        }
-    }
-
     @Override
     protected RouteBuilder createRouteBuilder() throws Exception {
         return new RouteBuilder() {
@@ -500,18 +378,6 @@ public class Olingo2ComponentTest extends AbstractOlingo2TestSupport {
                 from("direct:read-people-filterseen")
                     .to("olingo2://read/Manufacturers?filterAlreadySeen=true")
                     .to("mock:producer-alreadyseen");
-
-                //
-                // Consumer endpoint
-                //
-                from("olingo2://read/Manufacturers?filterAlreadySeen=true&consumer.delay=2&consumer.sendEmptyMessageWhenIdle=true&consumer.splitResult=false")
-                    .to("mock:consumer-alreadyseen");
-
-                from("olingo2://read/Manufacturers?consumer.splitResult=true")
-                    .to("mock:consumer-splitresult");
-
-                from("olingo2://read/Manufacturers('1')/Address?consumer.splitResult=true")
-                    .to("mock:consumer-value");
             }
         };
     }
diff --git a/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4Index.java b/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4Index.java
index c00adbb..d4db500 100644
--- a/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4Index.java
+++ b/components/camel-olingo4/camel-olingo4-component/src/main/java/org/apache/camel/component/olingo4/Olingo4Index.java
@@ -23,24 +23,33 @@ import java.util.List;
 import java.util.Set;
 import org.apache.olingo.client.api.domain.ClientEntity;
 import org.apache.olingo.client.api.domain.ClientEntitySet;
+import org.apache.olingo.client.core.domain.ClientEntitySetImpl;
 
 public class Olingo4Index {
 
     private Set<Integer> resultIndex = new HashSet<>();
 
     private Object filter(Object o) {
-        if (resultIndex.contains(o.hashCode())) {
+        if (o == null || resultIndex.contains(o.hashCode())) {
             return null;
         }
         return o;
     }
 
     private void indexDefault(Object o) {
+        if (o == null) {
+            return;
+        }
+
         resultIndex.add(o.hashCode());
     }
 
     private Iterable<?> filter(Iterable<?> iterable) {
         List<Object> filtered = new ArrayList<>();
+        if (iterable == null) {
+            return filtered;
+        }
+
         for (Object o : iterable) {
             if (resultIndex.contains(o.hashCode())) {
                 continue;
@@ -52,12 +61,20 @@ public class Olingo4Index {
     }
 
     private void index(Iterable<?> iterable) {
+        if (iterable == null) {
+            return;
+        }
+
         for (Object o : iterable) {
             resultIndex.add(o.hashCode());
         }
     }
 
     private ClientEntitySet filter(ClientEntitySet entitySet) {
+        if (entitySet == null) {
+            return new ClientEntitySetImpl();
+        }
+
         List<ClientEntity> entities = entitySet.getEntities();
 
         if (entities.isEmpty()) {
@@ -77,6 +94,10 @@ public class Olingo4Index {
     }
 
     private void index(ClientEntitySet entitySet) {
+        if (entitySet == null) {
+            return;
+        }
+
         for (ClientEntity entity : entitySet.getEntities()) {
             resultIndex.add(entity.hashCode());
         }
diff --git a/components/camel-olingo4/camel-olingo4-component/src/test/java/org/apache/camel/component/olingo4/Olingo4ComponentConsumerTest.java b/components/camel-olingo4/camel-olingo4-component/src/test/java/org/apache/camel/component/olingo4/Olingo4ComponentConsumerTest.java
new file mode 100644
index 0000000..ebf1b0f
--- /dev/null
+++ b/components/camel-olingo4/camel-olingo4-component/src/test/java/org/apache/camel/component/olingo4/Olingo4ComponentConsumerTest.java
@@ -0,0 +1,211 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.olingo4;
+
+import java.util.Iterator;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.olingo.client.api.domain.ClientCollectionValue;
+import org.apache.olingo.client.api.domain.ClientComplexValue;
+import org.apache.olingo.client.api.domain.ClientEntity;
+import org.apache.olingo.client.api.domain.ClientEntitySet;
+import org.apache.olingo.client.api.domain.ClientPrimitiveValue;
+import org.apache.olingo.client.api.domain.ClientProperty;
+import org.junit.Test;
+
+public class Olingo4ComponentConsumerTest extends AbstractOlingo4TestSupport {
+
+    private static final String PEOPLE = "People";
+    private static final String TEST_PEOPLE = "People('russellwhyte')";
+    private static final String AIRPORTS = "Airports";
+
+    public Olingo4ComponentConsumerTest() {
+        setUseRouteBuilder(false);
+    }
+
+    @Override
+    public boolean isCreateCamelContextPerClass() {
+        return false;
+    }
+
+    private void addRouteAndStartContext(RouteBuilder builder) throws Exception {
+        context().addRoutes(builder);
+        startCamelContext();
+    }
+
+    /**
+     * Read entity set of the People object
+     * and filter already seen items on subsequent exchanges
+     * Use a delay since the mock endpoint does not always get
+     * the correct number of exchanges before being satisfied.
+     *
+     * Note:
+     * - consumer.splitResults is set to false since this ensures the first returned message
+     *   contains all the results. This is preferred for the purposes of this test. The default
+     *   will mean the first n messages contain the results (where n is the result total) then
+     *   subsequent messages will be empty
+     */
+    @Test
+    public void testConsumerReadFilterAlreadySeen() throws Exception {
+        int expectedEntities = 20;
+        int expectedMsgCount = 3;
+        MockEndpoint mockEndpoint = getMockEndpoint("mock:consumer-alreadyseen");
+        mockEndpoint.expectedMinimumMessageCount(expectedMsgCount);
+
+        RouteBuilder builder = new RouteBuilder() {
+            public void configure() {
+                from("olingo4://read/" + PEOPLE + "?consumer.delay=2&consumer.sendEmptyMessageWhenIdle=true&consumer.splitResult=false&filterAlreadySeen=true")
+                    .to("mock:consumer-alreadyseen");
+            };
+        };
+        addRouteAndStartContext(builder);
+
+        mockEndpoint.assertIsSatisfied();
+
+        for (int i = 0; i < expectedMsgCount; ++i) {
+            Object body = mockEndpoint.getExchanges().get(i).getIn().getBody();
+
+            if (i == 0) {
+                //
+                // First polled messages contained all the entities
+                //
+                assertTrue(body instanceof ClientEntitySet);
+                ClientEntitySet set = (ClientEntitySet) body;
+                assertEquals(expectedEntities, set.getEntities().size());
+            } else {
+                //
+                // Subsequent polling messages should be empty
+                // since the filterAlreadySeen property is true
+                //
+                assertNull(body);
+            }
+        }
+    }
+
+    @Test
+    public void testConsumerReadFilterAlreadySeenWithPredicateAndSplitResults() throws Exception {
+        int expectedMsgCount = 3;
+        MockEndpoint mockEndpoint = getMockEndpoint("mock:consumer-splitresult-kp-airport");
+        mockEndpoint.expectedMinimumMessageCount(expectedMsgCount);
+
+        RouteBuilder builder = new RouteBuilder() {
+            public void configure() {
+                from("olingo4://read/" + AIRPORTS + "('KSFO')"
+                        + "?filterAlreadySeen=true&"
+                        + "consumer.delay=2&consumer.sendEmptyMessageWhenIdle=true&"
+                        + "consumer.splitResult=true")
+                    .to("mock:consumer-splitresult-kp-airport");
+            };
+        };
+        addRouteAndStartContext(builder);
+
+        mockEndpoint.assertIsSatisfied();
+
+        for (int i = 0; i < expectedMsgCount; ++i) {
+            Object body = mockEndpoint.getExchanges().get(i).getIn().getBody();
+
+            if (i == 0) {
+                //
+                // First polled messages contained all the entities
+                //
+                assertTrue(body instanceof ClientEntity);
+                ClientEntity ksfoEntity = (ClientEntity) body;
+                ClientProperty nameProp = ksfoEntity.getProperty("Name");
+                assertNotNull(nameProp);
+                assertEquals("San Francisco International Airport", nameProp.getValue().toString());
+            } else {
+                //
+                // Subsequent polling messages should be empty
+                // since the filterAlreadySeen property is true
+                //
+                assertNull(body);
+            }
+        }
+    }
+
+    /**
+     * Read entity set of the People object and split the results
+     * into individual messages
+     */
+    @Test
+    public void testConsumerReadSplitResults() throws Exception {
+        int expectedMsgCount = 3;
+        MockEndpoint mockEndpoint = getMockEndpoint("mock:consumer-splitresult");
+        mockEndpoint.expectedMinimumMessageCount(expectedMsgCount);
+
+        RouteBuilder builder = new RouteBuilder() {
+            public void configure() {
+                from("olingo4://read/" + PEOPLE + "?consumer.splitResult=true")
+                    .to("mock:consumer-splitresult");
+            };
+        };
+        addRouteAndStartContext(builder);
+
+        mockEndpoint.assertIsSatisfied();
+        //
+        // At least 3 individual messages in the exchange,
+        // each containing a different entity.
+        //
+        for (int i = 0; i < expectedMsgCount; ++i) {
+            Object body = mockEndpoint.getExchanges().get(i).getIn().getBody();
+            assertTrue(body instanceof ClientEntity);
+            ClientEntity entity = (ClientEntity)body;
+            ClientProperty nameProperty = entity.getProperty("UserName");
+            assertNotNull(nameProperty);
+
+            switch(i) {
+            case 0:
+                assertEquals("russellwhyte", nameProperty.getValue().toString());
+                break;
+            case 1:
+                assertEquals("scottketchum", nameProperty.getValue().toString());
+                break;
+            case 2:
+                assertEquals("ronaldmundy", nameProperty.getValue().toString());
+                break;
+            default:
+            }
+        }
+    }
+
+    /**
+     * Read value of the People object and split the results
+     * into individual messages
+     */
+    @Test
+    public void testConsumerReadClientValuesSplitResults() throws Exception {
+        MockEndpoint mockEndpoint = getMockEndpoint("mock:consumer-splitresult-value");
+        mockEndpoint.expectedMinimumMessageCount(1);
+
+        RouteBuilder builder = new RouteBuilder() {
+            public void configure() {
+                from("olingo4://read/" + TEST_PEOPLE + "/FavoriteFeature?consumer.splitResult=true")
+                    .to("mock:consumer-splitresult-value");
+            };
+        };
+        addRouteAndStartContext(builder);
+
+        mockEndpoint.assertIsSatisfied();
+        //
+        // 1 individual message in the exchange
+        //
+        Object body = mockEndpoint.getExchanges().get(0).getIn().getBody();
+        assertIsInstanceOf(ClientPrimitiveValue.class, body);
+        ClientPrimitiveValue value = (ClientPrimitiveValue) body;
+        assertEquals("Feature1", value.toString());
+    }
+}
diff --git a/components/camel-olingo4/camel-olingo4-component/src/test/java/org/apache/camel/component/olingo4/Olingo4ComponentTest.java b/components/camel-olingo4/camel-olingo4-component/src/test/java/org/apache/camel/component/olingo4/Olingo4ComponentProducerTest.java
similarity index 78%
rename from components/camel-olingo4/camel-olingo4-component/src/test/java/org/apache/camel/component/olingo4/Olingo4ComponentTest.java
rename to components/camel-olingo4/camel-olingo4-component/src/test/java/org/apache/camel/component/olingo4/Olingo4ComponentProducerTest.java
index c7d0125..e28bbb3 100644
--- a/components/camel-olingo4/camel-olingo4-component/src/test/java/org/apache/camel/component/olingo4/Olingo4ComponentTest.java
+++ b/components/camel-olingo4/camel-olingo4-component/src/test/java/org/apache/camel/component/olingo4/Olingo4ComponentProducerTest.java
@@ -32,7 +32,6 @@ import org.apache.olingo.client.api.domain.ClientComplexValue;
 import org.apache.olingo.client.api.domain.ClientEntity;
 import org.apache.olingo.client.api.domain.ClientEntitySet;
 import org.apache.olingo.client.api.domain.ClientPrimitiveValue;
-import org.apache.olingo.client.api.domain.ClientProperty;
 import org.apache.olingo.client.api.domain.ClientServiceDocument;
 import org.apache.olingo.client.api.domain.ClientValue;
 import org.apache.olingo.commons.api.Constants;
@@ -52,9 +51,9 @@ import org.slf4j.LoggerFactory;
  * service published on http://services.odata.org/TripPinRESTierService.
  * </p>
  */
-public class Olingo4ComponentTest extends AbstractOlingo4TestSupport {
+public class Olingo4ComponentProducerTest extends AbstractOlingo4TestSupport {
 
-    private static final Logger LOG = LoggerFactory.getLogger(Olingo4ComponentTest.class);
+    private static final Logger LOG = LoggerFactory.getLogger(Olingo4ComponentProducerTest.class);
 
     private static final String PEOPLE = "People";
     private static final String TEST_PEOPLE = "People('russellwhyte')";
@@ -299,53 +298,6 @@ public class Olingo4ComponentTest extends AbstractOlingo4TestSupport {
     }
 
     /**
-     * Read entity set of the People object
-     * and filter already seen items on subsequent exchanges
-     * Use a delay since the mock endpoint does not always get
-     * the correct number of exchanges before being satisfied.
-     *
-     * Note:
-     * - consumer.splitResults is set to false since this ensures the first returned message
-     *   contains all the results. This is preferred for the purposes of this test. The default
-     *   will mean the first n messages contain the results (where n is the result total) then
-     *   subsequent messages will be empty
-     */
-    @Test
-    public void testConsumerReadFilterAlreadySeen() throws Exception {
-        final Map<String, Object> headers = new HashMap<>();
-        String endpoint = "olingo4://read/People?filterAlreadySeen=true&consumer.delay=2&consumer.sendEmptyMessageWhenIdle=true&consumer.splitResult=false";
-        int expectedEntities = 20;
-        int expectedMsgCount = 3;
-        MockEndpoint mockEndpoint = getMockEndpoint("mock:consumer-alreadyseen");
-        mockEndpoint.expectedMessageCount(expectedMsgCount);
-
-        final ClientEntitySet entities = (ClientEntitySet)requestBodyAndHeaders(endpoint, null, headers);
-        assertNotNull(entities);
-        assertEquals(expectedEntities, entities.getEntities().size());
-
-        mockEndpoint.assertIsSatisfied();
-
-        for (int i = 0; i < expectedMsgCount; ++i) {
-            Object body = mockEndpoint.getExchanges().get(i).getIn().getBody();
-
-            if (i == 0) {
-                //
-                // First polled messages contained all the entities
-                //
-                assertTrue(body instanceof ClientEntitySet);
-                ClientEntitySet set = (ClientEntitySet) body;
-                assertEquals(expectedEntities, set.getEntities().size());
-            } else {
-                //
-                // Subsequent polling messages should be empty
-                // since the filterAlreadySeen property is true
-                //
-                assertNull(body);
-            }
-        }
-    }
-
-    /**
      *
      * Read entity set of the People object
      * and with no filter already seen, all items
@@ -423,75 +375,6 @@ public class Olingo4ComponentTest extends AbstractOlingo4TestSupport {
         }
     }
 
-    /**
-     * Read entity set of the People object and split the results
-     * into individual messages
-     */
-    @Test
-    public void testConsumerReadSplitResults() throws Exception {
-        final Map<String, Object> headers = new HashMap<>();
-        String endpoint = "olingo4://read/People?consumer.splitResult=true";
-        int expectedEntities = 20;
-
-        int expectedMsgCount = 3;
-        MockEndpoint mockEndpoint = getMockEndpoint("mock:consumer-splitresult");
-        mockEndpoint.expectedMinimumMessageCount(expectedMsgCount);
-
-        final ClientEntitySet entities = (ClientEntitySet)requestBodyAndHeaders(endpoint, null, headers);
-        assertNotNull(entities);
-        assertEquals(expectedEntities, entities.getEntities().size());
-
-        mockEndpoint.assertIsSatisfied();
-        //
-        // At least 3 individual messages in the exchange,
-        // each containing a different entity.
-        //
-        for (int i = 0; i < expectedMsgCount; ++i) {
-            Object body = mockEndpoint.getExchanges().get(i).getIn().getBody();
-            assertTrue(body instanceof ClientEntity);
-            ClientEntity entity = (ClientEntity)body;
-            ClientProperty nameProperty = entity.getProperty("UserName");
-            assertNotNull(nameProperty);
-
-            switch(i) {
-            case 0:
-                assertEquals("russellwhyte", nameProperty.getValue().toString());
-                break;
-            case 1:
-                assertEquals("scottketchum", nameProperty.getValue().toString());
-                break;
-            case 2:
-                assertEquals("ronaldmundy", nameProperty.getValue().toString());
-                break;
-            default:
-            }
-        }
-    }
-    /**
-     * Read value of the People object and split the results
-     * into individual messages
-     */
-    @Test
-    public void testConsumerReadClientValuesSplitResults() throws Exception {
-        final Map<String, Object> headers = new HashMap<>();
-        String endpoint = "olingo4://read/People('russellwhyte')/FavoriteFeature?consumer.splitResult=true";
-
-        MockEndpoint mockEndpoint = getMockEndpoint("mock:consumer-splitresult-value");
-        mockEndpoint.expectedMinimumMessageCount(1);
-
-        final ClientValue resultValue = requestBodyAndHeaders(endpoint, null, headers);
-        assertIsInstanceOf(ClientValue.class, resultValue);
-
-        mockEndpoint.assertIsSatisfied();
-        //
-        // 1 individual message in the exchange
-        //
-        Object body = mockEndpoint.getExchanges().get(0).getIn().getBody();
-        assertIsInstanceOf(ClientPrimitiveValue.class, body);
-        ClientPrimitiveValue value = (ClientPrimitiveValue) body;
-        assertEquals("Feature1", value.toString());
-    }
-
     @Override
     protected RouteBuilder createRouteBuilder() throws Exception {
         return new RouteBuilder() {
@@ -543,19 +426,6 @@ public class Olingo4ComponentTest extends AbstractOlingo4TestSupport {
                 from("direct:read-people-filterseen")
                     .to("olingo4://read/People?filterAlreadySeen=true")
                     .to("mock:producer-alreadyseen");
-
-                //
-                // Consumer endpoint
-                //
-                from("olingo4://read/People?filterAlreadySeen=true&consumer.delay=2&consumer.sendEmptyMessageWhenIdle=true&consumer.splitResult=false")
-                    .to("mock:consumer-alreadyseen");
-
-                from("olingo4://read/People?consumer.splitResult=true")
-                    .to("mock:consumer-splitresult");
-
-                from("olingo4://read/People('russellwhyte')/FavoriteFeature?consumer.splitResult=true")
-                    .to("mock:consumer-splitresult-value");
-
             }
         };
     }