pact 0.1.28 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (285) hide show
  1. data/.gitignore +2 -1
  2. data/.ruby-version +1 -0
  3. data/.travis.yml +8 -0
  4. data/CHANGELOG.md +374 -0
  5. data/Gemfile +0 -1
  6. data/Gemfile.lock +58 -55
  7. data/README.md +214 -139
  8. data/Rakefile +4 -28
  9. data/bin/pact +2 -2
  10. data/config.ru +3 -0
  11. data/documentation/README.md +13 -0
  12. data/documentation/configuration.md +166 -0
  13. data/documentation/diff_formatter_embedded.png +0 -0
  14. data/documentation/diff_formatter_list.png +0 -0
  15. data/documentation/diff_formatter_unix.png +0 -0
  16. data/example/animal-service/Gemfile +14 -0
  17. data/example/animal-service/Gemfile.lock +69 -0
  18. data/example/animal-service/Rakefile +5 -0
  19. data/example/animal-service/config.ru +3 -0
  20. data/example/animal-service/db/animal_db.sqlite3 +0 -0
  21. data/example/animal-service/lib/animal_service/animal_repository.rb +12 -0
  22. data/example/animal-service/lib/animal_service/api.rb +28 -0
  23. data/example/animal-service/lib/animal_service/db.rb +5 -0
  24. data/example/animal-service/spec/service_consumers/pact_helper.rb +11 -0
  25. data/example/animal-service/spec/service_consumers/provider_states_for_zoo_app.rb +26 -0
  26. data/example/zoo-app/Gemfile +12 -0
  27. data/example/zoo-app/Gemfile.lock +63 -0
  28. data/example/zoo-app/Rakefile +5 -0
  29. data/example/zoo-app/doc/pacts/markdown/README.md +3 -0
  30. data/example/zoo-app/doc/pacts/markdown/Zoo App - Animal Service.md +75 -0
  31. data/example/zoo-app/lib/zoo_app/animal_service_client.rb +40 -0
  32. data/example/zoo-app/lib/zoo_app/models/alligator.rb +15 -0
  33. data/example/zoo-app/spec/pacts/zoo_app-animal_service.json +67 -0
  34. data/example/zoo-app/spec/service_providers/animal_service_client_spec.rb +71 -0
  35. data/example/zoo-app/spec/service_providers/pact_helper.rb +15 -0
  36. data/example/zoo-app/spec/spec_helper.rb +6 -0
  37. data/lib/pact/cli.rb +138 -0
  38. data/lib/pact/configuration.rb +169 -28
  39. data/lib/pact/consumer/app_manager.rb +10 -29
  40. data/lib/pact/consumer/configuration/configuration_extensions.rb +15 -0
  41. data/lib/pact/consumer/configuration/dsl.rb +12 -0
  42. data/lib/pact/consumer/configuration/mock_service.rb +91 -0
  43. data/lib/pact/consumer/configuration/service_consumer.rb +51 -0
  44. data/lib/pact/consumer/configuration/service_provider.rb +40 -0
  45. data/lib/pact/consumer/configuration.rb +11 -0
  46. data/lib/pact/consumer/consumer_contract_builder.rb +44 -47
  47. data/lib/pact/consumer/interaction_builder.rb +41 -0
  48. data/lib/pact/consumer/interactions_filter.rb +48 -0
  49. data/lib/pact/consumer/mock_service/app.rb +82 -0
  50. data/lib/pact/consumer/mock_service/interaction_delete.rb +33 -0
  51. data/lib/pact/consumer/mock_service/interaction_list.rb +76 -0
  52. data/lib/pact/consumer/mock_service/interaction_mismatch.rb +73 -0
  53. data/lib/pact/consumer/mock_service/interaction_post.rb +31 -0
  54. data/lib/pact/consumer/mock_service/interaction_replay.rb +139 -0
  55. data/lib/pact/consumer/mock_service/log_get.rb +28 -0
  56. data/lib/pact/consumer/mock_service/missing_interactions_get.rb +30 -0
  57. data/lib/pact/consumer/mock_service/mock_service_administration_endpoint.rb +31 -0
  58. data/lib/pact/consumer/mock_service/pact_post.rb +33 -0
  59. data/lib/pact/consumer/mock_service/rack_request_helper.rb +51 -0
  60. data/lib/pact/consumer/mock_service/verification_get.rb +68 -0
  61. data/lib/pact/consumer/mock_service.rb +1 -339
  62. data/lib/pact/consumer/mock_service_client.rb +65 -0
  63. data/lib/pact/consumer/mock_service_interaction_expectation.rb +37 -0
  64. data/lib/pact/consumer/request.rb +27 -0
  65. data/lib/pact/consumer/rspec.rb +9 -19
  66. data/lib/pact/consumer/server.rb +90 -0
  67. data/lib/pact/consumer/spec_hooks.rb +38 -0
  68. data/lib/pact/consumer/world.rb +37 -0
  69. data/lib/pact/consumer.rb +10 -7
  70. data/lib/pact/consumer_contract/consumer_contract.rb +115 -0
  71. data/lib/pact/consumer_contract/consumer_contract_writer.rb +84 -0
  72. data/lib/pact/consumer_contract/file_name.rb +19 -0
  73. data/lib/pact/consumer_contract/headers.rb +51 -0
  74. data/lib/pact/consumer_contract/interaction.rb +67 -0
  75. data/lib/pact/consumer_contract/pact_file.rb +24 -0
  76. data/lib/pact/consumer_contract/request.rb +73 -0
  77. data/lib/pact/consumer_contract/service_consumer.rb +28 -0
  78. data/lib/pact/consumer_contract/service_provider.rb +28 -0
  79. data/lib/pact/consumer_contract.rb +1 -110
  80. data/lib/pact/doc/doc_file.rb +40 -0
  81. data/lib/pact/doc/generate.rb +11 -0
  82. data/lib/pact/doc/generator.rb +82 -0
  83. data/lib/pact/doc/interaction_view_model.rb +114 -0
  84. data/lib/pact/doc/markdown/consumer_contract_renderer.rb +56 -0
  85. data/lib/pact/doc/markdown/generator.rb +26 -0
  86. data/lib/pact/doc/markdown/index_renderer.rb +41 -0
  87. data/lib/pact/doc/markdown/interaction.erb +14 -0
  88. data/lib/pact/doc/markdown/interaction_renderer.rb +38 -0
  89. data/lib/pact/doc/sort_interactions.rb +17 -0
  90. data/lib/pact/matchers/actual_type.rb +16 -0
  91. data/lib/pact/matchers/base_difference.rb +37 -0
  92. data/lib/pact/matchers/differ.rb +153 -0
  93. data/lib/pact/matchers/difference.rb +13 -0
  94. data/lib/pact/matchers/difference_indicator.rb +26 -0
  95. data/lib/pact/matchers/embedded_diff_formatter.rb +62 -0
  96. data/lib/pact/matchers/expected_type.rb +35 -0
  97. data/lib/pact/matchers/index_not_found.rb +15 -0
  98. data/lib/pact/matchers/list_diff_formatter.rb +101 -0
  99. data/lib/pact/matchers/matchers.rb +91 -37
  100. data/lib/pact/matchers/no_diff_indicator.rb +18 -0
  101. data/lib/pact/matchers/regexp_difference.rb +13 -0
  102. data/lib/pact/matchers/type_difference.rb +16 -0
  103. data/lib/pact/matchers/unexpected_index.rb +11 -0
  104. data/lib/pact/matchers/unexpected_key.rb +11 -0
  105. data/lib/pact/matchers/unix_diff_formatter.rb +114 -0
  106. data/lib/pact/project_root.rb +7 -0
  107. data/lib/pact/provider/configuration/configuration_extension.rb +58 -0
  108. data/lib/pact/provider/configuration/dsl.rb +13 -0
  109. data/lib/pact/provider/configuration/pact_verification.rb +46 -0
  110. data/lib/pact/provider/configuration/service_provider_config.rb +16 -0
  111. data/lib/pact/provider/configuration/service_provider_dsl.rb +59 -0
  112. data/lib/pact/provider/configuration.rb +7 -0
  113. data/lib/pact/provider/context.rb +0 -0
  114. data/lib/pact/provider/matchers/messages.rb +45 -0
  115. data/lib/pact/provider/pact_helper_locator.rb +22 -0
  116. data/lib/pact/provider/pact_spec_runner.rb +123 -0
  117. data/lib/pact/provider/pact_verification.rb +17 -0
  118. data/lib/pact/provider/print_missing_provider_states.rb +30 -0
  119. data/lib/pact/provider/request.rb +70 -0
  120. data/lib/pact/provider/rspec/backtrace_formatter.rb +43 -0
  121. data/lib/pact/provider/rspec/custom_options_file +0 -0
  122. data/lib/pact/provider/rspec/formatter_rspec_2.rb +65 -0
  123. data/lib/pact/provider/rspec/formatter_rspec_3.rb +96 -0
  124. data/lib/pact/provider/rspec/matchers.rb +97 -0
  125. data/lib/pact/provider/rspec.rb +181 -0
  126. data/lib/pact/provider/state/provider_state.rb +181 -0
  127. data/lib/pact/provider/state/provider_state_configured_modules.rb +13 -0
  128. data/lib/pact/provider/state/provider_state_manager.rb +42 -0
  129. data/lib/pact/provider/state/provider_state_proxy.rb +39 -0
  130. data/lib/pact/provider/test_methods.rb +47 -0
  131. data/lib/pact/provider/verification_report.rb +36 -0
  132. data/lib/pact/provider/world.rb +23 -0
  133. data/lib/pact/provider.rb +3 -0
  134. data/lib/pact/reification.rb +6 -4
  135. data/lib/pact/rspec.rb +53 -0
  136. data/lib/pact/shared/active_support_support.rb +51 -0
  137. data/lib/pact/shared/dsl.rb +76 -0
  138. data/lib/pact/shared/jruby_support.rb +18 -0
  139. data/lib/pact/shared/json_differ.rb +15 -0
  140. data/lib/pact/shared/key_not_found.rb +15 -0
  141. data/lib/pact/shared/null_expectation.rb +31 -0
  142. data/lib/pact/shared/request.rb +80 -0
  143. data/lib/pact/shared/text_differ.rb +14 -0
  144. data/lib/pact/something_like.rb +49 -0
  145. data/lib/pact/symbolize_keys.rb +12 -0
  146. data/lib/pact/tasks/task_helper.rb +36 -0
  147. data/lib/pact/tasks/verification_task.rb +87 -0
  148. data/lib/pact/tasks.rb +2 -0
  149. data/lib/pact/templates/provider_state.erb +14 -0
  150. data/lib/pact/term.rb +47 -2
  151. data/lib/pact/version.rb +1 -1
  152. data/lib/pact.rb +1 -1
  153. data/lib/tasks/pact.rake +25 -2
  154. data/pact.gemspec +13 -11
  155. data/{scratchpad.txt → scratchpad.rb} +18 -2
  156. data/spec/features/consumption_spec.rb +24 -56
  157. data/spec/features/production_spec.rb +19 -24
  158. data/spec/features/{producer_states → provider_states}/zebras.rb +3 -3
  159. data/spec/integration/consumer_spec.rb +212 -0
  160. data/spec/integration/pact/consumer_configuration_spec.rb +66 -0
  161. data/spec/integration/pact/provider_configuration_spec.rb +25 -0
  162. data/spec/lib/pact/cli_spec.rb +47 -0
  163. data/spec/lib/pact/configuration_spec.rb +269 -7
  164. data/spec/lib/pact/consumer/app_manager_spec.rb +3 -3
  165. data/spec/lib/pact/consumer/configuration_spec.rb +57 -0
  166. data/spec/lib/pact/consumer/consumer_contract_builder_spec.rb +52 -70
  167. data/spec/lib/pact/consumer/interaction_builder_spec.rb +91 -0
  168. data/spec/lib/pact/consumer/interactions_spec.rb +64 -0
  169. data/spec/lib/pact/consumer/mock_service/app_spec.rb +52 -0
  170. data/spec/lib/pact/consumer/mock_service/interaction_list_spec.rb +78 -0
  171. data/spec/lib/pact/consumer/mock_service/interaction_mismatch_spec.rb +70 -0
  172. data/spec/lib/pact/consumer/mock_service/interaction_replay_spec.rb +12 -0
  173. data/spec/lib/pact/consumer/mock_service/rack_request_helper_spec.rb +88 -0
  174. data/spec/lib/pact/consumer/mock_service/verification_get_spec.rb +142 -0
  175. data/spec/lib/pact/consumer/mock_service_client_spec.rb +88 -0
  176. data/spec/lib/pact/consumer/mock_service_interaction_expectation_spec.rb +54 -0
  177. data/spec/lib/pact/consumer/request_spec.rb +24 -0
  178. data/spec/lib/pact/consumer/service_consumer_spec.rb +1 -1
  179. data/spec/lib/pact/consumer_contract/active_support_support_spec.rb +58 -0
  180. data/spec/lib/pact/consumer_contract/consumer_contract_spec.rb +180 -0
  181. data/spec/lib/pact/consumer_contract/consumer_contract_writer_spec.rb +111 -0
  182. data/spec/lib/pact/consumer_contract/headers_spec.rb +107 -0
  183. data/spec/lib/pact/consumer_contract/interaction_spec.rb +107 -0
  184. data/spec/lib/pact/{request_spec.rb → consumer_contract/request_spec.rb} +80 -67
  185. data/spec/lib/pact/doc/generator_spec.rb +84 -0
  186. data/spec/lib/pact/doc/interaction_view_model_spec.rb +132 -0
  187. data/spec/lib/pact/doc/markdown/consumer_contract_renderer_spec.rb +29 -0
  188. data/spec/lib/pact/doc/markdown/index_renderer_spec.rb +29 -0
  189. data/spec/lib/pact/matchers/differ_spec.rb +214 -0
  190. data/spec/lib/pact/matchers/difference_spec.rb +22 -0
  191. data/spec/lib/pact/matchers/embedded_diff_formatter_spec.rb +90 -0
  192. data/spec/lib/pact/matchers/index_not_found_spec.rb +21 -0
  193. data/spec/lib/pact/matchers/list_diff_formatter_spec.rb +114 -0
  194. data/spec/lib/pact/matchers/matchers_spec.rb +400 -254
  195. data/spec/lib/pact/matchers/regexp_difference_spec.rb +20 -0
  196. data/spec/lib/pact/matchers/type_difference_spec.rb +34 -0
  197. data/spec/lib/pact/matchers/unexpected_index_spec.rb +20 -0
  198. data/spec/lib/pact/matchers/unexpected_key_spec.rb +20 -0
  199. data/spec/lib/pact/matchers/unix_diff_formatter_spec.rb +216 -0
  200. data/spec/lib/pact/provider/configuration/configuration_extension_spec.rb +30 -0
  201. data/spec/lib/pact/provider/configuration/pact_verification_spec.rb +43 -0
  202. data/spec/lib/pact/provider/configuration/service_provider_config_spec.rb +21 -0
  203. data/spec/lib/pact/provider/configuration/service_provider_dsl_spec.rb +108 -0
  204. data/spec/lib/pact/provider/configuration_spec.rb +50 -0
  205. data/spec/lib/pact/provider/matchers/messages_spec.rb +116 -0
  206. data/spec/lib/pact/provider/pact_helper_locator_spec.rb +54 -0
  207. data/spec/lib/pact/provider/print_missing_provider_states_spec.rb +19 -0
  208. data/spec/lib/pact/provider/request_spec.rb +78 -0
  209. data/spec/lib/pact/provider/rspec/formatter_rspec_2_spec.rb +68 -0
  210. data/spec/lib/pact/provider/rspec/formatter_rspec_3_spec.rb +72 -0
  211. data/spec/lib/pact/provider/rspec_spec.rb +55 -0
  212. data/spec/lib/pact/provider/state/provider_state_manager_spec.rb +89 -0
  213. data/spec/lib/pact/provider/state/provider_state_proxy_spec.rb +80 -0
  214. data/spec/lib/pact/provider/state/provider_state_spec.rb +213 -0
  215. data/spec/lib/pact/provider/world_spec.rb +41 -0
  216. data/spec/lib/pact/reification_spec.rb +24 -0
  217. data/spec/lib/pact/shared/dsl_spec.rb +86 -0
  218. data/spec/lib/pact/shared/json_differ_spec.rb +36 -0
  219. data/spec/lib/pact/shared/key_not_found_spec.rb +20 -0
  220. data/spec/lib/pact/shared/request_spec.rb +111 -0
  221. data/spec/lib/pact/shared/text_differ_spec.rb +54 -0
  222. data/spec/lib/pact/something_like_spec.rb +21 -0
  223. data/spec/lib/pact/tasks/task_helper_spec.rb +74 -0
  224. data/spec/lib/pact/tasks/verification_task_spec.rb +75 -0
  225. data/spec/lib/pact/term_spec.rb +57 -4
  226. data/spec/pact_specification/compliance-1.0.0.rb +47 -0
  227. data/spec/spec_helper.rb +17 -0
  228. data/spec/standalone/consumer_fail_test.rb +55 -0
  229. data/spec/standalone/consumer_pass_test.rb +51 -0
  230. data/spec/support/a_consumer-a_producer.json +2 -4
  231. data/spec/support/a_consumer-a_provider.json +32 -0
  232. data/spec/support/active_support_if_configured.rb +6 -0
  233. data/spec/support/app_for_config_ru.rb +4 -0
  234. data/spec/support/consumer_contract_template.json +24 -0
  235. data/spec/support/dsl_spec_support.rb +7 -0
  236. data/spec/support/factories.rb +82 -0
  237. data/spec/support/generated_index.md +4 -0
  238. data/spec/support/generated_markdown.md +55 -0
  239. data/spec/support/interaction_view_model.json +63 -0
  240. data/spec/support/interaction_view_model_with_terms.json +50 -0
  241. data/spec/support/markdown_pact.json +48 -0
  242. data/spec/support/missing_provider_states_output.txt +25 -0
  243. data/spec/support/options.json +21 -0
  244. data/spec/support/options_app.rb +15 -0
  245. data/spec/support/pact_helper.rb +57 -0
  246. data/spec/support/shared_examples_for_request.rb +94 -0
  247. data/spec/support/spec_support.rb +20 -0
  248. data/spec/support/stubbing.json +22 -0
  249. data/spec/support/stubbing_using_allow.rb +29 -0
  250. data/spec/support/term.json +48 -0
  251. data/spec/support/test_app_fail.json +41 -2
  252. data/spec/support/test_app_pass.json +19 -2
  253. data/spec/support/test_app_with_right_content_type_differ.json +23 -0
  254. data/tasks/pact-test.rake +98 -8
  255. data/tasks/spec.rake +8 -0
  256. metadata +393 -95
  257. data/lib/pact/app.rb +0 -32
  258. data/lib/pact/consumer/configuration_dsl.rb +0 -71
  259. data/lib/pact/consumer/dsl.rb +0 -98
  260. data/lib/pact/consumer/interaction.rb +0 -70
  261. data/lib/pact/consumer/run_condor.rb +0 -4
  262. data/lib/pact/consumer/run_mock_contract_service.rb +0 -13
  263. data/lib/pact/consumer/service_consumer.rb +0 -22
  264. data/lib/pact/consumer/service_producer.rb +0 -23
  265. data/lib/pact/json_warning.rb +0 -23
  266. data/lib/pact/producer/configuration_dsl.rb +0 -62
  267. data/lib/pact/producer/matchers.rb +0 -22
  268. data/lib/pact/producer/pact_spec_runner.rb +0 -57
  269. data/lib/pact/producer/producer_state.rb +0 -81
  270. data/lib/pact/producer/rspec.rb +0 -127
  271. data/lib/pact/producer/test_methods.rb +0 -89
  272. data/lib/pact/producer.rb +0 -1
  273. data/lib/pact/rake_task.rb +0 -64
  274. data/lib/pact/request.rb +0 -109
  275. data/lib/pact/verification_task.rb +0 -57
  276. data/spec/integration/pact/configuration_spec.rb +0 -65
  277. data/spec/lib/pact/consumer/dsl_spec.rb +0 -52
  278. data/spec/lib/pact/consumer/interaction_spec.rb +0 -108
  279. data/spec/lib/pact/consumer/mock_service_spec.rb +0 -147
  280. data/spec/lib/pact/consumer_contract_spec.rb +0 -125
  281. data/spec/lib/pact/producer/configuration_dsl_spec.rb +0 -101
  282. data/spec/lib/pact/producer/producer_state_spec.rb +0 -103
  283. data/spec/lib/pact/producer/rspec_spec.rb +0 -48
  284. data/spec/lib/pact/verification_task_spec.rb +0 -64
  285. data/spec/support/pact_rake_support.rb +0 -41
