SPR-5260: RestTemplate

This commit is contained in:
Arjen Poutsma
2009-02-22 14:51:00 +00:00
parent cdd37d7e8b
commit ca535bb1d0
19 changed files with 1844 additions and 0 deletions

View File

@@ -0,0 +1,171 @@
/*
* Copyright 2002-2009 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.core;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.EnumSet;
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.junit.AfterClass;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.servlet.Context;
import org.mortbay.jetty.servlet.ServletHolder;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.http.HttpMethod;
import org.springframework.web.http.client.commons.CommonsClientHttpRequestFactory;
/**
* @author Arjen Poutsma
*/
public class RestTemplateIntegrationTests {
private RestTemplate template;
private static Server jettyServer;
@BeforeClass
public static void startJettyServer() throws Exception {
jettyServer = new Server(8889);
Context jettyContext = new Context(jettyServer, "/");
String s = "H\u00e9llo W\u00f6rld";
byte[] bytes = s.getBytes("UTF-8");
jettyContext.addServlet(new ServletHolder(new GetServlet(bytes, "text/plain;charset=utf-8")), "/get");
jettyContext
.addServlet(new ServletHolder(new PostServlet(s, new URI("http://localhost:8889/post/1"))), "/post");
jettyContext.addServlet(new ServletHolder(new ErrorServlet(404)), "/errors/notfound");
jettyContext.addServlet(new ServletHolder(new ErrorServlet(500)), "/errors/server");
jettyServer.start();
}
@Before
public void createTemplate() {
// template = new RestTemplate();
template = new RestTemplate(new CommonsClientHttpRequestFactory());
}
@AfterClass
public static void stopJettyServer() throws Exception {
if (jettyServer != null) {
jettyServer.stop();
}
}
@Test
public void getString() {
String s = template.getForObject("http://localhost:8889/{method}", String.class, "get");
assertEquals("Invalid content", "H\u00e9llo W\u00f6rld", s);
}
@Test
public void postString() throws URISyntaxException {
URI location = template.postForLocation("http://localhost:8889/{method}", "H\u00e9llo W\u00f6rld", "post");
assertEquals("Invalid location", new URI("http://localhost:8889/post/1"), location);
}
@Test(expected = HttpClientErrorException.class)
public void notFound() {
template.execute("http://localhost:8889/errors/notfound", HttpMethod.GET, null, null);
}
@Test(expected = HttpServerErrorException.class)
public void serverError() {
template.execute("http://localhost:8889/errors/server", HttpMethod.GET, null, null);
}
@Test
public void optionsForAllow() {
EnumSet<HttpMethod> allowed = template.optionsForAllow("http://localhost:8889/get");
assertEquals("Invalid response",
EnumSet.of(HttpMethod.GET, HttpMethod.OPTIONS, HttpMethod.HEAD, HttpMethod.TRACE), allowed);
}
/**
* Servlet that returns and error message for a given status code.
*/
private static class ErrorServlet extends GenericServlet {
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 final byte[] buf;
private final String contentType;
private GetServlet(byte[] buf, String contentType) {
this.buf = buf;
this.contentType = contentType;
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentLength(buf.length);
response.setContentType(contentType);
FileCopyUtils.copy(buf, response.getOutputStream());
}
}
private static class PostServlet extends HttpServlet {
private final String s;
private final URI location;
private PostServlet(String s, URI location) {
this.s = s;
this.location = location;
}
@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.toASCIIString());
}
}
}

View File

