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,50 @@
1
+ {
2
+ "provider": {
3
+ "name": "a provider"
4
+ },
5
+ "consumer": {
6
+ "name": "a consumer"
7
+ },
8
+ "interactions": [
9
+ {
10
+ "description": "an interaction with terms",
11
+ "request": {
12
+ "method": "post",
13
+ "path": "/path",
14
+ "query": "some=thing",
15
+ "headers": {
16
+ "key": "a header"
17
+ },
18
+ "body": {
19
+ "term": {
20
+ "json_class": "Pact::Term",
21
+ "data": {
22
+ "generate": "sunny",
23
+ "matcher": {
24
+ "json_class": "Regexp",
25
+ "o": 0,
26
+ "s": "sun"
27
+ }
28
+ }
29
+ }
30
+ }
31
+ },
32
+ "response": {
33
+ "status": 200,
34
+ "body": {
35
+ "term": {
36
+ "json_class": "Pact::Term",
37
+ "data": {
38
+ "generate": "rainy",
39
+ "matcher": {
40
+ "json_class": "Regexp",
41
+ "o": 0,
42
+ "s": "rain"
43
+ }
44
+ }
45
+ }
46
+ }
47
+ }
48
+ }
49
+ ]
50
+ }
@@ -0,0 +1,48 @@
1
+ {
2
+ "provider": {
3
+ "name": "Some Provider"
4
+ },
5
+ "consumer": {
6
+ "name": "Some Consumer"
7
+ },
8
+ "interactions": [
9
+ {
10
+ "description": "a request for alligators",
11
+ "provider_state": "alligators exist",
12
+ "request": {
13
+ "method": "get",
14
+ "path": "/alligators"
15
+ },
16
+ "response": {
17
+ "headers" : {"Content-Type": "application/json"},
18
+ "status" : 200,
19
+ "body" : {
20
+ "alligators": [{
21
+ "name": "Bob",
22
+ "phoneNumber" : {
23
+ "json_class": "Pact::Term",
24
+ "data": {
25
+ "generate": "12345678",
26
+ "matcher": {"json_class":"Regexp","o":0,"s":"\\d+"}
27
+ }
28
+ }
29
+ }]
30
+ }
31
+ }
32
+ },{
33
+ "description": "a request for polar bears",
34
+ "provider_state": null,
35
+ "request": {
36
+ "method": "get",
37
+ "path": "/polar-bears"
38
+ },
39
+ "response": {
40
+ "headers" : {"Content-Type": "application/json"},
41
+ "status" : 404,
42
+ "body" : {
43
+ "message": "Sorry, due to climate change, the polar bears are currently unavailable."
44
+ }
45
+ }
46
+ }
47
+ ]
48
+ }
@@ -0,0 +1,25 @@
1
+ Pact.provider_states_for "Consumer 1" do
2
+
3
+ provider_state "state1" do
4
+ set_up do
5
+ # Your set up code goes here
6
+ end
7
+ end
8
+
9
+ provider_state "state2" do
10
+ set_up do
11
+ # Your set up code goes here
12
+ end
13
+ end
14
+
15
+ end
16
+
17
+ Pact.provider_states_for "Consumer 2" do
18
+
19
+ provider_state "state3" do
20
+ set_up do
21
+ # Your set up code goes here
22
+ end
23
+ end
24
+
25
+ end
@@ -0,0 +1,21 @@
1
+ {
2
+ "consumer": {
3
+ "name": "Consumer"
4
+ },
5
+ "provider": {
6
+ "name": "Provider"
7
+ },
8
+ "interactions": [
9
+ {
10
+ "description": "an OPTIONS request",
11
+ "request": {
12
+ "method": "options",
13
+ "path": "/"
14
+ },
15
+ "response": {
16
+ "status": 200
17
+ },
18
+ "provider_state": null
19
+ }
20
+ ]
21
+ }
@@ -0,0 +1,15 @@
1
+ require 'pact/provider/rspec'
2
+
3
+ class App
4
+ def self.call env
5
+ if env['REQUEST_METHOD'] == 'OPTIONS'
6
+ [200, {}, []]
7
+ else
8
+ [500, {}, ["Expected an options request"]]
9
+ end
10
+ end
11
+ end
12
+
13
+ Pact.service_provider 'Provider' do
14
+ app { App }
15
+ end
@@ -0,0 +1,57 @@
1
+ # This is the pact_helper for rake pact:tests
2
+ require 'json'
3
+ require 'pact/provider/rspec'
4
+ require './spec/support/active_support_if_configured'
5
+
6
+ module Pact
7
+ module Test
8
+ class TestApp
9
+ def call env
10
+ if env['PATH_INFO'] == '/weather'
11
+ [200, {'Content-Type' => 'application/json'}, [{message: WEATHER[:current_state], :array => [{"foo"=> "blah"}]}.to_json]]
12
+ elsif env['PATH_INFO'] == '/sometext'
13
+ [200, {'Content-Type' => 'text/plain'}, ['some text']]
14
+ elsif env['PATH_INFO'] == '/content_type_is_important'
15
+ [200, {'Content-Type' => 'application/json'}, [{message: "A message", note: "This will cause verify to fail if it using the wrong content type differ."}.to_json]]
16
+ else
17
+ raise "unexpected path #{env['PATH_INFO']}!!!"
18
+ end
19
+ end
20
+ end
21
+
22
+ Pact.configure do | config |
23
+ config.logger.level = Logger::DEBUG
24
+ config.diff_formatter = :unix
25
+ end
26
+
27
+ Pact.service_provider "Some Provider" do
28
+ app { TestApp.new }
29
+
30
+ honours_pact_with 'some-test-consumer' do
31
+ pact_uri './spec/support/test_app_pass.json'
32
+ end
33
+ end
34
+
35
+ Pact.set_up do
36
+ WEATHER ||= {}
37
+ end
38
+
39
+ #one with a top level consumer
40
+ Pact.provider_states_for 'some-test-consumer' do
41
+
42
+ provider_state "the weather is sunny" do
43
+ set_up do
44
+
45
+ WEATHER[:current_state] = 'sunny'
46
+ end
47
+ end
48
+ end
49
+
50
+ #one without a top level consumer
51
+ Pact.provider_state "the weather is cloudy" do
52
+ set_up do
53
+ WEATHER[:current_state] = 'cloudy'
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,94 @@
1
+ shared_examples "a request" do
2
+
3
+ describe 'matching' do
4
+ let(:expected) do
5
+ Pact::Request::Expected.from_hash(
6
+ {'method' => 'get', 'path' => 'path', 'query' => /b/}
7
+ )
8
+ end
9
+
10
+ let(:actual) do
11
+ Pact::Consumer::Request::Actual.from_hash({'method' => 'get', 'path' => 'path', 'query' => 'blah', 'headers' => {}, 'body' => ''})
12
+ end
13
+
14
+ it "should match" do
15
+ expect(expected.difference(actual)).to eq({})
16
+ end
17
+ end
18
+
19
+ describe 'full_path' do
20
+ context "with empty path" do
21
+ subject { described_class.from_hash({:path => '', :method => 'get', :query => '', :headers => {}}) }
22
+ it "returns the full path"do
23
+ expect(subject.full_path).to eq "/"
24
+ end
25
+ end
26
+ context "with a path" do
27
+ subject { described_class.from_hash({:path => '/path', :method => 'get', :query => '', :headers => {}}) }
28
+ it "returns the full path"do
29
+ expect(subject.full_path).to eq "/path"
30
+ end
31
+ end
32
+ context "with a path and query" do
33
+ subject { described_class.from_hash({:path => '/path', :method => 'get', :query => "something", :headers => {}}) }
34
+ it "returns the full path"do
35
+ expect(subject.full_path).to eq "/path?something"
36
+ end
37
+ end
38
+ context "with a path and a query that is a Term" do
39
+ subject { described_class.from_hash({:path => '/path', :method => 'get', :headers => {}, :query => Pact::Term.new(generate: 'a', matcher: /a/)}) }
40
+ it "returns the full path with reified path" do
41
+ expect(subject.full_path).to eq "/path?a"
42
+ end
43
+ end
44
+ end
45
+
46
+ describe "building from a hash" do
47
+
48
+ let(:raw_request) do
49
+ {
50
+ 'method' => 'get',
51
+ 'path' => '/mallory',
52
+ 'query' => 'query',
53
+ 'headers' => {
54
+ 'Content-Type' => 'application/json'
55
+ },
56
+ 'body' => 'hello mallory'
57
+ }
58
+ end
59
+
60
+ subject { described_class.from_hash(raw_request) }
61
+
62
+ it "extracts the method" do
63
+ expect(subject.method).to eq 'get'
64
+ end
65
+
66
+ it "extracts the path" do
67
+ expect(subject.path).to eq '/mallory'
68
+ end
69
+
70
+ it "extracts the body" do
71
+ expect(subject.body).to eq 'hello mallory'
72
+ end
73
+
74
+ it "extracts the query" do
75
+ expect(subject.query).to eq 'query'
76
+ end
77
+
78
+ it "blows up if method is absent" do
79
+ raw_request.delete 'method'
80
+ expect { described_class.from_hash(raw_request) }.to raise_error
81
+ end
82
+
83
+ it "blows up if path is absent" do
84
+ raw_request.delete 'path'
85
+ expect { described_class.from_hash(raw_request) }.to raise_error
86
+ end
87
+
88
+ it "does not blow up if body is missing" do
89
+ raw_request.delete 'body'
90
+ expect { described_class.from_hash(raw_request) }.to_not raise_error
91
+ end
92
+
93
+ end
94
+ end
@@ -0,0 +1,20 @@
1
+ require 'pact/rspec'
2
+
3
+ module Pact
4
+ module SpecSupport
5
+
6
+ extend self
7
+
8
+ def remove_ansicolor string
9
+ string.gsub(/\e\[(\d+)m/, '')
10
+ end
11
+
12
+ Pact::RSpec.with_rspec_2 do
13
+
14
+ def instance_double *args
15
+ double(*args)
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,22 @@
1
+ {
2
+ "consumer": {
3
+ "name": "Consumer"
4
+ },
5
+ "provider": {
6
+ "name": "Provider"
7
+ },
8
+ "interactions": [
9
+ {
10
+ "description": "a test request",
11
+ "request": {
12
+ "method": "get",
13
+ "path": "/"
14
+ },
15
+ "response": {
16
+ "status": 200,
17
+ "body": "stubbing works"
18
+ },
19
+ "provider_state": "something is stubbed"
20
+ }
21
+ ]
22
+ }
@@ -0,0 +1,29 @@
1
+ require 'pact/provider/rspec'
2
+ require 'rspec/mocks'
3
+ require './spec/support/active_support_if_configured'
4
+
5
+ class StubbedThing
6
+ def self.stub_me
7
+ end
8
+ end
9
+
10
+ class App
11
+ def self.call env
12
+ [200, {}, [StubbedThing.stub_me]]
13
+ end
14
+ end
15
+
16
+ Pact.provider_states_for 'Consumer' do
17
+ provider_state 'something is stubbed' do
18
+ set_up do
19
+ allow(StubbedThing).to receive(:stub_me).and_return("stubbing works")
20
+ end
21
+ end
22
+ end
23
+
24
+ # Include the ExampleMethods module after the provider states are declared
25
+ # to ensure the ordering doesn't matter
26
+
27
+ Pact.service_provider 'Provider' do
28
+ app { App }
29
+ end
@@ -0,0 +1,48 @@
1
+ {
2
+ "consumer": {
3
+ "name": "some-test-consumer"
4
+ },
5
+ "provider": {
6
+ "name": "an unknown provider"
7
+ },
8
+ "interactions": [
9
+ {
10
+ "description": "a test request",
11
+ "request": {
12
+ "method": "get",
13
+ "path": "/weather",
14
+ "query": ""
15
+ },
16
+ "response": {
17
+ "status": 200,
18
+ "headers" : {
19
+ "Content-type": {
20
+ "json_class": "Pact::Term",
21
+ "data": {
22
+ "generate": "text/plain",
23
+ "matcher": {
24
+ "json_class": "Regexp",
25
+ "o": 0,
26
+ "s": "text"
27
+ }
28
+ }
29
+ }
30
+ },
31
+ "body": {
32
+ "message" : {
33
+ "json_class": "Pact::Term",
34
+ "data": {
35
+ "generate": "rainy",
36
+ "matcher": {
37
+ "json_class": "Regexp",
38
+ "o": 0,
39
+ "s": "rain"
40
+ }
41
+ }
42
+ }
43
+ }
44
+ },
45
+ "provider_state": "the weather is sunny"
46
+ }
47
+ ]
48
+ }
@@ -2,9 +2,12 @@
2
2
  "consumer": {
3
3
  "name": "an unknown consumer"
4
4
  },
5
+ "provider": {
6
+ "name": "an unknown provider"
7
+ },
5
8
  "interactions": [
6
9
  {
7
- "description": "A test request",
10
+ "description": "a test request",
8
11
  "request": {
9
12
  "method": "get",
10
13
  "path": "/weather",
@@ -13,10 +16,46 @@
13
16
  "response": {
14
17
  "status": 200,
15
18
  "headers" : {"Content-type": "application/json"},
19
+ "body": {"message" : "this is not the weather you are looking for", "array": [{"foo": "bar"}], "somethingElse" : {"blah" : {"nested" : "that is missing"} }}
20
+
21
+ },
22
+ "provider_state": "the weather is cloudy"
23
+ },{
24
+ "description": "another test request",
25
+ "request": {
26
+ "method": "get",
27
+ "path": "/weather",
28
+ "query": ""
29
+ },
30
+ "response": {
31
+ "status": 200,
32
+ "headers" : {
33
+ "Content-type": {
34
+ "json_class": "Pact::Term",
35
+ "data": {
36
+ "generate": "application/hal+json",
37
+ "matcher": {"json_class":"Regexp","o":0,"s":"hal"}
38
+ }
39
+ },
40
+ "X-Special-Header": "something"
41
+ },
16
42
  "body": {"message" : "this is not the weather you are looking for"}
17
43
 
44
+ }
45
+ },{
46
+ "description": "another test request",
47
+ "provider_state": "a missing provider state",
48
+ "request": {
49
+ "method": "get",
50
+ "path": "/weather",
51
+ "query": ""
18
52
  },
19
- "producer_state": "the weather is cloudy"
53
+ "response": {
54
+ "status": 200,
55
+ "headers" : {"Content-type": "application/json"},
56
+ "body": {"message" : "this is not the weather you are looking for"}
57
+
58
+ }
20
59
  }
21
60
  ]
22
61
  }
@@ -2,9 +2,12 @@
2
2
  "consumer": {
3
3
  "name": "some-test-consumer"
4
4
  },
5
+ "provider": {
6
+ "name": "an unknown provider"
7
+ },
5
8
  "interactions": [
6
9
  {
7
- "description": "A test request",
10
+ "description": "a test request",
8
11
  "request": {
9
12
  "method": "get",
10
13
  "path": "/weather",
@@ -15,7 +18,21 @@
15
18
  "headers" : {"Content-type": "application/json"},
16
19
  "body": {"message" : "sunny"}
17
20
  },
18
- "producer_state": "the weather is sunny"
21
+ "provider_state": "the weather is sunny"
22
+ },
23
+ {
24
+ "description": "a test request for text",
25
+ "request": {
26
+ "method": "get",
27
+ "path": "/sometext",
28
+ "query": "",
29
+ "body" : "some request text"
30
+ },
31
+ "response": {
32
+ "status": 200,
33
+ "headers" : {"Content-type": "text/plain"},
34
+ "body": "some text"
35
+ }
19
36
  }
20
37
  ]
21
38
  }
