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,52 @@
1
+ require 'spec_helper'
2
+ require 'rack/test'
3
+ require 'tempfile'
4
+
5
+ module Pact
6
+ module Consumer
7
+
8
+ describe MockService do
9
+
10
+ include Rack::Test::Methods
11
+
12
+ def app
13
+ MockService.new(log_file: temp_file)
14
+ end
15
+
16
+ let(:temp_file) { Tempfile.new('log') }
17
+
18
+ after do
19
+ temp_file.close
20
+ temp_file.unlink
21
+ end
22
+
23
+ context "when a StandardError is encountered" do
24
+ let(:response) { JSON.parse(last_response.body)}
25
+ let(:interaction_replay) { double(InteractionReplay, :match? => true)}
26
+
27
+ before do
28
+ expect(InteractionReplay).to receive(:new).and_return(interaction_replay)
29
+ expect(interaction_replay).to receive(:respond).and_raise("an error")
30
+ end
31
+
32
+ subject { get "/" }
33
+
34
+ it "returns a json error" do
35
+ subject
36
+ expect(last_response.content_type).to eq 'application/json'
37
+ end
38
+
39
+ it "includes the error message" do
40
+ subject
41
+ expect(response['message']).to eq "an error"
42
+ end
43
+
44
+ it "includes the backtrace" do
45
+ subject
46
+ expect(response['backtrace']).to be_instance_of Array
47
+ end
48
+ end
49
+
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,78 @@
1
+ require 'spec_helper'
2
+ require 'pact/consumer/mock_service/interaction_list'
3
+
4
+ module Pact::Consumer
5
+
6
+ describe InteractionList do
7
+ shared_context "unexpected requests and missed interactions" do
8
+ let(:expected_interaction) { InteractionFactory.create }
9
+ let(:unexpected_request) { RequestFactory.create_actual method: 'put' }
10
+ let(:candidate_interaction) { double("Pact::Interaction") }
11
+ let(:candidate_interactions) { [candidate_interaction] }
12
+ let(:interaction_mismatch) { instance_double("Pact::Consumer::InteractionMismatch", :short_summary => 'blah', :candidate_interactions => candidate_interactions)}
13
+ subject {
14
+ interactionList = InteractionList.new
15
+ interactionList.add expected_interaction
16
+ interactionList.register_unexpected_request unexpected_request
17
+ interactionList.register_interaction_mismatch interaction_mismatch
18
+ interactionList
19
+ }
20
+ end
21
+
22
+ shared_context "no unexpected requests or missed interactions exist" do
23
+ let(:expected_interaction) { InteractionFactory.create }
24
+ subject {
25
+ interactionList = InteractionList.new
26
+ interactionList.add expected_interaction
27
+ interactionList.register_matched expected_interaction
28
+ interactionList
29
+ }
30
+ end
31
+
32
+ describe "interaction_diffs" do
33
+ context "when unexpected requests and missed interactions exist" do
34
+ include_context "unexpected requests and missed interactions"
35
+ let(:expected_diff) {
36
+ {:missing_interactions=>["GET /path"],
37
+ :unexpected_requests=>["PUT /path?query"],
38
+ :interaction_mismatches => ['blah']}
39
+ }
40
+ it "returns the unexpected requests and missed interactions" do
41
+ expect(subject.interaction_diffs).to eq expected_diff
42
+ end
43
+ end
44
+
45
+ context "when no unexpected requests or missed interactions exist" do
46
+ include_context "no unexpected requests or missed interactions exist"
47
+ let(:expected_diff) {
48
+ {}
49
+ }
50
+ it "returns an empty hash" do
51
+ expect(subject.interaction_diffs).to eq expected_diff
52
+ end
53
+ end
54
+ end
55
+
56
+ describe "all_matched?" do
57
+ context "when unexpected requests or missed interactions exist" do
58
+ include_context "unexpected requests and missed interactions"
59
+ it "returns false" do
60
+ expect(subject.all_matched?).to be false
61
+ end
62
+ end
63
+ context "when unexpected requests or missed interactions do not exist" do
64
+ include_context "no unexpected requests or missed interactions exist"
65
+ it "returns false" do
66
+ expect(subject.all_matched?).to be true
67
+ end
68
+ end
69
+ end
70
+
71
+ describe "missing_interactions_summaries" do
72
+ include_context "unexpected requests and missed interactions"
73
+ it "returns a list of the method and paths for each missing interaction" do
74
+ expect(subject.missing_interactions_summaries).to eq ["GET /path"]
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+ require 'pact/consumer/mock_service/interaction_mismatch'
3
+
4
+ module Pact
5
+ module Consumer
6
+ describe InteractionMismatch do
7
+ let(:content_type) { 'some/content' }
8
+ let(:actual_request) { instance_double('Pact::Consumer::Request::Actual', :method_and_path => 'GET /path') }
9
+ let(:expected_request_1) { instance_double('Pact::Request::Expected', :content_type => content_type) }
10
+ let(:expected_request_2) { instance_double('Pact::Request::Expected', :content_type => content_type) }
11
+ let(:candidate_1) { instance_double('Pact::Interaction', request: expected_request_1, description_with_provider_state_quoted: "desc 1") }
12
+ let(:candidate_2) { instance_double('Pact::Interaction', request: expected_request_2, description_with_provider_state_quoted: "desc 2") }
13
+ let(:candidate_interactions) { [candidate_1, candidate_2] }
14
+ subject { InteractionMismatch.new(candidate_interactions, actual_request) }
15
+ let(:diff_1) { {body: 'diff'} }
16
+ let(:diff_2) { {} }
17
+
18
+ before do
19
+ allow(expected_request_1).to receive(:difference).with(actual_request).and_return(diff_1)
20
+ allow(expected_request_2).to receive(:difference).with(actual_request).and_return(diff_2)
21
+ end
22
+
23
+ describe "short_summary" do
24
+ it "includes the method and path" do
25
+ expect(subject.short_summary).to match /GET \/path \(.*\)/
26
+ end
27
+ context "when the body does not match" do
28
+ let(:diff_1) { {body: nil} }
29
+
30
+ it "returns a message indicating that the body does not match" do
31
+ expect(subject.short_summary).to include "(request body did not match)"
32
+ end
33
+ end
34
+ context "when the headers do not match" do
35
+ let(:diff_1) { {headers: nil} }
36
+ it "returns a message indicating that the body does not match" do
37
+ expect(subject.short_summary).to include "(request headers did not match)"
38
+ end
39
+ end
40
+ context "when the headers and body do not match" do
41
+ let(:diff_1) { {body: nil, headers: nil} }
42
+ let(:diff_2) { {body: nil, headers: nil} }
43
+ it "returns a message indicating that the headers and body do not match" do
44
+ expect(subject.short_summary).to include "(request body and headers did not match)"
45
+ end
46
+ end
47
+ end
48
+
49
+ describe "to_s" do
50
+ let(:expected_message) { "Diff with interaction: desc 1\ndiff 1\nDiff with interaction: desc 2\ndiff 2" }
51
+
52
+ let(:diff_formatter) { double("diff_formatter")}
53
+ before do
54
+ allow(Pact.configuration).to receive(:diff_formatter_for_content_type).with(content_type).and_return(diff_formatter)
55
+ allow(diff_formatter).to receive(:call).and_return("diff 1", "diff 2")
56
+ end
57
+
58
+ it "creates diff output using the configured diff_formatter" do
59
+ expect(diff_formatter).to receive(:call).with(diff_1, colour: false)
60
+ expect(diff_formatter).to receive(:call).with(diff_2, colour: false)
61
+ subject.to_s
62
+ end
63
+
64
+ it "includes a diff output in the string output" do
65
+ expect(subject.to_s).to eq expected_message
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+ require 'pact/consumer/mock_service/interaction_replay'
3
+
4
+ module Pact
5
+ module Consumer
6
+
7
+ describe InteractionReplay do
8
+
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+ require 'pact/consumer/mock_service/rack_request_helper'
3
+
4
+ module Pact::Consumer
5
+
6
+ describe RackRequestHelper do
7
+ class TestSubject
8
+ include RackRequestHelper
9
+ end
10
+
11
+ let(:rack_env) {
12
+ {
13
+ "CONTENT_LENGTH" => "16",
14
+ "CONTENT_TYPE" => content_type,
15
+ "GATEWAY_INTERFACE" => "CGI/1.1",
16
+ "PATH_INFO" => "/donuts",
17
+ "QUERY_STRING" => "",
18
+ "REMOTE_ADDR" => "127.0.0.1",
19
+ "REMOTE_HOST" => "localhost",
20
+ "REQUEST_METHOD" => "POST",
21
+ "REQUEST_URI" => "http://localhost:4321/donuts",
22
+ "SCRIPT_NAME" => "",
23
+ "SERVER_NAME" => "localhost",
24
+ "SERVER_PORT" => "4321",
25
+ "SERVER_PROTOCOL" => "HTTP/1.1",
26
+ "SERVER_SOFTWARE" => "WEBrick/1.3.1 (Ruby/1.9.3/2013-02-22)",
27
+ "HTTP_ACCEPT" => "text/plain",
28
+ "HTTP_USER_AGENT" => "Ruby",
29
+ "HTTP_HOST" => "localhost:4321",
30
+ "HTTP_X_SOMETHING" => "1, 2",
31
+ "rack.version" => [1, 2 ],
32
+ "rack.input" => StringIO.new(body),
33
+ "rack.errors" => nil,
34
+ "rack.multithread" => true,
35
+ "rack.multiprocess" => false,
36
+ "rack.run_once" => false,
37
+ "rack.url_scheme" => "http",
38
+ "HTTP_VERSION" => "HTTP/1.1",
39
+ "REQUEST_PATH" => "/donuts"
40
+ }
41
+ }
42
+
43
+ let(:content_type) { "" }
44
+ let(:body) { '' }
45
+
46
+ subject { TestSubject.new }
47
+
48
+ let(:expected_request) {
49
+ {
50
+ :query => "",
51
+ :method => "post",
52
+ :body => expected_body,
53
+ :path => "/donuts",
54
+ :headers => {
55
+ "Content-Type" => content_type,
56
+ "Content-Length" => "16",
57
+ "Accept" => "text/plain",
58
+ "User-Agent" => "Ruby",
59
+ "Host" => "localhost:4321",
60
+ "Version" => "HTTP/1.1",
61
+ "X-Something" => "1, 2"
62
+ }
63
+ }
64
+ }
65
+
66
+ context "with a text body" do
67
+ let(:content_type) { "application/x-www-form-urlencoded" }
68
+ let(:body) { 'this is the body' }
69
+ let(:expected_body) { body }
70
+
71
+ it "extracts the body" do
72
+ expect(subject.request_as_hash_from(rack_env)).to eq expected_request
73
+ end
74
+ end
75
+
76
+ context "with a json body" do
77
+ let(:content_type) { "application/json" }
78
+ let(:body) { '{"a" : "body" }' }
79
+ let(:expected_body) { {"a" => "body"} }
80
+
81
+ it "extracts the body" do
82
+ expect(subject.request_as_hash_from(rack_env)).to eq expected_request
83
+ end
84
+ end
85
+
86
+
87
+ end
88
+ end
@@ -0,0 +1,142 @@
1
+ require 'spec_helper'
2
+ require 'pact/consumer/mock_service/verification_get'
3
+
4
+ module Pact
5
+ module Consumer
6
+ describe VerificationGet do
7
+
8
+ let(:interaction_list) { instance_double("Pact::Consumer::InteractionList")}
9
+ let(:logger) { double("Logger").as_null_object }
10
+ let(:log_description) { "/log/pact.log" }
11
+
12
+ subject { VerificationGet.new('VerificationGet', logger, interaction_list, log_description) }
13
+
14
+ describe "request_path" do
15
+ it "is /interactions/verification" do
16
+ expect(subject.request_path).to eq '/interactions/verification'
17
+ end
18
+ end
19
+
20
+ describe "request_method" do
21
+ it "is GET" do
22
+ expect(subject.request_method).to eq 'GET'
23
+ end
24
+ end
25
+
26
+ describe "#respond" do
27
+ let(:env) { {
28
+ "QUERY_STRING" => "example_description=a description"
29
+ } }
30
+
31
+ before do
32
+ allow(interaction_list).to receive(:all_matched?).and_return(all_matched)
33
+ end
34
+
35
+ let(:response) { subject.respond env }
36
+
37
+ context "when all interactions have been matched" do
38
+ let(:all_matched) { true }
39
+
40
+ it "returns a 200 status" do
41
+ expect(response.first).to eq 200
42
+ end
43
+
44
+ it "returns a Content-Type of text/plain" do
45
+ expect(response[1]).to eq 'Content-Type' => 'text/plain'
46
+ end
47
+
48
+ it "returns a nice message" do
49
+ expect(response.last).to eq ['Interactions matched']
50
+ end
51
+
52
+ it "logs the success" do
53
+ expect(logger).to receive(:info).with(/Verifying - interactions matched.*a description/)
54
+ response
55
+ end
56
+ end
57
+
58
+ context "when all interactions not been matched" do
59
+ let(:all_matched) { false }
60
+ let(:failure_message) { "this is a failure message"}
61
+
62
+ before do
63
+ allow_any_instance_of(VerificationGet::FailureMessage).to receive(:to_s).and_return(failure_message)
64
+ end
65
+
66
+ it "returns a 500 status" do
67
+ expect(response.first).to eq 500
68
+ end
69
+
70
+ it "returns a Content-Type of text/plain" do
71
+ expect(response[1]).to eq 'Content-Type' => 'text/plain'
72
+ end
73
+
74
+ it "returns a message" do
75
+ expect(response.last.first).to include "Actual interactions do not match"
76
+ expect(response.last.first).to include failure_message
77
+ expect(response.last.first).to include log_description
78
+ end
79
+
80
+ it "logs the failure message" do
81
+ expect(logger).to receive(:warn).with(/Verifying - actual interactions do not match/)
82
+ expect(logger).to receive(:warn).with(failure_message)
83
+ response
84
+ end
85
+
86
+ end
87
+
88
+ end
89
+
90
+ describe "FailureMessage" do
91
+ let(:missing_interactions_summaries) { ["Blah", "Thing"]}
92
+ let(:interaction_mismatches_summaries) { []}
93
+ let(:unexpected_requests_summaries) { []}
94
+ let(:interaction_list) { instance_double("Pact::Consumer::InteractionList") }
95
+ subject { VerificationGet::FailureMessage.new(interaction_list).to_s }
96
+
97
+ before do
98
+ allow(interaction_list).to receive(:missing_interactions_summaries).and_return(missing_interactions_summaries)
99
+ allow(interaction_list).to receive(:interaction_mismatches_summaries).and_return(interaction_mismatches_summaries)
100
+ allow(interaction_list).to receive(:unexpected_requests_summaries).and_return(unexpected_requests_summaries)
101
+ end
102
+
103
+ context "with only a missing interactions" do
104
+
105
+ let(:expected_string) { <<-EOS
106
+ Missing requests:
107
+ \tBlah
108
+ \tThing
109
+
110
+ EOS
111
+ }
112
+ it "only includes missing interactions" do
113
+ expect(subject).to eq expected_string
114
+ end
115
+ end
116
+
117
+ context "with missing, mismatches and unexpected interactions" do
118
+
119
+ let(:interaction_mismatches_summaries) { ["wiffle"]}
120
+ let(:unexpected_requests_summaries) { ["moose"]}
121
+
122
+ let(:expected_string) { <<-EOS
123
+ Incorrect requests:
124
+ \twiffle
125
+
126
+ Missing requests:
127
+ \tBlah
128
+ \tThing
129
+
130
+ Unexpected requests:
131
+ \tmoose
132
+
133
+ EOS
134
+ }
135
+ it "includes all the things" do
136
+ expect(subject).to eq expected_string
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+ require 'pact/consumer/mock_service_client'
3
+
4
+ module Pact
5
+ module Consumer
6
+ describe MockServiceClient do
7
+
8
+ subject { MockServiceClient.new(4444) }
9
+
10
+ let(:administration_headers) { {'X-Pact-Mock-Service' => 'true'} }
11
+
12
+ describe "#add_expected_interaction" do
13
+ let(:interaction) { InteractionFactory.create }
14
+ let(:request_body) { MockServiceInteractionExpectation.new(interaction).to_json }
15
+
16
+ context "when successful" do
17
+ let!(:post_interaction) do
18
+ stub_request(:post, "localhost:4444/interactions").
19
+ with(body: request_body, headers: administration_headers.merge('Content-Type' => "application/json")).
20
+ to_return(status: 200)
21
+ end
22
+
23
+ it "sets up the expected interaction on the mock server" do
24
+ subject.add_expected_interaction interaction
25
+ expect(post_interaction).to have_been_made
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ describe "#verify" do
32
+
33
+ context "when all interactions are successfully verified" do
34
+
35
+ let!(:get_verification) do
36
+ stub_request(:get, "localhost:4444/interactions/verification?example_description=some%20example").
37
+ with(headers: administration_headers).
38
+ to_return(status: 200)
39
+ end
40
+
41
+ it "does not throw an error" do
42
+ subject.verify "some example"
43
+ expect(get_verification).to have_been_made
44
+ end
45
+ end
46
+ end
47
+
48
+ describe ".clear_interactions" do
49
+ let!(:delete_verifications) do
50
+ stub_request(:delete, "localhost:4444/interactions?example_description=some%20example").
51
+ with(headers: administration_headers).
52
+ to_return(status: 200)
53
+ end
54
+
55
+ it "deletes the interactions" do
56
+ MockServiceClient.clear_interactions 4444, "some example"
57
+ expect(delete_verifications).to have_been_made
58
+ end
59
+ end
60
+
61
+ describe "#write_pact" do
62
+ let(:consumer_contract_details) { {consumer: {name: 'Consumer'}, provider: {name: 'Provider'}, pactfile_write_mode: 'update'} }
63
+ let(:pact) { {a: 'pact'}.to_json }
64
+
65
+ let!(:post_pact) do
66
+ stub_request(:post, "localhost:4444/pact").
67
+ with(headers: administration_headers.merge('Content-Type' => "application/json"), body: consumer_contract_details).
68
+ to_return(status: 200, body: pact)
69
+ end
70
+
71
+ it "deletes the interactions" do
72
+ expect(subject.write_pact(consumer_contract_details)).to eq pact
73
+ expect(post_pact).to have_been_made
74
+ end
75
+
76
+ end
77
+
78
+ describe "#log" do
79
+ it "sends a log request to the mock server"
80
+ end
81
+
82
+ describe "#wait_for_interactions" do
83
+ it "waits until there are no missing interactions"
84
+ end
85
+ end
86
+ end
87
+ end
88
+
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+ require 'pact/consumer/mock_service_interaction_expectation'
3
+
4
+ describe Pact::Consumer::MockServiceInteractionExpectation do
5
+ describe "as_json" do
6
+
7
+ let(:options ) { {} }
8
+ let(:request_as_json) { {a: 'request'} }
9
+ let(:request) { instance_double('Pact::Request::Expected', :as_json => request_as_json, :options => options)}
10
+ let(:response) { double('response') }
11
+ let(:generated_response ) { double('generated_response', :to_json => 'generated_response') }
12
+ let(:interaction) { instance_double('Pact::Interaction', :description => 'description', :request => request, :response => response, :provider_state => 'some state') }
13
+ subject { described_class.new(interaction)}
14
+ let(:expected_hash) { {:response => generated_response, :request => as_json_with_options, :description => '' } }
15
+
16
+ before do
17
+ allow(Pact::Reification).to receive(:from_term).with(response).and_return(generated_response)
18
+ end
19
+
20
+ it "includes the response" do
21
+ expect(subject.as_json[:response]).to eq response
22
+ end
23
+
24
+ it "includes the options in the request" do
25
+ expect(subject.as_json[:request]).to eq request_as_json
26
+ end
27
+
28
+ it "includes the provider state" do
29
+ expect(subject.as_json[:provider_state]).to eq 'some state'
30
+ end
31
+
32
+ it "includes the description" do
33
+ expect(subject.as_json[:description]).to eq 'description'
34
+ end
35
+
36
+ it "doesn't have any other keys" do
37
+ expect(subject.as_json.keys).to eq [:description, :provider_state, :request, :response]
38
+ end
39
+
40
+ context "without options" do
41
+ it "does not include the options key" do
42
+ expect(subject.as_json.key?(:options)).to be false
43
+ end
44
+ end
45
+
46
+ context "with options" do
47
+ let(:options) { {:opts => 'blah'} }
48
+ it "includes the options in the request hash" do
49
+ expect(subject.as_json[:request][:options]).to eq options
50
+ end
51
+ end
52
+ end
53
+
54
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+ require 'support/shared_examples_for_request'
3
+
4
+ module Pact
5
+ describe Consumer::Request::Actual do
6
+ it_behaves_like "a request"
7
+
8
+ let(:raw_request) do
9
+ {
10
+ 'method' => 'get',
11
+ 'path' => '/mallory'
12
+ }
13
+ end
14
+
15
+ describe "from_hash" do
16
+ context "when field are not defined" do
17
+ subject { described_class.from_hash(raw_request) }
18
+ it "raises an error" do
19
+ expect{subject}.to raise_error KeyError
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- module Pact::Consumer
3
+ module Pact
4
4
  describe ServiceConsumer do
