Pact: Bi-Directional .NET example


Introduction

This post is a report of my experience trying to go through the Pact.NET Bi-Directional examples (which are compatible to eachother) provided by Pactflow community/team:

Provider example: https://github.com/pactflow/example-bi-directional-provider-dotnet

Consumer example: https://github.com/pactflow/example-bi-directional-consumer-dotnet

I just decided to post this, in case it would be helpful to anybody trying to go through the same examples.

Provider

I’ve been through the pact example in a WSL2 environment.

I made sure that the Pre-requisites are fullfilled in my environment.

This pact example also includes yml files to Create and run GitHub build pipelines. If you want to run GitHub pipelines then you have to fork the pact example to be able to commit and push your changes and to trigger the pipeline.

But to understand the workflow you don’t necessaray have to run those GitHub pipelines. You can just use the makefile commands to see and understand the Pactflow workflow involved in deploying the provider and the consumer.

So to playout the Pactflow workflow I first prepared the environment variables which are required by the makefile commands.

export PACT_BROKER_BASE_URL="https://my-company.pactflow.io"
export PACT_BROKER_TOKEN=my-token

These two variables can be copy pasted from this page of your Pactflow account.

Click on the settings symbol on the top on the right:

Click on the buttons for copying the URL and the read/write token to copy/paste the corresponding value:

Local Testing

As described in on the project documentation I executed the following command to generate the dll for the project and the swagger doc:

make publish_dll

Then I ran the command to verify the provider API endpoints againt the swagger doc:

make verify_swagger or make test (both call the same script: verify_swagger.sh)

And got the following results:

$ make verify_swagger
./example-bi-directional-provider-dotnet/scripts/verify_swagger.sh
Started dotnet API with process ID: 7620
Running schemathesis test to generate report
Stopping dotnet API

At this point you might have encounted the problem (described here: $GUIDr-E117D8CF-4C16-450A-8ADF-AFF201CE667E), which happened to me because I had missed the above commands and started directly with the make test command.

The results of the make verify_swagger (or make test) command will be written to the report file report.txt in root folder (see Makefile), which might look like this:

======================= Schemathesis test session starts =======================
Schema location: http://host.docker.internal:9000/swagger/v1/swagger.json
Base URL: http://host.docker.internal:9000/
Specification version: Open API 3.0.1
Workers: 1
Collected API operations: 2

GET /Products .                                                           [ 50%]
GET /Products/{id} .                                                      [100%]

=================================== SUMMARY ====================================

Performed checks:
    not_a_server_error                              101 / 101 passed          PASSED 
    status_code_conformance                         101 / 101 passed          PASSED 
    content_type_conformance                        101 / 101 passed          PASSED 
    response_headers_conformance                    101 / 101 passed          PASSED 
    response_schema_conformance                     101 / 101 passed          PASSED 

Hint: You can visualize test results in Schemathesis.io by using `--report` in your CLI command.

============================== 2 passed in 1.06s ===============================

Publishing to Pactflow

Once your local test with make verify_swagger or make test is successul you might proceed with publishing the test results to the Pactflow server using the following command, which passes the success code to the docker command for the Pactflow CLI container, which has the tools to execute commands against the Pactflow server:

EXIT_CODE=0 make publish_provider_contract

To understand better what this command is doing, you might check the Makefile:

VERSION?=$(shell npx -y absolute-version)
BRANCH?=$(shell git rev-parse --abbrev-ref HEAD)
OAS_PATH=example-bi-directional-provider-dotnet/swagger.json
REPORT_PATH?=report.txt
REPORT_FILE_CONTENT_TYPE?=text/plain
VERIFIER_TOOL?=schemathesis

...

publish_provider_contract:
	@echo "\n========== STAGE: publish-provider-contract (spec + results) ==========\n"
	${PACTFLOW_CLI_COMMAND} publish-provider-contract \
      ${OAS_PATH} \
      --provider ${PACTICIPANT} \
      --provider-app-version ${VERSION} \
      --branch ${BRANCH} \
      --content-type application/yaml \
      --verification-exit-code=${EXIT_CODE} \
      --verification-results ${REPORT_PATH} \
      --verification-results-content-type ${REPORT_FILE_CONTENT_TYPE}\
      --verifier ${VERIFIER_TOOL}
