Skip to content

Commit

Permalink
Command line application for verifying pacts
Browse files Browse the repository at this point in the history
- Added `pact-verifier` which is a command line application that calls the Ruby verifier
- It supports the same options as the JS version of Pact, including provider state and broker options
- Removed all Docker related requirements
  • Loading branch information
matthewbalvanz-wf committed May 20, 2017
1 parent 3130f9a commit 51eb338
Show file tree
Hide file tree
Showing 12 changed files with 394 additions and 93 deletions.
41 changes: 27 additions & 14 deletions Makefile
Expand Up @@ -34,17 +34,33 @@ deps:
pip install -r requirements_dev.txt


define E2E
set -e
cd e2e
nosetests ./contracts
python app.py &
APP_PID=$$!
function teardown {
echo 'Tearing down Flask server'
kill $$APP_PID
}
trap teardown EXIT
while ! nc -z localhost 5000; do
sleep 0.1
done
pact-verifier \
--provider-base-url=http://localhost:5000 \
--pact-urls=./pacts/consumer-provider.json \
--provider-states-url=http://localhost:5000/_pact/provider-states \
--provider-states-setup-url=http://localhost:5000/_pact/provider-states/active
endef


export E2E
.PHONY: e2e
e2e:
sh -c '\
cd e2e; \
docker-compose pull > /dev/null; \
nosetests ./contracts; \
docker-compose down; \
docker-compose up -d app pactverifier; \
docker-compose logs --follow >> ./pact/verifier-logs.txt & \
docker-compose exec pactverifier bundle exec rake verify_pacts; \
docker-compose down'
sh -c "$$E2E"


.PHONY: package
package: pact/bin
Expand All @@ -61,11 +77,8 @@ test: deps pact/bin
@echo "Checking version consistency..."
python -c "$$VERSION_CHECK"

@echo "flake8..."
flake8

@echo "pydocstyle..."
pydocstyle pact

@echo "testing..."
coverage erase
tox
coverage report --fail-under=100
88 changes: 43 additions & 45 deletions README.md
Expand Up @@ -225,59 +225,56 @@ services:
> the command line to be `8080`, your tests would need to contact `localhost:8080`.
## Verifying Pacts Against a Service
> pact-python does not yet have any involvement in the process of verifying a contract against
> a provider. This section is included to provide insight into the full cycle of a
> contract for those getting started.

Like the mock service, the provider verifier can be run in two ways:
In addition to writing Pacts for Python consumers, you can also verify those Pacts
against a provider of any language. After installing pact-python a `pact-verifier`
application should be available. To get details about its use you can call it with the
help argument:

1. [Install and use it as a Ruby application][pact-provider-verifier]
2. Run it as a Docker container

> Both choices have very similar configuration options. We will illustrate the Docker
> method below, but the Ruby method supports the same features.
```bash
pact-verifier --help
```

When verifying your contracts, you may find it easier to run the provider application
and the verifier in separate Docker containers. This gives you a nice isolated
network, where you can set the DNS records of the services to anything you desire
and not have to worry about port conflicts with other services on your computer.
Launching the provider verifier in a `docker-compose.yml` might look like this:
The simplest example is verifying a server with locally stored Pact files and no provider
states:

```yaml
version: '2'
services:
app:
image: the-provider-application-to-test

pactverifier:
command: ['tail', '-f', '/dev/null']
image: dius/pact-provider-verifier-docker
depends_on:
- app
volumes:
- ./contracts:/tmp/pacts
environment:
- pact_urls=/tmp/pacts/consumer-provider.json
- provider_base_url=http://app
- provider_states_url=http://app/_pact/provider-states
- provider_states_active_url=http://app/_pact/provider-states/active
```bash
pact-verifier --provider-base-url=http://localhost:8080 --pact-urls=./pacts/consumer-provider.json
```

In this example, our `app` container may take a few moments to start, so we don't
immediately start running the verification, and instead `tail -f /dev/null` which will keep
the container running forever. We can then use `docker-compose` to run the tests like so:
Which will immediately invoke the Pact verifier, making HTTP requests to the server located
at `http://localhost:8080` based on the Pacts in `./pacts/consumer-provider.json` and
reporting the results.

