1

I have a restFul API http://localhost:8080/books/{id} which return a book with a particular ID.

ex:

GET http://localhost:8080/books/1

will return

{ "id" : 1, "pages" : 20, "price" : 100 }

GET http://localhost:8080/books/2

will return

{ "id" : 2, "pages" : 30, "price" : 120 }

I have written my consumer expectations using regex in place of {id} and have generated the PACT.

There is no data present in the provider now. (no book information in present in the database). When I run pact verfication on provider side it fails since it is not able to get any information by hitting the actual service to cross check the contract.

Can the contract be verified without data being present in the provider database? or is there any workaround for the same?

Also the DB of provider can change if we deploying the provider into multiple environments, how to handle this?

Appreciate the help. Thanks.

Sam
  • 181
  • 2
  • 3
  • 13
  • Basically how the Data is handled in PACT? How to give the right data to provider so that the response returned is 200 which we need. – Sam Feb 21 '17 at 11:21

2 Answers2

1

Why would you want to workaround that? The point of contract testing is so that you can verify that both sides of the contract are properly met!

You might want to look at Provider States [1] for this.

Which language are you using?

The article provided gives you some background. In JVM, you can look at the @State annotation https://github.com/DiUS/pact-jvm/tree/master/pact-jvm-provider-junit#example-of-http-test.

In your consumer, you would specify a state such as "Given a book with ID 1 exists". On the provider side, the framework will invoke the @State annotation corresponding to this expectation. This gives you the opportunity to ensure any state data exists (in this case, that book) before the test case runs.

[1] https://docs.pact.io/documentation/provider_states.html

Matthew Fellows
  • 3,669
  • 1
  • 15
  • 18
  • Thanks for your support. If I understood it right, if its an empty DB at the provider side, the provider needs to insert some data (either by making use of provider states or some other way). Then only the request will be sent to the provider so that we get a 200 response. Is my understanding correct? – Sam Feb 27 '17 at 07:38
  • Yes, the JVM unit test running will invoke the @State annotation that matches the consumer specified state (in this case "Given a book with ID 1 exists"), prior to executing the test against the Provider. This gives the Provider the opportunity to setup the test fixture before the test itself runs. – Matthew Fellows Feb 27 '17 at 07:57
  • Got that clear, many thanks! One last query (as I am totally new to PACT), So in this case the endpoint which is specified in the contract by the consumer will contain an id (say book-Id 1) right?. Which ultimately means the endpoint of the contract will contain a hard-coded value in it, which will be inserted by the provider in its DB. We were thinking, doesn't that look a bit odd? eg: /bookStore/bookId/1 (this will be present in the PACT contract defined by the consumer. – Sam Feb 27 '17 at 08:33
  • 1
    Correct. The contract is really a set of examples that the consumer sends and a bunch matching rules on the provider _response_ (see [Matching Rules](https://github.com/DiUS/pact-jvm/tree/master/pact-jvm-consumer-junit#dsl-matching-methods)). It is assumed (and is your responsibility) to ensure that there are no contractual differences between book 1 and 2, for instance – Matthew Fellows Feb 28 '17 at 01:31
  • Thank you Matthew. I am clear now. One suggestion from your side if I may ask you, if PACT validation needs to be integrated onto the Jenkins pipeline. Where exactly should the PACT validation comes? Before smoke and regression test or after them? (considering the build, deploy of the application - provider is a pre-requisite.) – Sam Feb 28 '17 at 09:20
  • I assume you mean provider side verification when deploying the consumer code? If so, check out https://docs.pact.io/faq/#how-to-prevent-a-consumer-from-deploying-with-an-invalid-contract. The idea is that these are decoupled, so the short answer is "not at all". If you have lots of microservices, where do you draw the line? Do you trigger all providers and their providers etc, For most use cases this isn't a problem but there are some strategies you can employ – Matthew Fellows Feb 28 '17 at 09:34
  • Sure will go with that approach. And is there any way in PACT where I can 1) define Optional Fields in the consumer contract and 2) Define IF conditions in the contract (If the json field(key) "id" is present, i do not want to check wether the field(key) "price" is present, etc.,)? – Sam Mar 21 '17 at 07:32
  • The short answer is no, sorry. The first question is ultimately a paradox. The second is too difficult to achieve practically. – Matthew Fellows Mar 21 '17 at 11:50
  • Yes, I read the same in PACT documentation and blogs as well...Thanks. Was wondering, what exactly is the advantage of having a mock server in PACT. i created a PACT file , uploaded on PACT broker and there I can see some random values populated for every fields. What exactly is the purpose/advantage of that mock in PACT? – Sam Mar 24 '17 at 10:26
-1

First of all, none of the above URL works. & its so freaking difficult to use this framework.. none of the API has proper documentation and also bloody when some thing does not work, it does not give proper error message also.

In my case, I have been trying to send a Request Parameter called "business-date" which expects a date with format "yyyy-MM-dd" and none of the below options seems to be working --

matchQuery("business-date", "\\d{4}-\\d{2}-\\d{2}", "2020-05-18")

query("business-date="+getBusinessDate())

queryMatchingDate("business-date", "yyyy-MM-dd")

matchQuery("business-date", "\\d{4}-\\d{2}-\\d{2}")

queryMatchingDate("business-date", "yyyy-MM-dd")

queryMatchingISODate("business-date", "yyyy-MM-dd")

The exception looks like this

org.springframework.web.client.HttpServerErrorException$InternalServerError: 500 Internal Server Error: [{ "error": "Unexpected request : \tmethod: GET\n\tpath: \/api\/batch_activities\/ACTIVITY\/STARTED\n\tquery: {}\n\theaders: {X-b3-traceid=[6c88f0a1a0ae288e], Accept=[application\/json], Connection=[ke... (443 bytes)]

Caused by: org.springframework.web.client.HttpServerErrorException$InternalServerError: 500 Internal Server Error: [{ "error": "Unexpected request : \tmethod: GET\n\tpath: \/api\/batch_activities\/ACTIVITY\/STARTED\n\tquery: {}\n\theaders: {X-b3-traceid=[6c88f0a1a0ae288e], Accept=[application\/json], Connection=[ke... (443 bytes)]

Once instance of the DSL looks like below -

builder.given("Fetch Batch Activity by status")
        .uponReceiving("Receiving Batch activity status").headers(headers).method(HttpMethod.GET)
        .matchPath(pathRegex, path)
        .matchQuery("business-date", "\\d{4}-\\d{2}-\\d{2}")
        .willRespondWith().status(200).headers(headers).body(jsonUtil.getObjectAsString(
            formatBatchActivityForStatus(FeedExporterConstants.BATCH_STATUS_STARTED)))
        .toPact();
Rahul Mohan
  • 101
  • 1
  • 2
  • 6