parent
6e8bb6c4a9
commit
128acaff8a
|
@ -80,7 +80,7 @@ public class MockClientHttpResponse implements ClientHttpResponse {
|
||||||
public HttpHeaders getHeaders() {
|
public HttpHeaders getHeaders() {
|
||||||
if (!getCookies().isEmpty() && this.headers.get(HttpHeaders.SET_COOKIE) == null) {
|
if (!getCookies().isEmpty() && this.headers.get(HttpHeaders.SET_COOKIE) == null) {
|
||||||
getCookies().values().stream().flatMap(Collection::stream)
|
getCookies().values().stream().flatMap(Collection::stream)
|
||||||
.forEach(cookie -> getHeaders().add(HttpHeaders.SET_COOKIE, cookie.toString()));
|
.forEach(cookie -> this.headers.add(HttpHeaders.SET_COOKIE, cookie.toString()));
|
||||||
}
|
}
|
||||||
return this.headers;
|
return this.headers;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,220 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://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.test.web.reactive.server;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.hamcrest.Matcher;
|
||||||
|
import org.hamcrest.MatcherAssert;
|
||||||
|
|
||||||
|
import org.springframework.http.ResponseCookie;
|
||||||
|
import org.springframework.test.util.AssertionErrors;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assertions on cookies of the response.
|
||||||
|
* @author Rossen Stoyanchev
|
||||||
|
*/
|
||||||
|
public class CookieAssertions {
|
||||||
|
|
||||||
|
private final ExchangeResult exchangeResult;
|
||||||
|
|
||||||
|
private final WebTestClient.ResponseSpec responseSpec;
|
||||||
|
|
||||||
|
|
||||||
|
public CookieAssertions(ExchangeResult exchangeResult, WebTestClient.ResponseSpec responseSpec) {
|
||||||
|
this.exchangeResult = exchangeResult;
|
||||||
|
this.responseSpec = responseSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expect a header with the given name to match the specified values.
|
||||||
|
*/
|
||||||
|
public WebTestClient.ResponseSpec valueEquals(String name, String value) {
|
||||||
|
this.exchangeResult.assertWithDiagnostics(() -> {
|
||||||
|
String message = getMessage(name);
|
||||||
|
AssertionErrors.assertEquals(message, value, getCookie(name).getValue());
|
||||||
|
});
|
||||||
|
return this.responseSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert the first value of the response cookie with a Hamcrest {@link Matcher}.
|
||||||
|
*/
|
||||||
|
public WebTestClient.ResponseSpec value(String name, Matcher<? super String> matcher) {
|
||||||
|
String value = getCookie(name).getValue();
|
||||||
|
this.exchangeResult.assertWithDiagnostics(() -> {
|
||||||
|
String message = getMessage(name);
|
||||||
|
MatcherAssert.assertThat(message, value, matcher);
|
||||||
|
});
|
||||||
|
return this.responseSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Consume the value of the response cookie.
|
||||||
|
*/
|
||||||
|
public WebTestClient.ResponseSpec value(String name, Consumer<String> consumer) {
|
||||||
|
String value = getCookie(name).getValue();
|
||||||
|
this.exchangeResult.assertWithDiagnostics(() -> consumer.accept(value));
|
||||||
|
return this.responseSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expect that the cookie with the given name is present.
|
||||||
|
*/
|
||||||
|
public WebTestClient.ResponseSpec exists(String name) {
|
||||||
|
getCookie(name);
|
||||||
|
return this.responseSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expect that the cookie with the given name is not present.
|
||||||
|
*/
|
||||||
|
public WebTestClient.ResponseSpec doesNotExist(String name) {
|
||||||
|
ResponseCookie cookie = this.exchangeResult.getResponseCookies().getFirst(name);
|
||||||
|
if (cookie != null) {
|
||||||
|
String message = getMessage(name) + " exists with value=[" + cookie.getValue() + "]";
|
||||||
|
this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.fail(message));
|
||||||
|
}
|
||||||
|
return this.responseSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert a cookie's maxAge attribute.
|
||||||
|
*/
|
||||||
|
public WebTestClient.ResponseSpec maxAge(String name, Duration expected) {
|
||||||
|
Duration maxAge = getCookie(name).getMaxAge();
|
||||||
|
this.exchangeResult.assertWithDiagnostics(() -> {
|
||||||
|
String message = getMessage(name) + " maxAge";
|
||||||
|
AssertionErrors.assertEquals(message, expected, maxAge);
|
||||||
|
});
|
||||||
|
return this.responseSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert a cookie's maxAge attribute with a Hamcrest {@link Matcher}.
|
||||||
|
*/
|
||||||
|
public WebTestClient.ResponseSpec maxAge(String name, Matcher<? super Long> matcher) {
|
||||||
|
long maxAge = getCookie(name).getMaxAge().getSeconds();
|
||||||
|
this.exchangeResult.assertWithDiagnostics(() -> {
|
||||||
|
String message = getMessage(name) + " maxAge";
|
||||||
|
assertThat(message, maxAge, matcher);
|
||||||
|
});
|
||||||
|
return this.responseSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert a cookie's path attribute.
|
||||||
|
*/
|
||||||
|
public WebTestClient.ResponseSpec path(String name, String expected) {
|
||||||
|
String path = getCookie(name).getPath();
|
||||||
|
this.exchangeResult.assertWithDiagnostics(() -> {
|
||||||
|
String message = getMessage(name) + " path";
|
||||||
|
AssertionErrors.assertEquals(message, expected, path);
|
||||||
|
});
|
||||||
|
return this.responseSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert a cookie's path attribute with a Hamcrest {@link Matcher}.
|
||||||
|
*/
|
||||||
|
public WebTestClient.ResponseSpec path(String name, Matcher<? super String> matcher) {
|
||||||
|
String path = getCookie(name).getPath();
|
||||||
|
this.exchangeResult.assertWithDiagnostics(() -> {
|
||||||
|
String message = getMessage(name) + " path";
|
||||||
|
assertThat(message, path, matcher);
|
||||||
|
});
|
||||||
|
return this.responseSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert a cookie's domain attribute.
|
||||||
|
*/
|
||||||
|
public WebTestClient.ResponseSpec domain(String name, String expected) {
|
||||||
|
String path = getCookie(name).getDomain();
|
||||||
|
this.exchangeResult.assertWithDiagnostics(() -> {
|
||||||
|
String message = getMessage(name) + " domain";
|
||||||
|
AssertionErrors.assertEquals(message, expected, path);
|
||||||
|
});
|
||||||
|
return this.responseSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert a cookie's domain attribute with a Hamcrest {@link Matcher}.
|
||||||
|
*/
|
||||||
|
public WebTestClient.ResponseSpec domain(String name, Matcher<? super String> matcher) {
|
||||||
|
String domain = getCookie(name).getDomain();
|
||||||
|
this.exchangeResult.assertWithDiagnostics(() -> {
|
||||||
|
String message = getMessage(name) + " domain";
|
||||||
|
assertThat(message, domain, matcher);
|
||||||
|
});
|
||||||
|
return this.responseSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert a cookie's secure attribute.
|
||||||
|
*/
|
||||||
|
public WebTestClient.ResponseSpec secure(String name, boolean expected) {
|
||||||
|
boolean isSecure = getCookie(name).isSecure();
|
||||||
|
this.exchangeResult.assertWithDiagnostics(() -> {
|
||||||
|
String message = getMessage(name) + " secure";
|
||||||
|
AssertionErrors.assertEquals(message, expected, isSecure);
|
||||||
|
});
|
||||||
|
return this.responseSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert a cookie's httpOnly attribute.
|
||||||
|
*/
|
||||||
|
public WebTestClient.ResponseSpec httpOnly(String name, boolean expected) {
|
||||||
|
boolean isHttpOnly = getCookie(name).isHttpOnly();
|
||||||
|
this.exchangeResult.assertWithDiagnostics(() -> {
|
||||||
|
String message = getMessage(name) + " secure";
|
||||||
|
AssertionErrors.assertEquals(message, expected, isHttpOnly);
|
||||||
|
});
|
||||||
|
return this.responseSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert a cookie's sameSite attribute.
|
||||||
|
*/
|
||||||
|
public WebTestClient.ResponseSpec sameSite(String name, String expected) {
|
||||||
|
String sameSite = getCookie(name).getSameSite();
|
||||||
|
this.exchangeResult.assertWithDiagnostics(() -> {
|
||||||
|
String message = getMessage(name) + " secure";
|
||||||
|
AssertionErrors.assertEquals(message, expected, sameSite);
|
||||||
|
});
|
||||||
|
return this.responseSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private ResponseCookie getCookie(String name) {
|
||||||
|
ResponseCookie cookie = this.exchangeResult.getResponseCookies().getFirst(name);
|
||||||
|
if (cookie == null) {
|
||||||
|
String message = "No cookie with name '" + name + "'";
|
||||||
|
this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.fail(message));
|
||||||
|
}
|
||||||
|
return cookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getMessage(String cookie) {
|
||||||
|
return "Response cookie '" + cookie + "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -337,6 +337,11 @@ class DefaultWebTestClient implements WebTestClient {
|
||||||
return new HeaderAssertions(this.exchangeResult, this);
|
return new HeaderAssertions(this.exchangeResult, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CookieAssertions expectCookie() {
|
||||||
|
return new CookieAssertions(this.exchangeResult, this);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <B> BodySpec<B, ?> expectBody(Class<B> bodyType) {
|
public <B> BodySpec<B, ?> expectBody(Class<B> bodyType) {
|
||||||
B body = this.response.bodyToMono(bodyType).block(this.timeout);
|
B body = this.response.bodyToMono(bodyType).block(this.timeout);
|
||||||
|
|
|
@ -764,6 +764,12 @@ public interface WebTestClient {
|
||||||
*/
|
*/
|
||||||
HeaderAssertions expectHeader();
|
HeaderAssertions expectHeader();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assertions on the cookies of the response.
|
||||||
|
* @since 5.3
|
||||||
|
*/
|
||||||
|
CookieAssertions expectCookie();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Consume and decode the response body to a single object of type
|
* Consume and decode the response body to a single object of type
|
||||||
* {@code <B>} and then apply assertions.
|
* {@code <B>} and then apply assertions.
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://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.test.web.reactive.server;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import reactor.core.publisher.MonoProcessor;
|
||||||
|
import reactor.core.publisher.Sinks;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseCookie;
|
||||||
|
import org.springframework.mock.http.client.reactive.MockClientHttpRequest;
|
||||||
|
import org.springframework.mock.http.client.reactive.MockClientHttpResponse;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for {@link CookieAssertions}
|
||||||
|
* @author Rossen Stoyanchev
|
||||||
|
*/
|
||||||
|
public class CookieAssertionTests {
|
||||||
|
|
||||||
|
private final ResponseCookie cookie = ResponseCookie.from("foo", "bar")
|
||||||
|
.maxAge(Duration.ofMinutes(30))
|
||||||
|
.domain("foo.com")
|
||||||
|
.path("/foo")
|
||||||
|
.secure(true)
|
||||||
|
.httpOnly(true)
|
||||||
|
.sameSite("Lax")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
private final CookieAssertions assertions = cookieAssertions(cookie);
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void valueEquals() {
|
||||||
|
assertions.valueEquals("foo", "bar");
|
||||||
|
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.valueEquals("what?!", "bar"));
|
||||||
|
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.valueEquals("foo", "what?!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void value() {
|
||||||
|
assertions.value("foo", equalTo("bar"));
|
||||||
|
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.value("foo", equalTo("what?!")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void exists() {
|
||||||
|
assertions.exists("foo");
|
||||||
|
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.exists("what?!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void doesNotExist() {
|
||||||
|
assertions.doesNotExist("what?!");
|
||||||
|
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.doesNotExist("foo"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void maxAge() {
|
||||||
|
assertions.maxAge("foo", Duration.ofMinutes(30));
|
||||||
|
assertThatExceptionOfType(AssertionError.class)
|
||||||
|
.isThrownBy(() -> assertions.maxAge("foo", Duration.ofMinutes(29)));
|
||||||
|
|
||||||
|
assertions.maxAge("foo", equalTo(Duration.ofMinutes(30).getSeconds()));
|
||||||
|
assertThatExceptionOfType(AssertionError.class)
|
||||||
|
.isThrownBy(() -> assertions.maxAge("foo", equalTo(Duration.ofMinutes(29).getSeconds())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void domain() {
|
||||||
|
assertions.domain("foo", "foo.com");
|
||||||
|
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.domain("foo", "what.com"));
|
||||||
|
|
||||||
|
assertions.domain("foo", equalTo("foo.com"));
|
||||||
|
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.domain("foo", equalTo("what.com")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void path() {
|
||||||
|
assertions.path("foo", "/foo");
|
||||||
|
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.path("foo", "/what"));
|
||||||
|
|
||||||
|
assertions.path("foo", equalTo("/foo"));
|
||||||
|
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.path("foo", equalTo("/what")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void secure() {
|
||||||
|
assertions.secure("foo", true);
|
||||||
|
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.secure("foo", false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void httpOnly() {
|
||||||
|
assertions.httpOnly("foo", true);
|
||||||
|
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.httpOnly("foo", false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void sameSite() {
|
||||||
|
assertions.sameSite("foo", "Lax");
|
||||||
|
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.sameSite("foo", "Strict"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private CookieAssertions cookieAssertions(ResponseCookie cookie) {
|
||||||
|
MockClientHttpRequest request = new MockClientHttpRequest(HttpMethod.GET, URI.create("/"));
|
||||||
|
MockClientHttpResponse response = new MockClientHttpResponse(HttpStatus.OK);
|
||||||
|
response.getCookies().add(cookie.getName(), cookie);
|
||||||
|
|
||||||
|
MonoProcessor<byte[]> emptyContent = MonoProcessor.fromSink(Sinks.one());
|
||||||
|
emptyContent.onComplete();
|
||||||
|
|
||||||
|
ExchangeResult result = new ExchangeResult(request, response, emptyContent, emptyContent, Duration.ZERO, null, null);
|
||||||
|
return new CookieAssertions(result, mock(WebTestClient.ResponseSpec.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue