pact 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/CHANGELOG.md +31 -20
  2. data/Gemfile.lock +12 -12
  3. data/README.md +32 -16
  4. data/Rakefile +3 -3
  5. data/documentation/README.md +1 -0
  6. data/documentation/development-workflow.md +22 -0
  7. data/documentation/faq.md +8 -0
  8. data/documentation/provider-states.md +2 -0
  9. data/documentation/troubleshooting.md +4 -0
  10. data/documentation/verifying-pacts.md +97 -0
  11. data/lib/pact/app.rb +98 -4
  12. data/lib/pact/consumer/rspec.rb +3 -2
  13. data/lib/pact/doc/doc_file.rb +4 -4
  14. data/lib/pact/doc/generator.rb +3 -3
  15. data/lib/pact/doc/interaction_view_model.rb +1 -0
  16. data/lib/pact/doc/markdown/{interactions_renderer.rb → consumer_contract_renderer.rb} +1 -1
  17. data/lib/pact/doc/markdown/generator.rb +2 -2
  18. data/lib/pact/matchers/unix_diff_formatter.rb +1 -1
  19. data/lib/pact/project_root.rb +7 -0
  20. data/lib/pact/provider.rb +0 -1
  21. data/lib/pact/provider/context.rb +0 -0
  22. data/lib/pact/provider/matchers/messages.rb +15 -13
  23. data/lib/pact/provider/pact_spec_runner.rb +21 -22
  24. data/lib/pact/provider/rspec.rb +22 -15
  25. data/lib/pact/provider/rspec/custom_options_file +0 -0
  26. data/lib/pact/provider/{matchers.rb → rspec/matchers.rb} +2 -1
  27. data/lib/pact/rspec.rb +20 -0
  28. data/lib/pact/shared/request.rb +1 -1
  29. data/lib/pact/tasks/task_helper.rb +18 -15
  30. data/lib/pact/tasks/verification_task.rb +26 -32
  31. data/lib/pact/version.rb +1 -1
  32. data/lib/tasks/pact.rake +5 -11
  33. data/spec/integration/pact/consumer_configuration_spec.rb +3 -3
  34. data/spec/lib/pact/app_spec.rb +47 -0
  35. data/spec/lib/pact/consumer/app_manager_spec.rb +1 -1
  36. data/spec/lib/pact/consumer/mock_service/interaction_list_spec.rb +3 -3
  37. data/spec/lib/pact/consumer/mock_service/verification_get_spec.rb +10 -2
  38. data/spec/lib/pact/consumer/mock_service_interaction_expectation_spec.rb +2 -2
  39. data/spec/lib/pact/consumer_contract/consumer_contract_spec.rb +1 -1
  40. data/spec/lib/pact/consumer_contract/interaction_spec.rb +4 -4
  41. data/spec/lib/pact/consumer_contract/request_spec.rb +23 -23
  42. data/spec/lib/pact/doc/generator_spec.rb +4 -4
  43. data/spec/lib/pact/doc/markdown/{interactions_renderer_spec.rb → consumer_contract_renderer_spec.rb} +4 -4
  44. data/spec/lib/pact/matchers/unix_diff_formatter_spec.rb +8 -8
  45. data/spec/lib/pact/provider/configuration/configuration_extension_spec.rb +2 -2
  46. data/spec/lib/pact/provider/matchers/messages_spec.rb +17 -6
  47. data/spec/lib/pact/provider/rspec/formatter_spec.rb +3 -1
  48. data/spec/lib/pact/shared/dsl_spec.rb +1 -1
  49. data/spec/lib/pact/shared/request_spec.rb +8 -0
  50. data/spec/lib/pact/tasks/task_helper_spec.rb +39 -54
  51. data/spec/lib/pact/tasks/verification_task_spec.rb +75 -0
  52. data/spec/pact_specification/compliance-1.0.0.rb +47 -0
  53. data/spec/spec_helper.rb +2 -6
  54. data/spec/standalone/consumer_fail_test.rb +1 -0
  55. data/spec/standalone/consumer_pass_test.rb +1 -0
  56. data/spec/support/active_support_if_configured.rb +6 -0
  57. data/spec/support/pact_helper.rb +2 -1
  58. data/spec/support/shared_examples_for_request.rb +15 -4
  59. data/spec/support/spec_support.rb +3 -0
  60. data/spec/support/stubbing_using_allow.rb +1 -0
  61. data/spec/support/term.json +13 -1
  62. data/tasks/pact-test.rake +45 -26
  63. metadata +23 -13
  64. data/lib/pact/provider/client_project_pact_helper.rb +0 -4
  65. data/spec/lib/pact/provider/pact_spec_runner_spec.rb +0 -7
  66. data/spec/lib/pact/verification_task_spec.rb +0 -99
