spring-cloud / spring-cloud-contract

Support for Consumer Driven Contracts in Spring
https://cloud.spring.io/spring-cloud-contract
Apache License 2.0
720 stars 440 forks source link

Add ability to map Custom DSL to stub generation #1745

Closed jamietanna closed 2 years ago

jamietanna commented 2 years ago

Is your feature request related to a problem? Please describe.

When using the Custom DSL, such as:

BaseTestClass ```java package uk.gov.api.springboot.contract; import io.restassured.module.mockmvc.RestAssuredMockMvc; import java.util.UUID; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.annotation.DirtiesContext; import org.springframework.web.context.WebApplicationContext; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) @DirtiesContext public class BaseTestClass { @Autowired WebApplicationContext context; @BeforeEach void setup() { RestAssuredMockMvc.webAppContextSetup(context); } public String correlationId() { return UUID.randomUUID().toString(); } } ```

A contract such as:

canGet.groovy ```groovy package contracts.example import org.springframework.cloud.contract.spec.Contract Contract.make { request { method 'GET' url '/apis' headers { accept('application/*+json') header('correlation-id', execute('correlationId()')) } } response { status OK() headers { contentType('application/vnd.uk.gov.api.v1alpha+json') } } } ```

Gets created as the following:

canGet.json ```json { "id" : "32eb1ebb-32d6-463a-a660-b898f5102cc7", "request" : { "url" : "/apis", "method" : "GET", "headers" : { "Accept" : { "matches" : "application/\\*\\+json.*" }, "correlation-id" : { "equalTo" : "correlationId()" } } }, "response" : { "status" : 200, "headers" : { "Content-Type" : "application/vnd.uk.gov.api.v1alpha+json" }, "transformers" : [ "response-template", "spring-cloud-contract" ] }, "uuid" : "32eb1ebb-32d6-463a-a660-b898f5102cc7" } ```

However, there is no definition available to Wiremock for what correlationId() provides, so will fail, which reduces the utility of extending the DSL.

Describe the solution you'd like

Either:

Describe alternatives you've considered

N/A

Additional context

N/A

marcingrzejszczak commented 2 years ago

Why not call

      header('correlation-id', $(p(execute('correlationId()')), c("abcdefgh")))

so for the producer side you call a method and for the consumer you're explicit about the value?

jamietanna commented 2 years ago

That's a good shout - that would solve this problem :+1:

A slightly more complex example I'd want to use is where we're producing an ID Token or a JWT-based Access Token, which for the purpose of our tests would need to be in a specific format, possibly with some claims, and most importantly, signed for the server it's executing against.

It's unlikely that the consumer's integrated service works with the same signing key that the local test version does, so we'd want it dynamic.

See also the use of a client_secret or other authentication/authorization means that wouldn't be ideal to track in source control

marcingrzejszczak commented 2 years ago

I wouldn't expect that secret or token to be one from production. That would have to be a test version that would be used instead of a real one in your tests.

jamietanna commented 2 years ago

Interesting, thanks. This looks similar to what Pact recommends so looks like the way that most folks would assume to have this done :+1:

I think this issue can be closed - is there anything else we want to add to track / better document the syntax you mentioned above so folks don't have stubs that will never match correctly?

marcingrzejszczak commented 2 years ago

I think that's all (we describe the producer(...) and consumer(...) methods in the docs https://docs.spring.io/spring-cloud-contract/docs/3.1.0/reference/html/project-features.html#contract-dsl-dynamic-properties-in-body ). Thanks for reporting the issue :)