From f9961d17f69f2210c304ad61a0aa44e084af941e Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Wed, 14 Dec 2016 21:58:01 +0100 Subject: [PATCH] Fixed missing regex value generation without this change the autogenerated tests were wrong and contained a 'cursor' value with this change it got fixed fixes #168 --- README.adoc | 29 ++++++---- .../example/server/client1/expectation.groovy | 23 ++++---- .../fraud/shouldMarkClientAsFraud.groovy | 57 +++++++++---------- .../contract/spec/internal/Request.groovy | 8 +++ .../contract/spec/internal/Response.groovy | 8 +++ .../MockMvcMethodBodyBuilderSpec.groovy | 8 ++- 6 files changed, 81 insertions(+), 52 deletions(-) diff --git a/README.adoc b/README.adoc index c9fcc0cf37..09a0ee07f8 100644 --- a/README.adoc +++ b/README.adoc @@ -590,7 +590,7 @@ org.springframework.cloud.contract.spec.Contract.make { loanAmount: 99999 ]) headers { // (5) - header('Content-Type', 'application/vnd.fraud.v1+json') + contentType("application/vnd.fraud.v1+json") } } response { // (6) @@ -600,10 +600,7 @@ org.springframework.cloud.contract.spec.Contract.make { rejectionReason: "Amount too high" ]) headers { // (9) - header('Content-Type': value( - producer(regex('application/vnd.fraud.v1.json.*')), - consumer('application/vnd.fraud.v1+json')) - ) + contentType("application/vnd.fraud.v1+json") } } } @@ -871,16 +868,28 @@ That's because all the generated tests will extend that class. Over there you ca ---- package com.example.fraud; -import com.example.fraud.FraudDetectionController; -import com.jayway.restassured.module.mockmvc.RestAssuredMockMvc; - import org.junit.Before; +import com.jayway.restassured.module.mockmvc.RestAssuredMockMvc; + public class FraudBase { @Before public void setup() { - RestAssuredMockMvc.standaloneSetup(new FraudDetectionController()); + RestAssuredMockMvc.standaloneSetup(new FraudDetectionController(), + new FraudStatsController(stubbedStatsProvider())); + } + + private StatsProvider stubbedStatsProvider() { + return fraudType -> { + switch (fraudType) { + case DRUNKS: + return 100; + case ALL: + return 200; + } + return 0; + }; } public void assertThatRejectionReasonIsNull(Object rejectionReason) { @@ -1312,7 +1321,7 @@ Example of a `pom.xml` inside the `server` folder. UTF-8 1.8 1.1.0.BUILD-SNAPSHOT - Camden.BUILD-SNAPSHOT + Dalston.BUILD-SNAPSHOT diff --git a/samples/standalone/contracts/com/example/server/client1/expectation.groovy b/samples/standalone/contracts/com/example/server/client1/expectation.groovy index 47b9ba6662..e798cdc7eb 100644 --- a/samples/standalone/contracts/com/example/server/client1/expectation.groovy +++ b/samples/standalone/contracts/com/example/server/client1/expectation.groovy @@ -3,13 +3,13 @@ package contracts org.springframework.cloud.contract.spec.Contract.make { request { // (1) method 'PUT' // (2) - url '/fraudcheck1' // (3) + url '/fraudcheck' // (3) body([ // (4) - clientId: value(consumer(regex('[0-9]{10}'))), + clientId: $(regex('[0-9]{10}')), loanAmount: 99999 ]) headers { // (5) - header('Content-Type', 'application/vnd.fraud.v1+json') + contentType('application/vnd.fraud.v1+json') } } response { // (6) @@ -19,21 +19,20 @@ org.springframework.cloud.contract.spec.Contract.make { rejectionReason: "Amount too high" ]) headers { // (9) - header('Content-Type': value( - producer(regex('application/vnd.fraud.v1.json.*')), - consumer('application/vnd.fraud.v1+json')) - ) + contentType('application/vnd.fraud.v1+json') } } } /* Since we don't want to force on the user to hardcode values of fields that are dynamic -(timestamps, database ids etc.), one can provide parametrize those entries by using the -`value(consumer(...), producer(...))` method. That way what's present in the `consumer` -section will end up in the produced stub. What's there in the `producer` will end up in the -autogenerated test. If you provide only the regular expression side without the concrete -value then Spring Cloud Contract will generate one for you. +(timestamps, database ids etc.), one can parametrize those entries. If you wrap your field's + value in a `$(...)` or `value(...)` and provide a dynamic value of a field then + the concrete value will be generated for you. If you want to be really explicit about + which side gets which value you can do that by using the `value(consumer(...), producer(...))` notation. + That way what's present in the `consumer` section will end up in the produced stub. What's + there in the `producer` will end up in the autogenerated test. If you provide only the + regular expression side without the concrete value then Spring Cloud Contract will generate one for you. From the Consumer perspective, when shooting a request in the integration test: diff --git a/samples/standalone/dsl/http-server/src/test/resources/contracts/fraud/shouldMarkClientAsFraud.groovy b/samples/standalone/dsl/http-server/src/test/resources/contracts/fraud/shouldMarkClientAsFraud.groovy index 1745c3dffa..e798cdc7eb 100644 --- a/samples/standalone/dsl/http-server/src/test/resources/contracts/fraud/shouldMarkClientAsFraud.groovy +++ b/samples/standalone/dsl/http-server/src/test/resources/contracts/fraud/shouldMarkClientAsFraud.groovy @@ -1,39 +1,38 @@ package contracts org.springframework.cloud.contract.spec.Contract.make { - request { // (1) - method 'PUT' // (2) - url '/fraudcheck' // (3) - body([ // (4) - clientId: value(consumer(regex('[0-9]{10}'))), - loanAmount: 99999 - ]) - headers { // (5) - header('Content-Type', 'application/vnd.fraud.v1+json') - } - } - response { // (6) - status 200 // (7) - body([ // (8) - fraudCheckStatus: "FRAUD", - rejectionReason: "Amount too high" - ]) - headers { // (9) - header('Content-Type': value( - producer(regex('application/vnd.fraud.v1.json.*')), - consumer('application/vnd.fraud.v1+json')) - ) - } - } + request { // (1) + method 'PUT' // (2) + url '/fraudcheck' // (3) + body([ // (4) + clientId: $(regex('[0-9]{10}')), + loanAmount: 99999 + ]) + headers { // (5) + contentType('application/vnd.fraud.v1+json') + } + } + response { // (6) + status 200 // (7) + body([ // (8) + fraudCheckStatus: "FRAUD", + rejectionReason: "Amount too high" + ]) + headers { // (9) + contentType('application/vnd.fraud.v1+json') + } + } } /* Since we don't want to force on the user to hardcode values of fields that are dynamic -(timestamps, database ids etc.), one can provide parametrize those entries by using the -`value(consumer(...), producer(...))` method. That way what's present in the `consumer` -section will end up in the produced stub. What's there in the `producer` will end up in the -autogenerated test. If you provide only the regular expression side without the concrete -value then Spring Cloud Contract will generate one for you. +(timestamps, database ids etc.), one can parametrize those entries. If you wrap your field's + value in a `$(...)` or `value(...)` and provide a dynamic value of a field then + the concrete value will be generated for you. If you want to be really explicit about + which side gets which value you can do that by using the `value(consumer(...), producer(...))` notation. + That way what's present in the `consumer` section will end up in the produced stub. What's + there in the `producer` will end up in the autogenerated test. If you provide only the + regular expression side without the concrete value then Spring Cloud Contract will generate one for you. From the Consumer perspective, when shooting a request in the integration test: diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Request.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Request.groovy index 372728945e..b43f940111 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Request.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Request.groovy @@ -196,6 +196,14 @@ class Request extends Common { return value(client) } + DslProperty value(Pattern client) { + return value(new ClientDslProperty(client)) + } + + DslProperty $(Pattern client) { + return value(client) + } + @Override DslProperty value(ClientDslProperty client, ServerDslProperty server) { if (server.clientValue instanceof Pattern) { diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Response.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Response.groovy index 8e9acdd792..d758605642 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Response.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Response.groovy @@ -103,6 +103,14 @@ class Response extends Common { return value(server) } + DslProperty value(Pattern server) { + return value(new ServerDslProperty(server)) + } + + DslProperty $(Pattern server) { + return value(server) + } + @Override DslProperty value(ClientDslProperty client, ServerDslProperty server) { if (client.clientValue instanceof Pattern) { 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 430d6986c7..74712d1b2a 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 @@ -1697,6 +1697,7 @@ World.'''""" } @Issue('#149') + @Unroll def "should allow easier way of providing dynamic values"() { given: Contract contractDsl = Contract.make { @@ -1704,6 +1705,7 @@ World.'''""" method 'GET' urlPath '/get' body([ + duck: $(regex("[0-9]")), alpha: $(anyAlphaUnicode()), number: $(anyNumber()), aBoolean: $(aBoolean()), @@ -1734,7 +1736,7 @@ World.'''""" } } } - MethodBodyBuilder builder = new MockMvcSpockMethodRequestProcessingBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = methodBuilder(contractDsl) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -1749,6 +1751,10 @@ World.'''""" test.contains('assertThatJson(parsedJson).field("ip").matches("([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])\\\\.([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])\\\\.([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])\\\\.([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])")') test.contains('assertThatJson(parsedJson).field("uuid").matches("[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}")') !test.contains('cursor') + where: + methodBuilder << [{ Contract dsl -> new MockMvcSpockMethodRequestProcessingBodyBuilder(dsl, properties)}, + { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties)}] + } @Issue('#162')