0
votes

I have to do PACT verification in java + spring-boot + maven. I am currently running this tests with junit5.

My pom.xml looks like

        <dependency>
            <groupId>au.com.dius</groupId>
            <artifactId>pact-jvm-provider-junit5</artifactId>
            <version>4.0.10</version>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>com.google.code.gson</groupId>
                    <artifactId>gson</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>au.com.dius</groupId>
            <artifactId>pact-jvm-consumer-junit5</artifactId>
            <version>4.0.10</version>
        </dependency>
        <plugin>
                <groupId>au.com.dius.pact.provider</groupId>
                <artifactId>maven</artifactId>
                <version>4.1.11</version>
                <configuration>
                    <pactDirectory>${basedir}/target/pacts</pactDirectory>
                    <pactBrokerUrl><BROKERURL></pactBrokerUrl>
                    <projectVersion><PROJECTVERSION></projectVersion>
                    <trimSnapshot>true</trimSnapshot>
                </configuration>
            </plugin>

Consumer side code is runnning perfectly and published on pact broker too, here is the snippet of it.

package com.contract;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.fluent.Request;
import org.apache.http.entity.StringEntity;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.testng.Assert;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

import au.com.dius.pact.consumer.MockServer;
import au.com.dius.pact.consumer.dsl.PactDslWithProvider;
import au.com.dius.pact.consumer.junit5.PactConsumerTestExt;
import au.com.dius.pact.consumer.junit5.PactTestFor;
import au.com.dius.pact.core.model.RequestResponsePact;
import au.com.dius.pact.core.model.annotations.Pact;


@ExtendWith(PactConsumerTestExt.class)

class ContractTest {

    public static final String jwt_token = "Bearer eyJraWQiOiIyZjFiNzlmMS0xMDQ2LTQ2NGYtYjM5YS0xOGY4MDg5ZGMyMzIiLCJ0eXAiOiJhdCtqd3QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJodHRwczovL3RlbmFudDE1LWFkZW1hdHJpeHN0YWNrNC10cmlhbC5kc21sYWIuYm1jLmNvbSIsImNsaWVudF9pZCI6IjVmNDU4ZjBlLWZmMzAtNDQ2ZC04ZTQwLWYzNjBlNjgyZjYyNSIsInRlbmFudCI6InN0YWNrNHRlbmFudDYiLCJqdGkiOiI4NDc3MDBhNC1hYWY0LTQ2NWMtYmNhYi05MDM0MzYxOTY0MDIiLCJzdWIiOiJEZW1vIiwiaXNzIjoiaHR0cHM6Ly9hZGVpdHNtMi1yc3NvLmRzbWxhYi5ibWMuY29tL3Jzc28iLCJpYXQiOjE2MjY3Njg0MjQsImV4cCI6MTYyNjc2OTMyNH0.EoXpqiyo5nvdPeYHfqq0sa15dQKYayD60UEboPVJojuYBKmvvj2yU03e61wy9Fkq2pZdoTNTifAeLDiG0dYKdlYOI5YTx_K6HGMav6ofYeOwIUj4OBVu7NyWxXVQz-3aXoIyu-MifUtvs6oQwf2YZmOEVtbPuCBxa9C9yA4i72g1TD31Rba1-e5cGG5ipiIE7UaunJ2K-mkt-BL2kzmu6OHdIP6vly7iTzxfOccdrjXEmedgX2hpnPcL_2os5wHCLwdHJwuYLPlgqDbSLHgpXdGL43Jg4ASBbFHg3h30y1yXYJazlgOwvVeBoOVcQYnXBh7wHTMik7zVMAo1VL8N_Q";
    
    public static final String API_V1_VIEW_ALGORITHM = "/aif/api/v1.0/algorithm/b82d4617-c39f-448b-bdf8-3fd52e3250ba";
    
    public static final String BODY_GET_VIEW_ALGO_V1 = "{\"tenantId\":\"6881408\",\"id\":\"5bc098db-7acb-4361-86a9-3c439b477142\",\"name\":\"New Job\",\"description\":\"New Job\",\"creationTime\":\"1625054173273\",\"template\":\"\",\"modifiedTime\":\"1625054173273\",\"owner\":\"ppan\",\"enable\":\"true\",\"executionMode\":\"onDemand\",\"definition\":\"\"}";
    
    private final static Map<String, String> headers;
    static {
        headers = new HashMap<>();
        headers.put("Content-Type", "application/json");
        headers.put("Authorization", jwt_token);
        headers.put("authtype", "rsso-jwt");
    }

    @BeforeEach
    public void setUp(MockServer mockServer) {
        assertThat(mockServer, is(notNullValue()));
    }
    
    /* ----------------------------------Pact methods ----------------------------------------------------*/

    @Pact(provider = <provider name> , consumer = <consumer name>)
    public RequestResponsePact createPactViewAlgoV1(PactDslWithProvider builder) {

        return builder
                .given("algorithm id")
                .uponReceiving("a request with details of Algorithm")
                .path(API_V1_VIEW_ALGORITHM)
                    .method("GET")
                    .headers(headers)
                .willRespondWith()
                    .status(200)
                    .body(BODY_GET_VIEW_ALGO_V1)
                .toPact();
    }
    
    
    /* ----------------------------------Test methods ----------------------------------------------------*/
    
