blob: c72fe0f9c460ce2e0dcd6b987d758478071dda2a [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.io.InputStream;
import java.util.Map;
import javax.ws.rs.HttpMethod;
import okhttp3.HttpUrl;
import okhttp3.mockwebserver.Dispatcher;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;
import okio.Buffer;
import org.apache.camel.component.olingo2.api.Olingo2App;
import org.apache.camel.component.olingo2.api.impl.Olingo2AppImpl;
import org.apache.olingo.odata2.api.commons.HttpStatusCodes;
import org.apache.olingo.odata2.api.commons.ODataHttpHeaders;
import org.apache.olingo.odata2.api.edm.Edm;
import org.apache.olingo.odata2.api.edm.EdmEntityContainer;
import org.apache.olingo.odata2.api.edm.EdmEntitySet;
import org.apache.olingo.odata2.api.edm.EdmEntityType;
import org.apache.olingo.odata2.api.edm.EdmProperty;
import org.apache.olingo.odata2.api.edm.EdmServiceMetadata;
import org.apache.olingo.odata2.api.ep.EntityProvider;
import org.apache.olingo.odata2.api.ep.EntityProviderWriteProperties;
import org.apache.olingo.odata2.api.processor.ODataResponse;
import org.eclipse.jetty.http.HttpHeader;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
/**
* Tests support for concurrency properties which generate and require reading
* eTags before patch, update and delete operations. Since the embedded olingo2
* odata service does not contain any concurrency properties, it is necessary to
* mock up a new server. Uses a cutdown version of the reference odata service
* and adds in extra concurrency properties. Service's dispatcher only tests the
* correct calls are made and whether the eTags are correctly added as headers
* to the requisite requests.
*/
public class Olingo2AppAPIETagEnabledTest extends AbstractOlingo2AppAPITestSupport {
private static MockWebServer server;
private static Olingo2App olingoApp;
private static Edm edm;
private static EdmEntitySet manufacturersSet;
@BeforeClass
public static void scaffold() throws Exception {
initEdm();
initServer();
}
@AfterClass
public static void unscaffold() throws Exception {
if (olingoApp != null) {
olingoApp.close();
}
if (server != null) {
server.shutdown();
}
}
private static void initEdm() throws Exception {
InputStream edmXml = Olingo2AppAPIETagEnabledTest.class.getResourceAsStream("etag-enabled-service.xml");
edm = EntityProvider.readMetadata(edmXml, true);
assertNotNull(edm);
EdmEntityContainer entityContainer = edm.getDefaultEntityContainer();
assertNotNull(entityContainer);
manufacturersSet = entityContainer.getEntitySet(MANUFACTURERS);
assertNotNull(manufacturersSet);
EdmEntityType entityType = manufacturersSet.getEntityType();
assertNotNull(entityType);
//
// Check we have enabled eTag properties
//
EdmProperty property = (EdmProperty)entityType.getProperty("Id");
assertNotNull(property.getFacets());
}
private static void initServer() throws Exception {
server = new MockWebServer();
//
// Init dispatcher prior to start of server
//
server.setDispatcher(new Dispatcher() {
@SuppressWarnings("resource")
@Override
public MockResponse dispatch(RecordedRequest recordedRequest) throws InterruptedException {
MockResponse mockResponse = new MockResponse();
switch (recordedRequest.getMethod()) {
case HttpMethod.GET:
try {
if (recordedRequest.getPath().endsWith("/" + TEST_CREATE_MANUFACTURER)) {
ODataResponse odataResponse = EntityProvider.writeEntry(TEST_FORMAT.getMimeType(), manufacturersSet, getEntityData(),
EntityProviderWriteProperties.serviceRoot(getServiceUrl().uri()).build());
InputStream entityStream = odataResponse.getEntityAsStream();
mockResponse.setResponseCode(HttpStatusCodes.OK.getStatusCode());
mockResponse.setBody(new Buffer().readFrom(entityStream));
return mockResponse;
} else if (recordedRequest.getPath().endsWith("/" + Olingo2AppImpl.METADATA)) {
EdmServiceMetadata serviceMetadata = edm.getServiceMetadata();
return mockResponse.setResponseCode(HttpStatusCodes.OK.getStatusCode())
.addHeader(ODataHttpHeaders.DATASERVICEVERSION, serviceMetadata.getDataServiceVersion())
.setBody(new Buffer().readFrom(serviceMetadata.getMetadata()));
}
} catch (Exception ex) {
throw new RuntimeException(ex);
}
break;
case HttpMethod.PATCH:
case HttpMethod.PUT:
case HttpMethod.POST:
case HttpMethod.DELETE:
//
// Objective of the test:
// The Read has to have been called by
// Olingo2AppImpl.argumentWithETag
// which should then populate the IF-MATCH header with the
// eTag value.
// Verify the eTag value is present.
//
assertNotNull(recordedRequest.getHeader(HttpHeader.IF_MATCH.asString()));
return mockResponse.setResponseCode(HttpStatusCodes.NO_CONTENT.getStatusCode());
default:
break;
}
mockResponse.setResponseCode(HttpStatusCodes.NOT_FOUND.getStatusCode()).setBody("{ status: \"Not Found\"}");
return mockResponse;
}
});
server.start();
//
// have to init olingoApp after start of server
// since getBaseUrl() will call server start
//
olingoApp = new Olingo2AppImpl(getServiceUrl() + "/");
olingoApp.setContentType(TEST_FORMAT_STRING);
}
private static HttpUrl getServiceUrl() {
if (server == null) {
fail("Test programming failure. Server not initialised");
}
return server.url(SERVICE_NAME);
}
@Test
public void testPatchEntityWithETag() throws Exception {
TestOlingo2ResponseHandler<HttpStatusCodes> statusHandler = new TestOlingo2ResponseHandler<>();
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");
//
// Call patch
//
olingoApp.patch(edm, TEST_CREATE_MANUFACTURER, null, data, statusHandler);
HttpStatusCodes statusCode = statusHandler.await();
assertEquals(HttpStatusCodes.NO_CONTENT, statusCode);
}
@Test
public void testUpdateEntityWithETag() throws Exception {
TestOlingo2ResponseHandler<HttpStatusCodes> statusHandler = new TestOlingo2ResponseHandler<>();
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");
//
// Call update
//
olingoApp.update(edm, TEST_CREATE_MANUFACTURER, null, data, statusHandler);
HttpStatusCodes statusCode = statusHandler.await();
assertEquals(HttpStatusCodes.NO_CONTENT, statusCode);
}
@Test
public void testDeleteEntityWithETag() throws Exception {
TestOlingo2ResponseHandler<HttpStatusCodes> statusHandler = new TestOlingo2ResponseHandler<>();
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");
//
// Call delete
//
olingoApp.delete(TEST_CREATE_MANUFACTURER, null, statusHandler);
HttpStatusCodes statusCode = statusHandler.await();
assertEquals(HttpStatusCodes.NO_CONTENT, statusCode);
}
}