pact 1.67.5 → 2.0.1

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 (240) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -0
  3. data/lib/pact/configuration.rb +21 -0
  4. data/lib/pact/consumer/grpc_interaction_builder.rb +192 -0
  5. data/lib/pact/consumer/http_interaction_builder.rb +160 -0
  6. data/lib/pact/consumer/interaction_contents.rb +62 -0
  7. data/lib/pact/consumer/message_interaction_builder.rb +286 -0
  8. data/lib/pact/consumer/mock_server.rb +106 -0
  9. data/lib/pact/consumer/pact_config/base.rb +22 -0
  10. data/lib/pact/consumer/pact_config/grpc.rb +24 -0
  11. data/lib/pact/consumer/pact_config/http.rb +53 -0
  12. data/lib/pact/consumer/pact_config/message.rb +15 -0
  13. data/lib/pact/consumer/pact_config/plugin_async_message.rb +24 -0
  14. data/lib/pact/consumer/pact_config/plugin_http.rb +24 -0
  15. data/lib/pact/consumer/pact_config/plugin_sync_message.rb +24 -0
  16. data/lib/pact/consumer/pact_config.rb +28 -0
  17. data/lib/pact/consumer/plugin_async_message_interaction_builder.rb +169 -0
  18. data/lib/pact/consumer/plugin_http_interaction_builder.rb +199 -0
  19. data/lib/pact/consumer/plugin_sync_message_interaction_builder.rb +178 -0
  20. data/lib/pact/consumer.rb +6 -7
  21. data/lib/pact/generators/base.rb +285 -0
  22. data/lib/pact/generators.rb +47 -0
  23. data/lib/pact/matchers/base.rb +72 -0
  24. data/lib/pact/matchers/v1/equality.rb +17 -0
  25. data/lib/pact/matchers/v2/regex.rb +26 -0
  26. data/lib/pact/matchers/v2/type.rb +18 -0
  27. data/lib/pact/matchers/v3/boolean.rb +18 -0
  28. data/lib/pact/matchers/v3/content_type.rb +30 -0
  29. data/lib/pact/matchers/v3/date.rb +22 -0
  30. data/lib/pact/matchers/v3/date_time.rb +22 -0
  31. data/lib/pact/matchers/v3/decimal.rb +18 -0
  32. data/lib/pact/matchers/v3/each.rb +46 -0
  33. data/lib/pact/matchers/v3/include.rb +18 -0
  34. data/lib/pact/matchers/v3/integer.rb +18 -0
  35. data/lib/pact/matchers/v3/null.rb +13 -0
  36. data/lib/pact/matchers/v3/number.rb +18 -0
  37. data/lib/pact/matchers/v3/semver.rb +22 -0
  38. data/lib/pact/matchers/v3/time.rb +22 -0
  39. data/lib/pact/matchers/v3/values.rb +13 -0
  40. data/lib/pact/matchers/v4/each_key.rb +34 -0
  41. data/lib/pact/matchers/v4/each_key_value.rb +38 -0
  42. data/lib/pact/matchers/v4/each_value.rb +40 -0
  43. data/lib/pact/matchers/v4/not_empty.rb +22 -0
  44. data/lib/pact/matchers/v4/status_code.rb +15 -0
  45. data/lib/pact/matchers.rb +108 -0
  46. data/lib/pact/native/blocking_verifier.rb +15 -0
  47. data/lib/pact/native/logger.rb +24 -0
  48. data/lib/pact/provider/async_message_verifier.rb +29 -0
  49. data/lib/pact/provider/base_verifier.rb +259 -0
  50. data/lib/pact/provider/grpc_verifier.rb +40 -0
  51. data/lib/pact/provider/gruf_server.rb +73 -0
  52. data/lib/pact/provider/http_server.rb +77 -0
  53. data/lib/pact/provider/http_verifier.rb +45 -0
  54. data/lib/pact/provider/message_provider_servlet.rb +77 -0
  55. data/lib/pact/provider/mixed_verifier.rb +21 -0
  56. data/lib/pact/provider/pact_broker_proxy.rb +62 -0
  57. data/lib/pact/provider/pact_broker_proxy_runner.rb +78 -0
  58. data/lib/pact/provider/pact_config/async.rb +28 -0
  59. data/lib/pact/provider/pact_config/base.rb +101 -0
  60. data/lib/pact/provider/pact_config/grpc.rb +24 -0
  61. data/lib/pact/provider/pact_config/http.rb +25 -0
  62. data/lib/pact/provider/pact_config/mixed.rb +38 -0
  63. data/lib/pact/provider/pact_config.rb +24 -0
  64. data/lib/pact/provider/provider_server_runner.rb +90 -0
  65. data/lib/pact/provider/provider_state_configuration.rb +32 -0
  66. data/lib/pact/provider/provider_state_servlet.rb +84 -0
  67. data/lib/pact/provider.rb +6 -3
  68. data/lib/pact/railtie.rb +11 -0
  69. data/lib/pact/{v2/rspec → rspec}/support/pact_consumer_helpers.rb +8 -8
  70. data/lib/pact/{v2/rspec → rspec}/support/pact_provider_helpers.rb +25 -24
  71. data/lib/pact/{v2/rspec → rspec}/support/webmock/webmock_helpers.rb +1 -1
  72. data/lib/pact/{v2/rspec.rb → rspec.rb} +6 -5
  73. data/lib/pact/support/core_ext.rb +93 -0
  74. data/lib/pact/tasks/pact.rake +13 -0
  75. data/lib/pact/version.rb +1 -1
  76. data/lib/pact.rb +52 -11
  77. data/pact.gemspec +47 -64
  78. metadata +146 -404
  79. data/lib/pact/cli/generate_pact_docs.rb +0 -4
  80. data/lib/pact/cli/run_pact_verification.rb +0 -99
  81. data/lib/pact/cli/spec_criteria.rb +0 -26
  82. data/lib/pact/cli.rb +0 -45
  83. data/lib/pact/consumer/configuration/configuration_extensions.rb +0 -90
  84. data/lib/pact/consumer/configuration/dsl.rb +0 -11
  85. data/lib/pact/consumer/configuration/mock_service.rb +0 -112
  86. data/lib/pact/consumer/configuration/service_consumer.rb +0 -51
  87. data/lib/pact/consumer/configuration/service_provider.rb +0 -40
  88. data/lib/pact/consumer/configuration.rb +0 -10
  89. data/lib/pact/consumer/consumer_contract_builder.rb +0 -82
  90. data/lib/pact/consumer/consumer_contract_builders.rb +0 -10
  91. data/lib/pact/consumer/interaction_builder.rb +0 -45
  92. data/lib/pact/consumer/rspec.rb +0 -35
  93. data/lib/pact/consumer/spec_hooks.rb +0 -40
  94. data/lib/pact/consumer/world.rb +0 -37
  95. data/lib/pact/doc/README.md +0 -13
  96. data/lib/pact/doc/doc_file.rb +0 -40
  97. data/lib/pact/doc/generate.rb +0 -11
  98. data/lib/pact/doc/generator.rb +0 -82
  99. data/lib/pact/doc/interaction_view_model.rb +0 -124
  100. data/lib/pact/doc/markdown/consumer_contract_renderer.rb +0 -68
  101. data/lib/pact/doc/markdown/generator.rb +0 -26
  102. data/lib/pact/doc/markdown/index_renderer.rb +0 -43
  103. data/lib/pact/doc/markdown/interaction.erb +0 -14
  104. data/lib/pact/doc/markdown/interaction_renderer.rb +0 -43
  105. data/lib/pact/doc/sort_interactions.rb +0 -16
  106. data/lib/pact/hal/authorization_header_redactor.rb +0 -32
  107. data/lib/pact/hal/entity.rb +0 -110
  108. data/lib/pact/hal/http_client.rb +0 -146
  109. data/lib/pact/hal/link.rb +0 -112
  110. data/lib/pact/hal/non_json_entity.rb +0 -28
  111. data/lib/pact/hash_refinements.rb +0 -17
  112. data/lib/pact/pact_broker/fetch_pact_uris_for_verification.rb +0 -112
  113. data/lib/pact/pact_broker/fetch_pacts.rb +0 -103
  114. data/lib/pact/pact_broker/notices.rb +0 -34
  115. data/lib/pact/pact_broker/pact_selection_description.rb +0 -66
  116. data/lib/pact/pact_broker.rb +0 -25
  117. data/lib/pact/project_root.rb +0 -7
  118. data/lib/pact/provider/configuration/configuration_extension.rb +0 -69
  119. data/lib/pact/provider/configuration/dsl.rb +0 -18
  120. data/lib/pact/provider/configuration/message_provider_dsl.rb +0 -63
  121. data/lib/pact/provider/configuration/pact_verification.rb +0 -48
  122. data/lib/pact/provider/configuration/pact_verification_from_broker.rb +0 -126
  123. data/lib/pact/provider/configuration/service_provider_config.rb +0 -32
  124. data/lib/pact/provider/configuration/service_provider_dsl.rb +0 -107
  125. data/lib/pact/provider/configuration.rb +0 -7
  126. data/lib/pact/provider/context.rb +0 -0
  127. data/lib/pact/provider/help/console_text.rb +0 -76
  128. data/lib/pact/provider/help/content.rb +0 -38
  129. data/lib/pact/provider/help/pact_diff.rb +0 -43
  130. data/lib/pact/provider/help/prompt_text.rb +0 -49
  131. data/lib/pact/provider/help/write.rb +0 -56
  132. data/lib/pact/provider/matchers/messages.rb +0 -66
  133. data/lib/pact/provider/pact_helper_locator.rb +0 -24
  134. data/lib/pact/provider/pact_source.rb +0 -40
  135. data/lib/pact/provider/pact_spec_runner.rb +0 -188
  136. data/lib/pact/provider/pact_uri.rb +0 -55
  137. data/lib/pact/provider/pact_verification.rb +0 -17
  138. data/lib/pact/provider/print_missing_provider_states.rb +0 -35
  139. data/lib/pact/provider/request.rb +0 -90
  140. data/lib/pact/provider/rspec/backtrace_formatter.rb +0 -43
  141. data/lib/pact/provider/rspec/calculate_exit_code.rb +0 -18
  142. data/lib/pact/provider/rspec/custom_options_file +0 -0
  143. data/lib/pact/provider/rspec/formatter_rspec_2.rb +0 -76
  144. data/lib/pact/provider/rspec/formatter_rspec_3.rb +0 -195
  145. data/lib/pact/provider/rspec/json_formatter.rb +0 -100
  146. data/lib/pact/provider/rspec/matchers.rb +0 -80
  147. data/lib/pact/provider/rspec/pact_broker_formatter.rb +0 -76
  148. data/lib/pact/provider/rspec.rb +0 -234
  149. data/lib/pact/provider/state/provider_state.rb +0 -180
  150. data/lib/pact/provider/state/provider_state_configured_modules.rb +0 -15
  151. data/lib/pact/provider/state/provider_state_manager.rb +0 -42
  152. data/lib/pact/provider/state/provider_state_proxy.rb +0 -39
  153. data/lib/pact/provider/state/set_up.rb +0 -13
  154. data/lib/pact/provider/state/tear_down.rb +0 -13
  155. data/lib/pact/provider/test_methods.rb +0 -77
  156. data/lib/pact/provider/verification_report.rb +0 -36
  157. data/lib/pact/provider/verification_results/create.rb +0 -88
  158. data/lib/pact/provider/verification_results/publish.rb +0 -143
  159. data/lib/pact/provider/verification_results/publish_all.rb +0 -50
  160. data/lib/pact/provider/verification_results/verification_result.rb +0 -40
  161. data/lib/pact/provider/world.rb +0 -50
  162. data/lib/pact/retry.rb +0 -37
  163. data/lib/pact/tasks/task_helper.rb +0 -62
  164. data/lib/pact/tasks/verification_task.rb +0 -95
  165. data/lib/pact/tasks.rb +0 -2
  166. data/lib/pact/templates/help.erb +0 -22
  167. data/lib/pact/templates/provider_state.erb +0 -14
  168. data/lib/pact/utils/metrics.rb +0 -100
  169. data/lib/pact/utils/string.rb +0 -35
  170. data/lib/pact/v2/configuration.rb +0 -23
  171. data/lib/pact/v2/consumer/grpc_interaction_builder.rb +0 -194
  172. data/lib/pact/v2/consumer/http_interaction_builder.rb +0 -162
  173. data/lib/pact/v2/consumer/interaction_contents.rb +0 -62
  174. data/lib/pact/v2/consumer/message_interaction_builder.rb +0 -288
  175. data/lib/pact/v2/consumer/mock_server.rb +0 -108
  176. data/lib/pact/v2/consumer/pact_config/base.rb +0 -24
  177. data/lib/pact/v2/consumer/pact_config/grpc.rb +0 -26
  178. data/lib/pact/v2/consumer/pact_config/http.rb +0 -55
  179. data/lib/pact/v2/consumer/pact_config/message.rb +0 -17
  180. data/lib/pact/v2/consumer/pact_config/plugin_async_message.rb +0 -26
  181. data/lib/pact/v2/consumer/pact_config/plugin_http.rb +0 -26
  182. data/lib/pact/v2/consumer/pact_config/plugin_sync_message.rb +0 -26
  183. data/lib/pact/v2/consumer/pact_config.rb +0 -30
  184. data/lib/pact/v2/consumer/plugin_async_message_interaction_builder.rb +0 -171
  185. data/lib/pact/v2/consumer/plugin_http_interaction_builder.rb +0 -201
  186. data/lib/pact/v2/consumer/plugin_sync_message_interaction_builder.rb +0 -180
  187. data/lib/pact/v2/consumer.rb +0 -8
  188. data/lib/pact/v2/generators/base.rb +0 -287
  189. data/lib/pact/v2/generators.rb +0 -49
  190. data/lib/pact/v2/matchers/base.rb +0 -74
  191. data/lib/pact/v2/matchers/v1/equality.rb +0 -19
  192. data/lib/pact/v2/matchers/v2/regex.rb +0 -19
  193. data/lib/pact/v2/matchers/v2/type.rb +0 -17
  194. data/lib/pact/v2/matchers/v3/boolean.rb +0 -17
  195. data/lib/pact/v2/matchers/v3/content_type.rb +0 -32
  196. data/lib/pact/v2/matchers/v3/date.rb +0 -18
  197. data/lib/pact/v2/matchers/v3/date_time.rb +0 -18
  198. data/lib/pact/v2/matchers/v3/decimal.rb +0 -17
  199. data/lib/pact/v2/matchers/v3/each.rb +0 -42
  200. data/lib/pact/v2/matchers/v3/include.rb +0 -17
  201. data/lib/pact/v2/matchers/v3/integer.rb +0 -17
  202. data/lib/pact/v2/matchers/v3/null.rb +0 -16
  203. data/lib/pact/v2/matchers/v3/number.rb +0 -17
  204. data/lib/pact/v2/matchers/v3/semver.rb +0 -23
  205. data/lib/pact/v2/matchers/v3/time.rb +0 -18
  206. data/lib/pact/v2/matchers/v3/values.rb +0 -16
  207. data/lib/pact/v2/matchers/v4/each_key.rb +0 -26
  208. data/lib/pact/v2/matchers/v4/each_key_value.rb +0 -32
  209. data/lib/pact/v2/matchers/v4/each_value.rb +0 -33
  210. data/lib/pact/v2/matchers/v4/not_empty.rb +0 -24
  211. data/lib/pact/v2/matchers/v4/status_code.rb +0 -17
  212. data/lib/pact/v2/matchers.rb +0 -110
  213. data/lib/pact/v2/native/blocking_verifier.rb +0 -17
  214. data/lib/pact/v2/native/logger.rb +0 -25
  215. data/lib/pact/v2/provider/async_message_verifier.rb +0 -28
  216. data/lib/pact/v2/provider/base_verifier.rb +0 -242
  217. data/lib/pact/v2/provider/grpc_verifier.rb +0 -38
  218. data/lib/pact/v2/provider/gruf_server.rb +0 -75
  219. data/lib/pact/v2/provider/http_server.rb +0 -79
  220. data/lib/pact/v2/provider/http_verifier.rb +0 -43
  221. data/lib/pact/v2/provider/message_provider_servlet.rb +0 -79
  222. data/lib/pact/v2/provider/mixed_verifier.rb +0 -22
  223. data/lib/pact/v2/provider/pact_broker_proxy.rb +0 -66
  224. data/lib/pact/v2/provider/pact_broker_proxy_runner.rb +0 -80
  225. data/lib/pact/v2/provider/pact_config/async.rb +0 -29
  226. data/lib/pact/v2/provider/pact_config/base.rb +0 -103
  227. data/lib/pact/v2/provider/pact_config/grpc.rb +0 -26
  228. data/lib/pact/v2/provider/pact_config/http.rb +0 -27
  229. data/lib/pact/v2/provider/pact_config/mixed.rb +0 -40
  230. data/lib/pact/v2/provider/pact_config.rb +0 -26
  231. data/lib/pact/v2/provider/provider_server_runner.rb +0 -92
  232. data/lib/pact/v2/provider/provider_state_configuration.rb +0 -32
  233. data/lib/pact/v2/provider/provider_state_servlet.rb +0 -86
  234. data/lib/pact/v2/provider.rb +0 -8
  235. data/lib/pact/v2/railtie.rb +0 -13
  236. data/lib/pact/v2/tasks/pact.rake +0 -13
  237. data/lib/pact/v2.rb +0 -71
  238. data/lib/tasks/pact.rake +0 -34
  239. /data/lib/pact/{v2/rspec → rspec}/support/pact_message_helpers.rb +0 -0
  240. /data/lib/pact/{v2/rspec → rspec}/support/waterdrop/pact_waterdrop_client.rb +0 -0