@@ -0,0 +1,51 @@
1
+ module Pact
2
+ module ActiveSupportSupport
3
+
4
+ extend self
5
+
6
+ def fix_all_the_things thing
7
+ if thing.is_a?(Regexp)
8
+ fix_regexp(thing)
9
+ elsif thing.is_a?(Array)
10
+ thing.each{ | it | fix_all_the_things it }
11
+ elsif thing.is_a?(Hash)
12
+ thing.values.each{ | it | fix_all_the_things it }
13
+ elsif thing.class.name.start_with?("Pact")
14
+ thing.instance_variables.collect{ | iv_name | thing.instance_variable_get(iv_name)}.each do | iv |
15
+ fix_all_the_things iv
16
+ end
17
+ end
18
+ thing
19
+ end
20
+
21
+ # ActiveSupport JSON overwrites (i.e. TRAMPLES) the json methods of the Regexp class directly
22
+ # (beneath its destructive hooves of destruction).
23
+ # This does not seem to be able to be undone without affecting the JSON serialisation in the
24
+ # calling project, so the best way I've found to fix this issue is to reattach the
25
+ # original as_json to the Regexp instances in the ConsumerContract before we write them to the
26
+ # pact file. If anyone can find a better way, please submit a pull request ASAP!
27
+ def fix_regexp regexp
28
+ def regexp.as_json options = {}
29
+ {:json_class => 'Regexp', "o" => self.options, "s" => self.source }
30
+ end
31
+ regexp
32
+ end
33
+
34
+ # Having Active Support JSON loaded somehow kills the formatting of pretty_generate for objects.
35
+ # Don't ask me why, but it still seems to work for hashes, so the hacky work around is to
36
+ # reparse the generated JSON into a hash and pretty_generate that... sigh...
37
+ # Oh ActiveSupport, why....
38
+ def fix_json_formatting json
39
+ if json.include?("\n")
40
+ json
41
+ else
42
+ JSON.pretty_generate(JSON.parse(json, create_additions: false))
43
+ end
44
+ end
45
+
46
+ def remove_unicode json
47
+ json.gsub(/\\u([0-9A-Za-z]{4})/) {|s| [$1.to_i(16)].pack("U")}
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,76 @@
1
+ module Pact
2
+
3
+ class DslDelegator
4
+
5
+ def initialize delegation_target
6
+ @delegation_target = delegation_target
7
+ end
8
+
9
+ def instance_eval_with_previous_context_available(*args, &block)
10
+ with_previous_context_available(block.binding) do
11
+ bind_block_as_instance_method_on_self(&block).call(*args)
12
+ end
13
+ end
14
+
15
+ protected
16
+
17
+ def method_missing(method, *args, &block)
18
+ if delegation_target_responds_to? method
19
+ delegation_target.send(method, *args, &block)
20
+ else
21
+ previous_context.send(method, *args, &block)
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ attr_accessor :delegation_target, :previous_context
28
+
29
+ def bind_block_as_instance_method_on_self(&block)
30
+ create_instance_method_from_block(&block).bind(self)
31
+ end
32
+
33
+
34
+ def create_instance_method_from_block &block
35
+ meth = self.class.class_eval do
36
+ define_method :block_as_instance_method_, &block
37
+ meth = instance_method :block_as_instance_method_
38
+ remove_method :block_as_instance_method_
39
+ meth
40
+ end
41
+ end
42
+
43
+ def with_previous_context_available(binding, &block)
44
+ @previous_context = binding.eval('self')
45
+ result = block.call
46
+ @previous_context = nil
47
+ result
48
+ end
49
+
50
+ def delegation_target_responds_to?(method)
51
+ delegation_target.respond_to? method
52
+ end
53
+
54
+ end
55
+
56
+
57
+ # Ripped from http://blog.joecorcoran.co.uk/2013/09/04/simple-pattern-ruby-dsl
58
+ # and then fixed up by using http://www.skorks.com/2013/03/a-closure-is-not-always-a-closure-in-ruby/
59
+ # to access variables and methods defined in the calling scope.
60
+ module DSL
61
+ def build(*args, &block)
62
+ new_instance_of_delegation_target_class = self.new(*args)
63
+ dsl_delegator_class = self.const_get('DSL_DELEGATOR_CLASS')
64
+ dsl_delegator = dsl_delegator_class.new(new_instance_of_delegation_target_class)
65
+ dsl_delegator.instance_eval_with_previous_context_available(&block)
66
+ new_instance_of_delegation_target_class.finalize
67
+ new_instance_of_delegation_target_class
68
+ end
69
+
70
+ def dsl(&block)
71
+ dsl_delegator_class = Class.new(DslDelegator, &block)
72
+ self.const_set('DSL_DELEGATOR_CLASS', dsl_delegator_class)
73
+ end
74
+
75
+ end
76
+ end
@@ -0,0 +1,18 @@
1
+ module Pact
2
+ module JRubySupport
3
+
4
+ # Under jruby, JSON.pretty_generate inserts a blank new line between the opening and closing
5
+ # brackets of an empty hash, like so:
6
+ # {
7
+ # "empty": {
8
+ #
9
+ # }
10
+ # }
11
+ # This screws up the UnixDiffFormatter, so we need to remove the blank lines.
12
+
13
+ def fix_blank_lines_in_empty_hashes json
14
+ json.gsub(/({\n)\n(\s*})/,'\1\2')
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,15 @@
1
+ require 'pact/matchers/matchers'
2
+
3
+ module Pact
4
+ class JsonDiffer
5
+
6
+ extend Matchers
7
+
8
+
9
+ def self.call expected, actual, options = {}
10
+ diff expected, actual, options
11
+ end
12
+
13
+
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ require 'pact/matchers/difference_indicator'
2
+
3
+ module Pact
4
+ class KeyNotFound < Pact::DifferenceIndicator
5
+
6
+ def to_s
7
+ "<key not found>"
8
+ end
9
+
10
+ def empty?
11
+ true
12
+ end
13
+ end
14
+
15
+ end
@@ -0,0 +1,31 @@
1
+ module Pact
2
+ class NullExpectation
3
+ def to_s
4
+ "<No expectation>"
5
+ end
6
+
7
+ def ==(other_object)
8
+ other_object.is_a? NullExpectation
9
+ end
10
+
11
+ def ===(other_object)
12
+ other_object.is_a? NullExpectation
13
+ end
14
+
15
+ def eql?(other_object)
16
+ self == other_object
17
+ end
18
+
19
+ def hash
20
+ 2934820948209428748274238642672
21
+ end
22
+
23
+ def empty?
24
+ true
25
+ end
26
+
27
+ def nil?
28
+ true
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,80 @@
1
+ require 'pact/matchers'
2
+ require 'pact/symbolize_keys'
3
+ require 'pact/consumer_contract/headers'
4
+
5
+ module Pact
6
+
7
+ module Request
8
+
9
+ class Base
10
+ include Pact::Matchers
11
+ include Pact::SymbolizeKeys
12
+ extend Pact::Matchers
13
+
14
+ attr_reader :method, :path, :headers, :body, :query, :options
15
+
16
+ def initialize(method, path, headers, body, query)
17
+ @method = method.to_s
18
+ @path = path.chomp('/')
19
+ @headers = Hash === headers ? Headers.new(headers) : headers # Could be a NullExpectation - TODO make this more elegant
20
+ @body = body
21
+ @query = query
22
+ end
23
+
24
+ def to_json(options = {})
25
+ as_json.to_json(options)
26
+ end
27
+
28
+ def as_json options = {}
29
+ to_hash
30
+ end
31
+
32
+ def to_hash
33
+ hash = {
34
+ method: method,
35
+ path: path,
36
+ }
37
+
38
+ hash.merge!(query: query) unless query.is_a? self.class.key_not_found.class
39
+ hash.merge!(headers: headers) unless headers.is_a? self.class.key_not_found.class
40
+ hash.merge!(body: body) unless body.is_a? self.class.key_not_found.class
41
+ hash
42
+ end
43
+
44
+ def method_and_path
45
+ "#{method.upcase} #{full_path}"
46
+ end
47
+
48
+ def full_path
49
+ display_path + display_query
50
+ end
51
+
52
+ def content_type
53
+ return nil if headers.is_a? self.class.key_not_found.class
54
+ headers['Content-Type']
55
+ end
56
+
57
+ protected
58
+
59
+ def self.key_not_found
60
+ raise NotImplementedError
61
+ end
62
+
63
+ def to_hash_without_body
64
+ keep_keys = [:method, :path, :headers, :query]
65
+ as_json.reject{ |key, value| !keep_keys.include? key }.tap do | hash |
66
+ hash[:method] = method.upcase
67
+ end
68
+ end
69
+
70
+ def display_path
71
+ path.empty? ? "/" : path
72
+ end
73
+
74
+ def display_query
75
+ (query.nil? || query.empty?) ? '' : "?#{Pact::Reification.from_term(query)}"
76
+ end
77
+
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,14 @@
1
+ require 'pact/matchers/matchers'
2
+ require 'pact/matchers/difference'
3
+
4
+ module Pact
5
+ class TextDiffer
6
+
7
+ extend Matchers
8
+
9
+ def self.call expected, actual, options = {}
10
+ diff expected, actual, options
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,49 @@
1
+ require 'pact/symbolize_keys'
2
+ module Pact
3
+
4
+ # Specifies that the actual object should be considered a match if
5
+ # it includes the same keys, and the values of the keys are of the same class.
6
+
7
+ class SomethingLike
8
+ include SymbolizeKeys
9
+
10
+ attr_reader :contents
11
+
12
+ def initialize contents
13
+ @contents = contents
14
+ end
15
+
16
+ def to_hash
17
+ {
18
+ :json_class => self.class.name,
19
+ :contents => contents
20
+ }
21
+ end
22
+
23
+ def as_json
24
+ to_hash
25
+ end
26
+
27
+ def to_json opts = {}
28
+ as_json.to_json opts
29
+ end
30
+
31
+ def self.json_create hash
32
+ new(symbolize_keys(hash)[:contents])
33
+ end
34
+
35
+ def eq other
36
+ self == other
37
+ end
38
+
39
+ def == other
40
+ other.is_a?(SomethingLike) && other.contents == self.contents
41
+ end
42
+
43
+ def generate
44
+ contents
45
+ end
46
+ end
47
+ end
48
+
49
+
@@ -0,0 +1,12 @@
1
+ module Pact
2
+ module SymbolizeKeys
3
+
4
+ def self.included(base)
5
+ base.extend(self)
6
+ end
7
+
8
+ def symbolize_keys hash
9
+ hash.inject({}) { |memo, (k,v)| memo[k.to_sym] = v; memo }
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,36 @@
1
+ require 'pact/provider/pact_helper_locator'
2
+ require 'rake/file_utils'
3
+ require 'shellwords'
4
+
5
+ module Pact
6
+ module TaskHelper
7
+
8
+ extend self
9
+
10
+ def execute_pact_verify pact_uri = nil, pact_helper = nil, rspec_opts = nil
11
+ execute_cmd verify_command(pact_helper || Pact::Provider::PactHelperLocater.pact_helper_path, pact_uri, rspec_opts)
12
+ end
13
+
14
+ def handle_verification_failure
15
+ exit_status = yield
16
+ abort if exit_status != 0
17
+ end
18
+
19
+ def verify_command pact_helper, pact_uri, rspec_opts
20
+ command_parts = []
21
+ # Clear SPEC_OPTS, otherwise we can get extra formatters, creating duplicate output eg. CI Reporting.
22
+ # Allow deliberate configuration using rspec_opts in VerificationTask.
23
+ command_parts << "SPEC_OPTS=#{Shellwords.escape(rspec_opts || '')}"
24
+ command_parts << FileUtils::RUBY
25
+ command_parts << "-S pact verify"
26
+ command_parts << "-h" << (pact_helper.end_with?(".rb") ? pact_helper : pact_helper + ".rb")
27
+ (command_parts << "-p" << pact_uri) if pact_uri
28
+ command_parts.flatten.join(" ")
29
+ end
30
+
31
+ def execute_cmd command
32
+ system(command) ? 0 : 1
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,87 @@
1
+ require 'rake/tasklib'
2
+
3
+ =begin
4
+ To create a rake pact:verify:<something> task
5
+
6
+ Pact::VerificationTask.new(:head) do | pact |
7
+ pact.uri 'http://master.cd.vpc.realestate.com.au/browse/BIQ-MAS/latestSuccessful/artifact/JOB2/Pacts/mas-contract_transaction_service.json'
8
+ pact.uri 'http://master.cd.vpc.realestate.com.au/browse/BIQ-IMAGINARY-CONSUMER/latestSuccessful/artifact/JOB2/Pacts/imaginary_consumer-contract_transaction_service.json'
9
+ end
10
+
11
+ The pact.uri may be a local file system path or a remote URL.
12
+
13
+ To run a pact:verify:xxx task you need to define a pact_helper.rb, ideally in spec/service_consumers.
14
+ It should contain your service_provider definition, and load any provider state definition files.
15
+ It should also load all your app's dependencies (eg by calling out to spec_helper)
16
+
17
+ Eg.
18
+
19
+ require 'spec_helper'
20
+ require 'provider_states_for_my_consumer'
21
+
22
+ Pact.service_provider "My Provider" do
23
+ app { TestApp.new }
24
+ end
25
+
26
+ =end
27
+
28
+ module Pact
29
+ class VerificationTask < ::Rake::TaskLib
30
+
31
+ attr_reader :pact_spec_configs
32
+ attr_accessor :rspec_opts
33
+
34
+ def initialize(name)
35
+ @rspec_opts = nil
36
+ @pact_spec_configs = []
37
+ @name = name
38
+ yield self
39
+ rake_task
40
+ end
41
+
42
+ def uri(uri, options = {})
43
+ @pact_spec_configs << {uri: uri, pact_helper: options[:pact_helper]}
44
+ end
45
+
46
+ private
47
+
48
+ attr_reader :name
49
+
50
+ # def parse_pactfile config
51
+ # Pact::ConsumerContract.from_uri config[:uri]
52
+ # end
53
+
54
+ # def publish_report config, output, result, provider_ref, reports_dir
55
+ # consumer_contract = parse_pactfile config
56
+ # #TODO - when checking out a historical version, provider ref will be prod, however it will think it is head. Fix this!!!!
57
+ # report = Provider::VerificationReport.new(
58
+ # :result => result,
59
+ # :output => output,
60
+ # :consumer => {:name => consumer_contract.consumer.name, :ref => name},
61
+ # :provider => {:name => consumer_contract.provider.name, :ref => provider_ref}
62
+ # )
63
+
64
+ # FileUtils.mkdir_p reports_dir
65
+ # File.open("#{reports_dir}/#{report.report_file_name}", "w") { |file| file << JSON.pretty_generate(report) }
66
+ # end
67
+
68
+ def rake_task
69
+ namespace :pact do
70
+
71
+ desc "Verify provider against the consumer pacts for #{name}"
72
+ task "verify:#{name}" do |t, args|
73
+
74
+ require 'pact/tasks/task_helper'
75
+
76
+ exit_statuses = pact_spec_configs.collect do | config |
77
+ Pact::TaskHelper.execute_pact_verify config[:uri], config[:pact_helper], rspec_opts
78
+ end
79
+
80
+ Pact::TaskHelper.handle_verification_failure do
81
+ exit_statuses.count{ | status | status != 0 }
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
data/lib/pact/tasks.rb ADDED
@@ -0,0 +1,2 @@
1
+ load File.expand_path('../tasks/pact.rake', File.dirname(__FILE__))
2
+ require 'pact/tasks/verification_task'
@@ -0,0 +1,14 @@
1
+ Could not find one or more provider states.
2
+ Have you required the provider states file for this consumer in your pact_helper.rb?
3
+ If you have not yet defined these states, here is a template:
4
+ <% consumers.keys.each do | consumer_name | %>
5
+ Pact.provider_states_for "<%= consumer_name %>" do
6
+ <% consumers[consumer_name].each do | provider_state | %>
7
+ provider_state "<%= provider_state %>" do
8
+ set_up do
9
+ # Your set up code goes here
10
+ end
11
+ end
12
+ <% end %>
13
+ end
14
+ <% end %>
data/lib/pact/term.rb CHANGED
@@ -1,19 +1,46 @@
1
+ require 'pact/shared/active_support_support'
2
+ require 'json/add/regexp'
3
+
1
4
  module Pact
