Migrated to default WireMock helper methods; fixes gh-540
This commit is contained in:
@@ -1,89 +0,0 @@
|
||||
package org.springframework.cloud.contract.spec
|
||||
|
||||
/**
|
||||
* Contract for defining templated responses.
|
||||
*
|
||||
* If no implementation is provided then Handlebars will be picked as a default implementation.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 1.1.0
|
||||
*/
|
||||
interface ContractTemplate {
|
||||
|
||||
/**
|
||||
* Handlebars is using the Mustache template thus it looks like this
|
||||
* {{{ Mustache }}}. In this case the opening template would return {{{
|
||||
*/
|
||||
String openingTemplate()
|
||||
|
||||
/**
|
||||
* Handlebars is using the Mustache template thus it looks like this
|
||||
* {{{ Mustache }}}. In this case the closing template would return }}}
|
||||
*/
|
||||
String closingTemplate()
|
||||
|
||||
/**
|
||||
* Returns the template for retrieving a URL path and query from request
|
||||
*/
|
||||
String url()
|
||||
|
||||
/**
|
||||
* Returns the template for retrieving first value of a query parameter e.g. {{{ request.query.search }}}
|
||||
* @param key
|
||||
*/
|
||||
String query(String key)
|
||||
|
||||
/**
|
||||
* Returns the template for retrieving nth value of a query parameter (zero indexed) e.g. {{{ request.query.search.[5] }}}
|
||||
* @param key
|
||||
* @param index
|
||||
*/
|
||||
String query(String key, int index)
|
||||
|
||||
/**
|
||||
* Returns the template for retrieving a URL path
|
||||
*/
|
||||
String path()
|
||||
|
||||
/**
|
||||
* Returns the template for retrieving nth value of a URL path (zero indexed) e.g. {{{ request.path.[2] }}}
|
||||
* @param index
|
||||
*/
|
||||
String path(int index)
|
||||
|
||||
/**
|
||||
* Returns the template for retrieving the first value of a request header e.g. {{{ request.headers.X-Request-Id }}}
|
||||
* @param key
|
||||
*/
|
||||
String header(String key)
|
||||
|
||||
/**
|
||||
* Returns the template for retrieving the nth value of a request header (zero indexed) e.g. {{{ request.headers.X-Request-Id.[5] }}}
|
||||
* @param key
|
||||
* @param index
|
||||
*/
|
||||
String header(String key, int index)
|
||||
|
||||
/**
|
||||
* Retruns the tempalte for retrieving the first value of a cookie with certain key
|
||||
* @param key
|
||||
*/
|
||||
String cookie(String key)
|
||||
|
||||
/**
|
||||
* 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()
|
||||
|
||||
/**
|
||||
* Request body text (avoid for non-text bodies) e.g. {{{ escapejsonbody }}} . The body will not be escaped
|
||||
* so you will be able to embed it
|
||||
*/
|
||||
String escapedBody()
|
||||
|
||||
/**
|
||||
* Request body text for the given JsonPath. e.g. {{{ jsonpath this '$.a.b.c' }}}
|
||||
*/
|
||||
String body(String jsonPath)
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
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 {
|
||||
/**
|
||||
* Asserts whether the given text starts with proper opening template
|
||||
*/
|
||||
default boolean startsWithTemplate(String text) {
|
||||
return text.startsWith(openingTemplate());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {{
|
||||
*/
|
||||
String openingTemplate();
|
||||
|
||||
/**
|
||||
* Handlebars is using the Mustache template thus it looks like this
|
||||
* {{ Mustache }}. In this case the closing template would return }}
|
||||
*/
|
||||
String closingTemplate();
|
||||
|
||||
/**
|
||||
* Handlebars is using the Mustache template thus it looks like this
|
||||
* {{{ Mustache }}}. In this case the opening template would return {{{
|
||||
*/
|
||||
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 }}}
|
||||
*/
|
||||
default String escapedClosingTemplate() {
|
||||
return closingTemplate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the template for retrieving a URL path and query from request
|
||||
*/
|
||||
String url();
|
||||
|
||||
/**
|
||||
* Returns the template for retrieving first value of a query parameter e.g. {{ request.query.search }}
|
||||
*
|
||||
* @param key
|
||||
*/
|
||||
String query(String key);
|
||||
|
||||
/**
|
||||
* Returns the template for retrieving nth value of a query parameter (zero indexed) e.g. {{ request.query.search.[5] }}
|
||||
*
|
||||
* @param key
|
||||
* @param index
|
||||
*/
|
||||
String query(String key, int index);
|
||||
|
||||
/**
|
||||
* Returns the template for retrieving a URL path
|
||||
*/
|
||||
String path();
|
||||
|
||||
/**
|
||||
* Returns the template for retrieving nth value of a URL path (zero indexed) e.g. {{ request.path.[2] }}
|
||||
*
|
||||
* @param index
|
||||
*/
|
||||
String path(int index);
|
||||
|
||||
/**
|
||||
* Returns the template for retrieving the first value of a request header e.g. {{ request.headers.X-Request-Id }}
|
||||
*
|
||||
* @param key
|
||||
*/
|
||||
String header(String key);
|
||||
|
||||
/**
|
||||
* Returns the template for retrieving the nth value of a request header (zero indexed) e.g. {{ request.headers.X-Request-Id.[5] }}
|
||||
*
|
||||
* @param key
|
||||
* @param index
|
||||
*/
|
||||
String header(String key, int index);
|
||||
|
||||
/**
|
||||
* Retruns the template for retrieving the first value of a cookie with certain key
|
||||
*
|
||||
* @param key
|
||||
*/
|
||||
String cookie(String key);
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
/**
|
||||
* Request body text for the given JsonPath. e.g. {{ jsonPath request.body '$.a.b.c' }}
|
||||
*/
|
||||
String body(String jsonPath);
|
||||
|
||||
/**
|
||||
* Returns the template for retrieving a escaped URL path and query from request
|
||||
*/
|
||||
default String escapedUrl() {
|
||||
return url();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the template for retrieving escaped first value of a query parameter e.g. {{{ request.query.search }}}
|
||||
*
|
||||
* @param key
|
||||
*/
|
||||
default String escapedQuery(String key) {
|
||||
return query(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the template for retrieving esacped nth value of a query parameter (zero indexed) e.g. {{{ request.query.search.[5] }}}
|
||||
*
|
||||
* @param key
|
||||
* @param index
|
||||
*/
|
||||
default String escapedQuery(String key, int index) {
|
||||
return query(key, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the template for retrieving a escaped URL path
|
||||
*/
|
||||
default String escapedPath() {
|
||||
return path();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the template for retrieving escaped nth value of a URL path (zero indexed) e.g. {{{ request.path.[2] }}}
|
||||
*
|
||||
* @param index
|
||||
*/
|
||||
default String escapedPath(int index) {
|
||||
return path(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the template for retrieving the escaped first value of a request header e.g. {{{ request.headers.X-Request-Id }}}
|
||||
*
|
||||
* @param key
|
||||
*/
|
||||
default String escapedHeader(String key) {
|
||||
return header(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the template for retrieving the esacaped nth value of a request header (zero indexed) e.g. {{{ request.headers.X-Request-Id.[5] }}}
|
||||
*
|
||||
* @param key
|
||||
* @param index
|
||||
*/
|
||||
default String escapedHeader(String key, int index) {
|
||||
return header(key, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retruns the template for retrieving the escaped first value of a cookie with certain key
|
||||
*
|
||||
* @param key
|
||||
*/
|
||||
default String escapedCookie(String key) {
|
||||
return cookie(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,155 @@
|
||||
package org.springframework.cloud.contract.spec.internal
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
|
||||
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
|
||||
*/
|
||||
@CompileStatic
|
||||
class CompositeContractTemplate implements ContractTemplate {
|
||||
|
||||
private final CustomHandlebarsContractTemplate custom = new CustomHandlebarsContractTemplate()
|
||||
private final HandlebarsContractTemplate template = new HandlebarsContractTemplate()
|
||||
|
||||
@Override
|
||||
boolean startsWithTemplate(String text) {
|
||||
if (this.custom.startsWithTemplate(text)) {
|
||||
return true
|
||||
}
|
||||
return template.startsWithTemplate(text)
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean startsWithEscapedTemplate(String text) {
|
||||
return this.template.startsWithEscapedTemplate(text)
|
||||
}
|
||||
|
||||
@Override
|
||||
String openingTemplate() {
|
||||
return this.template.openingTemplate()
|
||||
}
|
||||
|
||||
@Override
|
||||
String closingTemplate() {
|
||||
return this.template.closingTemplate()
|
||||
}
|
||||
|
||||
@Override
|
||||
String escapedOpeningTemplate() {
|
||||
return this.template.escapedOpeningTemplate()
|
||||
}
|
||||
|
||||
@Override
|
||||
String escapedClosingTemplate() {
|
||||
return this.template.escapedClosingTemplate()
|
||||
}
|
||||
|
||||
@Override
|
||||
String url() {
|
||||
return this.template.url()
|
||||
}
|
||||
|
||||
@Override
|
||||
String query(String key) {
|
||||
return this.template.query(key)
|
||||
}
|
||||
|
||||
@Override
|
||||
String query(String key, int index) {
|
||||
return this.template.query(key, index)
|
||||
}
|
||||
|
||||
@Override
|
||||
String path() {
|
||||
return this.template.path()
|
||||
}
|
||||
|
||||
@Override
|
||||
String path(int index) {
|
||||
return this.template.path(index)
|
||||
}
|
||||
|
||||
@Override
|
||||
String header(String key) {
|
||||
return this.template.header(key)
|
||||
}
|
||||
|
||||
@Override
|
||||
String header(String key, int index) {
|
||||
return this.template.header(key, index)
|
||||
}
|
||||
|
||||
@Override
|
||||
String cookie(String key) {
|
||||
return this.template.cookie(key)
|
||||
}
|
||||
|
||||
@Override
|
||||
String body() {
|
||||
return this.template.body()
|
||||
}
|
||||
|
||||
@Override
|
||||
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
|
||||
String escapedBody(String jsonPath) {
|
||||
return this.template.escapedBody(jsonPath)
|
||||
}
|
||||
|
||||
@Override
|
||||
String body(String jsonPath) {
|
||||
return this.template.body(jsonPath)
|
||||
}
|
||||
|
||||
@Override
|
||||
String escapedUrl() {
|
||||
return this.template.escapedUrl()
|
||||
}
|
||||
|
||||
@Override
|
||||
String escapedQuery(String key) {
|
||||
return this.template.escapedQuery(key)
|
||||
}
|
||||
|
||||
@Override
|
||||
String escapedQuery(String key, int index) {
|
||||
return this.template.escapedQuery(key, index)
|
||||
}
|
||||
|
||||
@Override
|
||||
String escapedPath() {
|
||||
return this.template.escapedPath()
|
||||
}
|
||||
|
||||
@Override
|
||||
String escapedPath(int index) {
|
||||
return this.template.escapedPath(index)
|
||||
}
|
||||
|
||||
@Override
|
||||
String escapedHeader(String key) {
|
||||
return this.template.escapedHeader(key)
|
||||
}
|
||||
|
||||
@Override
|
||||
String escapedHeader(String key, int index) {
|
||||
return this.template.escapedHeader(key, index)
|
||||
}
|
||||
|
||||
@Override
|
||||
String escapedCookie(String key) {
|
||||
return this.template.escapedCookie(key)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package org.springframework.cloud.contract.spec.internal
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.PackageScope
|
||||
|
||||
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}
|
||||
*/
|
||||
@CompileStatic
|
||||
@PackageScope
|
||||
class CustomHandlebarsContractTemplate implements ContractTemplate {
|
||||
|
||||
@Override
|
||||
String openingTemplate() {
|
||||
return "{{{"
|
||||
}
|
||||
|
||||
@Override
|
||||
String closingTemplate() {
|
||||
return "}}}"
|
||||
}
|
||||
|
||||
@Override
|
||||
String url() {
|
||||
return wrapped("request.url")
|
||||
}
|
||||
|
||||
@Override
|
||||
String query(String key) {
|
||||
return query(key, 0)
|
||||
}
|
||||
|
||||
@Override
|
||||
String query(String key, int index) {
|
||||
return wrapped("request.query.${key}.[${index}]")
|
||||
}
|
||||
|
||||
@Override
|
||||
String path() {
|
||||
return wrapped("request.path")
|
||||
}
|
||||
|
||||
@Override
|
||||
String path(int index) {
|
||||
return wrapped("request.path.[${index}]")
|
||||
}
|
||||
|
||||
@Override
|
||||
String header(String key) {
|
||||
return header(key, 0)
|
||||
}
|
||||
|
||||
@Override
|
||||
String header(String key, int index) {
|
||||
return wrapped("request.headers.${key}.[${index}]")
|
||||
}
|
||||
|
||||
@Override
|
||||
String cookie(String key) {
|
||||
return wrapped("request.cookies.${key}")
|
||||
}
|
||||
|
||||
@Override
|
||||
String body() {
|
||||
return wrapped("request.body")
|
||||
}
|
||||
|
||||
@Override
|
||||
String escapedBody() {
|
||||
return wrapped("escapejsonbody")
|
||||
}
|
||||
|
||||
@Override
|
||||
String escapedBody(String jsonPath) {
|
||||
return body(jsonPath)
|
||||
}
|
||||
|
||||
@Override
|
||||
String body(String jsonPath) {
|
||||
return wrapped("jsonpath this '${jsonPath}'")
|
||||
}
|
||||
|
||||
private String wrapped(String text) {
|
||||
return openingTemplate() + text + closingTemplate()
|
||||
}
|
||||
}
|
||||
@@ -19,14 +19,14 @@ class FromRequest {
|
||||
}
|
||||
|
||||
private ContractTemplate template() {
|
||||
return new HandlebarsContractTemplate()
|
||||
return new CompositeContractTemplate()
|
||||
}
|
||||
|
||||
/**
|
||||
* URL path and query
|
||||
*/
|
||||
DslProperty url() {
|
||||
return new DslProperty(template.url())
|
||||
return new DslProperty(template.escapedUrl())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -34,7 +34,7 @@ class FromRequest {
|
||||
* @param key
|
||||
*/
|
||||
DslProperty query(String key) {
|
||||
return new DslProperty(template.query(key))
|
||||
return new DslProperty(template.escapedQuery(key))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,14 +43,14 @@ class FromRequest {
|
||||
* @param index
|
||||
*/
|
||||
DslProperty query(String key, int index) {
|
||||
return new DslProperty(template.query(key, index))
|
||||
return new DslProperty(template.escapedQuery(key, index))
|
||||
}
|
||||
|
||||
/**
|
||||
* URL path
|
||||
*/
|
||||
DslProperty path() {
|
||||
return new DslProperty(template.path())
|
||||
return new DslProperty(template.escapedPath())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,7 +58,7 @@ class FromRequest {
|
||||
* @param index
|
||||
*/
|
||||
DslProperty path(int index) {
|
||||
return new DslProperty(template.path(index))
|
||||
return new DslProperty(template.escapedPath(index))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,7 +66,7 @@ class FromRequest {
|
||||
* @param key
|
||||
*/
|
||||
DslProperty header(String key) {
|
||||
return new DslProperty(template.header(key))
|
||||
return new DslProperty(template.escapedHeader(key))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,7 +74,7 @@ class FromRequest {
|
||||
* @param key
|
||||
*/
|
||||
DslProperty header(String key, int index) {
|
||||
return new DslProperty(template.header(key, index))
|
||||
return new DslProperty(template.escapedHeader(key, index))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,20 +82,97 @@ class FromRequest {
|
||||
* @param key
|
||||
*/
|
||||
DslProperty cookie(String key) {
|
||||
return new DslProperty(template.cookie(key))
|
||||
return new DslProperty(template.escapedCookie(key))
|
||||
}
|
||||
|
||||
/**
|
||||
* Request body text (avoid for non-text bodies)
|
||||
*/
|
||||
DslProperty body() {
|
||||
return new DslProperty(template.body())
|
||||
return new DslProperty(template.escapedBody())
|
||||
}
|
||||
|
||||
/**
|
||||
* Request body text for the given JsonPath
|
||||
*/
|
||||
DslProperty body(String jsonPath) {
|
||||
return new DslProperty(template.escapedBody(jsonPath))
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescaped URL path and query
|
||||
*/
|
||||
DslProperty rawUrl() {
|
||||
return new DslProperty(template.url())
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescaped First value of a query parameter e.g. request.query.search
|
||||
* @param key
|
||||
*/
|
||||
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
|
||||
* @param index
|
||||
*/
|
||||
DslProperty rawQuery(String key, int index) {
|
||||
return new DslProperty(template.query(key, index))
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescaped URL path
|
||||
*/
|
||||
DslProperty rawPath() {
|
||||
return new DslProperty(template.path())
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescaped nth value of a URL path (zero indexed) e.g. {{{ request.path.[2] }}}
|
||||
* @param index
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
DslProperty rawHeader(String key, int index) {
|
||||
return new DslProperty(template.header(key, index))
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescaped Retruns the tempalte for retrieving the first value of a cookie with certain key
|
||||
* @param key
|
||||
*/
|
||||
DslProperty rawCookie(String key) {
|
||||
return new DslProperty(template.cookie(key))
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescaped Request body text (avoid for non-text bodies)
|
||||
*/
|
||||
DslProperty rawBody() {
|
||||
return new DslProperty(template.body())
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescaped Request body text for the given JsonPath
|
||||
*/
|
||||
DslProperty rawBody(String jsonPath) {
|
||||
return new DslProperty(template.body(jsonPath))
|
||||
}
|
||||
|
||||
|
||||
@@ -15,11 +15,21 @@ class HandlebarsContractTemplate implements ContractTemplate {
|
||||
|
||||
@Override
|
||||
String openingTemplate() {
|
||||
return "{{{"
|
||||
return "{{"
|
||||
}
|
||||
|
||||
@Override
|
||||
String closingTemplate() {
|
||||
return "}}"
|
||||
}
|
||||
|
||||
@Override
|
||||
String escapedOpeningTemplate() {
|
||||
return "{{{"
|
||||
}
|
||||
|
||||
@Override
|
||||
String escapedClosingTemplate() {
|
||||
return "}}}"
|
||||
}
|
||||
|
||||
@@ -70,15 +80,64 @@ class HandlebarsContractTemplate implements ContractTemplate {
|
||||
|
||||
@Override
|
||||
String escapedBody() {
|
||||
return wrapped("escapejsonbody")
|
||||
return escapedWrapped("request.body")
|
||||
}
|
||||
|
||||
@Override
|
||||
String escapedBody(String jsonPath) {
|
||||
return escapedWrapped("jsonPath request.body '${jsonPath}'")
|
||||
}
|
||||
|
||||
@Override
|
||||
String body(String jsonPath) {
|
||||
return wrapped("jsonpath this '${jsonPath}'")
|
||||
return wrapped("jsonPath request.body '${jsonPath}'")
|
||||
}
|
||||
|
||||
@Override
|
||||
String escapedUrl() {
|
||||
return escapedWrapped("request.url")
|
||||
}
|
||||
|
||||
@Override
|
||||
String escapedQuery(String key) {
|
||||
return escapedQuery(key, 0)
|
||||
}
|
||||
|
||||
@Override
|
||||
String escapedQuery(String key, int index) {
|
||||
return escapedWrapped("request.query.${key}.[${index}]")
|
||||
}
|
||||
|
||||
@Override
|
||||
String escapedPath() {
|
||||
return escapedWrapped("request.path")
|
||||
}
|
||||
|
||||
@Override
|
||||
String escapedPath(int index) {
|
||||
return escapedWrapped("request.path.[${index}]")
|
||||
}
|
||||
|
||||
@Override
|
||||
String escapedHeader(String key) {
|
||||
return escapedHeader(key, 0)
|
||||
}
|
||||
|
||||
@Override
|
||||
String escapedHeader(String key, int index) {
|
||||
return escapedWrapped("request.headers.${key}.[${index}]")
|
||||
}
|
||||
|
||||
@Override
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ abstract class MethodBodyBuilder {
|
||||
|
||||
private static final Closure GET_SERVER_VALUE = { it instanceof DslProperty ? it.serverValue : it }
|
||||
private static final String FROM_REQUEST_PREFIX = "request."
|
||||
private static final String FROM_REQUEST_BODY = "body"
|
||||
private static final String FROM_REQUEST_BODY = "escapejsonbody"
|
||||
private static final String FROM_REQUEST_PATH = "path"
|
||||
|
||||
protected final ContractVerifierConfigProperties configProperties
|
||||
@@ -422,11 +422,15 @@ abstract class MethodBodyBuilder {
|
||||
String entryAsString = (String) entry
|
||||
if (templateProcessor.containsTemplateEntry(entryAsString) &&
|
||||
!templateProcessor.containsJsonPathTemplateEntry(entryAsString)) {
|
||||
String justEntry = entryAsString - contractTemplate.openingTemplate() -
|
||||
// TODO: HANDLEBARS LEAKING VIA request.
|
||||
String justEntry = entryAsString - contractTemplate.escapedOpeningTemplate() -
|
||||
contractTemplate.openingTemplate() -
|
||||
contractTemplate.escapedClosingTemplate() -
|
||||
contractTemplate.closingTemplate() - FROM_REQUEST_PREFIX
|
||||
if (justEntry == FROM_REQUEST_BODY) {
|
||||
// the body should be transformed by standard mechanism
|
||||
return entry
|
||||
return contractTemplate.escapedOpeningTemplate() + FROM_REQUEST_PREFIX +
|
||||
"escapedBody" + contractTemplate.escapedClosingTemplate()
|
||||
}
|
||||
try {
|
||||
Object result = new PropertyUtilsBean().getProperty(templateModel, justEntry)
|
||||
@@ -451,6 +455,8 @@ abstract class MethodBodyBuilder {
|
||||
Object object = parsedRequestBody.read(jsonPathEntry)
|
||||
if (!(object instanceof String)) {
|
||||
return method
|
||||
.replace('"' + contractTemplate.escapedOpeningTemplate(), contractTemplate.escapedOpeningTemplate())
|
||||
.replace(contractTemplate.escapedClosingTemplate() + '"', contractTemplate.escapedClosingTemplate())
|
||||
.replace('"' + contractTemplate.openingTemplate(), contractTemplate.openingTemplate())
|
||||
.replace(contractTemplate.closingTemplate() + '"', contractTemplate.closingTemplate())
|
||||
}
|
||||
|
||||
@@ -41,14 +41,14 @@ class TestSideRequestTemplateModel {
|
||||
final Map<String, List<String>> headers
|
||||
|
||||
/**
|
||||
* Escaped request body that can be put into test
|
||||
* Request body as it would be sent to the controller
|
||||
*/
|
||||
final String body
|
||||
|
||||
/**
|
||||
* Request body as it would be sent to the controller
|
||||
* Escaped request body that can be put into test
|
||||
*/
|
||||
final String rawBody
|
||||
final String escapedBody
|
||||
|
||||
static TestSideRequestTemplateModel from(final Request request) {
|
||||
String url = MapConverter.getTestSideValues(request.url ?: request.urlPath)
|
||||
@@ -65,9 +65,9 @@ class TestSideRequestTemplateModel {
|
||||
}?.collectEntries {
|
||||
[(it.key): it.value.collect { MapConverter.getTestSideValues(it) }]
|
||||
})
|
||||
String body = trimmedAndEscapedBody(request.body)
|
||||
String rawBody = getBodyAsRawJson(request.body)
|
||||
return new TestSideRequestTemplateModel(fullUrl, query, paths, headers, body, rawBody)
|
||||
String escapedBody = trimmedAndEscapedBody(request.body)
|
||||
String body = getBodyAsRawJson(request.body)
|
||||
return new TestSideRequestTemplateModel(fullUrl, query, paths, headers, body, escapedBody)
|
||||
}
|
||||
|
||||
private static List<String> buildPathsFromUrl(String url) {
|
||||
@@ -86,6 +86,9 @@ class TestSideRequestTemplateModel {
|
||||
|
||||
private static String getBodyAsRawJson(Object body) {
|
||||
Object bodyValue = extractServerValueFromBody(body)
|
||||
if (bodyValue instanceof GString || bodyValue instanceof String) {
|
||||
return bodyValue.toString()
|
||||
}
|
||||
return bodyValue != null ? new JsonOutput().toJson(bodyValue) : bodyValue
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ class HandlebarsEscapeHelper implements Helper<Map<String, Object>> {
|
||||
}
|
||||
|
||||
private Object returnObjectForTest(Object model) {
|
||||
return ((TestSideRequestTemplateModel) model).rawBody
|
||||
return ((TestSideRequestTemplateModel) model).escapedBody
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.springframework.cloud.contract.verifier.builder.handlebars
|
||||
|
||||
import com.github.tomakehurst.wiremock.extension.responsetemplating.helpers.WireMockHelpers
|
||||
import org.apache.commons.text.StringEscapeUtils
|
||||
import wiremock.com.github.jknack.handlebars.Helper
|
||||
import wiremock.com.github.jknack.handlebars.Options
|
||||
import com.github.tomakehurst.wiremock.extension.responsetemplating.RequestTemplateModel
|
||||
@@ -15,21 +17,41 @@ import org.springframework.cloud.contract.verifier.builder.TestSideRequestTempla
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@CompileStatic
|
||||
class HandlebarsJsonPathHelper implements Helper<Map<String, Object>> {
|
||||
class HandlebarsJsonPathHelper implements Helper<Object> {
|
||||
|
||||
public static final String NAME = "jsonpath"
|
||||
public static final String REQUEST_MODEL_NAME = "request"
|
||||
|
||||
@Override
|
||||
Object apply(Map<String, Object> context, Options options) throws IOException {
|
||||
String jsonPath = options.param(0)
|
||||
Object model = context.get(REQUEST_MODEL_NAME)
|
||||
if (model instanceof TestSideRequestTemplateModel) {
|
||||
return returnObjectForTest(model, jsonPath)
|
||||
} else if (model instanceof RequestTemplateModel) {
|
||||
return returnObjectForStub(model, jsonPath)
|
||||
Object apply(Object context, Options options) throws IOException {
|
||||
if (context instanceof Map<String, Object>) {
|
||||
// legacy
|
||||
Map<String, Object> oldContext = (Map<String, Object>) context
|
||||
String jsonPath = options.param(0)
|
||||
Object model = oldContext.get(REQUEST_MODEL_NAME)
|
||||
if (model instanceof TestSideRequestTemplateModel) {
|
||||
return returnObjectForTest(model, jsonPath)
|
||||
} else if (model instanceof RequestTemplateModel) {
|
||||
return returnObjectForStub(model, jsonPath)
|
||||
}
|
||||
throw new IllegalArgumentException("Unsupported model")
|
||||
} else if (context instanceof String) {
|
||||
Object value = WireMockHelpers.jsonPath.apply(context, options)
|
||||
if (testSideModel(options)) {
|
||||
return processTestResponseValue(value)
|
||||
}
|
||||
return value
|
||||
}
|
||||
throw new IllegalArgumentException("Unsupported model")
|
||||
throw new IllegalArgumentException("Unsupported context")
|
||||
}
|
||||
|
||||
private boolean testSideModel(Options options) {
|
||||
Object model = options.context.model()
|
||||
if (!(model instanceof Map)) {
|
||||
return false
|
||||
}
|
||||
Map map = (Map) model
|
||||
return map.values().any { it instanceof TestSideRequestTemplateModel }
|
||||
}
|
||||
|
||||
private Object returnObjectForStub(Object model, String jsonPath) {
|
||||
@@ -37,10 +59,14 @@ class HandlebarsJsonPathHelper implements Helper<Map<String, Object>> {
|
||||
return documentContext.read(jsonPath)
|
||||
}
|
||||
|
||||
private Object returnObjectForTest(Object model, String jsonPath) {
|
||||
String body = removeSurroundingQuotes(((TestSideRequestTemplateModel) model).rawBody).replace('\\"', '"')
|
||||
private Object returnObjectForTest(TestSideRequestTemplateModel model, String jsonPath) {
|
||||
String body = removeSurroundingQuotes(model.escapedBody).replace('\\"', '"')
|
||||
DocumentContext documentContext = JsonPath.parse(body)
|
||||
Object value = documentContext.read(jsonPath)
|
||||
return processTestResponseValue(value)
|
||||
}
|
||||
|
||||
private Object processTestResponseValue(Object value) {
|
||||
if (value instanceof Long) {
|
||||
return String.valueOf(value) + "L"
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ abstract class BaseWireMockStubStrategy {
|
||||
return processEntriesForTemplating(transformedMap, context)
|
||||
}
|
||||
|
||||
private Object processEntriesForTemplating(transformedMap, DocumentContext context) {
|
||||
private Object processEntriesForTemplating(Object transformedMap, DocumentContext context) {
|
||||
return transformValues(transformedMap, {
|
||||
if (it instanceof String && processor.containsJsonPathTemplateEntry(it)) {
|
||||
String jsonPath = processor.jsonPathFromTemplateEntry(it)
|
||||
@@ -129,7 +129,8 @@ abstract class BaseWireMockStubStrategy {
|
||||
return it
|
||||
}
|
||||
return "${WRAPPER}${it}${WRAPPER}"
|
||||
} else if (it instanceof String && processor.containsTemplateEntry(it) && template.body() == it) {
|
||||
} else if (it instanceof String && processor.containsTemplateEntry(it) &&
|
||||
template.escapedBody() == it) {
|
||||
return template.escapedBody()
|
||||
}
|
||||
return it
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
package org.springframework.cloud.contract.verifier.template
|
||||
|
||||
import wiremock.com.github.jknack.handlebars.Handlebars
|
||||
import wiremock.com.github.jknack.handlebars.Template
|
||||
import groovy.transform.CompileStatic
|
||||
import org.springframework.cloud.contract.spec.ContractTemplate
|
||||
import org.springframework.cloud.contract.spec.internal.HandlebarsContractTemplate
|
||||
import org.springframework.cloud.contract.spec.internal.Request
|
||||
import org.springframework.cloud.contract.verifier.builder.handlebars.HandlebarsJsonPathHelper
|
||||
import org.springframework.cloud.contract.verifier.builder.TestSideRequestTemplateModel
|
||||
|
||||
import java.util.regex.Matcher
|
||||
import java.util.regex.Pattern
|
||||
|
||||
import com.github.tomakehurst.wiremock.extension.responsetemplating.helpers.WireMockHelpers
|
||||
import groovy.transform.CompileStatic
|
||||
import wiremock.com.github.jknack.handlebars.Handlebars
|
||||
import wiremock.com.github.jknack.handlebars.Template
|
||||
|
||||
import org.springframework.cloud.contract.spec.ContractTemplate
|
||||
import org.springframework.cloud.contract.spec.internal.CompositeContractTemplate
|
||||
import org.springframework.cloud.contract.spec.internal.Request
|
||||
import org.springframework.cloud.contract.verifier.builder.TestSideRequestTemplateModel
|
||||
import org.springframework.cloud.contract.verifier.builder.handlebars.HandlebarsJsonPathHelper
|
||||
|
||||
/**
|
||||
* Default Handlebars template processor
|
||||
*
|
||||
@@ -20,10 +23,17 @@ import java.util.regex.Pattern
|
||||
@CompileStatic
|
||||
class HandlebarsTemplateProcessor implements TemplateProcessor, ContractTemplate {
|
||||
|
||||
private static final Pattern JSON_PATH_PATTERN = Pattern.compile("^.*\\{\\{\\{jsonpath this '(.*)'}}}.*\$")
|
||||
private static final Pattern ESCAPED_LEGACY_JSON_PATH_PATTERN = Pattern.compile("^.*\\{\\{\\{jsonpath this '(.*)'}}}.*\$")
|
||||
private static final Pattern ESCAPED_JSON_PATH_PATTERN = Pattern.compile("^.*\\{\\{\\{jsonPath request.body '(.*)'}}}.*\$")
|
||||
private static final Pattern LEGACY_JSON_PATH_PATTERN = Pattern.compile("^.*\\{\\{jsonpath this '(.*)'}}.*\$")
|
||||
private static final Pattern JSON_PATH_PATTERN = Pattern.compile("^.*\\{\\{jsonPath request.body '(.*)'}}.*\$")
|
||||
private static final List<Pattern> PATTERNS = [ESCAPED_LEGACY_JSON_PATH_PATTERN,
|
||||
ESCAPED_JSON_PATH_PATTERN, LEGACY_JSON_PATH_PATTERN, JSON_PATH_PATTERN]
|
||||
private static final String LEGACY_JSON_PATH_TEMPLATE_NAME = HandlebarsJsonPathHelper.NAME
|
||||
private static final String JSON_PATH_TEMPLATE_NAME = WireMockHelpers.jsonPath.name()
|
||||
|
||||
@Delegate
|
||||
private final ContractTemplate contractTemplate = new HandlebarsContractTemplate()
|
||||
private final ContractTemplate contractTemplate = new CompositeContractTemplate()
|
||||
|
||||
@Override
|
||||
String transform(Request request, String testContents) {
|
||||
@@ -35,12 +45,16 @@ class HandlebarsTemplateProcessor implements TemplateProcessor, ContractTemplate
|
||||
|
||||
@Override
|
||||
boolean containsTemplateEntry(String line) {
|
||||
return line.matches('^.*\\{\\{\\{.*}}}.*$')
|
||||
return (line.contains(contractTemplate.openingTemplate()) && line.contains(contractTemplate.closingTemplate())) ||
|
||||
(line.contains(contractTemplate.escapedOpeningTemplate()) && line.contains(contractTemplate.escapedClosingTemplate()))
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean containsJsonPathTemplateEntry(String line) {
|
||||
return line.contains(openingTemplate() + HandlebarsJsonPathHelper.NAME)
|
||||
return line.contains(openingTemplate() + LEGACY_JSON_PATH_TEMPLATE_NAME) ||
|
||||
line.contains(openingTemplate() + JSON_PATH_TEMPLATE_NAME) ||
|
||||
line.contains(escapedOpeningTemplate() + LEGACY_JSON_PATH_TEMPLATE_NAME) ||
|
||||
line.contains(escapedOpeningTemplate() + JSON_PATH_TEMPLATE_NAME)
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -48,11 +62,13 @@ class HandlebarsTemplateProcessor implements TemplateProcessor, ContractTemplate
|
||||
if (!containsJsonPathTemplateEntry(line)) {
|
||||
return ""
|
||||
}
|
||||
Matcher matcher = JSON_PATH_PATTERN.matcher(line)
|
||||
if (!matcher.matches()) {
|
||||
return ""
|
||||
for (Pattern pattern : PATTERNS) {
|
||||
Matcher matcher = pattern.matcher(line)
|
||||
if (matcher.matches()) {
|
||||
return matcher.group(1)
|
||||
}
|
||||
}
|
||||
return matcher.group(1)
|
||||
return ""
|
||||
}
|
||||
|
||||
private String templatedResponseBody(Map< String, TestSideRequestTemplateModel> model, Template bodyTemplate) {
|
||||
@@ -71,6 +87,12 @@ class HandlebarsTemplateProcessor implements TemplateProcessor, ContractTemplate
|
||||
try {
|
||||
Handlebars handlebars = new Handlebars()
|
||||
handlebars.registerHelper(HandlebarsJsonPathHelper.NAME, new HandlebarsJsonPathHelper())
|
||||
handlebars.registerHelper(WireMockHelpers.jsonPath.name(), new HandlebarsJsonPathHelper())
|
||||
WireMockHelpers.values()
|
||||
.findAll { it != WireMockHelpers.jsonPath}
|
||||
.each { WireMockHelpers helper ->
|
||||
handlebars.registerHelper(helper.name(), helper)
|
||||
}
|
||||
return handlebars.compileInline(content)
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e)
|
||||
|
||||
@@ -26,14 +26,14 @@ interface TemplateProcessor {
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the current line contains template related entry for json path processing.
|
||||
* E.g. for Handlebars if a line contains {{{jsonpath ...}}} then
|
||||
* E.g. for Handlebars if a line contains {{{jsonpath ...}}} or {{{jsonPath ...}}} then
|
||||
* it's considered to contain template related entry for json path processing
|
||||
*/
|
||||
boolean containsJsonPathTemplateEntry(String line)
|
||||
|
||||
/**
|
||||
* Returns the json path entry from the current line that contains template related entry for json path processing.
|
||||
* E.g. for Handlebars if a line contains {{{jsonpath this '$.a.b.c'}}} then
|
||||
* E.g. for Handlebars if a line contains {{{jsonpath this '$.a.b.c'}}} or {{{jsonPath request.body ...}}} then
|
||||
* the te method would return {@code $.a.b.c}. Returns empty string if there's no matching
|
||||
* json path entry
|
||||
*/
|
||||
|
||||
@@ -1515,8 +1515,7 @@ World.'''"""
|
||||
method "GET"
|
||||
urlPath('/auth/oauth/check_token') {
|
||||
queryParameters {
|
||||
parameter 'token':
|
||||
value(
|
||||
parameter 'token': value(
|
||||
consumer(regex('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}')),
|
||||
producer('6973b31d-7140-402a-bca6-1cdb954e03a7')
|
||||
)
|
||||
@@ -1551,8 +1550,7 @@ World.'''"""
|
||||
method "GET"
|
||||
urlPath('/auth/oauth/check_token') {
|
||||
queryParameters {
|
||||
parameter 'token':
|
||||
value(
|
||||
parameter 'token': value(
|
||||
consumer(regex('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}')),
|
||||
producer('6973b31d-7140-402a-bca6-1cdb954e03a7')
|
||||
)
|
||||
@@ -2594,7 +2592,17 @@ DocumentContext parsedJson = JsonPath.parse(json);
|
||||
fullBody: fromRequest().body(),
|
||||
responseFoo: fromRequest().body('$.foo'),
|
||||
responseBaz: fromRequest().body('$.baz'),
|
||||
responseBaz2: "Bla bla ${fromRequest().body('$.foo')} bla bla"
|
||||
responseBaz2: "Bla bla ${fromRequest().body('$.foo')} bla bla",
|
||||
rawUrl: fromRequest().rawUrl(),
|
||||
rawPath: fromRequest().rawPath(),
|
||||
rawPathIndex: fromRequest().rawPath(1),
|
||||
rawParam: fromRequest().rawQuery("foo"),
|
||||
rawParamIndex: fromRequest().rawQuery("foo", 1),
|
||||
rawAuthorization: fromRequest().rawHeader("Authorization"),
|
||||
rawAuthorization2: fromRequest().rawHeader("Authorization", 1),
|
||||
rawResponseFoo: fromRequest().rawBody('$.foo'),
|
||||
rawResponseBaz: fromRequest().rawBody('$.baz'),
|
||||
rawResponseBaz2: "Bla bla ${fromRequest().rawBody('$.foo')} bla bla"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -2608,6 +2616,7 @@ DocumentContext parsedJson = JsonPath.parse(json);
|
||||
SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test)
|
||||
then:
|
||||
!test.contains('''DslProperty''')
|
||||
!test.contains('''ERROR: ''')
|
||||
test.contains('''assertThatJson(parsedJson).field("['url']").isEqualTo("/api/v1/xxxx?foo=bar&foo=bar2")''')
|
||||
test.contains('''assertThatJson(parsedJson).field("['path']").isEqualTo("/api/v1/xxxx")''')
|
||||
test.contains('''assertThatJson(parsedJson).field("['pathIndex']").isEqualTo("v1")''')
|
||||
@@ -2619,6 +2628,16 @@ DocumentContext parsedJson = JsonPath.parse(json);
|
||||
test.contains('''assertThatJson(parsedJson).field("['responseBaz']").isEqualTo(5)''')
|
||||
test.contains('''assertThatJson(parsedJson).field("['responseBaz2']").isEqualTo("Bla bla bar bla bla")''')
|
||||
test.contains('''assertThatJson(parsedJson).field("['param']").isEqualTo("bar")''')
|
||||
test.contains('''assertThatJson(parsedJson).field("['rawUrl']").isEqualTo("/api/v1/xxxx?foo=bar&foo=bar2")''')
|
||||
test.contains('''assertThatJson(parsedJson).field("['rawPath']").isEqualTo("/api/v1/xxxx")''')
|
||||
test.contains('''assertThatJson(parsedJson).field("['rawPathIndex']").isEqualTo("v1")''')
|
||||
test.contains('''assertThatJson(parsedJson).field("['rawParamIndex']").isEqualTo("bar2")''')
|
||||
test.contains('''assertThatJson(parsedJson).field("['rawResponseFoo']").isEqualTo("bar")''')
|
||||
test.contains('''assertThatJson(parsedJson).field("['rawAuthorization']").isEqualTo("secret")''')
|
||||
test.contains('''assertThatJson(parsedJson).field("['rawAuthorization2']").isEqualTo("secret2")''')
|
||||
test.contains('''assertThatJson(parsedJson).field("['rawResponseBaz']").isEqualTo(5)''')
|
||||
test.contains('''assertThatJson(parsedJson).field("['rawResponseBaz2']").isEqualTo("Bla bla bar bla bla")''')
|
||||
test.contains('''assertThatJson(parsedJson).field("['rawParam']").isEqualTo("bar")''')
|
||||
responseAssertion(test)
|
||||
where:
|
||||
methodBuilderName | methodBuilder | responseAssertion
|
||||
|
||||
@@ -1736,7 +1736,73 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
|
||||
}
|
||||
|
||||
@Issue('#237')
|
||||
def "should generate a stub with response template"() {
|
||||
def "should work with legacy mappings"() {
|
||||
given:
|
||||
def oldJsonMapping = '''
|
||||
{
|
||||
"request" : {
|
||||
"urlPath" : "/api/v1/xxxx",
|
||||
"method" : "POST",
|
||||
"headers" : {
|
||||
"Authorization" : {
|
||||
"equalTo" : "secret2"
|
||||
}
|
||||
},
|
||||
"cookies" : {
|
||||
"foo" : {
|
||||
"equalTo" : "bar"
|
||||
}
|
||||
},
|
||||
"queryParameters" : {
|
||||
"foo" : {
|
||||
"equalTo" : "bar2"
|
||||
}
|
||||
},
|
||||
"bodyPatterns" : [ {
|
||||
"matchesJsonPath" : "$[?(@.['baz'] == 5)]"
|
||||
}, {
|
||||
"matchesJsonPath" : "$[?(@.['foo'] == 'bar')]"
|
||||
} ]
|
||||
},
|
||||
"response" : {
|
||||
"status" : 200,
|
||||
"body" : "{\\"authorization\\":\\"{{{request.headers.Authorization.[0]}}}\\",\\"path\\":\\"{{{request.path}}}\\",\\"responseBaz\\":{{{jsonpath this '$.baz'}}} ,\\"param\\":\\"{{{request.query.foo.[0]}}}\\",\\"pathIndex\\":\\"{{{request.path.[1]}}}\\",\\"responseBaz2\\":\\"Bla bla {{{jsonpath this '$.foo'}}} bla bla\\",\\"responseFoo\\":\\"{{{jsonpath this '$.foo'}}}\\",\\"authorization2\\":\\"{{{request.headers.Authorization.[1]}}}\\",\\"fullBody\\":\\"{{{escapejsonbody}}}\\",\\"url\\":\\"{{{request.url}}}\\",\\"paramIndex\\":\\"{{{request.query.foo.[1]}}}\\"}",
|
||||
"headers" : {
|
||||
"Authorization" : "{{{request.headers.Authorization.[0]}}};foo"
|
||||
},
|
||||
"transformers" : [ "response-template", "foo-transformer" ]
|
||||
}
|
||||
}
|
||||
'''
|
||||
and:
|
||||
int port = SocketUtils.findAvailableTcpPort()
|
||||
WireMockServer server = new WireMockServer(config().port(port))
|
||||
server.start()
|
||||
and:
|
||||
server.addStubMapping(WireMockStubMapping.buildFrom(oldJsonMapping))
|
||||
when:
|
||||
ResponseEntity<String> entity = call(port)
|
||||
then:
|
||||
entity.headers.find { it.key == "Authorization" && it.value.contains("secret;foo") }
|
||||
AssertionUtil.assertThatJsonsAreEqual(('''
|
||||
{
|
||||
"url" : "/api/v1/xxxx?foo=bar&foo=bar2",
|
||||
"param" : "bar",
|
||||
"paramIndex" : "bar2",
|
||||
"authorization" : "secret",
|
||||
"authorization2" : "secret2",
|
||||
"fullBody" : "{\\"foo\\":\\"bar\\",\\"baz\\":5}",
|
||||
"responseFoo" : "bar",
|
||||
"responseBaz" : 5,
|
||||
"responseBaz2" : "Bla bla bar bla bla"
|
||||
}
|
||||
'''), entity.body)
|
||||
cleanup:
|
||||
server?.shutdown()
|
||||
}
|
||||
|
||||
@Issue('#540')
|
||||
def "should generate a stub with standard WireMock request template"() {
|
||||
given:
|
||||
org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract.make {
|
||||
request {
|
||||
@@ -1772,7 +1838,17 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
|
||||
fullBody: fromRequest().body(),
|
||||
responseFoo: fromRequest().body('$.foo'),
|
||||
responseBaz: fromRequest().body('$.baz'),
|
||||
responseBaz2: "Bla bla ${fromRequest().body('$.foo')} bla bla"
|
||||
responseBaz2: "Bla bla ${fromRequest().body('$.foo')} bla bla",
|
||||
rawUrl: fromRequest().rawUrl(),
|
||||
rawPath: fromRequest().rawPath(),
|
||||
rawPathIndex: fromRequest().rawPath(1),
|
||||
rawParam: fromRequest().rawQuery("foo"),
|
||||
rawParamIndex: fromRequest().rawQuery("foo", 1),
|
||||
rawAuthorization: fromRequest().rawHeader("Authorization"),
|
||||
rawAuthorization2: fromRequest().rawHeader("Authorization", 1),
|
||||
rawResponseFoo: fromRequest().rawBody('$.foo'),
|
||||
rawResponseBaz: fromRequest().rawBody('$.baz'),
|
||||
rawResponseBaz2: "Bla bla ${fromRequest().rawBody('$.foo')} bla bla"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1807,7 +1883,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
|
||||
},
|
||||
"response" : {
|
||||
"status" : 200,
|
||||
"body" : "{\\"authorization\\":\\"{{{request.headers.Authorization.[0]}}}\\",\\"path\\":\\"{{{request.path}}}\\",\\"responseBaz\\":{{{jsonpath this '$.baz'}}} ,\\"param\\":\\"{{{request.query.foo.[0]}}}\\",\\"pathIndex\\":\\"{{{request.path.[1]}}}\\",\\"responseBaz2\\":\\"Bla bla {{{jsonpath this '$.foo'}}} bla bla\\",\\"responseFoo\\":\\"{{{jsonpath this '$.foo'}}}\\",\\"authorization2\\":\\"{{{request.headers.Authorization.[1]}}}\\",\\"fullBody\\":\\"{{{escapejsonbody}}}\\",\\"url\\":\\"{{{request.url}}}\\",\\"paramIndex\\":\\"{{{request.query.foo.[1]}}}\\"}",
|
||||
"body" : "{\\"rawAuthorization2\\":\\"{{request.headers.Authorization.[1]}}\\",\\"responseBaz\\":{{{jsonPath request.body '$.baz'}}} ,\\"pathIndex\\":\\"{{{request.path.[1]}}}\\",\\"rawAuthorization\\":\\"{{request.headers.Authorization.[0]}}\\",\\"authorization2\\":\\"{{{request.headers.Authorization.[1]}}}\\",\\"rawParam\\":\\"{{request.query.foo.[0]}}\\",\\"url\\":\\"{{{request.url}}}\\",\\"paramIndex\\":\\"{{{request.query.foo.[1]}}}\\",\\"authorization\\":\\"{{{request.headers.Authorization.[0]}}}\\",\\"path\\":\\"{{{request.path}}}\\",\\"rawUrl\\":\\"{{request.url}}\\",\\"rawPath\\":\\"{{request.path}}\\",\\"rawResponseBaz2\\":\\"Bla bla {{jsonPath request.body '$.foo'}} bla bla\\",\\"param\\":\\"{{{request.query.foo.[0]}}}\\",\\"rawResponseBaz\\":{{jsonPath request.body '$.baz'}} ,\\"responseBaz2\\":\\"Bla bla {{{jsonPath request.body '$.foo'}}} bla bla\\",\\"rawResponseFoo\\":\\"{{jsonPath request.body '$.foo'}}\\",\\"responseFoo\\":\\"{{{jsonPath request.body '$.foo'}}}\\",\\"rawPathIndex\\":\\"{{request.path.[1]}}\\",\\"fullBody\\":\\"{{{escapejsonbody}}}\\",\\"rawParamIndex\\":\\"{{request.query.foo.[1]}}\\"}",
|
||||
"headers" : {
|
||||
"Authorization" : "{{{request.headers.Authorization.[0]}}};foo"
|
||||
},
|
||||
@@ -1827,16 +1903,28 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
|
||||
entity.headers.find { it.key == "Authorization" && it.value.contains("secret;foo") }
|
||||
and:
|
||||
AssertionUtil.assertThatJsonsAreEqual(('''
|
||||
{
|
||||
"url" : "/api/v1/xxxx?foo=bar&foo=bar2",
|
||||
"param" : "bar",
|
||||
"paramIndex" : "bar2",
|
||||
"authorization" : "secret",
|
||||
"authorization2" : "secret2",
|
||||
"fullBody" : "{\\"foo\\":\\"bar\\",\\"baz\\":5}",
|
||||
"responseFoo" : "bar",
|
||||
"responseBaz" : 5,
|
||||
"responseBaz2" : "Bla bla bar bla bla"
|
||||
{
|
||||
"rawAuthorization2":"secret2",
|
||||
"responseBaz":5,
|
||||
"pathIndex":"v1",
|
||||
"rawAuthorization":"secret",
|
||||
"authorization2":"secret2",
|
||||
"rawParam":"bar",
|
||||
"url":"/api/v1/xxxx?foo=bar&foo=bar2",
|
||||
"paramIndex":"bar2",
|
||||
"authorization":"secret",
|
||||
"path":"/api/v1/xxxx",
|
||||
"rawUrl":"/api/v1/xxxx?foo=bar&foo=bar2",
|
||||
"rawPath":"/api/v1/xxxx",
|
||||
"rawResponseBaz2":"Bla bla bar bla bla",
|
||||
"param":"bar",
|
||||
"rawResponseBaz":5,
|
||||
"responseBaz2":"Bla bla bar bla bla",
|
||||
"rawResponseFoo":"bar",
|
||||
"responseFoo":"bar",
|
||||
"rawPathIndex":"v1",
|
||||
"fullBody":"{\\"foo\\":\\"bar\\",\\"baz\\":5}",
|
||||
"rawParamIndex":"bar2"
|
||||
}
|
||||
'''), entity.body)
|
||||
cleanup:
|
||||
|
||||
Reference in New Issue
Block a user