Merge branch 'master' into 2.0.x

This commit is contained in:
Dave Syer
2017-08-30 09:31:49 +01:00
28 changed files with 28 additions and 856 deletions

View File

@@ -4,16 +4,10 @@
Modules giving you the possibility to use
http://wiremock.org[WireMock] with different servers by using the
"ambient" server embedded in a Spring Boot application. Check out the
http://wiremock.org[WireMock] in a Spring Boot application. Check out the
https://github.com/spring-cloud/spring-cloud-contract/tree/{branch}/samples[samples]
for more details.
IMPORTANT: The Spring Cloud Release Train BOM imports `spring-cloud-contract-dependencies`
which in turn has exclusions for the dependencies needed by WireMock. This might lead to a situation that
even if you're not using Spring Cloud Contract then your dependencies will be influenced
anyways.
If you have a Spring Boot application that uses Tomcat as an embedded
server, for example (the default with `spring-boot-starter-web`), then
you can simply add `spring-cloud-contract-wiremock` to your classpath

View File

@@ -76,7 +76,6 @@
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<configuration>
<skip>true</skip>
</configuration>

View File

@@ -21,7 +21,6 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<jetty.version>9.2.13.v20150730</jetty.version>
<spring-cloud-contract.version>2.0.0.BUILD-SNAPSHOT</spring-cloud-contract.version>
</properties>
@@ -51,7 +50,7 @@
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock</artifactId>
<artifactId>wiremock-standalone</artifactId>
<scope>test</scope>
</dependency>
<dependency>

View File

@@ -66,7 +66,6 @@
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<configuration>
<skip>true</skip>
</configuration>

View File

@@ -76,7 +76,6 @@
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<configuration>
<skip>true</skip>
</configuration>

View File

@@ -76,7 +76,6 @@
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<configuration>
<skip>true</skip>
</configuration>

View File

@@ -82,42 +82,8 @@
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock</artifactId>
<artifactId>wiremock-standalone</artifactId>
<version>${wiremock.version}</version>
<exclusions>
<exclusion>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</exclusion>
<exclusion>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
</exclusion>
<exclusion>
<groupId>net.sf.jopt-simple</groupId>
<artifactId>jopt-simple</artifactId>
</exclusion>
<exclusion>
<artifactId>jetty-server</artifactId>
<groupId>org.eclipse.jetty</groupId>
</exclusion>
<exclusion>
<artifactId>jetty-servlet</artifactId>
<groupId>org.eclipse.jetty</groupId>
</exclusion>
<exclusion>
<artifactId>jetty-servlets</artifactId>
<groupId>org.eclipse.jetty</groupId>
</exclusion>
<exclusion>
<artifactId>jetty-webapp</artifactId>
<groupId>org.eclipse.jetty</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.toomuchcoding.jsonassert</groupId>

View File