```
docker-compose up -d
# Insert code to check that `app` has finished starting and is ready for requests
docker-compose exec pactverifier bundle exec rake verify_pacts
```
There are several options for configuring how the Pacts are verified:

###### --provider-base-url

Required. Defines the URL of the server to make requests to when verifying the Pacts.

###### --pact-urls

Required. The location of the Pact files you want to verify. This can be a URL to a [Pact Broker]
or one or more local paths, separated by a comma.

###### --provider-states-url

The URL where your provider application will produce the list of available provider states.
The verifier calls this URL to ensure the Pacts specify valid states before making the HTTP
requests.

###### --provider-states-setup-url

The URL which should be called to setup a specific provider state before a Pact is verified.

###### --pact-broker-username

The username to use when contacting the Pact Broker.

###### --pact-broker-password

You configure the verifier in Docker using 4 environment variables:
- `pact_urls` - a comma delimited list of pact file urls
- `provider_base_url` - the base url of the pact provider
- `provider_states_url` - the full url of the endpoint which returns provider states by consumer
- `provider_states_active_url` - the full url of the endpoint which sets the active pact consumer and provider state
The password to use when contacting the Pact Broker. You can also specify this value
as the environment variable `PACT_BROKER_PASSWORD`.

### Provider States
In many cases, your contracts will need very specific data to exist on the provider
Expand Down Expand Up @@ -310,6 +307,7 @@ End to end: `make e2e`

[context manager]: https://en.wikibooks.org/wiki/Python_Programming/Context_Managers
[Pact]: https://www.gitbook.com/book/pact-foundation/pact/details
[Pact Broker]: https://docs.pact.io/documentation/sharings_pacts.html
[Pact documentation]: https://docs.pact.io/
[Pact Mock Service]: https://github.com/bethesque/pact-mock_service
[Provider States]: https://docs.pact.io/documentation/provider_states.html
Expand Down
2 changes: 1 addition & 1 deletion e2e/app.py
Expand Up @@ -51,4 +51,4 @@ def catch_all(path):


if __name__ == '__main__':
app.run(host='0.0.0.0', port='80')
app.run(port='5000')
28 changes: 0 additions & 28 deletions e2e/docker-compose.yml

This file was deleted.

11 changes: 11 additions & 0 deletions pact/constants.py
Expand Up @@ -11,5 +11,16 @@ def mock_service_exe():
return 'pact-mock-service'


def provider_verifier_exe():
"""Get the appropriate provider executable name for this platform."""
if os.name == 'nt':
return 'pact-provider-verifier.bat'
else:
return 'pact-provider-verifier'


MOCK_SERVICE_PATH = normpath(join(
dirname(__file__), 'bin', 'mock-service', 'bin', mock_service_exe()))

VERIFIER_PATH = normpath(join(
dirname(__file__), 'bin', 'verifier', 'bin', provider_verifier_exe()))
17 changes: 17 additions & 0 deletions pact/test/test_constants.py
Expand Up @@ -18,3 +18,20 @@ def test_other(self):
def test_windows(self):
self.mock_os.name = 'nt'
self.assertEqual(constants.mock_service_exe(), 'pact-mock-service.bat')


class provider_verifier_exeTestCase(TestCase):
def setUp(self):
super(provider_verifier_exeTestCase, self).setUp()
self.addCleanup(patch.stopall)
self.mock_os = patch.object(constants, 'os', autospec=True).start()

def test_other(self):
self.mock_os.name = 'posix'
self.assertEqual(
constants.provider_verifier_exe(), 'pact-provider-verifier')

def test_windows(self):
self.mock_os.name = 'nt'
self.assertEqual(
constants.provider_verifier_exe(), 'pact-provider-verifier.bat')

0 comments on commit 51eb338

Please sign in to comment.