| /******************************************************************************* |
| * 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.core.batch; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertTrue; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.util.List; |
| |
| import org.apache.olingo.odata2.api.batch.BatchException; |
| import org.apache.olingo.odata2.api.batch.BatchRequestPart; |
| import org.apache.olingo.odata2.api.commons.HttpHeaders; |
| import org.apache.olingo.odata2.api.commons.ODataHttpMethod; |
| import org.apache.olingo.odata2.api.ep.EntityProviderBatchProperties; |
| import org.apache.olingo.odata2.api.processor.ODataRequest; |
| import org.apache.olingo.odata2.core.ODataPathSegmentImpl; |
| import org.apache.olingo.odata2.core.PathInfoImpl; |
| import org.apache.olingo.odata2.core.batch.v2.BatchParser; |
| import org.apache.olingo.odata2.testutil.helper.StringHelper; |
| import org.junit.BeforeClass; |
| import org.junit.Test; |
| |
| public class BatchRequestParserTest { |
| |
| private static final String CRLF = "\r\n"; |
| private static final String CONTENT_ID_REFERENCE = "NewEmployee"; |
| private static final String PUT_MIME_HEADER_CONTENT_ID = "BBB_MIMEPART1"; |
| private static final String PUT_REQUEST_HEADER_CONTENT_ID = "BBB_REQUEST1"; |
| private static final String SERVICE_ROOT = "http://localhost/odata/"; |
| private static EntityProviderBatchProperties batchProperties; |
| private static final String BOUNDARY = "batch_8194-cf13-1f56"; |
| private static final String contentType = "multipart/mixed;boundary=" + BOUNDARY; |
| private static final String MIME_HEADERS = "Content-Type: application/http" + CRLF |
| + "Content-Transfer-Encoding: binary" + CRLF; |
| private static final String GET_REQUEST = MIME_HEADERS + CRLF |
| + "GET Employees('1')/EmployeeName HTTP/1.1" + CRLF |
| + CRLF |
| + CRLF; |
| |
| @BeforeClass |
| public static void setProperties() throws URISyntaxException { |
| PathInfoImpl pathInfo = new PathInfoImpl(); |
| pathInfo.setServiceRoot(new URI(SERVICE_ROOT)); |
| batchProperties = EntityProviderBatchProperties.init().pathInfo(pathInfo).build(); |
| } |
| |
| @Test |
| public void test() throws IOException, BatchException, URISyntaxException { |
| String fileName = "/batchWithPost.batch"; |
| InputStream in = ClassLoader.class.getResourceAsStream(fileName); |
| if (in == null) { |
| throw new IOException("Requested file '" + fileName + "' was not found."); |
| } |
| |
| in = StringHelper.toStream(in).asStreamWithLineSeparation(CRLF); |
| |
| BatchParser parser = new BatchParser(contentType, batchProperties, true); |
| List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); |
| assertNotNull(batchRequestParts); |
| assertEquals(false, batchRequestParts.isEmpty()); |
| for (BatchRequestPart object : batchRequestParts) { |
| if (!object.isChangeSet()) { |
| assertEquals(1, object.getRequests().size()); |
| ODataRequest retrieveRequest = object.getRequests().get(0); |
| assertEquals(ODataHttpMethod.GET, retrieveRequest.getMethod()); |
| if (!retrieveRequest.getAcceptableLanguages().isEmpty()) { |
| assertEquals(3, retrieveRequest.getAcceptableLanguages().size()); |
| } |
| assertEquals(new URI(SERVICE_ROOT), retrieveRequest.getPathInfo().getServiceRoot()); |
| ODataPathSegmentImpl pathSegment = new ODataPathSegmentImpl("Employees('2')", null); |
| assertEquals(pathSegment.getPath(), retrieveRequest.getPathInfo().getODataSegments().get(0).getPath()); |
| if (retrieveRequest.getQueryParameters().get("$format") != null) { |
| assertEquals("json", retrieveRequest.getQueryParameters().get("$format")); |
| } |
| assertEquals(SERVICE_ROOT + "Employees('2')/EmployeeName?$format=json", retrieveRequest.getPathInfo() |
| .getRequestUri().toASCIIString()); |
| } else { |
| List<ODataRequest> requests = object.getRequests(); |
| for (ODataRequest request : requests) { |
| |
| assertEquals(ODataHttpMethod.PUT, request.getMethod()); |
| assertEquals("100000", request.getRequestHeaderValue(HttpHeaders.CONTENT_LENGTH.toLowerCase())); |
| assertEquals("application/json;odata=verbose", request.getContentType()); |
| assertEquals(3, request.getAcceptHeaders().size()); |
| assertNotNull(request.getAcceptableLanguages()); |
| assertTrue(request.getAcceptableLanguages().isEmpty()); |
| assertEquals("*/*", request.getAcceptHeaders().get(2)); |
| assertEquals("application/atomsvc+xml", request.getAcceptHeaders().get(0)); |
| assertEquals(new URI(SERVICE_ROOT + "Employees('2')/EmployeeName").toASCIIString(), request.getPathInfo() |
| .getRequestUri().toASCIIString()); |
| |
| ODataPathSegmentImpl pathSegment = new ODataPathSegmentImpl("Employees('2')", null); |
| assertEquals(pathSegment.getPath(), request.getPathInfo().getODataSegments().get(0).getPath()); |
| ODataPathSegmentImpl pathSegment2 = new ODataPathSegmentImpl("EmployeeName", null); |
| assertEquals(pathSegment2.getPath(), request.getPathInfo().getODataSegments().get(1).getPath()); |
| |
| } |
| } |
| } |
| } |
| |
| @Test |
| public void testImageInContent() throws IOException, BatchException, URISyntaxException { |
| String fileName = "/batchWithContent.batch"; |
| InputStream contentInputStream = ClassLoader.class.getResourceAsStream(fileName); |
| if (contentInputStream == null) { |
| throw new IOException("Requested file '" + fileName + "' was not found."); |
| } |
| String content = StringHelper.inputStreamToString(contentInputStream); |
| String batch = "--" + BOUNDARY + CRLF |
| + MIME_HEADERS |
| + CRLF |
| + "GET Employees?$filter=Age%20gt%2040 HTTP/1.1" + CRLF |
| + "Accept: application/atomsvc+xml;q=0.8, application/json;odata=verbose;q=0.5, */*;q=0.1" + CRLF |
| + "MaxDataServiceVersion: 2.0" + CRLF |
| + CRLF |
| + CRLF |
| + "--" + BOUNDARY + CRLF |
| + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd" + CRLF |
| + "content-type: Application/http" + CRLF |
| + "content-transfer-encoding: Binary" + CRLF |
| + "Content-ID: 1" + CRLF |
| + CRLF |
| + "POST Employees HTTP/1.1" + CRLF |
| + "Content-length: 100000" + CRLF |
| + "Content-type: application/octet-stream" + CRLF |
| + CRLF |
| + content + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd--" + CRLF |
| + "--" + BOUNDARY + "--"; |
| List<BatchRequestPart> BatchRequestParts = parse(batch); |
| for (BatchRequestPart object : BatchRequestParts) { |
| if (!object.isChangeSet()) { |
| assertEquals(1, object.getRequests().size()); |
| ODataRequest retrieveRequest = object.getRequests().get(0); |
| assertEquals(ODataHttpMethod.GET, retrieveRequest.getMethod()); |
| assertEquals("Age gt 40", retrieveRequest.getQueryParameters().get("$filter")); |
| assertEquals(new URI("http://localhost/odata/Employees?$filter=Age%20gt%2040"), retrieveRequest.getPathInfo() |
| .getRequestUri()); |
| } else { |
| List<ODataRequest> requests = object.getRequests(); |
| for (ODataRequest request : requests) { |
| assertEquals(ODataHttpMethod.POST, request.getMethod()); |
| assertEquals("100000", request.getRequestHeaderValue(HttpHeaders.CONTENT_LENGTH.toLowerCase())); |
| assertEquals("1", request.getRequestHeaderValue(BatchHelper.MIME_HEADER_CONTENT_ID)); |
| assertEquals("application/octet-stream", request.getContentType()); |
| InputStream body = request.getBody(); |
| assertEquals(content, StringHelper.inputStreamToString(body)); |
| |
| } |
| |
| } |
| } |
| } |
| |
| @Test |
| public void testPostWithoutBody() throws IOException, BatchException, URISyntaxException { |
| String fileName = "/batchWithContent.batch"; |
| InputStream contentInputStream = ClassLoader.class.getResourceAsStream(fileName); |
| if (contentInputStream == null) { |
| throw new IOException("Requested file '" + fileName + "' was not found."); |
| } |
| StringHelper.inputStreamToString(contentInputStream); |
| String batch = CRLF |
| + "--" + BOUNDARY + CRLF |
| + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd" + CRLF |
| + MIME_HEADERS |
| + "Content-ID: changeRequest1" + CRLF |
| + CRLF |
| + "POST Employees('2') HTTP/1.1" + CRLF |
| + "Content-Length: 100" + CRLF |
| + "Content-Type: application/octet-stream" + CRLF |
| + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd--" + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| List<BatchRequestPart> batchRequestParts = parse(batch); |
| for (BatchRequestPart object : batchRequestParts) { |
| if (object.isChangeSet()) { |
| List<ODataRequest> requests = object.getRequests(); |
| for (ODataRequest request : requests) { |
| assertEquals(ODataHttpMethod.POST, request.getMethod()); |
| assertEquals("100", request.getRequestHeaderValue(HttpHeaders.CONTENT_LENGTH.toLowerCase())); |
| assertEquals("application/octet-stream", request.getContentType()); |
| assertNotNull(request.getBody()); |
| } |
| } |
| } |
| } |
| |
| @Test |
| public void testBoundaryParameterWithQuotas() throws BatchException { |
| String contentType = "multipart/mixed; boundary=\"batch_1.2+34:2j)0?\""; |
| |
| String batch = "--batch_1.2+34:2j)0?" + CRLF |
| + GET_REQUEST |
| + "--batch_1.2+34:2j)0?--"; |
| InputStream in = new ByteArrayInputStream(batch.getBytes()); |
| BatchParser parser = new BatchParser(contentType, batchProperties, true); |
| List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); |
| assertNotNull(batchRequestParts); |
| assertEquals(false, batchRequestParts.isEmpty()); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testBatchWithInvalidContentType() throws BatchException { |
| String invalidContentType = "multipart;boundary=batch_1740-bb84-2f7f"; |
| |
| String batch = "--batch_1740-bb84-2f7f" + CRLF |
| + GET_REQUEST |
| + "--batch_1740-bb84-2f7f--"; |
| InputStream in = new ByteArrayInputStream(batch.getBytes()); |
| BatchParser parser = new BatchParser(invalidContentType, batchProperties, true); |
| parser.parseBatchRequest(in); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testBatchWithoutBoundaryParameter() throws BatchException { |
| String invalidContentType = "multipart/mixed"; |
| String batch = "--batch_1740-bb84-2f7f" + CRLF |
| + GET_REQUEST |
| + "--batch_1740-bb84-2f7f--"; |
| InputStream in = new ByteArrayInputStream(batch.getBytes()); |
| BatchParser parser = new BatchParser(invalidContentType, batchProperties, true); |
| parser.parseBatchRequest(in); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testBoundaryParameterWithoutQuota() throws BatchException { |
| String invalidContentType = "multipart/mixed;boundary=batch_1740-bb:84-2f7f"; |
| String batch = "--batch_1740-bb:84-2f7f" + CRLF |
| + GET_REQUEST |
| + "--batch_1740-bb:84-2f7f--"; |
| InputStream in = new ByteArrayInputStream(batch.getBytes()); |
| BatchParser parser = new BatchParser(invalidContentType, batchProperties, true); |
| parser.parseBatchRequest(in); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testWrongBoundaryString() throws BatchException { |
| String batch = "--batch_8194-cf13-1f5" + CRLF |
| + GET_REQUEST |
| + "--" + BOUNDARY + "--"; |
| parseInvalidBatchBody(batch); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testMissingHttpVersion() throws BatchException { |
| String batch = "" |
| + "--" + BOUNDARY + CRLF |
| + "Content-Type: application/http" + CRLF |
| + "Content-Transfer-Encoding:binary" + CRLF |
| + CRLF |
| + "GET Employees?$format=json" + CRLF |
| + "Host: localhost:8080" + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| |
| parseInvalidBatchBody(batch); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testMissingHttpVersion2() throws BatchException { |
| String batch = "" |
| + "--" + BOUNDARY + CRLF |
| + "Content-Type: application/http" + CRLF |
| + "Content-Transfer-Encoding:binary" + CRLF |
| + CRLF |
| + "GET Employees?$format=json " + CRLF |
| + "Host: localhost:8080" + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| |
| parseInvalidBatchBody(batch); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testMissingHttpVersion3() throws BatchException { |
| String batch = "" |
| + "--" + BOUNDARY + CRLF |
| + "Content-Type: application/http" + CRLF |
| + "Content-Transfer-Encoding:binary" + CRLF |
| + CRLF |
| + "GET Employees?$format=json SMTP:3.1" + CRLF |
| + "Host: localhost:8080" + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| |
| parseInvalidBatchBody(batch); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testBoundaryWithoutHyphen() throws BatchException { |
| String batch = "--" + BOUNDARY + CRLF |
| + GET_REQUEST |
| + BOUNDARY + CRLF |
| + GET_REQUEST |
| + "--" + BOUNDARY + "--"; |
| parseInvalidBatchBody(batch); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testNoBoundaryString() throws BatchException { |
| String batch = "--" + BOUNDARY + CRLF |
| + GET_REQUEST |
| // + no boundary string |
| + GET_REQUEST |
| + "--" + BOUNDARY + "--"; |
| |
| parseInvalidBatchBody(batch); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testBatchBoundaryEqualsChangeSetBoundary() throws BatchException { |
| String batch = "--" + BOUNDARY + CRLF |
| + "Content-Type: multipart/mixed;boundary=batch_8194-cf13-1f56" + CRLF |
| + CRLF |
| + "--" + BOUNDARY + CRLF |
| + MIME_HEADERS |
| + CRLF |
| + "PUT Employees('2')/EmployeeName HTTP/1.1" + CRLF |
| + "Accept: application/atomsvc+xml;q=0.8, application/json;odata=verbose;q=0.5, */*;q=0.1" + CRLF |
| + "Content-Type: application/json;odata=verbose" + CRLF |
| + "MaxDataServiceVersion: 2.0" + CRLF |
| + CRLF |
| + "{\"EmployeeName\":\"Frederic Fall MODIFIED\"}" + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| parseInvalidBatchBody(batch); |
| } |
| |
| @Test |
| public void testContentTypeCharset() throws BatchException { |
| final String contentType = "multipart/mixed; charset=UTF-8;boundary=" + BOUNDARY; |
| final String batch = "--" + BOUNDARY + CRLF |
| + GET_REQUEST |
| + "--" + BOUNDARY + "--"; |
| final BatchParser parser = new BatchParser(contentType, batchProperties, true); |
| final List<BatchRequestPart> parts = parser.parseBatchRequest(new ByteArrayInputStream(batch.getBytes())); |
| |
| assertEquals(1, parts.size()); |
| } |
| |
| @Test |
| public void testContentTypeCharsetWrongBoundaryAtEnd() throws BatchException { |
| final String contentType = "multipart/mixed; charset=UTF-8;boundary=" + BOUNDARY + ";boundary=wrong_boundary"; |
| final String batch = "--" + BOUNDARY + CRLF |
| + GET_REQUEST |
| + "--" + BOUNDARY + "--"; |
| final BatchParser parser = new BatchParser(contentType, batchProperties, true); |
| final List<BatchRequestPart> parts = parser.parseBatchRequest(new ByteArrayInputStream(batch.getBytes())); |
| |
| assertEquals(1, parts.size()); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testContentTypeCharsetWrongBoundaryAtBeginning() throws BatchException { |
| final String contentType = "multipart/mixed; charset=UTF-8;boundary=wrong_boundary;boundary=" + BOUNDARY; |
| final String batch = "--" + BOUNDARY + CRLF |
| + GET_REQUEST |
| + "--" + BOUNDARY + "--"; |
| final BatchParser parser = new BatchParser(contentType, batchProperties, true); |
| final List<BatchRequestPart> parts = parser.parseBatchRequest(new ByteArrayInputStream(batch.getBytes())); |
| |
| assertEquals(1, parts.size()); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testNoContentType() throws BatchException { |
| String batch = "--" + BOUNDARY + CRLF |
| + "Content-Transfer-Encoding: binary" + CRLF |
| + CRLF |
| + "GET Employees('1')/EmployeeName HTTP/1.1" + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| parseInvalidBatchBody(batch); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testMimeHeaderContentType() throws BatchException { |
| String batch = "--" + BOUNDARY + CRLF |
| + "Content-Type: text/plain" + CRLF |
| + "Content-Transfer-Encoding: binary" + CRLF |
| + CRLF |
| + "GET Employees('1')/EmployeeName HTTP/1.1" + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| parseInvalidBatchBody(batch); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testMimeHeaderEncoding() throws BatchException { |
| String batch = "--" + BOUNDARY + CRLF |
| + "Content-Type: application/http" + CRLF |
| + "Content-Transfer-Encoding: 8bit" + CRLF |
| + CRLF |
| + "GET Employees('1')/EmployeeName HTTP/1.1" + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| parseInvalidBatchBody(batch); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testGetRequestMissingCRLF() throws BatchException { |
| String batch = "--" + BOUNDARY + CRLF |
| + MIME_HEADERS |
| + "Content-ID: 1" + CRLF |
| + CRLF |
| + "GET Employees('1')/EmployeeName HTTP/1.1" + CRLF |
| // + CRLF // Belongs to the GET request |
| + CRLF // Belongs to the |
| + "--" + BOUNDARY + "--"; |
| |
| parseInvalidBatchBody(batch); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testInvalidMethodForBatch() throws BatchException { |
| String batch = "--" + BOUNDARY + CRLF |
| + MIME_HEADERS |
| + CRLF |
| + "POST Employees('1')/EmployeeName HTTP/1.1" + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| parseInvalidBatchBody(batch); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testNoBoundaryFound() throws BatchException { |
| String batch = "--" + BOUNDARY + CRLF |
| + MIME_HEADERS |
| + CRLF |
| + "POST Employees('1')/EmployeeName HTTP/1.1" + CRLF |
| + CRLF; |
| parseInvalidBatchBody(batch); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testBadRequest() throws BatchException { |
| String batch = "This is a bad request. There is no syntax and also no semantic"; |
| parseInvalidBatchBody(batch); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testNoMethod() throws BatchException { |
| String batch = "--" + BOUNDARY + CRLF |
| + MIME_HEADERS |
| + CRLF |
| + /* GET */"Employees('1')/EmployeeName HTTP/1.1" + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| parseInvalidBatchBody(batch); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testInvalidMethodForChangeset() throws BatchException { |
| String batch = "--" + BOUNDARY + CRLF |
| + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd" + CRLF |
| + MIME_HEADERS |
| + CRLF |
| + "GET Employees('2')/EmployeeName HTTP/1.1" + CRLF |
| + "Content-Type: application/json;odata=verbose" + CRLF |
| + "MaxDataServiceVersion: 2.0" + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| parseInvalidBatchBody(batch); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testInvalidChangeSetBoundary() throws BatchException { |
| String batch = "--" + BOUNDARY + CRLF |
| + "Content-Type: multipart/mixed;boundary=changeset_f980-1cb6-94dd" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94d"/* +"d" */+ CRLF |
| + MIME_HEADERS |
| + CRLF |
| + "POST Employees('2') HTTP/1.1" + CRLF |
| + "Content-Type: application/json;odata=verbose" + CRLF |
| + "MaxDataServiceVersion: 2.0" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd--" + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| parseInvalidBatchBody(batch); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testNestedChangeset() throws BatchException { |
| String batch = "--" + BOUNDARY + CRLF |
| + "Content-Type: multipart/mixed;boundary=changeset_f980-1cb6-94dd" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd" + CRLF |
| + MIME_HEADERS |
| + CRLF |
| + "Content-Type: multipart/mixed;boundary=changeset_f980-1cb6-94dd2" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd2" + CRLF |
| + MIME_HEADERS |
| + CRLF |
| + "POST Employees('2') HTTP/1.1" + CRLF |
| + "Content-Type: application/json;odata=verbose" + CRLF |
| + "MaxDataServiceVersion: 2.0" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd--" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd--" + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| parse(batch); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testMissingContentTransferEncoding() throws BatchException { |
| String batch = "--" + BOUNDARY + CRLF |
| + "Content-Type: multipart/mixed;boundary=changeset_f980-1cb6-94dd" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd" + CRLF |
| + "Content-Type: application/http" + CRLF |
| // + "Content-Transfer-Encoding: binary" + CRLF |
| + CRLF |
| + "POST Employees('2') HTTP/1.1" + CRLF |
| + "Content-Type: application/json;odata=verbose" + CRLF |
| + "MaxDataServiceVersion: 2.0" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd--" + CRLF |
| + "--" + BOUNDARY + "--"; |
| parseInvalidBatchBody(batch); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testMissingContentType() throws BatchException { |
| String batch = "--" + BOUNDARY + CRLF |
| + "Content-Type: multipart/mixed;boundary=changeset_f980-1cb6-94dd" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd" + CRLF |
| // + "Content-Type: application/http" + CRLF |
| + "Content-Transfer-Encoding: binary" + CRLF |
| + CRLF |
| + "POST Employees('2') HTTP/1.1" + CRLF |
| + "Content-Type: application/json;odata=verbose" + CRLF |
| + "MaxDataServiceVersion: 2.0" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd--" + CRLF |
| + "--" + BOUNDARY + "--"; |
| parseInvalidBatchBody(batch); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testNoCloseDelimiter() throws BatchException { |
| String batch = "--" + BOUNDARY + CRLF |
| + GET_REQUEST; |
| parseInvalidBatchBody(batch); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testNoCloseDelimiter2() throws BatchException { |
| String batch = "--" + BOUNDARY + CRLF |
| + MIME_HEADERS |
| + CRLF |
| + "GET Employees('1')/EmployeeName HTTP/1.1" + CRLF; |
| parseInvalidBatchBody(batch); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testInvalidUri() throws BatchException { |
| String batch = "--" + BOUNDARY + CRLF |
| + MIME_HEADERS |
| + CRLF |
| + "GET http://localhost/aa/odata/Employees('1')/EmployeeName HTTP/1.1" + CRLF |
| + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| parseInvalidBatchBody(batch); |
| } |
| |
| @Test |
| public void uriWithAbsolutePath() throws Exception { |
| final String batch = "--" + BOUNDARY + CRLF |
| + MIME_HEADERS |
| + CRLF |
| + "GET /odata/Employees('1')/EmployeeName HTTP/1.1" + CRLF |
| + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| final List<BatchRequestPart> batchRequestParts = parse(batch); |
| assertEquals(1, batchRequestParts.size()); |
| assertEquals(1, batchRequestParts.get(0).getRequests().size()); |
| final ODataRequest request = batchRequestParts.get(0).getRequests().get(0); |
| assertEquals(ODataHttpMethod.GET, request.getMethod()); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void uriWithWrongAbsolutePath() throws BatchException { |
| String batch = "--" + BOUNDARY + CRLF |
| + MIME_HEADERS |
| + CRLF |
| + "GET /wrong/Employees('1')/EmployeeName HTTP/1.1" + CRLF |
| + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| parseInvalidBatchBody(batch); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void wrongHost() throws BatchException { |
| String batch = "--" + BOUNDARY + CRLF |
| + MIME_HEADERS |
| + CRLF |
| + "GET /odata/Employees('1')/EmployeeName HTTP/1.1" + CRLF |
| + "Host: wrongHost" + CRLF |
| + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| parseInvalidBatchBody(batch); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testNoCloseDelimiter3() throws BatchException { |
| String batch = "--" + BOUNDARY + CRLF |
| + GET_REQUEST + "--" + BOUNDARY + "-"; |
| parseInvalidBatchBody(batch); |
| } |
| |
| @Test |
| public void testAcceptHeaders() throws BatchException, URISyntaxException { |
| String batch = "--" + BOUNDARY + CRLF |
| + MIME_HEADERS |
| + CRLF |
| + "GET Employees('2')/EmployeeName HTTP/1.1" |
| + CRLF |
| + "Content-Length: 100000" |
| + CRLF |
| + "Content-Type: application/json;odata=verbose" |
| + CRLF |
| + "Accept: application/xml;q=0.3, application/atomsvc+xml;q=0.8, " + |
| "application/json;odata=verbose;q=0.5, */*;q=0.001" |
| + CRLF |
| + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| List<BatchRequestPart> batchRequestParts = parse(batch); |
| for (BatchRequestPart multipart : batchRequestParts) { |
| if (!multipart.isChangeSet()) { |
| assertEquals(1, multipart.getRequests().size()); |
| ODataRequest retrieveRequest = multipart.getRequests().get(0); |
| assertEquals(ODataHttpMethod.GET, retrieveRequest.getMethod()); |
| assertNotNull(retrieveRequest.getAcceptHeaders()); |
| assertEquals(4, retrieveRequest.getAcceptHeaders().size()); |
| assertEquals("application/atomsvc+xml", retrieveRequest.getAcceptHeaders().get(0)); |
| assertEquals("*/*", retrieveRequest.getAcceptHeaders().get(3)); |
| } |
| |
| } |
| } |
| |
| @Test |
| public void testAcceptHeaders2() throws BatchException, URISyntaxException { |
| String batch = "--" + BOUNDARY + CRLF |
| + MIME_HEADERS |
| + CRLF |
| + "GET Employees('2')/EmployeeName HTTP/1.1" + CRLF |
| + "Content-Length: 100000" + CRLF |
| + "Content-Type: application/json;odata=verbose" + CRLF |
| + "Accept: */*;q=0.5, application/json;odata=verbose;q=1.0,application/atom+xml" + CRLF |
| + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| List<BatchRequestPart> batchRequestParts = parse(batch); |
| for (BatchRequestPart multipart : batchRequestParts) { |
| if (!multipart.isChangeSet()) { |
| assertEquals(1, multipart.getRequests().size()); |
| ODataRequest retrieveRequest = multipart.getRequests().get(0); |
| assertEquals(ODataHttpMethod.GET, retrieveRequest.getMethod()); |
| assertNotNull(retrieveRequest.getAcceptHeaders()); |
| assertEquals(3, retrieveRequest.getAcceptHeaders().size()); |
| assertEquals("application/json;odata=verbose", retrieveRequest.getAcceptHeaders().get(0)); |
| assertEquals("application/atom+xml", retrieveRequest.getAcceptHeaders().get(1)); |
| assertEquals("*/*", retrieveRequest.getAcceptHeaders().get(2)); |
| } |
| |
| } |
| } |
| |
| @Test |
| public void testAcceptHeaders3() throws BatchException, URISyntaxException { |
| String batch = "--" + BOUNDARY + CRLF |
| + MIME_HEADERS |
| + CRLF |
| + "GET Employees('2')/EmployeeName HTTP/1.1" + CRLF |
| + "Content-Length: 100000" + CRLF |
| + "Content-Type: application/json;odata=verbose" + CRLF |
| + "accept: */*,application/atom+xml,application/atomsvc+xml,application/xml" + CRLF |
| + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| List<BatchRequestPart> batchRequestParts = parse(batch); |
| for (BatchRequestPart multipart : batchRequestParts) { |
| if (!multipart.isChangeSet()) { |
| assertEquals(1, multipart.getRequests().size()); |
| ODataRequest retrieveRequest = multipart.getRequests().get(0); |
| assertEquals(ODataHttpMethod.GET, retrieveRequest.getMethod()); |
| assertNotNull(retrieveRequest.getAcceptHeaders()); |
| assertEquals(4, retrieveRequest.getAcceptHeaders().size()); |
| |
| assertEquals("application/atom+xml", retrieveRequest.getAcceptHeaders().get(0)); |
| assertEquals("application/atomsvc+xml", retrieveRequest.getAcceptHeaders().get(1)); |
| |
| assertEquals("application/xml", retrieveRequest.getAcceptHeaders().get(2)); |
| } |
| |
| } |
| } |
| |
| @Test |
| public void testNegativeContentLengthChangeSet() throws BatchException, IOException { |
| String batch = "--" + BOUNDARY + CRLF |
| + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd" + CRLF |
| + MIME_HEADERS |
| + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF |
| + "Content-Length: -2" + CRLF |
| + CRLF |
| + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF |
| + "Content-Type: application/json;odata=verbose" + CRLF |
| + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF |
| + CRLF |
| + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF |
| + "--changeset_f980-1cb6-94dd--" + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| InputStream in = new ByteArrayInputStream(batch.getBytes()); |
| BatchParser parser = new BatchParser(contentType, batchProperties, true); |
| parser.parseBatchRequest(in); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testNegativeContentLengthRequest() throws BatchException, IOException { |
| String batch = "--" + BOUNDARY + CRLF |
| + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd" + CRLF |
| + MIME_HEADERS |
| + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF |
| + CRLF |
| + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF |
| + "Content-Type: application/json;odata=verbose" + CRLF |
| + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF |
| + "Content-Length: -2" + CRLF |
| + CRLF |
| + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF |
| + "--changeset_f980-1cb6-94dd--" + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| InputStream in = new ByteArrayInputStream(batch.getBytes()); |
| BatchParser parser = new BatchParser(contentType, batchProperties, true); |
| parser.parseBatchRequest(in); |
| } |
| |
| @Test |
| public void testContentLengthGreatherThanBodyLength() throws BatchException, IOException { |
| String batch = "--" + BOUNDARY + CRLF |
| + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd" + CRLF |
| + MIME_HEADERS |
| + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF |
| + CRLF |
| + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF |
| + "Content-Type: application/json;odata=verbose" + CRLF |
| + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF |
| + "Content-Length: 100000" + CRLF |
| + CRLF |
| + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF |
| + "--changeset_f980-1cb6-94dd--" + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| InputStream in = new ByteArrayInputStream(batch.getBytes()); |
| BatchParser parser = new BatchParser(contentType, batchProperties, true); |
| List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); |
| assertNotNull(batchRequestParts); |
| for (BatchRequestPart multipart : batchRequestParts) { |
| if (multipart.isChangeSet()) { |
| assertEquals(1, multipart.getRequests().size()); |
| ODataRequest request = multipart.getRequests().get(0); |
| assertEquals("{\"EmployeeName\":\"Peter Fall\"}", inputStreamToString(request.getBody())); |
| } |
| } |
| } |
| |
| @Test |
| public void testContentLengthSmallerThanBodyLength() throws BatchException, IOException { |
| String batch = "--" + BOUNDARY + CRLF |
| + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd" + CRLF |
| + MIME_HEADERS |
| + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF |
| + CRLF |
| + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF |
| + "Content-Type: application/json;odata=verbose" + CRLF |
| + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF |
| + "Content-Length: 10" + CRLF |
| + CRLF |
| + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF |
| + "--changeset_f980-1cb6-94dd--" + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| InputStream in = new ByteArrayInputStream(batch.getBytes()); |
| BatchParser parser = new BatchParser(contentType, batchProperties, true); |
| List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); |
| assertNotNull(batchRequestParts); |
| for (BatchRequestPart multipart : batchRequestParts) { |
| if (multipart.isChangeSet()) { |
| assertEquals(1, multipart.getRequests().size()); |
| ODataRequest request = multipart.getRequests().get(0); |
| assertEquals("{\"Employee", inputStreamToString(request.getBody())); |
| } |
| } |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testNonNumericContentLength() throws BatchException { |
| String batch = "--" + BOUNDARY + CRLF |
| + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd" + CRLF |
| + MIME_HEADERS |
| + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF |
| + CRLF |
| + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF |
| + "Content-Type: application/json;odata=verbose" + CRLF |
| + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF |
| + "Content-Length: 10abc" + CRLF |
| + CRLF |
| + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF |
| + "--changeset_f980-1cb6-94dd--" + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| InputStream in = new ByteArrayInputStream(batch.getBytes()); |
| BatchParser parser = new BatchParser(contentType, batchProperties, true); |
| parser.parseBatchRequest(in); |
| } |
| |
| @Test |
| public void testNonStrictParser() throws BatchException, IOException { |
| String batch = "--" + BOUNDARY + CRLF |
| + "Content-Type: multipart/mixed;boundary=changeset_8194-cf13-1f56" + CRLF |
| + "--changeset_8194-cf13-1f56" + CRLF |
| + MIME_HEADERS |
| + "Content-ID: myRequest" + CRLF |
| + "PUT Employees('2')/EmployeeName HTTP/1.1" + CRLF |
| + "Accept: application/atomsvc+xml;q=0.8, application/json;odata=verbose;q=0.5, */*;q=0.1" + CRLF |
| + "Content-Type: application/json;odata=verbose" + CRLF |
| + "MaxDataServiceVersion: 2.0" + CRLF |
| + "{\"EmployeeName\":\"Frederic Fall MODIFIED\"}" + CRLF |
| + "--changeset_8194-cf13-1f56--" + CRLF |
| + "--" + BOUNDARY + "--"; |
| |
| InputStream in = new ByteArrayInputStream(batch.getBytes()); |
| BatchParser parser = new BatchParser(contentType, batchProperties, false); |
| List<BatchRequestPart> requests = parser.parseBatchRequest(in); |
| assertNotNull(requests); |
| assertEquals(1, requests.size()); |
| |
| BatchRequestPart part = requests.get(0); |
| assertTrue(part.isChangeSet()); |
| assertNotNull(part.getRequests()); |
| assertEquals(1, part.getRequests().size()); |
| |
| ODataRequest changeRequest = part.getRequests().get(0); |
| assertEquals("{\"EmployeeName\":\"Frederic Fall MODIFIED\"}", inputStreamToString(changeRequest.getBody())); |
| assertEquals("application/json;odata=verbose", changeRequest.getContentType()); |
| assertEquals(ODataHttpMethod.PUT, changeRequest.getMethod()); |
| } |
| |
| @Test(expected = BatchException.class) |
| public void testNonStrictParserMoreCRLF() throws BatchException { |
| String batch = "--" + BOUNDARY + CRLF |
| + "Content-Type: multipart/mixed;boundary=changeset_8194-cf13-1f56" + CRLF |
| + "--changeset_8194-cf13-1f56" + CRLF |
| + MIME_HEADERS |
| + CRLF |
| + CRLF // Only one CRLF allowed |
| + "PUT Employees('2')/EmployeeName HTTP/1.1" + CRLF |
| + "Accept: application/atomsvc+xml;q=0.8, application/json;odata=verbose;q=0.5, */*;q=0.1" + CRLF |
| + "Content-Type: application/json;odata=verbose" + CRLF |
| + "MaxDataServiceVersion: 2.0" + CRLF |
| + "{\"EmployeeName\":\"Frederic Fall MODIFIED\"}" + CRLF |
| + "--changeset_8194-cf13-1f56--" + CRLF |
| + "--" + BOUNDARY + "--"; |
| |
| InputStream in = new ByteArrayInputStream(batch.getBytes()); |
| BatchParser parser = new BatchParser(contentType, batchProperties, false); |
| parser.parseBatchRequest(in); |
| } |
| |
| @Test |
| public void testContentId() throws BatchException { |
| String batch = "--" + BOUNDARY + CRLF |
| + MIME_HEADERS |
| + CRLF |
| + "GET Employees HTTP/1.1" + CRLF |
| + "accept: */*,application/atom+xml,application/atomsvc+xml,application/xml" + CRLF |
| + "Content-Id: BBB" + CRLF |
| + CRLF + CRLF |
| + "--batch_8194-cf13-1f56" + CRLF |
| + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd" + CRLF |
| + MIME_HEADERS |
| + "Content-Id: " + CONTENT_ID_REFERENCE + CRLF |
| + CRLF |
| + "POST Employees HTTP/1.1" + CRLF |
| + "Content-type: application/octet-stream" + CRLF |
| + CRLF |
| + "/9j/4AAQSkZJRgABAQEBLAEsAAD/4RM0RXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUAAAABAAAAYgEbAAUAAAA" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd" + CRLF |
| + MIME_HEADERS |
| + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF |
| + CRLF |
| + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF |
| + "Content-Type: application/json;odata=verbose" + CRLF |
| + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF |
| + CRLF |
| + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF |
| + "--changeset_f980-1cb6-94dd--" + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| InputStream in = new ByteArrayInputStream(batch.getBytes()); |
| BatchParser parser = new BatchParser(contentType, batchProperties, true); |
| List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); |
| assertNotNull(batchRequestParts); |
| for (BatchRequestPart multipart : batchRequestParts) { |
| if (!multipart.isChangeSet()) { |
| assertEquals(1, multipart.getRequests().size()); |
| ODataRequest retrieveRequest = multipart.getRequests().get(0); |
| assertEquals("BBB", retrieveRequest.getRequestHeaderValue(BatchHelper.REQUEST_HEADER_CONTENT_ID.toLowerCase())); |
| } else { |
| for (ODataRequest request : multipart.getRequests()) { |
| if (ODataHttpMethod.POST.equals(request.getMethod())) { |
| assertEquals(CONTENT_ID_REFERENCE, request.getRequestHeaderValue(BatchHelper.MIME_HEADER_CONTENT_ID |
| .toLowerCase())); |
| } else if (ODataHttpMethod.PUT.equals(request.getMethod())) { |
| assertEquals(PUT_MIME_HEADER_CONTENT_ID, request.getRequestHeaderValue(BatchHelper.MIME_HEADER_CONTENT_ID |
| .toLowerCase())); |
| assertEquals(PUT_REQUEST_HEADER_CONTENT_ID, request |
| .getRequestHeaderValue(BatchHelper.REQUEST_HEADER_CONTENT_ID.toLowerCase())); |
| assertNull(request.getPathInfo().getRequestUri()); |
| assertEquals("$" + CONTENT_ID_REFERENCE, request.getPathInfo().getODataSegments().get(0).getPath()); |
| } |
| } |
| } |
| } |
| } |
| |
| @Test |
| public void testNoContentId() throws BatchException { |
| String batch = "--" + BOUNDARY + CRLF |
| + MIME_HEADERS |
| + CRLF |
| + "GET Employees HTTP/1.1" + CRLF |
| + "accept: */*,application/atom+xml,application/atomsvc+xml,application/xml" + CRLF |
| + CRLF + CRLF |
| + "--batch_8194-cf13-1f56" + CRLF |
| + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd" + CRLF |
| + MIME_HEADERS |
| + CRLF |
| + "POST Employees HTTP/1.1" + CRLF |
| + "Content-type: application/octet-stream" + CRLF |
| + CRLF |
| + "/9j/4AAQSkZJRgABAQEBLAEsAAD/4RM0RXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUAAAABAAAAYgEbAAUAAAA" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd" + CRLF |
| + MIME_HEADERS |
| + CRLF |
| + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF |
| + "Content-Type: application/json;odata=verbose" + CRLF |
| + CRLF |
| + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF |
| + "--changeset_f980-1cb6-94dd--" + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| InputStream in = new ByteArrayInputStream(batch.getBytes()); |
| BatchParser parser = new BatchParser(contentType, batchProperties, true); |
| List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); // No exception should be thrown |
| assertNotNull(batchRequestParts); |
| } |
| |
| @Test |
| public void testPreamble() throws BatchException, IOException { |
| String batch = "" |
| + "This is a preamble and must be ignored" + CRLF |
| + CRLF |
| + CRLF |
| + "----1242" + CRLF |
| + "--" + BOUNDARY + CRLF |
| + MIME_HEADERS |
| + CRLF |
| + "GET Employees HTTP/1.1" + CRLF |
| + "accept: */*,application/atom+xml,application/atomsvc+xml,application/xml" + CRLF |
| + "Content-Id: BBB" + CRLF |
| + CRLF |
| + CRLF |
| + "--batch_8194-cf13-1f56" + CRLF |
| + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF |
| + CRLF |
| + "This is a preamble and must be ignored" + CRLF |
| + CRLF |
| + CRLF |
| + "----1242" + CRLF |
| + "--changeset_f980-1cb6-94dd" + CRLF |
| + MIME_HEADERS |
| + "Content-Id: " + CONTENT_ID_REFERENCE + CRLF |
| + CRLF |
| + "POST Employees HTTP/1.1" + CRLF |
| + "Content-type: application/octet-stream" + CRLF |
| + CRLF |
| + "/9j/4AAQSkZJRgABAQEBLAEsAAD/4RM0RXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUAAAABAAAAYgEbAAUAAAA" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd" + CRLF |
| + MIME_HEADERS |
| + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF |
| + CRLF |
| + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF |
| + "Content-Type: application/json;odata=verbose" + CRLF |
| + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF |
| + CRLF |
| + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF |
| + "--changeset_f980-1cb6-94dd--" + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| InputStream in = new ByteArrayInputStream(batch.getBytes()); |
| BatchParser parser = new BatchParser(contentType, batchProperties, true); |
| List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); |
| |
| assertNotNull(batchRequestParts); |
| assertEquals(2, batchRequestParts.size()); |
| |
| BatchRequestPart getRequestPart = batchRequestParts.get(0); |
| assertEquals(1, getRequestPart.getRequests().size()); |
| ODataRequest getRequest = getRequestPart.getRequests().get(0); |
| assertEquals(ODataHttpMethod.GET, getRequest.getMethod()); |
| |
| BatchRequestPart changeSetPart = batchRequestParts.get(1); |
| assertEquals(2, changeSetPart.getRequests().size()); |
| assertEquals("/9j/4AAQSkZJRgABAQEBLAEsAAD/4RM0RXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUAAAABAAAAYgEbAAUAAAA" |
| + CRLF, |
| inputStreamToString(changeSetPart.getRequests().get(0).getBody())); |
| assertEquals("{\"EmployeeName\":\"Peter Fall\"}", |
| inputStreamToString(changeSetPart.getRequests().get(1).getBody())); |
| } |
| |
| @SuppressWarnings("unused") |
| @Test |
| public void testContentTypeCaseInsensitive() throws BatchException, IOException { |
| String batch = "--" + BOUNDARY + CRLF |
| + "Content-Type: muLTiParT/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd" + CRLF |
| + MIME_HEADERS |
| + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF |
| + "Content-Length: -2" + CRLF |
| + CRLF |
| + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF |
| + "Content-Type: application/json;odata=verbose" + CRLF |
| + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF |
| + CRLF |
| + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF |
| + "--changeset_f980-1cb6-94dd--" + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| InputStream in = new ByteArrayInputStream(batch.getBytes()); |
| BatchParser parser = new BatchParser(contentType, batchProperties, true); |
| List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); |
| } |
| |
| @Test |
| public void testContentTypeBoundaryCaseInsensitive() throws BatchException, IOException { |
| String batch = "--" + BOUNDARY + CRLF |
| + "Content-Type: multipart/mixed; bOunDaRy=changeset_f980-1cb6-94dd" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd" + CRLF |
| + MIME_HEADERS |
| + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF |
| + "Content-Length: -2" + CRLF |
| + CRLF |
| + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF |
| + "Content-Type: application/json;odata=verbose" + CRLF |
| + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF |
| + CRLF |
| + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF |
| + "--changeset_f980-1cb6-94dd--" + CRLF |
| + CRLF |
| + "--" + BOUNDARY + "--"; |
| InputStream in = new ByteArrayInputStream(batch.getBytes()); |
| BatchParser parser = new BatchParser(contentType, batchProperties, true); |
| List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); |
| |
| assertNotNull(batchRequestParts); |
| assertEquals(1, batchRequestParts.size()); |
| assertTrue(batchRequestParts.get(0).isChangeSet()); |
| assertEquals(1, batchRequestParts.get(0).getRequests().size()); |
| } |
| |
| @Test |
| public void testEpilog() throws BatchException, IOException { |
| String batch = "--" + BOUNDARY + CRLF |
| + MIME_HEADERS |
| + CRLF |
| + "GET Employees HTTP/1.1" + CRLF |
| + "accept: */*,application/atom+xml,application/atomsvc+xml,application/xml" + CRLF |
| + "Content-Id: BBB" + CRLF |
| + CRLF |
| + CRLF |
| + "--batch_8194-cf13-1f56" + CRLF |
| + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd" + CRLF |
| + MIME_HEADERS |
| + "Content-Id: " + CONTENT_ID_REFERENCE + CRLF |
| + CRLF |
| + "POST Employees HTTP/1.1" + CRLF |
| + "Content-type: application/octet-stream" + CRLF |
| + CRLF |
| + "/9j/4AAQSkZJRgABAQEBLAEsAAD/4RM0RXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUAAAABAAAAYgEbAAUAAAA" + CRLF |
| + CRLF |
| + "--changeset_f980-1cb6-94dd" + CRLF |
| + MIME_HEADERS |
| + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF |
| + CRLF |
| + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF |
| + "Content-Type: application/json;odata=verbose" + CRLF |
| + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF |
| + CRLF |
| + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF |
| + "--changeset_f980-1cb6-94dd--" + CRLF |
| + CRLF |
| + "This is an epilog and must be ignored" + CRLF |
| + CRLF |
| + CRLF |
| + "----1242" + CRLF |
| + "--" + BOUNDARY + "--" + CRLF |
| + "This is an epilog and must be ignored" + CRLF |
| + CRLF |
| + CRLF |
| + "----1242"; |
| |
| InputStream in = new ByteArrayInputStream(batch.getBytes()); |
| BatchParser parser = new BatchParser(contentType, batchProperties, true); |
| List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); |
| |
| assertNotNull(batchRequestParts); |
| assertEquals(2, batchRequestParts.size()); |
| |
| BatchRequestPart getRequestPart = batchRequestParts.get(0); |
| assertEquals(1, getRequestPart.getRequests().size()); |
| ODataRequest getRequest = getRequestPart.getRequests().get(0); |
| assertEquals(ODataHttpMethod.GET, getRequest.getMethod()); |
| |
| BatchRequestPart changeSetPart = batchRequestParts.get(1); |
| assertEquals(2, changeSetPart.getRequests().size()); |
| assertEquals("/9j/4AAQSkZJRgABAQEBLAEsAAD/4RM0RXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUAAAABAAAAYgEbAAUAAAA" |
| + CRLF, |
| inputStreamToString(changeSetPart.getRequests().get(0).getBody())); |
| assertEquals("{\"EmployeeName\":\"Peter Fall\"}", |
| inputStreamToString(changeSetPart.getRequests().get(1).getBody())); |
| } |
| |
| @Test |
| public void testLargeBatch() throws BatchException, IOException { |
| String fileName = "/batchLarge.batch"; |
| InputStream in = ClassLoader.class.getResourceAsStream(fileName); |
| if (in == null) { |
| throw new IOException("Requested file '" + fileName + "' was not found."); |
| } |
| in = StringHelper.toStream(in).asStreamWithLineSeparation(CRLF); |
| BatchParser parser = new BatchParser(contentType, batchProperties, true); |
| parser.parseBatchRequest(in); |
| } |
| |
| @Test |
| public void testNonStrictGetRequestWithMissingCRLF() throws BatchException { |
| String batch = "--" + BOUNDARY + CRLF |
| + MIME_HEADERS |
| + "Content-ID: 1" + CRLF |
| + CRLF |
| + "GET Employees('1')/EmployeeName HTTP/1.1" + CRLF |
| // + CRLF // Belongs to the GET request |
| + CRLF // Belongs to the |
| + "--" + BOUNDARY + "--"; |
| |
| parse(batch, false); |
| } |
| |
| private List<BatchRequestPart> parse(final String batch) throws BatchException { |
| return parse(batch, true); |
| } |
| |
| private List<BatchRequestPart> parse(final String batch, final boolean isStrict) throws BatchException { |
| InputStream in = new ByteArrayInputStream(batch.getBytes()); |
| BatchParser parser = new BatchParser(contentType, batchProperties, isStrict); |
| List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); |
| assertNotNull(batchRequestParts); |
| assertEquals(false, batchRequestParts.isEmpty()); |
| return batchRequestParts; |
| } |
| |
| private void parseInvalidBatchBody(final String batch) throws BatchException { |
| InputStream in = new ByteArrayInputStream(batch.getBytes()); |
| BatchParser parser = new BatchParser(contentType, batchProperties, true); |
| parser.parseBatchRequest(in); |
| } |
| |
| private String inputStreamToString(final InputStream in) throws IOException { |
| int input; |
| final StringBuilder builder = new StringBuilder(); |
| |
| while ((input = in.read()) != -1) { |
| builder.append((char) input); |
| } |
| |
| return builder.toString(); |
| } |
| } |