You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by fm...@apache.org on 2013/07/26 13:22:12 UTC

[07/51] [partial] initial commit

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/test/java/org/apache/olingo/odata2/core/ODataRequestHandlerValidationTest.java
----------------------------------------------------------------------
diff --git a/odata-core/src/test/java/org/apache/olingo/odata2/core/ODataRequestHandlerValidationTest.java b/odata-core/src/test/java/org/apache/olingo/odata2/core/ODataRequestHandlerValidationTest.java
new file mode 100644
index 0000000..4658cf0
--- /dev/null
+++ b/odata-core/src/test/java/org/apache/olingo/odata2/core/ODataRequestHandlerValidationTest.java
@@ -0,0 +1,682 @@
+/*******************************************************************************
+ * 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;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.olingo.odata2.api.ODataService;
+import org.apache.olingo.odata2.api.ODataServiceFactory;
+import org.apache.olingo.odata2.api.commons.HttpContentType;
+import org.apache.olingo.odata2.api.commons.HttpStatusCodes;
+import org.apache.olingo.odata2.api.commons.ODataHttpHeaders;
+import org.apache.olingo.odata2.api.commons.ODataHttpMethod;
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.edm.EdmEntityType;
+import org.apache.olingo.odata2.api.edm.EdmFacets;
+import org.apache.olingo.odata2.api.edm.EdmFunctionImport;
+import org.apache.olingo.odata2.api.edm.EdmProperty;
+import org.apache.olingo.odata2.api.edm.EdmSimpleTypeKind;
+import org.apache.olingo.odata2.api.exception.ODataException;
+import org.apache.olingo.odata2.api.processor.ODataContext;
+import org.apache.olingo.odata2.api.processor.ODataProcessor;
+import org.apache.olingo.odata2.api.processor.ODataRequest;
+import org.apache.olingo.odata2.api.processor.ODataResponse;
+import org.apache.olingo.odata2.api.processor.part.BatchProcessor;
+import org.apache.olingo.odata2.api.processor.part.EntityComplexPropertyProcessor;
+import org.apache.olingo.odata2.api.processor.part.EntityLinkProcessor;
+import org.apache.olingo.odata2.api.processor.part.EntityLinksProcessor;
+import org.apache.olingo.odata2.api.processor.part.EntityMediaProcessor;
+import org.apache.olingo.odata2.api.processor.part.EntityProcessor;
+import org.apache.olingo.odata2.api.processor.part.EntitySetProcessor;
+import org.apache.olingo.odata2.api.processor.part.EntitySimplePropertyProcessor;
+import org.apache.olingo.odata2.api.processor.part.EntitySimplePropertyValueProcessor;
+import org.apache.olingo.odata2.api.processor.part.FunctionImportProcessor;
+import org.apache.olingo.odata2.api.processor.part.FunctionImportValueProcessor;
+import org.apache.olingo.odata2.api.processor.part.MetadataProcessor;
+import org.apache.olingo.odata2.api.processor.part.ServiceDocumentProcessor;
+import org.apache.olingo.odata2.api.uri.PathInfo;
+import org.apache.olingo.odata2.api.uri.PathSegment;
+import org.apache.olingo.odata2.api.uri.UriParser;
+import org.apache.olingo.odata2.core.commons.ContentType;
+import org.apache.olingo.odata2.core.commons.ContentType.ODataFormat;
+import org.apache.olingo.odata2.core.uri.UriInfoImpl;
+import org.apache.olingo.odata2.core.uri.UriType;
+import org.apache.olingo.odata2.testutil.fit.BaseTest;
+import org.apache.olingo.odata2.testutil.mock.MockFacade;
+
+/**
+ * Tests for the validation of HTTP method, URI path, query options,
+ * and request-body content type.
+ * @author SAP AG
+ */
+public class ODataRequestHandlerValidationTest extends BaseTest {
+
+  private Edm edm = null;
+
+  @Before
+  public void setEdm() throws ODataException {
+    edm = MockFacade.getMockEdm();
+  }
+
+  private List<String> createPathSegments(final UriType uriType, final boolean moreNavigation, final boolean isValue) {
+    List<String> segments = new ArrayList<String>();
+
+    if (uriType == UriType.URI1 || uriType == UriType.URI15) {
+      if (moreNavigation) {
+        segments.add("Managers('1')");
+        segments.add("nm_Employees");
+      } else {
+        segments.add("Employees");
+      }
+    } else if (uriType == UriType.URI2 || uriType == UriType.URI3
+        || uriType == UriType.URI4 || uriType == UriType.URI5
+        || uriType == UriType.URI16 || uriType == UriType.URI17) {
+      if (moreNavigation) {
+        segments.add("Managers('1')");
+        segments.add("nm_Employees('1')");
+      } else {
+        segments.add("Employees('1')");
+      }
+    } else if (uriType == UriType.URI6A || uriType == UriType.URI7A || uriType == UriType.URI50A) {
+      segments.add("Managers('1')");
+      if (moreNavigation) {
+        segments.add("nm_Employees('1')");
+        segments.add("ne_Manager");
+      }
+      if (uriType == UriType.URI7A || uriType == UriType.URI50A) {
+        segments.add("$links");
+      }
+      segments.add("nm_Employees('1')");
+    } else if (uriType == UriType.URI6B || uriType == UriType.URI7B || uriType == UriType.URI50B) {
+      segments.add("Managers('1')");
+      if (moreNavigation) {
+        segments.add("nm_Employees('1')");
+        segments.add("ne_Manager");
+      }
+      if (uriType == UriType.URI7B || uriType == UriType.URI50B) {
+        segments.add("$links");
+      }
+      segments.add("nm_Employees");
+    } else if (uriType == UriType.URI8) {
+      segments.add("$metadata");
+    } else if (uriType == UriType.URI9) {
+      segments.add("$batch");
+    } else if (uriType == UriType.URI10) {
+      segments.add("OldestEmployee");
+    } else if (uriType == UriType.URI11) {
+      segments.add("AllLocations");
+    } else if (uriType == UriType.URI12) {
+      segments.add("MostCommonLocation");
+    } else if (uriType == UriType.URI13) {
+      segments.add("AllUsedRoomIds");
+    } else if (uriType == UriType.URI14) {
+      segments.add("MaximalAge");
+    }
+
+    if (uriType == UriType.URI3 || uriType == UriType.URI4) {
+      segments.add("Location");
+    }
+    if (uriType == UriType.URI4) {
+      segments.add("Country");
+    } else if (uriType == UriType.URI5) {
+      segments.add("EmployeeName");
+    }
+
+    if (uriType == UriType.URI15 || uriType == UriType.URI16
+        || uriType == UriType.URI50A || uriType == UriType.URI50B) {
+      segments.add("$count");
+    }
+
+    if (uriType == UriType.URI17 || isValue) {
+      segments.add("$value");
+    }
+
+    // self-test
+    try {
+      final UriInfoImpl uriInfo = (UriInfoImpl) UriParser.parse(edm,
+          MockFacade.getPathSegmentsAsODataPathSegmentMock(segments),
+          Collections.<String, String> emptyMap());
+      assertEquals(uriType, uriInfo.getUriType());
+      assertEquals(uriType == UriType.URI17 || isValue, uriInfo.isValue());
+    } catch (final ODataException e) {
+      fail();
+    }
+
+    return segments;
+  }
+
+  private static Map<String, String> createOptions(
+      final boolean format,
+      final boolean filter, final boolean inlineCount, final boolean orderBy,
+      final boolean skipToken, final boolean skip, final boolean top,
+      final boolean expand, final boolean select) {
+
+    Map<String, String> map = new HashMap<String, String>();
+
+    if (format) {
+      map.put("$format", ODataFormat.XML.toString());
+    }
+    if (filter) {
+      map.put("$filter", "true");
+    }
+    if (inlineCount) {
+      map.put("$inlinecount", "none");
+    }
+    if (orderBy) {
+      map.put("$orderby", "Age");
+    }
+    if (skipToken) {
+      map.put("$skiptoken", "x");
+    }
+    if (skip) {
+      map.put("$skip", "0");
+    }
+    if (top) {
+      map.put("$top", "0");
+    }
+    if (expand) {
+      map.put("$expand", "ne_Team");
+    }
+    if (select) {
+      map.put("$select", "Age");
+    }
+
+    return map;
+  }
+
+  private ODataRequest mockODataRequest(
+      final ODataHttpMethod method,
+      final List<String> pathSegments,
+      final Map<String, String> queryParameters,
+      final String requestContentType) throws ODataException {
+    ODataRequest request = mock(ODataRequest.class);
+    when(request.getMethod()).thenReturn(method);
+    PathInfo pathInfo = mock(PathInfo.class);
+    List<PathSegment> segments = new ArrayList<PathSegment>();
+    for (final String pathSegment : pathSegments) {
+      PathSegment segment = mock(PathSegment.class);
+      when(segment.getPath()).thenReturn(pathSegment);
+      segments.add(segment);
+    }
+    when(pathInfo.getODataSegments()).thenReturn(segments);
+    when(request.getPathInfo()).thenReturn(pathInfo);
+    when(request.getQueryParameters())
+        .thenReturn(queryParameters == null ? new HashMap<String, String>() : queryParameters);
+    when(request.getContentType()).thenReturn(requestContentType);
+    return request;
+  }
+
+  private ODataService mockODataService(final ODataServiceFactory serviceFactory) throws ODataException {
+    ODataService service = DispatcherTest.getMockService();
+    when(service.getEntityDataModel()).thenReturn(edm);
+    when(service.getProcessor()).thenReturn(mock(ODataProcessor.class));
+    when(serviceFactory.createService(any(ODataContext.class))).thenReturn(service);
+
+    when(service.getSupportedContentTypes(BatchProcessor.class)).thenReturn(
+        Arrays.asList(HttpContentType.MULTIPART_MIXED));
+
+    when(service.getSupportedContentTypes(EntityProcessor.class)).thenReturn(Arrays.asList(
+        HttpContentType.APPLICATION_ATOM_XML_ENTRY_UTF8,
+        HttpContentType.APPLICATION_ATOM_XML_UTF8,
+        HttpContentType.APPLICATION_JSON_UTF8,
+        HttpContentType.APPLICATION_JSON_UTF8_VERBOSE,
+        HttpContentType.APPLICATION_XML_UTF8));
+
+    final List<String> jsonAndXml = Arrays.asList(
+        HttpContentType.APPLICATION_JSON_UTF8,
+        HttpContentType.APPLICATION_JSON_UTF8_VERBOSE,
+        HttpContentType.APPLICATION_XML_UTF8);
+    when(service.getSupportedContentTypes(FunctionImportProcessor.class)).thenReturn(jsonAndXml);
+    when(service.getSupportedContentTypes(EntityLinkProcessor.class)).thenReturn(jsonAndXml);
+    when(service.getSupportedContentTypes(EntityLinksProcessor.class)).thenReturn(jsonAndXml);
+    when(service.getSupportedContentTypes(EntitySimplePropertyProcessor.class)).thenReturn(jsonAndXml);
+    when(service.getSupportedContentTypes(EntityComplexPropertyProcessor.class)).thenReturn(jsonAndXml);
+
+    final List<String> wildcard = Arrays.asList(HttpContentType.WILDCARD);
+    when(service.getSupportedContentTypes(EntityMediaProcessor.class)).thenReturn(wildcard);
+    when(service.getSupportedContentTypes(EntitySimplePropertyValueProcessor.class)).thenReturn(wildcard);
+    when(service.getSupportedContentTypes(FunctionImportValueProcessor.class)).thenReturn(wildcard);
+
+    when(service.getSupportedContentTypes(EntitySetProcessor.class)).thenReturn(Arrays.asList(
+        HttpContentType.APPLICATION_ATOM_XML_FEED_UTF8,
+        HttpContentType.APPLICATION_ATOM_XML_UTF8,
+        HttpContentType.APPLICATION_JSON_UTF8,
+        HttpContentType.APPLICATION_JSON_UTF8_VERBOSE,
+        HttpContentType.APPLICATION_XML_UTF8));
+
+    when(service.getSupportedContentTypes(MetadataProcessor.class)).thenReturn(Arrays.asList(
+        HttpContentType.APPLICATION_XML_UTF8));
+
+    when(service.getSupportedContentTypes(ServiceDocumentProcessor.class)).thenReturn(Arrays.asList(
+        HttpContentType.APPLICATION_ATOM_SVC_UTF8,
+        HttpContentType.APPLICATION_JSON_UTF8,
+        HttpContentType.APPLICATION_JSON_UTF8_VERBOSE,
+        HttpContentType.APPLICATION_XML_UTF8));
+
+    return service;
+  }
+
+  private ODataResponse executeRequest(final ODataHttpMethod method,
+      final List<String> pathSegments,
+      final Map<String, String> queryParameters,
+      final String requestContentType) throws ODataException {
+    ODataServiceFactory serviceFactory = mock(ODataServiceFactory.class);
+    final ODataService service = mockODataService(serviceFactory);
+    when(serviceFactory.createService(any(ODataContext.class))).thenReturn(service);
+
+    final ODataRequest request = mockODataRequest(method, pathSegments, queryParameters, requestContentType);
+    final ODataContextImpl context = new ODataContextImpl(request, serviceFactory);
+
+    return new ODataRequestHandler(serviceFactory, service, context).handle(request);
+  }
+
+  private void executeAndValidateRequest(final ODataHttpMethod method,
+      final List<String> pathSegments,
+      final Map<String, String> queryParameters,
+      final String requestContentType,
+      final HttpStatusCodes expectedStatusCode) throws ODataException {
+
+    final ODataResponse response = executeRequest(method, pathSegments, queryParameters, requestContentType);
+    assertNotNull(response);
+    assertEquals(expectedStatusCode == null ? HttpStatusCodes.PAYMENT_REQUIRED : expectedStatusCode,
+        response.getStatus());
+  }
+
+  private void checkValueContentType(final ODataHttpMethod method, final UriType uriType, final String requestContentType) throws Exception {
+    executeAndValidateRequest(method, createPathSegments(uriType, false, true), null, requestContentType, null);
+  }
+
+  private void wrongRequest(final ODataHttpMethod method, final List<String> pathSegments, final Map<String, String> queryParameters) throws ODataException {
+    executeAndValidateRequest(method, pathSegments, queryParameters, null, HttpStatusCodes.METHOD_NOT_ALLOWED);
+  }
+
+  private void wrongOptions(final ODataHttpMethod method, final UriType uriType,
+      final boolean format,
+      final boolean filter, final boolean inlineCount, final boolean orderBy,
+      final boolean skipToken, final boolean skip, final boolean top,
+      final boolean expand, final boolean select) throws ODataException {
+    wrongRequest(method,
+        createPathSegments(uriType, false, false),
+        createOptions(format, filter, inlineCount, orderBy, skipToken, skip, top, expand, select));
+  }
+
+  private void wrongFunctionHttpMethod(final ODataHttpMethod method, final UriType uriType) throws ODataException {
+    wrongRequest(method,
+        uriType == UriType.URI1 ? Arrays.asList("EmployeeSearch") : createPathSegments(uriType, false, false),
+        null);
+  }
+
+  private void wrongProperty(final ODataHttpMethod method, final boolean ofComplex, final Boolean key) throws ODataException {
+    EdmProperty property = (EdmProperty) (ofComplex ?
+        edm.getComplexType("RefScenario", "c_Location").getProperty("Country") :
+        edm.getEntityType("RefScenario", "Employee").getProperty("Age"));
+    EdmFacets facets = mock(EdmFacets.class);
+    when(facets.isNullable()).thenReturn(false);
+    when(property.getFacets()).thenReturn(facets);
+
+    List<String> pathSegments;
+    if (ofComplex) {
+      pathSegments = createPathSegments(UriType.URI4, false, true);
+    } else {
+      pathSegments = createPathSegments(UriType.URI2, false, false);
+      pathSegments.add(key ? "EmployeeId" : "Age");
+      pathSegments.add("$value");
+    }
+
+    wrongRequest(method, pathSegments, null);
+  }
+
+  private void wrongNavigationPath(final ODataHttpMethod method, final UriType uriType, final HttpStatusCodes expectedStatusCode) throws ODataException {
+    executeAndValidateRequest(method, createPathSegments(uriType, true, false), null, null, expectedStatusCode);
+  }
+
+  private void wrongRequestContentType(final ODataHttpMethod method, final UriType uriType, final ContentType requestContentType) throws ODataException {
+    wrongRequestContentType(method, uriType, false, requestContentType);
+  }
+
+  private void wrongRequestContentType(final ODataHttpMethod method, final UriType uriType, final boolean isValue, final ContentType requestContentType) throws ODataException {
+    wrongRequestContentType(method, uriType, isValue, requestContentType.toContentTypeString());
+  }
+
+  private void wrongRequestContentType(final ODataHttpMethod method, final UriType uriType, final boolean isValue, final String requestContentType) throws ODataException {
+    executeAndValidateRequest(method, createPathSegments(uriType, false, isValue), null, requestContentType, HttpStatusCodes.UNSUPPORTED_MEDIA_TYPE);
+  }
+
+  @Test
+  public void dataServiceVersion() throws Exception {
+    ODataServiceFactory serviceFactory = mock(ODataServiceFactory.class);
+    final ODataService service = mockODataService(serviceFactory);
+    when(serviceFactory.createService(any(ODataContext.class))).thenReturn(service);
+
+    ODataRequest request = mockODataRequest(ODataHttpMethod.GET, createPathSegments(UriType.URI0, false, false), null, null);
+    ODataContextImpl context = new ODataContextImpl(request, serviceFactory);
+
+    final ODataRequestHandler handler = new ODataRequestHandler(serviceFactory, service, context);
+
+    when(request.getRequestHeaderValue(ODataHttpHeaders.DATASERVICEVERSION)).thenReturn("1.0");
+    ODataResponse response = handler.handle(request);
+    assertEquals(HttpStatusCodes.PAYMENT_REQUIRED, response.getStatus());
+
+    when(request.getRequestHeaderValue(ODataHttpHeaders.DATASERVICEVERSION)).thenReturn("2.0");
+    response = handler.handle(request);
+    assertEquals(HttpStatusCodes.PAYMENT_REQUIRED, response.getStatus());
+
+    when(request.getRequestHeaderValue(ODataHttpHeaders.DATASERVICEVERSION)).thenReturn("3.0");
+    response = handler.handle(request);
+    assertEquals(HttpStatusCodes.BAD_REQUEST, response.getStatus());
+
+    when(request.getRequestHeaderValue(ODataHttpHeaders.DATASERVICEVERSION)).thenReturn("4.2");
+    response = handler.handle(request);
+    assertEquals(HttpStatusCodes.BAD_REQUEST, response.getStatus());
+
+    when(request.getRequestHeaderValue(ODataHttpHeaders.DATASERVICEVERSION)).thenReturn("42");
+    response = handler.handle(request);
+    assertEquals(HttpStatusCodes.BAD_REQUEST, response.getStatus());
+
+    when(request.getRequestHeaderValue(ODataHttpHeaders.DATASERVICEVERSION)).thenReturn("test.2.0");
+    response = handler.handle(request);
+    assertEquals(HttpStatusCodes.BAD_REQUEST, response.getStatus());
+  }
+
+  @Test
+  public void allowedMethods() throws Exception {
+    executeAndValidateRequest(ODataHttpMethod.GET, createPathSegments(UriType.URI0, false, false), null, null, null);
+    executeAndValidateRequest(ODataHttpMethod.GET, createPathSegments(UriType.URI1, false, false), null, null, null);
+    executeAndValidateRequest(ODataHttpMethod.POST, createPathSegments(UriType.URI1, false, false), null, HttpContentType.APPLICATION_JSON, null);
+    executeAndValidateRequest(ODataHttpMethod.GET, createPathSegments(UriType.URI2, false, false), null, null, null);
+    executeAndValidateRequest(ODataHttpMethod.GET, createPathSegments(UriType.URI3, false, false), null, null, null);
+    executeAndValidateRequest(ODataHttpMethod.PATCH, createPathSegments(UriType.URI3, false, false), null, HttpContentType.APPLICATION_JSON, null);
+    executeAndValidateRequest(ODataHttpMethod.MERGE, createPathSegments(UriType.URI3, false, false), null, HttpContentType.APPLICATION_JSON, null);
+    executeAndValidateRequest(ODataHttpMethod.GET, createPathSegments(UriType.URI4, false, false), null, null, null);
+    executeAndValidateRequest(ODataHttpMethod.POST, createPathSegments(UriType.URI9, false, false), null, HttpContentType.MULTIPART_MIXED, null);
+    executeAndValidateRequest(ODataHttpMethod.GET, createPathSegments(UriType.URI15, false, false), null, null, null);
+    executeAndValidateRequest(ODataHttpMethod.GET, createPathSegments(UriType.URI17, false, false), null, null, null);
+  }
+
+  @Test
+  public void notAllowedMethod() throws Exception {
+    wrongRequest(ODataHttpMethod.DELETE, createPathSegments(UriType.URI0, false, false), null);
+    wrongRequest(ODataHttpMethod.DELETE, createPathSegments(UriType.URI1, false, false), null);
+    wrongRequest(ODataHttpMethod.POST, createPathSegments(UriType.URI2, false, false), null);
+    wrongRequest(ODataHttpMethod.DELETE, createPathSegments(UriType.URI3, false, false), null);
+    wrongRequest(ODataHttpMethod.POST, createPathSegments(UriType.URI4, false, false), null);
+    wrongRequest(ODataHttpMethod.POST, createPathSegments(UriType.URI5, false, false), null);
+    wrongRequest(ODataHttpMethod.POST, createPathSegments(UriType.URI6A, false, false), null);
+    wrongRequest(ODataHttpMethod.DELETE, createPathSegments(UriType.URI6B, false, false), null);
+    wrongRequest(ODataHttpMethod.POST, createPathSegments(UriType.URI7A, false, false), null);
+    wrongRequest(ODataHttpMethod.DELETE, createPathSegments(UriType.URI7B, false, false), null);
+    wrongRequest(ODataHttpMethod.DELETE, createPathSegments(UriType.URI8, false, false), null);
+    wrongRequest(ODataHttpMethod.DELETE, createPathSegments(UriType.URI9, false, false), null);
+    wrongRequest(ODataHttpMethod.DELETE, createPathSegments(UriType.URI15, false, false), null);
+    wrongRequest(ODataHttpMethod.DELETE, createPathSegments(UriType.URI16, false, false), null);
+    wrongRequest(ODataHttpMethod.PATCH, createPathSegments(UriType.URI17, false, false), null);
+    wrongRequest(ODataHttpMethod.DELETE, createPathSegments(UriType.URI50A, false, false), null);
+    wrongRequest(ODataHttpMethod.DELETE, createPathSegments(UriType.URI50B, false, false), null);
+  }
+
+  @Test
+  public void notAllowedOptions() throws Exception {
+    wrongOptions(ODataHttpMethod.POST, UriType.URI1, true, false, false, false, false, false, false, false, false);
+    wrongOptions(ODataHttpMethod.POST, UriType.URI1, false, true, false, false, false, false, false, false, false);
+    wrongOptions(ODataHttpMethod.POST, UriType.URI1, false, false, true, false, false, false, false, false, false);
+    wrongOptions(ODataHttpMethod.POST, UriType.URI1, false, false, false, true, false, false, false, false, false);
+    wrongOptions(ODataHttpMethod.POST, UriType.URI1, false, false, false, false, true, false, false, false, false);
+    wrongOptions(ODataHttpMethod.POST, UriType.URI1, false, false, false, false, false, true, false, false, false);
+    wrongOptions(ODataHttpMethod.POST, UriType.URI1, false, false, false, false, false, false, true, false, false);
+    wrongOptions(ODataHttpMethod.POST, UriType.URI1, false, false, false, false, false, false, false, true, false);
+    wrongOptions(ODataHttpMethod.POST, UriType.URI1, false, false, false, false, false, false, false, false, true);
+
+    wrongOptions(ODataHttpMethod.PUT, UriType.URI2, true, false, false, false, false, false, false, false, false);
+    wrongOptions(ODataHttpMethod.PUT, UriType.URI2, false, false, false, false, false, false, false, true, false);
+    wrongOptions(ODataHttpMethod.PUT, UriType.URI2, false, false, false, false, false, false, false, false, true);
+    wrongOptions(ODataHttpMethod.PATCH, UriType.URI2, true, false, false, false, false, false, false, false, false);
+    wrongOptions(ODataHttpMethod.PATCH, UriType.URI2, false, false, false, false, false, false, false, true, false);
+    wrongOptions(ODataHttpMethod.PATCH, UriType.URI2, false, false, false, false, false, false, false, false, true);
+    wrongOptions(ODataHttpMethod.DELETE, UriType.URI2, true, false, false, false, false, false, false, false, false);
+    wrongOptions(ODataHttpMethod.DELETE, UriType.URI2, false, true, false, false, false, false, false, false, false);
+    wrongOptions(ODataHttpMethod.DELETE, UriType.URI2, false, false, false, false, false, false, false, true, false);
+    wrongOptions(ODataHttpMethod.DELETE, UriType.URI2, false, false, false, false, false, false, false, false, true);
+
+    wrongOptions(ODataHttpMethod.PUT, UriType.URI3, true, false, false, false, false, false, false, false, false);
+    wrongOptions(ODataHttpMethod.PATCH, UriType.URI3, true, false, false, false, false, false, false, false, false);
+
+    wrongOptions(ODataHttpMethod.PUT, UriType.URI4, true, false, false, false, false, false, false, false, false);
+
+    wrongOptions(ODataHttpMethod.PUT, UriType.URI5, true, false, false, false, false, false, false, false, false);
+
+    wrongOptions(ODataHttpMethod.POST, UriType.URI6B, true, false, false, false, false, false, false, false, false);
+    wrongOptions(ODataHttpMethod.POST, UriType.URI6B, false, true, false, false, false, false, false, false, false);
+    wrongOptions(ODataHttpMethod.POST, UriType.URI6B, false, false, true, false, false, false, false, false, false);
+    wrongOptions(ODataHttpMethod.POST, UriType.URI6B, false, false, false, true, false, false, false, false, false);
+    wrongOptions(ODataHttpMethod.POST, UriType.URI6B, false, false, false, false, true, false, false, false, false);
+    wrongOptions(ODataHttpMethod.POST, UriType.URI6B, false, false, false, false, false, true, false, false, false);
+    wrongOptions(ODataHttpMethod.POST, UriType.URI6B, false, false, false, false, false, false, true, false, false);
+    wrongOptions(ODataHttpMethod.POST, UriType.URI6B, false, false, false, false, false, false, false, true, false);
+    wrongOptions(ODataHttpMethod.POST, UriType.URI6B, false, false, false, false, false, false, false, false, true);
+
+    wrongOptions(ODataHttpMethod.PUT, UriType.URI7A, true, false, false, false, false, false, false, false, false);
+    wrongOptions(ODataHttpMethod.PUT, UriType.URI7A, false, true, false, false, false, false, false, false, false);
+    wrongOptions(ODataHttpMethod.DELETE, UriType.URI7A, true, false, false, false, false, false, false, false, false);
+    wrongOptions(ODataHttpMethod.DELETE, UriType.URI7A, false, true, false, false, false, false, false, false, false);
+
+    wrongOptions(ODataHttpMethod.POST, UriType.URI7B, true, false, false, false, false, false, false, false, false);
+    wrongOptions(ODataHttpMethod.POST, UriType.URI7B, false, true, false, false, false, false, false, false, false);
+    wrongOptions(ODataHttpMethod.POST, UriType.URI7B, false, false, true, false, false, false, false, false, false);
+    wrongOptions(ODataHttpMethod.POST, UriType.URI7B, false, false, false, true, false, false, false, false, false);
+    wrongOptions(ODataHttpMethod.POST, UriType.URI7B, false, false, false, false, true, false, false, false, false);
+    wrongOptions(ODataHttpMethod.POST, UriType.URI7B, false, false, false, false, false, true, false, false, false);
+    wrongOptions(ODataHttpMethod.POST, UriType.URI7B, false, false, false, false, false, false, true, false, false);
+
+    wrongOptions(ODataHttpMethod.PUT, UriType.URI17, false, true, false, false, false, false, false, false, false);
+    wrongOptions(ODataHttpMethod.DELETE, UriType.URI17, true, false, false, false, false, false, false, false, false);
+    wrongOptions(ODataHttpMethod.DELETE, UriType.URI17, false, true, false, false, false, false, false, false, false);
+  }
+
+  @Test
+  public void functionImportWrongHttpMethod() throws Exception {
+    wrongFunctionHttpMethod(ODataHttpMethod.POST, UriType.URI1);
+    wrongFunctionHttpMethod(ODataHttpMethod.PUT, UriType.URI10);
+    wrongFunctionHttpMethod(ODataHttpMethod.POST, UriType.URI11);
+    wrongFunctionHttpMethod(ODataHttpMethod.PATCH, UriType.URI12);
+    wrongFunctionHttpMethod(ODataHttpMethod.POST, UriType.URI13);
+    wrongFunctionHttpMethod(ODataHttpMethod.PUT, UriType.URI14);
+  }
+
+  @Test
+  public void wrongProperty() throws Exception {
+    wrongProperty(ODataHttpMethod.DELETE, true, false);
+
+    wrongProperty(ODataHttpMethod.PUT, false, true);
+    wrongProperty(ODataHttpMethod.PATCH, false, true);
+    wrongProperty(ODataHttpMethod.DELETE, false, true);
+    wrongProperty(ODataHttpMethod.DELETE, false, false);
+  }
+
+  @Test
+  public void wrongNavigationPath() throws Exception {
+    wrongNavigationPath(ODataHttpMethod.PUT, UriType.URI3, HttpStatusCodes.BAD_REQUEST);
+    wrongNavigationPath(ODataHttpMethod.PATCH, UriType.URI3, HttpStatusCodes.BAD_REQUEST);
+
+    wrongNavigationPath(ODataHttpMethod.PUT, UriType.URI4, HttpStatusCodes.BAD_REQUEST);
+    wrongNavigationPath(ODataHttpMethod.PATCH, UriType.URI4, HttpStatusCodes.BAD_REQUEST);
+    wrongNavigationPath(ODataHttpMethod.DELETE, UriType.URI4, HttpStatusCodes.METHOD_NOT_ALLOWED);
+
+    wrongNavigationPath(ODataHttpMethod.PUT, UriType.URI5, HttpStatusCodes.BAD_REQUEST);
+    wrongNavigationPath(ODataHttpMethod.PATCH, UriType.URI5, HttpStatusCodes.BAD_REQUEST);
+    wrongNavigationPath(ODataHttpMethod.DELETE, UriType.URI5, HttpStatusCodes.METHOD_NOT_ALLOWED);
+
+    wrongNavigationPath(ODataHttpMethod.PUT, UriType.URI7A, HttpStatusCodes.BAD_REQUEST);
+    wrongNavigationPath(ODataHttpMethod.PATCH, UriType.URI7A, HttpStatusCodes.BAD_REQUEST);
+    wrongNavigationPath(ODataHttpMethod.DELETE, UriType.URI7A, HttpStatusCodes.BAD_REQUEST);
+
+    wrongNavigationPath(ODataHttpMethod.POST, UriType.URI6B, HttpStatusCodes.BAD_REQUEST);
+
+    wrongNavigationPath(ODataHttpMethod.POST, UriType.URI7B, HttpStatusCodes.BAD_REQUEST);
+
+    wrongNavigationPath(ODataHttpMethod.PUT, UriType.URI17, HttpStatusCodes.BAD_REQUEST);
+    wrongNavigationPath(ODataHttpMethod.DELETE, UriType.URI17, HttpStatusCodes.BAD_REQUEST);
+  }
+
+  @Test
+  public void requestContentType() throws Exception {
+    executeAndValidateRequest(ODataHttpMethod.PUT, createPathSegments(UriType.URI2, false, false), null, HttpContentType.APPLICATION_XML, null);
+    executeAndValidateRequest(ODataHttpMethod.PATCH, createPathSegments(UriType.URI2, false, false), null, HttpContentType.APPLICATION_XML, null);
+    executeAndValidateRequest(ODataHttpMethod.MERGE, createPathSegments(UriType.URI2, false, false), null, HttpContentType.APPLICATION_XML, null);
+
+    executeAndValidateRequest(ODataHttpMethod.PUT, createPathSegments(UriType.URI3, false, false), null, HttpContentType.APPLICATION_XML, null);
+    executeAndValidateRequest(ODataHttpMethod.PATCH, createPathSegments(UriType.URI3, false, false), null, HttpContentType.APPLICATION_XML, null);
+    executeAndValidateRequest(ODataHttpMethod.MERGE, createPathSegments(UriType.URI3, false, false), null, HttpContentType.APPLICATION_XML, null);
+
+    executeAndValidateRequest(ODataHttpMethod.PUT, createPathSegments(UriType.URI4, false, false), null, HttpContentType.APPLICATION_XML, null);
+    executeAndValidateRequest(ODataHttpMethod.PATCH, createPathSegments(UriType.URI4, false, false), null, HttpContentType.APPLICATION_XML, null);
+    executeAndValidateRequest(ODataHttpMethod.MERGE, createPathSegments(UriType.URI4, false, false), null, HttpContentType.APPLICATION_XML, null);
+
+    executeAndValidateRequest(ODataHttpMethod.PUT, createPathSegments(UriType.URI5, false, false), null, HttpContentType.APPLICATION_XML, null);
+    executeAndValidateRequest(ODataHttpMethod.PATCH, createPathSegments(UriType.URI5, false, false), null, HttpContentType.APPLICATION_XML, null);
+    executeAndValidateRequest(ODataHttpMethod.MERGE, createPathSegments(UriType.URI5, false, false), null, HttpContentType.APPLICATION_XML, null);
+
+    executeAndValidateRequest(ODataHttpMethod.PUT, createPathSegments(UriType.URI6A, false, false), null, HttpContentType.APPLICATION_XML, HttpStatusCodes.BAD_REQUEST);
+    executeAndValidateRequest(ODataHttpMethod.PATCH, createPathSegments(UriType.URI6A, false, false), null, HttpContentType.APPLICATION_XML, HttpStatusCodes.BAD_REQUEST);
+    executeAndValidateRequest(ODataHttpMethod.MERGE, createPathSegments(UriType.URI6A, false, false), null, HttpContentType.APPLICATION_XML, HttpStatusCodes.BAD_REQUEST);
+
+    executeAndValidateRequest(ODataHttpMethod.POST, createPathSegments(UriType.URI6B, false, false), null, HttpContentType.APPLICATION_XML, null);
+
+    executeAndValidateRequest(ODataHttpMethod.PUT, createPathSegments(UriType.URI7A, false, false), null, HttpContentType.APPLICATION_XML, null);
+    executeAndValidateRequest(ODataHttpMethod.PATCH, createPathSegments(UriType.URI7A, false, false), null, HttpContentType.APPLICATION_XML, null);
+    executeAndValidateRequest(ODataHttpMethod.MERGE, createPathSegments(UriType.URI7A, false, false), null, HttpContentType.APPLICATION_XML, null);
+
+    executeAndValidateRequest(ODataHttpMethod.POST, createPathSegments(UriType.URI7B, false, false), null, HttpContentType.APPLICATION_XML, null);
+
+    executeAndValidateRequest(ODataHttpMethod.POST, createPathSegments(UriType.URI9, false, false), null, HttpContentType.MULTIPART_MIXED, null);
+  }
+
+  @Test
+  public void requestContentTypeMediaResource() throws Exception {
+    executeAndValidateRequest(ODataHttpMethod.POST, createPathSegments(UriType.URI1, false, false), null, "image/jpeg", null);
+
+    executeAndValidateRequest(ODataHttpMethod.PUT, createPathSegments(UriType.URI17, false, true), null, "image/jpeg", null);
+  }
+
+  @Test
+  public void requestContentTypeFunctionImport() throws Exception {
+    EdmFunctionImport function = edm.getDefaultEntityContainer().getFunctionImport("MaximalAge");
+    when(function.getHttpMethod()).thenReturn(ODataHttpMethod.PUT.name());
+    executeAndValidateRequest(ODataHttpMethod.PUT, createPathSegments(UriType.URI14, false, false), null, null, null);
+    executeAndValidateRequest(ODataHttpMethod.PUT, createPathSegments(UriType.URI14, false, false), null, HttpContentType.WILDCARD, null);
+    checkValueContentType(ODataHttpMethod.PUT, UriType.URI14, null);
+    checkValueContentType(ODataHttpMethod.PUT, UriType.URI14, HttpContentType.WILDCARD);
+
+    function = edm.getDefaultEntityContainer().getFunctionImport("OldestEmployee");
+    when(function.getHttpMethod()).thenReturn(ODataHttpMethod.POST.name());
+    executeAndValidateRequest(ODataHttpMethod.POST, createPathSegments(UriType.URI10, false, false), null, null, null);
+  }
+
+  @Test
+  public void requestValueContentType() throws Exception {
+    checkValueContentType(ODataHttpMethod.PUT, UriType.URI4, HttpContentType.TEXT_PLAIN);
+    checkValueContentType(ODataHttpMethod.DELETE, UriType.URI4, HttpContentType.TEXT_PLAIN);
+    checkValueContentType(ODataHttpMethod.PATCH, UriType.URI4, HttpContentType.TEXT_PLAIN);
+    checkValueContentType(ODataHttpMethod.MERGE, UriType.URI4, HttpContentType.TEXT_PLAIN);
+    checkValueContentType(ODataHttpMethod.PUT, UriType.URI4, HttpContentType.TEXT_PLAIN_UTF8);
+    checkValueContentType(ODataHttpMethod.DELETE, UriType.URI4, HttpContentType.TEXT_PLAIN_UTF8);
+    checkValueContentType(ODataHttpMethod.PATCH, UriType.URI4, HttpContentType.TEXT_PLAIN_UTF8);
+    checkValueContentType(ODataHttpMethod.MERGE, UriType.URI4, HttpContentType.TEXT_PLAIN_UTF8);
+
+    checkValueContentType(ODataHttpMethod.PUT, UriType.URI5, HttpContentType.TEXT_PLAIN);
+    checkValueContentType(ODataHttpMethod.DELETE, UriType.URI5, HttpContentType.TEXT_PLAIN);
+    checkValueContentType(ODataHttpMethod.PATCH, UriType.URI5, HttpContentType.TEXT_PLAIN);
+    checkValueContentType(ODataHttpMethod.MERGE, UriType.URI5, HttpContentType.TEXT_PLAIN);
+
+    checkValueContentType(ODataHttpMethod.PUT, UriType.URI17, HttpContentType.TEXT_PLAIN);
+    checkValueContentType(ODataHttpMethod.DELETE, UriType.URI17, HttpContentType.TEXT_PLAIN);
+  }
+
+  @Test
+  public void requestBinaryValueContentType() throws Exception {
+    EdmProperty property = (EdmProperty) edm.getEntityType("RefScenario", "Employee").getProperty("EmployeeName");
+    when(property.getType()).thenReturn(EdmSimpleTypeKind.Binary.getEdmSimpleTypeInstance());
+    checkValueContentType(ODataHttpMethod.PUT, UriType.URI5, HttpContentType.TEXT_PLAIN);
+    when(property.getMimeType()).thenReturn("image/png");
+    checkValueContentType(ODataHttpMethod.PUT, UriType.URI5, "image/png");
+  }
+
+  @Test
+  public void wrongRequestContentType() throws Exception {
+    wrongRequestContentType(ODataHttpMethod.POST, UriType.URI1, ContentType.WILDCARD);
+
+    wrongRequestContentType(ODataHttpMethod.PUT, UriType.URI2, ContentType.APPLICATION_ATOM_SVC);
+    wrongRequestContentType(ODataHttpMethod.PUT, UriType.URI2, ContentType.APPLICATION_ATOM_SVC_CS_UTF_8);
+    wrongRequestContentType(ODataHttpMethod.PUT, UriType.URI2, ContentType.APPLICATION_ATOM_SVC);
+    wrongRequestContentType(ODataHttpMethod.PUT, UriType.URI2, ContentType.APPLICATION_ATOM_SVC_CS_UTF_8);
+
+    ODataHttpMethod[] methodsToTest = { ODataHttpMethod.PUT, ODataHttpMethod.PATCH, ODataHttpMethod.MERGE };
+
+    for (ODataHttpMethod oDataHttpMethod : methodsToTest) {
+      wrongRequestContentType(oDataHttpMethod, UriType.URI2, ContentType.create("image/jpeg"));
+
+      wrongRequestContentType(oDataHttpMethod, UriType.URI3, ContentType.TEXT_PLAIN);
+
+      wrongRequestContentType(oDataHttpMethod, UriType.URI4, false, ContentType.TEXT_PLAIN);
+
+      wrongRequestContentType(oDataHttpMethod, UriType.URI5, true, ContentType.APPLICATION_ATOM_SVC);
+      wrongRequestContentType(oDataHttpMethod, UriType.URI5, true, ContentType.APPLICATION_ATOM_SVC_CS_UTF_8);
+      wrongRequestContentType(oDataHttpMethod, UriType.URI5, true, ContentType.APPLICATION_XML);
+      wrongRequestContentType(oDataHttpMethod, UriType.URI5, true, ContentType.APPLICATION_XML_CS_UTF_8);
+      wrongRequestContentType(oDataHttpMethod, UriType.URI5, true, ContentType.APPLICATION_ATOM_XML);
+      wrongRequestContentType(oDataHttpMethod, UriType.URI5, true, ContentType.APPLICATION_ATOM_XML_CS_UTF_8);
+      wrongRequestContentType(oDataHttpMethod, UriType.URI5, true, ContentType.APPLICATION_JSON);
+      wrongRequestContentType(oDataHttpMethod, UriType.URI5, true, ContentType.APPLICATION_JSON_CS_UTF_8);
+      wrongRequestContentType(oDataHttpMethod, UriType.URI5, true, ContentType.create("image/jpeg"));
+
+      wrongRequestContentType(oDataHttpMethod, UriType.URI6A, ContentType.APPLICATION_ATOM_SVC);
+
+      wrongRequestContentType(oDataHttpMethod, UriType.URI7A, ContentType.APPLICATION_ATOM_SVC);
+    }
+
+    wrongRequestContentType(ODataHttpMethod.POST, UriType.URI7B, ContentType.APPLICATION_ATOM_SVC);
+
+    wrongRequestContentType(ODataHttpMethod.POST, UriType.URI9, ContentType.APPLICATION_OCTET_STREAM);
+  }
+
+  @Test
+  public void unsupportedRequestContentTypeNoMediaResource() throws Exception {
+    EdmEntityType entityType = edm.getDefaultEntityContainer().getEntitySet("Employees").getEntityType();
+    when(entityType.hasStream()).thenReturn(false);
+
+    wrongRequestContentType(ODataHttpMethod.POST, UriType.URI1, ContentType.APPLICATION_ATOM_SVC);
+    wrongRequestContentType(ODataHttpMethod.POST, UriType.URI1, ContentType.APPLICATION_ATOM_SVC_CS_UTF_8);
+    wrongRequestContentType(ODataHttpMethod.POST, UriType.URI1, ContentType.APPLICATION_OCTET_STREAM);
+    wrongRequestContentType(ODataHttpMethod.POST, UriType.URI6B, ContentType.APPLICATION_ATOM_SVC);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/test/java/org/apache/olingo/odata2/core/ODataResponseTest.java
----------------------------------------------------------------------
diff --git a/odata-core/src/test/java/org/apache/olingo/odata2/core/ODataResponseTest.java b/odata-core/src/test/java/org/apache/olingo/odata2/core/ODataResponseTest.java
new file mode 100644
index 0000000..197d74c
--- /dev/null
+++ b/odata-core/src/test/java/org/apache/olingo/odata2/core/ODataResponseTest.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * 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;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.HashSet;
+
+import org.junit.Test;
+
+import org.apache.olingo.odata2.api.commons.HttpContentType;
+import org.apache.olingo.odata2.api.commons.HttpHeaders;
+import org.apache.olingo.odata2.api.commons.HttpStatusCodes;
+import org.apache.olingo.odata2.api.processor.ODataResponse;
+import org.apache.olingo.odata2.testutil.fit.BaseTest;
+
+/**
+ * @author SAP AG
+ */
+public class ODataResponseTest extends BaseTest {
+
+  @Test
+  public void buildStatusResponseTest() {
+    ODataResponse response = ODataResponse.status(HttpStatusCodes.FOUND).build();
+    assertEquals(HttpStatusCodes.FOUND, response.getStatus());
+  }
+
+  @Test
+  public void buildEntityResponseTest() {
+    ODataResponse response = ODataResponse.entity("abc").build();
+    assertNull(response.getStatus());
+    assertEquals("abc", response.getEntity());
+  }
+
+  @Test
+  public void buildHeaderResponseTest() {
+    ODataResponse response = ODataResponse
+        .header("abc", "123")
+        .header("def", "456")
+        .header("ghi", null)
+        .build();
+    assertNull(response.getStatus());
+    assertEquals("123", response.getHeader("abc"));
+    assertEquals("456", response.getHeader("def"));
+    assertNull(response.getHeader("ghi"));
+  }
+
+  @Test
+  public void contentHeader() {
+    final ODataResponse response = ODataResponse.contentHeader(HttpContentType.APPLICATION_OCTET_STREAM).build();
+    assertNull(response.getStatus());
+    assertEquals(HttpContentType.APPLICATION_OCTET_STREAM, response.getContentHeader());
+    assertTrue(response.containsHeader(HttpHeaders.CONTENT_TYPE));
+    assertEquals(HttpContentType.APPLICATION_OCTET_STREAM, response.getHeader(HttpHeaders.CONTENT_TYPE));
+    assertFalse(response.containsHeader(HttpHeaders.CONTENT_LENGTH));
+    assertEquals(new HashSet<String>(Arrays.asList(HttpHeaders.CONTENT_TYPE)), response.getHeaderNames());
+  }
+
+  @Test
+  public void completeResponse() {
+    final ODataResponse response = ODataResponse.newBuilder()
+        .status(HttpStatusCodes.OK)
+        .header("def", "456")
+        .eTag("x")
+        .contentHeader(HttpContentType.TEXT_PLAIN)
+        .idLiteral("id")
+        .entity("body")
+        .build();
+    assertEquals(HttpStatusCodes.OK, response.getStatus());
+    assertEquals("456", response.getHeader("def"));
+    assertEquals("x", response.getETag());
+    assertEquals(HttpContentType.TEXT_PLAIN, response.getContentHeader());
+    assertEquals("id", response.getIdLiteral());
+    assertEquals(4, response.getHeaderNames().size());
+    assertEquals("body", response.getEntity());
+
+    final ODataResponse responseCopy = ODataResponse.fromResponse(response).build();
+    assertEquals(HttpStatusCodes.OK, responseCopy.getStatus());
+    assertEquals("456", responseCopy.getHeader("def"));
+    assertEquals("x", responseCopy.getETag());
+    assertEquals(HttpContentType.TEXT_PLAIN, response.getContentHeader());
+    assertEquals("id", responseCopy.getIdLiteral());
+    assertEquals("body", responseCopy.getEntity());
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/test/java/org/apache/olingo/odata2/core/PathSegmentTest.java
----------------------------------------------------------------------
diff --git a/odata-core/src/test/java/org/apache/olingo/odata2/core/PathSegmentTest.java b/odata-core/src/test/java/org/apache/olingo/odata2/core/PathSegmentTest.java
new file mode 100644
index 0000000..cba2439
--- /dev/null
+++ b/odata-core/src/test/java/org/apache/olingo/odata2/core/PathSegmentTest.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * 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;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.olingo.odata2.api.uri.PathSegment;
+import org.apache.olingo.odata2.testutil.fit.BaseTest;
+
+/**
+ * @author SAP AG
+ */
+public class PathSegmentTest extends BaseTest {
+
+  PathSegment segment;
+  PathSegment segmentNoMatrix;
+
+  @Before
+  public void before() {
+    Map<String, List<String>> map = new HashMap<String, List<String>>();
+    map.put("a", Arrays.asList("1"));
+    map.put("b", Arrays.asList("2"));
+    map.put("c", Arrays.asList("3"));
+    map.put("m", Arrays.asList("x", "y", "z"));
+
+    segment = new ODataPathSegmentImpl("segment", map);
+    segmentNoMatrix = new ODataPathSegmentImpl("segment", null);
+  }
+
+  @Test
+  public void testPathSegement() {
+    assertEquals("segment", segment.getPath());
+
+    assertEquals("1", segment.getMatrixParameters().get("a").get(0));
+    assertEquals("2", segment.getMatrixParameters().get("b").get(0));
+    assertEquals("3", segment.getMatrixParameters().get("c").get(0));
+
+    assertEquals("x", segment.getMatrixParameters().get("m").get(0));
+    assertEquals("y", segment.getMatrixParameters().get("m").get(1));
+    assertEquals("z", segment.getMatrixParameters().get("m").get(2));
+  }
+
+  @Test(expected = UnsupportedOperationException.class)
+  public void readonlyMatrixParameter() {
+    segment.getMatrixParameters().get("m").clear();
+  }
+
+  @Test
+  public void noMatrixParameter() {
+    assertEquals("segment", segmentNoMatrix.getPath());
+    assertTrue(segmentNoMatrix.getMatrixParameters().isEmpty());
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/AcceptParserTest.java
----------------------------------------------------------------------
diff --git a/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/AcceptParserTest.java b/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/AcceptParserTest.java
new file mode 100644
index 0000000..88b3c11
--- /dev/null
+++ b/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/AcceptParserTest.java
@@ -0,0 +1,152 @@
+/*******************************************************************************
+ * 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 java.util.List;
+
+import org.junit.Test;
+
+import org.apache.olingo.odata2.api.batch.BatchException;
+
+public class AcceptParserTest {
+  private static final String TAB = "\t";
+
+  @Test
+  public void testAcceptHeader() throws BatchException {
+    List<String> acceptHeaders = AcceptParser.parseAcceptHeaders("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
+    assertNotNull(acceptHeaders);
+    assertEquals(4, acceptHeaders.size());
+    assertEquals("text/html", acceptHeaders.get(0));
+    assertEquals("application/xhtml+xml", acceptHeaders.get(1));
+    assertEquals("application/xml", acceptHeaders.get(2));
+    assertEquals("*/*", acceptHeaders.get(3));
+  }
+
+  @Test
+  public void testAcceptHeaderWithParameter() throws BatchException {
+    List<String> acceptHeaders = AcceptParser.parseAcceptHeaders("application/json;odata=verbose;q=1.0, */*;q=0.1");
+    assertNotNull(acceptHeaders);
+    assertEquals(2, acceptHeaders.size());
+    assertEquals("application/json;odata=verbose", acceptHeaders.get(0));
+    ;
+    assertEquals("*/*", acceptHeaders.get(1));
+  }
+
+  @Test
+  public void testAcceptHeaderWithParameterAndLws() throws BatchException {
+    List<String> acceptHeaders = AcceptParser.parseAcceptHeaders("application/json;  odata=verbose;q=1.0, */*;q=0.1");
+    assertNotNull(acceptHeaders);
+    assertEquals(2, acceptHeaders.size());
+    assertEquals("application/json;  odata=verbose", acceptHeaders.get(0));
+    ;
+    assertEquals("*/*", acceptHeaders.get(1));
+  }
+
+  @Test
+  public void testAcceptHeaderWithTabulator() throws BatchException {
+    List<String> acceptHeaders = AcceptParser.parseAcceptHeaders("application/json;\todata=verbose;q=1.0, */*;q=0.1");
+    assertNotNull(acceptHeaders);
+    assertEquals(2, acceptHeaders.size());
+    assertEquals("application/json;" + TAB + "odata=verbose", acceptHeaders.get(0));
+    ;
+    assertEquals("*/*", acceptHeaders.get(1));
+  }
+
+  @Test
+  public void testAcceptHeaderWithTwoParameters() throws BatchException {
+    List<String> acceptHeaders = AcceptParser.parseAcceptHeaders("application/xml;another=test ; param=alskdf, */*;q=0.1");
+    assertNotNull(acceptHeaders);
+    assertEquals(2, acceptHeaders.size());
+    assertEquals("application/xml;another=test ; param=alskdf", acceptHeaders.get(0));
+    ;
+    assertEquals("*/*", acceptHeaders.get(1));
+  }
+
+  @Test
+  public void testAcceptHeader2() throws BatchException {
+    List<String> acceptHeaders = AcceptParser.parseAcceptHeaders("text/html;level=1, application/*, */*;q=0.1");
+    assertNotNull(acceptHeaders);
+    assertEquals(3, acceptHeaders.size());
+    assertEquals("text/html;level=1", acceptHeaders.get(0));
+    assertEquals("application/*", acceptHeaders.get(1));
+    assertEquals("*/*", acceptHeaders.get(2));
+  }
+
+  @Test
+  public void testMoreSpecificMediaType() throws BatchException {
+    List<String> acceptHeaders = AcceptParser.parseAcceptHeaders("application/*, application/xml");
+    assertNotNull(acceptHeaders);
+    assertEquals(2, acceptHeaders.size());
+    assertEquals("application/xml", acceptHeaders.get(0));
+    assertEquals("application/*", acceptHeaders.get(1));
+  }
+
+  @Test
+  public void testQualityParameter() throws BatchException {
+    List<String> acceptHeaders = AcceptParser.parseAcceptHeaders("application/*, */*; q=0.012");
+    assertNotNull(acceptHeaders);
+  }
+
+  @Test(expected = BatchException.class)
+  public void testInvalidAcceptHeader() throws BatchException {
+    AcceptParser.parseAcceptHeaders("appi cation/*, */*;q=0.1");
+  }
+
+  @Test(expected = BatchException.class)
+  public void testInvalidQualityParameter() throws BatchException {
+    AcceptParser.parseAcceptHeaders("appication/*, */*;q=0,9");
+  }
+
+  @Test(expected = BatchException.class)
+  public void testInvalidQualityParameter2() throws BatchException {
+    AcceptParser.parseAcceptHeaders("appication/*, */*;q=1.0001");
+  }
+
+  @Test
+  public void testAcceptLanguages() throws BatchException {
+    List<String> acceptLanguageHeaders = AcceptParser.parseAcceptableLanguages("en-US,en;q=0.7,en-UK;q=0.9");
+    assertNotNull(acceptLanguageHeaders);
+    assertEquals(3, acceptLanguageHeaders.size());
+    assertEquals("en-US", acceptLanguageHeaders.get(0));
+    assertEquals("en-UK", acceptLanguageHeaders.get(1));
+    assertEquals("en", acceptLanguageHeaders.get(2));
+  }
+
+  @Test
+  public void testAllAcceptLanguages() throws BatchException {
+    List<String> acceptLanguageHeaders = AcceptParser.parseAcceptableLanguages("*");
+    assertNotNull(acceptLanguageHeaders);
+    assertEquals(1, acceptLanguageHeaders.size());
+  }
+
+  @Test
+  public void testLongAcceptLanguageValue() throws BatchException {
+    List<String> acceptLanguageHeaders = AcceptParser.parseAcceptableLanguages("english");
+    assertNotNull(acceptLanguageHeaders);
+    assertEquals("english", acceptLanguageHeaders.get(0));
+  }
+
+  @Test(expected = BatchException.class)
+  public void testInvalidAcceptLanguageValue() throws BatchException {
+    AcceptParser.parseAcceptableLanguages("en_US");
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java
----------------------------------------------------------------------
diff --git a/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java b/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java
new file mode 100644
index 0000000..edf5f3e
--- /dev/null
+++ b/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java
@@ -0,0 +1,593 @@
+/*******************************************************************************
+ * 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.junit.BeforeClass;
+import org.junit.Test;
+
+import org.apache.olingo.odata2.api.batch.BatchException;
+import org.apache.olingo.odata2.api.batch.BatchPart;
+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.testutil.helper.StringHelper;
+
+/**
+ * @author SAP AG
+ */
+public class BatchRequestParserTest {
+
+  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 contentType = "multipart/mixed;boundary=batch_8194-cf13-1f56";
+  private static final String MIME_HEADERS = "Content-Type: application/http" + "\r\n"
+      + "Content-Transfer-Encoding: binary" + "\r\n";
+  private static final String GET_REQUEST = MIME_HEADERS + "\n"
+      + "GET Employees('1')/EmployeeName HTTP/1.1" + "\n"
+      + "\n"
+      + "\n";
+
+  @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.txt";
+    InputStream in = ClassLoader.class.getResourceAsStream(fileName);
+    if (in == null) {
+      throw new IOException("Requested file '" + fileName + "' was not found.");
+    }
+
+    BatchRequestParser parser = new BatchRequestParser(contentType, batchProperties);
+    List<BatchPart> batchParts = parser.parse(in);
+    assertNotNull(batchParts);
+    assertEquals(false, batchParts.isEmpty());
+    for (BatchPart object : batchParts) {
+      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.txt";
+    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 = "\r\n"
+        + "--batch_8194-cf13-1f56" + "\r" + "\n"
+        + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + "\r\n"
+        + "\r\n"
+        + "--changeset_f980-1cb6-94dd" + "\r\n"
+        + "content-type:     Application/http" + "\r\n"
+        + "content-transfer-encoding: Binary" + "\r\n"
+        + "Content-ID: 1" + "\r\n"
+        + "\r\n"
+        + "POST Employees HTTP/1.1" + "\r\n"
+        + "Content-length: 100000" + "\r\n"
+        + "Content-type: application/octet-stream" + "\r\n"
+        + "\r\n"
+        + content + "\r\n"
+        + "\r\n"
+        + "--changeset_f980-1cb6-94dd--" + "\r\n"
+        + "\r\n"
+        + "--batch_8194-cf13-1f56" + "\r\n"
+        + MIME_HEADERS
+        + "\r\n"
+        + "GET Employees?$filter=Age%20gt%2040 HTTP/1.1" + "\r\n"
+        + "Accept: application/atomsvc+xml;q=0.8, application/json;odata=verbose;q=0.5, */*;q=0.1" + "\r\n"
+        + "MaxDataServiceVersion: 2.0" + "\r\n"
+        + "\r\n"
+        + "\r\n"
+        + "--batch_8194-cf13-1f56--";
+    List<BatchPart> batchParts = parse(batch);
+    for (BatchPart object : batchParts) {
+      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(BatchConstants.MIME_HEADER_CONTENT_ID.toLowerCase()));
+          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.txt";
+    InputStream contentInputStream = ClassLoader.class.getResourceAsStream(fileName);
+    if (contentInputStream == null) {
+      throw new IOException("Requested file '" + fileName + "' was not found.");
+    }
+    StringHelper.inputStreamToString(contentInputStream);
+    String batch = "\r\n"
+        + "--batch_8194-cf13-1f56" + "\r" + "\n"
+        + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + "\r\n"
+        + "\r\n"
+        + "--changeset_f980-1cb6-94dd" + "\r\n"
+        + MIME_HEADERS
+        + "\r\n"
+        + "POST Employees('2') HTTP/1.1" + "\r\n"
+        + "Content-Length: 100" + "\r\n"
+        + "Content-Type: application/octet-stream" + "\r\n"
+        + "\r\n"
+        + "\r\n"
+        + "--changeset_f980-1cb6-94dd--" + "\r\n"
+        + "\r\n"
+        + "--batch_8194-cf13-1f56--";
+    List<BatchPart> batchParts = parse(batch);
+    for (BatchPart object : batchParts) {
+      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?" + "\n"
+        + GET_REQUEST
+        + "--batch_1.2+34:2j)0?--";
+    InputStream in = new ByteArrayInputStream(batch.getBytes());
+    BatchRequestParser parser = new BatchRequestParser(contentType, batchProperties);
+    List<BatchPart> batchParts = parser.parse(in);
+    assertNotNull(batchParts);
+    assertEquals(false, batchParts.isEmpty());
+  }
+
+  @Test(expected = BatchException.class)
+  public void testBatchWithInvalidContentType() throws BatchException {
+    String invalidContentType = "multipart;boundary=batch_1740-bb84-2f7f";
+
+    String batch = "--batch_1740-bb84-2f7f" + "\n"
+        + GET_REQUEST
+        + "--batch_1740-bb84-2f7f--";
+    InputStream in = new ByteArrayInputStream(batch.getBytes());
+    BatchRequestParser parser = new BatchRequestParser(invalidContentType, batchProperties);
+    parser.parse(in);
+  }
+
+  @Test(expected = BatchException.class)
+  public void testBatchWithoutBoundaryParameter() throws BatchException {
+    String invalidContentType = "multipart/mixed";
+    String batch = "--batch_1740-bb84-2f7f" + "\n"
+        + GET_REQUEST
+        + "--batch_1740-bb84-2f7f--";
+    InputStream in = new ByteArrayInputStream(batch.getBytes());
+    BatchRequestParser parser = new BatchRequestParser(invalidContentType, batchProperties);
+    parser.parse(in);
+  }
+
+  @Test(expected = BatchException.class)
+  public void testBoundaryParameterWithoutQuota() throws BatchException {
+    String invalidContentType = "multipart;boundary=batch_1740-bb:84-2f7f";
+    String batch = "--batch_1740-bb:84-2f7f" + "\n"
+        + GET_REQUEST
+        + "--batch_1740-bb:84-2f7f--";
+    InputStream in = new ByteArrayInputStream(batch.getBytes());
+    BatchRequestParser parser = new BatchRequestParser(invalidContentType, batchProperties);
+    parser.parse(in);
+  }
+
+  @Test(expected = BatchException.class)
+  public void testWrongBoundaryString() throws BatchException {
+    String batch = "--batch_8194-cf13-1f5" + "\n"
+        + GET_REQUEST
+        + "--batch_8194-cf13-1f56--";
+    parseInvalidBatchBody(batch);
+  }
+
+  @Test(expected = BatchException.class)
+  public void testBoundaryWithoutHyphen() throws BatchException {
+    String batch = "--batch_8194-cf13-1f56" + "\n"
+        + GET_REQUEST
+        + "batch_8194-cf13-1f56" + "\n"
+        + GET_REQUEST
+        + "--batch_8194-cf13-1f56--";
+    parseInvalidBatchBody(batch);
+  }
+
+  @Test(expected = BatchException.class)
+  public void testNoBoundaryString() throws BatchException {
+    String batch = "--batch_8194-cf13-1f56" + "\n"
+        + GET_REQUEST
+        //+ no boundary string
+        + GET_REQUEST
+        + "--batch_8194-cf13-1f56--";
+    parseInvalidBatchBody(batch);
+  }
+
+  @Test(expected = BatchException.class)
+  public void testBatchBoundaryEqualsChangeSetBoundary() throws BatchException {
+    String batch = "--batch_8194-cf13-1f56" + "\n"
+        + "Content-Type: multipart/mixed;boundary=batch_8194-cf13-1f56" + "\n"
+        + "\n"
+        + "--batch_8194-cf13-1f56" + "\n"
+        + MIME_HEADERS
+        + "\n"
+        + "PUT Employees('2')/EmployeeName HTTP/1.1" + "\n"
+        + "Accept: application/atomsvc+xml;q=0.8, application/json;odata=verbose;q=0.5, */*;q=0.1" + "\n"
+        + "Content-Type: application/json;odata=verbose" + "\n"
+        + "MaxDataServiceVersion: 2.0" + "\n"
+        + "\n"
+        + "{\"EmployeeName\":\"Frederic Fall MODIFIED\"}" + "\n"
+        + "\n"
+        + "--batch_8194-cf13-1f56--";
+    parseInvalidBatchBody(batch);
+  }
+
+  @Test(expected = BatchException.class)
+  public void testNoContentType() throws BatchException {
+    String batch = "--batch_8194-cf13-1f56" + "\n"
+        + "Content-Transfer-Encoding: binary" + "\n"
+        + "\n"
+        + "GET Employees('1')/EmployeeName HTTP/1.1" + "\n"
+        + "\n"
+        + "--batch_8194-cf13-1f56--";
+    parseInvalidBatchBody(batch);
+  }
+
+  @Test(expected = BatchException.class)
+  public void testMimeHeaderContentType() throws BatchException {
+    String batch = "--batch_8194-cf13-1f56" + "\n"
+        + "Content-Type: text/plain" + "\n"
+        + "Content-Transfer-Encoding: binary" + "\n"
+        + "\n"
+        + "GET Employees('1')/EmployeeName HTTP/1.1" + "\n"
+        + "\n"
+        + "--batch_8194-cf13-1f56--";
+    parseInvalidBatchBody(batch);
+  }
+
+  @Test(expected = BatchException.class)
+  public void testMimeHeaderEncoding() throws BatchException {
+    String batch = "--batch_8194-cf13-1f56" + "\n"
+        + "Content-Type: application/http" + "\n"
+        + "Content-Transfer-Encoding: 8bit" + "\n"
+        + "\n"
+        + "GET Employees('1')/EmployeeName HTTP/1.1" + "\n"
+        + "\n"
+        + "--batch_8194-cf13-1f56--";
+    parseInvalidBatchBody(batch);
+  }
+
+  @Test(expected = BatchException.class)
+  public void testMimeHeaderContentId() throws BatchException {
+    String batch = "--batch_8194-cf13-1f56" + "\n"
+        + MIME_HEADERS
+        + "Content-ID: 1" + "\n"
+        + "\n"
+        + "GET Employees('1')/EmployeeName HTTP/1.1" + "\n"
+        + "\n"
+        + "--batch_8194-cf13-1f56--";
+    parseInvalidBatchBody(batch);
+  }
+
+  @Test(expected = BatchException.class)
+  public void testInvalidMethodForBatch() throws BatchException {
+    String batch = "--batch_8194-cf13-1f56" + "\n"
+        + MIME_HEADERS
+        + "\n"
+        + "POST Employees('1')/EmployeeName HTTP/1.1" + "\n"
+        + "\n"
+        + "--batch_8194-cf13-1f56--";
+    parseInvalidBatchBody(batch);
+  }
+
+  @Test(expected = BatchException.class)
+  public void testNoMethod() throws BatchException {
+    String batch = "--batch_8194-cf13-1f56" + "\n"
+        + MIME_HEADERS
+        + "\n"
+        + /*GET*/"Employees('1')/EmployeeName HTTP/1.1" + "\n"
+        + "\n"
+        + "--batch_8194-cf13-1f56--";
+    parseInvalidBatchBody(batch);
+  }
+
+  @Test(expected = BatchException.class)
+  public void testInvalidMethodForChangeset() throws BatchException {
+    String batch = "--batch_8194-cf13-1f56" + "\n"
+        + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + "\n"
+        + "\n"
+        + "--changeset_f980-1cb6-94dd" + "\n"
+        + MIME_HEADERS
+        + "\n"
+        + "GET Employees('2')/EmployeeName HTTP/1.1" + "\n"
+        + "Content-Type: application/json;odata=verbose" + "\n"
+        + "MaxDataServiceVersion: 2.0" + "\n"
+        + "\n"
+        + "--batch_8194-cf13-1f56--";
+    parseInvalidBatchBody(batch);
+  }
+
+  @Test(expected = BatchException.class)
+  public void testInvalidChangeSetBoundary() throws BatchException {
+    String batch = "--batch_8194-cf13-1f56" + "\n"
+        + "Content-Type: multipart/mixed;boundary=changeset_f980-1cb6-94dd" + "\n"
+        + "\n"
+        + "--changeset_f980-1cb6-94d"/*+"d"*/+ "\n"
+        + MIME_HEADERS
+        + "\n"
+        + "POST Employees('2') HTTP/1.1" + "\n"
+        + "Content-Type: application/json;odata=verbose" + "\n"
+        + "MaxDataServiceVersion: 2.0" + "\n"
+        + "\n"
+        + "--batch_8194-cf13-1f56--";
+    parseInvalidBatchBody(batch);
+  }
+
+  @Test(expected = BatchException.class)
+  public void testNoCloseDelimiter() throws BatchException {
+    String batch = "--batch_8194-cf13-1f56" + "\n"
+        + GET_REQUEST;
+    parseInvalidBatchBody(batch);
+  }
+
+  @Test(expected = BatchException.class)
+  public void testNoCloseDelimiter2() throws BatchException {
+    String batch = "--batch_8194-cf13-1f56" + "\n"
+        + MIME_HEADERS
+        + "\n"
+        + "GET Employees('1')/EmployeeName HTTP/1.1" + "\n"
+    /*--batch_8194-cf13-1f56--*/;
+    parseInvalidBatchBody(batch);
+  }
+
+  @Test(expected = BatchException.class)
+  public void testNoCloseDelimiter3() throws BatchException {
+    String batch = "--batch_8194-cf13-1f56" + "\n" + GET_REQUEST + "--batch_8194-cf13-1f56-"/*no hash*/;
+    parseInvalidBatchBody(batch);
+  }
+
+  @Test
+  public void testAcceptHeaders() throws BatchException, URISyntaxException {
+    String batch = "--batch_8194-cf13-1f56" + "\n"
+        + MIME_HEADERS
+        + "\n"
+        + "GET Employees('2')/EmployeeName HTTP/1.1" + "\n"
+        + "Content-Length: 100000" + "\n"
+        + "Content-Type: application/json;odata=verbose" + "\n"
+        + "Accept: application/xml;q=0.3, application/atomsvc+xml;q=0.8, application/json;odata=verbose;q=0.5, */*;q=0.001" + "\n"
+        + "\n"
+        + "\n"
+        + "--batch_8194-cf13-1f56--";
+    List<BatchPart> batchParts = parse(batch);
+    for (BatchPart multipart : batchParts) {
+      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 = "--batch_8194-cf13-1f56" + "\n"
+        + MIME_HEADERS
+        + "\n"
+        + "GET Employees('2')/EmployeeName HTTP/1.1" + "\n"
+        + "Content-Length: 100000" + "\n"
+        + "Content-Type: application/json;odata=verbose" + "\n"
+        + "Accept: */*;q=0.5, application/json;odata=verbose;q=1.0,application/atom+xml" + "\n"
+        + "\n"
+        + "\n"
+        + "--batch_8194-cf13-1f56--";
+    List<BatchPart> batchParts = parse(batch);
+    for (BatchPart multipart : batchParts) {
+      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 = "--batch_8194-cf13-1f56" + "\n"
+        + MIME_HEADERS
+        + "\n"
+        + "GET Employees('2')/EmployeeName HTTP/1.1" + "\n"
+        + "Content-Length: 100000" + "\n"
+        + "Content-Type: application/json;odata=verbose" + "\n"
+        + "accept: */*,application/atom+xml,application/atomsvc+xml,application/xml" + "\n"
+        + "\n"
+        + "\n"
+        + "--batch_8194-cf13-1f56--";
+    List<BatchPart> batchParts = parse(batch);
+    for (BatchPart multipart : batchParts) {
+      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 testContentId() throws BatchException {
+    String batch = "--batch_8194-cf13-1f56" + "\n"
+        + MIME_HEADERS
+        + "\n"
+        + "GET Employees HTTP/1.1" + "\n"
+        + "accept: */*,application/atom+xml,application/atomsvc+xml,application/xml" + "\n"
+        + "Content-Id: BBB" + "\n"
+        + "\n" + "\n"
+        + "--batch_8194-cf13-1f56" + "\n"
+        + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + "\n"
+        + "\n"
+        + "--changeset_f980-1cb6-94dd" + "\n"
+        + MIME_HEADERS
+        + "Content-Id: " + CONTENT_ID_REFERENCE + "\n"
+        + "\n"
+        + "POST Employees HTTP/1.1" + "\n"
+        + "Content-type: application/octet-stream" + "\n"
+        + "\n"
+        + "/9j/4AAQSkZJRgABAQEBLAEsAAD/4RM0RXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUAAAABAAAAYgEbAAUAAAA" + "\n"
+        + "\n"
+        + "--changeset_f980-1cb6-94dd" + "\n"
+        + MIME_HEADERS
+        + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + "\n"
+        + "\n"
+        + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + "\n"
+        + "Content-Type: application/json;odata=verbose" + "\n"
+        + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + "\n"
+        + "\n"
+        + "{\"EmployeeName\":\"Peter Fall\"}" + "\n"
+        + "--changeset_f980-1cb6-94dd--" + "\n"
+        + "\n"
+        + "--batch_8194-cf13-1f56--";
+    InputStream in = new ByteArrayInputStream(batch.getBytes());
+    BatchRequestParser parser = new BatchRequestParser(contentType, batchProperties);
+    List<BatchPart> batchParts = parser.parse(in);
+    assertNotNull(batchParts);
+    for (BatchPart multipart : batchParts) {
+      if (!multipart.isChangeSet()) {
+        assertEquals(1, multipart.getRequests().size());
+        ODataRequest retrieveRequest = multipart.getRequests().get(0);
+        assertEquals("BBB", retrieveRequest.getRequestHeaderValue(BatchConstants.REQUEST_HEADER_CONTENT_ID.toLowerCase()));
+      } else {
+        for (ODataRequest request : multipart.getRequests()) {
+          if (ODataHttpMethod.POST.equals(request.getMethod())) {
+            assertEquals(CONTENT_ID_REFERENCE, request.getRequestHeaderValue(BatchConstants.MIME_HEADER_CONTENT_ID.toLowerCase()));
+          } else if (ODataHttpMethod.PUT.equals(request.getMethod())) {
+            assertEquals(PUT_MIME_HEADER_CONTENT_ID, request.getRequestHeaderValue(BatchConstants.MIME_HEADER_CONTENT_ID.toLowerCase()));
+            assertEquals(PUT_REQUEST_HEADER_CONTENT_ID, request.getRequestHeaderValue(BatchConstants.REQUEST_HEADER_CONTENT_ID.toLowerCase()));
+            assertNull(request.getPathInfo().getRequestUri());
+            assertEquals("$" + CONTENT_ID_REFERENCE, request.getPathInfo().getODataSegments().get(0).getPath());
+          }
+        }
+      }
+    }
+  }
+
+  private List<BatchPart> parse(final String batch) throws BatchException {
+    InputStream in = new ByteArrayInputStream(batch.getBytes());
+    BatchRequestParser parser = new BatchRequestParser(contentType, batchProperties);
+    List<BatchPart> batchParts = parser.parse(in);
+    assertNotNull(batchParts);
+    assertEquals(false, batchParts.isEmpty());
+    return batchParts;
+  }
+
+  private void parseInvalidBatchBody(final String batch) throws BatchException {
+    InputStream in = new ByteArrayInputStream(batch.getBytes());
+    BatchRequestParser parser = new BatchRequestParser(contentType, batchProperties);
+    parser.parse(in);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchResponseWriterTest.java
----------------------------------------------------------------------
diff --git a/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchResponseWriterTest.java b/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchResponseWriterTest.java
new file mode 100644
index 0000000..f236226
--- /dev/null
+++ b/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchResponseWriterTest.java
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * 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.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+
+import org.apache.olingo.odata2.api.batch.BatchException;
+import org.apache.olingo.odata2.api.batch.BatchResponsePart;
+import org.apache.olingo.odata2.api.commons.HttpStatusCodes;
+import org.apache.olingo.odata2.api.processor.ODataResponse;
+
+public class BatchResponseWriterTest {
+
+  @Test
+  public void testBatchResponse() throws BatchException, IOException {
+    List<BatchResponsePart> parts = new ArrayList<BatchResponsePart>();
+    ODataResponse response = ODataResponse.entity("Walter Winter")
+        .status(HttpStatusCodes.OK)
+        .contentHeader("application/json")
+        .build();
+    List<ODataResponse> responses = new ArrayList<ODataResponse>(1);
+    responses.add(response);
+    parts.add(BatchResponsePart.responses(responses).changeSet(false).build());
+
+    ODataResponse changeSetResponse = ODataResponse.status(HttpStatusCodes.NO_CONTENT).build();
+    responses = new ArrayList<ODataResponse>(1);
+    responses.add(changeSetResponse);
+    parts.add(BatchResponsePart.responses(responses).changeSet(true).build());
+
+    BatchResponseWriter writer = new BatchResponseWriter();
+    ODataResponse batchResponse = writer.writeResponse(parts);
+
+    assertEquals(202, batchResponse.getStatus().getStatusCode());
+    assertNotNull(batchResponse.getEntity());
+    String body = (String) batchResponse.getEntity();
+
+    assertTrue(body.contains("--batch"));
+    assertTrue(body.contains("--changeset"));
+    assertTrue(body.contains("HTTP/1.1 200 OK"));
+    assertTrue(body.contains("Content-Type: application/http"));
+    assertTrue(body.contains("Content-Transfer-Encoding: binary"));
+    assertTrue(body.contains("Walter Winter"));
+    assertTrue(body.contains("multipart/mixed; boundary=changeset"));
+    assertTrue(body.contains("HTTP/1.1 204 No Content"));
+
+  }
+
+  @Test
+  public void testResponse() throws BatchException, IOException {
+    List<BatchResponsePart> parts = new ArrayList<BatchResponsePart>();
+    ODataResponse response = ODataResponse.entity("Walter Winter").status(HttpStatusCodes.OK).contentHeader("application/json").build();
+    List<ODataResponse> responses = new ArrayList<ODataResponse>(1);
+    responses.add(response);
+    parts.add(BatchResponsePart.responses(responses).changeSet(false).build());
+    BatchResponseWriter writer = new BatchResponseWriter();
+    ODataResponse batchResponse = writer.writeResponse(parts);
+
+    assertEquals(202, batchResponse.getStatus().getStatusCode());
+    assertNotNull(batchResponse.getEntity());
+    String body = (String) batchResponse.getEntity();
+
+    assertTrue(body.contains("--batch"));
+    assertFalse(body.contains("--changeset"));
+    assertTrue(body.contains("HTTP/1.1 200 OK" + "\r\n"));
+    assertTrue(body.contains("Content-Type: application/http" + "\r\n"));
+    assertTrue(body.contains("Content-Transfer-Encoding: binary" + "\r\n"));
+    assertTrue(body.contains("Walter Winter"));
+    assertFalse(body.contains("multipart/mixed; boundary=changeset"));
+
+  }
+
+  @Test
+  public void testChangeSetResponse() throws BatchException, IOException {
+    List<BatchResponsePart> parts = new ArrayList<BatchResponsePart>();
+    ODataResponse changeSetResponse = ODataResponse.status(HttpStatusCodes.NO_CONTENT).build();
+    List<ODataResponse> responses = new ArrayList<ODataResponse>(1);
+    responses.add(changeSetResponse);
+    parts.add(BatchResponsePart.responses(responses).changeSet(true).build());
+
+    BatchResponseWriter writer = new BatchResponseWriter();
+    ODataResponse batchResponse = writer.writeResponse(parts);
+
+    assertEquals(202, batchResponse.getStatus().getStatusCode());
+    assertNotNull(batchResponse.getEntity());
+    String body = (String) batchResponse.getEntity();
+    assertTrue(body.contains("--batch"));
+    assertTrue(body.contains("--changeset"));
+    assertTrue(body.indexOf("--changeset") != body.lastIndexOf("--changeset"));
+    assertFalse(body.contains("HTTP/1.1 200 OK" + "\r\n"));
+    assertTrue(body.contains("Content-Type: application/http" + "\r\n"));
+    assertTrue(body.contains("Content-Transfer-Encoding: binary" + "\r\n"));
+    assertTrue(body.contains("HTTP/1.1 204 No Content" + "\r\n"));
+    assertTrue(body.contains("Content-Type: multipart/mixed; boundary=changeset"));
+
+  }
+
+  @Test
+  public void testContentIdEchoing() throws BatchException, IOException {
+    List<BatchResponsePart> parts = new ArrayList<BatchResponsePart>();
+    ODataResponse response = ODataResponse.entity("Walter Winter")
+        .status(HttpStatusCodes.OK)
+        .contentHeader("application/json")
+        .header(BatchConstants.MIME_HEADER_CONTENT_ID, "mimeHeaderContentId123")
+        .header(BatchConstants.REQUEST_HEADER_CONTENT_ID, "requestHeaderContentId123")
+        .build();
+    List<ODataResponse> responses = new ArrayList<ODataResponse>(1);
+    responses.add(response);
+    parts.add(BatchResponsePart.responses(responses).changeSet(false).build());
+    BatchResponseWriter writer = new BatchResponseWriter();
+    ODataResponse batchResponse = writer.writeResponse(parts);
+
+    assertEquals(202, batchResponse.getStatus().getStatusCode());
+    assertNotNull(batchResponse.getEntity());
+    String body = (String) batchResponse.getEntity();
+
+    String mimeHeader = "Content-Type: application/http" + "\r\n"
+        + "Content-Transfer-Encoding: binary" + "\r\n"
+        + "Content-Id: mimeHeaderContentId123" + "\r\n";
+
+    String requestHeader = "Content-Id: requestHeaderContentId123" + "\r\n"
+        + "Content-Type: application/json" + "\r\n"
+        + "Content-Length: 13" + "\r\n";
+
+    assertTrue(body.contains(mimeHeader));
+    assertTrue(body.contains(requestHeader));
+  }
+
+}