pact 1.67.4 → 2.0.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/lib/pact/configuration.rb +21 -0
- data/lib/pact/consumer/grpc_interaction_builder.rb +192 -0
- data/lib/pact/consumer/http_interaction_builder.rb +160 -0
- data/lib/pact/consumer/interaction_contents.rb +60 -0
- data/lib/pact/consumer/message_interaction_builder.rb +286 -0
- data/lib/pact/consumer/mock_server.rb +106 -0
- data/lib/pact/consumer/pact_config/base.rb +22 -0
- data/lib/pact/consumer/pact_config/grpc.rb +24 -0
- data/lib/pact/consumer/pact_config/http.rb +53 -0
- data/lib/pact/consumer/pact_config/message.rb +15 -0
- data/lib/pact/consumer/pact_config/plugin_async_message.rb +24 -0
- data/lib/pact/consumer/pact_config/plugin_http.rb +24 -0
- data/lib/pact/consumer/pact_config/plugin_sync_message.rb +24 -0
- data/lib/pact/consumer/pact_config.rb +28 -0
- data/lib/pact/consumer/plugin_async_message_interaction_builder.rb +169 -0
- data/lib/pact/consumer/plugin_http_interaction_builder.rb +199 -0
- data/lib/pact/consumer/plugin_sync_message_interaction_builder.rb +178 -0
- data/lib/pact/consumer.rb +6 -7
- data/lib/pact/generators/base.rb +285 -0
- data/lib/pact/generators.rb +47 -0
- data/lib/pact/matchers/base.rb +72 -0
- data/lib/pact/matchers/v1/equality.rb +17 -0
- data/lib/pact/matchers/v2/regex.rb +26 -0
- data/lib/pact/matchers/v2/type.rb +18 -0
- data/lib/pact/matchers/v3/boolean.rb +18 -0
- data/lib/pact/matchers/v3/content_type.rb +30 -0
- data/lib/pact/matchers/v3/date.rb +22 -0
- data/lib/pact/matchers/v3/date_time.rb +22 -0
- data/lib/pact/matchers/v3/decimal.rb +18 -0
- data/lib/pact/matchers/v3/each.rb +46 -0
- data/lib/pact/matchers/v3/include.rb +18 -0
- data/lib/pact/matchers/v3/integer.rb +18 -0
- data/lib/pact/matchers/v3/null.rb +13 -0
- data/lib/pact/matchers/v3/number.rb +18 -0
- data/lib/pact/matchers/v3/semver.rb +22 -0
- data/lib/pact/matchers/v3/time.rb +22 -0
- data/lib/pact/matchers/v3/values.rb +13 -0
- data/lib/pact/matchers/v4/each_key.rb +34 -0
- data/lib/pact/matchers/v4/each_key_value.rb +38 -0
- data/lib/pact/matchers/v4/each_value.rb +40 -0
- data/lib/pact/matchers/v4/not_empty.rb +22 -0
- data/lib/pact/matchers/v4/status_code.rb +15 -0
- data/lib/pact/matchers.rb +108 -0
- data/lib/pact/native/blocking_verifier.rb +15 -0
- data/lib/pact/native/logger.rb +24 -0
- data/lib/pact/provider/async_message_verifier.rb +29 -0
- data/lib/pact/provider/base_verifier.rb +259 -0
- data/lib/pact/provider/grpc_verifier.rb +40 -0
- data/lib/pact/provider/gruf_server.rb +73 -0
- data/lib/pact/provider/http_server.rb +77 -0
- data/lib/pact/provider/http_verifier.rb +45 -0
- data/lib/pact/provider/message_provider_servlet.rb +77 -0
- data/lib/pact/provider/mixed_verifier.rb +21 -0
- data/lib/pact/provider/pact_broker_proxy.rb +62 -0
- data/lib/pact/provider/pact_broker_proxy_runner.rb +78 -0
- data/lib/pact/provider/pact_config/async.rb +28 -0
- data/lib/pact/provider/pact_config/base.rb +101 -0
- data/lib/pact/provider/pact_config/grpc.rb +24 -0
- data/lib/pact/provider/pact_config/http.rb +25 -0
- data/lib/pact/provider/pact_config/mixed.rb +38 -0
- data/lib/pact/provider/pact_config.rb +24 -0
- data/lib/pact/provider/provider_server_runner.rb +90 -0
- data/lib/pact/provider/provider_state_configuration.rb +32 -0
- data/lib/pact/provider/provider_state_servlet.rb +84 -0
- data/lib/pact/provider.rb +6 -3
- data/lib/pact/railtie.rb +11 -0
- data/lib/pact/{v2/rspec → rspec}/support/pact_consumer_helpers.rb +8 -8
- data/lib/pact/{v2/rspec → rspec}/support/pact_provider_helpers.rb +25 -24
- data/lib/pact/{v2/rspec.rb → rspec.rb} +6 -5
- data/lib/pact/tasks/pact.rake +13 -0
- data/lib/pact/version.rb +1 -1
- data/lib/pact.rb +46 -11
- data/pact.gemspec +42 -65
- metadata +145 -404
- data/lib/pact/cli/generate_pact_docs.rb +0 -4
- data/lib/pact/cli/run_pact_verification.rb +0 -99
- data/lib/pact/cli/spec_criteria.rb +0 -26
- data/lib/pact/cli.rb +0 -45
- data/lib/pact/consumer/configuration/configuration_extensions.rb +0 -90
- data/lib/pact/consumer/configuration/dsl.rb +0 -11
- data/lib/pact/consumer/configuration/mock_service.rb +0 -112
- data/lib/pact/consumer/configuration/service_consumer.rb +0 -51
- data/lib/pact/consumer/configuration/service_provider.rb +0 -40
- data/lib/pact/consumer/configuration.rb +0 -10
- data/lib/pact/consumer/consumer_contract_builder.rb +0 -82
- data/lib/pact/consumer/consumer_contract_builders.rb +0 -10
- data/lib/pact/consumer/interaction_builder.rb +0 -45
- data/lib/pact/consumer/rspec.rb +0 -35
- data/lib/pact/consumer/spec_hooks.rb +0 -40
- data/lib/pact/consumer/world.rb +0 -37
- data/lib/pact/doc/README.md +0 -13
- data/lib/pact/doc/doc_file.rb +0 -40
- data/lib/pact/doc/generate.rb +0 -11
- data/lib/pact/doc/generator.rb +0 -82
- data/lib/pact/doc/interaction_view_model.rb +0 -124
- data/lib/pact/doc/markdown/consumer_contract_renderer.rb +0 -68
- data/lib/pact/doc/markdown/generator.rb +0 -26
- data/lib/pact/doc/markdown/index_renderer.rb +0 -43
- data/lib/pact/doc/markdown/interaction.erb +0 -14
- data/lib/pact/doc/markdown/interaction_renderer.rb +0 -43
- data/lib/pact/doc/sort_interactions.rb +0 -16
- data/lib/pact/hal/authorization_header_redactor.rb +0 -32
- data/lib/pact/hal/entity.rb +0 -110
- data/lib/pact/hal/http_client.rb +0 -128
- data/lib/pact/hal/link.rb +0 -112
- data/lib/pact/hal/non_json_entity.rb +0 -28
- data/lib/pact/hash_refinements.rb +0 -17
- data/lib/pact/pact_broker/fetch_pact_uris_for_verification.rb +0 -112
- data/lib/pact/pact_broker/fetch_pacts.rb +0 -103
- data/lib/pact/pact_broker/notices.rb +0 -34
- data/lib/pact/pact_broker/pact_selection_description.rb +0 -66
- data/lib/pact/pact_broker.rb +0 -25
- data/lib/pact/project_root.rb +0 -7
- data/lib/pact/provider/configuration/configuration_extension.rb +0 -69
- data/lib/pact/provider/configuration/dsl.rb +0 -18
- data/lib/pact/provider/configuration/message_provider_dsl.rb +0 -63
- data/lib/pact/provider/configuration/pact_verification.rb +0 -48
- data/lib/pact/provider/configuration/pact_verification_from_broker.rb +0 -126
- data/lib/pact/provider/configuration/service_provider_config.rb +0 -32
- data/lib/pact/provider/configuration/service_provider_dsl.rb +0 -107
- data/lib/pact/provider/configuration.rb +0 -7
- data/lib/pact/provider/context.rb +0 -0
- data/lib/pact/provider/help/console_text.rb +0 -76
- data/lib/pact/provider/help/content.rb +0 -38
- data/lib/pact/provider/help/pact_diff.rb +0 -43
- data/lib/pact/provider/help/prompt_text.rb +0 -49
- data/lib/pact/provider/help/write.rb +0 -56
- data/lib/pact/provider/matchers/messages.rb +0 -66
- data/lib/pact/provider/pact_helper_locator.rb +0 -24
- data/lib/pact/provider/pact_source.rb +0 -40
- data/lib/pact/provider/pact_spec_runner.rb +0 -188
- data/lib/pact/provider/pact_uri.rb +0 -55
- data/lib/pact/provider/pact_verification.rb +0 -17
- data/lib/pact/provider/print_missing_provider_states.rb +0 -35
- data/lib/pact/provider/request.rb +0 -90
- data/lib/pact/provider/rspec/backtrace_formatter.rb +0 -43
- data/lib/pact/provider/rspec/calculate_exit_code.rb +0 -18
- data/lib/pact/provider/rspec/custom_options_file +0 -0
- data/lib/pact/provider/rspec/formatter_rspec_2.rb +0 -76
- data/lib/pact/provider/rspec/formatter_rspec_3.rb +0 -195
- data/lib/pact/provider/rspec/json_formatter.rb +0 -100
- data/lib/pact/provider/rspec/matchers.rb +0 -80
- data/lib/pact/provider/rspec/pact_broker_formatter.rb +0 -76
- data/lib/pact/provider/rspec.rb +0 -234
- data/lib/pact/provider/state/provider_state.rb +0 -180
- data/lib/pact/provider/state/provider_state_configured_modules.rb +0 -15
- data/lib/pact/provider/state/provider_state_manager.rb +0 -42
- data/lib/pact/provider/state/provider_state_proxy.rb +0 -39
- data/lib/pact/provider/state/set_up.rb +0 -13
- data/lib/pact/provider/state/tear_down.rb +0 -13
- data/lib/pact/provider/test_methods.rb +0 -77
- data/lib/pact/provider/verification_report.rb +0 -36
- data/lib/pact/provider/verification_results/create.rb +0 -88
- data/lib/pact/provider/verification_results/publish.rb +0 -143
- data/lib/pact/provider/verification_results/publish_all.rb +0 -50
- data/lib/pact/provider/verification_results/verification_result.rb +0 -40
- data/lib/pact/provider/world.rb +0 -50
- data/lib/pact/retry.rb +0 -37
- data/lib/pact/tasks/task_helper.rb +0 -62
- data/lib/pact/tasks/verification_task.rb +0 -95
- data/lib/pact/tasks.rb +0 -2
- data/lib/pact/templates/help.erb +0 -22
- data/lib/pact/templates/provider_state.erb +0 -14
- data/lib/pact/utils/metrics.rb +0 -100
- data/lib/pact/utils/string.rb +0 -35
- data/lib/pact/v2/configuration.rb +0 -23
- data/lib/pact/v2/consumer/grpc_interaction_builder.rb +0 -194
- data/lib/pact/v2/consumer/http_interaction_builder.rb +0 -162
- data/lib/pact/v2/consumer/interaction_contents.rb +0 -62
- data/lib/pact/v2/consumer/message_interaction_builder.rb +0 -288
- data/lib/pact/v2/consumer/mock_server.rb +0 -108
- data/lib/pact/v2/consumer/pact_config/base.rb +0 -24
- data/lib/pact/v2/consumer/pact_config/grpc.rb +0 -26
- data/lib/pact/v2/consumer/pact_config/http.rb +0 -55
- data/lib/pact/v2/consumer/pact_config/message.rb +0 -17
- data/lib/pact/v2/consumer/pact_config/plugin_async_message.rb +0 -26
- data/lib/pact/v2/consumer/pact_config/plugin_http.rb +0 -26
- data/lib/pact/v2/consumer/pact_config/plugin_sync_message.rb +0 -26
- data/lib/pact/v2/consumer/pact_config.rb +0 -30
- data/lib/pact/v2/consumer/plugin_async_message_interaction_builder.rb +0 -171
- data/lib/pact/v2/consumer/plugin_http_interaction_builder.rb +0 -201
- data/lib/pact/v2/consumer/plugin_sync_message_interaction_builder.rb +0 -180
- data/lib/pact/v2/consumer.rb +0 -8
- data/lib/pact/v2/generators/base.rb +0 -287
- data/lib/pact/v2/generators.rb +0 -49
- data/lib/pact/v2/matchers/base.rb +0 -74
- data/lib/pact/v2/matchers/v1/equality.rb +0 -19
- data/lib/pact/v2/matchers/v2/regex.rb +0 -19
- data/lib/pact/v2/matchers/v2/type.rb +0 -17
- data/lib/pact/v2/matchers/v3/boolean.rb +0 -17
- data/lib/pact/v2/matchers/v3/content_type.rb +0 -32
- data/lib/pact/v2/matchers/v3/date.rb +0 -18
- data/lib/pact/v2/matchers/v3/date_time.rb +0 -18
- data/lib/pact/v2/matchers/v3/decimal.rb +0 -17
- data/lib/pact/v2/matchers/v3/each.rb +0 -42
- data/lib/pact/v2/matchers/v3/include.rb +0 -17
- data/lib/pact/v2/matchers/v3/integer.rb +0 -17
- data/lib/pact/v2/matchers/v3/null.rb +0 -16
- data/lib/pact/v2/matchers/v3/number.rb +0 -17
- data/lib/pact/v2/matchers/v3/semver.rb +0 -23
- data/lib/pact/v2/matchers/v3/time.rb +0 -18
- data/lib/pact/v2/matchers/v3/values.rb +0 -16
- data/lib/pact/v2/matchers/v4/each_key.rb +0 -26
- data/lib/pact/v2/matchers/v4/each_key_value.rb +0 -32
- data/lib/pact/v2/matchers/v4/each_value.rb +0 -33
- data/lib/pact/v2/matchers/v4/not_empty.rb +0 -24
- data/lib/pact/v2/matchers/v4/status_code.rb +0 -17
- data/lib/pact/v2/matchers.rb +0 -110
- data/lib/pact/v2/native/blocking_verifier.rb +0 -17
- data/lib/pact/v2/native/logger.rb +0 -25
- data/lib/pact/v2/provider/async_message_verifier.rb +0 -28
- data/lib/pact/v2/provider/base_verifier.rb +0 -242
- data/lib/pact/v2/provider/grpc_verifier.rb +0 -38
- data/lib/pact/v2/provider/gruf_server.rb +0 -75
- data/lib/pact/v2/provider/http_server.rb +0 -79
- data/lib/pact/v2/provider/http_verifier.rb +0 -43
- data/lib/pact/v2/provider/message_provider_servlet.rb +0 -79
- data/lib/pact/v2/provider/mixed_verifier.rb +0 -22
- data/lib/pact/v2/provider/pact_broker_proxy.rb +0 -66
- data/lib/pact/v2/provider/pact_broker_proxy_runner.rb +0 -80
- data/lib/pact/v2/provider/pact_config/async.rb +0 -29
- data/lib/pact/v2/provider/pact_config/base.rb +0 -103
- data/lib/pact/v2/provider/pact_config/grpc.rb +0 -26
- data/lib/pact/v2/provider/pact_config/http.rb +0 -27
- data/lib/pact/v2/provider/pact_config/mixed.rb +0 -40
- data/lib/pact/v2/provider/pact_config.rb +0 -26
- data/lib/pact/v2/provider/provider_server_runner.rb +0 -92
- data/lib/pact/v2/provider/provider_state_configuration.rb +0 -32
- data/lib/pact/v2/provider/provider_state_servlet.rb +0 -86
- data/lib/pact/v2/provider.rb +0 -8
- data/lib/pact/v2/railtie.rb +0 -13
- data/lib/pact/v2/tasks/pact.rake +0 -13
- data/lib/pact/v2.rb +0 -71
- data/lib/tasks/pact.rake +0 -34
- /data/lib/pact/{v2/rspec → rspec}/support/pact_message_helpers.rb +0 -0
- /data/lib/pact/{v2/rspec → rspec}/support/waterdrop/pact_waterdrop_client.rb +0 -0
- /data/lib/pact/{v2/rspec → rspec}/support/webmock/webmock_helpers.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
data/lib/pact/railtie.rb
ADDED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
require_relative "pact_message_helpers"
|
|
4
4
|
require "json"
|
|
5
5
|
|
|
6
|
-
module
|
|
7
|
-
include Pact::
|
|
8
|
-
include Pact::
|
|
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::
|
|
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::
|
|
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::
|
|
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
|
|
92
|
-
config.extend
|
|
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
|
|
4
|
-
require_relative
|
|
3
|
+
require_relative 'pact_message_helpers'
|
|
4
|
+
require_relative 'webmock/webmock_helpers'
|
|
5
5
|
|
|
6
|
-
module
|
|
6
|
+
module PactProducerDsl
|
|
7
7
|
module ClassMethods
|
|
8
|
-
PACT_PROVIDER_NOT_DECLARED_MESSAGE =
|
|
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
|
-
|
|
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::
|
|
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
|
-
#
|
|
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
|
-
|
|
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::
|
|
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::
|
|
87
|
+
async_klass = Pact::Provider::PactConfig::Async
|
|
87
88
|
if defined?(@_pact_config) &&
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
93
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
118
|
-
config.extend
|
|
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
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
|
|
5
|
-
require_relative
|
|
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 :
|
|
17
|
+
config.filter_run_excluding :pact
|
|
17
18
|
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
data/lib/pact.rb
CHANGED
|
@@ -1,12 +1,47 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
require '
|
|
4
|
-
require 'pact/
|
|
5
|
-
|
|
6
|
-
require 'pact/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'zeitwerk'
|
|
4
|
+
require 'pact/ffi'
|
|
5
|
+
|
|
6
|
+
require 'pact/railtie' if defined?(Rails::Railtie)
|
|
7
|
+
|
|
8
|
+
module Pact
|
|
9
|
+
class Error < StandardError; end
|
|
10
|
+
|
|
11
|
+
class ImplementationRequired < Error; end
|
|
12
|
+
|
|
13
|
+
class FfiError < Error
|
|
14
|
+
def initialize(msg, reason, status)
|
|
15
|
+
super(msg)
|
|
16
|
+
|
|
17
|
+
@msg = msg
|
|
18
|
+
@reason = reason
|
|
19
|
+
@status = status
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def message
|
|
23
|
+
"FFI error: reason: #{@reason}, status: #{@status}, message: #{@msg}"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.configure
|
|
28
|
+
yield configuration if block_given?
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.configuration
|
|
32
|
+
@configuration ||= Pact::Configuration.new
|
|
33
|
+
end
|
|
12
34
|
end
|
|
35
|
+
|
|
36
|
+
loader = Zeitwerk::Loader.new
|
|
37
|
+
loader.push_dir(File.join(__dir__))
|
|
38
|
+
|
|
39
|
+
loader.tag = 'pact'
|
|
40
|
+
|
|
41
|
+
loader.ignore("#{__dir__}/pact/version.rb")
|
|
42
|
+
loader.ignore("#{__dir__}/pact/rspec.rb")
|
|
43
|
+
loader.ignore("#{__dir__}/pact/rspec")
|
|
44
|
+
loader.ignore("#{__dir__}/pact/railtie.rb") unless defined?(Rails::Railtie)
|
|
45
|
+
|
|
46
|
+
loader.setup
|
|
47
|
+
loader.eager_load
|