Introduce additional constructors in MockClientHttp[Request|Response]

This commit introduces additional constructors in MockClientHttpRequest
and MockClientHttpResponse that were previously only present in the
internal "test fixtures" in spring-web.

This commit also aligns the mocks in spring-test with the test fixtures
in spring-web to simplify continued maintenance of the mocks and test
fixtures.

Closes gh-29670
This commit is contained in:
Sam Brannen
2022-12-09 15:46:08 -05:00
parent 9b38e43c17
commit 83eb8ac0ea
31 changed files with 280 additions and 228 deletions

View File

@@ -0,0 +1,67 @@
/*
* Copyright 2002-2022 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.web.testfixture.http;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.util.Assert;
/**
* Mock implementation of {@link HttpInputMessage}.
*
* @author Rossen Stoyanchev
* @since 3.2
*/
public class MockHttpInputMessage implements HttpInputMessage {
private final HttpHeaders headers = new HttpHeaders();
private final InputStream body;
/**
* Create a {@code MockHttpInputMessage} with the supplied body.
*/
public MockHttpInputMessage(byte[] body) {
Assert.notNull(body, "Byte array must not be null");
this.body = new ByteArrayInputStream(body);
}
/**
* Create a {@code MockHttpInputMessage} with the supplied body.
*/
public MockHttpInputMessage(InputStream body) {
Assert.notNull(body, "InputStream must not be null");
this.body = body;
}
@Override
public HttpHeaders getHeaders() {
return this.headers;
}
@Override
public InputStream getBody() throws IOException {
return this.body;
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright 2002-2022 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.web.testfixture.http;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpOutputMessage;
import org.springframework.util.StreamUtils;
/**
* Mock implementation of {@link HttpOutputMessage}.
*
* @author Rossen Stoyanchev
* @since 3.2
*/
public class MockHttpOutputMessage implements HttpOutputMessage {
private final HttpHeaders headers = new HttpHeaders();
private final ByteArrayOutputStream body = new ByteArrayOutputStream(1024);
@Override
public HttpHeaders getHeaders() {
return this.headers;
}
@Override
public OutputStream getBody() throws IOException {
return this.body;
}
/**
* Return the body content as a byte array.
*/
public byte[] getBodyAsBytes() {
return this.body.toByteArray();
}
/**
* Return the body content interpreted as a UTF-8 string.
*/
public String getBodyAsString() {
return getBodyAsString(StandardCharsets.UTF_8);
}
/**
* Return the body content interpreted as a string using the supplied character set.
* @param charset the charset to use to turn the body content into a String
*/
public String getBodyAsString(Charset charset) {
return StreamUtils.copyToString(this.body, charset);
}
}

View File

@@ -16,78 +16,67 @@
package org.springframework.web.testfixture.http.client;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StreamUtils;
import org.springframework.web.testfixture.http.MockHttpOutputMessage;
import org.springframework.web.util.UriComponentsBuilder;
/**
* Mock implementation of {@link ClientHttpRequest}.
*
* @author Brian Clozel
* @author Rossen Stoyanchev
* @author Brian Clozel
* @author Sam Brannen
* @since 3.2
*/
public class MockClientHttpRequest implements ClientHttpRequest {
private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
private final HttpHeaders headers = new HttpHeaders();
public class MockClientHttpRequest extends MockHttpOutputMessage implements ClientHttpRequest {
private HttpMethod httpMethod;
private URI uri;
private final ByteArrayOutputStream body = new ByteArrayOutputStream(1024);
@Nullable
private ClientHttpResponse clientHttpResponse;
private boolean executed = false;
/**
* Create a {@code MockClientHttpRequest} with {@link HttpMethod#GET GET} as
* the HTTP request method and {@code "/"} as the {@link URI}.
*/
public MockClientHttpRequest() {
this.httpMethod = HttpMethod.GET;
this.uri = URI.create("/");
this(HttpMethod.GET, URI.create("/"));
}
public MockClientHttpRequest(HttpMethod httpMethod, String urlTemplate, Object... vars) {
/**
* Create a {@code MockClientHttpRequest} with the given {@link HttpMethod},
* URI template, and URI template variable values.
* @since 6.0.3
*/
public MockClientHttpRequest(HttpMethod httpMethod, String uriTemplate, Object... vars) {
this(httpMethod, UriComponentsBuilder.fromUriString(uriTemplate).buildAndExpand(vars).encode().toUri());
}
/**
* Create a {@code MockClientHttpRequest} with the given {@link HttpMethod}
* and {@link URI}.
*/
public MockClientHttpRequest(HttpMethod httpMethod, URI uri) {
this.httpMethod = httpMethod;
this.uri = UriComponentsBuilder.fromUriString(urlTemplate).buildAndExpand(vars).encode().toUri();
this.uri = uri;
}
@Override
public HttpHeaders getHeaders() {
return this.headers;
}
@Override
public OutputStream getBody() throws IOException {
return this.body;
}
public byte[] getBodyAsBytes() {
return this.body.toByteArray();
}
public String getBodyAsString() {
return getBodyAsString(DEFAULT_CHARSET);
}
public String getBodyAsString(Charset charset) {
return StreamUtils.copyToString(this.body, charset);
}
/**
* Set the HTTP method of the request.
*/
public void setMethod(HttpMethod httpMethod) {
this.httpMethod = httpMethod;
}
@@ -97,13 +86,9 @@ public class MockClientHttpRequest implements ClientHttpRequest {
return this.httpMethod;
}
@SuppressWarnings("removal")
@Override
@Deprecated
public String getMethodValue() {
return this.httpMethod.name();
}
/**
* Set the URI of the request.
*/
public void setURI(URI uri) {
this.uri = uri;
}
@@ -113,25 +98,46 @@ public class MockClientHttpRequest implements ClientHttpRequest {
return this.uri;
}
/**
* Set the {@link ClientHttpResponse} to be used as the result of executing
* the this request.
* @see #execute()
*/
public void setResponse(ClientHttpResponse clientHttpResponse) {
this.clientHttpResponse = clientHttpResponse;
}
/**
* Get the {@link #isExecuted() executed} flag.
* @see #execute()
*/
public boolean isExecuted() {
return this.executed;
}
/**
* Set the {@link #isExecuted() executed} flag to {@code true} and return the
* configured {@link #setResponse(ClientHttpResponse) response}.
* @see #executeInternal()
*/
@Override
public final ClientHttpResponse execute() throws IOException {
this.executed = true;
return executeInternal();
}
/**
* The default implementation returns the configured
* {@link #setResponse(ClientHttpResponse) response}.
* <p>Override this method to execute the request and provide a response,
* potentially different from the configured response.
*/
protected ClientHttpResponse executeInternal() throws IOException {
Assert.state(this.clientHttpResponse != null, "No ClientHttpResponse");
return this.clientHttpResponse;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();

View File

@@ -16,74 +16,89 @@
package org.springframework.web.testfixture.http.client;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.Assert;
import org.springframework.web.testfixture.http.MockHttpInputMessage;
/**
* Mock implementation of {@link ClientHttpResponse}.
*
* @author Rossen Stoyanchev
* @author Brian Clozel
* @author Sam Brannen
* @since 3.2
*/
public class MockClientHttpResponse implements ClientHttpResponse {
public class MockClientHttpResponse extends MockHttpInputMessage implements ClientHttpResponse {
private final HttpHeaders headers = new HttpHeaders();
private final HttpStatus status;
private InputStream body;
private final HttpStatusCode statusCode;
/**
* Create a {@code MockClientHttpResponse} with an empty response body and
* HTTP status code {@link HttpStatus#OK OK}.
* @since 6.0.3
*/
public MockClientHttpResponse() {
this.status = HttpStatus.OK;
this(new byte[0], HttpStatus.OK);
}
public MockClientHttpResponse(HttpStatus statusCode) {
Assert.notNull(statusCode, "HttpStatus is required");
this.status = statusCode;
/**
* Create a {@code MockClientHttpResponse} with response body as a byte array
* and the supplied HTTP status code.
*/
public MockClientHttpResponse(byte[] body, HttpStatusCode statusCode) {
super(body);
Assert.notNull(statusCode, "HttpStatusCode must not be null");
this.statusCode = statusCode;
}
/**
* Create a {@code MockClientHttpResponse} with response body as a byte array
* and a custom HTTP status code.
* @since 5.3.17
*/
public MockClientHttpResponse(byte[] body, int statusCode) {
this(body, HttpStatusCode.valueOf(statusCode));
}
/**
* Create a {@code MockClientHttpResponse} with response body as {@link InputStream}
* and the supplied HTTP status code.
*/
public MockClientHttpResponse(InputStream body, HttpStatusCode statusCode) {
super(body);
Assert.notNull(statusCode, "HttpStatusCode must not be null");
this.statusCode = statusCode;
}
/**
* Create a {@code MockClientHttpResponse} with response body as {@link InputStream}
* and a custom HTTP status code.
* @since 5.3.17
*/
public MockClientHttpResponse(InputStream body, int statusCode) {
this(body, HttpStatusCode.valueOf(statusCode));
}
@Override
public HttpStatusCode getStatusCode() {
return this.statusCode;
}
@Override
public HttpStatus getStatusCode() throws IOException {
return this.status;
@Deprecated
public int getRawStatusCode() {
return this.statusCode.value();
}
@Override
@SuppressWarnings("deprecation")
public int getRawStatusCode() throws IOException {
return this.status.value();
}
@Override
public String getStatusText() throws IOException {
return this.status.getReasonPhrase();
}
@Override
public HttpHeaders getHeaders() {
return this.headers;
}
@Override
public InputStream getBody() throws IOException {
return this.body;
}
public void setBody(byte[] body) {
Assert.notNull(body, "body is required");
this.body = new ByteArrayInputStream(body);
}
public void setBody(String body) {
Assert.notNull(body, "body is required");
this.body = new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8));
public String getStatusText() {
return (this.statusCode instanceof HttpStatus status ? status.getReasonPhrase() : "");
}
@Override