From 5dcfd84d3bf5a01b4c90cab2bb9a88ff8ffae8c5 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Tue, 30 May 2017 10:58:19 -0400 Subject: [PATCH] MockServerHttpRequest and Response set cookie headers Issue: SPR-15522 --- .../reactive/MockServerHttpRequest.java | 13 +++-- .../reactive/MockServerHttpResponse.java | 4 ++ .../reactive/MockServerHttpRequestTests.java | 50 +++++++++++++++++ .../reactive/MockServerHttpResponseTests.java | 54 +++++++++++++++++++ .../org/springframework/http/HttpCookie.java | 5 ++ .../springframework/http/ResponseCookie.java | 29 ++++++++++ .../reactive/test/MockServerHttpRequest.java | 13 +++-- .../reactive/test/MockServerHttpResponse.java | 4 ++ ...ookieValueMethodArgumentResolverTests.java | 4 +- 9 files changed, 168 insertions(+), 8 deletions(-) create mode 100644 spring-test/src/test/java/org/springframework/mock/http/server/reactive/MockServerHttpRequestTests.java create mode 100644 spring-test/src/test/java/org/springframework/mock/http/server/reactive/MockServerHttpResponseTests.java 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 f1da2da40fb..cceb4ae7e95 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 @@ -21,6 +21,7 @@ import java.net.URI; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.Optional; @@ -231,7 +232,7 @@ public class MockServerHttpRequest extends AbstractServerHttpRequest { /** * Add one or more cookies. */ - B cookie(String name, HttpCookie... cookie); + B cookie(HttpCookie... cookie); /** * Add the given cookies. @@ -390,8 +391,8 @@ public class MockServerHttpRequest extends AbstractServerHttpRequest { } @Override - public BodyBuilder cookie(String name, HttpCookie... cookies) { - this.cookies.put(name, Arrays.asList(cookies)); + public BodyBuilder cookie(HttpCookie... cookies) { + Arrays.stream(cookies).forEach(cookie -> this.cookies.add(cookie.getName(), cookie)); return this; } @@ -485,9 +486,15 @@ public class MockServerHttpRequest extends AbstractServerHttpRequest { @Override public MockServerHttpRequest body(Publisher body) { + applyCookies(); return new MockServerHttpRequest(this.method, this.url, this.contextPath, this.headers, this.cookies, this.remoteAddress, body); } + + private void applyCookies() { + this.cookies.values().stream().flatMap(Collection::stream) + .forEach(cookie -> this.headers.add(HttpHeaders.COOKIE, cookie.toString())); + } } } \ No newline at end of file diff --git a/spring-test/src/main/java/org/springframework/mock/http/server/reactive/MockServerHttpResponse.java b/spring-test/src/main/java/org/springframework/mock/http/server/reactive/MockServerHttpResponse.java index c7987096e38..29eb02b1ae4 100644 --- a/spring-test/src/main/java/org/springframework/mock/http/server/reactive/MockServerHttpResponse.java +++ b/spring-test/src/main/java/org/springframework/mock/http/server/reactive/MockServerHttpResponse.java @@ -18,6 +18,7 @@ package org.springframework.mock.http.server.reactive; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.util.Collection; import java.util.Optional; import java.util.function.Function; @@ -28,6 +29,7 @@ import reactor.core.publisher.Mono; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.core.io.buffer.DefaultDataBufferFactory; +import org.springframework.http.HttpHeaders; import org.springframework.http.server.reactive.AbstractServerHttpResponse; import org.springframework.util.Assert; import org.springframework.util.MimeType; @@ -85,6 +87,8 @@ public class MockServerHttpResponse extends AbstractServerHttpResponse { @Override protected void applyCookies() { + getCookies().values().stream().flatMap(Collection::stream) + .forEach(cookie -> getHeaders().add(HttpHeaders.SET_COOKIE, cookie.toString())); } @Override diff --git a/spring-test/src/test/java/org/springframework/mock/http/server/reactive/MockServerHttpRequestTests.java b/spring-test/src/test/java/org/springframework/mock/http/server/reactive/MockServerHttpRequestTests.java new file mode 100644 index 00000000000..dc8f6e148b7 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/mock/http/server/reactive/MockServerHttpRequestTests.java @@ -0,0 +1,50 @@ +/* + * Copyright 2002-2017 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.mock.http.server.reactive; + +import java.util.Arrays; + +import org.junit.Test; + +import org.springframework.http.HttpCookie; +import org.springframework.http.HttpHeaders; + +import static org.junit.Assert.assertEquals; + +/** + * Unit tests for {@link MockServerHttpRequest}. + * @author Rossen Stoyanchev + */ +public class MockServerHttpRequestTests { + + + @Test + public void cookieHeaderSet() throws Exception { + HttpCookie foo11 = new HttpCookie("foo1", "bar1"); + HttpCookie foo12 = new HttpCookie("foo1", "bar2"); + HttpCookie foo21 = new HttpCookie("foo2", "baz1"); + HttpCookie foo22 = new HttpCookie("foo2", "baz2"); + + MockServerHttpRequest request = MockServerHttpRequest.get("/") + .cookie(foo11, foo12, foo21, foo22).build(); + + assertEquals(Arrays.asList(foo11, foo12), request.getCookies().get("foo1")); + assertEquals(Arrays.asList(foo21, foo22), request.getCookies().get("foo2")); + assertEquals(Arrays.asList("foo1=bar1", "foo1=bar2", "foo2=baz1", "foo2=baz2"), + request.getHeaders().get(HttpHeaders.COOKIE)); + } + +} diff --git a/spring-test/src/test/java/org/springframework/mock/http/server/reactive/MockServerHttpResponseTests.java b/spring-test/src/test/java/org/springframework/mock/http/server/reactive/MockServerHttpResponseTests.java new file mode 100644 index 00000000000..243c1043cc7 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/mock/http/server/reactive/MockServerHttpResponseTests.java @@ -0,0 +1,54 @@ +/* + * Copyright 2002-2017 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.mock.http.server.reactive; + +import java.util.Arrays; + +import org.junit.Test; + +import org.springframework.http.HttpCookie; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseCookie; + +import static org.junit.Assert.assertEquals; + +/** + * Unit tests for {@link MockServerHttpResponse}. + * @author Rossen Stoyanchev + */ +public class MockServerHttpResponseTests { + + @Test + public void cookieHeaderSet() throws Exception { + + ResponseCookie foo11 = ResponseCookie.from("foo1", "bar1").build(); + ResponseCookie foo12 = ResponseCookie.from("foo1", "bar2").build(); + ResponseCookie foo21 = ResponseCookie.from("foo2", "baz1").build(); + ResponseCookie foo22 = ResponseCookie.from("foo2", "baz2").build(); + + MockServerHttpResponse response = new MockServerHttpResponse(); + response.addCookie(foo11); + response.addCookie(foo12); + response.addCookie(foo21); + response.addCookie(foo22); + + response.applyCookies(); + + assertEquals(Arrays.asList("foo1=bar1", "foo1=bar2", "foo2=baz1", "foo2=baz2"), + response.getHeaders().get(HttpHeaders.SET_COOKIE)); + } + +} diff --git a/spring-web/src/main/java/org/springframework/http/HttpCookie.java b/spring-web/src/main/java/org/springframework/http/HttpCookie.java index 6a5b1bb3dab..d5c45c1dfd3 100644 --- a/spring-web/src/main/java/org/springframework/http/HttpCookie.java +++ b/spring-web/src/main/java/org/springframework/http/HttpCookie.java @@ -71,4 +71,9 @@ public class HttpCookie { return (this.name.equalsIgnoreCase(otherCookie.getName())); } + @Override + public String toString() { + return this.name + '=' + this.value; + } + } diff --git a/spring-web/src/main/java/org/springframework/http/ResponseCookie.java b/spring-web/src/main/java/org/springframework/http/ResponseCookie.java index 46c62c16c5c..38e3c1d147f 100644 --- a/spring-web/src/main/java/org/springframework/http/ResponseCookie.java +++ b/spring-web/src/main/java/org/springframework/http/ResponseCookie.java @@ -21,6 +21,7 @@ import java.time.Duration; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; /** * An {@code HttpCookie} subclass with the additional attributes allowed in @@ -125,6 +126,34 @@ public final class ResponseCookie extends HttpCookie { return result; } + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(getName()).append('=').append(getValue()); + if (StringUtils.hasText(getPath())) { + sb.append("; Path=").append(getPath()); + } + if (StringUtils.hasText(this.domain)) { + sb.append("; Domain=").append(this.domain); + } + if (!this.maxAge.isNegative()) { + sb.append("; Max-Age=").append(this.maxAge); + sb.append("; Expires="); + HttpHeaders headers = new HttpHeaders(); + long seconds = this.maxAge.getSeconds(); + headers.setExpires(seconds > 0 ? System.currentTimeMillis() + seconds : 0); + sb.append(headers.getFirst(HttpHeaders.EXPIRES)); + } + + if (this.secure) { + sb.append("; Secure"); + } + if (this.httpOnly) { + sb.append("; HttpOnly"); + } + return sb.toString(); + } + /** * Factory method to obtain a builder for a server-defined cookie that starts diff --git a/spring-web/src/test/java/org/springframework/mock/http/server/reactive/test/MockServerHttpRequest.java b/spring-web/src/test/java/org/springframework/mock/http/server/reactive/test/MockServerHttpRequest.java index 0bc81b004c6..99b3c9822ad 100644 --- a/spring-web/src/test/java/org/springframework/mock/http/server/reactive/test/MockServerHttpRequest.java +++ b/spring-web/src/test/java/org/springframework/mock/http/server/reactive/test/MockServerHttpRequest.java @@ -21,6 +21,7 @@ import java.net.URI; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.Optional; @@ -231,7 +232,7 @@ public class MockServerHttpRequest extends AbstractServerHttpRequest { /** * Add one or more cookies. */ - B cookie(String name, HttpCookie... cookie); + B cookie(HttpCookie... cookie); /** * Add the given cookies. @@ -390,8 +391,8 @@ public class MockServerHttpRequest extends AbstractServerHttpRequest { } @Override - public BodyBuilder cookie(String name, HttpCookie... cookies) { - this.cookies.put(name, Arrays.asList(cookies)); + public BodyBuilder cookie(HttpCookie... cookies) { + Arrays.stream(cookies).forEach(cookie -> this.cookies.add(cookie.getName(), cookie)); return this; } @@ -485,9 +486,15 @@ public class MockServerHttpRequest extends AbstractServerHttpRequest { @Override public MockServerHttpRequest body(Publisher body) { + applyCookies(); return new MockServerHttpRequest(this.method, this.url, this.contextPath, this.headers, this.cookies, this.remoteAddress, body); } + + private void applyCookies() { + this.cookies.values().stream().flatMap(Collection::stream) + .forEach(cookie -> this.headers.add(HttpHeaders.COOKIE, cookie.toString())); + } } } \ No newline at end of file diff --git a/spring-web/src/test/java/org/springframework/mock/http/server/reactive/test/MockServerHttpResponse.java b/spring-web/src/test/java/org/springframework/mock/http/server/reactive/test/MockServerHttpResponse.java index c886308697c..77efa5c48fd 100644 --- a/spring-web/src/test/java/org/springframework/mock/http/server/reactive/test/MockServerHttpResponse.java +++ b/spring-web/src/test/java/org/springframework/mock/http/server/reactive/test/MockServerHttpResponse.java @@ -18,6 +18,7 @@ package org.springframework.mock.http.server.reactive.test; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.util.Collection; import java.util.Optional; import java.util.function.Function; @@ -28,6 +29,7 @@ import reactor.core.publisher.Mono; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.core.io.buffer.DefaultDataBufferFactory; +import org.springframework.http.HttpHeaders; import org.springframework.http.server.reactive.AbstractServerHttpResponse; import org.springframework.util.Assert; import org.springframework.util.MimeType; @@ -85,6 +87,8 @@ public class MockServerHttpResponse extends AbstractServerHttpResponse { @Override protected void applyCookies() { + getCookies().values().stream().flatMap(Collection::stream) + .forEach(cookie -> getHeaders().add(HttpHeaders.SET_COOKIE, cookie.toString())); } @Override diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/CookieValueMethodArgumentResolverTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/CookieValueMethodArgumentResolverTests.java index 675f437a6a0..a5e4f06f31a 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/CookieValueMethodArgumentResolverTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/CookieValueMethodArgumentResolverTests.java @@ -98,7 +98,7 @@ public class CookieValueMethodArgumentResolverTests { @Test public void resolveCookieArgument() { HttpCookie expected = new HttpCookie("name", "foo"); - ServerWebExchange exchange = MockServerHttpRequest.get("/").cookie(expected.getName(), expected).toExchange(); + ServerWebExchange exchange = MockServerHttpRequest.get("/").cookie(expected).toExchange(); Mono mono = this.resolver.resolveArgument( this.cookieParameter, this.bindingContext, exchange); @@ -109,7 +109,7 @@ public class CookieValueMethodArgumentResolverTests { @Test public void resolveCookieStringArgument() { HttpCookie cookie = new HttpCookie("name", "foo"); - ServerWebExchange exchange = MockServerHttpRequest.get("/").cookie(cookie.getName(), cookie).toExchange(); + ServerWebExchange exchange = MockServerHttpRequest.get("/").cookie(cookie).toExchange(); Mono mono = this.resolver.resolveArgument( this.cookieStringParameter, this.bindingContext, exchange);