@@ -10,15 +10,16 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import com.github.jknack.handlebars.Helper;
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.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;
@@ -28,6 +29,8 @@ import org.springframework.util.SocketUtils;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import wiremock.com.github.jknack.handlebars.Helper;
/**
* Abstraction over WireMock as a HTTP Server Stub
*

View File

@@ -40,7 +40,7 @@
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock</artifactId>
<artifactId>wiremock-standalone</artifactId>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>

View File

@@ -16,7 +16,7 @@
package org.springframework.cloud.contract.verifier.converter
import com.google.common.collect.ListMultimap
import wiremock.com.google.common.collect.ListMultimap
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
import org.springframework.cloud.contract.spec.Contract

View File

@@ -35,7 +35,7 @@ import org.springframework.cloud.contract.stubrunner.StubRunner;
import org.springframework.cloud.contract.stubrunner.StubRunnerOptions;
import org.springframework.cloud.contract.stubrunner.StubRunnerOptionsBuilder;
import static com.google.common.base.Strings.isNullOrEmpty;
import static wiremock.com.google.common.base.Strings.isNullOrEmpty;
/**
*

View File

@@ -51,7 +51,7 @@
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock</artifactId>
<artifactId>wiremock-standalone</artifactId>
</dependency>
<dependency>
<groupId>com.toomuchcoding.jsonassert</groupId>

View File

@@ -20,7 +20,7 @@ import java.nio.charset.StandardCharsets
import java.nio.file.Path
import java.util.concurrent.atomic.AtomicInteger
import com.google.common.collect.ListMultimap
import wiremock.com.google.common.collect.ListMultimap
import groovy.transform.PackageScope
import org.apache.commons.lang3.StringUtils

View File

@@ -1,7 +1,7 @@
package org.springframework.cloud.contract.verifier.builder.handlebars
import com.github.jknack.handlebars.Helper
import com.github.jknack.handlebars.Options
import wiremock.com.github.jknack.handlebars.Helper
import wiremock.com.github.jknack.handlebars.Options
import com.github.tomakehurst.wiremock.extension.responsetemplating.RequestTemplateModel
import groovy.transform.CompileStatic
import org.apache.commons.lang3.StringEscapeUtils

View File

@@ -1,7 +1,7 @@
package org.springframework.cloud.contract.verifier.builder.handlebars
import com.github.jknack.handlebars.Helper
import com.github.jknack.handlebars.Options
import wiremock.com.github.jknack.handlebars.Helper
import wiremock.com.github.jknack.handlebars.Options
import com.github.tomakehurst.wiremock.extension.responsetemplating.RequestTemplateModel
import com.jayway.jsonpath.DocumentContext
import com.jayway.jsonpath.JsonPath

View File

@@ -16,8 +16,8 @@
package org.springframework.cloud.contract.verifier.file
import com.google.common.collect.ArrayListMultimap
import com.google.common.collect.ListMultimap
import wiremock.com.google.common.collect.ArrayListMultimap
import wiremock.com.google.common.collect.ListMultimap
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
import org.apache.commons.lang3.SystemUtils

View File

@@ -1,7 +1,7 @@
package org.springframework.cloud.contract.verifier.template
import com.github.jknack.handlebars.Handlebars
import com.github.jknack.handlebars.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

View File

@@ -16,7 +16,7 @@
package org.springframework.cloud.contract.verifier.file
import com.google.common.collect.ListMultimap
import wiremock.com.google.common.collect.ListMultimap
import spock.lang.Specification
import java.nio.file.Path

View File

@@ -1,6 +1,6 @@
package org.springframework.cloud.contract.verifier.messaging.amqp
import com.google.common.collect.ImmutableMap
import wiremock.com.google.common.collect.ImmutableMap
import org.springframework.amqp.core.Binding
import org.springframework.amqp.core.BindingBuilder
import org.springframework.amqp.core.DirectExchange

View File

@@ -15,7 +15,7 @@
<dependencies>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock</artifactId>
<artifactId>wiremock-standalone</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
@@ -28,17 +28,7 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
<optional>true</optional>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>

View File

@@ -1,93 +0,0 @@
/*
* Copyright 2016-2017 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
*
* http://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.wiremock;
import java.io.IOException;
import java.nio.channels.ByteChannel;
import javax.servlet.http.HttpServletResponse;
import com.github.tomakehurst.wiremock.core.FaultInjector;
import com.google.common.base.Charsets;
import org.eclipse.jetty.io.ChannelEndPoint;
import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.BufferUtil;
import static com.github.tomakehurst.wiremock.common.Exceptions.throwUnchecked;
import static com.github.tomakehurst.wiremock.jetty9.JettyUtils.unwrapResponse;
/**
* @author Dave Syer
*
*/
public class JettyFaultInjector implements FaultInjector {
private static final byte[] GARBAGE = "lskdu018973t09sylgasjkfg1][]'./.sdlv"
.getBytes(Charsets.UTF_8);
private final Response response;
private final ByteChannel socket;
public JettyFaultInjector(HttpServletResponse response) {
this.response = unwrapResponse(response);
this.socket = socket();
}
@Override
public void emptyResponseAndCloseConnection() {
try {
this.socket.close();
}
catch (IOException e) {
throwUnchecked(e);
}
}
@Override
public void malformedResponseChunk() {
try {
this.response.setStatus(200);
this.response.flushBuffer();
this.socket.write(BufferUtil.toBuffer(GARBAGE));
this.socket.close();
}
catch (IOException e) {
throwUnchecked(e);
}
}
@Override
public void randomDataAndCloseConnection() {
try {
this.socket.write(BufferUtil.toBuffer(GARBAGE));
this.socket.close();
}
catch (IOException e) {
throwUnchecked(e);
}
}
private ByteChannel socket() {
HttpChannel httpChannel = this.response.getHttpOutput().getHttpChannel();
ChannelEndPoint ep = (ChannelEndPoint) httpChannel.getEndPoint();
return ep.getChannel();
}
}

