From commits-return-73179-archive-asf-public=cust-asf.ponee.io@camel.apache.org Thu Jun 6 07:15:42 2019 Return-Path: X-Original-To: archive-asf-public@cust-asf.ponee.io Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [207.244.88.153]) by mx-eu-01.ponee.io (Postfix) with SMTP id B21B4180763 for ; Thu, 6 Jun 2019 09:15:41 +0200 (CEST) Received: (qmail 4800 invoked by uid 500); 6 Jun 2019 07:15:41 -0000 Mailing-List: contact commits-help@camel.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@camel.apache.org Delivered-To: mailing list commits@camel.apache.org Received: (qmail 4713 invoked by uid 99); 6 Jun 2019 07:15:41 -0000 Received: from ec2-52-202-80-70.compute-1.amazonaws.com (HELO gitbox.apache.org) (52.202.80.70) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 06 Jun 2019 07:15:41 +0000 Received: by gitbox.apache.org (ASF Mail Server at gitbox.apache.org, from userid 33) id F16B78ABA6; Thu, 6 Jun 2019 07:15:40 +0000 (UTC) Date: Thu, 06 Jun 2019 07:15:42 +0000 To: "commits@camel.apache.org" Subject: [camel] 03/03: fix(13606): Stop Olingo Index Classes generating NP Exceptions MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit From: acosentino@apache.org In-Reply-To: <155980533889.27725.12890083077900849589@gitbox.apache.org> References: <155980533889.27725.12890083077900849589@gitbox.apache.org> X-Git-Host: gitbox.apache.org X-Git-Repo: camel X-Git-Refname: refs/heads/camel-2.24.x X-Git-Reftype: branch X-Git-Rev: a3794d195aa7bb707f404fbcd4005429eaf73f54 X-Git-NotificationType: diff X-Git-Multimail-Version: 1.5.dev Auto-Submitted: auto-generated Message-Id: <20190606071540.F16B78ABA6@gitbox.apache.org> 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 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 resultIndex = new HashSet<>(); + private class EmptyODataFeed implements ODataFeed { + + @Override + public List 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 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 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. + *

+ * The integration test runs against Apache Olingo 2.0 sample server + * which is dynamically installed and started during the test. + *

+ */ +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 value = (Map) body; + Object addrObj = value.get("Address"); + assertIsInstanceOf(Map.class, addrObj); + Map addrMap = (Map) 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 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. *

*/ -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 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 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 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 value = (Map) body; - Object addrObj = value.get("Address"); - assertIsInstanceOf(Map.class, addrObj); - Map addrMap = (Map) 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 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 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 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 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 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. *

*/ -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 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 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 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"); - } }; }