diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Cookies.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Cookies.groovy index 29b7472de3..9060b89a5c 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Cookies.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Cookies.groovy @@ -63,4 +63,28 @@ class Cookies { int hashCode() { return entries.hashCode() } + + /** + * Converts the headers into their stub side representations and returns as + * a map of String key => Object value. + */ + Map asStubSideMap() { + def acc = [:].withDefault { [] as Collection } + return entries.inject(acc as Map) { Map map, Cookie cookie -> + map[cookie.key] = cookie.clientValue + return map + } as Map + } + + /** + * Converts the headers into their stub side representations and returns as + * a map of String key => Object value. + */ + Map asTestSideMap() { + def acc = [:].withDefault { [] as Collection } + return entries.inject(acc as Map) { Map map, Cookie cookie -> + map[cookie.key] = cookie.serverValue + return map + } as Map + } } diff --git a/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/CookiesSpec.groovy b/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/CookiesSpec.groovy new file mode 100644 index 0000000000..6341a6dea5 --- /dev/null +++ b/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/CookiesSpec.groovy @@ -0,0 +1,28 @@ +package org.springframework.cloud.contract.spec.internal + +import spock.lang.Specification + +/** + * @author Marcin Grzejszczak + */ +class CookiesSpec extends Specification { + + Cookies cookies = cookie() + + def "should convert cookies to a stub side map"() { + expect: + cookies.asStubSideMap() == [foo: "client", bar: "client"] + } + + def "should convert cookies to a test side map"() { + expect: + cookies.asTestSideMap() == [foo: "server", bar: "server"] + } + + private Cookies cookie() { + Cookies cookies = new Cookies() + cookies.cookie("foo", new DslProperty("client", "server")) + cookies.cookie(["bar": new DslProperty<>("client", "server")]) + return cookies + } +} diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.groovy index 11a18e8e32..056c6825c4 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.groovy @@ -26,6 +26,7 @@ import org.yaml.snakeyaml.Yaml import org.springframework.cloud.contract.spec.Contract import org.springframework.cloud.contract.spec.ContractConverter import org.springframework.cloud.contract.spec.internal.BodyMatcher +import org.springframework.cloud.contract.spec.internal.Cookies import org.springframework.cloud.contract.spec.internal.DslProperty import org.springframework.cloud.contract.spec.internal.ExecutionProperty import org.springframework.cloud.contract.spec.internal.Headers @@ -495,6 +496,7 @@ class YamlContractConverter implements ContractConverter> { method = contract?.request?.method?.clientValue url = contract?.request?.url?.clientValue headers = (contract?.request?.headers as Headers)?.asTestSideMap() + cookies = (contract?.request?.cookies as Cookies)?.asTestSideMap() body = MapConverter.getTestSideValues(contract?.request?.body) matchers = new StubMatchers() contract?.request?.matchers?.jsonPathMatchers()?.each { BodyMatcher matcher -> @@ -509,6 +511,7 @@ class YamlContractConverter implements ContractConverter> { yamlContract.response.with { status = contract?.response?.status?.clientValue as Integer headers = (contract?.response?.headers as Headers)?.asStubSideMap() + cookies = (contract?.response?.cookies as Cookies)?.asStubSideMap() body = MapConverter.getStubSideValues(contract?.response?.body) contract?.response?.matchers?.jsonPathMatchers()?.each { BodyMatcher matcher -> matchers.body << new BodyTestMatcher( 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 0d6bd5d4b3..334c242755 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 @@ -78,11 +78,13 @@ class YamlContractConverterSpec extends Specification { contract.request.url.clientValue == "/foo" contract.request.cookies.entries.find { it.key == "foo" && it.serverValue == "bar" } contract.request.cookies.entries.find { it.key == "fooRegex" && ((Pattern) it.clientValue).pattern == "reg" && it.serverValue == "reg" } + contract.request.cookies.entries.find { it.key == "fooPredefinedRegex" && ((Pattern) it.clientValue).pattern == "(true|false)" && it.serverValue == true } and: contract.response.status.clientValue == 200 contract.response.cookies.entries.find { it.key == "foo" && it.clientValue == "baz" } contract.response.cookies.entries.find { it.key == "fooRegex" && ((Pattern) it.serverValue).pattern == "[0-9]+" && it.clientValue == 123 } contract.response.cookies.entries.find { it.key == "source" && ((Pattern) it.serverValue).pattern == "ip_address" && it.clientValue == "ip_address" } + contract.response.cookies.entries.find { it.key == "fooPredefinedRegex" && ((Pattern) it.serverValue).pattern == "(true|false)" && it.clientValue == true } contract.response.body.clientValue == ["status": "OK"] } @@ -524,6 +526,10 @@ class YamlContractConverterSpec extends Specification { headers { header("foo", "bar") } + cookies { + cookie(foo: value(c("client"), p("server"))) + cookie("bar", value(c("client"), p("server"))) + } body([foo: "bar"]) } response { @@ -531,6 +537,10 @@ class YamlContractConverterSpec extends Specification { headers { header("foo2", "bar") } + cookies { + cookie(foo: value(c("client"), p("server"))) + cookie("bar", value(c("client"), p("server"))) + } body([foo2: "bar"]) } }] @@ -542,9 +552,13 @@ class YamlContractConverterSpec extends Specification { yamlContract.request.url == "/foo" yamlContract.request.method == "PUT" yamlContract.request.headers.find { it.key == "foo" && it.value == "bar" } + yamlContract.request.cookies.find { it.key == "bar" && it.value == "server" } + yamlContract.request.cookies.find { it.key == "foo" && it.value == "server" } yamlContract.request.body == [foo: "bar"] yamlContract.response.status == 200 yamlContract.response.headers.find { it.key == "foo2" && it.value == "bar" } yamlContract.response.body == [foo2: "bar"] + yamlContract.response.cookies.find { it.key == "foo" && it.value == "client" } + yamlContract.response.cookies.find { it.key == "bar" && it.value == "client" } } } diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/contract_cookies.yml b/spring-cloud-contract-verifier/src/test/resources/yml/contract_cookies.yml index 24c68802d0..2136d7df78 100644 --- a/spring-cloud-contract-verifier/src/test/resources/yml/contract_cookies.yml +++ b/spring-cloud-contract-verifier/src/test/resources/yml/contract_cookies.yml @@ -8,16 +8,20 @@ request: cookies: foo: bar fooRegex: reg + fooPredefinedRegex: true matchers: cookies: - key: fooRegex regex: reg + - key: fooPredefinedRegex + predefined: any_boolean response: status: 200 cookies: foo: baz fooRegex: 123 source: ip_address + fooPredefinedRegex: true body: status: OK matchers: @@ -26,3 +30,5 @@ response: regex: "[0-9]+" - key: source regex: ip_address + - key: fooPredefinedRegex + predefined: any_boolean