From 5dbac1f210723108937fb8a35726762e0ec87e54 Mon Sep 17 00:00:00 2001 From: Tim Ysewyn Date: Wed, 18 Apr 2018 23:17:59 +0200 Subject: [PATCH 1/2] Generated messaging tests could create compilation errors for certain regexes in headers (#622) * Fixed an issue with the generation of messaging tests where the regex pattern was creating compilation errors fixes gh-620 (cherry picked from commit f64feaf) --- .../JUnitMessagingMethodBodyBuilder.groovy | 4 +- .../SpockMessagingMethodBodyBuilder.groovy | 5 +- .../MessagingMethodBodyBuilderSpec.groovy | 59 +++++++++++++++++++ 3 files changed, 64 insertions(+), 4 deletions(-) diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JUnitMessagingMethodBodyBuilder.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JUnitMessagingMethodBodyBuilder.groovy index aa1b555819..902aa99911 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JUnitMessagingMethodBodyBuilder.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JUnitMessagingMethodBodyBuilder.groovy @@ -41,6 +41,7 @@ import static org.springframework.cloud.contract.verifier.config.TestFramework.J * * @author Marcin Grzejszczak * @author Jakub Kubrynski, codearte.io + * @author Tim Ysewyn * * @since 1.0.0 */ @@ -244,8 +245,7 @@ class JUnitMessagingMethodBodyBuilder extends MessagingMethodBodyBuilder { } protected String createHeaderComparison(Pattern headerValue) { - String escapedHeader = convertUnicodeEscapesIfRequired("$headerValue") - String escapedJavaHeader = escapeJava(escapedHeader) + String escapedJavaHeader = escapeJava(headerValue.pattern()) return "matches(\"$escapedJavaHeader\");" } diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SpockMessagingMethodBodyBuilder.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SpockMessagingMethodBodyBuilder.groovy index 2d461b7c5e..1c2777587d 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SpockMessagingMethodBodyBuilder.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SpockMessagingMethodBodyBuilder.groovy @@ -35,6 +35,7 @@ import static org.apache.commons.text.StringEscapeUtils.escapeJava /** * @author Jakub Kubrynski, codearte.io + * @author Tim Ysewyn */ @PackageScope @TypeChecked @@ -229,8 +230,8 @@ class SpockMessagingMethodBodyBuilder extends MessagingMethodBodyBuilder { } protected String convertHeaderComparison(Pattern headerValue) { - String converted = escapeJava(convertUnicodeEscapesIfRequired(headerValue.toString())) - return "==~ java.util.regex.Pattern.compile('$converted')" + String converted = escapeJava(convertUnicodeEscapesIfRequired(headerValue.pattern())) + return "==~ java.util.regex.Pattern.compile('${converted}')" } // #273 - should escape $ for Groovy since it will try to make it a GString diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy index 6b17892661..f1b158bfe0 100644 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy @@ -794,4 +794,63 @@ Contract.make { stripped(test) == stripped(expectedMsg) } + @Issue('#620') + def "should generate tests with message headers containing regular expression which compile for [#methodBuilderName]"() { + given: + Contract contractDsl = Contract.make { + label 'shouldPublishMessage' + // input to the contract + input { + // the contract will be triggered by a method + triggeredBy('foo()') + } + // output message of the contract + outputMessage { + // destination to which the output message will be sent + sentTo('messageExchange') + // the body of the output message + body([ + "field": "value" + ]) + headers { + header('Authorization', value(regex('Bearer [A-Za-z0-9\\-\\._~\\+\\/]+=*'))) + } + } + } + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + def test = blockBuilder.toString() + then: + !test.contains('cursor') + !test.contains('REGEXP>>') + test == expectedTest + where: + methodBuilderName | methodBuilder | expectedTest + "SpockMessagingMethodBodyBuilder" | { Contract dsl -> new SpockMessagingMethodBodyBuilder(dsl, properties) } | ''' when: + foo() + + then: + ContractVerifierMessage response = contractVerifierMessaging.receive('messageExchange') + assert response != null + response.getHeader('Authorization')?.toString() ==~ java.util.regex.Pattern.compile('Bearer [A-Za-z0-9-._~+/]+=*') + and: + DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.payload)) + assertThatJson(parsedJson).field("['field']").isEqualTo("value") +''' + "JUnitMessagingMethodBodyBuilder" | { Contract dsl -> new JUnitMessagingMethodBodyBuilder(dsl, properties) } | ''' // when: + foo(); + + // then: + ContractVerifierMessage response = contractVerifierMessaging.receive("messageExchange"); + assertThat(response).isNotNull(); + assertThat(response.getHeader("Authorization")).isNotNull(); + assertThat(response.getHeader("Authorization").toString()).matches("Bearer [A-Za-z0-9\\\\-\\\\._~\\\\+\\\\/]+=*"); + // and: + DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.getPayload())); + assertThatJson(parsedJson).field("['field']").isEqualTo("value"); +''' + } + } From bfb5495ae7a6f22faea57ac60bbad6871ca7778e Mon Sep 17 00:00:00 2001 From: Tim Ysewyn Date: Wed, 18 Apr 2018 23:19:00 +0200 Subject: [PATCH 2/2] Added the missing $() convenience method for messaging contracts (#623) Fixes gh-619 (cherry picked from commit 4cf6e19) --- .../cloud/contract/spec/internal/Input.groovy | 4 ++++ .../spec/internal/OutputMessage.groovy | 14 ++++++++++++- .../contract/spec/internal/InputSpec.groovy | 20 +++++++++++++++++++ .../spec/internal/OutputMessageSpec.groovy | 20 +++++++++++++++++++ 4 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/InputSpec.groovy create mode 100644 spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/OutputMessageSpec.groovy diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Input.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Input.groovy index 465df6461d..880628b29c 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Input.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Input.groovy @@ -90,6 +90,10 @@ class Input extends Common { return new DslProperty(client.clientValue, clientValue) } + DslProperty $(ClientDslProperty client) { + return value(client) + } + @EqualsAndHashCode(includeFields = true, callSuper = true) @ToString(includeSuper = true) static class BodyType extends DslProperty { diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/OutputMessage.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/OutputMessage.groovy index f369cc1761..d7c7a861c0 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/OutputMessage.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/OutputMessage.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2013-2017 the original author or authors. + * Copyright 2013-2018 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. @@ -25,6 +25,14 @@ import repackaged.nl.flotsam.xeger.Xeger import java.util.regex.Pattern +/** + * Represents an output for messaging. Used for verifying + * the body and headers that are sent. + * + * @author Marcin Grzejszczak + * @author Tim Ysewyn + * @since 1.0.0 + */ @TypeChecked @EqualsAndHashCode @ToString(includePackage = false, includeNames = true) @@ -88,6 +96,10 @@ class OutputMessage extends Common { return new DslProperty(value, server.serverValue) } + DslProperty $(ServerDslProperty server) { + return value(server) + } + void testMatchers(@DelegatesTo(ResponseBodyMatchers) Closure closure) { this.matchers = new ResponseBodyMatchers() closure.delegate = this.matchers diff --git a/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/InputSpec.groovy b/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/InputSpec.groovy new file mode 100644 index 0000000000..5c93855d1a --- /dev/null +++ b/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/InputSpec.groovy @@ -0,0 +1,20 @@ +package org.springframework.cloud.contract.spec.internal + +import spock.lang.Specification +/** + * @author Tim Ysewyn + */ +class InputSpec extends Specification { + + def 'should set property when using the $() convenience method'() { + given: + Input input = new Input() + DslProperty property + when: + input.with { + property = $(consumer(regex("[0-9]{5}"))) + } + then: + (property.serverValue as String).matches(/[0-9]{5}/) + } +} diff --git a/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/OutputMessageSpec.groovy b/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/OutputMessageSpec.groovy new file mode 100644 index 0000000000..2a1da4d1ac --- /dev/null +++ b/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/OutputMessageSpec.groovy @@ -0,0 +1,20 @@ +package org.springframework.cloud.contract.spec.internal + +import spock.lang.Specification +/** + * @author Tim Ysewyn + */ +class OutputMessageSpec extends Specification { + + def 'should set property when using the $() convenience method'() { + given: + Input input = new Input() + DslProperty property + when: + input.with { + property = $(consumer(regex("[0-9]{5}"))) + } + then: + (property.serverValue as String).matches(/[0-9]{5}/) + } +}