@@ -0,0 +1,23 @@
1
+ {
2
+ "consumer": {
3
+ "name": "some-test-consumer"
4
+ },
5
+ "provider": {
6
+ "name": "the test app in the pact_helper file"
7
+ },
8
+ "interactions": [
9
+ {
10
+ "description": "a test request expecting an application/json response",
11
+ "request": {
12
+ "method": "get",
13
+ "path": "/content_type_is_important",
14
+ "query": ""
15
+ },
16
+ "response": {
17
+ "status": 200,
18
+ "headers" : {"Content-type": "application/json"},
19
+ "body": {"message" : "A message"}
20
+ }
21
+ }
22
+ ]
23
+ }
data/tasks/pact-test.rake CHANGED
@@ -1,19 +1,109 @@
1
- require './lib/pact/producer/pact_spec_runner'
1
+ require 'pact/tasks/verification_task'
2
+ require 'open3'
3
+
4
+ Pact::VerificationTask.new(:stubbing) do | pact |
5
+ pact.uri './spec/support/stubbing.json', :pact_helper => './spec/support/stubbing_using_allow.rb'
6
+ end
7
+
8
+ Pact::VerificationTask.new(:options) do | pact |
9
+ pact.uri './spec/support/options.json', :pact_helper => './spec/support/options_app.rb'
10
+ end
11
+
12
+ Pact::VerificationTask.new(:pass) do | pact |
13
+ pact.uri './spec/support/test_app_pass.json'
14
+ end
15
+
16
+ Pact::VerificationTask.new(:fail) do | pact |
17
+ pact.uri './spec/support/test_app_pass.json'
18
+ pact.uri './spec/support/test_app_fail.json'
19
+ end
20
+
21
+ Pact::VerificationTask.new(:term) do | pact |
22
+ pact.uri './spec/support/term.json'
23
+ end
24
+
25
+ RSpec::Core::RakeTask.new('spec:standalone:fail') do | task |
26
+ task.pattern = FileList["spec/standalone/**/*_fail_test.rb"]
27
+ end
28
+
29
+ RSpec::Core::RakeTask.new('spec:standalone:pass') do | task |
30
+ task.pattern = FileList["spec/standalone/**/*_pass_test.rb"]
31
+ end
32
+
33
+ Pact::VerificationTask.new('test_app:pass') do | pact |
34
+ pact.uri './spec/support/test_app_pass.json'
35
+ end
36
+
37
+ Pact::VerificationTask.new('test_app:content_type') do | pact |
38
+ pact.uri './spec/support/test_app_with_right_content_type_differ.json'
39
+ end
40
+
41
+ Pact::VerificationTask.new('test_app:fail') do | pact |
42
+ pact.uri './spec/support/test_app_fail.json', pact_helper: './spec/support/pact_helper.rb'
43
+ end
44
+
45
+ task :bethtest => ['pact:tests:all','pact:tests:all:with_active_support']
2
46
 
