The idea is to have one file for both - contract definition and contract test specification.
I found the plugin 'guru.springframework:spring-cloud-contract-oa3:2.1.2.0' which should make what I want but it fails for me. I based my config on the examples from this repo https://github.com/springframeworkguru/sccoa3-fraud-example
Here is the error message after executing
gradle build clean
Error Processing yaml file. Skipping Contract Generation
java.lang.IllegalStateException: Exception occurred while processing the file [.../build/stubs/META-INF/com.bla.bla/api-mlpe/0.0.1-SNAPSHOT/contracts/v1/0/openapi.yml]
...
Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "openapi" (class org.springframework.cloud.contract.verifier.converter.YamlContract), not marked as ignorable (10 known properties: "response", "ignored", "label", "outputMessage", "input", "name", "description", "request", "inProgress", "priority"])
at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: org.springframework.cloud.contract.verifier.converter.YamlContract["openapi"])
here is my build.gradle config
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.springframework.cloud:spring-cloud-contract-gradle-plugin:2.2.4.RELEASE'
}
}
plugins {
id 'org.springframework.boot' version '2.3.4.RELEASE'
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
id 'java'
}
apply plugin: 'spring-cloud-contract'
group = 'com.bla.bla'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
repositories {
mavenCentral()
}
ext {
set('springCloudVersion', "Hoxton.SR8")
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework:spring-web:5.2.9.RELEASE'
implementation 'guru.springframework:spring-cloud-contract-oa3:2.1.2.0'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
testImplementation 'org.springframework.cloud:spring-cloud-starter-contract-verifier'
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
contracts {
testFramework = org.springframework.cloud.contract.verifier.config.TestFramework.JUNIT5
}
test {
useJUnitPlatform()
testLogging {
exceptionFormat = 'full'
}
}
and here is openapi.yml (based on the repo mentioned earlier and placed under test/resources/contracts)
openapi: 3.0.3
info:
description: Spring Cloud Contract Verifier Http Server OA3 Sample
version: "1.0.0"
title: Fraud Service API
paths:
/v1/consumers/global-consumers:
put:
summary: Perform Fraud Check
x-contracts:
- contractId: 1
name: Should Mark Client as Fraud
priority: 1
- contractId: 2
name: Should Not Mark Client as Fraud
requestBody:
content:
application/json:
schema:
type: object
properties:
"client.id":
type: integer
loanAmount:
type: integer
#START REQUEST - part with SPEC definitions
x-contracts:
- contractId: 1
body:
"client.id": 1234567890
loanAmount: 99999
matchers:
body:
- path: $.['client.id']
type: by_regex
value: "[0-9]{10}"
- contractId: 2
body:
"client.id": 1234567890
loanAmount: 123.123
matchers:
body:
- path: $.['client.id']
type: by_regex
value: "[0-9]{10}"
#END REQUEST - part with SPEC definitions
responses:
'200':
description: created ok
content:
application/json:
schema:
type: object
properties:
fraudCheckStatus:
type: string
"rejection.reason":
type: string
#START RESPONSE - part with SPEC definitions
x-contracts:
- contractId: 1
body:
fraudCheckStatus: "FRAUD"
"rejection.reason": "Amount too high"
headers:
Content-Type: application/json;charset=UTF-8
- contractId: 2
body:
fraudCheckStatus: "OK"
"rejection.reason": null
headers:
Content-Type: application/json;charset=UTF-8
matchers:
body:
- path: $.['rejection.reason']
type: by_command
value: assertThatRejectionReasonIsNull($it)
#END RESPONSE - part with SPEC definitions
Apart from the fact that it fails I am not sure If my configuration is proper to achieve my goal :-) My goal is to have one file describing contract (in OpenApi3 standard) including contract test specification (in the same file which should not break the OpenAPI3 spec standard) and basing on this file I want to generate:
Is it possible to have all of them in the way that I specified ? If yes - how to achieve that ? The mentioned plugin is not working for me in the provided configuration.
You need to add the guru.springframework:spring-cloud-contract-oa3:2.1.2.0
dependency to the plugin's classpath not to the project's classpath.
Not like this:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.springframework.cloud:spring-cloud-contract-gradle-plugin:2.2.4.RELEASE'
}
}
plugins {
id 'org.springframework.boot' version '2.3.4.RELEASE'
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
id 'java'
}
Like this:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.springframework.cloud:spring-cloud-contract-gradle-plugin:2.2.4.RELEASE'
classpath 'guru.springframework:spring-cloud-contract-oa3:2.1.2.0'
}
}
plugins {
id 'org.springframework.boot' version '2.3.4.RELEASE'
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
id 'java'
}
We describe that also in the docs (on another example) https://docs.spring.io/spring-cloud-contract/docs/2.2.4.RELEASE/reference/html/advanced.html#customization-plugin-dep
Oh such a lame mistake. Thanks @marcin-grzejszczak After applying changes it looks better. Parsing yaml spec works.
Now I have issue in the generateClientStubs
after running
gradle clean build -x test --stacktrace
I’m getting
Execution failed for task ':generateClientStubs'.
13:43:33.759 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] > Class org.springframework.cloud.contract.verifier.converter.YamlContract does not implement the requested interface groovy.lang.GroovyObject
….
Caused by: java.lang.IncompatibleClassChangeError: Class org.springframework.cloud.contract.verifier.converter.YamlContract does not implement the requested interface groovy.lang.GroovyObject
at org.springframework.cloud.contract.verifier.converter.OpenApiContractConverter$_convertFrom_closure2$_closure5$_closure6.doCall(OpenApiContractConverter.groovy:84)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
I found the issue reported some time ago which looks pretty similar [https://github.com/spring-cloud/spring-cloud-contract/issues/1289] Now the versions defined in my build gradle are the ones generated via spring initializr two days ago so I am assuming that they should be compatible. Is it possible that this issue comes from the added ‘guru.springframework:spring-cloud-contract-oa3’ plugin ? At first glance it rather looks like the mentioned similar reported issue.