This article demonstrates how a Concourse CI pipeline can run consumer driven tests between two cross language apps: a Java Spring Boot web app and a Ruby Sinatra API. The examples use the PACT framework and its jvm and Ruby implementations. This article assumes basic understanding of pact and how it works so if you want to learn more about it visit http://pact.io.
PACT has a broker to share contracts across applications but if your applications ecosystem is already in a pipeline contracts tests can be part of that.
All of the code is on github: the pipeline, the consumer, the provider and the pact repository. To run the example on your machine you’ll need to fork the repos and update the
pipeline.yml with the new URLs. You’ll also have to specify your Github key when setting the pipeline ie.
fly --target travel-inc set-pipeline --config pipeline.yml --pipeline travel-offers --var "pact-repository-key=$(cat your_id_rsa)".
For the sake of brevity I kept the tech stacks simple: the consumer code is a Spring Boot app using static templates, I used hardcoded provider responses for the Ruby API.
In this example I will start from a green pipeline and then commit a consumer change that will break the provider state. After fixing the provider the pipeline will go back to green.
Background about the example
This is a simplified example adapted from a real live application.
The web application Travel Offers displays fabulous travel offers fetched from the tedious legacy SEAL API.
The travel offers is a green field app so everybody on the team is excited about using new technologies and want to make sure the API integration is solid.
Instead the SEAL API is the classic app that nobody wants to work on, 5 years old, lots of inadvertent tech debt and a long backlog of bugfixes and features.
When the SEAL API team is asked to add a new endpoint or field by a consumer their approach has been to add all possible fields and then publish a document so the consumer can’t possibly ask for anything else.
Consumer driven test is a refreshing and pragmatic strategy to API design that helps comunication but it will fail miserably if there is no support on the SEAL API team.
Make sure the SEAL API team is willing to test and honor their contract
Pipeline to the help
Concourse is a CI pipeline that helps visualizing the consumer/provider dependency and automating the contract publishing and verification.
Consumer driven change
The pipeline has a travel-offers-webapp-consumer-tests job that tests the travel offers consumer app interaction with the API provider SEAL API.
I pushed a consumer change to add a
members_price on the provider. The pipeline picks up that change and runs the consumer tests.
That consumer test passes and it generates a JSON PACT (consumer-driven-api-contracts) that the pipeline will upload to a contract git repository. There is only one PACT file in this simplified example.
The Concourse pipeline will monitor the contract repository. When the new one is published it will run the API provider job (seal-api-provider-tests) and that will fail.
Provider update to fix the pipeline
The provider tests are broken.
On your workstation you will need to fetch the latest contract repositories to get the failing test.
I update the provider to satisfy the new contract. The pipeline will pickup the provider change and run its tests again returning to a green state.
If you want to run consumer driven tests in a highly visible Continuous Integration server Concourse can do that.
Rather then making the entire test suite fail having a consumer driven dedicated pipeline or jobs can increase the understanding of which parts of your ecosystem are broken and allow an incremental approach to TDD and CI.