2
5
  class Term
3
6
 
7
+ include Pact::ActiveSupportSupport
8
+
4
9
  attr_reader :generate, :matcher
5
10
 
6
11
  def self.json_create(obj)
7
12
  new(generate: obj['data']['generate'], matcher: obj['data']['matcher'])
8
13
  end
9
14
 
15
+ def self.unpack_regexps source
16
+ case source
17
+ when Pact::Term then source.matcher
18
+ when Array then unpack_regexps_from_array source
19
+ when Hash then unpack_regexps_from_hash source
20
+ else
21
+ source
22
+ end
23
+ end
24
+
10
25
  def initialize(attributes = {})
11
26
  @generate = attributes[:generate]
12
27
  @matcher = attributes[:matcher]
28
+ raise "Please specify a matcher for the Term" unless @matcher != nil
29
+ raise "Please specify a value to generate for the Term" unless @generate != nil
30
+ raise "Value to generate \"#{@generate}\" does not match regular expression #{@matcher}" unless @generate =~ @matcher
31
+ end
32
+
33
+ def to_hash
34
+ { json_class: self.class.name, data: { generate: generate, matcher: fix_regexp(matcher)} }
35
+ end
36
+
37
+ def as_json(options = {})
38
+ to_hash
13
39
  end
14
40
 
