From 58f3f429eb40ef7a9c221914fd146f95360805ae Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Mon, 27 Aug 2018 18:33:10 +0200 Subject: [PATCH] Upgraded to Greenwhich --- docker/spring-cloud-contract-docker/pom.xml | 2 +- pom.xml | 42 ++- samples/wiremock-jetty/pom.xml | 2 +- samples/wiremock-native/pom.xml | 2 +- samples/wiremock-tomcat/pom.xml | 2 +- samples/wiremock-undertow-ssl/pom.xml | 2 +- samples/wiremock-undertow/pom.xml | 2 +- .../cloud/contract/spec/internal/Url.groovy | 2 +- .../server/EnableStubRunnerServer.java | 2 +- .../server/StreamConfiguration.java | 29 -- .../stubrunner/server/StubRunnerBoot.java | 3 + .../main/resources/META-INF/spring.factories | 1 - .../StubRunnerStubsPerConsumerSpec.groovy | 3 +- ...tubsPerConsumerWithConsumerNameSpec.groovy | 3 +- .../build.gradle | 2 +- .../functionalTest/bootSimple/build.gradle | 4 +- .../sampleJerseyProject/build.gradle | 8 +- .../functionalTest/sampleProject/build.gradle | 8 +- .../scenarioProject/build.gradle | 8 +- .../TestSideRequestTemplateModel.groovy | 18 +- .../verifier/file/ContractFileScanner.groovy | 10 +- .../restdocs/ContractResultHandler.java | 327 +++++++++++++++++- .../restdocs/WireMockVerifyHelper.java | 4 +- ...ServerRestDocsMatcherApplicationTests.java | 2 +- 24 files changed, 404 insertions(+), 84 deletions(-) delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/StreamConfiguration.java diff --git a/docker/spring-cloud-contract-docker/pom.xml b/docker/spring-cloud-contract-docker/pom.xml index 4c958eb3bb..06db33b9d1 100644 --- a/docker/spring-cloud-contract-docker/pom.xml +++ b/docker/spring-cloud-contract-docker/pom.xml @@ -20,7 +20,7 @@ org.codehaus.groovy - groovy-all + groovy compile diff --git a/pom.xml b/pom.xml index 0640634c13..9ad5a9e448 100644 --- a/pom.xml +++ b/pom.xml @@ -26,17 +26,17 @@ 2.17 3.5.13 0.0.9 - 2.0.4.BUILD-SNAPSHOT - 2.0.0.BUILD-SNAPSHOT - Elmhurst.BUILD-SNAPSHOT - 2.0.0.BUILD-SNAPSHOT - 2.0.0.BUILD-SNAPSHOT - 2.0.0.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT + Fishtown.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT 5.0.3 3.2.4 1.0-groovy-2.4 0.5.1 - 2.0.0.RELEASE + 2.1.0.M2 0.2.2 1.1 4.0.6 @@ -83,11 +83,31 @@ org.spockframework spock-spring ${spock-spring.version} + + + org.codehaus.groovy + groovy-all + + + org.codehaus.groovy + groovy + + org.spockframework spock-core ${spock-spring.version} + + + org.codehaus.groovy + groovy-all + + + org.codehaus.groovy + groovy + + info.solidsoft.spock @@ -118,6 +138,10 @@ org.codehaus.groovy groovy-all + + org.codehaus.groovy + groovy + @@ -129,6 +153,10 @@ org.codehaus.groovy groovy-all + + org.codehaus.groovy + groovy + diff --git a/samples/wiremock-jetty/pom.xml b/samples/wiremock-jetty/pom.xml index a974ca7a58..11ac98b3be 100644 --- a/samples/wiremock-jetty/pom.xml +++ b/samples/wiremock-jetty/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.3.RELEASE + 2.1.0.M1 diff --git a/samples/wiremock-native/pom.xml b/samples/wiremock-native/pom.xml index a2de7fa4e6..caab291dcf 100644 --- a/samples/wiremock-native/pom.xml +++ b/samples/wiremock-native/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.3.RELEASE + 2.1.0.M1 diff --git a/samples/wiremock-tomcat/pom.xml b/samples/wiremock-tomcat/pom.xml index 5e80b32c10..bbbba762b9 100644 --- a/samples/wiremock-tomcat/pom.xml +++ b/samples/wiremock-tomcat/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.3.RELEASE + 2.1.0.M1 diff --git a/samples/wiremock-undertow-ssl/pom.xml b/samples/wiremock-undertow-ssl/pom.xml index c2a2e1152c..c7871b2402 100644 --- a/samples/wiremock-undertow-ssl/pom.xml +++ b/samples/wiremock-undertow-ssl/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.3.RELEASE + 2.1.0.M1 diff --git a/samples/wiremock-undertow/pom.xml b/samples/wiremock-undertow/pom.xml index f69418867c..b801ff7b97 100644 --- a/samples/wiremock-undertow/pom.xml +++ b/samples/wiremock-undertow/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.3.RELEASE + 2.1.0.M1 diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Url.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Url.groovy index be464280a2..d28d952aa7 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Url.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Url.groovy @@ -58,7 +58,7 @@ class Url extends DslProperty { url.values.collect { it instanceof Pattern ? new Xeger(it.pattern()).generate() : it } as String[], - url.strings.clone() as String[] + Arrays.copyOf(url.strings, url.strings.length) as String[] ).toString() return new Url(newUrl) } diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/EnableStubRunnerServer.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/EnableStubRunnerServer.java index fc7713d8f3..c50223e419 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/EnableStubRunnerServer.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/EnableStubRunnerServer.java @@ -34,7 +34,7 @@ import org.springframework.context.annotation.Import; @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited -@Import({HttpStubsController.class, TriggerController.class, StreamConfiguration.class, StubRunnerConfiguration.class}) +@Import({HttpStubsController.class, TriggerController.class, StubRunnerConfiguration.class}) public @interface EnableStubRunnerServer { } diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/StreamConfiguration.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/StreamConfiguration.java deleted file mode 100644 index 3d337159c4..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/StreamConfiguration.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.springframework.cloud.contract.stubrunner.server; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.cloud.stream.test.binder.MessageCollector; -import org.springframework.cloud.stream.test.binder.TestSupportBinder; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Primary; - -/** - * Configuration required to make Stub Runner server be executed at compile time - * - * @author Marcin Grzejszczak - * - * @since 1.0.0 - */ -@Configuration -class StreamConfiguration { - - @Bean - @Primary - @ConditionalOnClass(name = "org.springframework.cloud.stream.test.binder.TestSupportBinder") - @ConditionalOnMissingBean - public MessageCollector messageCollector() { - return new TestSupportBinder().messageCollector(); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/StubRunnerBoot.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/StubRunnerBoot.java index d68dd87906..a250d2de6c 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/StubRunnerBoot.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/StubRunnerBoot.java @@ -17,13 +17,16 @@ package org.springframework.cloud.contract.stubrunner.server; import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.stream.config.BindingServiceConfiguration; /** * @author Marcin Grzejszczak */ @SpringBootApplication @EnableStubRunnerServer +@AutoConfigureBefore(BindingServiceConfiguration.class) public class StubRunnerBoot { public static void main(String[] args) { diff --git a/spring-cloud-contract-stub-runner/src/main/resources/META-INF/spring.factories b/spring-cloud-contract-stub-runner/src/main/resources/META-INF/spring.factories index a6042d7383..1556b08c2f 100644 --- a/spring-cloud-contract-stub-runner/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-contract-stub-runner/src/main/resources/META-INF/spring.factories @@ -3,7 +3,6 @@ org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner=\ org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration,\ org.springframework.cloud.contract.stubrunner.spring.cloud.StubRunnerSpringCloudAutoConfiguration,\ org.springframework.cloud.contract.stubrunner.spring.cloud.ribbon.StubRunnerRibbonAutoConfiguration,\ -org.springframework.cloud.contract.stubrunner.messaging.stream.StubRunnerStreamConfiguration,\ org.springframework.cloud.contract.stubrunner.messaging.integration.StubRunnerIntegrationConfiguration,\ org.springframework.cloud.contract.stubrunner.spring.cloud.zookeeper.StubRunnerSpringCloudZookeeperAutoConfiguration,\ org.springframework.cloud.contract.stubrunner.spring.cloud.eureka.StubRunnerSpringCloudEurekaAutoConfiguration,\ diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerStubsPerConsumerSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerStubsPerConsumerSpec.groovy index eba68535f0..21ca1a3efb 100644 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerStubsPerConsumerSpec.groovy +++ b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerStubsPerConsumerSpec.groovy @@ -29,6 +29,7 @@ import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties import org.springframework.cloud.contract.verifier.messaging.MessageVerifier import org.springframework.cloud.stream.annotation.EnableBinding import org.springframework.cloud.stream.messaging.Sink +import org.springframework.cloud.stream.messaging.Source import org.springframework.context.annotation.Configuration import org.springframework.core.env.Environment import org.springframework.http.ResponseEntity @@ -86,6 +87,6 @@ class StubRunnerStubsPerConsumerSpec extends Specification { @Configuration @EnableAutoConfiguration - @EnableBinding(Sink) + @EnableBinding([Sink, Source]) static class Config {} } \ No newline at end of file diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerStubsPerConsumerWithConsumerNameSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerStubsPerConsumerWithConsumerNameSpec.groovy index 1e3ed7fed1..e9b9c47604 100644 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerStubsPerConsumerWithConsumerNameSpec.groovy +++ b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerStubsPerConsumerWithConsumerNameSpec.groovy @@ -29,6 +29,7 @@ import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties import org.springframework.cloud.contract.verifier.messaging.MessageVerifier import org.springframework.cloud.stream.annotation.EnableBinding import org.springframework.cloud.stream.messaging.Sink +import org.springframework.cloud.stream.messaging.Source import org.springframework.context.annotation.Configuration import org.springframework.core.env.Environment import org.springframework.http.ResponseEntity @@ -87,6 +88,6 @@ class StubRunnerStubsPerConsumerWithConsumerNameSpec extends Specification { @Configuration @EnableAutoConfiguration - @EnableBinding(Sink) + @EnableBinding([Sink, Source]) static class Config {} } \ No newline at end of file diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/build.gradle b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/build.gradle index d289534e48..2d843a0ecc 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/build.gradle +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/build.gradle @@ -23,7 +23,7 @@ ext { ] } -project.version = findProperty('verifierVersion') ?: '2.0.0.BUILD-SNAPSHOT' +project.version = findProperty('verifierVersion') ?: '2.1.0.BUILD-SNAPSHOT' apply plugin: 'groovy' apply from: "$rootDir/gradle/release.gradle" apply plugin: 'eclipse' diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/build.gradle b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/build.gradle index 2495415709..401ee34d3c 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/build.gradle +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/build.gradle @@ -36,7 +36,9 @@ dependencies { testCompile "com.github.tomakehurst:wiremock:${wiremockVersion}" testCompile "com.toomuchcoding.jsonassert:jsonassert:${jsonAssertVersion}" - testCompile "org.spockframework:spock-spring:1.0-groovy-2.4" + testCompile("org.spockframework:spock-spring:1.0-groovy-2.4") { + exclude(group: 'org.codehaus.groovy') + } testCompile "io.restassured:rest-assured:$restAssuredVersion" testCompile "io.restassured:spring-mock-mvc:$restAssuredVersion" testCompile "ch.qos.logback:logback-classic:1.1.2" diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/build.gradle b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/build.gradle index 3f1c06b451..de113ce1f2 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/build.gradle +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/build.gradle @@ -52,7 +52,9 @@ subprojects { dependencies { testCompile 'org.codehaus.groovy:groovy-all:2.5.0-beta-1' - testCompile "org.spockframework:spock-core:$spockVersion" + testCompile("org.spockframework:spock-core:$spockVersion") { + exclude(group: 'org.codehaus.groovy') + } testCompile 'junit:junit:4.12' testCompile "com.github.tomakehurst:wiremock:${wiremockVersion}" testCompile "com.toomuchcoding.jsonassert:jsonassert:${jsonAssertVersion}" @@ -81,7 +83,9 @@ configure([project(':fraudDetectionService'), project(':loanApplicationService') compile 'org.springframework.boot:spring-boot-starter-jersey' compile 'org.springframework.boot:spring-boot-starter-jetty' - testRuntime "org.spockframework:spock-spring:$spockVersion" + testRuntime("org.spockframework:spock-spring:$spockVersion") { + exclude(group: 'org.codehaus.groovy') + } testCompile "org.mockito:mockito-core" testCompile "org.springframework:spring-test" diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/sampleProject/build.gradle b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/sampleProject/build.gradle index 62f4407ffe..497a687518 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/sampleProject/build.gradle +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/sampleProject/build.gradle @@ -48,7 +48,9 @@ subprojects { } dependencies { - testCompile "org.codehaus.groovy:groovy-all:2.5.0-beta-1" + testCompile("org.codehaus.groovy:groovy-all:2.5.0-beta-1") { + exclude(group: 'org.codehaus.groovy') + } testCompile "org.spockframework:spock-core:$spockVersion" testCompile("junit:junit:4.12") testCompile "com.github.tomakehurst:wiremock:${wiremockVersion}" @@ -89,7 +91,9 @@ configure([project(':fraudDetectionService'), project(':loanApplicationService') compile("org.springframework.boot:spring-boot-starter-jetty") compile("org.springframework.boot:spring-boot-starter-actuator") - testRuntime "org.spockframework:spock-spring:$spockVersion" + testRuntime("org.spockframework:spock-spring:$spockVersion") { + exclude(group: 'org.codehaus.groovy') + } testCompile "org.mockito:mockito-core" testCompile "org.springframework:spring-test" testCompile "org.springframework.boot:spring-boot-test" diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/build.gradle b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/build.gradle index f54d7b18b0..52611a7a90 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/build.gradle +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/build.gradle @@ -50,7 +50,9 @@ subprojects { dependencies { testCompile "org.codehaus.groovy:groovy-all:2.5.0-beta-1" - testCompile "org.spockframework:spock-core:$spockVersion" + testCompile("org.spockframework:spock-core:$spockVersion") { + exclude(group: 'org.codehaus.groovy') + } testCompile "junit:junit:4.12" testCompile "com.github.tomakehurst:wiremock:${wiremockVersion}" testCompile "com.toomuchcoding.jsonassert:jsonassert:${jsonAssertVersion}" @@ -113,7 +115,9 @@ configure([project(':fraudDetectionService'), project(':loanApplicationService') compile("org.springframework.boot:spring-boot-starter-jetty") compile("org.springframework.boot:spring-boot-starter-actuator") - testRuntime "org.spockframework:spock-spring:$spockVersion" + testRuntime("org.spockframework:spock-spring:$spockVersion") { + exclude(group: 'org.codehaus.groovy') + } testCompile "org.mockito:mockito-core" testCompile "org.springframework:spring-test" testCompile "org.springframework.boot:spring-boot-test" diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/TestSideRequestTemplateModel.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/TestSideRequestTemplateModel.groovy index 841d97d243..e66bff6ecd 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/TestSideRequestTemplateModel.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/TestSideRequestTemplateModel.groovy @@ -17,7 +17,6 @@ import org.springframework.cloud.contract.verifier.util.MapConverter * @author Marcin Grzejszczak * @since 1.1.0 */ -@Immutable @CompileStatic class TestSideRequestTemplateModel { /** @@ -50,6 +49,15 @@ class TestSideRequestTemplateModel { */ final String escapedBody + private TestSideRequestTemplateModel(String url, Map> query, Path path, Map> headers, String body, String escapedBody) { + this.url = url + this.query = query + this.path = path + this.headers = headers + this.body = body + this.escapedBody = escapedBody + } + static TestSideRequestTemplateModel from(final Request request) { String url = MapConverter.getTestSideValues(request.url ?: request.urlPath) Path paths = new Path(buildPathsFromUrl(url)) @@ -63,7 +71,11 @@ class TestSideRequestTemplateModel { Map> headers = (Map>) (request.headers?.entries?.groupBy { it.name }?.collectEntries { - [(it.key): it.value.collect { MapConverter.getTestSideValues(it) }] + List headerValues = [] + for (Object value : it.value) { + headerValues.add(MapConverter.getTestSideValues(value)) + } + [(it.key): headerValues] }) String escapedBody = trimmedAndEscapedBody(request.body) String body = getBodyAsRawJson(request.body) @@ -94,7 +106,7 @@ class TestSideRequestTemplateModel { protected static Object extractServerValueFromBody(bodyValue) { if (bodyValue instanceof GString) { - bodyValue = ContentUtils.extractValue(bodyValue, { DslProperty dslProperty -> dslProperty.serverValue }) + bodyValue = ContentUtils.extractValue(bodyValue, { DslProperty dslProperty -> dslProperty.serverValue } as Closure) } else { bodyValue = MapConverter.transformValues(bodyValue, { it instanceof DslProperty ? it.serverValue : it diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/file/ContractFileScanner.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/file/ContractFileScanner.groovy index aab6ebeb06..2ebd11a740 100755 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/file/ContractFileScanner.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/file/ContractFileScanner.groovy @@ -68,14 +68,16 @@ class ContractFileScanner { private Set processPatterns(Set patterns) { FileSystem fileSystem = FileSystems.getDefault() - return patterns.collect({ - String syntaxAndPattern = MATCH_PREFIX + '**' + File.separator + it + Set pathMatchers = new HashSet() + for (String pattern : patterns) { + String syntaxAndPattern = MATCH_PREFIX + '**' + File.separator + pattern // FIXME: This looks strange, need to be checked on windows if (IS_OS_WINDOWS) { syntaxAndPattern = syntaxAndPattern.replace("\\", "\\\\") } - fileSystem.getPathMatcher(syntaxAndPattern) - }) as Set + pathMatchers.add(fileSystem.getPathMatcher(syntaxAndPattern)) + } + return pathMatchers } /** diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/ContractResultHandler.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/ContractResultHandler.java index db1f8cbb4b..d161a7abd4 100644 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/ContractResultHandler.java +++ b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/ContractResultHandler.java @@ -16,35 +16,73 @@ package org.springframework.cloud.contract.wiremock.restdocs; +import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStream; import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; +import java.util.Set; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; +import com.github.tomakehurst.wiremock.common.Gzip; +import com.github.tomakehurst.wiremock.http.ContentTypeHeader; +import com.github.tomakehurst.wiremock.http.Cookie; +import com.github.tomakehurst.wiremock.http.HttpHeader; +import com.github.tomakehurst.wiremock.http.HttpHeaders; +import com.github.tomakehurst.wiremock.http.QueryParameter; import com.github.tomakehurst.wiremock.http.Request; -import com.github.tomakehurst.wiremock.servlet.WireMockHttpServletRequestAdapter; - +import com.github.tomakehurst.wiremock.http.RequestMethod; +import com.github.tomakehurst.wiremock.servlet.WireMockHttpServletMultipartAdapter; import org.springframework.http.MediaType; +import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation; import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.ResultHandler; import org.springframework.util.StreamUtils; +import wiremock.com.google.common.base.Function; +import wiremock.com.google.common.base.Joiner; +import wiremock.com.google.common.base.Optional; +import wiremock.com.google.common.collect.FluentIterable; +import wiremock.com.google.common.collect.ImmutableList; +import wiremock.com.google.common.collect.ImmutableMultimap; +import wiremock.com.google.common.collect.Maps; +import wiremock.org.eclipse.jetty.util.MultiPartInputStreamParser; -public class ContractResultHandler extends - WireMockVerifyHelper implements ResultHandler { +import static com.github.tomakehurst.wiremock.common.Encoding.encodeBase64; +import static com.github.tomakehurst.wiremock.common.Exceptions.throwUnchecked; +import static com.github.tomakehurst.wiremock.common.Strings.stringFromBytes; +import static com.github.tomakehurst.wiremock.common.Urls.splitQuery; +import static java.util.Collections.list; +import static wiremock.com.google.common.base.Charsets.UTF_8; +import static wiremock.com.google.common.base.MoreObjects.firstNonNull; +import static wiremock.com.google.common.base.Strings.isNullOrEmpty; +import static wiremock.com.google.common.collect.FluentIterable.from; +import static wiremock.com.google.common.collect.Lists.newArrayList; +import static wiremock.com.google.common.io.ByteStreams.toByteArray; + +public class ContractResultHandler + extends WireMockVerifyHelper + implements ResultHandler { static final String ATTRIBUTE_NAME_CONFIGURATION = "org.springframework.restdocs.configuration"; - @Override - public void handle(MvcResult result) throws Exception { + @Override public void handle(MvcResult result) throws Exception { configure(result); MockMvcRestDocumentation.document(getName()).handle(result); } - @Override - protected ResponseDefinitionBuilder getResponseDefinition(MvcResult result) { + @Override protected ResponseDefinitionBuilder getResponseDefinition( + MvcResult result) { MockHttpServletResponse response = result.getResponse(); ResponseDefinitionBuilder definition; try { @@ -66,11 +104,9 @@ public class ContractResultHandler extends } } - @Override - protected Map getConfiguration(MvcResult result) { - @SuppressWarnings("unchecked") - Map map = (Map) result.getRequest() - .getAttribute(ATTRIBUTE_NAME_CONFIGURATION); + @Override protected Map getConfiguration(MvcResult result) { + @SuppressWarnings("unchecked") Map map = (Map) result + .getRequest().getAttribute(ATTRIBUTE_NAME_CONFIGURATION); if (map == null) { map = new HashMap<>(); result.getRequest().setAttribute(ATTRIBUTE_NAME_CONFIGURATION, map); @@ -78,18 +114,15 @@ public class ContractResultHandler extends return map; } - @Override - protected Request getWireMockRequest(MvcResult result) { + @Override protected Request getWireMockRequest(MvcResult result) { return new WireMockHttpServletRequestAdapter(result.getRequest()); } - @Override - protected MediaType getContentType(MvcResult result) { + @Override protected MediaType getContentType(MvcResult result) { return MediaType.valueOf(result.getRequest().getContentType()); } - @Override - protected byte[] getRequestBodyContent(MvcResult result) { + @Override protected byte[] getRequestBodyContent(MvcResult result) { try { return StreamUtils.copyToByteArray(result.getRequest().getInputStream()); } @@ -99,3 +132,259 @@ public class ContractResultHandler extends } } + +// COPIED FROM WIREMOCK +class WireMockHttpServletRequestAdapter implements Request { + + private static final String ORIGINAL_REQUEST_KEY = "wiremock.ORIGINAL_REQUEST"; + + private final HttpServletRequest request; + private byte[] cachedBody; + private Collection cachedMultiparts; + + WireMockHttpServletRequestAdapter(HttpServletRequest request) { + this.request = request; + } + + @Override public String getUrl() { + String url = this.request.getRequestURI(); + String contextPath = this.request.getContextPath(); + if (!isNullOrEmpty(contextPath) && url.startsWith(contextPath)) { + url = url.substring(contextPath.length()); + } + return withQueryStringIfPresent(url); + } + + @Override public String getAbsoluteUrl() { + return withQueryStringIfPresent(this.request.getRequestURL().toString()); + } + + private String withQueryStringIfPresent(String url) { + return url + (isNullOrEmpty(this.request.getQueryString()) ? + "" : + "?" + this.request.getQueryString()); + } + + @Override public RequestMethod getMethod() { + return RequestMethod.fromString(this.request.getMethod().toUpperCase()); + } + + @Override public String getScheme() { + return this.request.getScheme(); + } + + @Override public String getHost() { + return this.request.getServerName(); + } + + @Override public int getPort() { + return this.request.getServerPort(); + } + + @Override public String getClientIp() { + String forwardedForHeader = this.getHeader("X-Forwarded-For"); + + if (forwardedForHeader != null && forwardedForHeader.length() > 0) { + return forwardedForHeader; + } + + return this.request.getRemoteAddr(); + } + + // Something's wrong with reading the body from request + @Override public byte[] getBody() { + if (this.cachedBody == null || this.cachedBody.length == 0) { + try { + if (this.request instanceof MockHttpServletRequest) { + this.cachedBody = ((MockHttpServletRequest) this.request).getContentAsByteArray(); + return this.cachedBody; + } + byte[] body = toByteArray(this.request.getInputStream()); + boolean isGzipped = hasGzipEncoding() || Gzip.isGzipped(body); + this.cachedBody = isGzipped ? Gzip.unGzip(body) : body; + } + catch (IOException ioe) { + throw new RuntimeException(ioe); + } + } + return this.cachedBody; + } + + private Charset encodingFromContentTypeHeaderOrUtf8() { + ContentTypeHeader contentTypeHeader = contentTypeHeader(); + if (contentTypeHeader != null) { + return contentTypeHeader.charset(); + } + return UTF_8; + } + + private boolean hasGzipEncoding() { + String encodingHeader = this.request.getHeader("Content-Encoding"); + return encodingHeader != null && encodingHeader.contains("gzip"); + } + + @Override public String getBodyAsString() { + return stringFromBytes(getBody(), encodingFromContentTypeHeaderOrUtf8()); + } + + @Override public String getBodyAsBase64() { + return encodeBase64(getBody()); + } + + @SuppressWarnings("unchecked") @Override public String getHeader(String key) { + List headerNames = list(this.request.getHeaderNames()); + for (String currentKey : headerNames) { + if (currentKey.toLowerCase().equals(key.toLowerCase())) { + return this.request.getHeader(currentKey); + } + } + return null; + } + + @Override @SuppressWarnings("unchecked") public HttpHeader header(String key) { + List headerNames = list(this.request.getHeaderNames()); + for (String currentKey : headerNames) { + if (currentKey.toLowerCase().equals(key.toLowerCase())) { + List valueList = list(this.request.getHeaders(currentKey)); + if (valueList.isEmpty()) { + return HttpHeader.empty(key); + } + return new HttpHeader(key, valueList); + } + } + + return HttpHeader.absent(key); + } + + @Override public ContentTypeHeader contentTypeHeader() { + return getHeaders().getContentTypeHeader(); + } + + @Override public boolean containsHeader(String key) { + return header(key).isPresent(); + } + + @Override public HttpHeaders getHeaders() { + List headerList = newArrayList(); + for (String key : getAllHeaderKeys()) { + headerList.add(header(key)); + } + + return new HttpHeaders(headerList); + } + + @SuppressWarnings("unchecked") @Override public Set getAllHeaderKeys() { + LinkedHashSet headerKeys = new LinkedHashSet<>(); + for (Enumeration headerNames = this.request.getHeaderNames(); headerNames + .hasMoreElements(); ) { + headerKeys.add(headerNames.nextElement()); + } + + return headerKeys; + } + + @Override public Map getCookies() { + ImmutableMultimap.Builder builder = ImmutableMultimap.builder(); + javax.servlet.http.Cookie[] cookies = firstNonNull(this.request.getCookies(), + new javax.servlet.http.Cookie[0]); + for (javax.servlet.http.Cookie cookie : cookies) { + builder.put(cookie.getName(), cookie.getValue()); + } + return Maps.transformValues(builder.build().asMap(), + input -> new Cookie(null, ImmutableList.copyOf(input))); + } + + @Override public QueryParameter queryParameter(String key) { + return firstNonNull((splitQuery(this.request.getQueryString()).get(key)), + QueryParameter.absent(key)); + } + + @Override public boolean isBrowserProxyRequest() { + if (!isJetty()) { + return false; + } + return false; + } + + @Override @SuppressWarnings("unchecked") public Collection getParts() { + if (!isMultipart()) { + return null; + } + if (this.cachedMultiparts == null) { + try { + String contentTypeHeaderValue = FluentIterable + .from(contentTypeHeader().values()).join(Joiner.on(" ")); + InputStream inputStream = new ByteArrayInputStream(getBody()); + MultiPartInputStreamParser inputStreamParser = new MultiPartInputStreamParser( + inputStream, contentTypeHeaderValue, null, null); + this.cachedMultiparts = from(safelyGetRequestParts()) + .transform( + (Function) WireMockHttpServletMultipartAdapter::from).toList(); + } + catch (IOException | ServletException exception) { + return throwUnchecked(exception, Collection.class); + } + } + return (this.cachedMultiparts.size() > 0) ? this.cachedMultiparts : null; + } + + private Collection safelyGetRequestParts() + throws IOException, ServletException { + try { + return this.request.getParts(); + } + catch (IOException ioe) { + if (ioe.getMessage().contains("Missing content for multipart")) { + return Collections.emptyList(); + } + + throw ioe; + } + } + + @Override public boolean isMultipart() { + String header = getHeader("Content-Type"); + return (header != null && header.contains("multipart")); + } + + @Override public Part getPart(final String name) { + if (name == null || name.length() == 0) { + return null; + } + if (this.cachedMultiparts == null) { + if (getParts() == null) { + return null; + } + } + return from(this.cachedMultiparts).firstMatch( + input -> name.equals(input.getName())).get(); + } + + @Override public Optional getOriginalRequest() { + Request originalRequest = (Request) this.request.getAttribute(ORIGINAL_REQUEST_KEY); + return Optional.fromNullable(originalRequest); + } + + private boolean isJetty() { + try { + getClass("org.eclipse.jetty.server.Request"); + return true; + } + catch (Exception e) { + } + return false; + } + + private void getClass(String type) throws ClassNotFoundException { + ClassLoader contextCL = Thread.currentThread().getContextClassLoader(); + ClassLoader loader = contextCL == null ? + com.github.tomakehurst.wiremock.servlet.WireMockHttpServletRequestAdapter.class + .getClassLoader() : + contextCL; + Class.forName(type, false, loader); + } + + @Override public String toString() { + return this.request.toString() + getBodyAsString(); + } +} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockVerifyHelper.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockVerifyHelper.java index 9caee5b0b7..1e39534f70 100644 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockVerifyHelper.java +++ b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockVerifyHelper.java @@ -70,8 +70,8 @@ public abstract class WireMockVerifyHelper