/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed 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.springframework.web.client;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Set;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.servlet.Context;
import org.mortbay.jetty.servlet.ServletHolder;
import org.springframework.android.test.Assert;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpBasicAuthentication;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;
/**
* @author Arjen Poutsma
* @author Roy Clarkson
*/
public abstract class AbstractRestTemplateIntegrationTests extends AndroidTestCase {
protected static final String TAG = AbstractRestTemplateIntegrationTests.class.getSimpleName();
private static Server jettyServer;
private static String helloWorld = "H\u00e9llo W\u00f6rld!!";
private static String baseUrl;
private static MediaType contentType;
private RestTemplate restTemplate;
protected abstract RestTemplate getRestTemplate();
@Override
protected void setUp() throws Exception {
super.setUp();
this.restTemplate = getRestTemplate();
setUpJetty();
}
private static void setUpJetty() throws Exception {
if (jettyServer == null) {
int port = 8181;
jettyServer = new Server(port);
baseUrl = "http://localhost:" + port;
Context jettyContext = new Context(jettyServer, "/");
byte[] bytes = helloWorld.getBytes("UTF-8");
contentType = new MediaType("text", "plain", Collections.singletonMap("charset", "utf-8"));
jettyContext.addServlet(new ServletHolder(new GetServlet(bytes, contentType)), "/get");
jettyContext.addServlet(new ServletHolder(new GetServlet(new byte[0], contentType)), "/get/nothing");
jettyContext.addServlet(new ServletHolder(new GetServlet(bytes, null)), "/get/nocontenttype");
jettyContext.addServlet(new ServletHolder(new ErrorServlet(401)), "/get/notauthorized");
jettyContext.addServlet(new ServletHolder(new ErrorServlet(407)), "/get/notproxyauthorized");
jettyContext.addServlet(new ServletHolder(new PostServlet(helloWorld, baseUrl + "/post/1", bytes,
contentType)), "/post");
jettyContext.addServlet(new ServletHolder(new StatusCodeServlet(204)), "/status/nocontent");
jettyContext.addServlet(new ServletHolder(new StatusCodeServlet(304)), "/status/notmodified");
jettyContext.addServlet(new ServletHolder(new ErrorServlet(401)), "/status/notfound");
jettyContext.addServlet(new ServletHolder(new ErrorServlet(404)), "/status/notfound");
jettyContext.addServlet(new ServletHolder(new ErrorServlet(500)), "/status/server");
jettyContext.addServlet(new ServletHolder(new UriServlet()), "/uri/*");
jettyContext.addServlet(new ServletHolder(new MultipartServlet()), "/multipart");
jettyServer.start();
}
}
@Override
protected void tearDown() throws Exception {
this.restTemplate = null;
}
@Override
protected void finalize() throws Throwable {
super.finalize();
if (jettyServer != null) {
jettyServer.stop();
}
}
@MediumTest
public void testGetString() {
String s = restTemplate.getForObject(baseUrl + "/{method}", String.class, "get");
assertEquals("Invalid content", helloWorld, s);
}
@MediumTest
public void testGetEntity() {
ResponseEntity<String> entity = restTemplate.getForEntity(baseUrl + "/{method}", String.class, "get");
assertEquals("Invalid content", helloWorld, entity.getBody());
assertFalse("No headers", entity.getHeaders().isEmpty());
assertEquals("Invalid content-type", contentType, entity.getHeaders().getContentType());
assertEquals("Invalid status code", HttpStatus.OK, entity.getStatusCode());
}
@MediumTest
public void testGetEntityNotAuthorized() {
try {
restTemplate.getForEntity(baseUrl + "/get/notauthorized", String.class);
fail("HttpClientErrorException expected");
} catch (HttpClientErrorException ex) {
assertEquals(HttpStatus.UNAUTHORIZED, ex.getStatusCode());
assertEquals(HttpStatus.UNAUTHORIZED.getReasonPhrase(), ex.getStatusText());
assertNotNull(ex.getResponseBodyAsString());
}
}
@MediumTest
public void testGetEntityNotAuthorizedBadCredentials() {
try {
HttpHeaders headers = new HttpHeaders();
headers.setAuthorization(new HttpBasicAuthentication("bob", "password"));
HttpEntity<Void> requestEntity = new HttpEntity<Void>(headers);
restTemplate.exchange(baseUrl + "/get/notauthorized", HttpMethod.GET, requestEntity, String.class);
fail("HttpClientErrorException expected");
} catch (HttpClientErrorException ex) {
assertEquals(HttpStatus.UNAUTHORIZED, ex.getStatusCode());
assertEquals(HttpStatus.UNAUTHORIZED.getReasonPhrase(), ex.getStatusText());
assertNotNull(ex.getResponseBodyAsString());
}
}
@MediumTest
public void testGetEntityNotProxyAuthorized() {
try {
restTemplate.getForEntity(baseUrl + "/get/notproxyauthorized", String.class);
fail("HttpClientErrorException expected");
} catch (HttpClientErrorException ex) {
assertEquals(HttpStatus.PROXY_AUTHENTICATION_REQUIRED, ex.getStatusCode());
assertEquals(HttpStatus.PROXY_AUTHENTICATION_REQUIRED.getReasonPhrase(), ex.getStatusText());
assertNotNull(ex.getResponseBodyAsString());
}
}
@MediumTest
public void testGetNoResponse() {
String s = restTemplate.getForObject(baseUrl + "/get/nothing", String.class);
assertNull("Invalid content", s);
}
@MediumTest
public void testGetNoContentTypeHeader() throws UnsupportedEncodingException {
byte[] bytes = restTemplate.getForObject(baseUrl + "/get/nocontenttype", byte[].class);
Assert.assertArrayEquals("Invalid content", helloWorld.getBytes("UTF-8"), bytes);
}
@MediumTest
public void testGetNoContent() {
String s = restTemplate.getForObject(baseUrl + "/status/nocontent", String.class);
assertNull("Invalid content", s);
ResponseEntity<String> entity = restTemplate.getForEntity(baseUrl + "/status/nocontent", String.class);
assertEquals("Invalid response code", HttpStatus.NO_CONTENT, entity.getStatusCode());
assertNull("Invalid content", entity.getBody());
}
@MediumTest
public void testGetNotModified() {
String s = restTemplate.getForObject(baseUrl + "/status/notmodified", String.class);
assertNull("Invalid content", s);
ResponseEntity<String> entity = restTemplate.getForEntity(baseUrl + "/status/notmodified", String.class);
assertEquals("Invalid response code", HttpStatus.NOT_MODIFIED, entity.getStatusCode());
assertNull("Invalid content", entity.getBody());
}
@MediumTest
public void testPostForLocation() throws URISyntaxException {
URI location = restTemplate.postForLocation(baseUrl + "/{method}", helloWorld, "post");
assertEquals("Invalid location", new URI(baseUrl + "/post/1"), location);
}
@MediumTest
public void testPostForLocationEntity() throws URISyntaxException {
HttpHeaders entityHeaders = new HttpHeaders();
entityHeaders.setContentType(new MediaType("text", "plain", Charset.forName("ISO-8859-15")));
HttpEntity<String> entity = new HttpEntity<String>(helloWorld, entityHeaders);
URI location = restTemplate.postForLocation(baseUrl + "/{method}", entity, "post");
assertEquals("Invalid location", new URI(baseUrl + "/post/1"), location);
}
@MediumTest
public void testPostForObject() throws URISyntaxException {
String s = restTemplate.postForObject(baseUrl + "/{method}", helloWorld, String.class, "post");
assertEquals("Invalid content", helloWorld, s);
}
@MediumTest
public void testNotFound() {
try {
restTemplate.execute(baseUrl + "/status/notfound", HttpMethod.GET, null, null);
fail("HttpClientErrorException expected");
} catch (HttpClientErrorException ex) {
assertEquals(HttpStatus.NOT_FOUND, ex.getStatusCode());
assertNotNull(ex.getStatusText());
assertNotNull(ex.getResponseBodyAsString());
}
}
@MediumTest
public void testServerError() {
try {
restTemplate.execute(baseUrl + "/status/server", HttpMethod.GET, null, null);
fail("HttpServerErrorException expected");
} catch (HttpServerErrorException ex) {
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, ex.getStatusCode());
assertNotNull(ex.getStatusText());
assertNotNull(ex.getResponseBodyAsString());
}
}
@MediumTest
public void testOptionsForAllow() throws URISyntaxException {
Set<HttpMethod> allowed = restTemplate.optionsForAllow(new URI(baseUrl + "/get"));
assertEquals("Invalid response",
EnumSet.of(HttpMethod.GET, HttpMethod.OPTIONS, HttpMethod.HEAD, HttpMethod.TRACE), allowed);
}
@MediumTest
public void testUri() throws InterruptedException, URISyntaxException {
String result = restTemplate.getForObject(baseUrl + "/uri/{query}", String.class, "Z\u00fcrich");
assertEquals("Invalid request URI", "/uri/Z%C3%BCrich", result);
result = restTemplate.getForObject(baseUrl + "/uri/query={query}", String.class, "foo@bar");
assertEquals("Invalid request URI", "/uri/query=foo@bar", result);
result = restTemplate.getForObject(baseUrl + "/uri/query={query}", String.class, "T\u014dky\u014d");
assertEquals("Invalid request URI", "/uri/query=T%C5%8Dky%C5%8D", result);
}
@MediumTest
public void testMultipart() throws UnsupportedEncodingException {
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<String, Object>();
parts.add("name 1", "value 1");
parts.add("name 2", "value 2+1");
parts.add("name 2", "value 2+2");
Resource logo = new ClassPathResource("res/drawable/icon.png");
parts.add("logo", logo);
restTemplate.postForLocation(baseUrl + "/multipart", parts);
}
@MediumTest
public void testExchangeGet() throws Exception {
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("MyHeader", "MyValue");
HttpEntity<Void> requestEntity = new HttpEntity<Void>(requestHeaders);
ResponseEntity<String> response = restTemplate.exchange(baseUrl + "/{method}", HttpMethod.GET, requestEntity,
String.class, "get");
assertEquals("Invalid content", helloWorld, response.getBody());
}
@MediumTest
public void testExchangePost() throws Exception {
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("MyHeader", "MyValue");
requestHeaders.setContentType(MediaType.TEXT_PLAIN);
HttpEntity<String> requestEntity = new HttpEntity<String>(helloWorld, requestHeaders);
HttpEntity<Void> result = restTemplate.exchange(baseUrl + "/{method}", HttpMethod.POST, requestEntity,
Void.class, "post");
assertEquals("Invalid location", new URI(baseUrl + "/post/1"), result.getHeaders().getLocation());
assertFalse(result.hasBody());
}
// ANDROID-81
// ignoring since this test makes a request to an external address
// public void testMultipleHttpsRequests() throws Exception {
// HttpHeaders requestHeaders = new HttpHeaders();
// requestHeaders.setAcceptEncoding(ContentCodingType.GZIP);
// requestHeaders.set("Connection", "Close");
// requestHeaders.set("Cache-Control", "no-cache");
// requestHeaders.set("Pragma", "no-cache");
// HttpEntity<Void> requestEntity = new HttpEntity<Void>(requestHeaders);
// String url = "https://github.com/spring-guides/gs-consuming-rest-android";
// try {
// restTemplate.exchange(url, HttpMethod.GET, requestEntity, byte[].class);
// } catch (HttpClientErrorException e) {
// if (e.getStatusCode() != HttpStatus.NOT_FOUND) {
// throw e;
// }
// }
// url = "https://github.com/spring-guides/gs-consuming-rest-xml-android";
// restTemplate.exchange(url, HttpMethod.GET, requestEntity, byte[].class);
// }
/** Servlet that sets the given status code. */
private static class StatusCodeServlet extends GenericServlet {
private static final long serialVersionUID = 1L;
private final int sc;
private StatusCodeServlet(int sc) {
this.sc = sc;
}
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
((HttpServletResponse) response).setStatus(sc);
}
}
/** Servlet that returns an error message for a given status code. */
private static class ErrorServlet extends GenericServlet {
private static final long serialVersionUID = 1L;
private final int sc;
private ErrorServlet(int sc) {
this.sc = sc;
}
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
((HttpServletResponse) response).sendError(sc);
}
}
private static class GetServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private final byte[] buf;
private final MediaType contentType;
private GetServlet(byte[] buf, MediaType contentType) {
this.buf = buf;
this.contentType = contentType;
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
if (contentType != null) {
response.setContentType(contentType.toString());
}
response.setContentLength(buf.length);
FileCopyUtils.copy(buf, response.getOutputStream());
}
}
private static class PostServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private final String s;
private final String location;
private final byte[] buf;
private final MediaType contentType;
private PostServlet(String s, String location, byte[] buf, MediaType contentType) {
this.s = s;
this.location = location;
this.buf = buf;
this.contentType = contentType;
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
assertTrue("Invalid request content-length", request.getContentLength() > 0);
assertNotNull("No content-type", request.getContentType());
String body = FileCopyUtils.copyToString(request.getReader());
assertEquals("Invalid request body", s, body);
response.setStatus(HttpServletResponse.SC_CREATED);
response.setHeader("Location", location);
response.setContentLength(buf.length);
response.setContentType(contentType.toString());
FileCopyUtils.copy(buf, response.getOutputStream());
}
}
private static class UriServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/plain");
resp.setCharacterEncoding("UTF-8");
resp.getWriter().write(req.getRequestURI());
}
}
private static class MultipartServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO: determine how to test this
// assertTrue(ServletFileUpload.isMultipartContent(req));
// FileItemFactory factory = new DiskFileItemFactory();
// ServletFileUpload upload = new ServletFileUpload(factory);
// try {
// List<?> items = upload.parseRequest(req);
// assertEquals(4, items.size());
// FileItem item = (FileItem) items.get(0);
// assertTrue(item.isFormField());
// assertEquals("name 1", item.getFieldName());
// assertEquals("value 1", item.getString());
//
// item = (FileItem) items.get(1);
// assertTrue(item.isFormField());
// assertEquals("name 2", item.getFieldName());
// assertEquals("value 2+1", item.getString());
//
// item = (FileItem) items.get(2);
// assertTrue(item.isFormField());
// assertEquals("name 2", item.getFieldName());
// assertEquals("value 2+2", item.getString());
//
// item = (FileItem) items.get(3);
// assertFalse(item.isFormField());
// assertEquals("logo", item.getFieldName());
// assertEquals("logo.jpg", item.getName());
// assertEquals("image/jpeg", item.getContentType());
// } catch (FileUploadException ex) {
// throw new ServletException(ex);
// }
}
}
}