CAMEL-9038: Make the existing tests of camle-olingo2 automatically executable
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/e3190cf1 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/e3190cf1 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/e3190cf1 Branch: refs/heads/camel-2.15.x Commit: e3190cf101411124df956cf8fb8d764348d1091d Parents: 65bbda6 Author: Akitoshi Yoshida <a...@apache.org> Authored: Thu Jul 30 15:17:27 2015 +0200 Committer: Aki Yoshida <elak...@gmail.com> Committed: Fri Jul 31 18:28:11 2015 +0200 ---------------------------------------------------------------------- .../olingo2/api/Olingo2AppIntegrationTest.java | 615 ------------------- .../camel-olingo2-component/pom.xml | 123 ++++ .../olingo2/AbstractOlingo2TestSupport.java | 6 +- .../component/olingo2/Olingo2AppAPITest.java | 596 ++++++++++++++++++ .../olingo2/Olingo2AppIntegrationTest.java | 269 -------- .../component/olingo2/Olingo2ComponentTest.java | 295 +++++++++ .../component/olingo2/Olingo2SampleServer.java | 89 +++ .../test/resources/olingo2_ref/WEB-INF/web.xml | 45 ++ .../src/test/resources/test-options.properties | 2 +- 9 files changed, 1154 insertions(+), 886 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/e3190cf1/components/camel-olingo2/camel-olingo2-api/src/test/java/org/apache/camel/component/olingo2/api/Olingo2AppIntegrationTest.java ---------------------------------------------------------------------- diff --git a/components/camel-olingo2/camel-olingo2-api/src/test/java/org/apache/camel/component/olingo2/api/Olingo2AppIntegrationTest.java b/components/camel-olingo2/camel-olingo2-api/src/test/java/org/apache/camel/component/olingo2/api/Olingo2AppIntegrationTest.java deleted file mode 100644 index 9c361ef..0000000 --- a/components/camel-olingo2/camel-olingo2-api/src/test/java/org/apache/camel/component/olingo2/api/Olingo2AppIntegrationTest.java +++ /dev/null @@ -1,615 +0,0 @@ -/** - * 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.api; - -import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.regex.Pattern; - -import org.apache.camel.component.olingo2.api.batch.Olingo2BatchChangeRequest; -import org.apache.camel.component.olingo2.api.batch.Olingo2BatchQueryRequest; -import org.apache.camel.component.olingo2.api.batch.Olingo2BatchRequest; -import org.apache.camel.component.olingo2.api.batch.Olingo2BatchResponse; -import org.apache.camel.component.olingo2.api.batch.Operation; -import org.apache.camel.component.olingo2.api.impl.AbstractFutureCallback; -import org.apache.camel.component.olingo2.api.impl.Olingo2AppImpl; -import org.apache.camel.component.olingo2.api.impl.SystemQueryOption; -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.concurrent.FutureCallback; -import org.apache.http.entity.ByteArrayEntity; -import org.apache.http.entity.ContentType; -import org.apache.olingo.odata2.api.commons.HttpStatusCodes; -import org.apache.olingo.odata2.api.edm.Edm; -import org.apache.olingo.odata2.api.edm.EdmEntitySetInfo; -import org.apache.olingo.odata2.api.ep.entry.ODataEntry; -import org.apache.olingo.odata2.api.ep.feed.ODataDeltaFeed; -import org.apache.olingo.odata2.api.ep.feed.ODataFeed; -import org.apache.olingo.odata2.api.exception.ODataApplicationException; -import org.apache.olingo.odata2.api.servicedocument.Collection; -import org.apache.olingo.odata2.api.servicedocument.ServiceDocument; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -/** - * Integration test for {@link org.apache.camel.component.olingo2.api.impl.Olingo2AppImpl}. - * To test run the sample Olingo2 Server as outlined at - * http://olingo.apache.org/doc/tutorials/Olingo2V2BasicClientSample.html - */ -public class Olingo2AppIntegrationTest { - - private static final Logger LOG = LoggerFactory.getLogger(Olingo2AppIntegrationTest.class); - private static final long TIMEOUT = 10; - - private static final String MANUFACTURERS = "Manufacturers"; - private static final String FQN_MANUFACTURERS = "DefaultContainer.Manufacturers"; - private static final String ADDRESS = "Address"; - private static final String CARS = "Cars"; - - private static final String TEST_KEY = "'1'"; - private static final String TEST_CREATE_KEY = "'123'"; - private static final String TEST_MANUFACTURER = FQN_MANUFACTURERS + "(" + TEST_KEY + ")"; - private static final String TEST_CREATE_MANUFACTURER = MANUFACTURERS + "(" + TEST_CREATE_KEY + ")"; - - private static final String TEST_RESOURCE_CONTENT_ID = "1"; - private static final String TEST_RESOURCE = "$" + TEST_RESOURCE_CONTENT_ID; - - private static final char NEW_LINE = '\n'; - private static final String TEST_CAR = "Manufacturers('1')/Cars('1')"; - private static final String TEST_MANUFACTURER_FOUNDED_PROPERTY = "Manufacturers('1')/Founded"; - private static final String TEST_MANUFACTURER_FOUNDED_VALUE = "Manufacturers('1')/Founded/$value"; - private static final String FOUNDED_PROPERTY = "Founded"; - private static final String TEST_MANUFACTURER_ADDRESS_PROPERTY = "Manufacturers('1')/Address"; - private static final String TEST_MANUFACTURER_LINKS_CARS = "Manufacturers('1')/$links/Cars"; - private static final String TEST_CAR_LINK_MANUFACTURER = "Cars('1')/$links/Manufacturer"; - private static final String COUNT_OPTION = "/$count"; - - private static final String TEST_SERVICE_URL = "http://localhost:8080/MyFormula.svc"; - // private static final String TEST_SERVICE_URL = "http://localhost:8080/cars-annotations-sample/MyFormula.svc"; -// private static final ContentType TEST_FORMAT = ContentType.APPLICATION_XML_CS_UTF_8; - private static final ContentType TEST_FORMAT = ContentType.APPLICATION_JSON; - private static final String INDEX = "/index.jsp"; - private static final Pattern LINK_PATTERN = Pattern.compile("[^(]+\\('([^']+)'\\)"); - private static final String ID_PROPERTY = "Id"; - - private static Olingo2App olingoApp; - private static final String GEN_SAMPLE_DATA = "genSampleData=true"; - private static Edm edm; - - @BeforeClass - public static void beforeClass() throws Exception { - - olingoApp = new Olingo2AppImpl(TEST_SERVICE_URL + "/"); - olingoApp.setContentType(TEST_FORMAT.toString()); - - LOG.info("Generate sample data "); - generateSampleData(TEST_SERVICE_URL); - - LOG.info("Read Edm "); - final TestOlingo2ResponseHandler<Edm> responseHandler = new TestOlingo2ResponseHandler<Edm>(); - - olingoApp.read(null, Olingo2AppImpl.METADATA, null, responseHandler); - - edm = responseHandler.await(); - LOG.info("Read default EntityContainer: {}", responseHandler.await().getDefaultEntityContainer().getName()); - - // wait for generated data to be registered in server - Thread.sleep(2000); - } - - @AfterClass - public static void afterClass() { - olingoApp.close(); - } - - @Test - public void testServiceDocument() throws Exception { - final TestOlingo2ResponseHandler<ServiceDocument> responseHandler = - new TestOlingo2ResponseHandler<ServiceDocument>(); - - olingoApp.read(null, "", null, responseHandler); - - final ServiceDocument serviceDocument = responseHandler.await(); - final List<Collection> collections = serviceDocument.getAtomInfo().getWorkspaces().get(0).getCollections(); - assertEquals("Service Atom Collections", 3, collections.size()); - LOG.info("Service Atom Collections: {}", collections); - - final List<EdmEntitySetInfo> entitySetsInfo = serviceDocument.getEntitySetsInfo(); - assertEquals("Service Entity Sets", 3, entitySetsInfo.size()); - LOG.info("Service Document Entries: {}", entitySetsInfo); - } - - @Test - public void testReadFeed() throws Exception { - final TestOlingo2ResponseHandler<ODataFeed> responseHandler = new TestOlingo2ResponseHandler<ODataFeed>(); - - olingoApp.read(edm, MANUFACTURERS, null, responseHandler); - - final ODataFeed dataFeed = responseHandler.await(); - assertNotNull("Data feed", dataFeed); - LOG.info("Entries: {}", prettyPrint(dataFeed)); - } - - @Test - public void testReadEntry() throws Exception { - final TestOlingo2ResponseHandler<ODataEntry> responseHandler = new TestOlingo2ResponseHandler<ODataEntry>(); - - olingoApp.read(edm, TEST_MANUFACTURER, null, responseHandler); - ODataEntry entry = responseHandler.await(); - LOG.info("Single Entry: {}", prettyPrint(entry)); - - responseHandler.reset(); - - olingoApp.read(edm, TEST_CAR, null, responseHandler); - entry = responseHandler.await(); - LOG.info("Single Entry: {}", prettyPrint(entry)); - - responseHandler.reset(); - final Map<String, String> queryParams = new HashMap<String, String>(); - queryParams.put(SystemQueryOption.$expand.toString(), CARS); - - olingoApp.read(edm, TEST_MANUFACTURER, queryParams, responseHandler); - - ODataEntry entryExpanded = responseHandler.await(); - LOG.info("Single Entry with expanded Cars relation: {}", prettyPrint(entryExpanded)); - } - - @Test - public void testReadUpdateProperties() throws Exception { - // test simple property Manufacturer.Founded - final TestOlingo2ResponseHandler<Map<String, Object>> propertyHandler = - new TestOlingo2ResponseHandler<Map<String, Object>>(); - - olingoApp.read(edm, TEST_MANUFACTURER_FOUNDED_PROPERTY, null, propertyHandler); - - Calendar founded = (Calendar) propertyHandler.await().get(FOUNDED_PROPERTY); - LOG.info("Founded property {}", founded.toString()); - - final TestOlingo2ResponseHandler<Calendar> valueHandler = new TestOlingo2ResponseHandler<Calendar>(); - - olingoApp.read(edm, TEST_MANUFACTURER_FOUNDED_VALUE, null, valueHandler); - - founded = valueHandler.await(); - LOG.info("Founded property {}", founded.toString()); - - final TestOlingo2ResponseHandler<HttpStatusCodes> statusHandler = - new TestOlingo2ResponseHandler<HttpStatusCodes>(); - final HashMap<String, Object> properties = new HashMap<String, Object>(); - properties.put(FOUNDED_PROPERTY, new Date()); - -// olingoApp.update(edm, TEST_MANUFACTURER_FOUNDED_PROPERTY, properties, statusHandler); - // requires a plain Date for XML - olingoApp.update(edm, TEST_MANUFACTURER_FOUNDED_PROPERTY, new Date(), statusHandler); - - LOG.info("Founded property updated with status {}", statusHandler.await().getStatusCode()); - - statusHandler.reset(); - - olingoApp.update(edm, TEST_MANUFACTURER_FOUNDED_VALUE, new Date(), statusHandler); - - LOG.info("Founded property updated with status {}", statusHandler.await().getStatusCode()); - - // test complex property Manufacturer.Address - propertyHandler.reset(); - - olingoApp.read(edm, TEST_MANUFACTURER_ADDRESS_PROPERTY, null, propertyHandler); - - final Map<String, Object> address = propertyHandler.await(); - LOG.info("Address property {}", prettyPrint(address, 0)); - - statusHandler.reset(); - - address.clear(); - // Olingo2 sample server MERGE/PATCH behaves like PUT!!! -// address.put("Street", "Main Street"); - address.put("Street", "Star Street 137"); - address.put("City", "Stuttgart"); - address.put("ZipCode", "70173"); - address.put("Country", "Germany"); - -// olingoApp.patch(edm, TEST_MANUFACTURER_ADDRESS_PROPERTY, address, statusHandler); - olingoApp.merge(edm, TEST_MANUFACTURER_ADDRESS_PROPERTY, address, statusHandler); - - LOG.info("Address property updated with status {}", statusHandler.await().getStatusCode()); - } - - @Test - public void testReadDeleteCreateLinks() throws Exception { - final TestOlingo2ResponseHandler<List<String>> linksHandler = new TestOlingo2ResponseHandler<List<String>>(); - - olingoApp.read(edm, TEST_MANUFACTURER_LINKS_CARS, null, linksHandler); - - final List<String> links = linksHandler.await(); - assertFalse(links.isEmpty()); - LOG.info("Read links: {}", links); - - final TestOlingo2ResponseHandler<String> linkHandler = new TestOlingo2ResponseHandler<String>(); - - olingoApp.read(edm, TEST_CAR_LINK_MANUFACTURER, null, linkHandler); - - final String link = linkHandler.await(); - LOG.info("Read link: {}", link); - -//Deleting relationships through links is not supported in Olingo2 at the time of writing this test -/* - final TestOlingo2ResponseHandler<HttpStatusCodes> statusHandler = - new TestOlingo2ResponseHandler<HttpStatusCodes>(); - - final ArrayList<Map<String, Object>> carKeys = new ArrayList<Map<String, Object>>(); - for (String carLink : links) { - final Matcher matcher = LINK_PATTERN.matcher(carLink); - assertTrue("Link pattern " + carLink, matcher.matches()); - final String carId = matcher.group(1); - - final HashMap<String, Object> keys = new HashMap<String, Object>(); - keys.put(ID_PROPERTY, carId); - carKeys.add(keys); - - // delete manufacturer->car link - statusHandler.reset(); - final String resourcePath = TEST_MANUFACTURER_LINKS_CARS + "('" + carId + "')"; - olingoApp.delete(resourcePath, statusHandler); - - assertEquals("Delete car link " + resourcePath, HttpStatusCodes.OK.getStatusCode(), - statusHandler.await().getStatusCode()); - } - - // add links to all Cars - statusHandler.reset(); - olingoApp.create(edm, TEST_MANUFACTURER_LINKS_CARS, carKeys, statusHandler); - - assertEquals("Links update", HttpStatusCodes.ACCEPTED.getStatusCode(), statusHandler.await().getStatusCode()); - - // delete car->manufacturer link - statusHandler.reset(); - olingoApp.delete(TEST_CAR_LINK_MANUFACTURER, statusHandler); - - assertEquals("Delete manufacturer link " + TEST_CAR_LINK_MANUFACTURER, HttpStatusCodes.OK.getStatusCode(), - statusHandler.await().getStatusCode()); - - // add link to Manufacturer - statusHandler.reset(); - final HashMap<String, Object> manufacturerKey = new HashMap<String, Object>(); - manufacturerKey.put(ID_PROPERTY, "1"); - - olingoApp.create(edm, TEST_CAR_LINK_MANUFACTURER, manufacturerKey, statusHandler); - - assertEquals("Link update", HttpStatusCodes.ACCEPTED.getStatusCode(), statusHandler.await().getStatusCode()); -*/ - } - - @Test - public void testReadCount() throws Exception { - final TestOlingo2ResponseHandler<Long> countHandler = new TestOlingo2ResponseHandler<Long>(); - - olingoApp.read(edm, MANUFACTURERS + COUNT_OPTION, null, countHandler); - - LOG.info("Manufacturers count: {}", countHandler.await()); - - countHandler.reset(); - olingoApp.read(edm, TEST_MANUFACTURER + COUNT_OPTION, null, countHandler); - - LOG.info("Manufacturer count: {}", countHandler.await()); - - countHandler.reset(); - olingoApp.read(edm, TEST_MANUFACTURER_LINKS_CARS + COUNT_OPTION, null, countHandler); - - LOG.info("Manufacturers links count: {}", countHandler.await()); - - countHandler.reset(); - olingoApp.read(edm, TEST_CAR_LINK_MANUFACTURER + COUNT_OPTION, null, countHandler); - - LOG.info("Manufacturer link count: {}", countHandler.await()); - } - - @Test - public void testCreateUpdateDeleteEntry() throws Exception { - - // create entry to update - final TestOlingo2ResponseHandler<ODataEntry> entryHandler = new TestOlingo2ResponseHandler<ODataEntry>(); - - olingoApp.create(edm, MANUFACTURERS, getEntityData(), entryHandler); - - ODataEntry createdEntry = entryHandler.await(); - LOG.info("Created Entry: {}", prettyPrint(createdEntry)); - - Map<String, Object> data = getEntityData(); - @SuppressWarnings("unchecked") - Map<String, Object> address = (Map<String, Object>) data.get(ADDRESS); - - data.put("Name", "MyCarManufacturer Renamed"); - address.put("Street", "Main Street"); - final TestOlingo2ResponseHandler<HttpStatusCodes> statusHandler = - new TestOlingo2ResponseHandler<HttpStatusCodes>(); - - olingoApp.update(edm, TEST_CREATE_MANUFACTURER, data, statusHandler); - statusHandler.await(); - - statusHandler.reset(); - data.put("Name", "MyCarManufacturer Patched"); - olingoApp.patch(edm, TEST_CREATE_MANUFACTURER, data, statusHandler); - statusHandler.await(); - - entryHandler.reset(); - olingoApp.read(edm, TEST_CREATE_MANUFACTURER, null, entryHandler); - - ODataEntry updatedEntry = entryHandler.await(); - LOG.info("Updated Entry successfully: {}", prettyPrint(updatedEntry)); - - statusHandler.reset(); - olingoApp.delete(TEST_CREATE_MANUFACTURER, statusHandler); - - HttpStatusCodes statusCode = statusHandler.await(); - LOG.info("Deletion of Entry was successful: {}: {}", statusCode.getStatusCode(), statusCode.getInfo()); - - try { - LOG.info("Verify Delete Entry"); - - entryHandler.reset(); - olingoApp.read(edm, TEST_CREATE_MANUFACTURER, null, entryHandler); - - entryHandler.await(); - fail("Entry not deleted!"); - } catch (Exception e) { - LOG.info("Deleted entry not found: {}", e.getMessage()); - } - } - - @Test - public void testBatchRequest() throws Exception { - - final List<Olingo2BatchRequest> batchParts = new ArrayList<Olingo2BatchRequest>(); - - // Edm query - batchParts.add(Olingo2BatchQueryRequest.resourcePath(Olingo2AppImpl.METADATA).build()); - - // feed query - batchParts.add(Olingo2BatchQueryRequest.resourcePath(MANUFACTURERS).build()); - - // read - batchParts.add(Olingo2BatchQueryRequest.resourcePath(TEST_MANUFACTURER).build()); - - // read with expand - final HashMap<String, String> queryParams = new HashMap<String, String>(); - queryParams.put(SystemQueryOption.$expand.toString(), CARS); - batchParts.add(Olingo2BatchQueryRequest.resourcePath(TEST_MANUFACTURER).queryParams(queryParams).build()); - - // create - final Map<String, Object> data = getEntityData(); - batchParts.add(Olingo2BatchChangeRequest.resourcePath(MANUFACTURERS). - contentId(TEST_RESOURCE_CONTENT_ID).operation(Operation.CREATE).body(data).build()); - - // update - final Map<String, Object> updateData = new HashMap<String, Object>(data); - @SuppressWarnings("unchecked") - Map<String, Object> address = (Map<String, Object>) updateData.get(ADDRESS); - updateData.put("Name", "MyCarManufacturer Renamed"); - address.put("Street", "Main Street"); - - batchParts.add(Olingo2BatchChangeRequest.resourcePath(TEST_RESOURCE).operation(Operation.UPDATE) - .body(updateData).build()); - - // delete - batchParts.add(Olingo2BatchChangeRequest.resourcePath(TEST_RESOURCE).operation(Operation.DELETE).build()); - - final TestOlingo2ResponseHandler<List<Olingo2BatchResponse>> responseHandler = - new TestOlingo2ResponseHandler<List<Olingo2BatchResponse>>(); - - // read to verify delete - batchParts.add(Olingo2BatchQueryRequest.resourcePath(TEST_CREATE_MANUFACTURER).build()); - - olingoApp.batch(edm, batchParts, responseHandler); - - final List<Olingo2BatchResponse> responseParts = responseHandler.await(15, TimeUnit.MINUTES); - assertEquals("Batch responses expected", 8, responseParts.size()); - - assertNotNull(responseParts.get(0).getBody()); - final ODataFeed feed = (ODataFeed) responseParts.get(1).getBody(); - assertNotNull(feed); - LOG.info("Batch feed: {}", prettyPrint(feed)); - - ODataEntry dataEntry = (ODataEntry) responseParts.get(2).getBody(); - assertNotNull(dataEntry); - LOG.info("Batch read entry: {}", prettyPrint(dataEntry)); - - dataEntry = (ODataEntry) responseParts.get(3).getBody(); - assertNotNull(dataEntry); - LOG.info("Batch read entry with expand: {}", prettyPrint(dataEntry)); - - dataEntry = (ODataEntry) responseParts.get(4).getBody(); - assertNotNull(dataEntry); - LOG.info("Batch create entry: {}", prettyPrint(dataEntry)); - - assertEquals(HttpStatusCodes.NO_CONTENT.getStatusCode(), responseParts.get(5).getStatusCode()); - assertEquals(HttpStatusCodes.NO_CONTENT.getStatusCode(), responseParts.get(6).getStatusCode()); - - assertEquals(HttpStatusCodes.NOT_FOUND.getStatusCode(), responseParts.get(7).getStatusCode()); - final Exception exception = (Exception) responseParts.get(7).getBody(); - assertNotNull(exception); - LOG.info("Batch retrieve deleted entry: {}", exception); - } - - private Map<String, Object> getEntityData() { - Map<String, Object> data = new HashMap<String, Object>(); - data.put(ID_PROPERTY, "123"); - data.put("Name", "MyCarManufacturer"); - data.put(FOUNDED_PROPERTY, new Date()); - Map<String, Object> address = new HashMap<String, Object>(); - address.put("Street", "Main"); - address.put("ZipCode", "42421"); - address.put("City", "Fairy City"); - address.put("Country", "FarFarAway"); - data.put(ADDRESS, address); - return data; - } - - private static String prettyPrint(ODataFeed dataFeed) { - StringBuilder builder = new StringBuilder(); - builder.append("[\n"); - for (ODataEntry entry : dataFeed.getEntries()) { - builder.append(prettyPrint(entry.getProperties(), 1)).append('\n'); - } - builder.append("]\n"); - return builder.toString(); - } - - private static String prettyPrint(ODataEntry createdEntry) { - return prettyPrint(createdEntry.getProperties(), 0); - } - - private static String prettyPrint(Map<String, Object> properties, int level) { - StringBuilder b = new StringBuilder(); - Set<Map.Entry<String, Object>> entries = properties.entrySet(); - - for (Map.Entry<String, Object> entry : entries) { - indent(b, level); - b.append(entry.getKey()).append(": "); - Object value = entry.getValue(); - if (value instanceof Map) { - @SuppressWarnings("unchecked") - final Map<String, Object> objectMap = (Map<String, Object>) value; - value = prettyPrint(objectMap, level + 1); - b.append(value).append(NEW_LINE); - } else if (value instanceof Calendar) { - Calendar cal = (Calendar) value; - value = SimpleDateFormat.getInstance().format(cal.getTime()); - b.append(value).append(NEW_LINE); - } else if (value instanceof ODataDeltaFeed) { - ODataDeltaFeed feed = (ODataDeltaFeed) value; - List<ODataEntry> inlineEntries = feed.getEntries(); - b.append("{"); - for (ODataEntry oDataEntry : inlineEntries) { - value = prettyPrint(oDataEntry.getProperties(), level + 1); - b.append("\n[\n").append(value).append("\n],"); - } - b.deleteCharAt(b.length() - 1); - indent(b, level); - b.append("}\n"); - } else { - b.append(value).append(NEW_LINE); - } - } - // remove last line break - b.deleteCharAt(b.length() - 1); - return b.toString(); - } - - private static void indent(StringBuilder builder, int indentLevel) { - for (int i = 0; i < indentLevel; i++) { - builder.append(" "); - } - } - - private static void generateSampleData(String serviceUrl) throws IOException { - final HttpPost httpUriRequest = new HttpPost(serviceUrl.substring(0, serviceUrl.lastIndexOf('/')) + INDEX); - httpUriRequest.setEntity(new ByteArrayEntity(GEN_SAMPLE_DATA.getBytes())); - ((Olingo2AppImpl)olingoApp).execute(httpUriRequest, ContentType.APPLICATION_FORM_URLENCODED, - new FutureCallback<HttpResponse>() { - @Override - public void completed(HttpResponse result) { - try { - AbstractFutureCallback.checkStatus(result); - LOG.info("Sample data generated {}", result.getStatusLine()); - } catch (ODataApplicationException e) { - LOG.error("Sample data generation error: " + e.getMessage(), e); - } - } - - @Override - public void failed(Exception ex) { - LOG.error("Error generating sample data " + ex.getMessage(), ex); - } - - @Override - public void cancelled() { - LOG.error("Sample data generation canceled!"); - } - }); - } - - private static final class TestOlingo2ResponseHandler<T> implements Olingo2ResponseHandler<T> { - - private T response; - private Exception error; - private CountDownLatch latch = new CountDownLatch(1); - - @Override - public void onResponse(T response) { - this.response = response; - if (LOG.isDebugEnabled()) { - if (response instanceof ODataFeed) { - LOG.debug("Received response: {}", prettyPrint((ODataFeed) response)); - } else if (response instanceof ODataEntry) { - LOG.debug("Received response: {}", prettyPrint((ODataEntry) response)); - } else { - LOG.debug("Received response: {}", response); - } - } - latch.countDown(); - } - - @Override - public void onException(Exception ex) { - error = ex; - latch.countDown(); - } - - @Override - public void onCanceled() { - error = new IllegalStateException("Request Canceled"); - latch.countDown(); - } - - public T await() throws Exception { - return await(TIMEOUT, TimeUnit.SECONDS); - } - - public T await(long timeout, TimeUnit unit) throws Exception { - assertTrue("Timeout waiting for response", latch.await(timeout, unit)); - if (error != null) { - throw error; - } - assertNotNull("Response", response); - return response; - } - - public void reset() { - latch.countDown(); - latch = new CountDownLatch(1); - response = null; - error = null; - } - } -} http://git-wip-us.apache.org/repos/asf/camel/blob/e3190cf1/components/camel-olingo2/camel-olingo2-component/pom.xml ---------------------------------------------------------------------- diff --git a/components/camel-olingo2/camel-olingo2-component/pom.xml b/components/camel-olingo2/camel-olingo2-component/pom.xml index 49b7cae..6eee1bb 100644 --- a/components/camel-olingo2/camel-olingo2-component/pom.xml +++ b/components/camel-olingo2/camel-olingo2-component/pom.xml @@ -104,10 +104,59 @@ </exclusions> </dependency> <dependency> + <groupId>org.apache.olingo</groupId> + <artifactId>olingo-odata2-api-annotation</artifactId> + <version>${olingo2-version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.olingo</groupId> + <artifactId>olingo-odata2-annotation-processor-api</artifactId> + <version>${olingo2-version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.olingo</groupId> + <artifactId>olingo-odata2-annotation-processor-core</artifactId> + <version>${olingo2-version}</version> + <scope>test</scope> + </dependency> + <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-test</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-rt-frontend-jaxrs</artifactId> + <version>${cxf-version}</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-servlet</artifactId> + <version>${jetty9-version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + <version>${jetty9-version}</version> + <scope>test</scope> + <exclusions> + <exclusion> + <groupId>org.eclipse.jetty.orbit</groupId> + <artifactId>javax.servlet</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-webapp</artifactId> + <version>${jetty9-version}</version> + <scope>test</scope> + </dependency> </dependencies> <build> @@ -178,6 +227,26 @@ </executions> </plugin> + <!-- add the olingo odata2 sample service source. See profile get-olingo2-sample below --> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <executions> + <execution> + <id>add-test-source</id> + <phase>generate-test-sources</phase> + <goals> + <goal>add-test-source</goal> + </goals> + <configuration> + <sources> + <source>${basedir}/target/olingo2-my-car-service/src/main/java</source> + </sources> + </configuration> + </execution> + </executions> + </plugin> + </plugins> <pluginManagement> @@ -214,4 +283,58 @@ </plugins> </reporting> + <profiles> + <profile> + <!-- REVISIT as of now, the olingo odata2 sample service that is used in the tests + is not available in nexus and needs to be generated and built using its architype plugin. + If the sample service jar becomes available, we can use it directly --> + <id>get-olingo2-sample</id> + <activation> + <file> + <missing>${basedir}/target/olingo2-my-car-service</missing> + </file> + <!-- the above condition is evaluated prior to the mvn execution and consequently + it evaluates to false when "mvn clean install" is invoked while the folder exists, + which is correct, yet unfortunate, as the clean phase will remove the folder and + subsequently the source folder is not created. + So, we need activate this profle by default and set -fn option to the mvn below to + ignore the duplicate error ;-(( + --> + <activeByDefault>true</activeByDefault> + </activation> + <build> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>exec-maven-plugin</artifactId> + <executions> + <execution> + <id>generate-sources</id> + <phase>generate-test-sources</phase> + <goals> + <goal>exec</goal> + </goals> + </execution> + </executions> + <configuration> + <executable>mvn</executable> + <workingDirectory>${basedir}/target</workingDirectory> + <arguments> + <argument>archetype:generate</argument> + <argument>-q</argument> + <argument>-fn</argument> + <argument>-DinteractiveMode=false</argument> + <argument>-Dversion=${project.version}</argument> + <argument>-DgroupId=org.apache.camel</argument> + <argument>-DartifactId=olingo2-my-car-service</argument> + <argument>-DarchetypeGroupId=org.apache.olingo</argument> + <argument>-DarchetypeArtifactId=olingo-odata2-sample-cars-annotation-archetype</argument> + <argument>-DarchetypeVersion=${olingo2-version}</argument> + </arguments> + </configuration> + </plugin> + </plugins> + </build> + </profile> + </profiles> </project> http://git-wip-us.apache.org/repos/asf/camel/blob/e3190cf1/components/camel-olingo2/camel-olingo2-component/src/test/java/org/apache/camel/component/olingo2/AbstractOlingo2TestSupport.java ---------------------------------------------------------------------- diff --git a/components/camel-olingo2/camel-olingo2-component/src/test/java/org/apache/camel/component/olingo2/AbstractOlingo2TestSupport.java b/components/camel-olingo2/camel-olingo2-component/src/test/java/org/apache/camel/component/olingo2/AbstractOlingo2TestSupport.java index 094f0b1..c85c31a 100644 --- a/components/camel-olingo2/camel-olingo2-component/src/test/java/org/apache/camel/component/olingo2/AbstractOlingo2TestSupport.java +++ b/components/camel-olingo2/camel-olingo2-component/src/test/java/org/apache/camel/component/olingo2/AbstractOlingo2TestSupport.java @@ -32,6 +32,11 @@ import org.apache.camel.util.IntrospectionSupport; public class AbstractOlingo2TestSupport extends CamelTestSupport { private static final String TEST_OPTIONS_PROPERTIES = "/test-options.properties"; + private Properties properties = new Properties(); + + protected void setDefaultTestProperty(String key, String value) { + properties.setProperty(key, value); + } @Override protected CamelContext createCamelContext() throws Exception { @@ -39,7 +44,6 @@ public class AbstractOlingo2TestSupport extends CamelTestSupport { final CamelContext context = super.createCamelContext(); // read Olingo component configuration from TEST_OPTIONS_PROPERTIES - final Properties properties = new Properties(); try { properties.load(getClass().getResourceAsStream(TEST_OPTIONS_PROPERTIES)); } catch (Exception e) { http://git-wip-us.apache.org/repos/asf/camel/blob/e3190cf1/components/camel-olingo2/camel-olingo2-component/src/test/java/org/apache/camel/component/olingo2/Olingo2AppAPITest.java ---------------------------------------------------------------------- diff --git a/components/camel-olingo2/camel-olingo2-component/src/test/java/org/apache/camel/component/olingo2/Olingo2AppAPITest.java b/components/camel-olingo2/camel-olingo2-component/src/test/java/org/apache/camel/component/olingo2/Olingo2AppAPITest.java new file mode 100644 index 0000000..e502c6a --- /dev/null +++ b/components/camel-olingo2/camel-olingo2-component/src/test/java/org/apache/camel/component/olingo2/Olingo2AppAPITest.java @@ -0,0 +1,596 @@ +/** + * 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.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.apache.camel.component.olingo2.api.Olingo2App; +import org.apache.camel.component.olingo2.api.Olingo2ResponseHandler; +import org.apache.camel.component.olingo2.api.batch.Olingo2BatchChangeRequest; +import org.apache.camel.component.olingo2.api.batch.Olingo2BatchQueryRequest; +import org.apache.camel.component.olingo2.api.batch.Olingo2BatchRequest; +import org.apache.camel.component.olingo2.api.batch.Olingo2BatchResponse; +import org.apache.camel.component.olingo2.api.batch.Operation; +import org.apache.camel.component.olingo2.api.impl.Olingo2AppImpl; +import org.apache.camel.component.olingo2.api.impl.SystemQueryOption; +import org.apache.camel.test.AvailablePortFinder; +import org.apache.http.entity.ContentType; +import org.apache.olingo.odata2.api.commons.HttpStatusCodes; +import org.apache.olingo.odata2.api.edm.Edm; +import org.apache.olingo.odata2.api.edm.EdmEntitySetInfo; +import org.apache.olingo.odata2.api.ep.entry.ODataEntry; +import org.apache.olingo.odata2.api.ep.feed.ODataDeltaFeed; +import org.apache.olingo.odata2.api.ep.feed.ODataFeed; +import org.apache.olingo.odata2.api.servicedocument.Collection; +import org.apache.olingo.odata2.api.servicedocument.ServiceDocument; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * Integration test for {@link org.apache.camel.component.olingo2.api.impl.Olingo2AppImpl} + * using the sample Olingo2 Server dynamically downloaded and started during the test. + */ +public class Olingo2AppAPITest { + + private static final Logger LOG = LoggerFactory.getLogger(Olingo2AppAPITest.class); + private static final int PORT = AvailablePortFinder.getNextAvailable(); + + private static final long TIMEOUT = 10; + + private static final String MANUFACTURERS = "Manufacturers"; + private static final String FQN_MANUFACTURERS = "DefaultContainer.Manufacturers"; + private static final String ADDRESS = "Address"; + private static final String CARS = "Cars"; + + private static final String TEST_KEY = "'1'"; + private static final String TEST_CREATE_KEY = "'123'"; + private static final String TEST_MANUFACTURER = FQN_MANUFACTURERS + "(" + TEST_KEY + ")"; + private static final String TEST_CREATE_MANUFACTURER = MANUFACTURERS + "(" + TEST_CREATE_KEY + ")"; + + private static final String TEST_RESOURCE_CONTENT_ID = "1"; + private static final String TEST_RESOURCE = "$" + TEST_RESOURCE_CONTENT_ID; + + private static final char NEW_LINE = '\n'; + private static final String TEST_CAR = "Manufacturers('1')/Cars('1')"; + private static final String TEST_MANUFACTURER_FOUNDED_PROPERTY = "Manufacturers('1')/Founded"; + private static final String TEST_MANUFACTURER_FOUNDED_VALUE = "Manufacturers('1')/Founded/$value"; + private static final String FOUNDED_PROPERTY = "Founded"; + private static final String TEST_MANUFACTURER_ADDRESS_PROPERTY = "Manufacturers('1')/Address"; + private static final String TEST_MANUFACTURER_LINKS_CARS = "Manufacturers('1')/$links/Cars"; + private static final String TEST_CAR_LINK_MANUFACTURER = "Cars('1')/$links/Manufacturer"; + private static final String COUNT_OPTION = "/$count"; + + private static final String TEST_SERVICE_URL = "http://localhost:" + PORT + "/MyFormula.svc"; + // private static final String TEST_SERVICE_URL = "http://localhost:8080/cars-annotations-sample/MyFormula.svc"; +// private static final ContentType TEST_FORMAT = ContentType.APPLICATION_XML_CS_UTF_8; + private static final ContentType TEST_FORMAT = ContentType.APPLICATION_JSON; +// private static final Pattern LINK_PATTERN = Pattern.compile("[^(]+\\('([^']+)'\\)"); + private static final String ID_PROPERTY = "Id"; + + private static Olingo2App olingoApp; + private static Edm edm; + + private static Olingo2SampleServer server; + + @BeforeClass + public static void beforeClass() throws Exception { + startServers(PORT); + Olingo2SampleServer.generateSampleData(TEST_SERVICE_URL); + setupClient(); + } + + @AfterClass + public static void afterClass() throws Exception { + if (olingoApp != null) { + olingoApp.close(); + } + if (server != null) { + server.stop(); + server.destroy(); + } + } + + protected static void startServers(int port) throws Exception { + server = new Olingo2SampleServer(port, "/olingo2_ref"); + server.start(); + } + + protected static void setupClient() throws Exception { + olingoApp = new Olingo2AppImpl(TEST_SERVICE_URL + "/"); + olingoApp.setContentType(TEST_FORMAT.toString()); + + LOG.info("Read Edm "); + final TestOlingo2ResponseHandler<Edm> responseHandler = new TestOlingo2ResponseHandler<Edm>(); + + olingoApp.read(null, Olingo2AppImpl.METADATA, null, responseHandler); + + edm = responseHandler.await(); + LOG.info("Read default EntityContainer: {}", responseHandler.await().getDefaultEntityContainer().getName()); + + // wait for generated data to be registered in server + Thread.sleep(2000); + } + + @Test + public void testServiceDocument() throws Exception { + final TestOlingo2ResponseHandler<ServiceDocument> responseHandler = + new TestOlingo2ResponseHandler<ServiceDocument>(); + + olingoApp.read(null, "", null, responseHandler); + + final ServiceDocument serviceDocument = responseHandler.await(); + final List<Collection> collections = serviceDocument.getAtomInfo().getWorkspaces().get(0).getCollections(); + assertEquals("Service Atom Collections", 3, collections.size()); + LOG.info("Service Atom Collections: {}", collections); + + final List<EdmEntitySetInfo> entitySetsInfo = serviceDocument.getEntitySetsInfo(); + assertEquals("Service Entity Sets", 3, entitySetsInfo.size()); + LOG.info("Service Document Entries: {}", entitySetsInfo); + } + + @Test + public void testReadFeed() throws Exception { + final TestOlingo2ResponseHandler<ODataFeed> responseHandler = new TestOlingo2ResponseHandler<ODataFeed>(); + + olingoApp.read(edm, MANUFACTURERS, null, responseHandler); + + final ODataFeed dataFeed = responseHandler.await(); + assertNotNull("Data feed", dataFeed); + LOG.info("Entries: {}", prettyPrint(dataFeed)); + } + + @Test + public void testReadEntry() throws Exception { + final TestOlingo2ResponseHandler<ODataEntry> responseHandler = new TestOlingo2ResponseHandler<ODataEntry>(); + + olingoApp.read(edm, TEST_MANUFACTURER, null, responseHandler); + ODataEntry entry = responseHandler.await(); + LOG.info("Single Entry: {}", prettyPrint(entry)); + + responseHandler.reset(); + + olingoApp.read(edm, TEST_CAR, null, responseHandler); + entry = responseHandler.await(); + LOG.info("Single Entry: {}", prettyPrint(entry)); + + responseHandler.reset(); + final Map<String, String> queryParams = new HashMap<String, String>(); + queryParams.put(SystemQueryOption.$expand.toString(), CARS); + + olingoApp.read(edm, TEST_MANUFACTURER, queryParams, responseHandler); + + ODataEntry entryExpanded = responseHandler.await(); + LOG.info("Single Entry with expanded Cars relation: {}", prettyPrint(entryExpanded)); + } + + @Test + public void testReadUpdateProperties() throws Exception { + // test simple property Manufacturer.Founded + final TestOlingo2ResponseHandler<Map<String, Object>> propertyHandler = + new TestOlingo2ResponseHandler<Map<String, Object>>(); + + olingoApp.read(edm, TEST_MANUFACTURER_FOUNDED_PROPERTY, null, propertyHandler); + + Calendar founded = (Calendar) propertyHandler.await().get(FOUNDED_PROPERTY); + LOG.info("Founded property {}", founded.toString()); + + final TestOlingo2ResponseHandler<Calendar> valueHandler = new TestOlingo2ResponseHandler<Calendar>(); + + olingoApp.read(edm, TEST_MANUFACTURER_FOUNDED_VALUE, null, valueHandler); + + founded = valueHandler.await(); + LOG.info("Founded property {}", founded.toString()); + + final TestOlingo2ResponseHandler<HttpStatusCodes> statusHandler = + new TestOlingo2ResponseHandler<HttpStatusCodes>(); + final HashMap<String, Object> properties = new HashMap<String, Object>(); + properties.put(FOUNDED_PROPERTY, new Date()); + +// olingoApp.update(edm, TEST_MANUFACTURER_FOUNDED_PROPERTY, properties, statusHandler); + // requires a plain Date for XML + olingoApp.update(edm, TEST_MANUFACTURER_FOUNDED_PROPERTY, new Date(), statusHandler); + + LOG.info("Founded property updated with status {}", statusHandler.await().getStatusCode()); + + statusHandler.reset(); + + olingoApp.update(edm, TEST_MANUFACTURER_FOUNDED_VALUE, new Date(), statusHandler); + + LOG.info("Founded property updated with status {}", statusHandler.await().getStatusCode()); + + // test complex property Manufacturer.Address + propertyHandler.reset(); + + olingoApp.read(edm, TEST_MANUFACTURER_ADDRESS_PROPERTY, null, propertyHandler); + + final Map<String, Object> address = propertyHandler.await(); + LOG.info("Address property {}", prettyPrint(address, 0)); + + statusHandler.reset(); + + address.clear(); + // Olingo2 sample server MERGE/PATCH behaves like PUT!!! +// address.put("Street", "Main Street"); + address.put("Street", "Star Street 137"); + address.put("City", "Stuttgart"); + address.put("ZipCode", "70173"); + address.put("Country", "Germany"); + +// olingoApp.patch(edm, TEST_MANUFACTURER_ADDRESS_PROPERTY, address, statusHandler); + olingoApp.merge(edm, TEST_MANUFACTURER_ADDRESS_PROPERTY, address, statusHandler); + + LOG.info("Address property updated with status {}", statusHandler.await().getStatusCode()); + } + + @Test + public void testReadDeleteCreateLinks() throws Exception { + final TestOlingo2ResponseHandler<List<String>> linksHandler = new TestOlingo2ResponseHandler<List<String>>(); + + olingoApp.read(edm, TEST_MANUFACTURER_LINKS_CARS, null, linksHandler); + + final List<String> links = linksHandler.await(); + assertFalse(links.isEmpty()); + LOG.info("Read links: {}", links); + + final TestOlingo2ResponseHandler<String> linkHandler = new TestOlingo2ResponseHandler<String>(); + + olingoApp.read(edm, TEST_CAR_LINK_MANUFACTURER, null, linkHandler); + + final String link = linkHandler.await(); + LOG.info("Read link: {}", link); + +//Deleting relationships through links is not supported in Olingo2 at the time of writing this test +/* + final TestOlingo2ResponseHandler<HttpStatusCodes> statusHandler = + new TestOlingo2ResponseHandler<HttpStatusCodes>(); + + final ArrayList<Map<String, Object>> carKeys = new ArrayList<Map<String, Object>>(); + for (String carLink : links) { + final Matcher matcher = LINK_PATTERN.matcher(carLink); + assertTrue("Link pattern " + carLink, matcher.matches()); + final String carId = matcher.group(1); + + final HashMap<String, Object> keys = new HashMap<String, Object>(); + keys.put(ID_PROPERTY, carId); + carKeys.add(keys); + + // delete manufacturer->car link + statusHandler.reset(); + final String resourcePath = TEST_MANUFACTURER_LINKS_CARS + "('" + carId + "')"; + olingoApp.delete(resourcePath, statusHandler); + + assertEquals("Delete car link " + resourcePath, HttpStatusCodes.OK.getStatusCode(), + statusHandler.await().getStatusCode()); + } + + // add links to all Cars + statusHandler.reset(); + olingoApp.create(edm, TEST_MANUFACTURER_LINKS_CARS, carKeys, statusHandler); + + assertEquals("Links update", HttpStatusCodes.ACCEPTED.getStatusCode(), statusHandler.await().getStatusCode()); + + // delete car->manufacturer link + statusHandler.reset(); + olingoApp.delete(TEST_CAR_LINK_MANUFACTURER, statusHandler); + + assertEquals("Delete manufacturer link " + TEST_CAR_LINK_MANUFACTURER, HttpStatusCodes.OK.getStatusCode(), + statusHandler.await().getStatusCode()); + + // add link to Manufacturer + statusHandler.reset(); + final HashMap<String, Object> manufacturerKey = new HashMap<String, Object>(); + manufacturerKey.put(ID_PROPERTY, "1"); + + olingoApp.create(edm, TEST_CAR_LINK_MANUFACTURER, manufacturerKey, statusHandler); + + assertEquals("Link update", HttpStatusCodes.ACCEPTED.getStatusCode(), statusHandler.await().getStatusCode()); +*/ + } + + @Test + public void testReadCount() throws Exception { + final TestOlingo2ResponseHandler<Long> countHandler = new TestOlingo2ResponseHandler<Long>(); + + olingoApp.read(edm, MANUFACTURERS + COUNT_OPTION, null, countHandler); + + LOG.info("Manufacturers count: {}", countHandler.await()); + + countHandler.reset(); + olingoApp.read(edm, TEST_MANUFACTURER + COUNT_OPTION, null, countHandler); + + LOG.info("Manufacturer count: {}", countHandler.await()); + + countHandler.reset(); + olingoApp.read(edm, TEST_MANUFACTURER_LINKS_CARS + COUNT_OPTION, null, countHandler); + + LOG.info("Manufacturers links count: {}", countHandler.await()); + + countHandler.reset(); + olingoApp.read(edm, TEST_CAR_LINK_MANUFACTURER + COUNT_OPTION, null, countHandler); + + LOG.info("Manufacturer link count: {}", countHandler.await()); + } + + @Test + public void testCreateUpdateDeleteEntry() throws Exception { + + // create entry to update + final TestOlingo2ResponseHandler<ODataEntry> entryHandler = new TestOlingo2ResponseHandler<ODataEntry>(); + + olingoApp.create(edm, MANUFACTURERS, getEntityData(), entryHandler); + + ODataEntry createdEntry = entryHandler.await(); + LOG.info("Created Entry: {}", prettyPrint(createdEntry)); + + Map<String, Object> data = getEntityData(); + @SuppressWarnings("unchecked") + Map<String, Object> address = (Map<String, Object>) data.get(ADDRESS); + + data.put("Name", "MyCarManufacturer Renamed"); + address.put("Street", "Main Street"); + final TestOlingo2ResponseHandler<HttpStatusCodes> statusHandler = + new TestOlingo2ResponseHandler<HttpStatusCodes>(); + + olingoApp.update(edm, TEST_CREATE_MANUFACTURER, data, statusHandler); + statusHandler.await(); + + statusHandler.reset(); + data.put("Name", "MyCarManufacturer Patched"); + olingoApp.patch(edm, TEST_CREATE_MANUFACTURER, data, statusHandler); + statusHandler.await(); + + entryHandler.reset(); + olingoApp.read(edm, TEST_CREATE_MANUFACTURER, null, entryHandler); + + ODataEntry updatedEntry = entryHandler.await(); + LOG.info("Updated Entry successfully: {}", prettyPrint(updatedEntry)); + + statusHandler.reset(); + olingoApp.delete(TEST_CREATE_MANUFACTURER, statusHandler); + + HttpStatusCodes statusCode = statusHandler.await(); + LOG.info("Deletion of Entry was successful: {}: {}", statusCode.getStatusCode(), statusCode.getInfo()); + + try { + LOG.info("Verify Delete Entry"); + + entryHandler.reset(); + olingoApp.read(edm, TEST_CREATE_MANUFACTURER, null, entryHandler); + + entryHandler.await(); + fail("Entry not deleted!"); + } catch (Exception e) { + LOG.info("Deleted entry not found: {}", e.getMessage()); + } + } + + @Test + public void testBatchRequest() throws Exception { + + final List<Olingo2BatchRequest> batchParts = new ArrayList<Olingo2BatchRequest>(); + + // Edm query + batchParts.add(Olingo2BatchQueryRequest.resourcePath(Olingo2AppImpl.METADATA).build()); + + // feed query + batchParts.add(Olingo2BatchQueryRequest.resourcePath(MANUFACTURERS).build()); + + // read + batchParts.add(Olingo2BatchQueryRequest.resourcePath(TEST_MANUFACTURER).build()); + + // read with expand + final HashMap<String, String> queryParams = new HashMap<String, String>(); + queryParams.put(SystemQueryOption.$expand.toString(), CARS); + batchParts.add(Olingo2BatchQueryRequest.resourcePath(TEST_MANUFACTURER).queryParams(queryParams).build()); + + // create + final Map<String, Object> data = getEntityData(); + batchParts.add(Olingo2BatchChangeRequest.resourcePath(MANUFACTURERS). + contentId(TEST_RESOURCE_CONTENT_ID).operation(Operation.CREATE).body(data).build()); + + // update + final Map<String, Object> updateData = new HashMap<String, Object>(data); + @SuppressWarnings("unchecked") + Map<String, Object> address = (Map<String, Object>) updateData.get(ADDRESS); + updateData.put("Name", "MyCarManufacturer Renamed"); + address.put("Street", "Main Street"); + + batchParts.add(Olingo2BatchChangeRequest.resourcePath(TEST_RESOURCE).operation(Operation.UPDATE) + .body(updateData).build()); + + // delete + batchParts.add(Olingo2BatchChangeRequest.resourcePath(TEST_RESOURCE).operation(Operation.DELETE).build()); + + final TestOlingo2ResponseHandler<List<Olingo2BatchResponse>> responseHandler = + new TestOlingo2ResponseHandler<List<Olingo2BatchResponse>>(); + + // read to verify delete + batchParts.add(Olingo2BatchQueryRequest.resourcePath(TEST_CREATE_MANUFACTURER).build()); + + olingoApp.batch(edm, batchParts, responseHandler); + + final List<Olingo2BatchResponse> responseParts = responseHandler.await(15, TimeUnit.MINUTES); + assertEquals("Batch responses expected", 8, responseParts.size()); + + assertNotNull(responseParts.get(0).getBody()); + final ODataFeed feed = (ODataFeed) responseParts.get(1).getBody(); + assertNotNull(feed); + LOG.info("Batch feed: {}", prettyPrint(feed)); + + ODataEntry dataEntry = (ODataEntry) responseParts.get(2).getBody(); + assertNotNull(dataEntry); + LOG.info("Batch read entry: {}", prettyPrint(dataEntry)); + + dataEntry = (ODataEntry) responseParts.get(3).getBody(); + assertNotNull(dataEntry); + LOG.info("Batch read entry with expand: {}", prettyPrint(dataEntry)); + + dataEntry = (ODataEntry) responseParts.get(4).getBody(); + assertNotNull(dataEntry); + LOG.info("Batch create entry: {}", prettyPrint(dataEntry)); + + assertEquals(HttpStatusCodes.NO_CONTENT.getStatusCode(), responseParts.get(5).getStatusCode()); + assertEquals(HttpStatusCodes.NO_CONTENT.getStatusCode(), responseParts.get(6).getStatusCode()); + + assertEquals(HttpStatusCodes.NOT_FOUND.getStatusCode(), responseParts.get(7).getStatusCode()); + final Exception exception = (Exception) responseParts.get(7).getBody(); + assertNotNull(exception); + LOG.info("Batch retrieve deleted entry: {}", exception); + } + + private Map<String, Object> getEntityData() { + Map<String, Object> data = new HashMap<String, Object>(); + data.put(ID_PROPERTY, "123"); + data.put("Name", "MyCarManufacturer"); + data.put(FOUNDED_PROPERTY, new Date()); + Map<String, Object> address = new HashMap<String, Object>(); + address.put("Street", "Main"); + address.put("ZipCode", "42421"); + address.put("City", "Fairy City"); + address.put("Country", "FarFarAway"); + data.put(ADDRESS, address); + return data; + } + + private static String prettyPrint(ODataFeed dataFeed) { + StringBuilder builder = new StringBuilder(); + builder.append("[\n"); + for (ODataEntry entry : dataFeed.getEntries()) { + builder.append(prettyPrint(entry.getProperties(), 1)).append('\n'); + } + builder.append("]\n"); + return builder.toString(); + } + + private static String prettyPrint(ODataEntry createdEntry) { + return prettyPrint(createdEntry.getProperties(), 0); + } + + private static String prettyPrint(Map<String, Object> properties, int level) { + StringBuilder b = new StringBuilder(); + Set<Map.Entry<String, Object>> entries = properties.entrySet(); + + for (Map.Entry<String, Object> entry : entries) { + indent(b, level); + b.append(entry.getKey()).append(": "); + Object value = entry.getValue(); + if (value instanceof Map) { + @SuppressWarnings("unchecked") + final Map<String, Object> objectMap = (Map<String, Object>) value; + value = prettyPrint(objectMap, level + 1); + b.append(value).append(NEW_LINE); + } else if (value instanceof Calendar) { + Calendar cal = (Calendar) value; + value = SimpleDateFormat.getInstance().format(cal.getTime()); + b.append(value).append(NEW_LINE); + } else if (value instanceof ODataDeltaFeed) { + ODataDeltaFeed feed = (ODataDeltaFeed) value; + List<ODataEntry> inlineEntries = feed.getEntries(); + b.append("{"); + for (ODataEntry oDataEntry : inlineEntries) { + value = prettyPrint(oDataEntry.getProperties(), level + 1); + b.append("\n[\n").append(value).append("\n],"); + } + b.deleteCharAt(b.length() - 1); + indent(b, level); + b.append("}\n"); + } else { + b.append(value).append(NEW_LINE); + } + } + // remove last line break + b.deleteCharAt(b.length() - 1); + return b.toString(); + } + + private static void indent(StringBuilder builder, int indentLevel) { + for (int i = 0; i < indentLevel; i++) { + builder.append(" "); + } + } + + private static final class TestOlingo2ResponseHandler<T> implements Olingo2ResponseHandler<T> { + + private T response; + private Exception error; + private CountDownLatch latch = new CountDownLatch(1); + + @Override + public void onResponse(T response) { + this.response = response; + if (LOG.isDebugEnabled()) { + if (response instanceof ODataFeed) { + LOG.debug("Received response: {}", prettyPrint((ODataFeed) response)); + } else if (response instanceof ODataEntry) { + LOG.debug("Received response: {}", prettyPrint((ODataEntry) response)); + } else { + LOG.debug("Received response: {}", response); + } + } + latch.countDown(); + } + + @Override + public void onException(Exception ex) { + error = ex; + latch.countDown(); + } + + @Override + public void onCanceled() { + error = new IllegalStateException("Request Canceled"); + latch.countDown(); + } + + public T await() throws Exception { + return await(TIMEOUT, TimeUnit.SECONDS); + } + + public T await(long timeout, TimeUnit unit) throws Exception { + assertTrue("Timeout waiting for response", latch.await(timeout, unit)); + if (error != null) { + throw error; + } + assertNotNull("Response", response); + return response; + } + + public void reset() { + latch.countDown(); + latch = new CountDownLatch(1); + response = null; + error = null; + } + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e3190cf1/components/camel-olingo2/camel-olingo2-component/src/test/java/org/apache/camel/component/olingo2/Olingo2AppIntegrationTest.java ---------------------------------------------------------------------- diff --git a/components/camel-olingo2/camel-olingo2-component/src/test/java/org/apache/camel/component/olingo2/Olingo2AppIntegrationTest.java b/components/camel-olingo2/camel-olingo2-component/src/test/java/org/apache/camel/component/olingo2/Olingo2AppIntegrationTest.java deleted file mode 100644 index 9015807..0000000 --- a/components/camel-olingo2/camel-olingo2-component/src/test/java/org/apache/camel/component/olingo2/Olingo2AppIntegrationTest.java +++ /dev/null @@ -1,269 +0,0 @@ -/** - * 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.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.component.olingo2.api.batch.Olingo2BatchChangeRequest; -import org.apache.camel.component.olingo2.api.batch.Olingo2BatchQueryRequest; -import org.apache.camel.component.olingo2.api.batch.Olingo2BatchRequest; -import org.apache.camel.component.olingo2.api.batch.Olingo2BatchResponse; -import org.apache.camel.component.olingo2.api.batch.Operation; -import org.apache.camel.component.olingo2.api.impl.Olingo2AppImpl; -import org.apache.camel.component.olingo2.api.impl.SystemQueryOption; -import org.apache.camel.component.olingo2.internal.Olingo2Constants; -import org.apache.olingo.odata2.api.commons.HttpStatusCodes; -import org.apache.olingo.odata2.api.edm.Edm; -import org.apache.olingo.odata2.api.ep.entry.ODataEntry; -import org.apache.olingo.odata2.api.ep.feed.ODataFeed; -import org.apache.olingo.odata2.api.servicedocument.ServiceDocument; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test class for {@link org.apache.camel.component.olingo2.api.Olingo2App} APIs. - * <p> - * The integration test runs against Apache Olingo 2.0 sample server - * described at http://olingo.apache.org/doc/sample-setup.html - * </p> - * <p> - * Sample data must be first generated by using the sample client described with the server, - * or by running test <code>Olingo2AppIntegrationTest</code> in camel-olingo2-api module. - * </p> - */ -public class Olingo2AppIntegrationTest extends AbstractOlingo2TestSupport { - - private static final Logger LOG = LoggerFactory.getLogger(Olingo2AppIntegrationTest.class); - private static final String ID_PROPERTY = "Id"; - private static final String MANUFACTURERS = "Manufacturers"; - private static final String TEST_MANUFACTURER = "Manufacturers('1')"; - private static final String CARS = "Cars"; - private static final String TEST_RESOURCE_CONTENT_ID = "1"; - private static final String ADDRESS = "Address"; - private static final String TEST_RESOURCE = "$1"; - private static final String TEST_RESOURCE_ADDRESS = TEST_RESOURCE + "/Address"; - private static final String TEST_CREATE_MANUFACTURER = "DefaultContainer.Manufacturers('123')"; - - @Test - public void testRead() throws Exception { - final Map<String, Object> headers = new HashMap<String, Object>(); - - // read ServiceDocument - final ServiceDocument document = requestBodyAndHeaders("direct://READSERVICEDOC", null, headers); - assertNotNull(document); - assertFalse("ServiceDocument entity sets", document.getEntitySetsInfo().isEmpty()); - LOG.info("Service document has {} entity sets", document.getEntitySetsInfo().size()); - - // parameter type is java.util.Map - final HashMap<String, String> queryParams = new HashMap<String, String>(); - queryParams.put(SystemQueryOption.$top.name(), "5"); - headers.put("CamelOlingo2.queryParams", queryParams); - - // read ODataFeed - final ODataFeed manufacturers = requestBodyAndHeaders("direct://READFEED", null, headers); - assertNotNull(manufacturers); - final List<ODataEntry> manufacturersEntries = manufacturers.getEntries(); - assertFalse("Manufacturers empty entries", manufacturersEntries.isEmpty()); - LOG.info("Manufacturers feed has {} entries", manufacturersEntries.size()); - - // read ODataEntry - headers.clear(); - headers.put(Olingo2Constants.PROPERTY_PREFIX + "keyPredicate", "'1'"); - final ODataEntry manufacturer = requestBodyAndHeaders("direct://READENTRY", null, headers); - assertNotNull(manufacturer); - final Map<String, Object> properties = manufacturer.getProperties(); - assertEquals("Manufacturer Id", "1", properties.get(ID_PROPERTY)); - LOG.info("Manufacturer: {}", properties.toString()); - } - - @Test - public void testCreateUpdateDelete() throws Exception { - final Map<String, Object> data = getEntityData(); - Map<String, Object> address; - - final ODataEntry manufacturer = requestBody("direct://CREATE", data); - assertNotNull("Created Manufacturer", manufacturer); - final Map<String, Object> properties = manufacturer.getProperties(); - assertEquals("Created Manufacturer Id", "123", properties.get(ID_PROPERTY)); - LOG.info("Created Manufacturer: {}", properties); - - // update - data.put("Name", "MyCarManufacturer Renamed"); - address = (Map<String, Object>)data.get("Address"); - address.put("Street", "Main Street"); - - HttpStatusCodes status = requestBody("direct://UPDATE", data); - assertNotNull("Update status", status); - assertEquals("Update status", HttpStatusCodes.NO_CONTENT.getStatusCode(), status.getStatusCode()); - LOG.info("Update status: {}", status); - - // delete - status = requestBody("direct://DELETE", null); - assertNotNull("Delete status", status); - assertEquals("Delete status", HttpStatusCodes.NO_CONTENT.getStatusCode(), status.getStatusCode()); - LOG.info("Delete status: {}", status); - } - - private Map<String, Object> getEntityData() { - final Map<String, Object> data = new HashMap<String, Object>(); - data.put("Id", "123"); - data.put("Name", "MyCarManufacturer"); - data.put("Founded", new Date()); - Map<String, Object> address = new HashMap<String, Object>(); - address.put("Street", "Main"); - address.put("ZipCode", "42421"); - address.put("City", "Fairy City"); - address.put("Country", "FarFarAway"); - data.put("Address", address); - return data; - } - - @Test - public void testBatch() throws Exception { - final List<Olingo2BatchRequest> batchParts = new ArrayList<Olingo2BatchRequest>(); - - // 1. Edm query - batchParts.add(Olingo2BatchQueryRequest.resourcePath(Olingo2AppImpl.METADATA).build()); - - // 2. feed query - batchParts.add(Olingo2BatchQueryRequest.resourcePath(MANUFACTURERS).build()); - - // 3. read - batchParts.add(Olingo2BatchQueryRequest.resourcePath(TEST_MANUFACTURER).build()); - - // 4. read with expand - final HashMap<String, String> queryParams = new HashMap<String, String>(); - queryParams.put(SystemQueryOption.$expand.toString(), CARS); - batchParts.add(Olingo2BatchQueryRequest.resourcePath(TEST_MANUFACTURER).queryParams(queryParams).build()); - - // 5. create - final Map<String, Object> data = getEntityData(); - batchParts.add(Olingo2BatchChangeRequest.resourcePath(MANUFACTURERS). - contentId(TEST_RESOURCE_CONTENT_ID).operation(Operation.CREATE).body(data).build()); - - // 6. update address in created entry - @SuppressWarnings("unchecked") - final Map<String, Object> updateData = new HashMap<String, Object>(data); - Map<String, Object> address = (Map<String, Object>) updateData.get(ADDRESS); - address.put("Street", "Main Street"); - batchParts.add( - Olingo2BatchChangeRequest.resourcePath(TEST_RESOURCE_ADDRESS).operation(Operation.UPDATE).body(address).build()); - - // 7. update - updateData.put("Name", "MyCarManufacturer Renamed"); - batchParts.add(Olingo2BatchChangeRequest.resourcePath(TEST_RESOURCE).operation(Operation.UPDATE) - .body(updateData).build()); - - // 8. delete - batchParts.add(Olingo2BatchChangeRequest.resourcePath(TEST_RESOURCE).operation(Operation.DELETE).build()); - - // 9. read to verify delete - batchParts.add(Olingo2BatchQueryRequest.resourcePath(TEST_CREATE_MANUFACTURER).build()); - - // execute batch request - final List<Olingo2BatchResponse> responseParts = requestBody("direct://BATCH", batchParts); - assertNotNull("Batch response", responseParts); - assertEquals("Batch responses expected", 9, responseParts.size()); - - final Edm edm = (Edm) responseParts.get(0).getBody(); - assertNotNull(edm); - LOG.info("Edm entity sets: {}", edm.getEntitySets()); - - final ODataFeed feed = (ODataFeed) responseParts.get(1).getBody(); - assertNotNull(feed); - LOG.info("Read feed: {}", feed.getEntries()); - - ODataEntry dataEntry = (ODataEntry) responseParts.get(2).getBody(); - assertNotNull(dataEntry); - LOG.info("Read entry: {}", dataEntry.getProperties()); - - dataEntry = (ODataEntry) responseParts.get(3).getBody(); - assertNotNull(dataEntry); - LOG.info("Read entry with $expand: {}", dataEntry.getProperties()); - - dataEntry = (ODataEntry) responseParts.get(4).getBody(); - assertNotNull(dataEntry); - LOG.info("Created entry: {}", dataEntry.getProperties()); - - int statusCode = responseParts.get(5).getStatusCode(); - assertEquals(HttpStatusCodes.NO_CONTENT.getStatusCode(), statusCode); - LOG.info("Update address status: {}", statusCode); - - statusCode = responseParts.get(6).getStatusCode(); - assertEquals(HttpStatusCodes.NO_CONTENT.getStatusCode(), statusCode); - LOG.info("Update entry status: {}", statusCode); - - statusCode = responseParts.get(7).getStatusCode(); - assertEquals(HttpStatusCodes.NO_CONTENT.getStatusCode(), statusCode); - LOG.info("Delete status: {}", statusCode); - - assertEquals(HttpStatusCodes.NOT_FOUND.getStatusCode(), responseParts.get(8).getStatusCode()); - final Exception exception = (Exception) responseParts.get(8).getBody(); - assertNotNull(exception); - LOG.info("Read deleted entry exception: {}", exception); - } - - @Override - protected RouteBuilder createRouteBuilder() throws Exception { - return new RouteBuilder() { - public void configure() { - // test routes for read - from("direct://READSERVICEDOC") - .to("olingo2://read/"); - - from("direct://READFEED") - .to("olingo2://read/Manufacturers?$orderBy=Name%20asc"); - - from("direct://READENTRY") - .to("olingo2://read/DefaultContainer.Manufacturers"); - - // test route for create - from("direct://CREATE") - .to("olingo2://create/Manufacturers"); - - // test route for update - from("direct://UPDATE") - .to("olingo2://update/Manufacturers('123')"); - - // test route for delete - from("direct://DELETE") - .to("olingo2://delete/Manufacturers('123')"); - -/* - // test route for merge - from("direct://MERGE") - .to("olingo2://merge"); - - // test route for patch - from("direct://PATCH") - .to("olingo2://patch"); -*/ - - // test route for batch - from("direct://BATCH") - .to("olingo2://batch"); - - } - }; - } -} http://git-wip-us.apache.org/repos/asf/camel/blob/e3190cf1/components/camel-olingo2/camel-olingo2-component/src/test/java/org/apache/camel/component/olingo2/Olingo2ComponentTest.java ---------------------------------------------------------------------- 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/Olingo2ComponentTest.java new file mode 100644 index 0000000..b1f981c --- /dev/null +++ b/components/camel-olingo2/camel-olingo2-component/src/test/java/org/apache/camel/component/olingo2/Olingo2ComponentTest.java @@ -0,0 +1,295 @@ +/** + * 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.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.olingo2.api.batch.Olingo2BatchChangeRequest; +import org.apache.camel.component.olingo2.api.batch.Olingo2BatchQueryRequest; +import org.apache.camel.component.olingo2.api.batch.Olingo2BatchRequest; +import org.apache.camel.component.olingo2.api.batch.Olingo2BatchResponse; +import org.apache.camel.component.olingo2.api.batch.Operation; +import org.apache.camel.component.olingo2.api.impl.Olingo2AppImpl; +import org.apache.camel.component.olingo2.api.impl.SystemQueryOption; +import org.apache.camel.component.olingo2.internal.Olingo2Constants; +import org.apache.camel.test.AvailablePortFinder; +import org.apache.olingo.odata2.api.commons.HttpStatusCodes; +import org.apache.olingo.odata2.api.edm.Edm; +import org.apache.olingo.odata2.api.ep.entry.ODataEntry; +import org.apache.olingo.odata2.api.ep.feed.ODataFeed; +import org.apache.olingo.odata2.api.servicedocument.ServiceDocument; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 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 Olingo2ComponentTest extends AbstractOlingo2TestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(Olingo2ComponentTest.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')"; + private static final String CARS = "Cars"; + private static final String TEST_RESOURCE_CONTENT_ID = "1"; + private static final String ADDRESS = "Address"; + private static final String TEST_RESOURCE = "$1"; + private static final String TEST_RESOURCE_ADDRESS = TEST_RESOURCE + "/Address"; + private static final String TEST_CREATE_MANUFACTURER = "DefaultContainer.Manufacturers('123')"; + private static final String TEST_SERVICE_URL = "http://localhost:" + PORT + "/MyFormula.svc"; + + private static Olingo2SampleServer server; + + public Olingo2ComponentTest() { + 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(); + } + + @Test + public void testRead() throws Exception { + final Map<String, Object> headers = new HashMap<String, Object>(); + + // read ServiceDocument + final ServiceDocument document = requestBodyAndHeaders("direct://READSERVICEDOC", null, headers); + assertNotNull(document); + assertFalse("ServiceDocument entity sets", document.getEntitySetsInfo().isEmpty()); + LOG.info("Service document has {} entity sets", document.getEntitySetsInfo().size()); + + // parameter type is java.util.Map + final HashMap<String, String> queryParams = new HashMap<String, String>(); + queryParams.put(SystemQueryOption.$top.name(), "5"); + headers.put("CamelOlingo2.queryParams", queryParams); + + // read ODataFeed + final ODataFeed manufacturers = requestBodyAndHeaders("direct://READFEED", null, headers); + assertNotNull(manufacturers); + final List<ODataEntry> manufacturersEntries = manufacturers.getEntries(); + assertFalse("Manufacturers empty entries", manufacturersEntries.isEmpty()); + LOG.info("Manufacturers feed has {} entries", manufacturersEntries.size()); + + // read ODataEntry + headers.clear(); + headers.put(Olingo2Constants.PROPERTY_PREFIX + "keyPredicate", "'1'"); + final ODataEntry manufacturer = requestBodyAndHeaders("direct://READENTRY", null, headers); + assertNotNull(manufacturer); + final Map<String, Object> properties = manufacturer.getProperties(); + assertEquals("Manufacturer Id", "1", properties.get(ID_PROPERTY)); + LOG.info("Manufacturer: {}", properties.toString()); + } + + @Test + public void testCreateUpdateDelete() throws Exception { + final Map<String, Object> data = getEntityData(); + Map<String, Object> address; + + final ODataEntry manufacturer = requestBody("direct://CREATE", data); + assertNotNull("Created Manufacturer", manufacturer); + final Map<String, Object> properties = manufacturer.getProperties(); + assertEquals("Created Manufacturer Id", "123", properties.get(ID_PROPERTY)); + LOG.info("Created Manufacturer: {}", properties); + + // update + data.put("Name", "MyCarManufacturer Renamed"); + address = (Map<String, Object>)data.get("Address"); + address.put("Street", "Main Street"); + + HttpStatusCodes status = requestBody("direct://UPDATE", data); + assertNotNull("Update status", status); + assertEquals("Update status", HttpStatusCodes.NO_CONTENT.getStatusCode(), status.getStatusCode()); + LOG.info("Update status: {}", status); + + // delete + status = requestBody("direct://DELETE", null); + assertNotNull("Delete status", status); + assertEquals("Delete status", HttpStatusCodes.NO_CONTENT.getStatusCode(), status.getStatusCode()); + LOG.info("Delete status: {}", status); + } + + private Map<String, Object> getEntityData() { + final Map<String, Object> data = new HashMap<String, Object>(); + data.put("Id", "123"); + data.put("Name", "MyCarManufacturer"); + data.put("Founded", new Date()); + Map<String, Object> address = new HashMap<String, Object>(); + address.put("Street", "Main"); + address.put("ZipCode", "42421"); + address.put("City", "Fairy City"); + address.put("Country", "FarFarAway"); + data.put("Address", address); + return data; + } + + @Test + public void testBatch() throws Exception { + final List<Olingo2BatchRequest> batchParts = new ArrayList<Olingo2BatchRequest>(); + + // 1. Edm query + batchParts.add(Olingo2BatchQueryRequest.resourcePath(Olingo2AppImpl.METADATA).build()); + + // 2. feed query + batchParts.add(Olingo2BatchQueryRequest.resourcePath(MANUFACTURERS).build()); + + // 3. read + batchParts.add(Olingo2BatchQueryRequest.resourcePath(TEST_MANUFACTURER).build()); + + // 4. read with expand + final HashMap<String, String> queryParams = new HashMap<String, String>(); + queryParams.put(SystemQueryOption.$expand.toString(), CARS); + batchParts.add(Olingo2BatchQueryRequest.resourcePath(TEST_MANUFACTURER).queryParams(queryParams).build()); + + // 5. create + final Map<String, Object> data = getEntityData(); + batchParts.add(Olingo2BatchChangeRequest.resourcePath(MANUFACTURERS). + contentId(TEST_RESOURCE_CONTENT_ID).operation(Operation.CREATE).body(data).build()); + + // 6. update address in created entry + @SuppressWarnings("unchecked") + final Map<String, Object> updateData = new HashMap<String, Object>(data); + Map<String, Object> address = (Map<String, Object>) updateData.get(ADDRESS); + address.put("Street", "Main Street"); + batchParts.add( + Olingo2BatchChangeRequest.resourcePath(TEST_RESOURCE_ADDRESS).operation(Operation.UPDATE).body(address).build()); + + // 7. update + updateData.put("Name", "MyCarManufacturer Renamed"); + batchParts.add(Olingo2BatchChangeRequest.resourcePath(TEST_RESOURCE).operation(Operation.UPDATE) + .body(updateData).build()); + + // 8. delete + batchParts.add(Olingo2BatchChangeRequest.resourcePath(TEST_RESOURCE).operation(Operation.DELETE).build()); + + // 9. read to verify delete + batchParts.add(Olingo2BatchQueryRequest.resourcePath(TEST_CREATE_MANUFACTURER).build()); + + // execute batch request + final List<Olingo2BatchResponse> responseParts = requestBody("direct://BATCH", batchParts); + assertNotNull("Batch response", responseParts); + assertEquals("Batch responses expected", 9, responseParts.size()); + + final Edm edm = (Edm) responseParts.get(0).getBody(); + assertNotNull(edm); + LOG.info("Edm entity sets: {}", edm.getEntitySets()); + + final ODataFeed feed = (ODataFeed) responseParts.get(1).getBody(); + assertNotNull(feed); + LOG.info("Read feed: {}", feed.getEntries()); + + ODataEntry dataEntry = (ODataEntry) responseParts.get(2).getBody(); + assertNotNull(dataEntry); + LOG.info("Read entry: {}", dataEntry.getProperties()); + + dataEntry = (ODataEntry) responseParts.get(3).getBody(); + assertNotNull(dataEntry); + LOG.info("Read entry with $expand: {}", dataEntry.getProperties()); + + dataEntry = (ODataEntry) responseParts.get(4).getBody(); + assertNotNull(dataEntry); + LOG.info("Created entry: {}", dataEntry.getProperties()); + + int statusCode = responseParts.get(5).getStatusCode(); + assertEquals(HttpStatusCodes.NO_CONTENT.getStatusCode(), statusCode); + LOG.info("Update address status: {}", statusCode); + + statusCode = responseParts.get(6).getStatusCode(); + assertEquals(HttpStatusCodes.NO_CONTENT.getStatusCode(), statusCode); + LOG.info("Update entry status: {}", statusCode); + + statusCode = responseParts.get(7).getStatusCode(); + assertEquals(HttpStatusCodes.NO_CONTENT.getStatusCode(), statusCode); + LOG.info("Delete status: {}", statusCode); + + assertEquals(HttpStatusCodes.NOT_FOUND.getStatusCode(), responseParts.get(8).getStatusCode()); + final Exception exception = (Exception) responseParts.get(8).getBody(); + assertNotNull(exception); + LOG.info("Read deleted entry exception: {}", exception); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + public void configure() { + // test routes for read + from("direct://READSERVICEDOC") + .to("olingo2://read/"); + + from("direct://READFEED") + .to("olingo2://read/Manufacturers?$orderBy=Name%20asc"); + + from("direct://READENTRY") + .to("olingo2://read/DefaultContainer.Manufacturers"); + + // test route for create + from("direct://CREATE") + .to("olingo2://create/Manufacturers"); + + // test route for update + from("direct://UPDATE") + .to("olingo2://update/Manufacturers('123')"); + + // test route for delete + from("direct://DELETE") + .to("olingo2://delete/Manufacturers('123')"); + +/* + // test route for merge + from("direct://MERGE") + .to("olingo2://merge"); + + // test route for patch + from("direct://PATCH") + .to("olingo2://patch"); +*/ + + // test route for batch + from("direct://BATCH") + .to("olingo2://batch"); + + } + }; + } +}