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
@@ -1,127 +0,0 @@
1
- require 'open-uri'
2
- require 'pact/consumer_contract'
3
- require 'pact/json_warning'
4
- require_relative 'matchers'
5
- require_relative 'test_methods'
6
- require_relative 'configuration_dsl'
7
-
8
- module Pact
9
- module Producer
10
- module RSpec
11
-
12
- module InstanceMethods
13
- def app
14
- Pact.configuration.producer.app
15
- end
16
- end
17
-
18
- module ClassMethods
19
-
20
- include Pact::JsonWarning
21
-
22
- def honour_pactfile pactfile_uri, options = {}
23
- describe "Pact in #{pactfile_uri}" do
24
- consumer_contract = Pact::ConsumerContract.from_json(read_pact_from(pactfile_uri, options))
25
- honour_consumer_contract consumer_contract, options
26
- end
27
- end
28
-
29
- def honour_consumer_contract consumer_contract, options = {}
30
- check_for_active_support_json
31
- describe_consumer_contract consumer_contract, options.merge({:consumer => consumer_contract.consumer.name})
32
- end
33
-
34
- private
35
-
36
- def describe_consumer_contract consumer_contract, options
37
- consumer_contract.interactions.each do |interaction|
38
- describe_interaction_with_producer_state interaction, options
39
- end
40
- end
41
-
42
- def describe_interaction_with_producer_state interaction, options
43
- if interaction.producer_state
44
- describe "Given #{interaction.producer_state}" do
45
- describe_interaction interaction, options
46
- end
47
- else
48
- describe_interaction interaction, options
49
- end
50
- end
51
-
52
- def describe_interaction interaction, options
53
-
54
- describe description_for(interaction) do
55
-
56
- before do
57
- set_up_producer_state interaction.producer_state, options[:consumer]
58
- replay_interaction interaction
59
- end
60
-
61
- after do
62
- tear_down_producer_state interaction.producer_state, options[:consumer]
63
- end
64
-
65
- describe_response interaction.response
66
- end
67
-
68
- end
69
-
70
- def describe_response response
71
- describe "returns a response which" do
72
- if response['status']
73
- it "has status code #{response['status']}" do
74
- expect(last_response.status).to eql response['status']
75
- end
76
- end
77
-
78
- if response['headers']
79
- describe "includes headers" do
80
- response['headers'].each do |name, value|
81
- it "\"#{name}\" with value \"#{value}\"" do
82
- expect(last_response.headers[name]).to match_term value
83
- end
84
- end
85
- end
86
- end
87
-
88
- if response['body']
89
- it "has a matching body" do
90
- logger.debug "Response body is #{last_response.body}"
91
- expect(parse_entity_from_response(last_response)).to match_term response['body']
92
- end
93
- end
94
- end
95
- end
96
-
97
- def description_for interaction
98
- "#{interaction.description} to #{interaction.request.path}"
99
- end
100
-
101
- def read_pact_from uri, options = {}
102
- pact = open(uri) { | file | file.read }
103
- if options[:save_pactfile_to_tmp]
104
- save_pactfile_to_tmp pact, File.basename(uri)
105
- end
106
- pact
107
- rescue StandardError => e
108
- $stderr.puts "Error reading file from #{uri}"
109
- $stderr.puts "#{e.to_s} #{e.backtrace.join("\n")}"
110
- raise e
111
- end
112
-
113
- def save_pactfile_to_tmp pact, name
114
- File.open(Pact.configuration.tmp_dir + "/#{name}", "w") { |file| file << pact}
115
- end
116
-
117
- end
118
- end
119
- end
120
- end
121
-
122
- RSpec.configure do |config|
123
- config.extend Pact::Producer::RSpec::ClassMethods
124
- config.include Pact::Producer::RSpec::InstanceMethods
125
- config.include Pact::Producer::TestMethods
126
- config.include Pact::Producer::TestMethods
127
- end
@@ -1,89 +0,0 @@
1
- require 'pact/logging'
2
- require 'rack/test'
3
- require 'pact/reification'
4
- require 'pact/producer/producer_state'
5
-
6
- module Pact
7
- module Producer
8
- module TestMethods
9
-
10
- include Pact::Logging
11
- include Rack::Test::Methods
12
-
13
- def parse_entity_from_response response
14
- case response.headers['Content-Type']
15
- when /json/
16
- JSON.load(response.body)
17
- else
18
- response.body
19
- end
20
- end
21
-
22
- def set_up_producer_state producer_state_name, consumer
23
- if producer_state_name
24
- get_producer_state(producer_state_name, consumer).set_up
25
- end
26
- end
27
-
28
- def tear_down_producer_state producer_state_name, consumer
29
- if producer_state_name
30
- get_producer_state(producer_state_name, consumer).tear_down
31
- end
32
- end
33
-
34
- def replay_interaction interaction
35
- request = interaction.request
36
- path = request_path(request)
37
- args = [path, request_body(request)]
38
-
39
- if !request.headers.nil?
40
- args << request_headers(request)
41
- end
42
-
43
- logger.debug "Sending #{request.method} with #{args}"
44
- self.send(request.method, *args)
45
- end
46
-
47
- private
48
-
49
- def request_headers request
50
- request_headers = {}
51
- request.headers.each do |key, value|
52
- key = key.upcase
53
- if key.match(/CONTENT.TYPE/)
54
- request_headers['CONTENT_TYPE'] = value
55
- else
56
- request_headers['HTTP_' + key.to_s] = value
57
- end
58
- end
59
- request_headers
60
- end
61
-
62
- def request_path request
63
- path = request.path
64
- query = request.query
65
- if query && !query.empty?
66
- path += "?" + request.query
67
- end
68
- path
69
- end
70
-
71
- def request_body request
72
- body = request.body
73
- if body
74
- body = JSON.dump(Pact::Reification.from_term(body))
75
- else
76
- body = ""
77
- end
78
- end
79
-
80
- def get_producer_state producer_state_name, consumer
81
- unless producer_state = ProducerState.get(producer_state_name, :for => consumer)
82
- extra = consumer ? " for consumer \"#{consumer}\"" : ""
83
- raise "Could not find a producer state defined for \"#{producer_state_name}\"#{extra}. Have you required the producer state file in your spec?"
84
- end
85
- producer_state
86
- end
87
- end
88
- end
89
- end
data/lib/pact/producer.rb DELETED
@@ -1 +0,0 @@
1
- #TODO delete this file after checking if any projects load it
@@ -1,64 +0,0 @@
1
- require 'rake/tasklib'
2
-
3
-
4
- module Pact
5
-
6
- ##
7
- # To enable `rake pact`, put something like this in your Rakefile:
8
- #
9
- # ```
10
- # require 'pact/rake_task'
11
- #
12
- # Pact::RakeTask.new do |pact|
13
- # pact.file 'spec/pacts/some-pact.json',
14
- # from_url: 'http://example.com/some-pact.json'
15
- # pact.file 'spec/pacts/other-pact.json',
16
- # from_url: 'http://example.com/other-pact.json'
17
- # end
18
- # ```
19
- class RakeTask < ::Rake::TaskLib
20
- attr_reader :connections
21
-
22
- def initialize(name = :pact)
23
- @connections = []
24
-
25
- yield self
26
-
27
- namespace name do
28
- desc "Update integration pacts from external sources"
29
- task :pull do
30
- connections.each do |conn|
31
- body = fetch conn[:url]
32
- File.open(conn[:file], 'w') {|f| f.write body }
33
- puts "Wrote #{conn[:url]} to #{conn[:file]}"
34
- end
35
- end
36
- end
37
- task name => "#{name}:pull" # default task for the namespace
38
- end
39
-
40
- def file(filename, options = {})
41
- url = options.fetch(:from_url)
42
- @connections << {file: filename, url: url}
43
- end
44
-
45
- private
46
- # written with plain Net::HTTP to avoid bringing in extra dependencies
47
- def fetch(url_string, redirection_limit = 5)
48
- raise 'Too many HTTP redirects' if redirection_limit == 0
49
- url = URI.parse(url_string)
50
- response = Net::HTTP.get_response(url)
51
- case response
52
- when Net::HTTPSuccess then
53
- response.body
54
- when Net::HTTPRedirection then
55
- location = response['Location']
56
- fetch(location, redirection_limit - 1)
57
- else
58
- response.value # raise the appropriate error
59
- end
60
- end
61
- end
62
-
63
-
64
- end
data/lib/pact/request.rb DELETED
@@ -1,109 +0,0 @@
1
- require 'pact/matchers'
2
-
3
- module Pact
4
-
5
- module Request
6
-
7
- class NullExpectation
8
- def to_s
9
- "<No expectation>"
10
- end
11
-
12
- def ==(other_object)
13
- other_object.is_a? NullExpectation
14
- end
15
-
16
- def ===(other_object)
17
- other_object.is_a? NullExpectation
18
- end
19
-
20
- def eql?(other_object)
21
- self == other_object
22
- end
23
-
24
- def hash
25
- 2934820948209428748274238642672
26
- end
27
-
28
- def empty?
29
- true
30
- end
31
-
32
- def nil?
33
- true
34
- end
35
- end
36
-
37
- class Base
38
- include Pact::Matchers
39
- extend Pact::Matchers
40
-
41
- NULL_EXPECTATION = NullExpectation.new
42
-
43
- attr_reader :method, :path, :headers, :body, :query
44
-
45
- def self.from_hash(hash)
46
- sym_hash = hash.inject({}) { |memo, (k,v)| memo[k.to_sym] = v; memo }
47
- method = sym_hash.fetch(:method)
48
- path = sym_hash.fetch(:path)
49
- query = sym_hash.fetch(:query, NULL_EXPECTATION)
50
- headers = sym_hash.fetch(:headers, NULL_EXPECTATION)
51
- body = sym_hash.fetch(:body, NULL_EXPECTATION)
52
- new(method, path, headers, body, query)
53
- end
54
-
55
- def initialize(method, path, headers, body, query)
56
- @method = method.to_s
57
- @path = path.chomp('/')
58
- @headers = headers
59
- @body = body
60
- @query = query
61
- end
62
-
63
- def to_json(options = {})
64
- as_json.to_json(options)
65
- end
66
-
67
- def as_json
68
- base_json = {
69
- method: method,
70
- path: path,
71
- }
72
-
73
- base_json.merge!(body: body) unless body.is_a? NullExpectation
74
- base_json.merge!(headers: headers) unless headers.is_a? NullExpectation
75
- base_json.merge!(query: query) unless query.is_a? NullExpectation
76
- base_json
77
- end
78
-
79
- end
80
-
81
- class Expected < Base
82
-
83
- attr_accessor :description
84
-
85
- def self.from_hash(hash)
86
- request = super
87
- request.description = hash.fetch(:description, nil)
88
- request
89
- end
90
-
91
- def match(actual_request)
92
- difference(actual_request).empty?
93
- end
94
-
95
- def matches_route? actual_request
96
- diff({:method => method, :path => path}, {:method => actual_request.method, :path => actual_request.path}).empty?
97
- end
98
-
99
- def difference(actual_request)
100
- diff(as_json, actual_request.as_json)
101
- end
102
-
103
- end
104
-
105
- class Actual < Base
106
- end
107
-
108
- end
109
- end
@@ -1,57 +0,0 @@
1
- require 'rake/tasklib'
2
- require 'pact/producer/pact_spec_runner'
3
-
4
- =begin
5
- To create a rake pact:verify:<something> task
6
-
7
- Pact::VerificationTask.new(:head) do | pact |
8
- pact.uri 'http://master.cd.vpc.realestate.com.au/browse/BIQ-MAS/latestSuccessful/artifact/JOB2/Pacts/mas-contract_transaction_service.json',
9
- support_file: './spec/consumers/pact_helper'
10
- pact.uri 'http://master.cd.vpc.realestate.com.au/browse/BIQ-IMAGINARY-CONSUMER/latestSuccessful/artifact/JOB2/Pacts/imaginary_consumer-contract_transaction_service.json',
11
- support_file: './spec/consumers/pact_helper'
12
- end
13
-
14
- The pact.uri may be a local file system path or a remote URL.
15
- The support_file should include code that makes your rack app available for the rack testing framework.
16
- Eg.
17
-
18
- Pact.configure do | config |
19
- config.producer do
20
- name "My Producer"
21
- app { TestApp.new }
22
- end
23
- end
24
-
25
- It should also load all your app's dependencies (eg by calling out to spec_helper)
26
-
27
- =end
28
-
29
- module Pact
30
- class VerificationTask < ::Rake::TaskLib
31
- attr_reader :pact_spec_config
32
-
33
- def initialize(name)
34
- @pact_spec_config = []
35
-
36
- yield self
37
-
38
- namespace :pact do
39
- desc "Verify producer against the consumer pacts for #{name}"
40
- task "verify:#{name}" do
41
- exit_status = Producer::PactSpecRunner.run(pact_spec_config)
42
- fail failure_message if exit_status != 0
43
- end
44
-
45
- def failure_message
46
- "\n* * * * * * * * * * * * * * * * * * *\n" +
47
- "Producer did not honour pact file.\nSee\n * #{Pact.configuration.log_path}\n * #{Pact.configuration.tmp_dir}\nfor logs and pact files." +
48
- "\n* * * * * * * * * * * * * * * * * * *\n\n"
49
- end
50
- end
51
- end
52
-
53
- def uri(uri, options)
54
- @pact_spec_config << {uri: uri, support_file: options[:support_file], consumer: options[:consumer]}
55
- end
56
- end
57
- end
@@ -1,65 +0,0 @@
1
- require 'spec_helper'
2
- require 'pact/configuration'
3
- require 'pact/consumer/dsl'
4
- require 'pact/consumer/configuration_dsl'
5
- require 'pact/producer/configuration_dsl'
6
-
7
- describe "configure" do
8
-
9
- before do
10
- Pact.clear_configuration
11
- Pact::Consumer::AppManager.instance.clear_all
12
-
13
- Pact.configure do | config |
14
- config.consumer do
15
- name "My Consumer"
16
- end
17
- end
18
-
19
- Pact.with_producer "My Service" do
20
- mock_service :my_service do
21
- port 1234
22
- standalone true
23
- end
24
- end
25
-
26
- Pact.with_producer "My Other Service" do
27
- mock_service :my_other_service do
28
- port 1235
29
- standalone false
30
- end
31
- end
32
- end
33
-
34
- describe "configuration" do
35
- it "should return the same configuration object each time" do
36
- expect(Pact.configuration).to equal(Pact.configuration)
37
- end
38
- end
39
-
40
- describe "consumer" do
41
- it "should be configured" do
42
- Pact.configuration.consumer.name.should eq "My Consumer"
43
- end
44
- end
45
-
46
- describe "producers" do
47
- include Pact::Consumer::ConsumerContractBuilders
48
-
49
- it "should have defined methods in MockServices for the producers" do
50
- my_service.should be_instance_of Pact::Consumer::ConsumerContractBuilder
51
- end
52
-
53
- context "when standalone is true" do
54
- it "is not registerd with the AppManager" do
55
- Pact::Consumer::AppManager.instance.app_registered_on?(1234).should be_false
56
- end
57
- end
58
-
59
- context "when standalone is false" do
60
- it "should register the MockServices on their given ports if they are not" do
61
- Pact::Consumer::AppManager.instance.app_registered_on?(1235).should be_true
62
- end
63
- end
64
- end
65
- end
@@ -1,52 +0,0 @@
1
- require 'spec_helper'
2
- require 'pact/consumer/dsl'
3
- require 'pact/consumer/configuration_dsl'
4
-
5
- module Pact::Consumer::DSL
6
- describe Service do
7
- before do
8
- Pact.clear_configuration
9
- Pact::Consumer::AppManager.instance.stub(:register_mock_service_for)
10
- end
11
- describe "configure_consumer_contract_builder" do
12
- subject {
13
- Service.new :mock_service do
14
- port 1234
15
- standalone true
16
- verify true
17
- end
18
- }
19
-
20
- let(:producer_name) { 'Mock Producer'}
21
- let(:consumer_contract_builder) { double('Pact::Consumer::ConsumerContractBuilder').as_null_object}
22
- let(:url) { "http://localhost:1234"}
23
-
24
- it "adds a verification to the Pact configuration" do
25
- Pact::Consumer::ConsumerContractBuilder.stub(:new).and_return(consumer_contract_builder)
26
- subject.configure_consumer_contract_builder({})
27
- consumer_contract_builder.should_receive(:verify)
28
- Pact.configuration.producer_verifications.first.call
29
- end
30
-
31
- context "when standalone" do
32
- it "does not register the app with the AppManager" do
33
- Pact::Consumer::AppManager.instance.should_not_receive(:register_mock_service_for)
34
- subject.configure_consumer_contract_builder({})
35
- end
36
- end
37
- context "when not standalone" do
38
- subject {
39
- Service.new :mock_service do
40
- port 1234
41
- standalone false
42
- verify true
43
- end
44
- }
45
- it "registers the app with the AppManager" do
46
- Pact::Consumer::AppManager.instance.should_receive(:register_mock_service_for).with(producer_name, url)
47
- subject.configure_consumer_contract_builder({:producer_name => producer_name })
48
- end
49
- end
50
- end
51
- end
52
- end
@@ -1,108 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module Pact
4
- module Consumer
5
- describe InteractionBuilder do
6
-
7
- subject {
8
- interaction_builder = InteractionBuilder.new('Test request', nil).with(request)
9
- interaction_builder.on_interaction_fully_defined do | interaction |
10
- producer.callback interaction
11
- end
12
- interaction_builder
13
- }
14
-
15
- let(:pact_path) { File.expand_path('../../../../pacts/mock', __FILE__) }
16
-
17
- let(:request) do
18
- {
19
- method: 'post',
20
- path: '/foo',
21
- body: Term.new(generate: 'waffle', matcher: /ffl/),
22
- headers: { 'Content-Type' => 'application/json' },
23
- query: '',
24
- }
25
- end
26
-
27
- let(:response) do
28
- { baz: /qux/, wiffle: Term.new(generate: 'wiffle', matcher: /iff/) }
29
- end
30
-
31
- let(:producer) do
32
- double(callback: nil)
33
- end
34
-
35
- describe "setting up responses" do
36
-
37
- it "invokes the callback" do
38
- producer.should_receive(:callback).with(subject.interaction)
39
- subject.will_respond_with response
40
- end
41
-
42
- end
43
-
44
- describe "to JSON" do
45
-
46
- let(:parsed_result) do
47
- JSON.load(JSON.dump(subject.interaction))
48
- end
49
-
50
- before do
51
- subject.will_respond_with response
52
- end
53
-
54
- it "contains the request" do
55
- expect(parsed_result['request']).to eq({
56
- 'method' => 'post',
57
- 'path' => '/foo',
58
- 'headers' => {
59
- 'Content-Type' => 'application/json'
60
- },
61
- 'body' => Term.new(generate: 'waffle', matcher: /ffl/),
62
- 'query' => ''
63
- })
64
- end
65
-
66
- describe "response" do
67
-
68
- it "serialises regexes" do
69
- expect(parsed_result['response']['baz']).to eql /qux/
70
- end
71
-
72
- it "serialises terms" do
73
- term = Term.new(generate:'wiffle', matcher: /iff/)
74
- parsed_term = parsed_result['response']['wiffle']
75
- expect(term.matcher).to eql parsed_term.matcher
76
- expect(term.generate).to eql parsed_term.generate
77
- end
78
-
79
- end
80
-
81
- context "with a producer_state" do
82
- context "described with a string" do
83
- subject {
84
- interaction_builder = InteractionBuilder.new('Test request', "there are no alligators").with(request)
85
- interaction_builder.on_interaction_fully_defined {}
86
- interaction_builder
87
- }
88
-
89
- it "includes the state name as a string" do
90
- expect(parsed_result['producer_state']).to eql("there are no alligators")
91
- end
92
- end
93
- context "described with a symbol" do
94
- subject {
95
- interaction_builder = InteractionBuilder.new('Test request', :there_are_no_alligators).with(request)
96
- interaction_builder.on_interaction_fully_defined {}
97
- interaction_builder
98
- }
99
-
100
- it "includes the state name as a symbol" do
101
- expect(parsed_result['producer_state']).to eql("there_are_no_alligators")
102
- end
103
- end
104
- end
105
- end
106
- end
107
- end
108
- end