41
+
15
42
  def to_json(options = {})
16
- { json_class: self.class.name, data: { generate: generate, matcher: matcher} }.to_json(options)
43
+ as_json.to_json(options)
17
44
  end
18
45
 
19
46
  def match(literal)
@@ -26,7 +53,7 @@ module Pact
26
53
  end
27
54
 
28
55
  def to_s
29
- "Pact::Term matcher: #{matcher.to_s}" + (generate.nil? ? "" : " generate: \"#{generate}\"")
56
+ "Pact::Term matcher: #{matcher.inspect}" + (generate.nil? ? "" : " generate: \"#{generate}\"")
30
57
  end
31
58
 
32
59
  def diff_with_actual(actual)
@@ -36,5 +63,23 @@ module Pact
36
63
  }
37
64
  end
38
65
 
66
+ def empty?
67
+ false
68
+ end
69
+
70
+ private
71
+
72
+ def self.unpack_regexps_from_array source
73
+ source.each_with_object([]) do | item, destination |
74
+ destination << unpack_regexps(item)
75
+ end
76
+ end
77
+
78
+ def self.unpack_regexps_from_hash source
79
+ source.keys.each_with_object({}) do | key, destination |
80
+ destination[key] = unpack_regexps source[key]
81
+ end
82
+ end
83
+
39
84
  end