@@ -0,0 +1,38 @@
1
+ # # frozen_string_literal: true
2
+
3
+ module Pact
4
+ module Provider
5
+ module PactConfig
6
+ # Mixed config allows composing one of each: async, grpc, http
7
+ class Mixed < Base
8
+ attr_reader :async_config, :grpc_config, :http_config
9
+
10
+ def initialize(provider_name:, opts: {})
11
+ super
12
+ @provider_setup_server = ProviderServerRunner.new(port: @provider_setup_port, logger: @logger)
13
+ if @broker_url.present?
14
+ @pact_proxy_server = PactBrokerProxyRunner.new(
15
+ port: @pact_proxy_port,
16
+ pact_broker_host: @broker_url,
17
+ pact_broker_user: @broker_username,
18
+ pact_broker_password: @broker_password,
19
+ pact_broker_token: @broker_token,
20
+ logger: @logger
21
+ )
22
+ end
23
+ @http_config = opts[:http] ? Http.new(provider_name: provider_name, opts: opts[:http].merge(provider_setup_server: provider_setup_server, pact_proxy_server: @pact_proxy_server)) : nil
24
+ @grpc_config = opts[:grpc] ? Grpc.new(provider_name: provider_name, opts: opts[:grpc].merge(provider_setup_server: provider_setup_server, pact_proxy_server: @pact_proxy_server)) : nil
25
+ @async_config = opts[:async] ? Async.new(provider_name: provider_name, opts: opts[:async].merge(provider_setup_server: provider_setup_server, pact_proxy_server: @pact_proxy_server)) : nil
26
+ end
27
+
28
+ def configs
29
+ [@async_config, @grpc_config, @http_config].compact
30
+ end
31
+
32
+ def start_servers
33
+ end
34
+
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ # require_relative "pact_config/grpc"
4
+
5
+ module Pact
6
+ module Provider
7
+ module PactConfig
8
+ def self.new(transport_type, provider_name:, opts: {})
9
+ case transport_type
10
+ when :http
11
+ Http.new(provider_name: provider_name, opts: opts)
12
+ when :grpc
13
+ Grpc.new(provider_name: provider_name, opts: opts)
14
+ when :async
15
+ Async.new(provider_name: provider_name, opts: opts)
16
+ when :mixed
17
+ Mixed.new(provider_name: provider_name, opts: opts)
18
+ else
19
+ raise ArgumentError, "unknown transport_type: #{transport_type}"
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webrick"
4
+
5
+ module Pact
6
+ module Provider
7
+ class ProviderServerRunner
8
+ attr_reader :logger
9
+
10
+ SETUP_PROVIDER_STATE_PATH = "/setup-provider"
11
+ VERIFY_MESSAGE_PATH = "/verify-message"
12
+
13
+ def initialize(port: 9001, host: "127.0.0.1", logger: nil)
14
+ @host = host
15
+ @port = port
16
+ @provider_setup_states = {}
17
+ @provider_teardown_states = {}
18
+ @logger = logger || Logger.new($stdout)
19
+
20
+ @state_servlet = ProviderStateServlet.new(logger: @logger)
21
+ @message_servlet = MessageProviderServlet.new(logger: @logger)
22
+ @thread = nil
23
+ end
24
+
25
+ def state_setup_url
26
+ "http://#{@host}:#{@port}#{SETUP_PROVIDER_STATE_PATH}"
27
+ end
28
+
29
+ def message_setup_url
30
+ "http://#{@host}:#{@port}#{VERIFY_MESSAGE_PATH}"
31
+ end
32
+
33
+ def start
34
+ raise "server already running, stop server before starting new one" if @thread
35
+
36
+ @server = WEBrick::HTTPServer.new(
37
+ { BindAddress: @host, Port: @port, Logger: @logger, AccessLog: [] },
38
+ WEBrick::Config::HTTP
39
+ )
40
+ @server.mount(SETUP_PROVIDER_STATE_PATH, @state_servlet)
41
+ @server.mount(VERIFY_MESSAGE_PATH, @message_servlet)
42
+
43
+ @thread = Thread.new do
44
+ @logger.debug "starting provider setup server"
45
+ @server.start
46
+ end
47
+ end
48
+
49
+ def stop
50
+ @logger.info("stopping provider setup server")
51
+
52
+ @server&.shutdown
53
+ @thread&.join
54
+
55
+ @logger.info("provider setup server stopped")
56
+ end
57
+
58
+ def run
59
+ start
60
+
61
+ yield
62
+ rescue => e
63
+ logger.fatal("FATAL ERROR: #{e.message} #{e.backtrace.join("\n")}")
64
+ raise
65
+ ensure
66
+ stop
67
+ end
68
+
69
+ def add_message_handler(state_name, &block)
70
+ @message_servlet.add_message_handler(state_name, &block)
71
+ end
72
+
73
+ def add_setup_state(state_name, use_before_setup_hook = true, &block)
74
+ @state_servlet.add_setup_state(state_name, use_before_setup_hook, &block)
75
+ end
76
+
77
+ def add_teardown_state(state_name, use_after_teardown_hook = true, &block)
78
+ @state_servlet.add_teardown_state(state_name, use_after_teardown_hook, &block)
79
+ end
80
+
81
+ def set_before_setup_hook(&block)
82
+ @state_servlet.before_setup(&block)
83
+ end
84
+
85
+ def set_after_teardown_hook(&block)
86
+ @state_servlet.after_teardown(&block)
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pact
4
+ module Provider
5
+ class ProviderStateConfiguration
6
+ attr_reader :name, :opts, :setup_proc, :teardown_proc
7
+
8
+ class ProviderStateConfigurationError < ::Pact::Error; end
9
+
10
+ def initialize(name, opts: {})
11
+ @name = name
12
+ @opts = opts
13
+ @setup_proc = nil
14
+ @teardown_proc = nil
15
+ end
16
+
17
+ def set_up(&block)
18
+ @setup_proc = block
19
+ end
20
+
21
+ def tear_down(&block)
22
+ @teardown_proc = block
23
+ end
24
+
25
+ def validate!
26
+ return if @setup_proc || @teardown_proc
27
+
28
+ raise ProviderStateConfigurationError.new("no hooks configured for state #{@name}: \"provider_state\" declaration only needed if setup/teardown hooks are used for that state. Please add hooks or remove \"provider_state\" declaration") # rubocop:disable Layout/LineLength
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webrick"
4
+
5
+ module Pact
6
+ module Provider
7
+ class ProviderStateServlet < WEBrick::HTTPServlet::ProcHandler
8
+ attr_reader :logger
9
+
10
+ def initialize(logger: nil)
11
+ super(build_proc)
12
+
13
+ @logger = logger || Logger.new($stdout)
14
+
15
+ @provider_setup_states = {}
16
+ @provider_teardown_states = {}
17
+
18
+ @before_setup_hook_proc = nil
19
+ @after_teardown_hook_proc = nil
20
+
21
+ @global_setup_hook = ::Pact.configuration.before_provider_state_proc
22
+ @global_teardown_hook = ::Pact.configuration.after_provider_state_proc
23
+ end
24
+
25
+ def add_setup_state(name, use_before_setup_hook, &block)
26
+ raise "provider state #{name} already configured" if @provider_setup_states[name].present?
27
+
28
+ @provider_setup_states[name] = {proc: block, use_hooks: use_before_setup_hook}
29
+ end
30
+
31
+ def add_teardown_state(name, use_after_teardown_hook, &block)
32
+ raise "provider state #{name} already configured" if @provider_teardown_states[name].present?
33
+
34
+ @provider_teardown_states[name] = {proc: block, use_hooks: use_after_teardown_hook}
35
+ end
36
+
37
+ def before_setup(&block)
38
+ @before_setup_hook_proc = block
39
+ end
40
+
41
+ def after_teardown(&block)
42
+ @after_teardown_hook_proc = block
43
+ end
44
+
45
+ private
46
+
47
+ def call_setup(state_name, state_data)
48
+ logger.debug "call_setup #{state_name} with #{state_data}"
49
+ @global_setup_hook&.call
50
+ @before_setup_hook_proc&.call(state_name, state_data) if @provider_setup_states.dig(state_name, :use_hooks)
51
+ @provider_setup_states.dig(state_name, :proc)&.call(state_data)
52
+ end
53
+
54
+ def call_teardown(state_name, state_data)
55
+ logger.debug "call_teardown #{state_name} with #{state_data}"
56
+ @provider_teardown_states.dig(state_name, :proc)&.call(state_data)
57
+ @after_teardown_hook_proc&.call(state_name, state_data) if @provider_setup_states.dig(state_name, :use_hooks)
58
+ @global_teardown_hook&.call
59
+ end
60
+
61
+ def build_proc
62
+ proc do |request, response|
63
+ # {"action" => "setup", "params" => {"order_uuid" => "mxfcpcsfUOHO"},"state" => "order exists and can be saved"}
64
+ # {"action"=> "teardown", "params" => {"order_uuid" => "mxfcpcsfUOHO"}, "state" => "order exists and can be saved"}
65
+ data = JSON.parse(request.body)
66
+
67
+ action = data["action"]
68
+ state_name = data["state"]
69
+ state_data = data["params"]
70
+
71
+ logger.warn("unknown callback state action: #{action}") if action.blank?
72
+
73
+ call_setup(state_name, state_data) if action == "setup"
74
+ call_teardown(state_name, state_data) if action == "teardown"
75
+
76
+ response.status = 200
77
+ rescue JSON::ParserError => ex
78
+ logger.error("cannot parse request: #{ex.message}")
79
+ response.status = 500
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
data/lib/pact/provider.rb CHANGED
@@ -1,3 +1,6 @@
1
- require 'pact/configuration'
2
- require 'pact/provider/configuration'
3
- require 'pact/provider/world'
1
+ # frozen_string_literal: true
2
+
3
+ module Pact
4
+ module Provider
5
+ end
6
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/railtie'
4
+
5
+ module Pact
6
+ class Railtie < Rails::Railtie
7
+ rake_tasks do
8
+ load 'pact/tasks/pact.rake'
9
+ end
10
+ end
11
+ end
@@ -3,9 +3,9 @@
3
3
  require_relative "pact_message_helpers"
