Pact Contracts in Deployment Pipelines
By: Tom Muc
Tags: Java, Deployment, Pact, Contract Testing, Testing Micoservices

Learn how to make the best out of contract testing by using Pact Broker and can-i-deploy tools in your build & deployment pipelines.

Pact Broker

The Pact Broker is an open-source tool that allows you to share your pacts and store the results of their verification. You may treat it as a repository of your published contracts together with their testing report.

Pact publishing

In order to see your pact on Pact Broker pages, you need to publish it first. Pact contract testing follows the consumer-driven approach, which means it’s the consumer who creates a contract defining new requirements against the provider API.

As a part of her build — optionally for feature branches and, ideally, always for the main branch— the consumer runs tests that create pacts (i.e. using Groovy DSL), and later triggers their publication to Pact Broker.

You can use the following tools to publish a pact:

pactPublish task provided by Pact Gradle plugin

task provided by Pact Gradle plugin pact-broker publish command from Pact CLI

Pact verification

It is the responsibility of the API provider to check if it fulfills all the needs of its consumers, based on pacts published by them to the Pact Broker. Depending on the approach the provider should run a dedicated suite of tests during every build on the main branch and publish their results to Pact Broker. Embedding such checks into all builds prevents the Provider from breaking the contracts with its consumers.

In order to verify pacts you can use, among others:

Versioning

Generally speaking the versioning of your application in Pact Broker should follow the same set of rules as the semantic versioning approach we use for application artifacts.

Pact’s documentation mentions some guidelines worth to know though:

Ensure your application version changes whenever the contract requirements change or when there’s a new deployable artifact created. This is self-explanatory and goes well with semantic versioning.

Your application version should be unique. Because of that, I recommend using the branch name as a version when publishing contracts from a feature branch. Don’t use x.y.z-SNAPSHOT versioning, as it may lead to duplicates in Pact Broker when there are multiple feature branches developed at the same time.

versioning, as it may lead to duplicates in Pact Broker when there are multiple feature branches developed at the same time. Avoid using random data in your contracts. This is very important, because if you do, then every time you publish your pact it’ll be considered unique. As a result, Pact Broker will require you to verify each one separately rather than depend on its internal mechanism to detect duplicates (you’ll read more about this later).

Tagging

Tags are simply string values assigned to the specific version of a pacticipant in Pact Broker. A pacticipant in Pact’s nomenclature is a participant of a contract — either a consumer or a provider. It’s important to note that tags are not assigned to pacts themselves.

Some good tagging practices:

Tag it with the branch name indicating where the application version comes from. Typically it is going to be main , or master , but could also be dev or feature_branch_name if you want to check pacts which are under development.

, or , but could also be or if you want to check pacts which are under development. Add the environment-specific tag when deploying your application, i.e. use dev , test , prod

Why even bother with tagging your consumer or provider versions?

You can use tags to check different versions of a consumer and provider against each other in a specific context, i.e. while developing a new functionality on a branch, before merging your feature branch, or deploying your application to production. Ensuring the contract agreements between the consumer and provider, without a need to run additional integration tests is the essence of contract testing with Pact.

Can I deploy or can-i-deploy?

Have you ever wondered if you can deploy your application without interfering with your consumers? Or, from the other perspective, ever wondered if the provider you depend on has already published his new API, so that you could deploy your microservice and use it? If yes, then Pact’s tool named can-i-deploy is something you’ve been looking for!

Simply speaking, it allows you to check if a specific version of a consumer (or a producer) can be safely deployed to a given environment — meaning there’s a compatible version of producer (or a consumer) available there.

For instance, running the following CLI command might become a part of the deployment process of a consumer named “Some Consumer”, that checks if it’s safe to deploy to production (tagged as PROD ).

./pact-broker can-i-deploy --pacticipant "Some Consumer" --version 1.0.0 --to PROD -b localhost

Please mind the parameter name is pacticipant, not participant!

How it works in practice — step by step

Branch development

It’s a good practice to publish Pacts from your feature branches when developing the consumer code. This allows the provider to get notified about upcoming requirements. Also, it prevents you from merging code that is about to fail because of a missing or incompatible provider.

The rule of thumb is to tag them with a branch name. You don’t want to use snapshot versioning (i.e. 1.0.0-SNAPSHOT ), as it may be reused by a different feature branch developed in parallel. We don’t want to tag with git revision numbers either, as it’d flood our Pact Broker with new versions, one for every commit to your branch.