3
47
  namespace :pact do
4
48
 
49
+ desc "All the verification tests"
50
+ task "tests:all" do
51
+ Rake::Task['pact:verify:stubbing'].execute
52
+ Rake::Task['spec:standalone:pass'].execute
53
+ Rake::Task['pact:verify'].execute
54
+ Rake::Task['pact:verify:test_app:pass'].execute
55
+ Rake::Task['pact:test:fail'].execute
56
+ Rake::Task['pact:test:pactfile'].execute
57
+ Rake::Task['pact:verify:test_app:content_type'].execute
58
+ end
59
+
60
+ desc "All the verification tests with active support loaded"
61
+ task 'tests:all:with_active_support' => :set_active_support_on do
62
+ Rake::Task['pact:tests:all'].execute
63
+ end
64
+
65
+ desc "Ensure pact file is written"
66
+ task 'test:pactfile' do
67
+ pact_path = './spec/pacts/standalone_consumer-standalone_provider.json'
68
+ FileUtils.rm_rf pact_path
69
+ Rake::Task['spec:standalone:pass'].execute
70
+ fail "Did not find expected pact file at #{pact_path}" unless File.exist?(pact_path)
71
+ end
72
+
5
73
  desc 'Runs pact tests against a sample application, testing failure and success.'
6
- task :tests do
7
- puts "Running task pact:tests"
74
+ task 'test:fail' do
75
+
76
+ require 'open3'
77
+
78
+ silent = true
8
79
  # Run these specs silently, otherwise expected failures will be written to stdout and look like unexpected failures.