4
4
  require "json"
5
5
 
6
- module PactV2ConsumerDsl
7
- include Pact::V2::Matchers
8
- include Pact::V2::Generators
6
+ module PactConsumerDsl
7
+ include Pact::Matchers
8
+ include Pact::Generators
9
9
 
10
10
  module ClassMethods
11
11
  def has_http_pact_between(consumer, provider, opts: {})
@@ -39,7 +39,7 @@ module PactV2ConsumerDsl
39
39
 
40
40
  # rubocop:disable RSpec/BeforeAfterAll
41
41
  before(:context) do
42
- @_pact_config = Pact::V2::Consumer::PactConfig.new(transport_type, consumer_name: consumer, provider_name: provider, opts: opts)
42
+ @_pact_config = Pact::Consumer::PactConfig.new(transport_type, consumer_name: consumer, provider_name: provider, opts: opts)
43
43
  end
44
44
  # rubocop:enable RSpec/BeforeAfterAll
45
45
  end
@@ -59,7 +59,7 @@ module PactV2ConsumerDsl
59
59
 
60
60
  def execute_http_pact
61
61
  raise InteractionBuilderError.new("interaction is designed to be used one-time only") if defined?(@used)
62
- mock_server = Pact::V2::Consumer::MockServer.create_for_http!(
62
+ mock_server = Pact::Consumer::MockServer.create_for_http!(
63
63
  pact: pact_config.pact_handle, host: pact_config.mock_host, port: pact_config.mock_port
64
64
  )
65
65
 
@@ -70,7 +70,7 @@ module PactV2ConsumerDsl
70
70
  mock_server.write_pacts!(pact_config.pact_dir)
71
71
  else
72
72
  msg = mismatches_error_msg(mock_server)
73
- raise Pact::V2::Consumer::HttpInteractionBuilder::InteractionMismatchesError.new(msg)
73
+ raise Pact::Consumer::HttpInteractionBuilder::InteractionMismatchesError.new(msg)
74
74
  end
75
75
  @used = true
76
76
  mock_server&.cleanup
@@ -88,6 +88,6 @@ module PactV2ConsumerDsl
88
88
  end
89
89
 
90
90
  RSpec.configure do |config|
91
- config.include PactV2ConsumerDsl, pact_entity: :consumer
92
- config.extend PactV2ConsumerDsl::ClassMethods, pact_entity: :consumer
91
+ config.include PactConsumerDsl, pact_entity: :consumer
92
+ config.extend PactConsumerDsl::ClassMethods, pact_entity: :consumer
93
93
  end
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "pact_message_helpers"
4
- require_relative "webmock/webmock_helpers"
3
+ require_relative 'pact_message_helpers'
4
+ require_relative 'webmock/webmock_helpers'
5
5
 
6
- module PactV2ProducerDsl
6
+ module PactProducerDsl
7
7
  module ClassMethods
8
- PACT_PROVIDER_NOT_DECLARED_MESSAGE = "http_pact_provider or grpc_pact_provider should be declared first"
8
+ PACT_PROVIDER_NOT_DECLARED_MESSAGE = 'http_pact_provider or grpc_pact_provider should be declared first'
9
9
 
10
10
  def http_pact_provider(provider, opts: {})
11
11
  _pact_provider(:http, provider, opts: opts)
@@ -26,22 +26,21 @@ module PactV2ProducerDsl
26
26
  def execute_mixed_pact_provider(transport_type, provider, opts: {})
27
27
  raise "#{transport_type}_pact_provider is designed to be used with RSpec" unless defined?(::RSpec)
28
28
  raise "#{transport_type}_pact_provider has to be declared at the top level of a suite" unless top_level?
29
- raise "mixed_pact_provider is designed to be run once per provider so cannot be declared more than once" if defined?(@_pact_config)
29
+ if defined?(@_pact_config)
30
+ raise 'mixed_pact_provider is designed to be run once per provider so cannot be declared more than once'
31
+ end
30
32
 
31
- pact_config_instance = Pact::V2::Provider::PactConfig.new(transport_type, provider_name: provider, opts: opts)
33
+ pact_config_instance = Pact::Provider::PactConfig.new(transport_type, provider_name: provider, opts: opts)
32
34
  instance_variable_set(:@_pact_config, pact_config_instance)
33
35
 
34
- # rubocop:disable RSpec/BeforeAfterAll
35
36
  before(:context) do
36
37
  # rspec allows only context ivars in specs and ignores the rest
37
38
  # so we use block-as-a-closure feature to save pact_config ivar reference and make it available for descendants
38
39
  @_pact_config = pact_config_instance
39
40
  end
40
- # rubocop:enable RSpec/BeforeAfterAll
41
-
42
41
  it "verifies mixed interactions with provider #{provider}" do
43
42
  pact_config.start_servers
44
- # todo: call any available verifier, or exit if none specified
43
+ # TODO: call any available verifier, or exit if none specified
45
44
  pact_config.http_config.new_verifier(@_pact_config).verify!
46
45
  end
47
46
  end
@@ -49,19 +48,18 @@ module PactV2ProducerDsl
49
48
  def _pact_provider(transport_type, provider, opts: {})
50
49
  raise "#{transport_type}_pact_provider is designed to be used with RSpec" unless defined?(::RSpec)
51
50
  raise "#{transport_type}_pact_provider has to be declared at the top level of a suite" unless top_level?
52
- raise "*_pact_provider is designed to be run once per provider so cannot be declared more than once" if defined?(@_pact_config)
51
+ if defined?(@_pact_config)
52
+ raise '*_pact_provider is designed to be run once per provider so cannot be declared more than once'
53
+ end
53
54
 
54
- pact_config_instance = Pact::V2::Provider::PactConfig.new(transport_type, provider_name: provider, opts: opts)
55
+ pact_config_instance = Pact::Provider::PactConfig.new(transport_type, provider_name: provider, opts: opts)
55
56
  instance_variable_set(:@_pact_config, pact_config_instance)
56
57
 
57
- # rubocop:disable RSpec/BeforeAfterAll
58
58
  before(:context) do
59
59
  # rspec allows only context ivars in specs and ignores the rest
60
60
  # so we use block-as-a-closure feature to save pact_config ivar reference and make it available for descendants
61
61
  @_pact_config = pact_config_instance
62
62
  end
63
- # rubocop:enable RSpec/BeforeAfterAll
64
-
65
63
  it "verifies interactions with provider #{provider}" do
66
64
  pact_config.new_verifier.verify!
67
65
  end
@@ -69,37 +67,40 @@ module PactV2ProducerDsl
69
67
 
70
68
  def before_state_setup(&block)
71
69
  raise PACT_PROVIDER_NOT_DECLARED_MESSAGE unless pact_config
70
+
72
71
  pact_config.before_setup(&block)
73
72
  end
74
73
 
75
74
  def after_state_teardown(&block)
76
75
  raise PACT_PROVIDER_NOT_DECLARED_MESSAGE unless pact_config
76
+
77
77
  pact_config.after_teardown(&block)
78
78
  end
79
79
 
80
80
  def provider_state(name, opts: {}, &block)
81
81
  raise PACT_PROVIDER_NOT_DECLARED_MESSAGE unless pact_config
82
+
82
83
  pact_config.new_provider_state(name, opts: opts, &block)
83
84
  end
84
85
 
85
86
  def handle_message(name, opts: {}, &block)
86
- async_klass = Pact::V2::Provider::PactConfig::Async
87
+ async_klass = Pact::Provider::PactConfig::Async
87
88
  if defined?(@_pact_config) &&
88
- @_pact_config.respond_to?(:async_config) &&
89
- @_pact_config.async_config.is_a?(async_klass)
89
+ @_pact_config.respond_to?(:async_config) &&
90
+ @_pact_config.async_config.is_a?(async_klass)
90
91
  @_pact_config.async_config.new_message_handler(name, opts: opts, &block)
91
92
  elsif pact_config &&
92
- pact_config.respond_to?(:async_config) &&
93
- pact_config.async_config.is_a?(async_klass)
93
+ pact_config.respond_to?(:async_config) &&
94
+ pact_config.async_config.is_a?(async_klass)
94
95
  pact_config.async_config.new_message_handler(name, opts: opts, &block)
95
96
  elsif defined?(@_pact_config) &&
96
- @_pact_config.is_a?(async_klass)
97
+ @_pact_config.is_a?(async_klass)
97
98
  @_pact_config.new_message_handler(name, opts: opts, &block)
98
99
  elsif pact_config.is_a?(async_klass)
99
100
  pact_config.new_message_handler(name, opts: opts, &block)
100
101
 
101
102
  else
102
- raise "handle_message can only be used with message_pact_provider or mixed_pact_provider with an async block"
103
+ raise 'handle_message can only be used with message_pact_provider or mixed_pact_provider with an async block'
103
104
  end
104
105
  end
105
106
 
@@ -114,8 +115,8 @@ module PactV2ProducerDsl
114
115
  end
115
116
 
116
117
  RSpec.configure do |config|
117
- config.include PactV2ProducerDsl, pact_entity: :provider
118
- config.extend PactV2ProducerDsl::ClassMethods, pact_entity: :provider
118
+ config.include PactProducerDsl, pact_entity: :provider
119
+ config.extend PactProducerDsl::ClassMethods, pact_entity: :provider
119
120
 
120
121
  config.around pact_entity: :provider do |example|
121
122
  WebmockHelpers.turned_off do
@@ -2,7 +2,7 @@
2
2
 
3
3
  module WebmockHelpers
4
4
  def self.turned_off
5
- yield unless defined?(::WebMock)
5
+ return yield unless defined?(::WebMock)
6
6
 
7
7
  allow_net_connect = WebMock::Config.instance.allow_net_connect
8
8
  allow_localhost = WebMock::Config.instance.allow_localhost
@@ -1,17 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "rspec"
4
- require_relative "rspec/support/pact_consumer_helpers"
5
- require_relative "rspec/support/pact_provider_helpers"
3
+ require 'rspec'
4
+ require 'pact'
5
+ require_relative 'rspec/support/pact_consumer_helpers'
6
+ require_relative 'rspec/support/pact_provider_helpers'
6
7
 
7
8
  RSpec.configure do |config|
8
9
  config.define_derived_metadata(file_path: %r{spec/pact/}) { |metadata| metadata[:pact] = true }
9
10
 
10
- # it's not an error: consumer tests contain `providers` subdirectory (because we're testing against different providers)
11
+ # it's not an error: consumer tests contain `providers` subdirectory (because we're testing against different providers) # rubocop:disable Layout/LineLength
11
12
  config.define_derived_metadata(file_path: %r{spec/pact/providers/}) { |metadata| metadata[:pact_entity] = :consumer }
12
13
  # for provider tests it's the same thing: we're running tests which test consumers
13
14
  config.define_derived_metadata(file_path: %r{spec/pact/consumers/}) { |metadata| metadata[:pact_entity] = :provider }
14
15
 
15
16
  # exclude pact specs from generic rspec pipeline
16
- config.filter_run_excluding :pact_v2
17
+ config.filter_run_excluding :pact
17
18
  end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Minimal active_support polyfills for blank?/present? and deep_dup.
4
+ # Each block is skipped entirely if the method is already defined
5
+ # (e.g. active_support is loaded by the host application).
6
+
7
+ unless Object.method_defined?(:blank?)
8
+ class NilClass
9
+ def blank? = true
10
+ def present? = false
11
+ end
12
+
13
+ class FalseClass
14
+ def blank? = true
15
+ def present? = false
16
+ end
17
+
18
+ class TrueClass
19
+ def blank? = false
20
+ def present? = true
21
+ end
22
+
23
+ class String
24
+ BLANK_RE = /\A[[:space:]]*\z/
25
+
26
+ def blank?
27
+ empty? || BLANK_RE.match?(self)
28
+ end
29
+
30
+ def present? = !blank?
31
+ end
32
+
33
+ class Symbol
34
+ alias_method :blank?, :empty?
35
+ def present? = !blank?
36
+ end
37
+
38
+ class Array
39
+ alias_method :blank?, :empty?
40
+ def present? = !empty?
41
+ end
42
+
43
+ class Hash
44
+ alias_method :blank?, :empty?
45
+ def present? = !empty?
46
+ end
47
+
48
+ class Object
49
+ def blank? = respond_to?(:empty?) ? !!empty? : false
50
+ def present? = !blank?
51
+
52
+ def presence
53
+ self if present?
54
+ end
55
+ end
56
+ end
57
+
58
+ unless Object.method_defined?(:deep_dup)
59
+ class Object
60
+ def deep_dup
61
+ dup
62
+ rescue TypeError
63
+ self
64
+ end
65
+ end
66
+
67
+ class Array
68
+ def deep_dup
69
+ map(&:deep_dup)
70
+ end
71
+ end
72
+
73
+ class Hash
74
+ def deep_dup
75
+ hash = dup
76
+ each_pair do |key, value|
77
+ if ::String === key || ::Symbol === key
78
+ hash[key] = value.deep_dup
79
+ else
80
+ hash.delete(key)
81
+ hash[key.deep_dup] = value.deep_dup
82
+ end
83
+ end
84
+ hash
85
+ end
86
+ end
87
+
88
+ class Module
89
+ def deep_dup
90
+ name.nil? ? super : self
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:pact).tap do |task|
6
+ task.pattern = 'spec/pact/consumers/**/*_spec.rb'
7
+ task.rspec_opts = '--require rails_helper --tag pact'
8
+ end
9
+
10
+ namespace :pact do
11
+ desc 'Verifies the pact files'
12
+ task verify: :pact
13
+ end
data/lib/pact/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  # Remember to bump pact-provider-proxy when this changes major version
2
2
  module Pact
