| /******************************************************************************* |
| * 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())); |
| } |
| } |