Skip to content

Commit 4bf7b8b

Browse files
pact-python manages the mock service for the user
- Change the API so the user can control when the mock service starts and stops - Update the README.md to illustrate controlling the mock service - Switch the command line arguments to the mock service to be separate items in a list so that they are properly quoted for the shell - Increment the project to version 0.2.0
1 parent 0a278af commit 4bf7b8b

File tree

7 files changed

+47
-58
lines changed

7 files changed

+47
-58
lines changed

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
v0.1.0, 2017-03-30 -- Basic support for authoring contracts against a separately running mock service
2+
v0.2.0, 2017-04-22 -- Pact Python manages the Pact mock service

Makefile

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,6 @@ e2e:
3939
sh -c '\
4040
cd e2e; \
4141
docker-compose pull > /dev/null; \
42-
docker-compose up -d pactmockservice; \
43-
while ! nc -z localhost 1234; do sleep 0.1; done; \
44-
docker-compose logs --follow > ./pacts/mock-service-logs.txt & \
4542
nosetests ./contracts; \
4643
docker-compose down; \
4744
docker-compose up -d app pactverifier; \

README.md

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,19 @@ def user(user_name):
4040
Then `Consumer`'s contract test might look something like this:
4141

4242
```python
43+
import atexit
4344
import unittest
4445

4546
from pact import Consumer, Provider
4647

4748

49+
pact = Consumer('Consumer').has_pact_with(Provider('Provider'))
50+
pact.start()
51+
atexit.register(pact.stop)
52+
53+
4854
class GetUserInfoContract(unittest.TestCase):
4955
def test_get_user(self):
50-
pact = Consumer('Consumer').has_pact_with(Provider('Provider'))
5156
expected = {
5257
'username': 'UserA',
5358
'id': 123,
@@ -88,13 +93,12 @@ pact = Consumer('Consumer').has_pact_with(
8893
Provider('Provider'), host_name='mockservice', port=8080)
8994
```
9095

91-
This can be useful if you are running your tests and the mock service inside a Docker
92-
network, where you want to reference the service by its Docker name, instead of via
93-
the `localhost` interface. It is important to note that the code you are testing with
94-
this contract _must_ contact the mock service. So in this example, the `user` method
95-
could accept an argument to specify the location of the server, or retrieve it from an
96-
environment variable so you can change its URI during the test. Another option is to
97-
specify a Docker network alias so the requests that you make will go to the container.
96+
This can be useful if you need to run to create more than one Pact for your test
97+
because your code interacts with two different services. It is important to note
98+
that the code you are testing with this contract _must_ contact the mock service.
99+
So in this example, the `user` method could accept an argument to specify the
100+
location of the server, or retrieve it from an environment variable so you can
101+
change its URI during the test.
98102

99103
The mock service offers you several important features when building your contracts:
100104
- It provides a real HTTP server that your code can contact during the test and provides the responses you defined.

e2e/contracts/test_e2e.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import atexit
2+
13
import requests
24
import unittest
35

@@ -7,6 +9,8 @@
79

810

911
pact = Consumer('consumer').has_pact_with(Provider('provider'))
12+
pact.start()
13+
atexit.register(pact.stop)
1014

1115

1216
class BaseTestCase(unittest.TestCase):

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.1.0'
9+
__version__ = '0.2.0'

pact/pact.py

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,6 @@ def __enter__(self):
198198
199199
Sets up the mock service to expect the client requests.
200200
"""
201-
self.start()
202201
try:
203202
payload = {
204203
'description': self._description,
@@ -217,7 +216,6 @@ def __enter__(self):
217216

218217
assert resp.status_code == 200, resp.content
219218
except AssertionError:
220-
self.stop()
221219
raise
222220

223221
def __exit__(self, exc_type, exc_val, exc_tb):
@@ -228,24 +226,20 @@ def __exit__(self, exc_type, exc_val, exc_tb):
228226
expected, and has it write out the contracts to disk.
229227
"""
230228
if (exc_type, exc_val, exc_tb) != (None, None, None):
231-
self.stop()
232229
return
233230

234-
try:
235-
resp = requests.get(
236-
self.uri + '/interactions/verification',
237-
headers=self.HEADERS)
238-
assert resp.status_code == 200, resp.content
239-
payload = {
240-
'consumer': {'name': self.consumer.name},
241-
'provider': {'name': self.provider.name},
242-
'pact_dir': self.pact_dir
243-
}
244-
resp = requests.post(
245-
self.uri + '/pact', headers=self.HEADERS, json=payload)
246-
assert resp.status_code == 200, resp.content
247-
finally:
248-
self.stop()
231+
resp = requests.get(
232+
self.uri + '/interactions/verification',
233+
headers=self.HEADERS)
234+
assert resp.status_code == 200, resp.content
235+
payload = {
236+
'consumer': {'name': self.consumer.name},
237+
'provider': {'name': self.provider.name},
238+
'pact_dir': self.pact_dir
239+
}
240+
resp = requests.post(
241+
self.uri + '/pact', headers=self.HEADERS, json=payload)
242+
assert resp.status_code == 200, resp.content
249243

250244

251245
class FromTerms(object):

pact/test/test_pact.py