3
- VERSION = "1.67.5"
3
+ VERSION = "2.0.1"
4
4
  end
data/lib/pact.rb CHANGED
@@ -1,12 +1,53 @@
1
- require 'pact/support'
2
- require 'pact/version'
3
- require 'pact/configuration'
4
- require 'pact/consumer'
5
- require 'pact/provider'
6
- require 'pact/consumer_contract'
7
-
8
- begin
9
- require 'pact/v2'
10
- rescue LoadError
11
- # "Please ensure that the 'pact-ffi' gem is included in your Gemfile for pact/v2 support."
1
+ # frozen_string_literal: true
2
+
3
+ require 'zeitwerk'
4
+ require 'pact/ffi'
5
+
6
+ require 'pact/railtie' if defined?(Rails::Railtie)
7
+
8
+ # Load core_ext polyfills (blank?/present?, deep_dup) before Zeitwerk eager-loads
9
+ # the rest of the gem. Each polyfill is skipped if already defined by active_support
10
+ # or any other library loaded by the host application.
11
+ require 'pact/support/core_ext'
12
+
13
+ module Pact
14
+ class Error < StandardError; end
15
+
16
+ class ImplementationRequired < Error; end
17
+
18
+ class FfiError < Error
19
+ def initialize(msg, reason, status)
20
+ super(msg)
21
+
22
+ @msg = msg
23
+ @reason = reason
24
+ @status = status
25
+ end
26
+
27
+ def message
28
+ "FFI error: reason: #{@reason}, status: #{@status}, message: #{@msg}"
29
+ end
30
+ end
31
+
32
+ def self.configure
33
+ yield configuration if block_given?
34
+ end
35
+
36
+ def self.configuration
37
+ @configuration ||= Pact::Configuration.new
38
+ end
12
39
  end
40
+
41
+ loader = Zeitwerk::Loader.new
42
+ loader.push_dir(File.join(__dir__))
43
+
44
+ loader.tag = 'pact'
45
+
46
+ loader.ignore("#{__dir__}/pact/version.rb")
47
+ loader.ignore("#{__dir__}/pact/rspec.rb")
48
+ loader.ignore("#{__dir__}/pact/rspec")
49
+ loader.ignore("#{__dir__}/pact/support/core_ext.rb")
50
+ loader.ignore("#{__dir__}/pact/railtie.rb") unless defined?(Rails::Railtie)
51
+
52
+ loader.setup
53
+ loader.eager_load