@@ -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 (Beth, Mon May 5 12:29:51 2014 +1000)
9
- * ddd4677 - Fixed problem of Pact::Terms displaying inside diff output by unpacking all the regular expressions before the diff is calculated (Beth, Mon May 5 12:16:25 2014 +1000)
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 (Beth, Thu May 1 22:09:29 2014 +1000)
14
- * 01c5414 - Fixing doc generation bug where Pact::Terms were being displayed https://github.com/realestate-com-au/pact/issues/13 (Beth, Thu May 1 21:41:11 2014 +1000)
15
- * 292a14b - Cleaning doc dir before generating new docs as per https://github.com/realestate-com-au/pact/issues/11 (Beth, Tue Apr 29 12:44:47 2014 +1000)
16
- * 73c15dd - Changed default doc_dir to ./doc/pacts as per https://github.com/realestate-com-au/pact/issues/12 (Beth, Tue Apr 29 12:33:57 2014 +1000)
17
- * 78ca78c - Fixed bug where log_dir was being ignored when set to a non default value (Beth, Tue Apr 29 07:50:32 2014 +1000)
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 (Beth, Sun Apr 27 22:18:03 2014 +1000)
22
- * 8593fa9 - Updated zoo-app example (Beth, Sun Apr 27 20:54:51 2014 +1000)
23
- * 716e3a8 - Added standalone consumer spec and spec for VerificationGet (Beth, Thu Apr 24 10:15:17 2014 +1000)
24
- * c0f9bc6 - Copied RSpec::Expectations::Differ to Pact::Matchers::Differ - safer than trying to override behaviour (Beth, Thu Apr 24 09:17:58 2014 +
25
- * 0eeb032 - Changing default diff_formatter to unix (Beth, Thu Apr 24 08:19:15 2014 +1000)
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 (Beth, Tue Apr 22 21:45:17 2014 +1000)
30
- * 88e4572 - Moving best practices into its own file (Beth, Tue Apr 22 21:28:36 2014 +1000)
31
- * 5a3b92c - Moving provider state documentation out of main README into it's own file. (Beth, Tue Apr 22 19:59:48 2014 +1000)
32
- * 1d568c4 - Updated configuration documentation (Beth, Tue Apr 22 13:06:47 2014 +1000)
33
- * be1412e - Added configuration documentation (Beth, Tue Apr 22 13:04:33 2014 +1000)
34
- * 9f9d178 - Added HAL raq (Beth, Tue Apr 22 12:51:42 2014 +1000)
35
- * d9b6479 - Renamed ListOfPathsFormatter to ListDiffFormatter (Beth, Tue Apr 22 12:48:57 2014 +1000)
36
- * 6b82402 - Renamed NestedJsonDiffFormatter to EmbeddedDiffFormatter (Beth, Tue Apr 22 12:45:50 2014 +1000)
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)
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pact (1.1.0)
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.4)
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.14.1)
49
- rspec-core (~> 2.14.0)
50
- rspec-expectations (~> 2.14.0)
51
- rspec-mocks (~> 2.14.0)
52
- rspec-core (2.14.5)
53
- rspec-expectations (2.14.3)
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.2.0)
56
- rspec (~> 2.11)
57
- rspec-mocks (2.14.3)
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.1.0)
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 pacts better than using integration tests?
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 provider reduce likelihood of flakey tests.
31
- * Only one component is being tested at a time, making the causes of test failures easier to identify.
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 need to manage starting, stopping and fixture set up for multiple applications during a test run.
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 file must be called pact_helper.rb, however there is some flexibility in where it can be stored. The recommended place is `specs/service_consumers/pact_helper.rb`.
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](/documentation.md#provider) section of the Configuration documentation for more information.
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
- ## Gotchas
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 Gems
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, :spec_with_active_support, 'spec:standalone:pass', 'pact:tests']
8
+ task :default => [:spec, 'pact:tests:all', :spec_with_active_support, 'pact:tests:all:with_active_support']
9
9
 
@@ -7,4 +7,5 @@
7
7
  * [Frequently asked questions](faq.md)
8
8
  * [Rarely asked questions](raq.md)
9
9
  * [Best practices](best-practices.md)
10
+ * [Troubleshooting](troubleshooting.md)
10
11
  * [Testing with pact diagram](Testing with pact.png)
@@ -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.
@@ -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,4 @@
1
+ ## Gotchas
2
+
3
+ * 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.
4
+
@@ -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
+ ```
@@ -7,12 +7,90 @@ require 'rack/handler/webrick'
7
7
  module Pact
8
8
  class App < Thor
9
9
 
10
- desc 'service', "starts a mock service"
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
- private
30
- def log message
31
- puts message unless options[:quiet]
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