View File

@@ -1,37 +0,0 @@
/*
* Copyright 2016-2017 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
*
* http://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.wiremock;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.github.tomakehurst.wiremock.core.FaultInjector;
import com.github.tomakehurst.wiremock.servlet.FaultInjectorFactory;
/**
* @author Dave Syer
*
*/
public class JettyFaultInjectorFactory implements FaultInjectorFactory {
@Override
public FaultInjector buildFaultInjector(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse) {
return new JettyFaultInjector(httpServletResponse);
}
}

View File

@@ -1,515 +0,0 @@
/*
* Copyright 2015 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
*
* http://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.wiremock;
import javax.servlet.ServletContext;
import io.undertow.Undertow.Builder;
import com.github.tomakehurst.wiremock.common.HttpsSettings;
import com.github.tomakehurst.wiremock.common.Notifier;
import com.github.tomakehurst.wiremock.core.Options;
import com.github.tomakehurst.wiremock.core.WireMockApp;
import com.github.tomakehurst.wiremock.http.AdminRequestHandler;
import com.github.tomakehurst.wiremock.http.HttpServer;
import com.github.tomakehurst.wiremock.http.HttpServerFactory;
import com.github.tomakehurst.wiremock.http.RequestHandler;
import com.github.tomakehurst.wiremock.http.StubRequestHandler;
import com.github.tomakehurst.wiremock.servlet.FaultInjectorFactory;
import com.github.tomakehurst.wiremock.servlet.NoFaultInjectorFactory;
import com.github.tomakehurst.wiremock.servlet.WireMockHandlerDispatchingServlet;
import org.apache.catalina.connector.Connector;
import org.eclipse.jetty.server.ConnectionFactory;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.Banner.Mode;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.servlet.DefaultServletWebServerFactoryCustomizer;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.embedded.undertow.UndertowBuilderCustomizer;
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
import org.springframework.boot.web.server.Ssl;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.cloud.contract.wiremock.ContainerConfiguration.JettyContainerConfiguration;
import org.springframework.cloud.contract.wiremock.ContainerConfiguration.TomcatContainerConfiguration;
import org.springframework.cloud.contract.wiremock.ContainerConfiguration.UndertowContainerConfiguration;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.event.EventListener;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.web.context.ServletContextAware;
/**
* @author Dave Syer
*
*/
class SpringBootHttpServerFactory implements HttpServerFactory {
@Override
public HttpServer buildHttpServer(Options options,
AdminRequestHandler adminRequestHandler,
StubRequestHandler stubRequestHandler) {
return new SpringBootHttpServer(options, adminRequestHandler, stubRequestHandler);
}
}
class SpringBootHttpServer
implements HttpServer, ApplicationListener<ApplicationPreparedEvent> {
private volatile boolean running;
private Options options;
private AdminRequestHandler adminRequestHandler;
private StubRequestHandler stubRequestHandler;
private ConfigurableApplicationContext context;
public SpringBootHttpServer(Options options, AdminRequestHandler adminRequestHandler,
StubRequestHandler stubRequestHandler) {
this.options = options;
this.adminRequestHandler = adminRequestHandler;
this.stubRequestHandler = stubRequestHandler;
}
@Override
public void start() {
this.context = new SpringApplicationBuilder(WiremockServerConfiguration.class)
.logStartupInfo(false).bannerMode(Mode.OFF)
.properties("spring.cloud.bootstrap.enabled=false").listeners(this).run();
this.running = true;
}
@Override
public void stop() {
if (this.context != null) {
this.context.close();
}
this.running = false;
}
@Override
public boolean isRunning() {
return this.running;
}
@Override
public int port() {
return container().port();
}
@Override
public int httpsPort() {
return container().httpsPort();
}
private ContainerProperties container() {
if (this.context != null) {
return this.context.getBean(ContainerProperties.class);
}
return new ContainerProperties(this.options);
}
@Override
public void onApplicationEvent(ApplicationPreparedEvent event) {
GenericApplicationContext context = (GenericApplicationContext) event
.getApplicationContext();
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
if (beanFactory.containsBean("wireMockOptions")) {
// Be idempotent (the event might be emitted more than once)
return;
}
beanFactory.registerSingleton("wireMockOptions", this.options);
beanFactory.registerSingleton("adminRequestHandler", this.adminRequestHandler);
beanFactory.registerSingleton("stubRequestHandler", this.stubRequestHandler);
beanFactory.addBeanPostProcessor(new ServerPropertiesPostProcessor());
}
class ServerPropertiesPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof WiremockServerProperties) {
WiremockServerProperties server = (WiremockServerProperties) bean;
server.setPort(getPort());
setupHttps(server, SpringBootHttpServer.this.options.httpsSettings());
// TODO: other options
}
return bean;
}
private void setupHttps(WiremockServerProperties server,
HttpsSettings httpsSettings) {
if (httpsSettings.port() < 0 || !httpsSettings.enabled()) {
return;
}
Ssl ssl = server.getSsl();
if (ssl == null) {
ssl = new Ssl();
server.setSsl(ssl);
}
ssl.setKeyStore(httpsSettings.keyStorePath());
ssl.setKeyPassword(httpsSettings.keyStorePassword());
if (httpsSettings.hasTrustStore()) {
ssl.setTrustStore(httpsSettings.trustStorePath());
ssl.setTrustStorePassword(httpsSettings.trustStorePassword());
}
}
private int getPort() {
if (SpringBootHttpServer.this.options.httpsSettings().port() >= 0) {
return SpringBootHttpServer.this.options.httpsSettings().port();
}
return SpringBootHttpServer.this.options.portNumber();
}
}
}
class WiremockServerProperties implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
private ServerProperties delegate = new ServerProperties();
public Integer getPort() {
return this.delegate.getPort();
}
public void setPort(Integer port) {
this.delegate.setPort(port);
}
public Ssl getSsl() {
return this.delegate.getSsl();
}
public void setSsl(Ssl ssl) {
this.delegate.setSsl(ssl);
}
@Override
public void customize(ConfigurableServletWebServerFactory server) {
new DefaultServletWebServerFactoryCustomizer(this.delegate).customize(server);
}
}
@Configuration
class ServerPropertiesConfiguration {
@Bean
public WiremockServerProperties serverProperties() {
// Needs to be something that doesn't bind to "server.*"
return new WiremockServerProperties();
}
}
@Configuration
@Import({ TomcatContainerConfiguration.class, JettyContainerConfiguration.class,
UndertowContainerConfiguration.class, ServerPropertiesConfiguration.class,
BeanPostProcessorsRegistrar.class, ConfigurationPropertiesAutoConfiguration.class,
JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, ContainerProperties.class })
class WiremockServerConfiguration {
@Autowired
private AdminRequestHandler adminRequestHandler;
@Autowired
private StubRequestHandler stubRequestHandler;
@Autowired
private FaultInjectorFactory faultInjectorFactory;
@Autowired
private Options options;
@Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
public ServletRegistrationBean<WireMockHandlerDispatchingServlet> stubServletRegistration() {
ServletRegistrationBean<WireMockHandlerDispatchingServlet> reg = new ServletRegistrationBean<>();
reg.addInitParameter(RequestHandler.HANDLER_CLASS_KEY,
StubRequestHandler.class.getName());
if (WiremockServerConfiguration.this.faultInjectorFactory != null) {
reg.addInitParameter(FaultInjectorFactory.INJECTOR_CLASS_KEY,
FaultInjectorFactory.class.getName());
}
reg.setServlet(new WireMockHandlerDispatchingServlet());
reg.setName("stub");
reg.addUrlMappings("/");
return reg;
}
@Bean
public ServletRegistrationBean<WireMockHandlerDispatchingServlet> adminServletRegistration() {
ServletRegistrationBean<WireMockHandlerDispatchingServlet> reg = new ServletRegistrationBean<>();
reg.addInitParameter(RequestHandler.HANDLER_CLASS_KEY,
AdminRequestHandler.class.getName());
reg.setServlet(new WireMockHandlerDispatchingServlet());
reg.setName("admin");
reg.addUrlMappings(WireMockApp.ADMIN_CONTEXT_ROOT + "/*");
return reg;
}
@Bean
public ServletContextAware servletContextSetUp() {
return new ServletContextAware() {
@Override
public void setServletContext(ServletContext servletContext) {
servletContext.setAttribute(AdminRequestHandler.class.getName(),
WiremockServerConfiguration.this.adminRequestHandler);
servletContext.setAttribute(StubRequestHandler.class.getName(),
WiremockServerConfiguration.this.stubRequestHandler);
servletContext.setAttribute(Notifier.KEY,
WiremockServerConfiguration.this.options.notifier());
if (WiremockServerConfiguration.this.faultInjectorFactory != null) {
servletContext.setAttribute(FaultInjectorFactory.class.getName(),
WiremockServerConfiguration.this.faultInjectorFactory);
}
}
};
}
}
@Component
class ContainerProperties {
private Options options;
private Integer localPort;
private Integer localHttpsPort;
@Autowired
private ConfigurableApplicationContext context;
@Autowired
public ContainerProperties(Options options) {
this.options = options;
}
public int port() {
if (this.options.httpsSettings().enabled()) {
return this.options.portNumber();
}
if (this.localPort != null) {
return this.localPort;
}
ServletWebServerApplicationContext embedded = (ServletWebServerApplicationContext) this.context;
return embedded.getWebServer().getPort();
}
public int httpsPort() {
if (this.localHttpsPort != null) {
return this.localHttpsPort;
}
return this.options.httpsSettings().port();
}
public void setLocalPort(int localPort) {
this.localPort = localPort;
}
public void setLocalHttpsPort(int localHttpsPort) {
this.localHttpsPort = localHttpsPort;
}
}
class ContainerConfiguration {
@Configuration
@ConditionalOnMissingBean(ServletWebServerFactory.class)
@ConditionalOnClass({ TomcatServletWebServerFactory.class, Connector.class })
static class TomcatContainerConfiguration {
@Autowired
private Options options;
@Autowired
private ContainerProperties container;
private Connector connector;
@Bean
public ServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
if (this.options.httpsSettings().enabled()) {
tomcat.addAdditionalTomcatConnectors(createStandardConnector());
}
return tomcat;
}
@Bean
public FaultInjectorFactory faultInjectorFactory() {
return new TomcatFaultInjectorFactory();
}
@EventListener
public void serverUp(WebServerInitializedEvent event) {
if (this.connector != null) {
this.container.setLocalPort(this.connector.getLocalPort());
this.container
.setLocalHttpsPort(event.getWebServer().getPort());
}
}
private Connector createStandardConnector() {
Connector connector = new Connector(
"org.apache.coyote.http11.Http11NioProtocol");
connector.setPort(this.options.portNumber());
this.connector = connector;
return connector;
}
}
@Configuration
@ConditionalOnMissingBean(ServletWebServerFactory.class)
@ConditionalOnClass({ UndertowServletWebServerFactory.class, Builder.class })
static class UndertowContainerConfiguration {
@Autowired
private Options options;
@Autowired
private ContainerProperties container;
private Integer port;
@Bean
public ServletWebServerFactory servletContainer() {
UndertowServletWebServerFactory undertow = new UndertowServletWebServerFactory();
if (this.options.httpsSettings().enabled()) {
undertow.addBuilderCustomizers(new UndertowBuilderCustomizer() {
@Override
public void customize(Builder builder) {
builder.addHttpListener(
UndertowContainerConfiguration.this.options.portNumber(),
"localhost");
UndertowContainerConfiguration.this.port = UndertowContainerConfiguration.this.options
.portNumber();
}
});
}
return undertow;
}
@Bean
public FaultInjectorFactory faultInjectorFactory() {
return new NoFaultInjectorFactory();
}
@EventListener
public void serverUp(WebServerInitializedEvent event) {
if (this.port != null) {
// TODO: make it dynamic as well
this.container.setLocalPort(this.port);
this.container
.setLocalHttpsPort(event.getWebServer().getPort());
}
}
}
@Configuration
@ConditionalOnMissingBean(ServletWebServerFactory.class)
@ConditionalOnClass({ JettyServletWebServerFactory.class,
ServerConnector.class })
static class JettyContainerConfiguration {
@Autowired
private ContainerProperties container;
@Autowired
private Options options;
private ServerConnector connector;
@Bean
public ServletWebServerFactory servletContainer() {
final JettyServletWebServerFactory jetty = new JettyServletWebServerFactory();
if (this.options.httpsSettings().enabled()) {
jetty.addServerCustomizers(new JettyServerCustomizer() {
@Override
public void customize(Server server) {
server.addConnector(createStandardConnector(server));
}
});
}
return jetty;
}
@Bean
public JettyFaultInjectorFactory faultInjectorFactory() {
return new JettyFaultInjectorFactory();
}
private org.eclipse.jetty.server.Connector createStandardConnector(
Server server) {
ServerConnector connector = new ServerConnector(server, -1, -1);
connector.setHost("localhost");
connector.setPort(this.options.portNumber());
for (ConnectionFactory connectionFactory : connector
.getConnectionFactories()) {
if (connectionFactory instanceof HttpConfiguration.ConnectionFactory) {
((HttpConfiguration.ConnectionFactory) connectionFactory)
.getHttpConfiguration().setSendServerVersion(false);
}
}
this.connector = connector;
return connector;
}
@EventListener
public void serverUp(WebServerInitializedEvent event) {
if (this.connector != null) {
this.container.setLocalPort(this.connector.getLocalPort());
this.container
.setLocalHttpsPort(event.getWebServer().getPort());
}
}
}
}