5
5
  describe "as_json" do
6
6
  it "returns a hash representation of the object" do
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+ require 'pact/shared/active_support_support'
3
+
4
+ module Pact
5
+ describe ActiveSupportSupport do
6
+
7
+ include ActiveSupportSupport
8
+
9
+
10
+ describe "fix_regexp" do
11
+ let(:regexp) { /moose/ }
12
+
13
+ subject { fix_regexp regexp }
14
+
15
+ it "returns the original regexp" do
16
+ expect(subject).to be(regexp)
17
+ end
18
+
19
+ it "fixes the as_json method for Regexp that ActiveSupport tramples beneath its destructive hooves of destruction" do
20
+ expect(subject.to_json).to eq("{\"json_class\":\"Regexp\",\"o\":0,\"s\":\"moose\"}")
21
+ end
22
+ end
23
+
24
+ describe "fix_all_the_things" do
25
+ let(:hash) do
26
+ { 'body' => Pact::Term.new(matcher: /a*b/, generate: 'abba'), array: [/blah/], thing: /alligator/ }
27
+ end
28
+
29
+ subject { fix_all_the_things(hash) }
30
+
31
+ it "returns the original object" do
32
+ expect(subject).to be(hash)
33
+ end
34
+
35
+ it "finds all the Regexp objects in hashes or Pact class attributes and fixes the as_json method" do
36
+ json = subject.to_json
37
+ expect(json).to include("{\"json_class\":\"Regexp\",\"o\":0,\"s\":\"a*b\"}")
38
+ expect(json).to include("{\"json_class\":\"Regexp\",\"o\":0,\"s\":\"blah\"}")
39
+ expect(json).to include("{\"json_class\":\"Regexp\",\"o\":0,\"s\":\"alligator\"}")
40
+ end
41
+ end
42
+
43
+ describe "fix_json_formatting" do
44
+ let(:active_support_affected_pretty_generated_json) { "{\"json_class\":\"Regexp\",\"o\":0,\"s\":\"a*b\"}" }
45
+ let(:pretty_generated_json) do
46
+ '{
47
+ "json_class": "Regexp",
48
+ "o": 0,
49
+ "s": "a*b"
50
+ }'
51
+ end
52
+
53
+ it "pretty formats the json that has been not pretty formatted because of ActiveSupport" do
54
+ expect(fix_json_formatting(active_support_affected_pretty_generated_json)).to eq (pretty_generated_json.strip)
55
+ end
56
+ end
57
+ end
58
+ end