40
85
  end
data/lib/pact/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Pact
2
- VERSION = "0.1.28"
2
+ VERSION = "1.3.3"
3
3
  end
data/lib/pact.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require_relative 'pact/version'
2
2
  require_relative 'pact/configuration'
3
3
  require_relative 'pact/consumer'
4
- require_relative 'pact/producer'
4
+ require_relative 'pact/provider'
5
5
  require_relative 'pact/consumer_contract'
data/lib/tasks/pact.rake CHANGED
@@ -1,6 +1,29 @@
1
+
1
2
  namespace :pact do
2
- desc "Runs all the tasks prefixed with pact:verify in this project"
3
+
4
+ desc "Verifies the pact files configured in the pact_helper.rb against this service provider."
3
5
  task :verify do
4
- Rake::Task.tasks.find_all{ | task| task.name.start_with? "pact:verify:"}.map(&:invoke)
6
+
7
+ require 'pact/tasks/task_helper'
8
+
9
+ include Pact::TaskHelper
10
+
11
+ handle_verification_failure do
12
+ execute_pact_verify
13
+ end
5
14
  end
15
+
16
+ desc "Verifies the pact at the given URI against this service provider."
17
+ task 'verify:at', :pact_uri do | t, args |
18
+ require 'term/ansicolor'
19
+ require 'pact/tasks/task_helper'
20
+
21
+ include Pact::TaskHelper
22
+
23
+ abort(::Term::ANSIColor.red("Please provide a pact URI. eg. rake pact:verify:at[../my-consumer/spec/pacts/my_consumer-my_provider.json]")) unless args[:pact_uri]
24
+ handle_verification_failure do
25
+ execute_pact_verify args[:pact_uri]
26
+ end
27
+ end
28
+
6
29
  end
