Rewriting to java (#1131)
* Rewritting to java - rewritten a lot of Spring Cloud Contract Spec module to Java - extracted all Groovy stuff to a separate package - will now continue writing extension modules - spring-cloud-contract-spec will be written purely in java - spring-cloud-contract-spec-groovy will have Groovy extensions fixes gh-1130
This commit is contained in:
committed by
GitHub
parent
1e11e99dac
commit
6b9e377487
@@ -0,0 +1,372 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import groovy.lang.Closure;
|
||||
import groovy.lang.DelegatesTo;
|
||||
|
||||
import org.springframework.cloud.contract.spec.internal.Input;
|
||||
import org.springframework.cloud.contract.spec.internal.OutputMessage;
|
||||
import org.springframework.cloud.contract.spec.internal.Request;
|
||||
import org.springframework.cloud.contract.spec.internal.Response;
|
||||
|
||||
/**
|
||||
* The definition of a Contract. Contains helper methods in Groovy left for backward
|
||||
* compatibility reasons.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class Contract {
|
||||
|
||||
/**
|
||||
* You can set the level of priority of this contract. If there are two contracts
|
||||
* mapped for example to the same endpoint, then the one with greater priority should
|
||||
* take precedence. A priority of 1 is highest and takes precedence over a priority of
|
||||
* 2.
|
||||
*/
|
||||
private Integer priority;
|
||||
|
||||
/**
|
||||
* The HTTP request part of the contract.
|
||||
*/
|
||||
private Request request;
|
||||
|
||||
/**
|
||||
* The HTTP response part of the contract.
|
||||
*/
|
||||
private Response response;
|
||||
|
||||
/**
|
||||
* The label by which you'll reference the contract on the message consumer side.
|
||||
*/
|
||||
private String label;
|
||||
|
||||
/**
|
||||
* Description of a contract. May be used in the documentation generation.
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* Name of the generated test / stub. If not provided then the file name will be used.
|
||||
* If you have multiple contracts in a single file and you don't provide this value
|
||||
* then a prefix will be added to the file with the index number while iterating over
|
||||
* the collection of contracts.
|
||||
*
|
||||
* Remember to have a unique name for every single contract. Otherwise you might
|
||||
* generate tests that have two identical methods or you will override the stubs.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* The input side of a messaging contract.
|
||||
*/
|
||||
private Input input;
|
||||
|
||||
/**
|
||||
* The output side of a messaging contract.
|
||||
*/
|
||||
private OutputMessage outputMessage;
|
||||
|
||||
/**
|
||||
* Whether the contract should be ignored or not.
|
||||
*/
|
||||
private boolean ignored;
|
||||
|
||||
public Contract() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* You can set the level of priority of this contract. If there are two contracts
|
||||
* mapped for example to the same endpoint, then the one with greater priority should
|
||||
* take precedence. A priority of 1 is highest and takes precedence over a priority of
|
||||
* 2.
|
||||
* @param priority the higher the value the lower the priority
|
||||
*/
|
||||
public void priority(int priority) {
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the generated test / stub. If not provided then the file name will be used.
|
||||
* If you have multiple contracts in a single file and you don't provide this value
|
||||
* then a prefix will be added to the file with the index number while iterating over
|
||||
* the collection of contracts.
|
||||
*
|
||||
* Remember to have a unique name for every single contract. Otherwise you might
|
||||
* generate tests that have two identical methods or you will override the stubs.
|
||||
* @param name name of the contract
|
||||
*/
|
||||
public void name(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Label used by the messaging contracts to trigger a message on the consumer side.
|
||||
* @param label - name of the label of a messaging contract to trigger
|
||||
*/
|
||||
public void label(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Description text. Might be used to describe the usage scenario.
|
||||
* @param description - value of the description
|
||||
*/
|
||||
public void description(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public static void assertContract(Contract dsl) {
|
||||
if (dsl.getRequest() != null) {
|
||||
if (dsl.request.getUrl() == null && dsl.request.getUrlPath() == null) {
|
||||
throw new IllegalStateException(
|
||||
"URL is missing for HTTP contract(exclude = { TraceWebClientAutoConfiguration.class })");
|
||||
}
|
||||
if (dsl.request.getMethod() == null) {
|
||||
throw new IllegalStateException("Method is missing for HTTP contract");
|
||||
}
|
||||
}
|
||||
if (dsl.response != null) {
|
||||
if (dsl.response.getStatus() == null) {
|
||||
throw new IllegalStateException("Status is missing for HTTP contract");
|
||||
}
|
||||
}
|
||||
// Can't assert messaging part cause Pact doesn't require destinations it seems
|
||||
}
|
||||
|
||||
/**
|
||||
* Point of entry to build a contract.
|
||||
* @param consumer function to manipulate the contract
|
||||
* @return manipulated contract
|
||||
*/
|
||||
public static Contract make(Consumer<Contract> consumer) {
|
||||
Contract contract = new Contract();
|
||||
consumer.accept(contract);
|
||||
return contract;
|
||||
}
|
||||
|
||||
/**
|
||||
* Groovy point of entry to build a contract. Left for backward compatibility reasons.
|
||||
* @param closure function to manipulate the contract
|
||||
* @return manipulated contract
|
||||
*/
|
||||
public static Contract make(@DelegatesTo(Contract.class) Closure closure) {
|
||||
Contract dsl = new Contract();
|
||||
closure.setDelegate(dsl);
|
||||
closure.call();
|
||||
Contract.assertContract(dsl);
|
||||
return dsl;
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP request part of the contract.
|
||||
* @param consumer function to manipulate the request
|
||||
*/
|
||||
public void request(Consumer<Request> consumer) {
|
||||
this.request = new Request();
|
||||
consumer.accept(this.request);
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP response part of the contract.
|
||||
* @param consumer function to manipulate the response
|
||||
*/
|
||||
public void response(Consumer<Response> consumer) {
|
||||
this.response = new Response();
|
||||
consumer.accept(this.response);
|
||||
}
|
||||
|
||||
/**
|
||||
* The input part of the contract.
|
||||
* @param consumer function to manipulate the input
|
||||
*/
|
||||
public void input(Consumer<Input> consumer) {
|
||||
this.input = new Input();
|
||||
consumer.accept(this.input);
|
||||
}
|
||||
|
||||
/**
|
||||
* The output part of the contract.
|
||||
* @param consumer function to manipulate the output message
|
||||
*/
|
||||
public void outputMessage(Consumer<OutputMessage> consumer) {
|
||||
this.outputMessage = new OutputMessage();
|
||||
consumer.accept(this.outputMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP request part of the contract.
|
||||
* @param consumer function to manipulate the request
|
||||
*/
|
||||
public void request(@DelegatesTo(Request.class) Closure consumer) {
|
||||
this.request = new Request();
|
||||
consumer.setDelegate(this.request);
|
||||
consumer.call();
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP response part of the contract.
|
||||
* @param consumer function to manipulate the response
|
||||
*/
|
||||
public void response(@DelegatesTo(Response.class) Closure consumer) {
|
||||
this.response = new Response();
|
||||
consumer.setDelegate(this.response);
|
||||
consumer.call();
|
||||
}
|
||||
|
||||
/**
|
||||
* The input part of the contract.
|
||||
* @param consumer function to manipulate the input
|
||||
*/
|
||||
public void input(@DelegatesTo(Input.class) Closure consumer) {
|
||||
this.input = new Input();
|
||||
consumer.setDelegate(this.input);
|
||||
consumer.call();
|
||||
}
|
||||
|
||||
/**
|
||||
* The output part of the contract.
|
||||
* @param consumer function to manipulate the output message
|
||||
*/
|
||||
public void outputMessage(@DelegatesTo(OutputMessage.class) Closure consumer) {
|
||||
this.outputMessage = new OutputMessage();
|
||||
consumer.setDelegate(this.outputMessage);
|
||||
consumer.call();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the contract should be ignored or not.
|
||||
*/
|
||||
public void ignored() {
|
||||
this.ignored = true;
|
||||
}
|
||||
|
||||
public Integer getPriority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
public void setPriority(Integer priority) {
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
public Request getRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
public void setRequest(Request request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
public Response getResponse() {
|
||||
return response;
|
||||
}
|
||||
|
||||
public void setResponse(Response response) {
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public void setLabel(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Input getInput() {
|
||||
return input;
|
||||
}
|
||||
|
||||
public void setInput(Input input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
public OutputMessage getOutputMessage() {
|
||||
return outputMessage;
|
||||
}
|
||||
|
||||
public void setOutputMessage(OutputMessage outputMessage) {
|
||||
this.outputMessage = outputMessage;
|
||||
}
|
||||
|
||||
public boolean getIgnored() {
|
||||
return ignored;
|
||||
}
|
||||
|
||||
public boolean isIgnored() {
|
||||
return ignored;
|
||||
}
|
||||
|
||||
public void setIgnored(boolean ignored) {
|
||||
this.ignored = ignored;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Contract contract = (Contract) o;
|
||||
return ignored == contract.ignored && Objects.equals(priority, contract.priority)
|
||||
&& Objects.equals(request, contract.request)
|
||||
&& Objects.equals(response, contract.response)
|
||||
&& Objects.equals(label, contract.label)
|
||||
&& Objects.equals(description, contract.description)
|
||||
&& Objects.equals(name, contract.name)
|
||||
&& Objects.equals(input, contract.input)
|
||||
&& Objects.equals(outputMessage, contract.outputMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(priority, request, response, label, description, name, input,
|
||||
outputMessage, ignored);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Contract{" + "\npriority=" + priority + ", \n\trequest=" + request
|
||||
+ ", \n\tresponse=" + response + ", \n\tlabel='" + label + '\''
|
||||
+ ", \n\tdescription='" + description + '\'' + ", \n\tname='" + name
|
||||
+ '\'' + ", \n\tinput=" + input + ", \n\toutputMessage=" + outputMessage
|
||||
+ ", \n\tignored=" + ignored + '}';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Converter to be used to convert FROM {@link File} TO {@link Contract} and from
|
||||
* {@link Contract} to {@code T}.
|
||||
*
|
||||
* @param <T> - type to which we want to convert the contract
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public interface ContractConverter<T> extends ContractStorer<T> {
|
||||
|
||||
/**
|
||||
* Should this file be accepted by the converter. Can use the file extension to check
|
||||
* if the conversion is possible.
|
||||
* @param file - file to be considered for conversion
|
||||
* @return - {@code true} if the given implementation can convert the file
|
||||
*/
|
||||
boolean isAccepted(File file);
|
||||
|
||||
/**
|
||||
* Converts the given {@link File} to its {@link Contract} representation.
|
||||
* @param file - file to convert
|
||||
* @return - {@link Contract} representation of the file
|
||||
*/
|
||||
Collection<Contract> convertFrom(File file);
|
||||
|
||||
/**
|
||||
* Converts the given {@link Contract} to a {@link T} representation.
|
||||
* @param contract - the parsed contract
|
||||
* @return - {@link T} the type to which we do the conversion
|
||||
*/
|
||||
T convertTo(Collection<Contract> contract);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Defines how to store converted contracts to a byte array representation that can be
|
||||
* stored to drive.
|
||||
*
|
||||
* @param <T> contracts type
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 2.1.0
|
||||
*/
|
||||
public interface ContractStorer<T> {
|
||||
|
||||
/**
|
||||
* Stores the contracts as a map of filename and String.
|
||||
* @param contracts - to convert
|
||||
* @return mapping of filename to converted byte array representation of the contract
|
||||
*/
|
||||
default Map<String, byte[]> store(T contracts) {
|
||||
Map<String, byte[]> map = new HashMap<>();
|
||||
map.put(String.valueOf(Math.abs(hashCode())), contracts.toString().getBytes());
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec;
|
||||
|
||||
/**
|
||||
* Contract for defining templated responses.
|
||||
* <p>
|
||||
* If no implementation is provided then Handlebars will be picked as a default
|
||||
* implementation.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public interface ContractTemplate {
|
||||
|
||||
/**
|
||||
* @param text text to assert
|
||||
* @return asserts whether the given text starts with proper opening template.
|
||||
*/
|
||||
default boolean startsWithTemplate(String text) {
|
||||
return text.startsWith(openingTemplate());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param text text to assert
|
||||
* @return asserts whether the given text starts with proper opening template for
|
||||
* escaped value.
|
||||
*/
|
||||
default boolean startsWithEscapedTemplate(String text) {
|
||||
return text.startsWith(escapedOpeningTemplate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Handlebars is using the Mustache template thus it looks like this {{ Mustache }}.
|
||||
* In this case the opening template would return {{
|
||||
* @return opening template for a variable
|
||||
*/
|
||||
String openingTemplate();
|
||||
|
||||
/**
|
||||
* Handlebars is using the Mustache template thus it looks like this {{ Mustache }}.
|
||||
* In this case the closing template would return }}
|
||||
* @return closing template for a variable
|
||||
*/
|
||||
String closingTemplate();
|
||||
|
||||
/**
|
||||
* Handlebars is using the Mustache template thus it looks like this {{{ Mustache }}}.
|
||||
* In this case the opening template would return {{{
|
||||
* @return escaped opening template for a variable
|
||||
*/
|
||||
default String escapedOpeningTemplate() {
|
||||
return openingTemplate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handlebars is using the Mustache template thus it looks like this {{{ Mustache }}}.
|
||||
* In this case the closing template would return }}}
|
||||
* @return escaped closing template for a variable
|
||||
*/
|
||||
default String escapedClosingTemplate() {
|
||||
return closingTemplate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return returns the template for retrieving a URL path and query from request
|
||||
*/
|
||||
String url();
|
||||
|
||||
/**
|
||||
* @param key query parameter key
|
||||
* @return the template for retrieving first value of a query parameter e.g. {{
|
||||
* request.query.search }}
|
||||
*/
|
||||
String query(String key);
|
||||
|
||||
/**
|
||||
* @param key query parameter key
|
||||
* @param index query parameter index
|
||||
* @return the template for retrieving nth value of a query parameter (zero indexed)
|
||||
* e.g. {{ request.query.search.[5] }}
|
||||
*/
|
||||
String query(String key, int index);
|
||||
|
||||
/**
|
||||
* @return the template for retrieving a URL path
|
||||
*/
|
||||
String path();
|
||||
|
||||
/**
|
||||
* @param index request path index
|
||||
* @return the template for retrieving nth value of a URL path (zero indexed) e.g. {{
|
||||
* request.path.[2] }}
|
||||
*/
|
||||
String path(int index);
|
||||
|
||||
/**
|
||||
* @param key headers key
|
||||
* @return the template for retrieving the first value of a request header e.g. {{
|
||||
* request.headers.X-Request-Id }}
|
||||
*/
|
||||
String header(String key);
|
||||
|
||||
/**
|
||||
* @param key headers key
|
||||
* @param index headers index
|
||||
* @return the template for retrieving the nth value of a request header (zero
|
||||
* indexed) e.g. {{ request.headers.X-Request-Id.[5] }}
|
||||
*/
|
||||
String header(String key, int index);
|
||||
|
||||
/**
|
||||
* @param key cookie key
|
||||
* @return the template for retrieving the first value of a cookie with certain key
|
||||
*/
|
||||
String cookie(String key);
|
||||
|
||||
/**
|
||||
* @return request body text (avoid for non-text bodies) e.g. {{ request.body }} . The
|
||||
* body will not be escaped so you won't be able to directly embed it in a JSON for
|
||||
* example.
|
||||
*/
|
||||
String body();
|
||||
|
||||
/**
|
||||
* @param jsonPath json path value
|
||||
* @return request body text for the given JsonPath. e.g. {{ jsonPath request.body
|
||||
* '$.a.b.c' }}
|
||||
*/
|
||||
String body(String jsonPath);
|
||||
|
||||
/**
|
||||
* @return the template for retrieving a escaped URL path and query from request
|
||||
*/
|
||||
default String escapedUrl() {
|
||||
return url();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key query parameter key
|
||||
* @return the template for retrieving escaped first value of a query parameter e.g.
|
||||
* {{{ request.query.search }}}
|
||||
*/
|
||||
default String escapedQuery(String key) {
|
||||
return query(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key query parameter key
|
||||
* @param index query parameter index
|
||||
* @return the template for retrieving esacped nth value of a query parameter (zero
|
||||
* indexed) e.g. {{{ request.query.search.[5] }}}
|
||||
*/
|
||||
default String escapedQuery(String key, int index) {
|
||||
return query(key, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the template for retrieving a escaped URL path
|
||||
*/
|
||||
default String escapedPath() {
|
||||
return path();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param index path index
|
||||
* @return the template for retrieving escaped nth value of a URL path (zero indexed)
|
||||
* e.g. {{{ request.path.[2] }}}
|
||||
*/
|
||||
default String escapedPath(int index) {
|
||||
return path(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key headers key
|
||||
* @return the template for retrieving the escaped first value of a request header
|
||||
* e.g. {{{ request.headers.X-Request-Id }}}
|
||||
*/
|
||||
default String escapedHeader(String key) {
|
||||
return header(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key headers key
|
||||
* @param index headers index
|
||||
* @return the template for retrieving the esacaped nth value of a request header
|
||||
* (zero indexed) e.g. {{{ request.headers.X-Request-Id.[5] }}}
|
||||
*/
|
||||
default String escapedHeader(String key, int index) {
|
||||
return header(key, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key cookie key
|
||||
* @return the template for retrieving the escaped first value of a cookie with
|
||||
* certain key
|
||||
*/
|
||||
default String escapedCookie(String key) {
|
||||
return cookie(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return request body text (avoid for non-text bodies) e.g. {{{ request.body }}} .
|
||||
* The body will not be escaped so you won't be able to directly embed it in a JSON
|
||||
* for example.
|
||||
*/
|
||||
default String escapedBody() {
|
||||
return body();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param jsonPath json path value
|
||||
* @return request body text for the given JsonPath. e.g. {{{ jsonPath request.body
|
||||
* '$.a.b.c' }}}
|
||||
*/
|
||||
default String escapedBody(String jsonPath) {
|
||||
return body(jsonPath);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec;
|
||||
|
||||
/**
|
||||
* @author Jakub Kubrynski, codearte.io
|
||||
*/
|
||||
public class ContractVerifierException extends RuntimeException {
|
||||
|
||||
public ContractVerifierException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ContractVerifierException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Represents a body of a request / response or a message.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class Body extends DslProperty {
|
||||
|
||||
public Body(Map<String, DslProperty> body) {
|
||||
super(extractValue(body, ContractUtils.CLIENT_VALUE),
|
||||
extractValue(body, ContractUtils.SERVER_VALUE));
|
||||
}
|
||||
|
||||
public Body(List<DslProperty> bodyAsList) {
|
||||
super(bodyAsList.stream().map(DslProperty::getClientValue)
|
||||
.collect(Collectors.toList()),
|
||||
bodyAsList.stream().map(DslProperty::getServerValue)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
public Body(Object value) {
|
||||
super(ContractUtils.CLIENT_VALUE.apply(value),
|
||||
ContractUtils.SERVER_VALUE.apply(value));
|
||||
}
|
||||
|
||||
public Body(Byte[] bodyAsValue) {
|
||||
super(bodyAsValue);
|
||||
}
|
||||
|
||||
public Body(Number bodyAsValue) {
|
||||
super(bodyAsValue);
|
||||
}
|
||||
|
||||
public Body(String bodyAsValue) {
|
||||
super(bodyAsValue, bodyAsValue);
|
||||
}
|
||||
|
||||
public Body(DslProperty bodyAsValue) {
|
||||
super(bodyAsValue.getClientValue(), bodyAsValue.getServerValue());
|
||||
}
|
||||
|
||||
public Body(Serializable serializable) {
|
||||
super(serializable, serializable);
|
||||
}
|
||||
|
||||
public Body(MatchingStrategy matchingStrategy) {
|
||||
super(matchingStrategy, matchingStrategy);
|
||||
}
|
||||
|
||||
private static Map<String, Object> extractValue(Map<String, DslProperty> body,
|
||||
final Function valueProvider) {
|
||||
final Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
body.forEach((key, value) -> map.put(key, valueProvider.apply(value)));
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
/**
|
||||
* Matchers for the given path.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 1.0.3
|
||||
*/
|
||||
public interface BodyMatcher {
|
||||
|
||||
/**
|
||||
* @return What kind of matching are we dealing with.
|
||||
*/
|
||||
MatchingType matchingType();
|
||||
|
||||
/**
|
||||
* @return Path to the path. Example for JSON it will be JSON Path.
|
||||
*/
|
||||
String path();
|
||||
|
||||
/**
|
||||
* @return Optional value that the given path should be checked against. If there is
|
||||
* no value then presence will be checked only together with type check. Example if we
|
||||
* expect a JSON Path path {@code $.a} to be matched. by type, the defined response
|
||||
* body contained an integer but the actual one contained a string then the assertion
|
||||
* should fail.
|
||||
*/
|
||||
Object value();
|
||||
|
||||
/**
|
||||
* @return Min no of occurrence when matching by type. In all other cases it will be
|
||||
* ignored.
|
||||
*/
|
||||
Integer minTypeOccurrence();
|
||||
|
||||
/**
|
||||
* @return Max no of occurrence when matching by type. In all other cases it will be
|
||||
* ignored.
|
||||
*/
|
||||
Integer maxTypeOccurrence();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import groovy.lang.Closure;
|
||||
import groovy.lang.DelegatesTo;
|
||||
|
||||
/**
|
||||
* Matching strategy of dynamic parts of the body.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @since 1.0.3
|
||||
*/
|
||||
public class BodyMatchers {
|
||||
|
||||
protected final List<BodyMatcher> matchers = new LinkedList<>();
|
||||
|
||||
private final RegexPatterns regexPatterns = new RegexPatterns();
|
||||
|
||||
public void jsonPath(String path, MatchingTypeValue matchingType) {
|
||||
this.matchers.add(new PathBodyMatcher(path, matchingType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds xPath matcher; even though same implementation as in
|
||||
* {@link BodyMatchers#jsonPath(java.lang.String, org.springframework.cloud.contract.spec.internal.MatchingTypeValue)},
|
||||
* added for logical coherence in xml.
|
||||
* @param xPath the xPath used to find the element to match
|
||||
* @param matchingTypeValue to match the element found by the xPath against
|
||||
*/
|
||||
public void xPath(String xPath, MatchingTypeValue matchingTypeValue) {
|
||||
this.matchers.add(new PathBodyMatcher(xPath, matchingTypeValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use{@link #matchers()}
|
||||
* @return json path matchers
|
||||
*/
|
||||
@Deprecated
|
||||
public List<BodyMatcher> jsonPathMatchers() {
|
||||
return matchers();
|
||||
}
|
||||
|
||||
public boolean hasMatchers() {
|
||||
return !this.matchers.isEmpty();
|
||||
}
|
||||
|
||||
public List<BodyMatcher> matchers() {
|
||||
return this.matchers;
|
||||
}
|
||||
|
||||
public MatchingTypeValue byDate() {
|
||||
return new MatchingTypeValue(MatchingType.DATE, this.regexPatterns.isoDate());
|
||||
}
|
||||
|
||||
public MatchingTypeValue byTime() {
|
||||
return new MatchingTypeValue(MatchingType.TIME, this.regexPatterns.isoTime());
|
||||
}
|
||||
|
||||
public MatchingTypeValue byTimestamp() {
|
||||
return new MatchingTypeValue(MatchingType.TIMESTAMP,
|
||||
this.regexPatterns.isoDateTime());
|
||||
}
|
||||
|
||||
public RegexMatchingTypeValue byRegex(String regex) {
|
||||
return byRegex(Pattern.compile(regex));
|
||||
}
|
||||
|
||||
public RegexMatchingTypeValue byRegex(RegexProperty regex) {
|
||||
assertNotNull(regex);
|
||||
return new RegexMatchingTypeValue(MatchingType.REGEX, regex);
|
||||
}
|
||||
|
||||
public RegexMatchingTypeValue byRegex(Pattern regex) {
|
||||
assertNotNull(regex);
|
||||
return new RegexMatchingTypeValue(MatchingType.REGEX, new RegexProperty(regex));
|
||||
}
|
||||
|
||||
public MatchingTypeValue byEquality() {
|
||||
return new MatchingTypeValue(MatchingType.EQUALITY);
|
||||
}
|
||||
|
||||
private void assertNotNull(Object object) {
|
||||
if (object == null) {
|
||||
throw new IllegalStateException("Object can't be null!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
BodyMatchers that = (BodyMatchers) o;
|
||||
return Objects.equals(matchers, that.matchers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(matchers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BodyMatchers{" + "\nmatchers=" + matchers + '}';
|
||||
}
|
||||
|
||||
/**
|
||||
* The output part of the contract.
|
||||
* @param consumer function to manipulate the output message
|
||||
* @return matching type
|
||||
*/
|
||||
public MatchingTypeValue byType(Consumer<MatchingTypeValueHolder> consumer) {
|
||||
MatchingTypeValueHolder matchingTypeValue = new MatchingTypeValueHolder();
|
||||
consumer.accept(matchingTypeValue);
|
||||
return matchingTypeValue.matchingTypeValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* The output part of the contract.
|
||||
* @param consumer function to manipulate the output message
|
||||
* @return matching type
|
||||
*/
|
||||
public MatchingTypeValue byType(
|
||||
@DelegatesTo(MatchingTypeValueHolder.class) Closure consumer) {
|
||||
MatchingTypeValueHolder matchingTypeValue = new MatchingTypeValueHolder();
|
||||
consumer.setDelegate(matchingTypeValue);
|
||||
consumer.call();
|
||||
return matchingTypeValue.matchingTypeValue;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
/**
|
||||
* Some properties can contain dynamic values. If that's the case we need to know how to
|
||||
* generate a concrete value for them.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 2.1.0
|
||||
*/
|
||||
public interface CanBeDynamic {
|
||||
|
||||
/**
|
||||
* @return a generated, concrete value.
|
||||
*/
|
||||
Object generateConcreteValue();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
/**
|
||||
* Represents a client side {@link DslProperty}.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class ClientDslProperty extends DslProperty {
|
||||
|
||||
public ClientDslProperty(Object singleValue) {
|
||||
super(singleValue);
|
||||
}
|
||||
|
||||
public ClientDslProperty(Object client, Object server) {
|
||||
super(client, server);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
class ClientInput extends Input {
|
||||
|
||||
ClientInput(Input request) {
|
||||
super(request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
class ClientOutputMessage extends OutputMessage {
|
||||
|
||||
ClientOutputMessage(OutputMessage request) {
|
||||
super(request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,402 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Contains useful common methods for the DSL.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class Common {
|
||||
|
||||
private final RegexPatterns regexPatterns = new RegexPatterns();
|
||||
|
||||
public Map<String, DslProperty> convertObjectsToDslProperties(
|
||||
Map<String, Object> body) {
|
||||
return body.entrySet().stream().collect(Collectors.toMap(
|
||||
(Function<Map.Entry, String>) t -> t.getKey().toString(),
|
||||
(Function<Map.Entry, DslProperty>) t -> toDslProperty(t.getValue()),
|
||||
throwingMerger(), LinkedHashMap::new));
|
||||
}
|
||||
|
||||
private static <T> BinaryOperator<T> throwingMerger() {
|
||||
return (u, v) -> {
|
||||
throw new IllegalStateException(String.format("Duplicate key %s", u));
|
||||
};
|
||||
}
|
||||
|
||||
public Collection convertObjectsToDslProperties(List<Object> body) {
|
||||
return body.stream().map(this::toDslProperty).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public DslProperty toDslProperty(Object property) {
|
||||
return new DslProperty(property);
|
||||
}
|
||||
|
||||
public DslProperty toDslProperty(Map property) {
|
||||
return new DslProperty(convertObjectsToDslProperties(property));
|
||||
}
|
||||
|
||||
public DslProperty toDslProperty(List property) {
|
||||
return new DslProperty(convertObjectsToDslProperties(property));
|
||||
}
|
||||
|
||||
public DslProperty toDslProperty(DslProperty property) {
|
||||
return property;
|
||||
}
|
||||
|
||||
public NamedProperty named(DslProperty name, DslProperty value) {
|
||||
return new NamedProperty(name, value);
|
||||
}
|
||||
|
||||
public NamedProperty named(DslProperty name, DslProperty value,
|
||||
DslProperty contentType) {
|
||||
return new NamedProperty(name, value, contentType);
|
||||
}
|
||||
|
||||
public NamedProperty named(Map<String, DslProperty> namedMap) {
|
||||
return new NamedProperty(namedMap);
|
||||
}
|
||||
|
||||
public DslProperty value(DslProperty value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
public DslProperty $(DslProperty value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
public DslProperty value(Object value) {
|
||||
return new DslProperty(value);
|
||||
}
|
||||
|
||||
public DslProperty $(Object value) {
|
||||
return new DslProperty(value);
|
||||
}
|
||||
|
||||
public DslProperty value(ClientDslProperty client, ServerDslProperty server) {
|
||||
assertThatSidesMatch(client.getClientValue(), server.getServerValue());
|
||||
return new DslProperty(client.getClientValue(), server.getServerValue());
|
||||
}
|
||||
|
||||
public DslProperty $(ClientDslProperty client, ServerDslProperty server) {
|
||||
return value(client, server);
|
||||
}
|
||||
|
||||
public DslProperty value(ServerDslProperty server, ClientDslProperty client) {
|
||||
assertThatSidesMatch(client.getClientValue(), server.getServerValue());
|
||||
return new DslProperty(client.getClientValue(), server.getServerValue());
|
||||
}
|
||||
|
||||
public DslProperty $(ServerDslProperty server, ClientDslProperty client) {
|
||||
return value(server, client);
|
||||
}
|
||||
|
||||
public RegexProperty regex(String regex) {
|
||||
return regexProperty(Pattern.compile(regex));
|
||||
}
|
||||
|
||||
public RegexProperty regex(RegexProperty regex) {
|
||||
return regex;
|
||||
}
|
||||
|
||||
public RegexProperty regex(Pattern regex) {
|
||||
return regexProperty(regex);
|
||||
}
|
||||
|
||||
public OptionalProperty optional(Object object) {
|
||||
return new OptionalProperty(object);
|
||||
}
|
||||
|
||||
public RegexProperty regexProperty(Object object) {
|
||||
return new RegexProperty(object);
|
||||
}
|
||||
|
||||
public ExecutionProperty execute(String commandToExecute) {
|
||||
return new ExecutionProperty(commandToExecute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to provide a better name for the consumer side.
|
||||
* @param clientValue client value
|
||||
* @return client dsl property
|
||||
*/
|
||||
public ClientDslProperty client(Object clientValue) {
|
||||
return new ClientDslProperty(clientValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to provide a better name for the consumer side.
|
||||
* @param clientValue client value
|
||||
* @return client dsl property
|
||||
*/
|
||||
public ClientDslProperty stub(Object clientValue) {
|
||||
return new ClientDslProperty(clientValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to provide a better name for the consumer side.
|
||||
* @param clientValue client value
|
||||
* @return client dsl property
|
||||
*/
|
||||
public ClientDslProperty consumer(Object clientValue) {
|
||||
return new ClientDslProperty(clientValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to provide a better name for the server side.
|
||||
* @param serverValue server value
|
||||
* @return server dsl property
|
||||
*/
|
||||
public ServerDslProperty server(Object serverValue) {
|
||||
return new ServerDslProperty(serverValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to provide a better name for the consumer side.
|
||||
* @param clientValue client value
|
||||
* @return client dsl property
|
||||
*/
|
||||
public ClientDslProperty c(Object clientValue) {
|
||||
return new ClientDslProperty(clientValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to provide a better name for the server side.
|
||||
* @param serverValue server value
|
||||
* @return server dsl property
|
||||
*/
|
||||
public ServerDslProperty p(Object serverValue) {
|
||||
return new ServerDslProperty(serverValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to provide a better name for the server side.
|
||||
* @param serverValue server value
|
||||
* @return server dsl property
|
||||
*/
|
||||
public ServerDslProperty test(Object serverValue) {
|
||||
return new ServerDslProperty(serverValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read file contents as String.
|
||||
* @param relativePath of the file to read
|
||||
* @return String file contents
|
||||
*/
|
||||
public FromFileProperty file(String relativePath) {
|
||||
return file(relativePath, Charset.defaultCharset());
|
||||
}
|
||||
|
||||
/**
|
||||
* Read file contents as bytes[].
|
||||
* @param relativePath of the file to read
|
||||
* @return String file contents
|
||||
*/
|
||||
public FromFileProperty fileAsBytes(String relativePath) {
|
||||
return new FromFileProperty(fileLocation(relativePath), byte[].class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read file contents as String with the given Charset.
|
||||
* @param relativePath of the file to read
|
||||
* @param charset to use for converting the bytes to String
|
||||
* @return String file contents
|
||||
*/
|
||||
public FromFileProperty file(String relativePath, Charset charset) {
|
||||
return new FromFileProperty(fileLocation(relativePath), String.class, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read file contents as array of bytes.
|
||||
* @param relativePath of the file to read
|
||||
* @return file contents as an array of bytes
|
||||
*/
|
||||
private File fileLocation(String relativePath) {
|
||||
URL resource = Thread.currentThread().getContextClassLoader()
|
||||
.getResource(relativePath);
|
||||
if (resource == null) {
|
||||
throw new IllegalStateException("File [" + relativePath + "] is not present");
|
||||
}
|
||||
try {
|
||||
return new File(resource.toURI());
|
||||
}
|
||||
catch (URISyntaxException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to provide a better name for the server side.
|
||||
* @param serverValue server value
|
||||
* @return server dsl property
|
||||
*/
|
||||
public ServerDslProperty producer(Object serverValue) {
|
||||
return new ServerDslProperty(serverValue);
|
||||
}
|
||||
|
||||
private void throwAbsentError() {
|
||||
throw new IllegalStateException("Absent cannot only be used only on one side");
|
||||
}
|
||||
|
||||
private void assertThat(boolean condition, String msg) {
|
||||
if (!condition) {
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public void assertThatSidesMatch(Object firstSide, Object secondSide) {
|
||||
if (firstSide instanceof OptionalProperty) {
|
||||
assertThat(
|
||||
secondSide.toString()
|
||||
.matches(((OptionalProperty) firstSide).optionalPattern()),
|
||||
"Pattern [" + ((OptionalProperty) firstSide).optionalPattern()
|
||||
+ "] is not matched by [" + secondSide.toString() + "]");
|
||||
}
|
||||
else if ((firstSide instanceof Pattern || firstSide instanceof RegexProperty)
|
||||
&& secondSide instanceof String) {
|
||||
Pattern pattern = firstSide instanceof Pattern ? (Pattern) firstSide
|
||||
: ((RegexProperty) firstSide).getPattern();
|
||||
assertThat(((String) secondSide).toString().matches(pattern.pattern()),
|
||||
"Pattern [" + pattern.pattern() + "] is not matched by ["
|
||||
+ secondSide.toString() + "]");
|
||||
}
|
||||
else if ((secondSide instanceof Pattern || secondSide instanceof RegexProperty)
|
||||
&& firstSide instanceof String) {
|
||||
Pattern pattern = secondSide instanceof Pattern ? (Pattern) secondSide
|
||||
: ((RegexProperty) secondSide).getPattern();
|
||||
assertThat(((String) firstSide).matches(pattern.pattern()),
|
||||
"Pattern [" + pattern.pattern() + "] is not matched by ["
|
||||
+ firstSide.toString() + "]");
|
||||
}
|
||||
else if (firstSide instanceof MatchingStrategy
|
||||
&& secondSide instanceof MatchingStrategy) {
|
||||
if (((MatchingStrategy) firstSide).getType()
|
||||
.equals(MatchingStrategy.Type.ABSENT)
|
||||
&& !((MatchingStrategy) secondSide).getType()
|
||||
.equals(MatchingStrategy.Type.ABSENT)) {
|
||||
throwAbsentError();
|
||||
}
|
||||
|
||||
}
|
||||
else if (firstSide instanceof MatchingStrategy) {
|
||||
if (((MatchingStrategy) firstSide).getType()
|
||||
.equals(MatchingStrategy.Type.ABSENT)) {
|
||||
throwAbsentError();
|
||||
}
|
||||
|
||||
}
|
||||
else if (secondSide instanceof MatchingStrategy) {
|
||||
if (((MatchingStrategy) secondSide).getType()
|
||||
.equals(MatchingStrategy.Type.ABSENT)) {
|
||||
throwAbsentError();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public RegexProperty onlyAlphaUnicode() {
|
||||
return regexPatterns.onlyAlphaUnicode();
|
||||
}
|
||||
|
||||
public RegexProperty alphaNumeric() {
|
||||
return regexPatterns.alphaNumeric();
|
||||
}
|
||||
|
||||
public RegexProperty number() {
|
||||
return regexPatterns.number();
|
||||
}
|
||||
|
||||
public RegexProperty positiveInt() {
|
||||
return regexPatterns.positiveInt();
|
||||
}
|
||||
|
||||
public RegexProperty anyBoolean() {
|
||||
return regexPatterns.anyBoolean();
|
||||
}
|
||||
|
||||
public RegexProperty anInteger() {
|
||||
return regexPatterns.anInteger();
|
||||
}
|
||||
|
||||
public RegexProperty aDouble() {
|
||||
return regexPatterns.aDouble();
|
||||
}
|
||||
|
||||
public RegexProperty ipAddress() {
|
||||
return regexPatterns.ipAddress();
|
||||
}
|
||||
|
||||
public RegexProperty hostname() {
|
||||
return regexPatterns.hostname();
|
||||
}
|
||||
|
||||
public RegexProperty email() {
|
||||
return regexPatterns.email();
|
||||
}
|
||||
|
||||
public RegexProperty url() {
|
||||
return regexPatterns.url();
|
||||
}
|
||||
|
||||
public RegexProperty httpsUrl() {
|
||||
return regexPatterns.httpsUrl();
|
||||
}
|
||||
|
||||
public RegexProperty uuid() {
|
||||
return regexPatterns.uuid();
|
||||
}
|
||||
|
||||
public RegexProperty isoDate() {
|
||||
return regexPatterns.isoDate();
|
||||
}
|
||||
|
||||
public RegexProperty isoDateTime() {
|
||||
return regexPatterns.isoDateTime();
|
||||
}
|
||||
|
||||
public RegexProperty isoTime() {
|
||||
return regexPatterns.isoTime();
|
||||
}
|
||||
|
||||
public RegexProperty iso8601WithOffset() {
|
||||
return regexPatterns.iso8601WithOffset();
|
||||
}
|
||||
|
||||
public RegexProperty nonEmpty() {
|
||||
return regexPatterns.nonEmpty();
|
||||
}
|
||||
|
||||
public RegexProperty nonBlank() {
|
||||
return regexPatterns.nonBlank();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import org.springframework.cloud.contract.spec.ContractTemplate;
|
||||
|
||||
/**
|
||||
* For backward compatibility when assertions take place, first checks the custom setup.
|
||||
* Writes in a new format, can read the old format.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 2.1.0
|
||||
*/
|
||||
public class CompositeContractTemplate implements ContractTemplate {
|
||||
|
||||
private final CustomHandlebarsContractTemplate custom = new CustomHandlebarsContractTemplate();
|
||||
|
||||
private final HandlebarsContractTemplate template = new HandlebarsContractTemplate();
|
||||
|
||||
@Override
|
||||
public boolean startsWithTemplate(String text) {
|
||||
if (this.custom.startsWithTemplate(text)) {
|
||||
return true;
|
||||
}
|
||||
return template.startsWithTemplate(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startsWithEscapedTemplate(String text) {
|
||||
return this.template.startsWithEscapedTemplate(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String openingTemplate() {
|
||||
return this.template.openingTemplate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String closingTemplate() {
|
||||
return this.template.closingTemplate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapedOpeningTemplate() {
|
||||
return this.template.escapedOpeningTemplate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapedClosingTemplate() {
|
||||
return this.template.escapedClosingTemplate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String url() {
|
||||
return this.template.url();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String query(String key) {
|
||||
return this.template.query(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String query(String key, int index) {
|
||||
return this.template.query(key, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String path() {
|
||||
return this.template.path();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String path(int index) {
|
||||
return this.template.path(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String header(String key) {
|
||||
return this.template.header(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String header(String key, int index) {
|
||||
return this.template.header(key, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String cookie(String key) {
|
||||
return this.template.cookie(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String body() {
|
||||
return this.template.body();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapedBody() {
|
||||
// WireMock doesn't support proper escaping of JSON body
|
||||
// that's why we need to use our custom handlebars extension
|
||||
return this.custom.escapedBody();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapedBody(String jsonPath) {
|
||||
return this.template.escapedBody(jsonPath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String body(String jsonPath) {
|
||||
return this.template.body(jsonPath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapedUrl() {
|
||||
return this.template.escapedUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapedQuery(String key) {
|
||||
return this.template.escapedQuery(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapedQuery(String key, int index) {
|
||||
return this.template.escapedQuery(key, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapedPath() {
|
||||
return this.template.escapedPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapedPath(int index) {
|
||||
return this.template.escapedPath(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapedHeader(String key) {
|
||||
return this.template.escapedHeader(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapedHeader(String key, int index) {
|
||||
return this.template.escapedHeader(key, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapedCookie(String key) {
|
||||
return this.template.escapedCookie(key);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
final class ContractUtils {
|
||||
|
||||
static final Function CLIENT_VALUE = o -> o instanceof DslProperty
|
||||
? ((DslProperty) o).getClientValue() : o;
|
||||
static final Function SERVER_VALUE = o -> o instanceof DslProperty
|
||||
? ((DslProperty) o).getServerValue() : o;
|
||||
|
||||
private ContractUtils() {
|
||||
throw new IllegalStateException("Can't instantiate an utility class");
|
||||
}
|
||||
|
||||
static Object convertStubSideRecursively(Object object) {
|
||||
return convertRecursively(object, CLIENT_VALUE);
|
||||
}
|
||||
|
||||
static Object convertTestSideRecursively(Object object) {
|
||||
return convertRecursively(object, SERVER_VALUE);
|
||||
}
|
||||
|
||||
private static Object convertRecursively(Object object, Function function) {
|
||||
if (object instanceof DslProperty) {
|
||||
return convertRecursively(function.apply(object), function);
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents a http cookie.
|
||||
*
|
||||
* @author Alex Xandra Albert Sim
|
||||
* @since 1.2.5
|
||||
*/
|
||||
public class Cookie extends DslProperty {
|
||||
|
||||
private String key;
|
||||
|
||||
public Cookie(String key, DslProperty dslProperty) {
|
||||
super(dslProperty.getClientValue(), dslProperty.getServerValue());
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public Cookie(String key, MatchingStrategy value) {
|
||||
super(value);
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public Cookie(String key, Object value) {
|
||||
super(ContractUtils.CLIENT_VALUE.apply(value),
|
||||
ContractUtils.SERVER_VALUE.apply(value));
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public static Cookie build(String key, Object value) {
|
||||
if (value instanceof MatchingStrategy) {
|
||||
return new Cookie(key, (MatchingStrategy) value);
|
||||
}
|
||||
return new Cookie(key, value);
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
if (!super.equals(o)) {
|
||||
return false;
|
||||
}
|
||||
Cookie cookie = (Cookie) o;
|
||||
return Objects.equals(key, cookie.key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Cookie{" + "key='" + key + '\'' + "}, value=" + super.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Represents a set of http cookies.
|
||||
*
|
||||
* @author Alex Xandra Albert Sim
|
||||
* @since 1.2.5
|
||||
*/
|
||||
public class Cookies {
|
||||
|
||||
private Set<Cookie> entries = new HashSet<>();
|
||||
|
||||
public void cookie(Map<String, Object> singleCookie) {
|
||||
Iterator<Map.Entry<String, Object>> iterator = singleCookie.entrySet().iterator();
|
||||
if (iterator.hasNext()) {
|
||||
Map.Entry<String, Object> first = iterator.next();
|
||||
if (first != null) {
|
||||
entries.add(Cookie.build(first.getKey(), first.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void cookie(String cookieKey, Object cookieValue) {
|
||||
entries.add(Cookie.build(cookieKey, cookieValue));
|
||||
}
|
||||
|
||||
public void executeForEachCookie(final Consumer<Cookie> consumer) {
|
||||
entries.forEach(consumer::accept);
|
||||
}
|
||||
|
||||
public DslProperty matching(String value) {
|
||||
return new DslProperty(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Cookies cookies = (Cookies) o;
|
||||
return Objects.equals(entries, cookies.entries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(entries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Cookies{" + "entries=" + entries + '}';
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the headers into their stub side representations and returns as a map of
|
||||
* String key => Object value.
|
||||
* @return converted map
|
||||
*/
|
||||
public Map<String, Object> asStubSideMap() {
|
||||
final Map<String, Object> map = new LinkedHashMap<>();
|
||||
entries.forEach(cookie -> map.put(cookie.getKey(),
|
||||
ContractUtils.convertStubSideRecursively(cookie)));
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the headers into their stub side representations and returns as a map of
|
||||
* String key => Object value.
|
||||
* @return converted map
|
||||
*/
|
||||
public Map<String, Object> asTestSideMap() {
|
||||
final Map<String, Object> map = new HashMap<String, Object>();
|
||||
entries.forEach(cookie -> map.put(cookie.getKey(),
|
||||
ContractUtils.convertTestSideRecursively(cookie)));
|
||||
return map;
|
||||
}
|
||||
|
||||
public Set<Cookie> getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
public void setEntries(Set<Cookie> entries) {
|
||||
this.entries = entries;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import org.springframework.cloud.contract.spec.ContractTemplate;
|
||||
|
||||
/**
|
||||
* Represents the structure of templates using Handlebars compatible with WireMock
|
||||
* template model requirements.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 1.1.0*
|
||||
* @deprecated use {@link HandlebarsContractTemplate}
|
||||
*/
|
||||
class CustomHandlebarsContractTemplate implements ContractTemplate {
|
||||
|
||||
@Override
|
||||
public String openingTemplate() {
|
||||
return "{{{";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String closingTemplate() {
|
||||
return "}}}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String url() {
|
||||
return wrapped("request.url");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String query(String key) {
|
||||
return query(key, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String query(String key, int index) {
|
||||
return wrapped("request.query." + key + ".[" + index + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String path() {
|
||||
return wrapped("request.path");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String path(int index) {
|
||||
return wrapped("request.path.[" + index + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String header(String key) {
|
||||
return header(key, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String header(String key, int index) {
|
||||
return wrapped("request.headers." + key + ".[" + index + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String cookie(String key) {
|
||||
return wrapped("request.cookies." + key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String body() {
|
||||
return wrapped("request.body");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapedBody() {
|
||||
return wrapped("escapejsonbody");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapedBody(String jsonPath) {
|
||||
return body(jsonPath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String body(String jsonPath) {
|
||||
return wrapped("jsonpath this \'" + jsonPath + "\'");
|
||||
}
|
||||
|
||||
private String wrapped(String text) {
|
||||
return openingTemplate() + text + closingTemplate();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Represents an element of a DSL that can contain client or sever side values.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class DslProperty<T> implements Serializable {
|
||||
|
||||
private final T clientValue;
|
||||
|
||||
private final T serverValue;
|
||||
|
||||
public DslProperty(T clientValue, T serverValue) {
|
||||
this.clientValue = clientValue;
|
||||
this.serverValue = serverValue;
|
||||
}
|
||||
|
||||
public DslProperty(T singleValue) {
|
||||
this.clientValue = singleValue;
|
||||
this.serverValue = singleValue;
|
||||
}
|
||||
|
||||
public boolean isSingleValue() {
|
||||
return this.clientValue.equals(this.serverValue)
|
||||
|| (this.clientValue != null && this.serverValue == null)
|
||||
|| (this.serverValue != null && this.clientValue == null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
DslProperty<?> that = (DslProperty<?>) o;
|
||||
Object thisClientValue = stringPatternIfPattern(clientValue);
|
||||
Object thatClientValue = stringPatternIfPattern(that.clientValue);
|
||||
Object thisServerValue = stringPatternIfPattern(serverValue);
|
||||
Object thatServerValue = stringPatternIfPattern(that.serverValue);
|
||||
return Objects.equals(thisClientValue, thatClientValue)
|
||||
&& Objects.equals(thisServerValue, thatServerValue);
|
||||
}
|
||||
|
||||
private Object stringPatternIfPattern(Object value) {
|
||||
return value instanceof Pattern ? ((Pattern) value).pattern() : value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(stringPatternIfPattern(clientValue),
|
||||
stringPatternIfPattern(serverValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + "{" + "\nclientValue=" + clientValue
|
||||
+ ", \n\tserverValue=" + serverValue + '}';
|
||||
}
|
||||
|
||||
public final T getClientValue() {
|
||||
return clientValue;
|
||||
}
|
||||
|
||||
public final T getServerValue() {
|
||||
return serverValue;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
|
||||
/**
|
||||
* A hook mechanism to allow external languages and frameworks to convert types that are
|
||||
* not in Java for Spring Cloud Contract to understand.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public interface DslPropertyConverter {
|
||||
|
||||
/**
|
||||
* Default no op implementation.
|
||||
*/
|
||||
DslPropertyConverter DEFAULT = new DslPropertyConverter() {
|
||||
};
|
||||
|
||||
/**
|
||||
* A composite over available instances or default if none is present.
|
||||
*/
|
||||
DslPropertyConverter INSTANCE = instance();
|
||||
|
||||
/**
|
||||
* @return a composite {@link DslPropertyConverter} around a list of
|
||||
* {@link DslPropertyConverter} or a default no op instance
|
||||
*/
|
||||
static DslPropertyConverter instance() {
|
||||
if (INSTANCE != null) {
|
||||
return INSTANCE;
|
||||
}
|
||||
List<DslPropertyConverter> converters = SpringFactoriesLoader
|
||||
.loadFactories(DslPropertyConverter.class, null);
|
||||
if (converters.isEmpty()) {
|
||||
return DEFAULT;
|
||||
}
|
||||
return new DslPropertyConverter() {
|
||||
@Override
|
||||
public Object testSide(Object object) {
|
||||
Object convertedObject = object;
|
||||
for (DslPropertyConverter converter : converters) {
|
||||
convertedObject = converter.testSide(convertedObject);
|
||||
}
|
||||
return convertedObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object stubSide(Object object) {
|
||||
Object convertedObject = object;
|
||||
for (DslPropertyConverter converter : converters) {
|
||||
convertedObject = converter.stubSide(convertedObject);
|
||||
}
|
||||
return convertedObject;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Conversion mechanism for the test side manipulation.
|
||||
* @param object object to manipulate
|
||||
* @return converted object for the test side
|
||||
*/
|
||||
default Object testSide(Object object) {
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Conversion mechanism for the stub side manipulation.
|
||||
* @param object object to manipulate
|
||||
* @return converted object for the stub side
|
||||
*/
|
||||
default Object stubSide(Object object) {
|
||||
return object;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents a property that will become an executable method in the generated tests.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class ExecutionProperty implements Serializable {
|
||||
|
||||
private static final String PLACEHOLDER_VALUE = "$it";
|
||||
|
||||
private final String executionCommand;
|
||||
|
||||
public ExecutionProperty(String executionCommand) {
|
||||
this.executionCommand = executionCommand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the provided code as a parameter to the method and returns the code that
|
||||
* represents that method execution.
|
||||
* @param valueToInsert value to insert into the string
|
||||
* @return string with inserted value
|
||||
*/
|
||||
public String insertValue(String valueToInsert) {
|
||||
return executionCommand.replace(PLACEHOLDER_VALUE, valueToInsert);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return executionCommand;
|
||||
}
|
||||
|
||||
public final String getExecutionCommand() {
|
||||
return executionCommand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ExecutionProperty that = (ExecutionProperty) o;
|
||||
return Objects.equals(executionCommand, that.executionCommand);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(executionCommand);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
|
||||
/**
|
||||
* Represents a property that will become a File content.
|
||||
*
|
||||
* @since 2.1.0
|
||||
*/
|
||||
public class FromFileProperty implements Serializable {
|
||||
|
||||
private final File file;
|
||||
|
||||
private final String charset;
|
||||
|
||||
private final Class type;
|
||||
|
||||
public FromFileProperty(File file, Class type) {
|
||||
this(file, type, Charset.defaultCharset());
|
||||
}
|
||||
|
||||
public FromFileProperty(File file, Class type, Charset charset) {
|
||||
this.file = file;
|
||||
this.type = type;
|
||||
this.charset = charset.toString();
|
||||
}
|
||||
|
||||
public boolean isString() {
|
||||
return String.class.equals(this.type);
|
||||
}
|
||||
|
||||
public boolean isByte() {
|
||||
return byte[].class.equals(this.type) || Byte[].class.equals(this.type);
|
||||
}
|
||||
|
||||
public String asString() {
|
||||
try {
|
||||
return new String(asBytes(), this.charset);
|
||||
}
|
||||
catch (UnsupportedEncodingException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public String fileName() {
|
||||
return this.file.getName();
|
||||
}
|
||||
|
||||
public byte[] asBytes() {
|
||||
try {
|
||||
return Files.readAllBytes(this.file.toPath());
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return asString();
|
||||
}
|
||||
|
||||
public final File getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public final String getCharset() {
|
||||
return charset;
|
||||
}
|
||||
|
||||
public final Class getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import org.springframework.cloud.contract.spec.ContractTemplate;
|
||||
|
||||
/**
|
||||
* Helper class to reference the request body parameters.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class FromRequest {
|
||||
|
||||
private final ContractTemplate template;
|
||||
|
||||
public FromRequest() {
|
||||
this.template = template();
|
||||
}
|
||||
|
||||
private ContractTemplate template() {
|
||||
return new CompositeContractTemplate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return URL path and query.
|
||||
*/
|
||||
public DslProperty url() {
|
||||
return new DslProperty(template.escapedUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* First value of a query parameter e.g. request.query.search.
|
||||
* @param key key for the query param
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty query(String key) {
|
||||
return new DslProperty(template.escapedQuery(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* nth value of a query parameter (zero indexed) e.g. request.query.search.[5].
|
||||
* @param key key for the query param
|
||||
* @param index index of the query param
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty query(String key, int index) {
|
||||
return new DslProperty(template.escapedQuery(key, index));
|
||||
}
|
||||
|
||||
/**
|
||||
* URL path.
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty path() {
|
||||
return new DslProperty(template.escapedPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* nth value of a URL path (zero indexed) e.g. {{{ request.path.[2] }}}* @param index.
|
||||
* @param index path index
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty path(int index) {
|
||||
return new DslProperty(template.escapedPath(index));
|
||||
}
|
||||
|
||||
/**
|
||||
* First value of a request header e.g. request.headers.X-Request-Id.
|
||||
* @param key header key
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty header(String key) {
|
||||
return new DslProperty(template.escapedHeader(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* nth value of a request header (zero indexed) e.g. request.headers.X-Request-Id.
|
||||
* @param key header key
|
||||
* @param index header index
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty header(String key, int index) {
|
||||
return new DslProperty(template.escapedHeader(key, index));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retruns the tempalte for retrieving the first value of a cookie with certain key.
|
||||
* @param key cookie key
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty cookie(String key) {
|
||||
return new DslProperty(template.escapedCookie(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Request body text (avoid for non-text bodies).
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty body() {
|
||||
return new DslProperty(template.escapedBody());
|
||||
}
|
||||
|
||||
/**
|
||||
* Request body text for the given JsonPath.
|
||||
* @param jsonPath json path body
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty body(String jsonPath) {
|
||||
return new DslProperty(template.escapedBody(jsonPath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescaped URL path and query.
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty rawUrl() {
|
||||
return new DslProperty(template.url());
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescaped First value of a query parameter e.g. request.query.search.
|
||||
* @param key query key
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty rawQuery(String key) {
|
||||
return new DslProperty(template.query(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescaped nth value of a query parameter (zero indexed) e.g.
|
||||
* request.query.search.[5].
|
||||
* @param key query key
|
||||
* @param index query index
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty rawQuery(String key, int index) {
|
||||
return new DslProperty(template.query(key, index));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescaped URL path.
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty rawPath() {
|
||||
return new DslProperty(template.path());
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescaped nth value of a URL path (zero indexed) e.g. {{{ request.path.[2]. }}}*
|
||||
* @param index path index
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty rawPath(int index) {
|
||||
return new DslProperty(template.path(index));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescaped First value of a request header e.g. request.headers.X-Request-Id.
|
||||
* @param key header key
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty rawHeader(String key) {
|
||||
return new DslProperty(template.header(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescaped nth value of a request header (zero indexed) e.g.
|
||||
* request.headers.X-Request-Id.
|
||||
* @param key header key
|
||||
* @param index header index
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty rawHeader(String key, int index) {
|
||||
return new DslProperty(template.header(key, index));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescaped Returns the template for retrieving the first value of a cookie with
|
||||
* certain key.
|
||||
* @param key cookie key
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty rawCookie(String key) {
|
||||
return new DslProperty(template.cookie(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescaped Request body text (avoid for non-text bodies).
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty rawBody() {
|
||||
return new DslProperty(template.body());
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescaped Request body text for the given JsonPath.
|
||||
* @param jsonPath json path body
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty rawBody(String jsonPath) {
|
||||
return new DslProperty(template.body(jsonPath));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import org.springframework.cloud.contract.spec.ContractTemplate;
|
||||
|
||||
/**
|
||||
* Represents the structure of templates using Handlebars compatible with WireMock
|
||||
* template model requirements.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class HandlebarsContractTemplate implements ContractTemplate {
|
||||
|
||||
@Override
|
||||
public String openingTemplate() {
|
||||
return "{{";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String closingTemplate() {
|
||||
return "}}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapedOpeningTemplate() {
|
||||
return "{{{";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapedClosingTemplate() {
|
||||
return "}}}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String url() {
|
||||
return wrapped("request.url");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String query(String key) {
|
||||
return query(key, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String query(String key, int index) {
|
||||
return wrapped("request.query." + key + ".[" + String.valueOf(index) + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String path() {
|
||||
return wrapped("request.path");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String path(int index) {
|
||||
return wrapped("request.path.[" + String.valueOf(index) + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String header(String key) {
|
||||
return header(key, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String header(String key, int index) {
|
||||
return wrapped("request.headers." + key + ".[" + String.valueOf(index) + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String cookie(String key) {
|
||||
return wrapped("request.cookies." + key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String body() {
|
||||
return wrapped("request.body");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapedBody() {
|
||||
return escapedWrapped("request.body");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapedBody(String jsonPath) {
|
||||
return escapedWrapped("jsonPath request.body \'" + jsonPath + "\'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String body(String jsonPath) {
|
||||
return wrapped("jsonPath request.body \'" + jsonPath + "\'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapedUrl() {
|
||||
return escapedWrapped("request.url");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapedQuery(String key) {
|
||||
return escapedQuery(key, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapedQuery(String key, int index) {
|
||||
return escapedWrapped(
|
||||
"request.query." + key + ".[" + String.valueOf(index) + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapedPath() {
|
||||
return escapedWrapped("request.path");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapedPath(int index) {
|
||||
return escapedWrapped("request.path.[" + String.valueOf(index) + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapedHeader(String key) {
|
||||
return escapedHeader(key, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapedHeader(String key, int index) {
|
||||
return escapedWrapped(
|
||||
"request.headers." + key + ".[" + String.valueOf(index) + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapedCookie(String key) {
|
||||
return escapedWrapped("request.cookies." + key);
|
||||
}
|
||||
|
||||
private String wrapped(String text) {
|
||||
return openingTemplate() + text + closingTemplate();
|
||||
}
|
||||
|
||||
private String escapedWrapped(String text) {
|
||||
return escapedOpeningTemplate() + text + escapedClosingTemplate();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents a header of a request / response or a message.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class Header extends DslProperty {
|
||||
|
||||
private String name;
|
||||
|
||||
public Header(String name, DslProperty dslProperty) {
|
||||
super(dslProperty.getClientValue(), dslProperty.getServerValue());
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Header(String name, MatchingStrategy value) {
|
||||
super(value);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Header(String name, Object value) {
|
||||
super(ContractUtils.CLIENT_VALUE.apply(value),
|
||||
ContractUtils.SERVER_VALUE.apply(value));
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static Header build(String key, Object value) {
|
||||
if (value instanceof MatchingStrategy) {
|
||||
return new Header(key, (MatchingStrategy) value);
|
||||
}
|
||||
return new Header(key, value);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
if (!super.equals(o)) {
|
||||
return false;
|
||||
}
|
||||
Header header = (Header) o;
|
||||
return Objects.equals(name, header.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Header{" + "\nname='" + name + '\'' + "} \n" + super.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,490 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Represents a set of headers of a request / response or a message.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class Headers {
|
||||
|
||||
private static final BiFunction<String, Header, Object> CLIENT_SIDE = (s,
|
||||
header) -> ContractUtils.convertStubSideRecursively(header);
|
||||
|
||||
private static final BiFunction<String, Header, Object> SERVER_SIDE = (s,
|
||||
header) -> ContractUtils.convertTestSideRecursively(header);
|
||||
|
||||
private MediaTypes mediaTypes = new MediaTypes();
|
||||
|
||||
private HttpHeaders httpHeaders = new HttpHeaders();
|
||||
|
||||
private MessagingHeaders messagingHeaders = new MessagingHeaders();
|
||||
|
||||
private Set<Header> entries = new LinkedHashSet<>();
|
||||
|
||||
public void header(Map<String, Object> singleHeader) {
|
||||
Iterator<Map.Entry<String, Object>> iterator = singleHeader.entrySet().iterator();
|
||||
if (iterator.hasNext()) {
|
||||
Map.Entry<String, Object> first = iterator.next();
|
||||
if (first != null) {
|
||||
entries.add(Header.build(first.getKey(), first.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void header(String headerKey, Object headerValue) {
|
||||
entries.add(Header.build(headerKey, headerValue));
|
||||
}
|
||||
|
||||
public void executeForEachHeader(final Consumer<Header> consumer) {
|
||||
entries.forEach(consumer);
|
||||
}
|
||||
|
||||
public void headers(Set<Header> headers) {
|
||||
entries.addAll(headers);
|
||||
}
|
||||
|
||||
public void accept(String contentType) {
|
||||
header(accept(), matching(contentType));
|
||||
}
|
||||
|
||||
public void contentType(String contentType) {
|
||||
header(httpHeaders.contentType(), matching(contentType));
|
||||
}
|
||||
|
||||
public void messagingContentType(String contentType) {
|
||||
header(messagingHeaders.messagingContentType(), matching(contentType));
|
||||
}
|
||||
|
||||
/**
|
||||
* If for the consumer / producer you want to match exactly only the root of content
|
||||
* type. I.e. {@code application/json;charset=UTF8} you care only about
|
||||
* {@code application/json} then you should use this method
|
||||
* @param value regex as String
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty matching(String value) {
|
||||
return new DslProperty(value);
|
||||
}
|
||||
|
||||
protected NotToEscapePattern notEscaped(Pattern pattern) {
|
||||
return new NotToEscapePattern(pattern);
|
||||
}
|
||||
|
||||
public Map<String, Object> asMap(final BiFunction<String, Header, Object> consumer) {
|
||||
final Map<String, Object> map = new LinkedHashMap<>();
|
||||
entries.forEach(header -> map.put(header.getName(),
|
||||
consumer.apply(header.getName(), header)));
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the headers into their stub side representations and returns as a map of
|
||||
* String key => Object value.
|
||||
* @return converted map
|
||||
*/
|
||||
public Map<String, Object> asStubSideMap() {
|
||||
return asMap(CLIENT_SIDE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the headers into their stub side representations and returns as a map of
|
||||
* String key => Object value.
|
||||
* @return converted map
|
||||
*/
|
||||
public Map<String, Object> asTestSideMap() {
|
||||
return asMap(SERVER_SIDE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Headers headers = (Headers) o;
|
||||
return Objects.equals(entries, headers.entries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(entries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Headers{" + "\nentries=" + entries + '}';
|
||||
}
|
||||
|
||||
public MediaTypes getMediaTypes() {
|
||||
return mediaTypes;
|
||||
}
|
||||
|
||||
public void setMediaTypes(MediaTypes mediaTypes) {
|
||||
this.mediaTypes = mediaTypes;
|
||||
}
|
||||
|
||||
public HttpHeaders getHttpHeaders() {
|
||||
return httpHeaders;
|
||||
}
|
||||
|
||||
public void setHttpHeaders(HttpHeaders httpHeaders) {
|
||||
this.httpHeaders = httpHeaders;
|
||||
}
|
||||
|
||||
public MessagingHeaders getMessagingHeaders() {
|
||||
return messagingHeaders;
|
||||
}
|
||||
|
||||
public void setMessagingHeaders(MessagingHeaders messagingHeaders) {
|
||||
this.messagingHeaders = messagingHeaders;
|
||||
}
|
||||
|
||||
public Set<Header> getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
public void setEntries(Set<Header> entries) {
|
||||
this.entries = entries;
|
||||
}
|
||||
|
||||
public String messagingContentType() {
|
||||
return messagingHeaders.messagingContentType();
|
||||
}
|
||||
|
||||
public String accept() {
|
||||
return httpHeaders.accept();
|
||||
}
|
||||
|
||||
public String acceptCharset() {
|
||||
return httpHeaders.acceptCharset();
|
||||
}
|
||||
|
||||
public String acceptEncoding() {
|
||||
return httpHeaders.acceptEncoding();
|
||||
}
|
||||
|
||||
public String acceptLanguage() {
|
||||
return httpHeaders.acceptLanguage();
|
||||
}
|
||||
|
||||
public String acceptRanges() {
|
||||
return httpHeaders.acceptRanges();
|
||||
}
|
||||
|
||||
public String accessControlAllowCredentials() {
|
||||
return httpHeaders.accessControlAllowCredentials();
|
||||
}
|
||||
|
||||
public String accessControlAllowHeaders() {
|
||||
return httpHeaders.accessControlAllowHeaders();
|
||||
}
|
||||
|
||||
public String accessControlAllowMethods() {
|
||||
return httpHeaders.accessControlAllowMethods();
|
||||
}
|
||||
|
||||
public String accessControlAllowOrigin() {
|
||||
return httpHeaders.accessControlAllowOrigin();
|
||||
}
|
||||
|
||||
public String accessControlExposeHeaders() {
|
||||
return httpHeaders.accessControlExposeHeaders();
|
||||
}
|
||||
|
||||
public String accessControlMaxAge() {
|
||||
return httpHeaders.accessControlMaxAge();
|
||||
}
|
||||
|
||||
public String accessControlRequestHeaders() {
|
||||
return httpHeaders.accessControlRequestHeaders();
|
||||
}
|
||||
|
||||
public String accessControlRequestMethod() {
|
||||
return httpHeaders.accessControlRequestMethod();
|
||||
}
|
||||
|
||||
public String age() {
|
||||
return httpHeaders.age();
|
||||
}
|
||||
|
||||
public String allow() {
|
||||
return httpHeaders.allow();
|
||||
}
|
||||
|
||||
public String authorization() {
|
||||
return httpHeaders.authorization();
|
||||
}
|
||||
|
||||
public String cacheControl() {
|
||||
return httpHeaders.cacheControl();
|
||||
}
|
||||
|
||||
public String connection() {
|
||||
return httpHeaders.connection();
|
||||
}
|
||||
|
||||
public String contentEncoding() {
|
||||
return httpHeaders.contentEncoding();
|
||||
}
|
||||
|
||||
public String contentDisposition() {
|
||||
return httpHeaders.contentDisposition();
|
||||
}
|
||||
|
||||
public String contentLanguage() {
|
||||
return httpHeaders.contentLanguage();
|
||||
}
|
||||
|
||||
public String contentLength() {
|
||||
return httpHeaders.contentLength();
|
||||
}
|
||||
|
||||
public String contentLocation() {
|
||||
return httpHeaders.contentLocation();
|
||||
}
|
||||
|
||||
public String contentRange() {
|
||||
return httpHeaders.contentRange();
|
||||
}
|
||||
|
||||
public String contentType() {
|
||||
return httpHeaders.contentType();
|
||||
}
|
||||
|
||||
public String cookie() {
|
||||
return httpHeaders.cookie();
|
||||
}
|
||||
|
||||
public String date() {
|
||||
return httpHeaders.date();
|
||||
}
|
||||
|
||||
public String etag() {
|
||||
return httpHeaders.etag();
|
||||
}
|
||||
|
||||
public String expect() {
|
||||
return httpHeaders.expect();
|
||||
}
|
||||
|
||||
public String expires() {
|
||||
return httpHeaders.expires();
|
||||
}
|
||||
|
||||
public String from() {
|
||||
return httpHeaders.from();
|
||||
}
|
||||
|
||||
public String host() {
|
||||
return httpHeaders.host();
|
||||
}
|
||||
|
||||
public String ifMatch() {
|
||||
return httpHeaders.ifMatch();
|
||||
}
|
||||
|
||||
public String ifModifiedSince() {
|
||||
return httpHeaders.ifModifiedSince();
|
||||
}
|
||||
|
||||
public String ifNoneMatch() {
|
||||
return httpHeaders.ifNoneMatch();
|
||||
}
|
||||
|
||||
public String ifRange() {
|
||||
return httpHeaders.ifRange();
|
||||
}
|
||||
|
||||
public String ifUnmodifiedSince() {
|
||||
return httpHeaders.ifUnmodifiedSince();
|
||||
}
|
||||
|
||||
public String lastModified() {
|
||||
return httpHeaders.lastModified();
|
||||
}
|
||||
|
||||
public String link() {
|
||||
return httpHeaders.link();
|
||||
}
|
||||
|
||||
public String location() {
|
||||
return httpHeaders.location();
|
||||
}
|
||||
|
||||
public String max_forwards() {
|
||||
return httpHeaders.max_forwards();
|
||||
}
|
||||
|
||||
public String origin() {
|
||||
return httpHeaders.origin();
|
||||
}
|
||||
|
||||
public String pragma() {
|
||||
return httpHeaders.pragma();
|
||||
}
|
||||
|
||||
public String proxyAuthenticate() {
|
||||
return httpHeaders.proxyAuthenticate();
|
||||
}
|
||||
|
||||
public String proxyAuthorization() {
|
||||
return httpHeaders.proxyAuthorization();
|
||||
}
|
||||
|
||||
public String range() {
|
||||
return httpHeaders.range();
|
||||
}
|
||||
|
||||
public String referer() {
|
||||
return httpHeaders.referer();
|
||||
}
|
||||
|
||||
public String retryAfter() {
|
||||
return httpHeaders.retryAfter();
|
||||
}
|
||||
|
||||
public String server() {
|
||||
return httpHeaders.server();
|
||||
}
|
||||
|
||||
public String setCookie() {
|
||||
return httpHeaders.setCookie();
|
||||
}
|
||||
|
||||
public String setCookie2() {
|
||||
return httpHeaders.setCookie2();
|
||||
}
|
||||
|
||||
public String te() {
|
||||
return httpHeaders.te();
|
||||
}
|
||||
|
||||
public String trailer() {
|
||||
return httpHeaders.trailer();
|
||||
}
|
||||
|
||||
public String transferEncoding() {
|
||||
return httpHeaders.transferEncoding();
|
||||
}
|
||||
|
||||
public String upgrade() {
|
||||
return httpHeaders.upgrade();
|
||||
}
|
||||
|
||||
public String user_agent() {
|
||||
return httpHeaders.user_agent();
|
||||
}
|
||||
|
||||
public String vary() {
|
||||
return httpHeaders.vary();
|
||||
}
|
||||
|
||||
public String via() {
|
||||
return httpHeaders.via();
|
||||
}
|
||||
|
||||
public String warning() {
|
||||
return httpHeaders.warning();
|
||||
}
|
||||
|
||||
public String wwwAuthenticate() {
|
||||
return httpHeaders.wwwAuthenticate();
|
||||
}
|
||||
|
||||
public String allValue() {
|
||||
return mediaTypes.allValue();
|
||||
}
|
||||
|
||||
public String applicationAtomXml() {
|
||||
return mediaTypes.applicationAtomXml();
|
||||
}
|
||||
|
||||
public String applicationFormUrlencoded() {
|
||||
return mediaTypes.applicationFormUrlencoded();
|
||||
}
|
||||
|
||||
public String applicationJson() {
|
||||
return mediaTypes.applicationJson();
|
||||
}
|
||||
|
||||
public String applicationJsonUtf8() {
|
||||
return mediaTypes.applicationJsonUtf8();
|
||||
}
|
||||
|
||||
public String applicationOctetStream() {
|
||||
return mediaTypes.applicationOctetStream();
|
||||
}
|
||||
|
||||
public String applicationPdf() {
|
||||
return mediaTypes.applicationPdf();
|
||||
}
|
||||
|
||||
public String applicationXhtmlXml() {
|
||||
return mediaTypes.applicationXhtmlXml();
|
||||
}
|
||||
|
||||
public String applicationXml() {
|
||||
return mediaTypes.applicationXml();
|
||||
}
|
||||
|
||||
public String imageGif() {
|
||||
return mediaTypes.imageGif();
|
||||
}
|
||||
|
||||
public String imageJpeg() {
|
||||
return mediaTypes.imageJpeg();
|
||||
}
|
||||
|
||||
public String imagePng() {
|
||||
return mediaTypes.imagePng();
|
||||
}
|
||||
|
||||
public String multipartFormData() {
|
||||
return mediaTypes.multipartFormData();
|
||||
}
|
||||
|
||||
public String textHtml() {
|
||||
return mediaTypes.textHtml();
|
||||
}
|
||||
|
||||
public String textMarkdown() {
|
||||
return mediaTypes.textMarkdown();
|
||||
}
|
||||
|
||||
public String textPlain() {
|
||||
return mediaTypes.textPlain();
|
||||
}
|
||||
|
||||
public String textXml() {
|
||||
return mediaTypes.textXml();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,555 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
/**
|
||||
* Contains most commonly used http headers.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 1.0.2
|
||||
*/
|
||||
public class HttpHeaders {
|
||||
|
||||
/**
|
||||
* The HTTP {@code Accept} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-5.3.2" > Section 5.3.2 of
|
||||
* RFC 7231</a>
|
||||
*/
|
||||
public String accept() {
|
||||
return "Accept";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Accept-Charset} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-5.3.3" > Section 5.3.3 of
|
||||
* RFC 7231</a>
|
||||
*/
|
||||
public String acceptCharset() {
|
||||
return "Accept-Charset";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Accept-Encoding} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-5.3.4" > Section 5.3.4 of
|
||||
* RFC 7231</a>
|
||||
*/
|
||||
public String acceptEncoding() {
|
||||
return "Accept-Encoding";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Accept-Language} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-5.3.5" > Section 5.3.5 of
|
||||
* RFC 7231</a>
|
||||
*/
|
||||
public String acceptLanguage() {
|
||||
return "Accept-Language";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Accept-Ranges} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7233#section-2.3" > Section 5.3.5 of
|
||||
* RFC 7233</a>
|
||||
*/
|
||||
public String acceptRanges() {
|
||||
return "Accept-Ranges";
|
||||
}
|
||||
|
||||
/**
|
||||
* The CORS {@code Access-Control-Allow-Credentials} response header field name.
|
||||
* @see <ahref="https://www.w3.org/TR/cors/" > CORS W3C recommendation</a>
|
||||
*/
|
||||
public String accessControlAllowCredentials() {
|
||||
return "Access-Control-Allow-Credentials";
|
||||
}
|
||||
|
||||
/**
|
||||
* The CORS {@code Access-Control-Allow-Headers} response header field name.
|
||||
* @see <ahref="https://www.w3.org/TR/cors/" > CORS W3C recommendation</a>
|
||||
*/
|
||||
public String accessControlAllowHeaders() {
|
||||
return "Access-Control-Allow-Headers";
|
||||
}
|
||||
|
||||
/**
|
||||
* The CORS {@code Access-Control-Allow-Methods} response header field name.
|
||||
* @see <ahref="https://www.w3.org/TR/cors/" > CORS W3C recommendation</a>
|
||||
*/
|
||||
public String accessControlAllowMethods() {
|
||||
return "Access-Control-Allow-Methods";
|
||||
}
|
||||
|
||||
/**
|
||||
* The CORS {@code Access-Control-Allow-Origin} response header field name.
|
||||
* @see <ahref="https://www.w3.org/TR/cors/" > CORS W3C recommendation</a>
|
||||
*/
|
||||
public String accessControlAllowOrigin() {
|
||||
return "Access-Control-Allow-Origin";
|
||||
}
|
||||
|
||||
/**
|
||||
* The CORS {@code Access-Control-Expose-Headers} response header field name.
|
||||
* @see <ahref="https://www.w3.org/TR/cors/" > CORS W3C recommendation</a>
|
||||
*/
|
||||
public String accessControlExposeHeaders() {
|
||||
return "Access-Control-Expose-Headers";
|
||||
}
|
||||
|
||||
/**
|
||||
* The CORS {@code Access-Control-Max-Age} response header field name.
|
||||
* @see <ahref="https://www.w3.org/TR/cors/" > CORS W3C recommendation</a>
|
||||
*/
|
||||
public String accessControlMaxAge() {
|
||||
return "Access-Control-Max-Age";
|
||||
}
|
||||
|
||||
/**
|
||||
* The CORS {@code Access-Control-Request-Headers} request header field name.
|
||||
* @see <ahref="https://www.w3.org/TR/cors/" > CORS W3C recommendation</a>
|
||||
*/
|
||||
public String accessControlRequestHeaders() {
|
||||
return "Access-Control-Request-Headers";
|
||||
}
|
||||
|
||||
/**
|
||||
* The CORS {@code Access-Control-Request-Method} request header field name.
|
||||
* @see <ahref="https://www.w3.org/TR/cors/" > CORS W3C recommendation</a>
|
||||
*/
|
||||
public String accessControlRequestMethod() {
|
||||
return "Access-Control-Request-Method";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Age} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7234#section-5.1" > Section 5.1 of RFC
|
||||
* 7234</a>
|
||||
*/
|
||||
public String age() {
|
||||
return "Age";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Allow} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-7.4.1" > Section 7.4.1 of
|
||||
* RFC 7231</a>
|
||||
*/
|
||||
public String allow() {
|
||||
return "Allow";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Authorization} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7235#section-4.2" > Section 4.2 of RFC
|
||||
* 7235</a>
|
||||
*/
|
||||
public String authorization() {
|
||||
return "Authorization";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Cache-Control} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7234#section-5.2" > Section 5.2 of RFC
|
||||
* 7234</a>
|
||||
*/
|
||||
public String cacheControl() {
|
||||
return "Cache-Control";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Connection} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7230#section-6.1" > Section 6.1 of RFC
|
||||
* 7230</a>
|
||||
*/
|
||||
public String connection() {
|
||||
return "Connection";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Content-Encoding} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-3.1.2.2" > Section 3.1.2.2
|
||||
* of RFC 7231</a>
|
||||
*/
|
||||
public String contentEncoding() {
|
||||
return "Content-Encoding";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Content-Disposition} header field name
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc6266" > RFC 6266</a>
|
||||
*/
|
||||
public String contentDisposition() {
|
||||
return "Content-Disposition";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Content-Language} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-3.1.3.2" > Section 3.1.3.2
|
||||
* of RFC 7231</a>
|
||||
*/
|
||||
public String contentLanguage() {
|
||||
return "Content-Language";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Content-Length} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7230#section-3.3.2" > Section 3.3.2 of
|
||||
* RFC 7230</a>
|
||||
*/
|
||||
public String contentLength() {
|
||||
return "Content-Length";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Content-Location} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-3.1.4.2" > Section 3.1.4.2
|
||||
* of RFC 7231</a>
|
||||
*/
|
||||
public String contentLocation() {
|
||||
return "Content-Location";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Content-Range} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7233#section-4.2" > Section 4.2 of RFC
|
||||
* 7233</a>
|
||||
*/
|
||||
public String contentRange() {
|
||||
return "Content-Range";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Content-Type} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-3.1.1.5" > Section 3.1.1.5
|
||||
* of RFC 7231</a>
|
||||
*/
|
||||
public String contentType() {
|
||||
return "Content-Type";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Cookie} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc2109#section-4.3.4" > Section 4.3.4 of
|
||||
* RFC 2109</a>
|
||||
*/
|
||||
public String cookie() {
|
||||
return "Cookie";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Date} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-7.1.1.2" > Section 7.1.1.2
|
||||
* of RFC 7231</a>
|
||||
*/
|
||||
public String date() {
|
||||
return "Date";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code ETag} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7232#section-2.3" > Section 2.3 of RFC
|
||||
* 7232</a>
|
||||
*/
|
||||
public String etag() {
|
||||
return "ETag";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Expect} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-5.1.1" > Section 5.1.1 of
|
||||
* RFC 7231</a>
|
||||
*/
|
||||
public String expect() {
|
||||
return "Expect";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Expires} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7234#section-5.3" > Section 5.3 of RFC
|
||||
* 7234</a>
|
||||
*/
|
||||
public String expires() {
|
||||
return "Expires";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code From} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-5.5.1" > Section 5.5.1 of
|
||||
* RFC 7231</a>
|
||||
*/
|
||||
public String from() {
|
||||
return "From";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Host} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7230#section-5.4" > Section 5.4 of RFC
|
||||
* 7230</a>
|
||||
*/
|
||||
public String host() {
|
||||
return "Host";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code If-Match} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7232#section-3.1" > Section 3.1 of RFC
|
||||
* 7232</a>
|
||||
*/
|
||||
public String ifMatch() {
|
||||
return "If-Match";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code If-Modified-Since} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7232#section-3.3" > Section 3.3 of RFC
|
||||
* 7232</a>
|
||||
*/
|
||||
public String ifModifiedSince() {
|
||||
return "If-Modified-Since";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code If-None-Match} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7232#section-3.2" > Section 3.2 of RFC
|
||||
* 7232</a>
|
||||
*/
|
||||
public String ifNoneMatch() {
|
||||
return "If-None-Match";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code If-Range} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7233#section-3.2" > Section 3.2 of RFC
|
||||
* 7233</a>
|
||||
*/
|
||||
public String ifRange() {
|
||||
return "If-Range";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code If-Unmodified-Since} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7232#section-3.4" > Section 3.4 of RFC
|
||||
* 7232</a>
|
||||
*/
|
||||
public String ifUnmodifiedSince() {
|
||||
return "If-Unmodified-Since";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Last-Modified} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7232#section-2.2" > Section 2.2 of RFC
|
||||
* 7232</a>
|
||||
*/
|
||||
public String lastModified() {
|
||||
return "Last-Modified";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Link} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc5988" > RFC 5988</a>
|
||||
*/
|
||||
public String link() {
|
||||
return "Link";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Location} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-7.1.2" > Section 7.1.2 of
|
||||
* RFC 7231</a>
|
||||
*/
|
||||
public String location() {
|
||||
return "Location";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Max-Forwards} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-5.1.2" > Section 5.1.2 of
|
||||
* RFC 7231</a>
|
||||
*/
|
||||
public String max_forwards() {
|
||||
return "Max-Forwards";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Origin} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc6454" > RFC 6454</a>
|
||||
*/
|
||||
public String origin() {
|
||||
return "Origin";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Pragma} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7234#section-5.4" > Section 5.4 of RFC
|
||||
* 7234</a>
|
||||
*/
|
||||
public String pragma() {
|
||||
return "Pragma";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Proxy-Authenticate} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7235#section-4.3" > Section 4.3 of RFC
|
||||
* 7235</a>
|
||||
*/
|
||||
public String proxyAuthenticate() {
|
||||
return "Proxy-Authenticate";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Proxy-Authorization} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7235#section-4.4" > Section 4.4 of RFC
|
||||
* 7235</a>
|
||||
*/
|
||||
public String proxyAuthorization() {
|
||||
return "Proxy-Authorization";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Range} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7233#section-3.1" > Section 3.1 of RFC
|
||||
* 7233</a>
|
||||
*/
|
||||
public String range() {
|
||||
return "Range";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Referer} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-5.5.2" > Section 5.5.2 of
|
||||
* RFC 7231</a>
|
||||
*/
|
||||
public String referer() {
|
||||
return "Referer";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Retry-After} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-7.1.3" > Section 7.1.3 of
|
||||
* RFC 7231</a>
|
||||
*/
|
||||
public String retryAfter() {
|
||||
return "Retry-After";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Server} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-7.4.2" > Section 7.4.2 of
|
||||
* RFC 7231</a>
|
||||
*/
|
||||
public String server() {
|
||||
return "Server";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Set-Cookie} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc2109#section-4.2.2" > Section 4.2.2 of
|
||||
* RFC 2109</a>
|
||||
*/
|
||||
public String setCookie() {
|
||||
return "Set-Cookie";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Set-Cookie2} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc2965" > RFC 2965</a>
|
||||
*/
|
||||
public String setCookie2() {
|
||||
return "Set-Cookie2";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code TE} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7230#section-4.3" > Section 4.3 of RFC
|
||||
* 7230</a>
|
||||
*/
|
||||
public String te() {
|
||||
return "TE";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Trailer} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7230#section-4.4" > Section 4.4 of RFC
|
||||
* 7230</a>
|
||||
*/
|
||||
public String trailer() {
|
||||
return "Trailer";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Transfer-Encoding} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7230#section-3.3.1" > Section 3.3.1 of
|
||||
* RFC 7230</a>
|
||||
*/
|
||||
public String transferEncoding() {
|
||||
return "Transfer-Encoding";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Upgrade} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7230#section-6.7" > Section 6.7 of RFC
|
||||
* 7230</a>
|
||||
*/
|
||||
public String upgrade() {
|
||||
return "Upgrade";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code User-Agent} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-5.5.3" > Section 5.5.3 of
|
||||
* RFC 7231</a>
|
||||
*/
|
||||
public String user_agent() {
|
||||
return "User-Agent";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Vary} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-7.1.4" > Section 7.1.4 of
|
||||
* RFC 7231</a>
|
||||
*/
|
||||
public String vary() {
|
||||
return "Vary";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Via} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7230#section-5.7.1" > Section 5.7.1 of
|
||||
* RFC 7230</a>
|
||||
*/
|
||||
public String via() {
|
||||
return "Via";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code Warning} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7234#section-5.5" > Section 5.5 of RFC
|
||||
* 7234</a>
|
||||
*/
|
||||
public String warning() {
|
||||
return "Warning";
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP {@code WWW-Authenticate} header field name.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7235#section-4.1" > Section 4.1 of RFC
|
||||
* 7235</a>
|
||||
*/
|
||||
public String wwwAuthenticate() {
|
||||
return "WWW-Authenticate";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
/**
|
||||
* Contains Http Methods.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 1.0.2
|
||||
*/
|
||||
public class HttpMethods {
|
||||
|
||||
public HttpMethod GET() {
|
||||
return HttpMethod.GET;
|
||||
}
|
||||
|
||||
public HttpMethod HEAD() {
|
||||
return HttpMethod.HEAD;
|
||||
}
|
||||
|
||||
public HttpMethod POST() {
|
||||
return HttpMethod.POST;
|
||||
}
|
||||
|
||||
public HttpMethod PUT() {
|
||||
return HttpMethod.PUT;
|
||||
}
|
||||
|
||||
public HttpMethod PATCH() {
|
||||
return HttpMethod.PATCH;
|
||||
}
|
||||
|
||||
public HttpMethod DELETE() {
|
||||
return HttpMethod.DELETE;
|
||||
}
|
||||
|
||||
public HttpMethod OPTIONS() {
|
||||
return HttpMethod.OPTIONS;
|
||||
}
|
||||
|
||||
public HttpMethod TRACE() {
|
||||
return HttpMethod.TRACE;
|
||||
}
|
||||
|
||||
public enum HttpMethod {
|
||||
|
||||
GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,635 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
/**
|
||||
* Helper functions for HTTP statuses.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class HttpStatus {
|
||||
|
||||
/**
|
||||
* {@code 100 Continue}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.2.1" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.2.1</a>
|
||||
*/
|
||||
public int CONTINUE() {
|
||||
return 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 101 Switching Protocols}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.2.2" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.2.2</a>
|
||||
*/
|
||||
public int SWITCHING_PROTOCOLS() {
|
||||
return 101;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 102 Processing}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc2518#section-10.1" > WebDAV</a>
|
||||
*/
|
||||
public int PROCESSING() {
|
||||
return 102;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 103 Checkpoint}.
|
||||
* @see <ahref="https://code.google.com/p/gears/wiki/ResumableHttpRequestsProposal" >
|
||||
* A proposal for supporting resumable POST/PUT HTTP requests in HTTP/1.0</a>
|
||||
*/
|
||||
public int CHECKPOINT() {
|
||||
return 103;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 200 OK}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.3.1" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.3.1</a>
|
||||
*/
|
||||
public int OK() {
|
||||
return 200;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 201 Created}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.3.2" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.3.2</a>
|
||||
*/
|
||||
public int CREATED() {
|
||||
return 201;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 202 Accepted}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.3.3" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.3.3</a>
|
||||
*/
|
||||
public int ACCEPTED() {
|
||||
return 202;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 203 Non-Authoritative Information}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.3.4" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.3.4</a>
|
||||
*/
|
||||
public int NON_AUTHORITATIVE_INFORMATION() {
|
||||
return 203;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 204 No Content}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.3.5" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.3.5</a>
|
||||
*/
|
||||
public int NO_CONTENT() {
|
||||
return 204;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 205 Reset Content}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.3.6" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.3.6</a>
|
||||
*/
|
||||
public int RESET_CONTENT() {
|
||||
return 205;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 206 Partial Content}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7233#section-4.1" > HTTP/1.1: Range
|
||||
* Requests, section 4.1</a>
|
||||
*/
|
||||
public int PARTIAL_CONTENT() {
|
||||
return 206;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 207 Multi-Status}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc4918#section-13" > WebDAV</a>
|
||||
*/
|
||||
public int MULTI_STATUS() {
|
||||
return 207;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 208 Already Reported}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc5842#section-7.1" > WebDAV Binding
|
||||
* Extensions</a>
|
||||
*/
|
||||
public int ALREADY_REPORTED() {
|
||||
return 208;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 226 IM Used}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc3229#section-10.4.1" > Delta encoding
|
||||
* in HTTP</a>
|
||||
*/
|
||||
public int IM_USED() {
|
||||
return 226;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 300 Multiple Choices}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.4.1" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.4.1</a>
|
||||
*/
|
||||
public int MULTIPLE_CHOICES() {
|
||||
return 300;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 301 Moved Permanently}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.4.2" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.4.2</a>
|
||||
*/
|
||||
public int MOVED_PERMANENTLY() {
|
||||
return 301;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 302 Found}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.4.3" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.4.3</a>
|
||||
*/
|
||||
public int FOUND() {
|
||||
return 302;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 302 Moved Temporarily}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc1945#section-9.3" > HTTP/1.0, section
|
||||
* 9.3</a>
|
||||
* @deprecated in favor of {@link #FOUND} which will be returned from
|
||||
* {@code HttpStatus.valueOf(302)}
|
||||
*/
|
||||
@Deprecated
|
||||
public int MOVED_TEMPORARILY() {
|
||||
return 302;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 303 See Other}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.4.4" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.4.4</a>
|
||||
*/
|
||||
public int SEE_OTHER() {
|
||||
return 303;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 304 Not Modified}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7232#section-4.1" > HTTP/1.1:
|
||||
* Conditional Requests, section 4.1</a>
|
||||
*/
|
||||
public int NOT_MODIFIED() {
|
||||
return 304;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 305 Use Proxy}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.4.5" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.4.5</a>
|
||||
* @deprecated due to security concerns regarding in-band configuration of a proxy
|
||||
*/
|
||||
@Deprecated
|
||||
public int USE_PROXY() {
|
||||
return 305;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 307 Temporary Redirect}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.4.7" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.4.7</a>
|
||||
*/
|
||||
public int TEMPORARY_REDIRECT() {
|
||||
return 307;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 308 Permanent Redirect}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7238" > RFC 7238</a>
|
||||
*/
|
||||
public int PERMANENT_REDIRECT() {
|
||||
return 308;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 400 Bad Request}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.5.1" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.5.1</a>
|
||||
*/
|
||||
public int BAD_REQUEST() {
|
||||
return 400;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 401 Unauthorized}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7235#section-3.1" > HTTP/1.1:
|
||||
* Authentication, section 3.1</a>
|
||||
*/
|
||||
public int UNAUTHORIZED() {
|
||||
return 401;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 402 Payment Required}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.5.2" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.5.2</a>
|
||||
*/
|
||||
public int PAYMENT_REQUIRED() {
|
||||
return 402;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 403 Forbidden}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.5.3" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.5.3</a>
|
||||
*/
|
||||
public int FORBIDDEN() {
|
||||
return 403;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 404 Not Found}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.5.4" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.5.4</a>
|
||||
*/
|
||||
public int NOT_FOUND() {
|
||||
return 404;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 405 Method Not Allowed}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.5.5" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.5.5</a>
|
||||
*/
|
||||
public int METHOD_NOT_ALLOWED() {
|
||||
return 405;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 406 Not Acceptable}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.5.6" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.5.6</a>
|
||||
*/
|
||||
public int NOT_ACCEPTABLE() {
|
||||
return 406;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 407 Proxy Authentication Required}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7235#section-3.2" > HTTP/1.1:
|
||||
* Authentication, section 3.2</a>
|
||||
*/
|
||||
public int PROXY_AUTHENTICATION_REQUIRED() {
|
||||
return 407;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 408 Request Timeout}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.5.7" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.5.7</a>
|
||||
*/
|
||||
public int REQUEST_TIMEOUT() {
|
||||
return 408;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 409 Conflict}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.5.8" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.5.8</a>
|
||||
*/
|
||||
public int CONFLICT() {
|
||||
return 409;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 410 Gone}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.5.9" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.5.9</a>
|
||||
*/
|
||||
public int GONE() {
|
||||
return 410;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 411 Length Required}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.5.10" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.5.10</a>
|
||||
*/
|
||||
public int LENGTH_REQUIRED() {
|
||||
return 411;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 412 Precondition failed}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7232#section-4.2" > HTTP/1.1:
|
||||
* Conditional Requests, section 4.2</a>
|
||||
*/
|
||||
public int PRECONDITION_FAILED() {
|
||||
return 412;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 413 Payload Too Large}.
|
||||
* @since 4.1* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.5.11" >
|
||||
* HTTP/1.1: Semantics and Content, section 6.5.11</a>
|
||||
*/
|
||||
public int PAYLOAD_TOO_LARGE() {
|
||||
return 413;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 413 Request Entity Too Large}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc2616#section-10.4.14" > HTTP/1.1,
|
||||
* section 10.4.14</a>
|
||||
* @deprecated in favor of {@link #PAYLOAD_TOO_LARGE} which will be returned from
|
||||
* {@code HttpStatus.valueOf(413)}
|
||||
*/
|
||||
@Deprecated
|
||||
public int REQUEST_ENTITY_TOO_LARGE() {
|
||||
return 413;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 414 URI Too Long}.
|
||||
* @since 4.1* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.5.12" >
|
||||
* HTTP/1.1: Semantics and Content, section 6.5.12</a>
|
||||
*/
|
||||
public int URI_TOO_LONG() {
|
||||
return 414;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 414 Request-URI Too Long}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc2616#section-10.4.15" > HTTP/1.1,
|
||||
* section 10.4.15</a>
|
||||
* @deprecated in favor of {@link #URI_TOO_LONG} which will be returned from
|
||||
* {@code HttpStatus.valueOf(414)}
|
||||
*/
|
||||
@Deprecated
|
||||
public int REQUEST_URI_TOO_LONG() {
|
||||
return 414;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 415 Unsupported Media Type}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.5.13" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.5.13</a>
|
||||
*/
|
||||
public int UNSUPPORTED_MEDIA_TYPE() {
|
||||
return 415;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 416 Requested Range Not Satisfiable}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7233#section-4.4" > HTTP/1.1: Range
|
||||
* Requests, section 4.4</a>
|
||||
*/
|
||||
public int REQUESTED_RANGE_NOT_SATISFIABLE() {
|
||||
return 416;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 417 Expectation Failed}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.5.14" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.5.14</a>
|
||||
*/
|
||||
public int EXPECTATION_FAILED() {
|
||||
return 417;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 418 I'm a teapot}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc2324#section-2.3.2" > HTCPCP/1.0</a>
|
||||
*/
|
||||
public int I_AM_A_TEAPOT() {
|
||||
return 418;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated See <a href=
|
||||
* "https://tools.ietf.org/rfcdiff?difftype=--hwdiff&url2=draft-ietf-webdav-protocol-06.txt">WebDAV
|
||||
* Draft Changes</a>
|
||||
*/
|
||||
@Deprecated
|
||||
public int INSUFFICIENT_SPACE_ON_RESOURCE() {
|
||||
return 419;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated See <a href=
|
||||
* "https://tools.ietf.org/rfcdiff?difftype=--hwdiff&url2=draft-ietf-webdav-protocol-06.txt">WebDAV
|
||||
* Draft Changes</a>
|
||||
*/
|
||||
@Deprecated
|
||||
public int METHOD_FAILURE() {
|
||||
return 420;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated See <a href=
|
||||
* "https://tools.ietf.org/rfcdiff?difftype=--hwdiff&url2=draft-ietf-webdav-protocol-06.txt">WebDAV
|
||||
* Draft Changes</a>
|
||||
*/
|
||||
@Deprecated
|
||||
public int DESTINATION_LOCKED() {
|
||||
return 421;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 422 Unprocessable Entity}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc4918#section-11.2" > WebDAV</a>
|
||||
*/
|
||||
public int UNPROCESSABLE_ENTITY() {
|
||||
return 422;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 423 Locked}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc4918#section-11.3" > WebDAV</a>
|
||||
*/
|
||||
public int LOCKED() {
|
||||
return 423;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 424 Failed Dependency}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc4918#section-11.4" > WebDAV</a>
|
||||
*/
|
||||
public int FAILED_DEPENDENCY() {
|
||||
return 424;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 426 Upgrade Required}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc2817#section-6" > Upgrading to TLS
|
||||
* Within HTTP/1.1</a>
|
||||
*/
|
||||
public int UPGRADE_REQUIRED() {
|
||||
return 426;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 428 Precondition Required}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc6585#section-3" > Additional HTTP
|
||||
* Status Codes</a>
|
||||
*/
|
||||
public int PRECONDITION_REQUIRED() {
|
||||
return 428;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 429 Too Many Requests}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc6585#section-4" > Additional HTTP
|
||||
* Status Codes</a>
|
||||
*/
|
||||
public int TOO_MANY_REQUESTS() {
|
||||
return 429;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 431 Request Header Fields Too Large}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc6585#section-5" > Additional HTTP
|
||||
* Status Codes</a>
|
||||
*/
|
||||
public int REQUEST_HEADER_FIELDS_TOO_LARGE() {
|
||||
return 431;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 451 Unavailable For Legal Reasons}.
|
||||
* @see <ahref="https://tools.ietf.org/html/draft-ietf-httpbis-legally-restricted-status-04"
|
||||
* > An HTTP Status Code to Report Legal Obstacles</a>
|
||||
* @since 4.3
|
||||
*/
|
||||
public int UNAVAILABLE_FOR_LEGAL_REASONS() {
|
||||
return 451;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 500 Internal Server Error}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.6.1" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.6.1</a>
|
||||
*/
|
||||
public int INTERNAL_SERVER_ERROR() {
|
||||
return 500;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 501 Not Implemented}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.6.2" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.6.2</a>
|
||||
*/
|
||||
public int NOT_IMPLEMENTED() {
|
||||
return 501;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 502 Bad Gateway}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.6.3" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.6.3</a>
|
||||
*/
|
||||
public int BAD_GATEWAY() {
|
||||
return 502;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 503 Service Unavailable}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.6.4" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.6.4</a>
|
||||
*/
|
||||
public int SERVICE_UNAVAILABLE() {
|
||||
return 503;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 504 Gateway Timeout}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.6.5" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.6.5</a>
|
||||
*/
|
||||
public int GATEWAY_TIMEOUT() {
|
||||
return 504;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 505 HTTP Version Not Supported}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc7231#section-6.6.6" > HTTP/1.1:
|
||||
* Semantics and Content, section 6.6.6</a>
|
||||
*/
|
||||
public int HTTP_VERSION_NOT_SUPPORTED() {
|
||||
return 505;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 506 Variant Also Negotiates}
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc2295#section-8.1" > Transparent Content
|
||||
* Negotiation</a>
|
||||
*/
|
||||
public int VARIANT_ALSO_NEGOTIATES() {
|
||||
return 506;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 507 Insufficient Storage}
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc4918#section-11.5" > WebDAV</a>
|
||||
*/
|
||||
public int INSUFFICIENT_STORAGE() {
|
||||
return 507;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 508 Loop Detected}
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc5842#section-7.2" > WebDAV Binding
|
||||
* Extensions</a>
|
||||
*/
|
||||
public int LOOP_DETECTED() {
|
||||
return 508;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 509 Bandwidth Limit Exceeded}
|
||||
*/
|
||||
public int BANDWIDTH_LIMIT_EXCEEDED() {
|
||||
return 509;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 510 Not Extended}
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc2774#section-7" > HTTP Extension
|
||||
* Framework</a>
|
||||
*/
|
||||
public int NOT_EXTENDED() {
|
||||
return 510;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code 511 Network Authentication Required}.
|
||||
* @see <ahref="https://tools.ietf.org/html/rfc6585#section-6" > Additional HTTP
|
||||
* Status Codes</a>
|
||||
*/
|
||||
public int NETWORK_AUTHENTICATION_REQUIRED() {
|
||||
return 511;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,405 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import groovy.lang.Closure;
|
||||
import groovy.lang.DelegatesTo;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Represents an input for messaging. The input can be a message or some action inside the
|
||||
* application.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Tim Ysewyn
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class Input extends Common implements RegexCreatingProperty<ClientDslProperty> {
|
||||
|
||||
private static final Log log = LogFactory.getLog(Input.class);
|
||||
|
||||
private ClientPatternValueDslProperty property = new ClientPatternValueDslProperty();
|
||||
|
||||
private DslProperty<String> messageFrom;
|
||||
|
||||
private ExecutionProperty triggeredBy;
|
||||
|
||||
private Headers messageHeaders = new Headers();
|
||||
|
||||
private BodyType messageBody;
|
||||
|
||||
private ExecutionProperty assertThat;
|
||||
|
||||
private BodyMatchers bodyMatchers;
|
||||
|
||||
public Input() {
|
||||
}
|
||||
|
||||
public Input(Input input) {
|
||||
this.messageFrom = input.getMessageFrom();
|
||||
this.messageHeaders = input.getMessageHeaders();
|
||||
this.messageBody = input.getMessageBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of a destination from which message would come to trigger action in the
|
||||
* system.
|
||||
* @param messageFrom message destination
|
||||
*/
|
||||
public void messageFrom(String messageFrom) {
|
||||
this.messageFrom = new DslProperty<>(messageFrom);
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of a destination from which message would come to trigger action in the
|
||||
* system.
|
||||
* @param messageFrom message destination
|
||||
*/
|
||||
public void messageFrom(DslProperty messageFrom) {
|
||||
this.messageFrom = messageFrom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that needs to be executed to trigger action in the system.
|
||||
* @param triggeredBy method name that triggers the message
|
||||
*/
|
||||
public void triggeredBy(String triggeredBy) {
|
||||
this.triggeredBy = new ExecutionProperty(triggeredBy);
|
||||
}
|
||||
|
||||
public BodyType messageBody(Object bodyAsValue) {
|
||||
this.messageBody = new BodyType(bodyAsValue);
|
||||
return this.messageBody;
|
||||
}
|
||||
|
||||
public DslProperty value(ClientDslProperty client) {
|
||||
Object dynamicValue = client.getClientValue();
|
||||
Object concreteValue = client.getServerValue();
|
||||
if (dynamicValue instanceof RegexProperty) {
|
||||
return ((RegexProperty) dynamicValue).dynamicClientConcreteProducer();
|
||||
}
|
||||
return new DslProperty(dynamicValue, concreteValue);
|
||||
}
|
||||
|
||||
public DslProperty value(RegexProperty prop) {
|
||||
return value(client(prop));
|
||||
}
|
||||
|
||||
public DslProperty $(RegexProperty prop) {
|
||||
return value(client(prop));
|
||||
}
|
||||
|
||||
public DslProperty $(ClientDslProperty client) {
|
||||
return value(client);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegexProperty regexProperty(Object object) {
|
||||
return new RegexProperty(object).dynamicClientConcreteProducer();
|
||||
}
|
||||
|
||||
public void assertThat(String assertThat) {
|
||||
this.assertThat = new ExecutionProperty(assertThat);
|
||||
}
|
||||
|
||||
public ClientPatternValueDslProperty getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
public void setProperty(ClientPatternValueDslProperty property) {
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
public DslProperty<String> getMessageFrom() {
|
||||
return messageFrom;
|
||||
}
|
||||
|
||||
public void setMessageFrom(DslProperty<String> messageFrom) {
|
||||
this.messageFrom = messageFrom;
|
||||
}
|
||||
|
||||
public ExecutionProperty getTriggeredBy() {
|
||||
return triggeredBy;
|
||||
}
|
||||
|
||||
public void setTriggeredBy(ExecutionProperty triggeredBy) {
|
||||
this.triggeredBy = triggeredBy;
|
||||
}
|
||||
|
||||
public Headers getMessageHeaders() {
|
||||
return messageHeaders;
|
||||
}
|
||||
|
||||
public void setMessageHeaders(Headers messageHeaders) {
|
||||
this.messageHeaders = messageHeaders;
|
||||
}
|
||||
|
||||
public BodyType getMessageBody() {
|
||||
return messageBody;
|
||||
}
|
||||
|
||||
public void setMessageBody(BodyType messageBody) {
|
||||
this.messageBody = messageBody;
|
||||
}
|
||||
|
||||
public ExecutionProperty getAssertThat() {
|
||||
return assertThat;
|
||||
}
|
||||
|
||||
public void setAssertThat(ExecutionProperty assertThat) {
|
||||
this.assertThat = assertThat;
|
||||
}
|
||||
|
||||
public BodyMatchers getBodyMatchers() {
|
||||
return bodyMatchers;
|
||||
}
|
||||
|
||||
public void setBodyMatchers(BodyMatchers bodyMatchers) {
|
||||
this.bodyMatchers = bodyMatchers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyAlphaUnicode() {
|
||||
return property.anyAlphaUnicode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyAlphaNumeric() {
|
||||
return property.anyAlphaNumeric();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyNumber() {
|
||||
return property.anyNumber();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyInteger() {
|
||||
return property.anyInteger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyPositiveInt() {
|
||||
return property.anyPositiveInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyDouble() {
|
||||
return property.anyDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyHex() {
|
||||
return property.anyHex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty aBoolean() {
|
||||
return property.aBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyIpAddress() {
|
||||
return property.anyIpAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyHostname() {
|
||||
return property.anyHostname();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyEmail() {
|
||||
return property.anyEmail();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyUrl() {
|
||||
return property.anyUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyHttpsUrl() {
|
||||
return property.anyHttpsUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyUuid() {
|
||||
return property.anyUuid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyDate() {
|
||||
return property.anyDate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyDateTime() {
|
||||
return property.anyDateTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyTime() {
|
||||
return property.anyTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyIso8601WithOffset() {
|
||||
return property.anyIso8601WithOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyNonBlankString() {
|
||||
return property.anyNonBlankString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyNonEmptyString() {
|
||||
return property.anyNonEmptyString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyOf(String... values) {
|
||||
return property.anyOf(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* The message headers part of the contract.
|
||||
* @param consumer function to manipulate the message headers
|
||||
*/
|
||||
public void messageHeaders(Consumer<Headers> consumer) {
|
||||
this.messageHeaders = new Headers();
|
||||
consumer.accept(this.messageHeaders);
|
||||
}
|
||||
|
||||
/**
|
||||
* The stub matchers part of the contract.
|
||||
* @param consumer function to manipulate the body headers
|
||||
* @deprecated Deprecated in favor of bodyMatchers to support other future
|
||||
* bodyMatchers too
|
||||
*/
|
||||
@Deprecated
|
||||
public void stubMatchers(Consumer<BodyMatchers> consumer) {
|
||||
log.warn("stubMatchers method is deprecated. Please use bodyMatchers instead");
|
||||
bodyMatchers(consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* The stub matchers part of the contract.
|
||||
* @param consumer function to manipulate the message headers
|
||||
* @deprecated Deprecated in favor of bodyMatchers to support other future
|
||||
* bodyMatchers too
|
||||
*/
|
||||
public void bodyMatchers(Consumer<BodyMatchers> consumer) {
|
||||
this.bodyMatchers = new BodyMatchers();
|
||||
consumer.accept(this.bodyMatchers);
|
||||
}
|
||||
|
||||
/**
|
||||
* The message headers part of the contract.
|
||||
* @param consumer function to manipulate the message headers
|
||||
*/
|
||||
public void messageHeaders(@DelegatesTo(Headers.class) Closure consumer) {
|
||||
this.messageHeaders = new Headers();
|
||||
consumer.setDelegate(this.messageHeaders);
|
||||
consumer.call();
|
||||
}
|
||||
|
||||
/**
|
||||
* The stub matchers part of the contract.
|
||||
* @param consumer function to manipulate the body headers
|
||||
* @deprecated Deprecated in favor of bodyMatchers to support other future
|
||||
* bodyMatchers too
|
||||
*/
|
||||
@Deprecated
|
||||
public void stubMatchers(@DelegatesTo(BodyMatchers.class) Closure consumer) {
|
||||
log.warn("stubMatchers method is deprecated. Please use bodyMatchers instead");
|
||||
bodyMatchers(consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* The stub matchers part of the contract.
|
||||
* @param consumer function to manipulate the message headers
|
||||
* @deprecated Deprecated in favor of bodyMatchers to support other future
|
||||
* bodyMatchers too
|
||||
*/
|
||||
public void bodyMatchers(@DelegatesTo(BodyMatchers.class) Closure consumer) {
|
||||
this.bodyMatchers = new BodyMatchers();
|
||||
consumer.setDelegate(this.bodyMatchers);
|
||||
consumer.call();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Input input = (Input) o;
|
||||
return Objects.equals(messageFrom, input.messageFrom)
|
||||
&& Objects.equals(triggeredBy, input.triggeredBy)
|
||||
&& Objects.equals(messageHeaders, input.messageHeaders)
|
||||
&& Objects.equals(messageBody, input.messageBody)
|
||||
&& Objects.equals(assertThat, input.assertThat)
|
||||
&& Objects.equals(bodyMatchers, input.bodyMatchers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(messageFrom, triggeredBy, messageHeaders, messageBody,
|
||||
assertThat, bodyMatchers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Input{\n\tmessageFrom=" + messageFrom + ", \n\ttriggeredBy=" + triggeredBy
|
||||
+ ", \n\tmessageHeaders=" + messageHeaders + ", \n\tmessageBody="
|
||||
+ messageBody + ", \n\tassertThat=" + assertThat + ", \n\tbodyMatchers="
|
||||
+ bodyMatchers + "} \n\t" + super.toString();
|
||||
}
|
||||
|
||||
public static class BodyType extends DslProperty {
|
||||
|
||||
public BodyType(Object clientValue, Object serverValue) {
|
||||
super(clientValue, serverValue);
|
||||
}
|
||||
|
||||
public BodyType(Object singleValue) {
|
||||
super(singleValue);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ClientPatternValueDslProperty
|
||||
extends PatternValueDslProperty<ClientDslProperty> {
|
||||
|
||||
@Override
|
||||
protected ClientDslProperty createProperty(Pattern pattern,
|
||||
Object generatedValue) {
|
||||
return new ClientDslProperty(pattern, generatedValue);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
/**
|
||||
* Represents JSON comparison modes.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public enum JSONCompareMode {
|
||||
|
||||
/**
|
||||
* Strict checking. Not extensible, and strict array ordering.
|
||||
*/
|
||||
STRICT,
|
||||
/**
|
||||
* Lenient checking. Extensible, and non-strict array ordering.
|
||||
*/
|
||||
LENIENT,
|
||||
/**
|
||||
* Non-extensible checking. Not extensible, and non-strict array ordering.
|
||||
*/
|
||||
NON_EXTENSIBLE,
|
||||
/**
|
||||
* Strict order checking. Extensible, and strict array ordering.
|
||||
*/
|
||||
STRICT_ORDER;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents a matching strategy for a JSON.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class MatchingStrategy extends DslProperty {
|
||||
|
||||
private Type type;
|
||||
|
||||
private JSONCompareMode jsonCompareMode;
|
||||
|
||||
public MatchingStrategy(Object value, Type type) {
|
||||
this(value, type, null);
|
||||
}
|
||||
|
||||
public MatchingStrategy(Object value, Type type, JSONCompareMode jsonCompareMode) {
|
||||
super(value);
|
||||
this.type = type;
|
||||
this.jsonCompareMode = jsonCompareMode;
|
||||
}
|
||||
|
||||
public MatchingStrategy(DslProperty value, Type type) {
|
||||
this(value, type, null);
|
||||
}
|
||||
|
||||
public MatchingStrategy(DslProperty value, Type type,
|
||||
JSONCompareMode jsonCompareMode) {
|
||||
super(value.getClientValue(), value.getServerValue());
|
||||
this.type = type;
|
||||
this.jsonCompareMode = jsonCompareMode;
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public JSONCompareMode getJsonCompareMode() {
|
||||
return jsonCompareMode;
|
||||
}
|
||||
|
||||
public void setJsonCompareMode(JSONCompareMode jsonCompareMode) {
|
||||
this.jsonCompareMode = jsonCompareMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MatchingStrategy{" + "type=" + type + ", jsonCompareMode="
|
||||
+ jsonCompareMode + '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
if (!super.equals(o)) {
|
||||
return false;
|
||||
}
|
||||
MatchingStrategy that = (MatchingStrategy) o;
|
||||
return type == that.type && jsonCompareMode == that.jsonCompareMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), type, jsonCompareMode);
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
|
||||
/**
|
||||
* Equality check.
|
||||
*/
|
||||
EQUAL_TO("equalTo"),
|
||||
|
||||
/**
|
||||
* Contains check.
|
||||
*/
|
||||
CONTAINS("containing"),
|
||||
|
||||
/**
|
||||
* Matching check.
|
||||
*/
|
||||
MATCHING("matching"),
|
||||
|
||||
/**
|
||||
* Not matching check.
|
||||
*/
|
||||
NOT_MATCHING("notMatching"),
|
||||
|
||||
/**
|
||||
* Equal to JSON check.
|
||||
*/
|
||||
EQUAL_TO_JSON("equalToJson"),
|
||||
|
||||
/**
|
||||
* Equal to XML check.
|
||||
*/
|
||||
EQUAL_TO_XML("equalToXml"),
|
||||
|
||||
/**
|
||||
* Absence check.
|
||||
*/
|
||||
ABSENT("absent"),
|
||||
|
||||
/**
|
||||
* Binary equality check.
|
||||
*/
|
||||
BINARY_EQUAL_TO("binaryEqualTo");
|
||||
|
||||
private final String name;
|
||||
|
||||
Type(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public final String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
/**
|
||||
* Represents the type of matching the should be done against the body of the request or
|
||||
* response.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Tim Ysewyn
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @since 1.0.3
|
||||
*/
|
||||
public enum MatchingType {
|
||||
|
||||
/**
|
||||
* Verification by equality.
|
||||
*/
|
||||
EQUALITY,
|
||||
/**
|
||||
* Verification by type - is the type received in a body for the given path is of the
|
||||
* same type. If it's a collection you can verify number of occurrences.
|
||||
*/
|
||||
TYPE,
|
||||
/**
|
||||
* Special version of regex for date check.
|
||||
*/
|
||||
DATE,
|
||||
/**
|
||||
* Special version of regex for time check.
|
||||
*/
|
||||
TIME,
|
||||
/**
|
||||
* Special version of regex for timestamp check.
|
||||
*/
|
||||
TIMESTAMP,
|
||||
/**
|
||||
* Verification if the value for the given path matches the provided regex.
|
||||
*/
|
||||
REGEX,
|
||||
/**
|
||||
* The user can provide custom command to execute.
|
||||
*/
|
||||
COMMAND,
|
||||
/**
|
||||
* Verification if the value for the given path is null.
|
||||
*/
|
||||
NULL;
|
||||
|
||||
public static boolean regexRelated(MatchingType type) {
|
||||
return !type.equals(EQUALITY) && !type.equals(TYPE) && !type.equals(COMMAND)
|
||||
&& !type.equals(NULL);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Matching type with corresponding values.
|
||||
*/
|
||||
public class MatchingTypeValue {
|
||||
|
||||
private MatchingType type;
|
||||
|
||||
/**
|
||||
* Value to check.
|
||||
*/
|
||||
private Object value;
|
||||
|
||||
/**
|
||||
* Min occurrence when matching by type.
|
||||
*/
|
||||
private Integer minTypeOccurrence;
|
||||
|
||||
/**
|
||||
* Max occurrence when matching by type.
|
||||
*/
|
||||
private Integer maxTypeOccurrence;
|
||||
|
||||
MatchingTypeValue() {
|
||||
}
|
||||
|
||||
MatchingTypeValue(MatchingType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
MatchingTypeValue(MatchingType type, Object value) {
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
MatchingTypeValue(MatchingType type, Object value, Integer minTypeOccurrence) {
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
this.minTypeOccurrence = minTypeOccurrence;
|
||||
}
|
||||
|
||||
MatchingTypeValue(MatchingType type, Object value, Integer minTypeOccurrence,
|
||||
Integer maxTypeOccurrence) {
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
this.minTypeOccurrence = minTypeOccurrence;
|
||||
this.maxTypeOccurrence = maxTypeOccurrence;
|
||||
}
|
||||
|
||||
public MatchingType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(MatchingType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Integer getMinTypeOccurrence() {
|
||||
return minTypeOccurrence;
|
||||
}
|
||||
|
||||
public void setMinTypeOccurrence(Integer minTypeOccurrence) {
|
||||
this.minTypeOccurrence = minTypeOccurrence;
|
||||
}
|
||||
|
||||
public Integer getMaxTypeOccurrence() {
|
||||
return maxTypeOccurrence;
|
||||
}
|
||||
|
||||
public void setMaxTypeOccurrence(Integer maxTypeOccurrence) {
|
||||
this.maxTypeOccurrence = maxTypeOccurrence;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
MatchingTypeValue value1 = (MatchingTypeValue) o;
|
||||
return type == value1.type && Objects.equals(value, value1.value)
|
||||
&& Objects.equals(minTypeOccurrence, value1.minTypeOccurrence)
|
||||
&& Objects.equals(maxTypeOccurrence, value1.maxTypeOccurrence);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(type, value, minTypeOccurrence, maxTypeOccurrence);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MatchingTypeValue{" + "type=" + type + ", value=" + value
|
||||
+ ", minTypeOccurrence=" + minTypeOccurrence + ", maxTypeOccurrence="
|
||||
+ maxTypeOccurrence + '}';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
public class MatchingTypeValueHolder {
|
||||
|
||||
MatchingTypeValue matchingTypeValue = new MatchingTypeValue(MatchingType.TYPE);
|
||||
|
||||
public MatchingTypeValue minOccurrence(int number) {
|
||||
this.matchingTypeValue.setMinTypeOccurrence(number);
|
||||
return this.matchingTypeValue;
|
||||
}
|
||||
|
||||
public MatchingTypeValue maxOccurrence(int number) {
|
||||
this.matchingTypeValue.setMaxTypeOccurrence(number);
|
||||
return this.matchingTypeValue;
|
||||
}
|
||||
|
||||
public MatchingTypeValue occurrence(int number) {
|
||||
this.matchingTypeValue.setMinTypeOccurrence(number);
|
||||
this.matchingTypeValue.setMaxTypeOccurrence(number);
|
||||
return this.matchingTypeValue;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
/**
|
||||
* Contains most commonly used media types.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 1.0.2
|
||||
*/
|
||||
public class MediaTypes {
|
||||
|
||||
public String allValue() {
|
||||
return "*/*";
|
||||
}
|
||||
|
||||
public String applicationAtomXml() {
|
||||
return "application/atom+xml";
|
||||
}
|
||||
|
||||
public String applicationFormUrlencoded() {
|
||||
return "application/x-www-form-urlencoded";
|
||||
}
|
||||
|
||||
public String applicationJson() {
|
||||
return "application/json";
|
||||
}
|
||||
|
||||
public String applicationJsonUtf8() {
|
||||
return applicationJson() + ";charset=UTF-8";
|
||||
}
|
||||
|
||||
public String applicationOctetStream() {
|
||||
return "application/octet-stream";
|
||||
}
|
||||
|
||||
public String applicationPdf() {
|
||||
return "application/pdf";
|
||||
}
|
||||
|
||||
public String applicationXhtmlXml() {
|
||||
return "application/xhtml+xml";
|
||||
}
|
||||
|
||||
public String applicationXml() {
|
||||
return "application/xml";
|
||||
}
|
||||
|
||||
public String imageGif() {
|
||||
return "image/gif";
|
||||
}
|
||||
|
||||
public String imageJpeg() {
|
||||
return "image/jpeg";
|
||||
}
|
||||
|
||||
public String imagePng() {
|
||||
return "image/png";
|
||||
}
|
||||
|
||||
public String multipartFormData() {
|
||||
return "multipart/form-data";
|
||||
}
|
||||
|
||||
public String textHtml() {
|
||||
return "text/html";
|
||||
}
|
||||
|
||||
public String textMarkdown() {
|
||||
return "text/markdown";
|
||||
}
|
||||
|
||||
public String textPlain() {
|
||||
return "text/plain";
|
||||
}
|
||||
|
||||
public String textXml() {
|
||||
return "text/xml";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
/**
|
||||
* Contains most commonly used messaging headers.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 1.1.2
|
||||
*/
|
||||
public class MessagingHeaders {
|
||||
|
||||
/**
|
||||
* The Content Type of a message.
|
||||
* @return messaging content type
|
||||
*/
|
||||
public String messagingContentType() {
|
||||
return "contentType";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Multipart extends DslProperty {
|
||||
|
||||
public Multipart(Map<String, DslProperty> multipart) {
|
||||
super(extractValue(multipart, ContractUtils.CLIENT_VALUE),
|
||||
extractValue(multipart, ContractUtils.SERVER_VALUE));
|
||||
}
|
||||
|
||||
public Multipart(List<DslProperty> multipartAsList) {
|
||||
super(multipartAsList.stream().map(DslProperty::getClientValue)
|
||||
.collect(Collectors.toList()),
|
||||
multipartAsList.stream().map(DslProperty::getServerValue)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
public Multipart(Object value) {
|
||||
super(ContractUtils.CLIENT_VALUE.apply(value),
|
||||
ContractUtils.SERVER_VALUE.apply(value));
|
||||
}
|
||||
|
||||
public Multipart(DslProperty multipartAsValue) {
|
||||
super(multipartAsValue.getClientValue(), multipartAsValue.getServerValue());
|
||||
}
|
||||
|
||||
public Multipart(MatchingStrategy matchingStrategy) {
|
||||
super(matchingStrategy);
|
||||
}
|
||||
|
||||
public static Multipart build(Object value) {
|
||||
if (value instanceof MatchingStrategy) {
|
||||
return new Multipart((MatchingStrategy) value);
|
||||
}
|
||||
return new Multipart(value);
|
||||
}
|
||||
|
||||
private static Map<String, Object> extractValue(Map<String, DslProperty> multipart,
|
||||
final Function valueProvider) {
|
||||
final Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
multipart.forEach(
|
||||
(s, dslProperty) -> map.put(s, valueProvider.apply(dslProperty)));
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents a property that has name and content. Used together with multipart requests.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class NamedProperty {
|
||||
|
||||
private static final String NAME = "name";
|
||||
|
||||
private static final String CONTENT = "content";
|
||||
|
||||
private static final String CONTENT_TYPE = "contentType";
|
||||
|
||||
private DslProperty name;
|
||||
|
||||
private DslProperty value;
|
||||
|
||||
private DslProperty contentType;
|
||||
|
||||
public NamedProperty(DslProperty name, DslProperty value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.contentType = null;
|
||||
}
|
||||
|
||||
public NamedProperty(DslProperty name, DslProperty value, DslProperty contentType) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
public NamedProperty(Map<String, DslProperty> namedMap) {
|
||||
this(asDslProperty(value(namedMap, NAME)),
|
||||
asDslProperty(value(namedMap, CONTENT)),
|
||||
asDslProperty(value(namedMap, CONTENT_TYPE)));
|
||||
}
|
||||
|
||||
private static DslProperty value(Map<String, DslProperty> namedMap, String key) {
|
||||
if (namedMap == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return namedMap.get(key);
|
||||
}
|
||||
|
||||
public static DslProperty asDslProperty(Object o) {
|
||||
if (o == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (o instanceof DslProperty) {
|
||||
return ((DslProperty) (o));
|
||||
}
|
||||
|
||||
return new DslProperty(o);
|
||||
}
|
||||
|
||||
public DslProperty getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(DslProperty name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public DslProperty getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(DslProperty value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public DslProperty getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
public void setContentType(DslProperty contentType) {
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
NamedProperty that = (NamedProperty) o;
|
||||
return Objects.equals(name, that.name) && Objects.equals(value, that.value)
|
||||
&& Objects.equals(contentType, that.contentType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, value, contentType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NamedProperty{" + "name=" + name + ", value=" + value + ", contentType="
|
||||
+ contentType + '}';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Special case of Patterns that we don't want to escape.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 1.0.3
|
||||
*/
|
||||
public class NotToEscapePattern extends DslProperty<Pattern> {
|
||||
|
||||
public NotToEscapePattern(Pattern clientValue, Pattern serverValue) {
|
||||
super(clientValue, serverValue);
|
||||
}
|
||||
|
||||
public NotToEscapePattern(Pattern singleValue) {
|
||||
super(singleValue);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import repackaged.nl.flotsam.xeger.Xeger;
|
||||
|
||||
/**
|
||||
* Represents a property that may or may not be there.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class OptionalProperty implements Serializable, CanBeDynamic {
|
||||
|
||||
private final Object value;
|
||||
|
||||
public OptionalProperty(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* String version of a regular expression that wraps the provided value in an optional
|
||||
* function.
|
||||
* @return pattern wrapped in optional regular expresion
|
||||
*/
|
||||
public String optionalPattern() {
|
||||
return "(" + value() + ")?";
|
||||
}
|
||||
|
||||
public String value() {
|
||||
return this.value instanceof RegexProperty
|
||||
? ((RegexProperty) this.value).pattern() : this.value.toString();
|
||||
}
|
||||
|
||||
protected Pattern optionalPatternValue() {
|
||||
return Pattern.compile(optionalPattern());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return optionalPattern();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generateConcreteValue() {
|
||||
return new Xeger(optionalPattern()).generate();
|
||||
}
|
||||
|
||||
public final Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,400 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import groovy.lang.Closure;
|
||||
import groovy.lang.DelegatesTo;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Represents an output for messaging. Used for verifying the body and headers that are
|
||||
* sent.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Tim Ysewyn
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class OutputMessage extends Common
|
||||
implements RegexCreatingProperty<ServerDslProperty> {
|
||||
|
||||
private static final Log log = LogFactory.getLog(OutputMessage.class);
|
||||
|
||||
private DslProperty<String> sentTo;
|
||||
|
||||
private Headers headers;
|
||||
|
||||
private DslProperty body;
|
||||
|
||||
private ExecutionProperty assertThat;
|
||||
|
||||
private ResponseBodyMatchers bodyMatchers;
|
||||
|
||||
private ServerPatternValueDslProperty property = new ServerPatternValueDslProperty();
|
||||
|
||||
public OutputMessage() {
|
||||
}
|
||||
|
||||
public OutputMessage(OutputMessage outputMessage) {
|
||||
this.sentTo = outputMessage.getSentTo();
|
||||
this.headers = outputMessage.getHeaders();
|
||||
this.body = outputMessage.getBody();
|
||||
}
|
||||
|
||||
public void sentTo(String sentTo) {
|
||||
this.sentTo = new DslProperty(sentTo);
|
||||
}
|
||||
|
||||
public void sentTo(DslProperty sentTo) {
|
||||
this.sentTo = sentTo;
|
||||
}
|
||||
|
||||
public void body(Object bodyAsValue) {
|
||||
this.body = new DslProperty(bodyAsValue);
|
||||
}
|
||||
|
||||
public void body(DslProperty bodyAsValue) {
|
||||
this.body = bodyAsValue;
|
||||
}
|
||||
|
||||
public void assertThat(String assertThat) {
|
||||
this.assertThat = new ExecutionProperty(assertThat);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated - use the server dsl property
|
||||
* @param clientDslProperty client property
|
||||
* @return dsl property
|
||||
*/
|
||||
@Deprecated
|
||||
public DslProperty value(ClientDslProperty clientDslProperty) {
|
||||
return value(new ServerDslProperty(clientDslProperty.getServerValue(),
|
||||
clientDslProperty.getClientValue()));
|
||||
}
|
||||
|
||||
public DslProperty value(ServerDslProperty serverDslProperty) {
|
||||
Object concreteValue = serverDslProperty.getClientValue();
|
||||
Object dynamicValue = serverDslProperty.getServerValue();
|
||||
// for the output messages ran via stub runner,
|
||||
// entries have to have fixed values
|
||||
if (dynamicValue instanceof RegexProperty) {
|
||||
return ((RegexProperty) dynamicValue).concreteClientEscapedDynamicProducer();
|
||||
}
|
||||
|
||||
return new DslProperty(concreteValue, dynamicValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated - use the server dsl property
|
||||
* @param client client value
|
||||
* @return dsl proprty
|
||||
*/
|
||||
@Deprecated
|
||||
public DslProperty $(ClientDslProperty client) {
|
||||
return value(client);
|
||||
}
|
||||
|
||||
public DslProperty $(ServerDslProperty property) {
|
||||
return value(property);
|
||||
}
|
||||
|
||||
public DslProperty $(Pattern pattern) {
|
||||
return value(new RegexProperty(pattern));
|
||||
}
|
||||
|
||||
public DslProperty $(RegexProperty pattern) {
|
||||
return value(pattern);
|
||||
}
|
||||
|
||||
public DslProperty value(RegexProperty pattern) {
|
||||
return value(producer(pattern));
|
||||
}
|
||||
|
||||
public DslProperty $(OptionalProperty property) {
|
||||
return value(producer(property.optionalPatternValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegexProperty regexProperty(Object object) {
|
||||
return new RegexProperty(object).concreteClientDynamicProducer();
|
||||
}
|
||||
|
||||
public ServerPatternValueDslProperty getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
public void setProperty(ServerPatternValueDslProperty property) {
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
public DslProperty<String> getSentTo() {
|
||||
return sentTo;
|
||||
}
|
||||
|
||||
public void setSentTo(DslProperty<String> sentTo) {
|
||||
this.sentTo = sentTo;
|
||||
}
|
||||
|
||||
public Headers getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public void setHeaders(Headers headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
public DslProperty getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public void setBody(DslProperty body) {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public ExecutionProperty getAssertThat() {
|
||||
return assertThat;
|
||||
}
|
||||
|
||||
public void setAssertThat(ExecutionProperty assertThat) {
|
||||
this.assertThat = assertThat;
|
||||
}
|
||||
|
||||
public ResponseBodyMatchers getBodyMatchers() {
|
||||
return bodyMatchers;
|
||||
}
|
||||
|
||||
public void setBodyMatchers(ResponseBodyMatchers bodyMatchers) {
|
||||
this.bodyMatchers = bodyMatchers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyAlphaUnicode() {
|
||||
return property.anyAlphaUnicode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyAlphaNumeric() {
|
||||
return property.anyAlphaNumeric();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyNumber() {
|
||||
return property.anyNumber();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyInteger() {
|
||||
return property.anyInteger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyPositiveInt() {
|
||||
return property.anyPositiveInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyDouble() {
|
||||
return property.anyDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyHex() {
|
||||
return property.anyHex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty aBoolean() {
|
||||
return property.aBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyIpAddress() {
|
||||
return property.anyIpAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyHostname() {
|
||||
return property.anyHostname();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyEmail() {
|
||||
return property.anyEmail();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyUrl() {
|
||||
return property.anyUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyHttpsUrl() {
|
||||
return property.anyHttpsUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyUuid() {
|
||||
return property.anyUuid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyDate() {
|
||||
return property.anyDate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyDateTime() {
|
||||
return property.anyDateTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyTime() {
|
||||
return property.anyTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyIso8601WithOffset() {
|
||||
return property.anyIso8601WithOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyNonBlankString() {
|
||||
return property.anyNonBlankString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyNonEmptyString() {
|
||||
return property.anyNonEmptyString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyOf(String... values) {
|
||||
return property.anyOf(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* The message headers part of the contract.
|
||||
* @param consumer function to manipulate the message headers
|
||||
*/
|
||||
public void headers(Consumer<Headers> consumer) {
|
||||
this.headers = new Headers();
|
||||
consumer.accept(this.headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* The message headers part of the contract.
|
||||
* @param consumer function to manipulate the message headers
|
||||
* @deprecated Deprecated in favor of bodyMatchers to support other future
|
||||
* bodyMatchers too
|
||||
*/
|
||||
@Deprecated
|
||||
public void testMatchers(Consumer<ResponseBodyMatchers> consumer) {
|
||||
log.warn("testMatchers method is deprecated. Please use bodyMatchers instead");
|
||||
bodyMatchers(consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* The stub matchers part of the contract.
|
||||
* @param consumer function to manipulate the body matchers
|
||||
* @deprecated Deprecated in favor of bodyMatchers to support other future
|
||||
* bodyMatchers too
|
||||
*/
|
||||
@Deprecated
|
||||
public void bodyMatchers(Consumer<ResponseBodyMatchers> consumer) {
|
||||
this.bodyMatchers = new ResponseBodyMatchers();
|
||||
consumer.accept(this.bodyMatchers);
|
||||
}
|
||||
|
||||
/**
|
||||
* The message headers part of the contract.
|
||||
* @param consumer function to manipulate the message headers
|
||||
*/
|
||||
public void headers(@DelegatesTo(Headers.class) Closure consumer) {
|
||||
this.headers = new Headers();
|
||||
consumer.setDelegate(this.headers);
|
||||
consumer.call();
|
||||
}
|
||||
|
||||
/**
|
||||
* The message headers part of the contract.
|
||||
* @param consumer function to manipulate the message headers
|
||||
* @deprecated Deprecated in favor of bodyMatchers to support other future
|
||||
* bodyMatchers too
|
||||
*/
|
||||
@Deprecated
|
||||
public void testMatchers(@DelegatesTo(ResponseBodyMatchers.class) Closure consumer) {
|
||||
log.warn("testMatchers method is deprecated. Please use bodyMatchers instead");
|
||||
bodyMatchers(consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* The stub matchers part of the contract.
|
||||
* @param consumer function to manipulate the body matchers
|
||||
* @deprecated Deprecated in favor of bodyMatchers to support other future
|
||||
* bodyMatchers too
|
||||
*/
|
||||
@Deprecated
|
||||
public void bodyMatchers(@DelegatesTo(ResponseBodyMatchers.class) Closure consumer) {
|
||||
this.bodyMatchers = new ResponseBodyMatchers();
|
||||
consumer.setDelegate(this.bodyMatchers);
|
||||
consumer.call();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
OutputMessage that = (OutputMessage) o;
|
||||
return Objects.equals(sentTo, that.sentTo)
|
||||
&& Objects.equals(headers, that.headers)
|
||||
&& Objects.equals(body, that.body)
|
||||
&& Objects.equals(assertThat, that.assertThat)
|
||||
&& Objects.equals(bodyMatchers, that.bodyMatchers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(sentTo, headers, body, assertThat, bodyMatchers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "OutputMessage{" + "\n\tsentTo=" + sentTo + ", \n\theaders=" + headers
|
||||
+ ", \n\tbody=" + body + ", \n\tassertThat=" + assertThat
|
||||
+ ", \n\tbodyMatchers=" + bodyMatchers + "} \n\t" + super.toString();
|
||||
}
|
||||
|
||||
private class ServerPatternValueDslProperty
|
||||
extends PatternValueDslProperty<ServerDslProperty> {
|
||||
|
||||
@Override
|
||||
protected ServerDslProperty createProperty(Pattern pattern,
|
||||
Object generatedValue) {
|
||||
return new ServerDslProperty(pattern, generatedValue);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
public class PathBodyMatcher implements BodyMatcher {
|
||||
|
||||
private String path;
|
||||
|
||||
private MatchingTypeValue matchingTypeValue;
|
||||
|
||||
PathBodyMatcher(String path, MatchingTypeValue matchingTypeValue) {
|
||||
this.path = path;
|
||||
this.matchingTypeValue = matchingTypeValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MatchingType matchingType() {
|
||||
return this.matchingTypeValue.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String path() {
|
||||
return this.path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object value() {
|
||||
return this.matchingTypeValue.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer minTypeOccurrence() {
|
||||
return this.matchingTypeValue.getMinTypeOccurrence();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer maxTypeOccurrence() {
|
||||
return this.matchingTypeValue.getMaxTypeOccurrence();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
PathBodyMatcher that = (PathBodyMatcher) o;
|
||||
return Objects.equals(path, that.path)
|
||||
&& Objects.equals(matchingTypeValue, that.matchingTypeValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(path, matchingTypeValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PathBodyMatcher{" + "path='" + path + '\'' + ", matchingTypeValue="
|
||||
+ matchingTypeValue + '}';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Tim Ysewyn
|
||||
*/
|
||||
abstract class PatternValueDslProperty<T extends DslProperty>
|
||||
implements RegexCreatingProperty<T> {
|
||||
|
||||
private final Random random = new Random();
|
||||
|
||||
protected T createAndValidateProperty(Pattern pattern, Object object) {
|
||||
if (object != null) {
|
||||
String generatedValue = object.toString();
|
||||
boolean matches = pattern.matcher(generatedValue).matches();
|
||||
if (!matches) {
|
||||
throw new IllegalStateException("The generated value [" + generatedValue
|
||||
+ "] doesn\'t match the pattern [" + pattern.pattern() + "]");
|
||||
}
|
||||
|
||||
return createProperty(pattern, object);
|
||||
}
|
||||
|
||||
return createProperty(pattern, object);
|
||||
}
|
||||
|
||||
protected T createAndValidateProperty(Pattern pattern) {
|
||||
return createAndValidateProperty(pattern, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to generate the PatternValue. The resulting implementation will create
|
||||
* either a Client or a Server side impl.
|
||||
* @param pattern - pattern for which the value will be generated or reused
|
||||
* @param generatedValue - Nullable - potential generated value to be reused
|
||||
* @return {@link DslProperty} wrapping a pattern and generated value
|
||||
*/
|
||||
protected abstract T createProperty(Pattern pattern, Object generatedValue);
|
||||
|
||||
@Override
|
||||
public T anyAlphaUnicode() {
|
||||
return createAndValidateProperty(RegexPatterns.ONLY_ALPHA_UNICODE,
|
||||
RandomStringGenerator.randomString(20));
|
||||
}
|
||||
|
||||
@Override
|
||||
public T anyAlphaNumeric() {
|
||||
return createAndValidateProperty(RegexPatterns.ALPHA_NUMERIC,
|
||||
RandomStringUtils.randomAlphanumeric(20));
|
||||
}
|
||||
|
||||
@Override
|
||||
public T anyNumber() {
|
||||
return createAndValidateProperty(RegexPatterns.NUMBER, this.random.nextInt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public T anyInteger() {
|
||||
return createAndValidateProperty(RegexPatterns.INTEGER, this.random.nextInt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public T anyPositiveInt() {
|
||||
return createAndValidateProperty(RegexPatterns.POSITIVE_INT,
|
||||
Math.abs(this.random.nextInt() + 1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public T anyDouble() {
|
||||
return createAndValidateProperty(RegexPatterns.DOUBLE,
|
||||
this.random.nextInt(100) + this.random.nextDouble());
|
||||
}
|
||||
|
||||
@Override
|
||||
public T anyHex() {
|
||||
return createAndValidateProperty(RegexPatterns.HEX,
|
||||
RandomStringUtils.random(10, "0123456789abcdef"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public T aBoolean() {
|
||||
return createAndValidateProperty(RegexPatterns.TRUE_OR_FALSE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T anyIpAddress() {
|
||||
return createAndValidateProperty(RegexPatterns.IP_ADDRESS,
|
||||
"192.168.0." + this.random.nextInt(10));
|
||||
}
|
||||
|
||||
@Override
|
||||
public T anyHostname() {
|
||||
return createAndValidateProperty(RegexPatterns.HOSTNAME_PATTERN,
|
||||
"https://foo" + this.random.nextInt() + ".com");
|
||||
}
|
||||
|
||||
@Override
|
||||
public T anyEmail() {
|
||||
return createAndValidateProperty(RegexPatterns.EMAIL,
|
||||
"foo@bar" + this.random.nextInt() + ".com");
|
||||
}
|
||||
|
||||
@Override
|
||||
public T anyUrl() {
|
||||
return createAndValidateProperty(RegexPatterns.URL,
|
||||
"https://foo" + this.random.nextInt() + ".com");
|
||||
}
|
||||
|
||||
@Override
|
||||
public T anyHttpsUrl() {
|
||||
return createAndValidateProperty(RegexPatterns.HTTPS_URL,
|
||||
"https://baz" + this.random.nextInt() + ".com");
|
||||
}
|
||||
|
||||
@Override
|
||||
public T anyUuid() {
|
||||
return createAndValidateProperty(RegexPatterns.UUID,
|
||||
UUID.randomUUID().toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public T anyDate() {
|
||||
int d = this.random.nextInt(8) + 1;
|
||||
return createAndValidateProperty(RegexPatterns.ANY_DATE, "201" + String.valueOf(d)
|
||||
+ "-0" + String.valueOf(d) + "-1" + String.valueOf(d));
|
||||
}
|
||||
|
||||
@Override
|
||||
public T anyDateTime() {
|
||||
final int d = this.random.nextInt(8) + 1;
|
||||
return createAndValidateProperty(RegexPatterns.ANY_DATE_TIME,
|
||||
"201" + String.valueOf(d) + "-0" + String.valueOf(d) + "-1"
|
||||
+ String.valueOf(d) + "T12:23:34");
|
||||
}
|
||||
|
||||
@Override
|
||||
public T anyTime() {
|
||||
int d = this.random.nextInt(9);
|
||||
return createAndValidateProperty(RegexPatterns.ANY_TIME,
|
||||
"12:2" + String.valueOf(d) + ":3" + String.valueOf(d));
|
||||
}
|
||||
|
||||
@Override
|
||||
public T anyIso8601WithOffset() {
|
||||
final int d = this.random.nextInt(8) + 1;
|
||||
return createAndValidateProperty(RegexPatterns.ISO8601_WITH_OFFSET,
|
||||
"201" + String.valueOf(d) + "-0" + String.valueOf(d) + "-1"
|
||||
+ String.valueOf(d) + "T12:23:34.123Z");
|
||||
}
|
||||
|
||||
@Override
|
||||
public T anyNonBlankString() {
|
||||
return createAndValidateProperty(RegexPatterns.NON_BLANK,
|
||||
RandomStringGenerator.randomString(20));
|
||||
}
|
||||
|
||||
@Override
|
||||
public T anyNonEmptyString() {
|
||||
return createAndValidateProperty(RegexPatterns.NON_EMPTY,
|
||||
RandomStringGenerator.randomString(20));
|
||||
}
|
||||
|
||||
@Override
|
||||
public T anyOf(String... values) {
|
||||
return createAndValidateProperty(RegexPatterns.anyOf(values), values[0]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.springframework.cloud.contract.spec.util.ValidateUtils;
|
||||
|
||||
/**
|
||||
* Represents a single HTTP query parameter.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class QueryParameter extends DslProperty {
|
||||
|
||||
private String name;
|
||||
|
||||
public QueryParameter(String name, DslProperty dslProperty) {
|
||||
super(dslProperty.getClientValue(), dslProperty.getServerValue());
|
||||
ValidateUtils.validateServerValueIsAvailable(dslProperty.getServerValue(),
|
||||
"Query parameter \'" + name + "\'");
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public QueryParameter(String name, MatchingStrategy matchingStrategy) {
|
||||
super(matchingStrategy);
|
||||
ValidateUtils.validateServerValueIsAvailable(matchingStrategy,
|
||||
"Query parameter \'" + name + "\'");
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public QueryParameter(String name, Object value) {
|
||||
super(ContractUtils.CLIENT_VALUE.apply(value),
|
||||
ContractUtils.SERVER_VALUE.apply(value));
|
||||
ValidateUtils.validateServerValueIsAvailable(value,
|
||||
"Query parameter \'" + name + "\'");
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static QueryParameter build(String key, Object value) {
|
||||
if (value instanceof MatchingStrategy) {
|
||||
return new QueryParameter(key, (MatchingStrategy) value);
|
||||
}
|
||||
else if (value instanceof RegexProperty) {
|
||||
return new QueryParameter(key,
|
||||
((RegexProperty) value).dynamicClientEscapedConcreteProducer());
|
||||
}
|
||||
return new QueryParameter(key, value);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
if (!super.equals(o)) {
|
||||
return false;
|
||||
}
|
||||
QueryParameter that = (QueryParameter) o;
|
||||
return Objects.equals(name, that.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "QueryParameter{" + "name='" + name + '\'' + ", value=" + super.toString()
|
||||
+ '}';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class QueryParameters {
|
||||
|
||||
private List<QueryParameter> parameters = new LinkedList<QueryParameter>();
|
||||
|
||||
public void parameter(Map<String, Object> singleParameter) {
|
||||
Iterator<Map.Entry<String, Object>> iterator = singleParameter.entrySet()
|
||||
.iterator();
|
||||
if (iterator.hasNext()) {
|
||||
Map.Entry<String, Object> first = iterator.next();
|
||||
if (first != null) {
|
||||
parameters.add(QueryParameter.build(first.getKey(), first.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void parameter(String parameterName, Object parameterValue) {
|
||||
parameters.add(QueryParameter.build(parameterName, parameterValue));
|
||||
}
|
||||
|
||||
public List<QueryParameter> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
public void setParameters(List<QueryParameter> parameters) {
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
QueryParameters that = (QueryParameters) o;
|
||||
return Objects.equals(parameters, that.parameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(parameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "QueryParameters{" + "\nparameters=" + parameters + '}';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
final class RandomStringGenerator {
|
||||
|
||||
private RandomStringGenerator() {
|
||||
throw new IllegalStateException("Can't instantiate a utility class");
|
||||
}
|
||||
|
||||
static String randomString(int length) {
|
||||
char[] characterSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
|
||||
Random random = new Random();
|
||||
char[] result = new char[length];
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
// picks a random index out of character set > random character
|
||||
int randomCharIndex = random.nextInt(characterSet.length);
|
||||
result[i] = characterSet[randomCharIndex];
|
||||
}
|
||||
return new String(result);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
interface RegexCreatingProperty<T extends DslProperty> {
|
||||
|
||||
T anyAlphaUnicode();
|
||||
|
||||
T anyAlphaNumeric();
|
||||
|
||||
T anyNumber();
|
||||
|
||||
T anyInteger();
|
||||
|
||||
T anyPositiveInt();
|
||||
|
||||
T anyDouble();
|
||||
|
||||
T anyHex();
|
||||
|
||||
T aBoolean();
|
||||
|
||||
T anyIpAddress();
|
||||
|
||||
T anyHostname();
|
||||
|
||||
T anyEmail();
|
||||
|
||||
T anyUrl();
|
||||
|
||||
T anyHttpsUrl();
|
||||
|
||||
T anyUuid();
|
||||
|
||||
T anyDate();
|
||||
|
||||
T anyDateTime();
|
||||
|
||||
T anyTime();
|
||||
|
||||
T anyIso8601WithOffset();
|
||||
|
||||
T anyNonBlankString();
|
||||
|
||||
T anyNonEmptyString();
|
||||
|
||||
T anyOf(String... values);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
/**
|
||||
* Matching type with corresponding values.
|
||||
*/
|
||||
public class RegexMatchingTypeValue extends MatchingTypeValue {
|
||||
|
||||
RegexMatchingTypeValue(MatchingType type, Object value, Integer minTypeOccurrence,
|
||||
Integer maxTypeOccurrence) {
|
||||
super(type, value, minTypeOccurrence, maxTypeOccurrence);
|
||||
}
|
||||
|
||||
RegexMatchingTypeValue(MatchingType type, Object value) {
|
||||
super(type, value);
|
||||
}
|
||||
|
||||
public RegexMatchingTypeValue asInteger() {
|
||||
return typed(Integer.class);
|
||||
}
|
||||
|
||||
private RegexMatchingTypeValue typed(Class clazz) {
|
||||
if (!(this.getValue() instanceof RegexProperty)) {
|
||||
throw new IllegalStateException("Value has to be a regex");
|
||||
}
|
||||
RegexProperty regexProperty = (RegexProperty) this.getValue();
|
||||
return new RegexMatchingTypeValue(this.getType(),
|
||||
new RegexProperty(regexProperty.getClientValue(),
|
||||
regexProperty.getServerValue(), clazz),
|
||||
this.getMinTypeOccurrence(), this.getMaxTypeOccurrence());
|
||||
}
|
||||
|
||||
public RegexMatchingTypeValue asDouble() {
|
||||
return typed(Double.class);
|
||||
}
|
||||
|
||||
public RegexMatchingTypeValue asFloat() {
|
||||
return typed(Float.class);
|
||||
}
|
||||
|
||||
public RegexMatchingTypeValue asLong() {
|
||||
return typed(Long.class);
|
||||
}
|
||||
|
||||
public RegexMatchingTypeValue asShort() {
|
||||
return typed(Short.class);
|
||||
}
|
||||
|
||||
public RegexMatchingTypeValue asString() {
|
||||
return typed(String.class);
|
||||
}
|
||||
|
||||
public RegexMatchingTypeValue asBooleanType() {
|
||||
return typed(Boolean.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Contains most common regular expression patterns.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Tim Ysewyn
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class RegexPatterns {
|
||||
|
||||
// tag::regexps[]
|
||||
protected static final Pattern TRUE_OR_FALSE = Pattern.compile("(true|false)");
|
||||
|
||||
protected static final Pattern ALPHA_NUMERIC = Pattern.compile("[a-zA-Z0-9]+");
|
||||
|
||||
protected static final Pattern ONLY_ALPHA_UNICODE = Pattern.compile("[\\p{L}]*");
|
||||
|
||||
protected static final Pattern NUMBER = Pattern.compile("-?(\\d*\\.\\d+|\\d+)");
|
||||
|
||||
protected static final Pattern INTEGER = Pattern.compile("-?(\\d+)");
|
||||
|
||||
protected static final Pattern POSITIVE_INT = Pattern.compile("([1-9]\\d*)");
|
||||
|
||||
protected static final Pattern DOUBLE = Pattern.compile("-?(\\d*\\.\\d+)");
|
||||
|
||||
protected static final Pattern HEX = Pattern.compile("[a-fA-F0-9]+");
|
||||
|
||||
protected static final Pattern IP_ADDRESS = Pattern.compile(
|
||||
"([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])");
|
||||
|
||||
protected static final Pattern HOSTNAME_PATTERN = Pattern
|
||||
.compile("((http[s]?|ftp):/)/?([^:/\\s]+)(:[0-9]{1,5})?");
|
||||
|
||||
protected static final Pattern EMAIL = Pattern
|
||||
.compile("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,6}");
|
||||
|
||||
protected static final Pattern URL = UrlHelper.URL;
|
||||
|
||||
protected static final Pattern HTTPS_URL = UrlHelper.HTTPS_URL;
|
||||
|
||||
protected static final Pattern UUID = Pattern
|
||||
.compile("[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}");
|
||||
|
||||
protected static final Pattern ANY_DATE = Pattern
|
||||
.compile("(\\d\\d\\d\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])");
|
||||
|
||||
protected static final Pattern ANY_DATE_TIME = Pattern.compile(
|
||||
"([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])");
|
||||
|
||||
protected static final Pattern ANY_TIME = Pattern
|
||||
.compile("(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])");
|
||||
|
||||
protected static final Pattern NON_EMPTY = Pattern.compile("[\\S\\s]+");
|
||||
|
||||
protected static final Pattern NON_BLANK = Pattern.compile("^\\s*\\S[\\S\\s]*");
|
||||
|
||||
protected static final Pattern ISO8601_WITH_OFFSET = Pattern.compile(
|
||||
"([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\\.\\d{3})?(Z|[+-][01]\\d:[0-5]\\d)");
|
||||
|
||||
protected static Pattern anyOf(String... values) {
|
||||
return Pattern.compile(Arrays.stream(values).map(it -> '^' + it + '$')
|
||||
.collect(Collectors.joining("|")));
|
||||
}
|
||||
|
||||
public static String multipartParam(Object name, Object value) {
|
||||
return ".*--(.*)\r\nContent-Disposition: form-data; name=\"" + name
|
||||
+ "\"\r\n(Content-Type: .*\r\n)?(Content-Transfer-Encoding: .*\r\n)?(Content-Length: \\d+\r\n)?\r\n"
|
||||
+ value + "\r\n--\\1.*";
|
||||
}
|
||||
|
||||
public static String multipartFile(Object name, Object filename, Object content,
|
||||
Object contentType) {
|
||||
return ".*--(.*)\r\nContent-Disposition: form-data; name=\"" + name
|
||||
+ "\"; filename=\"" + filename + "\"\r\n(Content-Type: "
|
||||
+ toContentType(contentType)
|
||||
+ "\r\n)?(Content-Transfer-Encoding: .*\r\n)?(Content-Length: \\d+\r\n)?\r\n"
|
||||
+ content + "\r\n--\\1.*";
|
||||
}
|
||||
|
||||
private static String toContentType(Object contentType) {
|
||||
if (contentType == null) {
|
||||
return ".*";
|
||||
}
|
||||
if (contentType instanceof RegexProperty) {
|
||||
return ((RegexProperty) contentType).pattern();
|
||||
}
|
||||
return contentType.toString();
|
||||
}
|
||||
|
||||
public RegexProperty onlyAlphaUnicode() {
|
||||
return new RegexProperty(ONLY_ALPHA_UNICODE).asString();
|
||||
}
|
||||
|
||||
public RegexProperty alphaNumeric() {
|
||||
return new RegexProperty(ALPHA_NUMERIC).asString();
|
||||
}
|
||||
|
||||
public RegexProperty number() {
|
||||
return new RegexProperty(NUMBER).asDouble();
|
||||
}
|
||||
|
||||
public RegexProperty positiveInt() {
|
||||
return new RegexProperty(POSITIVE_INT).asInteger();
|
||||
}
|
||||
|
||||
public RegexProperty anyBoolean() {
|
||||
return new RegexProperty(TRUE_OR_FALSE).asBooleanType();
|
||||
}
|
||||
|
||||
public RegexProperty anInteger() {
|
||||
return new RegexProperty(INTEGER).asInteger();
|
||||
}
|
||||
|
||||
public RegexProperty aDouble() {
|
||||
return new RegexProperty(DOUBLE).asDouble();
|
||||
}
|
||||
|
||||
public RegexProperty ipAddress() {
|
||||
return new RegexProperty(IP_ADDRESS).asString();
|
||||
}
|
||||
|
||||
public RegexProperty hostname() {
|
||||
return new RegexProperty(HOSTNAME_PATTERN).asString();
|
||||
}
|
||||
|
||||
public RegexProperty email() {
|
||||
return new RegexProperty(EMAIL).asString();
|
||||
}
|
||||
|
||||
public RegexProperty url() {
|
||||
return new RegexProperty(URL).asString();
|
||||
}
|
||||
|
||||
public RegexProperty httpsUrl() {
|
||||
return new RegexProperty(HTTPS_URL).asString();
|
||||
}
|
||||
|
||||
public RegexProperty uuid() {
|
||||
return new RegexProperty(UUID).asString();
|
||||
}
|
||||
|
||||
public RegexProperty isoDate() {
|
||||
return new RegexProperty(ANY_DATE).asString();
|
||||
}
|
||||
|
||||
public RegexProperty isoDateTime() {
|
||||
return new RegexProperty(ANY_DATE_TIME).asString();
|
||||
}
|
||||
|
||||
public RegexProperty isoTime() {
|
||||
return new RegexProperty(ANY_TIME).asString();
|
||||
}
|
||||
|
||||
// end::regexps[]
|
||||
|
||||
public RegexProperty iso8601WithOffset() {
|
||||
return new RegexProperty(ISO8601_WITH_OFFSET).asString();
|
||||
}
|
||||
|
||||
public RegexProperty nonEmpty() {
|
||||
return new RegexProperty(NON_EMPTY).asString();
|
||||
}
|
||||
|
||||
public RegexProperty nonBlank() {
|
||||
return new RegexProperty(NON_BLANK).asString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.text.StringEscapeUtils;
|
||||
import repackaged.nl.flotsam.xeger.Xeger;
|
||||
|
||||
/**
|
||||
* Represents a regular expression property.
|
||||
*
|
||||
* @since 2.1.0
|
||||
*/
|
||||
public class RegexProperty extends DslProperty implements CanBeDynamic {
|
||||
|
||||
final Pattern pattern;
|
||||
|
||||
private final Class clazz;
|
||||
|
||||
public RegexProperty(Object value) {
|
||||
this(value, value, null);
|
||||
}
|
||||
|
||||
public RegexProperty(Object client, Object server) {
|
||||
this(client, server, null);
|
||||
}
|
||||
|
||||
public RegexProperty(Object client, Object server, Class clazz) {
|
||||
super(client, server);
|
||||
boolean clientDynamic = client instanceof Pattern
|
||||
|| client instanceof RegexProperty;
|
||||
boolean serverDynamic = server instanceof Pattern
|
||||
|| server instanceof RegexProperty;
|
||||
if (!clientDynamic && !serverDynamic) {
|
||||
throw new IllegalStateException("Neither client not server side is dynamic");
|
||||
}
|
||||
Object dynamicValue = clientDynamic ? client : server;
|
||||
if (dynamicValue instanceof Pattern) {
|
||||
this.pattern = (Pattern) dynamicValue;
|
||||
this.clazz = clazz != null ? clazz : String.class;
|
||||
}
|
||||
else if (dynamicValue instanceof RegexProperty) {
|
||||
RegexProperty regexProperty = ((RegexProperty) dynamicValue);
|
||||
this.pattern = regexProperty.pattern;
|
||||
this.clazz = clazz != null ? clazz : regexProperty.clazz;
|
||||
}
|
||||
else {
|
||||
this.clazz = clazz;
|
||||
this.pattern = null;
|
||||
}
|
||||
}
|
||||
|
||||
public Matcher matcher(CharSequence input) {
|
||||
return this.pattern.matcher(input);
|
||||
}
|
||||
|
||||
public String pattern() {
|
||||
return this.pattern.pattern();
|
||||
}
|
||||
|
||||
public Class clazz() {
|
||||
return this.getClass();
|
||||
}
|
||||
|
||||
public RegexProperty asInteger() {
|
||||
return new RegexProperty(this.getClientValue(), this.getServerValue(),
|
||||
Integer.class);
|
||||
}
|
||||
|
||||
public RegexProperty asDouble() {
|
||||
return new RegexProperty(this.getClientValue(), this.getServerValue(),
|
||||
Double.class);
|
||||
}
|
||||
|
||||
public RegexProperty asFloat() {
|
||||
return new RegexProperty(this.getClientValue(), this.getServerValue(),
|
||||
Float.class);
|
||||
}
|
||||
|
||||
public RegexProperty asLong() {
|
||||
return new RegexProperty(this.getClientValue(), this.getServerValue(),
|
||||
Long.class);
|
||||
}
|
||||
|
||||
public RegexProperty asShort() {
|
||||
return new RegexProperty(this.getClientValue(), this.getServerValue(),
|
||||
Short.class);
|
||||
}
|
||||
|
||||
public RegexProperty asString() {
|
||||
return new RegexProperty(this.getClientValue(), this.getServerValue(),
|
||||
String.class);
|
||||
}
|
||||
|
||||
public RegexProperty asBooleanType() {
|
||||
return new RegexProperty(this.getClientValue(), this.getServerValue(),
|
||||
Boolean.class);
|
||||
}
|
||||
|
||||
public Object generate() {
|
||||
return doGenerate(3);
|
||||
}
|
||||
|
||||
private Object doGenerate(int retries) {
|
||||
try {
|
||||
String generatedValue = new Xeger(this.pattern.pattern()).generate();
|
||||
if (Integer.class.equals(this.clazz)) {
|
||||
return Integer.parseInt(generatedValue);
|
||||
}
|
||||
else if (Double.class.equals(this.clazz)) {
|
||||
return Double.parseDouble(generatedValue);
|
||||
}
|
||||
else if (Float.class.equals(this.clazz)) {
|
||||
return Float.parseFloat(generatedValue);
|
||||
}
|
||||
else if (Long.class.equals(this.clazz)) {
|
||||
return Long.parseLong(generatedValue);
|
||||
}
|
||||
else if (Short.class.equals(this.clazz)) {
|
||||
return Short.parseShort(generatedValue);
|
||||
}
|
||||
else if (Boolean.class.equals(this.clazz)) {
|
||||
return Boolean.parseBoolean(generatedValue);
|
||||
}
|
||||
return generatedValue;
|
||||
}
|
||||
catch (NumberFormatException ex) {
|
||||
if (retries > 0) {
|
||||
retries = retries - 1;
|
||||
return doGenerate(retries);
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
public Object generateAndEscapeJavaStringIfNeeded() {
|
||||
Object generated = generate();
|
||||
if (isNumber()) {
|
||||
return generated;
|
||||
}
|
||||
return StringEscapeUtils.escapeJava(String.valueOf(generated));
|
||||
}
|
||||
|
||||
private boolean isNumber() {
|
||||
return Number.class.isAssignableFrom(this.clazz);
|
||||
}
|
||||
|
||||
public RegexProperty dynamicClientConcreteProducer() {
|
||||
return new RegexProperty(this.pattern, generate(), this.clazz);
|
||||
}
|
||||
|
||||
public RegexProperty concreteClientDynamicProducer() {
|
||||
return new RegexProperty(generate(), this.pattern, this.clazz);
|
||||
}
|
||||
|
||||
public RegexProperty concreteClientEscapedDynamicProducer() {
|
||||
return new RegexProperty(generateAndEscapeJavaStringIfNeeded(), this.pattern,
|
||||
this.clazz);
|
||||
}
|
||||
|
||||
public RegexProperty dynamicClientEscapedConcreteProducer() {
|
||||
return new RegexProperty(this.pattern, generateAndEscapeJavaStringIfNeeded(),
|
||||
this.clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
RegexProperty that = (RegexProperty) o;
|
||||
return Objects.equals(stringPatternIfPresent(pattern),
|
||||
stringPatternIfPresent(that.pattern))
|
||||
&& Objects.equals(clazz, that.clazz);
|
||||
}
|
||||
|
||||
private Object stringPatternIfPresent(Pattern value) {
|
||||
return value != null ? value.pattern() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(stringPatternIfPresent(pattern), clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.pattern();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generateConcreteValue() {
|
||||
return generate();
|
||||
}
|
||||
|
||||
public Pattern getPattern() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
public Class getClazz() {
|
||||
return clazz;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,848 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import groovy.lang.Closure;
|
||||
import groovy.lang.DelegatesTo;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cloud.contract.spec.util.RegexpUtils;
|
||||
|
||||
/**
|
||||
* Represents the request side of the HTTP communication.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Tim Ysewyn
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class Request extends Common implements RegexCreatingProperty<ClientDslProperty> {
|
||||
|
||||
private static final Log log = LogFactory.getLog(Request.class);
|
||||
|
||||
private ClientPatternValueDslProperty property = new ClientPatternValueDslProperty();
|
||||
|
||||
private HttpMethods httpMethods = new HttpMethods();
|
||||
|
||||
private DslProperty method;
|
||||
|
||||
private Url url;
|
||||
|
||||
private UrlPath urlPath;
|
||||
|
||||
private Headers headers;
|
||||
|
||||
private Cookies cookies;
|
||||
|
||||
private Body body;
|
||||
|
||||
private Multipart multipart;
|
||||
|
||||
private BodyMatchers bodyMatchers;
|
||||
|
||||
public Request() {
|
||||
}
|
||||
|
||||
public Request(Request request) {
|
||||
this.method = request.getMethod();
|
||||
this.url = request.getUrl();
|
||||
this.urlPath = request.getUrlPath();
|
||||
this.headers = request.getHeaders();
|
||||
this.cookies = request.getCookies();
|
||||
this.body = request.getBody();
|
||||
this.multipart = request.getMultipart();
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the HTTP method.
|
||||
* @param method HTTP method name
|
||||
*/
|
||||
public void method(String method) {
|
||||
this.method = toDslProperty(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the HTTP method.
|
||||
* @param httpMethod HTTP method name
|
||||
*/
|
||||
public void method(HttpMethods.HttpMethod httpMethod) {
|
||||
this.method = toDslProperty(httpMethod.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the HTTP method.
|
||||
* @param method HTTP method name
|
||||
*/
|
||||
public void method(DslProperty method) {
|
||||
this.method = toDslProperty(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param url URL to which the request will be sent
|
||||
*/
|
||||
public void url(Object url) {
|
||||
this.url = new Url(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param url URL to which the request will be sent
|
||||
*/
|
||||
public void url(DslProperty url) {
|
||||
this.url = new Url(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param path URL to which the request will be sent
|
||||
*/
|
||||
public void urlPath(String path) {
|
||||
this.urlPath = new UrlPath(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param path URL to which the request will be sent
|
||||
*/
|
||||
public void urlPath(Object path) {
|
||||
this.urlPath = new UrlPath(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param path URL to which the request will be sent
|
||||
*/
|
||||
public void urlPath(DslProperty path) {
|
||||
this.urlPath = new UrlPath(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows set an HTTP body.
|
||||
* @param body body to set
|
||||
*/
|
||||
public void body(Map<String, Object> body) {
|
||||
this.body = new Body(convertObjectsToDslProperties(body));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows set an HTTP body.
|
||||
* @param body body to set
|
||||
*/
|
||||
public void body(List body) {
|
||||
this.body = new Body(convertObjectsToDslProperties(body));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows set an HTTP body.
|
||||
* @param matchingStrategy body to set
|
||||
*/
|
||||
public void body(MatchingStrategy matchingStrategy) {
|
||||
this.body = new Body(matchingStrategy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows set an HTTP body.
|
||||
* @param dslProperty body to set
|
||||
*/
|
||||
public void body(DslProperty dslProperty) {
|
||||
this.body = new Body(dslProperty);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows set an HTTP body.
|
||||
* @param bodyAsValue body to set
|
||||
*/
|
||||
public void body(Object bodyAsValue) {
|
||||
this.body = new Body(bodyAsValue);
|
||||
}
|
||||
|
||||
public Body getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public void setBody(Body body) {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set multipart via the map notation.
|
||||
* @param body multipart in a map notation
|
||||
*/
|
||||
public void multipart(Map<String, Object> body) {
|
||||
this.multipart = new Multipart(convertObjectsToDslProperties(body));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set multipart via lists.
|
||||
* @param multipartAsList multipart in a list notation
|
||||
*/
|
||||
public void multipart(List multipartAsList) {
|
||||
this.multipart = Multipart.build(convertObjectsToDslProperties(multipartAsList));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set multipart value.
|
||||
* @param dslProperty multipart
|
||||
*/
|
||||
public void multipart(DslProperty dslProperty) {
|
||||
this.multipart = new Multipart(dslProperty);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set multipart value.
|
||||
* @param multipartAsValue multipart
|
||||
*/
|
||||
public void multipart(Object multipartAsValue) {
|
||||
this.multipart = Multipart.build(multipartAsValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the equality check to the given query parameter.
|
||||
* @param value value to check against
|
||||
* @return matching strategy
|
||||
*/
|
||||
public MatchingStrategy equalTo(Object value) {
|
||||
return new MatchingStrategy(value, MatchingStrategy.Type.EQUAL_TO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the containing check to the given query parameter.
|
||||
* @param value value to check against
|
||||
* @return matching strategy
|
||||
*/
|
||||
public MatchingStrategy containing(Object value) {
|
||||
return new MatchingStrategy(value, MatchingStrategy.Type.CONTAINS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the matching check to the given query parameter.
|
||||
* @param value value to check against
|
||||
* @return matching strategy
|
||||
*/
|
||||
public MatchingStrategy matching(Object value) {
|
||||
return new MatchingStrategy(value, MatchingStrategy.Type.MATCHING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the not matching check to the given query parameter.
|
||||
* @param value value to check against
|
||||
* @return matching strategy
|
||||
*/
|
||||
public MatchingStrategy notMatching(Object value) {
|
||||
return new MatchingStrategy(value, MatchingStrategy.Type.NOT_MATCHING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the XML equality check to the body.
|
||||
* @param value value to check against
|
||||
* @return matching strategy
|
||||
*/
|
||||
public MatchingStrategy equalToXml(Object value) {
|
||||
return new MatchingStrategy(value, MatchingStrategy.Type.EQUAL_TO_XML);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the JSON equality check to the body.
|
||||
* @param value value to check against
|
||||
* @return matching strategy
|
||||
*/
|
||||
public MatchingStrategy equalToJson(Object value) {
|
||||
return new MatchingStrategy(value, MatchingStrategy.Type.EQUAL_TO_JSON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets absence check to the given query parameter.
|
||||
* @return matching strategy
|
||||
*/
|
||||
public MatchingStrategy absent() {
|
||||
return new MatchingStrategy(true, MatchingStrategy.Type.ABSENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertThatSidesMatch(Object stubSide, Object testSide) {
|
||||
if (testSide instanceof OptionalProperty) {
|
||||
throw new IllegalStateException(
|
||||
"Optional can be used only for the stub side of the request!");
|
||||
}
|
||||
super.assertThatSidesMatch(stubSide, testSide);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set a dynamic value for the given element.
|
||||
* @param client client value
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty value(ClientDslProperty client) {
|
||||
Object concreteValue = client.getServerValue();
|
||||
Object dynamicValue = client.getClientValue();
|
||||
if (dynamicValue instanceof RegexProperty && client.isSingleValue()) {
|
||||
return ((RegexProperty) dynamicValue).dynamicClientEscapedConcreteProducer();
|
||||
}
|
||||
else if (concreteValue instanceof RegexProperty && !client.isSingleValue()) {
|
||||
concreteValue = dynamicValue;
|
||||
}
|
||||
|
||||
return new DslProperty(dynamicValue, concreteValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set a dynamic value for the given regular expression element.
|
||||
* @param property property to set
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty $(RegexProperty property) {
|
||||
return value(property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set a dynamic value for the given regular expression element.
|
||||
* @param property property to set
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty value(RegexProperty property) {
|
||||
return value(client(property));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set a dynamic value for the given element.
|
||||
* @param client property to set
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty $(ClientDslProperty client) {
|
||||
return value(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set a dynamic value for the Pattern element.
|
||||
* @param client property to set
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty value(Pattern client) {
|
||||
return value(new RegexProperty(client));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set a dynamic value for the given Pattern element.
|
||||
* @param client property to set
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty $(Pattern client) {
|
||||
return value(client);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegexProperty regexProperty(Object object) {
|
||||
return new RegexProperty(object).dynamicClientConcreteProducer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set a dynamic value for client and server side.
|
||||
* @param client client value
|
||||
* @param server server value
|
||||
* @return dsl property
|
||||
*/
|
||||
@Override
|
||||
public DslProperty value(ClientDslProperty client, ServerDslProperty server) {
|
||||
if (server.getClientValue() instanceof RegexProperty) {
|
||||
throw new IllegalStateException(
|
||||
"You can't have a regular expression for the request on the server side");
|
||||
}
|
||||
return super.value(client, server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set a dynamic value for client and server side.
|
||||
* @param client client value
|
||||
* @param server server value
|
||||
* @return dsl property
|
||||
*/
|
||||
@Override
|
||||
public DslProperty value(ServerDslProperty server, ClientDslProperty client) {
|
||||
if (server.getClientValue() instanceof RegexProperty) {
|
||||
throw new IllegalStateException(
|
||||
"You can't have a regular expression for the request on the server side");
|
||||
}
|
||||
|
||||
return super.value(server, client);
|
||||
}
|
||||
|
||||
public ClientPatternValueDslProperty getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
public void setProperty(ClientPatternValueDslProperty property) {
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
public HttpMethods getHttpMethods() {
|
||||
return httpMethods;
|
||||
}
|
||||
|
||||
public void setHttpMethods(HttpMethods httpMethods) {
|
||||
this.httpMethods = httpMethods;
|
||||
}
|
||||
|
||||
public DslProperty getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public void setMethod(DslProperty method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public Url getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(Url url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public UrlPath getUrlPath() {
|
||||
return urlPath;
|
||||
}
|
||||
|
||||
public void setUrlPath(UrlPath urlPath) {
|
||||
this.urlPath = urlPath;
|
||||
}
|
||||
|
||||
public Headers getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public void setHeaders(Headers headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
public Cookies getCookies() {
|
||||
return cookies;
|
||||
}
|
||||
|
||||
public void setCookies(Cookies cookies) {
|
||||
this.cookies = cookies;
|
||||
}
|
||||
|
||||
public Multipart getMultipart() {
|
||||
return multipart;
|
||||
}
|
||||
|
||||
public void setMultipart(Multipart multipart) {
|
||||
this.multipart = multipart;
|
||||
}
|
||||
|
||||
public BodyMatchers getBodyMatchers() {
|
||||
return bodyMatchers;
|
||||
}
|
||||
|
||||
public void setBodyMatchers(BodyMatchers bodyMatchers) {
|
||||
this.bodyMatchers = bodyMatchers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyAlphaUnicode() {
|
||||
return property.anyAlphaUnicode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyAlphaNumeric() {
|
||||
return property.anyAlphaNumeric();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyNumber() {
|
||||
return property.anyNumber();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyInteger() {
|
||||
return property.anyInteger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyPositiveInt() {
|
||||
return property.anyPositiveInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyDouble() {
|
||||
return property.anyDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyHex() {
|
||||
return property.anyHex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty aBoolean() {
|
||||
return property.aBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyIpAddress() {
|
||||
return property.anyIpAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyHostname() {
|
||||
return property.anyHostname();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyEmail() {
|
||||
return property.anyEmail();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyUrl() {
|
||||
return property.anyUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyHttpsUrl() {
|
||||
return property.anyHttpsUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyUuid() {
|
||||
return property.anyUuid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyDate() {
|
||||
return property.anyDate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyDateTime() {
|
||||
return property.anyDateTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyTime() {
|
||||
return property.anyTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyIso8601WithOffset() {
|
||||
return property.anyIso8601WithOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyNonBlankString() {
|
||||
return property.anyNonBlankString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyNonEmptyString() {
|
||||
return property.anyNonEmptyString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDslProperty anyOf(String... values) {
|
||||
return property.anyOf(values);
|
||||
}
|
||||
|
||||
public HttpMethods.HttpMethod GET() {
|
||||
return httpMethods.GET();
|
||||
}
|
||||
|
||||
public HttpMethods.HttpMethod HEAD() {
|
||||
return httpMethods.HEAD();
|
||||
}
|
||||
|
||||
public HttpMethods.HttpMethod POST() {
|
||||
return httpMethods.POST();
|
||||
}
|
||||
|
||||
public HttpMethods.HttpMethod PUT() {
|
||||
return httpMethods.PUT();
|
||||
}
|
||||
|
||||
public HttpMethods.HttpMethod PATCH() {
|
||||
return httpMethods.PATCH();
|
||||
}
|
||||
|
||||
public HttpMethods.HttpMethod DELETE() {
|
||||
return httpMethods.DELETE();
|
||||
}
|
||||
|
||||
public HttpMethods.HttpMethod OPTIONS() {
|
||||
return httpMethods.OPTIONS();
|
||||
}
|
||||
|
||||
public HttpMethods.HttpMethod TRACE() {
|
||||
return httpMethods.TRACE();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Request request = (Request) o;
|
||||
return Objects.equals(method, request.method) && Objects.equals(url, request.url)
|
||||
&& Objects.equals(urlPath, request.urlPath)
|
||||
&& Objects.equals(headers, request.headers)
|
||||
&& Objects.equals(cookies, request.cookies)
|
||||
&& Objects.equals(body, request.body)
|
||||
&& Objects.equals(multipart, request.multipart)
|
||||
&& Objects.equals(bodyMatchers, request.bodyMatchers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(method, url, urlPath, headers, cookies, body, multipart,
|
||||
bodyMatchers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Request{" + "\nmethod=" + method + ", \n\turl=" + url + ", \n\turlPath="
|
||||
+ urlPath + ", \n\theaders=" + headers + ", \n\tcookies=" + cookies
|
||||
+ ", \n\tbody=" + body + ", \n\tmultipart=" + multipart
|
||||
+ ", \n\tbodyMatchers=" + bodyMatchers + '}';
|
||||
}
|
||||
|
||||
/**
|
||||
* The URL of the contract.
|
||||
* @param url url value
|
||||
* @param consumer function to manipulate the URL
|
||||
*/
|
||||
public void url(Object url, Consumer<Url> consumer) {
|
||||
this.url = new Url(url);
|
||||
consumer.accept(this.url);
|
||||
}
|
||||
|
||||
/**
|
||||
* URL to which the request will be sent. Allows to customize additional query
|
||||
* parameters if needed
|
||||
* @param url url value
|
||||
* @param consumer function to manipulate the URL
|
||||
*/
|
||||
public void url(DslProperty url, Consumer<Url> consumer) {
|
||||
this.url = new Url(url);
|
||||
consumer.accept(this.url);
|
||||
}
|
||||
|
||||
/**
|
||||
* URL to which the request will be sent. Allows to customize additional query.
|
||||
* parameters if needed
|
||||
* @param path url value
|
||||
* @param consumer function to manipulate the URL
|
||||
*/
|
||||
public void urlPath(String path, Consumer<UrlPath> consumer) {
|
||||
this.urlPath = new UrlPath(path);
|
||||
consumer.accept(this.urlPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* URL to which the request will be sent. Allows to customize additional query.
|
||||
* parameters if needed
|
||||
* @param path url value
|
||||
* @param consumer function to manipulate the URL
|
||||
*/
|
||||
public void urlPath(DslProperty path, Consumer<UrlPath> consumer) {
|
||||
this.urlPath = new UrlPath(path);
|
||||
consumer.accept(this.urlPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to configure HTTP headers.
|
||||
* @param consumer function to manipulate the headers
|
||||
*/
|
||||
public void headers(Consumer<Request.RequestHeaders> consumer) {
|
||||
this.headers = new Request.RequestHeaders();
|
||||
consumer.accept((RequestHeaders) this.headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to configure HTTP cookies.
|
||||
* @param consumer function to manipulate the cookies
|
||||
*/
|
||||
public void cookies(Consumer<Request.RequestCookies> consumer) {
|
||||
this.cookies = new Request.RequestCookies();
|
||||
consumer.accept((RequestCookies) this.cookies);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param consumer function to manipulate the body matchers
|
||||
* @deprecated Deprecated in favor of bodyMatchers to support other future
|
||||
* bodyMatchers too
|
||||
*/
|
||||
@Deprecated
|
||||
public void stubMatchers(Consumer<BodyMatchers> consumer) {
|
||||
log.warn("stubMatchers method is deprecated. Please use bodyMatchers instead");
|
||||
bodyMatchers(consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set matchers for the body.
|
||||
* @param consumer function to manipulate the URL
|
||||
*/
|
||||
public void bodyMatchers(Consumer<BodyMatchers> consumer) {
|
||||
this.bodyMatchers = new BodyMatchers();
|
||||
consumer.accept(this.bodyMatchers);
|
||||
}
|
||||
|
||||
/**
|
||||
* The URL of the contract.
|
||||
* @param url url value
|
||||
* @param consumer function to manipulate the URL
|
||||
*/
|
||||
public void url(Object url, @DelegatesTo(Url.class) Closure consumer) {
|
||||
this.url = new Url(url);
|
||||
consumer.setDelegate(this.url);
|
||||
consumer.call();
|
||||
}
|
||||
|
||||
/**
|
||||
* URL to which the request will be sent. Allows to customize additional query
|
||||
* parameters if needed
|
||||
* @param url url value
|
||||
* @param consumer function to manipulate the URL
|
||||
*/
|
||||
public void url(DslProperty url, @DelegatesTo(Url.class) Closure consumer) {
|
||||
this.url = new Url(url);
|
||||
consumer.setDelegate(this.url);
|
||||
consumer.call();
|
||||
}
|
||||
|
||||
/**
|
||||
* URL to which the request will be sent. Allows to customize additional query.
|
||||
* parameters if needed
|
||||
* @param path url value
|
||||
* @param consumer function to manipulate the URL
|
||||
*/
|
||||
public void urlPath(String path, @DelegatesTo(UrlPath.class) Closure consumer) {
|
||||
this.urlPath = new UrlPath(path);
|
||||
consumer.setDelegate(this.urlPath);
|
||||
consumer.call();
|
||||
}
|
||||
|
||||
/**
|
||||
* URL to which the request will be sent. Allows to customize additional query.
|
||||
* parameters if needed
|
||||
* @param path url value
|
||||
* @param consumer function to manipulate the URL
|
||||
*/
|
||||
public void urlPath(DslProperty path, @DelegatesTo(UrlPath.class) Closure consumer) {
|
||||
this.urlPath = new UrlPath(path);
|
||||
consumer.setDelegate(this.urlPath);
|
||||
consumer.call();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to configure HTTP headers.
|
||||
* @param consumer function to manipulate the headers
|
||||
*/
|
||||
public void headers(@DelegatesTo(Request.RequestHeaders.class) Closure consumer) {
|
||||
this.headers = new Request.RequestHeaders();
|
||||
consumer.setDelegate(this.headers);
|
||||
consumer.call();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to configure HTTP cookies.
|
||||
* @param consumer function to manipulate the cookies
|
||||
*/
|
||||
public void cookies(@DelegatesTo(Request.RequestCookies.class) Closure consumer) {
|
||||
this.cookies = new Request.RequestCookies();
|
||||
consumer.setDelegate(this.cookies);
|
||||
consumer.call();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param consumer function to manipulate the body matchers
|
||||
* @deprecated Deprecated in favor of bodyMatchers to support other future
|
||||
* bodyMatchers too
|
||||
*/
|
||||
@Deprecated
|
||||
public void stubMatchers(@DelegatesTo(BodyMatchers.class) Closure consumer) {
|
||||
log.warn("stubMatchers method is deprecated. Please use bodyMatchers instead");
|
||||
bodyMatchers(consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set matchers for the body.
|
||||
* @param consumer function to manipulate the URL
|
||||
*/
|
||||
public void bodyMatchers(@DelegatesTo(BodyMatchers.class) Closure consumer) {
|
||||
this.bodyMatchers = new BodyMatchers();
|
||||
consumer.setDelegate(this.bodyMatchers);
|
||||
consumer.call();
|
||||
}
|
||||
|
||||
static class RequestHeaders extends Headers {
|
||||
|
||||
private final Common common = new Common();
|
||||
|
||||
@Override
|
||||
public DslProperty matching(String value) {
|
||||
return this.common.$(this.common.c(this.common
|
||||
.regex(RegexpUtils.escapeSpecialRegexWithSingleEscape(value) + ".*")),
|
||||
this.common.p(value));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class RequestCookies extends Cookies {
|
||||
|
||||
private final Common common = new Common();
|
||||
|
||||
@Override
|
||||
public DslProperty matching(String value) {
|
||||
return this.common.$(this.common.c(this.common
|
||||
.regex(RegexpUtils.escapeSpecialRegexWithSingleEscape(value) + ".*")),
|
||||
this.common.p(value));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ServerRequest extends Request {
|
||||
|
||||
ServerRequest(Request enclosing, Request request) {
|
||||
super(request);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ClientRequest extends Request {
|
||||
|
||||
ClientRequest(Request enclosing, Request request) {
|
||||
super(request);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ClientPatternValueDslProperty
|
||||
extends PatternValueDslProperty<ClientDslProperty> {
|
||||
|
||||
@Override
|
||||
protected ClientDslProperty createProperty(Pattern pattern,
|
||||
Object generatedValue) {
|
||||
return new ClientDslProperty(pattern, generatedValue);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,864 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import groovy.lang.Closure;
|
||||
import groovy.lang.DelegatesTo;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cloud.contract.spec.util.RegexpUtils;
|
||||
|
||||
/**
|
||||
* Represents the response side of the HTTP communication.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Tim Ysewyn
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class Response extends Common implements RegexCreatingProperty<ServerDslProperty> {
|
||||
|
||||
private static final Log log = LogFactory.getLog(Response.class);
|
||||
|
||||
private DslProperty status;
|
||||
|
||||
private DslProperty delay;
|
||||
|
||||
private Headers headers;
|
||||
|
||||
private Cookies cookies;
|
||||
|
||||
private Body body;
|
||||
|
||||
private boolean async;
|
||||
|
||||
private ResponseBodyMatchers bodyMatchers;
|
||||
|
||||
private ServerPatternValueDslProperty property = new ServerPatternValueDslProperty();
|
||||
|
||||
private HttpStatus httpStatus = new HttpStatus();
|
||||
|
||||
public Response() {
|
||||
}
|
||||
|
||||
public Response(Response response) {
|
||||
this.status = response.getStatus();
|
||||
this.headers = response.getHeaders();
|
||||
this.cookies = response.getCookies();
|
||||
this.body = response.getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set the HTTP status.
|
||||
* @param status HTTP status
|
||||
*/
|
||||
public void status(int status) {
|
||||
this.status = toDslProperty(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set the HTTP status.
|
||||
* @param status HTTP status
|
||||
*/
|
||||
public void status(DslProperty status) {
|
||||
this.status = toDslProperty(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows set an HTTP body.
|
||||
* @param body body to set
|
||||
*/
|
||||
public void body(Map<String, Object> body) {
|
||||
this.body = new Body(convertObjectsToDslProperties(body));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows set an HTTP body.
|
||||
* @param body body to set
|
||||
*/
|
||||
public void body(List body) {
|
||||
this.body = new Body(convertObjectsToDslProperties(body));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows set an HTTP body.
|
||||
* @param bodyAsValue body to set
|
||||
*/
|
||||
public void body(Object bodyAsValue) {
|
||||
if (bodyAsValue instanceof List) {
|
||||
body((List) bodyAsValue);
|
||||
}
|
||||
else {
|
||||
this.body = new Body(bodyAsValue);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set a fixed delay of the response in milliseconds.
|
||||
* @param timeInMilliseconds delay in millis
|
||||
*/
|
||||
public void fixedDelayMilliseconds(int timeInMilliseconds) {
|
||||
this.delay = toDslProperty(timeInMilliseconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns on the asynchronous mode for this contract. Used with MockMvc and the Servlet
|
||||
* 3.0 features.
|
||||
*/
|
||||
public void async() {
|
||||
this.async = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertThatSidesMatch(Object stubSide, Object testSide) {
|
||||
if (stubSide instanceof OptionalProperty) {
|
||||
throw new IllegalStateException(
|
||||
"Optional can be used only in the test side of the response!");
|
||||
}
|
||||
super.assertThatSidesMatch(stubSide, testSide);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set a dynamic value for the given element.
|
||||
* @param server server value
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty value(ServerDslProperty server) {
|
||||
Object dynamicValue = server.getServerValue();
|
||||
Object concreteValue = server.getClientValue();
|
||||
if (dynamicValue instanceof RegexProperty && server.isSingleValue()) {
|
||||
return ((RegexProperty) dynamicValue).concreteClientDynamicProducer();
|
||||
}
|
||||
return new DslProperty(concreteValue, dynamicValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set a dynamic value for the given element.
|
||||
* @param server server value
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty $(ServerDslProperty server) {
|
||||
return value(server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set a dynamic value for the given element.
|
||||
* @param server server value
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty value(Pattern server) {
|
||||
return value(new RegexProperty(server));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set a dynamic value for the given element.
|
||||
* @param server server value
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty value(RegexProperty server) {
|
||||
return value(new ServerDslProperty(server));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set a dynamic value for the given element.
|
||||
* @param server server value
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty $(RegexProperty server) {
|
||||
return value(server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set a dynamic value for the given element.
|
||||
* @param server server value
|
||||
* @return dsl property
|
||||
*/
|
||||
public DslProperty $(Pattern server) {
|
||||
return value(new RegexProperty(server));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegexProperty regexProperty(Object object) {
|
||||
return new RegexProperty(object).concreteClientDynamicProducer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to reference entries from the request.
|
||||
* @return from request object
|
||||
*/
|
||||
public FromRequest fromRequest() {
|
||||
return new FromRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set a dynamic value for the given element.
|
||||
* @param client client value
|
||||
* @param server server value
|
||||
* @return dsl property
|
||||
*/
|
||||
@Override
|
||||
public DslProperty value(ClientDslProperty client, ServerDslProperty server) {
|
||||
if (client.getClientValue() instanceof RegexProperty) {
|
||||
throw new IllegalStateException(
|
||||
"You can't have a regular expression for the response on the client side");
|
||||
}
|
||||
|
||||
return super.value(client, server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set a dynamic value for the given element.
|
||||
* @param server server value
|
||||
* @param client client value
|
||||
* @return dsl property
|
||||
*/
|
||||
@Override
|
||||
public DslProperty value(ServerDslProperty server, ClientDslProperty client) {
|
||||
if (client.getClientValue() instanceof RegexProperty) {
|
||||
throw new IllegalStateException(
|
||||
"You can't have a regular expression for the response on the client side");
|
||||
}
|
||||
|
||||
return super.value(server, client);
|
||||
}
|
||||
|
||||
public ServerPatternValueDslProperty getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
public void setProperty(ServerPatternValueDslProperty property) {
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
public HttpStatus getHttpStatus() {
|
||||
return httpStatus;
|
||||
}
|
||||
|
||||
public void setHttpStatus(HttpStatus httpStatus) {
|
||||
this.httpStatus = httpStatus;
|
||||
}
|
||||
|
||||
public DslProperty getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(DslProperty status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public DslProperty getDelay() {
|
||||
return delay;
|
||||
}
|
||||
|
||||
public void setDelay(DslProperty delay) {
|
||||
this.delay = delay;
|
||||
}
|
||||
|
||||
public Headers getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public void setHeaders(Headers headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
public Cookies getCookies() {
|
||||
return cookies;
|
||||
}
|
||||
|
||||
public void setCookies(Cookies cookies) {
|
||||
this.cookies = cookies;
|
||||
}
|
||||
|
||||
public Body getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public void setBody(Body body) {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public boolean getAsync() {
|
||||
return async;
|
||||
}
|
||||
|
||||
public boolean isAsync() {
|
||||
return async;
|
||||
}
|
||||
|
||||
public void setAsync(boolean async) {
|
||||
this.async = async;
|
||||
}
|
||||
|
||||
public ResponseBodyMatchers getBodyMatchers() {
|
||||
return bodyMatchers;
|
||||
}
|
||||
|
||||
public void setBodyMatchers(ResponseBodyMatchers bodyMatchers) {
|
||||
this.bodyMatchers = bodyMatchers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyAlphaUnicode() {
|
||||
return property.anyAlphaUnicode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyAlphaNumeric() {
|
||||
return property.anyAlphaNumeric();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyNumber() {
|
||||
return property.anyNumber();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyInteger() {
|
||||
return property.anyInteger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyPositiveInt() {
|
||||
return property.anyPositiveInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyDouble() {
|
||||
return property.anyDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyHex() {
|
||||
return property.anyHex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty aBoolean() {
|
||||
return property.aBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyIpAddress() {
|
||||
return property.anyIpAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyHostname() {
|
||||
return property.anyHostname();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyEmail() {
|
||||
return property.anyEmail();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyUrl() {
|
||||
return property.anyUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyHttpsUrl() {
|
||||
return property.anyHttpsUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyUuid() {
|
||||
return property.anyUuid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyDate() {
|
||||
return property.anyDate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyDateTime() {
|
||||
return property.anyDateTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyTime() {
|
||||
return property.anyTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyIso8601WithOffset() {
|
||||
return property.anyIso8601WithOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyNonBlankString() {
|
||||
return property.anyNonBlankString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyNonEmptyString() {
|
||||
return property.anyNonEmptyString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDslProperty anyOf(String... values) {
|
||||
return property.anyOf(values);
|
||||
}
|
||||
|
||||
public int CONTINUE() {
|
||||
return httpStatus.CONTINUE();
|
||||
}
|
||||
|
||||
public int SWITCHING_PROTOCOLS() {
|
||||
return httpStatus.SWITCHING_PROTOCOLS();
|
||||
}
|
||||
|
||||
public int PROCESSING() {
|
||||
return httpStatus.PROCESSING();
|
||||
}
|
||||
|
||||
public int CHECKPOINT() {
|
||||
return httpStatus.CHECKPOINT();
|
||||
}
|
||||
|
||||
public int OK() {
|
||||
return httpStatus.OK();
|
||||
}
|
||||
|
||||
public int CREATED() {
|
||||
return httpStatus.CREATED();
|
||||
}
|
||||
|
||||
public int ACCEPTED() {
|
||||
return httpStatus.ACCEPTED();
|
||||
}
|
||||
|
||||
public int NON_AUTHORITATIVE_INFORMATION() {
|
||||
return httpStatus.NON_AUTHORITATIVE_INFORMATION();
|
||||
}
|
||||
|
||||
public int NO_CONTENT() {
|
||||
return httpStatus.NO_CONTENT();
|
||||
}
|
||||
|
||||
public int RESET_CONTENT() {
|
||||
return httpStatus.RESET_CONTENT();
|
||||
}
|
||||
|
||||
public int PARTIAL_CONTENT() {
|
||||
return httpStatus.PARTIAL_CONTENT();
|
||||
}
|
||||
|
||||
public int MULTI_STATUS() {
|
||||
return httpStatus.MULTI_STATUS();
|
||||
}
|
||||
|
||||
public int ALREADY_REPORTED() {
|
||||
return httpStatus.ALREADY_REPORTED();
|
||||
}
|
||||
|
||||
public int IM_USED() {
|
||||
return httpStatus.IM_USED();
|
||||
}
|
||||
|
||||
public int MULTIPLE_CHOICES() {
|
||||
return httpStatus.MULTIPLE_CHOICES();
|
||||
}
|
||||
|
||||
public int MOVED_PERMANENTLY() {
|
||||
return httpStatus.MOVED_PERMANENTLY();
|
||||
}
|
||||
|
||||
public int FOUND() {
|
||||
return httpStatus.FOUND();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public int MOVED_TEMPORARILY() {
|
||||
return httpStatus.MOVED_TEMPORARILY();
|
||||
}
|
||||
|
||||
public int SEE_OTHER() {
|
||||
return httpStatus.SEE_OTHER();
|
||||
}
|
||||
|
||||
public int NOT_MODIFIED() {
|
||||
return httpStatus.NOT_MODIFIED();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public int USE_PROXY() {
|
||||
return httpStatus.USE_PROXY();
|
||||
}
|
||||
|
||||
public int TEMPORARY_REDIRECT() {
|
||||
return httpStatus.TEMPORARY_REDIRECT();
|
||||
}
|
||||
|
||||
public int PERMANENT_REDIRECT() {
|
||||
return httpStatus.PERMANENT_REDIRECT();
|
||||
}
|
||||
|
||||
public int BAD_REQUEST() {
|
||||
return httpStatus.BAD_REQUEST();
|
||||
}
|
||||
|
||||
public int UNAUTHORIZED() {
|
||||
return httpStatus.UNAUTHORIZED();
|
||||
}
|
||||
|
||||
public int PAYMENT_REQUIRED() {
|
||||
return httpStatus.PAYMENT_REQUIRED();
|
||||
}
|
||||
|
||||
public int FORBIDDEN() {
|
||||
return httpStatus.FORBIDDEN();
|
||||
}
|
||||
|
||||
public int NOT_FOUND() {
|
||||
return httpStatus.NOT_FOUND();
|
||||
}
|
||||
|
||||
public int METHOD_NOT_ALLOWED() {
|
||||
return httpStatus.METHOD_NOT_ALLOWED();
|
||||
}
|
||||
|
||||
public int NOT_ACCEPTABLE() {
|
||||
return httpStatus.NOT_ACCEPTABLE();
|
||||
}
|
||||
|
||||
public int PROXY_AUTHENTICATION_REQUIRED() {
|
||||
return httpStatus.PROXY_AUTHENTICATION_REQUIRED();
|
||||
}
|
||||
|
||||
public int REQUEST_TIMEOUT() {
|
||||
return httpStatus.REQUEST_TIMEOUT();
|
||||
}
|
||||
|
||||
public int CONFLICT() {
|
||||
return httpStatus.CONFLICT();
|
||||
}
|
||||
|
||||
public int GONE() {
|
||||
return httpStatus.GONE();
|
||||
}
|
||||
|
||||
public int LENGTH_REQUIRED() {
|
||||
return httpStatus.LENGTH_REQUIRED();
|
||||
}
|
||||
|
||||
public int PRECONDITION_FAILED() {
|
||||
return httpStatus.PRECONDITION_FAILED();
|
||||
}
|
||||
|
||||
public int PAYLOAD_TOO_LARGE() {
|
||||
return httpStatus.PAYLOAD_TOO_LARGE();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public int REQUEST_ENTITY_TOO_LARGE() {
|
||||
return httpStatus.REQUEST_ENTITY_TOO_LARGE();
|
||||
}
|
||||
|
||||
public int URI_TOO_LONG() {
|
||||
return httpStatus.URI_TOO_LONG();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public int REQUEST_URI_TOO_LONG() {
|
||||
return httpStatus.REQUEST_URI_TOO_LONG();
|
||||
}
|
||||
|
||||
public int UNSUPPORTED_MEDIA_TYPE() {
|
||||
return httpStatus.UNSUPPORTED_MEDIA_TYPE();
|
||||
}
|
||||
|
||||
public int REQUESTED_RANGE_NOT_SATISFIABLE() {
|
||||
return httpStatus.REQUESTED_RANGE_NOT_SATISFIABLE();
|
||||
}
|
||||
|
||||
public int EXPECTATION_FAILED() {
|
||||
return httpStatus.EXPECTATION_FAILED();
|
||||
}
|
||||
|
||||
public int I_AM_A_TEAPOT() {
|
||||
return httpStatus.I_AM_A_TEAPOT();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public int INSUFFICIENT_SPACE_ON_RESOURCE() {
|
||||
return httpStatus.INSUFFICIENT_SPACE_ON_RESOURCE();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public int METHOD_FAILURE() {
|
||||
return httpStatus.METHOD_FAILURE();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public int DESTINATION_LOCKED() {
|
||||
return httpStatus.DESTINATION_LOCKED();
|
||||
}
|
||||
|
||||
public int UNPROCESSABLE_ENTITY() {
|
||||
return httpStatus.UNPROCESSABLE_ENTITY();
|
||||
}
|
||||
|
||||
public int LOCKED() {
|
||||
return httpStatus.LOCKED();
|
||||
}
|
||||
|
||||
public int FAILED_DEPENDENCY() {
|
||||
return httpStatus.FAILED_DEPENDENCY();
|
||||
}
|
||||
|
||||
public int UPGRADE_REQUIRED() {
|
||||
return httpStatus.UPGRADE_REQUIRED();
|
||||
}
|
||||
|
||||
public int PRECONDITION_REQUIRED() {
|
||||
return httpStatus.PRECONDITION_REQUIRED();
|
||||
}
|
||||
|
||||
public int TOO_MANY_REQUESTS() {
|
||||
return httpStatus.TOO_MANY_REQUESTS();
|
||||
}
|
||||
|
||||
public int REQUEST_HEADER_FIELDS_TOO_LARGE() {
|
||||
return httpStatus.REQUEST_HEADER_FIELDS_TOO_LARGE();
|
||||
}
|
||||
|
||||
public int UNAVAILABLE_FOR_LEGAL_REASONS() {
|
||||
return httpStatus.UNAVAILABLE_FOR_LEGAL_REASONS();
|
||||
}
|
||||
|
||||
public int INTERNAL_SERVER_ERROR() {
|
||||
return httpStatus.INTERNAL_SERVER_ERROR();
|
||||
}
|
||||
|
||||
public int NOT_IMPLEMENTED() {
|
||||
return httpStatus.NOT_IMPLEMENTED();
|
||||
}
|
||||
|
||||
public int BAD_GATEWAY() {
|
||||
return httpStatus.BAD_GATEWAY();
|
||||
}
|
||||
|
||||
public int SERVICE_UNAVAILABLE() {
|
||||
return httpStatus.SERVICE_UNAVAILABLE();
|
||||
}
|
||||
|
||||
public int GATEWAY_TIMEOUT() {
|
||||
return httpStatus.GATEWAY_TIMEOUT();
|
||||
}
|
||||
|
||||
public int HTTP_VERSION_NOT_SUPPORTED() {
|
||||
return httpStatus.HTTP_VERSION_NOT_SUPPORTED();
|
||||
}
|
||||
|
||||
public int VARIANT_ALSO_NEGOTIATES() {
|
||||
return httpStatus.VARIANT_ALSO_NEGOTIATES();
|
||||
}
|
||||
|
||||
public int INSUFFICIENT_STORAGE() {
|
||||
return httpStatus.INSUFFICIENT_STORAGE();
|
||||
}
|
||||
|
||||
public int LOOP_DETECTED() {
|
||||
return httpStatus.LOOP_DETECTED();
|
||||
}
|
||||
|
||||
public int BANDWIDTH_LIMIT_EXCEEDED() {
|
||||
return httpStatus.BANDWIDTH_LIMIT_EXCEEDED();
|
||||
}
|
||||
|
||||
public int NOT_EXTENDED() {
|
||||
return httpStatus.NOT_EXTENDED();
|
||||
}
|
||||
|
||||
public int NETWORK_AUTHENTICATION_REQUIRED() {
|
||||
return httpStatus.NETWORK_AUTHENTICATION_REQUIRED();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Response response = (Response) o;
|
||||
return async == response.async && Objects.equals(status, response.status)
|
||||
&& Objects.equals(delay, response.delay)
|
||||
&& Objects.equals(headers, response.headers)
|
||||
&& Objects.equals(cookies, response.cookies)
|
||||
&& Objects.equals(body, response.body)
|
||||
&& Objects.equals(bodyMatchers, response.bodyMatchers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(status, delay, headers, cookies, body, async, bodyMatchers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Response{" + "\nstatus=" + status + ", \n\tdelay=" + delay
|
||||
+ ", \n\theaders=" + headers + ", \n\tcookies=" + cookies + ", \n\tbody="
|
||||
+ body + ", \n\tasync=" + async + ", \n\tbodyMatchers=" + bodyMatchers
|
||||
+ '}';
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to configure HTTP headers.
|
||||
* @param consumer function to manipulate the URL
|
||||
*/
|
||||
public void headers(Consumer<ResponseHeaders> consumer) {
|
||||
this.headers = new Response.ResponseHeaders();
|
||||
consumer.accept((ResponseHeaders) this.headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to configure HTTP cookies.
|
||||
* @param consumer function to manipulate the URL
|
||||
*/
|
||||
public void cookies(Consumer<Response.ResponseCookies> consumer) {
|
||||
this.cookies = new Response.ResponseCookies();
|
||||
consumer.accept((ResponseCookies) this.cookies);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Deprecated in favor of bodyMatchers to support other future
|
||||
* bodyMatchers too
|
||||
* @param consumer function to manipulate the URL
|
||||
*/
|
||||
@Deprecated
|
||||
public void testMatchers(Consumer<ResponseBodyMatchers> consumer) {
|
||||
log.warn("testMatchers method is deprecated. Please use bodyMatchers instead");
|
||||
bodyMatchers(consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set matchers for the body.
|
||||
* @param consumer function to manipulate the URL
|
||||
*/
|
||||
public void bodyMatchers(Consumer<ResponseBodyMatchers> consumer) {
|
||||
this.bodyMatchers = new ResponseBodyMatchers();
|
||||
consumer.accept(this.bodyMatchers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to configure HTTP headers.
|
||||
* @param consumer function to manipulate the URL
|
||||
*/
|
||||
public void headers(@DelegatesTo(ResponseHeaders.class) Closure consumer) {
|
||||
this.headers = new Response.ResponseHeaders();
|
||||
consumer.setDelegate(this.headers);
|
||||
consumer.call();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to configure HTTP cookies.
|
||||
* @param consumer function to manipulate the URL
|
||||
*/
|
||||
public void cookies(@DelegatesTo(Response.ResponseCookies.class) Closure consumer) {
|
||||
this.cookies = new Response.ResponseCookies();
|
||||
consumer.setDelegate(this.cookies);
|
||||
consumer.call();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Deprecated in favor of bodyMatchers to support other future
|
||||
* bodyMatchers too
|
||||
* @param consumer function to manipulate the URL
|
||||
*/
|
||||
@Deprecated
|
||||
public void testMatchers(@DelegatesTo(ResponseBodyMatchers.class) Closure consumer) {
|
||||
log.warn("testMatchers method is deprecated. Please use bodyMatchers instead");
|
||||
bodyMatchers(consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set matchers for the body.
|
||||
* @param consumer function to manipulate the URL
|
||||
*/
|
||||
public void bodyMatchers(@DelegatesTo(ResponseBodyMatchers.class) Closure consumer) {
|
||||
this.bodyMatchers = new ResponseBodyMatchers();
|
||||
consumer.setDelegate(this.bodyMatchers);
|
||||
consumer.call();
|
||||
}
|
||||
|
||||
static class ResponseHeaders extends Headers {
|
||||
|
||||
private final Common common = new Common();
|
||||
|
||||
@Override
|
||||
public DslProperty matching(final String value) {
|
||||
return this.common.$(this.common.p(notEscaped(Pattern.compile(
|
||||
RegexpUtils.escapeSpecialRegexWithSingleEscape(value) + ".*"))),
|
||||
this.common.c(value));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class ResponseCookies extends Cookies {
|
||||
|
||||
private final Common common = new Common();
|
||||
|
||||
@Override
|
||||
public DslProperty matching(final String value) {
|
||||
return this.common.$(this.common.p(this.common
|
||||
.regex(RegexpUtils.escapeSpecialRegexWithSingleEscape(value) + ".*")),
|
||||
this.common.c(value));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ServerResponse extends Response {
|
||||
|
||||
ServerResponse(Response enclosing, Response request) {
|
||||
super(request);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ClientResponse extends Response {
|
||||
|
||||
ClientResponse(Response enclosing, Response request) {
|
||||
super(request);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ServerPatternValueDslProperty
|
||||
extends PatternValueDslProperty<ServerDslProperty> {
|
||||
|
||||
@Override
|
||||
protected ServerDslProperty createProperty(Pattern pattern,
|
||||
Object generatedValue) {
|
||||
return new ServerDslProperty(pattern, generatedValue);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
/**
|
||||
* Body matchers for the response side (output message, REST response).
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Tim Ysewyn
|
||||
* @since 1.0.3
|
||||
*/
|
||||
public class ResponseBodyMatchers extends BodyMatchers {
|
||||
|
||||
public MatchingTypeValue byType() {
|
||||
MatchingTypeValue value = new MatchingTypeValue();
|
||||
value.setType(MatchingType.TYPE);
|
||||
return value;
|
||||
}
|
||||
|
||||
public MatchingTypeValue byCommand(String execute) {
|
||||
MatchingTypeValue value = new MatchingTypeValue();
|
||||
value.setType(MatchingType.COMMAND);
|
||||
value.setValue(new ExecutionProperty(execute));
|
||||
return value;
|
||||
}
|
||||
|
||||
public MatchingTypeValue byNull() {
|
||||
MatchingTypeValue value = new MatchingTypeValue();
|
||||
value.setType(MatchingType.NULL);
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
/**
|
||||
* Represents a server side {@link DslProperty}.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class ServerDslProperty extends DslProperty {
|
||||
|
||||
public ServerDslProperty(Object singleValue) {
|
||||
super(singleValue);
|
||||
}
|
||||
|
||||
public ServerDslProperty(Object server, Object client) {
|
||||
super(client, server);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
class ServerInput extends Input {
|
||||
|
||||
ServerInput(Input request) {
|
||||
super(request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
class ServerOutputMessage extends OutputMessage {
|
||||
|
||||
ServerOutputMessage(OutputMessage request) {
|
||||
super(request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import groovy.lang.Closure;
|
||||
import groovy.lang.DelegatesTo;
|
||||
|
||||
import org.springframework.cloud.contract.spec.util.ValidateUtils;
|
||||
|
||||
/**
|
||||
* Represents a URL that may contain query parameters.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class Url extends DslProperty {
|
||||
|
||||
private QueryParameters queryParameters;
|
||||
|
||||
public Url(DslProperty prop) {
|
||||
super(prop.getClientValue(), prop.getServerValue());
|
||||
ValidateUtils.validateServerValueIsAvailable(prop.getServerValue(), "Url");
|
||||
}
|
||||
|
||||
public Url(Object url) {
|
||||
super(url, testUrl(url));
|
||||
ValidateUtils.validateServerValueIsAvailable(url, "Url");
|
||||
}
|
||||
|
||||
// Can be overridable by extensions
|
||||
private static Object testUrl(Object url) {
|
||||
return DslPropertyConverter.INSTANCE.testSide(url);
|
||||
}
|
||||
|
||||
public QueryParameters getQueryParameters() {
|
||||
return queryParameters;
|
||||
}
|
||||
|
||||
public void setQueryParameters(QueryParameters queryParameters) {
|
||||
this.queryParameters = queryParameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
if (!super.equals(o)) {
|
||||
return false;
|
||||
}
|
||||
Url url = (Url) o;
|
||||
return Objects.equals(queryParameters, url.queryParameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), queryParameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Url{" + "\nqueryParameters=" + queryParameters + "} \n"
|
||||
+ super.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* The query parameters part of the contract.
|
||||
* @param consumer function to manipulate the query parameters
|
||||
*/
|
||||
public void queryParameters(Consumer<QueryParameters> consumer) {
|
||||
this.queryParameters = new QueryParameters();
|
||||
consumer.accept(this.queryParameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* The query parameters part of the contract.
|
||||
* @param consumer function to manipulate the query parameters
|
||||
*/
|
||||
public void queryParameters(@DelegatesTo(QueryParameters.class) Closure consumer) {
|
||||
this.queryParameters = new QueryParameters();
|
||||
consumer.setDelegate(this.queryParameters);
|
||||
consumer.call();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Taken from https://gist.github.com/skeller88/5eb73dc0090d4ff1249a.
|
||||
*/
|
||||
final class UrlHelper {
|
||||
|
||||
/**
|
||||
* Example: "http". Also called 'protocol'. Scheme component is optional, even though
|
||||
* the RFC doesn't make it optional. Since ((RegexProperty) this regex is validating a
|
||||
* submitted callback url, which determines where the browser will navigate to after a
|
||||
* successful authentication, the browser will use http or https for the scheme by
|
||||
* default. Not borrowed from dperini in order to allow any scheme type.
|
||||
*/
|
||||
private static final String REGEX_SCHEME = "[A-Za-z][+-.\\w^_]*:";
|
||||
|
||||
private static final String HTTPS_REGEX_SCHEME = "https:";
|
||||
|
||||
private static final String REGEX_AUTHORATIVE_DECLARATION = "/{2}";
|
||||
|
||||
private static final String REGEX_USERINFO = "(?:\\S+(?::\\S*)?@)?";
|
||||
|
||||
private static final String REGEX_HOST = "(?:"
|
||||
+ "(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"
|
||||
+ "|" + "(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)"
|
||||
+ "(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*"
|
||||
+ "(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))|(?:localhost))";
|
||||
|
||||
private static final String REGEX_PORT = "(?::\\d{2,5})?";
|
||||
|
||||
private static final String REGEX_RESOURCE_PATH = "(?:/\\S*)?";
|
||||
|
||||
protected static final Pattern HTTPS_URL = Pattern.compile(
|
||||
"^(?:" + HTTPS_REGEX_SCHEME + REGEX_AUTHORATIVE_DECLARATION + REGEX_USERINFO
|
||||
+ REGEX_HOST + REGEX_PORT + REGEX_RESOURCE_PATH + ")$");
|
||||
|
||||
protected static final Pattern URL = Pattern.compile("^(?:(?:" + REGEX_SCHEME
|
||||
+ REGEX_AUTHORATIVE_DECLARATION + ")?" + REGEX_USERINFO + REGEX_HOST
|
||||
+ REGEX_PORT + REGEX_RESOURCE_PATH + ")$");
|
||||
|
||||
private UrlHelper() {
|
||||
throw new IllegalStateException("Can't instantiate an utility class");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.internal;
|
||||
|
||||
/**
|
||||
* Represents a url path. Syntactic sugar when working with {@link QueryParameters}. It's
|
||||
* logically equal to {@link Url}.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class UrlPath extends Url {
|
||||
|
||||
public UrlPath(Object path) {
|
||||
super(path);
|
||||
}
|
||||
|
||||
public UrlPath(String path) {
|
||||
super(path);
|
||||
}
|
||||
|
||||
public UrlPath(DslProperty path) {
|
||||
super(path);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.util;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Useful utility methods to work with regular expressions.
|
||||
*
|
||||
* @since 1.0.2
|
||||
*/
|
||||
public final class RegexpUtils {
|
||||
|
||||
private RegexpUtils() {
|
||||
throw new IllegalStateException("Can't instantiate a utility class");
|
||||
}
|
||||
|
||||
public static String escapeSpecialRegexChars(String str) {
|
||||
return SPECIAL_REGEX_CHARS.matcher(str).replaceAll("\\\\\\\\$0");
|
||||
}
|
||||
|
||||
public static String escapeSpecialRegexWithSingleEscape(String str) {
|
||||
return SPECIAL_REGEX_CHARS.matcher(str).replaceAll("\\\\$0");
|
||||
}
|
||||
|
||||
private static final Pattern SPECIAL_REGEX_CHARS = Pattern
|
||||
.compile("[{}()\\[\\].+*?^$\\\\|]");
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.cloud.contract.spec.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.cloud.contract.spec.internal.DslProperty;
|
||||
import org.springframework.cloud.contract.spec.internal.MatchingStrategy;
|
||||
import org.springframework.cloud.contract.spec.internal.RegexProperty;
|
||||
|
||||
/**
|
||||
* Checks the validity of DSL entries.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public final class ValidateUtils {
|
||||
|
||||
private ValidateUtils() {
|
||||
throw new IllegalStateException("Can't instantiate an utility class");
|
||||
}
|
||||
|
||||
/**
|
||||
* Allowed matching types on the server side.
|
||||
*/
|
||||
public static List<MatchingStrategy.Type> ALLOWED_MATCHING_TYPES_ON_SERVER_SIDE = new ArrayList<>(
|
||||
Arrays.asList(MatchingStrategy.Type.EQUAL_TO, MatchingStrategy.Type.ABSENT));
|
||||
|
||||
/**
|
||||
* Validates if for given object the server value is present.
|
||||
* @param value value to check
|
||||
* @param msg potential exception message
|
||||
* @return object if everything is fine
|
||||
*/
|
||||
public static Object validateServerValueIsAvailable(Object value, String msg) {
|
||||
if (value instanceof Pattern) {
|
||||
validateServerValue((Pattern) value, msg);
|
||||
}
|
||||
else if (value instanceof RegexProperty) {
|
||||
RegexProperty property = (RegexProperty) value;
|
||||
validateServerValue(property.getPattern(), msg);
|
||||
}
|
||||
else if (value instanceof MatchingStrategy) {
|
||||
validateServerValue((MatchingStrategy) value, msg);
|
||||
}
|
||||
else if (value instanceof DslProperty) {
|
||||
validateServerValue((DslProperty) value, msg);
|
||||
}
|
||||
else {
|
||||
validateServerValue(value, msg);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static void validateServerValue(Pattern pattern, String msg) {
|
||||
throw new IllegalStateException(msg + " can\'t be a pattern for the server side");
|
||||
}
|
||||
|
||||
public static void validateServerValue(MatchingStrategy matchingStrategy,
|
||||
String msg) {
|
||||
if (!ALLOWED_MATCHING_TYPES_ON_SERVER_SIDE.contains(matchingStrategy.getType())) {
|
||||
throw new IllegalStateException(msg + " can\'t be of a matching type: "
|
||||
+ String.valueOf(matchingStrategy.getType())
|
||||
+ " for the server side");
|
||||
}
|
||||
|
||||
validateServerValue(matchingStrategy.getServerValue(), msg);
|
||||
}
|
||||
|
||||
public static void validateServerValue(DslProperty value, String msg) {
|
||||
validateServerValue(value.getServerValue(), msg);
|
||||
}
|
||||
|
||||
public static void validateServerValue(Object value, String msg) {
|
||||
// OK
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* Copyright 2009 Wilfred Springer
|
||||
* Copyright 2012 Jason Pell
|
||||
* Copyright 2013 Antonio García-Domínguez
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* The class is bundled together with our code because it has not been
|
||||
* released to any central repository.
|
||||
*/
|
||||
|
||||
package repackaged.nl.flotsam.xeger;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import dk.brics.automaton.Automaton;
|
||||
import dk.brics.automaton.RegExp;
|
||||
import dk.brics.automaton.State;
|
||||
import dk.brics.automaton.Transition;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* An object that will generate text from a regular expression. In a way, it's the
|
||||
* opposite of a regular expression matcher: an instance of this class will produce text
|
||||
* that is guaranteed to match the regular expression passed in.
|
||||
*
|
||||
* slight modifications by Marcin Grzejszczak
|
||||
*/
|
||||
public class Xeger {
|
||||
|
||||
// Added by Marcin Grzejszczak
|
||||
// may lead to stackoverflow when regex is unbounded
|
||||
static int ITERATION_LIMIT = 200;
|
||||
|
||||
private final Automaton automaton;
|
||||
|
||||
private Random random;
|
||||
|
||||
/**
|
||||
* Constructs a new instance, accepting the regular expression and the randomizer.
|
||||
* @param regex The regular expression. (Not <code>null</code>.)
|
||||
* @param random The object that will randomize the way the String is generated. (Not
|
||||
* <code>null</code>.)
|
||||
* @throws IllegalArgumentException If the regular expression is invalid.
|
||||
*/
|
||||
public Xeger(String regex, Random random) {
|
||||
assert regex != null;
|
||||
assert random != null;
|
||||
// https://stackoverflow.com/questions/1578789/how-do-i-generate-text-matching-a-regular-expression-from-a-regular-expression
|
||||
String pattern = regex.replace("\\d", "[0-9]") // Used d=Digit
|
||||
.replace("\\w", "[A-Za-z0-9_]") // Used =Word
|
||||
.replace("\\s", "[ \t\r\n]"); // Used s="White"Space
|
||||
this.automaton = new RegExp(pattern).toAutomaton();
|
||||
this.random = random;
|
||||
String generatedCharsSysProp = System
|
||||
.getProperty("springCloudContractGeneratedCharsFromRegex");
|
||||
String generatedCharsEnvVar = System
|
||||
.getenv("SPRING_CLOUD_CONTRACT_GENERATED_CHARS_FROM_REGEX");
|
||||
if (StringUtils.isNotEmpty(generatedCharsSysProp)) {
|
||||
ITERATION_LIMIT = Integer.parseInt(generatedCharsSysProp);
|
||||
}
|
||||
else if (StringUtils.isNotEmpty(generatedCharsEnvVar)) {
|
||||
ITERATION_LIMIT = Integer.parseInt(generatedCharsEnvVar);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* As {@link Xeger#Xeger(String, java.util.Random)}, creating a
|
||||
* {@link java.util.Random} instance implicityly.
|
||||
* @param regex as string
|
||||
*/
|
||||
public Xeger(String regex) {
|
||||
this(regex, new Random());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random number within the given bounds.
|
||||
* @param min The minimum number (inclusive).
|
||||
* @param max The maximum number (inclusive).
|
||||
* @param random The object used as the randomizer.
|
||||
* @return A random number in the given range.
|
||||
*/
|
||||
static int getRandomInt(int min, int max, Random random) {
|
||||
// Use random.nextInt as it guarantees a uniform distribution
|
||||
int maxForRandom = max - min + 1;
|
||||
return random.nextInt(maxForRandom) + min;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random String that is guaranteed to match the regular expression passed
|
||||
* to the constructor.
|
||||
* @return generated regexp
|
||||
*/
|
||||
public String generate() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
int counter = 0;
|
||||
generate(builder, this.automaton.getInitialState(), counter);
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private void generate(StringBuilder builder, State state, int counter) {
|
||||
if (counter >= ITERATION_LIMIT) {
|
||||
return;
|
||||
}
|
||||
List<Transition> transitions = state.getSortedTransitions(false);
|
||||
if (transitions.size() == 0) {
|
||||
assert state.isAccept();
|
||||
return;
|
||||
}
|
||||
int nroptions = state.isAccept() ? transitions.size() : transitions.size() - 1;
|
||||
int option = Xeger.getRandomInt(0, nroptions, this.random);
|
||||
if (state.isAccept() && option == 0) { // 0 is considered stop
|
||||
return;
|
||||
}
|
||||
// Moving on to next transition
|
||||
Transition transition = transitions.get(option - (state.isAccept() ? 1 : 0));
|
||||
appendChoice(builder, transition);
|
||||
generate(builder, transition.getDest(), ++counter);
|
||||
}
|
||||
|
||||
private void appendChoice(StringBuilder builder, Transition transition) {
|
||||
char c = (char) Xeger.getRandomInt(transition.getMin(), transition.getMax(),
|
||||
this.random);
|
||||
builder.append(c);
|
||||
}
|
||||
|
||||
public Random getRandom() {
|
||||
return this.random;
|
||||
}
|
||||
|
||||
public void setRandom(Random random) {
|
||||
this.random = random;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user