From 9980eb0e9d209e855ed1b417fe9b0a31014da0f6 Mon Sep 17 00:00:00 2001 From: Koki Igarashi Date: Thu, 24 Mar 2022 22:53:47 +0900 Subject: [PATCH] fix #1656: Add missing support for JSON values inside arrays in WireMockStub (#1764) Fixes #1656. Currently, numbers, booleans and null inside arrays are double-quoted when converting dsl into stub, which results in generating incorrect json stubs for WireMock. This commit fixes it. --- .../DslToWireMockClientConverterSpec.groovy | 60 +++++++++++++++++++ .../wiremock/BaseWireMockStubStrategy.java | 20 ++++++- .../WireMockResponseStubStrategySpec.groovy | 42 ++++++++++++- 3 files changed, 119 insertions(+), 3 deletions(-) diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverterSpec.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverterSpec.groovy index 2bf8b672d6..ebaeb49c32 100755 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverterSpec.groovy +++ b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverterSpec.groovy @@ -1134,4 +1134,64 @@ class DslToWireMockClientConverterSpec extends Specification { return stubMapping } + @Issue("1656") + def "should convert DSL file to WireMock JSON with array"() { + given: + def converter = new DslToWireMockClientConverter() + and: + File file = tmpFolder.newFile("dsl1656.groovy") + file.write(''' + org.springframework.cloud.contract.spec.Contract.make { + request { + method "GET" + url "/api/foo/61923376" + headers { + accept 'application/json' + } + } + response { + status OK() + headers { + contentType(applicationJson()) + } + //language=JSON + body( + """ + [ + 813146, + 814952, + 813102, + 813282 + ] + """ + ) + } + } + ''') + when: + String json = converter.convertContents("Test", new ContractMetadata(file.toPath(), false, 0, null, + ContractVerifierDslConverter.convertAsCollection(new File("/"), file))).values().first() + then: + JSONAssert.assertEquals(''' + { + "request" : { + "url" : "/api/foo/61923376", + "method" : "GET", + "headers" : { + "Accept" : { + "matches" : "application/json.*" + } + } + }, + "response" : { + "status" : 200, + "body" : "[813146,814952,813102,813282]", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + } + }''', json, false) + } + } diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/BaseWireMockStubStrategy.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/BaseWireMockStubStrategy.java index 0b986debda..cb2c551a66 100644 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/BaseWireMockStubStrategy.java +++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/BaseWireMockStubStrategy.java @@ -95,8 +95,15 @@ abstract class BaseWireMockStubStrategy { /** * For the given {@link ContentType} returns the Boolean version of the body. */ - String parseBody(Boolean value, ContentType contentType) { - return value.toString(); + Boolean parseBody(Boolean value, ContentType contentType) { + return value; + } + + /** + * For the given {@link ContentType} returns the Number version of the body. + */ + Number parseBody(Number value, ContentType contentType) { + return value; } /** @@ -156,6 +163,15 @@ abstract class BaseWireMockStubStrategy { else if (l instanceof List) { result.add(parseBody((List) l, contentType)); } + else if (l instanceof Boolean) { + result.add(parseBody((Boolean) l, contentType)); + } + else if (l instanceof Number) { + result.add(parseBody((Number) l, contentType)); + } + else if (l == null) { + result.add(null); + } else { result.add(parseBody(l, contentType)); } diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockResponseStubStrategySpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockResponseStubStrategySpec.groovy index 3bad520dbf..31ad4a6fe3 100644 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockResponseStubStrategySpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockResponseStubStrategySpec.groovy @@ -18,7 +18,6 @@ package org.springframework.cloud.contract.verifier.dsl.wiremock import groovy.json.JsonSlurper import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.converter.YamlContractConverter import org.springframework.cloud.contract.verifier.file.SingleContractMetadata import org.springframework.cloud.contract.verifier.util.ContentType import org.springframework.cloud.contract.verifier.util.MapConverter @@ -95,6 +94,47 @@ class WireMockResponseStubStrategySpec extends Specification { assert body.get("double") instanceof BigDecimal } + @Issue("#1656") + def "should not quote numbers, booleans, and null inside arrays"() { + given: + def irrelevantStatus = 200 + def contract = Contract.make { + request { + method GET() + url "/foo" + } + response { + status irrelevantStatus + body([ + anyPositiveInt(), + anyInteger(), + true, + anyNumber(), + null, + "value" + ]) + } + } + when: + SingleContractMetadata metadata = Stub() + metadata.evaluatedOutputStubContentType >> ContentType.JSON + def subject = new WireMockResponseStubStrategy(contract, metadata) { + @Override + Function parsingClosureForContentType() { + return MapConverter.JSON_PARSING_FUNCTION + } + } + def content = subject.buildClientResponseContent() + then: + List body = new JsonSlurper().parseText(content.body) as List + assert body.getAt(0) instanceof Integer + assert body.getAt(1) instanceof Integer + assert body.getAt(2) instanceof Boolean + assert body.getAt(3) instanceof Number + assert body.getAt(4) == null + assert body.getAt(5) instanceof String + } + def "should convert patterns to proper value"() { given: def contract = Contract.make {