From 5fe510f45e01ee8ec5a63f3cea9d2036e55ae1fa Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Tue, 12 Jul 2016 18:08:24 +0100 Subject: [PATCH] Add Wiremock features (Tomcat only for now) User can depend on spring-cloud-contract-wiremock and spring-cloud-starter-web (or tomcat) to get tomcat to run the wiremock server. The idea is that wiremock runs in the "ambient" server from Sprign Boot. So far we only support Tomcat (should be easy to extend). See tests in spring-cloud-contract-wiremock for details. --- pom.xml | 13 + spring-cloud-contract-dependencies/pom.xml | 130 +++------ spring-cloud-contract-stub-runner/pom.xml | 1 + .../stubrunner/boot/StubRunnerBootSpec.groovy | 9 +- .../README.adoc | 3 + .../pom.xml | 64 +++++ .../src/main/groovy/.empty | 0 .../src/test/groovy/.empty | 0 .../pom.xml | 2 +- .../pom.xml | 19 +- ...tubRunnerSpringCloudAutoConfiguration.java | 6 +- .../pom.xml | 14 +- .../spring/StubRunnerConfiguration.java | 4 +- .../spring/StubRunnerConfigurationSpec.groovy | 1 - .../spring-cloud-contract-stub-runner/pom.xml | 22 +- .../contract/stubrunner/StubServer.groovy | 21 +- spring-cloud-contract-wiremock/pom.xml | 44 +++ .../wiremock/SpringBootHttpServerFactory.java | 250 ++++++++++++++++++ .../wiremock/WireMockConfiguration.java | 89 +++++++ .../wiremock/WireMockExpectations.java | 83 ++++++ .../contract/wiremock/WireMockSpring.java | 74 ++++++ .../cloud/contract/wiremock/WireMockTest.java | 37 +++ .../WiremockHttpsServerApplicationTests.java | 38 +++ .../WiremockImportApplicationTests.java | 33 +++ .../WiremockMockServerApplicationTests.java | 35 +++ .../WiremockServerApplicationTests.java | 38 +++ .../wiremock/WiremockTestsApplication.java | 59 +++++ .../src/test/resources/stubs/resource.json | 10 + 28 files changed, 977 insertions(+), 122 deletions(-) create mode 100644 spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-jetty/README.adoc create mode 100644 spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-jetty/pom.xml create mode 100644 spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-jetty/src/main/groovy/.empty create mode 100644 spring-cloud-contract-stub-runner/spring-cloud-contract-stub-runner-jetty/src/test/groovy/.empty create mode 100644 spring-cloud-contract-wiremock/pom.xml create mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/SpringBootHttpServerFactory.java create mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockConfiguration.java create mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockExpectations.java create mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockSpring.java create mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockTest.java create mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockHttpsServerApplicationTests.java create mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockImportApplicationTests.java create mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockMockServerApplicationTests.java create mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerApplicationTests.java create mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockTestsApplication.java create mode 100644 spring-cloud-contract-wiremock/src/test/resources/stubs/resource.json 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