From 8ebc749d2fff125e05348be5e767334a378532f1 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Tue, 22 Jan 2019 09:14:08 +0100 Subject: [PATCH] Fixed the way regex entries are generated for message bodies; fixes gh-858 --- .../contract/spec/internal/OptionalProperty.groovy | 8 +++++++- .../contract/spec/internal/RegexProperty.groovy | 7 ++++++- .../stubrunner/StubRunnerExecutorSpec.groovy | 2 ++ .../src/test/resources/messages/message.groovy | 3 ++- .../contract/verifier/util/BodyExtractor.groovy | 13 ++++++++++++- 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/OptionalProperty.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/OptionalProperty.groovy index e94ad65272..41ed100899 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/OptionalProperty.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/OptionalProperty.groovy @@ -20,6 +20,7 @@ import java.util.regex.Pattern import groovy.transform.CompileStatic import groovy.transform.ToString +import repackaged.nl.flotsam.xeger.Xeger /** * Represents a property that may or may not be there @@ -28,7 +29,7 @@ import groovy.transform.ToString */ @CompileStatic @ToString(includePackage = false, includeNames = true) -class OptionalProperty implements Serializable { +class OptionalProperty implements Serializable, CanBeDynamic { final Object value OptionalProperty(Object value) { @@ -56,4 +57,9 @@ class OptionalProperty implements Serializable { String toString() { return optionalPattern() } + + @Override + Object generateConcreteValue() { + return new Xeger(optionalPattern()).generate() + } } diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/RegexProperty.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/RegexProperty.groovy index b5b944142f..7110e5ce7c 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/RegexProperty.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/RegexProperty.groovy @@ -33,7 +33,7 @@ import repackaged.nl.flotsam.xeger.Xeger @TypeChecked @EqualsAndHashCode @ToString(includePackage = false, includeNames = true) -class RegexProperty extends DslProperty { +class RegexProperty extends DslProperty implements CanBeDynamic { final Pattern pattern private final Class clazz @@ -169,4 +169,9 @@ class RegexProperty extends DslProperty { String toString() { return this.pattern() } + + @Override + Object generateConcreteValue() { + return generate() + } } diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerExecutorSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerExecutorSpec.groovy index 8aee94f390..1412c738ba 100644 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerExecutorSpec.groovy +++ b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerExecutorSpec.groovy @@ -160,8 +160,10 @@ class StubRunnerExecutorSpec extends Specification { then: triggered 1 * messageVerifier.send({ it -> + println "Body <${it}>" !it.toString().contains("cursor") }, { Map map -> + println "Headers <${map}>" !map.values().any { it.toString().contains("cursor")} }, _) cleanup: diff --git a/spring-cloud-contract-stub-runner/src/test/resources/messages/message.groovy b/spring-cloud-contract-stub-runner/src/test/resources/messages/message.groovy index 0e815b518f..a6cf2980a3 100644 --- a/spring-cloud-contract-stub-runner/src/test/resources/messages/message.groovy +++ b/spring-cloud-contract-stub-runner/src/test/resources/messages/message.groovy @@ -21,7 +21,8 @@ org.springframework.cloud.contract.spec.Contract.make { "firstName" : $(regex(nonEmpty())), "middleName": $(optional(regex(nonEmpty()))), "lastName" : $(regex(nonEmpty())), - "version" : $(producer(regex(number())), consumer(0l)) + "version" : $(producer(regex(number())), consumer(0l)), + "uid" : $(producer(regex(uuid()))) ]) } } \ No newline at end of file diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/BodyExtractor.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/BodyExtractor.groovy index ca82224bd7..3f1578cd88 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/BodyExtractor.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/BodyExtractor.groovy @@ -16,10 +16,15 @@ package org.springframework.cloud.contract.verifier.util +import java.util.regex.Pattern + import groovy.json.JsonOutput import groovy.json.StringEscapeUtils import groovy.transform.CompileStatic + +import org.springframework.cloud.contract.spec.internal.CanBeDynamic import org.springframework.cloud.contract.spec.internal.DslProperty +import org.springframework.cloud.contract.spec.internal.RegexProperty import static ContentUtils.extractValue /** @@ -78,7 +83,13 @@ class BodyExtractor { } else if (bodyValue instanceof DslProperty) { return extractClientValueFromBody(bodyValue.clientValue) } else { - return MapConverter.transformValues(bodyValue, { it instanceof DslProperty ? it.clientValue : it }) + return MapConverter.transformValues(bodyValue, { + Object prop = it instanceof DslProperty ? it.clientValue : it + if (prop instanceof CanBeDynamic || prop instanceof Pattern) { + return new RegexProperty(prop).generateConcreteValue() + } + return prop + }) } } }