Skip to content

Commit

Permalink
test(examples): tidy build and examples and make functionality betwee…
Browse files Browse the repository at this point in the history
…n Flask and FastAPI consistent

re pact-foundation#270
  • Loading branch information
mikegeeves committed Oct 12, 2021
1 parent 4603347 commit 7e0b49f
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 29 deletions.
97 changes: 81 additions & 16 deletions examples/README.md
Expand Up @@ -8,35 +8,48 @@
* [flask_provider](#flask_provider)
* [fastapi_provider](#fastapi_provider)
* [message](#message)
* [pacts](#pacts)

## Overview

TODO
Here you can find examples of how to use Pact using the python language. You can find more of an overview on Pact in the
[Pact Introduction].

Examples are given of both the [Consumer] and [Provider], this does not mean however that you must use python for both.
Different languages can be mixed and matched as required.

In these examples, `1` is just used to meet the need of having *some* consumer version.
In these examples, `1` is just used to meet the need of having *some* [Consumer] or [Provider] version. In reality, you
will generally want to use something more complicated and automated. Guidelines and best practices are available in the
[Versioning in the Pact Broker]

## broker

The [Pact Broker] stores Pacts and verification results. It is used here for the [consumer](#consumer), [flask_provider](#flask-provider) and [message](#message) tests.
The [Pact Broker] stores [Pact file]s and [Pact verification] results. It is used here for the [consumer](#consumer),
[flask_provider](#flask-provider) and [message](#message) tests.

### Running

These examples run the broker as part of the tests when specified. It can be run outside the tests as well by performing the following command from a separate terminal in the examples/broker folder:
These examples run the [Pact Broker] as part of the tests when specified. It can be run outside the tests as well by
performing the following command from a separate terminal in the `examples/broker` folder:
```bash
docker-compose up
```

You should then be able to open a browser and navigate to http://localhost where you will initially be able to see the default Example App/Example API Pact.
You should then be able to open a browser and navigate to http://localhost where you will initially be able to see the
default Example App/Example API Pact.

Running the broker outside the tests will mean you are able to then see the Pacts submitted to the broker as the various tests are performed.
Running the [Pact Broker] outside the tests will mean you are able to then see the [Pact file]s submitted to the
[Pact Broker] as the various tests are performed.

## consumer

Pact is consumer-driven, which means first the contracts are created. These Pact contracts are generated during execution of the consumer tests.
Pact is consumer-driven, which means first the contracts are created. These Pact contracts are generated during
execution of the consumer tests.

### Running

When the tests are run, the "minimum" is to generate the Pact contract JSON. Additional options are available, from the `examples/consumer` folder:
When the tests are run, the "minimum" is to generate the Pact contract JSON, additional options are available. The
following commands can be run from the `examples/consumer` folder:

- To startup the broker, run the tests, and publish the results to the broker:
```bash
Expand All @@ -60,21 +73,59 @@ When the tests are run, the "minimum" is to generate the Pact contract JSON. Add

The following file(s) will be created when the tests are run:

- **consumer/pact-mock-service.log**
- All interactions with the mock provider such as expected interactions, requests, and interaction verifications.
- **consumer/userserviceclient-userservice.json**
- This contains the Pact interactions between the `UserServiceClient` and `UserService`, as defined in the tests. The naming being derived from the named Pacticipants: `Consumer("UserServiceClient")` and `Provider("UserService")`
| Filename | Contents |
|---------------------------------------------| ----------|
| consumer/pact-mock-service.log | All interactions with the mock provider such as expected interactions, requests, and interaction verifications. |
| consumer/userserviceclient-userservice.json | This contains the Pact interactions between the `UserServiceClient` and `UserService`, as defined in the tests. The naming being derived from the named Pacticipants: `Consumer("UserServiceClient")` and `Provider("UserService")` |

## flask_provider

TODO
The Flask [Provider] example consists of a basic Flask app, with a single endpoint route.
This implements the service expected by the [consumer](#consumer).

The [Provider] side is responsible for performing the tests to verify if it is compliant with the [Pact file] contracts
associated with it.

As such, the tests use the pact-python Verifier to perform this verification. Two approaches are demonstrated:
- Testing against the [Pact broker]. Generally this is the preferred approach, see information on [Sharing Pacts].
- Testing against the [Pact file] directly. If no [Pact broker] is available you can verify against a static [Pact file].

### Running

To avoid package version conflicts with different applications, it is recommended to run these tests from a
[Virtual Environment]

The following commands can be run from within your [Virtual Environment], in the `examples/flask_provider`.

To perform the python tests:
```bash
pip install -r requirements.txt # Install the dependencies for the Flask example
pip install -e ../../ # Using setup.py in the pact-python root, install any pact dependencies and pact-python
./run_pytest.sh # Wrapper script to first run Flask, and then run the tests
```

To perform verification using CLI to verify the [Pact file] against the Flask [Provider] instead of the python tests:
```bash
pip install -r requirements.txt # Install the dependencies for the Flask example
./verify_pact.sh # Wrapper script to first run Flask, and then use `pact-verifier` to verify locally
```

To perform verification using CLI, but verifying the [Pact file] previously provided by a [Consumer], and publish the
results. This example requires that the [Pact broker] is already running, and the [Consumer] tests have been published
already, described in the [consumer](#consumer) section above.
```bash
pip install -r requirements.txt # Install the dependencies for the Flask example
./verify_pact.sh 1 # Wrapper script to first run Flask, and then use `pact-verifier` to verify and publish
```


### Output

The following file(s) will be created when the tests are run

- **flask_provider/log/pact.log**
- All Pact interactions with the Flask Provider. Every interaction example retrieved from the Pact Broker will be performed during the Verification test; the request/response logged here.
| Filename | Contents |
|-----------------------------| ----------|
| flask_provider/log/pact.log | All Pact interactions with the Flask Provider. Every interaction example retrieved from the Pact Broker will be performed during the Verification test; the request/response logged here. |


## fastapi_provider
Expand All @@ -85,4 +136,18 @@ TODO

TODO

[Pact Broker]: https://docs.pact.io/pact_broker
## pacts

Both the Flask and the FastAPI [Provider] examples implement the same service the [Consumer] example interacts with.
This folder contains the generated [Pact file] for reference, which is also used when running the [Provider] tests
without a [Pact Broker].

[Pact Broker]: https://docs.pact.io/pact_broker
[Pact Introduction]: https://docs.pact.io/
[Consumer]: https://docs.pact.io/getting_started/terminology#service-consumer
[Provider]: https://docs.pact.io/getting_started/terminology#service-provider
[Versioning in the Pact Broker]: https://docs.pact.io/getting_started/versioning_in_the_pact_broker/
[Pact file]: https://docs.pact.io/getting_started/terminology#pact-file
[Pact verification]: https://docs.pact.io/getting_started/terminology#pact-verification]
[Virtual Environment]: https://docs.python.org/3/tutorial/venv.html
[Sharing Pacts]: https://docs.pact.io/getting_started/sharing_pacts/]
2 changes: 1 addition & 1 deletion examples/flask_provider/run_pytest.sh
Expand Up @@ -17,4 +17,4 @@ trap teardown EXIT
sleep 1

# Now run the tests
pytest tests --run-broker True --publish-pact 1 -s
pytest tests --run-broker True --publish-pact 1
1 change: 0 additions & 1 deletion examples/flask_provider/tests/provider/test_provider.py
@@ -1,7 +1,6 @@
"""pact test for user service provider"""

import logging
import time

import pytest

Expand Down
28 changes: 17 additions & 11 deletions examples/flask_provider/verify_pact.sh
@@ -1,29 +1,35 @@
#!/bin/bash
set -o pipefail

python pact_provider.py & &>/dev/null
# Run the Flask server, using the pact_provider.py as the app to be able to
# inject the provider_states endpoint
FLASK_APP=tests/pact_provider.py python -m flask run -p 5001 &
FLASK_PID=$!
VERSION=$1

# Make sure the Flask server is stopped when finished to avoid blocking the port
function teardown {
echo "Tearing down Flask server ${FLASK_PID}"
CHILD=`pgrep -P $FLASK_PID`
echo "Kill provider app with pid $CHILD"

kill -9 $CHILD
echo "Tearing down Flask server: ${FLASK_PID}"
kill -9 $FLASK_PID
}
trap teardown EXIT

if [ -x $VERSION ];
# Wait a little in case Flask isn't quite ready
sleep 1

VERSION=$1
if [ -z "$VERSION" ];
then
echo "Validating provider locally"

pact-verifier --provider-base-url=http://localhost:5001 \
pact-verifier \
--provider-base-url=http://localhost:5001 \
--provider-states-setup-url=http://localhost:5001/_pact/provider_states \
./userserviceclient-userservice.json
../pacts/userserviceclient-userservice.json
else
echo "Validating against Pact Broker"

pact-verifier --provider-base-url=http://localhost:5001 \
pact-verifier \
--provider-base-url=http://localhost:5001 \
--provider-app-version $VERSION \
--pact-url="http://127.0.0.1/pacts/provider/UserService/consumer/UserServiceClient/latest" \
--pact-broker-username pactbroker \
Expand Down

0 comments on commit 7e0b49f

Please sign in to comment.