data/pact.gemspec CHANGED
@@ -6,11 +6,11 @@ require 'pact/version'
6
6
  Gem::Specification.new do |gem|
7
7
  gem.name = "pact"
8
8
  gem.version = Pact::VERSION
9
- gem.authors = ["James Fraser", "Sergei Matheson", "Brent Snook", "Ronald Holshausen", "Bethany Skurrie"]
9
+ gem.authors = ["James Fraser", "Sergei Matheson", "Brent Snook", "Ronald Holshausen", "Beth Skurrie"]
10
10
  gem.email = ["james.fraser@alumni.swinburne.edu", "sergei.matheson@gmail.com", "brent@fuglylogic.com", "uglyog@gmail.com", "bskurrie@dius.com.au"]
11
- gem.description = %q{Define a pact between service consumers and providers}
12
- gem.summary = %q{Define a pact between service consumers and providers}
13
- gem.homepage = "https://github.com/uglyog/pact.git"
11
+ gem.description = %q{Enables consumer driven contract testing, providing a mock service and DSL for the consumer project, and interaction playback and verification for the service provider project.}
12
+ gem.summary = %q{Enables consumer driven contract testing, providing a mock service and DSL for the consumer project, and interaction playback and verification for the service provider project.}
13
+ gem.homepage = "https://github.com/realestate-com-au/pact"
14
14
 
