pact 1.66.2 → 1.67.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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -0
  3. data/lib/pact/v2/configuration.rb +23 -0
  4. data/lib/pact/v2/consumer/grpc_interaction_builder.rb +194 -0
  5. data/lib/pact/v2/consumer/http_interaction_builder.rb +162 -0
  6. data/lib/pact/v2/consumer/interaction_contents.rb +62 -0
  7. data/lib/pact/v2/consumer/message_interaction_builder.rb +287 -0
  8. data/lib/pact/v2/consumer/mock_server.rb +100 -0
  9. data/lib/pact/v2/consumer/pact_config/base.rb +24 -0
  10. data/lib/pact/v2/consumer/pact_config/grpc.rb +26 -0
  11. data/lib/pact/v2/consumer/pact_config/http.rb +55 -0
  12. data/lib/pact/v2/consumer/pact_config/message.rb +17 -0
  13. data/lib/pact/v2/consumer/pact_config/plugin_async_message.rb +26 -0
  14. data/lib/pact/v2/consumer/pact_config/plugin_http.rb +26 -0
  15. data/lib/pact/v2/consumer/pact_config/plugin_sync_message.rb +26 -0
  16. data/lib/pact/v2/consumer/pact_config.rb +30 -0
  17. data/lib/pact/v2/consumer/plugin_async_message_interaction_builder.rb +171 -0
  18. data/lib/pact/v2/consumer/plugin_http_interaction_builder.rb +201 -0
  19. data/lib/pact/v2/consumer/plugin_sync_message_interaction_builder.rb +180 -0
  20. data/lib/pact/v2/consumer.rb +8 -0
  21. data/lib/pact/v2/generators/base.rb +287 -0
  22. data/lib/pact/v2/generators.rb +49 -0
  23. data/lib/pact/v2/matchers/base.rb +74 -0
  24. data/lib/pact/v2/matchers/v1/equality.rb +19 -0
  25. data/lib/pact/v2/matchers/v2/regex.rb +19 -0
  26. data/lib/pact/v2/matchers/v2/type.rb +17 -0
  27. data/lib/pact/v2/matchers/v3/boolean.rb +17 -0
  28. data/lib/pact/v2/matchers/v3/content_type.rb +32 -0
  29. data/lib/pact/v2/matchers/v3/date.rb +18 -0
  30. data/lib/pact/v2/matchers/v3/date_time.rb +18 -0
  31. data/lib/pact/v2/matchers/v3/decimal.rb +17 -0
  32. data/lib/pact/v2/matchers/v3/each.rb +42 -0
  33. data/lib/pact/v2/matchers/v3/include.rb +17 -0
  34. data/lib/pact/v2/matchers/v3/integer.rb +17 -0
  35. data/lib/pact/v2/matchers/v3/null.rb +16 -0
  36. data/lib/pact/v2/matchers/v3/number.rb +17 -0
  37. data/lib/pact/v2/matchers/v3/semver.rb +23 -0
  38. data/lib/pact/v2/matchers/v3/time.rb +18 -0
  39. data/lib/pact/v2/matchers/v3/values.rb +16 -0
  40. data/lib/pact/v2/matchers/v4/each_key.rb +26 -0
  41. data/lib/pact/v2/matchers/v4/each_key_value.rb +32 -0
  42. data/lib/pact/v2/matchers/v4/each_value.rb +33 -0
  43. data/lib/pact/v2/matchers/v4/not_empty.rb +24 -0
  44. data/lib/pact/v2/matchers/v4/status_code.rb +17 -0
  45. data/lib/pact/v2/matchers.rb +110 -0
  46. data/lib/pact/v2/native/blocking_verifier.rb +17 -0
  47. data/lib/pact/v2/native/logger.rb +25 -0
  48. data/lib/pact/v2/provider/async_message_verifier.rb +28 -0
  49. data/lib/pact/v2/provider/base_verifier.rb +242 -0
  50. data/lib/pact/v2/provider/grpc_verifier.rb +38 -0
  51. data/lib/pact/v2/provider/gruf_server.rb +75 -0
  52. data/lib/pact/v2/provider/http_server.rb +79 -0
  53. data/lib/pact/v2/provider/http_verifier.rb +43 -0
  54. data/lib/pact/v2/provider/message_provider_servlet.rb +79 -0
  55. data/lib/pact/v2/provider/mixed_verifier.rb +22 -0
  56. data/lib/pact/v2/provider/pact_broker_proxy.rb +66 -0
  57. data/lib/pact/v2/provider/pact_broker_proxy_runner.rb +77 -0
  58. data/lib/pact/v2/provider/pact_config/async.rb +29 -0
  59. data/lib/pact/v2/provider/pact_config/base.rb +101 -0
  60. data/lib/pact/v2/provider/pact_config/grpc.rb +26 -0
  61. data/lib/pact/v2/provider/pact_config/http.rb +27 -0
  62. data/lib/pact/v2/provider/pact_config/mixed.rb +39 -0
  63. data/lib/pact/v2/provider/pact_config.rb +26 -0
  64. data/lib/pact/v2/provider/provider_server_runner.rb +89 -0
  65. data/lib/pact/v2/provider/provider_state_configuration.rb +32 -0
  66. data/lib/pact/v2/provider/provider_state_servlet.rb +86 -0
  67. data/lib/pact/v2/provider.rb +8 -0
  68. data/lib/pact/v2/railtie.rb +13 -0
  69. data/lib/pact/v2/rspec/support/pact_consumer_helpers.rb +93 -0
  70. data/lib/pact/v2/rspec/support/pact_message_helpers.rb +42 -0
  71. data/lib/pact/v2/rspec/support/pact_provider_helpers.rb +129 -0
  72. data/lib/pact/v2/rspec/support/waterdrop/pact_waterdrop_client.rb +27 -0
  73. data/lib/pact/v2/rspec/support/webmock/webmock_helpers.rb +30 -0
  74. data/lib/pact/v2/rspec.rb +17 -0
  75. data/lib/pact/v2/tasks/pact.rake +13 -0
  76. data/lib/pact/v2.rb +71 -0
  77. data/lib/pact/version.rb +1 -1
  78. data/lib/pact.rb +6 -0
  79. data/pact.gemspec +54 -7
  80. metadata +405 -65
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pact
4
+ module V2
5
+ module Provider
6
+ # inspired by Gruf::Cli::Executor
7
+ class GrufServer
8
+ SERVER_STOP_TIMEOUT_SEC = 15
9
+
10
+ def initialize(options = {})
11
+ @options = options
12
+
13
+ setup!
14
+
15
+ @server_pid = nil
16
+
17
+ @services = @options[:services].is_a?(Array) ? @options[:services] : []
18
+ @logger = @options[:logger] || ::Logger.new($stdout)
19
+ end
20
+
21
+ def start
22
+ raise "server already running, stop server before starting new one" if @thread
23
+
24
+ @logger.info("[gruf] starting standalone server with options: #{@options}")
25
+
26
+ @server = Gruf::Server.new(Gruf.server_options)
27
+ @services.each { |s| @server.add_service(s) } if @services.any?
28
+ @thread = Thread.new do
29
+ @logger.debug "[gruf] starting grpc server"
30
+ @server.start!
31
+ end
32
+ @server.server.wait_till_running(10)
33
+
34
+ @logger.info("[gruf] standalone server started")
35
+ end
36
+
37
+ def stop
38
+ @logger.info("[gruf] stopping standalone server")
39
+
40
+ @server&.server&.stop
41
+ @thread&.join(SERVER_STOP_TIMEOUT_SEC)
42
+ @thread&.kill
43
+
44
+ @logger.info("[gruf] standalone server stopped")
45
+ end
46
+
47
+ ##
48
+ # Run the server
49
+ #
50
+ def run
51
+ start
52
+
53
+ yield
54
+ rescue => e
55
+ @logger.fatal("FATAL ERROR: #{e.message} #{e.backtrace.join("\n")}")
56
+ raise
57
+ ensure
58
+ stop
59
+ end
60
+
61
+ private
62
+
63
+ def setup!
64
+ Gruf.server_binding_url = @options[:host] if @options[:host]
65
+ if @options[:suppress_default_interceptors]
66
+ Gruf.interceptors.remove(Gruf::Interceptors::ActiveRecord::ConnectionReset)
67
+ Gruf.interceptors.remove(Gruf::Interceptors::Instrumentation::OutputMetadataTimer)
68
+ end
69
+ Gruf.backtrace_on_error = true if @options[:backtrace_on_error]
70
+ Gruf.health_check_enabled = true if @options[:health_check]
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pact
4
+ module V2
5
+ module Provider
6
+ # inspired by Gruf::Cli::Executor
7
+ class HttpServer
8
+ SERVER_STOP_TIMEOUT_SEC = 15
9
+
10
+ def initialize(options = {})
11
+ @options = options
12
+
13
+ @server_pid = nil
14
+
15
+ @host = @options[:host] || "localhost"
16
+ @logger = @options[:logger] || ::Logger.new($stdout)
17
+ # allow any rack based app to be passed in, otherwise
18
+ # we will load a Rails.application
19
+ # allows for backwards compat with pact-ruby v1
20
+ @app = @options[:app] || nil
21
+ end
22
+
23
+ def start
24
+ raise "server already running, stop server before starting new one" if @thread
25
+
26
+ @logger.info("[webrick] starting server with options: #{@options}")
27
+
28
+ @thread = Thread.new do
29
+ @logger.debug "[webrick] starting http server"
30
+
31
+ # TODO: load from config.ru, if not rails and no app provided?
32
+ # Rack 2/3 compatibility
33
+ begin
34
+ require 'rack/handler/webrick'
35
+ handler = ::Rack::Handler::WEBrick
36
+ rescue LoadError
37
+ require 'rackup/handler/webrick'
38
+ handler = Class.new(Rackup::Handler::WEBrick)
39
+ end
40
+ handler.run(@app || (defined?(Rails) ? Rails.application : nil),
41
+ Host: @options[:host],
42
+ Port: @options[:port],
43
+ Logger: @logger,
44
+ StartCallback: -> { @started = true }) do |server|
45
+ @server = server
46
+ end
47
+ end
48
+ sleep 0.001 until @started
49
+
50
+ @logger.info("[webrick] server started")
51
+ end
52
+
53
+ def stop
54
+ @logger.info("[webrick] stopping server")
55
+
56
+ @server&.shutdown
57
+ @thread&.join(SERVER_STOP_TIMEOUT_SEC)
58
+ @thread&.kill
59
+
60
+ @logger.info("[webrick] server stopped")
61
+ end
62
+
63
+ ##
64
+ # Run the server
65
+ #
66
+ def run
67
+ start
68
+
69
+ yield
70
+ rescue => e
71
+ @logger.fatal("FATAL ERROR: #{e.message} #{e.backtrace.join("\n")}")
72
+ raise
73
+ ensure
74
+ stop
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pact/ffi/verifier"
4
+ require "pact/v2/native/logger"
5
+
6
+ module Pact
7
+ module V2
8
+ module Provider
9
+ class HttpVerifier < BaseVerifier
10
+ PROVIDER_TRANSPORT_TYPE = "http"
11
+
12
+ def initialize(pact_config, mixed_config = nil)
13
+ super
14
+
15
+ raise ArgumentError, "pact_config must be an instance of Pact::V2::Provider::PactConfig::Http" unless pact_config.is_a?(::Pact::V2::Provider::PactConfig::Http)
16
+ @http_server = HttpServer.new(host: "127.0.0.1", port: @pact_config.http_port, app: @pact_config.app)
17
+ end
18
+
19
+ private
20
+
21
+ def set_provider_info(pact_handle)
22
+ PactFfi::Verifier.set_provider_info(pact_handle, @pact_config.provider_name, "", "", @pact_config.http_port, "")
23
+ end
24
+
25
+ def add_provider_transport(pact_handle)
26
+ # The http transport is already added when the `set_provider_info` method is called,
27
+ # so we don't need to explicitly add the transport here
28
+ end
29
+
30
+
31
+ def start_servers!
32
+ super
33
+ @http_server.start
34
+ end
35
+
36
+ def stop_servers
37
+ super
38
+ @http_server.stop
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webrick"
4
+
5
+ module Pact
6
+ module V2
7
+ module Provider
8
+ class MessageProviderServlet < WEBrick::HTTPServlet::ProcHandler
9
+ attr_reader :logger
10
+
11
+ CONTENT_TYPE_JSON = "application/json"
12
+ CONTENT_TYPE_PROTO = "application/protobuf"
13
+ METADATA_HEADER = "pact-message-metadata"
14
+
15
+ def initialize(logger: Logger.new($stdout))
16
+ super(build_proc)
17
+
18
+ @message_handlers = {}
19
+
20
+ @logger = logger
21
+ end
22
+
23
+ def add_message_handler(name, &block)
24
+ raise "message handler for #{name} already configured" if @message_handlers[name].present?
25
+
26
+ @message_handlers[name] = {proc: block}
27
+ end
28
+
29
+ private
30
+
31
+ def build_proc
32
+ proc do |request, response|
33
+ # {"description":"message: ","providerStates":[{"name":"pet exists","params":{"pet_id":1}}]}
34
+ data = JSON.parse(request.body)
35
+
36
+ description = data["description"]
37
+ provider_states = data["providerStates"]
38
+
39
+ body, metadata = handle(description, provider_states)
40
+
41
+ response.status = 200
42
+ if body.is_a?(String)
43
+ # protobuf-serialized body
44
+ response.body = body
45
+ response.content_type = metadata[:content_type] || CONTENT_TYPE_PROTO
46
+ else
47
+ response.body = body.to_json
48
+ response.content_type = CONTENT_TYPE_JSON
49
+ end
50
+ response[METADATA_HEADER] = Base64.urlsafe_encode64(metadata.to_json)
51
+ rescue JSON::ParserError => ex
52
+ logger.error("cannot parse request: #{ex.message}")
53
+ response.status = 500
54
+ rescue => ex
55
+ logger.error("cannot handle message request: #{ex.message}")
56
+ response.status = 500
57
+ end
58
+ end
59
+
60
+ def handle(description, provider_states)
61
+ handler = find_handler_for(description)
62
+ return {}, {} unless handler
63
+
64
+ body, metadata = handler[:proc].call(provider_states&.first || {})
65
+ unless metadata[:content_type]
66
+ # try to find content-type in provider states
67
+ content_type = provider_states&.filter_map { |state| state.dig("params", "contentType") }&.first
68
+ metadata[:content_type] = content_type if content_type
69
+ end
70
+ [body, metadata]
71
+ end
72
+
73
+ def find_handler_for(description)
74
+ @message_handlers[description]
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,22 @@
1
+ # # frozen_string_literal: true
2
+ module Pact
3
+ module V2
4
+ module Provider
5
+ # MixedVerifier coordinates verification for all present configs (async, grpc, http)
6
+ class MixedVerifier
7
+ attr_reader :mixed_config, :verifiers
8
+
9
+ def initialize(mixed_config)
10
+ unless mixed_config.is_a?(::Pact::V2::Provider::PactConfig::Mixed)
11
+ raise ArgumentError, "mixed_config must be a PactConfig::Mixed"
12
+ end
13
+ @mixed_config = mixed_config
14
+ @verifiers = []
15
+ @verifiers << AsyncMessageVerifier.new(mixed_config.async_config) if mixed_config.async_config
16
+ @verifiers << GrpcVerifier.new(mixed_config.grpc_config) if mixed_config.grpc_config
17
+ @verifiers << HttpVerifier.new(mixed_config.http_config) if mixed_config.http_config
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rack-proxy"
4
+
5
+ module Pact
6
+ module V2
7
+ module Provider
8
+ class PactBrokerProxy < Rack::Proxy
9
+ attr_reader :backend_uri, :path, :logger
10
+
11
+ # e.g. /pacts/provider/paas-stand-seeker/consumer/paas-stand-placer/pact-version/2967a9343bd8fdd28a286c4b8322380020618892/metadata/c1tdW2VdPXByb2R1Y3Rpb24mc1tdW2N2XT03MzIy
12
+ PACT_FILE_REQUEST_PATH_REGEX = %r{/pacts/provider/.+?/consumer/.+?/pact-version/.+}.freeze
13
+
14
+ def initialize(app = nil, opts = {})
15
+ super
16
+ @backend_uri = URI(opts[:backend])
17
+ @path = nil
18
+ @logger = opts[:logger] || Logger.new($stdout)
19
+ end
20
+
21
+ def perform_request(env)
22
+ request = Rack::Request.new(env)
23
+ env["rack.timeout"] ||= ENV.fetch("PACT_BROKER_REQUEST_TIMEOUT", 5).to_i
24
+ @path = request.path
25
+
26
+ super
27
+ end
28
+
29
+ def rewrite_env(env)
30
+ env["HTTP_HOST"] = backend_uri.host
31
+ env
32
+ end
33
+
34
+ def rewrite_response(triplet)
35
+ status, headers, body = triplet
36
+
37
+ if status == "200" && PACT_FILE_REQUEST_PATH_REGEX.match?(path)
38
+ patched_body = patch_response(body.first)
39
+
40
+ # we need to recalculate content length
41
+ headers[Rack::CONTENT_LENGTH] = patched_body.bytesize.to_s
42
+
43
+ return [status, headers, [patched_body]]
44
+ end
45
+
46
+ triplet
47
+ end
48
+
49
+ private
50
+
51
+ def patch_response(raw_body)
52
+ parsed_body = JSON.parse(raw_body)
53
+
54
+ return body if parsed_body["consumer"].blank? || parsed_body["provider"].blank?
55
+ return body if parsed_body["interactions"].blank?
56
+
57
+
58
+ JSON.generate(parsed_body)
59
+ rescue JSON::ParserError => ex
60
+ logger.error("cannot parse broker response: #{ex.message}")
61
+ end
62
+
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webrick"
4
+
5
+ module Pact
6
+ module V2
7
+ module Provider
8
+ class PactBrokerProxyRunner
9
+ attr_reader :logger
10
+
11
+
12
+ def initialize(pact_broker_host:, port: 9002, host: "127.0.0.1", pact_broker_user: nil, pact_broker_password: nil, pact_broker_token: nil, logger: nil)
13
+ @host = host
14
+ @port = port
15
+ @pact_broker_host = pact_broker_host
16
+ @pact_broker_user = pact_broker_user
17
+ @pact_broker_password = pact_broker_password
18
+ @pact_broker_token = pact_broker_token
19
+ @logger = logger || Logger.new($stdout)
20
+
21
+ @thread = nil
22
+ end
23
+
24
+ def proxy_url
25
+ "http://#{@host}:#{@port}"
26
+ end
27
+
28
+ def start
29
+ raise "server already running, stop server before starting new one" if @thread
30
+ # Rack 2/3 compatibility
31
+ begin
32
+ require 'rack/handler/webrick'
33
+ handler = ::Rack::Handler::WEBrick
34
+ rescue LoadError
35
+ require 'rackup/handler/webrick'
36
+ handler = Class.new(Rackup::Handler::WEBrick)
37
+ end
38
+ @server = WEBrick::HTTPServer.new({BindAddress: @host, Port: @port}, WEBrick::Config::HTTP)
39
+ @server.mount("/", handler, PactBrokerProxy.new(
40
+ nil,
41
+ backend: @pact_broker_host,
42
+ streaming: false,
43
+ username: @pact_broker_user || nil,
44
+ password: @pact_broker_password || nil,
45
+ token: @pact_broker_token || nil,
46
+ logger: @logger
47
+ ))
48
+
49
+ @thread = Thread.new do
50
+ @logger.debug "starting pact broker proxy server"
51
+ @server.start
52
+ end
53
+ end
54
+
55
+ def stop
56
+ @logger.info("stopping pact broker proxy server")
57
+
58
+ @server&.shutdown
59
+ @thread&.join
60
+
61
+ @logger.info("pact broker proxy server stopped")
62
+ end
63
+
64
+ def run
65
+ start
66
+
67
+ yield
68
+ rescue => e
69
+ logger.fatal("FATAL ERROR: #{e.message} #{e.backtrace.join("\n")}")
70
+ raise
71
+ ensure
72
+ stop
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module Pact
6
+ module V2
7
+ module Provider
8
+ module PactConfig
9
+ class Async < Base
10
+ def initialize(provider_name:, opts: {})
11
+ super
12
+ handlers = opts[:message_handlers] || {}
13
+ handlers.each do |name, block|
14
+ new_message_handler(name, &block)
15
+ end
16
+ end
17
+
18
+ def new_message_handler(name, opts: {}, &block)
19
+ provider_setup_server.add_message_handler(name, &block)
20
+ end
21
+
22
+ def new_verifier(config = nil)
23
+ AsyncMessageVerifier.new(self, config)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pact
4
+ module V2
5
+ module Provider
6
+ module PactConfig
7
+ class Base
8
+ attr_reader :provider_name, :provider_version, :log_level, :provider_setup_server, :provider_setup_port, :pact_proxy_port,
9
+ :consumer_branch, :consumer_version, :consumer_name, :broker_url, :broker_username, :broker_password, :verify_only, :pact_dir,
10
+ :pact_uri, :provider_version_branch, :provider_version_tags, :consumer_version_selectors, :enable_pending, :include_wip_pacts_since,
11
+ :fail_if_no_pacts_found, :provider_build_uri, :broker_token, :consumer_version_tags, :publish_verification_results
12
+
13
+
14
+ def initialize(provider_name:, opts: {})
15
+ @provider_name = provider_name
16
+ @log_level = opts[:log_level] || :info
17
+ @pact_dir = opts[:pact_dir] || nil
18
+ @provider_setup_port = opts[:provider_setup_port] || 9001
19
+ @pact_proxy_port = opts[:provider_setup_port] || 9002
20
+ @pact_uri = ENV.fetch("PACT_URL", nil) || opts.fetch(:pact_uri, nil)
21
+ @publish_verification_results = ENV.fetch("PACT_PUBLISH_VERIFICATION_RESULTS", nil) == "true" || opts.fetch(:publish_verification_results, false)
22
+ @provider_version = ENV.fetch("PACT_PROVIDER_VERSION", nil) || opts.fetch(:provider_version, nil)
23
+ @provider_build_uri = ENV.fetch("PACT_PROVIDER_BUILD_URL", nil) || opts.fetch(:provider_build_uri, nil)
24
+ @provider_version_branch = ENV.fetch("PACT_PROVIDER_BRANCH", nil) || opts.fetch(:provider_version_branch, nil)
25
+ @provider_version_tags = ENV.fetch("PACT_PROVIDER_VERSION_TAGS", nil) || opts.fetch(:provider_version_tags, [])
26
+ @consumer_version_tags = ENV.fetch("PACT_CONSUMER_VERSION_TAGS", nil) || opts.fetch(:consumer_version_tags, [])
27
+ @consumer_version_selectors = ENV.fetch("PACT_CONSUMER_VERSION_SELECTORS", nil) || opts.fetch(:consumer_version_selectors, nil)
28
+ @enable_pending = ENV.fetch("PACT_VERIFIER_ENABLE_PENDING", nil) == "true" || opts.fetch(:enable_pending, false)
29
+ @include_wip_pacts_since = ENV.fetch("PACT_INCLUDE_WIP_PACTS_SINCE", nil) || opts.fetch(:include_wip_pacts_since, nil)
30
+ @fail_if_no_pacts_found = ENV.fetch("PACT_FAIL_IF_NO_PACTS_FOUND", nil) == "true" || opts.fetch(:fail_if_no_pacts_found, true)
31
+ @consumer_branch = ENV.fetch("PACT_CONSUMER_BRANCH", nil) || opts.fetch(:consumer_branch, nil)
32
+ @consumer_version = ENV.fetch("PACT_CONSUMER_VERSION", nil) || opts.fetch(:consumer_version, nil)
33
+ @consumer_name = opts[:consumer_name]
34
+ @broker_url = ENV.fetch("PACT_BROKER_BASE_URL", nil) || opts.fetch(:broker_url, nil)
35
+ @broker_username = ENV.fetch("PACT_BROKER_USERNAME", nil) || opts.fetch(:broker_username, nil)
36
+ @broker_password = ENV.fetch("PACT_BROKER_PASSWORD", nil) || opts.fetch(:broker_password, nil)
37
+ @broker_token = ENV.fetch("PACT_BROKER_TOKEN", nil) || opts.fetch(:broker_token, nil)
38
+ @verify_only = [ENV.fetch("PACT_CONSUMER_FULL_NAME", nil)].compact || opts.fetch(:verify_only, [])
39
+
40
+ @provider_setup_server = opts[:provider_setup_server] || ProviderServerRunner.new(port: @provider_setup_port)
41
+ if @broker_url.present?
42
+ @pact_proxy_server = PactBrokerProxyRunner.new(
43
+ port: @pact_proxy_port,
44
+ pact_broker_host: @broker_url,
45
+ pact_broker_user: @broker_username,
46
+ pact_broker_password: @broker_password,
47
+ pact_broker_token: @broker_token
48
+ )
49
+ end
50
+ end
51
+
52
+
53
+ def start_servers
54
+ @provider_setup_server.start
55
+ @pact_proxy_server&.start
56
+ end
57
+
58
+ def stop_servers
59
+ @provider_setup_server.stop
60
+ @pact_proxy_server&.stop
61
+ end
62
+
63
+ def provider_setup_url
64
+ @provider_setup_server.state_setup_url
65
+ end
66
+
67
+ def message_setup_url # rubocop:disable Rails/Delegate
68
+ @provider_setup_server.message_setup_url
69
+ end
70
+
71
+ def pact_broker_proxy_url
72
+ @pact_proxy_server&.proxy_url
73
+ end
74
+
75
+ def new_provider_state(name, opts: {}, &block)
76
+ config = ProviderStateConfiguration.new(name, opts: opts)
77
+ config.instance_eval(&block)
78
+ config.validate!
79
+
80
+ use_hooks = !opts[:skip_hooks]
81
+
82
+ @provider_setup_server.add_setup_state(name, use_hooks, &config.setup_proc) if config.setup_proc
83
+ @provider_setup_server.add_teardown_state(name, use_hooks, &config.teardown_proc) if config.teardown_proc
84
+ end
85
+
86
+ def before_setup(&block)
87
+ @provider_setup_server.set_before_setup_hook(&block)
88
+ end
89
+
90
+ def after_teardown(&block)
91
+ @provider_setup_server.set_after_teardown_hook(&block)
92
+ end
93
+
94
+ def new_verifier
95
+ raise Pact::V2::ImplementationRequired, "#new_verifier should be implemented"
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module Pact
6
+ module V2
7
+ module Provider
8
+ module PactConfig
9
+ class Grpc < Base
10
+ attr_reader :grpc_port, :grpc_services, :grpc_server
11
+
12
+ def initialize(provider_name:, opts: {})
13
+ super
14
+
15
+ @grpc_port = opts[:grpc_port] || 0
16
+ @grpc_services = opts[:grpc_services] || []
17
+ end
18
+
19
+ def new_verifier(config = nil)
20
+ GrpcVerifier.new(self, config)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module Pact
6
+ module V2
7
+ module Provider
8
+ module PactConfig
9
+ class Http < Base
10
+ attr_reader :http_port
11
+ attr_reader :app
12
+
13
+ def initialize(provider_name:, opts: {})
14
+ super
15
+
16
+ @http_port = opts[:http_port] || 0
17
+ @app = opts[:app] || nil
18
+ end
19
+
20
+ def new_verifier(config = nil)
21
+ HttpVerifier.new(self, config)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,39 @@
1
+ # # frozen_string_literal: true
2
+
3
+ module Pact
4
+ module V2
5
+ module Provider
6
+ module PactConfig
7
+ # Mixed config allows composing one of each: async, grpc, http
8
+ class Mixed < Base
9
+ attr_reader :async_config, :grpc_config, :http_config
10
+
11
+ def initialize(provider_name:, opts: {})
12
+ super
13
+ @provider_setup_server = ProviderServerRunner.new(port: @provider_setup_port)
14
+ if @broker_url.present?
15
+ @pact_proxy_server = PactBrokerProxyRunner.new(
16
+ port: @pact_proxy_port,
17
+ pact_broker_host: @broker_url,
18
+ pact_broker_user: @broker_username,
19
+ pact_broker_password: @broker_password,
20
+ pact_broker_token: @broker_token
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
39
+ end