...

Its important to understand that the publish_provider_contract command publishes two “things”:

  • The swagger.json file and
  • The results of actual test involving HTTP requests.

After executing the publish_provider_contract command, the pact is published on the Pactflow Server:

Remark:
It might be a bit confusing why we would need to publish both the swagger.json and the test results to Pactflow. In fact you could leave out the test result in which case your contract would look like the following example, a contract with swagger data but without results:

can_i_deploy and deploy

After the pact is published to Pactflow, we can use the can_i_deploy command to check whether the provider can be published, which should be possible, because their is no consumer yet deployed which could be incompatible to provider:

make can_i_deploy

Then we can use the deploy option to record the deployment of the provider:

make deploy

Consumer

Also on the consumer side we can just clone the repository from github and test the makefile commands locally without any pipeline. Because to understand the Pact workflow we don’t really need the pipeline. Of course we can also fork the repository and trigger our own github pipeline by committing changes to our repository, but lets just leave out the pipeline and just work locally:

git clone https://github.com/pactflow/example-bi-directional-consumer-dotnet.git

Make sure that the environment variables are set, just like explained in the provider section:

export PACT_BROKER_BASE_URL="https://my-company.pactflow.io"
export PACT_BROKER_TOKEN=my-token

On the consumer side we need another environment variable to pass the name of the provider:

export PACT_PROVIDER=pactflow-example-bi-directional-provider-dotnet

Local Testing

Run the pact unit tests:

make test

That step generates the pact file.

Next we have to publish the pact file. The makefile offers the command make fake_ci which sets all required parameters, publishes the pact file and also executes the can_i_deploy step:

make fake_ci

...
ci: test publish_pacts can_i_deploy $(DEPLOY_TARGET)

# Run the ci target from a developer machine with the environment variables
# set as if it was on CI.
# Use this for quick feedback when playing around with your workflows.
fake_ci:
	@CI=true \
	GIT_COMMIT=`git rev-parse --short HEAD`+`date +%s` \
	GIT_BRANCH=`git rev-parse --abbrev-ref HEAD` \
	REACT_APP_API_BASE_URL=http://localhost:8080 \
	make ci

publish_pacts:
	@echo "\n========== STAGE: publish pacts ==========\n"
	@"${PACT_CLI}" publish ${PWD}/tests/pacts --consumer-app-version ${GIT_COMMIT} --branch ${GIT_BRANCH}
...

Troubleshooting

Error: “dotnet: command not found”

$GUIDi-E117D8CF-4C16-450A-8ADF-AFF201CE667E

Problem

Under provider, after running the following command:

make test

The following error is issued:

./example-bi-directional-provider-dotnet/scripts/verify_swagger.sh
Started dotnet API with process ID: 1263
Running schemathesis test to generate report
Unable to find image 'schemathesis/schemathesis:stable' locally
./example-bi-directional-provider-dotnet/scripts/verify_swagger.sh: line 3: dotnet: command not found
stable: Pulling from schemathesis/schemathesis
...
Status: Downloaded newer image for schemathesis/schemathesis:stable
Stopping dotnet API
./example-bi-directional-provider-dotnet/scripts/verify_swagger.sh: line 13: kill: (1263) - No such process
make: *** [Makefile:81: test] Error 1

Resolution

Make sure that dotnet SDK is installed in your WSL/Ubuntu environment.

First enable Microsoft PPA:

$ wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb 
$ sudo dpkg -i packages-microsoft-prod.deb

Then install the dotnet SDK:

$ sudo apt update
$ sudo apt install apt-transport-https
$ sudo apt install dotnet-sdk-3.1

This is because the command dotnet build was not executed yet and as a result the provider .NET project is not yet built. In my case, this was because I hadn’t executed the following commands before executing make test:

make publish_dll
make verify_swagger

Now the test command should work:

make test