15
15
  gem.files = `git ls-files`.split($/)
16
16
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
@@ -19,18 +19,20 @@ Gem::Specification.new do |gem|
19
19
  gem.license = 'MIT'
20
20
 
21
21
  gem.add_runtime_dependency 'randexp', '~> 0.1.7'
22
- gem.add_runtime_dependency 'hashie', '~> 2.0.5'
23
- gem.add_runtime_dependency 'rspec', '~> 2.12'
22
+ gem.add_runtime_dependency 'rspec', '>=2.14'
24
23
  gem.add_runtime_dependency 'find_a_port', '~> 1.0.1'
25
24
  gem.add_runtime_dependency 'rack-test', '~> 0.6.2'
26
- gem.add_runtime_dependency 'awesome_print', '~> 1.1.0'
27
- gem.add_runtime_dependency 'capybara', '~> 2.1.0'
25
+ gem.add_runtime_dependency 'awesome_print', '~> 1.1'
28
26
  gem.add_runtime_dependency 'thor'
29
- gem.add_runtime_dependency 'thin'
30
27
  gem.add_runtime_dependency 'json' #Not locking down a version because buncher gem requires 1.6, while other projects use 1.7.
28
+ gem.add_runtime_dependency 'webrick'
29
+ gem.add_runtime_dependency 'term-ansicolor', '~> 1.0'
31
30
 
32
- gem.add_development_dependency 'geminabox-client'
33
31
  gem.add_development_dependency 'rake', '~> 10.0.3'
34
- gem.add_development_dependency 'webmock', '~> 1.9.3'
32
+ gem.add_development_dependency 'webmock', '~> 1.18.0'
35
33
  gem.add_development_dependency 'pry'
34
+ gem.add_development_dependency 'fakefs', '~> 0.4'
35
+ gem.add_development_dependency 'hashie', '~> 2.0'
36
+ gem.add_development_dependency 'activesupport'
37
+ gem.add_development_dependency 'faraday'
36
38
  end