Skip to content

Commit d67a015

Browse files
Merge pull request #14 from pact-foundation/verify-pacts
Command line application for verifying pacts
2 parents 78bd029 + ea015eb commit d67a015

File tree

14 files changed

+399
-97
lines changed

14 files changed

+399
-97
lines changed

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
v0.1.0, 2017-03-30 -- Basic support for authoring contracts against a separately running mock service
22
v0.2.0, 2017-04-22 -- Pact Python manages the Pact mock service
33
v0.3.0, 2017-05-13 -- Upgraded Pact mock service to v2.1.0 and Pact provider verifier to v1.0.1
4+
v0.4.0, 2017-05-19 -- New pact-verifier command for running Pact verification against providers

Makefile

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,33 @@ deps:
3434
pip install -r requirements_dev.txt
3535

3636

37+
define E2E
38+
set -e
39+
cd e2e
40+
nosetests ./contracts
41+
python app.py &
42+
APP_PID=$$!
43+
function teardown {
44+
echo 'Tearing down Flask server'
45+
kill $$APP_PID
46+
}
47+
trap teardown EXIT
48+
while ! nc -z localhost 5000; do
49+
sleep 0.1
50+
done
51+
pact-verifier \
52+
--provider-base-url=http://localhost:5000 \
53+
--pact-urls=./pacts/consumer-provider.json \
54+
--provider-states-url=http://localhost:5000/_pact/provider-states \
55+
--provider-states-setup-url=http://localhost:5000/_pact/provider-states/active
56+
endef
57+
58+
59+
export E2E
3760
.PHONY: e2e
3861
e2e:
39-
sh -c '\
40-
cd e2e; \
41-
docker-compose pull > /dev/null; \
42-
nosetests ./contracts; \
43-
docker-compose down; \
44-
docker-compose up -d app pactverifier; \
45-
docker-compose logs --follow >> ./pact/verifier-logs.txt & \
46-
docker-compose exec pactverifier bundle exec rake verify_pacts; \
47-
docker-compose down'
62+
sh -c "$$E2E"
63+
4864

4965
.PHONY: package
5066
package: pact/bin
@@ -61,11 +77,8 @@ test: deps pact/bin
6177
@echo "Checking version consistency..."
6278
python -c "$$VERSION_CHECK"
6379

64-
@echo "flake8..."
6580
flake8
66-
67-
@echo "pydocstyle..."
6881
pydocstyle pact
69-
70-
@echo "testing..."
82+
coverage erase
7183
tox
84+
coverage report --fail-under=100

README.md