@@ -0,0 +1,349 @@
/*
* Copyright 2002-2009 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.core;
import java.io.IOException;
import java.net.URI;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.springframework.util.MediaType;
import org.springframework.web.client.HttpClientException;
import org.springframework.web.client.HttpIOException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.converter.ByteArrayHttpMessageConverter;
import org.springframework.web.converter.HttpMessageConverter;
import org.springframework.web.converter.StringHttpMessageConverter;
import org.springframework.web.http.HttpHeaders;
import org.springframework.web.http.HttpMethod;
import org.springframework.web.http.HttpStatus;
import org.springframework.web.http.client.ClientHttpRequest;
import org.springframework.web.http.client.ClientHttpRequestFactory;
import org.springframework.web.http.client.ClientHttpResponse;
/**
* @author Arjen Poutsma
*/
@SuppressWarnings("unchecked")
public class RestTemplateTest {
private RestTemplate template;
private ClientHttpRequestFactory requestFactory;
private ClientHttpRequest request;
private ClientHttpResponse response;
private HttpErrorHandler errorHandler;
private HttpMessageConverter converter;
@Before
public void setUp() {
requestFactory = createMock(ClientHttpRequestFactory.class);
request = createMock(ClientHttpRequest.class);
response = createMock(ClientHttpResponse.class);
errorHandler = createMock(HttpErrorHandler.class);
converter = createMock(HttpMessageConverter.class);
template = new RestTemplate(requestFactory);
template.setErrorHandler(errorHandler);
template.setMessageConverters(new HttpMessageConverter<?>[]{converter});
}
@Test
public void getSupportedMessageBodyConverters() {
ByteArrayHttpMessageConverter byteArrayConverter = new ByteArrayHttpMessageConverter();
StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
template.setMessageConverters(new HttpMessageConverter<?>[]{byteArrayConverter, stringConverter});
List<HttpMessageConverter<String>> result = template.getSupportedMessageConverters(String.class);
assertEquals("Invalid amount of String converters", 1, result.size());
assertEquals("Invalid String converters", stringConverter, result.get(0));
}
@Test
public void varArgsTemplateVariables() throws Exception {
expect(requestFactory.createRequest(new URI("http://example.com/hotels/42/bookings/21"), HttpMethod.GET))
.andReturn(request);
expect(request.execute()).andReturn(response);
expect(errorHandler.hasError(response)).andReturn(false);
response.close();
replayMocks();
template.execute("http://example.com/hotels/{hotel}/bookings/{booking}", HttpMethod.GET, null, null, "42",
"21");
verifyMocks();
}
@Test
public void mapTemplateVariables() throws Exception {
expect(requestFactory.createRequest(new URI("http://example.com/hotels/42/bookings/42"), HttpMethod.GET))
.andReturn(request);
expect(request.execute()).andReturn(response);
expect(errorHandler.hasError(response)).andReturn(false);
response.close();
replayMocks();
Map<String, String> vars = Collections.singletonMap("hotel", "42");
template.execute("http://example.com/hotels/{hotel}/bookings/{hotel}", HttpMethod.GET, null, null, vars);
verifyMocks();
}
@Test
public void errorHandling() throws Exception {
expect(requestFactory.createRequest(new URI("http://example.com"), HttpMethod.GET)).andReturn(request);
expect(request.execute()).andReturn(response);
expect(errorHandler.hasError(response)).andReturn(true);
errorHandler.handleError(response);
expectLastCall().andThrow(new HttpServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR));
response.close();
replayMocks();
try {
template.execute("http://example.com", HttpMethod.GET, null, null);
fail("HttpServerErrorException expected");
}
catch (HttpServerErrorException ex) {
// expected
}
verifyMocks();
}
@Test
public void getForObject() throws Exception {
expect(converter.supports(String.class)).andReturn(true).times(3);
MediaType textPlain = new MediaType("text", "plain");
expect(converter.getSupportedMediaTypes()).andReturn(Collections.singletonList(textPlain)).times(2);
expect(requestFactory.createRequest(new URI("http://example.com"), HttpMethod.GET)).andReturn(request);
HttpHeaders requestHeaders = new HttpHeaders();
expect(request.getHeaders()).andReturn(requestHeaders);
expect(request.execute()).andReturn(response);
expect(errorHandler.hasError(response)).andReturn(false);
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.setContentType(textPlain);
expect(response.getHeaders()).andReturn(responseHeaders);
String expected = "Hello World";
expect(converter.read(String.class, response)).andReturn(expected);
response.close();
replayMocks();
String result = template.getForObject("http://example.com", String.class);
assertEquals("Invalid GET result", expected, result);
verifyMocks();
}
@Test
public void getForObjectUnsupportedClass() throws Exception {
expect(converter.supports(String.class)).andReturn(false);
replayMocks();
try {
template.getForObject("http://example.com/{p}", String.class, "resource");
fail("IllegalArgumentException expected");
}
catch (IllegalArgumentException ex) {
// expected
}
verifyMocks();
}
@Test
public void getUnsupportedMediaType() throws Exception {
expect(converter.supports(String.class)).andReturn(true).times(3);
MediaType supportedMediaType = new MediaType("foo", "bar");
expect(converter.getSupportedMediaTypes()).andReturn(Collections.singletonList(supportedMediaType)).times(2);
expect(requestFactory.createRequest(new URI("http://example.com/resource"), HttpMethod.GET)).andReturn(request);
HttpHeaders requestHeaders = new HttpHeaders();
expect(request.getHeaders()).andReturn(requestHeaders);
expect(request.execute()).andReturn(response);
expect(errorHandler.hasError(response)).andReturn(false);
HttpHeaders responseHeaders = new HttpHeaders();
MediaType contentType = new MediaType("bar", "baz");
responseHeaders.setContentType(contentType);
expect(response.getHeaders()).andReturn(responseHeaders);
response.close();
replayMocks();
try {
template.getForObject("http://example.com/{p}", String.class, "resource");
fail("UnsupportedMediaTypeException expected");
}
catch (HttpClientException ex) {
// expected
}
verifyMocks();
}
@Test
public void headForHeaders() throws Exception {
expect(requestFactory.createRequest(new URI("http://example.com"), HttpMethod.HEAD)).andReturn(request);
expect(request.execute()).andReturn(response);
expect(errorHandler.hasError(response)).andReturn(false);
HttpHeaders responseHeaders = new HttpHeaders();
expect(response.getHeaders()).andReturn(responseHeaders);
response.close();
replayMocks();
HttpHeaders result = template.headForHeaders("http://example.com");
assertSame("Invalid headers returned", responseHeaders, result);
verifyMocks();
}
@Test
public void postForLocation() throws Exception {
expect(converter.supports(String.class)).andReturn(true).times(2);
expect(requestFactory.createRequest(new URI("http://example.com"), HttpMethod.POST)).andReturn(request);
String helloWorld = "Hello World";
converter.write(helloWorld, request);
expect(request.execute()).andReturn(response);
expect(errorHandler.hasError(response)).andReturn(false);
HttpHeaders responseHeaders = new HttpHeaders();
URI expected = new URI("http://example.com/hotels");
responseHeaders.setLocation(expected);
expect(response.getHeaders()).andReturn(responseHeaders);
response.close();
replayMocks();
URI result = template.postForLocation("http://example.com", helloWorld);
assertEquals("Invalid POST result", expected, result);
verifyMocks();
}
@Test
public void postForLocationNoLocation() throws Exception {
expect(converter.supports(String.class)).andReturn(true).times(2);
expect(requestFactory.createRequest(new URI("http://example.com"), HttpMethod.POST)).andReturn(request);
String helloWorld = "Hello World";
converter.write(helloWorld, request);
expect(request.execute()).andReturn(response);
expect(errorHandler.hasError(response)).andReturn(false);
HttpHeaders responseHeaders = new HttpHeaders();
expect(response.getHeaders()).andReturn(responseHeaders);
response.close();
replayMocks();
URI result = template.postForLocation("http://example.com", helloWorld);
assertNull("Invalid POST result", result);
verifyMocks();
}
@Test
public void put() throws Exception {
expect(converter.supports(String.class)).andReturn(true).times(2);
expect(requestFactory.createRequest(new URI("http://example.com"), HttpMethod.PUT)).andReturn(request);
String helloWorld = "Hello World";
converter.write(helloWorld, request);
expect(request.execute()).andReturn(response);
expect(errorHandler.hasError(response)).andReturn(false);
response.close();
replayMocks();
template.put("http://example.com", helloWorld);
verifyMocks();
}
@Test
public void delete() throws Exception {
expect(requestFactory.createRequest(new URI("http://example.com"), HttpMethod.DELETE)).andReturn(request);
expect(request.execute()).andReturn(response);
expect(errorHandler.hasError(response)).andReturn(false);
response.close();
replayMocks();
template.delete("http://example.com");
verifyMocks();
}
@Test
public void optionsForAllow() throws Exception {
expect(requestFactory.createRequest(new URI("http://example.com"), HttpMethod.OPTIONS)).andReturn(request);
expect(request.execute()).andReturn(response);
expect(errorHandler.hasError(response)).andReturn(false);
HttpHeaders responseHeaders = new HttpHeaders();
EnumSet<HttpMethod> expected = EnumSet.of(HttpMethod.GET, HttpMethod.POST);
responseHeaders.setAllow(expected);
expect(response.getHeaders()).andReturn(responseHeaders);
response.close();
replayMocks();
EnumSet<HttpMethod> result = template.optionsForAllow("http://example.com");
assertEquals("Invalid OPTIONS result", expected, result);
verifyMocks();
}
@Test
public void ioException() throws Exception {
expect(converter.supports(String.class)).andReturn(true).times(2);
MediaType mediaType = new MediaType("foo", "bar");
expect(converter.getSupportedMediaTypes()).andReturn(Collections.singletonList(mediaType));
expect(requestFactory.createRequest(new URI("http://example.com/resource"), HttpMethod.GET)).andReturn(request);
expect(request.getHeaders()).andReturn(new HttpHeaders());
expect(request.execute()).andThrow(new IOException());
replayMocks();
try {
template.getForObject("http://example.com/resource", String.class);
fail("RestClientException expected");
}
catch (HttpIOException ex) {
// expected
}
verifyMocks();
}
private void replayMocks() {
replay(requestFactory, request, response, errorHandler, converter);
}
private void verifyMocks() {
verify(requestFactory, request, response, errorHandler, converter);
}
}