How we reached Pact Nirvana — Diamond Level
At Go City, contract testing with Pact is part of each teams' definition of done, ensuring that we’re not breaking our REST APIs between our mobile apps, websites and suite of microservices.
We’ve just reached ‘Pact Nirvana — Diamond Level’, a level I personally have never reached on a production system, despite writing Pact contract tests for 6+ years.
What is ‘Pact Nirvana — Diamond Level’?
Reaching diamond level means you have automated every stage of Pact into your CI/CD workflow for PRs and release branches, helping to give you confidence that your changes can be safely released to production.
Flow (Simplified):
- PRs and release branches (
main
) publish consumer contracts to the broker. - Pact Webhooks trigger a build of the provider in your CI/CD tool if a consumer contract is new/modified and therefore requires verifying.
- Provider tests then run for the contract that needs verification and publishes the verification results back to the broker.
- Consumers and Providers both check with
can-i-deploy
before merging to your release branch or releasing to an environment.
Using theretry-while-unknown
andretry-interval
properties gives the provider tests time to run and report the verification results. - Consumers and Providers
recording-deployment
when the code has been promoted to an environment.
We even have GitHub status checks for Pact verifications on all our PRs and added the can-i-deploy
badges to each repo's README.md
How we did our provider webhook verification
To apply quickly across our suite of microservices, instead of updating every single CI/CD workflow with a “Run provider tests” job, we created a new repo called pact-contract-verification-webhook-receiver
which is triggered by a Pact webhook that includes all the information about the consumer and provider. It in turn checks out the required provider repo and branch/version, runs just the provider tests for the changed consumer contract and publishes the verification results to the Pact broker.
This works well for us because all our providers are Java or Kotlin and using the Pact Gradle plugin.
How did you get there?
Learn
This one is pretty obvious, but you need to learn about contract testing, how to write good contract tests.
When I introduced Pact at Go City, I encouraged all engineers to spend some of their monthly learning time watching the Introduction to contract testing with Pactflow video series. And then do one of their 2-hour workshops.
I would also run brown bag sessions with groups of engineers where we would write a contract test together.
Pair and write the first contract into a Production service
Learning through tutorials and demos can only get you so far, as these will most likely look different from your actual microservices. Find yourself a pair and write a contract test for a real production API in your system.
Start simple, don’t worry about recording deployments or blocking releases if a contract hasn’t been verified yet. We can add these steps on later.
Champion
You need all of your teams onboard with writing contract tests to get the full value. Be the champion. Make engineers excited about the problems contract tests solve. Make sure every engineer understands the value of why we write them. Always make yourself available to answer questions or get your hands dirty when people are having problems.
One of our engineering principles at Go City is testability. We want all engineers to be responsible for quality and be able to write all types of tests on the testing pyramid. We do this by having a couple of SDET’s who run a testing community of practice and a Slack channel where any engineer can come and ask for help on anything testing related.
Build into your CI/CD pipeline
Work through the CI/CD setup guide. At Go City, we’ve been migrating our deployment of our microservices onto our ‘golden path’ pipeline. This was the secret to reaching Diamond level — Adding the required steps only needed to be added in once place, and all services using this shared pipeline then automatically reached Diamond level.
With any pipeline, it’s good to have a ‘break glass’ procedure to get out an emergency fix. If you’re having problems with can-i-deploy
saying “No” and you’re OK with a short potential outage, because you’re in a chicken and egg scenario, or don’t have time to use the expand and contract pattern, then you can set the PACT_BROKER_CAN_I_DEPLOY_DRY_RUN=true
environment variable in your pipeline, which will return a success code and not block your pipeline.
Slack
Everyone gets stuck! The team over at Pact are always super helpful on Slack.
What’s next?
We still have plenty of work to do with Pact. At the time of writing, we have only experimented with messaging pacts (We use Kafka!).
We also want to look into the new plugins, bidirectional contracts, WIP and pending pacts to determine whether they will help improve the way we test our services at Go City.