| /******************************************************************************* |
| * 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.olingo.odata2.fit.ref; |
| |
| 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.assertArrayEquals; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.UnsupportedEncodingException; |
| import java.net.URI; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import junit.framework.Assert; |
| |
| import org.apache.http.HttpEntity; |
| import org.apache.http.HttpResponse; |
| import org.apache.http.client.ClientProtocolException; |
| import org.apache.http.client.methods.HttpPost; |
| import org.apache.http.entity.InputStreamEntity; |
| import org.apache.http.entity.StringEntity; |
| import org.apache.olingo.odata2.api.client.batch.BatchChangeSet; |
| import org.apache.olingo.odata2.api.client.batch.BatchChangeSetPart; |
| import org.apache.olingo.odata2.api.client.batch.BatchPart; |
| import org.apache.olingo.odata2.api.client.batch.BatchSingleResponse; |
| import org.apache.olingo.odata2.api.commons.HttpHeaders; |
| import org.apache.olingo.odata2.api.ep.EntityProvider; |
| import org.apache.olingo.odata2.core.batch.BatchRequestWriter; |
| import org.apache.olingo.odata2.ref.processor.Util; |
| import org.apache.olingo.odata2.testutil.helper.StringHelper; |
| import org.apache.olingo.odata2.testutil.server.ServletType; |
| import org.junit.Test; |
| |
| /** |
| * |
| * |
| */ |
| public class BatchTest extends AbstractRefTest { |
| |
| private static final String PUT = "PUT"; |
| private static final String POST = "POST"; |
| private static final String BOUNDARY = "batch_123"; |
| |
| public BatchTest(final ServletType servletType) { |
| super(servletType); |
| } |
| |
| @Test |
| public void testSimpleBatch() throws Exception { |
| String responseBody = execute("/simple.batch"); |
| assertFalse(responseBody |
| .contains("<error xmlns=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\">")); |
| assertTrue(responseBody.contains( |
| "<edmx:Edmx xmlns:edmx=\"http://schemas.microsoft.com/ado/2007/06/edmx\" Version=\"1.0\"")); |
| } |
| |
| @Test |
| public void functionImportBatch() throws Exception { |
| String responseBody = execute("/functionImport.batch"); |
| assertFalse(responseBody |
| .contains("<error xmlns=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\">")); |
| assertTrue(responseBody.contains("HTTP/1.1 200 OK")); |
| assertTrue(responseBody.contains("<?xml version='1.0' encoding='utf-8'?><ManagerPhoto xmlns=")); |
| } |
| |
| @Test |
| public void employeesWithFilterBatch() throws Exception { |
| String responseBody = execute("/employeesWithFilter.batch"); |
| assertFalse(responseBody |
| .contains("<error xmlns=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\">")); |
| assertTrue(responseBody.contains("HTTP/1.1 200 OK")); |
| assertTrue(responseBody.contains("<d:EmployeeName>Walter Winter</d:EmployeeName>")); |
| } |
| |
| @Test |
| public void testChangeSetBatch() throws Exception { |
| String responseBody = execute("/changeset.batch"); |
| assertTrue(responseBody.contains("Frederic Fall MODIFIED")); |
| } |
| |
| @Test |
| public void testContentIdReferencing() throws Exception { |
| String responseBody = execute("/batchWithContentId.batch"); |
| assertTrue(responseBody.contains("HTTP/1.1 201 Created")); |
| assertTrue(responseBody.contains("HTTP/1.1 204 No Content")); |
| assertTrue(responseBody.contains("HTTP/1.1 200 OK")); |
| assertTrue(responseBody.contains("\"EmployeeName\":\"Frederic Fall MODIFIED\"")); |
| assertTrue(responseBody.contains("\"Age\":40")); |
| } |
| |
| @Test |
| public void testContentIdEchoing() throws Exception { |
| String responseBody = execute("/batchWithContentId.batch"); |
| assertTrue(responseBody.contains("Content-Id: 1")); |
| assertTrue(responseBody.contains("Content-Id: 2")); |
| assertTrue(responseBody.contains("Content-Id: 3")); |
| assertTrue(responseBody.contains("Content-Id: 4")); |
| assertTrue(responseBody.contains("Content-Id: AAA")); |
| assertTrue(responseBody.contains("Content-Id: newEmployee")); |
| } |
| |
| @Test |
| public void testWrongContentId() throws Exception { |
| HttpResponse response = execute("/batchWithWrongContentId.batch", "batch_cf90-46e5-1246"); |
| String responseBody = StringHelper.inputStreamToString(response.getEntity().getContent(), true); |
| assertTrue(responseBody.contains("HTTP/1.1 404 Not Found")); |
| } |
| |
| @Test |
| public void testFailFirstRequest() throws Exception { |
| HttpResponse response = execute("/batchFailFirstCreateRequest.batch", "batch_cf90-46e5-1246"); |
| String responseBody = StringHelper.inputStreamToString(response.getEntity().getContent(), true); |
| assertTrue(responseBody.contains("HTTP/1.1 404 Not Found")); |
| } |
| |
| @Test |
| public void testGPPG() throws Exception { |
| HttpResponse response = execute("/batchWithContentIdPart2.batch", "batch_cf90-46e5-1246"); |
| String responseBody = StringHelper.inputStreamToString(response.getEntity().getContent(), true); |
| |
| assertContentContainValues(responseBody, |
| "{\"d\":{\"EmployeeName\":\"Frederic Fall\"}}", |
| "HTTP/1.1 201 Created", |
| "Content-Id: employee", |
| "Content-Type: application/json;odata=verbose", |
| "\"EmployeeId\":\"7\",\"EmployeeName\":\"Employee 7\",", |
| "HTTP/1.1 204 No Content", |
| "Content-Id: AAA", |
| "{\"d\":{\"EmployeeName\":\"Robert Fall\"}}"); |
| |
| // validate that response for PUT does not contains a Content Type |
| int indexNoContent = responseBody.indexOf("HTTP/1.1 204 No Content"); |
| int indexBoundary = responseBody.indexOf("--changeset_", indexNoContent); |
| |
| int indexContentType = responseBody.indexOf("Content-Type:", indexNoContent); |
| Assert.assertTrue(indexBoundary < indexContentType); |
| } |
| |
| @Test |
| public void testErrorBatch() throws Exception { |
| String responseBody = execute("/error.batch"); |
| assertTrue(responseBody.contains("HTTP/1.1 404 Not Found")); |
| } |
| |
| /** |
| * Validate that given <code>content</code> contains all <code>values</code> in the given order. |
| * |
| * @param content |
| * @param containingValues |
| */ |
| private void assertContentContainValues(final String content, final String... containingValues) { |
| int index = -1; |
| for (String value : containingValues) { |
| int newIndex = content.indexOf(value, index); |
| Assert.assertTrue("Value '" + value + "' not found after index position '" + index + "'.", newIndex >= 0); |
| index = newIndex; |
| } |
| } |
| |
| private String execute(final String batchResource) throws Exception { |
| HttpResponse response = execute(batchResource, "batch_123"); |
| |
| String responseBody = StringHelper.inputStreamToStringCRLFLineBreaks(response.getEntity().getContent()); |
| return responseBody; |
| } |
| |
| private HttpResponse execute(final String batchResource, final String boundary) throws IOException, |
| UnsupportedEncodingException, ClientProtocolException { |
| final HttpPost post = new HttpPost(URI.create(getEndpoint().toString() + "$batch")); |
| post.setHeader("Content-Type", "multipart/mixed;boundary=" + boundary); |
| |
| String body = StringHelper.inputStreamToStringCRLFLineBreaks(this.getClass().getResourceAsStream(batchResource)); |
| HttpEntity entity = new StringEntity(body); |
| post.setEntity(entity); |
| HttpResponse response = getHttpClient().execute(post); |
| |
| assertNotNull(response); |
| assertEquals(202, response.getStatusLine().getStatusCode()); |
| return response; |
| } |
| |
| /** |
| * @param method |
| * @param data |
| * @param contentType |
| * @return |
| */ |
| private InputStream createBatchRequest(String method, byte[] data, String contentType) { |
| List<BatchPart> batch = new ArrayList<BatchPart>(); |
| Map<String, String> headers = new HashMap<String, String>(); |
| |
| BatchChangeSetPart request = null; |
| if (method.equalsIgnoreCase(PUT)) { |
| headers.put("content-type", contentType); |
| request = BatchChangeSetPart.method(PUT) |
| .uri("Employees('2')/$value") |
| .body(data) |
| .headers(headers) |
| .contentId("1") |
| .build(); |
| } else if (method.equalsIgnoreCase(POST)) { |
| headers.put("content-type", contentType); |
| request = BatchChangeSetPart.method(POST) |
| .uri("Employees") |
| .body(data) |
| .headers(headers) |
| .contentId("1") |
| .build(); |
| } |
| |
| BatchChangeSet changeSet = BatchChangeSet.newBuilder().build(); |
| changeSet.add(request); |
| batch.add(changeSet); |
| |
| BatchRequestWriter writer = new BatchRequestWriter(); |
| InputStream batchRequest = writer.writeBatchRequest(batch, BOUNDARY); |
| |
| return batchRequest; |
| } |
| |
| @Test |
| public void testBatchWithChangesetWithRawBytesInPutOperation() throws Exception { |
| InputStream requestPayload = createBatchRequestWithRawBytes(PUT); |
| final HttpPost put = new HttpPost(URI.create(getEndpoint().toString() + "$batch")); |
| put.setHeader("Content-Type", "multipart/mixed;boundary=" + BOUNDARY); |
| HttpEntity entity = new InputStreamEntity(requestPayload, -1); |
| put.setEntity(entity); |
| HttpResponse response = getHttpClient().execute(put); |
| byte[] actualData = Util.getInstance().getBinaryContent(); |
| byte[] expectedData = rawBytes(); |
| // Comparing data stored in the data source and the data sent in the request |
| assertArrayEquals(actualData, expectedData); |
| |
| assertNotNull(response); |
| assertEquals(202, response.getStatusLine().getStatusCode()); |
| String responseBody = StringHelper.inputStreamToStringCRLFLineBreaks(response.getEntity().getContent()); |
| assertTrue(responseBody.contains("204 No Content")); |
| |
| HttpResponse resp = execute("/simpleGet.batch", BOUNDARY); |
| InputStream in = resp.getEntity().getContent(); |
| StringHelper.Stream batchRequestStream = StringHelper.toStream(in); |
| String requestBody = batchRequestStream.asString(); |
| |
| String contentType = resp.getFirstHeader(HttpHeaders.CONTENT_TYPE).getValue(); |
| List<BatchSingleResponse> responses = EntityProvider.parseBatchResponse( |
| new ByteArrayInputStream(requestBody.getBytes("iso-8859-1")), contentType); |
| for (BatchSingleResponse batchResp : responses) { |
| assertEquals("200", batchResp.getStatusCode()); |
| assertEquals("OK", batchResp.getStatusInfo()); |
| assertArrayEquals(batchResp.getBody().getBytes("iso-8859-1"), actualData); |
| } |
| } |
| |
| @Test |
| public void testBatchWithChangesetWithRawBytesInPOSTOperation() throws Exception { |
| InputStream requestPayload = createBatchRequestWithRawBytes(POST); |
| final HttpPost put = new HttpPost(URI.create(getEndpoint().toString() + "$batch")); |
| put.setHeader("Content-Type", "multipart/mixed;boundary=" + BOUNDARY); |
| HttpEntity entity = new InputStreamEntity(requestPayload, -1); |
| put.setEntity(entity); |
| HttpResponse response = getHttpClient().execute(put); |
| byte[] actualData = Util.getInstance().getBinaryContent(); |
| byte[] expectedData = rawBytes(); |
| // Comparing data stored in the data source and the data sent in the request |
| assertArrayEquals(actualData, expectedData); |
| |
| assertNotNull(response); |
| assertEquals(202, response.getStatusLine().getStatusCode()); |
| String responseBody = StringHelper.inputStreamToStringCRLFLineBreaks(response.getEntity().getContent()); |
| assertTrue(responseBody.contains("201 Created")); |
| |
| HttpResponse resp = execute("/simpleGet1.batch", BOUNDARY); |
| InputStream in = resp.getEntity().getContent(); |
| StringHelper.Stream batchRequestStream = StringHelper.toStream(in); |
| String requestBody = batchRequestStream.asString(); |
| |
| String contentType = resp.getFirstHeader(HttpHeaders.CONTENT_TYPE).getValue(); |
| List<BatchSingleResponse> responses = EntityProvider.parseBatchResponse( |
| new ByteArrayInputStream(requestBody.getBytes("iso-8859-1")), contentType); |
| for (BatchSingleResponse batchResp : responses) { |
| assertEquals("200", batchResp.getStatusCode()); |
| assertEquals("OK", batchResp.getStatusInfo()); |
| assertArrayEquals(batchResp.getBody().getBytes("iso-8859-1"), expectedData); |
| } |
| } |
| |
| @Test |
| public void testBatchWithChangesetWithImageObjectInPutOperation() throws Exception { |
| InputStream requestPayload = createBatchRequestWithImage("/Employee_1.png", PUT); |
| |
| final HttpPost put = new HttpPost(URI.create(getEndpoint().toString() + "$batch")); |
| put.setHeader("Content-Type", "multipart/mixed;boundary=" + BOUNDARY); |
| HttpEntity entity = new InputStreamEntity(requestPayload, -1); |
| put.setEntity(entity); |
| HttpResponse response = getHttpClient().execute(put); |
| byte[] actualData = Util.getInstance().getBinaryContent(); |
| byte[] expectedData = getImageData("/Employee_1.png"); |
| // Comparing data stored in the data source and the data sent in the request |
| assertArrayEquals(actualData, expectedData); |
| |
| assertNotNull(response); |
| assertEquals(202, response.getStatusLine().getStatusCode()); |
| String responseBody = StringHelper.inputStreamToStringCRLFLineBreaks(response.getEntity().getContent()); |
| assertTrue(responseBody.contains("204 No Content")); |
| |
| HttpResponse resp = execute("/simpleGet.batch", BOUNDARY); |
| InputStream in = resp.getEntity().getContent(); |
| StringHelper.Stream batchRequestStream = StringHelper.toStream(in); |
| String requestBody = batchRequestStream.asString(); |
| |
| String contentType = resp.getFirstHeader(HttpHeaders.CONTENT_TYPE).getValue(); |
| List<BatchSingleResponse> responses = EntityProvider.parseBatchResponse( |
| new ByteArrayInputStream(requestBody.getBytes("iso-8859-1")), contentType); |
| for (BatchSingleResponse batchResp : responses) { |
| assertEquals("200", batchResp.getStatusCode()); |
| assertEquals("OK", batchResp.getStatusInfo()); |
| assertArrayEquals(batchResp.getBody().getBytes("iso-8859-1"), actualData); |
| } |
| } |
| |
| private InputStream createBatchRequestWithImage(String imageUrl, String method) throws IOException { |
| byte[] data = getImageData(imageUrl); |
| return createBatchRequest(method, data, "image/jpeg"); |
| } |
| |
| private InputStream createBatchRequestWithRawBytes(String method) { |
| byte[] data = rawBytes(); |
| return createBatchRequest(method, data, "application/octect-stream"); |
| } |
| |
| /** |
| * @return |
| */ |
| private byte[] rawBytes() { |
| byte[] data = new byte[Byte.MAX_VALUE - Byte.MIN_VALUE + 1]; |
| // binary content, not a valid UTF-8 representation of a string |
| for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) { |
| data[i - Byte.MIN_VALUE] = (byte) i; |
| } |
| return data; |
| } |
| |
| /** |
| * @param imageUrl |
| * @return |
| * @throws IOException |
| */ |
| private byte[] getImageData(String imageUrl) throws IOException { |
| byte[] data = null; |
| try { |
| InputStream in = this.getClass().getResourceAsStream(imageUrl); |
| ByteArrayOutputStream stream = new ByteArrayOutputStream(); |
| int b = 0; |
| while ((b = in.read()) != -1) { |
| stream.write(b); |
| } |
| |
| data = stream.toByteArray(); |
| } catch (IOException e) { |
| throw new IOException(e); |
| } |
| return data; |
| } |
| } |