80
+ #Pact.configuration.output_stream = StringIO.new if silent
9
81
 
10
- result = Pact::Producer::PactSpecRunner.run([{ uri: './spec/support/test_app_pass.json', support_file: './spec/support/pact_rake_support.rb', consumer: 'some-test-consumer' }], silent: true)
11
- fail 'Expected pact to pass' unless (result == 0)
82
+ expect_to_fail "bundle exec rake pact:verify:test_app:fail", with: [/Could not find one or more provider states/]
83
+ expect_to_fail "bundle exec rake spec:standalone:fail", with: [/Actual interactions do not match expected interactions/]
84
+ expect_to_fail "bundle exec rake pact:verify:term", with: [%r{"Content-type" with value /text/}]
85
+ end
12
86
 
13
- result = Pact::Producer::PactSpecRunner.run([{ uri: './spec/support/test_app_fail.json', support_file: './spec/support/pact_rake_support.rb' }], silent: true)
14
- fail 'Expected pact to fail' if (result == 0)
87
+ def expect_to_fail command, options = {}
88
+ success = execute_command command, options
89
+ fail "Expected '#{command}' to fail" if success
90
+ end
91
+
92
+ def execute_command command, options
93
+ result = nil
94
+ Open3.popen3(command) {|stdin, stdout, stderr, wait_thr|
95
+ result = wait_thr.value
96
+ ensure_patterns_present(command, options, stdout, stderr) if options[:with]
97
+ }
98
+ result.success?
99
+ end
15
100
 
16
- puts "Task pact:tests completed succesfully."
101
+ def ensure_patterns_present command, options, stdout, stderr
102
+ require 'term/ansicolor'
103
+ output = stdout.read + stderr.read
104
+ options[:with].each do | pattern |
105
+ raise (::Term::ANSIColor.red("Could not find #{pattern.inspect} in output of #{command}") + "\n\n#{output}") unless output =~ pattern
106
+ end
17
107
  end
18
108
 
19
109
  end