Allow plugging in custom RequestExpectationManager
The MockRestServiceServer builder now has an option to plug in a custom RequestExpectationManager. Issue: SPR-11365
This commit is contained in:
@@ -24,11 +24,11 @@ import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Base class for {@code RequestExpectationManager} implementations.
|
||||
* Creates and contains expectations and stores actual requests.
|
||||
* Base class for {@code RequestExpectationManager} implementations responsible
|
||||
* for storing expectations and requests.
|
||||
*
|
||||
* <p>Sub-classes are responsible for matching actual to expected requests and
|
||||
* for verifying remaining expectations at the end.
|
||||
* <p>Sub-classes are responsible for matching requests to expectations and
|
||||
* verifying there are no remaining expectations at the end.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.3
|
||||
@@ -40,30 +40,26 @@ public abstract class AbstractRequestExpectationManager implements RequestExpect
|
||||
private final List<ClientHttpRequest> requests = new LinkedList<ClientHttpRequest>();
|
||||
|
||||
|
||||
public AbstractRequestExpectationManager() {
|
||||
}
|
||||
|
||||
public AbstractRequestExpectationManager(List<RequestExpectation> expectations) {
|
||||
this.expectations.addAll(expectations);
|
||||
}
|
||||
|
||||
|
||||
public List<RequestExpectation> getExpectations() {
|
||||
protected List<RequestExpectation> getExpectations() {
|
||||
return this.expectations;
|
||||
}
|
||||
|
||||
public List<ClientHttpRequest> getRequests() {
|
||||
protected List<ClientHttpRequest> getRequests() {
|
||||
return this.requests;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseActions expectRequest(RequestMatcher requestMatcher) {
|
||||
Assert.state(getRequests().isEmpty(), "Cannot add more expectations after actual requests are made.");
|
||||
DefaultResponseActions expectation = new DefaultResponseActions(requestMatcher);
|
||||
RequestExpectation expectation = createExpectation(requestMatcher);
|
||||
getExpectations().add(expectation);
|
||||
return expectation;
|
||||
}
|
||||
|
||||
protected RequestExpectation createExpectation(RequestMatcher requestMatcher) {
|
||||
return new DefaultRequestExpectation(requestMatcher);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientHttpResponse validateRequest(ClientHttpRequest request) throws IOException {
|
||||
ClientHttpResponse response = validateRequestInternal(request);
|
||||
|
||||
@@ -25,21 +25,20 @@ import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Default implementation of {@code ResponseActions} that is also a composite
|
||||
* {@code RequestMatcher}, invoking all request matchers it contains, as well as
|
||||
* a {@code ResponseCreator} delegating to the response creator it contains.
|
||||
* Default implementation of {@code RequestExpectation} that simply delegates
|
||||
* to the request matchers and the response creator it contains.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.3
|
||||
*/
|
||||
class DefaultResponseActions implements ResponseActions, RequestExpectation {
|
||||
public class DefaultRequestExpectation implements RequestExpectation {
|
||||
|
||||
private final List<RequestMatcher> requestMatchers = new LinkedList<RequestMatcher>();
|
||||
|
||||
private ResponseCreator responseCreator;
|
||||
|
||||
|
||||
public DefaultResponseActions(RequestMatcher requestMatcher) {
|
||||
public DefaultRequestExpectation(RequestMatcher requestMatcher) {
|
||||
Assert.notNull(requestMatcher, "RequestMatcher is required");
|
||||
this.requestMatchers.add(requestMatcher);
|
||||
}
|
||||
@@ -200,10 +200,19 @@ public class MockRestServiceServer {
|
||||
public interface MockRestServiceServerBuilder {
|
||||
|
||||
/**
|
||||
* When this option is set, requests can be executed in any order, i.e.
|
||||
* not matching the order in which expected requests are declared.
|
||||
* Allow expected requests to be executed in any order not necessarily
|
||||
* matching the order of declaration. This is a shortcut for:<br>
|
||||
* {@code builder.expectationManager(new UnorderedRequestExpectationManager)}
|
||||
*/
|
||||
MockRestServiceServerBuilder ignoreExpectOrder();
|
||||
MockRestServiceServerBuilder unordered();
|
||||
|
||||
/**
|
||||
* Configure a custom {@code RequestExpectationManager}.
|
||||
* <p>By default {@link SimpleRequestExpectationManager} is used. It is
|
||||
* also possible to switch to {@link UnorderedRequestExpectationManager}
|
||||
* by setting {@link #unordered()}.
|
||||
*/
|
||||
MockRestServiceServerBuilder expectationManager(RequestExpectationManager manager);
|
||||
|
||||
/**
|
||||
* Build the {@code MockRestServiceServer} and setting up the underlying
|
||||
@@ -220,7 +229,7 @@ public class MockRestServiceServer {
|
||||
|
||||
private final AsyncRestTemplate asyncRestTemplate;
|
||||
|
||||
private boolean ignoreExpectOrder;
|
||||
private RequestExpectationManager expectationManager = new SimpleRequestExpectationManager();
|
||||
|
||||
|
||||
public DefaultBuilder(RestTemplate restTemplate) {
|
||||
@@ -237,19 +246,21 @@ public class MockRestServiceServer {
|
||||
|
||||
|
||||
@Override
|
||||
public MockRestServiceServerBuilder ignoreExpectOrder() {
|
||||
this.ignoreExpectOrder = true;
|
||||
public MockRestServiceServerBuilder unordered() {
|
||||
expectationManager(new UnorderedRequestExpectationManager());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MockRestServiceServerBuilder expectationManager(RequestExpectationManager manager) {
|
||||
Assert.notNull(manager, "'manager' is required.");
|
||||
this.expectationManager = manager;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MockRestServiceServer build() {
|
||||
|
||||
MockRestServiceServer server = (this.ignoreExpectOrder ?
|
||||
new MockRestServiceServer(new UnorderedRequestExpectationManager()) :
|
||||
new MockRestServiceServer());
|
||||
|
||||
MockRestServiceServer server = new MockRestServiceServer(this.expectationManager);
|
||||
MockClientHttpRequestFactory factory = server.new MockClientHttpRequestFactory();
|
||||
if (this.restTemplate != null) {
|
||||
this.restTemplate.setRequestFactory(factory);
|
||||
@@ -257,7 +268,6 @@ public class MockRestServiceServer {
|
||||
if (this.asyncRestTemplate != null) {
|
||||
this.asyncRestTemplate.setAsyncRequestFactory(factory);
|
||||
}
|
||||
|
||||
return server;
|
||||
}
|
||||
}
|
||||
@@ -265,7 +275,7 @@ public class MockRestServiceServer {
|
||||
|
||||
/**
|
||||
* Mock ClientHttpRequestFactory that creates requests by iterating
|
||||
* over the list of expected {@link DefaultResponseActions}'s.
|
||||
* over the list of expected {@link DefaultRequestExpectation}'s.
|
||||
*/
|
||||
private class MockClientHttpRequestFactory implements ClientHttpRequestFactory, AsyncClientHttpRequestFactory {
|
||||
|
||||
|
||||
@@ -16,12 +16,16 @@
|
||||
package org.springframework.test.web.client;
|
||||
|
||||
/**
|
||||
* A contract that combines {@code RequestMatcher} with {@code ResponseCreator}
|
||||
* to define an expected request and a response to use for it.
|
||||
* An extension of {@code ResponseActions} that also implements
|
||||
* {@code RequestMatcher} and {@code ResponseCreator}
|
||||
*
|
||||
* <p>{@code ResponseActions} is the API for defining expectations while
|
||||
* {@code RequestExpectation} is the internal SPI to match those expectations
|
||||
* to actual requests and to create responses.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.3
|
||||
*/
|
||||
public interface RequestExpectation extends RequestMatcher, ResponseCreator {
|
||||
public interface RequestExpectation extends ResponseActions, RequestMatcher, ResponseCreator {
|
||||
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ import org.springframework.http.client.ClientHttpRequest;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
|
||||
/**
|
||||
* {@code RequestExpectationManager} that expects requests to follow the order
|
||||
* in which expected requests were declared.
|
||||
* Simple {@code RequestExpectationManager} that matches requests to expectations
|
||||
* sequentially, i.e. in the order of declaration of expectations.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.3
|
||||
@@ -43,7 +43,8 @@ public class SimpleRequestExpectationManager extends AbstractRequestExpectationM
|
||||
if (!this.iterator.hasNext()) {
|
||||
HttpMethod method = request.getMethod();
|
||||
URI uri = request.getURI();
|
||||
throw new AssertionError("No further requests expected: HTTP " + method + " " + uri);
|
||||
String firstLine = "No further requests expected: HTTP " + method + " " + uri + "\n";
|
||||
throw new AssertionError(createErrorMessage(firstLine));
|
||||
}
|
||||
RequestExpectation expectation = this.iterator.next();
|
||||
expectation.match(request);
|
||||
@@ -55,11 +56,11 @@ public class SimpleRequestExpectationManager extends AbstractRequestExpectationM
|
||||
if (getExpectations().isEmpty() || getExpectations().size() == getRequests().size()) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError(getVerifyMessage());
|
||||
throw new AssertionError(createErrorMessage("Further request(s) expected\n"));
|
||||
}
|
||||
|
||||
private String getVerifyMessage() {
|
||||
StringBuilder sb = new StringBuilder("Further request(s) expected\n");
|
||||
private String createErrorMessage(String firstLine) {
|
||||
StringBuilder sb = new StringBuilder(firstLine);
|
||||
if (getRequests().size() > 0) {
|
||||
sb.append("The following ");
|
||||
}
|
||||
|
||||
@@ -25,9 +25,8 @@ import org.springframework.http.client.ClientHttpRequest;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
|
||||
/**
|
||||
* {@code RequestExpectationManager} that tries to match actual requests to
|
||||
* expected requests regardless of the order in which expected requests were
|
||||
* declared.
|
||||
* {@code RequestExpectationManager} that matches requests to expectations
|
||||
* regardless of the order of declaration of expectations.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.3
|
||||
@@ -37,23 +36,20 @@ public class UnorderedRequestExpectationManager extends AbstractRequestExpectati
|
||||
private final List<RequestExpectation> remainingExpectations = new LinkedList<RequestExpectation>();
|
||||
|
||||
|
||||
public UnorderedRequestExpectationManager() {
|
||||
}
|
||||
|
||||
public UnorderedRequestExpectationManager(List<RequestExpectation> expectations) {
|
||||
super(expectations);
|
||||
protected List<RequestExpectation> getRemainingExpectations() {
|
||||
return this.remainingExpectations;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ClientHttpResponse validateRequestInternal(ClientHttpRequest request) throws IOException {
|
||||
if (getRequests().isEmpty()) {
|
||||
this.remainingExpectations.addAll(getExpectations());
|
||||
getRemainingExpectations().addAll(getExpectations());
|
||||
}
|
||||
for (RequestExpectation expectation : getExpectations()) {
|
||||
try {
|
||||
expectation.match(request);
|
||||
this.remainingExpectations.remove(expectation);
|
||||
getRemainingExpectations().remove(expectation);
|
||||
return expectation.createResponse(request);
|
||||
}
|
||||
catch (AssertionError error) {
|
||||
|
||||
Reference in New Issue
Block a user