
org.mockserver.mock.Expectation Maven / Gradle / Ivy
Show all versions of mockserver-core Show documentation
package org.mockserver.mock;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.mockserver.matchers.TimeToLive;
import org.mockserver.matchers.Times;
import org.mockserver.model.*;
import org.mockserver.uuid.UUIDService;
import java.util.Comparator;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import static org.mockserver.model.OpenAPIDefinition.openAPI;
/**
* @author jamesdbloom
*/
@SuppressWarnings("rawtypes")
public class Expectation extends ObjectWithJsonToString {
private static final String[] excludedFields = {"id", "created"};
private static final AtomicInteger EXPECTATION_COUNTER = new AtomicInteger(0);
private static final long START_TIME = System.currentTimeMillis();
private int hashCode;
private String id;
@JsonIgnore
private long created;
private final Integer priority;
private final RequestDefinition httpRequest;
private final Times times;
private final TimeToLive timeToLive;
private HttpResponse httpResponse;
private HttpTemplate httpResponseTemplate;
private HttpClassCallback httpResponseClassCallback;
private HttpObjectCallback httpResponseObjectCallback;
private HttpForward httpForward;
private HttpTemplate httpForwardTemplate;
private HttpClassCallback httpForwardClassCallback;
private HttpObjectCallback httpForwardObjectCallback;
private HttpOverrideForwardedRequest httpOverrideForwardedRequest;
private HttpError httpError;
public static final Comparator EXPECTATION_PRIORITY_COMPARATOR = Comparator
.comparing(Expectation::getPriority, Comparator.nullsLast(Comparator.reverseOrder()))
.thenComparing(Expectation::getCreated, Comparator.nullsLast(Comparator.naturalOrder()));
/**
* Specify the OpenAPI and operationId to match against by URL or payload and string as follows:
*
* // Create from a publicly hosted HTTP location (json or yaml)
* when("https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v3.0/petstore-expanded.yaml", "showPetById")
*
* // Create from a file on the local filesystem (json or yaml)
* when("file://Users/myuser/git/mockserver/mockserver-core/src/test/resources/org/mockserver/mock/openapi_petstore_example.json", "showPetById");
*
* // Create from a classpath resource in the /api package (json or yaml)
* when("org/mockserver/mock/openapi_petstore_example.json", "showPetById");
*
* // Create from an OpenAPI payload (json or yaml)
* when("{\"openapi\": \"3.0.0\", \"info\": { ...", "showPetById")
*
*
* @param specUrlOrPayload the OpenAPI to match against by URL or payload
* @param operationId operationId from the OpenAPI to match against i.e. "showPetById"
* @return the Expectation
*/
public static Expectation when(String specUrlOrPayload, String operationId) {
return new Expectation(openAPI(specUrlOrPayload, operationId));
}
/**
* Specify the OpenAPI and operationId to match against by URL or payload and string with a match priority as follows:
*
* // Create from a publicly hosted HTTP location (json or yaml)
* when("https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v3.0/petstore-expanded.yaml", "showPetById", 10)
*
* // Create from a file on the local filesystem (json or yaml)
* when("file://Users/myuser/git/mockserver/mockserver-core/src/test/resources/org/mockserver/mock/openapi_petstore_example.json", "showPetById", 10);
*
* // Create from a classpath resource in the /api package (json or yaml)
* when("org/mockserver/mock/openapi_petstore_example.json", "showPetById", 10);
*
* // Create from an OpenAPI payload (json or yaml)
* when("{\"openapi\": \"3.0.0\", \"info\": { ...", "showPetById", 10)
*
*
* @param specUrlOrPayload the OpenAPI to match against by URL or payload
* @param operationId operationId from the OpenAPI to match against i.e. "showPetById"
* @param priority the priority with which this expectation is used to match requests compared to other expectations (high first)
* @return the Expectation
*/
public static Expectation when(String specUrlOrPayload, String operationId, Integer priority) {
return new Expectation(openAPI(specUrlOrPayload, operationId), Times.unlimited(), TimeToLive.unlimited(), priority);
}
/**
* Specify the OpenAPI and operationId to match against by URL or payload and string for a limit number of times or time as follows:
*
* // Create from a publicly hosted HTTP location (json or yaml)
* when("https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v3.0/petstore-expanded.yaml", "showPetById", 5, exactly(TimeUnit.SECONDS, 90))
*
* // Create from a file on the local filesystem (json or yaml)
* when("file://Users/myuser/git/mockserver/mockserver-core/src/test/resources/org/mockserver/mock/openapi_petstore_example.json", "showPetById", 5, exactly(TimeUnit.SECONDS, 90));
*
* // Create from a classpath resource in the /api package (json or yaml)
* when("org/mockserver/mock/openapi_petstore_example.json", "showPetById", 5, exactly(TimeUnit.SECONDS, 90));
*
* // Create from an OpenAPI payload (json or yaml)
* when("{\"openapi\": \"3.0.0\", \"info\": { ...", "showPetById", 5, exactly(TimeUnit.SECONDS, 90))
*
*
* @param specUrlOrPayload the OpenAPI to match against by URL or payload
* @param operationId operationId from the OpenAPI to match against i.e. "showPetById"
* @param times the number of times to use this expectation to match requests
* @param timeToLive the time this expectation should be used to match requests
* @return the Expectation
*/
public static Expectation when(String specUrlOrPayload, String operationId, Times times, TimeToLive timeToLive) {
return new Expectation(openAPI(specUrlOrPayload, operationId), times, timeToLive, 0);
}
/**
* Specify the OpenAPI and operationId to match against by URL or payload and string for a limit number of times or time and a match priority as follows:
*
* // Create from a publicly hosted HTTP location (json or yaml)
* when("https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v3.0/petstore-expanded.yaml", "showPetById", 5, exactly(TimeUnit.SECONDS, 90))
*
* // Create from a file on the local filesystem (json or yaml)
* when("file://Users/myuser/git/mockserver/mockserver-core/src/test/resources/org/mockserver/mock/openapi_petstore_example.json", "showPetById", 5, exactly(TimeUnit.SECONDS, 90));
*
* // Create from a classpath resource in the /api package (json or yaml)
* when("org/mockserver/mock/openapi_petstore_example.json", "showPetById", 5, exactly(TimeUnit.SECONDS, 90));
*
* // Create from an OpenAPI payload (json or yaml)
* when("{\"openapi\": \"3.0.0\", \"info\": { ...", "showPetById", 5, exactly(TimeUnit.SECONDS, 90))
*
*
* @param specUrlOrPayload the OpenAPI to match against by URL or payload
* @param operationId operationId from the OpenAPI to match against i.e. "showPetById"
* @param times the number of times to use this expectation to match requests
* @param timeToLive the time this expectation should be used to match requests
* @param priority the priority with which this expectation is used to match requests compared to other expectations (high first)
* @return the Expectation
*/
public static Expectation when(String specUrlOrPayload, String operationId, Times times, TimeToLive timeToLive, Integer priority) {
return new Expectation(openAPI(specUrlOrPayload, operationId), times, timeToLive, priority);
}
/**
* Specify the HttpRequest to match against as follows:
*
* when(
* request()
* .withMethod("GET")
* .withPath("/some/path")
* ).thenRespond(
* response()
* .withContentType(APPLICATION_JSON_UTF_8)
* .withBody("{\"some\": \"body\"}")
* );
*
*
* @param httpRequest the HttpRequest to match against
* @return the Expectation
*/
public static Expectation when(HttpRequest httpRequest) {
return new Expectation(httpRequest);
}
/**
* Specify the HttpRequest to match against with a match priority as follows:
*
* when(
* request()
* .withMethod("GET")
* .withPath("/some/path"),
* 10
* ).thenRespond(
* response()
* .withContentType(APPLICATION_JSON_UTF_8)
* .withBody("{\"some\": \"body\"}")
* );
*
*
* @param httpRequest the HttpRequest to match against
* @param priority the priority with which this expectation is used to match requests compared to other expectations (high first)
* @return the Expectation
*/
public static Expectation when(HttpRequest httpRequest, Integer priority) {
return new Expectation(httpRequest, Times.unlimited(), TimeToLive.unlimited(), priority);
}
/**
* Specify the HttpRequest to match against for a limit number of times or time as follows:
*
* when(
* request()
* .withMethod("GET")
* .withPath("/some/path"),
* 5,
* exactly(TimeUnit.SECONDS, 90)
* ).thenRespond(
* response()
* .withContentType(APPLICATION_JSON_UTF_8)
* .withBody("{\"some\": \"body\"}")
* );
*
*
* @param httpRequest the HttpRequest to match against
* @param times the number of times to use this expectation to match requests
* @param timeToLive the time this expectation should be used to match requests
* @return the Expectation
*/
public static Expectation when(HttpRequest httpRequest, Times times, TimeToLive timeToLive) {
return new Expectation(httpRequest, times, timeToLive, 0);
}
/**
* Specify the HttpRequest to match against for a limit number of times or time and a match priority as follows:
*
* when(
* request()
* .withMethod("GET")
* .withPath("/some/path"),
* 5,
* exactly(TimeUnit.SECONDS, 90),
* 10
* ).thenRespond(
* response()
* .withContentType(APPLICATION_JSON_UTF_8)
* .withBody("{\"some\": \"body\"}")
* );
*
*
* @param httpRequest the HttpRequest to match against
* @param times the number of times to use this expectation to match requests
* @param timeToLive the time this expectation should be used to match requests
* @param priority the priority with which this expectation is used to match requests compared to other expectations (high first)
* @return the Expectation
*/
public static Expectation when(HttpRequest httpRequest, Times times, TimeToLive timeToLive, Integer priority) {
return new Expectation(httpRequest, times, timeToLive, priority);
}
public Expectation(RequestDefinition requestDefinition) {
this(requestDefinition, Times.unlimited(), TimeToLive.unlimited(), 0);
}
public Expectation(RequestDefinition requestDefinition, Times times, TimeToLive timeToLive, Integer priority) {
// ensure created enforces insertion order by relying on system time, and a counter
EXPECTATION_COUNTER.compareAndSet(Integer.MAX_VALUE, 0);
this.created = System.currentTimeMillis() - START_TIME + EXPECTATION_COUNTER.incrementAndGet();
this.httpRequest = requestDefinition;
this.times = times;
this.timeToLive = timeToLive;
this.priority = priority;
}
public Expectation withId(String key) {
this.id = key;
return this;
}
public String getId() {
if (id == null) {
withId(UUIDService.getUUID());
}
return id;
}
public Integer getPriority() {
return priority;
}
public Expectation withCreated(long created) {
this.created = created;
return this;
}
public long getCreated() {
return created;
}
public RequestDefinition getHttpRequest() {
return httpRequest;
}
public HttpResponse getHttpResponse() {
return httpResponse;
}
public HttpTemplate getHttpResponseTemplate() {
return httpResponseTemplate;
}
public HttpClassCallback getHttpResponseClassCallback() {
return httpResponseClassCallback;
}
public HttpObjectCallback getHttpResponseObjectCallback() {
return httpResponseObjectCallback;
}
public HttpForward getHttpForward() {
return httpForward;
}
public HttpTemplate getHttpForwardTemplate() {
return httpForwardTemplate;
}
public HttpClassCallback getHttpForwardClassCallback() {
return httpForwardClassCallback;
}
public HttpObjectCallback getHttpForwardObjectCallback() {
return httpForwardObjectCallback;
}
public HttpOverrideForwardedRequest getHttpOverrideForwardedRequest() {
return httpOverrideForwardedRequest;
}
public HttpError getHttpError() {
return httpError;
}
@JsonIgnore
public Action getAction() {
if (httpResponse != null) {
return getHttpResponse();
} else if (httpResponseTemplate != null) {
return getHttpResponseTemplate();
} else if (httpResponseClassCallback != null) {
return getHttpResponseClassCallback();
} else if (httpResponseObjectCallback != null) {
return getHttpResponseObjectCallback();
} else if (httpForward != null) {
return getHttpForward();
} else if (httpForwardTemplate != null) {
return getHttpForwardTemplate();
} else if (httpForwardClassCallback != null) {
return getHttpForwardClassCallback();
} else if (httpForwardObjectCallback != null) {
return getHttpForwardObjectCallback();
} else if (httpOverrideForwardedRequest != null) {
return getHttpOverrideForwardedRequest();
} else if (httpError != null) {
return getHttpError();
} else {
return null;
}
}
public Times getTimes() {
return times;
}
public TimeToLive getTimeToLive() {
return timeToLive;
}
public Expectation thenRespond(HttpResponse httpResponse) {
if (httpResponse != null) {
validationErrors("a response", httpResponse.getType());
this.httpResponse = httpResponse;
this.hashCode = 0;
}
return this;
}
public Expectation thenRespond(HttpTemplate httpTemplate) {
if (httpTemplate != null) {
httpTemplate.withActionType(Action.Type.RESPONSE_TEMPLATE);
validationErrors("a response template", httpTemplate.getType());
this.httpResponseTemplate = httpTemplate;
this.hashCode = 0;
}
return this;
}
public Expectation thenRespond(HttpClassCallback httpClassCallback) {
if (httpClassCallback != null) {
httpClassCallback.withActionType(Action.Type.RESPONSE_CLASS_CALLBACK);
validationErrors("a response class callback", httpClassCallback.getType());
this.httpResponseClassCallback = httpClassCallback;
this.hashCode = 0;
}
return this;
}
public Expectation thenRespond(HttpObjectCallback httpObjectCallback) {
if (httpObjectCallback != null) {
httpObjectCallback.withActionType(Action.Type.RESPONSE_OBJECT_CALLBACK);
validationErrors("a response object callback", httpObjectCallback.getType());
this.httpResponseObjectCallback = httpObjectCallback;
this.hashCode = 0;
}
return this;
}
public Expectation thenForward(HttpForward httpForward) {
if (httpForward != null) {
validationErrors("a forward", httpForward.getType());
this.httpForward = httpForward;
this.hashCode = 0;
}
return this;
}
public Expectation thenForward(HttpTemplate httpTemplate) {
if (httpTemplate != null) {
httpTemplate.withActionType(Action.Type.FORWARD_TEMPLATE);
validationErrors("a forward template", httpTemplate.getType());
this.httpForwardTemplate = httpTemplate;
this.hashCode = 0;
}
return this;
}
public Expectation thenForward(HttpClassCallback httpClassCallback) {
if (httpClassCallback != null) {
httpClassCallback.withActionType(Action.Type.FORWARD_CLASS_CALLBACK);
validationErrors("a forward class callback", httpClassCallback.getType());
this.httpForwardClassCallback = httpClassCallback;
this.hashCode = 0;
}
return this;
}
public Expectation thenForward(HttpObjectCallback httpObjectCallback) {
if (httpObjectCallback != null) {
httpObjectCallback
.withActionType(Action.Type.FORWARD_OBJECT_CALLBACK);
validationErrors("a forward object callback", httpObjectCallback.getType());
this.httpForwardObjectCallback = httpObjectCallback;
this.hashCode = 0;
}
return this;
}
public Expectation thenForward(HttpOverrideForwardedRequest httpOverrideForwardedRequest) {
if (httpOverrideForwardedRequest != null) {
validationErrors("a forward replace", httpOverrideForwardedRequest.getType());
this.httpOverrideForwardedRequest = httpOverrideForwardedRequest;
this.hashCode = 0;
}
return this;
}
public Expectation thenError(HttpError httpError) {
if (httpError != null) {
validationErrors("an error", httpError.getType());
this.httpError = httpError;
this.hashCode = 0;
}
return this;
}
private void validationErrors(String actionDescription, Action.Type actionType) {
if (actionType != Action.Type.RESPONSE && httpResponse != null) {
throw new IllegalArgumentException("It is not possible to set " + actionDescription + " once a response has been set");
}
if (actionType != Action.Type.RESPONSE_TEMPLATE && httpResponseTemplate != null) {
throw new IllegalArgumentException("It is not possible to set " + actionDescription + " once a response template has been set");
}
if (actionType != Action.Type.RESPONSE_CLASS_CALLBACK && httpResponseClassCallback != null) {
throw new IllegalArgumentException("It is not possible to set " + actionDescription + " once a class callback has been set");
}
if (actionType != Action.Type.RESPONSE_OBJECT_CALLBACK && httpResponseObjectCallback != null) {
throw new IllegalArgumentException("It is not possible to set " + actionDescription + " once an object callback has been set");
}
if (actionType != Action.Type.FORWARD && httpForward != null) {
throw new IllegalArgumentException("It is not possible to set " + actionDescription + " once a forward has been set");
}
if (actionType != Action.Type.FORWARD_TEMPLATE && httpForwardTemplate != null) {
throw new IllegalArgumentException("It is not possible to set " + actionDescription + " once a forward template has been set");
}
if (actionType != Action.Type.FORWARD_CLASS_CALLBACK && httpForwardClassCallback != null) {
throw new IllegalArgumentException("It is not possible to set " + actionDescription + " once a class callback has been set");
}
if (actionType != Action.Type.FORWARD_OBJECT_CALLBACK && httpForwardObjectCallback != null) {
throw new IllegalArgumentException("It is not possible to set " + actionDescription + " once an object callback has been set");
}
if (actionType != Action.Type.FORWARD_REPLACE && httpOverrideForwardedRequest != null) {
throw new IllegalArgumentException("It is not possible to set " + actionDescription + " once a forward replace has been set");
}
if (actionType != Action.Type.ERROR && httpError != null) {
throw new IllegalArgumentException("It is not possible to set " + actionDescription + " callback once an error has been set");
}
}
@JsonIgnore
public boolean isActive() {
return hasRemainingMatches() && isStillAlive();
}
private boolean hasRemainingMatches() {
return times == null || times.greaterThenZero();
}
private boolean isStillAlive() {
return timeToLive == null || timeToLive.stillAlive();
}
public boolean decrementRemainingMatches() {
if (times != null) {
return times.decrement();
}
return false;
}
@SuppressWarnings("PointlessNullCheck")
public boolean contains(HttpRequest httpRequest) {
return httpRequest != null && this.httpRequest.equals(httpRequest);
}
@SuppressWarnings("MethodDoesntCallSuperMethod")
public Expectation clone() {
return new Expectation(httpRequest, times.clone(), timeToLive, priority)
.withId(id)
.withCreated(created)
.thenRespond(httpResponse)
.thenRespond(httpResponseTemplate)
.thenRespond(httpResponseClassCallback)
.thenRespond(httpResponseObjectCallback)
.thenForward(httpForward)
.thenForward(httpForwardTemplate)
.thenForward(httpForwardClassCallback)
.thenForward(httpForwardObjectCallback)
.thenForward(httpOverrideForwardedRequest)
.thenError(httpError);
}
@Override
@JsonIgnore
public String[] fieldsExcludedFromEqualsAndHashCode() {
return excludedFields;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (hashCode() != o.hashCode()) {
return false;
}
Expectation that = (Expectation) o;
boolean equals = Objects.equals(httpResponse, that.httpResponse);
boolean equals1 = Objects.equals(httpRequest, that.httpRequest);
return Objects.equals(priority, that.priority) &&
equals1 &&
Objects.equals(times, that.times) &&
Objects.equals(timeToLive, that.timeToLive) &&
equals &&
Objects.equals(httpResponseTemplate, that.httpResponseTemplate) &&
Objects.equals(httpResponseClassCallback, that.httpResponseClassCallback) &&
Objects.equals(httpResponseObjectCallback, that.httpResponseObjectCallback) &&
Objects.equals(httpForward, that.httpForward) &&
Objects.equals(httpForwardTemplate, that.httpForwardTemplate) &&
Objects.equals(httpForwardClassCallback, that.httpForwardClassCallback) &&
Objects.equals(httpForwardObjectCallback, that.httpForwardObjectCallback) &&
Objects.equals(httpOverrideForwardedRequest, that.httpOverrideForwardedRequest) &&
Objects.equals(httpError, that.httpError);
}
@Override
public int hashCode() {
if (hashCode == 0) {
hashCode = Objects.hash(priority, httpRequest, times, timeToLive, httpResponse, httpResponseTemplate, httpResponseClassCallback, httpResponseObjectCallback, httpForward, httpForwardTemplate, httpForwardClassCallback, httpForwardObjectCallback, httpOverrideForwardedRequest, httpError);
}
return hashCode;
}
}