Introduced adding of custom WireMock extensions (#429)

without this change we set only a single extension "response-transformer" without an option to provide any other ones
with this change we introduce the "spring.factories" based extension model. It's enough to provide your own implementation of `org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockExtensions` and register it in `spring.factories`. That way you can control all extensions (request / response).

fixes #425
This commit is contained in:
Marcin Grzejszczak
2017-10-05 15:52:27 +02:00
committed by GitHub
parent 4a46760ee2
commit 0758f4ec38
12 changed files with 271 additions and 57 deletions

View File

@@ -8,27 +8,28 @@ import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.common.Slf4jNotifier;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import com.github.tomakehurst.wiremock.extension.responsetemplating.ResponseTemplateTransformer;
import com.github.tomakehurst.wiremock.extension.Extension;
import com.github.tomakehurst.wiremock.stubbing.StubMapping;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.contract.stubrunner.HttpServerStub;
import org.springframework.cloud.contract.verifier.builder.handlebars.HandlebarsEscapeHelper;
import org.springframework.cloud.contract.verifier.builder.handlebars.HandlebarsJsonPathHelper;
import org.springframework.cloud.contract.verifier.dsl.wiremock.DefaultResponseTransformer;
import org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockExtensions;
import org.springframework.cloud.contract.wiremock.WireMockSpring;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.util.ClassUtils;
import org.springframework.util.SocketUtils;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import wiremock.com.github.jknack.handlebars.Helper;
/**
@@ -47,18 +48,32 @@ public class WireMockHttpServerStub implements HttpServerStub {
private WireMockConfiguration config() {
if (ClassUtils.isPresent("org.springframework.cloud.contract.wiremock.WireMockSpring", null)) {
return WireMockSpring.options()
.extensions(responseTemplateTransformer());
.extensions(responseTransformers());
}
return new WireMockConfiguration().extensions(responseTemplateTransformer());
return new WireMockConfiguration().extensions(responseTransformers());
}
private ResponseTemplateTransformer responseTemplateTransformer() {
return new ResponseTemplateTransformer(false, helpers());
private Extension[] responseTransformers() {
List<WireMockExtensions> wireMockExtensions = SpringFactoriesLoader
.loadFactories(WireMockExtensions.class, null);
List<Extension> extensions = new ArrayList<>();
if (!wireMockExtensions.isEmpty()) {
for (WireMockExtensions wireMockExtension : wireMockExtensions) {
extensions.addAll(wireMockExtension.extensions());
}
} else {
extensions.add(new DefaultResponseTransformer(false, helpers()));
}
return extensions.toArray(new Extension[extensions.size()]);
}
/**
* Override this if you want to register your own helpers
*
* @deprecated - please use the {@link WireMockExtensions} mechanism and pass
* the helpers in your implementation
*/
@Deprecated
protected Map<String, Helper> helpers() {
Map<String, Helper> helpers = new HashMap<>();
helpers.put(HandlebarsJsonPathHelper.NAME, new HandlebarsJsonPathHelper());

View File

@@ -0,0 +1,56 @@
package org.springframework.cloud.contract.stubrunner.provider.wiremock
import com.github.tomakehurst.wiremock.common.FileSource
import com.github.tomakehurst.wiremock.extension.Extension
import com.github.tomakehurst.wiremock.extension.Parameters
import com.github.tomakehurst.wiremock.extension.ResponseTransformer
import com.github.tomakehurst.wiremock.http.Request
import com.github.tomakehurst.wiremock.http.Response
import org.springframework.cloud.contract.verifier.dsl.wiremock.DefaultResponseTransformer
import org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockExtensions
/**
* Extension that registers the default response transformer and a custom one too
*/
class TestWireMockExtensions implements WireMockExtensions {
@Override
List<Extension> extensions() {
return [
new DefaultResponseTransformer(),
new CustomExtension()
]
}
}
class CustomExtension extends ResponseTransformer {
/**
* We expect the mapping to contain "foo-transformer" in the list
* of "response-transformers" in the stub mapping
*/
@Override
String getName() {
return "foo-transformer"
}
/**
* Transformer returns the "surprise!" body regardless of what you
* the stub mapping returns
*/
@Override
Response transform(Request request, Response response, FileSource files, Parameters parameters) {
return new Response(response.status, response.statusMessage,
"surprise!", response.headers, response.wasConfigured(), response.fault, response.fromProxy)
}
/**
* We don't want this extension to be applied to every single mapping.
* We just want this to take place when a mapping explicitly expresses that in the
* "response-transformers" section
*/
@Override
boolean applyGlobally() {
return false
}
}

View File

@@ -23,31 +23,35 @@ import spock.lang.Specification
import org.springframework.boot.test.rule.OutputCapture
import org.springframework.boot.test.web.client.TestRestTemplate
import org.springframework.web.client.RestTemplate
class WireMockHttpServerStubSpec extends Specification {
public static
final File MAPPING_DESCRIPTOR = new File('src/test/resources/repository/mappings/spring/cloud/ping/ping.json')
final File MAPPING_DESCRIPTOR = new File('src/test/resources/transformers.json')
@Rule OutputCapture capture = new OutputCapture()
def 'should describe stub mapping'() {
given:
WireMockHttpServerStub mappingDescriptor = new WireMockHttpServerStub().start() as WireMockHttpServerStub
WireMockHttpServerStub mappingDescriptor = new WireMockHttpServerStub().start() as WireMockHttpServerStub
when:
StubMapping mapping = mappingDescriptor.getMapping(MAPPING_DESCRIPTOR)
StubMapping mapping = mappingDescriptor.getMapping(MAPPING_DESCRIPTOR)
then:
with(mapping) {
assert request.method == RequestMethod.GET
assert request.url == '/ping'
assert response.status == 200
assert response.body == 'pong'
assert response.headers.contentTypeHeader.mimeTypePart() == 'text/plain'
}
with(mapping) {
assert request.method == RequestMethod.GET
assert request.url == '/ping'
assert response.status == 200
assert response.body == 'pong'
assert response.headers.contentTypeHeader.mimeTypePart() == 'text/plain'
}
when:
mappingDescriptor.registerMappings([MAPPING_DESCRIPTOR])
then:
noExceptionThrown()
expect:
"surprise!" == new RestTemplate().getForObject("http://localhost:" + mappingDescriptor.port() + "/ping", String.class)
cleanup:
mappingDescriptor.stop()
mappingDescriptor.stop()
}
def 'should make WireMock print out logs on INFO'() {

View File

@@ -0,0 +1,2 @@
org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockExtensions=\
org.springframework.cloud.contract.stubrunner.provider.wiremock.TestWireMockExtensions

View File

@@ -0,0 +1,14 @@
{
"request": {
"method": "GET",
"url": "/ping"
},
"response": {
"status": 200,
"body": "pong",
"headers": {
"Content-Type": "text/plain"
},
"transformers" : [ "response-template", "foo-transformer" ]
}
}