blob: b3231e340fa42aced40597dd57750497dc09da4f [file] [log] [blame]
/*******************************************************************************
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
******************************************************************************/
package org.apache.olingo.odata2.core.servlet;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.HashSet;
import java.util.Random;
import javax.servlet.GenericServlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import junit.framework.Assert;
import org.apache.olingo.odata2.api.ODataService;
import org.apache.olingo.odata2.api.ODataServiceFactory;
import org.apache.olingo.odata2.api.commons.HttpHeaders;
import org.apache.olingo.odata2.api.commons.HttpStatusCodes;
import org.apache.olingo.odata2.api.processor.ODataContext;
import org.apache.olingo.odata2.api.processor.ODataProcessor;
import org.apache.olingo.odata2.api.processor.ODataResponse;
import org.apache.olingo.odata2.core.ODataResponseImpl;
import org.apache.olingo.odata2.core.rest.ODataServiceFactoryImpl;
import org.junit.Test;
import org.mockito.Mockito;
/**
*
*/
public class ODataServletTest {
private HttpServletRequest reqMock;
private HttpServletResponse respMock;
private ServletConfig configMock;
public ODataServletTest() {
reqMock = Mockito.mock(HttpServletRequest.class);
respMock = Mockito.mock(HttpServletResponse.class);
configMock = Mockito.mock(ServletConfig.class);
}
@Test
public void handleRedirect() throws Exception {
ODataServlet servlet = new ODataServlet();
prepareServlet(servlet);
prepareRequest(reqMock);
servlet.service(reqMock, respMock);
Mockito.verify(respMock).setStatus(HttpStatusCodes.TEMPORARY_REDIRECT.getStatusCode());
Mockito.verify(respMock).setHeader(HttpHeaders.LOCATION, "/context-path/servlet-path/");
}
@Test
public void handleRedirectWoServletPath() throws Exception {
ODataServlet servlet = new ODataServlet();
prepareServlet(servlet);
prepareRequest(reqMock, "/context-path", null);
servlet.service(reqMock, respMock);
Mockito.verify(respMock).setStatus(HttpStatusCodes.TEMPORARY_REDIRECT.getStatusCode());
Mockito.verify(respMock).setHeader(HttpHeaders.LOCATION, "/context-path/");
}
@Test
public void handleRedirectWoContextPath() throws Exception {
ODataServlet servlet = new ODataServlet();
prepareServlet(servlet);
prepareRequest(reqMock, null, "/servlet-path");
servlet.service(reqMock, respMock);
Mockito.verify(respMock).setStatus(HttpStatusCodes.TEMPORARY_REDIRECT.getStatusCode());
Mockito.verify(respMock).setHeader(HttpHeaders.LOCATION, "/servlet-path/");
}
@Test
public void handleRedirectWoPath() throws Exception {
ODataServlet servlet = new ODataServlet();
prepareServlet(servlet);
prepareRequest(reqMock, null, null);
servlet.service(reqMock, respMock);
Mockito.verify(respMock).setStatus(HttpStatusCodes.TEMPORARY_REDIRECT.getStatusCode());
Mockito.verify(respMock).setHeader(HttpHeaders.LOCATION, "/");
}
@Test
public void contentLengthCalculatedString() throws Exception {
final Method createResponse =
ODataServlet.class.getDeclaredMethod("createResponse", HttpServletResponse.class, ODataResponse.class);
createResponse.setAccessible(true);
final ODataServlet servlet = new ODataServlet();
final String content = "Test\r\n";
final ODataResponse response = ODataResponseImpl.status(HttpStatusCodes.OK).entity(content).build();
prepareResponseMockToWrite(respMock);
prepareServlet(servlet);
createResponse.invoke(servlet, respMock, response);
Mockito.verify(respMock).setContentLength(content.getBytes("utf-8").length);
}
@Test
public void contentLengthCalculatedStream() throws Exception {
final Method createResponse =
ODataServlet.class.getDeclaredMethod("createResponse", HttpServletResponse.class, ODataResponse.class);
createResponse.setAccessible(true);
final ODataServlet servlet = new ODataServlet();
final String content = "Test\r\n";
final ODataResponse response =
ODataResponseImpl.status(HttpStatusCodes.OK).entity(new ByteArrayInputStream(content.getBytes("utf-8")))
.build();
prepareResponseMockToWrite(respMock);
prepareServlet(servlet);
createResponse.invoke(servlet, respMock, response);
Mockito.verify(respMock).setContentLength(content.getBytes("utf-8").length);
}
@Test
public void testInputStreamResponse() throws Exception {
ODataServlet servlet = new ODataServlet();
prepareServlet(servlet);
final ByteArrayOutputStream bout = new ByteArrayOutputStream();
final ServletOutputStream out = new ServletOutputStream() {
@Override
public void write(int i) throws IOException {
bout.write(i);
}
};
Mockito.when(respMock.getOutputStream()).thenReturn(out);
HttpServletResponse servletResponse = Mockito.mock(HttpServletResponse.class);
Mockito.when(servletResponse.getOutputStream()).thenReturn(out);
ODataResponse odataResponse = Mockito.mock(ODataResponse.class);
Mockito.when(odataResponse.getStatus()).thenReturn(HttpStatusCodes.ACCEPTED);
Mockito.when(odataResponse.getHeaderNames()).thenReturn(new HashSet<String>());
InputStream input = new ByteArrayInputStream("SomeData".getBytes());
Mockito.when(odataResponse.getEntity()).thenReturn(input);
servlet.createResponse(servletResponse, odataResponse, true);
String outputContent = new String(bout.toByteArray());
Assert.assertEquals("", outputContent);
}
@Test
public void inputStreamResponse() throws Exception {
testInputStreamResponse("123", "utf-8", null);
testInputStreamResponse("1234567890", "utf-8", "5");
testInputStreamResponse(testData(200000), "utf-8", null);
testInputStreamResponse(testData(200000), "utf-8", "8192");
testInputStreamResponse(testData(200000), "utf-8", "32768");
//
testInputStreamResponse("üäö", "iso-8859-1", "8192");
testInputStreamResponse(testData(200000), "iso-8859-1", "32768");
testInputStreamResponse(testData(200000), "iso-8859-1", "8192");
testInputStreamResponse(testData(200000), "iso-8859-1", "32768");
//
testInputStreamResponse("1234567890", "utf-8", "5");
testInputStreamResponse("1234567890", "utf-8", "ABD");
testInputStreamResponse("1234567890", "utf-8", "");
testInputStreamResponse("1234567890", "utf-8", "-29");
}
private void testInputStreamResponse(String content, String encoding, String bufferSize) throws Exception {
ODataServlet servlet = new ODataServlet();
Mockito.when(configMock.getInitParameter(
"org.apache.olingo.odata2.core.servlet.buffer.size")).thenReturn(bufferSize);
prepareServlet(servlet);
final Charset charset = Charset.forName(encoding);
final ByteArrayOutputStream bout = new ByteArrayOutputStream();
final ServletOutputStream out = new ServletOutputStream() {
@Override
public void write(int i) throws IOException {
bout.write(i);
}
};
Mockito.when(respMock.getOutputStream()).thenReturn(out);
HttpServletResponse servletResponse = Mockito.mock(HttpServletResponse.class);
Mockito.when(servletResponse.getOutputStream()).thenReturn(out);
ODataResponse odataResponse = Mockito.mock(ODataResponse.class);
Mockito.when(odataResponse.getStatus()).thenReturn(HttpStatusCodes.ACCEPTED);
Mockito.when(odataResponse.getHeaderNames()).thenReturn(new HashSet<String>());
InputStream input = new ByteArrayInputStream(content.getBytes(charset));
Mockito.when(odataResponse.getEntity()).thenReturn(input);
servlet.createResponse(servletResponse, odataResponse);
String outputContent = new String(bout.toByteArray(), charset);
Assert.assertEquals(content, outputContent);
}
private String testData(int amount) {
StringBuilder result = new StringBuilder();
Random r = new Random();
for (int i = 0; i < amount; i++) {
result.append((char)(r.nextInt(26) + 'a'));
}
return result.toString();
}
@Test
public void serviceInstance() throws Exception {
ODataServlet servlet = new ODataServlet();
prepareServlet(servlet);
prepareRequest(reqMock, "", "/servlet-path");
Mockito.when(reqMock.getPathInfo()).thenReturn("/request-path-info");
Mockito.when(reqMock.getRequestURI()).thenReturn("http://localhost:8080/servlet-path/request-path-info");
ODataServiceFactory factory = Mockito.mock(ODataServiceFactory.class);
ODataService service = Mockito.mock(ODataService.class);
Mockito.when(factory.createService(Mockito.any(ODataContext.class))).thenReturn(service);
ODataProcessor processor = Mockito.mock(ODataProcessor.class);
Mockito.when(service.getProcessor()).thenReturn(processor);
Mockito.when(reqMock.getAttribute(ODataServiceFactory.FACTORY_INSTANCE_LABEL)).thenReturn(factory);
Mockito.when(respMock.getOutputStream()).thenReturn(Mockito.mock(ServletOutputStream.class));
servlet.service(reqMock, respMock);
Mockito.verify(factory).createService(Mockito.any(ODataContext.class));
}
@Test
public void serviceClassloader() throws Exception {
ODataServlet servlet = new ODataServlet();
prepareServlet(servlet);
prepareRequest(reqMock, "", "/servlet-path");
Mockito.when(reqMock.getPathInfo()).thenReturn("/request-path-info");
Mockito.when(reqMock.getRequestURI()).thenReturn("http://localhost:8080/servlet-path/request-path-info");
Mockito.when(respMock.getOutputStream()).thenReturn(Mockito.mock(ServletOutputStream.class));
servlet.service(reqMock, respMock);
Mockito.verify(configMock).getInitParameter(ODataServiceFactory.FACTORY_LABEL);
Mockito.verify(reqMock).getAttribute(ODataServiceFactory.FACTORY_CLASSLOADER_LABEL);
Assert.assertEquals(ODataServiceFactoryImpl.class, servlet.getServiceFactory(reqMock).getClass());
}
private void prepareResponseMockToWrite(final HttpServletResponse response) throws IOException {
Mockito.when(response.getOutputStream()).thenReturn(new ServletOutputStream() {
@Override
public void write(int b) throws IOException {}
});
}
private void prepareRequest(final HttpServletRequest req, final String contextPath, final String servletPath) {
Mockito.when(req.getMethod()).thenReturn("GET");
Mockito.when(req.getContextPath()).thenReturn(contextPath);
Mockito.when(req.getServletPath()).thenReturn(servletPath);
Mockito.when(req.getHeaderNames()).thenReturn(Collections.enumeration(Collections.emptyList()));
}
private void prepareRequest(final HttpServletRequest req) {
prepareRequest(req, "/context-path", "/servlet-path");
}
private void prepareServlet(final GenericServlet servlet) throws Exception {
// private transient ServletConfig config;
Field configField = GenericServlet.class.getDeclaredField("config");
configField.setAccessible(true);
configField.set(servlet, configMock);
String factoryClassName = ODataServiceFactoryImpl.class.getName();
Mockito.when(configMock.getInitParameter(ODataServiceFactory.FACTORY_LABEL)).thenReturn(factoryClassName);
}
@Test
public void testWithNoPathAfterServletPath() throws Exception {
ODataServlet servlet = new ODataServlet();
prepareServlet(servlet);
prepareRequestWithNoPathAfterServletPath(reqMock, "", "/servlet-path");
Mockito.when(reqMock.getPathInfo()).thenReturn("/Collection");
Mockito.when(reqMock.getRequestURI()).thenReturn("http://localhost:8080/servlet-path;v=1/Collection");
Mockito.when(servlet.getInitParameter("org.apache.olingo.odata2.path.split")).thenReturn("1");
Mockito.when(respMock.getOutputStream()).thenReturn(Mockito.mock(ServletOutputStream.class));
servlet.service(reqMock, respMock);
Mockito.verify(configMock).getInitParameter(ODataServiceFactory.FACTORY_LABEL);
Mockito.verify(reqMock).getAttribute(ODataServiceFactory.FACTORY_CLASSLOADER_LABEL);
Assert.assertEquals(ODataServiceFactoryImpl.class, servlet.getServiceFactory(reqMock).getClass());
}
private void prepareRequestWithNoPathAfterServletPath(final HttpServletRequest req,
final String contextPath, final String servletPath) {
Mockito.when(req.getMethod()).thenReturn("GET");
Mockito.when(req.getContextPath()).thenReturn(contextPath);
Mockito.when(req.getServletPath()).thenReturn(servletPath);
Mockito.when(req.getRequestURI()).thenReturn(servletPath + ";v=1" + "/Collection");
Mockito.when(req.getHeaderNames()).thenReturn(Collections.enumeration(Collections.emptyList()));
}
}