pactpact-javapact-jvm

pact-jvm : how to solve au.com.dius.pact.consumer.PactMismatchesException


I am trying to generate a pact between 2 of our services using pact-JVM. But when I try to run the Java class, I get this exception.

1) I suspect something is wrong with the Pact body, is that correct? There is an extra 'message' parameter in the JSON body of the PactDslWithProvider,but in the runTest1() method, I am equating only the lists and when I inspect the results, they are same to me. 2) Is it correct to provide the actual provider URL in the runTest1() method? (the provider is already in place)

au.com.dius.pact.consumer.PactMismatchesException: The following requests were not received:
method: GET
path: /devices/v1
query: [externalId:[0942dc67-35de-44f7-a061-743f59436a98]]
headers: [:]
matchers: MatchingRules(rules=[:])
generators: Generators(categories={})
body: OptionalBody(state=MISSING, value=null)

Below is my Java class

public class PactForDevice {
    Map<String, String> headers = MapUtils.putAll(new HashMap<String, String>(), new String[]{"Content-Type", "application/json;charset=UTF-8"});

@Rule
public PactProviderRuleMk2 provider = new PactProviderRuleMk2("device-service-m", this);

@Pact(consumer = "device-r", provider = "device-service-m")
public RequestResponsePact createFragment(PactDslWithProvider builder) {

    return builder
            .given("Device M details")
            .uponReceiving("retrieving Device details")
            .path("/devices/v1")
            .method("GET")
            .query("externalId=0942dc67-35de-44f7-a061-743f59436a98")
            .willRespondWith()
            .headers(headers)
            .status(200)
            .body("{" +
                    "\"data\": [,\n " +
                    "{ \n" +
                    " \"dateRegistered\": \"2017-07-13T11:10:51.000+12:00\",\n" +
                    " \"alias\": \"\",\n" +
                    " \"id\": \"a02b14ee72192ab3\",\n" +
                    " \"description\": \"Samsung SM-G930F\",\n" +
                    " \"title\": \"a02b14ee72192ab3\",\n" +
                    " \"externalId\": \"0942dc67-35de-44f7-a061-743f59436a98\"\n" +
                    "},\n" +
                    "{\n" +
                    " \"dateRegistered\": \"2017-07-13T10:45:51.000+12:00\",\n" +
                    " \"alias\": \"\",\n" +
                    " \"id\": \"a41c3af56ec35874\",\n" +
                    " \"description\": \"Samsung SM-T819\",\n" +
                    " \"title\": \"a41c3af56ec35874\",\n" +
                    " \"externalId\": \"0942dc67-35de-44f7-a061-743f59436a98\"\n" +
                    " },\n" +
                    " {\n" +
                    " \"dateRegistered\": \"2017-07-13T10:45:31.000+12:00\",\n" +
                    " \"alias\": \"\",\n" +
                    " \"id\": \"bd2b027bbd0a2f17\",\n" +
                    " \"description\": \"Samsung SM-A320Y\",\n" +
                    " \"title\": \"bd2b027bbd0a2f17\",\n" +
                    " \"externalId\": \"0942dc67-35de-44f7-a061-743f59436a98\"\n" +
                    " }\n" +
                    "],\n" +
                    " \"message\": \"3 devices found for the user 0942dc67-35de-44f7-a061-743f59436a98\"\n" +
                    "}")
            .toPact();
}

@PactVerification("device-service-m")
@Test
@JsonIgnoreProperties(ignoreUnknown = true)
public void runTest1() throws IOException {

    final GetDevicesResponse deviceResponse = new GetDevicesResponse();

    final List<Device> deviceList = new ArrayList<>();
    Device dev = new Device();
    dev.withDateRegistered("2017-07-13T11:10:51.000+12:00");
    dev.withAlias("");
    dev.withId("a02b14ee72192ab3");
    dev.withDescription("Samsung SM-G930F");
    dev.withTitle("a02b14ee72192ab3");
    dev.withExternalId("0942dc67-35de-44f7-a061-743f59436a98");
    deviceList.add(dev);

    Device dev1 = new Device();
    dev1.withDateRegistered("2017-07-13T10:45:51.000+12:00");
    dev1.withAlias("");
    dev1.withId("a41c3af56ec35874");
    dev1.withDescription("Samsung SM-T819");
    dev1.withTitle("a41c3af56ec35874");
    dev1.withExternalId("0942dc67-35de-44f7-a061-743f59436a98");
    deviceList.add(dev1);

    Device dev2 = new Device();
    dev2.withDateRegistered("2017-07-13T10:45:31.000+12:00");
    dev2.withAlias("");
    dev2.withId("bd2b027bbd0a2f17");
    dev2.withDescription("Samsung SM-A320Y");
    dev2.withTitle("bd2b027bbd0a2f17");
    dev2.withExternalId("0942dc67-35de-44f7-a061-743f59436a98");
    deviceList.add(dev2);

    deviceResponse.setDevices(deviceList);

    final RestTemplate restTemplate = new RestTemplate();
    GetDevicesResponse devices = restTemplate.getForObject("http://localhost:8091/devices/v1?externalId=0942dc67-35de-44f7-a061-743f59436a98", GetDevicesResponse.class);

    assertThat(devices, sameBeanAs(deviceResponse));

}  

}

