From 7e0b49fe3e24b026075c3f0cdbe1556388a223d1 Mon Sep 17 00:00:00 2001 From: Mike Geeves Date: Tue, 12 Oct 2021 10:44:27 +0100 Subject: [PATCH] test(examples): tidy build and examples and make functionality between Flask and FastAPI consistent re #270 --- examples/README.md | 97 ++++++++++++++++--- examples/flask_provider/run_pytest.sh | 2 +- .../tests/provider/test_provider.py | 1 - examples/flask_provider/verify_pact.sh | 28 +++--- 4 files changed, 99 insertions(+), 29 deletions(-) diff --git a/examples/README.md b/examples/README.md index fcb50deb8..f3f6edc2d 100644 --- a/examples/README.md +++ b/examples/README.md @@ -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 @@ -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 @@ -85,4 +136,18 @@ TODO TODO -[Pact Broker]: https://docs.pact.io/pact_broker \ No newline at end of file +## 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/] \ No newline at end of file diff --git a/examples/flask_provider/run_pytest.sh b/examples/flask_provider/run_pytest.sh index c7249be8c..ca022085f 100755 --- a/examples/flask_provider/run_pytest.sh +++ b/examples/flask_provider/run_pytest.sh @@ -17,4 +17,4 @@ trap teardown EXIT sleep 1 # Now run the tests -pytest tests --run-broker True --publish-pact 1 -s \ No newline at end of file +pytest tests --run-broker True --publish-pact 1 \ No newline at end of file diff --git a/examples/flask_provider/tests/provider/test_provider.py b/examples/flask_provider/tests/provider/test_provider.py index 646c3e147..ede0835d0 100644 --- a/examples/flask_provider/tests/provider/test_provider.py +++ b/examples/flask_provider/tests/provider/test_provider.py @@ -1,7 +1,6 @@ """pact test for user service provider""" import logging -import time import pytest diff --git a/examples/flask_provider/verify_pact.sh b/examples/flask_provider/verify_pact.sh index 539e08127..f70629699 100755 --- a/examples/flask_provider/verify_pact.sh +++ b/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 \