Add support for WireMock matchers on restdocs stub builder

This commit is contained in:
Dave Syer
2016-07-27 09:16:12 +01:00
parent 4e21cbd884
commit 5609ffe76c
6 changed files with 154 additions and 23 deletions

View File

@@ -18,6 +18,7 @@ package org.springframework.cloud.contract.wiremock.restdocs;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.LinkedHashMap;
@@ -25,6 +26,7 @@ import java.util.Map;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultHandler;
@@ -32,6 +34,11 @@ import org.springframework.util.ObjectUtils;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import com.github.tomakehurst.wiremock.client.RemoteMappingBuilder;
import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder;
import com.github.tomakehurst.wiremock.matching.MatchResult;
import com.github.tomakehurst.wiremock.servlet.WireMockHttpServletRequestAdapter;
import com.github.tomakehurst.wiremock.stubbing.StubMapping;
import com.jayway.jsonpath.JsonPath;
public class ContractRequestHandler implements ResultHandler {
@@ -42,6 +49,8 @@ public class ContractRequestHandler implements ResultHandler {
private MediaType contentType;
private String name;
private RemoteMappingBuilder<?, ?> builder;
public ContractRequestHandler() {
}
@@ -55,7 +64,7 @@ public class ContractRequestHandler implements ResultHandler {
@Override
public void handle(MvcResult result) throws Exception {
MockHttpServletRequest request = result.getRequest();
Map<String,Object> configuration = getConfiguration(result);
Map<String, Object> configuration = getConfiguration(result);
String actual = StreamUtils.copyToString(request.getInputStream(),
Charset.forName("UTF-8"));
for (JsonPath jsonPath : jsonPaths.values()) {
@@ -69,19 +78,50 @@ public class ContractRequestHandler implements ResultHandler {
assertThat(contentType.includes(MediaType.valueOf(resultType))).isTrue()
.as("content type did not match");
}
if (builder != null) {
builder.willReturn(getResponseDefinition(result));
StubMapping stubMapping = builder.build();
MatchResult match = stubMapping.getRequest()
.match(new WireMockHttpServletRequestAdapter(request));
assertThat(match.isExactMatch()).as("wiremock did not match request").isTrue();
configuration.put("contract.stubMapping", stubMapping);
}
MockMvcRestDocumentation.document(this.name).handle(result);
}
private ResponseDefinitionBuilder getResponseDefinition(MvcResult result)
throws UnsupportedEncodingException {
MockHttpServletResponse response = result.getResponse();
ResponseDefinitionBuilder definition = ResponseDefinitionBuilder
.responseDefinition().withBody(response.getContentAsString())
.withStatus(response.getStatus());
addResponseHeaders(definition, response);
return definition;
}
private void addResponseHeaders(ResponseDefinitionBuilder definition,
MockHttpServletResponse input) {
for (String name : input.getHeaderNames()) {
definition.withHeader(name, input.getHeader(name));
}
}
private Map<String, Object> getConfiguration(MvcResult result) {
@SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>) result.getRequest().getAttribute(ATTRIBUTE_NAME_CONFIGURATION);
if (map==null) {
Map<String, Object> map = (Map<String, Object>) result.getRequest()
.getAttribute(ATTRIBUTE_NAME_CONFIGURATION);
if (map == null) {
map = new HashMap<>();
result.getRequest().setAttribute(ATTRIBUTE_NAME_CONFIGURATION, map);
}
return map;
}
public ContractRequestHandler wiremock(RemoteMappingBuilder<?, ?> builder) {
this.builder = builder;
return this;
}
public ContractRequestHandler jsonPath(String expression, Object... args) {
compile(expression, args);
return this;

View File

@@ -0,0 +1,78 @@
package org.springframework.cloud.contract.wiremock;
import org.junit.ComparisonFailure;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.contract.wiremock.WiremockServerRestDocsMatcherApplicationTests.TestConfiguration;
import org.springframework.cloud.contract.wiremock.restdocs.WireMockRestDocs;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.test.annotation.DirtiesContext;
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.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 com.github.tomakehurst.wiremock.client.WireMock;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestConfiguration.class)
@AutoConfigureRestDocs(outputDir = "target/snippets")
@AutoConfigureMockMvc
@DirtiesContext
public class WiremockServerRestDocsMatcherApplicationTests {
@Autowired
private MockMvc mockMvc;
@Rule
public ExpectedException expected = ExpectedException.none();
@Test
public void matchesRequest() throws Exception {
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"));
}
@Test
public void doesNotMatch() throws Exception {
expected.expect(ComparisonFailure.class);
expected.expectMessage("wiremock did not match");
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("garbage.*")))
.stub("posted"));
}
@Configuration
@RestController
protected static class TestConfiguration {
@ResponseBody
@RequestMapping(value = "/resource", method = RequestMethod.POST)
public String resource(@RequestBody String body) {
return "Hello World";
}
}
}