Lines changed: 46 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -195,59 +195,56 @@ EachLike({
195195
For more information see [Matching](https://docs.pact.io/documentation/matching.html)
196196

197197
## Verifying Pacts Against a Service
198-
> pact-python does not yet have any involvement in the process of verifying a contract against
199-
> a provider. This section is included to provide insight into the full cycle of a
200-
> contract for those getting started.
201-
202-
Like the mock service, the provider verifier can be run in two ways:
203-
204-
1. [Install and use it as a Ruby application][pact-provider-verifier]
205-
2. Run it as a Docker container
206-
207-
> Both choices have very similar configuration options. We will illustrate the Docker
208-
> method below, but the Ruby method supports the same features.
209-
210-
When verifying your contracts, you may find it easier to run the provider application
211-
and the verifier in separate Docker containers. This gives you a nice isolated
212-
network, where you can set the DNS records of the services to anything you desire
213-
and not have to worry about port conflicts with other services on your computer.
214-
Launching the provider verifier in a `docker-compose.yml` might look like this:
215-
216-
```yaml
217-
version: '2'
218-
services:
219-
app:
220-
image: the-provider-application-to-test
221-
222-
pactverifier:
223-
command: ['tail', '-f', '/dev/null']
224-
image: dius/pact-provider-verifier-docker
225-
depends_on:
226-
- app
227-
volumes:
228-
- ./contracts:/tmp/pacts
229-
environment:
230-
- pact_urls=/tmp/pacts/consumer-provider.json
231-
- provider_base_url=http://app
232-
- provider_states_url=http://app/_pact/provider-states
233-
- provider_states_active_url=http://app/_pact/provider-states/active
234-
```
235198

236-
In this example, our `app` container may take a few moments to start, so we don't
237-
immediately start running the verification, and instead `tail -f /dev/null` which will keep
238-
the container running forever. We can then use `docker-compose` to run the tests like so:
199+
In addition to writing Pacts for Python consumers, you can also verify those Pacts
200+
against a provider of any language. After installing pact-python a `pact-verifier`
201+
application should be available. To get details about its use you can call it with the
202+
help argument:
239203

204+
```bash
205+
pact-verifier --help
240206
```
241-
docker-compose up -d
242-
# Insert code to check that `app` has finished starting and is ready for requests
243-
docker-compose exec pactverifier bundle exec rake verify_pacts
207+
208+
The simplest example is verifying a server with locally stored Pact files and no provider
209+
states:
210+
211+
```bash
212+
pact-verifier --provider-base-url=http://localhost:8080 --pact-urls=./pacts/consumer-provider.json
244213
```
245214

246-
You configure the verifier in Docker using 4 environment variables:
247-
- `pact_urls` - a comma delimited list of pact file urls
248-
- `provider_base_url` - the base url of the pact provider
249-
- `provider_states_url` - the full url of the endpoint which returns provider states by consumer
250-
- `provider_states_active_url` - the full url of the endpoint which sets the active pact consumer and provider state
215+
Which will immediately invoke the Pact verifier, making HTTP requests to the server located
216+
at `http://localhost:8080` based on the Pacts in `./pacts/consumer-provider.json` and
217+
reporting the results.
218+
219+
There are several options for configuring how the Pacts are verified:
220+
221+
###### --provider-base-url
222+
223+
Required. Defines the URL of the server to make requests to when verifying the Pacts.
224+
225+
###### --pact-urls
226+
227+
Required. The location of the Pact files you want to verify. This can be a URL to a [Pact Broker]
228+
or one or more local paths, separated by a comma.
229+
230+
###### --provider-states-url
231+
232+
The URL where your provider application will produce the list of available provider states.
233+
The verifier calls this URL to ensure the Pacts specify valid states before making the HTTP
234+
requests.
235+
236+
###### --provider-states-setup-url
237+
238+
The URL which should be called to setup a specific provider state before a Pact is verified.
239+
240+
###### --pact-broker-username
241+
242+
The username to use when contacting the Pact Broker.
243+
244+
###### --pact-broker-password
245+
246+
The password to use when contacting the Pact Broker. You can also specify this value
247+
as the environment variable `PACT_BROKER_PASSWORD`.
251248

252249
### Provider States
253250
In many cases, your contracts will need very specific data to exist on the provider
@@ -301,6 +298,7 @@ End to end: `make e2e`
301298
[bundler]: http://bundler.io/
302299
[context manager]: https://en.wikibooks.org/wiki/Python_Programming/Context_Managers
303300
[Pact]: https://www.gitbook.com/book/pact-foundation/pact/details
301+
[Pact Broker]: https://docs.pact.io/documentation/sharings_pacts.html
304302
[Pact documentation]: https://docs.pact.io/
305303
[Pact Mock Service]: https://github.com/bethesque/pact-mock_service
306304
[Provider States]: https://docs.pact.io/documentation/provider_states.html

e2e/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,4 @@ def catch_all(path):
5151

5252

5353
if __name__ == '__main__':
54-
app.run(host='0.0.0.0', port='80')
54+
app.run(port='5000')

e2e/docker-compose.yml

Lines changed: 0 additions & 28 deletions
This file was deleted.

pact/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@
66

77

88
__all__ = ('Consumer', 'EachLike', 'Pact', 'Provider', 'SomethingLike', 'Term')
9-
__version__ = '0.3.0'
9+
__version__ = '0.4.0'

pact/constants.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,16 @@ def mock_service_exe():
1111
return 'pact-mock-service'
1212

1313

14+
def provider_verifier_exe():
15+
"""Get the appropriate provider executable name for this platform."""
16+
if os.name == 'nt':
17+
return 'pact-provider-verifier.bat'
18+
else:
19+
return 'pact-provider-verifier'
20+
21+
1422
MOCK_SERVICE_PATH = normpath(join(
1523
dirname(__file__), 'bin', 'mock-service', 'bin', mock_service_exe()))
24+
25+
VERIFIER_PATH = normpath(join(
26+
dirname(__file__), 'bin', 'verifier', 'bin', provider_verifier_exe()))

pact/test/test_constants.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,20 @@ def test_other(self):
1818
def test_windows(self):
1919
self.mock_os.name = 'nt'
2020
self.assertEqual(constants.mock_service_exe(), 'pact-mock-service.bat')
21+
22+
23+
class provider_verifier_exeTestCase(TestCase):
24+
def setUp(self):
25+
super(provider_verifier_exeTestCase, self).setUp()
26+
self.addCleanup(patch.stopall)
27+
self.mock_os = patch.object(constants, 'os', autospec=True).start()
28+
29+
def test_other(self):
30+
self.mock_os.name = 'posix'
31+
self.assertEqual(
32+
constants.provider_verifier_exe(), 'pact-provider-verifier')
33+
34+
def test_windows(self):
35+
self.mock_os.name = 'nt'
36+
self.assertEqual(
37+
constants.provider_verifier_exe(), 'pact-provider-verifier.bat')

0 commit comments

Comments
 (0)