From 355434891941a3ea8409d91233b026978167909d Mon Sep 17 00:00:00 2001 From: Kamill Sokol Date: Mon, 28 Dec 2015 13:32:47 +0100 Subject: [PATCH 1/2] Support custom HTTP verbs in Spring MVC Test Prior to this commit, Spring MVC Test only supported HTTP methods GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE and multipart file upload. This change adds generic methods to MockMvcRequestBuilders in order to allow testing of arbitrary HTTP methods in a Spring MVC application. Issue: SPR-13719 --- .../MockHttpServletRequestBuilder.java | 38 ++++++++++++------- .../request/MockMvcRequestBuilders.java | 24 +++++++++++- .../MockHttpServletRequestBuilderTests.java | 22 ++++++++++- 3 files changed, 69 insertions(+), 15 deletions(-) diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilder.java b/spring-test/src/main/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilder.java index 1663bd2fb5..f111fd9a40 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilder.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilder.java @@ -60,16 +60,20 @@ import org.springframework.web.util.UriUtils; * *

Application tests will typically access this builder through the static factory * methods in {@link MockMvcRequestBuilders}. + *

Although this class cannot be extended, additional ways to initialize + * the {@code MockHttpServletRequest} can be plugged in via + * {@link #with(RequestPostProcessor)}. * * @author Rossen Stoyanchev * @author Arjen Poutsma * @author Sam Brannen + * @author Kamill Sokol * @since 3.2 */ public class MockHttpServletRequestBuilder implements ConfigurableSmartRequestBuilder, Mergeable { - private final HttpMethod method; + private final String method; private final URI url; @@ -109,37 +113,45 @@ public class MockHttpServletRequestBuilder /** - * Package private constructor. To get an instance, use static factory - * methods in {@link MockMvcRequestBuilders}. - *

Although this class cannot be extended, additional ways to initialize - * the {@code MockHttpServletRequest} can be plugged in via - * {@link #with(RequestPostProcessor)}. * @param httpMethod the HTTP method (GET, POST, etc) * @param url a URL template; the resulting URL will be encoded * @param vars zero or more URL variables */ MockHttpServletRequestBuilder(HttpMethod httpMethod, String url, Object... vars) { + this(httpMethod.name(), UriComponentsBuilder.fromUriString(url).buildAndExpand(vars).encode().toUri()); + } + + /** + * @param httpMethod the HTTP method (GET, POST, etc) + * @param url a URL template; the resulting URL will be encoded + * @param vars zero or more URL variables + * @since 4.3 + */ + MockHttpServletRequestBuilder(String httpMethod, String url, Object... vars) { this(httpMethod, UriComponentsBuilder.fromUriString(url).buildAndExpand(vars).encode().toUri()); } /** - * Package private constructor. To get an instance, use static factory - * methods in {@link MockMvcRequestBuilders}. - *

Although this class cannot be extended, additional ways to initialize - * the {@code MockHttpServletRequest} can be plugged in via - * {@link #with(RequestPostProcessor)}. * @param httpMethod the HTTP method (GET, POST, etc) * @param url the URL * @since 4.0.3 */ MockHttpServletRequestBuilder(HttpMethod httpMethod, URI url) { + this(httpMethod.name(), url); + } + + /** + * @param httpMethod the HTTP method (GET, POST, etc) + * @param url the URL + * @since 4.3 + */ + MockHttpServletRequestBuilder(String httpMethod, URI url) { Assert.notNull(httpMethod, "httpMethod is required"); Assert.notNull(url, "url is required"); this.method = httpMethod; this.url = url; } - /** * Add a request parameter to the {@link MockHttpServletRequest}. *

If called more than once, new values get added to existing ones. @@ -585,7 +597,7 @@ public class MockHttpServletRequestBuilder request.setServerPort(this.url.getPort()); } - request.setMethod(this.method.name()); + request.setMethod(this.method); for (String name : this.headers.keySet()) { for (Object value : this.headers.get(name)) { diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/request/MockMvcRequestBuilders.java b/spring-test/src/main/java/org/springframework/test/web/servlet/request/MockMvcRequestBuilders.java index 571699e614..c9455adc0e 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/request/MockMvcRequestBuilders.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/request/MockMvcRequestBuilders.java @@ -42,6 +42,7 @@ import org.springframework.test.web.servlet.RequestBuilder; * @author Greg Turnquist * @author Sebastien Deleuze * @author Sam Brannen + * @author Kamill Sokol * @since 3.2 */ public abstract class MockMvcRequestBuilders { @@ -175,7 +176,7 @@ public abstract class MockMvcRequestBuilders { /** * Create a {@link MockHttpServletRequestBuilder} for a request with the given HTTP method. - * @param httpMethod the HTTP method + * @param httpMethod the HTTP method (GET, POST, etc) * @param urlTemplate a URL template; the resulting URL will be encoded * @param urlVariables zero or more URL variables */ @@ -183,6 +184,17 @@ public abstract class MockMvcRequestBuilders { return new MockHttpServletRequestBuilder(httpMethod, urlTemplate, urlVariables); } + /** + * Create a {@link MockHttpServletRequestBuilder} for a request with the given HTTP method. + * @param httpMethod the HTTP method (GET, POST, etc) + * @param urlTemplate a URL template; the resulting URL will be encoded + * @param urlVariables zero or more URL variables + * @since 4.3 + */ + public static MockHttpServletRequestBuilder request(String httpMethod, String urlTemplate, Object... urlVariables) { + return new MockHttpServletRequestBuilder(httpMethod, urlTemplate, urlVariables); + } + /** * Create a {@link MockHttpServletRequestBuilder} for a request with the given HTTP method. * @param httpMethod the HTTP method (GET, POST, etc) @@ -193,6 +205,16 @@ public abstract class MockMvcRequestBuilders { return new MockHttpServletRequestBuilder(httpMethod, uri); } + /** + * Create a {@link MockHttpServletRequestBuilder} for a request with the given HTTP method. + * @param httpMethod the HTTP method (GET, POST, etc) + * @param uri the URL + * @since 4.3 + */ + public static MockHttpServletRequestBuilder request(String httpMethod, URI uri) { + return new MockHttpServletRequestBuilder(httpMethod, uri); + } + /** * Create a {@link MockMultipartHttpServletRequestBuilder} for a multipart request. * @param urlTemplate a URL template; the resulting URL will be encoded diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilderTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilderTests.java index 90ab35ba0b..1cb1a01ec8 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilderTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilderTests.java @@ -471,7 +471,9 @@ public class MockHttpServletRequestBuilderTests { assertEquals(user, request.getUserPrincipal()); } - // SPR-12945 + /** + * See SPR-12945 + */ @Test public void mergeInvokesDefaultRequestPostProcessorFirst() { final String ATTR = "ATTR"; @@ -492,6 +494,24 @@ public class MockHttpServletRequestBuilderTests { assertEquals(EXEPCTED, request.getAttribute(ATTR)); } + /** + * See SPR-13719 + */ + @Test + public void arbitraryMethod() { + /* + * http method is case-sensitive + * http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.1 + */ + String httpMethod = "REPort"; + this.builder = new MockHttpServletRequestBuilder(httpMethod, "/foo/{bar}", 42); + + MockHttpServletRequest request = this.builder.buildRequest(this.servletContext); + + assertEquals(httpMethod, request.getMethod()); + assertEquals("/foo/42", request.getPathInfo()); + } + private final class User implements Principal { From df223eb118abb870a5281e74ea3952069de1ad24 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Thu, 21 Jan 2016 09:12:05 -0500 Subject: [PATCH 2/2] Polish custom HTTP verb in Spring MVC Test Issue: SPR-13719 --- .../MockHttpServletRequestBuilder.java | 22 +++--- .../request/MockMvcRequestBuilders.java | 73 ++++++++----------- .../MockHttpServletRequestBuilderTests.java | 28 ++++--- 3 files changed, 54 insertions(+), 69 deletions(-) diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilder.java b/spring-test/src/main/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilder.java index f111fd9a40..c7ec885a67 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilder.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -113,6 +113,11 @@ public class MockHttpServletRequestBuilder /** + * Package private constructor. To get an instance, use static factory + * methods in {@link MockMvcRequestBuilders}. + *

Although this class cannot be extended, additional ways to initialize + * the {@code MockHttpServletRequest} can be plugged in via + * {@link #with(RequestPostProcessor)}. * @param httpMethod the HTTP method (GET, POST, etc) * @param url a URL template; the resulting URL will be encoded * @param vars zero or more URL variables @@ -122,25 +127,18 @@ public class MockHttpServletRequestBuilder } /** - * @param httpMethod the HTTP method (GET, POST, etc) - * @param url a URL template; the resulting URL will be encoded - * @param vars zero or more URL variables - * @since 4.3 - */ - MockHttpServletRequestBuilder(String httpMethod, String url, Object... vars) { - this(httpMethod, UriComponentsBuilder.fromUriString(url).buildAndExpand(vars).encode().toUri()); - } - - /** + * Alternative to {@link #MockHttpServletRequestBuilder(HttpMethod, String, Object...)} + * with a pre-built URI. * @param httpMethod the HTTP method (GET, POST, etc) * @param url the URL * @since 4.0.3 */ MockHttpServletRequestBuilder(HttpMethod httpMethod, URI url) { - this(httpMethod.name(), url); + this(httpMethod.name(), url); } /** + * Alternative constructor for custom HTTP methods. * @param httpMethod the HTTP method (GET, POST, etc) * @param url the URL * @since 4.3 diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/request/MockMvcRequestBuilders.java b/spring-test/src/main/java/org/springframework/test/web/servlet/request/MockMvcRequestBuilders.java index c9455adc0e..f0e21adbe8 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/request/MockMvcRequestBuilders.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/request/MockMvcRequestBuilders.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -50,10 +50,10 @@ public abstract class MockMvcRequestBuilders { /** * Create a {@link MockHttpServletRequestBuilder} for a GET request. * @param urlTemplate a URL template; the resulting URL will be encoded - * @param urlVariables zero or more URL variables + * @param urlVars zero or more URL variables */ - public static MockHttpServletRequestBuilder get(String urlTemplate, Object... urlVariables) { - return new MockHttpServletRequestBuilder(HttpMethod.GET, urlTemplate, urlVariables); + public static MockHttpServletRequestBuilder get(String urlTemplate, Object... urlVars) { + return new MockHttpServletRequestBuilder(HttpMethod.GET, urlTemplate, urlVars); } /** @@ -68,10 +68,10 @@ public abstract class MockMvcRequestBuilders { /** * Create a {@link MockHttpServletRequestBuilder} for a POST request. * @param urlTemplate a URL template; the resulting URL will be encoded - * @param urlVariables zero or more URL variables + * @param urlVars zero or more URL variables */ - public static MockHttpServletRequestBuilder post(String urlTemplate, Object... urlVariables) { - return new MockHttpServletRequestBuilder(HttpMethod.POST, urlTemplate, urlVariables); + public static MockHttpServletRequestBuilder post(String urlTemplate, Object... urlVars) { + return new MockHttpServletRequestBuilder(HttpMethod.POST, urlTemplate, urlVars); } /** @@ -86,10 +86,10 @@ public abstract class MockMvcRequestBuilders { /** * Create a {@link MockHttpServletRequestBuilder} for a PUT request. * @param urlTemplate a URL template; the resulting URL will be encoded - * @param urlVariables zero or more URL variables + * @param urlVars zero or more URL variables */ - public static MockHttpServletRequestBuilder put(String urlTemplate, Object... urlVariables) { - return new MockHttpServletRequestBuilder(HttpMethod.PUT, urlTemplate, urlVariables); + public static MockHttpServletRequestBuilder put(String urlTemplate, Object... urlVars) { + return new MockHttpServletRequestBuilder(HttpMethod.PUT, urlTemplate, urlVars); } /** @@ -104,10 +104,10 @@ public abstract class MockMvcRequestBuilders { /** * Create a {@link MockHttpServletRequestBuilder} for a PATCH request. * @param urlTemplate a URL template; the resulting URL will be encoded - * @param urlVariables zero or more URL variables + * @param urlVars zero or more URL variables */ - public static MockHttpServletRequestBuilder patch(String urlTemplate, Object... urlVariables) { - return new MockHttpServletRequestBuilder(HttpMethod.PATCH, urlTemplate, urlVariables); + public static MockHttpServletRequestBuilder patch(String urlTemplate, Object... urlVars) { + return new MockHttpServletRequestBuilder(HttpMethod.PATCH, urlTemplate, urlVars); } /** @@ -122,10 +122,10 @@ public abstract class MockMvcRequestBuilders { /** * Create a {@link MockHttpServletRequestBuilder} for a DELETE request. * @param urlTemplate a URL template; the resulting URL will be encoded - * @param urlVariables zero or more URL variables + * @param urlVars zero or more URL variables */ - public static MockHttpServletRequestBuilder delete(String urlTemplate, Object... urlVariables) { - return new MockHttpServletRequestBuilder(HttpMethod.DELETE, urlTemplate, urlVariables); + public static MockHttpServletRequestBuilder delete(String urlTemplate, Object... urlVars) { + return new MockHttpServletRequestBuilder(HttpMethod.DELETE, urlTemplate, urlVars); } /** @@ -140,10 +140,10 @@ public abstract class MockMvcRequestBuilders { /** * Create a {@link MockHttpServletRequestBuilder} for an OPTIONS request. * @param urlTemplate a URL template; the resulting URL will be encoded - * @param urlVariables zero or more URL variables + * @param urlVars zero or more URL variables */ - public static MockHttpServletRequestBuilder options(String urlTemplate, Object... urlVariables) { - return new MockHttpServletRequestBuilder(HttpMethod.OPTIONS, urlTemplate, urlVariables); + public static MockHttpServletRequestBuilder options(String urlTemplate, Object... urlVars) { + return new MockHttpServletRequestBuilder(HttpMethod.OPTIONS, urlTemplate, urlVars); } /** @@ -158,11 +158,11 @@ public abstract class MockMvcRequestBuilders { /** * Create a {@link MockHttpServletRequestBuilder} for a HEAD request. * @param urlTemplate a URL template; the resulting URL will be encoded - * @param urlVariables zero or more URL variables + * @param urlVars zero or more URL variables * @since 4.1 */ - public static MockHttpServletRequestBuilder head(String urlTemplate, Object... urlVariables) { - return new MockHttpServletRequestBuilder(HttpMethod.HEAD, urlTemplate, urlVariables); + public static MockHttpServletRequestBuilder head(String urlTemplate, Object... urlVars) { + return new MockHttpServletRequestBuilder(HttpMethod.HEAD, urlTemplate, urlVars); } /** @@ -176,23 +176,12 @@ public abstract class MockMvcRequestBuilders { /** * Create a {@link MockHttpServletRequestBuilder} for a request with the given HTTP method. - * @param httpMethod the HTTP method (GET, POST, etc) + * @param method the HTTP method (GET, POST, etc) * @param urlTemplate a URL template; the resulting URL will be encoded - * @param urlVariables zero or more URL variables + * @param urlVars zero or more URL variables */ - public static MockHttpServletRequestBuilder request(HttpMethod httpMethod, String urlTemplate, Object... urlVariables) { - return new MockHttpServletRequestBuilder(httpMethod, urlTemplate, urlVariables); - } - - /** - * Create a {@link MockHttpServletRequestBuilder} for a request with the given HTTP method. - * @param httpMethod the HTTP method (GET, POST, etc) - * @param urlTemplate a URL template; the resulting URL will be encoded - * @param urlVariables zero or more URL variables - * @since 4.3 - */ - public static MockHttpServletRequestBuilder request(String httpMethod, String urlTemplate, Object... urlVariables) { - return new MockHttpServletRequestBuilder(httpMethod, urlTemplate, urlVariables); + public static MockHttpServletRequestBuilder request(HttpMethod method, String urlTemplate, Object... urlVars) { + return new MockHttpServletRequestBuilder(method, urlTemplate, urlVars); } /** @@ -206,8 +195,8 @@ public abstract class MockMvcRequestBuilders { } /** - * Create a {@link MockHttpServletRequestBuilder} for a request with the given HTTP method. - * @param httpMethod the HTTP method (GET, POST, etc) + * Alternative factory method that allows for custom HTTP verbs (e.g. WebDAV). + * @param httpMethod the HTTP method * @param uri the URL * @since 4.3 */ @@ -218,10 +207,10 @@ public abstract class MockMvcRequestBuilders { /** * Create a {@link MockMultipartHttpServletRequestBuilder} for a multipart request. * @param urlTemplate a URL template; the resulting URL will be encoded - * @param urlVariables zero or more URL variables + * @param urlVars zero or more URL variables */ - public static MockMultipartHttpServletRequestBuilder fileUpload(String urlTemplate, Object... urlVariables) { - return new MockMultipartHttpServletRequestBuilder(urlTemplate, urlVariables); + public static MockMultipartHttpServletRequestBuilder fileUpload(String urlTemplate, Object... urlVars) { + return new MockMultipartHttpServletRequestBuilder(urlTemplate, urlVars); } /** diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilderTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilderTests.java index 1cb1a01ec8..5057e4c404 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilderTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -25,7 +25,6 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; - import javax.servlet.ServletContext; import javax.servlet.http.Cookie; @@ -43,8 +42,12 @@ import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.servlet.FlashMap; import org.springframework.web.servlet.support.SessionFlashMapManager; +import org.springframework.web.util.UriComponentsBuilder; -import static org.junit.Assert.*; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; /** * Unit tests for building a {@link MockHttpServletRequest} with @@ -429,7 +432,7 @@ public class MockHttpServletRequestBuilderTests { @Test public void sessionAttributes() { - Map map = new HashMap(); + Map map = new HashMap<>(); map.put("foo", "bar"); this.builder.sessionAttrs(map); @@ -471,9 +474,8 @@ public class MockHttpServletRequestBuilderTests { assertEquals(user, request.getUserPrincipal()); } - /** - * See SPR-12945 - */ + // SPR-12945 + @Test public void mergeInvokesDefaultRequestPostProcessorFirst() { final String ATTR = "ATTR"; @@ -494,17 +496,13 @@ public class MockHttpServletRequestBuilderTests { assertEquals(EXEPCTED, request.getAttribute(ATTR)); } - /** - * See SPR-13719 - */ + // SPR-13719 + @Test public void arbitraryMethod() { - /* - * http method is case-sensitive - * http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.1 - */ String httpMethod = "REPort"; - this.builder = new MockHttpServletRequestBuilder(httpMethod, "/foo/{bar}", 42); + URI url = UriComponentsBuilder.fromPath("/foo/{bar}").buildAndExpand(42).toUri(); + this.builder = new MockHttpServletRequestBuilder(httpMethod, url); MockHttpServletRequest request = this.builder.buildRequest(this.servletContext);