pact 1.1.0 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +31 -20
- data/Gemfile.lock +12 -12
- data/README.md +32 -16
- data/Rakefile +3 -3
- data/documentation/README.md +1 -0
- data/documentation/development-workflow.md +22 -0
- data/documentation/faq.md +8 -0
- data/documentation/provider-states.md +2 -0
- data/documentation/troubleshooting.md +4 -0
- data/documentation/verifying-pacts.md +97 -0
- data/lib/pact/app.rb +98 -4
- data/lib/pact/consumer/rspec.rb +3 -2
- data/lib/pact/doc/doc_file.rb +4 -4
- data/lib/pact/doc/generator.rb +3 -3
- data/lib/pact/doc/interaction_view_model.rb +1 -0
- data/lib/pact/doc/markdown/{interactions_renderer.rb → consumer_contract_renderer.rb} +1 -1
- data/lib/pact/doc/markdown/generator.rb +2 -2
- data/lib/pact/matchers/unix_diff_formatter.rb +1 -1
- data/lib/pact/project_root.rb +7 -0
- data/lib/pact/provider.rb +0 -1
- data/lib/pact/provider/context.rb +0 -0
- data/lib/pact/provider/matchers/messages.rb +15 -13
- data/lib/pact/provider/pact_spec_runner.rb +21 -22
- data/lib/pact/provider/rspec.rb +22 -15
- data/lib/pact/provider/rspec/custom_options_file +0 -0
- data/lib/pact/provider/{matchers.rb → rspec/matchers.rb} +2 -1
- data/lib/pact/rspec.rb +20 -0
- data/lib/pact/shared/request.rb +1 -1
- data/lib/pact/tasks/task_helper.rb +18 -15
- data/lib/pact/tasks/verification_task.rb +26 -32
- data/lib/pact/version.rb +1 -1
- data/lib/tasks/pact.rake +5 -11
- data/spec/integration/pact/consumer_configuration_spec.rb +3 -3
- data/spec/lib/pact/app_spec.rb +47 -0
- data/spec/lib/pact/consumer/app_manager_spec.rb +1 -1
- data/spec/lib/pact/consumer/mock_service/interaction_list_spec.rb +3 -3
- data/spec/lib/pact/consumer/mock_service/verification_get_spec.rb +10 -2
- data/spec/lib/pact/consumer/mock_service_interaction_expectation_spec.rb +2 -2
- data/spec/lib/pact/consumer_contract/consumer_contract_spec.rb +1 -1
- data/spec/lib/pact/consumer_contract/interaction_spec.rb +4 -4
- data/spec/lib/pact/consumer_contract/request_spec.rb +23 -23
- data/spec/lib/pact/doc/generator_spec.rb +4 -4
- data/spec/lib/pact/doc/markdown/{interactions_renderer_spec.rb → consumer_contract_renderer_spec.rb} +4 -4
- data/spec/lib/pact/matchers/unix_diff_formatter_spec.rb +8 -8
- data/spec/lib/pact/provider/configuration/configuration_extension_spec.rb +2 -2
- data/spec/lib/pact/provider/matchers/messages_spec.rb +17 -6
- data/spec/lib/pact/provider/rspec/formatter_spec.rb +3 -1
- data/spec/lib/pact/shared/dsl_spec.rb +1 -1
- data/spec/lib/pact/shared/request_spec.rb +8 -0
- data/spec/lib/pact/tasks/task_helper_spec.rb +39 -54
- data/spec/lib/pact/tasks/verification_task_spec.rb +75 -0
- data/spec/pact_specification/compliance-1.0.0.rb +47 -0
- data/spec/spec_helper.rb +2 -6
- data/spec/standalone/consumer_fail_test.rb +1 -0
- data/spec/standalone/consumer_pass_test.rb +1 -0
- data/spec/support/active_support_if_configured.rb +6 -0
- data/spec/support/pact_helper.rb +2 -1
- data/spec/support/shared_examples_for_request.rb +15 -4
- data/spec/support/spec_support.rb +3 -0
- data/spec/support/stubbing_using_allow.rb +1 -0
- data/spec/support/term.json +13 -1
- data/tasks/pact-test.rake +45 -26
- metadata +23 -13
- data/lib/pact/provider/client_project_pact_helper.rb +0 -4
- data/spec/lib/pact/provider/pact_spec_runner_spec.rb +0 -7
- data/spec/lib/pact/verification_task_spec.rb +0 -99
data/CHANGELOG.md
CHANGED
@@ -2,38 +2,49 @@ Do this to generate your change history
|
|
2
2
|
|
3
3
|
git log --pretty=format:' * %h - %s (%an, %ad)'
|
4
4
|
|
5
|
+
### 1.1.1 (3 June 2014)
|
6
|
+
|
7
|
+
* 503a3f4 - The pact verify executable now adds lib to the load path before requiring the pact_helper. (bethesque, Tue Jun 3 09:26:46 2014 +1000)
|
8
|
+
* f62622e - Fixed output when a Pact::Term is expected in a response header. (bethesque, Tue Jun 3 07:18:52 2014 +1000)
|
9
|
+
* bb5ae47 - Updated pact spec runner, matchers and pact verification code to work with both rspec 2.14 and 2.99. It's not pretty, but it does the job
|
10
|
+
* c150e35 - Created a "pact verify" executable and change the rake task to invoke it to avoid the problem of cross contamination of requires (eg. wit
|
11
|
+
* d981ab7 - Added "actual" response to pact:verify failure message to make it easier to identify the reason for failure. (bethesque, Tue May 20 21:49:06 2
|
12
|
+
* a18787d - Added pact specification compliance spec. WIP. (bethesque, Tue May 20 21:48:10 2014 +1000)
|
13
|
+
* 2d52356 - Adding back HTTP method and path to pact verify output, as it is otherwise impossible to tell from the output what the actual request was
|
14
|
+
* 674d8c9 - Addd query to request.method_and_path (bethesque, Sat May 17 16:23:20 2014 +1000)
|
15
|
+
|
5
16
|
### 1.1.0 (5 May 2014)
|
6
17
|
|
7
18
|
### 1.1.0.rc5 (5 May 2014)
|
8
|
-
* dc9855b - Downcasing HTTP methods before sending call to RSpec::Test::Methods because pact-jvm is using an upcase method https://github.com/DiUS/pact-jvm/issues/34 (
|
9
|
-
* ddd4677 - Fixed problem of Pact::Terms displaying inside diff output by unpacking all the regular expressions before the diff is calculated (
|
19
|
+
* dc9855b - Downcasing HTTP methods before sending call to RSpec::Test::Methods because pact-jvm is using an upcase method https://github.com/DiUS/pact-jvm/issues/34 (bethesque, Mon May 5 12:29:51 2014 +1000)
|
20
|
+
* ddd4677 - Fixed problem of Pact::Terms displaying inside diff output by unpacking all the regular expressions before the diff is calculated (bethesque, Mon May 5 12:16:25 2014 +1000)
|
10
21
|
|
11
22
|
### 1.1.0.rc4 (1 May 2014)
|
12
23
|
|
13
|
-
* 5e1b78d - Display / in logs when path is empty https://github.com/realestate-com-au/pact/issues/14 (
|
14
|
-
* 01c5414 - Fixing doc generation bug where Pact::Terms were being displayed https://github.com/realestate-com-au/pact/issues/13 (
|
15
|
-
* 292a14b - Cleaning doc dir before generating new docs as per https://github.com/realestate-com-au/pact/issues/11 (
|
16
|
-
* 73c15dd - Changed default doc_dir to ./doc/pacts as per https://github.com/realestate-com-au/pact/issues/12 (
|
17
|
-
* 78ca78c - Fixed bug where log_dir was being ignored when set to a non default value (
|
24
|
+
* 5e1b78d - Display / in logs when path is empty https://github.com/realestate-com-au/pact/issues/14 (bethesque, Thu May 1 22:09:29 2014 +1000)
|
25
|
+
* 01c5414 - Fixing doc generation bug where Pact::Terms were being displayed https://github.com/realestate-com-au/pact/issues/13 (bethesque, Thu May 1 21:41:11 2014 +1000)
|
26
|
+
* 292a14b - Cleaning doc dir before generating new docs as per https://github.com/realestate-com-au/pact/issues/11 (bethesque, Tue Apr 29 12:44:47 2014 +1000)
|
27
|
+
* 73c15dd - Changed default doc_dir to ./doc/pacts as per https://github.com/realestate-com-au/pact/issues/12 (bethesque, Tue Apr 29 12:33:57 2014 +1000)
|
28
|
+
* 78ca78c - Fixed bug where log_dir was being ignored when set to a non default value (bethesque, Tue Apr 29 07:50:32 2014 +1000)
|
18
29
|
|
19
30
|
### 1.1.0.rc3 (28 April 2014)
|
20
31
|
|
21
|
-
* 41fa409 - Cleaned up consumer after spec failure message (
|
22
|
-
* 8593fa9 - Updated zoo-app example (
|
23
|
-
* 716e3a8 - Added standalone consumer spec and spec for VerificationGet (
|
24
|
-
* c0f9bc6 - Copied RSpec::Expectations::Differ to Pact::Matchers::Differ - safer than trying to override behaviour (
|
25
|
-
* 0eeb032 - Changing default diff_formatter to unix (
|
32
|
+
* 41fa409 - Cleaned up consumer after spec failure message (bethesque, Sun Apr 27 22:18:03 2014 +1000)
|
33
|
+
* 8593fa9 - Updated zoo-app example (bethesque, Sun Apr 27 20:54:51 2014 +1000)
|
34
|
+
* 716e3a8 - Added standalone consumer spec and spec for VerificationGet (bethesque, Thu Apr 24 10:15:17 2014 +1000)
|
35
|
+
* c0f9bc6 - Copied RSpec::Expectations::Differ to Pact::Matchers::Differ - safer than trying to override behaviour (bethesque, Thu Apr 24 09:17:58 2014 +
|
36
|
+
* 0eeb032 - Changing default diff_formatter to unix (bethesque, Thu Apr 24 08:19:15 2014 +1000)
|
26
37
|
* ace5d4d - Update README.md (bethesque, Wed Apr 23 20:59:24 2014 +1000)
|
27
38
|
* 24efef6 - Update configuration.md (bethesque, Wed Apr 23 20:51:00 2014 +1000)
|
28
39
|
* 2d862b7 - Update best-practices.md (bethesque, Wed Apr 23 07:33:01 2014 +1000)
|
29
|
-
* ff8dfd2 - Updated doco (
|
30
|
-
* 88e4572 - Moving best practices into its own file (
|
31
|
-
* 5a3b92c - Moving provider state documentation out of main README into it's own file. (
|
32
|
-
* 1d568c4 - Updated configuration documentation (
|
33
|
-
* be1412e - Added configuration documentation (
|
34
|
-
* 9f9d178 - Added HAL raq (
|
35
|
-
* d9b6479 - Renamed ListOfPathsFormatter to ListDiffFormatter (
|
36
|
-
* 6b82402 - Renamed NestedJsonDiffFormatter to EmbeddedDiffFormatter (
|
40
|
+
* ff8dfd2 - Updated doco (bethesque, Tue Apr 22 21:45:17 2014 +1000)
|
41
|
+
* 88e4572 - Moving best practices into its own file (bethesque, Tue Apr 22 21:28:36 2014 +1000)
|
42
|
+
* 5a3b92c - Moving provider state documentation out of main README into it's own file. (bethesque, Tue Apr 22 19:59:48 2014 +1000)
|
43
|
+
* 1d568c4 - Updated configuration documentation (bethesque, Tue Apr 22 13:06:47 2014 +1000)
|
44
|
+
* be1412e - Added configuration documentation (bethesque, Tue Apr 22 13:04:33 2014 +1000)
|
45
|
+
* 9f9d178 - Added HAL raq (bethesque, Tue Apr 22 12:51:42 2014 +1000)
|
46
|
+
* d9b6479 - Renamed ListOfPathsFormatter to ListDiffFormatter (bethesque, Tue Apr 22 12:48:57 2014 +1000)
|
47
|
+
* 6b82402 - Renamed NestedJsonDiffFormatter to EmbeddedDiffFormatter (bethesque, Tue Apr 22 12:45:50 2014 +1000)
|
37
48
|
* def8afd - Merge branch 'master' into release-1.1.0 (bethesque, Tue Apr 22 09:13:41 2014 +1000)
|
38
49
|
* 789a471 - Added generated docs to zoo-app (bethesque, Tue Apr 15 17:20:08 2014 +1000)
|
39
50
|
* f5da7ab - Improved header match failure message (bethesque, Tue Apr 15 09:39:12 2014 +1000)
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
pact (1.1.
|
4
|
+
pact (1.1.1)
|
5
5
|
awesome_print (~> 1.1)
|
6
6
|
find_a_port (~> 1.0.1)
|
7
7
|
json
|
@@ -27,7 +27,7 @@ GEM
|
|
27
27
|
coderay (1.0.9)
|
28
28
|
crack (0.4.1)
|
29
29
|
safe_yaml (~> 0.9.0)
|
30
|
-
diff-lcs (1.2.
|
30
|
+
diff-lcs (1.2.5)
|
31
31
|
fakefs (0.4.2)
|
32
32
|
find_a_port (1.0.1)
|
33
33
|
hashie (2.0.5)
|
@@ -45,16 +45,16 @@ GEM
|
|
45
45
|
rack (>= 1.0)
|
46
46
|
rake (10.0.4)
|
47
47
|
randexp (0.1.7)
|
48
|
-
rspec (2.
|
49
|
-
rspec-core (~> 2.
|
50
|
-
rspec-expectations (~> 2.
|
51
|
-
rspec-mocks (~> 2.
|
52
|
-
rspec-core (2.
|
53
|
-
rspec-expectations (2.
|
48
|
+
rspec (2.99.0)
|
49
|
+
rspec-core (~> 2.99.0)
|
50
|
+
rspec-expectations (~> 2.99.0)
|
51
|
+
rspec-mocks (~> 2.99.0)
|
52
|
+
rspec-core (2.99.0)
|
53
|
+
rspec-expectations (2.99.0)
|
54
54
|
diff-lcs (>= 1.1.3, < 2.0)
|
55
|
-
rspec-fire (1.
|
56
|
-
rspec (
|
57
|
-
rspec-mocks (2.
|
55
|
+
rspec-fire (1.3.0)
|
56
|
+
rspec (>= 2.11, < 4)
|
57
|
+
rspec-mocks (2.99.0)
|
58
58
|
safe_yaml (0.9.5)
|
59
59
|
slop (3.4.6)
|
60
60
|
term-ansicolor (1.3.0)
|
@@ -62,7 +62,7 @@ GEM
|
|
62
62
|
thor (0.19.1)
|
63
63
|
thread_safe (0.1.3)
|
64
64
|
atomic
|
65
|
-
tins (1.
|
65
|
+
tins (1.3.0)
|
66
66
|
tzinfo (0.3.38)
|
67
67
|
webmock (1.9.3)
|
68
68
|
addressable (>= 2.2.7)
|
data/README.md
CHANGED
@@ -10,13 +10,19 @@ This gem is inspired by the concept of "Consumer driven contracts". See http://m
|
|
10
10
|
|
11
11
|
Travis CI Status: [![travis-ci.org Build Status](https://travis-ci.org/realestate-com-au/pact.png)](https://travis-ci.org/realestate-com-au/pact)
|
12
12
|
|
13
|
+
## What is it good for?
|
14
|
+
|
15
|
+
Pact is most valuable for designing and testing integrations where you (or your team/organisation/partner organisation) control the development of both the consumer and the provider. It is fantastic tool for intra-organsation microservices.
|
16
|
+
|
13
17
|
## Features
|
18
|
+
|
14
19
|
* A service is mocked using an actual process running on a specified port, so javascript clients can be tested as easily as backend clients.
|
15
20
|
* "Provider states" (similar to fixtures) allow the same request to be made with a different expected response.
|
16
21
|
* Consumers specify only the fields they are interested in, allowing a provider to return more fields without breaking the pact. This allows a provider to have a different pact with a different consumer, and know which fields each cares about in a given response.
|
17
22
|
* Rake tasks allow pacts to be verified against a service provider codebase.
|
18
23
|
* Different versions of a consumer/provider pairs can be easily tested against each other, allowing confidence when deploying new versions of each (see the pact_broker and pact_broker-client gems).
|
19
24
|
* Autogenerated API documentation - need we say more?
|
25
|
+
* Coming soon - autogenerated network diagrams with the [Pact Broker](https://github.com/bethesque/pact_broker)
|
20
26
|
|
21
27
|
## How does it work?
|
22
28
|
|
@@ -24,13 +30,13 @@ Travis CI Status: [![travis-ci.org Build Status](https://travis-ci.org/realestat
|
|
24
30
|
1. When the specs are run, the requests, and their expected responses, are written to a "pact" file.
|
25
31
|
1. The requests in the pact file are later replayed against the provider, and the actual responses are checked to make sure they match the expected responses.
|
26
32
|
|
27
|
-
## Why is developing and testing with
|
33
|
+
## Why is developing and testing with Pact better than using traditional system integration tests?
|
28
34
|
|
29
35
|
* Faster execution.
|
30
|
-
* Reliable responses from mock service
|
31
|
-
*
|
36
|
+
* Reliable responses from mock service reduce likelihood of flakey tests.
|
37
|
+
* Causes of failure are easier to identify as only one component is being tested at a time.
|
32
38
|
* Design of service provider is improved by considering first how the data is actually going to be used, rather than how it is most easily retrieved and serialised.
|
33
|
-
* No
|
39
|
+
* No separate integration environment required for automated integration tests - pact tests run in standalone CI builds.
|
34
40
|
|
35
41
|
## Contact
|
36
42
|
|
@@ -172,9 +178,9 @@ Require "pact/tasks" in your Rakefile.
|
|
172
178
|
require 'pact/tasks'
|
173
179
|
```
|
174
180
|
|
175
|
-
Create a `pact_helper.rb` in your service provider project. The
|
181
|
+
Create a `pact_helper.rb` in your service provider project. The recommended place is `spec/service_consumers/pact_helper.rb`.
|
176
182
|
|
177
|
-
See the [Provider](/
|
183
|
+
See [Verifying Pacts](documentation/verifying-pacts.md) and the [Provider](documentation/configuration.md#provider) section of the Configuration documentation for more information.
|
178
184
|
|
179
185
|
```ruby
|
180
186
|
# In specs/service_consumers/pact_helper.rb
|
@@ -183,12 +189,10 @@ require 'pact/provider/rspec'
|
|
183
189
|
|
184
190
|
Pact.service_provider "My Service Provider" do
|
185
191
|
|
186
|
-
app { MyApp.new } # Optional, loads app from config.ru by default
|
187
|
-
|
188
192
|
honours_pact_with 'My Service Consumer' do
|
189
193
|
|
190
194
|
# This example points to a local file, however, on a real project with a continuous
|
191
|
-
# integration box, you would publish your pacts as artifacts,
|
195
|
+
# integration box, you would use a [Pact Broker](https://github.com/bethesque/pact_broker) or publish your pacts as artifacts,
|
192
196
|
# and point the pact_uri to the pact published by the last successful build.
|
193
197
|
|
194
198
|
pact_uri '../path-to-your-consumer-project/specs/pacts/my_consumer-my_provider.json'
|
@@ -248,15 +252,15 @@ See the [Configuration](/documentation/configuration.md) section of the document
|
|
248
252
|
|
249
253
|
As in all things, there are good ways to implement Pacts, and there are not so good ways. Check out the [Best practices](/documentation/best-practices.md) section of the documentation to make sure you're not Pacting it Wrong.
|
250
254
|
|
251
|
-
##
|
252
|
-
|
253
|
-
* Be aware when using the app from the config.ru file is used (the default option) that the Rack::Builder.parse_file seems to require files even if they have already been required, so make sure your boot files are idempotent.
|
254
|
-
|
255
|
-
|
256
|
-
See [Frequently Asked Questions](https://github.com/realestate-com-au/pact/blob/master/documentation/faq.md) and [Rarely Asked Questions](https://github.com/realestate-com-au/pact/blob/master/documentation/raq.md) and [Terminology](https://github.com/realestate-com-au/pact/blob/master/documentation/terminology.md) for more information.
|
255
|
+
## Docs
|
257
256
|
|
257
|
+
* [Example](example)
|
258
|
+
* [Frequently Asked Questions](documentation/faq.md)
|
259
|
+
* [Rarely Asked Questions](documentation/raq.md)
|
260
|
+
* [Terminology](documentation/terminology.md)
|
261
|
+
* [Configuration](/documentation/configuration.md)
|
258
262
|
|
259
|
-
## Related
|
263
|
+
## Related libraries
|
260
264
|
|
261
265
|
[Pact Provider Proxy](https://github.com/bethesque/pact-provider-proxy) - Verify a pact against a running server, allowing you to use pacts with a provider of any language.
|
262
266
|
|
@@ -264,8 +268,20 @@ See [Frequently Asked Questions](https://github.com/realestate-com-au/pact/blob/
|
|
264
268
|
|
265
269
|
[Pact Broker Client](https://github.com/bethesque/pact_broker-client) - Contains rake tasks for publishing pacts to the pact_broker.
|
266
270
|
|
271
|
+
[Pact JVM](https://github.com/DiUS/pact-jvm) - A Pact implementation for the JVM (Java and Scala). It generates pact files that are compatible with the Ruby implementation.
|
272
|
+
|
267
273
|
[Shokkenki](https://github.com/brentsnook/shokkenki) - Another Consumer Driven Contract gem written by one of Pact's original authors, Brent Snook. Shokkenki allows matchers to be composed using jsonpath expressions and allows auto-generation of mock response values based on regular expressions.
|
268
274
|
|
275
|
+
## Links
|
276
|
+
|
277
|
+
[Pact specification](https://github.com/bethesque/pact-specification)
|
278
|
+
|
279
|
+
[Integrated tests are a scam](http://vimeo.com/80533536) - J.B. Rainsberger
|
280
|
+
|
281
|
+
[Consumer Driven Contracts](http://martinfowler.com/articles/consumerDrivenContracts.html) - Ian Robinson
|
282
|
+
|
283
|
+
[Integration Contract Tests](http://martinfowler.com/bliki/IntegrationContractTest.html) - Martin Fowler
|
284
|
+
|
269
285
|
## TODO
|
270
286
|
|
271
287
|
Short term:
|
data/Rakefile
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
2
|
require 'rspec/core/rake_task'
|
3
3
|
|
4
|
-
Dir.glob('lib/tasks/**/*.rake').each { |task| load task }
|
5
|
-
Dir.glob('tasks/**/*.rake').each { |task| load task }
|
4
|
+
Dir.glob('./lib/tasks/**/*.rake').each { |task| load task }
|
5
|
+
Dir.glob('./tasks/**/*.rake').each { |task| load task }
|
6
6
|
RSpec::Core::RakeTask.new(:spec)
|
7
7
|
|
8
|
-
task :default => [:spec,
|
8
|
+
task :default => [:spec, 'pact:tests:all', :spec_with_active_support, 'pact:tests:all:with_active_support']
|
9
9
|
|
data/documentation/README.md
CHANGED
@@ -0,0 +1,22 @@
|
|
1
|
+
# Development Workflow
|
2
|
+
|
3
|
+
Using consumer driven contracts enables you to reverse the "normal" order of development, allowing you to build your consumer, in its entirety if need be, before you build your provider.
|
4
|
+
|
5
|
+
The development process will be different for every organisation, but this is one that has worked for the pact authors.
|
6
|
+
|
7
|
+
## Initial development
|
8
|
+
1. Write consumer tests with pact
|
9
|
+
1. Implement consumer
|
10
|
+
1. Add `pact:publish` task to consumer build or publish pact as CI artifact
|
11
|
+
1. Create provider project
|
12
|
+
1. Configure pact:verify task to point to latest published pact
|
13
|
+
1. Implement provider until `pact:verify` passes
|
14
|
+
|
15
|
+
## New features
|
16
|
+
|
17
|
+
1. Add new feature, with pact specs, to consumer project on a branch.
|
18
|
+
1. In the provider project, use `rake pact:verify:at[/path/to/pact/on/branch]` to verify the new pact.
|
19
|
+
1. Commit/release new provider feature.
|
20
|
+
1. Merge consumer branch into master.
|
21
|
+
|
22
|
+
This may seem complex, but it is actually sufacing the underlying reality, that you cannot add new functionality to the consumer before it can be supported by the provider, but that the functionality that the provider supports should still be driven by the needs of the consumer.
|
data/documentation/faq.md
CHANGED
@@ -18,6 +18,14 @@ Unlike Webmock:
|
|
18
18
|
* Pact provides verification that the responses that have been stubbed are actually the responses that will be returned in the given conditions.
|
19
19
|
* Pact runs a mock server in an actual process, rather than intercepting requests within the Ruby code, allowing Javascript rich UI clients to be tested in a browser.
|
20
20
|
|
21
|
+
### How can I handle versioning?
|
22
|
+
|
23
|
+
Consumer driven contracts to some extent allows you to do away with versioning. As long as all your contract tests pass, you should be able to deploy changes without versioning the API. If you need to make a breaking change to a provider, you can do it in a multiple step process - add the new fields/endpoints to the provider and deploy. Update the consumers to use the new fields, then deploy. Remove the old fields/endpoints from the provider and deploy. At each step of the process, all the contract tests remain green.
|
24
|
+
|
25
|
+
Using a [Pact Broker]((https://github.com/bethesque/pact_broker), you can tag the production version of a pact when you make a release of a consumer. Then, any changes that you make to the provider can be checked agains the production version of the pact, as well as the latest version, to ensure backward compatiblity.
|
26
|
+
|
27
|
+
If you need to support multiple versions of the provider API concurrently, then you will probably be specifying which version your consumer uses by setting a header, or using a different URL component. As these are actually different requests, the interactions can be verified in the same pact without any problems.
|
28
|
+
|
21
29
|
### How can I verify a pact against a non-ruby provider?
|
22
30
|
|
23
31
|
You can verify a pact against any running server, regardless of language, using [pact-provider-proxy](https://github.com/bethesque/pact-provider-proxy).
|
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
Provider states allow you to set up data on the provider before the interaction is run, so that it can make a response that matches what the consumer expects. It also allows the consumer to make the same request with different expected responses.
|
4
4
|
|
5
|
+
Keep in mind that a provider state is all about the state of the *provider* (eg. what data is there), not about the state of the consumer or the request.
|
6
|
+
|
5
7
|
### Consumer codebase
|
6
8
|
|
7
9
|
For example, some code that creates a pact in a consumer project might look like this:
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# Verifying pacts
|
2
|
+
|
3
|
+
"Verifying a pact" is the second step of the Pact testing process. Each request in the pact file is replayed against
|
4
|
+
the provider, and the response that is returned is compared with the expected response in the pact file, and if the two
|
5
|
+
match, then we know the consumer and provider are compatible.
|
6
|
+
|
7
|
+
To verify a pact, we must:
|
8
|
+
|
9
|
+
1. Configure the location of the pact to be verified. This can be a HTTP URL, or a local file system path.
|
10
|
+
|
11
|
+
2. Set up the data for the [provider states](/documentation/provider-states.md).
|
12
|
+
|
13
|
+
## Using rake pact:verify
|
14
|
+
|
15
|
+
Using the pact:verify task is the default way to verify pacts. It is made available by requiring `'pact/tasks'` in your Rakefile.
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
# In Rakefile
|
19
|
+
require 'pact/tasks'
|
20
|
+
```
|
21
|
+
|
22
|
+
The pacts that will be verified by the pact:verify task are configured in the pact_helper.rb file in your provider codebase.
|
23
|
+
The file must be called pact_helper.rb, however there is some flexibility in where it can be stored.
|
24
|
+
The recommended place is `spec/service_consumers/pact_helper.rb`.
|
25
|
+
|
26
|
+
To ensure that the latest version of the consumer pact is used each time, it is recommended that you either use a [Pact Broker](https://github.com/bethesque/pact_broker)
|
27
|
+
or that you publish the pacts of a successful consumer build as artefacts in your CI system.
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
# In specs/service_consumers/pact_helper.rb
|
31
|
+
|
32
|
+
require 'pact/provider/rspec'
|
33
|
+
|
34
|
+
Pact.service_provider "My Service Provider" do
|
35
|
+
|
36
|
+
app { MyApp.new } # Optional, loads app from config.ru by default
|
37
|
+
|
38
|
+
honours_pact_with 'My Service Consumer' do
|
39
|
+
|
40
|
+
# This example points to a local file, however, on a real project with a continuous
|
41
|
+
# integration box, you would publish your pacts as artifacts,
|
42
|
+
# and point the pact_uri to the pact published by the last successful build.
|
43
|
+
|
44
|
+
pact_uri '../path-to-your-consumer-project/specs/pacts/my_consumer-my_provider.json'
|
45
|
+
end
|
46
|
+
|
47
|
+
# This block is repeated for every pact that this provider should be verified against.
|
48
|
+
honours_pact_with 'Some other Service Consumer' do
|
49
|
+
...
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
```
|
54
|
+
|
55
|
+
## Using rake pact:verify:at
|
56
|
+
|
57
|
+
You can also verify a pact at any arbitrary local or remote URL using the `pact:verify:at` task.
|
58
|
+
This is useful when you are writing the consumer and provider concurrently, and wish to
|
59
|
+
|
60
|
+
$ rake pact:verify:at[../path-to-your-consumer-project/specs/pacts/my_consumer-my_provider.json]
|
61
|
+
$ rake pact:verify:at[http://build-box/MyConsumerBuild/latestSuccessful/artifacts/my_consumer-my_provider.json]
|
62
|
+
|
63
|
+
|
64
|
+
## Using a custom pact:verify task
|
65
|
+
|
66
|
+
To make a shortcut task for verifying a pact an arbitrary URL that you do not want to verify as part of your normal pact:verify task,
|
67
|
+
(eg. when you are developing the consumer and provider side by side, and want a shorter feedback cycle than can be provided by
|
68
|
+
by your CI box) add the following to your Rakefile. The pact.uri may be a local file system path or a remote URL.
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
# In Rakefile or /tasks/pact.rake
|
72
|
+
|
73
|
+
# This creates a rake task that can be executed by running
|
74
|
+
# $ rake pact:verify:dev
|
75
|
+
|
76
|
+
Pact::VerificationTask.new(:dev) do | pact |
|
77
|
+
pact.uri '../path-to-your-consumer-project/specs/pacts/my_consumer-my_provider.json'
|
78
|
+
end
|
79
|
+
```
|
80
|
+
|
81
|
+
## Running one pact at a time
|
82
|
+
|
83
|
+
At some stage, you'll want to be able to run your specs one at a time while you implement each feature. At the bottom of the failed pact:verify output you will see the commands to rerun each failed interaction individually. A command to run just one interaction will look like this:
|
84
|
+
|
85
|
+
$ rake pact:verify PACT_DESCRIPTION="a request for something" PACT_PROVIDER_STATE="something exists"
|
86
|
+
|
87
|
+
## Pact Helper location
|
88
|
+
|
89
|
+
The search paths for the pact_helper are:
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
[
|
93
|
+
"spec/**/*service*consumer*/pact_helper.rb",
|
94
|
+
"spec/**/*consumer*/pact_helper.rb",
|
95
|
+
"spec/**/pact_helper.rb",
|
96
|
+
"**/pact_helper.rb"]
|
97
|
+
```
|
data/lib/pact/app.rb
CHANGED
@@ -7,12 +7,90 @@ require 'rack/handler/webrick'
|
|
7
7
|
module Pact
|
8
8
|
class App < Thor
|
9
9
|
|
10
|
-
desc '
|
10
|
+
desc 'verify', "Verify a pact"
|
11
|
+
method_option :pact_helper, aliases: "-h", desc: "Pact helper file", :required => true
|
12
|
+
method_option :pact_uri, aliases: "-p", desc: "Pact URI"
|
13
|
+
|
14
|
+
def verify
|
15
|
+
RunPactVerification.call(options)
|
16
|
+
end
|
17
|
+
|
18
|
+
desc 'service', "Start a mock service"
|
11
19
|
method_option :port, aliases: "-p", desc: "Port on which to run the service"
|
12
20
|
method_option :log, aliases: "-l", desc: "File to which to log output"
|
13
21
|
method_option :quiet, aliases: "-q", desc: "If true, no admin messages will be shown"
|
14
22
|
|
15
23
|
def service
|
24
|
+
RunStandaloneMockService.call(options)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def log message
|
30
|
+
puts message unless options[:quiet]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class RunPactVerification
|
35
|
+
|
36
|
+
attr_reader :options
|
37
|
+
|
38
|
+
def initialize options
|
39
|
+
@options = options
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.call options
|
43
|
+
new(options).call
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def call
|
48
|
+
setup_load_path
|
49
|
+
load_pact_helper
|
50
|
+
run_specs
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def setup_load_path
|
56
|
+
require 'pact/provider/pact_spec_runner'
|
57
|
+
lib = Dir.pwd + "/lib" # Assume we are running from within the project root. RSpec is smarter about this.
|
58
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
59
|
+
end
|
60
|
+
|
61
|
+
def load_pact_helper
|
62
|
+
load options[:pact_helper]
|
63
|
+
end
|
64
|
+
|
65
|
+
def run_specs
|
66
|
+
exit_code = if options[:pact_uri]
|
67
|
+
run_with_pact_uri
|
68
|
+
else
|
69
|
+
run_with_configured_pacts
|
70
|
+
end
|
71
|
+
exit 1 unless exit_code == 0
|
72
|
+
end
|
73
|
+
|
74
|
+
def run_with_pact_uri
|
75
|
+
Pact::Provider::PactSpecRunner.new([{uri: options[:pact_uri]}], pact_spec_options).run
|
76
|
+
end
|
77
|
+
|
78
|
+
def run_with_configured_pacts
|
79
|
+
pact_verifications = Pact.configuration.pact_verifications
|
80
|
+
verification_configs = pact_verifications.collect { | pact_verification | { :uri => pact_verification.uri }}
|
81
|
+
raise "Please configure a pact to verify" if verification_configs.empty?
|
82
|
+
Pact::Provider::PactSpecRunner.new(verification_configs, options).run
|
83
|
+
end
|
84
|
+
|
85
|
+
def pact_spec_options
|
86
|
+
{criteria: SpecCriteria.call}
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
class RunStandaloneMockService
|
92
|
+
|
93
|
+
def self.call options
|
16
94
|
service_options = {}
|
17
95
|
if options[:log]
|
18
96
|
log = File.open(options[:log], 'w')
|
@@ -25,10 +103,26 @@ module Pact
|
|
25
103
|
trap(:INT) { Rack::Handler::WEBrick.shutdown }
|
26
104
|
Rack::Handler::WEBrick.run(mock_service, :Port => port, :AccessLog => [])
|
27
105
|
end
|
106
|
+
end
|
28
107
|
|
29
|
-
|
30
|
-
|
31
|
-
|
108
|
+
class SpecCriteria
|
109
|
+
|
110
|
+
def self.call
|
111
|
+
criteria = {}
|
112
|
+
|
113
|
+
description = ENV["PACT_DESCRIPTION"]
|
114
|
+
criteria[:description] = Regexp.new(description) if description
|
115
|
+
|
116
|
+
provider_state = ENV["PACT_PROVIDER_STATE"]
|
117
|
+
if provider_state
|
118
|
+
if provider_state.length == 0
|
119
|
+
criteria[:provider_state] = nil #Allow PACT_PROVIDER_STATE="" to mean no provider state
|
120
|
+
else
|
121
|
+
criteria[:provider_state] = Regexp.new(provider_state)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
criteria
|
32
126
|
end
|
33
127
|
end
|
34
128
|
end
|