pact-v2 2.0.0.pre.preview1
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 +7 -0
- data/CHANGELOG.md +1321 -0
- data/LICENSE.txt +23 -0
- data/bin/pact +4 -0
- data/lib/pact/cli/generate_pact_docs.rb +4 -0
- data/lib/pact/cli/run_pact_verification.rb +99 -0
- data/lib/pact/cli/spec_criteria.rb +26 -0
- data/lib/pact/cli.rb +45 -0
- data/lib/pact/consumer/configuration/configuration_extensions.rb +90 -0
- data/lib/pact/consumer/configuration/dsl.rb +11 -0
- data/lib/pact/consumer/configuration/mock_service.rb +112 -0
- data/lib/pact/consumer/configuration/service_consumer.rb +51 -0
- data/lib/pact/consumer/configuration/service_provider.rb +40 -0
- data/lib/pact/consumer/configuration.rb +10 -0
- data/lib/pact/consumer/consumer_contract_builder.rb +82 -0
- data/lib/pact/consumer/consumer_contract_builders.rb +10 -0
- data/lib/pact/consumer/interaction_builder.rb +45 -0
- data/lib/pact/consumer/rspec.rb +35 -0
- data/lib/pact/consumer/spec_hooks.rb +40 -0
- data/lib/pact/consumer/world.rb +37 -0
- data/lib/pact/consumer.rb +7 -0
- data/lib/pact/doc/README.md +13 -0
- data/lib/pact/doc/doc_file.rb +40 -0
- data/lib/pact/doc/generate.rb +11 -0
- data/lib/pact/doc/generator.rb +82 -0
- data/lib/pact/doc/interaction_view_model.rb +124 -0
- data/lib/pact/doc/markdown/consumer_contract_renderer.rb +68 -0
- data/lib/pact/doc/markdown/generator.rb +26 -0
- data/lib/pact/doc/markdown/index_renderer.rb +43 -0
- data/lib/pact/doc/markdown/interaction.erb +14 -0
- data/lib/pact/doc/markdown/interaction_renderer.rb +43 -0
- data/lib/pact/doc/sort_interactions.rb +16 -0
- data/lib/pact/hal/authorization_header_redactor.rb +32 -0
- data/lib/pact/hal/entity.rb +110 -0
- data/lib/pact/hal/http_client.rb +128 -0
- data/lib/pact/hal/link.rb +112 -0
- data/lib/pact/hal/non_json_entity.rb +28 -0
- data/lib/pact/hash_refinements.rb +17 -0
- data/lib/pact/pact_broker/fetch_pact_uris_for_verification.rb +112 -0
- data/lib/pact/pact_broker/fetch_pacts.rb +103 -0
- data/lib/pact/pact_broker/notices.rb +34 -0
- data/lib/pact/pact_broker/pact_selection_description.rb +66 -0
- data/lib/pact/pact_broker.rb +25 -0
- data/lib/pact/project_root.rb +7 -0
- data/lib/pact/provider/configuration/configuration_extension.rb +69 -0
- data/lib/pact/provider/configuration/dsl.rb +18 -0
- data/lib/pact/provider/configuration/message_provider_dsl.rb +63 -0
- data/lib/pact/provider/configuration/pact_verification.rb +48 -0
- data/lib/pact/provider/configuration/pact_verification_from_broker.rb +126 -0
- data/lib/pact/provider/configuration/service_provider_config.rb +32 -0
- data/lib/pact/provider/configuration/service_provider_dsl.rb +107 -0
- data/lib/pact/provider/configuration.rb +7 -0
- data/lib/pact/provider/context.rb +0 -0
- data/lib/pact/provider/help/console_text.rb +76 -0
- data/lib/pact/provider/help/content.rb +38 -0
- data/lib/pact/provider/help/pact_diff.rb +43 -0
- data/lib/pact/provider/help/prompt_text.rb +49 -0
- data/lib/pact/provider/help/write.rb +56 -0
- data/lib/pact/provider/matchers/messages.rb +66 -0
- data/lib/pact/provider/pact_helper_locator.rb +24 -0
- data/lib/pact/provider/pact_source.rb +40 -0
- data/lib/pact/provider/pact_spec_runner.rb +188 -0
- data/lib/pact/provider/pact_uri.rb +55 -0
- data/lib/pact/provider/pact_verification.rb +17 -0
- data/lib/pact/provider/print_missing_provider_states.rb +35 -0
- data/lib/pact/provider/request.rb +77 -0
- data/lib/pact/provider/rspec/backtrace_formatter.rb +43 -0
- data/lib/pact/provider/rspec/calculate_exit_code.rb +18 -0
- data/lib/pact/provider/rspec/custom_options_file +0 -0
- data/lib/pact/provider/rspec/formatter_rspec_2.rb +76 -0
- data/lib/pact/provider/rspec/formatter_rspec_3.rb +195 -0
- data/lib/pact/provider/rspec/json_formatter.rb +100 -0
- data/lib/pact/provider/rspec/matchers.rb +80 -0
- data/lib/pact/provider/rspec/pact_broker_formatter.rb +76 -0
- data/lib/pact/provider/rspec.rb +234 -0
- data/lib/pact/provider/state/provider_state.rb +180 -0
- data/lib/pact/provider/state/provider_state_configured_modules.rb +15 -0
- data/lib/pact/provider/state/provider_state_manager.rb +42 -0
- data/lib/pact/provider/state/provider_state_proxy.rb +39 -0
- data/lib/pact/provider/state/set_up.rb +13 -0
- data/lib/pact/provider/state/tear_down.rb +13 -0
- data/lib/pact/provider/test_methods.rb +77 -0
- data/lib/pact/provider/verification_report.rb +36 -0
- data/lib/pact/provider/verification_results/create.rb +88 -0
- data/lib/pact/provider/verification_results/publish.rb +143 -0
- data/lib/pact/provider/verification_results/publish_all.rb +50 -0
- data/lib/pact/provider/verification_results/verification_result.rb +40 -0
- data/lib/pact/provider/world.rb +50 -0
- data/lib/pact/provider.rb +3 -0
- data/lib/pact/retry.rb +37 -0
- data/lib/pact/tasks/task_helper.rb +62 -0
- data/lib/pact/tasks/verification_task.rb +95 -0
- data/lib/pact/tasks.rb +2 -0
- data/lib/pact/templates/help.erb +22 -0
- data/lib/pact/templates/provider_state.erb +14 -0
- data/lib/pact/utils/metrics.rb +100 -0
- data/lib/pact/utils/string.rb +35 -0
- data/lib/pact/v2/configuration.rb +23 -0
- data/lib/pact/v2/consumer/grpc_interaction_builder.rb +187 -0
- data/lib/pact/v2/consumer/http_interaction_builder.rb +163 -0
- data/lib/pact/v2/consumer/interaction_contents.rb +54 -0
- data/lib/pact/v2/consumer/message_interaction_builder.rb +280 -0
- data/lib/pact/v2/consumer/mock_server.rb +99 -0
- data/lib/pact/v2/consumer/pact_config/base.rb +24 -0
- data/lib/pact/v2/consumer/pact_config/grpc.rb +26 -0
- data/lib/pact/v2/consumer/pact_config/http.rb +55 -0
- data/lib/pact/v2/consumer/pact_config/message.rb +17 -0
- data/lib/pact/v2/consumer/pact_config.rb +24 -0
- data/lib/pact/v2/consumer.rb +8 -0
- data/lib/pact/v2/matchers/base.rb +67 -0
- data/lib/pact/v2/matchers/v1/equality.rb +19 -0
- data/lib/pact/v2/matchers/v2/regex.rb +19 -0
- data/lib/pact/v2/matchers/v2/type.rb +17 -0
- data/lib/pact/v2/matchers/v3/boolean.rb +17 -0
- data/lib/pact/v2/matchers/v3/date.rb +18 -0
- data/lib/pact/v2/matchers/v3/date_time.rb +18 -0
- data/lib/pact/v2/matchers/v3/decimal.rb +17 -0
- data/lib/pact/v2/matchers/v3/each.rb +42 -0
- data/lib/pact/v2/matchers/v3/include.rb +17 -0
- data/lib/pact/v2/matchers/v3/integer.rb +17 -0
- data/lib/pact/v2/matchers/v3/number.rb +17 -0
- data/lib/pact/v2/matchers/v3/time.rb +18 -0
- data/lib/pact/v2/matchers/v4/each_key.rb +26 -0
- data/lib/pact/v2/matchers/v4/each_key_value.rb +32 -0
- data/lib/pact/v2/matchers/v4/each_value.rb +33 -0
- data/lib/pact/v2/matchers/v4/not_empty.rb +17 -0
- data/lib/pact/v2/matchers.rb +94 -0
- data/lib/pact/v2/native/blocking_verifier.rb +17 -0
- data/lib/pact/v2/native/logger.rb +25 -0
- data/lib/pact/v2/provider/async_message_verifier.rb +28 -0
- data/lib/pact/v2/provider/base_verifier.rb +242 -0
- data/lib/pact/v2/provider/grpc_verifier.rb +38 -0
- data/lib/pact/v2/provider/gruf_server.rb +75 -0
- data/lib/pact/v2/provider/http_server.rb +79 -0
- data/lib/pact/v2/provider/http_verifier.rb +43 -0
- data/lib/pact/v2/provider/message_provider_servlet.rb +79 -0
- data/lib/pact/v2/provider/mixed_verifier.rb +22 -0
- data/lib/pact/v2/provider/pact_broker_proxy.rb +71 -0
- data/lib/pact/v2/provider/pact_broker_proxy_runner.rb +77 -0
- data/lib/pact/v2/provider/pact_config/async.rb +29 -0
- data/lib/pact/v2/provider/pact_config/base.rb +101 -0
- data/lib/pact/v2/provider/pact_config/grpc.rb +26 -0
- data/lib/pact/v2/provider/pact_config/http.rb +27 -0
- data/lib/pact/v2/provider/pact_config/mixed.rb +39 -0
- data/lib/pact/v2/provider/pact_config.rb +26 -0
- data/lib/pact/v2/provider/provider_server_runner.rb +89 -0
- data/lib/pact/v2/provider/provider_state_configuration.rb +32 -0
- data/lib/pact/v2/provider/provider_state_servlet.rb +86 -0
- data/lib/pact/v2/provider.rb +8 -0
- data/lib/pact/v2/railtie.rb +13 -0
- data/lib/pact/v2/rspec/support/pact_consumer_helpers.rb +80 -0
- data/lib/pact/v2/rspec/support/pact_message_helpers.rb +42 -0
- data/lib/pact/v2/rspec/support/pact_provider_helpers.rb +129 -0
- data/lib/pact/v2/rspec/support/waterdrop/pact_waterdrop_client.rb +27 -0
- data/lib/pact/v2/rspec/support/webmock/webmock_helpers.rb +30 -0
- data/lib/pact/v2/rspec.rb +17 -0
- data/lib/pact/v2/tasks/pact.rake +13 -0
- data/lib/pact/v2/version.rb +8 -0
- data/lib/pact/v2.rb +71 -0
- data/lib/pact/version.rb +4 -0
- data/lib/pact.rb +13 -0
- data/lib/tasks/pact.rake +34 -0
- data/pact.gemspec +106 -0
- metadata +529 -0
@@ -0,0 +1,43 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Core
|
3
|
+
|
4
|
+
# RSpec 3 has a hardwired @system_exclusion_patterns which removes everything matching /bin\//
|
5
|
+
# This causes *all* the backtrace lines to be cleaned, as rake pact:verify now shells out
|
6
|
+
# to the executable `pact verify ...`
|
7
|
+
# which then causes *all* the lines to be included as the BacktraceFormatter will
|
8
|
+
# include all lines of the backtrace if all lines were filtered out.
|
9
|
+
# This monkey patch only shows lines including bin/pact and removes the
|
10
|
+
# "show all lines if no lines would otherwise be shown" logic.
|
11
|
+
|
12
|
+
class BacktraceFormatter
|
13
|
+
|
14
|
+
|
15
|
+
def format_backtrace(backtrace, options = {})
|
16
|
+
return backtrace if options[:full_backtrace]
|
17
|
+
backtrace.map { |l| backtrace_line(l) }.compact
|
18
|
+
end
|
19
|
+
|
20
|
+
def backtrace_line(line)
|
21
|
+
relative_path(line) unless exclude?(line)
|
22
|
+
rescue SecurityError
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def exclude?(line)
|
27
|
+
return false if @full_backtrace
|
28
|
+
relative_line = relative_path(line)
|
29
|
+
return true unless /bin\/pact/ =~ relative_line
|
30
|
+
end
|
31
|
+
|
32
|
+
# Copied from Metadata so a refactor can't break this overridden class
|
33
|
+
def relative_path(line)
|
34
|
+
line = line.sub(File.expand_path("."), ".")
|
35
|
+
line = line.sub(/\A([^:]+:\d+)$/, '\\1')
|
36
|
+
return nil if line == '-e:1'
|
37
|
+
line
|
38
|
+
rescue SecurityError
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Pact
|
2
|
+
module Provider
|
3
|
+
module RSpec
|
4
|
+
module CalculateExitCode
|
5
|
+
def self.call(pact_sources, failed_examples)
|
6
|
+
any_non_pending_failures = pact_sources.any? do |pact_source|
|
7
|
+
if pact_source.pending?
|
8
|
+
nil
|
9
|
+
else
|
10
|
+
failed_examples.select { |e| e.metadata[:pact_source] == pact_source }.any?
|
11
|
+
end
|
12
|
+
end
|
13
|
+
any_non_pending_failures ? 1 : 0
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
File without changes
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'pact/provider/print_missing_provider_states'
|
2
|
+
require 'rspec/core/formatters/documentation_formatter'
|
3
|
+
require 'rainbow'
|
4
|
+
require 'pact/provider/help/prompt_text'
|
5
|
+
|
6
|
+
module Pact
|
7
|
+
module Provider
|
8
|
+
module RSpec
|
9
|
+
class Formatter2 < ::RSpec::Core::Formatters::DocumentationFormatter
|
10
|
+
|
11
|
+
class NilFormatter < ::RSpec::Core::Formatters::DocumentationFormatter
|
12
|
+
def dump_commands_to_rerun_failed_examples
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def dump_commands_to_rerun_failed_examples
|
17
|
+
return if failed_examples.empty?
|
18
|
+
|
19
|
+
print_rerun_commands
|
20
|
+
print_failure_message
|
21
|
+
print_missing_provider_states
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def print_rerun_commands
|
28
|
+
output.puts("\n")
|
29
|
+
interaction_rerun_commands.each do | message |
|
30
|
+
output.puts(message)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def print_missing_provider_states
|
35
|
+
if executing_with_ruby?
|
36
|
+
PrintMissingProviderStates.call Pact.provider_world.provider_states.missing_provider_states, output
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def interaction_rerun_commands
|
41
|
+
failed_examples.collect do |example|
|
42
|
+
interaction_rerun_command_for example
|
43
|
+
end.uniq
|
44
|
+
end
|
45
|
+
|
46
|
+
def interaction_rerun_command_for example
|
47
|
+
example_description = example.metadata[:pact_interaction_example_description]
|
48
|
+
if ENV['PACT_INTERACTION_RERUN_COMMAND']
|
49
|
+
cmd = String.new(ENV['PACT_INTERACTION_RERUN_COMMAND'])
|
50
|
+
provider_state = example.metadata[:pact_interaction].provider_state
|
51
|
+
description = example.metadata[:pact_interaction].description
|
52
|
+
pactfile_uri = example.metadata[:pactfile_uri]
|
53
|
+
cmd.gsub!("<PACT_URI>", pactfile_uri.to_s)
|
54
|
+
cmd.gsub!("<PACT_DESCRIPTION>", description)
|
55
|
+
cmd.gsub!("<PACT_PROVIDER_STATE>", "#{provider_state}")
|
56
|
+
failure_color(cmd) + " " + detail_color("# #{example_description}")
|
57
|
+
else
|
58
|
+
failure_color("* #{example_description}")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def print_failure_message
|
63
|
+
output.puts(failure_message) if executing_with_ruby?
|
64
|
+
end
|
65
|
+
|
66
|
+
def failure_message
|
67
|
+
"\n" + Pact::Provider::Help::PromptText.() + "\n"
|
68
|
+
end
|
69
|
+
|
70
|
+
def executing_with_ruby?
|
71
|
+
ENV['PACT_EXECUTING_LANGUAGE'] == 'ruby'
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,195 @@
|
|
1
|
+
require 'pact/provider/print_missing_provider_states'
|
2
|
+
require 'rspec/core/formatters'
|
3
|
+
require 'rainbow'
|
4
|
+
require 'pact/provider/help/prompt_text'
|
5
|
+
|
6
|
+
module Pact
|
7
|
+
module Provider
|
8
|
+
module RSpec
|
9
|
+
class Formatter < ::RSpec::Core::Formatters::DocumentationFormatter
|
10
|
+
|
11
|
+
class NilFormatter < ::RSpec::Core::Formatters::BaseFormatter
|
12
|
+
Pact::RSpec.with_rspec_3 do
|
13
|
+
::RSpec::Core::Formatters.register self, :start, :example_group_started, :close
|
14
|
+
end
|
15
|
+
|
16
|
+
def dump_summary(summary)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
Pact::RSpec.with_rspec_3 do
|
21
|
+
::RSpec::Core::Formatters.register self, :example_group_started, :example_group_finished,
|
22
|
+
:example_passed, :example_pending, :example_failed
|
23
|
+
end
|
24
|
+
|
25
|
+
def example_group_started(notification)
|
26
|
+
# This is the metadata on the top level "Verifying a pact between X and Y" describe block
|
27
|
+
if @group_level == 0
|
28
|
+
Pact.configuration.output_stream.puts
|
29
|
+
pact_uri = notification.group.metadata[:pactfile_uri]
|
30
|
+
::RSpec.configuration.failure_color = pact_uri.metadata[:pending] ? :yellow : :red
|
31
|
+
|
32
|
+
if pact_uri.metadata[:notices]
|
33
|
+
pact_uri.metadata[:notices].before_verification_notices_text.each do | text |
|
34
|
+
Pact.configuration.output_stream.puts("DEBUG: #{text}")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
criteria = notification.group.metadata[:pact_criteria]
|
39
|
+
Pact.configuration.output_stream.puts "DEBUG: Filtering interactions by: #{criteria}" if criteria && criteria.any?
|
40
|
+
end
|
41
|
+
super
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
def dump_summary(summary)
|
46
|
+
output.puts "\n" + colorized_totals_line(summary)
|
47
|
+
return if summary.failure_count == 0
|
48
|
+
print_rerun_commands summary
|
49
|
+
print_failure_message
|
50
|
+
print_missing_provider_states
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def interactions_count(summary)
|
56
|
+
summary.examples.collect{ |e| interaction_unique_key(e) }.uniq.size
|
57
|
+
end
|
58
|
+
|
59
|
+
def failed_interactions_count(summary)
|
60
|
+
failed_interaction_examples(summary).size
|
61
|
+
end
|
62
|
+
|
63
|
+
def pending_interactions_count(summary)
|
64
|
+
pending_interaction_examples(summary).size
|
65
|
+
end
|
66
|
+
|
67
|
+
def failure_title summary
|
68
|
+
::RSpec::Core::Formatters::Helpers.pluralize(failed_interactions_count(summary), "failure")
|
69
|
+
end
|
70
|
+
|
71
|
+
def totals_line summary
|
72
|
+
line = ::RSpec::Core::Formatters::Helpers.pluralize(interactions_count(summary), "interaction")
|
73
|
+
line << ", " << failure_title(summary)
|
74
|
+
pending_count = pending_interactions_count(summary)
|
75
|
+
line << ", " << "#{pending_count} pending" if pending_count > 0
|
76
|
+
line
|
77
|
+
end
|
78
|
+
|
79
|
+
def colorized_totals_line(summary)
|
80
|
+
colorizer.wrap(totals_line(summary), color_for_summary(summary))
|
81
|
+
end
|
82
|
+
|
83
|
+
def color_for_summary summary
|
84
|
+
summary.failure_count > 0 ? ::RSpec.configuration.failure_color : ::RSpec.configuration.success_color
|
85
|
+
end
|
86
|
+
|
87
|
+
def print_rerun_commands summary
|
88
|
+
if pending_interactions_count(summary) > 0
|
89
|
+
set_rspec_failure_color(:yellow)
|
90
|
+
output.puts("\nPending interactions: (Failures listed here are expected and do not affect your suite's status)\n\n")
|
91
|
+
interaction_rerun_commands(pending_interaction_examples(summary)).each do | message |
|
92
|
+
output.puts(message)
|
93
|
+
end
|
94
|
+
set_rspec_failure_color(:red)
|
95
|
+
end
|
96
|
+
|
97
|
+
if failed_interactions_count(summary) > 0
|
98
|
+
output.puts("\nFailed interactions:\n\n")
|
99
|
+
interaction_rerun_commands(failed_interaction_examples(summary)).each do | message |
|
100
|
+
output.puts(message)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def print_missing_provider_states
|
106
|
+
if executing_with_ruby?
|
107
|
+
PrintMissingProviderStates.call Pact.provider_world.provider_states.missing_provider_states, output
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def pending_interaction_examples(summary)
|
112
|
+
one_failed_example_per_interaction(summary).select do | example |
|
113
|
+
example.metadata[:pactfile_uri].metadata[:pending]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def failed_interaction_examples(summary)
|
118
|
+
one_failed_example_per_interaction(summary).select do | example |
|
119
|
+
!example.metadata[:pactfile_uri].metadata[:pending]
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def one_failed_example_per_interaction(summary)
|
124
|
+
summary.failed_examples.group_by{| e| interaction_unique_key(e)}.values.collect(&:first)
|
125
|
+
end
|
126
|
+
|
127
|
+
def interaction_rerun_commands examples
|
128
|
+
examples.collect do |example|
|
129
|
+
interaction_rerun_command_for example
|
130
|
+
end.compact.uniq
|
131
|
+
end
|
132
|
+
|
133
|
+
def interaction_unique_key(example)
|
134
|
+
# pending is just to make the counting easier, it isn't required for the unique key
|
135
|
+
{
|
136
|
+
pactfile_uri: example.metadata[:pactfile_uri],
|
137
|
+
index: example.metadata[:pact_interaction].index,
|
138
|
+
}
|
139
|
+
end
|
140
|
+
|
141
|
+
def interaction_rerun_command_for example
|
142
|
+
example_description = example.metadata[:pact_interaction_example_description]
|
143
|
+
|
144
|
+
_id = example.metadata[:pact_interaction]._id
|
145
|
+
index = example.metadata[:pact_interaction].index
|
146
|
+
provider_state = example.metadata[:pact_interaction].provider_state
|
147
|
+
description = example.metadata[:pact_interaction].description
|
148
|
+
pactfile_uri = example.metadata[:pactfile_uri]
|
149
|
+
|
150
|
+
if _id && ENV['PACT_INTERACTION_RERUN_COMMAND_FOR_BROKER']
|
151
|
+
cmd = String.new(ENV['PACT_INTERACTION_RERUN_COMMAND_FOR_BROKER'])
|
152
|
+
cmd.gsub!("<PACT_URI>", example.metadata[:pactfile_uri].to_s)
|
153
|
+
cmd.gsub!("<PACT_BROKER_INTERACTION_ID>", "#{_id}")
|
154
|
+
colorizer.wrap("#{cmd} ", ::RSpec.configuration.failure_color) + colorizer.wrap("# #{example_description}", ::RSpec.configuration.detail_color)
|
155
|
+
elsif ENV['PACT_INTERACTION_RERUN_COMMAND']
|
156
|
+
cmd = String.new(ENV['PACT_INTERACTION_RERUN_COMMAND'])
|
157
|
+
cmd.gsub!("<PACT_URI>", pactfile_uri.to_s)
|
158
|
+
cmd.gsub!("<PACT_DESCRIPTION>", description)
|
159
|
+
cmd.gsub!("<PACT_PROVIDER_STATE>", "#{provider_state}")
|
160
|
+
cmd.gsub!("<PACT_INTERACTION_INDEX>", "#{index}")
|
161
|
+
colorizer.wrap("#{cmd} ", ::RSpec.configuration.failure_color) + colorizer.wrap("# #{example_description}", ::RSpec.configuration.detail_color)
|
162
|
+
else
|
163
|
+
message = if _id
|
164
|
+
"* #{example_description} (to re-run just this interaction, set environment variable PACT_BROKER_INTERACTION_ID=\"#{_id}\")"
|
165
|
+
else
|
166
|
+
"* #{example_description} (to re-run just this interaction, set environment variables PACT_DESCRIPTION=\"#{description}\" PACT_PROVIDER_STATE=\"#{provider_state}\")"
|
167
|
+
end
|
168
|
+
colorizer.wrap(message, ::RSpec.configuration.failure_color)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def print_failure_message
|
173
|
+
output.puts(failure_message) if executing_with_ruby?
|
174
|
+
end
|
175
|
+
|
176
|
+
def failure_message
|
177
|
+
"\n" + Pact::Provider::Help::PromptText.() + "\n"
|
178
|
+
end
|
179
|
+
|
180
|
+
def colorizer
|
181
|
+
@colorizer ||= ::RSpec::Core::Formatters::ConsoleCodes
|
182
|
+
end
|
183
|
+
|
184
|
+
def executing_with_ruby?
|
185
|
+
ENV['PACT_EXECUTING_LANGUAGE'] == 'ruby'
|
186
|
+
end
|
187
|
+
|
188
|
+
def set_rspec_failure_color color
|
189
|
+
::RSpec.configuration.failure_color = color
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'rspec/core/formatters/json_formatter'
|
2
|
+
|
3
|
+
module Pact
|
4
|
+
module Provider
|
5
|
+
module RSpec
|
6
|
+
class JsonFormatter < ::RSpec::Core::Formatters::JsonFormatter
|
7
|
+
::RSpec::Core::Formatters.register self, :message, :dump_summary, :dump_profile, :stop, :seed, :close
|
8
|
+
|
9
|
+
def dump_summary(summary)
|
10
|
+
super(create_custom_summary(summary))
|
11
|
+
output_hash[:summary][:pacts] = pacts(summary)
|
12
|
+
end
|
13
|
+
|
14
|
+
def format_example(example)
|
15
|
+
{
|
16
|
+
:id => example.id,
|
17
|
+
:interaction_index => example.metadata[:pact_interaction].index,
|
18
|
+
:description => example.description,
|
19
|
+
:full_description => example.full_description,
|
20
|
+
:status => calculate_status(example),
|
21
|
+
:file_path => example.metadata[:file_path],
|
22
|
+
:line_number => example.metadata[:line_number],
|
23
|
+
:run_time => example.execution_result.run_time,
|
24
|
+
:mismatches => extract_differences(example),
|
25
|
+
:pact_url => example.metadata[:pact_uri].uri
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def stop(notification)
|
30
|
+
output_hash[:examples] = notification.examples.map do |example|
|
31
|
+
format_example(example).tap do |hash|
|
32
|
+
e = example.exception
|
33
|
+
if e
|
34
|
+
hash[:exception] = {
|
35
|
+
class: e.class.name,
|
36
|
+
message: e.message,
|
37
|
+
}
|
38
|
+
# No point providing a backtrace for a mismatch, too much noise
|
39
|
+
if !e.is_a?(::RSpec::Expectations::ExpectationNotMetError)
|
40
|
+
hash[:exception][:backtrace]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def calculate_status(example)
|
48
|
+
if example.execution_result.status == :failed && example.metadata[:pact_ignore_failures]
|
49
|
+
'pending'
|
50
|
+
else
|
51
|
+
example.execution_result.status.to_s
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# There will most likely be only one pact associated with this RSpec execution, because
|
56
|
+
# the most likely user of this formatter is the Go implementation that parses the JSON
|
57
|
+
# and builds Go tests from them.
|
58
|
+
# If the JSON formatter is used by someone else and they have multiple pacts, all the notices
|
59
|
+
# for the pacts will be mushed together in one collection, so it will be hard to know which notice
|
60
|
+
# belongs to which pact.
|
61
|
+
def pacts(summary)
|
62
|
+
unique_pact_metadatas(summary).collect do | example_metadata |
|
63
|
+
pact_uri = example_metadata[:pact_uri]
|
64
|
+
notices = (pact_uri.metadata[:notices] && pact_uri.metadata[:notices].before_verification_notices) || []
|
65
|
+
{
|
66
|
+
notices: notices,
|
67
|
+
url: pact_uri.uri,
|
68
|
+
consumer_name: example_metadata[:pact_consumer_contract].consumer.name,
|
69
|
+
provider_name: example_metadata[:pact_consumer_contract].provider.name,
|
70
|
+
short_description: pact_uri.metadata[:short_description]
|
71
|
+
}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def unique_pact_metadatas(summary)
|
76
|
+
summary.examples.collect(&:metadata).group_by{ | metadata | metadata[:pact_uri].uri }.values.collect(&:first)
|
77
|
+
end
|
78
|
+
|
79
|
+
def create_custom_summary(summary)
|
80
|
+
::RSpec::Core::Notifications::SummaryNotification.new(
|
81
|
+
summary.duration,
|
82
|
+
summary.examples,
|
83
|
+
summary.examples.select{ | example | example.execution_result.status == :failed && !example.metadata[:pact_ignore_failures] },
|
84
|
+
summary.examples.select{ | example | example.execution_result.status == :failed && example.metadata[:pact_ignore_failures] },
|
85
|
+
summary.load_time,
|
86
|
+
summary.errors_outside_of_examples_count
|
87
|
+
)
|
88
|
+
end
|
89
|
+
|
90
|
+
def extract_differences(example)
|
91
|
+
if example.metadata[:pact_diff]
|
92
|
+
Pact::Matchers::ExtractDiffMessages.call(example.metadata[:pact_diff]).to_a
|
93
|
+
else
|
94
|
+
[]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'pact/matchers'
|
3
|
+
require 'pact/provider/matchers/messages'
|
4
|
+
require 'pact/rspec'
|
5
|
+
require 'pact/shared/json_differ'
|
6
|
+
|
7
|
+
module Pact
|
8
|
+
module RSpec
|
9
|
+
module Matchers
|
10
|
+
module RSpec2Delegator
|
11
|
+
# For backwards compatibility with rspec-2
|
12
|
+
def method_missing(method, *args, &block)
|
13
|
+
if method_name == :failure_message_for_should
|
14
|
+
failure_message method, *args, &block
|
15
|
+
else
|
16
|
+
super
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class MatchTerm
|
22
|
+
include Pact::Matchers::Messages
|
23
|
+
include RSpec2Delegator
|
24
|
+
|
25
|
+
def initialize expected, differ, diff_formatter, example
|
26
|
+
@expected = expected
|
27
|
+
@differ = differ
|
28
|
+
@diff_formatter = diff_formatter
|
29
|
+
@example = example
|
30
|
+
end
|
31
|
+
|
32
|
+
def matches? actual
|
33
|
+
@actual = actual
|
34
|
+
@difference = @differ.call(@expected, @actual)
|
35
|
+
unless @difference.empty?
|
36
|
+
Pact::RSpec.with_rspec_3 do
|
37
|
+
@example.metadata[:pact_diff] = @difference
|
38
|
+
end
|
39
|
+
Pact::RSpec.with_rspec_2 do
|
40
|
+
@example.example.metadata[:pact_diff] = @difference
|
41
|
+
end
|
42
|
+
end
|
43
|
+
@difference.empty?
|
44
|
+
end
|
45
|
+
|
46
|
+
def failure_message
|
47
|
+
match_term_failure_message @difference, @actual, @diff_formatter, Pact::RSpec.color_enabled?
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def match_term expected, options, example
|
52
|
+
MatchTerm.new(expected, options.fetch(:with), options.fetch(:diff_formatter), example)
|
53
|
+
end
|
54
|
+
|
55
|
+
class MatchHeader
|
56
|
+
include Pact::Matchers
|
57
|
+
include Pact::Matchers::Messages
|
58
|
+
include RSpec2Delegator
|
59
|
+
|
60
|
+
def initialize header_name, expected
|
61
|
+
@header_name = header_name
|
62
|
+
@expected = expected
|
63
|
+
end
|
64
|
+
|
65
|
+
def matches? actual
|
66
|
+
@actual = actual
|
67
|
+
diff(@expected, @actual).empty?
|
68
|
+
end
|
69
|
+
|
70
|
+
def failure_message
|
71
|
+
match_header_failure_message @header_name, @expected, @actual
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def match_header header_name, expected
|
76
|
+
MatchHeader.new(header_name, expected)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'rspec/core/formatters'
|
2
|
+
require 'pact/provider/verification_results/publish_all'
|
3
|
+
require 'rainbow'
|
4
|
+
require 'pact/matchers/extract_diff_messages'
|
5
|
+
|
6
|
+
module Pact
|
7
|
+
module Provider
|
8
|
+
module RSpec
|
9
|
+
class PactBrokerFormatter < ::RSpec::Core::Formatters::BaseFormatter
|
10
|
+
Pact::RSpec.with_rspec_3 do
|
11
|
+
::RSpec::Core::Formatters.register self, :stop, :close
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :output_hash
|
15
|
+
|
16
|
+
def initialize(output)
|
17
|
+
super
|
18
|
+
@output_hash = {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def stop(notification)
|
22
|
+
@output_hash[:tests] = notification
|
23
|
+
.examples
|
24
|
+
.map { |example| format_example(example) }
|
25
|
+
end
|
26
|
+
|
27
|
+
def close(_notification)
|
28
|
+
Pact::Provider::VerificationResults::PublishAll.call(Pact.provider_world.pact_sources, output_hash, { verbose: Pact.provider_world.verbose })
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def format_example(example)
|
34
|
+
{
|
35
|
+
testDescription: example.description,
|
36
|
+
testFullDescription: example.full_description,
|
37
|
+
status: example.execution_result.status.to_s,
|
38
|
+
interactionProviderState: example.metadata[:pact_interaction].provider_state,
|
39
|
+
interactionDescription: example.metadata[:pact_interaction].description,
|
40
|
+
pact_uri: example.metadata[:pact_uri],
|
41
|
+
pact_interaction: example.metadata[:pact_interaction]
|
42
|
+
}.tap do |hash|
|
43
|
+
if example.exception
|
44
|
+
hash[:exception] = {
|
45
|
+
class: example.exception.class.name,
|
46
|
+
message: "\e[0m#{example.exception.message}"
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
if example.metadata[:pact_actual_status]
|
51
|
+
hash[:actualStatus] = example.metadata[:pact_actual_status]
|
52
|
+
end
|
53
|
+
|
54
|
+
if example.metadata[:pact_actual_headers]
|
55
|
+
hash[:actualHeaders] = example.metadata[:pact_actual_headers]
|
56
|
+
end
|
57
|
+
|
58
|
+
if example.metadata[:pact_actual_body]
|
59
|
+
hash[:actualBody] = example.metadata[:pact_actual_body]
|
60
|
+
end
|
61
|
+
|
62
|
+
if example.metadata[:pact_actual_contents]
|
63
|
+
hash[:actualContents] = example.metadata[:pact_actual_contents]
|
64
|
+
end
|
65
|
+
|
66
|
+
if example.metadata[:pact_diff]
|
67
|
+
hash[:differences] = Pact::Matchers::ExtractDiffMessages.call(example.metadata[:pact_diff])
|
68
|
+
.to_a
|
69
|
+
.collect{ | description | { description: description } }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|