From 8204055924fbcd6cbb6a5be55cebe150f830aa93 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Fri, 22 May 2020 06:45:38 +0100 Subject: [PATCH] MockServerHttpRequest accepts custom HTTP method Closes gh-25109 --- .../reactive/MockServerHttpRequest.java | 100 ++++++++++++------ .../reactive/MockServerHttpRequest.java | 100 ++++++++++++------ 2 files changed, 140 insertions(+), 60 deletions(-) diff --git a/spring-test/src/main/java/org/springframework/mock/http/server/reactive/MockServerHttpRequest.java b/spring-test/src/main/java/org/springframework/mock/http/server/reactive/MockServerHttpRequest.java index 66c741eb6b9f..356367c55d69 100644 --- a/spring-test/src/main/java/org/springframework/mock/http/server/reactive/MockServerHttpRequest.java +++ b/spring-test/src/main/java/org/springframework/mock/http/server/reactive/MockServerHttpRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 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. @@ -40,6 +40,7 @@ import org.springframework.http.server.reactive.AbstractServerHttpRequest; import org.springframework.http.server.reactive.SslInfo; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MimeType; import org.springframework.util.MultiValueMap; @@ -54,8 +55,12 @@ */ public final class MockServerHttpRequest extends AbstractServerHttpRequest { + @Nullable private final HttpMethod httpMethod; + @Nullable + private final String customHttpMethod; + private final MultiValueMap cookies; @Nullable @@ -70,13 +75,15 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest { private final Flux body; - private MockServerHttpRequest(HttpMethod httpMethod, URI uri, @Nullable String contextPath, - HttpHeaders headers, MultiValueMap cookies, + private MockServerHttpRequest(@Nullable HttpMethod httpMethod, @Nullable String customHttpMethod, + URI uri, @Nullable String contextPath, HttpHeaders headers, MultiValueMap cookies, @Nullable InetSocketAddress remoteAddress, @Nullable InetSocketAddress localAddress, @Nullable SslInfo sslInfo, Publisher body) { super(uri, contextPath, headers); + Assert.isTrue(httpMethod != null || customHttpMethod != null, "HTTP method must not be null"); this.httpMethod = httpMethod; + this.customHttpMethod = customHttpMethod; this.cookies = cookies; this.remoteAddress = remoteAddress; this.localAddress = localAddress; @@ -91,8 +98,9 @@ public HttpMethod getMethod() { } @Override + @SuppressWarnings("ConstantConditions") public String getMethodValue() { - return this.httpMethod.name(); + return (this.httpMethod != null ? this.httpMethod.name() : this.customHttpMethod); } @Override @@ -131,30 +139,6 @@ public T getNativeRequest() { // Static builder methods - /** - * Create a builder with the given HTTP method and a {@link URI}. - * @param method the HTTP method (GET, POST, etc) - * @param url the URL - * @return the created builder - */ - public static BodyBuilder method(HttpMethod method, URI url) { - return new DefaultBodyBuilder(method, url); - } - - /** - * Alternative to {@link #method(HttpMethod, URI)} that accepts a URI template. - * The given URI may contain query parameters, or those may be added later via - * {@link BaseBuilder#queryParam queryParam} builder methods. - * @param method the HTTP method (GET, POST, etc) - * @param urlTemplate the URL template - * @param vars variables to expand into the template - * @return the created builder - */ - public static BodyBuilder method(HttpMethod method, String urlTemplate, Object... vars) { - URI url = UriComponentsBuilder.fromUriString(urlTemplate).buildAndExpand(vars).encode().toUri(); - return new DefaultBodyBuilder(method, url); - } - /** * Create an HTTP GET builder with the given URI template. The given URI may * contain query parameters, or those may be added later via @@ -228,6 +212,44 @@ public static BaseBuilder options(String urlTemplate, Object... uriVars) { return method(HttpMethod.OPTIONS, urlTemplate, uriVars); } + /** + * Create a builder with the given HTTP method and a {@link URI}. + * @param method the HTTP method (GET, POST, etc) + * @param url the URL + * @return the created builder + */ + public static BodyBuilder method(HttpMethod method, URI url) { + return new DefaultBodyBuilder(method, url); + } + + /** + * Alternative to {@link #method(HttpMethod, URI)} that accepts a URI template. + * The given URI may contain query parameters, or those may be added later via + * {@link BaseBuilder#queryParam queryParam} builder methods. + * @param method the HTTP method (GET, POST, etc) + * @param urlTemplate the URL template + * @param vars variables to expand into the template + * @return the created builder + */ + public static BodyBuilder method(HttpMethod method, String urlTemplate, Object... vars) { + URI url = UriComponentsBuilder.fromUriString(urlTemplate).buildAndExpand(vars).encode().toUri(); + return new DefaultBodyBuilder(method, url); + } + + /** + * Create a builder with a raw HTTP method value that is outside the range + * of {@link HttpMethod} enum values. + * @param method the HTTP method value + * @param urlTemplate the URL template + * @param vars variables to expand into the template + * @return the created builder + * @since 5.2.7 + */ + public static BodyBuilder method(String method, String urlTemplate, Object... vars) { + URI url = UriComponentsBuilder.fromUriString(urlTemplate).buildAndExpand(vars).encode().toUri(); + return new DefaultBodyBuilder(method, url); + } + /** * Request builder exposing properties not related to the body. @@ -408,8 +430,12 @@ private static class DefaultBodyBuilder implements BodyBuilder { private static final DataBufferFactory BUFFER_FACTORY = new DefaultDataBufferFactory(); + @Nullable private final HttpMethod method; + @Nullable + private final String customMethod; + private final URI url; @Nullable @@ -431,8 +457,22 @@ private static class DefaultBodyBuilder implements BodyBuilder { private SslInfo sslInfo; - public DefaultBodyBuilder(HttpMethod method, URI url) { + DefaultBodyBuilder(HttpMethod method, URI url) { this.method = method; + this.customMethod = null; + this.url = url; + } + + DefaultBodyBuilder(String method, URI url) { + HttpMethod resolved = HttpMethod.resolve(method); + if (resolved != null) { + this.method = resolved; + this.customMethod = null; + } + else { + this.method = null; + this.customMethod = method; + } this.url = url; } @@ -569,7 +609,7 @@ private Charset getCharset() { @Override public MockServerHttpRequest body(Publisher body) { applyCookiesIfNecessary(); - return new MockServerHttpRequest(this.method, getUrlToUse(), this.contextPath, + return new MockServerHttpRequest(this.method, this.customMethod, getUrlToUse(), this.contextPath, this.headers, this.cookies, this.remoteAddress, this.localAddress, this.sslInfo, body); } diff --git a/spring-web/src/testFixtures/java/org/springframework/web/testfixture/http/server/reactive/MockServerHttpRequest.java b/spring-web/src/testFixtures/java/org/springframework/web/testfixture/http/server/reactive/MockServerHttpRequest.java index 0f41a41d21d0..96708ef2fb5c 100644 --- a/spring-web/src/testFixtures/java/org/springframework/web/testfixture/http/server/reactive/MockServerHttpRequest.java +++ b/spring-web/src/testFixtures/java/org/springframework/web/testfixture/http/server/reactive/MockServerHttpRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 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. @@ -40,6 +40,7 @@ import org.springframework.http.server.reactive.AbstractServerHttpRequest; import org.springframework.http.server.reactive.SslInfo; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MimeType; import org.springframework.util.MultiValueMap; @@ -54,8 +55,12 @@ */ public final class MockServerHttpRequest extends AbstractServerHttpRequest { + @Nullable private final HttpMethod httpMethod; + @Nullable + private final String customHttpMethod; + private final MultiValueMap cookies; @Nullable @@ -70,13 +75,15 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest { private final Flux body; - private MockServerHttpRequest(HttpMethod httpMethod, URI uri, @Nullable String contextPath, - HttpHeaders headers, MultiValueMap cookies, + private MockServerHttpRequest(@Nullable HttpMethod httpMethod, @Nullable String customHttpMethod, + URI uri, @Nullable String contextPath, HttpHeaders headers, MultiValueMap cookies, @Nullable InetSocketAddress remoteAddress, @Nullable InetSocketAddress localAddress, @Nullable SslInfo sslInfo, Publisher body) { super(uri, contextPath, headers); + Assert.isTrue(httpMethod != null || customHttpMethod != null, "HTTP method must not be null"); this.httpMethod = httpMethod; + this.customHttpMethod = customHttpMethod; this.cookies = cookies; this.remoteAddress = remoteAddress; this.localAddress = localAddress; @@ -91,8 +98,9 @@ public HttpMethod getMethod() { } @Override + @SuppressWarnings("ConstantConditions") public String getMethodValue() { - return this.httpMethod.name(); + return (this.httpMethod != null ? this.httpMethod.name() : this.customHttpMethod); } @Override @@ -131,30 +139,6 @@ public T getNativeRequest() { // Static builder methods - /** - * Create a builder with the given HTTP method and a {@link URI}. - * @param method the HTTP method (GET, POST, etc) - * @param url the URL - * @return the created builder - */ - public static BodyBuilder method(HttpMethod method, URI url) { - return new DefaultBodyBuilder(method, url); - } - - /** - * Alternative to {@link #method(HttpMethod, URI)} that accepts a URI template. - * The given URI may contain query parameters, or those may be added later via - * {@link BaseBuilder#queryParam queryParam} builder methods. - * @param method the HTTP method (GET, POST, etc) - * @param urlTemplate the URL template - * @param vars variables to expand into the template - * @return the created builder - */ - public static BodyBuilder method(HttpMethod method, String urlTemplate, Object... vars) { - URI url = UriComponentsBuilder.fromUriString(urlTemplate).buildAndExpand(vars).encode().toUri(); - return new DefaultBodyBuilder(method, url); - } - /** * Create an HTTP GET builder with the given URI template. The given URI may * contain query parameters, or those may be added later via @@ -228,6 +212,44 @@ public static BaseBuilder options(String urlTemplate, Object... uriVars) { return method(HttpMethod.OPTIONS, urlTemplate, uriVars); } + /** + * Create a builder with the given HTTP method and a {@link URI}. + * @param method the HTTP method (GET, POST, etc) + * @param url the URL + * @return the created builder + */ + public static BodyBuilder method(HttpMethod method, URI url) { + return new DefaultBodyBuilder(method, url); + } + + /** + * Alternative to {@link #method(HttpMethod, URI)} that accepts a URI template. + * The given URI may contain query parameters, or those may be added later via + * {@link BaseBuilder#queryParam queryParam} builder methods. + * @param method the HTTP method (GET, POST, etc) + * @param urlTemplate the URL template + * @param vars variables to expand into the template + * @return the created builder + */ + public static BodyBuilder method(HttpMethod method, String urlTemplate, Object... vars) { + URI url = UriComponentsBuilder.fromUriString(urlTemplate).buildAndExpand(vars).encode().toUri(); + return new DefaultBodyBuilder(method, url); + } + + /** + * Create a builder with a raw HTTP method value that is outside the range + * of {@link HttpMethod} enum values. + * @param method the HTTP method value + * @param urlTemplate the URL template + * @param vars variables to expand into the template + * @return the created builder + * @since 5.2.7 + */ + public static BodyBuilder method(String method, String urlTemplate, Object... vars) { + URI url = UriComponentsBuilder.fromUriString(urlTemplate).buildAndExpand(vars).encode().toUri(); + return new DefaultBodyBuilder(method, url); + } + /** * Request builder exposing properties not related to the body. @@ -408,8 +430,12 @@ private static class DefaultBodyBuilder implements BodyBuilder { private static final DataBufferFactory BUFFER_FACTORY = new DefaultDataBufferFactory(); + @Nullable private final HttpMethod method; + @Nullable + private final String customMethod; + private final URI url; @Nullable @@ -431,8 +457,22 @@ private static class DefaultBodyBuilder implements BodyBuilder { private SslInfo sslInfo; - public DefaultBodyBuilder(HttpMethod method, URI url) { + DefaultBodyBuilder(HttpMethod method, URI url) { this.method = method; + this.customMethod = null; + this.url = url; + } + + DefaultBodyBuilder(String method, URI url) { + HttpMethod resolved = HttpMethod.resolve(method); + if (resolved != null) { + this.method = resolved; + this.customMethod = null; + } + else { + this.method = null; + this.customMethod = method; + } this.url = url; } @@ -569,7 +609,7 @@ private Charset getCharset() { @Override public MockServerHttpRequest body(Publisher body) { applyCookiesIfNecessary(); - return new MockServerHttpRequest(this.method, getUrlToUse(), this.contextPath, + return new MockServerHttpRequest(this.method, this.customMethod, getUrlToUse(), this.contextPath, this.headers, this.cookies, this.remoteAddress, this.localAddress, this.sslInfo, body); }