HttpHeaders are no longer a MultiValueMap
This change removes the `MultiValueMap` nature of `HttpHeaders`, since it inherits APIs that do not align well with underlying server implementations. Notably, methods that allows to iterate over the whole collection of headers are susceptible to artificially introduced duplicates when multiple casings are used for a given header, depending on the underlying implementation. This change includes a dedicated key set implementation to support iterator-based removal, and either keeps map method implementations that are relevant or introduces header-focused methods that have a similar responsibility (like `hasHeaderValues(String, List)` and `containsHeaderValue(String, String)`). In order to nudge users away from using an HttpHeaders as a Map, the `asSingleValueMap` view is deprecated. In order to offer an escape hatch to users that do make use of the `MultiValueMap` API, a similar `asMultiValueMap` view is introduced but is immediately marked as deprecated. This change also adds map-like but header-focused assertions to `HttpHeadersAssert`, since it cannot extend `AbstractMapAssert` anymore. Closes gh-33913
This commit is contained in:
@@ -45,7 +45,7 @@ class HttpHeadersAssertTests {
|
||||
Map<String, String> map = Map.of("first", "1");
|
||||
assertThatExceptionOfType(AssertionError.class)
|
||||
.isThrownBy(() -> assertThat(map).containsHeader("wrong-name"))
|
||||
.withMessageContainingAll("HTTP headers", "first", "wrong-name");
|
||||
.withMessageContainingAll("HTTP header", "first", "wrong-name");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -71,8 +71,8 @@ class HttpHeadersAssertTests {
|
||||
void doesNotContainHeaderWithNamePresent() {
|
||||
Map<String, String> map = Map.of("first", "1");
|
||||
assertThatExceptionOfType(AssertionError.class)
|
||||
.isThrownBy(() -> assertThat(map).doesNotContainKey("first"))
|
||||
.withMessageContainingAll("HTTP headers", "first");
|
||||
.isThrownBy(() -> assertThat(map).doesNotContainHeader("first"))
|
||||
.withMessageContainingAll("HTTP header", "first");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -112,7 +112,7 @@ class HttpHeadersAssertTests {
|
||||
headers.addAll("header", List.of("first", "second", "third"));
|
||||
assertThatExceptionOfType(AssertionError.class)
|
||||
.isThrownBy(() -> assertThat(headers).hasValue("wrong-name", "second"))
|
||||
.withMessageContainingAll("HTTP headers", "header", "wrong-name");
|
||||
.withMessageContainingAll("HTTP header", "header", "wrong-name");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -121,7 +121,7 @@ class HttpHeadersAssertTests {
|
||||
map.add("test-header", "a");
|
||||
assertThatExceptionOfType(AssertionError.class)
|
||||
.isThrownBy(() -> assertThat(map).hasValue("wrong-name", "a"))
|
||||
.withMessageContainingAll("HTTP headers", "test-header", "wrong-name");
|
||||
.withMessageContainingAll("HTTP header", "test-header", "wrong-name");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -146,7 +146,7 @@ class HttpHeadersAssertTests {
|
||||
map.addAll("header", List.of("123", "456", "789"));
|
||||
assertThatExceptionOfType(AssertionError.class)
|
||||
.isThrownBy(() -> assertThat(map).hasValue("wrong-name", 456))
|
||||
.withMessageContainingAll("HTTP headers", "header", "wrong-name");
|
||||
.withMessageContainingAll("HTTP header", "header", "wrong-name");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -164,7 +164,7 @@ class HttpHeadersAssertTests {
|
||||
map.setInstant("header", instant);
|
||||
assertThatExceptionOfType(AssertionError.class)
|
||||
.isThrownBy(() -> assertThat(map).hasValue("wrong-name", instant.minusSeconds(30)))
|
||||
.withMessageContainingAll("HTTP headers", "header", "wrong-name");
|
||||
.withMessageContainingAll("HTTP header", "header", "wrong-name");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -174,7 +174,7 @@ class HttpHeadersAssertTests {
|
||||
map.setInstant("header", instant);
|
||||
assertThatExceptionOfType(AssertionError.class)
|
||||
.isThrownBy(() -> assertThat(map).hasValue("wrong-name", instant.minusSeconds(1)))
|
||||
.withMessageContainingAll("HTTP headers", "header", "wrong-name");
|
||||
.withMessageContainingAll("HTTP header", "header", "wrong-name");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ class ResponseCreatorsTests {
|
||||
MockClientHttpResponse response = (MockClientHttpResponse) MockRestResponseCreators.withSuccess().createResponse(null);
|
||||
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(response.getHeaders()).isEmpty();
|
||||
assertThat(response.getHeaders().isEmpty()).as("isEmpty").isTrue();
|
||||
assertThat(StreamUtils.copyToByteArray(response.getBody())).isEmpty();
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ class ResponseCreatorsTests {
|
||||
MockClientHttpResponse response = (MockClientHttpResponse) responseCreator.createResponse(null);
|
||||
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT);
|
||||
assertThat(response.getHeaders()).isEmpty();
|
||||
assertThat(response.getHeaders().isEmpty()).as("isEmpty").isTrue();
|
||||
assertThat(StreamUtils.copyToByteArray(response.getBody())).isEmpty();
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ class ResponseCreatorsTests {
|
||||
MockClientHttpResponse response = (MockClientHttpResponse) responseCreator.createResponse(null);
|
||||
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
|
||||
assertThat(response.getHeaders()).isEmpty();
|
||||
assertThat(response.getHeaders().isEmpty()).as("isEmpty").isTrue();
|
||||
assertThat(StreamUtils.copyToByteArray(response.getBody())).isEmpty();
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ class ResponseCreatorsTests {
|
||||
MockClientHttpResponse response = (MockClientHttpResponse) responseCreator.createResponse(null);
|
||||
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
assertThat(response.getHeaders()).isEmpty();
|
||||
assertThat(response.getHeaders().isEmpty()).as("isEmpty").isTrue();
|
||||
assertThat(StreamUtils.copyToByteArray(response.getBody())).isEmpty();
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ class ResponseCreatorsTests {
|
||||
MockClientHttpResponse response = (MockClientHttpResponse) responseCreator.createResponse(null);
|
||||
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.TOO_MANY_REQUESTS);
|
||||
assertThat(response.getHeaders()).doesNotContainKey(HttpHeaders.RETRY_AFTER);
|
||||
assertThat(response.getHeaders().headerNames()).doesNotContain(HttpHeaders.RETRY_AFTER);
|
||||
assertThat(StreamUtils.copyToByteArray(response.getBody())).isEmpty();
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ class ResponseCreatorsTests {
|
||||
MockClientHttpResponse response = (MockClientHttpResponse) responseCreator.createResponse(null);
|
||||
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
assertThat(response.getHeaders()).isEmpty();
|
||||
assertThat(response.getHeaders().isEmpty()).as("isEmpty").isTrue();
|
||||
assertThat(StreamUtils.copyToByteArray(response.getBody())).isEmpty();
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@ class ResponseCreatorsTests {
|
||||
MockClientHttpResponse response = (MockClientHttpResponse) responseCreator.createResponse(null);
|
||||
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
assertThat(response.getHeaders()).isEmpty();
|
||||
assertThat(response.getHeaders().isEmpty()).as("isEmpty").isTrue();
|
||||
assertThat(StreamUtils.copyToByteArray(response.getBody())).isEmpty();
|
||||
}
|
||||
|
||||
|
||||
@@ -100,15 +100,15 @@ public class MockServerTests {
|
||||
WebTestClient clientFromMutatedBuilder = mutatedBuilder.build();
|
||||
|
||||
client1.mutate().filters(filters -> assertThat(filters).hasSize(1));
|
||||
client1.mutate().defaultHeaders(headers -> assertThat(headers).hasSize(1));
|
||||
client1.mutate().defaultHeaders(headers -> assertThat(headers.size()).isOne());
|
||||
client1.mutate().defaultCookies(cookies -> assertThat(cookies).hasSize(1));
|
||||
|
||||
client2.mutate().filters(filters -> assertThat(filters).hasSize(2));
|
||||
client2.mutate().defaultHeaders(headers -> assertThat(headers).hasSize(2));
|
||||
client2.mutate().defaultHeaders(headers -> assertThat(headers.size()).isEqualTo(2));
|
||||
client2.mutate().defaultCookies(cookies -> assertThat(cookies).hasSize(2));
|
||||
|
||||
clientFromMutatedBuilder.mutate().filters(filters -> assertThat(filters).hasSize(2));
|
||||
clientFromMutatedBuilder.mutate().defaultHeaders(headers -> assertThat(headers).hasSize(2));
|
||||
clientFromMutatedBuilder.mutate().defaultHeaders(headers -> assertThat(headers.size()).isEqualTo(2));
|
||||
clientFromMutatedBuilder.mutate().defaultCookies(cookies -> assertThat(cookies).hasSize(2));
|
||||
}
|
||||
|
||||
|
||||
@@ -322,8 +322,8 @@ public class MockMvcTesterIntegrationTests {
|
||||
}
|
||||
|
||||
private Consumer<HttpHeaders> textContent(String charset) {
|
||||
return headers -> assertThat(headers).containsEntry(
|
||||
"Content-Type", List.of("text/plain;charset=%s".formatted(charset)));
|
||||
return headers -> assertThat(headers.hasHeaderValues("Content-Type", List.of("text/plain;charset=%s".formatted(charset))))
|
||||
.as("hasHeaderValues").isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ public class MockWebResponseBuilderTests {
|
||||
WebResponse webResponse = this.responseBuilder.build();
|
||||
|
||||
List<NameValuePair> responseHeaders = webResponse.getResponseHeaders();
|
||||
assertThat(responseHeaders).hasSize(1);
|
||||
assertThat(responseHeaders.size()).as("size").isOne();
|
||||
NameValuePair header = responseHeaders.get(0);
|
||||
assertThat(header.getName()).isEqualTo("Set-Cookie");
|
||||
assertThat(header.getValue()).isEqualTo("cookieA=valueA");
|
||||
|
||||
@@ -130,7 +130,7 @@ public class FrameworkExtensionTests {
|
||||
|
||||
@Override
|
||||
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
|
||||
for (String headerName : this.headers.keySet()) {
|
||||
for (String headerName : this.headers.headerNames()) {
|
||||
request.addHeader(headerName, this.headers.get(headerName));
|
||||
}
|
||||
return request;
|
||||
|
||||
@@ -94,7 +94,7 @@ public class FrameworkExtensionTests {
|
||||
|
||||
@Override
|
||||
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
|
||||
for (String headerName : this.headers.keySet()) {
|
||||
for (String headerName : this.headers.headerNames()) {
|
||||
request.addHeader(headerName, this.headers.get(headerName));
|
||||
}
|
||||
return request;
|
||||
|
||||
Reference in New Issue
Block a user