diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/YamlToContracts.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/YamlToContracts.java index c3bbad2707..9800d93cdd 100644 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/YamlToContracts.java +++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/YamlToContracts.java @@ -54,6 +54,7 @@ import org.springframework.cloud.contract.spec.internal.OutputMessage; import org.springframework.cloud.contract.spec.internal.RegexPatterns; import org.springframework.cloud.contract.spec.internal.Request; import org.springframework.cloud.contract.spec.internal.Response; +import org.springframework.cloud.contract.spec.internal.Url; import org.springframework.cloud.contract.verifier.util.ContentType; import org.springframework.cloud.contract.verifier.util.NamesUtil; import org.springframework.util.StringUtils; @@ -169,7 +170,7 @@ class YamlToContracts { if (yamlContractRequest != null) { dslContract.request((dslContractRequest) -> { mapRequestMethod(yamlContractRequest, dslContractRequest); - mapRequestUrl(yamlContractRequest, dslContractRequest); + mapRequestUrl(yamlContract, dslContractRequest); mapRequestUrlPath(yamlContract, dslContractRequest); mapRequestHeaders(yamlContractRequest, dslContractRequest); mapRequestCookies(yamlContractRequest, dslContractRequest); @@ -186,24 +187,13 @@ class YamlToContracts { } } - private void mapRequestUrl(YamlContract.Request yamlContractRequest, Request dslContractRequest) { - String yamlContractRequestUrl = yamlContractRequest.url; + private void mapRequestUrl(YamlContract yamlContract, Request dslContractRequest) { + String yamlContractRequestUrl = yamlContract.request.url; if (yamlContractRequestUrl != null) { YamlContract.KeyValueMatcher yamlContractRequestMatchersUrl = Optional - .ofNullable(yamlContractRequest.matchers).map(matchers -> matchers.url).orElse(null); - dslContractRequest.url(urlValue(yamlContractRequestUrl, yamlContractRequestMatchersUrl), (url) -> { - if (yamlContractRequest.queryParameters != null) { - url.queryParameters( - (queryParameters -> yamlContractRequest.queryParameters.forEach((key, value) -> { - if (value instanceof List) { - ((List) value).forEach(v -> queryParameters.parameter(key, v)); - } - else { - queryParameters.parameter(key, value); - } - }))); - } - }); + .ofNullable(yamlContract.request.matchers).map(matchers -> matchers.url).orElse(null); + dslContractRequest.url(urlValue(yamlContractRequestUrl, yamlContractRequestMatchersUrl), + url -> handleQueryParameters(yamlContract, url)); } } @@ -212,20 +202,23 @@ class YamlToContracts { if (yamlContractRequestUrlPath != null) { YamlContract.KeyValueMatcher yamlContractRequestMatchersUrl = Optional .ofNullable(yamlContract.request.matchers).map(matchers -> matchers.url).orElse(null); - dslContractRequest.urlPath(urlValue(yamlContractRequestUrlPath, yamlContractRequestMatchersUrl), (url) -> { - if (yamlContract.request.queryParameters != null) { - url.queryParameters( - (queryParameters -> yamlContract.request.queryParameters.forEach((key, value) -> { - if (value instanceof List) { - ((List) value).forEach( - v -> queryParameters.parameter(key, queryParamValue(yamlContract, key, v))); - } - else { - queryParameters.parameter(key, queryParamValue(yamlContract, key, value)); - } - }))); - } - }); + dslContractRequest.urlPath(urlValue(yamlContractRequestUrlPath, yamlContractRequestMatchersUrl), + urlPath -> handleQueryParameters(yamlContract, urlPath)); + } + } + + private void handleQueryParameters(YamlContract yamlContract, Url url) { + if (yamlContract.request.queryParameters != null) { + url.queryParameters( + (queryParameters -> yamlContract.request.queryParameters.forEach((key, value) -> { + if (value instanceof List) { + ((List) value).forEach( + v -> queryParameters.parameter(key, queryParamValue(yamlContract, key, v))); + } + else { + queryParameters.parameter(key, queryParamValue(yamlContract, key, value)); + } + }))); } } diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverterSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverterSpec.groovy index 2b4f8bc1f8..d59b7e8ed1 100644 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverterSpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverterSpec.groovy @@ -22,6 +22,7 @@ import groovy.json.JsonSlurper import spock.lang.Issue import spock.lang.Shared import spock.lang.Specification +import spock.lang.Unroll import org.springframework.cloud.contract.spec.Contract import org.springframework.cloud.contract.spec.internal.ExecutionProperty @@ -72,8 +73,6 @@ class YamlContractConverterSpec extends Specification { File ymlBody = new File(ymlBodyFile.toURI()) URL ymlReferenceFile = YamlContractConverterSpec.getResource("/yml/contract_reference_request.yml") File ymlReference = new File(ymlReferenceFile.toURI()) - URL ymlMatchersFile = YamlContractConverterSpec.getResource("/yml/contract_matchers.yml") - File ymlMatchers = new File(ymlMatchersFile.toURI()) URL ymlMultipleFile = YamlContractConverterSpec.getResource("/yml/multiple_contracts.yml") File ymlMultiple = new File(ymlMultipleFile.toURI()) URL ymlMessagingMatchersFile = YamlContractConverterSpec.getResource("/yml/contract_message_matchers.yml") @@ -259,9 +258,18 @@ class YamlContractConverterSpec extends Specification { } } - def "should convert YAML with REST matchers to DSL"() { + @Issue('#1778') + @Unroll + def 'should convert YAML with REST matchers and path property #urlPropertyName to DSL'() { given: - assert converter.isAccepted(ymlMatchers) + File ymlMatchers = File.createTempFile('contract_matchers', '.yml').with { + write YamlContractConverterSpec.getResource('/yml/contract_matchers.yml') + .text + .replace('\n urlPath:', "\n $urlPropertyName:") + it + } + expect: + converter.isAccepted(ymlMatchers) when: Collection contracts = converter.convertFrom(ymlMatchers) then: @@ -271,10 +279,11 @@ class YamlContractConverterSpec extends Specification { it.name == "Content-Type" && ((Pattern) it.clientValue).pattern() == "application/json.*" && it.serverValue == "application/json" } - ((Pattern) contract.request.urlPath.clientValue).pattern() == "/get/[0-9]" - contract.request.urlPath.serverValue == "/get/1" - contract.request.urlPath.queryParameters.parameters.size() == 8 - QueryParameters queryParameters = contract.request.urlPath.queryParameters + def url = contract.request."$urlPropertyName" + ((Pattern) url.clientValue).pattern() == "/get/[0-9]" + url.serverValue == "/get/1" + url.queryParameters.parameters.size() == 8 + QueryParameters queryParameters = url.queryParameters assertQueryParam(queryParameters, "limit", 10, MatchingStrategy.Type.EQUAL_TO, 20) assertQueryParam(queryParameters, "offset", 20, @@ -378,6 +387,9 @@ class YamlContractConverterSpec extends Specification { contract.response.bodyMatchers.matchers[15].path() == '$.duck' contract.response.bodyMatchers.matchers[15].matchingType() == COMMAND contract.response.bodyMatchers.matchers[15].value() == new ExecutionProperty('assertThatValueIsANumber($it)') + + where: + urlPropertyName << ['url', 'urlPath'] } protected Object assertQueryParam(QueryParameters queryParameters, String queryParamName, Object serverValue,