diff --git a/docs/src/main/asciidoc/_project-features-flows.adoc b/docs/src/main/asciidoc/_project-features-flows.adoc
index e5fe8c3814..7f46a49d0b 100644
--- a/docs/src/main/asciidoc/_project-features-flows.adoc
+++ b/docs/src/main/asciidoc/_project-features-flows.adoc
@@ -290,7 +290,7 @@ public class ApplicationTests {
.content("{\"id\":\"123456\",\"message\":\"Hello World\"}"))
.andExpect(status().isOk())
.andDo(verify().jsonPath("$.id")
- .stub("resource"));
+ .andDo(document("resource"));
}
}
----
@@ -317,7 +317,7 @@ following example shows:
.wiremock(WireMock.post(
urlPathEquals("/resource"))
.withRequestBody(matchingJsonPath("$.id"))
- .stub("post-resource"));
+ .andDo(document("post-resource"));
}
----
diff --git a/samples/standalone/restdocs/http-server/src/assembly/stub.xml b/samples/standalone/restdocs/http-server/src/assembly/stub.xml
index 70ae6e17f3..310a3af245 100644
--- a/samples/standalone/restdocs/http-server/src/assembly/stub.xml
+++ b/samples/standalone/restdocs/http-server/src/assembly/stub.xml
@@ -22,6 +22,15 @@
**/model/Fraud*.*
+
+ ${project.build.directory}/generated-snippets/stubs
+
+ META-INF/${project.groupId}/${project.artifactId}/${project.version}/mappings
+
+
+ **/*
+
+
${project.build.directory}/snippets/stubs
diff --git a/samples/standalone/restdocs/http-server/src/main/resources/application.yml b/samples/standalone/restdocs/http-server/src/main/resources/application.yml
index 1c421cf2b7..e69de29bb2 100644
--- a/samples/standalone/restdocs/http-server/src/main/resources/application.yml
+++ b/samples/standalone/restdocs/http-server/src/main/resources/application.yml
@@ -1 +0,0 @@
-server.port=0
\ No newline at end of file
diff --git a/samples/standalone/restdocs/http-server/src/test/java/com/example/fraud/StubGeneratorTests.java b/samples/standalone/restdocs/http-server/src/test/java/com/example/fraud/StubGeneratorTests.java
index d8fbcb04f1..49f81b36a6 100644
--- a/samples/standalone/restdocs/http-server/src/test/java/com/example/fraud/StubGeneratorTests.java
+++ b/samples/standalone/restdocs/http-server/src/test/java/com/example/fraud/StubGeneratorTests.java
@@ -36,6 +36,7 @@ import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import static org.springframework.cloud.contract.wiremock.restdocs.WireMockRestDocs.verify;
+import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
@RunWith(SpringRunner.class)
@@ -69,8 +70,8 @@ public class StubGeneratorTests {
.andExpect(jsonPath("$.rejectionReason").value("Amount too high"))
.andDo(verify().jsonPath("$.clientId")
.jsonPath("$[?(@.loanAmount > 1000)]")
- .contentType(MediaType.valueOf("application/vnd.fraud.v1+json"))
- .stub("markClientAsFraud"));
+ .contentType(MediaType.valueOf("application/vnd.fraud.v1+json")))
+ .andDo(document("markClientAsFraud"));
}
@Test
@@ -85,8 +86,8 @@ public class StubGeneratorTests {
.andExpect(jsonPath("$.rejectionReason").doesNotExist())
.andDo(verify().jsonPath("$.clientId")
.jsonPath("$[?(@.loanAmount <= 1000)]")
- .contentType(MediaType.valueOf("application/vnd.fraud.v1+json"))
- .stub("markClientAsNotFraud"));
+ .contentType(MediaType.valueOf("application/vnd.fraud.v1+json")))
+ .andDo(document("markClientAsNotFraud"));
}
}
diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/HttpServerStubConfiguration.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/HttpServerStubConfiguration.java
index c5c8365807..b481c56aed 100644
--- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/HttpServerStubConfiguration.java
+++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/HttpServerStubConfiguration.java
@@ -44,17 +44,33 @@ public final class HttpServerStubConfiguration {
*/
public final Integer port;
+ /**
+ * Is port a random one or was it fixed.
+ */
+ public boolean randomPort;
+
public HttpServerStubConfiguration(HttpServerStubConfigurer configurer,
StubRunnerOptions stubRunnerOptions, StubConfiguration stubConfiguration,
Integer port) {
+ this(configurer, stubRunnerOptions, stubConfiguration, port, randomPort(port));
+ }
+
+ public HttpServerStubConfiguration(HttpServerStubConfigurer configurer,
+ StubRunnerOptions stubRunnerOptions, StubConfiguration stubConfiguration,
+ Integer port, boolean randomPort) {
this.configurer = configurer;
this.stubRunnerOptions = stubRunnerOptions;
this.stubConfiguration = stubConfiguration;
this.port = port;
+ this.randomPort = randomPort;
+ }
+
+ private static boolean randomPort(Integer port) {
+ return port == null || port == 0;
}
public boolean isRandomPort() {
- return this.port == null || this.port == 0;
+ return randomPort(this.port);
}
public String toColonSeparatedDependencyNotation() {
diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerExecutor.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerExecutor.java
index 69e7a92d3a..396110506f 100644
--- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerExecutor.java
+++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerExecutor.java
@@ -274,8 +274,9 @@ class StubRunnerExecutor implements StubFinder {
final List mappings = repository.getStubs();
final Collection contracts = repository.contracts;
Integer port = stubRunnerOptions.port(stubConfiguration);
+ boolean randomPort = randomPort(port);
HttpServerStubConfiguration configuration = new HttpServerStubConfiguration(
- configurer, stubRunnerOptions, stubConfiguration, port);
+ configurer, stubRunnerOptions, stubConfiguration, port, randomPort);
if (!hasRequest(contracts) && mappings.isEmpty()) {
if (log.isDebugEnabled()) {
log.debug("There are no HTTP related contracts. Won't start any servers");
@@ -284,7 +285,7 @@ class StubRunnerExecutor implements StubFinder {
new NoOpHttpServerStub()).start(configuration);
return this.stubServer;
}
- if (port != null && port >= 0) {
+ if (!randomPort) {
this.stubServer = new StubServer(stubConfiguration, mappings, contracts,
httpServerStub()).start(configuration);
}
@@ -297,7 +298,7 @@ class StubRunnerExecutor implements StubFinder {
httpServerStub()).start(
new HttpServerStubConfiguration(configurer,
stubRunnerOptions, stubConfiguration,
- availablePort));
+ availablePort, true));
}
});
}
@@ -305,6 +306,10 @@ class StubRunnerExecutor implements StubFinder {
return this.stubServer;
}
+ private boolean randomPort(Integer port) {
+ return port == null || port == 0;
+ }
+
private boolean hasRequest(Collection contracts) {
if (contracts.isEmpty()) {
return false;
diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStub.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStub.java
index 046f96491f..d3fcb1a7fd 100644
--- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStub.java
+++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStub.java
@@ -130,9 +130,9 @@ public class WireMockHttpServerStub implements HttpServerStub {
}
return this;
}
- int port = SocketUtils.findAvailableTcpPort();
- HttpServerStub serverStub = start(defaultConfiguration(port));
- cacheStubServer(true, port);
+ HttpServerStubConfiguration configuration = defaultConfiguration();
+ HttpServerStub serverStub = start(configuration);
+ cacheStubServer(configuration.randomPort, configuration.port);
return serverStub;
}
@@ -142,6 +142,13 @@ public class WireMockHttpServerStub implements HttpServerStub {
null, port);
}
+ private HttpServerStubConfiguration defaultConfiguration() {
+ int port = SocketUtils.findAvailableTcpPort();
+ return new HttpServerStubConfiguration(
+ HttpServerStubConfigurer.NoOpHttpServerStubConfigurer.INSTANCE, null,
+ null, port, true);
+ }
+
@Override
public HttpServerStub start(int port) {
return start(defaultConfiguration(port));
@@ -175,7 +182,7 @@ public class WireMockHttpServerStub implements HttpServerStub {
+ " Started WireMock at [" + (this.https ? "https" : "http")
+ "] port [" + port + "]");
}
- cacheStubServer(false, port);
+ cacheStubServer(configuration.randomPort, port);
return this;
}
diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStubAccessor.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStubAccessor.groovy
new file mode 100644
index 0000000000..82b3690440
--- /dev/null
+++ b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStubAccessor.groovy
@@ -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.stubrunner.provider.wiremock
+
+class WireMockHttpServerStubAccessor {
+
+ static boolean everyPortRandom() {
+ assert WireMockHttpServerStub.SERVERS.every { it.value.random }
+ return true
+ }
+}
diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfigurationSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfigurationSpec.groovy
index f6457e443e..9016d3a993 100644
--- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfigurationSpec.groovy
+++ b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfigurationSpec.groovy
@@ -33,6 +33,7 @@ import org.springframework.boot.test.context.SpringBootTest
import org.springframework.cloud.contract.stubrunner.HttpServerStubConfiguration
import org.springframework.cloud.contract.stubrunner.StubFinder
import org.springframework.cloud.contract.stubrunner.StubNotFoundException
+import org.springframework.cloud.contract.stubrunner.provider.wiremock.WireMockHttpServerStubAccessor
import org.springframework.cloud.contract.stubrunner.provider.wiremock.WireMockHttpServerStubConfigurer
import org.springframework.context.annotation.Configuration
import org.springframework.core.env.Environment
@@ -75,6 +76,11 @@ class StubRunnerConfigurationSpec extends Specification {
System.clearProperty("stubrunner.classifier")
}
+ def 'should mark all ports as random'() {
+ expect:
+ WireMockHttpServerStubAccessor.everyPortRandom()
+ }
+
def 'should start WireMock servers'() {
expect: 'WireMocks are running'
stubFinder.findStubUrl('org.springframework.cloud.contract.verifier.stubs', 'loanIssuance') != null
diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverterSpec.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverterSpec.groovy
index c7f089a4b5..318eff80a3 100755
--- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverterSpec.groovy
+++ b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverterSpec.groovy
@@ -748,7 +748,7 @@ class DslToWireMockClientConverterSpec extends Specification {
},
"response" : {
"status" : 200,
- "body" : "{\\"date\\":\\"2017-01-01\\",\\"dateTime\\":\\"2017-01-01T01:23:45\\",\\"aBoolean\\":true,\\"valueWithMax\\":[1,2,3],\\"valueWithOccurrence\\":[1,2,3,4],\\"number\\":123,\\"duck\\":123,\\"alpha\\":\\"abc\\",\\"valueWithMin\\":[1,2,3],\\"time\\":\\"01:02:34\\",\\"valueWithTypeMatch\\":\\"string\\",\\"valueWithMinMax\\":[1,2,3],\\"valueWithoutAMatcher\\":\\"foo\\"}",
+ "body" : "{\\"duck\\":123,\\"alpha\\":\\"abc\\",\\"number\\":123,\\"aBoolean\\":true,\\"date\\":\\"2017-01-01\\",\\"dateTime\\":\\"2017-01-01T01:23:45\\",\\"time\\":\\"01:02:34\\",\\"valueWithoutAMatcher\\":\\"foo\\",\\"valueWithTypeMatch\\":\\"string\\",\\"valueWithMin\\":[1,2,3],\\"valueWithMax\\":[1,2,3],\\"valueWithMinMax\\":[1,2,3],\\"valueWithOccurrence\\":[1,2,3,4]}",
"headers" : {
"Content-Type" : "application/json"
},
@@ -987,7 +987,7 @@ class DslToWireMockClientConverterSpec extends Specification {
},
"response" : {
"status" : 400,
- "body" : "{\\"reason\\":{\\"@type\\":\\"ErrorReason\\",\\"description\\":\\"Bad Request\\",\\"oid\\":\\"3.7\\",\\"httpCode\\":\\"400\\"},\\"subject\\":{\\"@type\\":\\"ErrorSubject\\",\\"description\\":\\"Profile\\",\\"oid\\":\\"8.2\\"},\\"message\\":\\"[8.2 Profile/3.7 Bad Request]\\"}",
+ "body" : "{\\"subject\\":{\\"@type\\":\\"ErrorSubject\\",\\"oid\\":\\"8.2\\",\\"description\\":\\"Profile\\"},\\"reason\\":{\\"@type\\":\\"ErrorReason\\",\\"oid\\":\\"3.7\\",\\"description\\":\\"Bad Request\\",\\"httpCode\\":\\"400\\"},\\"message\\":\\"[8.2 Profile/3.7 Bad Request]\\"}",
"headers" : {
"CorrelationID" : "11111111-1111-1111-1111-111111111111",
"Content-Type" : "application/json;charset=UTF-8"
diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/BaseWireMockStubStrategy.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/BaseWireMockStubStrategy.groovy
index ed5d05bbda..1dbae89777 100755
--- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/BaseWireMockStubStrategy.groovy
+++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/BaseWireMockStubStrategy.groovy
@@ -16,12 +16,11 @@
package org.springframework.cloud.contract.verifier.dsl.wiremock
+import com.fasterxml.jackson.databind.ObjectMapper
import com.jayway.jsonpath.DocumentContext
import com.jayway.jsonpath.JsonPath
-import groovy.json.JsonBuilder
import groovy.transform.PackageScope
import groovy.transform.TypeChecked
-import org.json.JSONObject
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.spec.ContractTemplate
@@ -38,7 +37,6 @@ import static org.springframework.cloud.contract.verifier.util.ContentType.UNKNO
import static org.springframework.cloud.contract.verifier.util.ContentUtils.extractValue
import static org.springframework.cloud.contract.verifier.util.ContentUtils.getClientContentType
import static org.springframework.cloud.contract.verifier.util.MapConverter.transformValues
-
/**
* Common abstraction over WireMock Request / Response conversion implementations
*
@@ -189,11 +187,10 @@ abstract class BaseWireMockStubStrategy {
Map convertedMap = MapConverter.transformValues(value) {
it instanceof GString ? it.toString() : it
} as Map
- String jsonOutput = new JSONObject(new JsonBuilder(convertedMap).toString()).
- toString()
+ String jsonOutput = new ObjectMapper().writeValueAsString(convertedMap)
return jsonOutput.replaceAll("\\\\\\\\\\\\", "\\\\")
}
- return new JsonBuilder(value).toString()
+ return new ObjectMapper().writeValueAsString(value)
}
/**
diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockGroovyDslSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockGroovyDslSpec.groovy
index b125eba2a7..3a3ad28411 100755
--- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockGroovyDslSpec.groovy
+++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockGroovyDslSpec.groovy
@@ -29,6 +29,7 @@ import org.springframework.boot.test.web.client.TestRestTemplate
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.verifier.builder.handlebars.HandlebarsEscapeHelper
import org.springframework.cloud.contract.verifier.builder.handlebars.HandlebarsJsonPathHelper
+import org.springframework.cloud.contract.verifier.converter.YamlContractConverter
import org.springframework.cloud.contract.verifier.file.ContractMetadata
import org.springframework.cloud.contract.verifier.util.AssertionUtil
import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter
@@ -78,7 +79,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
},
"response" : {
"status" : 200,
- "body" : "{\\"surname\\":\\"Kowalsky\\",\\"created\\":\\"2014-02-02 12:23:43\\",\\"name\\":\\"Jan\\",\\"id\\":\\"123\\"}",
+ "body" : "{\\"id\\":\\"123\\",\\"surname\\":\\"Kowalsky\\",\\"name\\":\\"Jan\\",\\"created\\":\\"2014-02-02 12:23:43\\"}",
"headers" : {
"Content-Type" : "application/json"
},
@@ -131,7 +132,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
},
"response" : {
"status" : 200,
- "body" : "{\\"ingredients\\":[{\\"quantity\\":100,\\"type\\":\\"MALT\\"},{\\"quantity\\":200,\\"type\\":\\"WATER\\"},{\\"quantity\\":300,\\"type\\":\\"HOP\\"},{\\"quantity\\":400,\\"type\\":\\"YIEST\\"}]}",
+ "body" : "{\\"ingredients\\":[{\\"type\\":\\"MALT\\",\\"quantity\\":100},{\\"type\\":\\"WATER\\",\\"quantity\\":200},{\\"type\\":\\"HOP\\",\\"quantity\\":300},{\\"type\\":\\"YIEST\\",\\"quantity\\":400}]}",
"transformers" : [ "response-template", "foo-transformer" ]
}
}
@@ -191,7 +192,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
},
"response": {
"status": 204,
- "body": "{\\"foundExistingPayment\\":false,\\"paymentId\\":\\"4\\"}",
+ "body": "{\\"paymentId\\":\\"4\\",\\"foundExistingPayment\\":false}",
"transformers" : [ "response-template", "foo-transformer" ]
}
}
@@ -1968,7 +1969,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
},
"response" : {
"status" : 200,
- "body" : "{\\"number\\":0,\\"last\\":true,\\"numberOfElements\\":1,\\"size\\":1,\\"totalPages\\":1,\\"sort\\":[{\\"nullHandling\\":\\"NATIVE\\",\\"ignoreCase\\":false,\\"property\\":\\"id\\",\\"ascending\\":true,\\"direction\\":\\"ASC\\"}],\\"content\\":[{\\"id\\":\\"00000000-0000-0000-0000-000000000000\\",\\"state\\":\\"ACTIVE\\",\\"type\\":\\"Extraordinary\\"}],\\"first\\":true,\\"totalElements\\":1}",
+ "body" : "{\\"content\\":[{\\"id\\":\\"00000000-0000-0000-0000-000000000000\\",\\"type\\":\\"Extraordinary\\",\\"state\\":\\"ACTIVE\\"}],\\"totalPages\\":1,\\"totalElements\\":1,\\"last\\":true,\\"sort\\":[{\\"direction\\":\\"ASC\\",\\"property\\":\\"id\\",\\"ignoreCase\\":false,\\"nullHandling\\":\\"NATIVE\\",\\"ascending\\":true}],\\"first\\":true,\\"numberOfElements\\":1,\\"size\\":1,\\"number\\":0}",
"transformers" : [ "response-template", "foo-transformer" ]
}
}
@@ -2216,7 +2217,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
},
"response" : {
"status" : 200,
- "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]}}\\"}",
+ "body" : "{\\"url\\":\\"{{{request.url}}}\\",\\"path\\":\\"{{{request.path}}}\\",\\"pathIndex\\":\\"{{{request.path.[1]}}}\\",\\"param\\":\\"{{{request.query.foo.[0]}}}\\",\\"paramIndex\\":\\"{{{request.query.foo.[1]}}}\\",\\"authorization\\":\\"{{{request.headers.Authorization.[0]}}}\\",\\"authorization2\\":\\"{{{request.headers.Authorization.[1]}}}\\",\\"fullBody\\":\\"{{{escapejsonbody}}}\\",\\"responseFoo\\":\\"{{{jsonPath request.body '$.foo'}}}\\",\\"responseBaz\\":{{{jsonPath request.body '$.baz'}}} ,\\"responseBaz2\\":\\"Bla bla {{{jsonPath request.body '$.foo'}}} bla bla\\",\\"rawUrl\\":\\"{{request.url}}\\",\\"rawPath\\":\\"{{request.path}}\\",\\"rawPathIndex\\":\\"{{request.path.[1]}}\\",\\"rawParam\\":\\"{{request.query.foo.[0]}}\\",\\"rawParamIndex\\":\\"{{request.query.foo.[1]}}\\",\\"rawAuthorization\\":\\"{{request.headers.Authorization.[0]}}\\",\\"rawAuthorization2\\":\\"{{request.headers.Authorization.[1]}}\\",\\"rawResponseFoo\\":\\"{{jsonPath request.body '$.foo'}}\\",\\"rawResponseBaz\\":{{jsonPath request.body '$.baz'}} ,\\"rawResponseBaz2\\":\\"Bla bla {{jsonPath request.body '$.foo'}} bla bla\\"}",
"headers" : {
"Authorization" : "{{{request.headers.Authorization.[0]}}};foo"
},
@@ -2327,7 +2328,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
},
"response" : {
"status" : 200,
- "body" : "{\\"access_token\\":\\"RANDOM_ACCESS_TOKEN\\",\\"refresh_token\\":\\"RANDOM_REFRESH_TOKEN\\",\\"scope\\":[\\"task\\"],\\"token_type\\":\\"bearer\\",\\"expires_in\\":3600,\\"user\\":{\\"name\\":\\"User\\",\\"id\\":1,\\"username\\":\\"user\\"}}",
+ "body" : "{\\"refresh_token\\":\\"RANDOM_REFRESH_TOKEN\\",\\"access_token\\":\\"RANDOM_ACCESS_TOKEN\\",\\"token_type\\":\\"bearer\\",\\"expires_in\\":3600,\\"scope\\":[\\"task\\"],\\"user\\":{\\"id\\":1,\\"username\\":\\"user\\",\\"name\\":\\"User\\"}}",
"headers" : {
"Content-Type" : "application/json"
},
@@ -2570,7 +2571,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
},
"response" : {
"status" : 200,
- "body" : "{\\"code\\":91015,\\"payload\\":null,\\"description\\":\\"订单已失效\\",\\"lastUpdateTime\\":\\"0\\"}",
+ "body" : "{\\"code\\":91015,\\"description\\":\\"订单已失效\\",\\"lastUpdateTime\\":\\"0\\",\\"payload\\":null}",
"transformers" : [ "response-template", "foo-transformer" ]
}
}
@@ -2641,7 +2642,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
},
"response" : {
"status" : 200,
- "body" : "{\\"access_token\\":\\"RANDOM_ACCESS_TOKEN\\",\\"refresh_token\\":\\"RANDOM_REFRESH_TOKEN\\",\\"scope\\":[\\"task\\"],\\"token_type\\":\\"bearer\\",\\"expires_in\\":3600,\\"user\\":{\\"name\\":\\"User\\",\\"id\\":1,\\"username\\":\\"user\\"}}",
+ "body" : "{\\"refresh_token\\":\\"RANDOM_REFRESH_TOKEN\\",\\"access_token\\":\\"RANDOM_ACCESS_TOKEN\\",\\"token_type\\":\\"bearer\\",\\"expires_in\\":3600,\\"scope\\":[\\"task\\"],\\"user\\":{\\"id\\":1,\\"username\\":\\"user\\",\\"name\\":\\"User\\"}}",
"headers" : {
"Content-Type" : "application/json;charset=UTF-8"
},
@@ -2844,6 +2845,23 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
}
+ @Issue("#1038")
+ def "should deal with unicode strings"() {
+ given:
+ File file = new File(WireMockGroovyDslSpec.getResource("/yml/issue1038.yml").
+ toURI())
+ Contract contractDsl = new YamlContractConverter().convertFrom(file).first()
+ when:
+ String wireMockStub = new WireMockStubStrategy("Test",
+ new ContractMetadata(null, false, 0, null, contractDsl), contractDsl)
+ .toWireMockClientStub()
+
+ then:
+ wireMockStub.contains('''\\"country\\":\\"日本\\"''')
+ stubMappingIsValidWireMockStub(wireMockStub)
+
+ }
+
WireMockConfiguration config() {
return new WireMockConfiguration().extensions(responseTemplateTransformer())
}
diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/issue1038.yml b/spring-cloud-contract-verifier/src/test/resources/yml/issue1038.yml
new file mode 100644
index 0000000000..ea749fd479
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/test/resources/yml/issue1038.yml
@@ -0,0 +1,15 @@
+name: get-all-users
+request:
+ url: /users
+ method: GET
+response:
+ status: 200
+ headers:
+ content-type: application/json; charset=UTF-8
+ body:
+ - id: 001
+ name: alice
+ country: US
+ - id: 002
+ name: bob
+ country: 日本
\ No newline at end of file
diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/SpringCloudContractRestDocs.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/SpringCloudContractRestDocs.java
index ef9f1191d6..531080fa8c 100644
--- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/SpringCloudContractRestDocs.java
+++ b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/SpringCloudContractRestDocs.java
@@ -47,8 +47,7 @@ import org.springframework.restdocs.snippet.Snippet;
* // first WireMock
* .andDo(WireMockRestDocs.verify()
* .jsonPath("$[?(@.foo >= 20)]")
- * .contentType(MediaType.valueOf("application/json"))
- * .stub("shouldGrantABeerIfOldEnough"))
+ * .contentType(MediaType.valueOf("application/json")))
* // then Contract DSL documentation
* .andDo(document("index", SpringCloudContractRestDocs.dslContract()));
* }
diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockRestDocs.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockRestDocs.java
index 5982a84627..c4c9db6b36 100644
--- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockRestDocs.java
+++ b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockRestDocs.java
@@ -33,7 +33,8 @@ package org.springframework.cloud.contract.wiremock.restdocs;
* public void contextLoads() throws Exception {
* mockMvc.perform(get("/resource"))
* .andExpect(content().string("Hello World"))
- * .andDo(verify().stub("resource"));
+ * .andDo(verify())
+ * .andDo(document("resource"));
* }
* which creates a file "target/snippets/stubs/resource.json" matching any GET
* request to "/resource". To match POST and PUT, you can also specify the content type
diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockVerifyHelper.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockVerifyHelper.java
index 6bfe920fb8..43a73b7130 100644
--- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockVerifyHelper.java
+++ b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockVerifyHelper.java
@@ -42,20 +42,19 @@ public abstract class WireMockVerifyHelperandDo(document(name))
+ */
@SuppressWarnings("unchecked")
+ @Deprecated
public S stub(String name) {
- this.name = name;
return (S) this;
}
- protected String getName() {
- return this.name;
- }
-
public void configure(T result) {
Map configuration = getConfiguration(result);
String actual = new String(getRequestBodyContent(result),
diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerRestDocsMatcherApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerRestDocsMatcherApplicationTests.java
index 36998b827d..7b02bb6c92 100644
--- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerRestDocsMatcherApplicationTests.java
+++ b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerRestDocsMatcherApplicationTests.java
@@ -16,6 +16,8 @@
package org.springframework.cloud.contract.wiremock;
+import java.io.File;
+
import com.github.tomakehurst.wiremock.client.WireMock;
import org.junit.Rule;
import org.junit.Test;
@@ -34,12 +36,16 @@ import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
+import org.springframework.util.FileSystemUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
+
@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestConfiguration.class)
@AutoConfigureRestDocs(outputDir = "target/snippets")
@@ -54,14 +60,16 @@ public class WiremockServerRestDocsMatcherApplicationTests {
@Test
public void matchesRequest() throws Exception {
+ FileSystemUtils.deleteRecursively(new File("target/snippets/stubs/posted.json"));
this.mockMvc
.perform(MockMvcRequestBuilders.post("/resource").content("greeting")
.contentType(MediaType.TEXT_PLAIN))
.andExpect(MockMvcResultMatchers.content().string("Hello World"))
.andDo(WireMockRestDocs.verify()
.wiremock(WireMock.post(WireMock.urlPathEqualTo("/resource"))
- .withRequestBody(WireMock.matching("greeting.*")))
- .stub("posted"));
+ .withRequestBody(WireMock.matching("greeting.*"))))
+ .andDo(document("posted"));
+ assertThat(new File("target/snippets/stubs/posted.json")).exists();
}
@Test
@@ -74,8 +82,8 @@ public class WiremockServerRestDocsMatcherApplicationTests {
.andExpect(MockMvcResultMatchers.content().string("Hello World"))
.andDo(WireMockRestDocs.verify()
.wiremock(WireMock.post(WireMock.urlPathEqualTo("/resource"))
- .withRequestBody(WireMock.matching("garbage.*")))
- .stub("posted"));
+ .withRequestBody(WireMock.matching("garbage.*"))))
+ .andDo(document("posted"));
}
@Configuration
diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/restdocs/ContractDslSnippetTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/restdocs/ContractDslSnippetTests.java
index a163041627..d5bd2ee40a 100644
--- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/restdocs/ContractDslSnippetTests.java
+++ b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/restdocs/ContractDslSnippetTests.java
@@ -77,7 +77,9 @@ public class ContractDslSnippetTests {
@Before
public void setUp() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
- .apply(documentationConfiguration(this.restDocumentation)).build();
+ .apply(documentationConfiguration(this.restDocumentation).snippets()
+ .withAdditionalDefaults(new WireMockSnippet()))
+ .build();
}
@Test
@@ -92,13 +94,13 @@ public class ContractDslSnippetTests {
// first WireMock
.andDo(WireMockRestDocs.verify().jsonPath("$[?(@.foo >= 20)]")
.jsonPath("$[?(@.bar in ['baz','bazz','bazzz'])]")
- .contentType(MediaType.valueOf("application/json"))
- .stub("shouldGrantABeerIfOldEnough"))
+ .contentType(MediaType.valueOf("application/json")))
// then Contract DSL documentation
.andDo(document("index", SpringCloudContractRestDocs.dslContract()));
// end::contract_snippet[]
then(file("/contracts/index.groovy")).exists();
+ then(file("/stubs/index.json")).exists();
then(file("/index/dsl-contract.adoc")).exists();
Collection parsedContracts = ContractVerifierDslConverter
.convertAsCollection(new File("/"), file("/contracts/index.groovy"));
@@ -131,8 +133,7 @@ public class ContractDslSnippetTests {
// first WireMock
.andDo(WireMockRestDocs.verify().jsonPath("$[?(@.foo >= 20)]")
.jsonPath("$[?(@.bar in ['baz','bazz','bazzz'])]")
- .contentType(MediaType.valueOf("application/json"))
- .stub("shouldGrantABeerIfOldEnough"))
+ .contentType(MediaType.valueOf("application/json")))
// then Contract DSL documentation
.andDo(document("{methodName}",
SpringCloudContractRestDocs.dslContract()));
@@ -140,6 +141,9 @@ public class ContractDslSnippetTests {
then(file(
"/contracts/should_create_contract_template_and_doc_with_placeholder_names.groovy"))
.exists();
+ then(file(
+ "/stubs/should_create_contract_template_and_doc_with_placeholder_names.json"))
+ .exists();
then(file(
"/should_create_contract_template_and_doc_with_placeholder_names/dsl-contract.adoc"))
.exists();