Browse Source

Polishing

pull/32446/head
Sam Brannen 2 years ago
parent
commit
7211db9262
  1. 13
      spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/SplittingStompEncoder.java
  2. 18
      spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompDecoder.java
  3. 23
      spring-test/src/main/java/org/springframework/test/context/bean/override/convention/TestBeanOverrideProcessor.java
  4. 52
      spring-test/src/main/java/org/springframework/test/web/reactive/server/CookieAssertions.java
  5. 43
      spring-test/src/main/java/org/springframework/test/web/reactive/server/HeaderAssertions.java
  6. 43
      spring-test/src/test/java/org/springframework/test/context/bean/override/OverrideMetadataTests.java
  7. 66
      spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanOverrideProcessorTests.java
  8. 93
      spring-test/src/test/java/org/springframework/test/web/servlet/samples/client/standalone/resultmatches/HeaderAssertionTests.java

13
spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/SplittingStompEncoder.java

@ -24,9 +24,9 @@ import java.util.Map;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
* Uses {@link org.springframework.messaging.simp.stomp.StompEncoder} to encode * Uses a {@link StompEncoder} to encode a message and splits it into parts no
* a message and splits it into parts no larger than the configured * larger than the configured
* {@link SplittingStompEncoder#bufferSizeLimit}. * {@linkplain #SplittingStompEncoder(StompEncoder, int) buffer size limit}.
* *
* @author Injae Kim * @author Injae Kim
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
@ -40,6 +40,11 @@ public class SplittingStompEncoder {
private final int bufferSizeLimit; private final int bufferSizeLimit;
/**
* Create a new {@code SplittingStompEncoder}.
* @param encoder the {@link StompEncoder} to use
* @param bufferSizeLimit the buffer size limit
*/
public SplittingStompEncoder(StompEncoder encoder, int bufferSizeLimit) { public SplittingStompEncoder(StompEncoder encoder, int bufferSizeLimit) {
Assert.notNull(encoder, "StompEncoder is required"); Assert.notNull(encoder, "StompEncoder is required");
Assert.isTrue(bufferSizeLimit > 0, "Buffer size limit must be greater than 0"); Assert.isTrue(bufferSizeLimit > 0, "Buffer size limit must be greater than 0");
@ -49,7 +54,7 @@ public class SplittingStompEncoder {
/** /**
* Encode the given payload and headers to a STOMP frame, and split into a * Encode the given payload and headers to a STOMP frame, and split it into a
* list of parts based on the configured buffer size limit. * list of parts based on the configured buffer size limit.
* @param headers the STOMP message headers * @param headers the STOMP message headers
* @param payload the STOMP message payload * @param payload the STOMP message payload

18
spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompDecoder.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2022 the original author or authors. * Copyright 2002-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -78,10 +78,10 @@ public class StompDecoder {
* Decodes one or more STOMP frames from the given {@code ByteBuffer} into a * Decodes one or more STOMP frames from the given {@code ByteBuffer} into a
* list of {@link Message Messages}. If the input buffer contains partial STOMP frame * list of {@link Message Messages}. If the input buffer contains partial STOMP frame
* content, or additional content with a partial STOMP frame, the buffer is * content, or additional content with a partial STOMP frame, the buffer is
* reset and an empty list is returned. * reset, and an empty list is returned.
* @param byteBuffer the buffer to decode the STOMP frame from * @param byteBuffer the buffer to decode the STOMP frame from
* @return the decoded messages, or an empty list if none * @return the decoded messages, or an empty list if none
* @throws StompConversionException raised in case of decoding issues * @throws StompConversionException in case of decoding issues
*/ */
public List<Message<byte[]>> decode(ByteBuffer byteBuffer) { public List<Message<byte[]>> decode(ByteBuffer byteBuffer) {
return decode(byteBuffer, null); return decode(byteBuffer, null);
@ -93,18 +93,18 @@ public class StompDecoder {
* <p>If the given ByteBuffer contains only partial STOMP frame content and no * <p>If the given ByteBuffer contains only partial STOMP frame content and no
* complete STOMP frames, an empty list is returned, and the buffer is reset * complete STOMP frames, an empty list is returned, and the buffer is reset
* to where it was. * to where it was.
* <p>If the buffer contains one or more STOMP frames, those are returned and * <p>If the buffer contains one or more STOMP frames, those are returned, and
* the buffer reset to point to the beginning of the unused partial content. * the buffer is reset to point to the beginning of the unused partial content.
* <p>The output partialMessageHeaders map is used to store successfully parsed * <p>The {@code partialMessageHeaders} map is used to store successfully parsed
* headers in case of partial content. The caller can then check if a * headers in case of partial content. The caller can then check if a
* "content-length" header was read, which helps to determine how much more * "content-length" header was read, which helps to determine how much more
* content is needed before the next attempt to decode. * content is needed before the next attempt to decode.
* @param byteBuffer the buffer to decode the STOMP frame from * @param byteBuffer the buffer to decode the STOMP frame from
* @param partialMessageHeaders an empty output map that will store the last * @param partialMessageHeaders an empty output map that will store the last
* successfully parsed partialMessageHeaders in case of partial message content * successfully parsed partial message headers in case of partial message content
* in cases where the partial buffer ended with a partial STOMP frame * in cases where the partial buffer ended with a partial STOMP frame
* @return the decoded messages, or an empty list if none * @return the decoded messages, or an empty list if none
* @throws StompConversionException raised in case of decoding issues * @throws StompConversionException in case of decoding issues
*/ */
public List<Message<byte[]>> decode(ByteBuffer byteBuffer, public List<Message<byte[]>> decode(ByteBuffer byteBuffer,
@Nullable MultiValueMap<String, String> partialMessageHeaders) { @Nullable MultiValueMap<String, String> partialMessageHeaders) {
@ -127,7 +127,7 @@ public class StompDecoder {
} }
/** /**
* Decode a single STOMP frame from the given {@code buffer} into a {@link Message}. * Decode a single STOMP frame from the given {@code byteBuffer} into a {@link Message}.
*/ */
@Nullable @Nullable
private Message<byte[]> decodeMessage(ByteBuffer byteBuffer, @Nullable MultiValueMap<String, String> headers) { private Message<byte[]> decodeMessage(ByteBuffer byteBuffer, @Nullable MultiValueMap<String, String> headers) {

23
spring-test/src/main/java/org/springframework/test/context/bean/override/convention/TestBeanOverrideProcessor.java

@ -56,10 +56,10 @@ public class TestBeanOverrideProcessor implements BeanOverrideProcessor {
Assert.isTrue(expectedMethodNames.length > 0, "At least one expectedMethodName is required"); Assert.isTrue(expectedMethodNames.length > 0, "At least one expectedMethodName is required");
Set<String> expectedNames = new LinkedHashSet<>(Arrays.asList(expectedMethodNames)); Set<String> expectedNames = new LinkedHashSet<>(Arrays.asList(expectedMethodNames));
final List<Method> found = Arrays.stream(enclosingClass.getDeclaredMethods()) List<Method> found = Arrays.stream(enclosingClass.getDeclaredMethods())
.filter(method -> Modifier.isStatic(method.getModifiers())) .filter(method -> Modifier.isStatic(method.getModifiers()) &&
.filter(method -> expectedNames.contains(method.getName()) expectedNames.contains(method.getName()) &&
&& expectedMethodReturnType.isAssignableFrom(method.getReturnType())) expectedMethodReturnType.isAssignableFrom(method.getReturnType()))
.toList(); .toList();
Assert.state(found.size() == 1, () -> "Found " + found.size() + " static methods " + Assert.state(found.size() == 1, () -> "Found " + found.size() + " static methods " +
@ -71,13 +71,13 @@ public class TestBeanOverrideProcessor implements BeanOverrideProcessor {
@Override @Override
public OverrideMetadata createMetadata(Field field, Annotation overrideAnnotation, ResolvableType typeToOverride) { public OverrideMetadata createMetadata(Field field, Annotation overrideAnnotation, ResolvableType typeToOverride) {
final Class<?> enclosingClass = field.getDeclaringClass(); Class<?> declaringClass = field.getDeclaringClass();
// if we can get an explicit method name right away, fail fast if it doesn't match // If we can, get an explicit method name right away; fail fast if it doesn't match.
if (overrideAnnotation instanceof TestBean testBeanAnnotation) { if (overrideAnnotation instanceof TestBean testBeanAnnotation) {
Method overrideMethod = null; Method overrideMethod = null;
String beanName = null; String beanName = null;
if (!testBeanAnnotation.methodName().isBlank()) { if (!testBeanAnnotation.methodName().isBlank()) {
overrideMethod = ensureMethod(enclosingClass, field.getType(), testBeanAnnotation.methodName()); overrideMethod = ensureMethod(declaringClass, field.getType(), testBeanAnnotation.methodName());
} }
if (!testBeanAnnotation.name().isBlank()) { if (!testBeanAnnotation.name().isBlank()) {
beanName = testBeanAnnotation.name(); beanName = testBeanAnnotation.name();
@ -85,9 +85,8 @@ public class TestBeanOverrideProcessor implements BeanOverrideProcessor {
return new MethodConventionOverrideMetadata(field, overrideMethod, beanName, return new MethodConventionOverrideMetadata(field, overrideMethod, beanName,
overrideAnnotation, typeToOverride); overrideAnnotation, typeToOverride);
} }
// otherwise defer the resolution of the static method until OverrideMetadata#createOverride // Otherwise defer the resolution of the static method until OverrideMetadata#createOverride.
return new MethodConventionOverrideMetadata(field, null, null, overrideAnnotation, return new MethodConventionOverrideMetadata(field, null, null, overrideAnnotation, typeToOverride);
typeToOverride);
} }
static final class MethodConventionOverrideMetadata extends OverrideMetadata { static final class MethodConventionOverrideMetadata extends OverrideMetadata {
@ -100,6 +99,7 @@ public class TestBeanOverrideProcessor implements BeanOverrideProcessor {
public MethodConventionOverrideMetadata(Field field, @Nullable Method overrideMethod, @Nullable String beanName, public MethodConventionOverrideMetadata(Field field, @Nullable Method overrideMethod, @Nullable String beanName,
Annotation overrideAnnotation, ResolvableType typeToOverride) { Annotation overrideAnnotation, ResolvableType typeToOverride) {
super(field, overrideAnnotation, typeToOverride, BeanOverrideStrategy.REPLACE_DEFINITION); super(field, overrideAnnotation, typeToOverride, BeanOverrideStrategy.REPLACE_DEFINITION);
this.overrideMethod = overrideMethod; this.overrideMethod = overrideMethod;
this.beanName = beanName; this.beanName = beanName;
@ -121,6 +121,7 @@ public class TestBeanOverrideProcessor implements BeanOverrideProcessor {
@Override @Override
protected Object createOverride(String beanName, @Nullable BeanDefinition existingBeanDefinition, protected Object createOverride(String beanName, @Nullable BeanDefinition existingBeanDefinition,
@Nullable Object existingBeanInstance) { @Nullable Object existingBeanInstance) {
Method methodToInvoke = this.overrideMethod; Method methodToInvoke = this.overrideMethod;
if (methodToInvoke == null) { if (methodToInvoke == null) {
methodToInvoke = ensureMethod(field().getDeclaringClass(), field().getType(), methodToInvoke = ensureMethod(field().getDeclaringClass(), field().getType(),
@ -135,7 +136,7 @@ public class TestBeanOverrideProcessor implements BeanOverrideProcessor {
} }
catch (IllegalAccessException | InvocationTargetException ex) { catch (IllegalAccessException | InvocationTargetException ex) {
throw new IllegalArgumentException("Could not invoke bean overriding method " + methodToInvoke.getName() + throw new IllegalArgumentException("Could not invoke bean overriding method " + methodToInvoke.getName() +
", a static method with no input parameters is expected", ex); "; a static method with no formal parameters is expected", ex);
} }
return override; return override;

52
spring-test/src/main/java/org/springframework/test/web/reactive/server/CookieAssertions.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -24,9 +24,10 @@ import org.hamcrest.Matcher;
import org.hamcrest.MatcherAssert; import org.hamcrest.MatcherAssert;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.test.util.AssertionErrors;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.springframework.test.util.AssertionErrors.assertEquals;
import static org.springframework.test.util.AssertionErrors.fail;
/** /**
* Assertions on cookies of the response. * Assertions on cookies of the response.
@ -48,18 +49,20 @@ public class CookieAssertions {
/** /**
* Expect a header with the given name to match the specified values. * Expect a response cookie with the given name to match the specified value.
*/ */
public WebTestClient.ResponseSpec valueEquals(String name, String value) { public WebTestClient.ResponseSpec valueEquals(String name, String value) {
String cookieValue = getCookie(name).getValue();
this.exchangeResult.assertWithDiagnostics(() -> { this.exchangeResult.assertWithDiagnostics(() -> {
String message = getMessage(name); String message = getMessage(name);
AssertionErrors.assertEquals(message, value, getCookie(name).getValue()); assertEquals(message, value, cookieValue);
}); });
return this.responseSpec; return this.responseSpec;
} }
/** /**
* Assert the first value of the response cookie with a Hamcrest {@link Matcher}. * Assert the value of the response cookie with the given name with a Hamcrest
* {@link Matcher}.
*/ */
public WebTestClient.ResponseSpec value(String name, Matcher<? super String> matcher) { public WebTestClient.ResponseSpec value(String name, Matcher<? super String> matcher) {
String value = getCookie(name).getValue(); String value = getCookie(name).getValue();
@ -71,7 +74,7 @@ public class CookieAssertions {
} }
/** /**
* Consume the value of the response cookie. * Consume the value of the response cookie with the given name.
*/ */
public WebTestClient.ResponseSpec value(String name, Consumer<String> consumer) { public WebTestClient.ResponseSpec value(String name, Consumer<String> consumer) {
String value = getCookie(name).getValue(); String value = getCookie(name).getValue();
@ -94,25 +97,25 @@ public class CookieAssertions {
ResponseCookie cookie = this.exchangeResult.getResponseCookies().getFirst(name); ResponseCookie cookie = this.exchangeResult.getResponseCookies().getFirst(name);
if (cookie != null) { if (cookie != null) {
String message = getMessage(name) + " exists with value=[" + cookie.getValue() + "]"; String message = getMessage(name) + " exists with value=[" + cookie.getValue() + "]";
this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.fail(message)); this.exchangeResult.assertWithDiagnostics(() -> fail(message));
} }
return this.responseSpec; return this.responseSpec;
} }
/** /**
* Assert a cookie's maxAge attribute. * Assert a cookie's "Max-Age" attribute.
*/ */
public WebTestClient.ResponseSpec maxAge(String name, Duration expected) { public WebTestClient.ResponseSpec maxAge(String name, Duration expected) {
Duration maxAge = getCookie(name).getMaxAge(); Duration maxAge = getCookie(name).getMaxAge();
this.exchangeResult.assertWithDiagnostics(() -> { this.exchangeResult.assertWithDiagnostics(() -> {
String message = getMessage(name) + " maxAge"; String message = getMessage(name) + " maxAge";
AssertionErrors.assertEquals(message, expected, maxAge); assertEquals(message, expected, maxAge);
}); });
return this.responseSpec; return this.responseSpec;
} }
/** /**
* Assert a cookie's maxAge attribute with a Hamcrest {@link Matcher}. * Assert a cookie's "Max-Age" attribute with a Hamcrest {@link Matcher}.
*/ */
public WebTestClient.ResponseSpec maxAge(String name, Matcher<? super Long> matcher) { public WebTestClient.ResponseSpec maxAge(String name, Matcher<? super Long> matcher) {
long maxAge = getCookie(name).getMaxAge().getSeconds(); long maxAge = getCookie(name).getMaxAge().getSeconds();
@ -124,19 +127,19 @@ public class CookieAssertions {
} }
/** /**
* Assert a cookie's path attribute. * Assert a cookie's "Path" attribute.
*/ */
public WebTestClient.ResponseSpec path(String name, String expected) { public WebTestClient.ResponseSpec path(String name, String expected) {
String path = getCookie(name).getPath(); String path = getCookie(name).getPath();
this.exchangeResult.assertWithDiagnostics(() -> { this.exchangeResult.assertWithDiagnostics(() -> {
String message = getMessage(name) + " path"; String message = getMessage(name) + " path";
AssertionErrors.assertEquals(message, expected, path); assertEquals(message, expected, path);
}); });
return this.responseSpec; return this.responseSpec;
} }
/** /**
* Assert a cookie's path attribute with a Hamcrest {@link Matcher}. * Assert a cookie's "Path" attribute with a Hamcrest {@link Matcher}.
*/ */
public WebTestClient.ResponseSpec path(String name, Matcher<? super String> matcher) { public WebTestClient.ResponseSpec path(String name, Matcher<? super String> matcher) {
String path = getCookie(name).getPath(); String path = getCookie(name).getPath();
@ -148,19 +151,19 @@ public class CookieAssertions {
} }
/** /**
* Assert a cookie's domain attribute. * Assert a cookie's "Domain" attribute.
*/ */
public WebTestClient.ResponseSpec domain(String name, String expected) { public WebTestClient.ResponseSpec domain(String name, String expected) {
String path = getCookie(name).getDomain(); String path = getCookie(name).getDomain();
this.exchangeResult.assertWithDiagnostics(() -> { this.exchangeResult.assertWithDiagnostics(() -> {
String message = getMessage(name) + " domain"; String message = getMessage(name) + " domain";
AssertionErrors.assertEquals(message, expected, path); assertEquals(message, expected, path);
}); });
return this.responseSpec; return this.responseSpec;
} }
/** /**
* Assert a cookie's domain attribute with a Hamcrest {@link Matcher}. * Assert a cookie's "Domain" attribute with a Hamcrest {@link Matcher}.
*/ */
public WebTestClient.ResponseSpec domain(String name, Matcher<? super String> matcher) { public WebTestClient.ResponseSpec domain(String name, Matcher<? super String> matcher) {
String domain = getCookie(name).getDomain(); String domain = getCookie(name).getDomain();
@ -172,37 +175,37 @@ public class CookieAssertions {
} }
/** /**
* Assert a cookie's secure attribute. * Assert a cookie's "Secure" attribute.
*/ */
public WebTestClient.ResponseSpec secure(String name, boolean expected) { public WebTestClient.ResponseSpec secure(String name, boolean expected) {
boolean isSecure = getCookie(name).isSecure(); boolean isSecure = getCookie(name).isSecure();
this.exchangeResult.assertWithDiagnostics(() -> { this.exchangeResult.assertWithDiagnostics(() -> {
String message = getMessage(name) + " secure"; String message = getMessage(name) + " secure";
AssertionErrors.assertEquals(message, expected, isSecure); assertEquals(message, expected, isSecure);
}); });
return this.responseSpec; return this.responseSpec;
} }
/** /**
* Assert a cookie's httpOnly attribute. * Assert a cookie's "HttpOnly" attribute.
*/ */
public WebTestClient.ResponseSpec httpOnly(String name, boolean expected) { public WebTestClient.ResponseSpec httpOnly(String name, boolean expected) {
boolean isHttpOnly = getCookie(name).isHttpOnly(); boolean isHttpOnly = getCookie(name).isHttpOnly();
this.exchangeResult.assertWithDiagnostics(() -> { this.exchangeResult.assertWithDiagnostics(() -> {
String message = getMessage(name) + " httpOnly"; String message = getMessage(name) + " httpOnly";
AssertionErrors.assertEquals(message, expected, isHttpOnly); assertEquals(message, expected, isHttpOnly);
}); });
return this.responseSpec; return this.responseSpec;
} }
/** /**
* Assert a cookie's sameSite attribute. * Assert a cookie's "SameSite" attribute.
*/ */
public WebTestClient.ResponseSpec sameSite(String name, String expected) { public WebTestClient.ResponseSpec sameSite(String name, String expected) {
String sameSite = getCookie(name).getSameSite(); String sameSite = getCookie(name).getSameSite();
this.exchangeResult.assertWithDiagnostics(() -> { this.exchangeResult.assertWithDiagnostics(() -> {
String message = getMessage(name) + " sameSite"; String message = getMessage(name) + " sameSite";
AssertionErrors.assertEquals(message, expected, sameSite); assertEquals(message, expected, sameSite);
}); });
return this.responseSpec; return this.responseSpec;
} }
@ -211,13 +214,12 @@ public class CookieAssertions {
private ResponseCookie getCookie(String name) { private ResponseCookie getCookie(String name) {
ResponseCookie cookie = this.exchangeResult.getResponseCookies().getFirst(name); ResponseCookie cookie = this.exchangeResult.getResponseCookies().getFirst(name);
if (cookie == null) { if (cookie == null) {
this.exchangeResult.assertWithDiagnostics(() -> this.exchangeResult.assertWithDiagnostics(() -> fail("No cookie with name '" + name + "'"));
AssertionErrors.fail("No cookie with name '" + name + "'"));
} }
return Objects.requireNonNull(cookie); return Objects.requireNonNull(cookie);
} }
private String getMessage(String cookie) { private static String getMessage(String cookie) {
return "Response cookie '" + cookie + "'"; return "Response cookie '" + cookie + "'";
} }

43
spring-test/src/main/java/org/springframework/test/web/reactive/server/HeaderAssertions.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -23,19 +23,19 @@ import java.util.Objects;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.hamcrest.Matcher; import org.hamcrest.Matcher;
import org.hamcrest.MatcherAssert;
import org.springframework.http.CacheControl; import org.springframework.http.CacheControl;
import org.springframework.http.ContentDisposition; import org.springframework.http.ContentDisposition;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.test.util.AssertionErrors;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.springframework.test.util.AssertionErrors.assertEquals; import static org.springframework.test.util.AssertionErrors.assertEquals;
import static org.springframework.test.util.AssertionErrors.assertNotNull; import static org.springframework.test.util.AssertionErrors.assertNotNull;
import static org.springframework.test.util.AssertionErrors.assertTrue; import static org.springframework.test.util.AssertionErrors.assertTrue;
import static org.springframework.test.util.AssertionErrors.fail;
/** /**
* Assertions on headers of the response. * Assertions on headers of the response.
@ -73,8 +73,8 @@ public class HeaderAssertions {
public WebTestClient.ResponseSpec valueEquals(String headerName, long value) { public WebTestClient.ResponseSpec valueEquals(String headerName, long value) {
String actual = getHeaders().getFirst(headerName); String actual = getHeaders().getFirst(headerName);
this.exchangeResult.assertWithDiagnostics(() -> this.exchangeResult.assertWithDiagnostics(() ->
assertTrue("Response does not contain header '" + headerName + "'", actual != null)); assertNotNull("Response does not contain header '" + headerName + "'", actual));
return assertHeader(headerName, value, Long.parseLong(Objects.requireNonNull(actual))); return assertHeader(headerName, value, Long.parseLong(actual));
} }
/** /**
@ -94,7 +94,7 @@ public class HeaderAssertions {
headers.setDate("expected", value); headers.setDate("expected", value);
headers.set("actual", headerValue); headers.set("actual", headerValue);
assertEquals("Response header '" + headerName + "'='" + headerValue + "' " + assertEquals(getMessage(headerName) + "='" + headerValue + "' " +
"does not match expected value '" + headers.getFirst("expected") + "'", "does not match expected value '" + headers.getFirst("expected") + "'",
headers.getFirstDate("expected"), headers.getFirstDate("actual")); headers.getFirstDate("expected"), headers.getFirstDate("actual"));
}); });
@ -109,7 +109,7 @@ public class HeaderAssertions {
public WebTestClient.ResponseSpec valueMatches(String name, String pattern) { public WebTestClient.ResponseSpec valueMatches(String name, String pattern) {
String value = getRequiredValue(name); String value = getRequiredValue(name);
String message = getMessage(name) + "=[" + value + "] does not match [" + pattern + "]"; String message = getMessage(name) + "=[" + value + "] does not match [" + pattern + "]";
this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.assertTrue(message, value.matches(pattern))); this.exchangeResult.assertWithDiagnostics(() -> assertTrue(message, value.matches(pattern)));
return this.responseSpec; return this.responseSpec;
} }
@ -123,16 +123,16 @@ public class HeaderAssertions {
* @since 5.3 * @since 5.3
*/ */
public WebTestClient.ResponseSpec valuesMatch(String name, String... patterns) { public WebTestClient.ResponseSpec valuesMatch(String name, String... patterns) {
List<String> values = getRequiredValues(name);
this.exchangeResult.assertWithDiagnostics(() -> { this.exchangeResult.assertWithDiagnostics(() -> {
List<String> values = getRequiredValues(name); assertTrue(
AssertionErrors.assertTrue(
getMessage(name) + " has fewer or more values " + values + getMessage(name) + " has fewer or more values " + values +
" than number of patterns to match with " + Arrays.toString(patterns), " than number of patterns to match with " + Arrays.toString(patterns),
values.size() == patterns.length); values.size() == patterns.length);
for (int i = 0; i < values.size(); i++) { for (int i = 0; i < values.size(); i++) {
String value = values.get(i); String value = values.get(i);
String pattern = patterns[i]; String pattern = patterns[i];
AssertionErrors.assertTrue( assertTrue(
getMessage(name) + "[" + i + "]='" + value + "' does not match '" + pattern + "'", getMessage(name) + "[" + i + "]='" + value + "' does not match '" + pattern + "'",
value.matches(pattern)); value.matches(pattern));
} }
@ -150,7 +150,7 @@ public class HeaderAssertions {
String value = getHeaders().getFirst(name); String value = getHeaders().getFirst(name);
this.exchangeResult.assertWithDiagnostics(() -> { this.exchangeResult.assertWithDiagnostics(() -> {
String message = getMessage(name); String message = getMessage(name);
MatcherAssert.assertThat(message, value, matcher); assertThat(message, value, matcher);
}); });
return this.responseSpec; return this.responseSpec;
} }
@ -165,7 +165,7 @@ public class HeaderAssertions {
List<String> values = getHeaders().get(name); List<String> values = getHeaders().get(name);
this.exchangeResult.assertWithDiagnostics(() -> { this.exchangeResult.assertWithDiagnostics(() -> {
String message = getMessage(name); String message = getMessage(name);
MatcherAssert.assertThat(message, values, matcher); assertThat(message, values, matcher);
}); });
return this.responseSpec; return this.responseSpec;
} }
@ -201,8 +201,7 @@ public class HeaderAssertions {
private List<String> getRequiredValues(String name) { private List<String> getRequiredValues(String name) {
List<String> values = getHeaders().get(name); List<String> values = getHeaders().get(name);
if (CollectionUtils.isEmpty(values)) { if (CollectionUtils.isEmpty(values)) {
this.exchangeResult.assertWithDiagnostics(() -> this.exchangeResult.assertWithDiagnostics(() -> fail(getMessage(name) + " not found"));
AssertionErrors.fail(getMessage(name) + " not found"));
} }
return Objects.requireNonNull(values); return Objects.requireNonNull(values);
} }
@ -214,7 +213,7 @@ public class HeaderAssertions {
public WebTestClient.ResponseSpec exists(String name) { public WebTestClient.ResponseSpec exists(String name) {
if (!getHeaders().containsKey(name)) { if (!getHeaders().containsKey(name)) {
String message = getMessage(name) + " does not exist"; String message = getMessage(name) + " does not exist";
this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.fail(message)); this.exchangeResult.assertWithDiagnostics(() -> fail(message));
} }
return this.responseSpec; return this.responseSpec;
} }
@ -225,7 +224,7 @@ public class HeaderAssertions {
public WebTestClient.ResponseSpec doesNotExist(String name) { public WebTestClient.ResponseSpec doesNotExist(String name) {
if (getHeaders().containsKey(name)) { if (getHeaders().containsKey(name)) {
String message = getMessage(name) + " exists with value=[" + getHeaders().getFirst(name) + "]"; String message = getMessage(name) + " exists with value=[" + getHeaders().getFirst(name) + "]";
this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.fail(message)); this.exchangeResult.assertWithDiagnostics(() -> fail(message));
} }
return this.responseSpec; return this.responseSpec;
} }
@ -272,7 +271,7 @@ public class HeaderAssertions {
MediaType actual = getHeaders().getContentType(); MediaType actual = getHeaders().getContentType();
String message = getMessage("Content-Type") + "=[" + actual + "] is not compatible with [" + mediaType + "]"; String message = getMessage("Content-Type") + "=[" + actual + "] is not compatible with [" + mediaType + "]";
this.exchangeResult.assertWithDiagnostics(() -> this.exchangeResult.assertWithDiagnostics(() ->
AssertionErrors.assertTrue(message, (actual != null && actual.isCompatibleWith(mediaType)))); assertTrue(message, (actual != null && actual.isCompatibleWith(mediaType))));
return this.responseSpec; return this.responseSpec;
} }
@ -310,16 +309,16 @@ public class HeaderAssertions {
return this.exchangeResult.getResponseHeaders(); return this.exchangeResult.getResponseHeaders();
} }
private String getMessage(String headerName) {
return "Response header '" + headerName + "'";
}
private WebTestClient.ResponseSpec assertHeader(String name, @Nullable Object expected, @Nullable Object actual) { private WebTestClient.ResponseSpec assertHeader(String name, @Nullable Object expected, @Nullable Object actual) {
this.exchangeResult.assertWithDiagnostics(() -> { this.exchangeResult.assertWithDiagnostics(() -> {
String message = getMessage(name); String message = getMessage(name);
AssertionErrors.assertEquals(message, expected, actual); assertEquals(message, expected, actual);
}); });
return this.responseSpec; return this.responseSpec;
} }
private static String getMessage(String headerName) {
return "Response header '" + headerName + "'";
}
} }

43
spring-test/src/test/java/org/springframework/test/context/bean/override/OverrideMetadataTests.java

@ -29,12 +29,35 @@ import org.springframework.lang.Nullable;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link OverrideMetadata}.
*
* @author Simon Baslé
* @since 6.2
*/
class OverrideMetadataTests { class OverrideMetadataTests {
@Test
void implicitConfigurations() throws Exception {
OverrideMetadata metadata = exampleOverride();
assertThat(metadata.getExpectedBeanName()).as("expectedBeanName").isEqualTo(metadata.field().getName());
}
@NonNull
String annotated = "exampleField";
private static OverrideMetadata exampleOverride() throws Exception {
Field field = OverrideMetadataTests.class.getDeclaredField("annotated");
return new ConcreteOverrideMetadata(Objects.requireNonNull(field), field.getAnnotation(NonNull.class),
ResolvableType.forClass(String.class), BeanOverrideStrategy.REPLACE_DEFINITION);
}
static class ConcreteOverrideMetadata extends OverrideMetadata { static class ConcreteOverrideMetadata extends OverrideMetadata {
ConcreteOverrideMetadata(Field field, Annotation overrideAnnotation, ResolvableType typeToOverride, ConcreteOverrideMetadata(Field field, Annotation overrideAnnotation, ResolvableType typeToOverride,
BeanOverrideStrategy strategy) { BeanOverrideStrategy strategy) {
super(field, overrideAnnotation, typeToOverride, strategy); super(field, overrideAnnotation, typeToOverride, strategy);
} }
@ -44,25 +67,11 @@ class OverrideMetadataTests {
} }
@Override @Override
protected Object createOverride(String beanName, @Nullable BeanDefinition existingBeanDefinition, @Nullable Object existingBeanInstance) { protected Object createOverride(String beanName, @Nullable BeanDefinition existingBeanDefinition,
@Nullable Object existingBeanInstance) {
return BeanOverrideStrategy.REPLACE_DEFINITION; return BeanOverrideStrategy.REPLACE_DEFINITION;
} }
} }
@NonNull
public String annotated = "exampleField";
static OverrideMetadata exampleOverride() throws NoSuchFieldException {
final Field annotated = OverrideMetadataTests.class.getField("annotated");
return new ConcreteOverrideMetadata(Objects.requireNonNull(annotated), annotated.getAnnotation(NonNull.class),
ResolvableType.forClass(String.class), BeanOverrideStrategy.REPLACE_DEFINITION);
}
@Test
void implicitConfigurations() throws NoSuchFieldException {
final OverrideMetadata metadata = exampleOverride();
assertThat(metadata.getExpectedBeanName()).as("expectedBeanName")
.isEqualTo(metadata.field().getName());
}
} }

66
spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanOverrideProcessorTests.java

@ -24,78 +24,85 @@ import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationUtils; import org.springframework.test.context.bean.override.convention.TestBeanOverrideProcessor.MethodConventionOverrideMetadata;
import org.springframework.test.context.bean.override.example.ExampleService; import org.springframework.test.context.bean.override.example.ExampleService;
import org.springframework.test.context.bean.override.example.FailingExampleService; import org.springframework.test.context.bean.override.example.FailingExampleService;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatException; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
/**
* Tests for {@link TestBeanOverrideProcessor}.
*
* @author Simon Baslé
* @since 6.2
*/
class TestBeanOverrideProcessorTests { class TestBeanOverrideProcessorTests {
@Test @Test
void ensureMethodFindsFromList() { void ensureMethodFindsFromList() {
Method m = TestBeanOverrideProcessor.ensureMethod(MethodConventionConf.class, ExampleService.class, Method method = TestBeanOverrideProcessor.ensureMethod(MethodConventionConf.class, ExampleService.class,
"example1", "example2", "example3"); "example1", "example2", "example3");
assertThat(m.getName()).isEqualTo("example2"); assertThat(method.getName()).isEqualTo("example2");
} }
@Test @Test
void ensureMethodNotFound() { void ensureMethodNotFound() {
assertThatException().isThrownBy(() -> TestBeanOverrideProcessor.ensureMethod( assertThatIllegalStateException()
MethodConventionConf.class, ExampleService.class, "example1", "example3")) .isThrownBy(() -> TestBeanOverrideProcessor.ensureMethod(MethodConventionConf.class, ExampleService.class,
"example1", "example3"))
.withMessage("Found 0 static methods instead of exactly one, matching a name in [example1, example3] with return type " + .withMessage("Found 0 static methods instead of exactly one, matching a name in [example1, example3] with return type " +
ExampleService.class.getName() + " on class " + MethodConventionConf.class.getName()) ExampleService.class.getName() + " on class " + MethodConventionConf.class.getName());
.isInstanceOf(IllegalStateException.class);
} }
@Test @Test
void ensureMethodTwoFound() { void ensureMethodTwoFound() {
assertThatException().isThrownBy(() -> TestBeanOverrideProcessor.ensureMethod( assertThatIllegalStateException()
MethodConventionConf.class, ExampleService.class, "example2", "example4")) .isThrownBy(() -> TestBeanOverrideProcessor.ensureMethod(MethodConventionConf.class, ExampleService.class,
"example2", "example4"))
.withMessage("Found 2 static methods instead of exactly one, matching a name in [example2, example4] with return type " + .withMessage("Found 2 static methods instead of exactly one, matching a name in [example2, example4] with return type " +
ExampleService.class.getName() + " on class " + MethodConventionConf.class.getName()) ExampleService.class.getName() + " on class " + MethodConventionConf.class.getName());
.isInstanceOf(IllegalStateException.class);
} }
@Test @Test
void ensureMethodNoNameProvided() { void ensureMethodNoNameProvided() {
assertThatException().isThrownBy(() -> TestBeanOverrideProcessor.ensureMethod( assertThatIllegalArgumentException()
MethodConventionConf.class, ExampleService.class)) .isThrownBy(() -> TestBeanOverrideProcessor.ensureMethod(MethodConventionConf.class, ExampleService.class))
.withMessage("At least one expectedMethodName is required") .withMessage("At least one expectedMethodName is required");
.isInstanceOf(IllegalArgumentException.class);
} }
@Test @Test
void createMetaDataForUnknownExplicitMethod() throws NoSuchFieldException { void createMetaDataForUnknownExplicitMethod() throws NoSuchFieldException {
Field f = ExplicitMethodNameConf.class.getField("a"); Field field = ExplicitMethodNameConf.class.getField("a");
final TestBean overrideAnnotation = Objects.requireNonNull(AnnotationUtils.getAnnotation(f, TestBean.class)); TestBean overrideAnnotation = Objects.requireNonNull(field.getAnnotation(TestBean.class));
TestBeanOverrideProcessor processor = new TestBeanOverrideProcessor(); TestBeanOverrideProcessor processor = new TestBeanOverrideProcessor();
assertThatException().isThrownBy(() -> processor.createMetadata(f, overrideAnnotation, ResolvableType.forClass(ExampleService.class))) assertThatIllegalStateException()
.isThrownBy(() -> processor.createMetadata(field, overrideAnnotation, ResolvableType.forClass(ExampleService.class)))
.withMessage("Found 0 static methods instead of exactly one, matching a name in [explicit1] with return type " + .withMessage("Found 0 static methods instead of exactly one, matching a name in [explicit1] with return type " +
ExampleService.class.getName() + " on class " + ExplicitMethodNameConf.class.getName()) ExampleService.class.getName() + " on class " + ExplicitMethodNameConf.class.getName());
.isInstanceOf(IllegalStateException.class);
} }
@Test @Test
void createMetaDataForKnownExplicitMethod() throws NoSuchFieldException { void createMetaDataForKnownExplicitMethod() throws NoSuchFieldException {
Field f = ExplicitMethodNameConf.class.getField("b"); Field field = ExplicitMethodNameConf.class.getField("b");
final TestBean overrideAnnotation = Objects.requireNonNull(AnnotationUtils.getAnnotation(f, TestBean.class)); TestBean overrideAnnotation = Objects.requireNonNull(field.getAnnotation(TestBean.class));
TestBeanOverrideProcessor processor = new TestBeanOverrideProcessor(); TestBeanOverrideProcessor processor = new TestBeanOverrideProcessor();
assertThat(processor.createMetadata(f, overrideAnnotation, ResolvableType.forClass(ExampleService.class))) assertThat(processor.createMetadata(field, overrideAnnotation, ResolvableType.forClass(ExampleService.class)))
.isInstanceOf(TestBeanOverrideProcessor.MethodConventionOverrideMetadata.class); .isInstanceOf(MethodConventionOverrideMetadata.class);
} }
@Test @Test
void createMetaDataWithDeferredEnsureMethodCheck() throws NoSuchFieldException { void createMetaDataWithDeferredEnsureMethodCheck() throws NoSuchFieldException {
Field f = MethodConventionConf.class.getField("field"); Field field = MethodConventionConf.class.getField("field");
final TestBean overrideAnnotation = Objects.requireNonNull(AnnotationUtils.getAnnotation(f, TestBean.class)); TestBean overrideAnnotation = Objects.requireNonNull(field.getAnnotation(TestBean.class));
TestBeanOverrideProcessor processor = new TestBeanOverrideProcessor(); TestBeanOverrideProcessor processor = new TestBeanOverrideProcessor();
assertThat(processor.createMetadata(f, overrideAnnotation, ResolvableType.forClass(ExampleService.class))) assertThat(processor.createMetadata(field, overrideAnnotation, ResolvableType.forClass(ExampleService.class)))
.isInstanceOf(TestBeanOverrideProcessor.MethodConventionOverrideMetadata.class); .isInstanceOf(MethodConventionOverrideMetadata.class);
} }
static class MethodConventionConf { static class MethodConventionConf {
@TestBean @TestBean
@ -127,4 +134,5 @@ class TestBeanOverrideProcessorTests {
return new FailingExampleService(); return new FailingExampleService();
} }
} }
} }

93
spring-test/src/test/java/org/springframework/test/web/servlet/samples/client/standalone/resultmatches/HeaderAssertionTests.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2023 the original author or authors. * Copyright 2002-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -35,9 +35,7 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.WebRequest; import org.springframework.web.context.request.WebRequest;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.fail;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.hasItems;
@ -53,10 +51,7 @@ import static org.springframework.http.HttpHeaders.VARY;
* *
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
*/ */
public class HeaderAssertionTests { class HeaderAssertionTests {
private static final String ERROR_MESSAGE = "Should have thrown an AssertionError";
private String now; private String now;
@ -70,7 +65,7 @@ public class HeaderAssertionTests {
@BeforeEach @BeforeEach
public void setup() { void setup() {
this.dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); this.dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
this.dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); this.dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
this.now = dateFormat.format(new Date(this.currentTime)); this.now = dateFormat.format(new Date(this.currentTime));
@ -83,7 +78,7 @@ public class HeaderAssertionTests {
@Test @Test
public void stringWithCorrectResponseHeaderValue() { void stringWithCorrectResponseHeaderValue() {
testClient.get().uri("/persons/1").header(IF_MODIFIED_SINCE, minuteAgo) testClient.get().uri("/persons/1").header(IF_MODIFIED_SINCE, minuteAgo)
.exchange() .exchange()
.expectStatus().isOk() .expectStatus().isOk()
@ -91,7 +86,7 @@ public class HeaderAssertionTests {
} }
@Test @Test
public void stringWithMatcherAndCorrectResponseHeaderValue() { void stringWithMatcherAndCorrectResponseHeaderValue() {
testClient.get().uri("/persons/1").header(IF_MODIFIED_SINCE, minuteAgo) testClient.get().uri("/persons/1").header(IF_MODIFIED_SINCE, minuteAgo)
.exchange() .exchange()
.expectStatus().isOk() .expectStatus().isOk()
@ -99,7 +94,7 @@ public class HeaderAssertionTests {
} }
@Test @Test
public void multiStringHeaderValue() { void multiStringHeaderValue() {
testClient.get().uri("/persons/1") testClient.get().uri("/persons/1")
.exchange() .exchange()
.expectStatus().isOk() .expectStatus().isOk()
@ -107,7 +102,7 @@ public class HeaderAssertionTests {
} }
@Test @Test
public void multiStringHeaderValueWithMatchers() { void multiStringHeaderValueWithMatchers() {
testClient.get().uri("/persons/1") testClient.get().uri("/persons/1")
.exchange() .exchange()
.expectStatus().isOk() .expectStatus().isOk()
@ -115,7 +110,7 @@ public class HeaderAssertionTests {
} }
@Test @Test
public void dateValueWithCorrectResponseHeaderValue() { void dateValueWithCorrectResponseHeaderValue() {
testClient.get().uri("/persons/1") testClient.get().uri("/persons/1")
.header(IF_MODIFIED_SINCE, minuteAgo) .header(IF_MODIFIED_SINCE, minuteAgo)
.exchange() .exchange()
@ -124,7 +119,7 @@ public class HeaderAssertionTests {
} }
@Test @Test
public void longValueWithCorrectResponseHeaderValue() { void longValueWithCorrectResponseHeaderValue() {
testClient.get().uri("/persons/1") testClient.get().uri("/persons/1")
.exchange() .exchange()
.expectStatus().isOk() .expectStatus().isOk()
@ -132,7 +127,7 @@ public class HeaderAssertionTests {
} }
@Test @Test
public void stringWithMissingResponseHeader() { void stringWithMissingResponseHeader() {
testClient.get().uri("/persons/1") testClient.get().uri("/persons/1")
.header(IF_MODIFIED_SINCE, now) .header(IF_MODIFIED_SINCE, now)
.exchange() .exchange()
@ -141,7 +136,7 @@ public class HeaderAssertionTests {
} }
@Test @Test
public void stringWithMatcherAndMissingResponseHeader() { void stringWithMatcherAndMissingResponseHeader() {
testClient.get().uri("/persons/1").header(IF_MODIFIED_SINCE, now) testClient.get().uri("/persons/1").header(IF_MODIFIED_SINCE, now)
.exchange() .exchange()
.expectStatus().isNotModified() .expectStatus().isNotModified()
@ -149,25 +144,18 @@ public class HeaderAssertionTests {
} }
@Test @Test
public void longValueWithMissingResponseHeader() { void longValueWithMissingResponseHeader() {
try { String headerName = "X-Custom-Header";
testClient.get().uri("/persons/1").header(IF_MODIFIED_SINCE, now) assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
.exchange() testClient.get().uri("/persons/1").header(IF_MODIFIED_SINCE, now)
.expectStatus().isNotModified() .exchange()
.expectHeader().valueEquals("X-Custom-Header", 99L); .expectStatus().isNotModified()
.expectHeader().valueEquals(headerName, 99L))
fail(ERROR_MESSAGE); .withMessage("Response does not contain header '%s'", headerName);
}
catch (AssertionError err) {
if (ERROR_MESSAGE.equals(err.getMessage())) {
throw err;
}
assertThat(err.getMessage()).startsWith("Response does not contain header 'X-Custom-Header'");
}
} }
@Test @Test
public void exists() { void exists() {
testClient.get().uri("/persons/1") testClient.get().uri("/persons/1")
.exchange() .exchange()
.expectStatus().isOk() .expectStatus().isOk()
@ -175,7 +163,7 @@ public class HeaderAssertionTests {
} }
@Test @Test
public void existsFail() { void existsFail() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
testClient.get().uri("/persons/1") testClient.get().uri("/persons/1")
.exchange() .exchange()
@ -184,7 +172,7 @@ public class HeaderAssertionTests {
} }
@Test @Test
public void doesNotExist() { void doesNotExist() {
testClient.get().uri("/persons/1") testClient.get().uri("/persons/1")
.exchange() .exchange()
.expectStatus().isOk() .expectStatus().isOk()
@ -192,7 +180,7 @@ public class HeaderAssertionTests {
} }
@Test @Test
public void doesNotExistFail() { void doesNotExistFail() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
testClient.get().uri("/persons/1") testClient.get().uri("/persons/1")
.exchange() .exchange()
@ -201,7 +189,7 @@ public class HeaderAssertionTests {
} }
@Test @Test
public void longValueWithIncorrectResponseHeaderValue() { void longValueWithIncorrectResponseHeaderValue() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
testClient.get().uri("/persons/1") testClient.get().uri("/persons/1")
.exchange() .exchange()
@ -210,7 +198,7 @@ public class HeaderAssertionTests {
} }
@Test @Test
public void stringWithMatcherAndIncorrectResponseHeaderValue() { void stringWithMatcherAndIncorrectResponseHeaderValue() {
long secondLater = this.currentTime + 1000; long secondLater = this.currentTime + 1000;
String expected = this.dateFormat.format(new Date(secondLater)); String expected = this.dateFormat.format(new Date(secondLater));
assertIncorrectResponseHeader(spec -> spec.expectHeader().valueEquals(LAST_MODIFIED, expected), expected); assertIncorrectResponseHeader(spec -> spec.expectHeader().valueEquals(LAST_MODIFIED, expected), expected);
@ -222,30 +210,13 @@ public class HeaderAssertionTests {
} }
private void assertIncorrectResponseHeader(Consumer<WebTestClient.ResponseSpec> assertions, String expected) { private void assertIncorrectResponseHeader(Consumer<WebTestClient.ResponseSpec> assertions, String expected) {
try { WebTestClient.ResponseSpec spec = testClient.get().uri("/persons/1")
WebTestClient.ResponseSpec spec = testClient.get().uri("/persons/1") .header(IF_MODIFIED_SINCE, minuteAgo)
.header(IF_MODIFIED_SINCE, minuteAgo) .exchange()
.exchange() .expectStatus().isOk();
.expectStatus().isOk(); assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertions.accept(spec))
assertions.accept(spec); .withMessageContainingAll("Response header '" + LAST_MODIFIED + "'", expected, this.now);
fail(ERROR_MESSAGE);
}
catch (AssertionError err) {
if (ERROR_MESSAGE.equals(err.getMessage())) {
throw err;
}
assertMessageContains(err, "Response header '" + LAST_MODIFIED + "'");
assertMessageContains(err, expected);
assertMessageContains(err, this.now);
}
}
private void assertMessageContains(AssertionError error, String expected) {
assertThat(error.getMessage())
.as("Failure message should contain [" + expected + "], actual is [" + error.getMessage() + "]")
.contains(expected);
} }

Loading…
Cancel
Save