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

Incorrect autogenerated test for an array with one unique value #1091

Closed aaguila closed 5 years ago

aaguila commented 5 years ago

I think that the issue could be related with https://github.com/spring-cloud/spring-cloud-contract/issues/880 issue, but the error case is different.

When we create a contract where the response is array object with a one unique value the autogenerated test assert that the object is empty.

image

In case of adding an another value to the array, the autogenerated tests will be ok. But we need to have a response with one value in the array.

image

In this case the autogenerated test only assert the last value of the array.

Build.gradle info

buildscript { repositories { mavenCentral() } dependencies { classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:2.1.1.RELEASE" } }

plugins { id 'org.springframework.boot' version '2.1.5.RELEASE' }

dependencies { testImplementation 'org.springframework.cloud:spring-cloud-starter-contract-verifier:2.1.1.RELEASE' }

Thanks for all :)

OlgaMaciaszek commented 5 years ago

Hello @aaguila Thanks for reporting an issue. Please do not paste screenshot and paste code (or link to a GH repo with the code) instead.

Please provide the contract that resulted in this test being generated.

aaguila commented 5 years ago

Hi Olga, thanks for the response. Sure, the contract code:

description: |
  Represents a successful scenario of getting the product variants with a country and date
#
# when:
#  the call is submitted
# then:
#  the list of all product variants be obtained
#
name: should find all product variants based on date and country
request:
  method: GET
  url: /catalog/variants?barcodes=0000000084659,0000000062152&price.country=ES&price.date=2019-05-29
  headers:
    Content-Type: application/json
response:
  status: 200
  body:
    -
      id: "652a506c-81a0-41c8-8be0-2b550a8bcd4c"
      barcode: "0000000084659"
      prices:
        -
          country: "ES"
          original_price: 1500
          discounted_price: 750
          discount_start_date: "2019-05-28"
          discount_end_date: "2019-05-30"
          discount: 50

  matchers:
    body:
      -
        path: "$.[0].id"
        type: by_regex
        predefined: uuid
      -
        path: "$.[0].barcode"
        type: by_regex
        predefined: non_blank
      -
        path: "$.[0].prices[0].country"
        type: by_regex
        predefined: non_blank
      -
        path: "$.[0].prices[0].original_price"
        type: by_regex
        predefined: number
      -
        path: "$.[0].prices[0].discounted_price"
        type: by_regex
        predefined: number
      -
        path: "$.[0].prices[0].discount_start_date"
        type: by_regex
        predefined: non_blank
      -
        path: "$.[0].prices[0].discount_end_date"
        type: by_regex
        predefined: non_blank
      -
        path: "$.[0].prices[0].discount"
        type: by_regex
        predefined: number
  headers:
    Content-Type: application/json;charset=UTF-8

And the generated test:

package contract.test;

import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import contract.base.GetProductVariantsControllerBase;
import io.restassured.module.mockmvc.specification.MockMvcRequestSpecification;
import io.restassured.response.ResponseOptions;
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.junit.jupiter.api.Test;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;

import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson;
import static io.restassured.module.mockmvc.RestAssuredMockMvc.*;
import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat;
import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.*;

public class GetProductVariantsControllerTest extends GetProductVariantsControllerBase {

    @Test
    public void validate_should_find_all_product_variants_based_on_date_and_country() throws Exception {
        // given:
            MockMvcRequestSpecification request = given()
                    .header("Content-Type", "application/json");

        // when:
            ResponseOptions response = given().spec(request)
                    .get("/catalog/variants?barcodes=0000000084659,0000000062152&price.country=ES&price.date=2019-05-29");

        // then:
            assertThat(response.statusCode()).isEqualTo(200);
            assertThat(response.header("Content-Type")).isEqualTo("application/json;charset=UTF-8");
        // and:
            DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
            assertThatJson(parsedJson).array().array("['prices']").isEmpty();
        // and:
            assertThat(parsedJson.read("$.[0].id", String.class)).matches("[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}");
            assertThat(parsedJson.read("$.[0].barcode", String.class)).matches("^\\s*\\S[\\S\\s]*");
            assertThat(parsedJson.read("$.[0].prices[0].country", String.class)).matches("^\\s*\\S[\\S\\s]*");
            assertThat(parsedJson.read("$.[0].prices[0].original_price", String.class)).matches("-?(\\d*\\.\\d+|\\d+)");
            assertThat(parsedJson.read("$.[0].prices[0].discounted_price", String.class)).matches("-?(\\d*\\.\\d+|\\d+)");
            assertThat(parsedJson.read("$.[0].prices[0].discount_start_date", String.class)).matches("^\\s*\\S[\\S\\s]*");
            assertThat(parsedJson.read("$.[0].prices[0].discount_end_date", String.class)).matches("^\\s*\\S[\\S\\s]*");
            assertThat(parsedJson.read("$.[0].prices[0].discount", String.class)).matches("-?(\\d*\\.\\d+|\\d+)");
    }

}
aaguila commented 5 years ago

Hi :) Any news about this issue? Thanks!

OlgaMaciaszek commented 5 years ago

Hi @aaguila It is a bug. I was able to reproduce it. We'll work on a fix.

OlgaMaciaszek commented 5 years ago

Hi @aaguila Sorry for the confusion - this apparently has already been fixed. When I triage it on the following versions:

Spring Boot: 2.1.6.RELEASE Spring Cloud Release Train: Greenwich.SR2 Spring Cloud Contract: 2.1.2.RELEASE

I can't reproduce the issue. Please verify on these versions.

aaguila commented 5 years ago

Hi Olga. Thanks for the answer :). We have updated the versions, but we still have the same problem :(. If you want I can send you more data. Maybe with groovy DSL the error will not happen.

Regards,

OlgaMaciaszek commented 5 years ago

Hi @aaguila could you provide a Please provide a minimal, complete, verifiable example that reproduces the issue? A small project on GH or in .zip where you will have the contract, the build files setup and the controller that reproduces this issue? I

aaguila commented 5 years ago

Hi @OlgaMaciaszek :),

I have added a dummy example project with the same problem (the project have the versions that you said previously).

scc-example.zip

OlgaMaciaszek commented 5 years ago

Hi, @aaguila so it actually only happens when the matchers section is present and later on I have tested without it. The bug is there. We'll provide a fix. Thanks.

aaguila commented 5 years ago

Thanks to you :)