View File

@@ -1,95 +0,0 @@
/*
* Copyright 2016-2017 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
*
* http://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.wiremock;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import javax.servlet.http.HttpServletResponse;
import com.github.tomakehurst.wiremock.common.Exceptions;
import com.github.tomakehurst.wiremock.core.FaultInjector;
import com.google.common.base.Charsets;
import org.apache.coyote.Response;
import org.apache.tomcat.util.net.SocketWrapperBase;
import org.springframework.util.ReflectionUtils;
import static com.github.tomakehurst.wiremock.common.Exceptions.throwUnchecked;
/**
* @author Dave Syer
*
*/
public class TomcatFaultInjector implements FaultInjector {
private static final byte[] GARBAGE = "lskdu018973t09sylgasjkfg1][]'./.sdlv"
.getBytes(Charsets.UTF_8);
private final Response response;
private SocketWrapperBase<?> socket;
public TomcatFaultInjector(HttpServletResponse response) {
this.response = ((org.apache.catalina.connector.Response) getField(response,
"response")).getCoyoteResponse();
this.socket = (SocketWrapperBase<?>) getField(
getField(this.response, "outputBuffer"), "socketWrapper");
}
private Object getField(Object target, String string) {
Field field = ReflectionUtils.findField(target.getClass(), string);
ReflectionUtils.makeAccessible(field);
return ReflectionUtils.getField(field, target);
}
@Override
public void emptyResponseAndCloseConnection() {
try {
this.socket.close();
}
catch (IOException e) {
Exceptions.throwUnchecked(e);
}
}
@Override
public void malformedResponseChunk() {
try {
this.response.sendHeaders();
this.response.doWrite(ByteBuffer.wrap(GARBAGE));
this.socket.flush(true);
this.socket.close();
}
catch (IOException e) {
throwUnchecked(e);
}
}
@Override
public void randomDataAndCloseConnection() {
try {
this.socket.write(true, GARBAGE, 0, GARBAGE.length);
this.socket.flush(true);
this.socket.close();
}
catch (IOException e) {
throwUnchecked(e);
}
}
}