EDIT:

I just found that if I comment out @Rule part, the test is getting passed - but a pact file is not getting generated. Shouod I explicitly specify a "pact" folder for that?


Solution

  • I had a similar issue with pacts not being generated after the test would run. I never got them to work using the annotation approach, instead I solved it by extending ConsumerPactTestMk2. Pact will setup the mockserver and mock the response for you.

    public class PactForDevice extends ConsumerPactTestMk2 {
        Map<String, String> headers = MapUtils.putAll(new HashMap<String, String>(), new String[]{"Content-Type", "application/json;charset=UTF-8"});
    
        public RequestResponsePact createPact(PactDslWithProvider builder) {
            return builder
              .given("Device M details")
              .uponReceiving("retrieving Device details")
              .path("/devices/v1")
              .method("GET")
              .query("externalId=0942dc67-35de-44f7-a061-743f59436a98")
              .willRespondWith()
              .headers(headers)
              .status(200)
              .body("{" +
                    "\"data\": [,\n " +
                    "{ \n" +
                    " \"dateRegistered\": \"2017-07-13T11:10:51.000+12:00\",\n" +
                    " \"alias\": \"\",\n" +
                    " \"id\": \"a02b14ee72192ab3\",\n" +
                    " \"description\": \"Samsung SM-G930F\",\n" +
                    " \"title\": \"a02b14ee72192ab3\",\n" +
                    " \"externalId\": \"0942dc67-35de-44f7-a061-743f59436a98\"\n" +
                    "},\n" +
                    "{\n" +
                    " \"dateRegistered\": \"2017-07-13T10:45:51.000+12:00\",\n" +
                    " \"alias\": \"\",\n" +
                    " \"id\": \"a41c3af56ec35874\",\n" +
                    " \"description\": \"Samsung SM-T819\",\n" +
                    " \"title\": \"a41c3af56ec35874\",\n" +
                    " \"externalId\": \"0942dc67-35de-44f7-a061-743f59436a98\"\n" +
                    " },\n" +
                    " {\n" +
                    " \"dateRegistered\": \"2017-07-13T10:45:31.000+12:00\",\n" +
                    " \"alias\": \"\",\n" +
                    " \"id\": \"bd2b027bbd0a2f17\",\n" +
                    " \"description\": \"Samsung SM-A320Y\",\n" +
                    " \"title\": \"bd2b027bbd0a2f17\",\n" +
                    " \"externalId\": \"0942dc67-35de-44f7-a061-743f59436a98\"\n" +
                    " }\n" +
                    "],\n" +
                    " \"message\": \"3 devices found for the user 0942dc67-35de-44f7-a061-743f59436a98\"\n" +
                    "}")
            .toPact();
        }
    
        @Override
        protected String providerName() {
            return "device-service-m";
        }
    
        @Override
        protected String consumerName() {
            return "device-r";
        }
    
        @Override
        protected void runTest(MockServer mockServer) throws IOException {
            final GetDevicesResponse deviceResponse = new GetDevicesResponse();
    
            final List<Device> deviceList = new ArrayList<>();
            Device dev = new Device();
            dev.withDateRegistered("2017-07-13T11:10:51.000+12:00");
            dev.withAlias("");
            dev.withId("a02b14ee72192ab3");
            dev.withDescription("Samsung SM-G930F");
            dev.withTitle("a02b14ee72192ab3");
            dev.withExternalId("0942dc67-35de-44f7-a061-743f59436a98");
            deviceList.add(dev);
    
            Device dev1 = new Device();
            dev1.withDateRegistered("2017-07-13T10:45:51.000+12:00");
            dev1.withAlias("");
            dev1.withId("a41c3af56ec35874");
            dev1.withDescription("Samsung SM-T819");
            dev1.withTitle("a41c3af56ec35874");
            dev1.withExternalId("0942dc67-35de-44f7-a061-743f59436a98");
            deviceList.add(dev1);
    
            Device dev2 = new Device();
            dev2.withDateRegistered("2017-07-13T10:45:31.000+12:00");
            dev2.withAlias("");
            dev2.withId("bd2b027bbd0a2f17");
            dev2.withDescription("Samsung SM-A320Y");
            dev2.withTitle("bd2b027bbd0a2f17");
            dev2.withExternalId("0942dc67-35de-44f7-a061-743f59436a98");
            deviceList.add(dev2);
    
            deviceResponse.setDevices(deviceList);
    
            String url = mockServer.getUrl();
            String path = "devices/v1";
            String query = "externalId=0942dc67-35de-44f7-a061-743f59436a98";
    
            URIBuilder uriBuilder = null;
            try {
                uriBuilder = new URIBuilder(url)
                                    .setPath(path)
                                    .setQuery(query);
            } catch (URISyntaxException e) {
                e.printStackTrace();
            }
    
            GetDevicesResponse devices = new ObjectMapper().readValue(Request.Get(uriBuilder.toString())
                    .addHeader("content-type", "application/json")
                    .execute().returnContent().asString(), GetDevicesResponse.class);
            assertThat(devices, sameBeanAs(deviceResponse));
        }
    }
    

    With this approach I had to add google guava 19 to my pom. But it works good.

    <dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
      <version>19.0</version>
    </dependency>