Does not do JSON assertions for byte payloads

without this change we're doing json assertions for payload that should read payloads as bytes

this is a workaround around the issues like https://github.com/spring-cloud/spring-cloud-contract/issues/1701 and https://github.com/spring-cloud/spring-cloud-contract/issues/1627 .

The problem is that due to the fact that we accept GString payloads where you can have complex json structures with consumer / producer parts, we are doing recursive analysis of that json structure. We're parsing the keys and values and then we're creating the final Json payload map. The issue is that sometimes the value is actually textual json which we shouldn't parse. We don't know that when the processing happens.

The workaround is about telling the framework to read the payload from a file as bytes and then simple equality check will happen without additional JSON assertions.

We will need to look into some better fixes for that in the future (e.g. 5.0.0).

fixes gh-1627
fixes gh-1701
This commit is contained in:
Marcin Grzejszczak
2023-04-26 14:03:18 +02:00
parent ee52a9f6ae
commit a2444550d5
4 changed files with 124 additions and 0 deletions

View File

@@ -27,6 +27,7 @@ import org.apache.commons.text.StringEscapeUtils;
import org.springframework.cloud.contract.spec.ContractTemplate;
import org.springframework.cloud.contract.spec.internal.BodyMatchers;
import org.springframework.cloud.contract.spec.internal.ExecutionProperty;
import org.springframework.cloud.contract.spec.internal.FromFileProperty;
import org.springframework.cloud.contract.verifier.config.TestFramework;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
import org.springframework.cloud.contract.verifier.template.HandlebarsTemplateProcessor;
@@ -195,6 +196,10 @@ class GenericJsonBodyThen implements Then {
@Override
public boolean accept(SingleContractMetadata metadata) {
Object responseBody = this.bodyParser.responseBody(metadata).getServerValue();
if (responseBody instanceof FromFileProperty) {
return !((FromFileProperty) responseBody).isByte();
}
ContentType outputTestContentType = metadata.getOutputTestContentType();
return JSON == outputTestContentType || mostLikelyJson(outputTestContentType, metadata);
}

View File

@@ -1679,6 +1679,119 @@ public class FooTest {
assertThatJson(parsedJson).field("['uid']").matches("[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}");
}
}
"""
}
@Issue('#1701')
def "should generate output for message whose body is json and contains string that looks like json [#methodBuilderName]"() {
given:
Contract contractDsl = org.springframework.cloud.contract.spec.Contract.make {
name "foo"
description 'issue #650'
label 'trigger'
input {
triggeredBy('toString()')
}
outputMessage {
sentTo("foo")
headers {
messagingContentType(applicationJson())
}
body(fileAsBytes('messageResponse.json'))
}
}
methodBuilder()
when:
String test = singleTestGenerator(contractDsl)
then:
!test.contains('cursor')
!test.contains('REGEXP>>')
test.trim() == expectedTest.trim()
where:
methodBuilderName | methodBuilder | expectedTest
"spock" | { properties.testFramework = TestFramework.SPOCK } | """\
package com.example
import com.jayway.jsonpath.DocumentContext
import com.jayway.jsonpath.JsonPath
import spock.lang.Specification
import javax.inject.Inject
import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper
import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage
import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging
import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat
import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.*
import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson
import static org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers
import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.fileToBytes
@SuppressWarnings("rawtypes")
class FooSpec extends Specification {
@Inject ContractVerifierMessaging contractVerifierMessaging
@Inject ContractVerifierObjectMapper contractVerifierObjectMapper
def validate_foo() throws Exception {
when:
toString()
then:
ContractVerifierMessage response = contractVerifierMessaging.receive("foo",
contract(this, "foo.yml"))
response != null
and:
response.getHeader("contentType") != null
response.getHeader("contentType").toString() == 'application/json'
and:
response.getPayloadAsByteArray() == fileToBytes(this, "foo_response_messageResponse.json")
}
}
"""
"junit" | { properties.testFramework = TestFramework.JUNIT } | """\
package com.example;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import org.junit.Test;
import org.junit.Rule;
import javax.inject.Inject;
import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper;
import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage;
import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging;
import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat;
import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.*;
import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson;
import static org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers;
import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.fileToBytes;
@SuppressWarnings("rawtypes")
public class FooTest {
@Inject ContractVerifierMessaging contractVerifierMessaging;
@Inject ContractVerifierObjectMapper contractVerifierObjectMapper;
@Test
public void validate_foo() throws Exception {
// when:
toString();
// then:
ContractVerifierMessage response = contractVerifierMessaging.receive("foo",
contract(this, "foo.yml"));
assertThat(response).isNotNull();
// and:
assertThat(response.getHeader("contentType")).isNotNull();
assertThat(response.getHeader("contentType").toString()).isEqualTo("application/json");
// and:
assertThat(response.getPayloadAsByteArray()).isEqualTo(fileToBytes(this, "foo_response_messageResponse.json"));
}
}
"""
}

View File

@@ -0,0 +1,3 @@
{
"payload": "{\"propsA\":\"valueA\",\"propsB\":\"valueB\"}"
}

View File

@@ -0,0 +1,3 @@
{
"payload": "{\"propsA\":\"valueA\",\"propsB\":\"valueB\"}"
}