diff --git a/pom.xml b/pom.xml index b7c82e8ee5..8b8f0f15f4 100644 --- a/pom.xml +++ b/pom.xml @@ -26,11 +26,13 @@ 2.17.0 1.0.2.RELEASE + 4.3.1.BUILD-SNAPSHOT spring-cloud-contract-dependencies docs + spring-cloud-contract-wiremock spring-cloud-contract-verifier spring-cloud-contract-spec spring-cloud-contract-stub-runner @@ -62,6 +64,17 @@ pom import + + org.springframework + spring-core + ${spring-framework.version} + + + commons-logging + commons-logging + + + diff --git a/spring-cloud-contract-dependencies/pom.xml b/spring-cloud-contract-dependencies/pom.xml index 772fe61ca6..f914c6c111 100644 --- a/spring-cloud-contract-dependencies/pom.xml +++ b/spring-cloud-contract-dependencies/pom.xml @@ -19,7 +19,6 @@ 0.4.7 2.17.0 1.1.0 - 9.2.13.v20150730 1.0.2.RELEASE 1.0.3.BUILD-SNAPSHOT 1.1.5.BUILD-SNAPSHOT @@ -27,6 +26,11 @@ + + org.springframework.cloud.contract + spring-cloud-contract-wiremock + ${project.version} + org.springframework.cloud.contract spring-cloud-contract-spec @@ -47,6 +51,11 @@ spring-cloud-contract-stub-runner ${project.version} + + org.springframework.cloud.contract + spring-cloud-contract-stub-runner-jetty + ${project.version} + org.springframework.cloud.contract spring-cloud-contract-stub-runner-spring @@ -81,91 +90,40 @@ com.github.tomakehurst wiremock ${wiremock.version} - - - org.eclipse.jetty - jetty-annotations - ${jetty.version} - - - org.eclipse.jetty - jetty-client - ${jetty.version} - - - org.eclipse.jetty - jetty-continuation - ${jetty.version} - - - org.eclipse.jetty - jetty-deploy - ${jetty.version} - - - org.eclipse.jetty - jetty-http - ${jetty.version} - - - org.eclipse.jetty - jetty-io - ${jetty.version} - - - org.eclipse.jetty - apache-jstl - ${jetty.version} - - - org.eclipse.jetty - apache-jsp - ${jetty.version} - - - org.eclipse.jetty - jetty-jmx - ${jetty.version} - - - org.eclipse.jetty - jetty-plus - ${jetty.version} - - - org.eclipse.jetty - jetty-security - ${jetty.version} - - - org.eclipse.jetty - jetty-server - ${jetty.version} - - - org.eclipse.jetty - jetty-servlet - ${jetty.version} - - - org.eclipse.jetty - jetty-servlets - ${jetty.version} - - - org.eclipse.jetty - jetty-util - ${jetty.version} - - - org.eclipse.jetty - jetty-webapp - ${jetty.version} - - - org.eclipse.jetty - jetty-xml - ${jetty.version} + + + org.mortbay.jetty + jetty + + + org.apache.httpcomponents + httpclient + + + com.jayway.jsonpath + json-path + + + net.sf.jopt-simple + jopt-simple + + + jetty-server + org.eclipse.jetty + + + jetty-servlet + org.eclipse.jetty + + + jetty-servlets + org.eclipse.jetty + + + jetty-webapp + org.eclipse.jetty + + com.toomuchcoding.jsonassert diff --git a/spring-cloud-contract-stub-runner/pom.xml b/spring-cloud-contract-stub-runner/pom.xml index f0aac06979..8de4bb90ff 100644 --- a/spring-cloud-contract-stub-runner/pom.xml +++ b/spring-cloud-contract-stub-runner/pom.xml @@ -19,6 +19,7 @@ spring-cloud-contract-stub-runner + spring-cloud-contract-stub-runner-jetty spring-cloud-contract-stub-runner-junit spring-cloud-contract-stub-runner-spring spring-cloud-contract-stub-runner-boot diff --git a/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-boot/src/test/groovy/org/springframework/cloud/contract/stubrunner/boot/StubRunnerBootSpec.groovy b/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-boot/src/test/groovy/org/springframework/cloud/contract/stubrunner/boot/StubRunnerBootSpec.groovy index 40a2e22f41..5b39f6e657 100644 --- a/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-boot/src/test/groovy/org/springframework/cloud/contract/stubrunner/boot/StubRunnerBootSpec.groovy +++ b/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-boot/src/test/groovy/org/springframework/cloud/contract/stubrunner/boot/StubRunnerBootSpec.groovy @@ -16,21 +16,24 @@ package org.springframework.cloud.contract.stubrunner.boot -import com.jayway.restassured.module.mockmvc.RestAssuredMockMvc import groovy.json.JsonSlurper + import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.SpringApplicationContextLoader +import org.springframework.boot.test.context.SpringBootContextLoader import org.springframework.cloud.contract.stubrunner.StubRunning import org.springframework.cloud.stream.annotation.EnableBinding import org.springframework.context.annotation.Configuration import org.springframework.test.context.ContextConfiguration + import spock.lang.Specification +import com.jayway.restassured.module.mockmvc.RestAssuredMockMvc + /** * @author Marcin Grzejszczak */ // tag::boot_usage[] -@ContextConfiguration(classes = [StubRunnerBootSpec, StubRunnerBoot], loader = SpringApplicationContextLoader) +@ContextConfiguration(classes = [StubRunnerBootSpec, StubRunnerBoot], loader = SpringBootContextLoader) @EnableBinding @Configuration class StubRunnerBootSpec extends Specification { diff --git a/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-jetty/README.adoc b/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-jetty/README.adoc new file mode 100644 index 0000000000..28d6f0e22c --- /dev/null +++ b/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-jetty/README.adoc @@ -0,0 +1,3 @@ +=== Stub Runner Jetty + +Convenience module that pulls together the dependencies needed to run the Stub Runner with wiremock, but without Spring Boot. \ No newline at end of file diff --git a/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-jetty/pom.xml b/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-jetty/pom.xml new file mode 100644 index 0000000000..b72b48685b --- /dev/null +++ b/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-jetty/pom.xml @@ -0,0 +1,64 @@ + + + 4.0.0 + + org.springframework.cloud.contract + spring-cloud-contract-stub-runner-build + 1.0.0.BUILD-SNAPSHOT + .. + + spring-cloud-contract-stub-runner-jetty + jar + spring-cloud-contract-stub-runner-jetty + Spring Cloud Contract Stub Runner + + + org.springframework.cloud.contract + spring-cloud-contract-stub-runner + + + jetty-server + org.eclipse.jetty + + + jetty-servlet + org.eclipse.jetty + + + jetty-servlets + org.eclipse.jetty + + + cglib + cglib + test + + + org.spockframework + spock-core + test + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-web + test + + + + + + org.codehaus.gmavenplus + gmavenplus-plugin + + true + + + + + diff --git a/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-jetty/src/main/groovy/.empty b/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-jetty/src/main/groovy/.empty new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-jetty/src/test/groovy/.empty b/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-jetty/src/test/groovy/.empty new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-junit/pom.xml b/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-junit/pom.xml index 84b7548438..a868438808 100644 --- a/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-junit/pom.xml +++ b/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-junit/pom.xml @@ -15,7 +15,7 @@ org.springframework.cloud.contract - spring-cloud-contract-stub-runner + spring-cloud-contract-stub-runner-jetty junit diff --git a/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-spring-cloud/pom.xml b/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-spring-cloud/pom.xml index 5e4eaf63ff..91316e49f6 100644 --- a/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-spring-cloud/pom.xml +++ b/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-spring-cloud/pom.xml @@ -17,6 +17,10 @@ org.springframework.cloud.contract spring-cloud-contract-stub-runner-boot + + org.springframework.cloud.contract + spring-cloud-contract-wiremock + org.springframework.cloud spring-cloud-starter-ribbon @@ -27,11 +31,6 @@ spring-cloud-starter-zookeeper-discovery true - - org.apache.curator - curator-test - test - org.codehaus.groovy groovy @@ -41,6 +40,16 @@ spock-spring test + + org.apache.curator + curator-test + test + + + org.springframework.boot + spring-boot-starter-web + test + org.springframework.boot spring-boot-starter-test diff --git a/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-spring-cloud/src/main/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerSpringCloudAutoConfiguration.java b/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-spring-cloud/src/main/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerSpringCloudAutoConfiguration.java index 6a5ec3f72d..7c312a6e63 100644 --- a/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-spring-cloud/src/main/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerSpringCloudAutoConfiguration.java +++ b/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-spring-cloud/src/main/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerSpringCloudAutoConfiguration.java @@ -21,15 +21,12 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration; import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.cloud.contract.stubrunner.StubFinder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Primary; -import org.springframework.cloud.contract.stubrunner.StubFinder; - /** * Wraps {@link DiscoveryClient} in a Stub Runner implementation that tries to find * a corresponding WireMock server for a searched dependency @@ -39,7 +36,6 @@ import org.springframework.cloud.contract.stubrunner.StubFinder; @Configuration @EnableConfigurationProperties @ConditionalOnClass(DiscoveryClient.class) -@Import(StubRunnerConfiguration.class) @ConditionalOnProperty(value = "stubrunner.cloud.enabled", matchIfMissing = true) public class StubRunnerSpringCloudAutoConfiguration { diff --git a/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-spring/pom.xml b/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-spring/pom.xml index 382994f61b..40aa26f52e 100644 --- a/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-spring/pom.xml +++ b/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-spring/pom.xml @@ -18,23 +18,23 @@ spring-cloud-contract-stub-runner - org.springframework.boot - spring-boot-starter - test + org.springframework.cloud.contract + spring-cloud-contract-wiremock org.codehaus.groovy groovy - - org.springframework - spring-context - org.spockframework spock-spring test + + org.springframework.boot + spring-boot-starter-web + test + org.springframework.boot spring-boot-starter-test diff --git a/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-spring/src/main/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfiguration.java b/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-spring/src/main/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfiguration.java index bea711f6f1..1626ed7a25 100644 --- a/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-spring/src/main/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfiguration.java +++ b/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-spring/src/main/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfiguration.java @@ -20,6 +20,7 @@ import java.io.IOException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.cloud.contract.stubrunner.AetherStubDownloader; import org.springframework.cloud.contract.stubrunner.BatchStubRunner; import org.springframework.cloud.contract.stubrunner.BatchStubRunnerFactory; @@ -38,6 +39,7 @@ import org.springframework.core.io.Resource; * Configuration that initializes a {@link BatchStubRunner} that runs {@link StubRunner} instance for each stub */ @Configuration +@ConditionalOnMissingBean(type="org.springframework.cloud.contract.wiremock.WiremockServerConfiguration") public class StubRunnerConfiguration { @Autowired(required = false) ContractVerifierMessaging contractVerifierMessaging; @@ -55,7 +57,7 @@ public class StubRunnerConfiguration { * @param workOffline forces offline work * @param stubs comma separated list of stubs presented in Ivy notation */ - @Bean(destroyMethod = "close") + @Bean public StubRunning batchStubRunner( @Value("${stubrunner.port.range.min:10000}") Integer minPortValue, @Value("${stubrunner.port.range.max:15000}") Integer maxPortValue, diff --git a/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-spring/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfigurationSpec.groovy b/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-spring/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfigurationSpec.groovy index 4d9b01856d..c032ffb89a 100644 --- a/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-spring/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfigurationSpec.groovy +++ b/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-spring/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfigurationSpec.groovy @@ -50,7 +50,6 @@ class StubRunnerConfigurationSpec extends Specification { } @Configuration - @Import(StubRunnerConfiguration) @EnableAutoConfiguration static class Config {} } diff --git a/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner/pom.xml b/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner/pom.xml index da4d9af00c..49b1277038 100644 --- a/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner/pom.xml +++ b/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner/pom.xml @@ -17,6 +17,11 @@ org.springframework.cloud.contract spring-cloud-contract-verifier-core + + org.springframework.cloud.contract + spring-cloud-contract-wiremock + true + org.springframework.cloud.contract spring-cloud-contract-verifier-messaging-core @@ -25,18 +30,14 @@ org.springframework.cloud.contract spring-cloud-contract-spec + + org.springframework + spring-core + org.codehaus.groovy groovy - - com.github.tomakehurst - wiremock - - - javax.servlet - javax.servlet-api - args4j args4j @@ -80,6 +81,11 @@ spring-boot-starter-test test + + org.springframework.boot + spring-boot-starter-web + test + diff --git a/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner/src/main/groovy/org/springframework/cloud/contract/stubrunner/StubServer.groovy b/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner/src/main/groovy/org/springframework/cloud/contract/stubrunner/StubServer.groovy index 5ef2d0968d..7c474fec54 100644 --- a/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner/src/main/groovy/org/springframework/cloud/contract/stubrunner/StubServer.groovy +++ b/spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner/src/main/groovy/org/springframework/cloud/contract/stubrunner/StubServer.groovy @@ -16,13 +16,17 @@ package org.springframework.cloud.contract.stubrunner -import com.github.tomakehurst.wiremock.WireMockServer -import com.github.tomakehurst.wiremock.client.WireMock -import com.github.tomakehurst.wiremock.core.WireMockConfiguration import groovy.transform.CompileStatic import groovy.transform.PackageScope import groovy.util.logging.Slf4j + import org.springframework.cloud.contract.spec.Contract +import org.springframework.cloud.contract.wiremock.WireMockSpring +import org.springframework.util.ClassUtils + +import com.github.tomakehurst.wiremock.WireMockServer +import com.github.tomakehurst.wiremock.client.WireMock +import com.github.tomakehurst.wiremock.core.WireMockConfiguration @CompileStatic @Slf4j @@ -34,13 +38,20 @@ class StubServer { final Collection contracts StubServer(int port, StubConfiguration stubConfiguration, Collection mappings, - Collection contracts) { + Collection contracts) { this.stubConfiguration = stubConfiguration this.mappings = mappings - this.wireMockServer = new WireMockServer(WireMockConfiguration.wireMockConfig().port(port)) + this.wireMockServer = new WireMockServer(config().port(port)) this.contracts = contracts } + private WireMockConfiguration config() { + if (ClassUtils.isPresent('org.springframework.cloud.contract.wiremock.WireMockSpring', null)) { + return WireMockSpring.config() + } + return new WireMockConfiguration() + } + StubServer start() { wireMockServer.start() log.info("Started stub server for project ${stubConfiguration.toColonSeparatedDependencyNotation()} on port ${wireMockServer.port()}") diff --git a/spring-cloud-contract-wiremock/pom.xml b/spring-cloud-contract-wiremock/pom.xml new file mode 100644 index 0000000000..b365d4608b --- /dev/null +++ b/spring-cloud-contract-wiremock/pom.xml @@ -0,0 +1,44 @@ + + + 4.0.0 + + org.springframework.cloud.contract + spring-cloud-contract-parent + 1.0.0.BUILD-SNAPSHOT + .. + + spring-cloud-contract-wiremock + jar + spring-cloud-contract-wiremock + Spring Cloud Contract Wiremock + + + com.github.tomakehurst + wiremock + + + org.apache.httpcomponents + httpclient + true + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-tomcat + true + + + org.springframework + spring-web + + + org.springframework.boot + spring-boot-starter-test + true + + + diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/SpringBootHttpServerFactory.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/SpringBootHttpServerFactory.java new file mode 100644 index 0000000000..88cf0366d6 --- /dev/null +++ b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/SpringBootHttpServerFactory.java @@ -0,0 +1,250 @@ +/* + * 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 org.apache.catalina.connector.Connector; +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.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration; +import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; +import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration; +import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration.BeanPostProcessorsRegistrar; +import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration; +import org.springframework.boot.autoconfigure.web.ServerProperties; +import org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory; +import org.springframework.boot.context.embedded.Ssl; +import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; +import org.springframework.boot.context.event.ApplicationPreparedEvent; +import org.springframework.boot.web.servlet.ServletRegistrationBean; +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.support.GenericApplicationContext; +import org.springframework.web.context.ServletContextAware; + +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.WireMockHandlerDispatchingServlet; + +/** + * @author Dave Syer + * + */ +public 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 { + + 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).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 this.options.portNumber(); + } + + @Override + public int httpsPort() { + return this.options.httpsSettings().port(); + } + + @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 ServerProperties) { + ServerProperties server = (ServerProperties) bean; + server.setPort(getPort()); + setupHttps(server, SpringBootHttpServer.this.options.httpsSettings()); + // TODO: other options + } + return bean; + } + + private void setupHttps(ServerProperties 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(); + } + + } + +} + +@Configuration +@Import({ ServerPropertiesAutoConfiguration.class, BeanPostProcessorsRegistrar.class, + ConfigurationPropertiesAutoConfiguration.class, JacksonAutoConfiguration.class, + HttpMessageConvertersAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class }) +class WiremockServerConfiguration { + + @Autowired + private AdminRequestHandler adminRequestHandler; + @Autowired + private StubRequestHandler stubRequestHandler; + @Autowired + private Options options; + + @Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME) + public ServletRegistrationBean stubServletRegistration() { + ServletRegistrationBean reg = new ServletRegistrationBean(); + reg.addInitParameter(RequestHandler.HANDLER_CLASS_KEY, + StubRequestHandler.class.getName()); + reg.setServlet(new WireMockHandlerDispatchingServlet()); + reg.setName("stub"); + reg.addUrlMappings("/"); + return reg; + } + + @Bean + public ServletRegistrationBean adminServletRegistration() { + ServletRegistrationBean 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, options.notifier()); + } + }; + } + + @Bean + public EmbeddedServletContainerFactory servletContainer() { + // TODO support for other containers + TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory(); + if (this.options.httpsSettings().enabled()) { + tomcat.addAdditionalTomcatConnectors(createStandardConnector()); + } + return tomcat; + } + + private Connector createStandardConnector() { + Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol"); + connector.setPort(this.options.portNumber()); + return connector; + } + +} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockConfiguration.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockConfiguration.java new file mode 100644 index 0000000000..9f3338de0b --- /dev/null +++ b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockConfiguration.java @@ -0,0 +1,89 @@ +/* + * Copyright 2012-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.annotation.PostConstruct; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.SmartLifecycle; +import org.springframework.context.annotation.Configuration; + +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.core.Options; + +/** + * @author Dave Syer + * + */ +@Configuration +public class WireMockConfiguration implements SmartLifecycle { + + private volatile boolean running; + + private WireMockServer server; + + @Autowired(required = false) + private Options options; + + @PostConstruct + public void init() { + if (options == null) { + this.options = com.github.tomakehurst.wiremock.core.WireMockConfiguration + .wireMockConfig() + .httpServerFactory(new SpringBootHttpServerFactory()); + } + server = new WireMockServer(options); + } + + @Override + public void start() { + server.start(); + WireMock.configureFor("localhost", options.portNumber()); + running = true; + } + + @Override + public void stop() { + if (running) { + server.stop(); + running = false; + } + } + + @Override + public boolean isRunning() { + return running; + } + + @Override + public int getPhase() { + return 0; + } + + @Override + public boolean isAutoStartup() { + return true; + } + + @Override + public void stop(Runnable callback) { + stop(); + callback.run(); + } + +} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockExpectations.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockExpectations.java new file mode 100644 index 0000000000..007f053b77 --- /dev/null +++ b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockExpectations.java @@ -0,0 +1,83 @@ +/* + * 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 static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; + +import java.io.IOException; +import java.nio.charset.Charset; + +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.http.MediaType; +import org.springframework.test.web.client.MockRestServiceServer; +import org.springframework.util.StreamUtils; +import org.springframework.web.client.RestTemplate; + +import com.github.tomakehurst.wiremock.common.Json; +import com.github.tomakehurst.wiremock.stubbing.StubMapping; + +/** + * @author Dave Syer + * + */ +public class WireMockExpectations { + + private PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + + private String prefix = "classpath:/stubs/"; + + private String suffix = ".json"; + + private String baseUrl = ""; + + private MockRestServiceServer server; + + private WireMockExpectations(RestTemplate restTemplate) { + this.server = MockRestServiceServer.bindTo(restTemplate).build(); + } + + public WireMockExpectations baseUrl(String baseUrl) { + this.baseUrl = baseUrl; + return this; + } + + public MockRestServiceServer expect(String... locations) { + for (String location : locations) { + try { + for (Resource resource : this.resolver.getResources(this.prefix + location + this.suffix)) { + StubMapping mapping; + mapping = Json.read(StreamUtils.copyToString(resource.getInputStream(), Charset.defaultCharset()), + StubMapping.class); + this.server.expect(requestTo(this.baseUrl + mapping.getRequest().getUrlPath())) + .andRespond(withSuccess(mapping.getResponse().getBody(), MediaType.TEXT_PLAIN)); + } + } + catch (IOException e) { + throw new IllegalStateException("Cannot load resources for: " + location, e); + } + } + return this.server; + } + + public static WireMockExpectations with(RestTemplate restTemplate) { + WireMockExpectations result = new WireMockExpectations(restTemplate); + return result; + } + +} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockSpring.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockSpring.java new file mode 100644 index 0000000000..25737e3219 --- /dev/null +++ b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockSpring.java @@ -0,0 +1,74 @@ +/* + * 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.net.ssl.HttpsURLConnection; + +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.TrustSelfSignedStrategy; +import org.apache.http.ssl.SSLContexts; +import org.junit.Assert; +import org.springframework.util.ClassUtils; + +import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.core.WireMockConfiguration; + +/** + * Convenience factory class for a {@link WireMockConfiguration} that knows how to use + * Spring Boot to create a stub server. Use, for example, in a JUnit rule: + * + *
+ * @ClassRule
+ * public static WireMockClassRule wiremock = new WireMockClassRule(
+ * 		WireMockSpring.config());
+ * 
+ * + * and then use {@link WireMock} as normal in your test methods. + * + * @author Dave Syer + * + */ +public abstract class WireMockSpring { + + private static boolean initialized = false; + + public static WireMockConfiguration config() { + if (!initialized) { + if (ClassUtils.isPresent("org.apache.http.conn.ssl.NoopHostnameVerifier", + null)) { + HttpsURLConnection + .setDefaultHostnameVerifier(NoopHostnameVerifier.INSTANCE); + try { + HttpsURLConnection + .setDefaultSSLSocketFactory(SSLContexts.custom() + .loadTrustMaterial(null, + TrustSelfSignedStrategy.INSTANCE) + .build().getSocketFactory()); + } + catch (Exception e) { + Assert.fail("Cannot install custom socket factory: [" + e.getMessage() + + "]"); + } + } + initialized = true; + } + WireMockConfiguration config = new WireMockConfiguration(); + config.httpServerFactory(new SpringBootHttpServerFactory()); + return config; + } + +} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockTest.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockTest.java new file mode 100644 index 0000000000..ce94990abe --- /dev/null +++ b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockTest.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012-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 java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.context.annotation.Import; + +/** + * @author Dave Syer + * + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Import(WireMockConfiguration.class) +public @interface WireMockTest { + +} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockHttpsServerApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockHttpsServerApplicationTests.java new file mode 100644 index 0000000000..2fe7a7a2b8 --- /dev/null +++ b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockHttpsServerApplicationTests.java @@ -0,0 +1,38 @@ +package org.springframework.cloud.contract.wiremock; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringRunner; + +import com.github.tomakehurst.wiremock.junit.WireMockClassRule; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes=WiremockTestsApplication.class, properties="app.baseUrl=https://localhost:8443") +@DirtiesContext +public class WiremockHttpsServerApplicationTests { + + @ClassRule + public static WireMockClassRule wiremock = new WireMockClassRule( + WireMockSpring.config().httpsPort(8443)); + + @Autowired + private Service service; + + @Test + public void contextLoads() throws Exception { + stubFor(get(urlEqualTo("/resource")) + .willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!"))); + assertThat(this.service.go()).isEqualTo("Hello World!"); + } + +} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockImportApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockImportApplicationTests.java new file mode 100644 index 0000000000..d52bdc81f1 --- /dev/null +++ b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockImportApplicationTests.java @@ -0,0 +1,33 @@ +package org.springframework.cloud.contract.wiremock; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes=WiremockTestsApplication.class, properties="app.baseUrl=http://localhost:8080", webEnvironment=WebEnvironment.NONE) +@DirtiesContext +@WireMockTest +public class WiremockImportApplicationTests { + + @Autowired + private Service service; + + @Test + public void contextLoads() throws Exception { + stubFor(get(urlEqualTo("/resource")) + .willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!"))); + assertThat(this.service.go()).isEqualTo("Hello World!"); + } + +} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockMockServerApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockMockServerApplicationTests.java new file mode 100644 index 0000000000..d22632d07c --- /dev/null +++ b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockMockServerApplicationTests.java @@ -0,0 +1,35 @@ +package org.springframework.cloud.contract.wiremock; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.client.MockRestServiceServer; +import org.springframework.web.client.RestTemplate; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes=WiremockTestsApplication.class, webEnvironment=WebEnvironment.NONE) +@DirtiesContext +public class WiremockMockServerApplicationTests { + + @Autowired + private RestTemplate restTemplate; + + @Autowired + private Service service; + + @Test + public void contextLoads() throws Exception { + MockRestServiceServer server = WireMockExpectations.with(this.restTemplate) // + .baseUrl("http://example.org") // + .expect("resource"); + assertThat(this.service.go()).isEqualTo("Hello World"); + server.verify(); + } + +} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerApplicationTests.java new file mode 100644 index 0000000000..7275fd9869 --- /dev/null +++ b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerApplicationTests.java @@ -0,0 +1,38 @@ +package org.springframework.cloud.contract.wiremock; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringRunner; + +import com.github.tomakehurst.wiremock.junit.WireMockClassRule; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes=WiremockTestsApplication.class, properties="app.baseUrl=http://localhost:8080", webEnvironment=WebEnvironment.NONE) +@DirtiesContext +public class WiremockServerApplicationTests { + + @ClassRule + public static WireMockClassRule wiremock = new WireMockClassRule(WireMockSpring.config()); + + @Autowired + private Service service; + + @Test + public void contextLoads() throws Exception { + stubFor(get(urlEqualTo("/resource")) + .willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!"))); + assertThat(this.service.go()).isEqualTo("Hello World!"); + } + +} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockTestsApplication.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockTestsApplication.java new file mode 100644 index 0000000000..a5d0a82167 --- /dev/null +++ b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockTestsApplication.java @@ -0,0 +1,59 @@ +package org.springframework.cloud.contract.wiremock; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +@Configuration +@EnableAutoConfiguration +@Import({Service.class, Controller.class}) +public class WiremockTestsApplication { + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } + + public static void main(String[] args) { + SpringApplication.run(WiremockTestsApplication.class, args); + } +} + +@RestController +class Controller { + + private final Service service; + + public Controller(Service service) { + this.service = service; + } + + @RequestMapping("/") + public String home() { + return this.service.go(); + } +} + +@Component +class Service { + + @Value("${app.baseUrl:http://example.org}") + private String base; + + private RestTemplate restTemplate; + + public Service(RestTemplate restTemplate) { + this.restTemplate = restTemplate; + } + + public String go() { + return this.restTemplate.getForEntity(this.base + "/resource", String.class).getBody(); + } +} diff --git a/spring-cloud-contract-wiremock/src/test/resources/stubs/resource.json b/spring-cloud-contract-wiremock/src/test/resources/stubs/resource.json new file mode 100644 index 0000000000..41a9d4e920 --- /dev/null +++ b/spring-cloud-contract-wiremock/src/test/resources/stubs/resource.json @@ -0,0 +1,10 @@ +{ + "request" : { + "urlPath" : "/resource", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "Hello World" + } +} \ No newline at end of file