Another way to approach it is to make pact publishing on branches a manual step — ideally, run only once or twice, and only if pact verification is needed sooner.

Let’s see how it works.

❶ Some Consumer develops a feature on some_feature_branch and publishes a Pact. It appears in Pact Broker like this:

❷ Some Provider verifies interactions with its consumers — i.e. in a dedicated verification job when triggered by a webhook from Pact Broker, or as a part of builds running on the main branch— and publishes the verification results for version 5.0.0 , tagging it as MAIN . Pact Broker is updated as follows:

❸ As a part of a build of some_feature_branch (or simply before merging it to the main branch) Some Consumer may check if all of its requirements are met by Some Provider:

./pact-broker can-i-deploy --pacticipant "Some Consumer" --version some_feature_branch --to MAIN -b localhost

It’s ok! Some Consumer may now safely merge its feature branch to the main branch, release a new version — 1.0.0 — and tag it as MAIN in Pact Broker.

Notice that Pact Broker is instantly aware that it’s already been verified before by Some Provider, version 5.0.0 . How is it possible? There’s a nice feature under the hood that detects duplicate pacts by using the comparison of hashes generated for the pact file. This eliminates a need for repeated verifications if the contract hasn’t changed. This, as you can see, is particularly useful when working with feature branches.

Production deployments

We now have Some Consumer and Some Provider with their changes merged to their main branch, released as 1.0.0 , and 5.0.0 , respectively. Both tagged as MAIN in Pact Broker.

We’re ready to deploy them to production, let’s see how it goes.

❶ Some Consumer checks if it can be safely deployed to production:

./pact-broker can-i-deploy --pacticipant "Some Consumer" --version 1.0.0 --to PROD -b localhost

The answer is no — Some Provider hasn’t been deployed to production yet.

❷ Some Provider runs can-i-deploy tool to verify if it’s fine to deploy to production as a part of its deployment scripts:

./pact-broker can-i-deploy --pacticipant "Some Provider" --version 5.0.0 --to PROD -b localhost

It’s fine, as the newest 5.0.0 version fulfills all the requirements defined in contracts involving Some Provider.

❸ Some Provider deploys version 5.0.0 to production and tags it as PROD in Pact Broker

./pact-broker create-version-tag --pacticipant "Some Provider" --version 5.0.0 --tag PROD -b localhost

Pact Broker now shows PROD tag assigned to provider version 5.0.0 :

❹ Some Consumer checks if it can be safely deployed to production again:

./pact-broker can-i-deploy --pacticipant "Some Consumer" --version 1.0.0 --to PROD -b localhost

The computer says “yes, yay!” Some Provider is deployed to production with all the necessary changes already.

❺ Some Consumer deploys version 1.0.0 to production and tags it as PROD in Pact Broker:

./pact-broker create-version-tag --pacticipant "Some Consumer" --version 1.0.0 --tag PROD -b localhost

Pact Broker now shows PROD tag assigned to consumer version 1.0.0 :

Rollback

From time to time you might find yourself in a situation when you need to rollback the version you just deployed to production. How does it work with pacts, tags, and Pact Broker? Let’s find out.

❶ Some Provider deploys version 5.1.0 to production, tagging it as PROD in Pact Broker:

❷ Some Provider performs a rollback from version 5.1.0 to 5.0.0 . After redeploy the PROD tag is still there, assigned to 5.1.0 in Pact Broker, just like in the previous step.

❸ Some Consumer checks if it can be safely deployed to production:

./pact-broker can-i-deploy --pacticipant "Some Consumer" --version 1.0.0 --to PROD -b localhost

Notice it is being verified against Some Provider version 5.1.0 which has just been rolled back to 5.0.0 on production.

❹ In order to make the tagging right, Some Provider must remove PROD tag from the rolled back version — 5.1.0 . As currently the Pact CLI does not support this, the only way is to use the REST API:

Now Pact Broker tags reflect the production environment state — Some Provider runs 5.0.0 on production, and this version is correctly tagged as PROD , not 5.1.0 anymore:

❺ Some Consumer may now check if it can be deployed to production:

./pact-broker can-i-deploy --pacticipant "Some Consumer" --version 1.0.0 --to PROD -b localhost

Now it gets verified against the correct 5.0.0 version of Some Provider as expected.

Why is that?

When using can-i-deploy Pact Broker selects the latest pacticipant version tagged as PROD from all the versions with this tag. It’s not the other way around — find the most recently created PROD tag, and then select the pacticipant version.