Lines changed: 17 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,11 @@ def test_start_fails(self):
126126
MOCK_SERVICE_PATH, 'start',
127127
'--host=localhost',
128128
'--port=1234',
129-
'--log="/logs/pact-mock-service.log"',
130-
'--pact-dir="/pacts"',
131-
'--pact-specification-version="2.0.0"',
132-
'--consumer="consumer"',
133-
'--provider="provider"'])
129+
'--log', '/logs/pact-mock-service.log',
130+
'--pact-dir', '/pacts',
131+
'--pact-specification-version=2.0.0',
132+
'--consumer', 'consumer',
133+
'--provider', 'provider'])
134134

135135
self.mock_Popen.return_value.communicate.assert_called_once_with()
136136

@@ -143,11 +143,11 @@ def test_start_no_ssl(self):
143143
MOCK_SERVICE_PATH, 'start',
144144
'--host=localhost',
145145
'--port=1234',
146-
'--log="/logs/pact-mock-service.log"',
147-
'--pact-dir="/pacts"',
148-
'--pact-specification-version="2.0.0"',
149-
'--consumer="consumer"',
150-
'--provider="provider"'])
146+
'--log', '/logs/pact-mock-service.log',
147+
'--pact-dir', '/pacts',
148+
'--pact-specification-version=2.0.0',
149+
'--consumer', 'consumer',
150+
'--provider', 'provider'])
151151

152152
self.mock_Popen.return_value.communicate.assert_called_once_with()
153153

@@ -161,14 +161,14 @@ def test_start_with_ssl(self):
161161
MOCK_SERVICE_PATH, 'start',
162162
'--host=localhost',
163163
'--port=1234',
164-
'--log="/logs/pact-mock-service.log"',
165-
'--pact-dir="/pacts"',
166-
'--pact-specification-version="2.0.0"',
167-
'--consumer="consumer"',
168-
'--provider="provider"',
164+
'--log', '/logs/pact-mock-service.log',
165+
'--pact-dir', '/pacts',
166+
'--pact-specification-version=2.0.0',
167+
'--consumer', 'consumer',
168+
'--provider', 'provider',
169169
'--ssl',
170-
'--sslcert="/ssl.cert"',
171-
'--sslkey="/ssl.key"'])
170+
'--sslcert', '/ssl.cert',
171+
'--sslkey', '/ssl.key'])
172172

173173
self.mock_Popen.return_value.communicate.assert_called_once_with()
174174

@@ -196,8 +196,6 @@ def setUp(self):
196196
super(PactContextManagerTestCase, self).setUp()
197197
self.addCleanup(patch.stopall)
198198
self.mock_requests = patch('requests.api.request').start()
199-
self.mock_start = patch.object(Pact, 'start', autospec=True).start()
200-
self.mock_stop = patch.object(Pact, 'stop', autospec=True).start()
201199
self.consumer = Consumer('TestConsumer')
202200
self.provider = Provider('TestProvider')
203201
self.target = Pact(self.consumer, self.provider)
@@ -245,8 +243,6 @@ def test_successful(self):
245243
self.mock_requests.assert_has_calls([
246244
self.delete_call, self.post_interactions_call,
247245
self.get_verification_call, self.post_publish_pacts_call])
248-
self.mock_start.assert_called_once_with(self.target)
249-
self.mock_stop.assert_called_once_with(self.target)
250246

251247
def test_error_deleting_interactions(self):
252248
self.mock_requests.side_effect = iter([
@@ -258,8 +254,6 @@ def test_error_deleting_interactions(self):
258254
self.assertEqual(str(e.exception), 'deletion error')
259255
self.assertEqual(self.mock_requests.call_count, 1)
260256
self.mock_requests.assert_has_calls([self.delete_call])
261-
self.mock_start.assert_called_once_with(self.target)
262-
self.mock_stop.assert_called_once_with(self.target)
263257

264258
def test_error_posting_interactions(self):
265259
self.mock_requests.side_effect = iter([
@@ -273,14 +267,11 @@ def test_error_posting_interactions(self):
273267
self.assertEqual(self.mock_requests.call_count, 2)
274268
self.mock_requests.assert_has_calls(
275269
[self.delete_call, self.post_interactions_call])
276-
self.mock_start.assert_called_once_with(self.target)
277-
self.mock_stop.assert_called_once_with(self.target)
278270

279271
def test_error_raised(self):
280272
self.mock_requests.side_effect = TypeError('type error')
281273
self.target.__exit__(TypeError, 'type error', Mock())
282274
self.assertFalse(self.mock_requests.called)
283-
self.mock_stop.assert_called_once_with(self.target)
284275

285276
def test_error_verifying_interactions(self):
286277
self.mock_requests.side_effect = iter([
@@ -293,7 +284,6 @@ def test_error_verifying_interactions(self):
293284
self.assertEqual(self.mock_requests.call_count, 1)
294285
self.mock_requests.assert_has_calls([
295286
self.get_verification_call])
296-
self.mock_stop.assert_called_once_with(self.target)
297287

298288
def test_error_writing_pacts_to_file(self):
299289
self.mock_requests.side_effect = iter([
@@ -307,7 +297,6 @@ def test_error_writing_pacts_to_file(self):
307297
self.assertEqual(self.mock_requests.call_count, 2)
308298
self.mock_requests.assert_has_calls([
309299
self.get_verification_call, self.post_publish_pacts_call])
310-
self.mock_stop.assert_called_once_with(self.target)
311300

312301

313302
class FromTermsTestCase(TestCase):

0 commit comments

Comments
 (0)