    @Test
    @PactTestFor(pactMethod = "createPactViewAlgoV1")
    public void testTokenRequest(MockServer mockServer) throws ClientProtocolException, IOException {
        HttpResponse httpResponse = Request.Get(mockServer.getUrl() + API_V1_VIEW_ALGORITHM)
                .addHeader("Content-Type", headers.get("Content-Type"))
                .addHeader("Authorization",headers.get("Authorization"))
                .addHeader("authtype", headers.get("authtype"))
                .execute()
                .returnResponse();
        assertEquals(httpResponse.getStatusLine().getStatusCode(), 200);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
        AIFAlgorithmModelNew actualResult = objectMapper.readValue(httpResponse.getEntity().getContent(), AIFAlgorithmModelNew.class);
        assertEquals(actualResult.getTenantId().toString(), "6881408");
        assertEquals(actualResult.getExecutionMode().toString(), "onDemand");
        assertEquals(actualResult.getEnable().toString(), "true");
        assertEquals(actualResult.getName().toString(), "New Job");
    }
}

I have written my Pact provider test class with standard pact format. I am currently trying to run this on port: 8091. Tried with port 9362 as well. looks like this

package com.aif.api.contract;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringExtension;

<Code libraries>

import au.com.dius.pact.provider.junit.Provider;
import au.com.dius.pact.provider.junit.State;
import au.com.dius.pact.provider.junit.loader.PactBroker;
import au.com.dius.pact.provider.junit5.HttpTestTarget;
import au.com.dius.pact.provider.junit5.HttpsTestTarget;
import au.com.dius.pact.provider.junit5.PactVerificationContext;
import au.com.dius.pact.provider.junit5.PactVerificationInvocationContextProvider;

import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.restassured.RestAssured;
import io.restassured.http.Cookie;
import io.restassured.config.SSLConfig;

import static org.mockito.Mockito.when;

import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Base64;
import java.util.UUID;

import javax.ws.rs.core.Response;

import org.apache.http.HttpRequest;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.TestTemplate;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, classes = main.class)
@AutoConfigureMockMvc
@TestPropertySource(locations = "classpath:application-contract-test.properties")
@Provider("Provider")
@PactBroker(
        host="${PACTBROKER_HOST:PACTBroker URL}",
        port="${PACTBROKER_PORT:9292}"
        )
public class BasicTest {
    
    static {
        System.setProperty("javax.net.ssl.keyStore", "./conf/server_key.p12");
        System.setProperty("javax.net.ssl.keyStorePassword", "Y2hhbmdlaXQ=");
        }
    
    @Autowired
    private ApplicationContext context;
    
    @MockBean
    Algor
    
    @MockBean
    AlgorithmResource algorithmResource;
    
    @Value("${server.port}")
    private int serverPort;
    
    @Value("${pact.provider.version}")
    private String version;
    
    @Value("${pact.verifier.publishResults}")
    private String publishResults;
    
    @BeforeEach
    void setupTestTarget(PactVerificationContext context) {
        System.out.println("Inside setupTestTarget");
        MockitoAnnotations.initMocks(this);
        context.setTarget(new HttpTestTarget("localhost", serverPort, "/"));
        System.setProperty("pact.provider.version", version);
        System.setProperty("pact.verifier.publishResults", publishResults);   
    }
    
    @TestTemplate
      @ExtendWith(PactVerificationInvocationContextProvider.class)
      void pactVerificationTestTemplate(PactVerificationContext context, HttpRequest request) {
        context.verifyInteraction();
      }
    
    /* consumer = <Consumer Name> */
    @State("algorithm id")
    public void getAlgorithmById() throws Exception {
        System.out.println("Inside getAlgorithmById");
        AlgorithmResponseTOFull responseTO = new AlgorithmResponseTOFull();
        responseTO.setTenantId("6881408");
        responseTO.setId("5bc098db-7acb-4361-86a9-3c439b477142");
        responseTO.setName("New Job");
        responseTO.setDefinition("");
        responseTO.setDescription("New Job");
        responseTO.setCreationTime("1625054173273");
        responseTO.setModifiedTime("1625054173273");
        responseTO.setOwner("ppans");
        responseTO.setEnable("true");
        responseTO.setExecutionMode("onDemand");
        responseTO.setTemplate(getAlgorithmTemplateResponseTO());
        
        Response response = Response.ok(Util.buildResponse(responseTO, Constant.STATUS_MSG_SUCCESS)).build();
        
        when(algorithmResource.getById(Mockito.any())).thenReturn(response);
    }
}

When I run this, I get error like

Verifying a pact between <consumer name> and <provider name>
  [Using Pact Broker PACTBROKERURL:9292]
  Given algorithm id
  a request with details of Algorithm
Inside pactVerificationTestTemplate
    returns a response which
      has status code 200 (FAILED)
      has a matching body (FAILED)

Failures:

0) Verifying a pact between <consumer name> and <provider name> - a request with details of Algorithm returns a response which has statusResult code 200
      expected status of 200 but was 401

1) Verifying a pact between <consumer name> and <provider name> - a request with details of Algorithm returns a response which has a matching body
      Expected a response type of 'application/json' but the actual type was 'text/html'

Please help me to resolve this, as I am getting above error and not able to resolve it

2

2 Answers

0
votes

In the consumer where the test is written , it is expecting a response of 200 and response type of "application/json". If possible, please share the consumer test also that you have written. Please check that the pact which is getting generated at the pact broker url, and also what is the response and response type it is expecting.

0
votes

A 401 indicates the request contained invalid or no credentials.

Given that your consumer test has a JWT in it, my guess is that it's expired by the time the provider test runs.

See https://docs.pact.io/provider/handling_auth/ for strategies in dealing with this and the workshops here to see how to out them into action: https://docs.pact.io/implementation_guides/workshops/