blob: d351e5759625c35c8e6dcac5b2c4882db9505400 [file] [log] [blame]
/*
* 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.mock.MockEndpoint;
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 Olingo2ComponentProducerTest extends AbstractOlingo2TestSupport {
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')";
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 Olingo2ComponentProducerTest() {
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<>();
// 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<>();
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);
}
@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<>();
data.put("Id", "123");
data.put("Name", "MyCarManufacturer");
data.put("Founded", new Date());
Map<String, Object> address = new HashMap<>();
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<>();
// 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<>();
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
final Map<String, Object> updateData = new HashMap<>(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);
}
/**
* Read entity set of the People object and with no filter already seen, all
* items should be present in each message
*
* @throws Exception
*/
@Test
public void testProducerReadNoFilterAlreadySeen() throws Exception {
final Map<String, Object> headers = new HashMap<>();
String endpoint = "direct:read-people-nofilterseen";
int expectedMsgCount = 3;
MockEndpoint mockEndpoint = getMockEndpoint("mock:producer-noalreadyseen");
mockEndpoint.expectedMessageCount(expectedMsgCount);
int expectedEntities = -1;
for (int i = 0; i < expectedMsgCount; ++i) {
final ODataFeed manufacturers = (ODataFeed)requestBodyAndHeaders(endpoint, null, headers);
assertNotNull(manufacturers);
if (i == 0) {
expectedEntities = manufacturers.getEntries().size();
}
}
mockEndpoint.assertIsSatisfied();
for (int i = 0; i < expectedMsgCount; ++i) {
Object body = mockEndpoint.getExchanges().get(i).getIn().getBody();
assertTrue(body instanceof ODataFeed);
ODataFeed set = (ODataFeed)body;
//
// All messages contained all the manufacturers
//
assertEquals(expectedEntities, set.getEntries().size());
}
}
/**
* Read entity set of the People object and filter already seen items on
* subsequent exchanges
*/
@Test
public void testProducerReadFilterAlreadySeen() throws Exception {
final Map<String, Object> headers = new HashMap<>();
String endpoint = "direct:read-people-filterseen";
int expectedMsgCount = 3;
MockEndpoint mockEndpoint = getMockEndpoint("mock:producer-alreadyseen");
mockEndpoint.expectedMessageCount(expectedMsgCount);
int expectedEntities = -1;
for (int i = 0; i < expectedMsgCount; ++i) {
final ODataFeed manufacturers = (ODataFeed)requestBodyAndHeaders(endpoint, null, headers);
assertNotNull(manufacturers);
if (i == 0) {
expectedEntities = manufacturers.getEntries().size();
}
}
mockEndpoint.assertIsSatisfied();
for (int i = 0; i < expectedMsgCount; ++i) {
Object body = mockEndpoint.getExchanges().get(i).getIn().getBody();
assertTrue(body instanceof ODataFeed);
ODataFeed set = (ODataFeed)body;
if (i == 0) {
//
// First polled messages contained all the manufacturers
//
assertEquals(expectedEntities, set.getEntries().size());
} else {
//
// Subsequent messages should be empty
// since the filterAlreadySeen property is true
//
assertEquals(0, set.getEntries().size());
}
}
}
@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");
from("direct:read-people-nofilterseen").to("olingo2://read/Manufacturers").to("mock:producer-noalreadyseen");
from("direct:read-people-filterseen").to("olingo2://read/Manufacturers?filterAlreadySeen=true").to("mock:producer-alreadyseen");
}
};
}
}