View File

@@ -1,37 +0,0 @@
/*
* Copyright 2016-2017 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
*
* http://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.wiremock;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.github.tomakehurst.wiremock.core.FaultInjector;
import com.github.tomakehurst.wiremock.servlet.FaultInjectorFactory;
/**
* @author Dave Syer
*
*/
public class TomcatFaultInjectorFactory implements FaultInjectorFactory {
@Override
public FaultInjector buildFaultInjector(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse) {
return new TomcatFaultInjector(httpServletResponse);
}
}

View File

@@ -67,7 +67,6 @@ public abstract class WireMockSpring {
initialized = true;
}
WireMockConfiguration config = new WireMockConfiguration();
config.httpServerFactory(new SpringBootHttpServerFactory());
return config;
}

View File

@@ -1,8 +1,8 @@
package org.springframework.cloud.contract.wiremock;
import org.eclipse.jetty.http.HttpStatus;
import org.junit.Test;
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;
@@ -21,6 +21,8 @@ import org.springframework.web.bind.annotation.RestController;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import wiremock.org.eclipse.jetty.http.HttpStatus;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestConfiguration.class)
@AutoConfigureRestDocs(outputDir = "target/snippets")

View File

@@ -16,7 +16,7 @@
package com.example.loan;
import com.google.common.collect.ImmutableMap;
import wiremock.com.google.common.collect.ImmutableMap;
import org.junit.Test;
import org.springframework.beans.BeanInstantiationException;