From 3552684f9358f02dff0d78921f9dce29e0107366 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Thu, 11 Aug 2016 14:33:30 +0200 Subject: [PATCH] Invalid array size check there was a problem with the way property related to array size check was passed. Not only was the condition inverse, but also the properties weren't passed. With this change those issues were fixed, we've added the missing maven plugin feature and ensured that the array check is the default option. fixes #60 --- pom.xml | 26 +++ .../camel/StubRunnerCamelPredicate.java | 3 +- .../StubRunnerIntegrationMessageSelector.java | 2 +- .../StubRunnerStreamMessageSelector.java | 2 +- .../DslToWireMockClientConverter.groovy | 4 +- ...erateWireMockClientStubsFromDslTask.groovy | 3 +- .../maven/verifier/GenerateTestsMojo.java | 16 ++ .../maven/verifier/PluginUnitTest.java | 23 +++ .../test/resources/contracts/WithList.groovy | 34 ++++ .../ContractVerifierConfigProperties.groovy | 2 +- .../WireMockRequestStubStrategy.groovy | 3 +- .../util/JsonToJsonPathsConverter.groovy | 29 +++- .../JaxRsClientMethodBuilderSpec.groovy | 40 ++++- .../MockMvcMethodBodyBuilderSpec.groovy | 74 ++++++++- .../util/JsonToJsonPathsConverterSpec.groovy | 154 +++++++++++++++++- 15 files changed, 395 insertions(+), 20 deletions(-) create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic/src/test/resources/contracts/WithList.groovy diff --git a/pom.xml b/pom.xml index 8b9841716a..f0e517233f 100644 --- a/pom.xml +++ b/pom.xml @@ -190,6 +190,32 @@ + + + org.apache.maven.plugins + maven-clean-plugin + 3.0.0 + + + + target + + + ${env.HOME}/.m2/repository/com/example/ + + **/* + + + + ${env.HOME}/.m2/repository/org/springframework/cloud/contract/verifier/stubs/ + + **/* + + + + + + diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelPredicate.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelPredicate.java index 985ee3e66a..d0174bbba6 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelPredicate.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelPredicate.java @@ -55,7 +55,8 @@ class StubRunnerCamelPredicate implements Predicate { } Object inputMessage = exchange.getIn().getBody(); JsonPaths jsonPaths = JsonToJsonPathsConverter - .transformToJsonPathWithStubsSideValues(groovyDsl.getInput().getMessageBody()); + .transformToJsonPathWithStubsSideValuesAndNoArraySizeCheck( + groovyDsl.getInput().getMessageBody()); DocumentContext parsedJson; try { parsedJson = JsonPath diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/integration/StubRunnerIntegrationMessageSelector.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/integration/StubRunnerIntegrationMessageSelector.java index d69147cd24..12a567e4c2 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/integration/StubRunnerIntegrationMessageSelector.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/integration/StubRunnerIntegrationMessageSelector.java @@ -55,7 +55,7 @@ class StubRunnerIntegrationMessageSelector implements MessageSelector { } Object inputMessage = message.getPayload(); JsonPaths jsonPaths = JsonToJsonPathsConverter - .transformToJsonPathWithStubsSideValues( + .transformToJsonPathWithStubsSideValuesAndNoArraySizeCheck( groovyDsl.getInput().getMessageBody()); DocumentContext parsedJson; try { diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/stream/StubRunnerStreamMessageSelector.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/stream/StubRunnerStreamMessageSelector.java index 9292707667..a448536aa4 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/stream/StubRunnerStreamMessageSelector.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/stream/StubRunnerStreamMessageSelector.java @@ -55,7 +55,7 @@ class StubRunnerStreamMessageSelector implements MessageSelector { } Object inputMessage = message.getPayload(); JsonPaths jsonPaths = JsonToJsonPathsConverter - .transformToJsonPathWithStubsSideValues( + .transformToJsonPathWithStubsSideValuesAndNoArraySizeCheck( groovyDsl.getInput().getMessageBody()); DocumentContext parsedJson; try { diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverter.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverter.groovy index 3fe90afb25..cae1b34b86 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverter.groovy +++ b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverter.groovy @@ -21,7 +21,6 @@ import org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockStubStra import org.springframework.cloud.contract.verifier.file.ContractMetadata import java.nio.charset.StandardCharsets - /** * Converts DSLs to WireMock stubs * @@ -33,6 +32,7 @@ class DslToWireMockClientConverter extends DslToWireMockConverter { @Override String convertContent(String rootName, ContractMetadata contract) { String dslContent = contract.path.getText(StandardCharsets.UTF_8.toString()) - return new WireMockStubStrategy(rootName, contract, createGroovyDSLFromStringContent(dslContent)).toWireMockClientStub() + return new WireMockStubStrategy(rootName, contract, + createGroovyDSLFromStringContent(dslContent)).toWireMockClientStub() } } diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/GenerateWireMockClientStubsFromDslTask.groovy b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/GenerateWireMockClientStubsFromDslTask.groovy index e87a0422cd..a3693e28c8 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/GenerateWireMockClientStubsFromDslTask.groovy +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/GenerateWireMockClientStubsFromDslTask.groovy @@ -47,7 +47,8 @@ class GenerateWireMockClientStubsFromDslTask extends ConventionTask { ContractVerifierConfigProperties props = getConfigProperties() File outMappingsDir = props.stubsOutputDir != null ? new File(props.stubsOutputDir, DEFAULT_MAPPINGS_FOLDER) : new File(project.buildDir, "stubs/$DEFAULT_MAPPINGS_FOLDER") - RecursiveFilesConverter converter = new RecursiveFilesConverter(new DslToWireMockClientConverter(), + RecursiveFilesConverter converter = new RecursiveFilesConverter( + new DslToWireMockClientConverter(), getConfigProperties(), outMappingsDir) converter.processFiles() } diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/GenerateTestsMojo.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/GenerateTestsMojo.java index fd6c43ea98..3e90e34e5c 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/GenerateTestsMojo.java +++ b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/GenerateTestsMojo.java @@ -80,6 +80,14 @@ public class GenerateTestsMojo extends AbstractMojo { @Parameter private List excludedFiles; + /** + * Incubating feature. You can check the size of JSON arrays. If not turned on + * explicitly will be disabled. + */ + @Parameter(property = "spring.cloud.contract.verifier.assert.size", + defaultValue = "false") + private boolean assertJsonSize; + /** * Patterns for which Spring Cloud Contract Verifier should generate @Ignored tests */ @@ -119,6 +127,7 @@ public class GenerateTestsMojo extends AbstractMojo { config.setStaticImports(staticImports); config.setIgnoredFiles(ignoredFiles); config.setExcludedFiles(excludedFiles); + config.setAssertJsonSize(assertJsonSize); project.addTestCompileSourceRoot(generatedTestSourcesDir.getAbsolutePath()); if (getLog().isInfoEnabled()) { getLog().info( @@ -155,4 +164,11 @@ public class GenerateTestsMojo extends AbstractMojo { this.ignoredFiles = ignoredFiles; } + public boolean isAssertJsonSize() { + return assertJsonSize; + } + + public void setAssertJsonSize(boolean assertJsonSize) { + this.assertJsonSize = assertJsonSize; + } } diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/maven/verifier/PluginUnitTest.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/maven/verifier/PluginUnitTest.java index 4c4b6804a3..60e7959978 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/maven/verifier/PluginUnitTest.java +++ b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/maven/verifier/PluginUnitTest.java @@ -18,6 +18,7 @@ package org.springframework.cloud.contract.maven.verifier; import java.io.File; +import org.apache.commons.io.FileUtils; import org.junit.Rule; import org.junit.Test; @@ -27,6 +28,7 @@ import io.takari.maven.testing.TestResources; import static io.takari.maven.testing.TestMavenRuntime.newParameter; import static io.takari.maven.testing.TestResources.assertFilesNotPresent; import static io.takari.maven.testing.TestResources.assertFilesPresent; +import static org.assertj.core.api.BDDAssertions.then; public class PluginUnitTest { @@ -58,6 +60,7 @@ public class PluginUnitTest { assertFilesPresent(basedir, "target/stubs/contracts/Sample.groovy"); assertFilesPresent(basedir, "target/stubs/contracts/Messaging.groovy"); } + @Test public void shouldGenerateWireMockStubsInSelectedLocation() throws Exception { File basedir = resources.getBasedir("basic"); @@ -89,6 +92,26 @@ public class PluginUnitTest { "target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/ContractVerifierTest.java"); } + @Test + public void shouldGenerateContractTestsWithoutArraySize() throws Exception { + File basedir = resources.getBasedir("basic"); + maven.executeMojo(basedir, "generateTests"); + assertFilesPresent(basedir, + "target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/ContractVerifierTest.java"); + File test = new File(basedir, "target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/ContractVerifierTest.java"); + then(FileUtils.readFileToString(test)).doesNotContain("hasSize(4)"); + } + + @Test + public void shouldGenerateContractTestsWithArraySize() throws Exception { + File basedir = resources.getBasedir("basic"); + maven.executeMojo(basedir, "generateTests", newParameter("assertJsonSize", "true")); + assertFilesPresent(basedir, + "target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/ContractVerifierTest.java"); + File test = new File(basedir, "target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/ContractVerifierTest.java"); + then(FileUtils.readFileToString(test)).contains("hasSize(4)"); + } + @Test public void shouldGenerateStubs() throws Exception { File basedir = resources.getBasedir("generatedStubs"); diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic/src/test/resources/contracts/WithList.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic/src/test/resources/contracts/WithList.groovy new file mode 100644 index 0000000000..f542a19e9a --- /dev/null +++ b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic/src/test/resources/contracts/WithList.groovy @@ -0,0 +1,34 @@ +/** + * + * Copyright 2013-2016 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +org.springframework.cloud.contract.spec.Contract.make { + request { + method 'POST' + url('/users') { + + } + headers { + header 'Content-Type': 'application/json' + } + } + response { + status 200 + headers { + header 'Location': '/users/john' + } + body '''{ "list" : [ "login", "john", "name", "John The Contract" ] }''' + } +} \ No newline at end of file diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/config/ContractVerifierConfigProperties.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/config/ContractVerifierConfigProperties.groovy index 366c9c4c96..6e34af897e 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/config/ContractVerifierConfigProperties.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/config/ContractVerifierConfigProperties.groovy @@ -100,6 +100,6 @@ class ContractVerifierConfigProperties { * Incubating feature. You can check the size of JSON arrays. If not turned on * explicitly will be disabled. */ - Boolean assertJsonSize + Boolean assertJsonSize = false } diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockRequestStubStrategy.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockRequestStubStrategy.groovy index c156ec3aaa..2725e8c158 100755 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockRequestStubStrategy.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockRequestStubStrategy.groovy @@ -75,7 +75,8 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy { } ContentType contentType = tryToGetContentType(request.body.clientValue, request.headers) if (contentType == ContentType.JSON) { - JsonPaths values = JsonToJsonPathsConverter.transformToJsonPathWithStubsSideValues(getMatchingStrategyFromBody(request.body)?.clientValue) + JsonPaths values = JsonToJsonPathsConverter.transformToJsonPathWithStubsSideValuesAndNoArraySizeCheck( + getMatchingStrategyFromBody(request.body)?.clientValue) if (values.empty) { requestPattern.withRequestBody(WireMock.equalToJson(JsonOutput.toJson(getMatchingStrategy(request.body.clientValue).clientValue), false, false)) } else { diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/JsonToJsonPathsConverter.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/JsonToJsonPathsConverter.groovy index 7825035622..35ecbdc3e8 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/JsonToJsonPathsConverter.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/JsonToJsonPathsConverter.groovy @@ -53,14 +53,20 @@ class JsonToJsonPathsConverter { JsonToJsonPathsConverter() { this.configProperties = new ContractVerifierConfigProperties() + log.debug("Creating JsonToJsonPaths converter with default properties") } - public static JsonPaths transformToJsonPathWithTestsSideValues(def json) { - return new JsonToJsonPathsConverter().transformToJsonPathWithValues(json, SERVER_SIDE) + public JsonPaths transformToJsonPathWithTestsSideValues(def json) { + return transformToJsonPathWithValues(json, SERVER_SIDE) } - public static JsonPaths transformToJsonPathWithStubsSideValues(def json) { - return new JsonToJsonPathsConverter().transformToJsonPathWithValues(json, CLIENT_SIDE) + public JsonPaths transformToJsonPathWithStubsSideValues(def json) { + return transformToJsonPathWithValues(json, CLIENT_SIDE) + } + + public static JsonPaths transformToJsonPathWithStubsSideValuesAndNoArraySizeCheck(def json) { + return new JsonToJsonPathsConverter() + .transformToJsonPathWithValues(json, CLIENT_SIDE) } private JsonPaths transformToJsonPathWithValues(def json, boolean clientSide) { @@ -134,14 +140,19 @@ class JsonToJsonPathsConverter { // Size verification: https://github.com/Codearte/accurest/issues/279 private void addSizeVerificationForListWithPrimitives(MethodBufferingJsonVerifiable key, Closure closure, List value) { - Boolean systemPropValue = Boolean.parseBoolean(System.getProperty(SIZE_ASSERTION_SYSTEM_PROP, "false")) + String systemPropValue = System.getProperty(SIZE_ASSERTION_SYSTEM_PROP) Boolean configPropValue = configProperties.assertJsonSize - boolean configPropSet = configPropValue != null - if (configPropSet && !configPropValue) { - return - } else if (!configPropSet && systemPropValue) { + if ((systemPropValue != null && Boolean.parseBoolean(systemPropValue)) || + configPropValue) { + addArraySizeCheck(key, value, closure) + } else { + log.debug("Turning off the incubating feature of JSON array check. " + + "System property [$systemPropValue]. Config property [$configPropValue]") return } + } + + private void addArraySizeCheck(MethodBufferingJsonVerifiable key, List value, Closure closure) { log.debug("WARNING: Turning on the incubating feature of JSON array check") if (isRootElement(key) || key.assertsConcreteValue()) { if (value.size() > 0) { diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientMethodBuilderSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientMethodBuilderSpec.groovy index 849c06591d..46569c0a0a 100644 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientMethodBuilderSpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientMethodBuilderSpec.groovy @@ -18,11 +18,12 @@ package org.springframework.cloud.contract.verifier.builder import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties import org.springframework.cloud.contract.verifier.dsl.WireMockStubVerifier -import org.springframework.cloud.contract.verifier.file.ContractMetadata import org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockStubStrategy +import org.springframework.cloud.contract.verifier.file.ContractMetadata import spock.lang.Issue import spock.lang.Shared import spock.lang.Specification +import spock.util.environment.RestoreSystemProperties class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStubVerifier { @@ -114,6 +115,43 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) + then: + blockBuilder.toString().contains("""assertThatJson(parsedJson).field("property1").isEqualTo("a")""") + blockBuilder.toString().contains("""assertThatJson(parsedJson).array("property2").contains("a").isEqualTo("sth")""") + blockBuilder.toString().contains("""assertThatJson(parsedJson).array("property2").contains("b").isEqualTo("sthElse")""") + and: + stubMappingIsValidWireMockStub(new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null), contractDsl).toWireMockClientStub()) + where: + methodBuilderName | methodBuilder + "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } + "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } + } + + @Issue("#79") + @RestoreSystemProperties + def "should generate assertions for simple response body constructed from map with a list with #methodBuilderName with array size check"() { + given: + System.setProperty('spring.cloud.contract.verifier.assert.size', 'true') + org.springframework.cloud.contract.spec.Contract contractDsl = org.springframework.cloud.contract.spec.Contract.make { + request { + method "GET" + url "test" + } + response { + status 200 + body( + property1: 'a', + property2: [ + [a: 'sth'], + [b: 'sthElse'] + ] + ) + } + } + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) then: blockBuilder.toString().contains("""assertThatJson(parsedJson).field("property1").isEqualTo("a")""") blockBuilder.toString().contains("""assertThatJson(parsedJson).array("property2").contains("a").isEqualTo("sth")""") diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderSpec.groovy index 58a44e8193..a46d9c3a76 100644 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderSpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderSpec.groovy @@ -22,6 +22,7 @@ import org.springframework.cloud.contract.verifier.dsl.WireMockStubVerifier import spock.lang.Issue import spock.lang.Shared import spock.lang.Specification +import spock.util.environment.RestoreSystemProperties import java.util.regex.Pattern /** @@ -186,6 +187,43 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub then: blockBuilder.toString().contains("""assertThatJson(parsedJson).field("property1").isEqualTo("a")""") blockBuilder.toString().contains("""assertThatJson(parsedJson).array("property2").contains("a").isEqualTo("sth")""") + blockBuilder.toString().contains("""assertThatJson(parsedJson).array("property2").contains("b").isEqualTo("sthElse")""") + and: + stubMappingIsValidWireMockStub(contractDsl) + where: + methodBuilderName | methodBuilder + "MockMvcSpockMethodBuilder" | { Contract dsl -> new MockMvcSpockMethodRequestProcessingBodyBuilder(dsl, properties) } + "MockMvcJUnitMethodBuilder" | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } + } + + @Issue("#79") + @RestoreSystemProperties + def "should generate assertions for simple response body constructed from map with a list with #methodBuilderName with array size check"() { + given: + System.setProperty('spring.cloud.contract.verifier.assert.size', 'true') + Contract contractDsl = Contract.make { + request { + method "GET" + url "test" + } + response { + status 200 + body( + property1: 'a', + property2: [ + [a: 'sth'], + [b: 'sthElse'] + ] + ) + } + } + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + then: + blockBuilder.toString().contains("""assertThatJson(parsedJson).field("property1").isEqualTo("a")""") + blockBuilder.toString().contains("""assertThatJson(parsedJson).array("property2").contains("a").isEqualTo("sth")""") blockBuilder.toString().contains("""assertThatJson(parsedJson).array("property2").hasSize(2)""") blockBuilder.toString().contains("""assertThatJson(parsedJson).array("property2").contains("b").isEqualTo("sthElse")""") and: @@ -1271,6 +1309,41 @@ World.'''""" when: builder.then(blockBuilder) def test = blockBuilder.toString() + then: + test.contains('assertThatJson(parsedJson).arrayField().contains("Java8").value()') + test.contains('assertThatJson(parsedJson).arrayField().contains("Spring").value()') + test.contains('assertThatJson(parsedJson).arrayField().contains("Java").value()') + test.contains('assertThatJson(parsedJson).arrayField().contains("Stream").value()') + test.contains('assertThatJson(parsedJson).arrayField().contains("SpringBoot").value()') + where: + methodBuilderName | methodBuilder + "MockMvcSpockMethodBuilder" | { Contract dsl -> new MockMvcSpockMethodRequestProcessingBodyBuilder(dsl, properties) } + "MockMvcJUnitMethodBuilder" | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } + } + + @Issue('266') + @RestoreSystemProperties + def "should generate proper test code with top level array using #methodBuilderName with array size check"() { + given: + System.setProperty('spring.cloud.contract.verifier.assert.size', 'true') + Contract contractDsl = Contract.make { + request { + method 'GET' + urlPath '/api/tags' + } + response { + status 200 + body(["Java", "Java8", "Spring", "SpringBoot", "Stream"]) + headers { + header('Content-Type': 'application/json;charset=UTF-8') + } + } + } + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.then(blockBuilder) + def test = blockBuilder.toString() then: test.contains('assertThatJson(parsedJson).hasSize(5)') test.contains('assertThatJson(parsedJson).arrayField().contains("Java8").value()') @@ -1306,7 +1379,6 @@ World.'''""" builder.then(blockBuilder) def test = blockBuilder.toString() then: - test.contains('assertThatJson(parsedJson).hasSize(2)') test.contains('assertThatJson(parsedJson).array().arrayField().isEqualTo("Programming").value()') test.contains('assertThatJson(parsedJson).array().arrayField().isEqualTo("Java").value()') test.contains('assertThatJson(parsedJson).array().arrayField().isEqualTo("Spring").value()') diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/JsonToJsonPathsConverterSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/JsonToJsonPathsConverterSpec.groovy index aefe865f00..fb2e4152b3 100644 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/JsonToJsonPathsConverterSpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/JsonToJsonPathsConverterSpec.groovy @@ -25,6 +25,7 @@ import groovy.json.JsonOutput import groovy.json.JsonSlurper import net.minidev.json.JSONArray import spock.lang.Specification +import spock.util.environment.RestoreSystemProperties import java.util.regex.Pattern @@ -369,6 +370,36 @@ class JsonToJsonPathsConverterSpec extends Specification { it.method()== """.array("property2").contains("a").isEqualTo("sth")""" && it.jsonPath() == """\$.property2[*][?(@.a == 'sth')]""" } + pathAndValues.find { + it.method()== """.array("property2").contains("b").isEqualTo("sthElse")""" && + it.jsonPath() == """\$.property2[*][?(@.b == 'sthElse')]""" + } + and: + pathAndValues.size() == 3 + } + + @RestoreSystemProperties + def "should generate assertions for simple response body constructed from map with a list with array size check"() { + given: + System.setProperty('spring.cloud.contract.verifier.assert.size', 'true') + Map json = [ + property1: 'a', + property2: [ + [a: 'sth'], + [b: 'sthElse'] + ] + ] + when: + JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(json) + then: + pathAndValues.find { + it.method()== """.field("property1").isEqualTo("a")""" && + it.jsonPath() == """\$[?(@.property1 == 'a')]""" + } + pathAndValues.find { + it.method()== """.array("property2").contains("a").isEqualTo("sth")""" && + it.jsonPath() == """\$.property2[*][?(@.a == 'sth')]""" + } pathAndValues.find { it.method()== """.array("property2").hasSize(2)""" && it.jsonPath() == """\$.property2[*]""" @@ -410,6 +441,32 @@ class JsonToJsonPathsConverterSpec extends Specification { { "property1": "a" }, + { + "property2": "b" + }]""" + when: + JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(new JsonSlurper().parseText(json)) + then: + pathAndValues.find { + it.method()== """.array().contains("property1").isEqualTo("a")""" && + it.jsonPath() == """\$[*][?(@.property1 == 'a')]""" + } + pathAndValues.find { + it.method()== """.array().contains("property2").isEqualTo("b")""" && + it.jsonPath() == """\$[*][?(@.property2 == 'b')]""" + } + and: + pathAndValues.size() == 2 + } + + @RestoreSystemProperties + def "should generate assertions for array in response body with array size check"() { + given: + System.setProperty('spring.cloud.contract.verifier.assert.size', 'true') + String json = """[ + { + "property1": "a" + }, { "property2": "b" }]""" @@ -439,6 +496,31 @@ class JsonToJsonPathsConverterSpec extends Specification { { "property2": "test1"}, { "property3": "test2"} ] +}""" + when: + JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(new JsonSlurper().parseText(json)) + then: + pathAndValues.find { + it.method()== """.array("property1").contains("property2").isEqualTo("test1")""" && + it.jsonPath() == """\$.property1[*][?(@.property2 == 'test1')]""" + } + pathAndValues.find { + it.method()== """.array("property1").contains("property3").isEqualTo("test2")""" && + it.jsonPath() == """\$.property1[*][?(@.property3 == 'test2')]""" + } + and: + pathAndValues.size() == 2 + } + + @RestoreSystemProperties + def "should generate assertions for array inside response body element with array size check"() { + given: + System.setProperty('spring.cloud.contract.verifier.assert.size', 'true') + String json = """{ + "property1": [ + { "property2": "test1"}, + { "property3": "test2"} + ] }""" when: JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(new JsonSlurper().parseText(json)) @@ -517,7 +599,6 @@ class JsonToJsonPathsConverterSpec extends Specification { pathAndValues.size() == 1 } - def "should work with more complex stuff and jsonpaths"() { given: Map json = [ @@ -537,6 +618,31 @@ class JsonToJsonPathsConverterSpec extends Specification { it.method()== """.array("errors").contains("message").isEqualTo("incorrect_format")""" && it.jsonPath() == """\$.errors[*][?(@.message == 'incorrect_format')]""" } + and: + pathAndValues.size() == 2 + } + + @RestoreSystemProperties + def "should work with more complex stuff and jsonpaths with array size check"() { + given: + System.setProperty('spring.cloud.contract.verifier.assert.size', 'true') + Map json = [ + errors: [ + [property: "bank_account_number", + message: "incorrect_format"] + ] + ] + when: + JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(json) + then: + pathAndValues.find { + it.method()== """.array("errors").contains("property").isEqualTo("bank_account_number")""" && + it.jsonPath() == """\$.errors[*][?(@.property == 'bank_account_number')]""" + } + pathAndValues.find { + it.method()== """.array("errors").contains("message").isEqualTo("incorrect_format")""" && + it.jsonPath() == """\$.errors[*][?(@.message == 'incorrect_format')]""" + } pathAndValues.find { it.method()== """.array("errors").hasSize(1)""" && it.jsonPath() == """\$.errors[*]""" @@ -581,6 +687,52 @@ class JsonToJsonPathsConverterSpec extends Specification { it.method()== """.array().field("place").field("bounding_box").array("coordinates").array().arrayField().isEqualTo(38.791645)""" && it.jsonPath() == """\$[*].place.bounding_box.coordinates[*][*][?(@ == 38.791645)]""" } + and: + pathAndValues.size() == 4 + and: + pathAndValues.each { + JsonAssertion.assertThat(json).matchesJsonPath(it.jsonPath()) + } + } + + @RestoreSystemProperties + def "should manage to parse a double array with array size check"() { + given: + System.setProperty('spring.cloud.contract.verifier.assert.size', 'true') + String json = ''' + [{ + "place": + { + "bounding_box": + { + "coordinates": + [[ + [-77.119759,38.995548], + [-76.909393,38.791645] + ]] + } + } + }] + ''' + when: + JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(new JsonSlurper().parseText(json)) + then: + pathAndValues.find { + it.method()== """.array().field("place").field("bounding_box").array("coordinates").array().arrayField().isEqualTo(38.995548)""" && + it.jsonPath() == """\$[*].place.bounding_box.coordinates[*][*][?(@ == 38.995548)]""" + } + pathAndValues.find { + it.method()== """.array().field("place").field("bounding_box").array("coordinates").array().arrayField().isEqualTo(-77.119759)""" && + it.jsonPath() == """\$[*].place.bounding_box.coordinates[*][*][?(@ == -77.119759)]""" + } + pathAndValues.find { + it.method()== """.array().field("place").field("bounding_box").array("coordinates").array().arrayField().isEqualTo(-76.909393)""" && + it.jsonPath() == """\$[*].place.bounding_box.coordinates[*][*][?(@ == -76.909393)]""" + } + pathAndValues.find { + it.method()== """.array().field("place").field("bounding_box").array("coordinates").array().arrayField().isEqualTo(38.791645)""" && + it.jsonPath() == """\$[*].place.bounding_box.coordinates[*][*][?(@ == 38.791645)]""" + } pathAndValues.find { it.method()== """.hasSize(1)""" && it.jsonPath() == """\$"""